1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */ /*!
20 * \file
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23
24 #include "esextcGeometryShaderPrimitiveQueries.hpp"
25
26 #include "gluDefs.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuTestLog.hpp"
30
31 namespace glcts
32 {
33
34 /* Fragment shader */
35 const char* GeometryShaderPrimitiveQueries::m_fs_code = "${VERSION}\n"
36 "\n"
37 "precision highp float;\n"
38 "\n"
39 "void main()\n"
40 "{\n"
41 "}\n";
42
43 /* Vertex shader */
44 const char* GeometryShaderPrimitiveQueries::m_vs_code = "${VERSION}\n"
45 "\n"
46 "precision highp float;\n"
47 "\n"
48 "void main()\n"
49 "{\n"
50 " gl_Position = vec4(gl_VertexID, 0, 0, 1);\n"
51 "}\n";
52
53 /* Geometry shader */
54 const char* GeometryShaderPrimitiveQueriesPoints::m_gs_code =
55 "${VERSION}\n"
56 "\n"
57 "${GEOMETRY_SHADER_REQUIRE}\n"
58 "\n"
59 "precision highp float;\n"
60 "\n"
61 "layout(points) in;\n"
62 "layout(points, max_vertices=8) out;\n"
63 "\n"
64 "void main()\n"
65 "{\n"
66 " for (int n = 0; n < 8; ++n)\n"
67 " {\n"
68 " gl_Position = vec4(1.0 / (float(n) + 1.0), 1.0 / (float(n) + 2.0), 0.0, 1.0);\n"
69 " EmitVertex();\n"
70 " }\n"
71 "\n"
72 " EndPrimitive();\n"
73 "}\n";
74
75 /* Geometry shader */
76 const char* GeometryShaderPrimitiveQueriesLines::m_gs_code =
77 "${VERSION}\n"
78 "\n"
79 "${GEOMETRY_SHADER_REQUIRE}\n"
80 "\n"
81 "precision highp float;\n"
82 "\n"
83 "layout(points) in;\n"
84 "layout(line_strip, max_vertices=10) out;\n"
85 "\n"
86 "void main()\n"
87 "{\n"
88 " for (int n = 0; n < 10; ++n)\n"
89 " {\n"
90 " gl_Position = vec4(1.0 / (float(n) + 1.0), 1.0 / (float(n) + 2.0), 0.0, 1.0);\n"
91 " EmitVertex();\n"
92 " }\n"
93 "\n"
94 " EndPrimitive();\n"
95 "}\n";
96
97 /* Geometry shader */
98 const char* GeometryShaderPrimitiveQueriesTriangles::m_gs_code =
99 "${VERSION}\n"
100 "\n"
101 "${GEOMETRY_SHADER_REQUIRE}\n"
102 "\n"
103 "precision highp float;\n"
104 "\n"
105 "layout(points) in;\n"
106 "layout(triangle_strip, max_vertices=12) out;\n"
107 "\n"
108 "void main()\n"
109 "{\n"
110 " for (int n = 0; n < 12; ++n)\n"
111 " {\n"
112 " gl_Position = vec4(1.0 / (float(n) + 1.0), 1.0 / (float(n) + 2.0), 0.0, 1.0);\n"
113 " EmitVertex();\n"
114 " }\n"
115 "\n"
116 " EndPrimitive();\n"
117 "}\n";
118
119 /** Constructor
120 *
121 * @param context Test context
122 * @param name Test case's name
123 * @param description Test case's description
124 **/
GeometryShaderPrimitiveQueriesPoints(Context & context,const ExtParameters & extParams,const char * name,const char * description)125 GeometryShaderPrimitiveQueriesPoints::GeometryShaderPrimitiveQueriesPoints(Context& context,
126 const ExtParameters& extParams,
127 const char* name, const char* description)
128 : GeometryShaderPrimitiveQueries(context, extParams, name, description)
129 {
130 }
131
132 /** Gets geometry shader code
133 *
134 * @return geometry shader code
135 **/
getGeometryShaderCode()136 const char* GeometryShaderPrimitiveQueriesPoints::getGeometryShaderCode()
137 {
138 return m_gs_code;
139 }
140
141 /** Gets the number of emitted vertices
142 *
143 * @return number of emitted vertices
144 **/
getAmountOfEmittedVertices()145 glw::GLint GeometryShaderPrimitiveQueriesPoints::getAmountOfEmittedVertices()
146 {
147 return 8;
148 }
149
150 /** Gets the transform feedback mode
151 *
152 * @return transform feedback mode
153 **/
getTFMode()154 glw::GLenum GeometryShaderPrimitiveQueriesPoints::getTFMode()
155 {
156 return GL_POINTS;
157 }
158
159 /** Constructor
160 *
161 * @param context Test context
162 * @param name Test case's name
163 * @param description Test case's desricption
164 **/
GeometryShaderPrimitiveQueriesLines(Context & context,const ExtParameters & extParams,const char * name,const char * description)165 GeometryShaderPrimitiveQueriesLines::GeometryShaderPrimitiveQueriesLines(Context& context,
166 const ExtParameters& extParams,
167 const char* name, const char* description)
168 : GeometryShaderPrimitiveQueries(context, extParams, name, description)
169 {
170 }
171
172 /** Gets geometry shader code
173 *
174 * @return geometry shader code
175 **/
getGeometryShaderCode()176 const char* GeometryShaderPrimitiveQueriesLines::getGeometryShaderCode()
177 {
178 return m_gs_code;
179 }
180
181 /** Gets the number of emitted vertices
182 *
183 * @return number of emitted vertices
184 **/
getAmountOfEmittedVertices()185 glw::GLint GeometryShaderPrimitiveQueriesLines::getAmountOfEmittedVertices()
186 {
187 return 18;
188 }
189
190 /** Gets the transform feedback mode
191 *
192 * @return transform feedback mode
193 **/
getTFMode()194 glw::GLenum GeometryShaderPrimitiveQueriesLines::getTFMode()
195 {
196 return GL_LINES;
197 }
198
199 /** Constructor
200 *
201 * @param context Test context
202 * @param name Test case's name
203 * @param description Test case's desricption
204 **/
GeometryShaderPrimitiveQueriesTriangles(Context & context,const ExtParameters & extParams,const char * name,const char * description)205 GeometryShaderPrimitiveQueriesTriangles::GeometryShaderPrimitiveQueriesTriangles(Context& context,
206 const ExtParameters& extParams,
207 const char* name,
208 const char* description)
209 : GeometryShaderPrimitiveQueries(context, extParams, name, description)
210 {
211 }
212
213 /** Gets geometry shader code
214 *
215 * @return geometry shader code
216 **/
getGeometryShaderCode()217 const char* GeometryShaderPrimitiveQueriesTriangles::getGeometryShaderCode()
218 {
219 return m_gs_code;
220 }
221
222 /** Gets the number of emitted vertices
223 *
224 * @return number of emitted vertices
225 **/
getAmountOfEmittedVertices()226 glw::GLint GeometryShaderPrimitiveQueriesTriangles::getAmountOfEmittedVertices()
227 {
228 return 30;
229 }
230
231 /** Gets the transform feedback mode
232 *
233 * @return transform feedback mode
234 **/
getTFMode()235 glw::GLenum GeometryShaderPrimitiveQueriesTriangles::getTFMode()
236 {
237 return GL_TRIANGLES;
238 }
239
240 /** Constructor
241 *
242 * @param context Test context
243 * @param name Test case's name
244 * @param description Test case's desricption
245 **/
GeometryShaderPrimitiveQueries(Context & context,const ExtParameters & extParams,const char * name,const char * description)246 GeometryShaderPrimitiveQueries::GeometryShaderPrimitiveQueries(Context& context, const ExtParameters& extParams,
247 const char* name, const char* description)
248 : TestCaseBase(context, extParams, name, description)
249 , m_n_texture_components(4)
250 , m_bo_large_id(0)
251 , m_bo_small_id(0)
252 , m_fs_id(0)
253 , m_gs_id(0)
254 , m_po_id(0)
255 , m_qo_primitives_generated_id(0)
256 , m_qo_tf_primitives_written_id(0)
257 , m_vao_id(0)
258 , m_vs_id(0)
259 {
260 /* Nothing to be done here */
261 }
262
263 /** Deinitializes GLES objects created during the test.
264 *
265 */
deinit(void)266 void GeometryShaderPrimitiveQueries::deinit(void)
267 {
268 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
269
270 /* Reset OpenGL ES state */
271 gl.useProgram(0);
272 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
273 gl.bindVertexArray(0);
274
275 if (m_po_id != 0)
276 {
277 gl.deleteProgram(m_po_id);
278 }
279
280 if (m_fs_id != 0)
281 {
282 gl.deleteShader(m_fs_id);
283 }
284
285 if (m_gs_id != 0)
286 {
287 gl.deleteShader(m_gs_id);
288 }
289
290 if (m_vs_id != 0)
291 {
292 gl.deleteShader(m_vs_id);
293 }
294
295 if (m_bo_small_id != 0)
296 {
297 gl.deleteBuffers(1, &m_bo_small_id);
298 }
299
300 if (m_bo_large_id != 0)
301 {
302 gl.deleteBuffers(1, &m_bo_large_id);
303 }
304
305 if (m_qo_primitives_generated_id != 0)
306 {
307 gl.deleteQueries(1, &m_qo_primitives_generated_id);
308 }
309
310 if (m_qo_tf_primitives_written_id != 0)
311 {
312 gl.deleteQueries(1, &m_qo_tf_primitives_written_id);
313 }
314
315 if (m_vao_id != 0)
316 {
317 gl.deleteVertexArrays(1, &m_vao_id);
318 }
319
320 /* Release base class */
321 TestCaseBase::deinit();
322 }
323
324 /** Executes the test.
325 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
326 * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
327 * Note the function throws exception should an error occur!
328 **/
iterate(void)329 tcu::TestNode::IterateResult GeometryShaderPrimitiveQueries::iterate(void)
330 {
331 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
332
333 /* Check if geometry_shader extension is supported */
334 if (!m_is_geometry_shader_extension_supported)
335 {
336 throw tcu::NotSupportedError(GEOMETRY_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
337 }
338
339 /* Create shader objects and a program object */
340 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
341 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
342 m_gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
343 m_po_id = gl.createProgram();
344
345 GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating program/shader objects.");
346
347 /* Try to build test-specific program object */
348 const char* tf_varyings[] = { "gl_Position" };
349 const char* gs_code = getGeometryShaderCode();
350
351 gl.transformFeedbackVaryings(m_po_id, sizeof(tf_varyings) / sizeof(tf_varyings[0]), tf_varyings,
352 GL_SEPARATE_ATTRIBS);
353
354 if (!buildProgram(m_po_id, m_fs_id, 1 /* part */, &m_fs_code, m_gs_id, 1 /* part */, &gs_code, m_vs_id,
355 1 /* part */, &m_vs_code))
356 {
357 TCU_FAIL("Could not create a program for GeometryShaderPrimitiveQueries!");
358 }
359
360 /* Create and bind a vertex array object */
361 gl.genVertexArrays(1, &m_vao_id);
362 gl.bindVertexArray(m_vao_id);
363
364 GLU_EXPECT_NO_ERROR(gl.getError(), "Error creating a vertex array object.");
365
366 /* Create two buffer objects
367 *
368 * One with sufficiently large storage space to hold position data for particular output.
369 * Another one of insufficient size.
370 */
371 gl.genBuffers(1, &m_bo_large_id);
372 gl.genBuffers(1, &m_bo_small_id);
373
374 gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_large_id);
375 gl.bufferData(GL_ARRAY_BUFFER,
376 getAmountOfEmittedVertices() * m_n_texture_components /* components */ * sizeof(float), NULL,
377 GL_STATIC_DRAW);
378
379 gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_small_id);
380 gl.bufferData(GL_ARRAY_BUFFER,
381 (getAmountOfEmittedVertices() / 2) * m_n_texture_components /* components */ * sizeof(float), NULL,
382 GL_STATIC_DRAW);
383
384 GLU_EXPECT_NO_ERROR(gl.getError(), "Error allocating buffer objects.");
385
386 /* Create primitive query objects */
387 gl.genQueries(1, &m_qo_tf_primitives_written_id);
388 gl.genQueries(1, &m_qo_primitives_generated_id);
389
390 glw::GLuint nPrimitivesGenerated = 0;
391 glw::GLuint nTFPrimitivesWritten = 0;
392
393 /* Test case 13.1 */
394 readPrimitiveQueryValues(m_bo_large_id, &nPrimitivesGenerated, &nTFPrimitivesWritten);
395
396 if (nPrimitivesGenerated == 0)
397 {
398 m_testCtx.getLog()
399 << tcu::TestLog::Message
400 << "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value is zero which should never happen."
401 << tcu::TestLog::EndMessage;
402
403 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
404 return STOP;
405 }
406
407 if (nTFPrimitivesWritten == 0)
408 {
409 m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query "
410 "object value is zero which should never happen."
411 << tcu::TestLog::EndMessage;
412
413 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
414 return STOP;
415 }
416
417 if (nPrimitivesGenerated != nTFPrimitivesWritten)
418 {
419 m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value("
420 << nPrimitivesGenerated
421 << ") is different than for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN ("
422 << nTFPrimitivesWritten << ")" << tcu::TestLog::EndMessage;
423
424 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
425 return STOP;
426 }
427
428 /* Test case 13.2 */
429 nPrimitivesGenerated = 0;
430 nTFPrimitivesWritten = 0;
431
432 readPrimitiveQueryValues(m_bo_small_id, &nPrimitivesGenerated, &nTFPrimitivesWritten);
433
434 if (nPrimitivesGenerated == 0)
435 {
436 m_testCtx.getLog()
437 << tcu::TestLog::Message
438 << "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value is zero which should never happen."
439 << tcu::TestLog::EndMessage;
440
441 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
442 return STOP;
443 }
444
445 if (nTFPrimitivesWritten == 0)
446 {
447 m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query "
448 "object value is zero which should never happen."
449 << tcu::TestLog::EndMessage;
450
451 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
452 return STOP;
453 }
454
455 if ((nPrimitivesGenerated / 2) != nTFPrimitivesWritten)
456 {
457 m_testCtx.getLog() << tcu::TestLog::Message
458 << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object value("
459 << nPrimitivesGenerated << ") should be half the amount of GL_PRIMITIVES_GENERATED_EXT ("
460 << nTFPrimitivesWritten << ")" << tcu::TestLog::EndMessage;
461
462 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
463 return STOP;
464 }
465
466 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
467 return STOP;
468 }
469
470 /**
471 * The function binds the provided bufferId to transform feedback target and sets up a query
472 * for GL_PRIMITIVES_GENERATED_EXT GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN.
473 * It then issues a draw call to execute the vertex and geometry shaders. Then results
474 * of the queries are written to nPrimitivesGenerated and nPrimitivesWritten variables.
475 *
476 * @param context bufferId id of the buffer to be bound to transform feedback target
477 * @return nPrimitivesGenerated the result of GL_PRIMITIVES_GENERATED_EXT query
478 * @return nPrimitivesWritten the result of GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query
479 */
readPrimitiveQueryValues(glw::GLint bufferId,glw::GLuint * nPrimitivesGenerated,glw::GLuint * nPrimitivesWritten)480 void GeometryShaderPrimitiveQueries::readPrimitiveQueryValues(glw::GLint bufferId, glw::GLuint* nPrimitivesGenerated,
481 glw::GLuint* nPrimitivesWritten)
482 {
483 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
484
485 /* Bind the buffer object to hold the captured data.*/
486 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bufferId);
487
488 /* Activate the program object */
489 gl.useProgram(m_po_id);
490 GLU_EXPECT_NO_ERROR(gl.getError(), "Error using program object");
491
492 gl.beginTransformFeedback(getTFMode());
493 GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting transform feedback");
494
495 /* Activate the queries */
496 gl.beginQuery(m_glExtTokens.PRIMITIVES_GENERATED, m_qo_primitives_generated_id);
497 GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting GL_PRIMITIVES_GENERATED_EXT query");
498
499 gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_qo_tf_primitives_written_id);
500 GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query");
501
502 /* Render */
503 gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
504 GLU_EXPECT_NO_ERROR(gl.getError(), "Error executing draw call");
505
506 gl.endTransformFeedback();
507 GLU_EXPECT_NO_ERROR(gl.getError(), "Error finishing transform feedback");
508
509 /* Query objects end here. */
510 gl.endQuery(m_glExtTokens.PRIMITIVES_GENERATED);
511 gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
512
513 /* Retrieve query values */
514 gl.getQueryObjectuiv(m_qo_primitives_generated_id, GL_QUERY_RESULT, nPrimitivesGenerated);
515 gl.getQueryObjectuiv(m_qo_tf_primitives_written_id, GL_QUERY_RESULT, nPrimitivesWritten);
516
517 GLU_EXPECT_NO_ERROR(gl.getError(), "Error retrieving query values.");
518 }
519
520 } // namespace glcts
521