JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
GLContextDrawableSwitchBase1.java
Go to the documentation of this file.
1/**
2 * Copyright 2013 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.opengl.test.junit.jogl.acore.glels;
30
31import java.awt.Dimension;
32import java.awt.Frame;
33
34import com.jogamp.opengl.GLAnimatorControl;
35import com.jogamp.opengl.GLAutoDrawable;
36import com.jogamp.opengl.GLCapabilities;
37import com.jogamp.opengl.GLContext;
38import com.jogamp.opengl.GLDrawableFactory;
39import com.jogamp.opengl.GLOffscreenAutoDrawable;
40import com.jogamp.opengl.GLProfile;
41import com.jogamp.opengl.awt.GLCanvas;
42
43import jogamp.nativewindow.jawt.JAWTUtil;
44
45import com.jogamp.newt.Screen;
46import com.jogamp.newt.opengl.GLWindow;
47
48import com.jogamp.opengl.GLEventListenerState;
49import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
50import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
51import com.jogamp.opengl.test.junit.util.GLEventListenerCounter;
52import com.jogamp.opengl.test.junit.util.GLTestUtil;
53import com.jogamp.opengl.test.junit.util.TestUtil;
54import com.jogamp.opengl.test.junit.util.UITestCase;
55
56import org.junit.Assert;
57import org.junit.Assume;
58import org.junit.BeforeClass;
59
60/**
61 * Test re-association of GLContext/GLDrawables,
62 * here GLContext's survival of GLDrawable destruction
63 * and reuse w/ new or recreated GLDrawable.
64 * <p>
65 * Test utilizes {@link GLEventListenerState} for preserving the
66 * GLAutoDrawable state, i.e. GLContext, all GLEventListener
67 * and the GLAnimatorControl association.
68 * </p>
69 * <p>
70 * See Bug 665 - https://jogamp.org/bugzilla/show_bug.cgi?id=665.
71 * </p>
72 */
73public abstract class GLContextDrawableSwitchBase1 extends UITestCase {
74 static protected enum GLADType { GLCanvasOnscreen, GLCanvasOffscreen, GLWindow, GLOffscreen };
75
76 // default period for 1 GLAD cycle
77 static long duration = 1000; // ms
78
79 static int width, height;
80
81 static GLCapabilities getCaps(final String profile) {
82 if( !GLProfile.isAvailable(profile) ) {
83 System.err.println("Profile "+profile+" n/a");
84 return null;
85 }
86 return new GLCapabilities(GLProfile.get(profile));
87 }
88
89 @BeforeClass
90 public static void initClass() {
91 width = 256;
92 height = 256;
93 }
94
95 static void setGLCanvasSize(final GLCanvas glc, final Dimension new_sz) {
96 try {
97 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
98 public void run() {
99 glc.setMinimumSize(new_sz);
100 glc.setPreferredSize(new_sz);
101 glc.setSize(new_sz);
102 } } );
103 } catch( final Throwable throwable ) {
104 throwable.printStackTrace();
105 Assume.assumeNoException( throwable );
106 }
107 }
108
109 static void setFrameVisible(final Frame frame) throws InterruptedException {
110 try {
111 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
112 public void run() {
113 frame.pack();
114 frame.setVisible(true);
115 }});
116 } catch( final Throwable throwable ) {
117 throwable.printStackTrace();
118 Assume.assumeNoException( throwable );
119 }
120 }
121
122 static void destroyFrame(final Frame frame) throws InterruptedException {
123 try {
124 javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
125 public void run() {
126 frame.dispose();
127 }});
128 } catch( final Throwable throwable ) {
129 throwable.printStackTrace();
130 Assume.assumeNoException( throwable );
131 }
132 }
133
134 private GLOffscreenAutoDrawable createGLOffscreenAutoDrawable(final GLCapabilities caps, final int width, final int height) throws InterruptedException {
135 final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
136 return factory.createOffscreenAutoDrawable(null, caps, null, width, height);
137 }
138
139 protected static boolean validateOnOffscreenLayer(final GLADType gladType1, final GLADType gladType2) {
140 final boolean useOffscreenLayer = GLADType.GLCanvasOffscreen == gladType1 || GLADType.GLCanvasOffscreen == gladType2 ;
141 final boolean useOnscreenLayer = GLADType.GLCanvasOnscreen == gladType1 || GLADType.GLCanvasOnscreen == gladType2 ;
142 if( useOffscreenLayer ) {
143 if( !JAWTUtil.isOffscreenLayerSupported() ) {
144 System.err.println("Platform doesn't support offscreen rendering.");
145 return false;
146 }
147 } else if( useOnscreenLayer ) {
148 if( JAWTUtil.isOffscreenLayerRequired() ) {
149 System.err.println("Platform requires offscreen rendering.");
150 return false;
151 }
152 }
153 return true;
154 }
155
156 protected void testGLADOneLifecycle(final Screen screen, final GLCapabilities caps, final GLADType gladType, final int width,
157 final int height, final GLEventListenerCounter glelTracker,
158 final SnapshotGLEventListener snapshotGLEventListener, final GLEventListenerState glelsIn, final GLEventListenerState glelsOut[], final GLAnimatorControl animator)
159 throws InterruptedException {
160
161 System.err.println("GLAD Lifecycle.0 "+gladType+", restoring "+((null!=glelsIn)?true:false)+", preserving "+((null!=glelsOut)?true:false));
162 final Frame frame;
163 final GLAutoDrawable glad;
164 if( GLADType.GLCanvasOnscreen == gladType ) {
165 if( jogamp.nativewindow.jawt.JAWTUtil.isOffscreenLayerRequired() ) {
166 throw new InternalError("Platform requires offscreen rendering, but onscreen requested: "+gladType);
167 }
168 frame = new Frame("AWT GLCanvas");
169
170 glad = new GLCanvas(caps);
171 setGLCanvasSize((GLCanvas)glad, new Dimension(width, height));
172 frame.add((GLCanvas)glad);
173 } else if( GLADType.GLCanvasOffscreen == gladType ) {
174 if( !jogamp.nativewindow.jawt.JAWTUtil.isOffscreenLayerSupported() ) {
175 throw new InternalError("Platform doesn't support offscreen rendering: "+gladType);
176 }
177 frame = new Frame("AWT GLCanvas");
178
179 glad = new GLCanvas(caps);
180 ((GLCanvas)glad).setShallUseOffscreenLayer(true);
181 setGLCanvasSize((GLCanvas)glad, new Dimension(width, height));
182 frame.add((GLCanvas)glad);
183 } else if( GLADType.GLWindow == gladType ) {
184 frame = null;
185
186 if( null != screen ) {
187 glad = GLWindow.create(screen, caps);
188 } else {
189 glad = GLWindow.create(caps);
190 }
191 ((GLWindow)glad).setTitle("Newt GLWindow");
192 ((GLWindow)glad).setSize(width, height);
193 } else if( GLADType.GLOffscreen == gladType ) {
194 frame = null;
195
196 glad = this.createGLOffscreenAutoDrawable(caps, width, height);
197 } else {
198 throw new InternalError("Unsupported: "+gladType);
199 }
200
201 if( null == glelsIn ) {
202 if( null != animator ) {
203 animator.add(glad);
204 }
205 glad.addGLEventListener(glelTracker);
206 glad.addGLEventListener(new GearsES2(1));
207 glad.addGLEventListener(snapshotGLEventListener);
208 }
209 snapshotGLEventListener.setMakeSnapshot();
210
211 if( GLADType.GLCanvasOnscreen == gladType || GLADType.GLCanvasOffscreen == gladType ) {
212 setFrameVisible(frame);
213 Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, true, null));
214 } else if( GLADType.GLWindow == gladType ) {
215 ((GLWindow)glad).setVisible(true);
216 }
217 Assert.assertEquals(true, GLTestUtil.waitForRealized(glad, true, null));
218 Assert.assertNotNull(glad.getContext());
219 Assert.assertTrue(glad.isRealized());
220
221 if( null != glelsIn ) {
222 Assert.assertEquals(0, glad.getGLEventListenerCount());
223 System.err.println(".. restoring.0");
224 glelsIn.moveTo(glad);
225 System.err.println(".. restoring.X");
226
227 Assert.assertEquals(1, glelTracker.initCount);
228 Assert.assertTrue(1 <= glelTracker.reshapeCount);
229 Assert.assertTrue(1 <= glelTracker.displayCount);
230 Assert.assertEquals(0, glelTracker.disposeCount);
231 Assert.assertEquals(3, glad.getGLEventListenerCount());
232
233 Assert.assertEquals(glelsIn.context, glad.getContext());
234 Assert.assertEquals(glelsIn.listenerCount(), glad.getGLEventListenerCount());
235 Assert.assertEquals(glelsIn.context.getGLReadDrawable(), glad.getDelegatedDrawable());
236 Assert.assertEquals(glelsIn.context.getGLDrawable(), glad.getDelegatedDrawable());
237 Assert.assertEquals(false, glelsIn.isOwner());
238 }
239
240 for (int wait=0; wait<TestUtil.POLL_DIVIDER &&
241 ( 1 > glelTracker.initCount || 1 > glelTracker.reshapeCount || 1 > glelTracker.displayCount );
242 wait++) {
243 Thread.sleep(TestUtil.TIME_SLICE);
244 }
245
246 final long t0 = System.currentTimeMillis();
247 long t1 = t0;
248
249 while( ( t1 - t0 ) < duration ) {
250 Thread.sleep(100);
251 t1 = System.currentTimeMillis();
252 }
253
254 Assert.assertEquals(1, glelTracker.initCount);
255 Assert.assertTrue(1 <= glelTracker.reshapeCount);
256 Assert.assertTrue(1 <= glelTracker.displayCount);
257 Assert.assertEquals(0, glelTracker.disposeCount);
258
259 if( null != glelsOut ) {
260 final GLContext context1 = glad.getContext();
261 System.err.println(".. preserving.0");
262 glelsOut[0] = GLEventListenerState.moveFrom(glad);
263 System.err.println(".. preserving.X");
264
265 Assert.assertEquals(context1, glelsOut[0].context);
266 Assert.assertNull(context1.getGLReadDrawable());
267 Assert.assertNull(context1.getGLDrawable());
268 Assert.assertEquals(3, glelsOut[0].listenerCount());
269 Assert.assertEquals(true, glelsOut[0].isOwner());
270 Assert.assertEquals(null, glad.getContext());
271 Assert.assertEquals(0, glad.getGLEventListenerCount());
272 }
273 if( GLADType.GLCanvasOnscreen == gladType || GLADType.GLCanvasOffscreen == gladType ) {
274 destroyFrame(frame);
275 Assert.assertEquals(true, AWTRobotUtil.waitForVisible(frame, false, null));
276 } else if( GLADType.GLWindow == gladType ) {
277 glad.destroy();
278 } else if( GLADType.GLOffscreen == gladType ) {
279 glad.destroy();
280 }
281 Assert.assertEquals(true, GLTestUtil.waitForRealized(glad, false, null));
282
283 Assert.assertEquals(1, glelTracker.initCount);
284 Assert.assertTrue(1 <= glelTracker.reshapeCount);
285 Assert.assertTrue(1 <= glelTracker.displayCount);
286 if( null != glelsOut ) {
287 Assert.assertEquals(0, glelTracker.disposeCount);
288 } else {
289 Assert.assertEquals(1, glelTracker.disposeCount);
290 }
291 System.err.println("GLAD Lifecycle.X "+gladType);
292 }
293}
A screen may span multiple MonitorDevices representing their combined virtual size.
Definition: Screen.java:58
An implementation of GLAutoDrawable and Window interface, using a delegated Window instance,...
Definition: GLWindow.java:121
final void setTitle(final String title)
Definition: GLWindow.java:297
static GLWindow create(final GLCapabilitiesImmutable caps)
Creates a new GLWindow attaching a new Window referencing a new default Screen and default Display wi...
Definition: GLWindow.java:169
Specifies a set of OpenGL capabilities.
Abstraction for an OpenGL rendering context.
Definition: GLContext.java:74
abstract GLDrawable getGLDrawable()
Returns the write-drawable this context uses for framebuffer operations.
abstract GLDrawable getGLReadDrawable()
Returns the read-Drawable this context uses for read framebuffer operations.
GLEventListenerState is holding GLAutoDrawable components crucial to relocating all its GLEventListen...
static GLEventListenerState moveFrom(final GLAutoDrawable src)
Moves all GLEventListenerState components from the given GLAutoDrawable to a newly created instance.
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
static boolean isAvailable(final AbstractGraphicsDevice device, final String profile)
Returns the availability of a profile on a device.
Definition: GLProfile.java:305
static GLProfile get(final AbstractGraphicsDevice device, String profile)
Returns a GLProfile object.
A heavyweight AWT component which provides OpenGL rendering support.
Definition: GLCanvas.java:170
Test re-association of GLContext/GLDrawables, here GLContext's survival of GLDrawable destruction and...
static boolean validateOnOffscreenLayer(final GLADType gladType1, final GLADType gladType2)
void testGLADOneLifecycle(final Screen screen, final GLCapabilities caps, final GLADType gladType, final int width, final int height, final GLEventListenerCounter glelTracker, final SnapshotGLEventListener snapshotGLEventListener, final GLEventListenerState glelsIn, final GLEventListenerState glelsOut[], final GLAnimatorControl animator)
static boolean waitForVisible(final java.awt.Component comp, final boolean visible, final Runnable waitAction)
static boolean waitForRealized(final GLAutoDrawable glad, final boolean realized, final Runnable waitAction)
Definition: GLTestUtil.java:91
An animator control interface, which implementation may drive a com.jogamp.opengl....
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
void addGLEventListener(GLEventListener listener)
Adds the given listener to the end of this drawable queue.
int getGLEventListenerCount()
Returns the number of GLEventListener of this drawable queue.
void destroy()
Destroys all resources associated with this GLAutoDrawable, inclusive the GLContext.
GLContext getContext()
Returns the context associated with this drawable.
GLDrawable getDelegatedDrawable()
If the implementation uses delegation, return the delegated GLDrawable instance, otherwise return thi...
boolean isRealized()
Returns true if this drawable is realized, otherwise false.
void setSize(int width, int height)
Requests a new width and height for this AWTGLAutoDrawable.