Skip to content

Commit 35293c0

Browse files
committed
Implemented necessary logic in PSurfaceJOGL to handle context sharing and object synchronization
1 parent 69d14ab commit 35293c0

File tree

1 file changed

+81
-25
lines changed

1 file changed

+81
-25
lines changed

core/src/processing/opengl/PSurfaceJOGL.java

Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.io.InputStream;
4040
import java.net.URL;
4141
import java.nio.ByteBuffer;
42+
import java.util.ArrayList;
4243
import java.util.HashMap;
4344
import java.util.Map;
4445

@@ -56,6 +57,7 @@
5657
import com.jogamp.opengl.GLEventListener;
5758
import com.jogamp.opengl.GLException;
5859
import com.jogamp.opengl.GLProfile;
60+
import com.jogamp.opengl.GLDrawableFactory;
5961
import com.jogamp.nativewindow.MutableGraphicsConfiguration;
6062
import com.jogamp.nativewindow.WindowClosingProtocol;
6163
import com.jogamp.newt.Display;
@@ -107,6 +109,11 @@ public class PSurfaceJOGL implements PSurface {
107109

108110
protected NewtCanvasAWT canvas;
109111

112+
protected static GLAutoDrawable sharedDrawable;
113+
protected static ArrayList<FPSAnimator> animators = new ArrayList<>();
114+
private final static Object sharedSyncMutex = new Object();
115+
private Object syncMutex;
116+
110117
protected int windowScaleFactor;
111118

112119
protected float[] currentPixelScale = { 0, 0 };
@@ -254,6 +261,29 @@ protected void initGL() {
254261
caps.setBackgroundOpaque(true);
255262
caps.setOnscreen(true);
256263
pgl.setCaps(caps);
264+
265+
if (sharedDrawable == null) {
266+
// Create a shared drawable to enable context sharing across multiple GL windows
267+
// https://jogamp.org/deployment/jogamp-next/javadoc/jogl/javadoc/com/jogamp/opengl/GLSharedContextSetter.html
268+
sharedDrawable = GLDrawableFactory.getFactory(profile).createDummyAutoDrawable(null, true, caps, null);
269+
sharedDrawable.display();
270+
}
271+
}
272+
273+
274+
// To properly deal with synchronization when context sharing across multiple drawables (windows), we need a
275+
// synchronization mutex object to ensure that rendering of each frame completes in their respective animator thread:
276+
// https://jogamp.org/deployment/jogamp-next/javadoc/jogl/javadoc/com/jogamp/opengl/GLSharedContextSetter.html#synchronization
277+
private Object getSyncMutex(GLAutoDrawable drawable) {
278+
pgl.getGL(drawable);
279+
if (pgl.needSharedObjectSync()) {
280+
syncMutex = sharedSyncMutex;
281+
} else {
282+
if (syncMutex == null) {
283+
syncMutex = new Object();
284+
}
285+
}
286+
return syncMutex;
257287
}
258288

259289

@@ -327,6 +357,8 @@ protected void initWindow() {
327357
window.setTopLevelSize((int) displayRect.getWidth(), (int) displayRect.getHeight());
328358
}
329359
}
360+
361+
window.setSharedAutoDrawable(sharedDrawable);
330362
}
331363

332364

@@ -354,6 +386,7 @@ protected void initAnimator() {
354386
}
355387

356388
animator = new FPSAnimator(window, 60);
389+
animators.add(animator);
357390

