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();
+ }
+ }
}