From 0e6f9f9aeca8ebb46b40780dbfeca24a5682f457 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 29 Apr 2020 18:24:57 -0400 Subject: [PATCH] gpu: add support for osx Compute shaders must be forced off due to macos not supporting opengl 4.3 --- runelite-client/pom.xml | 14 + .../client/plugins/gpu/GpuPlugin.java | 260 +++++++++++------- 2 files changed, 180 insertions(+), 94 deletions(-) diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 578bd6e952..527914a8b1 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -117,6 +117,13 @@ natives-linux-amd64 runtime + + net.runelite.jogl + jogl-all + ${jogl.version} + natives-macosx-universal + runtime + net.runelite.gluegen gluegen-rt @@ -143,6 +150,13 @@ natives-linux-amd64 runtime + + net.runelite.gluegen + gluegen-rt + ${jogl.version} + natives-macosx-universal + runtime + net.runelite archive-patcher diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java index d7fc8f56d0..4e16ffd2e0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java @@ -35,6 +35,7 @@ import com.jogamp.opengl.GLContext; import com.jogamp.opengl.GLDrawable; import com.jogamp.opengl.GLDrawableFactory; import com.jogamp.opengl.GLException; +import com.jogamp.opengl.GLFBODrawable; import com.jogamp.opengl.GLProfile; import java.awt.Canvas; import java.awt.Dimension; @@ -51,6 +52,7 @@ import javax.inject.Inject; import javax.swing.SwingUtilities; import jogamp.nativewindow.SurfaceScaleUtils; import jogamp.nativewindow.jawt.x11.X11JAWTWindow; +import jogamp.nativewindow.macosx.OSXUtil; import jogamp.newt.awt.NewtFactoryAWT; import lombok.extern.slf4j.Slf4j; import net.runelite.api.BufferProvider; @@ -286,7 +288,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks return false; } - useComputeShaders = config.useComputeShaders(); + // OSX supports up to OpenGL 4.1, however 4.3 is required for compute shaders + useComputeShaders = config.useComputeShaders() && OSType.getOSType() != OSType.MacOS; canvas.setIgnoreRepaint(true); @@ -304,55 +307,73 @@ public class GpuPlugin extends Plugin implements DrawCallbacks GLProfile.initSingleton(); - GLProfile glProfile = GLProfile.get(GLProfile.GL4); - - GLCapabilities glCaps = new GLCapabilities(glProfile); - AWTGraphicsConfiguration config = AWTGraphicsConfiguration.create(canvas.getGraphicsConfiguration(), glCaps, glCaps); - - jawtWindow = NewtFactoryAWT.getNativeWindow(canvas, config); - canvas.setFocusable(true); - - GLDrawableFactory glDrawableFactory = GLDrawableFactory.getFactory(glProfile); - - glDrawable = glDrawableFactory.createGLDrawable(jawtWindow); - glDrawable.setRealized(true); - - glContext = glDrawable.createContext(null); - if (log.isDebugEnabled()) + invokeOnMainThread(() -> { - // Debug config on context needs to be set before .makeCurrent call - glContext.enableGLDebugMessage(true); - } + GLProfile glProfile = GLProfile.get(GLProfile.GL4); - int res = glContext.makeCurrent(); - if (res == GLContext.CONTEXT_NOT_CURRENT) - { - throw new GLException("Unable to make context current"); - } + GLCapabilities glCaps = new GLCapabilities(glProfile); + AWTGraphicsConfiguration config = AWTGraphicsConfiguration.create(canvas.getGraphicsConfiguration(), glCaps, glCaps); - // Surface needs to be unlocked on X11 window otherwise input is blocked - if (jawtWindow instanceof X11JAWTWindow && jawtWindow.getLock().isLocked()) - { - jawtWindow.unlockSurface(); - } + jawtWindow = NewtFactoryAWT.getNativeWindow(canvas, config); + canvas.setFocusable(true); - this.gl = glContext.getGL().getGL4(); - gl.setSwapInterval(0); + GLDrawableFactory glDrawableFactory = GLDrawableFactory.getFactory(glProfile); - if (log.isDebugEnabled()) - { - gl.glEnable(gl.GL_DEBUG_OUTPUT); + jawtWindow.lockSurface(); + try + { + glDrawable = glDrawableFactory.createGLDrawable(jawtWindow); + glDrawable.setRealized(true); - // Suppress warning messages which flood the log on NVIDIA systems. - gl.getContext().glDebugMessageControl(gl.GL_DEBUG_SOURCE_API, gl.GL_DEBUG_TYPE_OTHER, - gl.GL_DEBUG_SEVERITY_NOTIFICATION, 0, null, 0, false); - } + glContext = glDrawable.createContext(null); + if (log.isDebugEnabled()) + { + // Debug config on context needs to be set before .makeCurrent call + glContext.enableGLDebugMessage(true); + } + } + finally + { + jawtWindow.unlockSurface(); + } - initVao(); - initProgram(); - initInterfaceTexture(); - initUniformBuffer(); - initBuffers(); + int res = glContext.makeCurrent(); + if (res == GLContext.CONTEXT_NOT_CURRENT) + { + throw new GLException("Unable to make context current"); + } + + // Surface needs to be unlocked on X11 window otherwise input is blocked + if (jawtWindow instanceof X11JAWTWindow && jawtWindow.getLock().isLocked()) + { + jawtWindow.unlockSurface(); + } + + this.gl = glContext.getGL().getGL4(); + gl.setSwapInterval(0); + + if (log.isDebugEnabled()) + { + gl.glEnable(gl.GL_DEBUG_OUTPUT); + + // Suppress warning messages which flood the log on NVIDIA systems. + gl.getContext().glDebugMessageControl(gl.GL_DEBUG_SOURCE_API, gl.GL_DEBUG_TYPE_OTHER, + gl.GL_DEBUG_SEVERITY_NOTIFICATION, 0, null, 0, false); + } + + initVao(); + try + { + initProgram(); + } + catch (ShaderException ex) + { + throw new RuntimeException(ex); + } + initInterfaceTexture(); + initUniformBuffer(); + initBuffers(); + }); client.setDrawCallbacks(this); client.setGpu(true); @@ -408,41 +429,51 @@ public class GpuPlugin extends Plugin implements DrawCallbacks client.setGpu(false); client.setDrawCallbacks(null); - if (gl != null) + invokeOnMainThread(() -> { - if (textureArrayId != -1) + if (gl != null) { - textureManager.freeTextureArray(gl, textureArrayId); - textureArrayId = -1; + if (textureArrayId != -1) + { + textureManager.freeTextureArray(gl, textureArrayId); + textureArrayId = -1; + } + + if (uniformBufferId != -1) + { + GLUtil.glDeleteBuffer(gl, uniformBufferId); + uniformBufferId = -1; + } + + shutdownBuffers(); + shutdownInterfaceTexture(); + shutdownProgram(); + shutdownVao(); + shutdownAAFbo(); } - if (uniformBufferId != -1) + if (jawtWindow != null) { - GLUtil.glDeleteBuffer(gl, uniformBufferId); - uniformBufferId = -1; + if (!jawtWindow.getLock().isLocked()) + { + jawtWindow.lockSurface(); + } + + if (glContext != null) + { + glContext.destroy(); + } + + // this crashes on osx when the plugin is turned back on, don't know why + // we'll just leak the window... + if (OSType.getOSType() != OSType.MacOS) + { + NewtFactoryAWT.destroyNativeWindow(jawtWindow); + } } + }); - shutdownBuffers(); - shutdownInterfaceTexture(); - shutdownProgram(); - shutdownVao(); - shutdownAAFbo(); - } - - if (jawtWindow != null) - { - if (!jawtWindow.getLock().isLocked()) - { - jawtWindow.lockSurface(); - } - - if (glContext != null) - { - glContext.destroy(); - } - - NewtFactoryAWT.destroyNativeWindow(jawtWindow); - } + GLProfile.shutdown(); jawtWindow = null; gl = null; @@ -839,6 +870,42 @@ public class GpuPlugin extends Plugin implements DrawCallbacks @Override public void draw() + { + invokeOnMainThread(this::drawFrame); + } + + private void resize(int canvasWidth, int canvasHeight, int viewportWidth, int viewportHeight) + { + // If the viewport has changed, update the projection matrix + if (viewportWidth > 0 && viewportHeight > 0 && (viewportWidth != lastViewportWidth || viewportHeight != lastViewportHeight)) + { + lastViewportWidth = viewportWidth; + lastViewportHeight = viewportHeight; + createProjectionMatrix(0, viewportWidth, viewportHeight, 0, 0, Constants.SCENE_SIZE * Perspective.LOCAL_TILE_SIZE); + } + + if (canvasWidth != lastCanvasWidth || canvasHeight != lastCanvasHeight) + { + lastCanvasWidth = canvasWidth; + lastCanvasHeight = canvasHeight; + + gl.glBindTexture(gl.GL_TEXTURE_2D, interfaceTexture); + gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, canvasWidth, canvasHeight, 0, gl.GL_BGRA, gl.GL_UNSIGNED_INT_8_8_8_8_REV, null); + gl.glBindTexture(gl.GL_TEXTURE_2D, 0); + + if (OSType.getOSType() == OSType.MacOS && glDrawable instanceof GLFBODrawable) + { + // GLDrawables created with createGLDrawable() do not have a resize listener + // I don't know why this works with Windows/Linux, but on OSX + // it prevents JOGL from resizing its FBOs and underlying GL textures. So, + // we manually trigger a resize here. + GLFBODrawable glfboDrawable = (GLFBODrawable) glDrawable; + glfboDrawable.resetSize(gl); + } + } + } + + private void drawFrame() { if (jawtWindow.getAWTComponent() != client.getCanvas()) { @@ -862,13 +929,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks final int viewportHeight = client.getViewportHeight(); final int viewportWidth = client.getViewportWidth(); - // If the viewport has changed, update the projection matrix - if (viewportWidth > 0 && viewportHeight > 0 && (viewportWidth != lastViewportWidth || viewportHeight != lastViewportHeight)) - { - createProjectionMatrix(0, viewportWidth, viewportHeight, 0, 0, Constants.SCENE_SIZE * Perspective.LOCAL_TILE_SIZE); - lastViewportWidth = viewportWidth; - lastViewportHeight = viewportHeight; - } + resize(canvasWidth, canvasHeight, viewportWidth, viewportHeight); // Setup anti-aliasing final AntiAliasingMode antiAliasingMode = config.antiAliasingMode(); @@ -1176,16 +1237,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks gl.glBlendFunc(gl.GL_ONE, gl.GL_ONE_MINUS_SRC_ALPHA); gl.glBindTexture(gl.GL_TEXTURE_2D, interfaceTexture); - if (canvasWidth != lastCanvasWidth || canvasHeight != lastCanvasHeight) - { - gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, width, height, 0, gl.GL_BGRA, gl.GL_UNSIGNED_INT_8_8_8_8_REV, interfaceBuffer); - lastCanvasWidth = canvasWidth; - lastCanvasHeight = canvasHeight; - } - else - { - gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, width, height, gl.GL_BGRA, gl.GL_UNSIGNED_INT_8_8_8_8_REV, interfaceBuffer); - } + gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, width, height, gl.GL_BGRA, gl.GL_UNSIGNED_INT_8_8_8_8_REV, interfaceBuffer); // Use the texture bound in the first pass final UIScalingMode uiScalingMode = config.uiScalingMode(); @@ -1526,12 +1578,20 @@ public class GpuPlugin extends Plugin implements DrawCallbacks private void glDpiAwareViewport(final int x, final int y, final int width, final int height) { - final AffineTransform t = ((Graphics2D) canvas.getGraphics()).getTransform(); - gl.glViewport( - getScaledValue(t.getScaleX(), x), - getScaledValue(t.getScaleY(), y), - getScaledValue(t.getScaleX(), width), - getScaledValue(t.getScaleY(), height)); + if (OSType.getOSType() == OSType.MacOS) + { + // JOGL seems to handle DPI scaling for us already + gl.glViewport(x, y, width, height); + } + else + { + final AffineTransform t = ((Graphics2D) canvas.getGraphics()).getTransform(); + gl.glViewport( + getScaledValue(t.getScaleX(), x), + getScaledValue(t.getScaleY(), y), + getScaledValue(t.getScaleX(), width), + getScaledValue(t.getScaleY(), height)); + } } private int getDrawDistance() @@ -1539,4 +1599,16 @@ public class GpuPlugin extends Plugin implements DrawCallbacks final int limit = useComputeShaders ? MAX_DISTANCE : DEFAULT_DISTANCE; return Ints.constrainToRange(config.drawDistance(), 0, limit); } + + private static void invokeOnMainThread(Runnable runnable) + { + if (OSType.getOSType() == OSType.MacOS) + { + OSXUtil.RunOnMainThread(true, false, runnable); + } + else + { + runnable.run(); + } + } }