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 "esextcTessellationShaderPoints.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluDefs.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuTestLog.hpp"
30
31 namespace glcts
32 {
33
34 const unsigned int TessellationShaderPointsgl_PointSize::m_rt_height =
35 16; /* note: update shaders if you change this value */
36 const unsigned int TessellationShaderPointsgl_PointSize::m_rt_width =
37 16; /* note: update shaders if you change this value */
38
39 /** Constructor
40 *
41 * @param context Test context
42 **/
TessellationShaderPointsTests(glcts::Context & context,const ExtParameters & extParams)43 TessellationShaderPointsTests::TessellationShaderPointsTests(glcts::Context& context, const ExtParameters& extParams)
44 : TestCaseGroupBase(context, extParams, "tessellation_shader_point_mode", "Verifies point mode functionality")
45 {
46 /* No implementation needed */
47 }
48
49 /**
50 * Initializes test groups for geometry shader tests
51 **/
init(void)52 void TessellationShaderPointsTests::init(void)
53 {
54 addChild(new glcts::TessellationShaderPointsgl_PointSize(m_context, m_extParams));
55 addChild(new glcts::TessellationShaderPointsVerification(m_context, m_extParams));
56 }
57
58 /** Constructor
59 *
60 * @param context Test context
61 * @param name Test case's name
62 * @param description Test case's desricption
63 **/
TessellationShaderPointsgl_PointSize(Context & context,const ExtParameters & extParams)64 TessellationShaderPointsgl_PointSize::TessellationShaderPointsgl_PointSize(Context& context,
65 const ExtParameters& extParams)
66 : TestCaseBase(context, extParams, "point_rendering", "Verifies point size used to render points is taken from"
67 " the right stage")
68 , m_fbo_id(0)
69 , m_to_id(0)
70 , m_vao_id(0)
71 {
72 /* Left blank on purpose */
73 }
74
75 /** Deinitializes all ES objects created for the test. */
deinit()76 void TessellationShaderPointsgl_PointSize::deinit()
77 {
78 /** Call base class' deinit() function */
79 TestCaseBase::deinit();
80
81 if (!m_is_tessellation_shader_supported)
82 {
83 return;
84 }
85
86 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
87
88 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
89 {
90 /* Disable point size */
91 gl.disable(GL_PROGRAM_POINT_SIZE);
92 }
93
94 /* Reset the program object */
95 gl.useProgram(0);
96
97 /* Revert GL_PATCH_VERTICES_EXT to default value */
98 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
99
100 /* Unbind vertex array object */
101 gl.bindVertexArray(0);
102
103 /* Deinitialize test-specific objects */
104 for (_tests_iterator it = m_tests.begin(); it != m_tests.end(); ++it)
105 {
106 const _test_descriptor& test = *it;
107
108 if (test.fs_id != 0)
109 {
110 gl.deleteShader(test.fs_id);
111 }
112
113 if (test.gs_id != 0)
114 {
115 gl.deleteShader(test.gs_id);
116 }
117
118 if (test.po_id != 0)
119 {
120 gl.deleteProgram(test.po_id);
121 }
122
123 if (test.tes_id != 0)
124 {
125 gl.deleteShader(test.tes_id);
126 }
127
128 if (test.tcs_id != 0)
129 {
130 gl.deleteShader(test.tcs_id);
131 }
132
133 if (test.vs_id != 0)
134 {
135 gl.deleteShader(test.vs_id);
136 }
137 }
138 m_tests.clear();
139
140 if (m_fbo_id != 0)
141 {
142 gl.deleteFramebuffers(1, &m_fbo_id);
143
144 m_fbo_id = 0;
145 }
146
147 if (m_to_id != 0)
148 {
149 gl.deleteTextures(1, &m_to_id);
150
151 m_to_id = 0;
152 }
153
154 if (m_vao_id != 0)
155 {
156 gl.deleteVertexArrays(1, &m_vao_id);
157
158 m_vao_id = 0;
159 }
160 }
161
162 /** Initializes all ES objects that will be used for the test. */
initTest()163 void TessellationShaderPointsgl_PointSize::initTest()
164 {
165 /* The test should only execute if maximum point size is at least 2 */
166 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
167 glw::GLint gl_max_point_size_value[2] = { 0 };
168 const int min_max_point_size = 2;
169
170 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
171 {
172 gl.getIntegerv(GL_POINT_SIZE_RANGE, gl_max_point_size_value);
173 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_POINT_SIZE_RANGE failed.");
174 }
175 else
176 {
177 gl.getIntegerv(GL_ALIASED_POINT_SIZE_RANGE, gl_max_point_size_value);
178 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_ALIASED_POINT_SIZE_RANGE failed.");
179 }
180
181 if (gl_max_point_size_value[1] < min_max_point_size)
182 {
183 throw tcu::NotSupportedError("Maximum point size is lower than 2.");
184 }
185
186 /* The test requires EXT_tessellation_shader, EXT_tessellation_shader_point_size */
187 if (!m_is_tessellation_shader_supported || !m_is_tessellation_shader_point_size_supported)
188 {
189 throw tcu::NotSupportedError("At least one of the required extensions is not supported.");
190 }
191
192 /* Initialize vertex array object */
193 gl.genVertexArrays(1, &m_vao_id);
194 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
195
196 gl.bindVertexArray(m_vao_id);
197 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
198
199 /* Initialize fs+gs+vs test descriptor */
200 if (m_is_geometry_shader_extension_supported)
201 {
202 _test_descriptor pass_fs_gs_tes_vs;
203
204 /* Configure shader bodies */
205 pass_fs_gs_tes_vs.fs_body = "${VERSION}\n"
206 "\n"
207 "precision highp float;\n"
208 "\n"
209 "in vec4 color;\n"
210 "out vec4 result;\n"
211 "\n"
212 "void main()\n"
213 "{\n"
214 " result = color;\n"
215 "}\n";
216
217 pass_fs_gs_tes_vs.gs_body = "${VERSION}\n"
218 "\n"
219 "${GEOMETRY_SHADER_REQUIRE}\n"
220 "${GEOMETRY_POINT_SIZE_REQUIRE}\n"
221 "\n"
222 "layout(points) in;\n"
223 "layout(points, max_vertices=5) out;\n"
224 "\n"
225 "out vec4 color;\n"
226 "\n"
227 "void main()\n"
228 "{\n"
229 " const float point_dx = 2.0 / 16.0 /* rendertarget width */;\n"
230 " const float point_dy = 2.0 / 16.0 /* rendertarget_height */;\n"
231 "\n"
232 /* Center */
233 " color = vec4(0.1, 0.2, 0.3, 0.4);\n"
234 " gl_PointSize = 2.0;\n"
235 " gl_Position = vec4(point_dx + 0.0, point_dy + 0.0, 0.0, 1.0);\n"
236 " EmitVertex();\n"
237 "\n"
238 /* Top-left corner */
239 " color = vec4(0.2, 0.3, 0.4, 0.5);\n"
240 " gl_PointSize = 2.0;\n"
241 " gl_Position = vec4(point_dx - 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
242 " EmitVertex();\n"
243 "\n"
244 /* Top-right corner */
245 " color = vec4(0.3, 0.4, 0.5, 0.6);\n"
246 " gl_PointSize = 2.0;\n"
247 " gl_Position = vec4(-point_dx + 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
248 " EmitVertex();\n"
249 "\n"
250 /* Bottom-left corner */
251 " color = vec4(0.4, 0.5, 0.6, 0.7);\n"
252 " gl_PointSize = 2.0;\n"
253 " gl_Position = vec4(point_dx - 1.0, point_dy - 1.0, 0.0, 1.0);\n"
254 " EmitVertex();\n"
255 "\n"
256 /* Bottom-right corner */
257 " color = vec4(0.5, 0.6, 0.7, 0.8);\n"
258 " gl_PointSize = 2.0;\n"
259 " gl_Position = vec4(-point_dx + 1.0, point_dy - 1.0, 0.0, 1.0);\n"
260 " EmitVertex();\n"
261 "\n"
262 "}\n";
263
264 pass_fs_gs_tes_vs.tes_body = "${VERSION}\n"
265 "\n"
266 "${TESSELLATION_SHADER_REQUIRE}\n"
267 "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
268 "\n"
269 "layout(isolines, point_mode) in;\n"
270 "\n"
271 "void main()\n"
272 "{\n"
273 " gl_PointSize = 0.1;\n"
274 "}\n";
275
276 pass_fs_gs_tes_vs.tcs_body = "${VERSION}\n"
277 "\n"
278 "${TESSELLATION_SHADER_REQUIRE}\n"
279 "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
280 "\n"
281 "layout(vertices=1) out;\n"
282 "\n"
283 "void main()\n"
284 "{\n"
285 " gl_out[gl_InvocationID].gl_Position =\n"
286 " gl_in[gl_InvocationID].gl_Position;\n"
287 " gl_out[gl_InvocationID].gl_PointSize =\n"
288 " gl_in[gl_InvocationID].gl_PointSize;\n"
289 "\n"
290 " gl_TessLevelOuter[0] = 1.0;\n"
291 " gl_TessLevelOuter[1] = 1.0;\n"
292 " gl_TessLevelOuter[2] = 1.0;\n"
293 " gl_TessLevelOuter[3] = 1.0;\n"
294 " gl_TessLevelInner[0] = 1.0;\n"
295 " gl_TessLevelInner[1] = 1.0;\n"
296 "}\n";
297
298 pass_fs_gs_tes_vs.vs_body = "${VERSION}\n"
299 "\n"
300 "void main()\n"
301 "{\n"
302 " gl_PointSize = 0.01;\n"
303 "}\n";
304
305 pass_fs_gs_tes_vs.draw_call_count = 1;
306
307 /* Store the descriptor in a vector that will be used by iterate() */
308 m_tests.push_back(pass_fs_gs_tes_vs);
309 } /* if (m_is_geometry_shader_extension_supported) */
310
311 /* Initialize fs+te+vs test descriptor */
312 if (m_is_tessellation_shader_supported)
313 {
314 _test_descriptor pass_fs_tes_vs;
315
316 /* Configure shader bodies */
317 pass_fs_tes_vs.fs_body = "${VERSION}\n"
318 "\n"
319 "precision highp float;\n"
320 "\n"
321 "in vec4 result_color;\n"
322 "out vec4 result;\n"
323 "\n"
324 "void main()\n"
325 "{\n"
326 " result = result_color;\n"
327 "}\n";
328
329 pass_fs_tes_vs.tes_body = "${VERSION}\n"
330 "\n"
331 "${TESSELLATION_SHADER_REQUIRE}\n"
332 "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
333 "\n"
334 "layout(isolines, point_mode) in;\n"
335 "\n"
336 "in vec4 tcColor[];\n"
337 "out vec4 result_color;\n"
338 "\n"
339 "void main()\n"
340 "{\n"
341 " gl_PointSize = 2.0;\n"
342 " gl_Position = gl_in[0].gl_Position;\n"
343 " result_color = tcColor[0];\n"
344 "}\n";
345
346 pass_fs_tes_vs.tcs_body = "${VERSION}\n"
347 "\n"
348 "${TESSELLATION_SHADER_REQUIRE}\n"
349 "${TESSELLATION_POINT_SIZE_REQUIRE}\n"
350 "\n"
351 "layout(vertices=1) out;\n"
352 "\n"
353 "in vec4 color[];\n"
354 "out vec4 tcColor[];\n"
355 "\n"
356 "void main()\n"
357 "{\n"
358 " tcColor[gl_InvocationID] = color[gl_InvocationID];\n"
359 " gl_out[gl_InvocationID].gl_Position =\n"
360 " gl_in[gl_InvocationID].gl_Position;\n"
361 " gl_out[gl_InvocationID].gl_PointSize =\n"
362 " gl_in[gl_InvocationID].gl_PointSize;\n"
363 "\n"
364 " gl_TessLevelOuter[0] = 1.0;\n"
365 " gl_TessLevelOuter[1] = 1.0;\n"
366 " gl_TessLevelOuter[2] = 1.0;\n"
367 " gl_TessLevelOuter[3] = 1.0;\n"
368 " gl_TessLevelInner[0] = 1.0;\n"
369 " gl_TessLevelInner[1] = 1.0;\n"
370 "}\n";
371
372 pass_fs_tes_vs.vs_body = "${VERSION}\n"
373 "\n"
374 "out vec4 color;\n"
375 "\n"
376 "void main()\n"
377 "{\n"
378 " const float point_dx = 2.0 / 16.0 /* rendertarget width */;\n"
379 " const float point_dy = 2.0 / 16.0 /* rendertarget_height */;\n"
380 "\n"
381 " gl_PointSize = 0.1;\n"
382 "\n"
383 " switch (gl_VertexID)\n"
384 " {\n"
385 " case 0:\n"
386 " {\n"
387 /* Center */
388 " color = vec4(0.1, 0.2, 0.3, 0.4);\n"
389 " gl_Position = vec4(point_dx + 0.0, point_dy + 0.0, 0.0, 1.0);\n"
390 "\n"
391 " break;\n"
392 " }\n"
393 "\n"
394 " case 1:\n"
395 " {\n"
396 /* Top-left corner */
397 " color = vec4(0.2, 0.3, 0.4, 0.5);\n"
398 " gl_Position = vec4(point_dx - 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
399 "\n"
400 " break;\n"
401 " }\n"
402 "\n"
403 " case 2:\n"
404 " {\n"
405 /* Top-right corner */
406 " color = vec4(0.3, 0.4, 0.5, 0.6);\n"
407 " gl_Position = vec4(-point_dx + 1.0, -point_dy + 1.0, 0.0, 1.0);\n"
408 "\n"
409 " break;\n"
410 " }\n"
411 "\n"
412 " case 3:\n"
413 " {\n"
414 /* Bottom-left corner */
415 " color = vec4(0.4, 0.5, 0.6, 0.7);\n"
416 " gl_Position = vec4(point_dx - 1.0, point_dy - 1.0, 0.0, 1.0);\n"
417 "\n"
418 " break;\n"
419 " }\n"
420 "\n"
421 " case 4:\n"
422 " {\n"
423 /* Bottom-right corner */
424 " color = vec4(0.5, 0.6, 0.7, 0.8);\n"
425 " gl_Position = vec4(-point_dx + 1.0, point_dy - 1.0, 0.0, 1.0);\n"
426 "\n"
427 " break;\n"
428 " }\n"
429 " }\n"
430 "}\n";
431
432 pass_fs_tes_vs.draw_call_count = 5; /* points in total */
433
434 /* Store the descriptor in a vector that will be used by iterate() */
435 m_tests.push_back(pass_fs_tes_vs);
436 } /* if (m_is_tessellation_shader_supported) */
437
438 /* Set up a color texture we will be rendering to */
439 gl.genTextures(1, &m_to_id);
440 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures() failed");
441
442 gl.bindTexture(GL_TEXTURE_2D, m_to_id);
443 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() failed");
444
445 gl.texStorage2D(GL_TEXTURE_2D, 1 /* levels */, GL_RGBA8, m_rt_width, m_rt_height);
446 GLU_EXPECT_NO_ERROR(gl.getError(), "glTexStorage2D() failed");
447
448 /* Set up a FBO we'll use for rendering */
449 gl.genFramebuffers(1, &m_fbo_id);
450 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers() failed");
451
452 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_id);
453 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer() failed");
454
455 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_to_id, 0 /* level */);
456 GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferTexture2D() failed");
457
458 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
459 {
460 /* Enable point size */
461 gl.enable(GL_PROGRAM_POINT_SIZE);
462 }
463
464 /* We're good to execute the test! */
465 }
466
467 /** Executes the test.
468 *
469 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
470 *
471 * Note the function throws exception should an error occur!
472 *
473 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
474 **/
iterate(void)475 tcu::TestNode::IterateResult TessellationShaderPointsgl_PointSize::iterate(void)
476 {
477 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
478
479 initTest();
480
481 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
482 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed");
483
484 /* Iterate through all test descriptors.. */
485 for (_tests_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); test_iterator++)
486 {
487 _test_descriptor& test = *test_iterator;
488
489 /* Generate all shader objects we'll need */
490 if (test.fs_body != NULL)
491 {
492 test.fs_id = gl.createShader(GL_FRAGMENT_SHADER);
493 }
494
495 if (test.gs_body != NULL)
496 {
497 test.gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
498 }
499
500 if (test.tes_body != NULL)
501 {
502 test.tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
503 }
504
505 if (test.tcs_body != NULL)
506 {
507 test.tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
508 }
509
510 if (test.vs_body != NULL)
511 {
512 test.vs_id = gl.createShader(GL_VERTEX_SHADER);
513 }
514 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
515
516 /* Generate a test program object before we continue */
517 test.po_id = gl.createProgram();
518 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call failed");
519
520 bool link_success =
521 buildProgram(test.po_id, test.fs_id, test.fs_id ? 1 : 0, &test.fs_body, test.gs_id, test.gs_id ? 1 : 0,
522 &test.gs_body, test.tes_id, test.tes_id ? 1 : 0, &test.tes_body, test.tcs_id,
523 test.tcs_id ? 1 : 0, &test.tcs_body, test.vs_id, test.vs_id ? 1 : 0, &test.vs_body);
524
525 if (!link_success)
526 {
527 TCU_FAIL("Program linking failed");
528 }
529
530 /* Prepare for rendering */
531 gl.clearColor(0.0f /* red */, 0.0f /* green */, 0.0f /* blue */, 0.0f /* alpha */);
532 GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor() failed");
533
534 gl.clear(GL_COLOR_BUFFER_BIT);
535 GLU_EXPECT_NO_ERROR(gl.getError(), "glClear(GL_COLOR_BUFFER_BIT) failed");
536
537 gl.viewport(0 /* x */, 0 /* x */, m_rt_width, m_rt_height);
538 GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport() failed");
539
540 gl.useProgram(test.po_id);
541 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
542
543 /* Render */
544 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, test.draw_call_count);
545 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
546
547 /* Read back the rendered data */
548 unsigned char buffer[m_rt_width * m_rt_height * 4 /* components */] = { 0 };
549
550 gl.readPixels(0, /* x */
551 0, /* y */
552 m_rt_width, m_rt_height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
553 GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels() failed");
554
555 /* Verify all 5 points were rendered correctly */
556 const float epsilon = (float)1.0f / 255.0f;
557 const unsigned int pixel_size = 4; /* components, GL_UNSIGNED_BYTE */
558 const float point_data[] = {
559 /* x */ /* y */ /* r */ /* g */ /* b */ /* a */
560 0.5f, 0.5f, 0.1f, 0.2f, 0.3f, 0.4f, /* center */
561 0.0f, 1.0f, 0.2f, 0.3f, 0.4f, 0.5f, /* top-left */
562 1.0f, 1.0f, 0.3f, 0.4f, 0.5f, 0.6f, /* top-right */
563 0.0f, 0.0f, 0.4f, 0.5f, 0.6f, 0.7f, /* bottom-left */
564 1.0f, 0.0f, 0.5f, 0.6f, 0.7f, 0.8f /* bottom-right */
565 };
566 const unsigned int row_size = pixel_size * m_rt_width;
567 const unsigned int n_fields_per_point = 6;
568 const unsigned int n_points = sizeof(point_data) / sizeof(point_data[0]) / n_fields_per_point;
569
570 for (unsigned int n_point = 0; n_point < n_points; ++n_point)
571 {
572 int x = (int)(point_data[n_point * n_fields_per_point + 0] * float(m_rt_width - 1) + 0.5f);
573 int y = (int)(point_data[n_point * n_fields_per_point + 1] * float(m_rt_height - 1) + 0.5f);
574 float expected_color_r = point_data[n_point * n_fields_per_point + 2];
575 float expected_color_g = point_data[n_point * n_fields_per_point + 3];
576 float expected_color_b = point_data[n_point * n_fields_per_point + 4];
577 float expected_color_a = point_data[n_point * n_fields_per_point + 5];
578
579 const unsigned char* rendered_color_ubyte_ptr = buffer + row_size * y + x * pixel_size;
580 const float rendered_color_r = float(rendered_color_ubyte_ptr[0]) / 255.0f;
581 const float rendered_color_g = float(rendered_color_ubyte_ptr[1]) / 255.0f;
582 const float rendered_color_b = float(rendered_color_ubyte_ptr[2]) / 255.0f;
583 const float rendered_color_a = float(rendered_color_ubyte_ptr[3]) / 255.0f;
584
585 /* Compare the pixels */
586 if (de::abs(expected_color_r - rendered_color_r) > epsilon ||
587 de::abs(expected_color_g - rendered_color_g) > epsilon ||
588 de::abs(expected_color_b - rendered_color_b) > epsilon ||
589 de::abs(expected_color_a - rendered_color_a) > epsilon)
590 {
591 m_testCtx.getLog() << tcu::TestLog::Message << "Pixel data comparison failed; expected: "
592 << "(" << expected_color_r << ", " << expected_color_g << ", " << expected_color_b
593 << ", " << expected_color_a << ") rendered: "
594 << "(" << rendered_color_r << ", " << rendered_color_g << ", " << rendered_color_b
595 << ", " << rendered_color_a << ") epsilon: " << epsilon << tcu::TestLog::EndMessage;
596
597 TCU_FAIL("Pixel data comparison failed");
598 }
599 } /* for (all points) */
600 } /* for (all tests) */
601
602 /* All done */
603 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
604 return STOP;
605 }
606
607 /** Constructor
608 *
609 * @param context Test context
610 **/
TessellationShaderPointsVerification(Context & context,const ExtParameters & extParams)611 TessellationShaderPointsVerification::TessellationShaderPointsVerification(Context& context,
612 const ExtParameters& extParams)
613 : TestCaseBase(context, extParams, "points_verification",
614 "Verifies points generated by the tessellator unit do not duplicate "
615 "and that their amount is correct")
616 , m_utils(DE_NULL)
617 , m_vao_id(0)
618 {
619 /* Left blank on purpose */
620 }
621
622 /* Deinitializes all ES Instances generated for the test */
deinit()623 void TessellationShaderPointsVerification::deinit()
624 {
625 /* Call base class' deinit() */
626 TestCaseBase::deinit();
627
628 if (!m_is_tessellation_shader_supported)
629 {
630 return;
631 }
632
633 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
634
635 /* Unbind vertex array object */
636 gl.bindVertexArray(0);
637
638 /* Delete utils instances */
639 if (m_utils != DE_NULL)
640 {
641 delete m_utils;
642
643 m_utils = DE_NULL;
644 }
645
646 /* Delete vertex array object */
647 if (m_vao_id != 0)
648 {
649 gl.deleteVertexArrays(1, &m_vao_id);
650
651 m_vao_id = 0;
652 }
653 }
654
655 /** Initializes ES objects necessary to run the test. */
initTest()656 void TessellationShaderPointsVerification::initTest()
657 {
658 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
659
660 /* Skip if required extensions are not supported. */
661 if (!m_is_tessellation_shader_supported)
662 {
663 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
664 }
665
666 /* Initialize and bind vertex array object */
667 gl.genVertexArrays(1, &m_vao_id);
668 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
669
670 gl.bindVertexArray(m_vao_id);
671 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
672
673 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
674 glw::GLint gl_max_tess_gen_level_value = 0;
675
676 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
677 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
678
679 /* Initialize all test iterations */
680 const _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
681 TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
682 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
683 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
684
685 const _tessellation_shader_vertex_spacing vertex_spacings[] = {
686 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
687 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
688 };
689 const unsigned int n_vertex_spacings = sizeof(vertex_spacings) / sizeof(vertex_spacings[0]);
690
691 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
692 {
693 _tessellation_levels_set levels_set;
694 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
695
696 levels_set = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
697 primitive_mode, gl_max_tess_gen_level_value,
698 TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES);
699
700 for (unsigned int n_vertex_spacing = 0; n_vertex_spacing < n_vertex_spacings; ++n_vertex_spacing)
701 {
702 _tessellation_shader_vertex_spacing vertex_spacing = vertex_spacings[n_vertex_spacing];
703
704 for (_tessellation_levels_set_const_iterator levels_set_iterator = levels_set.begin();
705 levels_set_iterator != levels_set.end(); levels_set_iterator++)
706 {
707 const _tessellation_levels& levels = *levels_set_iterator;
708
709 /* Skip border cases that this test cannot handle */
710 if ((primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS ||
711 primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES) &&
712 vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD &&
713 (levels.inner[0] <= 1 || levels.inner[1] <= 1))
714 {
715 continue;
716 }
717
718 /* Initialize a test run descriptor for the iteration-specific properties */
719 _run run;
720
721 memcpy(run.inner, levels.inner, sizeof(run.inner));
722 memcpy(run.outer, levels.outer, sizeof(run.outer));
723
724 run.primitive_mode = primitive_mode;
725 run.vertex_spacing = vertex_spacing;
726
727 m_runs.push_back(run);
728 } /* for (all level sets) */
729 } /* for (all vertex spacing modes) */
730 } /* for (all primitive modes) */
731
732 /* Initialize utils instance.
733 */
734 m_utils = new TessellationShaderUtils(gl, this);
735 }
736
737 /** Executes the test.
738 *
739 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
740 *
741 * Note the function throws exception should an error occur!
742 *
743 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
744 **/
iterate(void)745 tcu::TestNode::IterateResult TessellationShaderPointsVerification::iterate(void)
746 {
747 initTest();
748
749 /* Do not execute if required extensions are not supported. */
750 if (!m_is_tessellation_shader_supported)
751 {
752 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
753 }
754
755 /* Iterate through all the test descriptors */
756 for (std::vector<_run>::const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
757 {
758 const _run& run = *run_iterator;
759 std::vector<char> run_data;
760 unsigned int run_n_vertices = 0;
761
762 run_data = m_utils->getDataGeneratedByTessellator(run.inner, true, /* point_mode */
763 run.primitive_mode, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
764 run.vertex_spacing, run.outer);
765
766 run_n_vertices = m_utils->getAmountOfVerticesGeneratedByTessellator(run.primitive_mode, run.inner, run.outer,
767 run.vertex_spacing, true); /* point_mode */
768
769 /* First, make sure a valid amount of duplicate vertices was found for a single data set */
770 verifyCorrectAmountOfDuplicateVertices(run, &run_data[0], run_n_vertices);
771
772 /* Now, verify that amount of generated vertices is correct, given
773 * tessellation shader stage configuration */
774 verifyCorrectAmountOfVertices(run, &run_data[0], run_n_vertices);
775 } /* for (all tests) */
776
777 /* All done */
778 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
779 return STOP;
780 }
781
782 /** Verifies that a correct amount of vertices was generated, given test iteration-specific properties.
783 * Throws a TestError exception in if an incorrect amount of vertices was generated by the tessellator.
784 *
785 * @param run Run descriptor.
786 * @param run_data Data generated for the run.
787 * @param run_n_vertices Amount of vertices present at @param run_data.
788 */
verifyCorrectAmountOfVertices(const _run & run,const void * run_data,unsigned int run_n_vertices)789 void TessellationShaderPointsVerification::verifyCorrectAmountOfVertices(const _run& run, const void* run_data,
790 unsigned int run_n_vertices)
791 {
792 (void)run_data;
793
794 const float epsilon = 1e-5f;
795 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
796 unsigned int n_expected_vertices = 0;
797 float post_vs_inner_tess_levels[2] = { 0.0f };
798 float post_vs_outer_tess_levels[4] = { 0.0f };
799
800 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value*/
801 glw::GLint gl_max_tess_gen_level_value = 0;
802
803 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &gl_max_tess_gen_level_value);
804 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() call failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
805
806 /* Determine vertex spacing that the tessellator should have used for current primitive mode */
807 glw::GLfloat actual_inner_levels[2] = { 0.0f };
808 _tessellation_shader_vertex_spacing actual_vs_mode = run.vertex_spacing;
809 glw::GLfloat clamped_inner_levels[2] = { 0.0f };
810
811 memcpy(actual_inner_levels, run.inner, sizeof(run.inner));
812
813 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
814 run.vertex_spacing, actual_inner_levels[0], gl_max_tess_gen_level_value, clamped_inner_levels + 0,
815 DE_NULL); /* out_clamped_and_rounded */
816
817 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
818 run.vertex_spacing, actual_inner_levels[1], gl_max_tess_gen_level_value, clamped_inner_levels + 1,
819 DE_NULL); /* out_clamped_and_rounded */
820
821 if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
822 {
823 /* For isolines tessellation, outer[1] is subdivided as per specified vertex spacing as specified.
824 * outer[0] should be subdivided using equal vertex spacing.
825 *
826 * This is owing to the following language in the spec (* marks important subtleties):
827 *
828 * The *u==0* and *u==1* edges of the rectangle are subdivided according to the first outer
829 * tessellation level. For the purposes of *this* subdivision, the tessellation spacing mode
830 * is ignored and treated as "equal_spacing".
831 */
832 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
833 run.outer[0], gl_max_tess_gen_level_value,
834 DE_NULL, /* out_clamped */
835 post_vs_outer_tess_levels);
836
837 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
838 actual_vs_mode, run.outer[1], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
839 post_vs_outer_tess_levels + 1);
840 }
841
842 if (run.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS)
843 {
844 /* As per extension spec:
845 *
846 * if either clamped inner tessellation level is one, that tessellation level
847 * is treated as though it were originally specified as 1+epsilon, which would
848 * rounded up to result in a two- or three-segment subdivision according to the
849 * tessellation spacing.
850 *
851 **/
852 if (de::abs(clamped_inner_levels[0] - 1.0f) < epsilon)
853 {
854 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
855 run.vertex_spacing, clamped_inner_levels[0] + 1.0f, /* epsilon */
856 gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
857 actual_inner_levels + 0);
858 }
859
860 if (de::abs(clamped_inner_levels[1] - 1.0f) < epsilon)
861 {
862 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
863 run.vertex_spacing, clamped_inner_levels[1] + 1.0f, /* epsilon */
864 gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
865 actual_inner_levels + 1);
866 }
867 }
868
869 /* Retrieve tessellation level values, taking vertex spacing setting into account */
870 for (int n = 0; n < 2 /* inner tessellation level values */; ++n)
871 {
872 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
873 actual_vs_mode, actual_inner_levels[n], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
874 post_vs_inner_tess_levels + n);
875 }
876
877 if (run.primitive_mode != TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES)
878 {
879 for (int n = 0; n < 4 /* outer tessellation level values */; ++n)
880 {
881 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
882 actual_vs_mode, run.outer[n], gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
883 post_vs_outer_tess_levels + n);
884 }
885 }
886
887 /* Calculate amount of vertices that should be generated in point mode */
888 switch (run.primitive_mode)
889 {
890 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
891 {
892 n_expected_vertices = int(post_vs_outer_tess_levels[0]) * int(post_vs_outer_tess_levels[1] + 1);
893
894 break;
895 }
896
897 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
898 {
899 n_expected_vertices = /* outer quad */
900 int(post_vs_outer_tess_levels[0]) + int(post_vs_outer_tess_levels[1]) + int(post_vs_outer_tess_levels[2]) +
901 int(post_vs_outer_tess_levels[3]) +
902 /* inner quad */
903 (int(post_vs_inner_tess_levels[0]) - 1) * (int(post_vs_inner_tess_levels[1]) - 1);
904
905 break;
906 }
907
908 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
909 {
910 /* If the first inner tessellation level and all three outer tessellation
911 * levels are exactly one after clamping and rounding, only a single triangle
912 * with (u,v,w) coordinates of (0,0,1), (1,0,0), and (0,1,0) is generated.
913 */
914 if (de::abs(run.inner[0] - 1.0f) < epsilon && de::abs(run.outer[0] - 1.0f) < epsilon &&
915 de::abs(run.outer[1] - 1.0f) < epsilon && de::abs(run.outer[2] - 1.0f) < epsilon)
916 {
917 n_expected_vertices = 3;
918 }
919 else
920 {
921 /* If the inner tessellation level is one and any of the outer tessellation
922 * levels is greater than one, the inner tessellation level is treated as
923 * though it were originally specified as 1+epsilon and will be rounded up to
924 * result in a two- or three-segment subdivision according to the
925 * tessellation spacing.
926 */
927 if (de::abs(run.inner[0] - 1.0f) < epsilon &&
928 (run.outer[0] > 1.0f || run.outer[1] > 1.0f || run.outer[2] > 1.0f))
929 {
930 TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(
931 run.vertex_spacing, 2.0f, gl_max_tess_gen_level_value, DE_NULL, /* out_clamped */
932 post_vs_inner_tess_levels);
933 }
934
935 /* Count vertices making up concentric inner triangles */
936 n_expected_vertices = (int)post_vs_outer_tess_levels[0] + (int)post_vs_outer_tess_levels[1] +
937 (int)post_vs_outer_tess_levels[2];
938
939 for (int n = (int)post_vs_inner_tess_levels[0]; n >= 0; n -= 2)
940 {
941 /* For the outermost inner triangle, the inner triangle is degenerate -
942 * a single point at the center of the triangle -- if <n> is two.
943 */
944 if (n == 2)
945 {
946 n_expected_vertices++; /* degenerate vertex */
947
948 break;
949 }
950
951 /* If <n> is three, the edges of the inner triangle are not subdivided and is
952 * the final triangle in the set of concentric triangles.
953 */
954 if (n == 3)
955 {
956 n_expected_vertices += 3 /* vertices per triangle */;
957
958 break;
959 }
960
961 /* Otherwise, each edge of the inner triangle is divided into <n>-2 segments,
962 * with the <n>-1 vertices of this subdivision produced by intersecting the
963 * inner edge with lines perpendicular to the edge running through the <n>-1
964 * innermost vertices of the subdivision of the outer edge.
965 */
966 if (n >= 2)
967 {
968 n_expected_vertices += (n - 2) * 3 /* triangle edges */;
969 }
970 else
971 {
972 /* Count in the degenerate point instead */
973 n_expected_vertices++;
974 }
975 } /* for (all inner triangles) */
976 }
977
978 break;
979 }
980
981 default:
982 {
983 TCU_FAIL("Unrecognized primitive mode");
984 }
985 } /* switch (test.primitive_mode) */
986
987 /* Compare two values */
988 if (run_n_vertices != n_expected_vertices)
989 {
990 std::string primitive_mode = TessellationShaderUtils::getESTokenForPrimitiveMode(run.primitive_mode);
991 std::string vertex_spacing = TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
992
993 m_testCtx.getLog() << tcu::TestLog::Message << run_n_vertices
994 << " vertices were generated by the tessellator instead of expected " << n_expected_vertices
995 << " for primitive mode [" << primitive_mode << "], vertex spacing mode [" << vertex_spacing
996 << "], inner tessellation levels:[" << run.inner[0] << ", " << run.inner[1]
997 << "], outer tessellation levels:[" << run.outer[0] << ", " << run.outer[1] << ", "
998 << run.outer[2] << ", " << run.outer[3] << "], point mode enabled."
999 << tcu::TestLog::EndMessage;
1000
1001 TCU_FAIL("Amount of vertices generated in point mode was incorrect");
1002 } /* if (test.n_vertices != n_expected_vertices) */
1003 }
1004
1005 /** Verifies a valid amount of duplicate vertices is present in the set of coordinates
1006 * generated by the tessellator, as described by user-provided test iteration descriptor.
1007 * Throws a TestError exception if the vertex set does not meet the requirements.
1008 *
1009 * @param test Test iteration descriptor.
1010 * @param run_data Data generated for the run.
1011 * @param run_n_vertices Amount of vertices present at @param run_data.
1012 **/
verifyCorrectAmountOfDuplicateVertices(const _run & run,const void * run_data,unsigned int run_n_vertices)1013 void TessellationShaderPointsVerification::verifyCorrectAmountOfDuplicateVertices(const _run& run, const void* run_data,
1014 unsigned int run_n_vertices)
1015 {
1016 const float epsilon = 1e-5f;
1017 unsigned int n_duplicate_vertices = 0;
1018
1019 for (unsigned int n_vertex_a = 0; n_vertex_a < run_n_vertices; ++n_vertex_a)
1020 {
1021 const float* vertex_a = (const float*)run_data + n_vertex_a * 3; /* components */
1022
1023 for (unsigned int n_vertex_b = n_vertex_a + 1; n_vertex_b < run_n_vertices; ++n_vertex_b)
1024 {
1025 const float* vertex_b = (const float*)run_data + n_vertex_b * 3; /* components */
1026
1027 if (de::abs(vertex_a[0] - vertex_b[0]) < epsilon && de::abs(vertex_a[1] - vertex_b[1]) < epsilon &&
1028 de::abs(vertex_a[2] - vertex_b[2]) < epsilon)
1029 {
1030 n_duplicate_vertices++;
1031 }
1032 } /* for (all vertices) */
1033 } /* for (all vertices) */
1034
1035 if (n_duplicate_vertices != 0)
1036 {
1037 std::string vertex_spacing = TessellationShaderUtils::getESTokenForVertexSpacingMode(run.vertex_spacing);
1038
1039 m_testCtx.getLog() << tcu::TestLog::Message << "Duplicate vertices found for the following tesselelation"
1040 " configuration: tessellation level:"
1041 "["
1042 << run.inner[0] << ", " << run.inner[1] << "], "
1043 "outer tessellation level:"
1044 " ["
1045 << run.outer[0] << ", " << run.outer[1] << ", " << run.outer[2] << ", " << run.outer[3]
1046 << "], "
1047 << "vertex spacing mode:[" << vertex_spacing.c_str() << "]" << tcu::TestLog::EndMessage;
1048
1049 TCU_FAIL("Duplicate vertex found");
1050 }
1051 }
1052
1053 } /* namespace glcts */
1054