358391
drawException = null;
359392
animator.setUncaughtExceptionHandler((animator, drawable, cause) -> {
@@ -637,6 +670,10 @@ public boolean stopThread() {
637670
drawExceptionHandler = null;
638671
}
639672
if (animator != null) {
673+
// Stops all other animators to avoid exceptions when closing a window in a multiple window configuration
674+
for (FPSAnimator ani: animators) {
675+
if (ani != animator) ani.stop();
676+
}
640677
return animator.stop();
641678
} else {
642679
return false;
@@ -753,9 +790,13 @@ public void requestFocus() {
753790

754791

755792
public class DrawListener implements GLEventListener {
793+
private boolean isInit = false;
794+
756795
public void display(GLAutoDrawable drawable) {
796+
if (!isInit) return;
797+
757798
if (display.getEDTUtil().isCurrentThreadEDT()) {
758-
// For an unknown reason, the first two frames of the animator run on
799+
// For some unknown reason, a few frames of the animator run on
759800
// the EDT. For those, we just skip this draw call to avoid badness.
760801
return;
761802
}
@@ -770,17 +811,19 @@ public void display(GLAutoDrawable drawable) {
770811
}
771812

772813
if (!sketch.finished) {
773-
pgl.getGL(drawable);
774-
int prevFrameCount = sketch.frameCount;
775-
sketch.handleDraw();
776-
if (prevFrameCount == sketch.frameCount || sketch.finished) {
777-
// This hack allows the FBO layer to be swapped normally even if
778-
// the sketch is no looping or finished because it does not call draw(),
779-
// otherwise background artifacts may occur (depending on the hardware/drivers).
780-
pgl.beginRender();
781-
pgl.endRender(sketch.sketchWindowColor());
814+
synchronized (getSyncMutex(drawable)) {
815+
pgl.getGL(drawable);
816+
int prevFrameCount = sketch.frameCount;
817+
sketch.handleDraw();
818+
if (prevFrameCount == sketch.frameCount || sketch.finished) {
819+
// This hack allows the FBO layer to be swapped normally even if
820+
// the sketch is no looping or finished because it does not call draw(),
821+
// otherwise background artifacts may occur (depending on the hardware/drivers).
822+
pgl.beginRender();
823+
pgl.endRender(sketch.sketchWindowColor());
824+
}
825+
PGraphicsOpenGL.completeFinishedPixelTransfers();
782826
}
783-
PGraphicsOpenGL.completeFinishedPixelTransfers();
784827
}
785828

786829
if (sketch.exitCalled()) {
@@ -796,24 +839,37 @@ public void dispose(GLAutoDrawable drawable) {
796839
}
797840

798841
public void init(GLAutoDrawable drawable) {
799-
pgl.getGL(drawable);
800-
pgl.init(drawable);
801-
sketch.start();
842+
if (display.getEDTUtil().isCurrentThreadEDT()) {
843+
return;
844+
}
802845

803-
int c = graphics.backgroundColor;
804-
pgl.clearColor(((c >> 16) & 0xff) / 255f,
805-
((c >> 8) & 0xff) / 255f,
806-
(c & 0xff) / 255f,
807-
((c >> 24) & 0xff) / 255f);
808-
pgl.clear(PGL.COLOR_BUFFER_BIT);
846+
synchronized (getSyncMutex(drawable)) {
847+
pgl.init(drawable);
848+
sketch.start();
849+
850+
int c = graphics.backgroundColor;
851+
pgl.clearColor(((c >> 16) & 0xff) / 255f,
852+
((c >> 8) & 0xff) / 255f,
853+
(c & 0xff) / 255f,
854+
((c >> 24) & 0xff) / 255f);
855+
pgl.clear(PGL.COLOR_BUFFER_BIT);
856+
isInit = true;
857+
}
809858
}
810859

811860
public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
812-
pgl.resetFBOLayer();
813-
pgl.getGL(drawable);
814-
float scale = PApplet.platform == PConstants.MACOS ?
815-
getCurrentPixelScale() : getPixelScale();
816-
setSize((int) (w / scale), (int) (h / scale));
861+
if (!isInit) return;
862+
863+
if (display.getEDTUtil().isCurrentThreadEDT()) {
864+
return;
865+
}
866+
867+
synchronized (getSyncMutex(drawable)) {
868+
pgl.resetFBOLayer();
869+
float scale = PApplet.platform == PConstants.MACOS ?
870+
getCurrentPixelScale() : getPixelScale();
871+
setSize((int) (w / scale), (int) (h / scale));
872+
}
817873
}
818874
}
819875

0 commit comments

Comments
 (0)