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 /*!
25  * \file esextcTessellationShaderPrimitiveCoverage.cpp
26  * \brief TessellationShadePrimitiveCoverage (Test 31)
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "esextcTessellationShaderPrimitiveCoverage.hpp"
30 #include "esextcTessellationShaderUtils.hpp"
31 #include "gluContextInfo.hpp"
32 #include "gluDefs.hpp"
33 #include "glwEnums.hpp"
34 #include "glwFunctions.hpp"
35 #include "tcuTestLog.hpp"
36 #include <cstdarg>
37 #include <cstddef>
38 #include <cstdlib>
39 
40 namespace glcts
41 {
42 
43 /* Vertex shader */
44 const char *TessellationShaderPrimitiveCoverage::m_vs_code = "${VERSION}\n"
45                                                              "\n"
46                                                              "precision highp float;\n"
47                                                              "\n"
48                                                              "layout(location = 0) in vec4 position;\n"
49                                                              "\n"
50                                                              "void main()\n"
51                                                              "{\n"
52                                                              "    gl_Position = position;\n"
53                                                              "}\n";
54 
55 /* Tessellation Control Shaders' source code  */
56 const char *TessellationShaderPrimitiveCoverage::m_quad_tessellation_tcs_code =
57     "${VERSION}\n"
58     "\n"
59     "${TESSELLATION_SHADER_REQUIRE}\n"
60     "\n"
61     "precision highp float;\n"
62     "\n"
63     "layout(vertices = 4) out;\n"
64     "\n"
65     "uniform vec2 innerLevel;"
66     "uniform vec4 outerLevel;"
67     "\n"
68     "void main()\n"
69     "{\n"
70     "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
71     "\n"
72     "    gl_TessLevelInner[0] = innerLevel.x;\n"
73     "    gl_TessLevelInner[1] = innerLevel.y;\n"
74     "    gl_TessLevelOuter[0] = outerLevel.x;\n"
75     "    gl_TessLevelOuter[1] = outerLevel.y;\n"
76     "    gl_TessLevelOuter[2] = outerLevel.z;\n"
77     "    gl_TessLevelOuter[3] = outerLevel.w;\n"
78     "}\n";
79 
80 /* Tessellation Evaluation Shaders' source code  */
81 const char *TessellationShaderPrimitiveCoverage::m_quad_tessellation_tes_code =
82     "${VERSION}\n"
83     "\n"
84     "${TESSELLATION_SHADER_REQUIRE}\n"
85     "\n"
86     "precision highp float;\n"
87     "\n"
88     "layout (quads) in;\n"
89     "\n"
90     "void main()\n"
91     "{\n"
92     "    gl_Position = gl_in[0].gl_Position * (1.0 - gl_TessCoord.x) * (1.0 - "
93     "gl_TessCoord.y)\n" /* Specifying the vertex's position */
94     "                + gl_in[1].gl_Position * (      gl_TessCoord.x) * (1.0 - "
95     "gl_TessCoord.y)\n" /* using the bilinear interpolation */
96     "                + gl_in[2].gl_Position * (      gl_TessCoord.x) * (      "
97     "gl_TessCoord.y)\n"
98     "                + gl_in[3].gl_Position * (1.0 - gl_TessCoord.x) * (      "
99     "gl_TessCoord.y);\n"
100     "}\n";
101 
102 /* Tessellation Control Shaders' source code  */
103 const char *TessellationShaderPrimitiveCoverage::m_triangles_tessellation_tcs_code =
104     "${VERSION}\n"
105     "\n"
106     "${TESSELLATION_SHADER_REQUIRE}\n"
107     "\n"
108     "precision highp float;\n"
109     "\n"
110     "layout(vertices = 3) out;\n"
111     "\n"
112     "uniform vec2 innerLevel;"
113     "uniform vec4 outerLevel;"
114     "\n"
115     "void main()\n"
116     "{\n"
117     "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
118     "\n"
119     "    gl_TessLevelInner[0] = innerLevel.x;\n"
120     "    gl_TessLevelInner[1] = innerLevel.y;\n"
121     "    gl_TessLevelOuter[0] = outerLevel.x;\n"
122     "    gl_TessLevelOuter[1] = outerLevel.y;\n"
123     "    gl_TessLevelOuter[2] = outerLevel.z;\n"
124     "    gl_TessLevelOuter[3] = outerLevel.w;\n"
125     "}\n";
126 
127 /* Tessellation Evaluation Shader code for triangle test */
128 const char *TessellationShaderPrimitiveCoverage::m_triangles_tessellation_tes_code =
129     "${VERSION}\n"
130     "\n"
131     "${TESSELLATION_SHADER_REQUIRE}\n"
132     "\n"
133     "precision highp float;\n"
134     "\n"
135     "layout (triangles) in;\n"
136     "\n"
137     "void main()\n"
138     "{\n"
139     "    gl_Position = gl_in[0].gl_Position * gl_TessCoord.x\n" /* Specifying the vertex's position */
140     "                + gl_in[1].gl_Position * gl_TessCoord.y\n" /* using the barycentric interpolation */
141     "                + gl_in[2].gl_Position * gl_TessCoord.z;\n"
142     "}\n";
143 
144 /* Fragment Shader code */
145 const char *TessellationShaderPrimitiveCoverage::m_fs_code = "${VERSION}\n"
146                                                              "\n"
147                                                              "precision highp float;\n"
148                                                              "\n"
149                                                              "uniform highp vec4 stencil_fail_color;\n"
150                                                              "\n"
151                                                              "layout(location = 0) out highp vec4 color;\n"
152                                                              "\n"
153                                                              "void main()\n"
154                                                              "{\n"
155                                                              "    color = stencil_fail_color;\n"
156                                                              "}\n";
157 
158 /* A clear color used to set up framebuffer */
159 const glw::GLfloat TessellationShaderPrimitiveCoverage::m_clear_color[4] = {
160     255.f / 255.f, /* red   */
161     128.f / 255.f, /* green */
162     64.f / 255.f,  /* blue  */
163     32.f / 255.f   /* alpha */
164 };
165 
166 /* A color used to draw differences between the tesselated primitive
167  * and the reference primitive (when stencil test passes)
168  */
169 const glw::GLfloat TessellationShaderPrimitiveCoverage::m_stencil_pass_color[4] = {
170     32.f / 255.f,  /* red   */
171     64.f / 255.f,  /* green */
172     128.f / 255.f, /* blue  */
173     255.f / 255.f  /* alpha */
174 };
175 
176 /* Rendering area height */
177 const glw::GLuint TessellationShaderPrimitiveCoverage::m_height =
178     2048; /* minimum maximum as required by ES specification */
179 /* Number of components as used for color attachment */
180 const glw::GLuint TessellationShaderPrimitiveCoverage::m_n_components = 4;
181 /* Rendering area width */
182 const glw::GLuint TessellationShaderPrimitiveCoverage::m_width =
183     2048; /* minimum maximum as required by ES specification */
184 
185 /* Buffer size for fetched pixels */
186 const glw::GLuint TessellationShaderPrimitiveCoverage::m_rendered_data_buffer_size = m_width    /* width */
187                                                                                      * m_height /* height */
188                                                                                      * m_n_components /* components */;
189 
190 /** Constructor
191  *
192  * @param context     Test context
193  * @param name        Test case's name
194  * @param description Test case's description
195  **/
TessellationShaderPrimitiveCoverage(Context & context,const ExtParameters & extParams)196 TessellationShaderPrimitiveCoverage::TessellationShaderPrimitiveCoverage(Context &context,
197                                                                          const ExtParameters &extParams)
198     : TestCaseBase(context, extParams, "primitive_coverage",
199                    "Verifies that no fragments are generated more than once when the "
200                    "rendering pipeline (consisting of TC+TE stages) generates a "
201                    "tessellated full-screen quad or two tessellated triangles.")
202     , m_vao_id(0)
203     , m_quad_tessellation_po_id(0)
204     , m_stencil_verification_po_id(0)
205     , m_triangles_tessellation_po_id(0)
206     , m_bo_id(0)
207     , m_fs_id(0)
208     , m_quad_tessellation_tcs_id(0)
209     , m_quad_tessellation_tes_id(0)
210     , m_triangles_tessellation_tcs_id(0)
211     , m_triangles_tessellation_tes_id(0)
212     , m_vs_id(0)
213     , m_fbo_id(0)
214     , m_color_rbo_id(0)
215     , m_stencil_rbo_id(0)
216     , m_rendered_data_buffer(DE_NULL)
217 {
218     /* Nothing to be done here */
219 }
220 
221 /** Deinitializes all ES objects created for the test. */
deinit(void)222 void TessellationShaderPrimitiveCoverage::deinit(void)
223 {
224     /* Deinitialize base class */
225     TestCaseBase::deinit();
226 
227     if (!m_is_tessellation_shader_supported)
228     {
229         return;
230     }
231 
232     /* Retrieve ES entry-points */
233     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
234 
235     /* Reset OpenGL ES state */
236     gl.useProgram(0);
237     gl.bindBuffer(GL_ARRAY_BUFFER, 0);
238     gl.bindFramebuffer(GL_READ_FRAMEBUFFER, 0);
239     gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
240     gl.disable(GL_STENCIL_TEST);
241     gl.bindVertexArray(0);
242 
243     /* Reset GL_PATCH_VERTICES_EXT to the default value. */
244     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
245     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed!");
246 
247     /* Delete buffers */
248     if (m_rendered_data_buffer != DE_NULL)
249     {
250         free(m_rendered_data_buffer);
251 
252         m_rendered_data_buffer = DE_NULL;
253     }
254 
255     /* Delete program and shader objects */
256     if (m_quad_tessellation_po_id != 0)
257     {
258         gl.deleteProgram(m_quad_tessellation_po_id);
259 
260         m_quad_tessellation_po_id = 0;
261     }
262 
263     if (m_stencil_verification_po_id != 0)
264     {
265         gl.deleteProgram(m_stencil_verification_po_id);
266 
267         m_stencil_verification_po_id = 0;
268     }
269 
270     if (m_triangles_tessellation_po_id != 0)
271     {
272         gl.deleteProgram(m_triangles_tessellation_po_id);
273 
274         m_triangles_tessellation_po_id = 0;
275     }
276 
277     if (m_fs_id != 0)
278     {
279         gl.deleteShader(m_fs_id);
280 
281         m_fs_id = 0;
282     }
283 
284     if (m_quad_tessellation_tcs_id != 0)
285     {
286         gl.deleteShader(m_quad_tessellation_tcs_id);
287 
288         m_quad_tessellation_tcs_id = 0;
289     }
290 
291     if (m_quad_tessellation_tes_id != 0)
292     {
293         gl.deleteShader(m_quad_tessellation_tes_id);
294 
295         m_quad_tessellation_tes_id = 0;
296     }
297 
298     if (m_triangles_tessellation_tcs_id != 0)
299     {
300         gl.deleteShader(m_triangles_tessellation_tcs_id);
301 
302         m_triangles_tessellation_tcs_id = 0;
303     }
304 
305     if (m_triangles_tessellation_tes_id != 0)
306     {
307         gl.deleteShader(m_triangles_tessellation_tes_id);
308 
309         m_triangles_tessellation_tes_id = 0;
310     }
311 
312     if (m_vs_id != 0)
313     {
314         gl.deleteShader(m_vs_id);
315 
316         m_vs_id = 0;
317     }
318 
319     /* Delete framebuffer and renderbuffer objects */
320     if (m_fbo_id != 0)
321     {
322         gl.deleteFramebuffers(1, &m_fbo_id);
323 
324         m_fbo_id = 0;
325     }
326 
327     if (m_color_rbo_id != 0)
328     {
329         gl.deleteRenderbuffers(1, &m_color_rbo_id);
330 
331         m_color_rbo_id = 0;
332     }
333 
334     if (m_stencil_rbo_id != 0)
335     {
336         gl.deleteRenderbuffers(1, &m_stencil_rbo_id);
337 
338         m_stencil_rbo_id = 0;
339     }
340 
341     /* Delete buffer objects */
342     if (m_bo_id != 0)
343     {
344         gl.deleteBuffers(1, &m_bo_id);
345 
346         m_bo_id = 0;
347     }
348 
349     if (m_vao_id != 0)
350     {
351         gl.deleteVertexArrays(1, &m_vao_id);
352 
353         m_vao_id = 0;
354     }
355 }
356 
357 /** Initializes the test.
358  *
359  *  Note the function throws exception should an error occur!
360  **/
initTest(void)361 void TessellationShaderPrimitiveCoverage::initTest(void)
362 {
363     /* Skip if GL_EXT_tessellation_shader extension is not supported. */
364     if (!m_is_tessellation_shader_supported)
365     {
366         throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED, "", __FILE__, __LINE__);
367     }
368 
369     /* Retrieve ES entry-points */
370     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
371 
372     /* Generate and bind VAO */
373     gl.genVertexArrays(1, &m_vao_id);
374     GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
375 
376     gl.bindVertexArray(m_vao_id);
377     GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
378 
379     /* Initialize objects used by the test */
380     initProgramObjects();
381     initFramebuffer();
382     initBufferObjects();
383 
384     /* setup of pixels buffer for fetching data*/
385     m_rendered_data_buffer = (glw::GLubyte *)malloc(m_rendered_data_buffer_size);
386 
387     /* Enable stencil test. */
388     gl.enable(GL_STENCIL_TEST);
389     GLU_EXPECT_NO_ERROR(gl.getError(), "Stencil test could not be enabled!");
390 
391     /* Set up viewport */
392     gl.viewport(0 /* x */, 0 /* y */, m_width, m_height);
393     GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() failed!");
394 }
395 
396 /** Initializes program objects used by the test.
397  *
398  *  Note the function throws exception should an error occur!
399  **/
initProgramObjects(void)400 void TessellationShaderPrimitiveCoverage::initProgramObjects(void)
401 {
402     /* Retrieve ES entry-points */
403     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
404 
405     /* Create program objects needed for the test */
406     m_stencil_verification_po_id = gl.createProgram();
407     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed!");
408 
409     m_quad_tessellation_po_id = gl.createProgram();
410     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed!");
411 
412     m_triangles_tessellation_po_id = gl.createProgram();
413     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed!");
414 
415     /* Set up shader objects */
416     m_vs_id = gl.createShader(GL_VERTEX_SHADER);
417     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_VERTEX_SHADER) failed!");
418 
419     m_quad_tessellation_tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
420     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_CONTROL_SHADER_EXT) failed!");
421 
422     m_quad_tessellation_tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
423     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_EVALUATION_SHADER_EXT) failed!");
424 
425     m_triangles_tessellation_tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
426     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_CONTROL_SHADER_EXT) failed!");
427 
428     m_triangles_tessellation_tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
429     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_EVALUATION_SHADER_EXT) failed!");
430 
431     m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
432     GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_FRAGMENT_SHADER) failed!");
433 
434     /* Build a program object that does not define the tessellation stage */
435     if (!buildProgram(m_stencil_verification_po_id, m_vs_id, 1, &m_vs_code, m_fs_id, 1, &m_fs_code))
436     {
437         TCU_FAIL("Could not create a program object");
438     }
439 
440     /* Build a program object that uses quad tessellation */
441     if (!buildProgram(m_quad_tessellation_po_id, m_vs_id, 1, &m_vs_code, m_quad_tessellation_tcs_id, 1,
442                       &m_quad_tessellation_tcs_code, m_quad_tessellation_tes_id, 1, &m_quad_tessellation_tes_code,
443                       m_fs_id, 1, &m_fs_code))
444     {
445         TCU_FAIL("Could not create a program object");
446     }
447 
448     /* Build a program object that uses triangle tessellation */
449     if (!buildProgram(m_triangles_tessellation_po_id, m_vs_id, 1, &m_vs_code, m_triangles_tessellation_tcs_id, 1,
450                       &m_triangles_tessellation_tcs_code, m_triangles_tessellation_tes_id, 1,
451                       &m_triangles_tessellation_tes_code, m_fs_id, 1, &m_fs_code))
452     {
453         TCU_FAIL("Could not create a program object");
454     }
455 }
456 
457 /** Initializes a framebuffer object.
458  *
459  *  Note the function throws exception should an error occur!
460  **/
initFramebuffer(void)461 void TessellationShaderPrimitiveCoverage::initFramebuffer(void)
462 {
463     /* Retrieve ES entry-points. */
464     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
465 
466     /* Framebuffer setup */
467     gl.genFramebuffers(1, &m_fbo_id);
468     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() failed!");
469 
470     gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
471     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() failed!");
472 
473     /* Set up a renderbuffer object and bind it as a color attachment to the
474      * framebuffer object */
475     gl.genRenderbuffers(1, &m_color_rbo_id);
476     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers() failed!");
477 
478     gl.bindRenderbuffer(GL_RENDERBUFFER, m_color_rbo_id);
479     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer() failed!");
480 
481     gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, m_width, m_height);
482     GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage() failed!");
483 
484     gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_color_rbo_id);
485     GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer() failed!");
486 
487     /* Set up a renderbuffer object and bind it as a stencil attachment to
488      * the framebuffer object */
489     gl.genRenderbuffers(1, &m_stencil_rbo_id);
490     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers() failed!");
491 
492     gl.bindRenderbuffer(GL_RENDERBUFFER, m_stencil_rbo_id);
493     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer() failed!");
494 
495     gl.renderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, m_width, m_height);
496     GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage() failed!");
497 
498     gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencil_rbo_id);
499     GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer() failed!");
500 
501     gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
502     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer() failed!");
503 
504     /* Check framebuffer completness */
505     if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
506     {
507         TCU_FAIL("Test framebuffer has been reported as incomplete");
508     }
509 }
510 
511 /** Initializes buffer objects used by the test.
512  *
513  *  Note the function throws exception should an error occur!
514  **/
initBufferObjects(void)515 void TessellationShaderPrimitiveCoverage::initBufferObjects(void)
516 {
517     /* Retrieve ES entry-points */
518     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
519 
520     /* Set up an array of vertices that will be fed into vertex shader */
521     glw::GLfloat vertices[6 /* vertices */ * m_n_components /* components */] = {
522         -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f,
523         -1.0f, 0.0f, 1.0f,       /* A half-screen triangle (patch) (CCW) is defined until here */
524         1.0f,  1.0f, 0.0f, 1.0f, /* A full screen quad (patch) (CCW) is defined until here */
525         -1.0f, 1.0f, 0.0f, 1.0f, 1.0f,  -1.0f, 0.0f, 1.0f /* A full screen quad (2 triangles) (CCW) is defined until here */
526     };
527 
528     /* Configure a buffer object to hold vertex data */
529     gl.genBuffers(1, &m_bo_id);
530     GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed!");
531 
532     gl.bindBuffer(GL_ARRAY_BUFFER, m_bo_id);
533     GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!");
534 
535     gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
536     GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed!");
537 
538     /* Configure "position" vertex attribute array and enable it */
539     gl.vertexAttribPointer(0,        /* index */
540                            4,        /* size */
541                            GL_FLOAT, /* type */
542                            GL_FALSE, /* normalized */
543                            0,        /* stride */
544                            0);       /* pointer */
545     GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() failed!");
546 
547     gl.enableVertexAttribArray(0);
548     GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() failed!");
549 }
550 
551 /** The function:
552  *
553  *  1) Clears the FBO's color/stencil attachments with zeros;
554  *  2) Issues a draw call using a program object, for which either triangles or quads
555  *     tessellation has been enabled. This draw call updates both color and stencil
556  *     buffers of the framebuffer: fragment shader stores vec4(1) in the color attachment
557  *     and stencil index is set to 0x1 for all affected fragments;
558  *  3) Issues a draw call using another program object, this time without tessellation
559  *     stage enabled. Stencil test is configured to only pass those fragments, for which
560  *     stencil index is not equal to 0xFF.
561  *
562  *  Note the function throws exception should an error occur!
563  *
564  *  @param po_id                   program object handle to draw tesselated primitive
565  *  @param n_patch_vertices        number of input vertices for a single patch (must
566  *                                 be 3 for triangles or 4 for quads).
567  *  @param n_draw_call_vertices    number of input vertices for a reference draw call
568  *                                 (must be 3 for triangle or 6 for quad (2 triangles)).
569  *  @param inner_levels            array of the inner tessellation levels
570  *  @param outer_levels            array of the outer tessellation levels
571  *
572  *  @return false if the test failed, or true if test passed.
573  **/
drawPatch(glw::GLuint po_id,glw::GLuint n_patch_vertices,glw::GLuint n_draw_call_vertices,const glw::GLfloat inner_levels[],const glw::GLfloat outer_levels[])574 void TessellationShaderPrimitiveCoverage::drawPatch(glw::GLuint po_id, glw::GLuint n_patch_vertices,
575                                                     glw::GLuint n_draw_call_vertices, const glw::GLfloat inner_levels[],
576                                                     const glw::GLfloat outer_levels[])
577 {
578     /* Quick check */
579     DE_ASSERT(n_draw_call_vertices == 3 || n_draw_call_vertices == 6);
580 
581     /* Retrieve ES entry-points */
582     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
583 
584     /* Activate user-provided program object with tessellation stage defined*/
585     gl.useProgram(po_id);
586     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed!");
587 
588     /* Set up tessellation levels */
589     glw::GLint innerLevelUniformLocation = -1;
590     glw::GLint outerLevelUniformLocation = -1;
591 
592     innerLevelUniformLocation = gl.getUniformLocation(po_id, "innerLevel");
593     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() failed!");
594 
595     outerLevelUniformLocation = gl.getUniformLocation(po_id, "outerLevel");
596     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() failed!");
597 
598     gl.uniform2fv(innerLevelUniformLocation, 1 /* count */, inner_levels);
599     GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() failed!");
600 
601     gl.uniform4fv(outerLevelUniformLocation, 1 /* count */, outer_levels);
602     GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() failed!");
603 
604     gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, n_patch_vertices);
605     GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed!");
606 
607     /* Set up clear color */
608     gl.clearColor(m_clear_color[0],  /* red */
609                   m_clear_color[1],  /* green */
610                   m_clear_color[2],  /* blue */
611                   m_clear_color[3]); /* alpha */
612     GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() failed!");
613 
614     /* Set up fragment color to be used for the first stage */
615     glw::GLint stencilPassColorUniformLocation = -1;
616 
617     stencilPassColorUniformLocation = gl.getUniformLocation(po_id, "stencil_fail_color");
618     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() failed!");
619 
620     gl.uniform4fv(stencilPassColorUniformLocation, 1, m_stencil_pass_color);
621     GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() failed!");
622 
623     /* Draw to stencil buffer */
624     gl.clearStencil(0 /* s */);
625     GLU_EXPECT_NO_ERROR(gl.getError(), "glClearStencil() failed!");
626 
627     gl.clear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
628     GLU_EXPECT_NO_ERROR(gl.getError(), "glClear() failed!");
629 
630     gl.stencilOp(GL_REPLACE /* sfail */, GL_KEEP /* dpfail */, GL_KEEP /* dppass */);
631     GLU_EXPECT_NO_ERROR(gl.getError(), "glStencilOp() failed!");
632 
633     gl.stencilFunc(GL_NEVER /* func */, 1 /* ref */, 0xFF /* mask */);
634     GLU_EXPECT_NO_ERROR(gl.getError(), "glStencilFunc() failed!");
635 
636     gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, n_patch_vertices);
637     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
638 
639     /* Now verify the stencil buffer data contents by doing another
640      * full-screen draw call. This time without any tessellation.
641      * The pass will output fragments of predefined color, if stencil
642      * test passes (which will only happen if the stencil buffer is
643      * not filled with predefined index value).
644      */
645     gl.useProgram(m_stencil_verification_po_id);
646     GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed!");
647 
648     /* Color setup for 2nd program*/
649     stencilPassColorUniformLocation = gl.getUniformLocation(m_stencil_verification_po_id, "stencil_fail_color");
650 
651     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() failed!");
652 
653     gl.uniform4fv(stencilPassColorUniformLocation, 1 /* count */, m_stencil_pass_color);
654     GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() failed!");
655 
656     /* Draw to framebuffer */
657     gl.stencilOp(GL_KEEP /* sfail */, GL_KEEP /* dpfail */, GL_KEEP /* dppass */);
658     GLU_EXPECT_NO_ERROR(gl.getError(), "glStencilOp() failed!");
659 
660     gl.stencilFunc(GL_NOTEQUAL /* func */, 1 /* ref */, 0xFF /* mask */);
661     GLU_EXPECT_NO_ERROR(gl.getError(), "glStencilFunc() failed!");
662 
663     gl.drawArrays(GL_TRIANGLES, 0 /* first */, n_draw_call_vertices);
664     GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
665 }
666 
667 /** Retrieves data from test FBO's zeroth color attachment and verifies
668  *  no cracks are present.
669  *
670  *  Note the function throws exception should an error occur!
671  *
672  *  @return false if the check failed or true if check passed.
673  **/
verifyDrawBufferContents(void)674 bool TessellationShaderPrimitiveCoverage::verifyDrawBufferContents(void)
675 {
676     /* Retrieve ES entry-points */
677     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
678 
679     /* Fetch the data */
680     gl.readBuffer(GL_COLOR_ATTACHMENT0);
681     GLU_EXPECT_NO_ERROR(gl.getError(), "glReadBuffer() failed");
682 
683     gl.readPixels(0,                          /* x */
684                   0,                          /* y */
685                   m_height, m_width, GL_RGBA, /* format */
686                   GL_UNSIGNED_BYTE,           /* type */
687                   m_rendered_data_buffer);
688     GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() failed");
689 
690     /* Verify result data */
691     bool result = true;
692 
693     for (glw::GLuint n_pixel = 0; n_pixel < (m_rendered_data_buffer_size >> 2); n_pixel += m_n_components)
694     {
695         glw::GLubyte expected_result_ubyte[] = {
696             (glw::GLubyte)(m_clear_color[0] * 255.0f), (glw::GLubyte)(m_clear_color[1] * 255.0f),
697             (glw::GLubyte)(m_clear_color[2] * 255.0f), (glw::GLubyte)(m_clear_color[3] * 255.0f)};
698         glw::GLubyte rendered_result_ubyte[] = {
699             m_rendered_data_buffer[n_pixel + 0], m_rendered_data_buffer[n_pixel + 1],
700             m_rendered_data_buffer[n_pixel + 2], m_rendered_data_buffer[n_pixel + 3]};
701 
702         if (memcmp(expected_result_ubyte, rendered_result_ubyte, sizeof(rendered_result_ubyte)) != 0)
703         {
704             m_testCtx.getLog() << tcu::TestLog::Message << "Rendered pixel at index (" << n_pixel
705                                << ") of value"
706                                   " ("
707                                << rendered_result_ubyte[0] << ", " << rendered_result_ubyte[1] << ", "
708                                << rendered_result_ubyte[2] << ", " << rendered_result_ubyte[3]
709                                << ") does not match expected pixel"
710                                   " ("
711                                << expected_result_ubyte[0] << ", " << expected_result_ubyte[1] << ", "
712                                << expected_result_ubyte[2] << ", " << expected_result_ubyte[3] << ")"
713                                << tcu::TestLog::EndMessage;
714 
715             result = false;
716 
717             break;
718         } /* if (rendered pixel is invalid) */
719     }     /* for (all pixels) */
720 
721     return result;
722 }
723 
724 /** Executes the test.
725  *
726  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
727  *
728  *  Note the function throws exception should an error occur!
729  *
730  *  @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
731  **/
iterate(void)732 tcu::TestNode::IterateResult TessellationShaderPrimitiveCoverage::iterate(void)
733 {
734     /* Retriveing GL. */
735     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
736 
737     /* Initialize test */
738     initTest();
739 
740     bool has_test_passed = true;
741 
742     /* Define tessellation level values that we will use to draw single tessellated primitive */
743     const glw::GLfloat inner_tess_levels_single[] = {1.0f, 1.0f};
744     const glw::GLfloat outer_tess_levels_single[] = {1.0f, 1.0f, 1.0f, 1.0f};
745 
746     /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
747     glw::GLint gl_max_tess_gen_level_value = 0;
748 
749     gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
750     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
751 
752     /* Verify no cracks can be found if a degenerate triangle
753      * is outputted by the tessellator */
754     drawPatch(m_triangles_tessellation_po_id, 3 /* n_patch_vertices */, 3 /* n_triangle_vertices */,
755               inner_tess_levels_single, outer_tess_levels_single);
756 
757     has_test_passed &= verifyDrawBufferContents();
758 
759     /* Verify no cracks can be found if multiple triangles
760      * are outputted by the tessellator.
761      */
762     _tessellation_levels_set levels_sets = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
763         TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, gl_max_tess_gen_level_value,
764         TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
765 
766     for (_tessellation_levels_set_const_iterator set_iterator = levels_sets.begin(); set_iterator != levels_sets.end();
767          set_iterator++)
768     {
769         const _tessellation_levels &set = *set_iterator;
770 
771         drawPatch(m_triangles_tessellation_po_id, 3 /* n_patch_vertices */, 3 /* n_triangle_vertices */, set.inner,
772                   set.outer);
773 
774         has_test_passed &= verifyDrawBufferContents();
775     }
776 
777     /* Verify no cracks can be found if a degenerate quad
778      * is outputted by the tessellator.
779      */
780     drawPatch(m_quad_tessellation_po_id, 4 /* n_patch_vertices */, 6 /* n_triangle_vertices (quad == 2 triangles) */,
781               inner_tess_levels_single, outer_tess_levels_single);
782 
783     has_test_passed &= verifyDrawBufferContents();
784 
785     /* Verify no cracks can be found if multiple triangles
786      * (to which the generated quads will be broken into)
787      * are outputted by the tessellator.
788      */
789     levels_sets = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
790         TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, gl_max_tess_gen_level_value,
791         TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
792 
793     for (_tessellation_levels_set_const_iterator set_iterator = levels_sets.begin(); set_iterator != levels_sets.end();
794          set_iterator++)
795     {
796         const _tessellation_levels &set = *set_iterator;
797 
798         drawPatch(m_quad_tessellation_po_id, 4 /* n_patch_vertices */,
799                   6 /* n_triangle_vertices (quad == 2 triangles) */, set.inner, set.outer);
800         has_test_passed &= verifyDrawBufferContents();
801     }
802 
803     /* Has the test passed? */
804     if (has_test_passed)
805     {
806         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
807     }
808     else
809     {
810         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
811     }
812 
813     return STOP;
814 }
815 
816 } /* namespace glcts */
817