JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
TestBug692GL3VAONEWT.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 */
28package com.jogamp.opengl.test.junit.jogl.acore;
29
30import java.io.IOException;
31import java.nio.FloatBuffer;
32import java.nio.ShortBuffer;
33import java.util.logging.Level;
34import java.util.logging.Logger;
35
36import com.jogamp.opengl.GL;
37import com.jogamp.opengl.GL2ES2;
38import com.jogamp.opengl.GL3;
39import com.jogamp.opengl.GL3bc;
40import com.jogamp.opengl.GLAutoDrawable;
41import com.jogamp.opengl.GLCapabilities;
42import com.jogamp.opengl.GLEventListener;
43import com.jogamp.opengl.GLException;
44import com.jogamp.opengl.GLProfile;
45
46import org.junit.Assert;
47import org.junit.Test;
48import org.junit.FixMethodOrder;
49import org.junit.runners.MethodSorters;
50
51import com.jogamp.common.nio.Buffers;
52import com.jogamp.newt.opengl.GLWindow;
53import com.jogamp.opengl.test.junit.util.MiscUtils;
54import com.jogamp.opengl.test.junit.util.QuitAdapter;
55import com.jogamp.opengl.test.junit.util.UITestCase;
56import com.jogamp.opengl.util.Animator;
57import com.jogamp.opengl.util.GLBuffers;
58
59/**
60 * Test Vertex Array Object (VAO) Usage and BufferStateTracker
61 * <p>
62 * All combinations of CPU_SRC, VBO_ONLY and VBO_VAO are tested
63 * and validate the fix for Bug 692, i.e. <https://jogamp.org/bugzilla/show_bug.cgi?id=692>.
64 * </p>
65 * <p>
66 * Test order is important!
67 * </p>
68 * <p>
69 * Note that VAO initialization does unbind the VBO .. since otherwise they are still bound
70 * and the CPU_SRC test will fail!<br/>
71 * The OpenGL spec does not mention that unbinding a VAO will also unbind the bound VBOs
72 * during their setup.<br/>
73 * Local tests here on NV and AMD proprietary driver resulted in <i>no ourput image</i>
74 * when not unbinding said VBOs before the CPU_SRC tests.<br/>
75 * Hence Bug 692 Comment 5 is invalid, i.e. <https://jogamp.org/bugzilla/show_bug.cgi?id=692#c5>,
76 * and we should throw an exception to give users a hint!
77 * </p>
78 */
79@FixMethodOrder(MethodSorters.NAME_ASCENDING)
80public class TestBug692GL3VAONEWT extends UITestCase {
81 static long duration = 500; // ms
82
83 static class GL3VAODemo implements GLEventListener {
84 /** Different modes of displaying the geometry */
85 public enum Mode {
86 CPU_SRC {
87 @Override
88 void display(final GL3VAODemo t, final GL3bc gl) {
89 t.displayCPUSourcing(gl);
90 }
91 },
92
93 /** Traditional one without using VAO */
94 VBO_ONLY {
95 @Override
96 void display(final GL3VAODemo t, final GL3bc gl) {
97 t.displayVBOOnly(gl);
98 }
99 },
100
101 /** Using VAOs throws [incorrectly as of JOGL 2.0rc11] a GLException */
102 VBO_VAO {
103 @Override
104 void display(final GL3VAODemo t, final GL3bc gl) {
105 t.displayVBOVAO(gl);
106 }
107 };
108
109 abstract void display(GL3VAODemo t, GL3bc gl);
110 }
111
112 private final Mode[] allModes;
113 private Mode currentMode;
114 private int currentModeIdx;
115
116 public GL3VAODemo(final Mode[] modes) {
117 allModes = modes;
118 currentMode = allModes[0];
119 currentModeIdx = 0;
120 }
121
122 private final static float[] vertexColorData = new float[]{
123 0.0f, 0.75f, 0.0f, 1,0,0,
124 -0.5f, -0.75f, 0.0f, 0,1,0,
125 0.9f, -0.75f, 0.0f, 0,0,1
126 };
127 private final FloatBuffer vertexColorDataBuffer = GLBuffers.newDirectFloatBuffer(vertexColorData);
128
129 private final short[] indices = new short[]{0, 1, 2};
130 private final ShortBuffer indicesBuffer = GLBuffers.newDirectShortBuffer(indices);
131
132
133 private int ibo = -1;
134 private int vbo = -1;
135 private int vertID = -1;
136 private int fragID = -1;
137 private int progID = -1;
138
139 private int vao = -1;
140
141 private static int createShader(final GL3 gl, final int type,
142 final String[] srcLines){
143 final int shaderID = gl.glCreateShader(type);
144 assert shaderID > 0;
145 final int[] lengths = new int[srcLines.length];
146 for (int i = 0; i < srcLines.length; i++) {
147 lengths[i] = srcLines[i].length();
148 }
149 gl.glShaderSource(shaderID, srcLines.length, srcLines, lengths, 0);
150 gl.glCompileShader(shaderID);
151 return shaderID;
152 }
153
154 private void initBuffers(final GL3 gl) {
155 // IDs for 2 buffers
156 final int[] buffArray = new int[2];
157 gl.glGenBuffers(buffArray.length, buffArray, 0);
158 vbo = buffArray[0];
159 assert vbo > 0;
160
161 // Bind buffer and upload data
163 gl.glBufferData(GL.GL_ARRAY_BUFFER, vertexColorData.length * Buffers.SIZEOF_FLOAT,
164 vertexColorDataBuffer, GL.GL_STATIC_DRAW);
166
167 // Buffer with the 3 indices required for one triangle
168 ibo = buffArray[1];
169 assert ibo > 0;
171 gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER,indices.length*Buffers.SIZEOF_SHORT,
172 indicesBuffer, GL.GL_STATIC_DRAW);
174 }
175 private void initShaders(final GL3 gl) {
176 final String[] vertSrc = new String[]{
177 "#version 150\n",
178 "in vec4 vPosition;\n",
179 "in vec4 vColor;\n",
180 "out vec4 pColor;\n",
181 "void main() {\n",
182 " pColor = vColor;\n",
183 " gl_Position = vPosition;\n",
184 "}\n"
185 };
186 vertID = createShader(gl, GL2ES2.GL_VERTEX_SHADER, vertSrc);
187
188 final String[] fragSrc = new String[]{
189 "#version 150\n",
190 "in vec4 pColor;\n",
191 "void main() {\n",
192 " gl_FragColor = pColor;\n",
193 "}\n"
194 };
195 fragID = createShader(gl, GL2ES2.GL_FRAGMENT_SHADER, fragSrc);
196
197 // We're done with the compiler
199
200 progID = gl.glCreateProgram();
201 assert progID > 0;
202 gl.glAttachShader(progID, vertID);
203 gl.glAttachShader(progID, fragID);
204 gl.glLinkProgram(progID);
205 gl.glValidateProgram(progID);
206 }
207
208 private int initVAO(final GL3 gl) {
209 final int[] buff = new int[1];
210 gl.glGenVertexArrays(1, buff, 0);
211 final int vao = buff[0];
212 Assert.assertTrue("Invalid VAO: "+vao, vao > 0);
213
214
215 gl.glUseProgram(progID);
216 final int posLoc = gl.glGetAttribLocation(progID, "vPosition");
217 final int colorLoc = gl.glGetAttribLocation(progID, "vColor");
218 gl.glUseProgram(0);
219
220 gl.glBindVertexArray(vao);
221 gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo);
222 gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, ibo);
223
224 gl.glEnableVertexAttribArray(posLoc);
225 gl.glEnableVertexAttribArray(colorLoc);
226
227 final int stride = 6 * Buffers.SIZEOF_FLOAT;
228 final int cOff = 3 * Buffers.SIZEOF_FLOAT;
229 gl.glVertexAttribPointer(posLoc, 3, GL.GL_FLOAT, false, stride, 0L);
230 gl.glVertexAttribPointer(colorLoc,3, GL.GL_FLOAT, false, stride, cOff);
231
232 gl.glBindVertexArray(0);
233 // See class documentation above!
234 gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
235 gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
236 return vao;
237 }
238
239 @Override
240 public void init(final GLAutoDrawable drawable) {
241 final GL3 gl = drawable.getGL().getGL3();
242 gl.glEnable(GL.GL_DEPTH_TEST);
243 gl.glDisable(GL.GL_CULL_FACE);
244 initBuffers(gl);
245 initShaders(gl);
246
247 vao = initVAO(gl);
248
249 gl.setSwapInterval(1);
250 }
251
252 @Override
253 public void dispose(final GLAutoDrawable drawable) {
254 final GL3 gl = drawable.getGL().getGL3();
255 gl.glDeleteBuffers(2, new int[]{vbo, ibo}, 0);
256 gl.glDetachShader(progID, fragID);
257 gl.glDetachShader(progID, vertID);
258 gl.glDeleteProgram(progID);
259 gl.glDeleteShader(fragID);
260 gl.glDeleteShader(vertID);
261 }
262
263 private void displayCPUSourcing(final GL3bc gl) {
264 final int posLoc = gl.glGetAttribLocation(progID, "vPosition");
265 final int colorLoc = gl.glGetAttribLocation(progID, "vColor");
266 gl.glEnableVertexAttribArray(posLoc);
267 gl.glEnableVertexAttribArray(colorLoc);
268
269 final int stride = 6 * Buffers.SIZEOF_FLOAT;
270 // final int cOff = 3 * Buffers.SIZEOF_FLOAT;
271 gl.glVertexAttribPointer(posLoc, 3, GL.GL_FLOAT, false, stride, vertexColorDataBuffer);
272 vertexColorDataBuffer.position(3); // move to cOff
273 gl.glVertexAttribPointer(colorLoc,3, GL.GL_FLOAT, false, stride, vertexColorDataBuffer);
274 vertexColorDataBuffer.position(0); // rewind cOff
275
276 gl.glDrawElements(GL.GL_TRIANGLES, 3, GL.GL_UNSIGNED_SHORT, indicesBuffer);
277
278 gl.glDisableVertexAttribArray(posLoc);
279 gl.glDisableVertexAttribArray(colorLoc);
280 }
281
282 private void displayVBOOnly(final GL3 gl) {
283 final int posLoc = gl.glGetAttribLocation(progID, "vPosition");
284 final int colorLoc = gl.glGetAttribLocation(progID, "vColor");
285 gl.glEnableVertexAttribArray(posLoc);
286 gl.glEnableVertexAttribArray(colorLoc);
287
288 gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo);
289 final int stride = 6 * Buffers.SIZEOF_FLOAT;
290 final int cOff = 3 * Buffers.SIZEOF_FLOAT;
291 gl.glVertexAttribPointer(posLoc, 3, GL.GL_FLOAT, false, stride, 0L);
292 gl.glVertexAttribPointer(colorLoc,3, GL.GL_FLOAT, false, stride, cOff);
293 gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, ibo);
294 gl.glDrawElements(GL.GL_TRIANGLES, 3, GL.GL_UNSIGNED_SHORT, 0L);
295
296 gl.glDisableVertexAttribArray(posLoc);
297 gl.glDisableVertexAttribArray(colorLoc);
298 gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
299 gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
300 }
301
302 private void displayVBOVAO(final GL3 gl) {
303 try {
304 gl.glBindVertexArray(vao);
305 gl.glDrawElements(GL.GL_TRIANGLES, 3, GL.GL_UNSIGNED_SHORT, 0L);
306 gl.glBindVertexArray(0);
307 } catch (final GLException ex) {
308 Logger.getLogger(TestBug692GL3VAONEWT.class.getName()).log(Level.SEVERE,null,ex);
309 }
310 }
311
312 @Override
313 public void display(final GLAutoDrawable drawable) {
314 final GL3bc gl = drawable.getGL().getGL3bc();
315 final float color = ((float) currentMode.ordinal() + 1) / (Mode.values().length + 2);
316 gl.glClearColor(color, color, color, 0);
317 gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
318 gl.glUseProgram(progID);
319 final Mode newMode;
320 {
321 currentModeIdx = ( currentModeIdx + 1 ) % allModes.length;
322 newMode = allModes[ currentModeIdx ];
323 }
324 if (newMode != currentMode) {
325 currentMode = newMode;
326 System.out.println("Display mode: " + currentMode);
327 }
328 currentMode.display(this, gl);
329 gl.glUseProgram(0);
330 }
331
332 @Override
333 public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int w, final int h) {
334 }
335 }
336
337 private void testImpl(final GLProfile profile, final GL3VAODemo.Mode[] modes) throws InterruptedException {
338 final GLCapabilities capabilities = new GLCapabilities(profile);
339 final GLWindow glWindow = GLWindow.create(capabilities);
340 glWindow.setSize(512, 512);
341
342 final Animator anim = new Animator(glWindow);
343
344 final QuitAdapter quitAdapter = new QuitAdapter();
345 glWindow.addKeyListener(quitAdapter);
346 glWindow.addWindowListener(quitAdapter);
347
348 final GL3VAODemo vaoTest = new GL3VAODemo(modes);
349 glWindow.addGLEventListener(vaoTest);
350 glWindow.setVisible(true);
351 anim.start();
352
353 final long t0 = System.currentTimeMillis();
354 long t1 = t0;
355 while(!quitAdapter.shouldQuit() && t1-t0<duration) {
356 Thread.sleep(100);
357 t1 = System.currentTimeMillis();
358 }
359
360 anim.stop();
361 glWindow.destroy();
362 }
363
364 @Test
365 public void test01CPUSource() throws GLException, InterruptedException {
367 System.err.println("GL3bc n/a");
368 return;
369 }
370 final GL3VAODemo.Mode[] modes = new GL3VAODemo.Mode[] { GL3VAODemo.Mode.CPU_SRC };
371 testImpl(GLProfile.get(GLProfile.GL3bc), modes);
372 }
373
374 @Test
375 public void test02VBOOnly() throws GLException, InterruptedException {
377 System.err.println("GL3bc n/a");
378 return;
379 }
380 final GL3VAODemo.Mode[] modes = new GL3VAODemo.Mode[] { GL3VAODemo.Mode.VBO_ONLY };
381 testImpl(GLProfile.get(GLProfile.GL3bc), modes);
382 }
383
384 @Test
385 public void test03VBOVAO() throws GLException, InterruptedException {
387 System.err.println("GL3bc n/a");
388 return;
389 }
390 final GL3VAODemo.Mode[] modes = new GL3VAODemo.Mode[] { GL3VAODemo.Mode.VBO_VAO };
391 testImpl(GLProfile.get(GLProfile.GL3bc), modes);
392 }
393
394 @Test
395 public void test12CPUSourceAndVBOOnly() throws GLException, InterruptedException {
397 System.err.println("GL3bc n/a");
398 return;
399 }
400 final GL3VAODemo.Mode[] modes = new GL3VAODemo.Mode[] { GL3VAODemo.Mode.CPU_SRC, GL3VAODemo.Mode.VBO_ONLY };
401 testImpl(GLProfile.get(GLProfile.GL3bc), modes);
402 }
403
404 @Test
405 public void test13CPUSourceAndVBOVAO() throws GLException, InterruptedException {
407 System.err.println("GL3bc n/a");
408 return;
409 }
410 final GL3VAODemo.Mode[] modes = new GL3VAODemo.Mode[] { GL3VAODemo.Mode.CPU_SRC, GL3VAODemo.Mode.VBO_VAO };
411 testImpl(GLProfile.get(GLProfile.GL3bc), modes);
412 }
413
414 @Test
415 public void test23VBOOnlyAndVBOVAO() throws GLException, InterruptedException {
417 System.err.println("GL3bc n/a");
418 return;
419 }
420 final GL3VAODemo.Mode[] modes = new GL3VAODemo.Mode[] { GL3VAODemo.Mode.VBO_ONLY, GL3VAODemo.Mode.VBO_VAO };
421 testImpl(GLProfile.get(GLProfile.GL3bc), modes);
422 }
423
424 @Test
425 public void test88AllModes() throws GLException, InterruptedException {
427 System.err.println("GL3bc n/a");
428 return;
429 }
430 final GL3VAODemo.Mode[] modes = new GL3VAODemo.Mode[] { GL3VAODemo.Mode.CPU_SRC, GL3VAODemo.Mode.VBO_ONLY, GL3VAODemo.Mode.VBO_VAO };
431 testImpl(GLProfile.get(GLProfile.GL3bc), modes);
432 }
433
434 public static void main(final String args[]) throws IOException {
435 for(int i=0; i<args.length; i++) {
436 if(args[i].equals("-time")) {
437 duration = MiscUtils.atoi(args[++i], (int)duration);
438 }
439 }
440 final String tstname = TestBug692GL3VAONEWT.class.getName();
441 org.junit.runner.JUnitCore.main(tstname);
442 }
443
444}
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
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.
static final String GL3bc
The desktop OpenGL compatibility profile 3.x, with x >= 1, ie GL2 plus GL3.
Definition: GLProfile.java:573
Test Vertex Array Object (VAO) Usage and BufferStateTracker.
static int atoi(final String str, final int def)
Definition: MiscUtils.java:57
Utility routines for dealing with direct buffers.
Definition: GLBuffers.java:60
void glCompileShader(int shader)
Entry point to C language function: void {@native glCompileShader}(GLuint shader) Part of GL_ES_VE...
void glValidateProgram(int program)
Entry point to C language function: void {@native glValidateProgram}(GLuint program) Part of GL_ES...
int glCreateProgram()
Entry point to C language function: GLuint {@native glCreateProgram}() Part of GL_ES_VERSION_2_0,...
void glReleaseShaderCompiler()
Start: GL_ARB_ES2_compatibility functions, which are part of ES2 core as well.
void glShaderSource(int shader, int count, String[] string, IntBuffer length)
Entry point to C language function: void {@native glShaderSource}(GLuint shader, GLsizei count,...
void glAttachShader(int program, int shader)
Entry point to C language function: void {@native glAttachShader}(GLuint program,...
int glCreateShader(int type)
Entry point to C language function: GLuint {@native glCreateShader}(GLenum type) Part of GL_ES_VER...
void glLinkProgram(int program)
Entry point to C language function: void {@native glLinkProgram}(GLuint program) Part of GL_ES_VER...
Declares events which client code can use to manage OpenGL rendering into a GLAutoDrawable.
void glGenBuffers(int n, IntBuffer buffers)
Entry point to C language function: void {@native glGenBuffers}(GLsizei n, GLuint * buffers) Part ...
static final int GL_STATIC_DRAW
GL_VERSION_1_5, GL_ES_VERSION_2_0, GL_VERSION_ES_1_0, GL_ARB_vertex_buffer_object Alias for: GL_STATI...
Definition: GL.java:673
static final int GL_ELEMENT_ARRAY_BUFFER
GL_VERSION_1_5, GL_ES_VERSION_2_0, GL_VERSION_ES_1_0, GL_ARB_vertex_buffer_object Alias for: GL_ELEME...
Definition: GL.java:318
void glBindBuffer(int target, int buffer)
Entry point to C language function: void {@native glBindBuffer}(GLenum target, GLuint buffer) Part...
void glBufferData(int target, long size, Buffer data, int usage)
Entry point to C language function: void {@native glBufferData}(GLenum target, GLsizeiptr size,...
static final int GL_ARRAY_BUFFER
GL_VERSION_1_5, GL_ES_VERSION_2_0, GL_VERSION_ES_1_0, GL_ARB_vertex_buffer_object Alias for: GL_ARRAY...
Definition: GL.java:633