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 "esextcTessellationShaderTCTE.hpp"
25 #include "esextcTessellationShaderUtils.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDefs.hpp"
28 #include "glwEnums.hpp"
29 #include "glwFunctions.hpp"
30 #include "tcuTestLog.hpp"
31 #include <algorithm>
32
33 namespace glcts
34 {
35 /** Constructor
36 *
37 * @param context Test context
38 **/
TessellationShaderTCTETests(glcts::Context & context,const ExtParameters & extParams)39 TessellationShaderTCTETests::TessellationShaderTCTETests(glcts::Context& context, const ExtParameters& extParams)
40 : TestCaseGroupBase(context, extParams, "tessellation_control_to_tessellation_evaluation",
41 "Verifies various aspects of communication between tessellation "
42 "control and tessellation evaluation stages")
43 {
44 /* No implementation needed */
45 }
46
47 /**
48 * Initializes test groups for geometry shader tests
49 **/
init(void)50 void TessellationShaderTCTETests::init(void)
51 {
52 addChild(new glcts::TessellationShaderTCTEDataPassThrough(m_context, m_extParams));
53 addChild(new glcts::TessellationShaderTCTEgl_in(m_context, m_extParams));
54 addChild(new glcts::TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize(m_context, m_extParams));
55 addChild(new glcts::TessellationShaderTCTEgl_PatchVerticesIn(m_context, m_extParams));
56 addChild(new glcts::TessellationShaderTCTEgl_TessLevel(m_context, m_extParams));
57 }
58
59 /** Constructor
60 *
61 * @param context Test context
62 **/
TessellationShaderTCTEDataPassThrough(Context & context,const ExtParameters & extParams)63 TessellationShaderTCTEDataPassThrough::TessellationShaderTCTEDataPassThrough(Context& context,
64 const ExtParameters& extParams)
65 : TestCaseBase(context, extParams, "data_pass_through",
66 "Verifies data is correctly passed down the VS->TC->TS->(GS) pipeline.")
67 , m_bo_id(0)
68 , m_n_input_vertices_per_run(4)
69 , m_utils_ptr(DE_NULL)
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 TessellationShaderTCTEDataPassThrough::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 /* Revert GL_PATCH_VERTICES_EXT value to the default setting */
89 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
90
91 /* Disable GL_RASTERIZER_DISCARD mode */
92 gl.disable(GL_RASTERIZER_DISCARD);
93
94 /* Revert TF buffer object bindings */
95 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
96 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
97
98 /* Unbind vertex array object */
99 gl.bindVertexArray(0);
100
101 /* Release all objects we might've created */
102 if (m_bo_id != 0)
103 {
104 gl.deleteBuffers(1, &m_bo_id);
105
106 m_bo_id = 0;
107 }
108
109 if (m_vao_id != 0)
110 {
111 gl.deleteVertexArrays(1, &m_vao_id);
112
113 m_vao_id = 0;
114 }
115
116 for (_runs::iterator it = m_runs.begin(); it != m_runs.end(); ++it)
117 {
118 deinitTestRun(*it);
119 }
120 m_runs.clear();
121
122 /* Release Utils instance */
123 if (m_utils_ptr != DE_NULL)
124 {
125 delete m_utils_ptr;
126
127 m_utils_ptr = DE_NULL;
128 }
129 }
130
131 /** Deinitializes all ES object created for a specific test run. **/
deinitTestRun(_run & run)132 void TessellationShaderTCTEDataPassThrough::deinitTestRun(_run& run)
133 {
134 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
135
136 if (run.fs_id != 0)
137 {
138 gl.deleteShader(run.fs_id);
139
140 run.fs_id = 0;
141 }
142
143 if (run.gs_id != 0)
144 {
145 gl.deleteShader(run.gs_id);
146
147 run.gs_id = 0;
148 }
149
150 if (run.po_id != 0)
151 {
152 gl.deleteProgram(run.po_id);
153
154 run.po_id = 0;
155 }
156
157 if (run.tcs_id != 0)
158 {
159 gl.deleteShader(run.tcs_id);
160
161 run.tcs_id = 0;
162 }
163
164 if (run.tes_id != 0)
165 {
166 gl.deleteShader(run.tes_id);
167
168 run.tes_id = 0;
169 }
170
171 if (run.vs_id != 0)
172 {
173 gl.deleteShader(run.vs_id);
174
175 run.vs_id = 0;
176 }
177 }
178
179 /** Initializes all ES objects that will be used for the test. */
initTest()180 void TessellationShaderTCTEDataPassThrough::initTest()
181 {
182 /* The test requires EXT_tessellation_shader */
183 if (!m_is_tessellation_shader_supported)
184 {
185 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
186 }
187
188 /* Create an Utils instance */
189 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
190
191 m_utils_ptr = new TessellationShaderUtils(gl, this);
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 /* Our program objects take a single vertex per patch */
201 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
202 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed");
203
204 /* Disable rasterization */
205 gl.enable(GL_RASTERIZER_DISCARD);
206 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
207
208 /* Create a buffer object we will use for XFB */
209 gl.genBuffers(1, &m_bo_id);
210 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
211
212 /* Set up XFB buffer object bindings */
213 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
214 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() failed");
215
216 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
217 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() failed");
218
219 /* Prepare all the runs */
220 const _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
221 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
222 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
223 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
224
225 /* Iterate over all supported primitive modes */
226 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; ++n_primitive_mode)
227 {
228 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
229
230 /* If geometry shaders are supported, include a separate iteration to include them
231 * in the pipeline
232 */
233 for (int n_gs_stage_usage = 0; n_gs_stage_usage < ((m_is_geometry_shader_extension_supported) ? 2 : 1);
234 ++n_gs_stage_usage)
235 {
236 bool use_gs_stage = (n_gs_stage_usage == 1);
237
238 /* If geometry shaders support gl_PointSize, include a separate iteration to pass
239 * point size data as well */
240 for (int n_gs_pointsize_usage = 0;
241 n_gs_pointsize_usage < ((m_is_geometry_shader_point_size_supported) ? 2 : 1); ++n_gs_pointsize_usage)
242 {
243 bool use_gs_pointsize_data = (n_gs_pointsize_usage == 1);
244
245 /* If tessellation shaders support gl_PointSize, include a separate iteration to pass
246 * point size data as well */
247 for (int n_ts_pointsize_usage = 0;
248 n_ts_pointsize_usage < ((m_is_tessellation_shader_point_size_supported) ? 2 : 1);
249 ++n_ts_pointsize_usage)
250 {
251 bool use_ts_pointsize_data = (n_ts_pointsize_usage == 1);
252
253 /* Note: it does not make sense to try to pass gl_PointSize data
254 * in geometry stage if tessellation stage did not provide it.
255 */
256 if (!use_ts_pointsize_data && use_gs_pointsize_data)
257 {
258 continue;
259 }
260
261 /* Initialize test run data */
262 _run run;
263
264 executeTestRun(run, primitive_mode, use_gs_stage, use_gs_pointsize_data, use_ts_pointsize_data);
265
266 /* Store the run for later usage */
267 m_runs.push_back(run);
268 } /* for (tessellation point size data usage off and on cases) */
269 } /* for (geometry point size data usage off and on cases) */
270 } /* for (GS stage usage) */
271 } /* for (all primitive modes) */
272 }
273
274 /** Initializes a test run, executes it and gathers all the rendered data for further
275 * processing. Extracted data is stored in the run descriptor.
276 *
277 * @param run Test run descriptor to fill with ES object data,
278 * as well as generated data.
279 * @param primitive_mode Primitive mode to use for the test run.
280 * @param should_use_geometry_shader true if the test run should use Geometry Shader stage,
281 * false otherwise.
282 * @param should_pass_point_size_data_in_gs true if the test run should define two output variables
283 * in Geometry Shader, later set to gl_PointSize values from
284 * TC and TE stages. False to skip them.
285 * Only set to true if GL_EXT_geometry_point_size extension
286 * is supported.
287 * @param should_pass_point_size_data_in_ts true if the test run should define two output variables
288 * in both Tessellation Shader types, set to gl_PointSize values
289 * as accessible during execution. False to skip the definitions.
290 * Only set to true if GL_EXT_tessellation_point_size extension
291 * is supported.
292 */
executeTestRun(_run & run,_tessellation_primitive_mode primitive_mode,bool should_use_geometry_shader,bool should_pass_point_size_data_in_gs,bool should_pass_point_size_data_in_ts)293 void TessellationShaderTCTEDataPassThrough::executeTestRun(_run& run, _tessellation_primitive_mode primitive_mode,
294 bool should_use_geometry_shader,
295 bool should_pass_point_size_data_in_gs,
296 bool should_pass_point_size_data_in_ts)
297 {
298 run.primitive_mode = primitive_mode;
299
300 /* Retrieve ES entry-points before we start */
301 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
302
303 /* Create a program object first */
304 run.po_id = gl.createProgram();
305
306 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
307
308 /* Create all shader objects we wil be later attaching to the program object */
309 run.fs_id = gl.createShader(GL_FRAGMENT_SHADER);
310 run.tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
311 run.tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
312 run.vs_id = gl.createShader(GL_VERTEX_SHADER);
313
314 if (should_use_geometry_shader)
315 {
316 run.gs_id = gl.createShader(m_glExtTokens.GEOMETRY_SHADER);
317 }
318
319 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
320
321 /* Attach the shader objects to the program object */
322 gl.attachShader(run.po_id, run.fs_id);
323 gl.attachShader(run.po_id, run.tcs_id);
324 gl.attachShader(run.po_id, run.tes_id);
325 gl.attachShader(run.po_id, run.vs_id);
326
327 if (should_use_geometry_shader)
328 {
329 gl.attachShader(run.po_id, run.gs_id);
330 }
331
332 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed");
333
334 /* Set vertex shader's body */
335 const char* vs_body = "${VERSION}\n"
336 "\n"
337 "${SHADER_IO_BLOCKS_REQUIRE}\n"
338 "\n"
339 "out OUT_VS\n"
340 "{\n"
341 " vec4 value1;\n"
342 " ivec4 value2;\n"
343 "} out_data;\n"
344 "\n"
345 "void main()\n"
346 "{\n"
347 " gl_Position = vec4( float(gl_VertexID) );\n"
348 " gl_PointSize = 1.0 / float(gl_VertexID + 1);\n"
349 " out_data.value1 = vec4(float(gl_VertexID), float(gl_VertexID) * 0.5,\n"
350 " float(gl_VertexID) * 0.25, float(gl_VertexID) * 0.125);\n"
351 " out_data.value2 = ivec4(gl_VertexID, gl_VertexID + 1,\n"
352 " gl_VertexID + 2, gl_VertexID + 3);\n"
353 "}\n";
354
355 shaderSourceSpecialized(run.vs_id, 1 /* count */, &vs_body);
356 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for vertex shader");
357
358 /* Set minimal fragment shader's body */
359 const char* fs_body = "${VERSION}\n"
360 "\n"
361 "void main()\n"
362 "{\n"
363 "}\n";
364
365 shaderSourceSpecialized(run.fs_id, 1 /* count */, &fs_body);
366 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for fragment shader");
367
368 /* Set tessellation control shader's body */
369 {
370 std::stringstream body_sstream;
371 std::string body_string;
372 const char* body_raw_ptr = DE_NULL;
373
374 body_sstream << "${VERSION}\n"
375 "\n"
376 "${TESSELLATION_SHADER_REQUIRE}\n";
377
378 if (should_pass_point_size_data_in_ts)
379 {
380 body_sstream << "${TESSELLATION_POINT_SIZE_REQUIRE}\n";
381 }
382
383 body_sstream << "\n"
384 "layout(vertices = 2) out;\n"
385 "\n"
386 "in OUT_VS\n"
387 "{\n"
388 " vec4 value1;\n"
389 " ivec4 value2;\n"
390 "} in_vs_data[];\n"
391 "\n"
392 "out OUT_TC\n"
393 "{\n";
394
395 if (should_pass_point_size_data_in_ts)
396 {
397 body_sstream << " float tc_pointSize;\n";
398 }
399
400 body_sstream << " vec4 tc_position;\n"
401 " vec4 tc_value1;\n"
402 " ivec4 tc_value2;\n"
403 "} out_data[];\n"
404 "\n"
405 "patch out vec4 tc_patch_data;\n"
406 "\n"
407 "void main()\n"
408 "{\n"
409 " int multiplier = 1;\n"
410 "\n"
411 " if (gl_InvocationID == 0)\n"
412 " {\n"
413 " multiplier = 2;\n"
414 " }\n";
415
416 if (should_pass_point_size_data_in_ts)
417 {
418 body_sstream << " out_data [gl_InvocationID].tc_pointSize = gl_in[0].gl_PointSize;\n"
419 " gl_out [gl_InvocationID].gl_PointSize = gl_in[0].gl_PointSize * 2.0;\n";
420 }
421
422 body_sstream << " out_data [gl_InvocationID].tc_position = gl_in [0].gl_Position;\n"
423 " out_data [gl_InvocationID].tc_value1 = in_vs_data[0].value1 * "
424 "vec4(float(multiplier) );\n"
425 " out_data [gl_InvocationID].tc_value2 = in_vs_data[0].value2 * ivec4( "
426 "multiplier);\n"
427 " gl_out [gl_InvocationID].gl_Position = gl_in [0].gl_Position + vec4(3.0);\n"
428 " gl_TessLevelInner[0] = 4.0;\n"
429 " gl_TessLevelInner[1] = 4.0;\n"
430 " gl_TessLevelOuter[0] = 4.0;\n"
431 " gl_TessLevelOuter[1] = 4.0;\n"
432 " gl_TessLevelOuter[2] = 4.0;\n"
433 " gl_TessLevelOuter[3] = 4.0;\n"
434 "\n"
435 " if (gl_InvocationID == 0)\n"
436 " {\n"
437 " tc_patch_data = in_vs_data[0].value1 * vec4(float(multiplier) );\n"
438 " }\n"
439 "}\n";
440
441 body_string = body_sstream.str();
442 body_raw_ptr = body_string.c_str();
443
444 shaderSourceSpecialized(run.tcs_id, 1 /* count */, &body_raw_ptr);
445 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for tessellation control shader");
446 }
447
448 /* Set tessellation evaluation shader's body */
449 {
450 std::stringstream body_sstream;
451 std::string body_string;
452 const char* body_raw_ptr = DE_NULL;
453
454 /* Preamble */
455 body_sstream << "${VERSION}\n"
456 "\n"
457 "${TESSELLATION_SHADER_REQUIRE}\n";
458
459 if (should_pass_point_size_data_in_ts)
460 {
461 body_sstream << "${TESSELLATION_POINT_SIZE_REQUIRE}\n";
462 }
463
464 /* Layout qualifiers */
465 body_sstream << "\n"
466 "layout(PRIMITIVE_MODE, point_mode) in;\n"
467 "\n"
468
469 /* Input block definition starts here: */
470 "in OUT_TC\n"
471 "{\n";
472
473 if (should_pass_point_size_data_in_ts)
474 {
475 body_sstream << " float tc_pointSize;\n";
476 }
477
478 body_sstream << " vec4 tc_position;\n"
479 " vec4 tc_value1;\n"
480 " ivec4 tc_value2;\n"
481 "} in_data[];\n"
482 "\n"
483 "patch in vec4 tc_patch_data;\n"
484 "\n";
485 /* Input block definition ends here. */
486
487 /* Output block definition (only defined if GS stage is present) starts here: */
488 if (should_use_geometry_shader)
489 {
490 body_sstream << "out OUT_TE\n"
491 "{\n";
492
493 /* Output block contents */
494 if (should_pass_point_size_data_in_ts)
495 {
496 body_sstream << " float tc_pointSize;\n"
497 " float te_pointSize;\n";
498 }
499
500 body_sstream << " vec4 tc_position;\n"
501 " vec4 tc_value1;\n"
502 " ivec4 tc_value2;\n"
503 " vec4 te_position;\n"
504 "} out_data;\n";
505 }
506 /* Output block definition ends here. */
507 else
508 {
509 if (should_pass_point_size_data_in_ts)
510 {
511 body_sstream << "out float tc_pointSize;\n"
512 "out float te_pointSize;\n";
513 }
514
515 body_sstream << "out vec4 tc_position;\n"
516 "out vec4 tc_value1;\n"
517 "flat out ivec4 tc_value2;\n"
518 "out vec4 te_position;\n"
519 "out vec4 te_patch_data;\n";
520 }
521
522 body_sstream << "\n"
523 "void main()\n"
524 "{\n";
525
526 if (should_use_geometry_shader)
527 {
528 body_sstream << "#define OUTPUT_VARIABLE(x) out_data.x\n";
529 }
530 else
531 {
532 body_sstream << "#define OUTPUT_VARIABLE(x) x\n";
533 }
534
535 if (should_pass_point_size_data_in_ts)
536 {
537 body_sstream << " OUTPUT_VARIABLE(tc_pointSize) = in_data[1].tc_pointSize;\n"
538 " OUTPUT_VARIABLE(te_pointSize) = gl_in[1].gl_PointSize;\n";
539 }
540
541 body_sstream << " OUTPUT_VARIABLE(tc_position) = in_data[1].tc_position;\n"
542 " OUTPUT_VARIABLE(tc_value1) = in_data[0].tc_value1;\n"
543 " OUTPUT_VARIABLE(tc_value2) = in_data[1].tc_value2;\n"
544 " OUTPUT_VARIABLE(te_position) = gl_in[0].gl_Position;\n";
545
546 if (!should_use_geometry_shader)
547 {
548 body_sstream << " OUTPUT_VARIABLE(te_patch_data) = tc_patch_data;\n";
549 }
550 body_sstream << "}\n";
551
552 body_string = body_sstream.str();
553
554 /* Replace PRIMITIVE_MODE token with user-requested primitive mode */
555 std::string primitive_mode_replacement = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
556 std::string primitive_mode_token = "PRIMITIVE_MODE";
557 std::size_t primitive_mode_token_position = std::string::npos;
558
559 primitive_mode_token_position = body_string.find(primitive_mode_token);
560
561 while (primitive_mode_token_position != std::string::npos)
562 {
563 body_string = body_string.replace(primitive_mode_token_position, primitive_mode_token.length(),
564 primitive_mode_replacement);
565
566 primitive_mode_token_position = body_string.find(primitive_mode_token);
567 }
568
569 body_raw_ptr = body_string.c_str();
570
571 shaderSourceSpecialized(run.tes_id, 1 /* count */, &body_raw_ptr);
572 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for tessellation evaluation shader");
573 }
574
575 /* Set geometry shader's body (if requested) */
576 if (should_use_geometry_shader)
577 {
578 std::stringstream body_sstream;
579 std::string body_string;
580 const char* body_raw_ptr = DE_NULL;
581
582 body_sstream << "${VERSION}\n"
583 "\n"
584 "${GEOMETRY_SHADER_REQUIRE}\n";
585
586 if (should_pass_point_size_data_in_gs)
587 {
588 body_sstream << "${GEOMETRY_POINT_SIZE_REQUIRE}\n";
589 }
590
591 body_sstream << "${SHADER_IO_BLOCKS_REQUIRE}\n"
592 "\n"
593 "layout(points) in;\n"
594 "layout(max_vertices = 2, points) out;\n"
595 "\n"
596 "in OUT_TE\n"
597 "{\n";
598
599 if (should_pass_point_size_data_in_ts)
600 {
601 body_sstream << " float tc_pointSize;\n"
602 " float te_pointSize;\n";
603 }
604
605 body_sstream << " vec4 tc_position;\n"
606 " vec4 tc_value1;\n"
607 " ivec4 tc_value2;\n"
608 " vec4 te_position;\n"
609 "} in_data[1];\n"
610 "\n"
611 "out float gs_tc_pointSize;\n"
612 "out float gs_te_pointSize;\n"
613 "out vec4 gs_tc_position;\n"
614 "out vec4 gs_tc_value1;\n"
615 "flat out ivec4 gs_tc_value2;\n"
616 "out vec4 gs_te_position;\n"
617 "\n"
618 "void main()\n"
619 "{\n";
620
621 if (should_pass_point_size_data_in_gs)
622 {
623 body_sstream << " gs_tc_pointSize = in_data[0].tc_pointSize;\n"
624 " gs_te_pointSize = in_data[0].te_pointSize;\n";
625 }
626
627 body_sstream << " gs_tc_position = in_data[0].tc_position;\n"
628 " gs_tc_value1 = in_data[0].tc_value1;\n"
629 " gs_tc_value2 = in_data[0].tc_value2;\n"
630 " gs_te_position = in_data[0].te_position;\n"
631 " EmitVertex();\n";
632
633 if (should_pass_point_size_data_in_gs)
634 {
635 body_sstream << " gs_tc_pointSize = in_data[0].tc_pointSize + 1.0;\n"
636 " gs_te_pointSize = in_data[0].te_pointSize + 1.0;\n";
637 }
638
639 body_sstream << " gs_tc_position = in_data[0].tc_position + vec4(1.0);\n"
640 " gs_tc_value1 = in_data[0].tc_value1 + vec4(1.0);\n"
641 " gs_tc_value2 = in_data[0].tc_value2 + ivec4(1);\n"
642 " gs_te_position = in_data[0].te_position + vec4(1.0);\n"
643 "\n"
644 " EmitVertex();\n"
645 "\n"
646 "}\n";
647
648 body_string = body_sstream.str();
649 body_raw_ptr = body_string.c_str();
650
651 shaderSourceSpecialized(run.gs_id, 1 /* count */, &body_raw_ptr);
652 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for geometry shader");
653 }
654
655 /* Configure varyings */
656 unsigned int n_varyings = 0;
657 int varying_tc_pointSize_offset = -1;
658 int varying_tc_position_offset = -1;
659 int varying_tc_value1_offset = -1;
660 int varying_tc_value2_offset = -1;
661 int varying_te_patch_data_offset = -1;
662 int varying_te_pointSize_offset = -1;
663 int varying_te_position_offset = -1;
664 const unsigned int varying_patch_data_size = sizeof(float) * 4; /* vec4 */
665 const unsigned int varying_pointSize_size = sizeof(float);
666 const unsigned int varying_position_size = sizeof(float) * 4; /* vec4 */
667 const unsigned int varying_value1_size = sizeof(float) * 4; /* vec4 */
668 const unsigned int varying_value2_size = sizeof(int) * 4; /* ivec4 */
669 const char** varyings = DE_NULL;
670 unsigned int varyings_size = 0;
671
672 const char* gs_non_point_size_varyings[] = { "gs_tc_position", "gs_tc_value1", "gs_tc_value2", "gs_te_position" };
673 const char* gs_point_size_varyings[] = { "gs_tc_position", "gs_tc_value1", "gs_tc_value2",
674 "gs_te_position", "gs_tc_pointSize", "gs_te_pointSize" };
675 const char* non_gs_non_point_size_varyings[] = { "tc_position", "tc_value1", "tc_value2", "te_position",
676 "te_patch_data" };
677 const char* non_gs_point_size_varyings[] = { "tc_position", "tc_value1", "tc_value2", "te_position",
678 "tc_pointSize", "te_pointSize", "te_patch_data" };
679
680 if (should_use_geometry_shader)
681 {
682 if (should_pass_point_size_data_in_gs)
683 {
684 n_varyings = sizeof(gs_point_size_varyings) / sizeof(gs_point_size_varyings[0]);
685 varyings = gs_point_size_varyings;
686 varyings_size = varying_position_size + /* gs_tc_position */
687 varying_value1_size + /* gs_tc_value1 */
688 varying_value2_size + /* gs_tc_value2 */
689 varying_position_size + /* gs_te_position */
690 varying_pointSize_size + /* gs_tc_pointSize */
691 varying_pointSize_size; /* gs_te_pointSize */
692
693 varying_tc_position_offset = 0;
694 varying_tc_value1_offset = varying_tc_position_offset + varying_position_size;
695 varying_tc_value2_offset = varying_tc_value1_offset + varying_value1_size;
696 varying_te_position_offset = varying_tc_value2_offset + varying_value2_size;
697 varying_tc_pointSize_offset = varying_te_position_offset + varying_position_size;
698 varying_te_pointSize_offset = varying_tc_pointSize_offset + varying_pointSize_size;
699 }
700 else
701 {
702 n_varyings = sizeof(gs_non_point_size_varyings) / sizeof(gs_non_point_size_varyings[0]);
703 varyings = gs_non_point_size_varyings;
704 varyings_size = varying_position_size + /* gs_tc_position */
705 varying_value1_size + /* gs_tc_value1 */
706 varying_value2_size + /* gs_tc_value2 */
707 varying_position_size; /* gs_te_position */
708
709 varying_tc_position_offset = 0;
710 varying_tc_value1_offset = varying_tc_position_offset + varying_position_size;
711 varying_tc_value2_offset = varying_tc_value1_offset + varying_value1_size;
712 varying_te_position_offset = varying_tc_value2_offset + varying_value2_size;
713 }
714 } /* if (should_use_geometry_shader) */
715 else
716 {
717 if (should_pass_point_size_data_in_ts)
718 {
719 n_varyings = sizeof(non_gs_point_size_varyings) / sizeof(non_gs_point_size_varyings[0]);
720 varyings = non_gs_point_size_varyings;
721 varyings_size = varying_position_size + /* tc_position */
722 varying_value1_size + /* tc_value1 */
723 varying_value2_size + /* tc_value2 */
724 varying_position_size + /* te_position */
725 varying_pointSize_size + /* tc_pointSize */
726 varying_pointSize_size + /* te_pointSize */
727 varying_patch_data_size; /* tc_patch_data */
728
729 varying_tc_position_offset = 0;
730 varying_tc_value1_offset = varying_tc_position_offset + varying_position_size;
731 varying_tc_value2_offset = varying_tc_value1_offset + varying_value1_size;
732 varying_te_position_offset = varying_tc_value2_offset + varying_value2_size;
733 varying_tc_pointSize_offset = varying_te_position_offset + varying_position_size;
734 varying_te_pointSize_offset = varying_tc_pointSize_offset + varying_pointSize_size;
735 varying_te_patch_data_offset = varying_te_pointSize_offset + varying_pointSize_size;
736 }
737 else
738 {
739 n_varyings = sizeof(non_gs_non_point_size_varyings) / sizeof(non_gs_non_point_size_varyings[0]);
740 varyings = non_gs_non_point_size_varyings;
741 varyings_size = varying_position_size + /* tc_position */
742 varying_value1_size + /* tc_value1 */
743 varying_value2_size + /* tc_value2 */
744 varying_position_size + /* te_position */
745 varying_patch_data_size; /* tc_patch_data */
746
747 varying_tc_position_offset = 0;
748 varying_tc_value1_offset = varying_tc_position_offset + varying_position_size;
749 varying_tc_value2_offset = varying_tc_value1_offset + varying_value1_size;
750 varying_te_position_offset = varying_tc_value2_offset + varying_value2_size;
751 varying_te_patch_data_offset = varying_te_position_offset + varying_position_size;
752 }
753 }
754
755 gl.transformFeedbackVaryings(run.po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
756 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
757
758 /* Compile all the shader objects */
759 const glw::GLuint shaders[] = { run.fs_id, run.gs_id, run.tcs_id, run.tes_id, run.vs_id };
760 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
761
762 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
763 {
764 glw::GLuint shader = shaders[n_shader];
765
766 if (shader != 0)
767 {
768 m_utils_ptr->compileShaders(1 /* n_shaders */, &shader, true);
769 }
770 }
771
772 /* Link the program object */
773 gl.linkProgram(run.po_id);
774 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed");
775
776 /* Make sure the linking has succeeded */
777 glw::GLint link_status = GL_FALSE;
778
779 gl.getProgramiv(run.po_id, GL_LINK_STATUS, &link_status);
780 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
781
782 if (link_status != GL_TRUE)
783 {
784 TCU_FAIL("Program linking failed");
785 }
786
787 /* Now that we have a linked program object, it's time to determine how much space
788 * we will need to hold XFB data.
789 */
790 unsigned int bo_size = 0;
791 unsigned int n_result_tess_coords = 0;
792 const float tess_levels[] = /* as per shaders constructed by the test */
793 { 4.0f, 4.0f, 4.0f, 4.0f };
794
795 n_result_tess_coords = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
796 run.primitive_mode, tess_levels, tess_levels, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL,
797 true); /* is_point_mode_enabled */
798
799 if (should_use_geometry_shader)
800 {
801 /* Geometry shader will output twice as many vertices */
802 n_result_tess_coords *= 2;
803 }
804
805 run.n_result_vertices_per_patch = n_result_tess_coords;
806 n_result_tess_coords *= m_n_input_vertices_per_run;
807 bo_size = n_result_tess_coords * varyings_size;
808
809 /* Proceed with buffer object storage allocation */
810 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, /* data */
811 GL_STATIC_DRAW);
812 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
813
814 /* Great, time to actually render the data! */
815 glw::GLenum tf_mode =
816 TessellationShaderUtils::getTFModeForPrimitiveMode(run.primitive_mode, true); /* is_point_mode_enabled */
817
818 gl.useProgram(run.po_id);
819 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
820
821 gl.beginTransformFeedback(tf_mode);
822 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed");
823 {
824 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, m_n_input_vertices_per_run);
825 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() failed");
826 }
827 gl.endTransformFeedback();
828 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
829
830 /* The data should have landed in the buffer object storage by now. Map the BO into
831 * process space. */
832 const void* bo_ptr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
833 bo_size, GL_MAP_READ_BIT);
834
835 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
836
837 /* Extract varyings' data */
838 for (unsigned int n_tess_coord = 0; n_tess_coord < n_result_tess_coords; ++n_tess_coord)
839 {
840 const char* data = (const char*)bo_ptr + n_tess_coord * varyings_size;
841
842 if (varying_tc_position_offset != -1)
843 {
844 const float* position_data((const float*)(data + varying_tc_position_offset));
845 _vec4 new_entry(position_data[0], position_data[1], position_data[2], position_data[3]);
846
847 run.result_tc_position_data.push_back(new_entry);
848 }
849
850 if (varying_tc_value1_offset != -1)
851 {
852 const float* value1_data((const float*)(data + varying_tc_value1_offset));
853 _vec4 new_entry(value1_data[0], value1_data[1], value1_data[2], value1_data[3]);
854
855 run.result_tc_value1_data.push_back(new_entry);
856 }
857
858 if (varying_tc_value2_offset != -1)
859 {
860 const int* value2_data((const int*)(data + varying_tc_value2_offset));
861 _ivec4 new_entry(value2_data[0], value2_data[1], value2_data[2], value2_data[3]);
862
863 run.result_tc_value2_data.push_back(new_entry);
864 }
865
866 if (varying_te_position_offset != -1)
867 {
868 const float* position_data((const float*)(data + varying_te_position_offset));
869 _vec4 new_entry(position_data[0], position_data[1], position_data[2], position_data[3]);
870
871 run.result_te_position_data.push_back(new_entry);
872 }
873
874 if (varying_tc_pointSize_offset != -1)
875 {
876 const float* pointSize_ptr((const float*)(data + varying_tc_pointSize_offset));
877
878 run.result_tc_pointSize_data.push_back(*pointSize_ptr);
879 }
880
881 if (varying_te_pointSize_offset != -1)
882 {
883 const float* pointSize_ptr((const float*)(data + varying_te_pointSize_offset));
884
885 run.result_te_pointSize_data.push_back(*pointSize_ptr);
886 }
887
888 if (varying_te_patch_data_offset != -1)
889 {
890 const float* patch_data_ptr((const float*)(data + varying_te_patch_data_offset));
891 _vec4 new_entry(patch_data_ptr[0], patch_data_ptr[1], patch_data_ptr[2], patch_data_ptr[3]);
892
893 run.result_te_patch_data.push_back(new_entry);
894 }
895 } /* for (all XFB data associated with tessellated coordinates) */
896
897 /* Now that we're done extracting the data we need, we're fine to unmap the buffer object */
898 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
899 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed");
900 }
901
902 /** Executes the test.
903 *
904 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
905 *
906 * Note the function throws exception should an error occur!
907 *
908 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
909 **/
iterate(void)910 tcu::TestNode::IterateResult TessellationShaderTCTEDataPassThrough::iterate(void)
911 {
912 const float epsilon = 1e-5f;
913
914 /* Initialize ES test objects */
915 initTest();
916
917 /* Iterate over all runs */
918 for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); ++run_iterator)
919 {
920 const _run& run = *run_iterator;
921
922 /* Check result tc_pointSize data if available */
923 unsigned int n_vertex = 0;
924
925 for (std::vector<glw::GLfloat>::const_iterator data_iterator = run.result_tc_pointSize_data.begin();
926 data_iterator != run.result_tc_pointSize_data.end(); data_iterator++, n_vertex++)
927 {
928 const glw::GLfloat data = *data_iterator;
929 unsigned int vertex_id = n_vertex / run.n_result_vertices_per_patch;
930 float expected_value = 1.0f / (float(vertex_id) + 1.0f);
931
932 if (run.gs_id != 0 && (n_vertex % 2) != 0)
933 {
934 /* Odd vertices emitted by geometry shader add 1 to all components */
935 expected_value += 1.0f;
936 }
937
938 if (de::abs(data - expected_value) > epsilon)
939 {
940 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_pointSize value found at index [" << n_vertex
941 << "];"
942 " expected:["
943 << expected_value << "], "
944 " found:["
945 << data << "]." << tcu::TestLog::EndMessage;
946
947 TCU_FAIL("Invalid tc_pointSize value found");
948 }
949 }
950
951 /* Check result tc_position data if available */
952 n_vertex -= n_vertex;
953
954 for (std::vector<_vec4>::const_iterator data_iterator = run.result_tc_position_data.begin();
955 data_iterator != run.result_tc_position_data.end(); data_iterator++, n_vertex++)
956 {
957 const _vec4& data = *data_iterator;
958 float expected_value = (float)(n_vertex / run.n_result_vertices_per_patch);
959
960 if (run.gs_id != 0 && (n_vertex % 2) != 0)
961 {
962 /* Odd vertices emitted by geometry shader add 1 to all components */
963 expected_value += 1.0f;
964 }
965
966 if (de::abs(data.x - expected_value) > epsilon || de::abs(data.y - expected_value) > epsilon ||
967 de::abs(data.z - expected_value) > epsilon || de::abs(data.w - expected_value) > epsilon)
968 {
969 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_position value found at index [" << n_vertex
970 << "];"
971 " expected:"
972 " ["
973 << expected_value << ", " << expected_value << ", " << expected_value << ", "
974 << expected_value << "], found:"
975 " ["
976 << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
977 << tcu::TestLog::EndMessage;
978
979 TCU_FAIL("Invalid tc_position value found");
980 }
981 }
982
983 /* Check result tc_value1 data if available */
984 n_vertex -= n_vertex;
985
986 for (std::vector<_vec4>::const_iterator data_iterator = run.result_tc_value1_data.begin();
987 data_iterator != run.result_tc_value1_data.end(); data_iterator++, n_vertex++)
988 {
989 const _vec4& data = *data_iterator;
990 unsigned int vertex_id = n_vertex / run.n_result_vertices_per_patch;
991 _vec4 expected_value = _vec4((float)vertex_id, ((float)vertex_id) * 0.5f, ((float)vertex_id) * 0.25f,
992 ((float)vertex_id) * 0.125f);
993
994 /* TE uses an even vertex outputted by TC, so we need
995 * to multiply the expected value by 2.
996 */
997 expected_value.x *= 2.0f;
998 expected_value.y *= 2.0f;
999 expected_value.z *= 2.0f;
1000 expected_value.w *= 2.0f;
1001
1002 if (run.gs_id != 0 && (n_vertex % 2) != 0)
1003 {
1004 /* Odd vertices emitted by geometry shader add 1 to all components */
1005 expected_value.x += 1.0f;
1006 expected_value.y += 1.0f;
1007 expected_value.z += 1.0f;
1008 expected_value.w += 1.0f;
1009 }
1010
1011 if (de::abs(data.x - expected_value.x) > epsilon || de::abs(data.y - expected_value.y) > epsilon ||
1012 de::abs(data.z - expected_value.z) > epsilon || de::abs(data.w - expected_value.w) > epsilon)
1013 {
1014 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_value1 value found at index [" << n_vertex
1015 << "];"
1016 " expected:"
1017 " ["
1018 << expected_value.x << ", " << expected_value.y << ", " << expected_value.z << ", "
1019 << expected_value.w << "], found:"
1020 " ["
1021 << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
1022 << tcu::TestLog::EndMessage;
1023
1024 TCU_FAIL("Invalid tc_value1 value found");
1025 }
1026 }
1027
1028 /* Check result tc_value2 data if available */
1029 n_vertex -= n_vertex;
1030
1031 for (std::vector<_ivec4>::const_iterator data_iterator = run.result_tc_value2_data.begin();
1032 data_iterator != run.result_tc_value2_data.end(); data_iterator++, n_vertex++)
1033 {
1034 const _ivec4& data = *data_iterator;
1035 unsigned int vertex_id = n_vertex / run.n_result_vertices_per_patch;
1036 _ivec4 expected_value = _ivec4(vertex_id, vertex_id + 1, vertex_id + 2, vertex_id + 3);
1037
1038 if (run.gs_id != 0 && (n_vertex % 2) != 0)
1039 {
1040 /* Odd vertices emitted by geometry shader add 1 to all components */
1041 expected_value.x++;
1042 expected_value.y++;
1043 expected_value.z++;
1044 expected_value.w++;
1045 }
1046
1047 if (data.x != expected_value.x || data.y != expected_value.y || data.z != expected_value.z ||
1048 data.w != expected_value.w)
1049 {
1050 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_value2 value found at index [" << n_vertex
1051 << "];"
1052 " expected:"
1053 " ["
1054 << expected_value.x << ", " << expected_value.y << ", " << expected_value.z << ", "
1055 << expected_value.w << "], found:"
1056 " ["
1057 << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
1058 << tcu::TestLog::EndMessage;
1059
1060 TCU_FAIL("Invalid tc_value2 value found");
1061 }
1062 }
1063
1064 /* Check result te_pointSize data if available */
1065 n_vertex -= n_vertex;
1066
1067 for (std::vector<glw::GLfloat>::const_iterator data_iterator = run.result_te_pointSize_data.begin();
1068 data_iterator != run.result_te_pointSize_data.end(); data_iterator++, n_vertex++)
1069 {
1070 const glw::GLfloat data = *data_iterator;
1071 unsigned int vertex_id = n_vertex / run.n_result_vertices_per_patch;
1072 float expected_value = 2.0f / (float(vertex_id) + 1.0f);
1073
1074 if (run.gs_id != 0 && (n_vertex % 2) != 0)
1075 {
1076 /* Odd vertices emitted by geometry shader add 1 to all components */
1077 expected_value += 1.0f;
1078 }
1079
1080 if (de::abs(data - expected_value) > epsilon)
1081 {
1082 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid te_pointSize value found at index [" << n_vertex
1083 << "];"
1084 " expected:["
1085 << expected_value << "], "
1086 " found:["
1087 << data << "]." << tcu::TestLog::EndMessage;
1088
1089 TCU_FAIL("Invalid te_pointSize value found");
1090 }
1091 }
1092
1093 /* Check result te_position data if available */
1094 n_vertex -= n_vertex;
1095
1096 for (std::vector<_vec4>::const_iterator data_iterator = run.result_te_position_data.begin();
1097 data_iterator != run.result_te_position_data.end(); data_iterator++, n_vertex++)
1098 {
1099 const _vec4& data = *data_iterator;
1100 float expected_value = (float)(n_vertex / run.n_result_vertices_per_patch);
1101
1102 /* te_position should be equal to tc_position, with 3 added to all components */
1103 expected_value += 3.0f;
1104
1105 if (run.gs_id != 0 && (n_vertex % 2) != 0)
1106 {
1107 /* Odd vertices emitted by geometry shader add 1 to all components */
1108 expected_value += 1.0f;
1109 }
1110
1111 if (de::abs(data.x - expected_value) > epsilon || de::abs(data.y - expected_value) > epsilon ||
1112 de::abs(data.z - expected_value) > epsilon || de::abs(data.w - expected_value) > epsilon)
1113 {
1114 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid te_position value found at index [" << n_vertex
1115 << "];"
1116 " expected:"
1117 " ["
1118 << expected_value << ", " << expected_value << ", " << expected_value << ", "
1119 << expected_value << "], found:"
1120 " ["
1121 << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
1122 << tcu::TestLog::EndMessage;
1123
1124 TCU_FAIL("Invalid te_position value found");
1125 }
1126 }
1127
1128 /* Check result tc_patch_data data if available */
1129 n_vertex -= n_vertex;
1130
1131 for (std::vector<_vec4>::const_iterator data_iterator = run.result_te_patch_data.begin();
1132 data_iterator != run.result_te_patch_data.end(); data_iterator++, n_vertex++)
1133 {
1134 const _vec4& data = *data_iterator;
1135 unsigned int vertex_id = n_vertex / run.n_result_vertices_per_patch;
1136 _vec4 expected_value = _vec4((float)vertex_id, ((float)vertex_id) * 0.5f, ((float)vertex_id) * 0.25f,
1137 ((float)vertex_id) * 0.125f);
1138
1139 /* TE uses an even vertex outputted by TC, so we need
1140 * to multiply the expected value by 2.
1141 */
1142 expected_value.x *= 2.0f;
1143 expected_value.y *= 2.0f;
1144 expected_value.z *= 2.0f;
1145 expected_value.w *= 2.0f;
1146
1147 if (de::abs(data.x - expected_value.x) > epsilon || de::abs(data.y - expected_value.y) > epsilon ||
1148 de::abs(data.z - expected_value.z) > epsilon || de::abs(data.w - expected_value.w) > epsilon)
1149 {
1150 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid tc_patch_data value found at index ["
1151 << n_vertex << "];"
1152 " expected:"
1153 " ["
1154 << expected_value.x << ", " << expected_value.y << ", " << expected_value.z << ", "
1155 << expected_value.w << "], found:"
1156 " ["
1157 << data.x << ", " << data.y << ", " << data.z << ", " << data.w << "]."
1158 << tcu::TestLog::EndMessage;
1159
1160 TCU_FAIL("Invalid tc_patch_data value found");
1161 }
1162 }
1163 } /* for (all runs) */
1164
1165 /* All done */
1166 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1167 return STOP;
1168 }
1169
1170 /** Constructor
1171 *
1172 * @param context Test context
1173 **/
TessellationShaderTCTEgl_in(Context & context,const ExtParameters & extParams)1174 TessellationShaderTCTEgl_in::TessellationShaderTCTEgl_in(Context& context, const ExtParameters& extParams)
1175 : TestCaseBase(context, extParams, "gl_in", "Verifies values of gl_in[] in a tessellation evaluation shader "
1176 "are taken from output variables of a tessellation control shader"
1177 "if one is present.")
1178 , m_bo_id(0)
1179 , m_fs_id(0)
1180 , m_po_id(0)
1181 , m_tcs_id(0)
1182 , m_tes_id(0)
1183 , m_vao_id(0)
1184 , m_vs_id(0)
1185 {
1186 /* Left blank on purpose */
1187 }
1188
1189 /** Deinitializes all ES objects created for the test. */
deinit()1190 void TessellationShaderTCTEgl_in::deinit()
1191 {
1192 /** Call base class' deinit() function */
1193 TestCaseBase::deinit();
1194
1195 if (!m_is_tessellation_shader_supported)
1196 {
1197 return;
1198 }
1199
1200 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1201
1202 /* Revert TF buffer object bindings */
1203 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
1204 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
1205
1206 /* Reset GL_PATCH_VERTICES_EXT value to the default setting */
1207 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
1208
1209 /* Disable GL_RASTERIZER_DISCARD mdoe */
1210 gl.disable(GL_RASTERIZER_DISCARD);
1211
1212 /* Unbind vertex array object */
1213 gl.bindVertexArray(0);
1214
1215 /* Release all objects we might've created */
1216 if (m_bo_id != 0)
1217 {
1218 gl.deleteBuffers(1, &m_bo_id);
1219
1220 m_bo_id = 0;
1221 }
1222
1223 if (m_fs_id != 0)
1224 {
1225 gl.deleteShader(m_fs_id);
1226
1227 m_fs_id = 0;
1228 }
1229
1230 if (m_po_id != 0)
1231 {
1232 gl.deleteProgram(m_po_id);
1233
1234 m_po_id = 0;
1235 }
1236
1237 if (m_tcs_id != 0)
1238 {
1239 gl.deleteShader(m_tcs_id);
1240
1241 m_tcs_id = 0;
1242 }
1243
1244 if (m_tes_id != 0)
1245 {
1246 gl.deleteShader(m_tes_id);
1247
1248 m_tes_id = 0;
1249 }
1250
1251 if (m_vs_id != 0)
1252 {
1253 gl.deleteShader(m_vs_id);
1254
1255 m_vs_id = 0;
1256 }
1257
1258 if (m_vao_id != 0)
1259 {
1260 gl.deleteVertexArrays(1, &m_vao_id);
1261
1262 m_vao_id = 0;
1263 }
1264 }
1265
1266 /** Initializes all ES objects that will be used for the test. */
initTest()1267 void TessellationShaderTCTEgl_in::initTest()
1268 {
1269 /* The test requires EXT_tessellation_shader */
1270 if (!m_is_tessellation_shader_supported)
1271 {
1272 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
1273 }
1274
1275 /* Generate a program object we will later configure */
1276 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1277
1278 /* Initialize vertex array object */
1279 gl.genVertexArrays(1, &m_vao_id);
1280 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
1281
1282 gl.bindVertexArray(m_vao_id);
1283 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
1284
1285 /* Create program object */
1286 m_po_id = gl.createProgram();
1287
1288 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
1289
1290 /* Generate shader objects the test will use */
1291 m_fs_id = gl.createShader(GL_FRAGMENT_SHADER);
1292 m_tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
1293 m_tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
1294 m_vs_id = gl.createShader(GL_VERTEX_SHADER);
1295
1296 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
1297
1298 /* Configure fragment shader */
1299 const char* fs_body = "${VERSION}\n"
1300 "\n"
1301 "void main()\n"
1302 "{\n"
1303 "}\n";
1304
1305 shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
1306 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader object");
1307
1308 /* Configure tessellation control shader */
1309 const char* tc_body = "${VERSION}\n"
1310 "\n"
1311 /* Required EXT_tessellation_shader functionality */
1312 "${TESSELLATION_SHADER_REQUIRE}\n"
1313 "\n"
1314 "layout (vertices = 1) out;\n"
1315 "\n"
1316 "out float out_float[];\n"
1317 "out int out_int[];\n"
1318 "out ivec3 out_ivec3[];\n"
1319 "out mat2 out_mat2[];\n"
1320 "out uint out_uint[];\n"
1321 "out uvec2 out_uvec2[];\n"
1322 "out vec4 out_vec4[];\n"
1323 "\n"
1324 "out struct\n"
1325 "{\n"
1326 " int test1;\n"
1327 " float test2;\n"
1328 "} out_struct[];\n"
1329 /* Body */
1330 "void main()\n"
1331 "{\n"
1332 " gl_out [gl_InvocationID].gl_Position = vec4(5.0, 6.0, 7.0, 8.0);\n"
1333 " gl_TessLevelOuter[0] = 1.0;\n"
1334 " gl_TessLevelOuter[1] = 1.0;\n"
1335 "\n"
1336 " out_float[gl_InvocationID] = 22.0;\n"
1337 " out_int [gl_InvocationID] = 23;\n"
1338 " out_ivec3[gl_InvocationID] = ivec3(24, 25, 26);\n"
1339 " out_mat2 [gl_InvocationID] = mat2(vec2(27.0, 28.0), vec2(29.0, 30.0) );\n"
1340 " out_uint [gl_InvocationID] = 31u;\n"
1341 " out_uvec2[gl_InvocationID] = uvec2(32, 33);\n"
1342 " out_vec4 [gl_InvocationID] = vec4(34.0, 35.0, 36.0, 37.0);\n"
1343 "\n"
1344 " out_struct[gl_InvocationID].test1 = 38;\n"
1345 " out_struct[gl_InvocationID].test2 = 39.0;\n"
1346 "}\n";
1347
1348 shaderSourceSpecialized(m_tcs_id, 1 /* count */, &tc_body);
1349 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader object");
1350
1351 /* Configure tessellation evaluation shader */
1352 const char* te_body = "${VERSION}\n"
1353 "\n"
1354 "${TESSELLATION_SHADER_REQUIRE}\n"
1355 "\n"
1356 "layout (isolines, point_mode) in;\n"
1357 "\n"
1358 "in float out_float[];\n"
1359 "in int out_int[];\n"
1360 "in ivec3 out_ivec3[];\n"
1361 "in mat2 out_mat2[];\n"
1362 "in uint out_uint[];\n"
1363 "in uvec2 out_uvec2[];\n"
1364 "in vec4 out_vec4[];\n"
1365 "in struct\n"
1366 "{\n"
1367 " int test1;\n"
1368 " float test2;\n"
1369 "} out_struct[];\n"
1370 "\n"
1371 "out float result_float;\n"
1372 "flat out int result_int;\n"
1373 "flat out ivec3 result_ivec3;\n"
1374 "out mat2 result_mat2;\n"
1375 "flat out int result_struct_test1;\n"
1376 "out float result_struct_test2;\n"
1377 "flat out uint result_uint;\n"
1378 "flat out uvec2 result_uvec2;\n"
1379 "out vec4 result_vec4;\n"
1380 "\n"
1381 "void main()\n"
1382 "{\n"
1383 " gl_Position = gl_in[0].gl_Position;\n"
1384 "\n"
1385 " result_float = out_float [0];\n"
1386 " result_int = out_int [0];\n"
1387 " result_ivec3 = out_ivec3 [0];\n"
1388 " result_mat2 = out_mat2 [0];\n"
1389 " result_struct_test1 = out_struct[0].test1;\n"
1390 " result_struct_test2 = out_struct[0].test2;\n"
1391 " result_uint = out_uint [0];\n"
1392 " result_uvec2 = out_uvec2 [0];\n"
1393 " result_vec4 = out_vec4 [0];\n"
1394 "}\n";
1395
1396 shaderSourceSpecialized(m_tes_id, 1 /* count */, &te_body);
1397 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader object");
1398
1399 /* Configure vertex shader */
1400 const char* vs_body = "${VERSION}\n"
1401 "\n"
1402 "${SHADER_IO_BLOCKS_ENABLE}\n"
1403 "\n"
1404 "out float out_float;\n"
1405 "flat out int out_int;\n"
1406 "flat out ivec3 out_ivec3;\n"
1407 "out mat2 out_mat2;\n"
1408 "flat out uint out_uint;\n"
1409 "flat out uvec2 out_uvec2;\n"
1410 "out vec4 out_vec4;\n"
1411 "\n"
1412 "flat out struct\n"
1413 "{\n"
1414 " int test1;\n"
1415 " float test2;\n"
1416 "} out_struct;\n"
1417 "\n"
1418 "void main()\n"
1419 "{\n"
1420 " gl_Position = vec4(1.0, 2.0, 3.0, 4.0);\n"
1421 "\n"
1422 " out_float = 1.0;\n"
1423 " out_int = 2;\n"
1424 " out_ivec3 = ivec3(3, 4, 5);\n"
1425 " out_mat2 = mat2(vec2(6.0, 7.0), vec2(8.0, 9.0) );\n"
1426 " out_uint = 10u;\n"
1427 " out_uvec2 = uvec2(11u, 12u);\n"
1428 " out_vec4 = vec4(12.0, 13.0, 14.0, 15.0);\n"
1429 " out_struct.test1 = 20;\n"
1430 " out_struct.test2 = 21.0;\n"
1431 "}\n";
1432
1433 shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
1434 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader object");
1435
1436 /* Compile all shaders of our interest */
1437 const glw::GLuint shaders[] = { m_fs_id, m_tcs_id, m_tes_id, m_vs_id };
1438 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
1439
1440 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
1441 {
1442 glw::GLint compile_status = GL_FALSE;
1443 glw::GLuint shader = shaders[n_shader];
1444
1445 gl.compileShader(shader);
1446 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
1447
1448 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
1449 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
1450
1451 if (compile_status != GL_TRUE)
1452 {
1453 const char* src[] = { fs_body, tc_body, te_body, vs_body };
1454 m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader
1455 << " failed.\n"
1456 << "Info log:\n"
1457 << getCompilationInfoLog(shader) << "Shader:\n"
1458 << src[n_shader] << tcu::TestLog::EndMessage;
1459
1460 TCU_FAIL("Shader compilation failed");
1461 }
1462 } /* for (all shaders) */
1463
1464 /* Attach the shaders to the test program object, set up XFB and then link the program */
1465 glw::GLint link_status = GL_FALSE;
1466 glw::GLint n_xfb_varyings = 0;
1467 const glw::GLchar** xfb_varyings = NULL;
1468 glw::GLint xfb_size = 0;
1469
1470 getXFBProperties(&xfb_varyings, &n_xfb_varyings, &xfb_size);
1471
1472 gl.transformFeedbackVaryings(m_po_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
1473 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
1474
1475 gl.attachShader(m_po_id, m_fs_id);
1476 gl.attachShader(m_po_id, m_tcs_id);
1477 gl.attachShader(m_po_id, m_tes_id);
1478 gl.attachShader(m_po_id, m_vs_id);
1479 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
1480
1481 gl.linkProgram(m_po_id);
1482 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
1483
1484 gl.getProgramiv(m_po_id, GL_LINK_STATUS, &link_status);
1485 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
1486
1487 if (link_status != GL_TRUE)
1488 {
1489 TCU_FAIL("Program linking failed");
1490 }
1491
1492 /* Generate and set up a buffer object we will use to hold XFBed data. */
1493 gl.genBuffers(1, &m_bo_id);
1494 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
1495
1496 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
1497 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
1498 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
1499 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
1500
1501 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_size, NULL /* data */, GL_STATIC_DRAW);
1502 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
1503
1504 /* We're good to execute the test! */
1505 }
1506
1507 /** Retrieves XFB-specific properties that are used in various locations of
1508 * this test implementation.
1509 *
1510 * @param out_names Deref will be used to store location of an array keeping
1511 * names of varyings that should be used for TF. Can be NULL,
1512 * in which case nothing will be stored under *out_names.
1513 * @param out_n_names Deref will be used to store number of strings the @param
1514 * out_names array holds. Can be NULL, in which case nothing
1515 * will be stored under *out_n_names.
1516 * @param out_xfb_size Deref will be used to store amount of bytes needed to hold
1517 * all data generated by a draw call used by this test. Can be
1518 * NULL, in which case nothing will be stored under *out_xfb_size.
1519 **/
getXFBProperties(const glw::GLchar *** out_names,glw::GLint * out_n_names,glw::GLint * out_xfb_size)1520 void TessellationShaderTCTEgl_in::getXFBProperties(const glw::GLchar*** out_names, glw::GLint* out_n_names,
1521 glw::GLint* out_xfb_size)
1522 {
1523 static const glw::GLchar* xfb_varyings[] = { "result_float", "result_int", "result_ivec3",
1524 "result_mat2", "result_struct_test1", "result_struct_test2",
1525 "result_uint", "result_uvec2", "result_vec4",
1526 "gl_Position" };
1527 static const unsigned int xfb_size = (sizeof(float) + /* result_float */
1528 sizeof(int) + /* result_int */
1529 sizeof(int) * 3 + /* result_ivec3 */
1530 sizeof(float) * 4 + /* result_mat2 */
1531 sizeof(int) + /* result_struct_test1 */
1532 sizeof(float) + /* result_struct_test2 */
1533 sizeof(int) + /* result_uint */
1534 sizeof(int) * 2 + /* result_uvec2 */
1535 sizeof(float) * 4 + /* result_vec4 */
1536 sizeof(float) * 4) * /* gl_Position */
1537 2; /* two points will be generated by tessellation */
1538
1539 static const unsigned int n_xfb_varyings = sizeof(xfb_varyings) / sizeof(xfb_varyings[0]);
1540
1541 if (out_names != NULL)
1542 {
1543 *out_names = xfb_varyings;
1544 }
1545
1546 if (out_n_names != NULL)
1547 {
1548 *out_n_names = n_xfb_varyings;
1549 }
1550
1551 if (out_xfb_size != NULL)
1552 {
1553 /* NOTE: Tessellator is expected to generate two points for the purpose of
1554 * this test, which is why we need to multiply the amount of bytes store
1555 * in xfb_size by two.
1556 */
1557 *out_xfb_size = xfb_size * 2;
1558 }
1559 }
1560
1561 /** Executes the test.
1562 *
1563 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
1564 *
1565 * Note the function throws exception should an error occur!
1566 *
1567 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
1568 **/
iterate(void)1569 tcu::TestNode::IterateResult TessellationShaderTCTEgl_in::iterate(void)
1570 {
1571 /* Initialize ES test objects */
1572 initTest();
1573
1574 /* Our program object takes a single vertex per patch */
1575 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1576
1577 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
1578 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed");
1579
1580 /* Render the geometry. We're only interested in XFB data, not the visual outcome,
1581 * so disable rasterization before we fire a draw call.
1582 */
1583 gl.useProgram(m_po_id);
1584 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
1585
1586 gl.enable(GL_RASTERIZER_DISCARD);
1587 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed");
1588
1589 gl.beginTransformFeedback(GL_POINTS);
1590 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback(GL_POINTS) call failed");
1591 {
1592 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
1593
1594 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
1595 }
1596 gl.endTransformFeedback();
1597 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
1598
1599 /* Download the data we stored with TF */
1600 glw::GLint n_xfb_names = 0;
1601 void* rendered_data = NULL;
1602 const glw::GLchar** xfb_names = NULL;
1603 glw::GLint xfb_size = 0;
1604
1605 getXFBProperties(&xfb_names, &n_xfb_names, &xfb_size);
1606
1607 rendered_data = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* offset */, xfb_size, GL_MAP_READ_BIT);
1608 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
1609
1610 /* Move through the result buffer and make sure the values we retrieved are valid.
1611 * Note that two points will be generated by the tessellator, so run the checks
1612 * twice.
1613 */
1614 typedef enum {
1615 XFB_VARYING_TYPE_FLOAT,
1616 XFB_VARYING_TYPE_INT,
1617
1618 XFB_VARYING_TYPE_UNKNOWN
1619 } _xfb_varying_type;
1620
1621 unsigned char* traveller_ptr = (unsigned char*)rendered_data;
1622
1623 for (glw::GLint n_point = 0; n_point < 2 /* points */; ++n_point)
1624 {
1625 for (glw::GLint n_xfb_name = 0; n_xfb_name < n_xfb_names; ++n_xfb_name)
1626 {
1627 glw::GLfloat expected_value_float[4] = { 0.0f };
1628 glw::GLint expected_value_int[4] = { 0 };
1629 std::string name = xfb_names[n_xfb_name];
1630 unsigned int n_varying_components = 0;
1631 _xfb_varying_type varying_type = XFB_VARYING_TYPE_UNKNOWN;
1632
1633 if (name.compare("result_float") == 0)
1634 {
1635 expected_value_float[0] = 22.0f;
1636 n_varying_components = 1;
1637 varying_type = XFB_VARYING_TYPE_FLOAT;
1638 }
1639 else if (name.compare("result_int") == 0)
1640 {
1641 expected_value_int[0] = 23;
1642 n_varying_components = 1;
1643 varying_type = XFB_VARYING_TYPE_INT;
1644 }
1645 else if (name.compare("result_ivec3") == 0)
1646 {
1647 expected_value_int[0] = 24;
1648 expected_value_int[1] = 25;
1649 expected_value_int[2] = 26;
1650 n_varying_components = 3;
1651 varying_type = XFB_VARYING_TYPE_INT;
1652 }
1653 else if (name.compare("result_mat2") == 0)
1654 {
1655 expected_value_float[0] = 27.0f;
1656 expected_value_float[1] = 28.0f;
1657 expected_value_float[2] = 29.0f;
1658 expected_value_float[3] = 30.0f;
1659 n_varying_components = 4;
1660 varying_type = XFB_VARYING_TYPE_FLOAT;
1661 }
1662 else if (name.compare("result_struct_test1") == 0)
1663 {
1664 expected_value_int[0] = 38;
1665 n_varying_components = 1;
1666 varying_type = XFB_VARYING_TYPE_INT;
1667 }
1668 else if (name.compare("result_struct_test2") == 0)
1669 {
1670 expected_value_float[0] = 39.0f;
1671 n_varying_components = 1;
1672 varying_type = XFB_VARYING_TYPE_FLOAT;
1673 }
1674 else if (name.compare("result_uint") == 0)
1675 {
1676 expected_value_int[0] = 31;
1677 n_varying_components = 1;
1678 varying_type = XFB_VARYING_TYPE_INT;
1679 }
1680 else if (name.compare("result_uvec2") == 0)
1681 {
1682 expected_value_int[0] = 32;
1683 expected_value_int[1] = 33;
1684 n_varying_components = 2;
1685 varying_type = XFB_VARYING_TYPE_INT;
1686 }
1687 else if (name.compare("result_vec4") == 0)
1688 {
1689 expected_value_float[0] = 34.0f;
1690 expected_value_float[1] = 35.0f;
1691 expected_value_float[2] = 36.0f;
1692 expected_value_float[3] = 37.0f;
1693 n_varying_components = 4;
1694 varying_type = XFB_VARYING_TYPE_FLOAT;
1695 }
1696 else if (name.compare("gl_Position") == 0)
1697 {
1698 expected_value_float[0] = 5.0f;
1699 expected_value_float[1] = 6.0f;
1700 expected_value_float[2] = 7.0f;
1701 expected_value_float[3] = 8.0f;
1702 n_varying_components = 4;
1703 varying_type = XFB_VARYING_TYPE_FLOAT;
1704 }
1705 else
1706 {
1707 TCU_FAIL("Unrecognized XFB name");
1708 }
1709
1710 /* Move through the requested amount of components and perform type-specific
1711 * comparison.
1712 */
1713 const float epsilon = (float)1e-5;
1714
1715 for (unsigned int n_component = 0; n_component < n_varying_components; ++n_component)
1716 {
1717 switch (varying_type)
1718 {
1719 case XFB_VARYING_TYPE_FLOAT:
1720 {
1721 glw::GLfloat* rendered_value = (glw::GLfloat*)traveller_ptr;
1722
1723 if (de::abs(*rendered_value - expected_value_float[n_component]) > epsilon)
1724 {
1725 m_testCtx.getLog()
1726 << tcu::TestLog::Message << "Invalid component at index [" << n_component << "] "
1727 << "(found:" << *rendered_value << " expected:" << expected_value_float[n_component]
1728 << ") for varying [" << name.c_str() << "]" << tcu::TestLog::EndMessage;
1729 }
1730
1731 traveller_ptr += sizeof(glw::GLfloat);
1732
1733 break;
1734 }
1735
1736 case XFB_VARYING_TYPE_INT:
1737 {
1738 glw::GLint* rendered_value = (glw::GLint*)traveller_ptr;
1739
1740 if (*rendered_value != expected_value_int[n_component])
1741 {
1742 m_testCtx.getLog()
1743 << tcu::TestLog::Message << "Invalid component at index [" << n_component << "] "
1744 << "(found:" << *rendered_value << " expected:" << expected_value_int[n_component]
1745 << ") for varying [" << name.c_str() << "]" << tcu::TestLog::EndMessage;
1746
1747 TCU_FAIL("Invalid rendered value");
1748 }
1749
1750 traveller_ptr += sizeof(glw::GLint);
1751
1752 break;
1753 }
1754
1755 default:
1756 {
1757 TCU_FAIL("Unrecognized varying type");
1758 }
1759 } /* switch(varying_type) */
1760
1761 } /* for (all components) */
1762 } /* for (all XFBed variables) */
1763 } /* for (both points) */
1764
1765 /* Unmap the BO */
1766 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1767 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
1768
1769 /* All done */
1770 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1771 return STOP;
1772 }
1773
1774 /** Constructor
1775 *
1776 * @param context Test context
1777 **/
1778 TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::
TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize(Context & context,const ExtParameters & extParams)1779 TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize(Context& context, const ExtParameters& extParams)
1780 : TestCaseBase(context, extParams, "gl_MaxPatchVertices_Position_PointSize",
1781 "Verifies gl_Position and gl_PointSize (if supported) "
1782 "are set to correct values in TE stage. Checks if up to "
1783 "gl_MaxPatchVertices input block values can be accessed "
1784 "from TE stage. Also verifies if TC/TE stage properties "
1785 "can be correctly queried for both regular and separate "
1786 "program objects.")
1787 , m_bo_id(0)
1788 , m_gl_max_patch_vertices_value(0)
1789 , m_gl_max_tess_gen_level_value(0)
1790 , m_utils_ptr(DE_NULL)
1791 , m_vao_id(0)
1792 {
1793 /* Left blank on purpose */
1794 }
1795
1796 /** Deinitializes all ES objects created for the test. */
deinit()1797 void TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::deinit()
1798 {
1799 /** Call base class' deinit() function */
1800 TestCaseBase::deinit();
1801
1802 if (!m_is_tessellation_shader_supported)
1803 {
1804 return;
1805 }
1806
1807 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1808
1809 /* Revert TF buffer object bindings */
1810 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
1811 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
1812
1813 /* Reset GL_PATCH_VERTICES_EXT value to the default setting */
1814 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
1815
1816 /* Disable GL_RASTERIZER_DISCARD mode */
1817 gl.disable(GL_RASTERIZER_DISCARD);
1818
1819 /* Unbind vertex array object */
1820 gl.bindVertexArray(0);
1821
1822 /* Release all objects we might've created */
1823 if (m_bo_id != 0)
1824 {
1825 gl.deleteBuffers(1, &m_bo_id);
1826
1827 m_bo_id = 0;
1828 }
1829 if (m_vao_id != 0)
1830 {
1831 gl.deleteVertexArrays(1, &m_vao_id);
1832
1833 m_vao_id = 0;
1834 }
1835
1836 if (m_utils_ptr != DE_NULL)
1837 {
1838 delete m_utils_ptr;
1839
1840 m_utils_ptr = DE_NULL;
1841 }
1842
1843 /* Release all test runs */
1844 for (_runs::iterator it = m_runs.begin(); it != m_runs.end(); ++it)
1845 {
1846 deinitTestRun(*it);
1847 }
1848 m_runs.clear();
1849 }
1850
1851 /** Deinitializes all ES objects generated for a test run */
deinitTestRun(_run & run)1852 void TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::deinitTestRun(_run& run)
1853 {
1854 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1855
1856 if (run.fs_id != 0)
1857 {
1858 gl.deleteShader(run.fs_id);
1859
1860 run.fs_id = 0;
1861 }
1862
1863 if (run.fs_program_id != 0)
1864 {
1865 gl.deleteProgram(run.fs_program_id);
1866
1867 run.fs_program_id = 0;
1868 }
1869
1870 if (run.pipeline_object_id != 0)
1871 {
1872 gl.deleteProgramPipelines(1, &run.pipeline_object_id);
1873
1874 run.pipeline_object_id = 0;
1875 }
1876
1877 if (run.po_id != 0)
1878 {
1879 gl.deleteProgram(run.po_id);
1880
1881 run.po_id = 0;
1882 }
1883
1884 if (run.tc_id != 0)
1885 {
1886 gl.deleteShader(run.tc_id);
1887
1888 run.tc_id = 0;
1889 }
1890
1891 if (run.tc_program_id != 0)
1892 {
1893 gl.deleteProgram(run.tc_program_id);
1894
1895 run.tc_program_id = 0;
1896 }
1897
1898 if (run.te_id != 0)
1899 {
1900 gl.deleteShader(run.te_id);
1901
1902 run.te_id = 0;
1903 }
1904
1905 if (run.te_program_id != 0)
1906 {
1907 gl.deleteProgram(run.te_program_id);
1908
1909 run.te_program_id = 0;
1910 }
1911
1912 if (run.vs_id != 0)
1913 {
1914 gl.deleteShader(run.vs_id);
1915
1916 run.vs_id = 0;
1917 }
1918
1919 if (run.vs_program_id != 0)
1920 {
1921 gl.deleteProgram(run.vs_program_id);
1922
1923 run.vs_program_id = 0;
1924 }
1925 }
1926
1927 /** Retrieves a minimal fragment shader code to be used for forming program objects
1928 * used by the test.
1929 *
1930 * @return As per description.
1931 **/
getFragmentShaderCode(bool should_accept_pointsize_data)1932 std::string TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::getFragmentShaderCode(
1933 bool should_accept_pointsize_data)
1934 {
1935 // Requires input to match previous stage's output
1936 std::stringstream result_code;
1937
1938 result_code << "${VERSION}\n"
1939 "\n"
1940 "${SHADER_IO_BLOCKS_REQUIRE}\n"
1941 "\n"
1942 "precision highp float;\n"
1943 "precision highp int;\n"
1944 "out layout (location = 0) vec4 col;\n";
1945
1946 if (should_accept_pointsize_data)
1947 {
1948 result_code << "in float te_pointsize;\n";
1949 }
1950
1951 result_code << "in vec4 te_position;\n"
1952 "in vec2 te_value1;\n"
1953 "in flat ivec4 te_value2;\n"
1954 "\n"
1955 "void main()\n"
1956 "{\n"
1957 " col = vec4(1.0, 1.0, 1.0, 1.0);\n"
1958 "}\n";
1959
1960 return result_code.str();
1961 }
1962
1963 /** Retrieves tessellation control shader source code, given user-provided arguments.
1964 *
1965 * @param should_pass_pointsize_data true if Tessellation Control shader should configure
1966 * gl_PointSize value. This should be only set to true
1967 * if the tested ES implementation reports support of
1968 * GL_EXT_tessellation_point_size extension.
1969 * @param inner_tess_levels Two FP values defining inner tessellation level values.
1970 * Must not be NULL.
1971 * @param outer_tess_levels Four FP values defining outer tessellation level values.
1972 * Must not be NULL.
1973 *
1974 * @return As per description.
1975 **/
getTessellationControlShaderCode(bool should_pass_pointsize_data,const glw::GLfloat * inner_tess_levels,const glw::GLfloat * outer_tess_levels)1976 std::string TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::getTessellationControlShaderCode(
1977 bool should_pass_pointsize_data, const glw::GLfloat* inner_tess_levels, const glw::GLfloat* outer_tess_levels)
1978 {
1979 std::stringstream result_code;
1980
1981 result_code << "${VERSION}\n"
1982 "\n"
1983 "${TESSELLATION_SHADER_REQUIRE}\n";
1984
1985 if (should_pass_pointsize_data)
1986 {
1987 result_code << "${TESSELLATION_POINT_SIZE_REQUIRE}\n";
1988 }
1989
1990 result_code << "\n"
1991 "layout(vertices = "
1992 << m_gl_max_patch_vertices_value << ") out;\n"
1993 "\n";
1994 if (should_pass_pointsize_data)
1995 {
1996 result_code << "${IN_PER_VERTEX_DECL_ARRAY_POINT_SIZE}";
1997 result_code << "${OUT_PER_VERTEX_DECL_ARRAY_POINT_SIZE}";
1998 }
1999 else
2000 {
2001 result_code << "${IN_PER_VERTEX_DECL_ARRAY}";
2002 result_code << "${OUT_PER_VERTEX_DECL_ARRAY}";
2003 }
2004 result_code << "out OUT_TC\n"
2005 "{\n"
2006 " vec2 value1;\n"
2007 " ivec4 value2;\n"
2008 "} result[];\n"
2009 "\n"
2010 "void main()\n"
2011 "{\n";
2012
2013 if (should_pass_pointsize_data)
2014 {
2015 result_code << " gl_out[gl_InvocationID].gl_PointSize = 1.0 / float(gl_InvocationID + 1);\n";
2016 }
2017
2018 result_code << " gl_out[gl_InvocationID].gl_Position = vec4( float(gl_InvocationID * 4 + 0), "
2019 "float(gl_InvocationID * 4 + 1),\n"
2020 " float(gl_InvocationID * 4 + 2), "
2021 "float(gl_InvocationID * 4 + 3));\n"
2022 " result[gl_InvocationID].value1 = vec2(1.0 / float(gl_InvocationID + 1), 1.0 / "
2023 "float(gl_InvocationID + 2) );\n"
2024 " result[gl_InvocationID].value2 = ivec4( gl_InvocationID + 1, "
2025 "gl_InvocationID + 2,\n"
2026 " gl_InvocationID + 3, "
2027 "gl_InvocationID + 4);\n"
2028 "\n"
2029 " gl_TessLevelInner[0] = float("
2030 << inner_tess_levels[0] << ");\n"
2031 " gl_TessLevelInner[1] = float("
2032 << inner_tess_levels[1] << ");\n"
2033 " gl_TessLevelOuter[0] = float("
2034 << outer_tess_levels[0] << ");\n"
2035 " gl_TessLevelOuter[1] = float("
2036 << outer_tess_levels[1] << ");\n"
2037 " gl_TessLevelOuter[2] = float("
2038 << outer_tess_levels[2] << ");\n"
2039 " gl_TessLevelOuter[3] = float("
2040 << outer_tess_levels[3] << ");\n"
2041 "}\n";
2042
2043 return result_code.str();
2044 }
2045
2046 /** Retrieves tessellation evaluation shader source code, given user-provided arguments.
2047 *
2048 * @param should_pass_pointsize_data true if Tessellation Evaluation shader should set
2049 * gl_PointSize to the value set by Tessellation Control
2050 * stage. This should be only set to true if the tested
2051 * ES implementation reports support of GL_EXT_tessellation_point_size
2052 * extension, and TC stage assigns a value to gl_PointSize.
2053 * @param primitive_mode Primitive mode to use for the stage.
2054 * @param vertex_ordering Vertex ordering to use for the stage.
2055 * @param vertex_spacing Vertex spacing to use for the stage.
2056 * @param is_point_mode_enabled true to make the TE stage work in point mode, false otherwise.
2057 *
2058 * @return As per description.
2059 **/
getTessellationEvaluationShaderCode(bool should_pass_pointsize_data,_tessellation_primitive_mode primitive_mode,_tessellation_shader_vertex_ordering vertex_ordering,_tessellation_shader_vertex_spacing vertex_spacing,bool is_point_mode_enabled)2060 std::string TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::getTessellationEvaluationShaderCode(
2061 bool should_pass_pointsize_data, _tessellation_primitive_mode primitive_mode,
2062 _tessellation_shader_vertex_ordering vertex_ordering, _tessellation_shader_vertex_spacing vertex_spacing,
2063 bool is_point_mode_enabled)
2064 {
2065 std::stringstream result_sstream;
2066 std::string result;
2067
2068 result_sstream << "${VERSION}\n"
2069 "\n"
2070 "${TESSELLATION_SHADER_REQUIRE}\n";
2071
2072 if (should_pass_pointsize_data)
2073 {
2074 result_sstream << "${TESSELLATION_POINT_SIZE_REQUIRE}\n";
2075 }
2076
2077 result_sstream << "\n"
2078 "layout (TESSELLATOR_PRIMITIVE_MODE VERTEX_SPACING_MODE VERTEX_ORDERING POINT_MODE) in;\n"
2079 "\n";
2080 if (should_pass_pointsize_data)
2081 {
2082 result_sstream << "${IN_PER_VERTEX_DECL_ARRAY_POINT_SIZE}";
2083 result_sstream << "${OUT_PER_VERTEX_DECL_POINT_SIZE}";
2084 }
2085 else
2086 {
2087 result_sstream << "${IN_PER_VERTEX_DECL_ARRAY}";
2088 result_sstream << "${OUT_PER_VERTEX_DECL}";
2089 }
2090 result_sstream << "in OUT_TC\n"
2091 "{\n"
2092 " vec2 value1;\n"
2093 " ivec4 value2;\n"
2094 "} tc_data[];\n"
2095 "\n";
2096
2097 if (should_pass_pointsize_data)
2098 {
2099 result_sstream << "out float te_pointsize;\n";
2100 }
2101
2102 result_sstream << "out vec4 te_position;\n"
2103 "out vec2 te_value1;\n"
2104 "out flat ivec4 te_value2;\n"
2105 "\n"
2106 "void main()\n"
2107 "{\n";
2108
2109 if (should_pass_pointsize_data)
2110 {
2111 result_sstream << " te_pointsize = 0.0;\n";
2112 }
2113
2114 result_sstream << " te_position = vec4 (0.0);\n"
2115 " te_value1 = vec2 (0.0);\n"
2116 " te_value2 = ivec4(0);\n"
2117 "\n"
2118 " for (int n = 0; n < "
2119 << m_gl_max_patch_vertices_value << "; ++n)\n"
2120 " {\n";
2121
2122 if (should_pass_pointsize_data)
2123 {
2124 result_sstream << " te_pointsize += gl_in[n].gl_PointSize;\n";
2125 }
2126
2127 result_sstream << " te_position += gl_in [n].gl_Position;\n"
2128 " te_value1 += tc_data[n].value1;\n"
2129 " te_value2 += tc_data[n].value2;\n"
2130 " }\n"
2131 "}\n";
2132
2133 result = result_sstream.str();
2134
2135 /* Replace the tokens */
2136 const char* point_mode_token = "POINT_MODE";
2137 std::size_t point_mode_token_index = std::string::npos;
2138 std::string primitive_mode_string = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
2139 const char* primitive_mode_token = "TESSELLATOR_PRIMITIVE_MODE";
2140 std::size_t primitive_mode_token_index = std::string::npos;
2141 std::string vertex_ordering_string;
2142 const char* vertex_ordering_token = "VERTEX_ORDERING";
2143 std::size_t vertex_ordering_token_index = std::string::npos;
2144 std::string vertex_spacing_mode_string;
2145 const char* vertex_spacing_token = "VERTEX_SPACING_MODE";
2146 std::size_t vertex_spacing_token_index = std::string::npos;
2147
2148 /* Prepare the vertex ordering token. We need to do this manually, because the default vertex spacing
2149 * mode translates to empty string and the shader would fail to compile if we hadn't taken care of the
2150 * comma
2151 */
2152 if (vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT)
2153 {
2154 vertex_ordering_string = TessellationShaderUtils::getESTokenForVertexOrderingMode(vertex_ordering);
2155 }
2156 else
2157 {
2158 std::stringstream helper_sstream;
2159
2160 helper_sstream << ", " << TessellationShaderUtils::getESTokenForVertexOrderingMode(vertex_ordering);
2161
2162 vertex_ordering_string = helper_sstream.str();
2163 }
2164
2165 /* Do the same for vertex spacing token */
2166 if (vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT)
2167 {
2168 vertex_spacing_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing);
2169 }
2170 else
2171 {
2172 std::stringstream helper_sstream;
2173
2174 helper_sstream << ", " << TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing);
2175
2176 vertex_spacing_mode_string = helper_sstream.str();
2177 }
2178
2179 /* Primitive mode */
2180 while ((primitive_mode_token_index = result.find(primitive_mode_token)) != std::string::npos)
2181 {
2182 result = result.replace(primitive_mode_token_index, strlen(primitive_mode_token), primitive_mode_string);
2183
2184 primitive_mode_token_index = result.find(primitive_mode_token);
2185 }
2186
2187 /* Vertex ordering */
2188 while ((vertex_ordering_token_index = result.find(vertex_ordering_token)) != std::string::npos)
2189 {
2190 result = result.replace(vertex_ordering_token_index, strlen(vertex_ordering_token), vertex_ordering_string);
2191
2192 vertex_ordering_token_index = result.find(vertex_ordering_token);
2193 }
2194
2195 /* Vertex spacing */
2196 while ((vertex_spacing_token_index = result.find(vertex_spacing_token)) != std::string::npos)
2197 {
2198 result = result.replace(vertex_spacing_token_index, strlen(vertex_spacing_token), vertex_spacing_mode_string);
2199
2200 vertex_spacing_token_index = result.find(vertex_spacing_token);
2201 }
2202
2203 /* Point mode */
2204 while ((point_mode_token_index = result.find(point_mode_token)) != std::string::npos)
2205 {
2206 result = result.replace(point_mode_token_index, strlen(point_mode_token),
2207 (is_point_mode_enabled) ? ", point_mode" : "");
2208
2209 point_mode_token_index = result.find(point_mode_token);
2210 }
2211
2212 return result;
2213 }
2214
2215 /** Retrieves a minimal vertex shader code to be used for forming program objects
2216 * used by the test.
2217 *
2218 * @return As per description.
2219 **/
getVertexShaderCode(bool should_pass_pointsize_data)2220 std::string TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::getVertexShaderCode(
2221 bool should_pass_pointsize_data)
2222 {
2223 std::stringstream result_sstream;
2224 result_sstream << "${VERSION}\n\n";
2225 if (should_pass_pointsize_data)
2226 {
2227 result_sstream << "${OUT_PER_VERTEX_DECL_POINT_SIZE}";
2228 }
2229 else
2230 {
2231 result_sstream << "${OUT_PER_VERTEX_DECL}";
2232 }
2233 result_sstream << "\n"
2234 "void main()\n"
2235 "{\n"
2236 "}\n";
2237
2238 return result_sstream.str();
2239 }
2240
2241 /** Initializes all ES objects that will be used for the test. */
initTest()2242 void TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::initTest()
2243 {
2244 /* The test requires EXT_tessellation_shader */
2245 if (!m_is_tessellation_shader_supported)
2246 {
2247 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
2248 }
2249
2250 /* Retrieve ES entry-points */
2251 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2252
2253 /* Initialize vertex array object */
2254 gl.genVertexArrays(1, &m_vao_id);
2255 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
2256
2257 gl.bindVertexArray(m_vao_id);
2258 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
2259
2260 /* Generate a buffer object we will use to hold XFB data */
2261 gl.genBuffers(1, &m_bo_id);
2262 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() failed");
2263
2264 /* Configure XFB buffer object bindings */
2265 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
2266 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
2267
2268 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() / glBindBufferBase() call(s) failed");
2269
2270 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value */
2271 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &m_gl_max_tess_gen_level_value);
2272 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_TESS_GEN_LEVEL_EXT pname");
2273
2274 /* Retrieve GL_MAX_PATCH_VERTICES_EXT value */
2275 gl.getIntegerv(m_glExtTokens.MAX_PATCH_VERTICES, &m_gl_max_patch_vertices_value);
2276 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() failed for GL_MAX_PATCH_VERTICES_EXT pname");
2277
2278 /* We only need 1 vertex per input patch */
2279 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 1);
2280 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed for GL_PATCH_VERTICES_EXT pname");
2281
2282 /* Disable rasterization */
2283 gl.enable(GL_RASTERIZER_DISCARD);
2284 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
2285
2286 /* Spawn utilities class instance */
2287 m_utils_ptr = new TessellationShaderUtils(gl, this);
2288
2289 /* Initialize all test iterations */
2290 bool point_mode_enabled_flags[] = { false, true };
2291 const _tessellation_primitive_mode primitive_modes[] = { TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES,
2292 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS,
2293 TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES };
2294 const _tessellation_shader_vertex_ordering vertex_ordering_modes[] = {
2295 TESSELLATION_SHADER_VERTEX_ORDERING_CCW, TESSELLATION_SHADER_VERTEX_ORDERING_CW,
2296 TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT
2297 };
2298 const _tessellation_shader_vertex_spacing vertex_spacing_modes[] = {
2299 TESSELLATION_SHADER_VERTEX_SPACING_EQUAL, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN,
2300 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD, TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT
2301 };
2302 const unsigned int n_point_mode_enabled_flags =
2303 sizeof(point_mode_enabled_flags) / sizeof(point_mode_enabled_flags[0]);
2304 const unsigned int n_primitive_modes = sizeof(primitive_modes) / sizeof(primitive_modes[0]);
2305 const unsigned int n_vertex_ordering_modes = sizeof(vertex_ordering_modes) / sizeof(vertex_ordering_modes[0]);
2306 const unsigned int n_vertex_spacing_modes = sizeof(vertex_spacing_modes) / sizeof(vertex_spacing_modes[0]);
2307
2308 bool deleteResources = false;
2309
2310 for (unsigned int n_primitive_mode = 0; n_primitive_mode < n_primitive_modes; n_primitive_mode++)
2311 {
2312 _tessellation_primitive_mode primitive_mode = primitive_modes[n_primitive_mode];
2313 _tessellation_levels_set tessellation_levels = TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
2314 primitive_mode, m_gl_max_tess_gen_level_value, TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE);
2315
2316 for (_tessellation_levels_set_const_iterator tessellation_levels_iterator = tessellation_levels.begin();
2317 tessellation_levels_iterator != tessellation_levels.end(); tessellation_levels_iterator++)
2318 {
2319 const _tessellation_levels& tess_levels = *tessellation_levels_iterator;
2320
2321 for (unsigned int n_vertex_ordering_mode = 0; n_vertex_ordering_mode < n_vertex_ordering_modes;
2322 ++n_vertex_ordering_mode)
2323 {
2324 _tessellation_shader_vertex_ordering vertex_ordering = vertex_ordering_modes[n_vertex_ordering_mode];
2325
2326 for (unsigned int n_vertex_spacing_mode = 0; n_vertex_spacing_mode < n_vertex_spacing_modes;
2327 ++n_vertex_spacing_mode)
2328 {
2329 _tessellation_shader_vertex_spacing vertex_spacing = vertex_spacing_modes[n_vertex_spacing_mode];
2330
2331 for (unsigned int n_point_mode_enabled_flag = 0;
2332 n_point_mode_enabled_flag < n_point_mode_enabled_flags; ++n_point_mode_enabled_flag)
2333 {
2334 bool is_point_mode_enabled = point_mode_enabled_flags[n_point_mode_enabled_flag];
2335
2336 /* Only create gl_PointSize-enabled runs if the implementation supports
2337 * GL_EXT_tessellation_point_size extension
2338 */
2339 if (!m_is_tessellation_shader_point_size_supported && is_point_mode_enabled)
2340 {
2341 continue;
2342 }
2343
2344 /* Execute the test run */
2345 _run run;
2346
2347 memcpy(run.inner, tess_levels.inner, sizeof(run.inner));
2348 memcpy(run.outer, tess_levels.outer, sizeof(run.outer));
2349
2350 run.point_mode = is_point_mode_enabled;
2351 run.primitive_mode = primitive_mode;
2352 run.vertex_ordering = vertex_ordering;
2353 run.vertex_spacing = vertex_spacing;
2354
2355 initTestRun(run);
2356
2357 if (deleteResources)
2358 {
2359 deinitTestRun(run);
2360 }
2361
2362 deleteResources = true;
2363
2364 /* Store it for further processing */
2365 m_runs.push_back(run);
2366 } /* for (all 'point mode' enabled flags) */
2367 } /* for (all vertex spacing modes) */
2368 } /* for (all vertex ordering modes) */
2369 } /* for (all tessellation levels for active primitive mode) */
2370 } /* for (all primitive modes) */
2371 }
2372
2373 /** Initializes all ES objects used by the test, captures the tessellation coordinates
2374 * and stores them in the descriptor.
2375 * Also performs a handful of other minor checks, as described by test specification.
2376 *
2377 * @param run Run descriptor to operate on.
2378 **/
initTestRun(_run & run)2379 void TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::initTestRun(_run& run)
2380 {
2381 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2382
2383 /* Build shader objects */
2384 run.fs_id = gl.createShader(GL_FRAGMENT_SHADER);
2385 run.tc_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
2386 run.te_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
2387 run.vs_id = gl.createShader(GL_VERTEX_SHADER);
2388
2389 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() call(s) failed");
2390
2391 /* Generate fragment shader (or stand-alone program) */
2392 std::string fs_code_string = getFragmentShaderCode(run.point_mode);
2393 const char* fs_code_raw_ptr = fs_code_string.c_str();
2394
2395 shaderSourceSpecialized(run.fs_id, 1 /* count */, &fs_code_raw_ptr);
2396
2397 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for fragment shader");
2398
2399 /* Generate tessellation control shader (or stand-alone program) */
2400 std::string tc_code_string = getTessellationControlShaderCode(run.point_mode, run.inner, run.outer);
2401 const char* tc_code_raw_ptr = tc_code_string.c_str();
2402
2403 shaderSourceSpecialized(run.tc_id, 1 /* count */, &tc_code_raw_ptr);
2404
2405 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for tessellation control shader");
2406
2407 /* Generate tessellation evaluation shader (or stand-alone program) */
2408 std::string te_code_string = getTessellationEvaluationShaderCode(
2409 run.point_mode, run.primitive_mode, run.vertex_ordering, run.vertex_spacing, run.point_mode);
2410 const char* te_code_raw_ptr = te_code_string.c_str();
2411
2412 shaderSourceSpecialized(run.te_id, 1 /* count */, &te_code_raw_ptr);
2413
2414 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for tessellation evaluation shader");
2415
2416 /* Generate vertex shader (or stand-alone program) */
2417 std::string vs_code_string = getVertexShaderCode(run.point_mode);
2418 const char* vs_code_raw_ptr = vs_code_string.c_str();
2419
2420 shaderSourceSpecialized(run.vs_id, 1 /* count */, &vs_code_raw_ptr);
2421
2422 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() call failed for vertex shader");
2423
2424 /* Compile all shaders first. Also make sure the shader objects we have
2425 * attached are correctly reported.
2426 */
2427 const glw::GLuint shaders[] = { run.fs_id, run.tc_id, run.te_id, run.vs_id };
2428 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
2429
2430 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
2431 {
2432 glw::GLint compile_status = GL_FALSE;
2433 glw::GLint shader = shaders[n_shader];
2434
2435 gl.compileShader(shader);
2436 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() failed");
2437
2438 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
2439 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() failed");
2440
2441 if (compile_status != GL_TRUE)
2442 {
2443 m_testCtx.getLog() << tcu::TestLog::Message << "Info log:\n"
2444 << getCompilationInfoLog(shader) << "\nShader:\n"
2445 << getShaderSource(shader) << tcu::TestLog::EndMessage;
2446 TCU_FAIL("Shader compilation failed");
2447 }
2448 }
2449
2450 /* Run two iterations:
2451 *
2452 * 1) First, using a program object;
2453 * 2) The other one using pipeline objects;
2454 */
2455 for (unsigned int n_iteration = 0; n_iteration < 2 /* program / pipeline objects */; ++n_iteration)
2456 {
2457 bool should_use_program_object = (n_iteration == 0);
2458
2459 /* Generate container object(s) first */
2460 if (!should_use_program_object)
2461 {
2462 gl.genProgramPipelines(1, &run.pipeline_object_id);
2463 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenProgramPipelines() failed");
2464
2465 /* As per test spec, make sure no tessellation stages are defined for
2466 * a pipeline object by default */
2467 glw::GLint program_tc_id = 1;
2468 glw::GLint program_te_id = 1;
2469
2470 gl.getProgramPipelineiv(run.pipeline_object_id, m_glExtTokens.TESS_CONTROL_SHADER, &program_tc_id);
2471 gl.getProgramPipelineiv(run.pipeline_object_id, m_glExtTokens.TESS_EVALUATION_SHADER, &program_te_id);
2472 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() failed");
2473
2474 if (program_tc_id != 0 || program_te_id != 0)
2475 {
2476 GLU_EXPECT_NO_ERROR(gl.getError(), "A pipeline object returned a non-zero ID of "
2477 "a separate program object when asked for TC/TE"
2478 " program ID.");
2479 }
2480 }
2481 else
2482 {
2483 run.po_id = gl.createProgram();
2484 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
2485 }
2486
2487 if (!should_use_program_object)
2488 {
2489 run.fs_program_id = gl.createProgram();
2490 run.tc_program_id = gl.createProgram();
2491 run.te_program_id = gl.createProgram();
2492 run.vs_program_id = gl.createProgram();
2493
2494 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() call(s) failed");
2495 }
2496
2497 /* Link program object(s) (and configure the pipeline object, if necessary) */
2498 const glw::GLuint programs_for_pipeline_iteration[] = { run.fs_program_id, run.tc_program_id, run.te_program_id,
2499 run.vs_program_id };
2500 const glw::GLuint programs_for_program_iteration[] = { run.po_id };
2501 const unsigned int n_programs_for_pipeline_iteration =
2502 sizeof(programs_for_pipeline_iteration) / sizeof(programs_for_pipeline_iteration[0]);
2503 const unsigned int n_programs_for_program_iteration =
2504 sizeof(programs_for_program_iteration) / sizeof(programs_for_program_iteration[0]);
2505
2506 unsigned int n_programs = 0;
2507 const glw::GLuint* programs = DE_NULL;
2508 int xfb_pointsize_data_offset = -1;
2509 int xfb_position_data_offset = -1;
2510 int xfb_value1_data_offset = -1;
2511 int xfb_value2_data_offset = -1;
2512 int xfb_varyings_size = 0;
2513
2514 if (should_use_program_object)
2515 {
2516 n_programs = n_programs_for_program_iteration;
2517 programs = programs_for_program_iteration;
2518 }
2519 else
2520 {
2521 n_programs = n_programs_for_pipeline_iteration;
2522 programs = programs_for_pipeline_iteration;
2523 }
2524
2525 /* Attach and verify shader objects */
2526 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
2527 {
2528 glw::GLuint parent_po_id = 0;
2529 glw::GLuint shader = shaders[n_shader];
2530
2531 if (should_use_program_object)
2532 {
2533 gl.attachShader(run.po_id, shader);
2534 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
2535
2536 parent_po_id = run.po_id;
2537 }
2538 else
2539 {
2540 if (shader == run.fs_id)
2541 {
2542 gl.attachShader(run.fs_program_id, run.fs_id);
2543
2544 parent_po_id = run.fs_program_id;
2545 }
2546 else if (shader == run.tc_id)
2547 {
2548 gl.attachShader(run.tc_program_id, run.tc_id);
2549
2550 parent_po_id = run.tc_program_id;
2551 }
2552 else if (shader == run.te_id)
2553 {
2554 gl.attachShader(run.te_program_id, run.te_id);
2555
2556 parent_po_id = run.te_program_id;
2557 }
2558 else
2559 {
2560 DE_ASSERT(shader == run.vs_id);
2561
2562 gl.attachShader(run.vs_program_id, run.vs_id);
2563
2564 parent_po_id = run.vs_program_id;
2565 }
2566
2567 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() failed");
2568 }
2569
2570 /* Make sure the shader object we've attached is reported as a part
2571 * of the program object.
2572 */
2573 unsigned int attached_shaders[n_shaders] = { 0 };
2574 bool has_found_attached_shader = false;
2575 glw::GLsizei n_attached_shaders = 0;
2576
2577 memset(attached_shaders, 0, sizeof(attached_shaders));
2578
2579 gl.getAttachedShaders(parent_po_id, n_shaders, &n_attached_shaders, attached_shaders);
2580 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetAttachedShaders() failed");
2581
2582 for (glw::GLsizei n_attached_shader = 0; n_attached_shader < n_attached_shaders; n_attached_shader++)
2583 {
2584 if (attached_shaders[n_attached_shader] == shader)
2585 {
2586 has_found_attached_shader = true;
2587
2588 break;
2589 }
2590 } /* for (all attached shader object IDs) */
2591
2592 if (!has_found_attached_shader)
2593 {
2594 TCU_FAIL("A shader object that was successfully attached to a program "
2595 "object was not reported as one by subsequent glGetAttachedShaders() "
2596 "call");
2597 }
2598 }
2599
2600 /* Set up XFB */
2601 const char* xfb_varyings_w_pointsize[] = { "te_position", "te_value1", "te_value2", "te_pointsize" };
2602 const char* xfb_varyings_wo_pointsize[] = {
2603 "te_position", "te_value1", "te_value2",
2604 };
2605 const char** xfb_varyings = DE_NULL;
2606 unsigned int n_xfb_varyings = 0;
2607
2608 if (run.point_mode)
2609 {
2610 xfb_varyings = xfb_varyings_w_pointsize;
2611 n_xfb_varyings = sizeof(xfb_varyings_w_pointsize) / sizeof(xfb_varyings_w_pointsize[0]);
2612
2613 xfb_position_data_offset = 0;
2614 xfb_value1_data_offset =
2615 static_cast<unsigned int>(xfb_position_data_offset + sizeof(float) * 4); /* size of te_position */
2616 xfb_value2_data_offset =
2617 static_cast<unsigned int>(xfb_value1_data_offset + sizeof(float) * 2); /* size of te_value1 */
2618 xfb_pointsize_data_offset =
2619 static_cast<unsigned int>(xfb_value2_data_offset + sizeof(int) * 4); /* size of te_value2 */
2620
2621 xfb_varyings_size = sizeof(float) * 4 + /* size of te_position */
2622 sizeof(float) * 2 + /* size of te_value1 */
2623 sizeof(int) * 4 + /* size of te_value2 */
2624 sizeof(int); /* size of te_pointsize */
2625 }
2626 else
2627 {
2628 xfb_varyings = xfb_varyings_wo_pointsize;
2629 n_xfb_varyings = sizeof(xfb_varyings_wo_pointsize) / sizeof(xfb_varyings_wo_pointsize[0]);
2630
2631 xfb_position_data_offset = 0;
2632 xfb_value1_data_offset =
2633 static_cast<unsigned int>(xfb_position_data_offset + sizeof(float) * 4); /* size of te_position */
2634 xfb_value2_data_offset =
2635 static_cast<unsigned int>(xfb_value1_data_offset + sizeof(float) * 2); /* size of te_value1 */
2636
2637 xfb_varyings_size = sizeof(float) * 4 + /* size of te_position */
2638 sizeof(float) * 2 + /* size of te_value1 */
2639 sizeof(int) * 4;
2640 }
2641
2642 if (!should_use_program_object)
2643 {
2644 gl.transformFeedbackVaryings(run.te_program_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
2645
2646 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
2647 }
2648 else
2649 {
2650 gl.transformFeedbackVaryings(run.po_id, n_xfb_varyings, xfb_varyings, GL_INTERLEAVED_ATTRIBS);
2651
2652 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
2653 }
2654
2655 /* Mark all program objects as separable for pipeline run */
2656 if (!should_use_program_object)
2657 {
2658 for (unsigned int n_program = 0; n_program < n_programs; ++n_program)
2659 {
2660 glw::GLuint program = programs[n_program];
2661
2662 gl.programParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
2663 GLU_EXPECT_NO_ERROR(gl.getError(), "glProgramParameteri() failed.");
2664 }
2665 }
2666
2667 /* Link the program object(s) */
2668 for (unsigned int n_program = 0; n_program < n_programs; ++n_program)
2669 {
2670 glw::GLint link_status = GL_FALSE;
2671 glw::GLuint program = programs[n_program];
2672
2673 gl.linkProgram(program);
2674 GLU_EXPECT_NO_ERROR(gl.getError(), "Program linking failed");
2675
2676 gl.getProgramiv(program, GL_LINK_STATUS, &link_status);
2677 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed");
2678
2679 if (link_status != GL_TRUE)
2680 {
2681 m_testCtx.getLog() << tcu::TestLog::Message << "Info log:\n"
2682 << getLinkingInfoLog(program) << tcu::TestLog::EndMessage;
2683 TCU_FAIL("Program linking failed");
2684 }
2685
2686 /* Make sure glGetProgramiv() reports correct tessellation properties for
2687 * the program object we've just linked successfully */
2688 if (program == run.po_id || program == run.tc_program_id || program == run.te_program_id)
2689 {
2690 glw::GLenum expected_tess_gen_mode_value = GL_NONE;
2691 glw::GLenum expected_tess_gen_spacing_value = GL_NONE;
2692 glw::GLenum expected_tess_gen_vertex_order_value = GL_NONE;
2693 glw::GLint tess_control_output_vertices_value = GL_NONE;
2694 glw::GLint tess_gen_mode_value = GL_NONE;
2695 glw::GLint tess_gen_point_mode_value = GL_NONE;
2696 glw::GLint tess_gen_spacing_value = GL_NONE;
2697 glw::GLint tess_gen_vertex_order_value = GL_NONE;
2698
2699 switch (run.primitive_mode)
2700 {
2701 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
2702 expected_tess_gen_mode_value = m_glExtTokens.ISOLINES;
2703 break;
2704 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
2705 expected_tess_gen_mode_value = m_glExtTokens.QUADS;
2706 break;
2707 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
2708 expected_tess_gen_mode_value = GL_TRIANGLES;
2709 break;
2710
2711 default:
2712 {
2713 /* Unrecognized primitive mode? */
2714 DE_ASSERT(false);
2715 }
2716 } /* switch (run.primitive_mode) */
2717
2718 switch (run.vertex_spacing)
2719 {
2720 case TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT:
2721 case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
2722 expected_tess_gen_spacing_value = GL_EQUAL;
2723 break;
2724 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN:
2725 expected_tess_gen_spacing_value = m_glExtTokens.FRACTIONAL_EVEN;
2726 break;
2727 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
2728 expected_tess_gen_spacing_value = m_glExtTokens.FRACTIONAL_ODD;
2729 break;
2730
2731 default:
2732 {
2733 /* Unrecognized vertex spacing mode? */
2734 DE_ASSERT(false);
2735 }
2736 } /* switch (run.vertex_spacing) */
2737
2738 switch (run.vertex_ordering)
2739 {
2740 case TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT:
2741 case TESSELLATION_SHADER_VERTEX_ORDERING_CCW:
2742 expected_tess_gen_vertex_order_value = GL_CCW;
2743 break;
2744 case TESSELLATION_SHADER_VERTEX_ORDERING_CW:
2745 expected_tess_gen_vertex_order_value = GL_CW;
2746 break;
2747
2748 default:
2749 {
2750 /* Unrecognized vertex ordering mode? */
2751 DE_ASSERT(false);
2752 }
2753 } /* switch (run.vertex_ordering) */
2754
2755 if (program == run.po_id || program == run.tc_program_id)
2756 {
2757 gl.getProgramiv(program, m_glExtTokens.TESS_CONTROL_OUTPUT_VERTICES,
2758 &tess_control_output_vertices_value);
2759 GLU_EXPECT_NO_ERROR(gl.getError(),
2760 "glGetProgramiv() failed for GL_TESS_CONTROL_OUTPUT_VERTICES_EXT pname");
2761
2762 if (tess_control_output_vertices_value != m_gl_max_patch_vertices_value)
2763 {
2764 TCU_FAIL(
2765 "Invalid value returned by glGetProgramiv() for GL_TESS_CONTROL_OUTPUT_VERTICES_EXT query");
2766 }
2767 }
2768
2769 if (program == run.po_id || program == run.te_program_id)
2770 {
2771 gl.getProgramiv(program, m_glExtTokens.TESS_GEN_MODE, &tess_gen_mode_value);
2772 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed for GL_TESS_GEN_MODE_EXT pname");
2773
2774 if ((glw::GLuint)tess_gen_mode_value != expected_tess_gen_mode_value)
2775 {
2776 TCU_FAIL("Invalid value returned by glGetProgramiv() for GL_TESS_GEN_MODE_EXT query");
2777 }
2778 }
2779
2780 if (program == run.po_id || program == run.te_program_id)
2781 {
2782 gl.getProgramiv(program, m_glExtTokens.TESS_GEN_SPACING, &tess_gen_spacing_value);
2783 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed for GL_TESS_GEN_SPACING_EXT pname");
2784
2785 if ((glw::GLuint)tess_gen_spacing_value != expected_tess_gen_spacing_value)
2786 {
2787 TCU_FAIL("Invalid value returned by glGetProgramiv() for GL_TESS_GEN_SPACING_EXT query");
2788 }
2789 }
2790
2791 if (program == run.po_id || program == run.te_program_id)
2792 {
2793 gl.getProgramiv(program, m_glExtTokens.TESS_GEN_VERTEX_ORDER, &tess_gen_vertex_order_value);
2794 GLU_EXPECT_NO_ERROR(gl.getError(),
2795 "glGetProgramiv() failed for GL_TESS_GEN_VERTEX_ORDER_EXT pname");
2796
2797 if ((glw::GLuint)tess_gen_vertex_order_value != expected_tess_gen_vertex_order_value)
2798 {
2799 TCU_FAIL("Invalid value returned by glGetProgramiv() for GL_TESS_GEN_VERTEX_ORDER_EXT query");
2800 }
2801 }
2802
2803 if (program == run.po_id || program == run.te_program_id)
2804 {
2805 gl.getProgramiv(program, m_glExtTokens.TESS_GEN_POINT_MODE, &tess_gen_point_mode_value);
2806 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() failed for GL_TESS_GEN_POINT_MODE_EXT pname");
2807
2808 if (tess_gen_point_mode_value != ((run.point_mode) ? GL_TRUE : GL_FALSE))
2809 {
2810 TCU_FAIL("Invalid value returned by glGetProgramiv() for GL_TESS_GEN_POINT_MODE_EXT query");
2811 }
2812 }
2813 } /* if (program == run.po_id || program == run.tc_program_id || program == run.te_program_id) */
2814 } /* for (all considered program objects) */
2815
2816 if (!should_use_program_object)
2817 {
2818 /* Attach all stages to the pipeline object */
2819 gl.useProgramStages(run.pipeline_object_id, GL_FRAGMENT_SHADER_BIT, run.fs_program_id);
2820 gl.useProgramStages(run.pipeline_object_id, m_glExtTokens.TESS_CONTROL_SHADER_BIT, run.tc_program_id);
2821 gl.useProgramStages(run.pipeline_object_id, m_glExtTokens.TESS_EVALUATION_SHADER_BIT, run.te_program_id);
2822 gl.useProgramStages(run.pipeline_object_id, GL_VERTEX_SHADER_BIT, run.vs_program_id);
2823 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgramStages() call(s) failed");
2824
2825 /* Make sure the pipeline object validates correctly */
2826 glw::GLint validate_status = GL_FALSE;
2827
2828 gl.validateProgramPipeline(run.pipeline_object_id);
2829 GLU_EXPECT_NO_ERROR(gl.getError(), "glValidateProgramPipeline() call failed");
2830
2831 gl.getProgramPipelineiv(run.pipeline_object_id, GL_VALIDATE_STATUS, &validate_status);
2832 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() call failed");
2833
2834 if (validate_status != GL_TRUE)
2835 {
2836 m_testCtx.getLog() << tcu::TestLog::Message << "Info log:\n"
2837 << getPipelineInfoLog(run.pipeline_object_id) << "\n\nVertex Shader:\n"
2838 << vs_code_raw_ptr << "\n\nTessellation Control Shader:\n"
2839 << tc_code_raw_ptr << "\n\nTessellation Evaluation Shader:\n"
2840 << te_code_raw_ptr << "\n\nFragment Shader:\n"
2841 << fs_code_raw_ptr << tcu::TestLog::EndMessage;
2842 TCU_FAIL("Pipeline object was found to be invalid");
2843 }
2844 }
2845
2846 /* Determine how many vertices are going to be generated by the tessellator
2847 * for particular tessellation configuration.
2848 */
2849 unsigned int n_vertices_generated = m_utils_ptr->getAmountOfVerticesGeneratedByTessellator(
2850 run.primitive_mode, run.inner, run.outer, run.vertex_spacing, run.point_mode);
2851
2852 /* Allocate enough space to hold the result XFB data */
2853 const unsigned int bo_size = xfb_varyings_size * n_vertices_generated;
2854
2855 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL /* data */, GL_STATIC_DRAW);
2856 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
2857
2858 /* Use the pipeline or program object and render the data */
2859 glw::GLenum tf_mode = TessellationShaderUtils::getTFModeForPrimitiveMode(run.primitive_mode, run.point_mode);
2860
2861 if (should_use_program_object)
2862 {
2863 gl.bindProgramPipeline(0);
2864 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed");
2865
2866 gl.useProgram(run.po_id);
2867 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
2868 }
2869 else
2870 {
2871 gl.bindProgramPipeline(run.pipeline_object_id);
2872 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindProgramPipeline() call failed");
2873
2874 gl.useProgram(0);
2875 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
2876 }
2877
2878 gl.beginTransformFeedback(tf_mode);
2879 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
2880 {
2881 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, 1 /* count */);
2882
2883 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
2884 }
2885 gl.endTransformFeedback();
2886 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
2887
2888 /* Map the buffer object contents into process space */
2889 const char* xfb_data = (const char*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
2890 bo_size, GL_MAP_READ_BIT);
2891
2892 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed");
2893
2894 /* Iterate through all vertices and extract all captured data. To reduce amount
2895 * of time necessary to verify the generated data, only store *unique* values.
2896 */
2897 for (unsigned int n_vertex = 0; n_vertex < n_vertices_generated; ++n_vertex)
2898 {
2899 if (xfb_pointsize_data_offset != -1)
2900 {
2901 const float* data_ptr =
2902 (const float*)(xfb_data + xfb_varyings_size * n_vertex + xfb_pointsize_data_offset);
2903
2904 if (std::find(run.result_pointsize_data.begin(), run.result_pointsize_data.end(), *data_ptr) ==
2905 run.result_pointsize_data.end())
2906 {
2907 run.result_pointsize_data.push_back(*data_ptr);
2908 }
2909 }
2910
2911 if (xfb_position_data_offset != -1)
2912 {
2913 const float* data_ptr =
2914 (const float*)(xfb_data + xfb_varyings_size * n_vertex + xfb_position_data_offset);
2915 _vec4 new_item = _vec4(data_ptr[0], data_ptr[1], data_ptr[2], data_ptr[3]);
2916
2917 if (std::find(run.result_position_data.begin(), run.result_position_data.end(), new_item) ==
2918 run.result_position_data.end())
2919 {
2920 run.result_position_data.push_back(new_item);
2921 }
2922 }
2923
2924 if (xfb_value1_data_offset != -1)
2925 {
2926 const float* data_ptr =
2927 (const float*)(xfb_data + xfb_varyings_size * n_vertex + xfb_value1_data_offset);
2928 _vec2 new_item = _vec2(data_ptr[0], data_ptr[1]);
2929
2930 if (std::find(run.result_value1_data.begin(), run.result_value1_data.end(), new_item) ==
2931 run.result_value1_data.end())
2932 {
2933 run.result_value1_data.push_back(new_item);
2934 }
2935 }
2936
2937 if (xfb_value2_data_offset != -1)
2938 {
2939 const int* data_ptr = (const int*)(xfb_data + xfb_varyings_size * n_vertex + xfb_value2_data_offset);
2940 _ivec4 new_item = _ivec4(data_ptr[0], data_ptr[1], data_ptr[2], data_ptr[3]);
2941
2942 if (std::find(run.result_value2_data.begin(), run.result_value2_data.end(), new_item) ==
2943 run.result_value2_data.end())
2944 {
2945 run.result_value2_data.push_back(new_item);
2946 }
2947 }
2948 } /* for (all result tessellation coordinates) */
2949
2950 /* Good to unmap the buffer object at this point */
2951 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2952 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed");
2953 } /* for (two iterations) */
2954 }
2955
2956 /** Executes the test.
2957 *
2958 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
2959 *
2960 * Note the function throws exception should an error occur!
2961 *
2962 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
2963 **/
iterate(void)2964 tcu::TestNode::IterateResult TessellationShaderTCTEgl_MaxPatchVertices_Position_PointSize::iterate(void)
2965 {
2966 /* Initialize ES test objects */
2967 initTest();
2968
2969 /* Calculate reference values that should be generated for all runs */
2970 float reference_result_pointsize(0);
2971 _vec4 reference_result_position(0, 0, 0, 0);
2972 _vec2 reference_result_value1(0, 0);
2973 _ivec4 reference_result_value2(0, 0, 0, 0);
2974 const float epsilon = (float)1e-5;
2975
2976 for (glw::GLint n_invocation = 0; n_invocation < m_gl_max_patch_vertices_value; ++n_invocation)
2977 {
2978 /* As per TC and TE shaders */
2979 reference_result_pointsize += 1.0f / static_cast<float>(n_invocation + 1);
2980
2981 reference_result_position.x += static_cast<float>(n_invocation * 4 + 0);
2982 reference_result_position.y += static_cast<float>(n_invocation * 4 + 1);
2983 reference_result_position.z += static_cast<float>(n_invocation * 4 + 2);
2984 reference_result_position.w += static_cast<float>(n_invocation * 4 + 3);
2985
2986 reference_result_value1.x += 1.0f / static_cast<float>(n_invocation + 1);
2987 reference_result_value1.y += 1.0f / static_cast<float>(n_invocation + 2);
2988
2989 reference_result_value2.x += (n_invocation + 1);
2990 reference_result_value2.y += (n_invocation + 2);
2991 reference_result_value2.z += (n_invocation + 3);
2992 reference_result_value2.w += (n_invocation + 4);
2993 }
2994
2995 /* Iterate through test runs and analyse the result data */
2996 for (_runs_const_iterator run_iterator = m_runs.begin(); run_iterator != m_runs.end(); run_iterator++)
2997 {
2998 const _run& run = *run_iterator;
2999
3000 /* For the very first run, make sure that the type of tessellation shader objects
3001 * is reported correctly for both program and pipeline object cases.
3002 */
3003 if (run_iterator == m_runs.begin())
3004 {
3005 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3006 glw::GLint shader_type_tc = GL_NONE;
3007 glw::GLint shader_type_te = GL_NONE;
3008
3009 /* Program objects first */
3010 gl.getShaderiv(run.tc_id, GL_SHADER_TYPE, &shader_type_tc);
3011 gl.getShaderiv(run.te_id, GL_SHADER_TYPE, &shader_type_te);
3012 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call(s) failed");
3013
3014 if ((glw::GLenum)shader_type_tc != m_glExtTokens.TESS_CONTROL_SHADER)
3015 {
3016 TCU_FAIL("Invalid shader type reported by glGetShaderiv() for a tessellation control shader");
3017 }
3018
3019 if ((glw::GLenum)shader_type_te != m_glExtTokens.TESS_EVALUATION_SHADER)
3020 {
3021 TCU_FAIL("Invalid shader type reported by glGetShaderiv() for a tessellation evaluation shader");
3022 }
3023
3024 /* Let's query the pipeline object now */
3025 glw::GLint shader_id_tc = 0;
3026 glw::GLint shader_id_te = 0;
3027
3028 gl.getProgramPipelineiv(run.pipeline_object_id, m_glExtTokens.TESS_CONTROL_SHADER, &shader_id_tc);
3029 gl.getProgramPipelineiv(run.pipeline_object_id, m_glExtTokens.TESS_EVALUATION_SHADER, &shader_id_te);
3030
3031 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramPipelineiv() failed for GL_TESS_CONTROL_SHADER_EXT / "
3032 "GL_TESS_EVALUATION_SHADER_EXT enum(s)");
3033
3034 if ((glw::GLuint)shader_id_tc != run.tc_program_id)
3035 {
3036 TCU_FAIL("Invalid separate program object ID reported for Tessellation Control stage");
3037 }
3038
3039 if ((glw::GLuint)shader_id_te != run.te_program_id)
3040 {
3041 TCU_FAIL("Invalid separate program object ID reported for Tessellation Evaluation stage");
3042 }
3043 }
3044
3045 if ((run.point_mode && run.result_pointsize_data.size() != 1) ||
3046 (run.point_mode && de::abs(run.result_pointsize_data[0] - reference_result_pointsize) > epsilon))
3047 {
3048 /* It is a test bug if result_pointsize_data.size() == 0 */
3049 DE_ASSERT(run.result_pointsize_data.size() > 0);
3050
3051 m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation Evaluation stage set gl_PointSize value to "
3052 << run.result_pointsize_data[0] << " instead of expected value "
3053 << reference_result_pointsize << tcu::TestLog::EndMessage;
3054
3055 TCU_FAIL("Invalid gl_PointSize data exposed in TE stage");
3056 }
3057
3058 if (run.result_position_data.size() != 1 || run.result_position_data[0] != reference_result_position)
3059 {
3060 /* It is a test bug if result_position_data.size() == 0 */
3061 DE_ASSERT(run.result_position_data.size() > 0);
3062
3063 m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation Evaluation stage set gl_Position to "
3064 << " (" << run.result_position_data[0].x << ", " << run.result_position_data[0].y << ", "
3065 << run.result_position_data[0].z << ", " << run.result_position_data[0].w
3066 << " ) instead of expected value"
3067 " ("
3068 << reference_result_position.x << ", " << reference_result_position.y << ", "
3069 << reference_result_position.z << ", " << reference_result_position.w << ")"
3070 << tcu::TestLog::EndMessage;
3071
3072 TCU_FAIL("Invalid gl_Position data exposed in TE stage");
3073 }
3074
3075 if (run.result_value1_data.size() != 1 ||
3076 de::abs(run.result_value1_data[0].x - reference_result_value1.x) > epsilon ||
3077 de::abs(run.result_value1_data[0].y - reference_result_value1.y) > epsilon)
3078 {
3079 /* It is a test bug if result_value1_data.size() == 0 */
3080 DE_ASSERT(run.result_value1_data.size() > 0);
3081
3082 m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation Evaluation stage set te_value1 to "
3083 << " (" << run.result_value1_data[0].x << ", " << run.result_value1_data[0].y
3084 << " ) instead of expected value"
3085 " ("
3086 << reference_result_value1.x << ", " << reference_result_value1.y << ")"
3087 << tcu::TestLog::EndMessage;
3088
3089 TCU_FAIL("Invalid gl_Position data exposed in TE stage");
3090 }
3091
3092 if (run.result_value2_data.size() != 1 || run.result_value2_data[0] != reference_result_value2)
3093 {
3094 /* It is a test bug if result_value2_data.size() == 0 */
3095 DE_ASSERT(run.result_value2_data.size() > 0);
3096
3097 m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation Evaluation stage set te_value2 to "
3098 << " (" << run.result_value2_data[0].x << ", " << run.result_value2_data[0].y << ", "
3099 << run.result_value2_data[0].z << ", " << run.result_value2_data[0].w
3100 << " ) instead of expected value"
3101 " ("
3102 << reference_result_value2.x << ", " << reference_result_value2.y << ", "
3103 << reference_result_value2.z << ", " << reference_result_value2.w << ")"
3104 << tcu::TestLog::EndMessage;
3105
3106 TCU_FAIL("Invalid value2 data saved in TE stage");
3107 }
3108 } /* for (all runs) */
3109
3110 /* All done */
3111 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3112 return STOP;
3113 }
3114
3115 /** Constructor
3116 *
3117 * @param context Test context
3118 **/
TessellationShaderTCTEgl_TessLevel(Context & context,const ExtParameters & extParams)3119 TessellationShaderTCTEgl_TessLevel::TessellationShaderTCTEgl_TessLevel(Context& context, const ExtParameters& extParams)
3120 : TestCaseBase(context, extParams, "gl_tessLevel",
3121 "Verifies gl_TessLevelOuter and gl_TessLevelInner patch variable "
3122 "values in a tessellation evaluation shader are valid and correspond"
3123 "to values configured in a tessellation control shader (should one be "
3124 "present) or to the default values, as set with glPatchParameterfv() calls")
3125 , m_gl_max_tess_gen_level_value(0)
3126 , m_bo_id(0)
3127 , m_vao_id(0)
3128 {
3129 /* Left blank on purpose */
3130 }
3131
3132 /** Deinitializes all ES objects created for the test. */
deinit()3133 void TessellationShaderTCTEgl_TessLevel::deinit()
3134 {
3135 /** Call base class' deinit() function */
3136 TestCaseBase::deinit();
3137
3138 if (!m_is_tessellation_shader_supported)
3139 {
3140 return;
3141 }
3142
3143 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3144
3145 /* Reset TF buffer object bindings */
3146 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
3147 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
3148
3149 /* Reset GL_PATCH_VERTICES_EXT value to the default setting */
3150 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
3151
3152 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3153 {
3154 /* Revert GL_PATCH_DEFAULT_INNER_LEVEL and GL_PATCH_DEFAULT_OUTER_LEVEL pname
3155 * values to the default settings */
3156 const float default_levels[] = { 1.0f, 1.0f, 1.0f, 1.0f };
3157 gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, default_levels);
3158 gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, default_levels);
3159 }
3160
3161 /* Disable GL_RASTERIZER_DISCARD mode */
3162 gl.disable(GL_RASTERIZER_DISCARD);
3163
3164 /* Unbind vertex array object */
3165 gl.bindVertexArray(0);
3166
3167 /* Release all objects we might've created */
3168 if (m_bo_id != 0)
3169 {
3170 gl.deleteBuffers(1, &m_bo_id);
3171
3172 m_bo_id = 0;
3173 }
3174
3175 if (m_vao_id != 0)
3176 {
3177 gl.deleteVertexArrays(1, &m_vao_id);
3178
3179 m_vao_id = 0;
3180 }
3181
3182 for (_tests::iterator it = m_tests.begin(); it != m_tests.end(); ++it)
3183 {
3184 deinitTestDescriptor(&*it);
3185 }
3186 m_tests.clear();
3187 }
3188
3189 /** Deinitializes ES objects created for particular test pass.
3190 *
3191 * @param test_ptr Test run descriptor. Must not be NULL.
3192 *
3193 **/
deinitTestDescriptor(_test_descriptor * test_ptr)3194 void TessellationShaderTCTEgl_TessLevel::deinitTestDescriptor(_test_descriptor* test_ptr)
3195 {
3196 /* Call base class' deinit() */
3197 TestCaseBase::deinit();
3198
3199 /* Release all objects */
3200 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3201
3202 if (test_ptr->fs_id != 0)
3203 {
3204 gl.deleteShader(test_ptr->fs_id);
3205
3206 test_ptr->fs_id = 0;
3207 }
3208
3209 if (test_ptr->po_id != 0)
3210 {
3211 gl.deleteProgram(test_ptr->po_id);
3212
3213 test_ptr->po_id = 0;
3214 }
3215
3216 if (test_ptr->tcs_id != 0)
3217 {
3218 gl.deleteShader(test_ptr->tcs_id);
3219
3220 test_ptr->tcs_id = 0;
3221 }
3222
3223 if (test_ptr->tes_id != 0)
3224 {
3225 gl.deleteShader(test_ptr->tes_id);
3226
3227 test_ptr->tes_id = 0;
3228 }
3229
3230 if (test_ptr->vs_id != 0)
3231 {
3232 gl.deleteShader(test_ptr->vs_id);
3233
3234 test_ptr->vs_id = 0;
3235 }
3236 }
3237
3238 /** Initializes all ES objects that will be used for the test. */
initTest()3239 void TessellationShaderTCTEgl_TessLevel::initTest()
3240 {
3241 /* The test requires EXT_tessellation_shader */
3242 if (!m_is_tessellation_shader_supported)
3243 {
3244 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
3245 }
3246
3247 /* Retrieve GL_MAX_TESS_GEN_LEVEL_EXT value before we carry on */
3248 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3249
3250 /* Initialize vertex array object */
3251 gl.genVertexArrays(1, &m_vao_id);
3252 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
3253
3254 gl.bindVertexArray(m_vao_id);
3255 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
3256
3257 /* Retrieve gen level */
3258 gl.getIntegerv(m_glExtTokens.MAX_TESS_GEN_LEVEL, &m_gl_max_tess_gen_level_value);
3259
3260 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_MAX_TESS_GEN_LEVEL_EXT pname failed");
3261
3262 /* Initialize test descriptors */
3263 _test_descriptor test_tcs_tes_equal;
3264 _test_descriptor test_tcs_tes_fe;
3265 _test_descriptor test_tcs_tes_fo;
3266 _test_descriptor test_tes_equal;
3267 _test_descriptor test_tes_fe;
3268 _test_descriptor test_tes_fo;
3269
3270 initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_equal, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL);
3271 initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_fe,
3272 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN);
3273 initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_fo,
3274 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD);
3275 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3276 {
3277 initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_equal, TESSELLATION_SHADER_VERTEX_SPACING_EQUAL);
3278 initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_fe,
3279 TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN);
3280 initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_fo, TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD);
3281 }
3282
3283 m_tests.push_back(test_tcs_tes_equal);
3284 m_tests.push_back(test_tcs_tes_fe);
3285 m_tests.push_back(test_tcs_tes_fo);
3286 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3287 {
3288 m_tests.push_back(test_tes_equal);
3289 m_tests.push_back(test_tes_fe);
3290 m_tests.push_back(test_tes_fo);
3291 }
3292
3293 /* Generate and set up a buffer object we will use to hold XFBed data.
3294 *
3295 * NOTE: We do not set the buffer object's storage here because its size
3296 * is iteration-specific.
3297 **/
3298 gl.genBuffers(1, &m_bo_id);
3299 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
3300
3301 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
3302 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
3303 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
3304 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
3305
3306 /* We're good to execute the test! */
3307 }
3308
3309 /** Initializes ES objects for a particular tess pass.
3310 *
3311 * @param test_type Determines test type to be used for initialization.
3312 * TEST_TYPE_TCS_TES will use both TC and TE stages,
3313 * TEST_TYPE_TES will assume only TE stage should be used.
3314 * @param out_test_ptr Deref will be used to store object data. Must not be NULL.
3315 * @param vertex_spacing_mode Vertex spacing mode to use for the TE stage.
3316 *
3317 **/
initTestDescriptor(_tessellation_test_type test_type,_test_descriptor * out_test_ptr,_tessellation_shader_vertex_spacing vertex_spacing_mode)3318 void TessellationShaderTCTEgl_TessLevel::initTestDescriptor(_tessellation_test_type test_type,
3319 _test_descriptor* out_test_ptr,
3320 _tessellation_shader_vertex_spacing vertex_spacing_mode)
3321 {
3322 out_test_ptr->type = test_type;
3323 out_test_ptr->vertex_spacing = vertex_spacing_mode;
3324
3325 /* Generate a program object we will later configure */
3326 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3327
3328 out_test_ptr->po_id = gl.createProgram();
3329
3330 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
3331
3332 /* Generate shader objects the test will use */
3333 out_test_ptr->fs_id = gl.createShader(GL_FRAGMENT_SHADER);
3334 out_test_ptr->vs_id = gl.createShader(GL_VERTEX_SHADER);
3335
3336 if (test_type == TESSELLATION_TEST_TYPE_TCS_TES || test_type == TESSELLATION_TEST_TYPE_TES)
3337 {
3338 out_test_ptr->tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
3339 }
3340
3341 if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3342 {
3343 out_test_ptr->tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
3344 }
3345
3346 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
3347
3348 /* Configure fragment shader */
3349 const char* fs_body = "${VERSION}\n"
3350 "\n"
3351 "void main()\n"
3352 "{\n"
3353 "}\n";
3354
3355 shaderSourceSpecialized(out_test_ptr->fs_id, 1 /* count */, &fs_body);
3356 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader object");
3357
3358 /* Configure tessellation control shader */
3359 const char* tc_body = "${VERSION}\n"
3360 "\n"
3361 /* Required EXT_tessellation_shader functionality */
3362 "${TESSELLATION_SHADER_REQUIRE}\n"
3363 "\n"
3364 "layout (vertices = 4) out;\n"
3365 "\n"
3366 "uniform vec2 inner_tess_levels;\n"
3367 "uniform vec4 outer_tess_levels;\n"
3368 "\n"
3369 "void main()\n"
3370 "{\n"
3371 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
3372 " if (gl_InvocationID == 0) {\n"
3373 " gl_TessLevelInner[0] = inner_tess_levels[0];\n"
3374 " gl_TessLevelInner[1] = inner_tess_levels[1];\n"
3375 " gl_TessLevelOuter[0] = outer_tess_levels[0];\n"
3376 " gl_TessLevelOuter[1] = outer_tess_levels[1];\n"
3377 " gl_TessLevelOuter[2] = outer_tess_levels[2];\n"
3378 " gl_TessLevelOuter[3] = outer_tess_levels[3];\n"
3379 " }\n"
3380 "}\n";
3381
3382 if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3383 {
3384 shaderSourceSpecialized(out_test_ptr->tcs_id, 1 /* count */, &tc_body);
3385 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader object");
3386 }
3387
3388 /* Configure tessellation evaluation shader */
3389 const char* te_body = "${VERSION}\n"
3390 "\n"
3391 "${TESSELLATION_SHADER_REQUIRE}\n"
3392 "\n"
3393 "layout (quads, point_mode, VERTEX_SPACING_MODE) in;\n"
3394 "\n"
3395 "out vec2 result_tess_level_inner;\n"
3396 "out vec4 result_tess_level_outer;\n"
3397 "\n"
3398 "void main()\n"
3399 "{\n"
3400 " vec4 p1 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
3401 " vec4 p2 = mix(gl_in[2].gl_Position,gl_in[3].gl_Position,gl_TessCoord.x);\n"
3402 " gl_Position = mix(p1, p2, gl_TessCoord.y);\n"
3403 "\n"
3404 " result_tess_level_inner = vec2(gl_TessLevelInner[0],\n"
3405 " gl_TessLevelInner[1]);\n"
3406 " result_tess_level_outer = vec4(gl_TessLevelOuter[0],\n"
3407 " gl_TessLevelOuter[1],\n"
3408 " gl_TessLevelOuter[2],\n"
3409 " gl_TessLevelOuter[3]);\n"
3410 "}\n";
3411
3412 if (test_type == TESSELLATION_TEST_TYPE_TCS_TES || test_type == TESSELLATION_TEST_TYPE_TES)
3413 {
3414 /* Replace VERTEX_SPACING_MODE with the mode provided by the caller */
3415 std::stringstream te_body_stringstream;
3416 std::string te_body_string;
3417 const std::string token = "VERTEX_SPACING_MODE";
3418 std::size_t token_index;
3419 std::string vertex_spacing_string =
3420 TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing_mode);
3421
3422 te_body_stringstream << te_body;
3423 te_body_string = te_body_stringstream.str();
3424
3425 token_index = te_body_string.find(token);
3426
3427 while (token_index != std::string::npos)
3428 {
3429 te_body_string = te_body_string.replace(token_index, token.length(), vertex_spacing_string.c_str());
3430
3431 token_index = te_body_string.find(token);
3432 }
3433
3434 /* Set the shader source */
3435 const char* te_body_string_raw = te_body_string.c_str();
3436
3437 shaderSourceSpecialized(out_test_ptr->tes_id, 1 /* count */, &te_body_string_raw);
3438 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader object");
3439 }
3440
3441 /* Configure vertex shader */
3442 const char* vs_body = "${VERSION}\n"
3443 "\n"
3444 "void main()\n"
3445 "{\n"
3446 " gl_Position = vec4(1.0, 2.0, 3.0, 4.0);\n"
3447 "}\n";
3448
3449 shaderSourceSpecialized(out_test_ptr->vs_id, 1 /* count */, &vs_body);
3450 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader object");
3451
3452 /* Compile all shaders of our interest */
3453 const glw::GLuint shaders[] = { out_test_ptr->fs_id, out_test_ptr->tcs_id, out_test_ptr->tes_id,
3454 out_test_ptr->vs_id };
3455 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
3456
3457 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
3458 {
3459 glw::GLint compile_status = GL_FALSE;
3460 glw::GLuint shader = shaders[n_shader];
3461
3462 if (shader != 0)
3463 {
3464 gl.compileShader(shader);
3465 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
3466
3467 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
3468 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
3469
3470 if (compile_status != GL_TRUE)
3471 {
3472 m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader
3473 << " failed." << tcu::TestLog::EndMessage;
3474
3475 TCU_FAIL("Shader compilation failed");
3476 }
3477 } /* if (shader != 0) */
3478 } /* for (all shaders) */
3479
3480 /* Attach the shaders to the test program object, set up XFB and then link the program */
3481 glw::GLint link_status = GL_FALSE;
3482 const char* varyings[] = { "result_tess_level_inner", "result_tess_level_outer" };
3483 const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
3484
3485 gl.transformFeedbackVaryings(out_test_ptr->po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
3486 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
3487
3488 gl.attachShader(out_test_ptr->po_id, out_test_ptr->fs_id);
3489 gl.attachShader(out_test_ptr->po_id, out_test_ptr->vs_id);
3490
3491 if (out_test_ptr->tcs_id != 0)
3492 {
3493 gl.attachShader(out_test_ptr->po_id, out_test_ptr->tcs_id);
3494 }
3495
3496 if (out_test_ptr->tes_id != 0)
3497 {
3498 gl.attachShader(out_test_ptr->po_id, out_test_ptr->tes_id);
3499 }
3500
3501 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
3502
3503 gl.linkProgram(out_test_ptr->po_id);
3504 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
3505
3506 gl.getProgramiv(out_test_ptr->po_id, GL_LINK_STATUS, &link_status);
3507 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
3508
3509 if (link_status != GL_TRUE)
3510 {
3511 TCU_FAIL("Program linking failed");
3512 }
3513
3514 /* Retrieve uniform locations */
3515 out_test_ptr->inner_tess_levels_uniform_location = gl.getUniformLocation(out_test_ptr->po_id, "inner_tess_levels");
3516 out_test_ptr->outer_tess_levels_uniform_location = gl.getUniformLocation(out_test_ptr->po_id, "outer_tess_levels");
3517
3518 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation() call(s) failed");
3519
3520 if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3521 {
3522 DE_ASSERT(out_test_ptr->inner_tess_levels_uniform_location != -1);
3523 DE_ASSERT(out_test_ptr->outer_tess_levels_uniform_location != -1);
3524 }
3525 }
3526
3527 /** Executes the test.
3528 *
3529 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
3530 *
3531 * Note the function throws exception should an error occur!
3532 *
3533 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
3534 **/
iterate(void)3535 tcu::TestNode::IterateResult TessellationShaderTCTEgl_TessLevel::iterate(void)
3536 {
3537 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3538
3539 /* Initialize ES test objects */
3540 initTest();
3541
3542 /* Our program object takes a single quad per patch */
3543 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 4);
3544 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed");
3545
3546 /* Prepare for rendering */
3547 gl.enable(GL_RASTERIZER_DISCARD);
3548 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed.");
3549
3550 /* We will iterate through all added tests. */
3551 for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); ++test_iterator)
3552 {
3553 /* Iterate through a few different inner/outer tessellation level combinations */
3554 glw::GLfloat tessellation_level_combinations[] = {
3555 /* inner[0] */ /* inner[1] */ /* outer[0] */ /* outer[1] */ /* outer[2] */ /* outer[3] */
3556 1.1f, 1.4f, 2.7f, 3.1f, 4.4f, 5.7f, 64.2f, 32.5f, 16.8f, 8.2f, 4.5f, 2.8f, 3.3f, 6.6f, 9.9f, 12.3f, 15.6f,
3557 18.9f
3558 };
3559 const unsigned int n_tessellation_level_combinations = sizeof(tessellation_level_combinations) /
3560 sizeof(tessellation_level_combinations[0]) /
3561 6; /* 2 inner + 4 outer levels */
3562
3563 for (unsigned int n_combination = 0; n_combination < n_tessellation_level_combinations; ++n_combination)
3564 {
3565 glw::GLfloat inner_tess_level[] = { tessellation_level_combinations[n_combination * 6 + 0],
3566 tessellation_level_combinations[n_combination * 6 + 1] };
3567
3568 glw::GLfloat outer_tess_level[] = { tessellation_level_combinations[n_combination * 6 + 2],
3569 tessellation_level_combinations[n_combination * 6 + 3],
3570 tessellation_level_combinations[n_combination * 6 + 4],
3571 tessellation_level_combinations[n_combination * 6 + 5] };
3572
3573 TessellationShaderUtils tessUtils(gl, this);
3574 const unsigned int n_rendered_vertices = tessUtils.getAmountOfVerticesGeneratedByTessellator(
3575 TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS, inner_tess_level, outer_tess_level,
3576 test_iterator->vertex_spacing, true); /* is_point_mode_enabled */
3577
3578 /* Test type determines how the tessellation levels should be set. */
3579 gl.useProgram(test_iterator->po_id);
3580 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
3581
3582 switch (test_iterator->type)
3583 {
3584 case TESSELLATION_TEST_TYPE_TCS_TES:
3585 {
3586 gl.uniform2fv(test_iterator->inner_tess_levels_uniform_location, 1, /* count */
3587 inner_tess_level);
3588 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform2fv() call failed");
3589
3590 gl.uniform4fv(test_iterator->outer_tess_levels_uniform_location, 1, /* count */
3591 outer_tess_level);
3592 GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform4fv() call failed");
3593
3594 break;
3595 }
3596
3597 case TESSELLATION_TEST_TYPE_TES:
3598 {
3599 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3600 {
3601 gl.patchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, inner_tess_level);
3602
3603 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameterfv() call failed for"
3604 " GL_PATCH_DEFAULT_INNER_LEVEL pname");
3605
3606 gl.patchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, outer_tess_level);
3607
3608 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameterfv() call failed for"
3609 " GL_PATCH_DEFAULT_OUTER_LEVEL pname");
3610 }
3611 break;
3612 }
3613
3614 default:
3615 {
3616 TCU_FAIL("Unrecognized test type");
3617 }
3618 } /* switch (test_iterator->type) */
3619
3620 /* Set up storage properties for the buffer object, to which XFBed data will be
3621 * written.
3622 */
3623 const unsigned int n_bytes_needed =
3624 static_cast<unsigned int>(n_rendered_vertices * (2 /* vec2 */ + 4 /* vec4 */) * sizeof(float));
3625
3626 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, n_bytes_needed, NULL /* data */, GL_STATIC_DRAW);
3627 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
3628
3629 /* Render the test geometry */
3630 gl.beginTransformFeedback(GL_POINTS);
3631 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
3632 {
3633 /* A single vertex will do, since we configured GL_PATCH_VERTICES_EXT to be 1 */
3634 gl.drawArrays(GL_PATCHES_EXT, 0 /* first */, 4 /* count */);
3635
3636 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
3637 }
3638 gl.endTransformFeedback();
3639 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
3640
3641 /* Now that the BO is filled with data, map it so we can check the storage's contents */
3642 const float* mapped_data_ptr = (const float*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
3643 n_bytes_needed, GL_MAP_READ_BIT);
3644
3645 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
3646
3647 /* Verify the contents. For each result vertex, inner/outer tessellation levels should
3648 * be unchanged. */
3649 const float epsilon = (float)1e-5;
3650 const unsigned int n_result_points =
3651 static_cast<unsigned int>(n_bytes_needed / sizeof(float) / (2 /* vec2 */ + 4 /* vec4 */));
3652
3653 for (unsigned int n_point = 0; n_point < n_result_points; ++n_point)
3654 {
3655 const float* point_data_ptr = mapped_data_ptr + (2 /* vec2 */ + 4 /* vec4 */) * n_point;
3656
3657 if (de::abs(point_data_ptr[2] - outer_tess_level[0]) > epsilon ||
3658 de::abs(point_data_ptr[3] - outer_tess_level[1]) > epsilon)
3659 {
3660 std::string vertex_spacing_mode_string =
3661 TessellationShaderUtils::getESTokenForVertexSpacingMode(test_iterator->vertex_spacing);
3662
3663 m_testCtx.getLog() << tcu::TestLog::Message
3664 << "Invalid inner/outer tessellation level used in TE stage;"
3665 << " expected outer:(" << outer_tess_level[0] << ", " << outer_tess_level[1]
3666 << ") "
3667 << " rendered outer:(" << point_data_ptr[2] << ", " << point_data_ptr[3] << ")"
3668 << " vertex spacing mode: " << vertex_spacing_mode_string.c_str()
3669 << tcu::TestLog::EndMessage;
3670
3671 TCU_FAIL("Invalid inner/outer tessellation level used in TE stage");
3672 }
3673 } /* for (all points) */
3674
3675 /* All done - unmap the storage */
3676 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
3677 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
3678 } /* for (all tess level combinations) */
3679 } /* for (all tests) */
3680
3681 /* All done */
3682 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3683 return STOP;
3684 }
3685
3686 /** Constructor
3687 *
3688 * @param context Test context
3689 **/
TessellationShaderTCTEgl_PatchVerticesIn(Context & context,const ExtParameters & extParams)3690 TessellationShaderTCTEgl_PatchVerticesIn::TessellationShaderTCTEgl_PatchVerticesIn(Context& context,
3691 const ExtParameters& extParams)
3692 : TestCaseBase(context, extParams, "gl_PatchVerticesIn",
3693 "Verifies gl_PatchVerticesIn size is valid in a tessellation"
3694 " evaluation shader and corresponds to the value configured in"
3695 " a tessellation control shader (should one be present) or to"
3696 " the default value, as set with glPatchParameteriEXT() call")
3697 , m_gl_max_patch_vertices_value(0)
3698 , m_bo_id(0)
3699 , m_vao_id(0)
3700 {
3701 /* Left blank on purpose */
3702 }
3703
3704 /** Deinitializes all ES objects created for the test. */
deinit()3705 void TessellationShaderTCTEgl_PatchVerticesIn::deinit()
3706 {
3707 /** Call base class' deinit() function */
3708 TestCaseBase::deinit();
3709
3710 if (!m_is_tessellation_shader_supported)
3711 {
3712 return;
3713 }
3714
3715 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3716
3717 /* Reset TF buffer object bindings */
3718 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
3719 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
3720
3721 /* Disable GL_RASTERIZER_DISCARD mode */
3722 gl.disable(GL_RASTERIZER_DISCARD);
3723
3724 /* Reset GL_PATCH_VERTICES_EXT to the default setting */
3725 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
3726
3727 /* Unbind vertex array object */
3728 gl.bindVertexArray(0);
3729
3730 /* Release all objects we might've created */
3731 if (m_bo_id != 0)
3732 {
3733 gl.deleteBuffers(1, &m_bo_id);
3734
3735 m_bo_id = 0;
3736 }
3737
3738 if (m_vao_id != 0)
3739 {
3740 gl.deleteVertexArrays(1, &m_vao_id);
3741
3742 m_vao_id = 0;
3743 }
3744
3745 for (_tests::iterator it = m_tests.begin(); it != m_tests.end(); ++it)
3746 {
3747 deinitTestDescriptor(&*it);
3748 }
3749 m_tests.clear();
3750 }
3751
3752 /** Deinitializes ES objects created for particular test pass.
3753 *
3754 * @param test_ptr Test run descriptor. Must not be NULL.
3755 *
3756 **/
deinitTestDescriptor(_test_descriptor * test_ptr)3757 void TessellationShaderTCTEgl_PatchVerticesIn::deinitTestDescriptor(_test_descriptor* test_ptr)
3758 {
3759 /* Call base class' deinit() */
3760 TestCaseBase::deinit();
3761
3762 /* Release all objects */
3763 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3764
3765 if (test_ptr->fs_id != 0)
3766 {
3767 gl.deleteShader(test_ptr->fs_id);
3768
3769 test_ptr->fs_id = 0;
3770 }
3771
3772 if (test_ptr->po_id != 0)
3773 {
3774 gl.deleteProgram(test_ptr->po_id);
3775
3776 test_ptr->po_id = 0;
3777 }
3778
3779 if (test_ptr->tcs_id != 0)
3780 {
3781 gl.deleteShader(test_ptr->tcs_id);
3782
3783 test_ptr->tcs_id = 0;
3784 }
3785
3786 if (test_ptr->tes_id != 0)
3787 {
3788 gl.deleteShader(test_ptr->tes_id);
3789
3790 test_ptr->tes_id = 0;
3791 }
3792
3793 if (test_ptr->vs_id != 0)
3794 {
3795 gl.deleteShader(test_ptr->vs_id);
3796
3797 test_ptr->vs_id = 0;
3798 }
3799 }
3800
3801 /** Initializes all ES objects that will be used for the test. */
initTest()3802 void TessellationShaderTCTEgl_PatchVerticesIn::initTest()
3803 {
3804 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3805
3806 /* The test requires EXT_tessellation_shader */
3807 if (!m_is_tessellation_shader_supported)
3808 {
3809 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
3810 }
3811
3812 /* Initialize vertex array object */
3813 gl.genVertexArrays(1, &m_vao_id);
3814 GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
3815
3816 gl.bindVertexArray(m_vao_id);
3817 GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
3818
3819 /* Retrieve GL_MAX_PATCH_VERTICES_EXT value before we carry on */
3820 gl.getIntegerv(m_glExtTokens.MAX_PATCH_VERTICES, &m_gl_max_patch_vertices_value);
3821
3822 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv() for GL_MAX_PATCH_VERTICES_EXT pname failed");
3823
3824 /* Initialize test descriptors.
3825 *
3826 * Make sure the values we use are multiples of 4 - this is because we're using isolines in the
3827 * tessellation stage, and in order to have the requested amount of line segments generated, we need
3828 * to use a multiply of 4 vertices per patch */
3829 glw::GLint n_half_max_patch_vertices_mul_4 = m_gl_max_patch_vertices_value / 2;
3830 glw::GLint n_max_patch_vertices_mul_4 = m_gl_max_patch_vertices_value;
3831
3832 if ((n_half_max_patch_vertices_mul_4 % 4) != 0)
3833 {
3834 /* Round to nearest mul-of-4 integer */
3835 n_half_max_patch_vertices_mul_4 += (4 - (m_gl_max_patch_vertices_value / 2) % 4);
3836 }
3837
3838 if ((n_max_patch_vertices_mul_4 % 4) != 0)
3839 {
3840 /* Round to previous nearest mul-of-4 integer */
3841 n_max_patch_vertices_mul_4 -= (m_gl_max_patch_vertices_value % 4);
3842 }
3843
3844 _test_descriptor test_tcs_tes_4;
3845 _test_descriptor test_tcs_tes_half_max_patch_vertices_mul_4;
3846 _test_descriptor test_tcs_tes_max_patch_vertices_mul_4;
3847 _test_descriptor test_tes_4;
3848 _test_descriptor test_tes_half_max_patch_vertices_mul_4;
3849 _test_descriptor test_tes_max_patch_vertices_mul_4;
3850
3851 initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_4, 4);
3852 initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_half_max_patch_vertices_mul_4,
3853 n_half_max_patch_vertices_mul_4);
3854 initTestDescriptor(TESSELLATION_TEST_TYPE_TCS_TES, &test_tcs_tes_max_patch_vertices_mul_4,
3855 n_max_patch_vertices_mul_4);
3856 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3857 {
3858 initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_4, 4);
3859 initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_half_max_patch_vertices_mul_4,
3860 n_half_max_patch_vertices_mul_4);
3861 initTestDescriptor(TESSELLATION_TEST_TYPE_TES, &test_tes_max_patch_vertices_mul_4, n_max_patch_vertices_mul_4);
3862 }
3863
3864 m_tests.push_back(test_tcs_tes_4);
3865 m_tests.push_back(test_tcs_tes_half_max_patch_vertices_mul_4);
3866 m_tests.push_back(test_tcs_tes_max_patch_vertices_mul_4);
3867 if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
3868 {
3869 m_tests.push_back(test_tes_4);
3870 m_tests.push_back(test_tes_half_max_patch_vertices_mul_4);
3871 m_tests.push_back(test_tes_max_patch_vertices_mul_4);
3872 }
3873
3874 /* Generate and set up a buffer object we will use to hold XFBed data.
3875 *
3876 * NOTE: We do not set the buffer object's storage here because its size
3877 * is iteration-specific.
3878 **/
3879 gl.genBuffers(1, &m_bo_id);
3880 GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers() call failed");
3881
3882 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
3883 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer() call failed");
3884 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
3885 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferBase() call failed");
3886
3887 /* We're good to execute the test! */
3888 }
3889
3890 /** Initializes ES objects for a particular tess pass.
3891 *
3892 * @param test_type Determines test type to be used for initialization.
3893 * TEST_TYPE_TCS_TES will use both TC and TE stages,
3894 * TEST_TYPE_TES will assume only TE stage should be used.
3895 * @param out_test_ptr Deref will be used to store object data. Must not be NULL.
3896 * @param input_patch_size Tells how many vertices should be used per patch for hte
3897 * result program object.
3898 **/
initTestDescriptor(_tessellation_test_type test_type,_test_descriptor * out_test_ptr,unsigned int input_patch_size)3899 void TessellationShaderTCTEgl_PatchVerticesIn::initTestDescriptor(_tessellation_test_type test_type,
3900 _test_descriptor* out_test_ptr,
3901 unsigned int input_patch_size)
3902 {
3903 out_test_ptr->input_patch_size = input_patch_size;
3904 out_test_ptr->type = test_type;
3905
3906 /* Generate a program object we will later configure */
3907 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
3908
3909 out_test_ptr->po_id = gl.createProgram();
3910
3911 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
3912
3913 /* Generate shader objects the test will use */
3914 out_test_ptr->fs_id = gl.createShader(GL_FRAGMENT_SHADER);
3915 out_test_ptr->vs_id = gl.createShader(GL_VERTEX_SHADER);
3916
3917 if (test_type == TESSELLATION_TEST_TYPE_TCS_TES || test_type == TESSELLATION_TEST_TYPE_TES)
3918 {
3919 out_test_ptr->tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
3920 }
3921
3922 if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3923 {
3924 out_test_ptr->tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
3925 }
3926
3927 GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateShader() failed");
3928
3929 /* Configure fragment shader */
3930 const char* fs_body = "${VERSION}\n"
3931 "\n"
3932 "void main()\n"
3933 "{\n"
3934 "}\n";
3935
3936 shaderSourceSpecialized(out_test_ptr->fs_id, 1 /* count */, &fs_body);
3937 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for fragment shader object");
3938
3939 /* Configure tessellation control shader */
3940 const char* tc_body = "${VERSION}\n"
3941 "\n"
3942 /* Required EXT_tessellation_shader functionality */
3943 "${TESSELLATION_SHADER_REQUIRE}\n"
3944 "\n"
3945 "layout (vertices = VERTICES_TOKEN) out;\n"
3946 "\n"
3947 "void main()\n"
3948 "{\n"
3949 " gl_out [gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
3950 " gl_TessLevelOuter[0] = 1.0;\n"
3951 " gl_TessLevelOuter[1] = 1.0;\n"
3952 "}\n";
3953
3954 if (test_type == TESSELLATION_TEST_TYPE_TCS_TES)
3955 {
3956 const char* result_body = NULL;
3957 std::string tc_body_string = tc_body;
3958 std::size_t token_index = -1;
3959 const char* token_string = "VERTICES_TOKEN";
3960 std::stringstream vertices_stringstream;
3961 std::string vertices_string;
3962
3963 vertices_stringstream << input_patch_size;
3964 vertices_string = vertices_stringstream.str();
3965
3966 while ((token_index = tc_body_string.find(token_string)) != std::string::npos)
3967 {
3968 tc_body_string = tc_body_string.replace(token_index, strlen(token_string), vertices_string);
3969 }
3970
3971 result_body = tc_body_string.c_str();
3972
3973 shaderSourceSpecialized(out_test_ptr->tcs_id, 1 /* count */, &result_body);
3974 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation control shader object");
3975 }
3976
3977 /* Configure tessellation evaluation shader */
3978 const char* te_body = "${VERSION}\n"
3979 "\n"
3980 "${TESSELLATION_SHADER_REQUIRE}\n"
3981 "\n"
3982 "layout (isolines, point_mode) in;\n"
3983 "\n"
3984 "flat out int result_PatchVerticesIn;\n"
3985 "\n"
3986 "void main()\n"
3987 "{\n"
3988 " gl_Position = gl_in[0].gl_Position;\n"
3989 "\n"
3990 " result_PatchVerticesIn = gl_PatchVerticesIn;\n"
3991 "}\n";
3992
3993 shaderSourceSpecialized(out_test_ptr->tes_id, 1 /* count */, &te_body);
3994 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for tessellation evaluation shader object");
3995
3996 /* Configure vertex shader */
3997 const char* vs_body = "${VERSION}\n"
3998 "\n"
3999 "void main()\n"
4000 "{\n"
4001 " gl_Position = vec4(float(gl_VertexID), 2.0, 3.0, 4.0);\n"
4002 "}\n";
4003
4004 shaderSourceSpecialized(out_test_ptr->vs_id, 1 /* count */, &vs_body);
4005 GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderSource() failed for vertex shader object");
4006
4007 /* Compile all shaders of our interest */
4008 const glw::GLuint shaders[] = { out_test_ptr->fs_id, out_test_ptr->tcs_id, out_test_ptr->tes_id,
4009 out_test_ptr->vs_id };
4010 const unsigned int n_shaders = sizeof(shaders) / sizeof(shaders[0]);
4011
4012 for (unsigned int n_shader = 0; n_shader < n_shaders; ++n_shader)
4013 {
4014 glw::GLint compile_status = GL_FALSE;
4015 glw::GLuint shader = shaders[n_shader];
4016
4017 if (shader != 0)
4018 {
4019 gl.compileShader(shader);
4020 GLU_EXPECT_NO_ERROR(gl.getError(), "glCompileShader() call failed");
4021
4022 gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
4023 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetShaderiv() call failed");
4024
4025 if (compile_status != GL_TRUE)
4026 {
4027 m_testCtx.getLog() << tcu::TestLog::Message << "Compilation of shader object at index " << n_shader
4028 << " failed." << tcu::TestLog::EndMessage;
4029
4030 TCU_FAIL("Shader compilation failed");
4031 }
4032 } /* if (shader != 0) */
4033 } /* for (all shaders) */
4034
4035 /* Attach the shaders to the test program object, set up XFB and then link the program */
4036 glw::GLint link_status = GL_FALSE;
4037 const char* varyings[] = {
4038 "result_PatchVerticesIn",
4039 };
4040 const unsigned int n_varyings = sizeof(varyings) / sizeof(varyings[0]);
4041
4042 gl.transformFeedbackVaryings(out_test_ptr->po_id, n_varyings, varyings, GL_INTERLEAVED_ATTRIBS);
4043 GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() call failed");
4044
4045 gl.attachShader(out_test_ptr->po_id, out_test_ptr->fs_id);
4046 gl.attachShader(out_test_ptr->po_id, out_test_ptr->vs_id);
4047
4048 if (out_test_ptr->tcs_id != 0)
4049 {
4050 gl.attachShader(out_test_ptr->po_id, out_test_ptr->tcs_id);
4051 }
4052
4053 if (out_test_ptr->tes_id != 0)
4054 {
4055 gl.attachShader(out_test_ptr->po_id, out_test_ptr->tes_id);
4056 }
4057
4058 GLU_EXPECT_NO_ERROR(gl.getError(), "glAttachShader() call(s) failed.");
4059
4060 gl.linkProgram(out_test_ptr->po_id);
4061 GLU_EXPECT_NO_ERROR(gl.getError(), "glLinkProgram() call failed.");
4062
4063 gl.getProgramiv(out_test_ptr->po_id, GL_LINK_STATUS, &link_status);
4064 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetProgramiv() call failed.");
4065
4066 if (link_status != GL_TRUE)
4067 {
4068 TCU_FAIL("Program linking failed");
4069 }
4070 }
4071
4072 /** Executes the test.
4073 *
4074 * Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
4075 *
4076 * Note the function throws exception should an error occur!
4077 *
4078 * @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
4079 **/
iterate(void)4080 tcu::TestNode::IterateResult TessellationShaderTCTEgl_PatchVerticesIn::iterate(void)
4081 {
4082 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
4083
4084 /* Initialize ES test objects */
4085 initTest();
4086
4087 /* Prepare for rendering */
4088 gl.enable(GL_RASTERIZER_DISCARD);
4089 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) call failed.");
4090
4091 /* We will iterate through all added tests. */
4092 for (_tests_const_iterator test_iterator = m_tests.begin(); test_iterator != m_tests.end(); ++test_iterator)
4093 {
4094 /* Activate test-specific program object first. */
4095 gl.useProgram(test_iterator->po_id);
4096 GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() call failed");
4097
4098 /* Test type tells determines how the tessellation levels should be set.
4099 * We don't need to do anything specific if TCS+TES are in, but if no
4100 * TCS is present, we need to configure default amount of input patch-vertices
4101 * to the test-specific value.
4102 */
4103 glw::GLint n_patch_vertices = 0;
4104
4105 switch (test_iterator->type)
4106 {
4107 case TESSELLATION_TEST_TYPE_TCS_TES:
4108 {
4109 /* We're using isolines mode which requires at least 4 input vertices per patch */
4110 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 4);
4111 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() for GL_PATCH_VERTICES_EXT failed.");
4112
4113 n_patch_vertices = 4;
4114
4115 break;
4116 }
4117
4118 case TESSELLATION_TEST_TYPE_TES:
4119 {
4120 gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, test_iterator->input_patch_size);
4121 GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() call failed");
4122
4123 n_patch_vertices = test_iterator->input_patch_size;
4124
4125 break;
4126 }
4127
4128 default:
4129 {
4130 TCU_FAIL("Unrecognized test type");
4131 }
4132 } /* switch (test_iterator->type) */
4133
4134 /* Set up storage properties for the buffer object, to which XFBed data will be
4135 * written.
4136 **/
4137 const unsigned int n_bytes_needed = sizeof(int) * 2; /* the tessellator will output two vertices */
4138
4139 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, n_bytes_needed, NULL /* data */, GL_STATIC_DRAW);
4140 GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData() call failed");
4141
4142 /* Render the test geometry */
4143 gl.beginTransformFeedback(GL_POINTS);
4144 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() call failed");
4145 {
4146 /* Pass a single patch only */
4147 gl.drawArrays(m_glExtTokens.PATCHES, 0 /* first */, n_patch_vertices);
4148
4149 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() call failed");
4150 }
4151 gl.endTransformFeedback();
4152 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() call failed");
4153
4154 /* Now that the BO is filled with data, map it so we can check the storage's contents */
4155 const int* mapped_data_ptr = (const int*)gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
4156 n_bytes_needed, GL_MAP_READ_BIT);
4157
4158 GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() call failed.");
4159
4160 /* Verify the contents. Make sure the value we retrieved is equal to the test-specific
4161 * amount of vertices per patch.
4162 */
4163 for (unsigned int n_vertex = 0; n_vertex < 2 /* output vertices */; ++n_vertex)
4164 {
4165 unsigned int te_PatchVerticesInSize = mapped_data_ptr[n_vertex];
4166
4167 if (te_PatchVerticesInSize != test_iterator->input_patch_size)
4168 {
4169 m_testCtx.getLog() << tcu::TestLog::Message << "Invalid gl_PatchVerticesIn defined for TE stage "
4170 << " and result vertex index:" << n_vertex
4171 << " expected:" << test_iterator->input_patch_size
4172 << " rendered:" << te_PatchVerticesInSize << tcu::TestLog::EndMessage;
4173
4174 TCU_FAIL("Invalid gl_PatchVerticesIn size used in TE stage");
4175 } /* if (comparison failed) */
4176 }
4177
4178 /* All done - unmap the storage */
4179 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4180 GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() call failed.");
4181 } /* for (all tests) */
4182
4183 /* All done */
4184 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4185 return STOP;
4186 }
4187
4188 } /* namespace glcts */
4189