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
410                            << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query "
411                               "object value is zero which should never happen."
412                            << tcu::TestLog::EndMessage;
413 
414         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
415         return STOP;
416     }
417 
418     if (nPrimitivesGenerated != nTFPrimitivesWritten)
419     {
420         m_testCtx.getLog() << tcu::TestLog::Message << "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value("
421                            << nPrimitivesGenerated
422                            << ") is different than for GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN ("
423                            << nTFPrimitivesWritten << ")" << tcu::TestLog::EndMessage;
424 
425         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
426         return STOP;
427     }
428 
429     /* Test case 13.2 */
430     nPrimitivesGenerated = 0;
431     nTFPrimitivesWritten = 0;
432 
433     readPrimitiveQueryValues(m_bo_small_id, &nPrimitivesGenerated, &nTFPrimitivesWritten);
434 
435     if (nPrimitivesGenerated == 0)
436     {
437         m_testCtx.getLog()
438             << tcu::TestLog::Message
439             << "Retrieved GL_PRIMITIVES_GENERATED_EXT query object value is zero which should never happen."
440             << tcu::TestLog::EndMessage;
441 
442         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
443         return STOP;
444     }
445 
446     if (nTFPrimitivesWritten == 0)
447     {
448         m_testCtx.getLog() << tcu::TestLog::Message
449                            << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query "
450                               "object value is zero which should never happen."
451                            << tcu::TestLog::EndMessage;
452 
453         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
454         return STOP;
455     }
456 
457     if ((nPrimitivesGenerated / 2) != nTFPrimitivesWritten)
458     {
459         m_testCtx.getLog() << tcu::TestLog::Message
460                            << "Retrieved GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query object value("
461                            << nPrimitivesGenerated << ") should be half the amount of GL_PRIMITIVES_GENERATED_EXT ("
462                            << nTFPrimitivesWritten << ")" << tcu::TestLog::EndMessage;
463 
464         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
465         return STOP;
466     }
467 
468     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
469     return STOP;
470 }
471 
472 /**
473  * The function binds the provided bufferId to transform feedback target and sets up a query
474  * for GL_PRIMITIVES_GENERATED_EXT GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN.
475  * It then issues a draw call to execute the vertex and geometry shaders. Then results
476  * of the queries are written to nPrimitivesGenerated and nPrimitivesWritten variables.
477  *
478  * @param context bufferId   id of the buffer to be bound to transform feedback target
479  * @return nPrimitivesGenerated      the result of GL_PRIMITIVES_GENERATED_EXT query
480  * @return nPrimitivesWritten        the result of GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query
481  */
readPrimitiveQueryValues(glw::GLint bufferId,glw::GLuint * nPrimitivesGenerated,glw::GLuint * nPrimitivesWritten)482 void GeometryShaderPrimitiveQueries::readPrimitiveQueryValues(glw::GLint bufferId, glw::GLuint *nPrimitivesGenerated,
483                                                               glw::GLuint *nPrimitivesWritten)
484 {
485     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
486 
487     /* Bind the buffer object to hold the captured data.*/
488     gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bufferId);
489 
490     /* Activate the program object */
491     gl.useProgram(m_po_id);
492     GLU_EXPECT_NO_ERROR(gl.getError(), "Error using program object");
493 
494     gl.beginTransformFeedback(getTFMode());
495     GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting transform feedback");
496 
497     /* Activate the queries */
498     gl.beginQuery(m_glExtTokens.PRIMITIVES_GENERATED, m_qo_primitives_generated_id);
499     GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting GL_PRIMITIVES_GENERATED_EXT query");
500 
501     gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, m_qo_tf_primitives_written_id);
502     GLU_EXPECT_NO_ERROR(gl.getError(), "Error starting GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query");
503 
504     /* Render */
505     gl.drawArrays(GL_POINTS, 0 /* first */, 1 /* count */);
506     GLU_EXPECT_NO_ERROR(gl.getError(), "Error executing draw call");
507 
508     gl.endTransformFeedback();
509     GLU_EXPECT_NO_ERROR(gl.getError(), "Error finishing transform feedback");
510 
511     /* Query objects end here. */
512     gl.endQuery(m_glExtTokens.PRIMITIVES_GENERATED);
513     gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
514 
515     /* Retrieve query values */
516     gl.getQueryObjectuiv(m_qo_primitives_generated_id, GL_QUERY_RESULT, nPrimitivesGenerated);
517     gl.getQueryObjectuiv(m_qo_tf_primitives_written_id, GL_QUERY_RESULT, nPrimitivesWritten);
518 
519     GLU_EXPECT_NO_ERROR(gl.getError(), "Error retrieving query values.");
520 }
521 
522 } // namespace glcts
523