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 "esextcTessellationShaderUtils.hpp"
25 #include "deMath.h"
26 #include "glwEnums.hpp"
27 #include "glwFunctions.hpp"
28 #include "tcuTestLog.hpp"
29 #include <sstream>
30
31 namespace glcts
32 {
33
34 /** Constructor
35 *
36 * @param gl DEQP container for ES entry-points
37 * @param parentTest Pointer to owning test instance.
38 **/
TessellationShaderUtils(const glw::Functions & gl,glcts::TestCaseBase * parentTest)39 TessellationShaderUtils::TessellationShaderUtils(const glw::Functions& gl, glcts::TestCaseBase* parentTest)
40 : m_gl(gl), m_bo_id(0), m_fs_id(0), m_qo_pg_id(0), m_vs_id(0), m_parent_test(parentTest)
41 {
42 init();
43 }
44
45 /** Destructor */
~TessellationShaderUtils()46 TessellationShaderUtils::~TessellationShaderUtils()
47 {
48 deinit();
49 }
50
51 /** Captures data generated by the tessellator when a geometry is drawn
52 * for user-provided vertex counter program.
53 *
54 * @param program Vertex counter program to use.
55 **/
captureTessellationData(_tessellation_vertex_counter_program & program)56 void TessellationShaderUtils::captureTessellationData(_tessellation_vertex_counter_program& program)
57 {
58 /* Cache current program object ID before we continue */
59 glw::GLint current_po_id = 0;
60
61 m_gl.getIntegerv(GL_CURRENT_PROGRAM, ¤t_po_id);
62 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() failed for GL_CURRENT_PROGRAM pname");
63
64 /* Cache current GL_PATCH_VERTICES_EXT setting before continuing */
65 glw::GLint current_patch_vertices = 0;
66
67 m_gl.getIntegerv(GL_PATCH_VERTICES, ¤t_patch_vertices);
68 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetIntegerv() failed for GL_PATCH_VERTICES_EXT pname");
69
70 /* Activate the program object and the query object */
71 m_gl.useProgram(program.po_id);
72 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
73
74 m_gl.beginQuery(m_parent_test->m_glExtTokens.PRIMITIVES_GENERATED, m_qo_pg_id);
75 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginQuery() called for target GL_PRIMITIVES_GENERATED_EXT failed");
76
77 /* Disable rasterization, if it's enabled */
78 glw::GLboolean is_rasterization_disabled = m_gl.isEnabled(GL_RASTERIZER_DISCARD);
79
80 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glIsEnabled(GL_RASTERIZER_DISCARD) failed");
81
82 if (is_rasterization_disabled)
83 {
84 m_gl.enable(GL_RASTERIZER_DISCARD);
85
86 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
87 }
88
89 /* Update GL_PATCH_VERTICES_EXT */
90 m_gl.patchParameteri(m_parent_test->m_glExtTokens.PATCH_VERTICES, program.n_patch_vertices);
91 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glPatchParameteriEXT() failed");
92
93 /* Draw the test geometry */
94 m_gl.drawArrays(m_parent_test->m_glExtTokens.PATCHES, 0, /* first */
95 program.n_patch_vertices); /* count */
96 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() failed");
97
98 /* End the query and retrieve the result */
99 glw::GLuint queryValue = 0;
100
101 m_gl.endQuery(m_parent_test->m_glExtTokens.PRIMITIVES_GENERATED);
102 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndQuery(GL_PRIMITIVES_GENERATED_EXT) failed");
103
104 m_gl.getQueryObjectuiv(m_qo_pg_id, GL_QUERY_RESULT, &queryValue);
105 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetQueryiv() failed");
106
107 /* Store amount of primitives under result */
108 program.n_data_vertices = ((unsigned int)queryValue);
109
110 if (!program.is_point_mode_enabled)
111 {
112 /* Quads get tessellated into triangles, meaning our primitives counter tells how
113 * many triangles were generated for both triangles and quads; isolines get
114 * tessellated into line segments.
115 */
116 if (program.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS ||
117 program.primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES)
118 {
119 program.n_data_vertices *= 3; /* each triangle gets 3 vertices */
120 }
121 else
122 {
123 program.n_data_vertices *= 2; /* each isoline gets 2 vertices */
124 }
125 } /* if (!is_point_mode_enabled) */
126
127 if (program.n_data_vertices != 0)
128 {
129 /* Now that we now, how many vertices we need to allocate space for, set up TF */
130 glw::GLint bo_size = static_cast<glw::GLint>(sizeof(float) * 3 /* components */ * program.n_data_vertices);
131
132 m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
133 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBuffer() failed");
134
135 m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
136 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBindBufferBase() failed");
137
138 m_gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bo_size, DE_NULL, /* data */
139 GL_STATIC_DRAW);
140 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBufferData() failed");
141
142 /* Set up TF */
143 glw::GLenum tf_mode =
144 TessellationShaderUtils::getTFModeForPrimitiveMode(program.primitive_mode, program.is_point_mode_enabled);
145
146 m_gl.beginTransformFeedback(tf_mode);
147 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glBeginTransformFeedback() failed");
148
149 m_gl.drawArrays(m_parent_test->m_glExtTokens.PATCHES, 0, /* first */
150 program.n_patch_vertices); /* count */
151 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() failed");
152
153 m_gl.endTransformFeedback();
154 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glEndTransformFeedback() failed");
155
156 /* Map the BO and copy the contents */
157 const void* xfb_data = m_gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, /* offset */
158 bo_size, GL_MAP_READ_BIT);
159 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glMapBufferRange() failed");
160
161 program.m_data.resize(bo_size);
162
163 memcpy(&program.m_data[0], xfb_data, bo_size);
164
165 m_gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
166 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUnmapBuffer() failed");
167 } /* if (program.n_data_vertices != 0) */
168
169 /* Bring the rasterization back up, if it was enabled prior to this call */
170 if (!is_rasterization_disabled)
171 {
172 m_gl.disable(GL_RASTERIZER_DISCARD);
173
174 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDisable(GL_RASTERIZER_DISCARD) failed");
175 }
176
177 /* Activate the pre-call program object*/
178 m_gl.useProgram(current_po_id);
179 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
180
181 /* Bring back pre-call GL_PATCH_VERTICES_EXT setting */
182 m_gl.patchParameteri(m_parent_test->m_glExtTokens.PATCH_VERTICES, current_patch_vertices);
183 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glPatchParameteriEXT() failed");
184 }
185
186 /** Compiles all requested shaders. Should any of the shaders not compile,
187 * TestError exception can be thrown if @param should_succeed is set to true.
188 *
189 * @param n_shaders Amount of shader IDs passed in @param shaders argument.
190 * @param shaders IDs of shader objects to compile.
191 * @param should_succeed True if the shaders are expected to compile, false if
192 * it's fine for them to not to compile successfully.
193 **/
compileShaders(glw::GLint n_shaders,const glw::GLuint * shaders,bool should_succeed)194 void TessellationShaderUtils::compileShaders(glw::GLint n_shaders, const glw::GLuint* shaders, bool should_succeed)
195 {
196 for (glw::GLint n_shader = 0; n_shader < n_shaders; ++n_shader)
197 {
198 glw::GLuint shader = shaders[n_shader];
199
200 if (shader != 0)
201 {
202 glw::GLint compile_status = GL_FALSE;
203
204 m_gl.compileShader(shader);
205 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCompileShader() failed");
206
207 m_gl.getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
208 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv() failed");
209
210 if (should_succeed && compile_status != GL_TRUE)
211 {
212 std::string info_log = m_parent_test->getCompilationInfoLog(shader);
213 std::string shader_source = m_parent_test->getShaderSource(shader);
214
215 m_parent_test->m_context.getTestContext().getLog() << tcu::TestLog::Message
216 << "Compilation failure:\n\n"
217 << info_log << "\n\n"
218 << "Source:\n\n"
219 << shader_source << "\n\n"
220 << tcu::TestLog::EndMessage;
221 TCU_FAIL("Shader compilation failed");
222 }
223 else if (!should_succeed && compile_status == GL_TRUE)
224 {
225 std::string shader_source = m_parent_test->getShaderSource(shader);
226 m_parent_test->m_context.getTestContext().getLog() << tcu::TestLog::Message
227 << "Compilation failure expected.\nSource:\n\n"
228 << shader_source << "\n\n"
229 << tcu::TestLog::EndMessage;
230 TCU_FAIL("Shader compiled successfully, even though it was "
231 "expected to fail.");
232 }
233 }
234 } /* for (all shaders) */
235 }
236
237 /** Converts input barycentric coordinates to Cartesian coordinate system. The function assumes
238 * a triangle basis built of the following verticeS: (0.5, 0), (1, 1), (0, 1).
239 *
240 * @param barycentric_coordinates Three FP values storing barycentric coordinates of a point. Must
241 * NOT be NULL.
242 * @param out_cartesian_coordinates Deref will be used to store two result FP values. Must not be NULL.
243 **/
convertBarycentricCoordinatesToCartesian(const float * barycentric_coordinates,float * out_cartesian_coordinates)244 void TessellationShaderUtils::convertBarycentricCoordinatesToCartesian(const float* barycentric_coordinates,
245 float* out_cartesian_coordinates)
246 {
247 /* Assume output triangle uses the following base:
248 *
249 * (0.5, 0)
250 * (1, 1)
251 * (0, 1)
252 */
253 const float triangle_vertex1_cartesian[2] = { 0.5f, 0.0f };
254 const float triangle_vertex2_cartesian[2] = { 1.0f, 1.0f };
255 const float triangle_vertex3_cartesian[2] = { 0.0f, 1.0f };
256
257 out_cartesian_coordinates[0] = (float)((double)barycentric_coordinates[0] * (double)triangle_vertex1_cartesian[0] +
258 (double)barycentric_coordinates[1] * (double)triangle_vertex2_cartesian[0] +
259 (double)barycentric_coordinates[2] * (double)triangle_vertex3_cartesian[0]);
260 out_cartesian_coordinates[1] = barycentric_coordinates[0] * triangle_vertex1_cartesian[1] +
261 barycentric_coordinates[1] * triangle_vertex2_cartesian[1] +
262 barycentric_coordinates[2] * triangle_vertex3_cartesian[1];
263 }
264
265 /** Converts input Cartesian coordinates to barycentric coordinate system. The function assumes
266 * a triangle basis built of the following verticeS: (0.5, 0), (1, 1), (0, 1).
267 *
268 * @param cartesian_coordinates Two FP values storing Cartesian coordinates of a point. Must NOT
269 * be NULL.
270 * @param out_barycentric_coordinates Deref will be used to store three result FP values. Must NOT be NULL.
271 **/
convertCartesianCoordinatesToBarycentric(const float * cartesian_coordinates,float * out_barycentric_coordinates)272 void TessellationShaderUtils::convertCartesianCoordinatesToBarycentric(const float* cartesian_coordinates,
273 float* out_barycentric_coordinates)
274 {
275 /* Assume input triangle uses the following base:
276 *
277 * (0.5, 0)
278 * (1, 1)
279 * (0, 1)
280 */
281 const float x1 = 0.5f;
282 const float x2 = 1.0f;
283 const float x3 = 0.0f;
284 const float y1 = 0.0f;
285 const float y2 = 1.0f;
286 const float y3 = 1.0f;
287
288 out_barycentric_coordinates[0] =
289 ((y2 - y3) * (cartesian_coordinates[0] - x3) + (x3 - x2) * (cartesian_coordinates[1] - y3)) /
290 ((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3));
291 out_barycentric_coordinates[1] =
292 ((y3 - y1) * (cartesian_coordinates[0] - x3) + (x1 - x3) * (cartesian_coordinates[1] - y3)) /
293 ((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3));
294 out_barycentric_coordinates[2] = 1.0f - out_barycentric_coordinates[0] - out_barycentric_coordinates[1];
295 }
296
297 /** Deinitializes ES objects created for TessellationShaderUtils
298 * instance.
299 **/
deinit()300 void TessellationShaderUtils::deinit()
301 {
302 if (!m_parent_test->m_is_tessellation_shader_supported)
303 {
304 return;
305 }
306
307 if (m_bo_id != 0)
308 {
309 m_gl.deleteBuffers(1, &m_bo_id);
310
311 m_bo_id = 0;
312 }
313
314 if (m_fs_id != 0)
315 {
316 m_gl.deleteShader(m_fs_id);
317
318 m_fs_id = 0;
319 }
320
321 if (m_qo_pg_id != 0)
322 {
323 m_gl.deleteQueries(1, &m_qo_pg_id);
324
325 m_qo_pg_id = 0;
326 }
327
328 if (m_vs_id != 0)
329 {
330 m_gl.deleteShader(m_vs_id);
331
332 m_vs_id = 0;
333 }
334
335 /* Revert TF buffer object bindings */
336 m_gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
337 m_gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
338
339 /* Disable GL_RASTERIZER_DISCARD mode */
340 m_gl.disable(GL_RASTERIZER_DISCARD);
341
342 /* Restore GL_PATCH_VERTICES_EXT value */
343 m_gl.patchParameteri(m_parent_test->m_glExtTokens.PATCH_VERTICES, 3);
344 }
345
346 /** Retrieves generic tessellation control shader source code.
347 * The shader users user-specified amount of output patch vertices and:
348 *
349 * - sets gl_Position to gl_in[0].gl_Position if second argument is set to false.
350 * - sets gl_Position to gl_in[gl_InvocationID].gl_Position otherwise.
351 *
352 * @param n_patch_vertices Amount of output patch vertices
353 * to use in the shader.
354 * @param should_use_glInvocationID_indexed_input See above.
355 *
356 * @return Requested string.
357 */
getGenericTCCode(unsigned int n_patch_vertices,bool should_use_glInvocationID_indexed_input)358 std::string TessellationShaderUtils::getGenericTCCode(unsigned int n_patch_vertices,
359 bool should_use_glInvocationID_indexed_input)
360 {
361 std::string result;
362 const char* tc_body_false = "${VERSION}\n"
363 "\n"
364 "${TESSELLATION_SHADER_REQUIRE}\n"
365 "\n"
366 "layout (vertices = MAX_VERTICES) out;\n"
367 "\n"
368 "uniform vec2 inner_tess_level;\n"
369 "uniform vec4 outer_tess_level;\n"
370 "\n"
371 "void main()\n"
372 "{\n"
373 " gl_out[gl_InvocationID].gl_Position = gl_in[0].gl_Position;\n"
374 "\n"
375 " gl_TessLevelInner[0] = inner_tess_level.x;\n"
376 " gl_TessLevelInner[1] = inner_tess_level.y;\n"
377 " gl_TessLevelOuter[0] = outer_tess_level.x;\n"
378 " gl_TessLevelOuter[1] = outer_tess_level.y;\n"
379 " gl_TessLevelOuter[2] = outer_tess_level.z;\n"
380 " gl_TessLevelOuter[3] = outer_tess_level.w;\n"
381 "}\n";
382
383 const char* tc_body_true = "${VERSION}\n"
384 "\n"
385 "${TESSELLATION_SHADER_REQUIRE}\n"
386 "\n"
387 "layout (vertices = MAX_VERTICES) out;\n"
388 "\n"
389 "uniform vec2 inner_tess_level;\n"
390 "uniform vec4 outer_tess_level;\n"
391 "\n"
392 "void main()\n"
393 "{\n"
394 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
395 "\n"
396 " gl_TessLevelInner[0] = inner_tess_level.x;\n"
397 " gl_TessLevelInner[1] = inner_tess_level.y;\n"
398 " gl_TessLevelOuter[0] = outer_tess_level.x;\n"
399 " gl_TessLevelOuter[1] = outer_tess_level.y;\n"
400 " gl_TessLevelOuter[2] = outer_tess_level.z;\n"
401 " gl_TessLevelOuter[3] = outer_tess_level.w;\n"
402 "}\n";
403
404 const char* n_patch_vertices_raw_ptr = NULL;
405 std::stringstream n_patch_vertices_sstream;
406 std::string n_patch_vertices_string;
407 std::string token = "MAX_VERTICES";
408 std::size_t token_index = std::string::npos;
409
410 n_patch_vertices_sstream << n_patch_vertices;
411 n_patch_vertices_string = n_patch_vertices_sstream.str();
412 n_patch_vertices_raw_ptr = n_patch_vertices_string.c_str();
413
414 result = (should_use_glInvocationID_indexed_input) ? tc_body_true : tc_body_false;
415
416 while ((token_index = result.find(token)) != std::string::npos)
417 {
418 result = result.replace(token_index, token.length(), n_patch_vertices_raw_ptr);
419
420 token_index = result.find(token);
421 }
422
423 return result;
424 }
425
426 /** Retrieves generic tessellation evaluation shader source code.
427 * The shader users user-specified tessellation properties.
428 *
429 * @param vertex_spacing Vertex spacing mode to use in the shader.
430 * @param primitive_mode Primitive mode to use in the shader.
431 * @param point_mode true to use point_mode in the shader, false
432 * to omit it.
433 *
434 * @return Requested string.
435 */
getGenericTECode(_tessellation_shader_vertex_spacing vertex_spacing,_tessellation_primitive_mode primitive_mode,_tessellation_shader_vertex_ordering vertex_ordering,bool point_mode)436 std::string TessellationShaderUtils::getGenericTECode(_tessellation_shader_vertex_spacing vertex_spacing,
437 _tessellation_primitive_mode primitive_mode,
438 _tessellation_shader_vertex_ordering vertex_ordering,
439 bool point_mode)
440 {
441 std::string result;
442 const char* te_body = "${VERSION}\n"
443 "\n"
444 "${TESSELLATION_SHADER_REQUIRE}\n"
445 "\n"
446 "layout (TESSELLATOR_PRIMITIVE_MODE VERTEX_SPACING_MODE VERTEX_ORDERING POINT_MODE) in;\n"
447 "\n"
448 "out vec3 result_uvw;\n"
449 "\n"
450 "void main()\n"
451 "{\n"
452 " gl_Position = gl_in[0].gl_Position;\n"
453 " result_uvw = gl_TessCoord;\n"
454 "}\n";
455
456 const char* point_mode_token = "POINT_MODE";
457 std::size_t point_mode_token_index = std::string::npos;
458 std::string primitive_mode_string = TessellationShaderUtils::getESTokenForPrimitiveMode(primitive_mode);
459 const char* primitive_mode_token = "TESSELLATOR_PRIMITIVE_MODE";
460 std::size_t primitive_mode_token_index = std::string::npos;
461 std::string vertex_ordering_string;
462 const char* vertex_ordering_token = "VERTEX_ORDERING";
463 std::size_t vertex_ordering_token_index = std::string::npos;
464 std::string vertex_spacing_mode_string;
465 const char* vertex_spacing_token = "VERTEX_SPACING_MODE";
466 std::size_t vertex_spacing_token_index = std::string::npos;
467
468 result = te_body;
469
470 /* Prepare the vertex ordering token. We need to do this manually, because the default vertex spacing
471 * mode translates to empty string and the shader would fail to compile if we hadn't taken care of the
472 * comma
473 */
474 if (vertex_ordering == TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT)
475 {
476 vertex_ordering_string = TessellationShaderUtils::getESTokenForVertexOrderingMode(vertex_ordering);
477 }
478 else
479 {
480 std::stringstream helper_sstream;
481
482 helper_sstream << ", " << TessellationShaderUtils::getESTokenForVertexOrderingMode(vertex_ordering);
483
484 vertex_ordering_string = helper_sstream.str();
485 }
486
487 /* Do the same for vertex spacing token */
488 if (vertex_spacing == TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT)
489 {
490 vertex_spacing_mode_string = TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing);
491 }
492 else
493 {
494 std::stringstream helper_sstream;
495
496 helper_sstream << ", " << TessellationShaderUtils::getESTokenForVertexSpacingMode(vertex_spacing);
497
498 vertex_spacing_mode_string = helper_sstream.str();
499 }
500
501 /* Primitive mode */
502 while ((primitive_mode_token_index = result.find(primitive_mode_token)) != std::string::npos)
503 {
504 result = result.replace(primitive_mode_token_index, strlen(primitive_mode_token), primitive_mode_string);
505
506 primitive_mode_token_index = result.find(primitive_mode_token);
507 }
508
509 /* Vertex ordering */
510 while ((vertex_ordering_token_index = result.find(vertex_ordering_token)) != std::string::npos)
511 {
512 result = result.replace(vertex_ordering_token_index, strlen(vertex_ordering_token), vertex_ordering_string);
513
514 vertex_ordering_token_index = result.find(vertex_ordering_token);
515 }
516
517 /* Vertex spacing */
518 while ((vertex_spacing_token_index = result.find(vertex_spacing_token)) != std::string::npos)
519 {
520 result = result.replace(vertex_spacing_token_index, strlen(vertex_spacing_token), vertex_spacing_mode_string);
521
522 vertex_spacing_token_index = result.find(vertex_spacing_token);
523 }
524
525 /* Point mode */
526 while ((point_mode_token_index = result.find(point_mode_token)) != std::string::npos)
527 {
528 result = result.replace(point_mode_token_index, strlen(point_mode_token), (point_mode) ? ", point_mode" : "");
529
530 point_mode_token_index = result.find(point_mode_token);
531 }
532
533 return result;
534 }
535
536 /** Initializes ES objects that will be needed for non-static calls
537 *
538 * This function throws TestError exception if an error occurs.
539 *
540 **/
init()541 void TessellationShaderUtils::init()
542 {
543 if (!m_parent_test->m_is_tessellation_shader_supported)
544 {
545 throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
546 }
547
548 /* Create buffer object used to hold XFB data */
549 m_gl.genBuffers(1, &m_bo_id);
550 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenBuffers() failed");
551
552 /* Create query object */
553 m_gl.genQueries(1, &m_qo_pg_id);
554 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGenQueries() failed");
555
556 /* Initialize shader objects */
557 m_fs_id = m_gl.createShader(GL_FRAGMENT_SHADER);
558 m_vs_id = m_gl.createShader(GL_VERTEX_SHADER);
559
560 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glCreateShader() failed");
561
562 /* Initialize bodies of the shaders and try to compile them */
563 const glw::GLuint shaders[] = { m_fs_id, m_vs_id };
564 const unsigned int n_shaders = DE_LENGTH_OF_ARRAY(shaders);
565
566 const char* fs_body = "${VERSION}\n"
567 "\n"
568 "void main()\n"
569 "{\n"
570 "}\n";
571 const char* vs_body = "${VERSION}\n"
572 "\n"
573 "void main()\n"
574 "{\n"
575 " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
576 "}\n";
577
578 m_parent_test->shaderSourceSpecialized(m_fs_id, 1 /* count */, &fs_body);
579 m_parent_test->shaderSourceSpecialized(m_vs_id, 1 /* count */, &vs_body);
580 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glShaderSource() failed");
581
582 compileShaders(n_shaders, shaders, true);
583 }
584
585 /** Retrieves amount of vertices that will be generated for a draw call
586 * that uses a program object, which is built of (at least) one tessellation
587 * stage.
588 *
589 * NOTE: This function can temporarily unbind active program object.
590 * This function throws TestError exception if an error occurs.
591 *
592 * @param primitive_mode Primitive mode used for the tessellation.
593 * @param inner_tessellation_level Two FP values that define inner tessellation levels.
594 * Must NOT be NULL.
595 * @param outer_tessellation_level Four FP values that define outer tessellation levels.
596 * Must NOT be NULL.
597 * @param vertex_spacing Vertex spacing mode used for the tessellation.
598 * @param is_point_mode_enabled true if point_mode should be enabled for the query,
599 * false otherwise.
600 *
601 * This function REQUIRES GL_EXT_geometry_shader support.
602 * This function throws TestError exception, should an error occur.
603 *
604 * @return Amount of vertices that would be generated by the tessellator unit for
605 * a particular draw call.
606 **/
getAmountOfVerticesGeneratedByTessellator(_tessellation_primitive_mode primitive_mode,const float * inner_tessellation_level,const float * outer_tessellation_level,_tessellation_shader_vertex_spacing vertex_spacing,bool is_point_mode_enabled)607 unsigned int TessellationShaderUtils::getAmountOfVerticesGeneratedByTessellator(
608 _tessellation_primitive_mode primitive_mode, const float* inner_tessellation_level,
609 const float* outer_tessellation_level, _tessellation_shader_vertex_spacing vertex_spacing,
610 bool is_point_mode_enabled)
611 {
612 unsigned int result = 0;
613
614 switch (primitive_mode)
615 {
616 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
617 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
618 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
619 {
620 /* We refer to a counter program, TC and TE stages are configured as specified
621 * by the caller. Before we issue the draw call, we begin a query introduced in
622 * GL_EXT_geometry_shader that allows us to count how many primitives would have been generated. Doing so
623 * allows us to determine how many vertices were generated during the processed.
624 */
625 const glw::GLint test_n_patch_vertices = 1;
626 _tessellation_vertex_counter_program test_program(m_gl);
627
628 initTessellationVertexCounterProgram(inner_tessellation_level, outer_tessellation_level, test_n_patch_vertices,
629 vertex_spacing, primitive_mode, is_point_mode_enabled, test_program);
630
631 result = test_program.n_data_vertices;
632 break;
633 }
634
635 default:
636 {
637 TCU_FAIL("Unrecognized primitive mode");
638 }
639 } /* switch (primitive_mode) */
640
641 return result;
642 }
643
644 /** Retrieves data generated by a tessellator for a particular tessellation configuration.
645 *
646 * @param inner Two FP values defining inner tessellation values to be used for tessellation.
647 * Must not be NULL.
648 * @param point_mode true if point mode is to be used for tessellation, false otherwise.
649 * @param primitive_mode Primitive mode to be used for tessellation.
650 * @param vertex_ordering Vertex ordering to be used for tessellation.
651 * @param vertex_spacing Vertex spacing to be used for tessellation.
652 * @param outer Four FP values defining outer tessellation values to be used for tessellation.
653 * Must not be NULL.
654 *
655 * @return Pointer to buffer containing tessellated coordinates.
656 **/
getDataGeneratedByTessellator(const float * inner,bool point_mode,_tessellation_primitive_mode primitive_mode,_tessellation_shader_vertex_ordering vertex_ordering,_tessellation_shader_vertex_spacing vertex_spacing,const float * outer)657 std::vector<char> TessellationShaderUtils::getDataGeneratedByTessellator(
658 const float* inner, bool point_mode, _tessellation_primitive_mode primitive_mode,
659 _tessellation_shader_vertex_ordering vertex_ordering, _tessellation_shader_vertex_spacing vertex_spacing,
660 const float* outer)
661 {
662 (void)vertex_ordering;
663
664 glw::GLint test_n_patch_vertices = getPatchVerticesForPrimitiveMode(primitive_mode);
665 _tessellation_vertex_counter_program test_program(m_gl);
666
667 initTessellationVertexCounterProgram(inner, outer, test_n_patch_vertices, vertex_spacing, primitive_mode,
668 point_mode, test_program);
669 return test_program.m_data;
670 }
671
672 /** Retrieves ESSL token corresponding to particular primitive mode.
673 * Will throw TestError exception if @param primitive_mode is not
674 * valid.
675 *
676 * @param primitive_mode Primitive mode to consider.
677 *
678 * @return String telling how the primitive mode would be expressed in
679 * ES SL.
680 **/
getESTokenForPrimitiveMode(_tessellation_primitive_mode primitive_mode)681 std::string TessellationShaderUtils::getESTokenForPrimitiveMode(_tessellation_primitive_mode primitive_mode)
682 {
683 std::string result = "?";
684
685 switch (primitive_mode)
686 {
687 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
688 {
689 result = "isolines";
690
691 break;
692 }
693
694 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
695 {
696 result = "quads";
697
698 break;
699 }
700
701 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
702 {
703 result = "triangles";
704
705 break;
706 }
707
708 default:
709 {
710 TCU_FAIL("Unrecognized tessellation primitive mode");
711 }
712 }
713
714 return result;
715 }
716
717 /** Retrieves ESSL token corresponding to particular vertex ordering.
718 * Will throw TestError exception if @param vertex_ordering is not
719 * valid.
720 *
721 * @param vertex_ordering Vertex ordering to consider.
722 *
723 * @return String telling how the vertex mode would be expressed in
724 * ES SL.
725 **/
getESTokenForVertexOrderingMode(_tessellation_shader_vertex_ordering vertex_ordering)726 std::string TessellationShaderUtils::getESTokenForVertexOrderingMode(
727 _tessellation_shader_vertex_ordering vertex_ordering)
728 {
729 std::string result;
730
731 switch (vertex_ordering)
732 {
733 case TESSELLATION_SHADER_VERTEX_ORDERING_CCW:
734 {
735 result = "ccw";
736
737 break;
738 }
739
740 case TESSELLATION_SHADER_VERTEX_ORDERING_CW:
741 {
742 result = "cw";
743
744 break;
745 }
746
747 case TESSELLATION_SHADER_VERTEX_ORDERING_DEFAULT:
748 {
749 /* Simply return an empty token */
750 result = "";
751
752 break;
753 }
754
755 default:
756 {
757 TCU_FAIL("Unrecognized tessellation shader vertex ordering");
758 }
759 } /* switch (vertex_ordering) */
760
761 return result;
762 }
763
764 /** Retrieves ESSL token corresponding to particular vertex spacing mode.
765 * Will throw TestError exception if @param vertex_spacing is not
766 * valid.
767 *
768 * @param vertex_spacing Vertex spacing mode to consider.
769 *
770 * @return String telling how the vertex spacing mode would be expressed in
771 * ES SL.
772 **/
getESTokenForVertexSpacingMode(_tessellation_shader_vertex_spacing vertex_spacing)773 std::string TessellationShaderUtils::getESTokenForVertexSpacingMode(_tessellation_shader_vertex_spacing vertex_spacing)
774 {
775 std::string result;
776
777 switch (vertex_spacing)
778 {
779 case TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT:
780 {
781 result = "";
782
783 break;
784 }
785
786 case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
787 {
788 result = "equal_spacing";
789
790 break;
791 }
792
793 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN:
794 {
795 result = "fractional_even_spacing";
796
797 break;
798 }
799
800 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
801 {
802 result = "fractional_odd_spacing";
803
804 break;
805 }
806
807 default:
808 {
809 TCU_FAIL("Invalid vertex spacing mode requested");
810 }
811 }
812
813 return result;
814 }
815
816 /** Tells how many vertices should be passed in a single patch for
817 * particular primitive mode to work for tessellation stage.
818 *
819 * Throws TestError exception if @param primitive_mode is invalid.
820 *
821 * @param primitive_mode Primitive mode to consider.
822 *
823 * @return Requested value.
824 **/
getPatchVerticesForPrimitiveMode(_tessellation_primitive_mode primitive_mode)825 glw::GLint TessellationShaderUtils::getPatchVerticesForPrimitiveMode(_tessellation_primitive_mode primitive_mode)
826 {
827 glw::GLint result = 0;
828
829 switch (primitive_mode)
830 {
831 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
832 result = 4;
833 break;
834 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
835 result = 4;
836 break;
837 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
838 result = 3;
839 break;
840
841 default:
842 {
843 TCU_FAIL("Unrecognized primitive mode");
844 }
845 } /* switch (primitive_mode) */
846
847 return result;
848 }
849
850 /** Retrieves tessellation level used by the tessellator, given
851 * vertex spacing setting.
852 *
853 * @param vertex_spacing Vertex spacing used for tessellation
854 * evaluation stage;
855 * @param level Tessellation level as defined in TC
856 * stage OR as configured with
857 * GL_PATCH_DEFAULT_*_LEVEL pnames.
858 * @param gl_max_tess_gen_level_value GL_MAX_TESS_GEN_LEVEL_EXT pname value,
859 * as reported by the implementation.
860 * @param out_clamped Deref will be used to store clamped (but
861 * not rounded) representation. Can be NULL.
862 * @param out_clamped_and_rounded Deref will be used to store clamped and
863 * rounded representation. Can be NULL.
864 **/
getTessellationLevelAfterVertexSpacing(_tessellation_shader_vertex_spacing vertex_spacing,float level,glw::GLint gl_max_tess_gen_level_value,float * out_clamped,float * out_clamped_and_rounded)865 void TessellationShaderUtils::getTessellationLevelAfterVertexSpacing(_tessellation_shader_vertex_spacing vertex_spacing,
866 float level,
867 glw::GLint gl_max_tess_gen_level_value,
868 float* out_clamped, float* out_clamped_and_rounded)
869 {
870 /* Behavior is as per EXT_tessellation_shader spec */
871 switch (vertex_spacing)
872 {
873 case TESSELLATION_SHADER_VERTEX_SPACING_DEFAULT:
874 case TESSELLATION_SHADER_VERTEX_SPACING_EQUAL:
875 {
876 if (level < 1.0f)
877 {
878 level = 1.0f;
879 }
880 else if (level > (float)gl_max_tess_gen_level_value)
881 {
882 level = (float)gl_max_tess_gen_level_value;
883 }
884
885 if (out_clamped != DE_NULL)
886 {
887 *out_clamped = level;
888 }
889
890 /* Round *up* to nearest integer */
891 level = (float)((int)(deFloatCeil(level) + 0.5f));
892
893 if (out_clamped_and_rounded != DE_NULL)
894 {
895 *out_clamped_and_rounded = level;
896 }
897
898 break;
899 }
900
901 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_EVEN:
902 {
903 if (level < 2.0f)
904 {
905 level = 2.0f;
906 }
907 else if (level > (float)gl_max_tess_gen_level_value)
908 {
909 level = (float)gl_max_tess_gen_level_value;
910 }
911
912 if (out_clamped != DE_NULL)
913 {
914 *out_clamped = level;
915 }
916
917 /* Round *up* to nearest *even* integer */
918 int level_temp = (int)(deFloatCeil(level) + 0.5f);
919
920 if ((level_temp % 2) != 0)
921 {
922 level_temp++;
923 }
924
925 if (out_clamped_and_rounded != DE_NULL)
926 {
927 *out_clamped_and_rounded = (float)level_temp;
928 }
929
930 break;
931 }
932
933 case TESSELLATION_SHADER_VERTEX_SPACING_FRACTIONAL_ODD:
934 {
935 if (level < 1.0f)
936 {
937 level = 1.0f;
938 }
939 else if (level > (float)(gl_max_tess_gen_level_value - 1))
940 {
941 level = (float)(gl_max_tess_gen_level_value - 1);
942 }
943
944 if (out_clamped != DE_NULL)
945 {
946 *out_clamped = level;
947 }
948
949 /* Round to *up* nearest *odd* integer */
950 int level_temp = (int)(deFloatCeil(level) + 0.5f);
951
952 if ((level_temp % 2) != 1)
953 {
954 level_temp++;
955 }
956
957 if (out_clamped_and_rounded != DE_NULL)
958 {
959 *out_clamped_and_rounded = (float)level_temp;
960 }
961
962 break;
963 }
964
965 default:
966 {
967 TCU_FAIL("Unrecognized vertex spacing mode");
968 }
969 } /* switch(vertex_spacing) */
970 }
971
972 /** Returns a vector of _tessellation_levels instances with different level values.
973 *
974 * @param primitive_mode Primitive mode to consider.
975 * @param gl_max_tess_gen_level_value Implementation-specific GL_MAX_TESS_GEN_LEVEL_EXT value.
976 * @param filter Condition which all generated tuples should meet in
977 * order to land in the result vector.
978 *
979 * @return _tessellation_levels_set instance storing described values.
980 **/
getTessellationLevelSetForPrimitiveMode(_tessellation_primitive_mode primitive_mode,glw::GLint gl_max_tess_gen_level_value,_tessellation_level_set_filter filter)981 _tessellation_levels_set TessellationShaderUtils::getTessellationLevelSetForPrimitiveMode(
982 _tessellation_primitive_mode primitive_mode, glw::GLint gl_max_tess_gen_level_value,
983 _tessellation_level_set_filter filter)
984 {
985 /* As a starter value, use a tessellation level that is different for each
986 * primitive modes, just to make sure the implementation can correctly
987 * handle various tessellation level values */
988 glw::GLint n_min_patch_vertices = getPatchVerticesForPrimitiveMode(primitive_mode);
989
990 glw::GLint n_half_max_patch_vertices_mul_min = gl_max_tess_gen_level_value / 2;
991 glw::GLint n_max_patch_vertices_mul_min = gl_max_tess_gen_level_value;
992
993 if ((n_half_max_patch_vertices_mul_min % n_min_patch_vertices) != 0)
994 {
995 /* Round to nearest mul-of-min integer */
996 n_half_max_patch_vertices_mul_min +=
997 (n_min_patch_vertices - (gl_max_tess_gen_level_value / 2) % n_min_patch_vertices);
998 }
999
1000 if ((n_max_patch_vertices_mul_min % n_min_patch_vertices) != 0)
1001 {
1002 /* Round to previous nearest mul-of-min integer */
1003 n_max_patch_vertices_mul_min -= (gl_max_tess_gen_level_value % n_min_patch_vertices);
1004 }
1005
1006 /* Prepare the result vector items */
1007 _tessellation_levels_set result;
1008
1009 if ((filter & TESSELLATION_LEVEL_SET_FILTER_ALL_LEVELS_USE_THE_SAME_VALUE) != 0)
1010 {
1011 /* Prepare the result vector items */
1012 _tessellation_levels item_1;
1013 _tessellation_levels item_2;
1014 _tessellation_levels item_3;
1015
1016 item_1.inner[0] = float(n_min_patch_vertices);
1017 item_1.inner[1] = float(n_min_patch_vertices + 1);
1018 item_1.outer[0] = float(n_min_patch_vertices + 3);
1019 item_1.outer[1] = float(n_min_patch_vertices + 2);
1020 item_1.outer[2] = float(n_min_patch_vertices + 1);
1021 item_1.outer[3] = float(n_min_patch_vertices);
1022
1023 item_2.inner[0] = float(n_half_max_patch_vertices_mul_min);
1024 item_2.inner[1] = float(n_half_max_patch_vertices_mul_min - 1);
1025 item_2.outer[0] = float(n_half_max_patch_vertices_mul_min - 3);
1026 item_2.outer[1] = float(n_half_max_patch_vertices_mul_min - 2);
1027 item_2.outer[2] = float(n_half_max_patch_vertices_mul_min - 1);
1028 item_2.outer[3] = float(n_half_max_patch_vertices_mul_min);
1029
1030 item_3.inner[0] = float(n_max_patch_vertices_mul_min - 1);
1031 item_3.inner[1] = float(n_max_patch_vertices_mul_min - 2);
1032 item_3.outer[0] = float(n_max_patch_vertices_mul_min - 3);
1033 item_3.outer[1] = float(n_max_patch_vertices_mul_min - 4);
1034 item_3.outer[2] = float(n_max_patch_vertices_mul_min - 5);
1035 item_3.outer[3] = float(n_max_patch_vertices_mul_min - 6);
1036
1037 /* Push the items onto result vector. */
1038 result.push_back(item_1);
1039 result.push_back(item_2);
1040 result.push_back(item_3);
1041 }
1042 else
1043 {
1044 DE_ASSERT((filter & TESSELLATION_LEVEL_SET_FILTER_ALL_COMBINATIONS) != 0 ||
1045 (filter & TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES) != 0);
1046
1047 const glw::GLint base_values[] = { -1, 1, n_half_max_patch_vertices_mul_min, n_max_patch_vertices_mul_min };
1048 const unsigned int n_base_values = DE_LENGTH_OF_ARRAY(base_values);
1049
1050 const unsigned int n_relevant_inner_tess_levels =
1051 (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES) ?
1052 0 :
1053 (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 2 : 1;
1054
1055 const unsigned int n_relevant_outer_tess_levels =
1056 (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES) ?
1057 2 :
1058 (primitive_mode == TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS) ? 4 : 3;
1059
1060 for (unsigned int n_inner0_base_value = 0;
1061 n_inner0_base_value < ((n_relevant_inner_tess_levels > 0) ? n_base_values : 1); ++n_inner0_base_value)
1062 {
1063 const glw::GLint inner0_value = base_values[n_inner0_base_value];
1064
1065 for (unsigned int n_inner1_base_value = 0;
1066 n_inner1_base_value < ((n_relevant_inner_tess_levels > 1) ? n_base_values : 1); ++n_inner1_base_value)
1067 {
1068 const glw::GLint inner1_value = base_values[n_inner1_base_value];
1069
1070 for (unsigned int n_outer0_base_value = 0;
1071 n_outer0_base_value < ((n_relevant_outer_tess_levels > 0) ? n_base_values : 1);
1072 ++n_outer0_base_value)
1073 {
1074 const glw::GLint outer0_value = base_values[n_outer0_base_value];
1075
1076 for (unsigned int n_outer1_base_value = 0;
1077 n_outer1_base_value < ((n_relevant_outer_tess_levels > 1) ? n_base_values : 1);
1078 ++n_outer1_base_value)
1079 {
1080 const glw::GLint outer1_value = base_values[n_outer1_base_value];
1081
1082 for (unsigned int n_outer2_base_value = 0;
1083 n_outer2_base_value < ((n_relevant_outer_tess_levels > 2) ? n_base_values : 1);
1084 ++n_outer2_base_value)
1085 {
1086 const glw::GLint outer2_value = base_values[n_outer2_base_value];
1087
1088 for (unsigned int n_outer3_base_value = 0;
1089 n_outer3_base_value < ((n_relevant_outer_tess_levels > 3) ? n_base_values : 1);
1090 ++n_outer3_base_value)
1091 {
1092 const glw::GLint outer3_value = base_values[n_outer3_base_value];
1093
1094 /* Skip combinations where any of the relevant outer tessellation level values
1095 * is negative. These would cause no tessellation coordinates to be generated
1096 * by the tessellator.
1097 */
1098 if ((n_relevant_outer_tess_levels > 0 && outer0_value < 0) ||
1099 (n_relevant_outer_tess_levels > 1 && outer1_value < 0) ||
1100 (n_relevant_outer_tess_levels > 2 && outer2_value < 0) ||
1101 (n_relevant_outer_tess_levels > 3 && outer3_value < 0))
1102 {
1103 continue;
1104 }
1105
1106 /* If TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES
1107 * filter was requested, make sure the values used separately for inner and outer
1108 * tess levels are actually different. */
1109 if ((filter &
1110 TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES) != 0)
1111 {
1112 DE_ASSERT(n_base_values >= 4 /* outer tess levels supported */);
1113
1114 if ((n_relevant_inner_tess_levels > 1 && inner0_value == inner1_value) ||
1115 (n_relevant_outer_tess_levels > 1 && outer0_value == outer1_value) ||
1116 (n_relevant_outer_tess_levels > 2 && outer1_value == outer2_value) ||
1117 (n_relevant_outer_tess_levels > 3 && outer2_value == outer3_value))
1118 {
1119 continue;
1120 }
1121 } /* if ((filter & TESSELLATION_LEVEL_SET_FILTER_INNER_AND_OUTER_LEVELS_USE_DIFFERENT_VALUES) != 0) */
1122
1123 /* If TESSELLATION_LEVEL_SET_FILTER_EXCLUDE_NEGATIVE_BASE_VALUE, make sure
1124 * no inner/outer tessellation level we're about to use is negative. */
1125 if ((filter & TESSELLATION_LEVEL_SET_FILTER_EXCLUDE_NEGATIVE_BASE_VALUE) != 0)
1126 {
1127 if ((n_relevant_inner_tess_levels > 0 && inner0_value < 0) ||
1128 (n_relevant_inner_tess_levels > 1 && inner1_value < 0) ||
1129 (n_relevant_outer_tess_levels > 0 && outer0_value < 0) ||
1130 (n_relevant_outer_tess_levels > 1 && outer1_value < 0) ||
1131 (n_relevant_outer_tess_levels > 2 && outer2_value < 0) ||
1132 (n_relevant_outer_tess_levels > 3 && outer3_value < 0))
1133 {
1134 continue;
1135 }
1136 }
1137
1138 /* Construct the tess level combination */
1139 _tessellation_levels item;
1140
1141 item.inner[0] = (glw::GLfloat)inner0_value;
1142 item.inner[1] = (glw::GLfloat)inner1_value;
1143 item.outer[0] = (glw::GLfloat)outer0_value;
1144 item.outer[1] = (glw::GLfloat)outer1_value;
1145 item.outer[2] = (glw::GLfloat)outer2_value;
1146 item.outer[3] = (glw::GLfloat)outer3_value;
1147
1148 /* Store it */
1149 result.push_back(item);
1150 } /* for (all outer[3] base values) */
1151 } /* for (all outer[2] base values) */
1152 } /* for (all outer[1] base values) */
1153 } /* for (all outer[0] base values) */
1154 } /* for (all inner[1] base values) */
1155 } /* for (all inner[0] base values) */
1156 }
1157
1158 return result;
1159 }
1160
1161 /** Retrieves transform feedback mode that should be used for glBeginTransformFeedback()
1162 * call, if TF is to be active while a tessellated draw call is made.
1163 *
1164 * This function throws TestError exception if @param primitive_mode is invalid.
1165 *
1166 * @param primitive_mode Primitive mode to consider
1167 * @param is_point_mode true if tessellation is run in point_mode mode, false otherwise.
1168 *
1169 * @return Corresponding ES enum.
1170 **/
getTFModeForPrimitiveMode(_tessellation_primitive_mode primitive_mode,bool is_point_mode)1171 glw::GLenum TessellationShaderUtils::getTFModeForPrimitiveMode(_tessellation_primitive_mode primitive_mode,
1172 bool is_point_mode)
1173 {
1174 glw::GLenum result = GL_NONE;
1175
1176 if (is_point_mode)
1177 {
1178 result = GL_POINTS;
1179 }
1180 else
1181 {
1182 switch (primitive_mode)
1183 {
1184 case TESSELLATION_SHADER_PRIMITIVE_MODE_ISOLINES:
1185 {
1186 result = GL_LINES;
1187
1188 break;
1189 }
1190
1191 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1192 {
1193 result = GL_TRIANGLES;
1194
1195 break;
1196 }
1197
1198 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1199 {
1200 result = GL_TRIANGLES;
1201
1202 break;
1203 }
1204
1205 default:
1206 {
1207 TCU_FAIL("Unrecognized primitive mode");
1208 }
1209 } /* switch (primitive_mode) */
1210 }
1211
1212 return result;
1213 }
1214
1215 /** Initializes a counter program.
1216 *
1217 * This function throws a TestError exception, should an error occur.
1218 *
1219 * @param inner_tess_level Two FP values to be used for inner tessellation levels. Must not be NULL.
1220 * @param outer_tess_level Four FP values to be used for outer tessellation levels. Must not be NULL.
1221 * @param n_patch_vertices Amount of TC stage output patch vertices.
1222 * @param vertex_spacing Vertex spacing mode to be used for tessellation.
1223 * @param primitive_mode Primitive mode to be used for tessellation.
1224 * @param is_point_mode_enabled true if the point mode should be enabled for the program, false otherwise.
1225 * @param result_descriptor Objects created during initialization will be stored in the referenced descriptor.
1226 *
1227 **/
initTessellationVertexCounterProgram(const float * inner_tess_level,const float * outer_tess_level,glw::GLint n_patch_vertices,_tessellation_shader_vertex_spacing vertex_spacing,_tessellation_primitive_mode primitive_mode,bool is_point_mode_enabled,_tessellation_vertex_counter_program & result_descriptor)1228 void TessellationShaderUtils::initTessellationVertexCounterProgram(
1229 const float* inner_tess_level, const float* outer_tess_level, glw::GLint n_patch_vertices,
1230 _tessellation_shader_vertex_spacing vertex_spacing, _tessellation_primitive_mode primitive_mode,
1231 bool is_point_mode_enabled, _tessellation_vertex_counter_program& result_descriptor)
1232 {
1233 glw::GLint po_id = 0;
1234 glw::GLint tc_id = 0;
1235 glw::GLint te_id = 0;
1236
1237 /* Generate the shader objects */
1238 tc_id = m_gl.createShader(m_parent_test->m_glExtTokens.TESS_CONTROL_SHADER);
1239 te_id = m_gl.createShader(m_parent_test->m_glExtTokens.TESS_EVALUATION_SHADER);
1240
1241 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Could not create TC/TE shader objects");
1242
1243 /* Generate the program object */
1244 po_id = m_gl.createProgram();
1245
1246 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Could not create a program object");
1247
1248 /* Initialize the shaders.
1249 *
1250 * Note: it's fine to use CCW ordering here, since it does not affect the amount
1251 * of primitives generated by the tessellator.
1252 **/
1253 std::string tc_code = getGenericTCCode(n_patch_vertices, false);
1254 const char* tc_code_ptr = tc_code.c_str();
1255 std::string te_code = getGenericTECode(vertex_spacing, primitive_mode, TESSELLATION_SHADER_VERTEX_ORDERING_CCW,
1256 is_point_mode_enabled);
1257 const char* te_code_ptr = te_code.c_str();
1258
1259 /* Set up XFB */
1260 const char* varyings[] = { "result_uvw" };
1261
1262 m_gl.transformFeedbackVaryings(po_id, 1, /* count */
1263 varyings, GL_INTERLEAVED_ATTRIBS);
1264 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glTransformFeedbackVaryings() call failed");
1265
1266 /* Link the program and check that the linking has succeeded */
1267 bool build_success = m_parent_test->buildProgram(po_id, m_fs_id, 0 /* precompiled */, NULL, tc_id, 1, &tc_code_ptr,
1268 te_id, 1, &te_code_ptr, m_vs_id, 0 /* precompiled */, NULL);
1269
1270 if (!build_success)
1271 {
1272 TCU_FAIL("Compilation and/or linking failed");
1273 }
1274
1275 /* Set up the inner/outer tess level uniforms */
1276 glw::GLint inner_tess_level_uniform_location = -1;
1277 glw::GLint outer_tess_level_uniform_location = -1;
1278
1279 inner_tess_level_uniform_location = m_gl.getUniformLocation(po_id, "inner_tess_level");
1280 outer_tess_level_uniform_location = m_gl.getUniformLocation(po_id, "outer_tess_level");
1281
1282 DE_ASSERT(inner_tess_level_uniform_location != -1);
1283 DE_ASSERT(outer_tess_level_uniform_location != -1);
1284
1285 m_gl.useProgram(po_id);
1286 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() call failed");
1287
1288 m_gl.uniform2fv(inner_tess_level_uniform_location, 1, /* count */
1289 inner_tess_level);
1290 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUniform2fv() call failed");
1291
1292 m_gl.uniform4fv(outer_tess_level_uniform_location, 1, /* count */
1293 outer_tess_level);
1294 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUniform4fv() call failed");
1295
1296 /* Initialize the test descriptor */
1297 memcpy(result_descriptor.inner_tess_level, inner_tess_level, sizeof(result_descriptor.inner_tess_level));
1298 memcpy(result_descriptor.outer_tess_level, outer_tess_level, sizeof(result_descriptor.outer_tess_level));
1299
1300 result_descriptor.is_point_mode_enabled = is_point_mode_enabled;
1301 result_descriptor.n_patch_vertices = n_patch_vertices;
1302 result_descriptor.po_id = po_id;
1303 result_descriptor.primitive_mode = primitive_mode;
1304 result_descriptor.tc_id = tc_id;
1305 result_descriptor.te_id = te_id;
1306 result_descriptor.tess_level_inner_uniform_location = inner_tess_level_uniform_location;
1307 result_descriptor.tess_level_outer_uniform_location = outer_tess_level_uniform_location;
1308 result_descriptor.vertex_spacing = vertex_spacing;
1309
1310 captureTessellationData(result_descriptor);
1311 }
1312
1313 /** Tells whether user-provided vertex (expressed in tessellation space) generated
1314 * during triangle tessellation is an outer edge vertex.
1315 *
1316 * @param primitive_mode Primitive mode, for which the tessellated vertex
1317 * data was generated.
1318 * @param tessellated_vertex_data Vertex data to check. Must define 3 floats.
1319 *
1320 * @return true if the vertex is a part of an outer edge, false otherwise.
1321 **/
isOuterEdgeVertex(_tessellation_primitive_mode primitive_mode,const float * tessellated_vertex_data)1322 bool TessellationShaderUtils::isOuterEdgeVertex(_tessellation_primitive_mode primitive_mode,
1323 const float* tessellated_vertex_data)
1324 {
1325 const float epsilon = 1e-5f;
1326 bool result = false;
1327
1328 switch (primitive_mode)
1329 {
1330 case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES:
1331 {
1332 if (de::abs(tessellated_vertex_data[0]) < epsilon || de::abs(tessellated_vertex_data[0] - 1.0f) < epsilon ||
1333 de::abs(tessellated_vertex_data[1]) < epsilon || de::abs(tessellated_vertex_data[1] - 1.0f) < epsilon ||
1334 de::abs(tessellated_vertex_data[2]) < epsilon || de::abs(tessellated_vertex_data[2] - 1.0f) < epsilon)
1335 {
1336 /* Make sure vertex is inside the triangle */
1337 if (0.0f <= tessellated_vertex_data[0] && tessellated_vertex_data[0] <= 1.0f &&
1338 0.0f <= tessellated_vertex_data[1] && tessellated_vertex_data[1] <= 1.0f &&
1339 0.0f <= tessellated_vertex_data[2] && tessellated_vertex_data[2] <= 1.0f)
1340 {
1341 result = true;
1342 }
1343 }
1344
1345 break;
1346 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_TRIANGLES: */
1347
1348 case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS:
1349 {
1350 if (de::abs(tessellated_vertex_data[0]) < epsilon || de::abs(tessellated_vertex_data[0] - 1.0f) < epsilon ||
1351 de::abs(tessellated_vertex_data[1]) < epsilon || de::abs(tessellated_vertex_data[1] - 1.0f) < epsilon)
1352 {
1353 result = true;
1354 }
1355
1356 break;
1357 } /* case TESSELLATION_SHADER_PRIMITIVE_MODE_QUADS: */
1358
1359 default:
1360 {
1361 DE_FATAL("Unrecognized primitive mode");
1362 }
1363 }
1364
1365 return result;
1366 }
1367
1368 /** Returns true if two triangles are the same. Takes potentially different
1369 * vertex ordering into consideration.
1370 *
1371 * @param triangle_vertex_data Reference 9 FP values defining a triangle
1372 * that the triangle defined by @param vertex_data
1373 * will be compared against.
1374 * @param vertex_data 9 FP values defining a triangle, perhaps in
1375 * a different order, that @param triangle_vertex_data
1376 * will be checked against.
1377 *
1378 * @return true if the triangles are the same; false otherwise.
1379 *
1380 **/
isTriangleDefined(const float * triangle_vertex_data,const float * vertex_data)1381 bool TessellationShaderUtils::isTriangleDefined(const float* triangle_vertex_data, const float* vertex_data)
1382 {
1383 const float epsilon = 1e-5f;
1384 bool has_triangle_vertex1_been_found = false;
1385 bool has_triangle_vertex2_been_found = false;
1386 bool has_triangle_vertex3_been_found = false;
1387 bool result = false;
1388
1389 if ((de::abs(triangle_vertex_data[0] - vertex_data[0]) < epsilon &&
1390 de::abs(triangle_vertex_data[1] - vertex_data[1]) < epsilon &&
1391 de::abs(triangle_vertex_data[2] - vertex_data[2]) < epsilon) ||
1392 (de::abs(triangle_vertex_data[3] - vertex_data[0]) < epsilon &&
1393 de::abs(triangle_vertex_data[4] - vertex_data[1]) < epsilon &&
1394 de::abs(triangle_vertex_data[5] - vertex_data[2]) < epsilon) ||
1395 (de::abs(triangle_vertex_data[6] - vertex_data[0]) < epsilon &&
1396 de::abs(triangle_vertex_data[7] - vertex_data[1]) < epsilon &&
1397 de::abs(triangle_vertex_data[8] - vertex_data[2]) < epsilon))
1398 {
1399 has_triangle_vertex1_been_found = true;
1400 }
1401
1402 if ((de::abs(triangle_vertex_data[0] - vertex_data[3]) < epsilon &&
1403 de::abs(triangle_vertex_data[1] - vertex_data[4]) < epsilon &&
1404 de::abs(triangle_vertex_data[2] - vertex_data[5]) < epsilon) ||
1405 (de::abs(triangle_vertex_data[3] - vertex_data[3]) < epsilon &&
1406 de::abs(triangle_vertex_data[4] - vertex_data[4]) < epsilon &&
1407 de::abs(triangle_vertex_data[5] - vertex_data[5]) < epsilon) ||
1408 (de::abs(triangle_vertex_data[6] - vertex_data[3]) < epsilon &&
1409 de::abs(triangle_vertex_data[7] - vertex_data[4]) < epsilon &&
1410 de::abs(triangle_vertex_data[8] - vertex_data[5]) < epsilon))
1411 {
1412 has_triangle_vertex2_been_found = true;
1413 }
1414
1415 if ((de::abs(triangle_vertex_data[0] - vertex_data[6]) < epsilon &&
1416 de::abs(triangle_vertex_data[1] - vertex_data[7]) < epsilon &&
1417 de::abs(triangle_vertex_data[2] - vertex_data[8]) < epsilon) ||
1418 (de::abs(triangle_vertex_data[3] - vertex_data[6]) < epsilon &&
1419 de::abs(triangle_vertex_data[4] - vertex_data[7]) < epsilon &&
1420 de::abs(triangle_vertex_data[5] - vertex_data[8]) < epsilon) ||
1421 (de::abs(triangle_vertex_data[6] - vertex_data[6]) < epsilon &&
1422 de::abs(triangle_vertex_data[7] - vertex_data[7]) < epsilon &&
1423 de::abs(triangle_vertex_data[8] - vertex_data[8]) < epsilon))
1424 {
1425 has_triangle_vertex3_been_found = true;
1426 }
1427
1428 if (has_triangle_vertex1_been_found && has_triangle_vertex2_been_found && has_triangle_vertex3_been_found)
1429 {
1430 result = true;
1431 }
1432
1433 return result;
1434 }
1435
1436 } // namespace glcts
1437