JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
TestFBOOffThreadSharedContextMix2DemosES2NEWT.java
Go to the documentation of this file.
1/**
2 * Copyright 2012 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;
30
31import java.io.BufferedReader;
32import java.io.IOException;
33import java.io.InputStreamReader;
34
35import com.jogamp.newt.event.WindowEvent;
36import com.jogamp.newt.event.WindowAdapter;
37import com.jogamp.newt.opengl.GLWindow;
38import com.jogamp.opengl.test.junit.util.MiscUtils;
39import com.jogamp.opengl.test.junit.util.NewtTestUtil;
40import com.jogamp.opengl.test.junit.util.UITestCase;
41import com.jogamp.opengl.test.junit.util.QuitAdapter;
42
43import com.jogamp.opengl.util.Animator;
44import com.jogamp.opengl.util.FPSAnimator;
45import com.jogamp.opengl.util.GLReadBufferUtil;
46import com.jogamp.opengl.util.texture.TextureIO;
47import com.jogamp.opengl.test.junit.jogl.demos.GLFinishOnDisplay;
48import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
49import com.jogamp.opengl.test.junit.jogl.demos.es2.Mix2TexturesES2;
50import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2;
51import com.jogamp.common.util.InterruptSource;
52import com.jogamp.nativewindow.NativeSurface;
53import com.jogamp.nativewindow.SurfaceUpdatedListener;
54import com.jogamp.opengl.GL;
55import com.jogamp.opengl.GLAutoDrawable;
56import com.jogamp.opengl.GLCapabilities;
57import com.jogamp.opengl.GLCapabilitiesImmutable;
58import com.jogamp.opengl.GLContext;
59import com.jogamp.opengl.GLDrawableFactory;
60import com.jogamp.opengl.GLEventListener;
61import com.jogamp.opengl.GLOffscreenAutoDrawable;
62import com.jogamp.opengl.GLProfile;
63
64import org.junit.Assert;
65import org.junit.AfterClass;
66import org.junit.Test;
67import org.junit.FixMethodOrder;
68import org.junit.runners.MethodSorters;
69
70/**
71 * Toolkit agnostic {@link GLOffscreenAutoDrawable.FBO} tests using the
72 * {@link GLDrawableFactory#createOffscreenAutoDrawable(com.jogamp.nativewindow.AbstractGraphicsDevice, GLCapabilitiesImmutable, com.jogamp.opengl.GLCapabilitiesChooser, int, int, GLContext) factory model}.
73 * <p>
74 * The created {@link GLOffscreenAutoDrawable.FBO} is being used to run the {@link GLEventListener}.
75 * </p>
76 * <p>
77 * This test simulates shared off-thread GL context / texture usage,
78 * where the producer use FBOs and delivers shared textures.
79 * The receiver blends the shared textures onscreen.
80 * In detail the test consist of:
81 * <ul>
82 * <li>2 {@link GLOffscreenAutoDrawable.FBO} double buffered
83 * <ul>
84 * <li>each with their own {@link GLContext}, which is shares the {@link GLWindow} one (see below)</li>
85 * <li>both run within one {@link FPSAnimator} @ 30fps</li>
86 * <li>produce a texture</li>
87 * <li>notify the onscreen renderer about new textureID (swapping double buffer)</li>
88 * </ul></li>
89 * <li>1 onscreen {@link GLWindow}
90 * <ul>
91 * <li>shares it's {@link GLContext} w/ above FBOs</li>
92 * <li>running within one {@link Animator} at v-sync</li>
93 * <li>uses the shared FBO textures and blends them onscreen</li>
94 * </ul></li>
95 * </ul>
96 * </p>
97 */
98@FixMethodOrder(MethodSorters.NAME_ASCENDING)
100 static long duration = 500; // ms
101 static int swapInterval = 1;
102 static boolean showFPS = false;
103 static boolean forceES2 = false;
104 static boolean mainRun = false;
105
106 @AfterClass
107 public static void releaseClass() {
108 }
109
110 protected void runTestGL(final GLCapabilitiesImmutable caps) throws InterruptedException {
111 final GLReadBufferUtil screenshot = new GLReadBufferUtil(false, false);
112 System.err.println("requested: vsync "+swapInterval+", "+caps);
113
114 final GLWindow glWindow = GLWindow.create(caps);
115 Assert.assertNotNull(glWindow);
116 glWindow.setTitle("Gears NEWT Test (translucent "+!caps.isBackgroundOpaque()+"), swapInterval "+swapInterval);
117 if(mainRun) {
118 glWindow.setSize(512, 512);
119 } else {
120 glWindow.setSize(256, 256);
121 }
122 // eager initialization of context
123 glWindow.setVisible(true);
124 glWindow.display();
125
126 final int fbod1_texUnit = 0;
127 final int fbod2_texUnit = 1;
128
129 final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
130 final GLCapabilities fbodCaps = (GLCapabilities) caps.cloneMutable();
131 // fbodCaps.setDoubleBuffered(false);
132
133 final Mix2TexturesES2 mixerDemo = new Mix2TexturesES2(1, fbod1_texUnit, fbod2_texUnit);
134
135 // FBOD1
136 final GLOffscreenAutoDrawable.FBO fbod1 = (GLOffscreenAutoDrawable.FBO)
137 factory.createOffscreenAutoDrawable(null, fbodCaps, null, glWindow.getSurfaceWidth(), glWindow.getSurfaceHeight());
138 fbod1.setSharedAutoDrawable(glWindow);
139 fbod1.setUpstreamWidget(glWindow); // connect the real GLWindow (mouse/key) to offscreen!
140 fbod1.setTextureUnit(fbod1_texUnit);
141 {
142 final GearsES2 demo0 = new GearsES2(-1);
143 fbod1.addGLEventListener(demo0);
144 fbod1.addGLEventListener(new GLFinishOnDisplay());
145 demo0.setIgnoreFocus(true);
146 }
147 fbod1.getNativeSurface().addSurfaceUpdatedListener(new SurfaceUpdatedListener() {
148 @Override
149 public void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) {
150 mixerDemo.setTexID0(fbod1.getColorbuffer(GL.GL_FRONT).getName());
151 } });
152 fbod1.display(); // init
153 System.err.println("FBOD1 "+fbod1);
154 Assert.assertTrue(fbod1.isInitialized());
155
156 // FBOD2
157 final GLOffscreenAutoDrawable.FBO fbod2 = (GLOffscreenAutoDrawable.FBO)
158 factory.createOffscreenAutoDrawable(null, fbodCaps, null, glWindow.getSurfaceWidth(), glWindow.getSurfaceHeight());
159 fbod2.setSharedAutoDrawable(glWindow);
160 fbod2.setTextureUnit(fbod2_texUnit);
161 fbod2.addGLEventListener(new RedSquareES2(-1));
162 fbod2.addGLEventListener(new GLFinishOnDisplay());
163 fbod2.getNativeSurface().addSurfaceUpdatedListener(new SurfaceUpdatedListener() {
164 @Override
165 public void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) {
166 mixerDemo.setTexID1(fbod2.getColorbuffer(GL.GL_FRONT).getName());
167 } });
168 fbod2.display(); // init
169 System.err.println("FBOD2 "+fbod2);
170 Assert.assertTrue(fbod2.isInitialized());
171
172 // preinit texIDs
173 mixerDemo.setTexID0(fbod1.getColorbuffer(GL.GL_FRONT).getName());
174 mixerDemo.setTexID1(fbod2.getColorbuffer(GL.GL_FRONT).getName());
175
176 glWindow.addGLEventListener(mixerDemo);
177 glWindow.addGLEventListener(new GLEventListener() {
178 int i=0, c=0;
179 @Override
180 public void init(final GLAutoDrawable drawable) {}
181 @Override
182 public void dispose(final GLAutoDrawable drawable) {}
183 @Override
184 public void display(final GLAutoDrawable drawable) {
185 if(mainRun) return;
186
187 final int dw = drawable.getSurfaceWidth();
188 final int dh = drawable.getSurfaceHeight();
189 c++;
190
191 if(dw<800) {
192 System.err.println("XXX: "+dw+"x"+dh+", c "+c);
193 if(8 == c) {
194 snapshot(i++, "msaa"+fbod1.getNumSamples(), drawable.getGL(), screenshot, TextureIO.PNG, null);
195 }
196 if(9 == c) {
197 c=0;
198 new InterruptSource.Thread() {
199 @Override
200 public void run() {
201 glWindow.setSize(dw+256, dh+256);
202 } }.start();
203 }
204 }
205 }
206 @Override
207 public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
208 fbod1.setSurfaceSize(width, height);
209 fbod2.setSurfaceSize(width, height);
210 }
211 });
212
213 final FPSAnimator animator0 = new FPSAnimator(30);
214 animator0.add(fbod1);
215 animator0.add(fbod2);
216
217 final Animator animator1 = new Animator(0 /* w/o AWT */);
218 animator1.add(glWindow);
219
220 final QuitAdapter quitAdapter = new QuitAdapter();
221
222 //glWindow.addKeyListener(new TraceKeyAdapter(quitAdapter));
223 //glWindow.addWindowListener(new TraceWindowAdapter(quitAdapter));
224 glWindow.addKeyListener(quitAdapter);
225 glWindow.addWindowListener(quitAdapter);
226
227 glWindow.addWindowListener(new WindowAdapter() {
228 @Override
229 public void windowResized(final WindowEvent e) {
230 System.err.println("window resized: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight());
231 }
232 @Override
233 public void windowMoved(final WindowEvent e) {
234 System.err.println("window moved: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight());
235 }
236 });
237
238 animator0.start();
239 animator1.start();
240 // glWindow.setSkipContextReleaseThread(animator.getThread());
241
242 glWindow.setVisible(true);
243
244 System.err.println("NW chosen: "+glWindow.getDelegatedWindow().getChosenCapabilities());
245 System.err.println("GL chosen: "+glWindow.getChosenCapabilities());
246 System.err.println("window pos/siz: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", "+glWindow.getInsets());
247
248 animator0.setUpdateFPSFrames(30, showFPS ? System.err : null);
249 animator1.setUpdateFPSFrames(60, showFPS ? System.err : null);
250
251 while(!quitAdapter.shouldQuit() && animator1.isAnimating() && animator1.getTotalFPSDuration()<duration) {
252 Thread.sleep(100);
253 }
254
255 animator0.stop();
256 Assert.assertFalse(animator0.isAnimating());
257 Assert.assertFalse(animator0.isStarted());
258
259 animator1.stop();
260 Assert.assertFalse(animator1.isAnimating());
261 Assert.assertFalse(animator1.isStarted());
262
263 fbod1.destroy();
264 fbod2.destroy();
265
266 glWindow.destroy();
267 Assert.assertEquals(true, NewtTestUtil.waitForRealized(glWindow, false, null));
268 }
269
270 @Test
271 public void test01() throws InterruptedException {
273 caps.setAlphaBits(1);
274 runTestGL(caps);
275 }
276
277 public static void main(final String args[]) throws IOException {
278 boolean waitForKey = false;
279
280 mainRun = true;
281
282 for(int i=0; i<args.length; i++) {
283 if(args[i].equals("-time")) {
284 i++;
285 duration = MiscUtils.atol(args[i], duration);
286 } else if(args[i].equals("-vsync")) {
287 i++;
288 swapInterval = MiscUtils.atoi(args[i], swapInterval);
289 } else if(args[i].equals("-es2")) {
290 forceES2 = true;
291 } else if(args[i].equals("-showFPS")) {
292 showFPS = true;
293 } else if(args[i].equals("-wait")) {
294 waitForKey = true;
295 } else if(args[i].equals("-nomain")) {
296 mainRun = false;
297 }
298 }
299
300 System.err.println("swapInterval "+swapInterval);
301 System.err.println("forceES2 "+forceES2);
302
303 if(waitForKey) {
304 final BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
305 System.err.println("Press enter to continue");
306 try {
307 System.err.println(stdin.readLine());
308 } catch (final IOException e) { }
309 }
310 org.junit.runner.JUnitCore.main(TestFBOOffThreadSharedContextMix2DemosES2NEWT.class.getName());
311 }
312}
void setAlphaBits(final int alphaBits)
Sets the number of bits requested for the color buffer's alpha component.
NEWT Window events are provided for notification purposes ONLY.
An implementation of GLAutoDrawable and Window interface, using a delegated Window instance,...
Definition: GLWindow.java:121
final int getSurfaceHeight()
Returns the height of this GLDrawable's surface client area in pixel units.
Definition: GLWindow.java:466
final void setTitle(final String title)
Definition: GLWindow.java:297
final int getX()
Returns the current x position of this window, relative to it's parent.
Definition: GLWindow.java:436
final void addKeyListener(final KeyListener l)
Appends the given com.jogamp.newt.event.KeyListener to the end of the list.
Definition: GLWindow.java:902
final int getY()
Returns the current y position of the top-left corner of the client area relative to it's parent in w...
Definition: GLWindow.java:441
final int getSurfaceWidth()
Returns the width of this GLDrawable's surface client area in pixel units.
Definition: GLWindow.java:461
final void setSize(final int width, final int height)
Sets the size of the window's client area in window units, excluding decorations.
Definition: GLWindow.java:625
final void setVisible(final boolean visible)
Calls setVisible(true, visible), i.e.
Definition: GLWindow.java:615
final void addWindowListener(final WindowListener l)
Appends the given com.jogamp.newt.event.WindowListener to the end of the list.
Definition: GLWindow.java:882
final CapabilitiesImmutable getChosenCapabilities()
Gets an immutable set of chosen capabilities.
Definition: GLWindow.java:266
final InsetsImmutable getInsets()
Returns the insets defined as the width and height of the window decoration on the left,...
Definition: GLWindow.java:431
final void destroy()
Destroys all resources associated with this GLAutoDrawable, inclusive the GLContext.
Definition: GLWindow.java:605
final Window getDelegatedWindow()
If the implementation uses delegation, return the delegated Window instance, otherwise return this in...
Definition: GLWindow.java:277
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.
abstract GLOffscreenAutoDrawable createOffscreenAutoDrawable(AbstractGraphicsDevice device, GLCapabilitiesImmutable caps, GLCapabilitiesChooser chooser, int width, int height)
Creates a realized GLOffscreenAutoDrawable incl it's offscreen NativeSurface with the given capabilit...
static GLDrawableFactory getFactory(final GLProfile glProfile)
Returns the sole GLDrawableFactory instance.
Specifies the the OpenGL profile.
Definition: GLProfile.java:77
static final String GLES2
The embedded OpenGL profile ES 2.x, with x >= 0.
Definition: GLProfile.java:585
static GLProfile get(final AbstractGraphicsDevice device, String profile)
Returns a GLProfile object.
static GLProfile getGL2ES2(final AbstractGraphicsDevice device)
Returns the GL2ES2 profile implementation, hence compatible w/ GL2ES2.
Definition: GLProfile.java:913
static int atoi(final String str, final int def)
Definition: MiscUtils.java:57
static long atol(final String str, final long def)
Definition: MiscUtils.java:66
static boolean waitForRealized(final Screen screen, final boolean realized, final Runnable waitAction)
final synchronized void add(final GLAutoDrawable drawable)
Adds a drawable to this animator's list of rendering drawables.
final void setUpdateFPSFrames(final int frames, final PrintStream out)
synchronized boolean isStarted()
Indicates whether this animator has been started.
final synchronized boolean start()
Starts this animator, if not running.
Definition: Animator.java:344
final synchronized boolean stop()
Stops this animator.
Definition: Animator.java:368
An Animator subclass which attempts to achieve a target frames-per-second rate to avoid using all CPU...
final synchronized boolean start()
Starts this animator, if not running.
final synchronized boolean stop()
Stops this FPSAnimator.
Utility to read out the current FB to TextureData, optionally writing the data back to a texture obje...
static final String PNG
Constant which can be used as a file suffix to indicate a PNG file, value {@value}.
Definition: TextureIO.java:171
Provides low-level information required for hardware-accelerated rendering using a surface in a platf...
Clients may add their SurfaceUpdateListener implementation to a com.jogamp.nativewindow....
CapabilitiesImmutable getChosenCapabilities()
Gets an immutable set of chosen capabilities.
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
GL getGL()
Returns the GL pipeline object this GLAutoDrawable uses.
void addGLEventListener(GLEventListener listener)
Adds the given listener to the end of this drawable queue.
Specifies an immutable set of OpenGL capabilities.
int getSurfaceWidth()
Returns the width of this GLDrawable's surface client area in pixel units.
int getSurfaceHeight()
Returns the height of this GLDrawable's surface client area in pixel units.
Declares events which client code can use to manage OpenGL rendering into a GLAutoDrawable.
FBObject based GLOffscreenAutoDrawable specialization
Platform-independent GLAutoDrawable specialization, exposing offscreen functionality.
void setSharedAutoDrawable(GLAutoDrawable sharedAutoDrawable)
Specifies an GLAutoDrawable, which OpenGL context shall be shared by this GLAutoDrawable's GLContext.
static final int GL_FRONT
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_FRONT" with expressio...
Definition: GL.java:597