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