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 /* Sanity 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[] = { (glw::GLubyte)(m_clear_color[0] * 255.0f),
696 (glw::GLubyte)(m_clear_color[1] * 255.0f),
697 (glw::GLubyte)(m_clear_color[2] * 255.0f),
698 (glw::GLubyte)(m_clear_color[3] * 255.0f) };
699 glw::GLubyte rendered_result_ubyte[] = { m_rendered_data_buffer[n_pixel + 0],
700 m_rendered_data_buffer[n_pixel + 1],
701 m_rendered_data_buffer[n_pixel + 2],
702 m_rendered_data_buffer[n_pixel + 3] };
703
704 if (memcmp(expected_result_ubyte, rendered_result_ubyte, sizeof(rendered_result_ubyte)) != 0)
705 {
706 m_testCtx.getLog() << tcu::TestLog::Message << "Rendered pixel at index (" << n_pixel << ") of value"
707 " ("
708 << rendered_result_ubyte[0] << ", " << rendered_result_ubyte[1] << ", "
709 << rendered_result_ubyte[2] << ", " << rendered_result_ubyte[3]
710 << ") does not match expected pixel"
711 " ("
712 << expected_result_ubyte[0] << ", " << expected_result_ubyte[1] << ", "
713 << expected_result_ubyte[2] << ", " << expected_result_ubyte[3] << ")"
714 << tcu::TestLog::EndMessage;
715
716 result = false;
717
718 break;
719 } /* if (rendered pixel is invalid) */
720 } /* for (all pixels) */
721
722 return result;
723 }
724
725 /** Executes the test.
726 *
727 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
728 *
729 * Note the function throws exception should an error occur!
730 *
731 * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
732 **/
iterate(void)733 tcu::TestNode::IterateResult TessellationShaderPrimitiveCoverage::iterate(void)
734 {
735 /* Retriveing GL. */
736 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
737
738 /* Initialize test */
739 initTest();
740
741 bool has_test_passed = true;
742
743 /* Define tessellation level values that we will use to draw single tessellated primitive */
744 const glw::GLfloat inner_tess_levels_single[] = { 1.0f, 1.0f };
745 const glw::GLfloat outer_tess_levels_single[] = { 1.0f, 1.0f, 1.0f, 1.0f };
746
747 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
748 glw::GLint gl_max_tess_gen_level_value = 0;
749
750 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
751 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
752
753 /* Verify no cracks can be found if a degenerate triangle
754 * is outputted by the tessellator */
755 drawPatch(m_triangles_tessellation_po_id, 3 /* n_patch_vertices */, 3 /* n_triangle_vertices */,
756 inner_tess_levels_single, outer_tess_levels_single);
757
758 has_test_passed &= verifyDrawBufferContents();
759
760 /* Verify no cracks can be found if multiple triangles
761 * are outputted by the tessellator.
762 */
763 _tessellation_levels_set levels_sets = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
764 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES, gl_max_tess_gen_level_value,
765 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
766
767 for (_tessellation_levels_set_const_iterator set_iterator = levels_sets.begin(); set_iterator != levels_sets.end();
768 set_iterator++)
769 {
770 const _tessellation_levels& set = *set_iterator;
771
772 drawPatch(m_triangles_tessellation_po_id, 3 /* n_patch_vertices */, 3 /* n_triangle_vertices */, set.inner,
773 set.outer);
774
775 has_test_passed &= verifyDrawBufferContents();
776 }
777
778 /* Verify no cracks can be found if a degenerate quad
779 * is outputted by the tessellator.
780 */
781 drawPatch(m_quad_tessellation_po_id, 4 /* n_patch_vertices */, 6 /* n_triangle_vertices (quad == 2 triangles) */,
782 inner_tess_levels_single, outer_tess_levels_single);
783
784 has_test_passed &= verifyDrawBufferContents();
785
786 /* Verify no cracks can be found if multiple triangles
787 * (to which the generated quads will be broken into)
788 * are outputted by the tessellator.
789 */
790 levels_sets = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
791 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, gl_max_tess_gen_level_value,
792 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
793
794 for (_tessellation_levels_set_const_iterator set_iterator = levels_sets.begin(); set_iterator != levels_sets.end();
795 set_iterator++)
796 {
797 const _tessellation_levels& set = *set_iterator;
798
799 drawPatch(m_quad_tessellation_po_id, 4 /* n_patch_vertices */,
800 6 /* n_triangle_vertices (quad == 2 triangles) */, set.inner, set.outer);
801 has_test_passed &= verifyDrawBufferContents();
802 }
803
804 /* Has the test passed? */
805 if (has_test_passed)
806 {
807 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
808 }
809 else
810 {
811 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
812 }
813
814 return STOP;
815 }
816
817 } /* namespace glcts */
818