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