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 "esextcTessellationShaderTessellation.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluDefs.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuTestLog.hpp"
30 #include <cstdlib>
31
32 namespace glcts
33 {
34
35 /** Vertex shader source code for max_in_out_attributes test. */
36 const char* TessellationShaderTessellationMaxInOut::m_vs_code =
37 "${VERSION}\n"
38 "\n"
39 "${TESSELLATION_SHADER_REQUIRE}\n"
40 "${SHADER_IO_BLOCKS_ENABLE}\n"
41 "\n"
42 "precision highp float;\n"
43 "\n"
44 "layout(location = 0) in vec4 in_fv;\n"
45 "\n"
46 "out Vertex\n"
47 "{\n"
48 " /* Note: we need to leave some space for gl_Position */\n"
49 " vec4 value[(gl_MaxTessControlInputComponents) / 4 - 1];\n"
50 "} outVertex;\n"
51 "\n"
52 "void main()\n"
53 "{\n"
54 " gl_Position = in_fv;\n"
55 "\n"
56 " for (int i = 0 ; i < (gl_MaxTessControlInputComponents - "
57 "4) / 4 ; i++)\n" /* Max vec4 output attributes - gl_Position */
58 " {\n"
59 " outVertex.value[i] = vec4(float(4*i), float(4*i) + "
60 "1.0, float(4*i) + 2.0, float(4*i) + 3.0);\n"
61 " }\n"
62 "}\n";
63
64 /* Tessellation Control Shader code for max_in_out_attributes test */
65 const char* TessellationShaderTessellationMaxInOut::m_tcs_code_1 =
66 "${VERSION}\n"
67 "\n"
68 "${TESSELLATION_SHADER_REQUIRE}\n"
69 "\n"
70 "precision highp float;\n"
71 "\n"
72 "layout(vertices = 2) out;\n"
73 "\n"
74 "in Vertex\n"
75 "{\n"
76 " /* Note: we need to leave some space for gl_Position */\n"
77 " vec4 value[(gl_MaxTessControlInputComponents - 4) / 4];\n"
78 "} inVertex[];\n"
79 "\n"
80 "out Vertex\n"
81 "{\n"
82 " /* Note: we need to leave some space for gl_Position */\n"
83 " vec4 value[(gl_MaxTessControlOutputComponents - 4) / 4];\n"
84 "} outVariables[];\n"
85 "\n"
86 "void main()\n"
87 "{\n"
88 " gl_TessLevelInner[0] = 1.0;\n"
89 " gl_TessLevelInner[1] = 1.0;\n"
90 " gl_TessLevelOuter[0] = 1.0;\n"
91 " gl_TessLevelOuter[1] = 1.0;\n"
92 " gl_TessLevelOuter[2] = 1.0;\n"
93 " gl_TessLevelOuter[3] = 1.0;\n"
94 "\n"
95 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
96 "\n"
97 " for (int j = 0; j < (gl_MaxTessControlOutputComponents - 4) / 4; j++)\n"
98 " {\n"
99 " outVariables[gl_InvocationID].value[j] = vec4(float(4*j), float(4*j) + 1.0, float(4*j) + 2.0, float(4*j) "
100 "+ 3.0);\n"
101 "\n"
102 " for (int i = 0; i < (gl_MaxTessControlInputComponents-4)/4; i++)\n"
103 " {\n"
104 " outVariables[gl_InvocationID].value[j] += inVertex[gl_InvocationID].value[i];\n"
105 " }\n"
106 " }\n"
107 "}\n";
108
109 /* Tessellation Control Shader code for max_in_out_attributes test */
110 const char* TessellationShaderTessellationMaxInOut::m_tcs_code_2 =
111 "${VERSION}\n"
112 "\n"
113 "${TESSELLATION_SHADER_REQUIRE}\n"
114 "\n"
115 "precision highp float;\n"
116 "\n"
117 "layout(vertices = 2) out;\n"
118 "\n"
119 "patch out vec4 value[gl_MaxTessPatchComponents/4];\n"
120 "\n"
121 "void main()\n"
122 "{\n"
123 " gl_TessLevelInner[0] = 1.0;\n"
124 " gl_TessLevelInner[1] = 1.0;\n"
125 " gl_TessLevelOuter[0] = 1.0;\n"
126 " gl_TessLevelOuter[1] = 1.0;\n"
127 " gl_TessLevelOuter[2] = 1.0;\n"
128 " gl_TessLevelOuter[3] = 1.0;\n"
129 "\n"
130 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
131 "\n"
132 " for (int j = 0; j < gl_MaxTessPatchComponents / 4; j++)\n"
133 " {\n"
134 " value[j] = vec4(float(4*j), float(4*j) + 1.0, float(4*j) + 2.0, float(4*j) + 3.0);\n"
135 " }\n"
136 "}\n";
137
138 /* Tessellation Evaluation Shader code for max_in_out_attributes test */
139 const char* TessellationShaderTessellationMaxInOut::m_tes_code_1 =
140 "${VERSION}\n"
141 "\n"
142 "${TESSELLATION_SHADER_REQUIRE}\n"
143 "\n"
144 "precision highp float;\n"
145 "\n"
146 "layout (isolines, point_mode) in;\n"
147 "\n"
148 "in Vertex\n"
149 "{\n"
150 " vec4 value[(gl_MaxTessEvaluationInputComponents - 4) / 4];\n"
151 "} inVariables[];\n"
152 "\n"
153 "out Vertex\n"
154 "{\n"
155 " vec4 value[(gl_MaxTessEvaluationOutputComponents - 4) / 4];\n"
156 "} outVariables;\n"
157 "\n"
158 "void main()\n"
159 "{\n"
160 " gl_Position = gl_in[0].gl_Position;\n"
161 "\n"
162 " for (int j = 0; j < (gl_MaxTessEvaluationOutputComponents - 4) / 4; j++)\n"
163 " {\n"
164 " outVariables.value[j] = vec4(float(4*j), float(4*j) + 1.0, float(4*j) + 2.0, float(4*j) + 3.0);\n"
165 "\n"
166 " for (int i = 0 ; i < (gl_MaxTessEvaluationInputComponents - 4) / 4; i++)\n"
167 " {\n"
168 " outVariables.value[j] += inVariables[0].value[i];\n"
169 " }\n"
170 " }\n"
171 "}\n";
172
173 /* Tessellation Evaluation Shader code for max_in_out_attributes test */
174 const char* TessellationShaderTessellationMaxInOut::m_tes_code_2 =
175 "${VERSION}\n"
176 "\n"
177 "${TESSELLATION_SHADER_REQUIRE}\n"
178 "\n"
179 "precision highp float;\n"
180 "\n"
181 "layout (isolines, point_mode) in;\n"
182 "\n"
183 "patch in vec4 value[gl_MaxTessPatchComponents / 4];\n"
184 "\n"
185 "out vec4 out_value;\n"
186 "\n"
187 "void main()\n"
188 "{\n"
189 " gl_Position = gl_in[0].gl_Position;\n"
190 " out_value = vec4(0.0);\n"
191 "\n"
192 " for (int i = 0; i < gl_MaxTessPatchComponents / 4; i++)\n"
193 " {\n"
194 " out_value += value[i];\n"
195 " }\n"
196 "}\n";
197
198 /* Fragment Shader code for max_in_out_attributes test */
199 const char* TessellationShaderTessellationMaxInOut::m_fs_code = "${VERSION}\n"
200 "\n"
201 "void main()\n"
202 "{\n"
203 "}\n";
204
205 /** Constructor
206 *
207 * @param context Test context
208 **/
TessellationShaderTessellationTests(glcts::Context & context,const ExtParameters & extParams)209 TessellationShaderTessellationTests::TessellationShaderTessellationTests(glcts::Context& context,
210 const ExtParameters& extParams)
211 : TestCaseGroupBase(context, extParams, "tessellation_shader_tessellation",
212 "Verifies general tessellation functionality")
213 {
214 /* No implementation needed */
215 }
216
217 /**
218 * Initializes test groups for geometry shader tests
219 **/
init(void)220 void TessellationShaderTessellationTests::init(void)
221 {
222 addChild(
223 new glcts::TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID(m_context, m_extParams));
224 addChild(
225 new glcts::TessellationShaderTessellationgl_TessCoord(m_context, m_extParams, TESSELLATION_TEST_TYPE_TCS_TES));
226 addChild(new glcts::TessellationShaderTessellationgl_TessCoord(m_context, m_extParams, TESSELLATION_TEST_TYPE_TES));
227 addChild(new glcts::TessellationShaderTessellationInputPatchDiscard(m_context, m_extParams));
228 addChild(new glcts::TessellationShaderTessellationMaxInOut(m_context, m_extParams));
229 }
230
231 /** Constructor
232 *
233 * @param context Test context
234 **/
TessellationShaderTessellationInputPatchDiscard(Context & context,const ExtParameters & extParams)235 TessellationShaderTessellationInputPatchDiscard::TessellationShaderTessellationInputPatchDiscard(
236 Context& context, const ExtParameters& extParams)
237 : TestCaseBase(context, extParams, "input_patch_discard",
238 "Verifies that patches, for which relevant outer tessellation levels have"
239 " been defined to 0 or less, are discard by the tessellation primitive "
240 " generator.")
241 , m_bo_id(0)
242 , m_fs_id(0)
243 , m_vs_id(0)
244 , m_vao_id(0)
245 , m_utils_ptr(0)
246 {
247 /* Left blank on purpose */
248 }
249
250 /** Deinitializes ES objects created for the test. */
deinit()251 void TessellationShaderTessellationInputPatchDiscard::deinit()
252 {
253 /* Call base class' deinit() */
254 TestCaseBase::deinit();
255
256 if (!m_is_tessellation_shader_supported)
257 {
258 return;
259 }
260
261 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
262
263 /* Remove TF buffer object bindings */
264 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
265 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
266
267 /* Disable GL_RASTERIZER_DISCARD mode */
268 gl.disable(GL_RASTERIZER_DISCARD);
269
270 /* Restore GL_PATCH_VERTICES_EXT value */
271 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
272
273 /* Unbind vertex array object */
274 gl.bindVertexArray(0);
275
276 /* Free all ES objects we allocated for the test */
277 if (m_bo_id != 0)
278 {
279 gl.deleteBuffers(1, &m_bo_id);
280
281 m_bo_id = 0;
282 }
283
284 if (m_fs_id != 0)
285 {
286 gl.deleteShader(m_fs_id);
287
288 m_fs_id = 0;
289 }
290
291 if (m_vs_id != 0)
292 {
293 gl.deleteShader(m_vs_id);
294
295 m_vs_id = 0;
296 }
297
298 if (m_vao_id != 0)
299 {
300 gl.deleteVertexArrays(1, &m_vao_id);
301
302 m_vao_id = 0;
303 }
304
305 /* Deinitialize all test descriptors */
306 for (_runs::iterator it = m_runs.begin(); it != m_runs.end(); ++it)
307 {
308 deinitRun(*it);
309 }
310 m_runs.clear();
311
312 /* Release tessellation shader test utilities instance */
313 if (m_utils_ptr != NULL)
314 {
315 delete m_utils_ptr;
316
317 m_utils_ptr = NULL;
318 }
319 }
320
321 /** Deinitialize all test pass-specific ES objects.
322 *
323 * @param test Descriptor of a test pass to deinitialize.
324 **/
deinitRun(_run & run)325 void TessellationShaderTessellationInputPatchDiscard::deinitRun(_run& run)
326 {
327 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
328
329 if (run.po_id != 0)
330 {
331 gl.deleteProgram(run.po_id);
332
333 run.po_id = 0;
334 }
335
336 if (run.tc_id != 0)
337 {
338 gl.deleteShader(run.tc_id);
339
340 run.tc_id = 0;
341 }
342
343 if (run.te_id != 0)
344 {
345 gl.deleteShader(run.te_id);
346
347 run.te_id = 0;
348 }
349 }
350
351 /** Returns source code of a tessellation control shader for the test.
352 *
353 * @return Requested string.
354 **/
getTCCode()355 std::string TessellationShaderTessellationInputPatchDiscard::getTCCode()
356 {
357 std::string result;
358
359 result = "${VERSION}\n"
360 "\n"
361 "${TESSELLATION_SHADER_REQUIRE}\n"
362 "\n"
363 "layout(vertices = 2) out;\n"
364 "\n"
365 "out int tc_primitive_id[];\n"
366 "\n"
367 "void main()\n"
368 "{\n"
369 " if ((gl_PrimitiveID % 4) == 0)\n"
370 " {\n"
371 " gl_TessLevelOuter[0] = 0.0;\n"
372 " gl_TessLevelOuter[1] = 0.0;\n"
373 " gl_TessLevelOuter[2] = 0.0;\n"
374 " gl_TessLevelOuter[3] = 0.0;\n"
375 " }\n"
376 " else\n"
377 " if ((gl_PrimitiveID % 4) == 2)\n"
378 " {\n"
379 " gl_TessLevelOuter[0] = -1.0;\n"
380 " gl_TessLevelOuter[1] = -1.0;\n"
381 " gl_TessLevelOuter[2] = -1.0;\n"
382 " gl_TessLevelOuter[3] = -1.0;\n"
383 " }\n"
384 " else\n"
385 " {\n"
386 " gl_TessLevelOuter[0] = 1.0;\n"
387 " gl_TessLevelOuter[1] = 1.0;\n"
388 " gl_TessLevelOuter[2] = 1.0;\n"
389 " gl_TessLevelOuter[3] = 1.0;\n"
390 " }\n"
391 "\n"
392 " gl_TessLevelInner[0] = 1.0;\n"
393 " gl_TessLevelInner[1] = 1.0;\n"
394 " gl_out [gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
395 " tc_primitive_id [gl_InvocationID] = gl_PrimitiveID;\n"
396 "}\n";
397
398 return result;
399 }
400
401 /** Returns source code of a tessellation evaluation shader for the test,
402 * given user-specified vertex spacing and primitive modes.
403 *
404 * Throws TestError exception if either of the arguments is invalid.
405 *
406 * @param primitive_mode Primitive mode to use in the shader.
407 *
408 * @return Requested string.
409 **/
getTECode(_tessellation_primitive_mode primitive_mode)410 std::string TessellationShaderTessellationInputPatchDiscard::getTECode(_tessellation_primitive_mode primitive_mode)
411 {
412 std::string result = "${VERSION}\n"
413 "\n"
414 "${TESSELLATION_SHADER_REQUIRE}\n"
415 "\n"
416 "layout(PRIMITIVE_MODE) in;\n"
417 "\n"
418 "in int tc_primitive_id [];\n"
419 "out ivec2 te_tc_primitive_id;\n"
420 "out int te_primitive_id;\n"
421 "\n"
422 "void main()\n"
423 "{\n"
424 " te_tc_primitive_id[0] = tc_primitive_id[0];\n"
425 " te_tc_primitive_id[1] = tc_primitive_id[1];\n"
426 " te_primitive_id = gl_PrimitiveID;\n"
427 "}\n";
428
429 /* Replace PRIMITIVE_MODE token with actual primitive_mode */
430 std::string primitive_mode_string = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
431 const char* primitive_mode_token = "PRIMITIVE_MODE";
432 std::size_t primitive_mode_token_index = std::string::npos;
433
434 while ((primitive_mode_token_index = result.find(primitive_mode_token)) != std::string::npos)
435 {
436 result = result.replace(primitive_mode_token_index, strlen(primitive_mode_token), primitive_mode_string);
437
438 primitive_mode_token_index = result.find(primitive_mode_token);
439 }
440
441 /* Done */
442 return result;
443 }
444
445 /** Initializes ES objects necessary to run the test. */
initTest()446 void TessellationShaderTessellationInputPatchDiscard::initTest()
447 {
448 /* Skip if required extensions are not supported. */
449 if (!m_is_tessellation_shader_supported)
450 {
451 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
452 }
453
454 /* Generate all test-wide objects needed for test execution */
455 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
456 m_utils_ptr = new TessellationShaderUtils(gl, this);
457
458 gl.genVertexArrays(1, &m_vao_id);
459 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
460
461 gl.bindVertexArray(m_vao_id);
462 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
463
464 gl.genBuffers(1, &m_bo_id);
465 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
466
467 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
468 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
469 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
470
471 /* Configure fragment shader body */
472 const char* fs_body = "${VERSION}\n"
473 "\n"
474 "void main()\n"
475 "{\n"
476 "}\n";
477
478 shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
479 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
480
481 /* Configure vertex shader body */
482 const char* vs_body = "${VERSION}\n"
483 "\n"
484 "void main()\n"
485 "{\n"
486 " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
487 "}\n";
488
489 shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
490 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
491
492 /* Compile all the shaders */
493 const glw::GLuint shaders[] = { m_fs_id, m_vs_id };
494 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
495
496 m_utils_ptr->compileShaders(n_shaders, shaders, true);
497
498 /* Initialize all the runs. */
499 const _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
500 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
501 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
502 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
503
504 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
505 {
506 /* Initialize the run */
507 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
508 _run run;
509
510 initRun(run, primitive_mode);
511
512 /* Store the run */
513 m_runs.push_back(run);
514 } /* for (all primitive modes) */
515
516 /* Set up buffer object bindings. Storage size will be determined on
517 * a per-iteration basis.
518 **/
519 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
520 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
521
522 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
523 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
524 }
525
526 /** Initializes all ES objects necessary to run a specific test pass.
527 *
528 * Throws TestError exception if any of the arguments is found invalid.
529 *
530 * @param run Run descriptor to fill with IDs of initialized objects.
531 * @param primitive_mode Primitive mode to use for the pass.
532 **/
initRun(_run & run,_tessellation_primitive_mode primitive_mode)533 void TessellationShaderTessellationInputPatchDiscard::initRun(_run& run, _tessellation_primitive_mode primitive_mode)
534 {
535 run.primitive_mode = primitive_mode;
536
537 /* Set up a program object for the descriptor */
538 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
539
540 run.po_id = gl.createProgram();
541 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
542
543 /* Set up tessellation shader objects. */
544 run.tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
545 run.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
546
547 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
548
549 /* Configure tessellation control shader body */
550 std::string tc_body = getTCCode();
551 const char* tc_body_raw_ptr = tc_body.c_str();
552
553 shaderSourceSpecialized(run.tc_id, 1 /* count */, &tc_body_raw_ptr);
554 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
555
556 /* Configure tessellation evaluation shader body */
557 std::string te_body = getTECode(primitive_mode);
558 const char* te_body_raw_ptr = te_body.c_str();
559
560 shaderSourceSpecialized(run.te_id, 1 /* count */, &te_body_raw_ptr);
561 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
562
563 /* Compile the tessellation evaluation shader */
564 glw::GLuint shaders[] = { run.tc_id, run.te_id };
565 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
566
567 m_utils_ptr->compileShaders(n_shaders, shaders, true);
568
569 /* Attach all shader to the program object */
570 gl.attachShader(run.po_id, m_fs_id);
571 gl.attachShader(run.po_id, run.tc_id);
572 gl.attachShader(run.po_id, run.te_id);
573 gl.attachShader(run.po_id, m_vs_id);
574
575 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
576
577 /* Set up XFB */
578 const char* varyings[] = { "te_tc_primitive_id", "te_primitive_id" };
579 const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
580
581 gl.transformFeedbackVaryings(run.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
582 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
583
584 /* Link the program object */
585 glw::GLint link_status = GL_FALSE;
586
587 gl.linkProgram(run.po_id);
588 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
589
590 gl.getProgramiv(run.po_id, GL_LINK_STATUS, &link_status);
591 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
592
593 if (link_status != GL_TRUE)
594 {
595 TCU_FAIL("Program linking failed");
596 }
597 }
598
599 /** Executes the test.
600 *
601 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
602 *
603 * Note the function throws exception should an error occur!
604 *
605 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
606 **/
iterate(void)607 tcu::TestNode::IterateResult TessellationShaderTessellationInputPatchDiscard::iterate(void)
608 {
609 /* Do not execute if required extensions are not supported. */
610 if (!m_is_tessellation_shader_supported)
611 {
612 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
613 }
614
615 /* Initialize ES test objects */
616 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
617
618 initTest();
619
620 /* We don't need rasterization for this test */
621 gl.enable(GL_RASTERIZER_DISCARD);
622 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
623
624 /* Configure amount of vertices per input patch */
625 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
626 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
627
628 /* Iterate through all tests configured */
629 for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
630 {
631 const _run& run = *run_iterator;
632
633 /* Set up XFB target BO storage size. Each input patch will generate:
634 *
635 * a) 1 ivec2 and 1 int IF it is an odd patch;
636 * b) 0 bytes otherwise.
637 *
638 * This gives us a total of 2 * (sizeof(int)*2 + sizeof(int)) = 24 bytes per result coordinate,
639 * assuming it does not get discarded along the way.
640 *
641 * Amount of vertices that TE processes is mode-dependent. Note that for 'quads' we use 6 instead
642 * of 4 because the geometry will be broken down to triangles (1 quad = 2 triangles = 6 vertices)
643 * later in the pipeline.
644 */
645 const unsigned int n_total_primitives = 4;
646 const unsigned int n_vertices_per_patch =
647 ((run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES) ?
648 2 :
649 (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 6 : 3);
650 const unsigned int n_bytes_per_result_vertex = sizeof(int) + 2 * sizeof(int);
651 const unsigned int n_bytes_needed = (n_total_primitives / 2) * n_vertices_per_patch * n_bytes_per_result_vertex;
652
653 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, n_bytes_needed, NULL, /* data */
654 GL_STATIC_DRAW);
655 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
656
657 /* Activate the program object */
658 gl.useProgram(run.po_id);
659 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
660
661 /* Draw the test geometry. */
662 glw::GLenum tf_mode =
663 TessellationShaderUtils::getTFModeForPrimitiveMode(run.primitive_mode, false); /* is_point_mode_enabled */
664
665 gl.beginTransformFeedback(tf_mode);
666 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed.");
667
668 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* vertices per patch */ * n_total_primitives);
669 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
670
671 gl.endTransformFeedback();
672 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
673
674 /* Map the BO with result data into user space */
675 int* result_data = (int*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
676 n_bytes_needed, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
677
678 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
679
680 /* Verification is based on the following reasoning:
681 *
682 * a) Both TC and TE stages should operate on the same primitive IDs (no re-ordering
683 * of the IDs is allowed)
684 * b) Under test-specific configuration, tessellator will output 2 line segments (4 coordinates).
685 * Two first two coordinates will be generated during tessellation of the second primitive,
686 * and the other two coordinates will be generated during tessellation of the fourth primitive
687 * (out of all four primitives that will enter the pipeline).
688 * c) In case of quads, 6 first coordinates will be generated during tessellation of the second primitive,
689 * and the other six will be generated during tessellation of the fourth primitive.
690 * d) Finally, tessellator will output 2 triangles (6 coordinates). The first three coordinates will
691 * be generated during tessellation of the second primitive, and the other two for the fourth
692 * primitive.
693 * */
694 const int expected_primitive_ids[] = {
695 1, /* second primitive */
696 3 /* fourth primitive */
697 };
698 const unsigned int n_expected_primitive_ids =
699 sizeof(expected_primitive_ids) / sizeof(expected_primitive_ids[0]);
700 const unsigned int n_expected_repetitions =
701 (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES) ?
702 2 :
703 (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 6 : 3;
704 const int* traveller_ptr = result_data;
705
706 for (unsigned int n_primitive_id = 0; n_primitive_id < n_expected_primitive_ids; ++n_primitive_id)
707 {
708 int expected_primitive_id = expected_primitive_ids[n_primitive_id];
709
710 for (unsigned int n_repetition = 0; n_repetition < n_expected_repetitions; ++n_repetition)
711 {
712 for (unsigned int n_integer = 0; n_integer < 3 /* ivec2 + int */; ++n_integer)
713 {
714 if (*traveller_ptr != expected_primitive_id)
715 {
716 std::string primitive_mode_string =
717 TessellationShaderUtils::getESTokenForPrimitiveMode(run.primitive_mode);
718
719 m_testCtx.getLog() << tcu::TestLog::Message << "For primitive mode: " << primitive_mode_string
720 << " invalid gl_PrimitiveID of value " << *traveller_ptr
721 << " was found instead of expected " << expected_primitive_id
722 << " at index:" << n_primitive_id * 3 /* ivec2 + int */ + n_integer
723 << tcu::TestLog::EndMessage;
724
725 TCU_FAIL("Discard mechanism failed");
726 }
727
728 traveller_ptr++;
729 } /* for (all captured integers) */
730 } /* for (all repetitions) */
731 } /* for (all non-discarded primitive ids) */
732
733 /* Clear the buffer storage space before we unmap it */
734 memset(result_data, 0, n_bytes_needed);
735
736 /* Unmap the BO */
737 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
738 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
739 }
740
741 /* All done */
742 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
743 return STOP;
744 }
745
746 /** Constructor
747 *
748 * @param context Test context
749 **/
750 TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::
TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID(Context & context,const ExtParameters & extParams)751 TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID(Context& context,
752 const ExtParameters& extParams)
753 : TestCaseBase(context, extParams, "gl_InvocationID_PatchVerticesIn_PrimitiveID",
754 "Verifies that gl_InvocationID, gl_PatchVerticesIn and gl_PrimitiveID "
755 "are assigned correct values in TC and TE stages (where appropriate), "
756 "when invoked with arrayed and indiced draw calls. Also verifies that "
757 "restarting primitive topology does not restart primitive ID counter.")
758 , m_bo_id(0)
759 , m_fs_id(0)
760 , m_vs_id(0)
761 , m_vao_id(0)
762 , m_utils_ptr(0)
763 {
764 /* Left blank on purpose */
765 }
766
767 /** Deinitializes ES objects created for the test. */
deinit()768 void TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::deinit()
769 {
770 /* Call base class' deinit() */
771 TestCaseBase::deinit();
772
773 if (!m_is_tessellation_shader_supported)
774 {
775 return;
776 }
777
778 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
779
780 /* Disable modes this test has enabled */
781 gl.disable(GL_RASTERIZER_DISCARD);
782 GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) failed");
783
784 gl.disable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
785 GLU_EXPECT_NO_ERROR(gl.getError(), "glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX) failed");
786
787 /* Remove TF buffer object bindings */
788 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
789 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
790
791 /* Restore GL_PATCH_VERTICES_EXT value */
792 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
793
794 /* Unbind vertex array object */
795 gl.bindVertexArray(0);
796
797 /* Free all ES objects we allocated for the test */
798 if (m_bo_id != 0)
799 {
800 gl.deleteBuffers(1, &m_bo_id);
801
802 m_bo_id = 0;
803 }
804
805 if (m_fs_id != 0)
806 {
807 gl.deleteShader(m_fs_id);
808
809 m_fs_id = 0;
810 }
811
812 if (m_vs_id != 0)
813 {
814 gl.deleteShader(m_vs_id);
815
816 m_vs_id = 0;
817 }
818
819 if (m_vao_id != 0)
820 {
821 gl.deleteVertexArrays(1, &m_vao_id);
822
823 m_vao_id = 0;
824 }
825
826 /* Deinitialize all run descriptors */
827 for (_runs::iterator it = m_runs.begin(); it != m_runs.end(); ++it)
828 {
829 deinitRun(*it);
830 }
831 m_runs.clear();
832
833 /* Release tessellation shader test utilities instance */
834 if (m_utils_ptr != NULL)
835 {
836 delete m_utils_ptr;
837
838 m_utils_ptr = NULL;
839 }
840 }
841
842 /** Deinitialize all test pass-specific ES objects.
843 *
844 * @param test Descriptor of a test pass to deinitialize.
845 **/
deinitRun(_run & run)846 void TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::deinitRun(_run& run)
847 {
848 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
849
850 if (run.bo_indices_id != 0)
851 {
852 gl.deleteBuffers(1, &run.bo_indices_id);
853
854 run.bo_indices_id = 0;
855 }
856
857 if (run.po_id != 0)
858 {
859 gl.deleteProgram(run.po_id);
860
861 run.po_id = 0;
862 }
863
864 if (run.tc_id != 0)
865 {
866 gl.deleteShader(run.tc_id);
867
868 run.tc_id = 0;
869 }
870
871 if (run.te_id != 0)
872 {
873 gl.deleteShader(run.te_id);
874
875 run.te_id = 0;
876 }
877 }
878
879 /** Returns source code of a tessellation control shader.
880 *
881 * @param n_patch_vertices Amount of vertices per patch to
882 * output in TC stage;
883 *
884 * @return Requested string.
885 **/
getTCCode(glw::GLuint n_patch_vertices)886 std::string TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::getTCCode(
887 glw::GLuint n_patch_vertices)
888 {
889 static const char* tc_body =
890 "${VERSION}\n"
891 "\n"
892 "${TESSELLATION_SHADER_REQUIRE}\n"
893 "\n"
894 "layout(vertices = N_PATCH_VERTICES) out;\n"
895 "\n"
896 "out TC_OUT\n"
897 "{\n"
898 " int tc_invocation_id;\n"
899 " int tc_patch_vertices_in;\n"
900 " int tc_primitive_id;\n"
901 "} out_te[];\n"
902 "\n"
903 "void main()\n"
904 "{\n"
905 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
906 " out_te[gl_InvocationID].tc_invocation_id = gl_InvocationID;\n"
907 " out_te[gl_InvocationID].tc_patch_vertices_in = gl_PatchVerticesIn;\n"
908 " out_te[gl_InvocationID].tc_primitive_id = gl_PrimitiveID;\n"
909 "\n"
910 " gl_TessLevelInner[0] = 4.0;\n"
911 " gl_TessLevelInner[1] = 4.0;\n"
912 " gl_TessLevelOuter[0] = 4.0;\n"
913 " gl_TessLevelOuter[1] = 4.0;\n"
914 " gl_TessLevelOuter[2] = 4.0;\n"
915 " gl_TessLevelOuter[3] = 4.0;\n"
916 "}\n";
917
918 /* Construct a string out of user-provided integer value */
919 std::stringstream n_patch_vertices_sstream;
920 std::string n_patch_vertices_string;
921
922 n_patch_vertices_sstream << n_patch_vertices;
923 n_patch_vertices_string = n_patch_vertices_sstream.str();
924
925 /* Replace N_PATCH_VERTICES with user-provided value */
926 std::string result = tc_body;
927 const std::string token = "N_PATCH_VERTICES";
928 std::size_t token_index = std::string::npos;
929
930 while ((token_index = result.find(token)) != std::string::npos)
931 {
932 result = result.replace(token_index, token.length(), n_patch_vertices_string.c_str());
933
934 token_index = result.find(token);
935 }
936
937 return result;
938 }
939
940 /** Returns source code of a tessellation evaluation shader for the test,
941 * given user-specified primitive mode.
942 *
943 * Throws TestError exception if either of the arguments is invalid.
944 *
945 * @param primitive_mode Primitive mode to use in the shader.
946 *
947 * @return Requested string.
948 **/
getTECode(_tessellation_primitive_mode primitive_mode)949 std::string TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::getTECode(
950 _tessellation_primitive_mode primitive_mode)
951 {
952 static const char* te_body = "${VERSION}\n"
953 "\n"
954 "${TESSELLATION_SHADER_REQUIRE}\n"
955 "\n"
956 "layout(PRIMITIVE_MODE) in;\n"
957 "\n"
958 "in TC_OUT\n"
959 "{\n"
960 " int tc_invocation_id;\n"
961 " int tc_patch_vertices_in;\n"
962 " int tc_primitive_id;\n"
963 "} in_tc[];\n"
964 "\n"
965 "out int te_tc_invocation_id;\n"
966 "out int te_tc_patch_vertices_in;\n"
967 "out int te_tc_primitive_id;\n"
968 "out int te_patch_vertices_in;\n"
969 "out int te_primitive_id;\n"
970 "\n"
971 "void main()\n"
972 "{\n"
973 " te_tc_invocation_id = in_tc[gl_PatchVerticesIn-1].tc_invocation_id;\n"
974 " te_tc_patch_vertices_in = in_tc[gl_PatchVerticesIn-1].tc_patch_vertices_in;\n"
975 " te_tc_primitive_id = in_tc[gl_PatchVerticesIn-1].tc_primitive_id;\n"
976 " te_patch_vertices_in = gl_PatchVerticesIn;\n"
977 " te_primitive_id = gl_PrimitiveID;\n"
978 "}";
979
980 /* Replace PRIMITIVE_MODE with user-provided value */
981 std::string primitive_mode_string = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
982 std::string result = te_body;
983 const std::string token = "PRIMITIVE_MODE";
984 std::size_t token_index = std::string::npos;
985
986 while ((token_index = result.find(token)) != std::string::npos)
987 {
988 result = result.replace(token_index, token.length(), primitive_mode_string.c_str());
989
990 token_index = result.find(token);
991 }
992
993 return result;
994 }
995
996 /** Initializes ES objects necessary to run the test. */
initTest()997 void TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::initTest()
998 {
999 /* Skip if required extensions are not supported. */
1000 if (!m_is_tessellation_shader_supported)
1001 {
1002 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
1003 }
1004
1005 /* Set up Utils instance */
1006 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1007
1008 m_utils_ptr = new TessellationShaderUtils(gl, this);
1009
1010 /* Initialize vertex array object */
1011 gl.genVertexArrays(1, &m_vao_id);
1012 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
1013
1014 gl.bindVertexArray(m_vao_id);
1015 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
1016
1017 /* Generate all test-wide objects needed for test execution */
1018 gl.genBuffers(1, &m_bo_id);
1019 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
1020
1021 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
1022 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1023 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
1024
1025 /* Configure fragment shader body */
1026 const char* fs_body = "${VERSION}\n"
1027 "\n"
1028 "void main()\n"
1029 "{\n"
1030 "}\n";
1031
1032 shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
1033 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
1034
1035 /* Configure vertex shader body */
1036 const char* vs_body = "${VERSION}\n"
1037 "\n"
1038 "in vec4 vertex_data;\n"
1039 "\n"
1040 "void main()\n"
1041 "{\n"
1042 " gl_Position = vertex_data;\n"
1043 "}\n";
1044
1045 shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
1046 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
1047
1048 /* Compile all the shaders */
1049 const glw::GLuint shaders[] = { m_fs_id, m_vs_id };
1050 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
1051
1052 m_utils_ptr->compileShaders(n_shaders, shaders, true /* should_succeed */);
1053
1054 /* Retrieve GL_MAX_PATCH_VERTICES_EXT value before we continue */
1055 glw::GLint gl_max_patch_vertices_value = 0;
1056
1057 gl.getIntegerv(m_glExtTokens.MAX_PATCH_VERTICES, &gl_max_patch_vertices_value);
1058 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_PATCH_VERTICES_EXT pname");
1059
1060 /* Initialize all test passes */
1061 const unsigned int drawcall_count_multipliers[] = { 3, 6 };
1062 const bool is_indiced_draw_call_flags[] = { false, true };
1063 const glw::GLint n_instances[] = { 1, 4 };
1064 const glw::GLint n_patch_vertices[] = { 4, gl_max_patch_vertices_value / 2, gl_max_patch_vertices_value };
1065 const _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
1066 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
1067 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
1068 const unsigned int n_drawcall_count_multipliers =
1069 sizeof(drawcall_count_multipliers) / sizeof(drawcall_count_multipliers[0]);
1070 const unsigned int n_is_indiced_draw_call_flags =
1071 sizeof(is_indiced_draw_call_flags) / sizeof(is_indiced_draw_call_flags[0]);
1072 const unsigned int n_n_instances = sizeof(n_instances) / sizeof(n_instances[0]);
1073 const unsigned int n_n_patch_vertices = sizeof(n_patch_vertices) / sizeof(n_patch_vertices[0]);
1074 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
1075
1076 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
1077 {
1078 _tessellation_primitive_mode current_primitive_mode = primitive_modes[n_primitive_mode];
1079
1080 for (unsigned int n_patch_vertices_item = 0; n_patch_vertices_item < n_n_patch_vertices;
1081 ++n_patch_vertices_item)
1082 {
1083 glw::GLint current_n_patch_vertices = n_patch_vertices[n_patch_vertices_item];
1084
1085 for (unsigned int n_is_indiced_draw_call_flag = 0;
1086 n_is_indiced_draw_call_flag < n_is_indiced_draw_call_flags; ++n_is_indiced_draw_call_flag)
1087 {
1088 bool current_is_indiced_draw_call = is_indiced_draw_call_flags[n_is_indiced_draw_call_flag];
1089
1090 for (unsigned int n_instances_item = 0; n_instances_item < n_n_instances; ++n_instances_item)
1091 {
1092 glw::GLint current_n_instances = n_instances[n_instances_item];
1093
1094 for (unsigned int n_drawcall_count_multiplier = 0;
1095 n_drawcall_count_multiplier < n_drawcall_count_multipliers; ++n_drawcall_count_multiplier)
1096 {
1097 const unsigned int drawcall_count_multiplier =
1098 drawcall_count_multipliers[n_drawcall_count_multiplier];
1099
1100 /* Form the run descriptor */
1101 _run run;
1102
1103 initRun(run, current_primitive_mode, current_n_patch_vertices, current_is_indiced_draw_call,
1104 current_n_instances, drawcall_count_multiplier);
1105
1106 /* Store the descriptor for later execution */
1107 m_runs.push_back(run);
1108 }
1109 } /* for (all 'number of instances' settings) */
1110 } /* for (all 'is indiced draw call' flags) */
1111 } /* for (all 'n patch vertices' settings) */
1112 } /* for (all primitive modes) */
1113
1114 /* Set up buffer object bindings. Storage size will be determined on
1115 * a per-iteration basis.
1116 **/
1117 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
1118 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
1119
1120 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
1121 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
1122 }
1123
1124 /** Initializes all ES objects necessary to run a specific test pass.
1125 *
1126 * Throws TestError exception if any of the arguments is found invalid.
1127 *
1128 * @param run Test run descriptor to fill with IDs of initialized objects.
1129 * @param primitive_mode Primitive mode to use for the pass.
1130 * @param n_patch_vertices Amount of output patch vertices to use for the pass.
1131 * @param is_indiced true if the draw call to be used for the test run should be indiced;
1132 * false to use the non-indiced one.
1133 * @param n_instances Amount of instances to use for the draw call. Set to 1 if the draw
1134 * call should be non-instanced.
1135 * @param drawcall_count_multiplier Will be used to multiply the "count" argument of the draw call API
1136 * function, effectively multiplying amount of primitives that will be
1137 * generated by the tessellator.
1138 **/
initRun(_run & run,_tessellation_primitive_mode primitive_mode,glw::GLint n_patch_vertices,bool is_indiced,glw::GLint n_instances,unsigned int drawcall_count_multiplier)1139 void TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::initRun(
1140 _run& run, _tessellation_primitive_mode primitive_mode, glw::GLint n_patch_vertices, bool is_indiced,
1141 glw::GLint n_instances, unsigned int drawcall_count_multiplier)
1142 {
1143 run.drawcall_count_multiplier = drawcall_count_multiplier;
1144 run.drawcall_is_indiced = is_indiced;
1145 run.n_instances = n_instances;
1146 run.n_patch_vertices = n_patch_vertices;
1147 run.primitive_mode = primitive_mode;
1148
1149 /* Set up a program object for the descriptor */
1150 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1151
1152 run.po_id = gl.createProgram();
1153 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
1154
1155 /* Set up tessellation control shader object */
1156 std::string tc_body = getTCCode(n_patch_vertices);
1157 const char* tc_body_raw_ptr = tc_body.c_str();
1158
1159 run.tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
1160 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
1161
1162 shaderSourceSpecialized(run.tc_id, 1 /* count */, &tc_body_raw_ptr);
1163 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
1164
1165 /* Set up tessellation evaluation shader object. */
1166 std::string te_body = getTECode(primitive_mode);
1167 const char* te_body_raw_ptr = te_body.c_str();
1168
1169 run.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
1170 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call failed");
1171
1172 shaderSourceSpecialized(run.te_id, 1 /* count */, &te_body_raw_ptr);
1173 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
1174
1175 /* Compile the shaders */
1176 const glw::GLuint shader_ids[] = { run.tc_id, run.te_id };
1177 const unsigned int n_shader_ids = sizeof(shader_ids) / sizeof(shader_ids[0]);
1178
1179 m_utils_ptr->compileShaders(n_shader_ids, shader_ids, true /* should_succeed */);
1180
1181 /* Attach all shader to the program object */
1182 gl.attachShader(run.po_id, m_fs_id);
1183 gl.attachShader(run.po_id, run.te_id);
1184 gl.attachShader(run.po_id, m_vs_id);
1185 gl.attachShader(run.po_id, run.tc_id);
1186
1187 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
1188
1189 /* Set up XFB */
1190 const char* varyings[] = { "te_tc_invocation_id", "te_tc_patch_vertices_in", "te_tc_primitive_id",
1191 "te_patch_vertices_in", "te_primitive_id" };
1192 const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
1193
1194 gl.transformFeedbackVaryings(run.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
1195 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
1196
1197 /* Link the program object */
1198 glw::GLint link_status = GL_FALSE;
1199
1200 gl.linkProgram(run.po_id);
1201 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
1202
1203 gl.getProgramiv(run.po_id, GL_LINK_STATUS, &link_status);
1204 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
1205
1206 if (link_status != GL_TRUE)
1207 {
1208 TCU_FAIL("Program linking failed");
1209 }
1210
1211 /* If this is going to be an indiced draw call, we need to initialize a buffer
1212 * object that will hold index data. GL_UNSIGNED_BYTE index type will be always
1213 * used for the purpose of this test.
1214 */
1215 if (is_indiced)
1216 {
1217 gl.genBuffers(1, &run.bo_indices_id);
1218 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
1219
1220 /* Implementations are allowed NOT to support primitive restarting for patches.
1221 * Take this into account and do not insert restart indices, if ES reports no
1222 * support.
1223 */
1224 glw::GLboolean is_primitive_restart_supported = GL_TRUE;
1225
1226 gl.getBooleanv(GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, &is_primitive_restart_supported);
1227 GLU_EXPECT_NO_ERROR(gl.getError(),
1228 "glGetIntegerv() failed for GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED pname");
1229
1230 /* Set up index buffer storage. Note that we're not using any attributes
1231 * in any stage - our goal is just to make sure the primitive counter does
1232 * not restart whenever restart index is encountered during a draw call */
1233 DE_ASSERT(run.n_patch_vertices > 3);
1234 DE_ASSERT(run.drawcall_count_multiplier > 1);
1235
1236 const unsigned int interleave_rate = run.n_patch_vertices * 2;
1237 unsigned char* bo_contents = DE_NULL;
1238 unsigned int bo_size =
1239 static_cast<unsigned int>(sizeof(unsigned char) * run.n_patch_vertices * run.drawcall_count_multiplier);
1240
1241 /* Count in restart indices if necessary */
1242 if (is_primitive_restart_supported)
1243 {
1244 run.n_restart_indices = (bo_size / interleave_rate);
1245 bo_size += 1 /* restart index */ * run.n_restart_indices;
1246 }
1247
1248 /* Allocate space for the index buffer */
1249 bo_contents = new unsigned char[bo_size];
1250
1251 /* Interleave the restart index every two complete sets of vertices, each set
1252 * making up a full set of vertices. Fill all other indices with zeros. The
1253 * indices don't really matter since test shaders do not use any attributes -
1254 * what we want to verify is that the restart index does not break the primitive
1255 * id counter.
1256 *
1257 * NOTE: Our interleave rate is just an arbitrary value that makes
1258 * sense, given the multipliers we use for the test */
1259 const unsigned char restart_index = 0xFF;
1260
1261 memset(bo_contents, 0, bo_size);
1262
1263 if (is_primitive_restart_supported)
1264 {
1265 for (unsigned int n_index = interleave_rate; n_index < bo_size; n_index += interleave_rate)
1266 {
1267 bo_contents[n_index] = restart_index;
1268
1269 /* Move one index ahead */
1270 n_index++;
1271 }
1272 }
1273
1274 /* Set up the buffer object storage */
1275 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, run.bo_indices_id);
1276 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
1277
1278 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, bo_size, bo_contents, GL_STATIC_DRAW);
1279 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
1280
1281 /* Release the buffer */
1282 delete[] bo_contents;
1283
1284 bo_contents = NULL;
1285 }
1286
1287 /* Retrieve amount of tessellation coordinates.
1288 *
1289 * Note: this test assumes a constant tessellation level value of 4 for all
1290 * inner/outer tessellation levels */
1291 const glw::GLfloat tess_levels[] = { 4.0f, 4.0f, 4.0f, 4.0f };
1292
1293 run.n_result_vertices = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
1294 run.primitive_mode, tess_levels, tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1295 false); /* is_point_mode_enabled */
1296
1297 /* The value we have at this point is for single patch only. To end up
1298 * with actual amount of coordinates that will be generated by the tessellator,
1299 * we need to multiply it by drawcall_count_multiplier * n_instances */
1300 run.n_result_vertices *= run.drawcall_count_multiplier * run.n_instances;
1301
1302 /* We're done! */
1303 }
1304
1305 /** Executes the test.
1306 *
1307 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1308 *
1309 * Note the function throws exception should an error occur!
1310 *
1311 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
1312 **/
iterate(void)1313 tcu::TestNode::IterateResult TessellationShaderTessellationgl_InvocationID_PatchVerticesIn_PrimitiveID::iterate(void)
1314 {
1315 /* Do not execute if required extensions are not supported. */
1316 if (!m_is_tessellation_shader_supported)
1317 {
1318 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
1319 }
1320
1321 /* Initialize ES test objects */
1322 initTest();
1323
1324 /* Initialize tessellation shader utilities */
1325 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1326
1327 /* We don't need rasterization for this test */
1328 gl.enable(GL_RASTERIZER_DISCARD);
1329 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
1330
1331 /* Enable GL_PRIMITIVE_RESTART_FIXED_INDEX mode for indiced draw calls. */
1332 gl.enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
1333 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX) failed.");
1334
1335 /* Iterate through all test runs configured */
1336 for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
1337 {
1338 const _run& run = *run_iterator;
1339
1340 /* Configure run-specific amount of vertices per patch */
1341 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, run.n_patch_vertices);
1342 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
1343
1344 /* Activate run-specific program object */
1345 gl.useProgram(run.po_id);
1346 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
1347
1348 /* Update GL_ELEMENT_ARRAY_BUFFER binding, depending on run properties */
1349 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, (run.drawcall_is_indiced) ? run.bo_indices_id : 0);
1350 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not update GL_ELEMENT_ARRAY_BUFFER binding");
1351
1352 /* Update transform feedback buffer bindings */
1353 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
1354 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
1355
1356 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
1357 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
1358
1359 /* Update the transform feedback buffer object storage. For each generated
1360 * tessellated coordinate, TE stage will output 5 integers. */
1361 glw::GLint bo_size = static_cast<glw::GLint>(run.n_result_vertices * 5 /* ints */ * sizeof(int));
1362
1363 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, GL_STATIC_DRAW);
1364 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
1365
1366 /* Render the geometry */
1367 glw::GLint drawcall_count = run.n_patch_vertices * run.drawcall_count_multiplier + run.n_restart_indices;
1368 glw::GLenum tf_mode =
1369 TessellationShaderUtils::getTFModeForPrimitiveMode(run.primitive_mode, false); /* is_point_mode_enabled */
1370
1371 gl.beginTransformFeedback(tf_mode);
1372 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed");
1373 {
1374 if (run.drawcall_is_indiced)
1375 {
1376 if (run.n_instances != 1)
1377 {
1378 gl.drawElementsInstanced(m_glExtTokens.PATCHES, drawcall_count, GL_UNSIGNED_BYTE,
1379 DE_NULL, /* indices */
1380 run.n_instances);
1381 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElementsInstanced() failed");
1382 } /* if (run.n_instances != 0) */
1383 else
1384 {
1385 gl.drawElements(m_glExtTokens.PATCHES, drawcall_count, GL_UNSIGNED_BYTE, DE_NULL); /* indices */
1386 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElements() failed");
1387 }
1388 } /* if (run.drawcall_is_indiced) */
1389 else
1390 {
1391 if (run.n_instances != 1)
1392 {
1393 gl.drawArraysInstanced(m_glExtTokens.PATCHES, 0, /* first */
1394 drawcall_count, run.n_instances);
1395 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArraysInstanced() failed");
1396 }
1397 else
1398 {
1399 gl.drawArrays(m_glExtTokens.PATCHES, 0, /* first */
1400 drawcall_count);
1401 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
1402 }
1403 }
1404 }
1405 gl.endTransformFeedback();
1406 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
1407
1408 /* Map the result buffer object */
1409 const int* result_data = (const int*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
1410 bo_size, GL_MAP_READ_BIT);
1411
1412 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
1413
1414 /* Verify gl_InvocationID values used in both stages were correct. In TE:
1415 *
1416 * te_tc_invocation_id = in_tc[gl_PatchVerticesIn-1].tc_invocation_id;
1417 *
1418 * In the list of varyings passed to glTransformFeedbackVaryings(),
1419 * te_tc_invocation_id is the very first item, so no need to offset
1420 * result_data when initializing result_traveller_ptr below.
1421 */
1422 const unsigned int n_int_varyings_per_tess_coordinate = 5;
1423 const int* result_traveller_ptr = result_data;
1424
1425 for (unsigned int n_coordinate = 0; n_coordinate < run.n_result_vertices;
1426 ++n_coordinate, result_traveller_ptr += n_int_varyings_per_tess_coordinate)
1427 {
1428 const int expected_invocation_id = run.n_patch_vertices - 1;
1429 const int invocation_id_value = *result_traveller_ptr;
1430
1431 if (invocation_id_value != expected_invocation_id)
1432 {
1433 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_InvocationID value (" << invocation_id_value
1434 << ") "
1435 "was found for result coordinate at index "
1436 << n_coordinate << " "
1437 "instead of expected value ("
1438 << expected_invocation_id << ")." << tcu::TestLog::EndMessage;
1439
1440 TCU_FAIL("Invalid gl_InvocationID value used in TC stage");
1441 }
1442 } /* for (all result coordinates) */
1443
1444 /* Verify gl_PrimitiveID values used in both stages were correct. In TE:
1445 *
1446 * te_tc_primitive_id = in_tc[gl_PatchVerticesIn-1].tc_primitive_id;
1447 * te_primitive_id = gl_PrimitiveID;
1448 *
1449 * In the list of varyings passed to glTransformFeedbackVaryings(),
1450 * te_tc_primitive_id is passed as 3rd string and te_primitive_id is located on
1451 * 5th location.
1452 */
1453 const unsigned int n_result_vertices_per_patch_vertex_batch =
1454 run.n_result_vertices / run.drawcall_count_multiplier / run.n_instances;
1455 const unsigned int n_result_vertices_per_instance = run.n_result_vertices / run.n_instances;
1456
1457 for (unsigned int n_coordinate = 0; n_coordinate < run.n_result_vertices; ++n_coordinate)
1458 {
1459 unsigned int actual_n_coordinate = n_coordinate;
1460
1461 /* Subsequent instances reset gl_PrimitiveID counter */
1462 while (actual_n_coordinate >= n_result_vertices_per_instance)
1463 {
1464 actual_n_coordinate -= n_result_vertices_per_instance;
1465 }
1466
1467 /* Calculate expected gl_PrimitiveID value */
1468 const int expected_primitive_id = actual_n_coordinate / n_result_vertices_per_patch_vertex_batch;
1469
1470 /* te_tc_primitive_id */
1471 result_traveller_ptr =
1472 result_data + n_coordinate * n_int_varyings_per_tess_coordinate + 2; /* as per comment */
1473
1474 if (*result_traveller_ptr != expected_primitive_id)
1475 {
1476 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PrimitiveID value (" << *result_traveller_ptr
1477 << ") "
1478 "was used in TC stage instead of expected value ("
1479 << expected_primitive_id << ") "
1480 " as stored for result coordinate at index "
1481 << n_coordinate << "." << tcu::TestLog::EndMessage;
1482
1483 TCU_FAIL("Invalid gl_PrimitiveID value used in TC stage");
1484 }
1485
1486 /* te_primitive_id */
1487 result_traveller_ptr =
1488 result_data + n_coordinate * n_int_varyings_per_tess_coordinate + 4; /* as per comment */
1489
1490 if (*result_traveller_ptr != expected_primitive_id)
1491 {
1492 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PrimitiveID value (" << *result_traveller_ptr
1493 << ") "
1494 "was used in TE stage instead of expected value ("
1495 << expected_primitive_id << ") "
1496 " as stored for result coordinate at index "
1497 << n_coordinate << "." << tcu::TestLog::EndMessage;
1498
1499 TCU_FAIL("Invalid gl_PrimitiveID value used in TE stage");
1500 }
1501 } /* for (all result coordinates) */
1502
1503 /* Verify gl_PatchVerticesIn values used in both stages were correct. In TE:
1504 *
1505 * te_tc_patch_vertices_in = in_tc[gl_PatchVerticesIn-1].tc_patch_vertices_in;
1506 * te_patch_vertices_in = gl_PatchVerticesIn;
1507 *
1508 * In the list of varyings passed to glTransformFeedbackVaryings(),
1509 * te_tc_patch_vertices_in takes 2nd location and te_patch_vertices_in is
1510 * located at 4th position.
1511 *
1512 **/
1513 for (unsigned int n_coordinate = 0; n_coordinate < run.n_result_vertices; ++n_coordinate)
1514 {
1515 const int expected_patch_vertices_in_value = run.n_patch_vertices;
1516
1517 /* te_tc_patch_vertices_in */
1518 result_traveller_ptr =
1519 result_data + n_coordinate * n_int_varyings_per_tess_coordinate + 1; /* as per comment */
1520
1521 if (*result_traveller_ptr != expected_patch_vertices_in_value)
1522 {
1523 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PatchVerticesIn value ("
1524 << *result_traveller_ptr << ") "
1525 "was used in TC stage instead of expected value ("
1526 << expected_patch_vertices_in_value << ") "
1527 " as stored for result coordinate at index "
1528 << n_coordinate << "." << tcu::TestLog::EndMessage;
1529
1530 TCU_FAIL("Invalid gl_PatchVerticesIn value used in TC stage");
1531 }
1532
1533 /* te_patch_vertices_in */
1534 result_traveller_ptr =
1535 result_data + n_coordinate * n_int_varyings_per_tess_coordinate + 3; /* as per comment */
1536
1537 if (*result_traveller_ptr != expected_patch_vertices_in_value)
1538 {
1539 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PatchVerticesIn value ("
1540 << *result_traveller_ptr << ") "
1541 "was used in TE stage instead of expected value ("
1542 << expected_patch_vertices_in_value << ") "
1543 " as stored for result coordinate at index "
1544 << n_coordinate << "." << tcu::TestLog::EndMessage;
1545 }
1546 } /* for (all result coordinates) */
1547
1548 /* Unmap the buffer object - we're done with this iteration */
1549 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1550 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed");
1551 } /* for (all runs) */
1552
1553 /* All done */
1554 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1555 return STOP;
1556 }
1557
getTypeName(_tessellation_test_type test_type)1558 std::string TessellationShaderTessellationgl_TessCoord::getTypeName(_tessellation_test_type test_type)
1559 {
1560 static const char* names[2] = { "TCS_TES", "TES" };
1561 DE_ASSERT(0 <= test_type && test_type <= DE_LENGTH_OF_ARRAY(names));
1562 DE_STATIC_ASSERT(0 == TESSELLATION_TEST_TYPE_TCS_TES && 1 == TESSELLATION_TEST_TYPE_TES);
1563 return names[test_type];
1564 }
1565
1566 /** Constructor
1567 *
1568 * @param context Test context
1569 **/
TessellationShaderTessellationgl_TessCoord(Context & context,const ExtParameters & extParams,_tessellation_test_type test_type)1570 TessellationShaderTessellationgl_TessCoord::TessellationShaderTessellationgl_TessCoord(
1571 Context& context, const ExtParameters& extParams, _tessellation_test_type test_type)
1572 : TestCaseBase(context, extParams, getTypeName(test_type).c_str(),
1573 "Verifies that u, v, w components of gl_TessCoord are within "
1574 "range for a variety of input/outer tessellation level combinations "
1575 "for all primitive modes. Verifies each component is within valid "
1576 " range. Also checks that w is always equal to 0 for isolines mode.")
1577 , m_test_type(test_type)
1578 , m_bo_id(0)
1579 , m_broken_ts_id(0)
1580 , m_fs_id(0)
1581 , m_vs_id(0)
1582 , m_vao_id(0)
1583 , m_utils_ptr(0)
1584 {
1585 /* Left blank on purpose */
1586 }
1587
1588 /** Deinitializes ES objects created for the test. */
deinit()1589 void TessellationShaderTessellationgl_TessCoord::deinit()
1590 {
1591 /* Call base class' deinit() */
1592 TestCaseBase::deinit();
1593
1594 if (!m_is_tessellation_shader_supported)
1595 {
1596 return;
1597 }
1598
1599 if (glu::isContextTypeES(m_context.getRenderContext().getType()) && m_test_type == TESSELLATION_TEST_TYPE_TES)
1600 {
1601 return;
1602 }
1603
1604 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1605
1606 /* Revert buffer object bindings */
1607 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
1608 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
1609
1610 /* Disable GL_RASTERIZER_DISCARD mode */
1611 gl.disable(GL_RASTERIZER_DISCARD);
1612
1613 /* Restore GL_PATCH_VERTICES_EXT, GL_PATCH_DEFAULT_INNER_LEVEL and
1614 * GL_PATCH_DEFAULT_OUTER_LEVEL values */
1615 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
1616 {
1617 const float default_tess_levels[] = { 1.0f, 1.0f, 1.0f, 1.0f };
1618 gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, default_tess_levels);
1619 gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, default_tess_levels);
1620 }
1621 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
1622
1623 /* Unbind vertex array object */
1624 gl.bindVertexArray(0);
1625
1626 /* Free all ES objects we allocated for the test */
1627 if (m_bo_id != 0)
1628 {
1629 gl.deleteBuffers(1, &m_bo_id);
1630
1631 m_bo_id = 0;
1632 }
1633
1634 if (m_broken_ts_id != 0)
1635 {
1636 gl.deleteShader(m_broken_ts_id);
1637
1638 m_broken_ts_id = 0;
1639 }
1640
1641 if (m_fs_id != 0)
1642 {
1643 gl.deleteShader(m_fs_id);
1644
1645 m_fs_id = 0;
1646 }
1647
1648 if (m_vs_id != 0)
1649 {
1650 gl.deleteShader(m_vs_id);
1651
1652 m_vs_id = 0;
1653 }
1654
1655 if (m_vao_id != 0)
1656 {
1657 gl.deleteVertexArrays(1, &m_vao_id);
1658
1659 m_vao_id = 0;
1660 }
1661
1662 /* Deinitialize all test descriptors */
1663 for (_tests::iterator it = m_tests.begin(); it != m_tests.end(); ++it)
1664 {
1665 deinitTestDescriptor(*it);
1666 }
1667 m_tests.clear();
1668
1669 /* Release tessellation shader test utilities instance */
1670 if (m_utils_ptr != NULL)
1671 {
1672 delete m_utils_ptr;
1673
1674 m_utils_ptr = NULL;
1675 }
1676 }
1677
1678 /** Deinitialize all test pass-specific ES objects.
1679 *
1680 * @param test Descriptor of a test pass to deinitialize.
1681 **/
deinitTestDescriptor(_test_descriptor & test)1682 void TessellationShaderTessellationgl_TessCoord::deinitTestDescriptor(_test_descriptor& test)
1683 {
1684 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1685
1686 if (test.po_id != 0)
1687 {
1688 gl.deleteProgram(test.po_id);
1689
1690 test.po_id = 0;
1691 }
1692
1693 if (test.tc_id != 0)
1694 {
1695 gl.deleteShader(test.tc_id);
1696
1697 test.tc_id = 0;
1698 }
1699
1700 if (test.te_id != 0)
1701 {
1702 gl.deleteShader(test.te_id);
1703
1704 test.te_id = 0;
1705 }
1706 }
1707
1708 /** Returns source code of a tessellation control shader for the test,
1709 * given user-specified amount of output patch vertices.
1710 *
1711 * @param n_patch_vertices Amount of output patch vertices for TC stage.
1712 *
1713 * @return Requested string.
1714 **/
getTCCode(glw::GLint n_patch_vertices)1715 std::string TessellationShaderTessellationgl_TessCoord::getTCCode(glw::GLint n_patch_vertices)
1716 {
1717 return TessellationShaderUtils::getGenericTCCode(n_patch_vertices, true);
1718 }
1719
1720 /** Returns source code of a tessellation evaluation shader for the test,
1721 * given user-specified vertex spacing and primitive modes.
1722 *
1723 * Throws TestError exception if either of the arguments is invalid.
1724 *
1725 * @param vertex_spacing Vertex spacing mode to use in the shader.
1726 * @param primitive_mode Primitive mode to use in the shader.
1727 *
1728 * @return Requested string.
1729 **/
getTECode(_tessellation_shader_vertex_spacing vertex_spacing,_tessellation_primitive_mode primitive_mode)1730 std::string TessellationShaderTessellationgl_TessCoord::getTECode(_tessellation_shader_vertex_spacing vertex_spacing,
1731 _tessellation_primitive_mode primitive_mode)
1732 {
1733 return TessellationShaderUtils::getGenericTECode(vertex_spacing, primitive_mode,
1734 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, false);
1735 }
1736
1737 /** Initializes ES objects necessary to run the test. */
initTest()1738 void TessellationShaderTessellationgl_TessCoord::initTest()
1739 {
1740 /* Skip if required extensions are not supported. */
1741 if (!m_is_tessellation_shader_supported)
1742 {
1743 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
1744 }
1745
1746 if (glu::isContextTypeES(m_context.getRenderContext().getType()) && m_test_type == TESSELLATION_TEST_TYPE_TES)
1747 {
1748 throw tcu::NotSupportedError("Test can't be run in ES context");
1749 }
1750
1751 /* Generate all test-wide objects needed for test execution */
1752 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1753
1754 gl.genVertexArrays(1, &m_vao_id);
1755 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
1756
1757 gl.bindVertexArray(m_vao_id);
1758 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
1759
1760 gl.genBuffers(1, &m_bo_id);
1761 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
1762
1763 m_broken_ts_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
1764 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
1765 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1766 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
1767
1768 /* Configure fragment shader body */
1769 const char* fs_body = "${VERSION}\n"
1770 "\n"
1771 "void main()\n"
1772 "{\n"
1773 "}\n";
1774
1775 shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
1776 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader");
1777
1778 /* Configure vertex shader body */
1779 const char* vs_body = "${VERSION}\n"
1780 "\n"
1781 "void main()\n"
1782 "{\n"
1783 " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
1784 "}\n";
1785
1786 shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
1787 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader");
1788
1789 /* Compile all the shaders */
1790 const glw::GLuint shaders[] = { m_fs_id, m_vs_id };
1791 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
1792
1793 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
1794 {
1795 glw::GLuint shader = shaders[n_shader];
1796
1797 if (shader != 0)
1798 {
1799 glw::GLint compile_status = GL_FALSE;
1800
1801 gl.compileShader(shader);
1802 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
1803
1804 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
1805 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
1806
1807 if (compile_status != GL_TRUE)
1808 {
1809 TCU_FAIL("Shader compilation failed");
1810 }
1811 }
1812 } /* for (all shaders) */
1813
1814 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value before we start looping */
1815 glw::GLint gl_max_tess_gen_level_value = 0;
1816
1817 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
1818 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
1819
1820 /* Initialize all test passes - iterate over all primitive modes supported.. */
1821 for (int primitive_mode = static_cast<int>(TESSELLATION_SHADER_PRIMITIVE_MODE_FIRST);
1822 primitive_mode != static_cast<int>(TESSELLATION_SHADER_PRIMITIVE_MODE_COUNT); primitive_mode++)
1823 {
1824 /* Iterate over all tessellation level combinations defined for current primitive mode */
1825 _tessellation_levels_set tessellation_levels = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
1826 static_cast<_tessellation_primitive_mode>(primitive_mode), gl_max_tess_gen_level_value,
1827 TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
1828
1829 for (_tessellation_levels_set_const_iterator levels_iterator = tessellation_levels.begin();
1830 levels_iterator != tessellation_levels.end(); levels_iterator++)
1831 {
1832 const _tessellation_levels& levels = *levels_iterator;
1833 _test_descriptor test;
1834
1835 initTestDescriptor(test, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
1836 static_cast<_tessellation_primitive_mode>(primitive_mode), 1, /* n_patch_vertices */
1837 levels.inner, levels.outer, m_test_type);
1838
1839 /* Store the test descriptor */
1840 m_tests.push_back(test);
1841 } /* for (all tessellation level combinations for current primitive mode) */
1842 } /* for (all primitive modes) */
1843
1844 /* Set up buffer object bindings. Storage size will be determined on
1845 * a per-iteration basis.
1846 **/
1847 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
1848 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
1849
1850 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
1851 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
1852 }
1853
1854 /** Initializes all ES objects necessary to run a specific test pass.
1855 *
1856 * Throws TestError exception if any of the arguments is found invalid.
1857 *
1858 * @param test Test descriptor to fill with IDs of initialized objects.
1859 * @param vertex_spacing Vertex spacing mode to use for the pass.
1860 * @param primitive_mode Primitive mode to use for the pass.
1861 * @param n_patch_vertices Amount of output patch vertices to use for the pass.
1862 * @param inner_tess_level Inner tessellation level values to be used for the pass.
1863 * Must not be NULL.
1864 * @param outer_tess_level Outer tessellation level values to be used for the pass.
1865 * Must not be NULL.
1866 * @param test_type Defines which tessellation stages should be defined for the pass.
1867 **/
initTestDescriptor(_test_descriptor & test,_tessellation_shader_vertex_spacing vertex_spacing,_tessellation_primitive_mode primitive_mode,glw::GLint n_patch_vertices,const float * inner_tess_level,const float * outer_tess_level,_tessellation_test_type test_type)1868 void TessellationShaderTessellationgl_TessCoord::initTestDescriptor(
1869 _test_descriptor& test, _tessellation_shader_vertex_spacing vertex_spacing,
1870 _tessellation_primitive_mode primitive_mode, glw::GLint n_patch_vertices, const float* inner_tess_level,
1871 const float* outer_tess_level, _tessellation_test_type test_type)
1872 {
1873 test.n_patch_vertices = n_patch_vertices;
1874 test.primitive_mode = primitive_mode;
1875 test.type = test_type;
1876 test.vertex_spacing = vertex_spacing;
1877
1878 memcpy(test.tess_level_inner, inner_tess_level, sizeof(float) * 2 /* components */);
1879 memcpy(test.tess_level_outer, outer_tess_level, sizeof(float) * 4 /* components */);
1880
1881 /* Set up a program object for the descriptor */
1882 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1883
1884 test.po_id = gl.createProgram();
1885 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
1886
1887 /* Set up a pass-specific tessellation shader objects. */
1888 if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
1889 {
1890 test.tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
1891 }
1892
1893 test.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
1894
1895 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
1896
1897 /* Configure tessellation control shader body */
1898 if (test.tc_id != 0)
1899 {
1900 std::string tc_body = getTCCode(n_patch_vertices);
1901 const char* tc_body_raw_ptr = tc_body.c_str();
1902
1903 shaderSourceSpecialized(test.tc_id, 1 /* count */, &tc_body_raw_ptr);
1904 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader");
1905 }
1906
1907 /* Configure tessellation evaluation shader body */
1908 std::string te_body = getTECode(vertex_spacing, primitive_mode);
1909 const char* te_body_raw_ptr = te_body.c_str();
1910
1911 shaderSourceSpecialized(test.te_id, 1 /* count */, &te_body_raw_ptr);
1912 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader");
1913
1914 /* Compile the tessellation evaluation shader */
1915 glw::GLint compile_status = GL_FALSE;
1916 glw::GLuint shaders[] = { test.tc_id, test.te_id };
1917 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
1918
1919 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
1920 {
1921 glw::GLuint shader = shaders[n_shader];
1922
1923 if (shader != 0)
1924 {
1925 gl.compileShader(shader);
1926 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed for tessellation shader");
1927
1928 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
1929 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed for tessellation shader");
1930
1931 if (compile_status != GL_TRUE)
1932 {
1933 TCU_FAIL("Tessellation shader compilation failed");
1934 }
1935 }
1936 } /* for (all shaders) */
1937
1938 /* Attach all shader to the program object */
1939 gl.attachShader(test.po_id, m_fs_id);
1940 gl.attachShader(test.po_id, test.te_id);
1941 gl.attachShader(test.po_id, m_vs_id);
1942
1943 if (test.tc_id != 0)
1944 {
1945 gl.attachShader(test.po_id, test.tc_id);
1946 }
1947
1948 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
1949
1950 /* Set up XFB */
1951 const char* varyings[] = { "result_uvw" };
1952 const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
1953
1954 gl.transformFeedbackVaryings(test.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
1955 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
1956
1957 /* Link the program object */
1958 glw::GLint link_status = GL_FALSE;
1959
1960 gl.linkProgram(test.po_id);
1961 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() failed");
1962
1963 gl.getProgramiv(test.po_id, GL_LINK_STATUS, &link_status);
1964 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
1965
1966 if (link_status != GL_TRUE)
1967 {
1968 TCU_FAIL("Program linking failed");
1969 }
1970
1971 /* If TCS stage is present, set up the corresponding uniforms as needed */
1972 if (test.type == TESSELLATION_TEST_TYPE_TCS_TES)
1973 {
1974 test.inner_tess_level_uniform_location = gl.getUniformLocation(test.po_id, "inner_tess_level");
1975 test.outer_tess_level_uniform_location = gl.getUniformLocation(test.po_id, "outer_tess_level");
1976
1977 DE_ASSERT(test.inner_tess_level_uniform_location != -1);
1978 DE_ASSERT(test.outer_tess_level_uniform_location != -1);
1979
1980 /* Now that we have the locations, let's configure the uniforms */
1981 gl.useProgram(test.po_id);
1982 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
1983
1984 gl.uniform2fv(test.inner_tess_level_uniform_location, 1, /* count */
1985 test.tess_level_inner);
1986 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
1987
1988 gl.uniform4fv(test.outer_tess_level_uniform_location, 1, /* count */
1989 test.tess_level_outer);
1990 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
1991 }
1992 }
1993
1994 /** Executes the test.
1995 *
1996 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1997 *
1998 * Note the function throws exception should an error occur!
1999 *
2000 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
2001 **/
iterate(void)2002 tcu::TestNode::IterateResult TessellationShaderTessellationgl_TessCoord::iterate(void)
2003 {
2004 /* Do not execute if required extensions are not supported. */
2005 if (!m_is_geometry_shader_extension_supported || !m_is_tessellation_shader_supported)
2006 {
2007 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
2008 }
2009
2010 /* On ES skip test configurations that don't have TCS. */
2011 if (isContextTypeES(m_context.getRenderContext().getType()) && (m_test_type == TESSELLATION_TEST_TYPE_TES))
2012 {
2013 throw tcu::NotSupportedError("Implementation requires TCS and TES be used together; skipping.");
2014 }
2015
2016 /* Initialize ES test objects */
2017 initTest();
2018
2019 /* Initialize tessellation shader utilities */
2020 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2021
2022 m_utils_ptr = new TessellationShaderUtils(gl, this);
2023
2024 /* We don't need rasterization for this test */
2025 gl.enable(GL_RASTERIZER_DISCARD);
2026 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed.");
2027
2028 /* Iterate through all tests configured */
2029 for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); test_iterator++)
2030 {
2031 const _test_descriptor& test = *test_iterator;
2032
2033 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
2034 {
2035 /* If there is no TCS defined, define inner/outer tessellation levels */
2036 if (test.type == TESSELLATION_TEST_TYPE_TES)
2037 {
2038 gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, test.tess_level_inner);
2039 GLU_EXPECT_NO_ERROR(gl.getError(),
2040 "glPatchParameterfv() failed for GL_PATCH_DEFAULT_INNER_LEVEL pname");
2041
2042 gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, test.tess_level_outer);
2043 GLU_EXPECT_NO_ERROR(gl.getError(),
2044 "glPatchParameterfv() failed for GL_PATCH_DEFAULT_OUTER_LEVEL pname");
2045 }
2046 }
2047
2048 /* Configure amount of vertices per patch */
2049 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, test.n_patch_vertices);
2050 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
2051
2052 /* Set up XFB target BO storage size. We will be capturing a total of 12 FP components per
2053 * result vertex.
2054 */
2055 unsigned int n_bytes_needed = 0;
2056 unsigned int n_result_vertices = 0;
2057
2058 n_result_vertices = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2059 test.primitive_mode, test.tess_level_inner, test.tess_level_outer, test.vertex_spacing, false);
2060 n_bytes_needed = static_cast<unsigned int>(n_result_vertices * sizeof(float) * 12 /* components */);
2061
2062 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, n_bytes_needed, NULL, /* data */
2063 GL_STATIC_DRAW);
2064 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
2065
2066 /* Activate the program object */
2067 gl.useProgram(test.po_id);
2068 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
2069
2070 /* Draw the test geometry. */
2071 glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(test.primitive_mode, false);
2072
2073 gl.beginTransformFeedback(tf_mode);
2074 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_PATCHES_EXT) failed.");
2075
2076 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, test.n_patch_vertices);
2077 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
2078
2079 gl.endTransformFeedback();
2080 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
2081
2082 /* Map the BO with result data into user space */
2083 const float* vertex_data = (const float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
2084 n_bytes_needed, GL_MAP_READ_BIT);
2085
2086 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
2087
2088 /* (test 1): Make sure that u+v+w == 1 (applicable for triangles only) */
2089 const float epsilon = 1e-5f;
2090
2091 if (test.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
2092 {
2093 for (unsigned int n_vertex = 0; n_vertex < n_result_vertices; ++n_vertex)
2094 {
2095 const float* vertex_uvw = vertex_data + 3 /* components */ * n_vertex;
2096 float sum_uvw = vertex_uvw[0] + vertex_uvw[1] + vertex_uvw[2];
2097
2098 if (de::abs(sum_uvw - 1.0f) > epsilon)
2099 {
2100 m_testCtx.getLog() << tcu::TestLog::Message << "For triangles, U+V+W coordinates outputted "
2101 "by tessellator should sum up to 1.0. Instead, the "
2102 "following coordinates:"
2103 << " (" << vertex_uvw[0] << ", " << vertex_uvw[1] << ", " << vertex_uvw[2]
2104 << ") "
2105 "sum up to "
2106 << sum_uvw << "." << tcu::TestLog::EndMessage;
2107
2108 TCU_FAIL("U+V+W coordinates do not add up to 1, even though triangle/tessellation"
2109 " was requested");
2110 }
2111 } /* for (all vertices) */
2112 } /* if (we're dealing with triangles or quads) */
2113
2114 /* (test 2): Make sure that u, v, w e <0, 1> (always applicable) */
2115 for (unsigned int n_vertex = 0; n_vertex < n_result_vertices; ++n_vertex)
2116 {
2117 const float* vertex_uvw = vertex_data + 3 /* components */ * n_vertex;
2118
2119 if (!(vertex_uvw[0] >= 0.0f && vertex_uvw[0] <= 1.0f && vertex_uvw[1] >= 0.0f && vertex_uvw[1] <= 1.0f &&
2120 vertex_uvw[2] >= 0.0f && vertex_uvw[2] <= 1.0f))
2121 {
2122 m_testCtx.getLog() << tcu::TestLog::Message
2123 << "U, V and W coordinates outputted by the tessellator should "
2124 "be within <0, 1> range. However, "
2125 << "vertex at index: " << n_vertex << "is defined by the following triple:"
2126 << " (" << vertex_uvw[0] << ", " << vertex_uvw[1] << ", " << vertex_uvw[2] << ")."
2127 << tcu::TestLog::EndMessage;
2128
2129 TCU_FAIL("U/V/W coordinate outputted by the tessellator is outside allowed range.");
2130 }
2131 } /* for (all vertices) */
2132
2133 /* (test 3): Make sure w is always zero (applicable to quads and isolines) */
2134 if (test.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS ||
2135 test.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
2136 {
2137 for (unsigned int n_vertex = 0; n_vertex < n_result_vertices; ++n_vertex)
2138 {
2139 const float* vertex_uvw = vertex_data + 3 /* components */ * n_vertex;
2140
2141 if (de::abs(vertex_uvw[2]) > epsilon)
2142 {
2143 m_testCtx.getLog() << tcu::TestLog::Message
2144 << "W coordinate should be zero for all vertices outputted "
2145 "for isolines and quads; for at least one vertex, W was "
2146 "found to be equal to: "
2147 << vertex_uvw[2] << tcu::TestLog::EndMessage;
2148
2149 TCU_FAIL("W coordinate was found to be non-zero for at least one tessellation coordinate"
2150 " generated in either quads or isolines primitive mode");
2151 }
2152 } /* for (all vertices) */
2153 } /* if (we're dealing with quads or isolines) */
2154
2155 /* Unmap the BO */
2156 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2157 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
2158 }
2159
2160 /* All done */
2161 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2162 return STOP;
2163 }
2164
2165 /** Constructor
2166 *
2167 * @param context Test context
2168 * @param name Test case's name
2169 * @param description Test case's desricption
2170 **/
TessellationShaderTessellationMaxInOut(Context & context,const ExtParameters & extParams)2171 TessellationShaderTessellationMaxInOut::TessellationShaderTessellationMaxInOut(Context& context,
2172 const ExtParameters& extParams)
2173 : TestCaseBase(context, extParams, "max_in_out_attributes",
2174 "Make sure it is possible to use up GL_MAX_TESS_*_COMPONENTS_EXT.")
2175 , m_po_id_1(0)
2176 , m_po_id_2(0)
2177 , m_fs_id(0)
2178 , m_tcs_id_1(0)
2179 , m_tcs_id_2(0)
2180 , m_tes_id_1(0)
2181 , m_tes_id_2(0)
2182 , m_vs_id_1(0)
2183 , m_vs_id_2(0)
2184 , m_tf_bo_id_1(0)
2185 , m_tf_bo_id_2(0)
2186 , m_patch_data_bo_id(0)
2187 , m_vao_id(0)
2188 , m_gl_max_tess_control_input_components_value(0)
2189 , m_gl_max_tess_control_output_components_value(0)
2190 , m_gl_max_tess_evaluation_input_components_value(0)
2191 , m_gl_max_tess_evaluation_output_components_value(0)
2192 , m_gl_max_transform_feedback_interleaved_components_value(0)
2193 , m_gl_max_tess_patch_components_value(0)
2194 , m_gl_max_vertex_output_components_value(0)
2195 , m_ref_vertex_attributes(DE_NULL)
2196 , m_tf_varyings_names(DE_NULL)
2197 {
2198 m_ref_patch_attributes[0] = 0.0f;
2199 m_ref_patch_attributes[1] = 0.0f;
2200 m_ref_patch_attributes[2] = 0.0f;
2201 m_ref_patch_attributes[3] = 0.0f;
2202 }
2203
2204 /** Deinitializes all ES objects created for the test. */
deinit(void)2205 void TessellationShaderTessellationMaxInOut::deinit(void)
2206 {
2207 /* Call base class deinitialization routine */
2208 TestCaseBase::deinit();
2209
2210 if (!m_is_tessellation_shader_supported)
2211 {
2212 return;
2213 }
2214
2215 /* Deallocate dynamic arrays */
2216 if (m_ref_vertex_attributes != DE_NULL)
2217 {
2218 free(m_ref_vertex_attributes);
2219
2220 m_ref_vertex_attributes = DE_NULL;
2221 }
2222
2223 /* Deallocate the varyings array */
2224 if (m_tf_varyings_names != DE_NULL)
2225 {
2226 for (int i = 0; i < (m_gl_max_tess_evaluation_output_components_value) / 4 - 1 /* gl_Position */; i++)
2227 {
2228 if (m_tf_varyings_names[i] != DE_NULL)
2229 {
2230 free(m_tf_varyings_names[i]);
2231
2232 m_tf_varyings_names[i] = DE_NULL;
2233 }
2234 }
2235
2236 free(m_tf_varyings_names);
2237
2238 m_tf_varyings_names = DE_NULL;
2239 }
2240
2241 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2242
2243 /* Reset GL_PATCH_VERTICES_EXT pname value */
2244 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
2245 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed!");
2246
2247 /* Unbind vertex array object */
2248 gl.bindVertexArray(0);
2249
2250 /* Release ES objects */
2251 if (m_fs_id != 0)
2252 {
2253 gl.deleteShader(m_fs_id);
2254
2255 m_fs_id = 0;
2256 }
2257
2258 if (m_po_id_1 != 0)
2259 {
2260 gl.deleteProgram(m_po_id_1);
2261
2262 m_po_id_1 = 0;
2263 }
2264
2265 if (m_po_id_2 != 0)
2266 {
2267 gl.deleteProgram(m_po_id_2);
2268
2269 m_po_id_2 = 0;
2270 }
2271
2272 if (m_tcs_id_1 != 0)
2273 {
2274 gl.deleteShader(m_tcs_id_1);
2275
2276 m_tcs_id_1 = 0;
2277 }
2278
2279 if (m_tcs_id_2 != 0)
2280 {
2281 gl.deleteShader(m_tcs_id_2);
2282
2283 m_tcs_id_2 = 0;
2284 }
2285
2286 if (m_tes_id_1 != 0)
2287 {
2288 gl.deleteShader(m_tes_id_1);
2289
2290 m_tes_id_1 = 0;
2291 }
2292
2293 if (m_tes_id_2 != 0)
2294 {
2295 gl.deleteShader(m_tes_id_2);
2296
2297 m_tes_id_2 = 0;
2298 }
2299
2300 if (m_vs_id_1 != 0)
2301 {
2302 gl.deleteShader(m_vs_id_1);
2303
2304 m_vs_id_1 = 0;
2305 }
2306
2307 if (m_vs_id_2 != 0)
2308 {
2309 gl.deleteShader(m_vs_id_2);
2310
2311 m_vs_id_2 = 0;
2312 }
2313
2314 if (m_tf_bo_id_1 != 0)
2315 {
2316 gl.deleteBuffers(1, &m_tf_bo_id_1);
2317
2318 m_tf_bo_id_1 = 0;
2319 }
2320
2321 if (m_tf_bo_id_2 != 0)
2322 {
2323 gl.deleteBuffers(1, &m_tf_bo_id_2);
2324
2325 m_tf_bo_id_2 = 0;
2326 }
2327
2328 if (m_patch_data_bo_id != 0)
2329 {
2330 gl.deleteBuffers(1, &m_patch_data_bo_id);
2331
2332 m_patch_data_bo_id = 0;
2333 }
2334
2335 if (m_vao_id != 0)
2336 {
2337 gl.deleteVertexArrays(1, &m_vao_id);
2338
2339 m_vao_id = 0;
2340 }
2341 }
2342
2343 /** Executes the test.
2344 *
2345 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
2346 *
2347 * Note the function throws exception should an error occur!
2348 *
2349 * @return STOP if the test has finished, CONTINUE to indicate iterate should be called once again.
2350 **/
iterate(void)2351 tcu::TestNode::IterateResult TessellationShaderTessellationMaxInOut::iterate(void)
2352 {
2353 /* Retrieve ES entry-points. */
2354 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2355
2356 /* Initialize test-specific ES objects. */
2357 initTest();
2358
2359 /* Execute test case 1 */
2360 gl.useProgram(m_po_id_1);
2361 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed!");
2362
2363 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
2364 m_tf_bo_id_1);
2365 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed!");
2366
2367 gl.beginTransformFeedback(GL_POINTS);
2368 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed");
2369
2370 gl.drawArrays(m_glExtTokens.PATCHES, 0, /* first */
2371 2); /* count */
2372 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
2373
2374 gl.endTransformFeedback();
2375 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
2376
2377 /* Verify the rendered data. */
2378 bool test_passed = true;
2379
2380 test_passed &= compareValues("Per-vertex components test ", m_ref_vertex_attributes,
2381 m_gl_max_tess_evaluation_output_components_value / 4);
2382
2383 /* Execute test case 2 */
2384 gl.useProgram(m_po_id_2);
2385 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed!");
2386
2387 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* index */
2388 m_tf_bo_id_2);
2389 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed!");
2390
2391 gl.beginTransformFeedback(GL_POINTS);
2392 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed");
2393
2394 gl.drawArrays(m_glExtTokens.PATCHES, 0, /* first */
2395 2); /* count */
2396 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
2397
2398 gl.endTransformFeedback();
2399 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
2400
2401 /* Verify the rendered data */
2402 test_passed &=
2403 compareValues("Per-patch components test ", m_ref_patch_attributes, 1 /* amount of output vectors */);
2404
2405 /* Test passed. */
2406 if (test_passed)
2407 {
2408 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2409 }
2410 else
2411 {
2412 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
2413 }
2414
2415 return STOP;
2416 }
2417
2418 /** Sets up buffer objects.
2419 *
2420 * Note the function throws exception should an error occur!
2421 **/
initBufferObjects(void)2422 void TessellationShaderTessellationMaxInOut::initBufferObjects(void)
2423 {
2424 /* Retrieve ES entry-points. */
2425 glw::GLint bo_size = 0;
2426 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2427
2428 /* Transform feedback buffer object for case 1 */
2429 gl.genBuffers(1, &m_tf_bo_id_1);
2430 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed!");
2431
2432 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo_id_1);
2433 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!");
2434
2435 bo_size = static_cast<glw::GLint>(2 /* vertices */
2436 * 4 /* components */
2437 * m_gl_max_tess_evaluation_output_components_value / 4 /* attributes */
2438 * sizeof(glw::GLfloat)); /* attribute size */
2439
2440 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, NULL, GL_STATIC_DRAW);
2441 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
2442
2443 /* Transform feedback buffer object for case 2 */
2444 bo_size = 2 * /* vertices */
2445 sizeof(glw::GLfloat) * 4; /* components */
2446
2447 gl.genBuffers(1, &m_tf_bo_id_2);
2448 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed!");
2449
2450 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_tf_bo_id_2);
2451 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!");
2452
2453 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, NULL, GL_STATIC_DRAW);
2454 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed");
2455
2456 /* Set up vertex data buffer storage */
2457 glw::GLfloat vertices[2 /* vertices */ * 4 /* components */];
2458
2459 bo_size = sizeof(vertices);
2460 vertices[0] = 0.f;
2461 vertices[1] = 0.f;
2462 vertices[2] = 0.f;
2463 vertices[3] = 1.f;
2464 vertices[4] = 1.f;
2465 vertices[5] = 1.f;
2466 vertices[6] = 1.f;
2467 vertices[7] = 1.f;
2468
2469 gl.genBuffers(1, &m_patch_data_bo_id);
2470 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed!");
2471
2472 gl.bindBuffer(GL_ARRAY_BUFFER, m_patch_data_bo_id);
2473 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed!");
2474
2475 gl.bufferData(GL_ARRAY_BUFFER, bo_size, vertices, GL_STATIC_DRAW);
2476 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() failed!");
2477
2478 gl.enableVertexAttribArray(0);
2479 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray() failed!");
2480
2481 gl.vertexAttribPointer(0, /* index */
2482 4, /* size */
2483 GL_FLOAT, GL_FALSE, /* normalized */
2484 0, /* stride */
2485 0); /* pointer */
2486 GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer() failed!");
2487 }
2488
2489 /** Initializes the test.
2490 *
2491 * Note the function throws exception should an error occur!
2492 **/
initProgramObjects(void)2493 void TessellationShaderTessellationMaxInOut::initProgramObjects(void)
2494 {
2495 /* Retrieve ES entry-points */
2496 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2497
2498 /* Create program objects. */
2499 m_po_id_1 = gl.createProgram();
2500 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed!");
2501
2502 m_po_id_2 = gl.createProgram();
2503 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed!");
2504
2505 /* Set up all the shader objects that will be used for the test */
2506 m_vs_id_1 = gl.createShader(GL_VERTEX_SHADER);
2507 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_VERTEX_SHADER) failed!");
2508
2509 m_vs_id_2 = gl.createShader(GL_VERTEX_SHADER);
2510 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_VERTEX_SHADER) failed!");
2511
2512 m_tcs_id_1 = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
2513 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_CONTROL_SHADER_EXT) failed!");
2514
2515 m_tcs_id_2 = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
2516 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_CONTROL_SHADER_EXT) failed!");
2517
2518 m_tes_id_1 = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
2519 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_EVALUATION_SHADER_EXT) failed!");
2520
2521 m_tes_id_2 = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
2522 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_TESS_EVALUATION_SHADER_EXT) failed!");
2523
2524 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
2525 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader(GL_FRAGMENT_SHADER) failed!");
2526
2527 /* Transform Feedback setup for case 1
2528 *
2529 * Varyings array: m_tf_varyings_names[i < m_gl_max_tess_evaluation_output_components_value / 4-1] == "Vertex.value[i]"
2530 * m_tf_varyings_names[i == m_gl_max_tess_evaluation_output_components_value / 4-1] == "gl_Position"
2531 */
2532 const char position_varying[] = "gl_Position";
2533
2534 m_tf_varyings_names = (char**)malloc((m_gl_max_tess_evaluation_output_components_value / 4) * sizeof(char*));
2535
2536 if (m_tf_varyings_names == DE_NULL)
2537 {
2538 throw tcu::ResourceError("Unable to allocate memory!");
2539 }
2540
2541 for (int i = 0; i < (m_gl_max_tess_evaluation_output_components_value) / 4 /* attributes */ - 1 /* gl_Position */;
2542 i++)
2543 {
2544 std::stringstream tf_varying_stream;
2545 const char* tf_varying_raw_ptr = DE_NULL;
2546 std::string tf_varying_string;
2547
2548 tf_varying_stream << "Vertex.value[" << i << "]";
2549 tf_varying_string = tf_varying_stream.str();
2550 tf_varying_raw_ptr = tf_varying_string.c_str();
2551
2552 m_tf_varyings_names[i] = (char*)malloc(strlen(tf_varying_raw_ptr) + 1 /* '\0' */);
2553 if (m_tf_varyings_names[i] == DE_NULL)
2554 {
2555 throw tcu::ResourceError("Unable to allocate memory!");
2556 }
2557
2558 memcpy(m_tf_varyings_names[i], tf_varying_raw_ptr, strlen(tf_varying_raw_ptr) + 1);
2559 }
2560
2561 m_tf_varyings_names[m_gl_max_tess_evaluation_output_components_value / 4 - 1 /* gl_Position */] =
2562 (char*)malloc(sizeof(position_varying));
2563 if (m_tf_varyings_names[m_gl_max_tess_evaluation_output_components_value / 4 - 1 /* gl_Position */] == DE_NULL)
2564 {
2565 throw tcu::ResourceError("Unable to allocate memory!");
2566 }
2567
2568 memcpy(m_tf_varyings_names[m_gl_max_tess_evaluation_output_components_value / 4 - 1 /* gl_Position */],
2569 position_varying, sizeof(position_varying));
2570
2571 /* Set up XFB */
2572 gl.transformFeedbackVaryings(m_po_id_1, m_gl_max_tess_evaluation_output_components_value / 4, m_tf_varyings_names,
2573 GL_INTERLEAVED_ATTRIBS);
2574 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed!");
2575
2576 /* Set up program objects */
2577 const char* vs_code_raw_ptr = m_vs_code;
2578 const char* tcs_code_1_raw_ptr = m_tcs_code_1;
2579 const char* tes_code_1_raw_ptr = m_tes_code_1;
2580 const char* tcs_code_2_raw_ptr = m_tcs_code_2;
2581 const char* tes_code_2_raw_ptr = m_tes_code_2;
2582
2583 /* Build a program object to test case 1. */
2584 if (!TessellationShaderTessellationMaxInOut::buildProgram(m_po_id_1, m_vs_id_1, 1, &vs_code_raw_ptr, m_tcs_id_1, 1,
2585 &tcs_code_1_raw_ptr, m_tes_id_1, 1, &tes_code_1_raw_ptr,
2586 m_fs_id, 1, &m_fs_code))
2587 {
2588 TCU_FAIL("Could not build first test program object");
2589 }
2590
2591 /* Tranform Feedback setup for case 2 */
2592 const char* const tf_varying_2 = "out_value";
2593
2594 gl.transformFeedbackVaryings(m_po_id_2, 1 /* count */, &tf_varying_2, GL_INTERLEAVED_ATTRIBS);
2595 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed!");
2596
2597 /* Build a program object for case 2 */
2598 if (!(TessellationShaderTessellationMaxInOut::buildProgram(m_po_id_2, m_vs_id_2, 1, &vs_code_raw_ptr, m_tcs_id_2, 1,
2599 &tcs_code_2_raw_ptr, m_tes_id_2, 1, &tes_code_2_raw_ptr,
2600 m_fs_id, 1, &m_fs_code)))
2601 {
2602 TCU_FAIL("Could not link second test program object");
2603 }
2604 }
2605
2606 /** Initializes the test.
2607 *
2608 * Note the function throws exception should an error occur!
2609 **/
initTest(void)2610 void TessellationShaderTessellationMaxInOut::initTest(void)
2611 {
2612 /* Render state setup */
2613 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2614
2615 /* Skip if required extensions are not supported. */
2616 if (!m_is_tessellation_shader_supported)
2617 {
2618 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
2619 }
2620
2621 /* Initialize vertex array object */
2622 gl.genVertexArrays(1, &m_vao_id);
2623 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
2624
2625 gl.bindVertexArray(m_vao_id);
2626 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
2627
2628 /* All tessellation control shaders used by this test assume two
2629 * vertices are going to be provided per input patch. */
2630 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 2);
2631
2632 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed!");
2633
2634 /* Carry on with initialization */
2635 retrieveGLConstantValues();
2636 initProgramObjects();
2637 initBufferObjects();
2638 initReferenceValues();
2639
2640 gl.enable(GL_RASTERIZER_DISCARD);
2641 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(RASTERIZER_DISCARD) failed!");
2642 }
2643
2644 /** Initializes reference values that will be compared against
2645 * values generated by the program object.
2646 * Fills m_ref_vertex_attributes and m_ref_patch_attributes arrays.
2647 * These arrays are later used by compareValues() function.
2648 **/
initReferenceValues(void)2649 void TessellationShaderTessellationMaxInOut::initReferenceValues(void)
2650 {
2651 /* Allocate vertex attribute array data needed for reference values preparation. */
2652 int max_array_size = de::max(m_gl_max_tess_control_input_components_value,
2653 de::max(m_gl_max_tess_control_output_components_value,
2654 de::max(m_gl_max_tess_evaluation_input_components_value,
2655 m_gl_max_tess_evaluation_output_components_value)));
2656
2657 m_ref_vertex_attributes = (glw::GLfloat*)malloc(sizeof(glw::GLfloat) * (max_array_size));
2658 if (m_ref_vertex_attributes == DE_NULL)
2659 {
2660 throw tcu::ResourceError("Unable to allocate memory!");
2661 }
2662
2663 /* We need to create an array consisting of gl_max_tess_evaluation_output_components items.
2664 * The array will be filled with the following values:
2665 *
2666 * reference_value[0],
2667 * (...)
2668 * reference_value[gl_max_tess_evaluation_output_components / 4 - 2],
2669 * reference_gl_Position
2670 *
2671 * which corresponds to output block defined for Tessellation Evaluation Stage:
2672 *
2673 * out Vertex
2674 * {
2675 * vec4 value[(gl_MaxTessControlInputComponents) / 4 - 1];
2676 * } outVertex;
2677 *
2678 * + gl_Position.
2679 */
2680 glw::GLfloat sumInTCS[] = { 0.0f, 0.0f, 0.0f, 0.0f };
2681 glw::GLfloat sumInTES[] = { 0.0f, 0.0f, 0.0f, 0.0f };
2682
2683 for (int i = 0; i < m_gl_max_tess_control_input_components_value - 4; /* gl_Position */
2684 i++)
2685 {
2686 m_ref_vertex_attributes[i] = (glw::GLfloat)i;
2687 }
2688
2689 for (int i = 0; i < m_gl_max_tess_control_input_components_value - 4; /* gl_Position */
2690 i++)
2691 {
2692 sumInTCS[i % 4 /* component selector */] += m_ref_vertex_attributes[i];
2693 }
2694
2695 for (int i = 0; i < m_gl_max_tess_control_output_components_value - 4; /* gl_Position */
2696 i++)
2697 {
2698 m_ref_vertex_attributes[i] = sumInTCS[i % 4] + (glw::GLfloat)i;
2699 }
2700
2701 for (int i = m_gl_max_tess_control_input_components_value - 4; /* gl_Position */
2702 i < m_gl_max_tess_control_output_components_value - 4; /* gl_Position */
2703 i++)
2704 {
2705 m_ref_vertex_attributes[i] = (glw::GLfloat)i;
2706 }
2707
2708 for (int i = 0; i < m_gl_max_tess_evaluation_input_components_value - 4; /* gl_Position */
2709 i++)
2710 {
2711 sumInTES[i % 4 /* component selector */] += m_ref_vertex_attributes[i];
2712 }
2713
2714 for (int i = 0; i < m_gl_max_tess_evaluation_output_components_value - 4; /* gl_Position */
2715 i++)
2716 {
2717 m_ref_vertex_attributes[i] = sumInTES[i % 4 /* component selector */] + (glw::GLfloat)i;
2718 }
2719
2720 for (int i = m_gl_max_tess_evaluation_input_components_value - 4; /* gl_Position */
2721 i < m_gl_max_tess_evaluation_output_components_value - 4; /* gl_Position */
2722 i++)
2723 {
2724 m_ref_vertex_attributes[i] = (glw::GLfloat)i;
2725 }
2726
2727 /* Store gl_Position reference values (only first vertex will be compared) */
2728 m_ref_vertex_attributes[m_gl_max_tess_evaluation_output_components_value - 4] = 0.0f;
2729 m_ref_vertex_attributes[m_gl_max_tess_evaluation_output_components_value - 3] = 0.0f;
2730 m_ref_vertex_attributes[m_gl_max_tess_evaluation_output_components_value - 2] = 0.0f;
2731 m_ref_vertex_attributes[m_gl_max_tess_evaluation_output_components_value - 1] = 1.0f;
2732
2733 /* Set up reference data for case 2
2734 *
2735 * Only one output vector will be needed for comparison.
2736 */
2737 m_ref_patch_attributes[0] = 0.0f;
2738 m_ref_patch_attributes[1] = 0.0f;
2739 m_ref_patch_attributes[2] = 0.0f;
2740 m_ref_patch_attributes[3] = 0.0f;
2741
2742 for (int i = 0; i < m_gl_max_tess_patch_components_value; i++)
2743 {
2744 m_ref_patch_attributes[i % 4] += (glw::GLfloat)i;
2745 }
2746 }
2747
2748 /** Retrieve OpenGL state and implementation values.
2749 *
2750 * Note the function throws exception should an error occur!
2751 **/
retrieveGLConstantValues(void)2752 void TessellationShaderTessellationMaxInOut::retrieveGLConstantValues(void)
2753 {
2754 /* Retrieve ES entry-points. */
2755 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2756
2757 /* Query implementation constants */
2758 gl.getIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &m_gl_max_vertex_output_components_value);
2759 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_VERTEX_OUTPUT_COMPONENTS pname!");
2760
2761 gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_INPUT_COMPONENTS, &m_gl_max_tess_control_input_components_value);
2762 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT pname!");
2763
2764 gl.getIntegerv(m_glExtTokens.MAX_TESS_CONTROL_OUTPUT_COMPONENTS, &m_gl_max_tess_control_output_components_value);
2765 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT pname!");
2766
2767 gl.getIntegerv(m_glExtTokens.MAX_TESS_PATCH_COMPONENTS, &m_gl_max_tess_patch_components_value);
2768 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_PATCH_COMPONENTS_EXT pname!");
2769
2770 gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_INPUT_COMPONENTS,
2771 &m_gl_max_tess_evaluation_input_components_value);
2772 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT pname!");
2773
2774 gl.getIntegerv(m_glExtTokens.MAX_TESS_EVALUATION_OUTPUT_COMPONENTS,
2775 &m_gl_max_tess_evaluation_output_components_value);
2776 GLU_EXPECT_NO_ERROR(gl.getError(),
2777 "glGetIntegerv() failed for GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT pname!");
2778
2779 gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
2780 &m_gl_max_transform_feedback_interleaved_components_value);
2781 GLU_EXPECT_NO_ERROR(gl.getError(),
2782 "glGetIntegerv() failed for GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS pname!");
2783
2784 /* Sanity checks */
2785 DE_ASSERT(m_gl_max_vertex_output_components_value != 0);
2786 DE_ASSERT(m_gl_max_tess_control_input_components_value != 0);
2787 DE_ASSERT(m_gl_max_tess_control_output_components_value != 0);
2788 DE_ASSERT(m_gl_max_tess_patch_components_value != 0);
2789 DE_ASSERT(m_gl_max_tess_evaluation_input_components_value != 0);
2790 DE_ASSERT(m_gl_max_tess_evaluation_output_components_value != 0);
2791 DE_ASSERT(m_gl_max_transform_feedback_interleaved_components_value != 0);
2792
2793 /* Make sure it is possible to transfer all components through all the stages.
2794 * If not, the test may fail, so we throw not supported. */
2795 if (m_gl_max_vertex_output_components_value < m_gl_max_tess_control_input_components_value)
2796 {
2797 m_testCtx.getLog() << tcu::TestLog::Message << "Warning: GL_MAX_VERTEX_OUTPUT_COMPONENTS value:"
2798 << m_gl_max_vertex_output_components_value
2799 << " is less than GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT: "
2800 << m_gl_max_tess_control_input_components_value
2801 << ". It may not be possible to pass all GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT "
2802 "per-vertex components from Vertex Shader to Tessellation Control Shader."
2803 << tcu::TestLog::EndMessage;
2804 throw tcu::NotSupportedError("GL_MAX_VERTEX_OUTPUT_COMPONENTS < GL_MAX_TESS_CONTROL_INPUT_COMPONENTS");
2805 }
2806
2807 if (m_gl_max_tess_control_output_components_value != m_gl_max_tess_evaluation_input_components_value)
2808 {
2809 m_testCtx.getLog() << tcu::TestLog::Message << "Warning: GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT:"
2810 << m_gl_max_tess_control_output_components_value
2811 << " is not equal to GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT:"
2812 << m_gl_max_tess_evaluation_input_components_value
2813 << ". It may not be possible to pass all GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT "
2814 "per-vertex components from Tessellation Control Shader to Tessellation "
2815 "Evaluation Shader."
2816 << tcu::TestLog::EndMessage;
2817 throw tcu::NotSupportedError("GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS != "
2818 "GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS");
2819 }
2820
2821 if (m_gl_max_tess_evaluation_output_components_value > m_gl_max_transform_feedback_interleaved_components_value)
2822 {
2823 m_testCtx.getLog() << tcu::TestLog::Message << "Warning: GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT:"
2824 << m_gl_max_tess_evaluation_output_components_value
2825 << " is greater than GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:"
2826 << m_gl_max_transform_feedback_interleaved_components_value
2827 << ". It may not be possible to check all GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT "
2828 "per-vertex components from Tessellation Evaluation Shader."
2829 << tcu::TestLog::EndMessage;
2830 throw tcu::NotSupportedError("GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS > "
2831 "GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS");
2832 }
2833 }
2834
2835 /** Maps buffer object storage bound to GL_TRANSFORM_FEEDBACK_BUFFER binding point into process space
2836 * and verifies the downloaded data matches the user-provided reference data.
2837 *
2838 * Note the function throws exception should an error occur!
2839 *
2840 * @param description Case description;
2841 * @param reference_values Array storing reference data;
2842 * @param n_reference_values Number of vec4s available for reading under @param reference_values;
2843 *
2844 * @return false if the comparison failed, or true otherwise.
2845 **/
compareValues(char const * description,glw::GLfloat * reference_values,int n_reference_values)2846 bool TessellationShaderTessellationMaxInOut::compareValues(char const* description, glw::GLfloat* reference_values,
2847 int n_reference_values)
2848 {
2849 /* Retrieve ES entry-points */
2850 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2851
2852 /* Map the buffer storage into process space. */
2853 glw::GLint bo_size = static_cast<glw::GLint>(2 /* number of vertices */ * sizeof(glw::GLfloat) *
2854 n_reference_values * 4); /* number of components */
2855 glw::GLfloat* resultFloats =
2856 (glw::GLfloat*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, bo_size, GL_MAP_READ_BIT);
2857 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
2858
2859 /* Verify the data */
2860 const glw::GLfloat epsilon = (glw::GLfloat)1e-5f;
2861 bool test_passed = true;
2862
2863 for (int i = 0; i < n_reference_values * 4 /* number of components */; i += 4 /* number of components */)
2864 {
2865 if ((de::abs(resultFloats[i] - reference_values[i]) > epsilon) ||
2866 (de::abs(resultFloats[i + 1] - reference_values[i + 1]) > epsilon) ||
2867 (de::abs(resultFloats[i + 2] - reference_values[i + 2]) > epsilon) ||
2868 (de::abs(resultFloats[i + 3] - reference_values[i + 3]) > epsilon))
2869 {
2870 m_testCtx.getLog() << tcu::TestLog::Message << description << ": captured results "
2871 << "vec4(" << resultFloats[i + 0] << ", " << resultFloats[i + 1] << ", "
2872 << resultFloats[i + 2] << ", " << resultFloats[i + 3] << ") "
2873 << "are different from the expected values "
2874 << "vec4(" << reference_values[i + 0] << ", " << reference_values[i + 1] << ", "
2875 << reference_values[i + 2] << ", " << reference_values[i + 3] << ")."
2876 << tcu::TestLog::EndMessage;
2877
2878 test_passed = false;
2879 break;
2880 }
2881 }
2882
2883 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2884 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed!");
2885
2886 return test_passed;
2887 }
2888
2889 } /* namespace glcts */
2890