• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "esextcTessellationShaderBarrier.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluDefs.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuTestLog.hpp"
30 
31 namespace glcts
32 {
33 
34 /** Constructor
35  *
36  * @param context       Test context
37  * @param name          Test case's name
38  * @param description   Test case's description
39  **/
TessellationShaderBarrierTests(Context & context,const ExtParameters & extParams)40 TessellationShaderBarrierTests::TessellationShaderBarrierTests(Context& context, const ExtParameters& extParams)
41 	: TestCaseGroupBase(context, extParams, "tessellation_shader_tc_barriers",
42 						"Verifies memory barrier work correctly when used in"
43 						"tessellation control shaders")
44 {
45 	/* Left blank on purpose */
46 }
47 
48 /* Instantiates all tests and adds them as children to the node */
init(void)49 void TessellationShaderBarrierTests::init(void)
50 {
51 	addChild(new glcts::TessellationShaderBarrier1(m_context, m_extParams));
52 	addChild(new glcts::TessellationShaderBarrier2(m_context, m_extParams));
53 	addChild(new glcts::TessellationShaderBarrier3(m_context, m_extParams));
54 }
55 
56 /** Constructor
57  *
58  * @param context       Test context
59  * @param name          Test case's name
60  * @param description   Test case's desricption
61  **/
TessellationShaderBarrierTestCase(Context & context,const ExtParameters & extParams,const char * name,const char * description)62 TessellationShaderBarrierTestCase::TessellationShaderBarrierTestCase(Context& context, const ExtParameters& extParams,
63 																	 const char* name, const char* description)
64 	: TestCaseBase(context, extParams, name, description)
65 	, m_bo_id(0)
66 	, m_fs_id(0)
67 	, m_po_id(0)
68 	, m_tcs_id(0)
69 	, m_tes_id(0)
70 	, m_vao_id(0)
71 	, m_vs_id(0)
72 {
73 	/* Left blank on purpose */
74 }
75 
76 /** Deinitializes all ES objects created for the test. */
deinit()77 void TessellationShaderBarrierTestCase::deinit()
78 {
79 	/** Call base class' deinit() function */
80 	TestCaseBase::deinit();
81 
82 	if (!m_is_tessellation_shader_supported)
83 	{
84 		return;
85 	}
86 
87 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
88 
89 	/* Disable GL_RASTERIZER_DISCARD mode the test has enabled */
90 	gl.disable(GL_RASTERIZER_DISCARD);
91 
92 	/* Bring back the original GL_PATCH_VERTICES_EXT setting */
93 	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, 3);
94 
95 	/* Revert buffer object bindings */
96 	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* buffer */);
97 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, 0 /* buffer */);
98 
99 	/* Unbind vertex array object */
100 	gl.bindVertexArray(0);
101 
102 	/* Free all the objects that might have been initialized */
103 	if (m_bo_id != 0)
104 	{
105 		gl.deleteBuffers(1, &m_bo_id);
106 
107 		m_bo_id = 0;
108 	}
109 
110 	if (m_fs_id != 0)
111 	{
112 		gl.deleteShader(m_fs_id);
113 
114 		m_fs_id = 0;
115 	}
116 
117 	if (m_po_id != 0)
118 	{
119 		gl.deleteProgram(m_po_id);
120 
121 		m_po_id = 0;
122 	}
123 
124 	if (m_tcs_id != 0)
125 	{
126 		gl.deleteShader(m_tcs_id);
127 
128 		m_tcs_id = 0;
129 	}
130 
131 	if (m_tes_id != 0)
132 	{
133 		gl.deleteShader(m_tes_id);
134 
135 		m_tes_id = 0;
136 	}
137 
138 	if (m_vs_id != 0)
139 	{
140 		gl.deleteShader(m_vs_id);
141 
142 		m_vs_id = 0;
143 	}
144 
145 	if (m_vao_id != 0)
146 	{
147 		gl.deleteVertexArrays(1, &m_vao_id);
148 
149 		m_vao_id = 0;
150 	}
151 }
152 
153 /** Initializes all ES objects that will be used for the test. */
initTest()154 void TessellationShaderBarrierTestCase::initTest()
155 {
156 	/* The test requires EXT_tessellation_shader */
157 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
158 
159 	if (!m_is_tessellation_shader_supported)
160 	{
161 		return;
162 	}
163 
164 	gl.genVertexArrays(1, &m_vao_id);
165 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not generate vertex array object");
166 
167 	gl.bindVertexArray(m_vao_id);
168 	GLU_EXPECT_NO_ERROR(gl.getError(), "Error binding vertex array object!");
169 
170 	/* Set up storage for XFB data. Also configure the BO binding points */
171 	const unsigned int xfb_data_size = getXFBBufferSize();
172 
173 	gl.genBuffers(1, &m_bo_id);
174 	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_bo_id);
175 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* index */, m_bo_id);
176 	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_data_size, NULL /* data */, GL_STATIC_DRAW);
177 
178 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not set up storage for XFB data");
179 
180 	/* Set up shader objects */
181 	m_fs_id  = gl.createShader(GL_FRAGMENT_SHADER);
182 	m_tcs_id = gl.createShader(m_glExtTokens.TESS_CONTROL_SHADER);
183 	m_tes_id = gl.createShader(m_glExtTokens.TESS_EVALUATION_SHADER);
184 	m_vs_id  = gl.createShader(GL_VERTEX_SHADER);
185 
186 	GLU_EXPECT_NO_ERROR(gl.getError(), "Could not create shader objects");
187 
188 	/* Set up fragment shader body */
189 	const char* fs_body = "${VERSION}\n"
190 						  "\n"
191 						  "void main()\n"
192 						  "{\n"
193 						  "}\n";
194 
195 	/* Set up tessellation control shader body */
196 	const char* tcs_body = getTCSCode();
197 
198 	/* Set up tessellation evaluation shader body */
199 	const char* tes_body = getTESCode();
200 
201 	/* Set up vertex shader body */
202 	const char* vs_body = getVSCode();
203 
204 	/* Set up a program object */
205 	m_po_id = gl.createProgram();
206 
207 	GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateProgram() failed");
208 
209 	/* Set up XFB */
210 	const char** names   = NULL;
211 	int			 n_names = 0;
212 
213 	getXFBProperties(&n_names, &names);
214 
215 	gl.transformFeedbackVaryings(m_po_id, n_names, names, GL_INTERLEAVED_ATTRIBS);
216 	GLU_EXPECT_NO_ERROR(gl.getError(), "glTransformFeedbackVaryings() failed");
217 
218 	/* Try to compile and link all the shader objects */
219 	if (!buildProgram(m_po_id, m_fs_id, 1, &fs_body, m_tcs_id, 1, &tcs_body, m_tes_id, 1, &tes_body, m_vs_id, 1,
220 					  &vs_body))
221 	{
222 		TCU_FAIL("Program linking failed");
223 	}
224 
225 	/* All set! */
226 }
227 
228 /** Executes the test.
229  *
230  *  Sets the test result to QP_TEST_RESULT_FAIL if the test failed, QP_TEST_RESULT_PASS otherwise.
231  *
232  *  Note the function throws exception should an error occur!
233  *
234  *  @return STOP if the test has finished, CONTINUE to indicate iterate() should be called once again.
235  **/
iterate(void)236 tcu::TestNode::IterateResult TessellationShaderBarrierTestCase::iterate(void)
237 {
238 	initTest();
239 
240 	/* Do not execute if required extensions are not supported. */
241 	if (!m_is_tessellation_shader_supported)
242 	{
243 		throw tcu::NotSupportedError(TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED);
244 	}
245 
246 	/* Prepare for the draw call */
247 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
248 
249 	glw::GLint  drawcall_count		 = 0;
250 	glw::GLenum drawcall_mode		 = GL_NONE;
251 	glw::GLint  drawcall_n_instances = 1;
252 	glw::GLint  n_patch_vertices	 = 0;
253 	glw::GLenum tf_mode				 = GL_NONE;
254 
255 	getDrawCallArgs(&drawcall_mode, &drawcall_count, &tf_mode, &n_patch_vertices, &drawcall_n_instances);
256 
257 	gl.enable(GL_RASTERIZER_DISCARD);
258 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_RASTERIZER_DISCARD) failed");
259 
260 	gl.patchParameteri(m_glExtTokens.PATCH_VERTICES, n_patch_vertices);
261 	GLU_EXPECT_NO_ERROR(gl.getError(), "glPatchParameteriEXT() failed");
262 
263 	gl.useProgram(m_po_id);
264 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram() failed");
265 
266 	gl.beginTransformFeedback(tf_mode);
267 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginTransformFeedback() failed");
268 	{
269 		if (drawcall_n_instances == 1)
270 		{
271 			gl.drawArrays(drawcall_mode, 0 /* first */, drawcall_count);
272 		}
273 		else
274 		{
275 			DE_ASSERT(drawcall_n_instances > 1);
276 
277 			gl.drawArraysInstanced(drawcall_mode, 0 /* first */, drawcall_count, drawcall_n_instances);
278 		}
279 		GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArrays() or glDrawArraysInstanced() failed");
280 	}
281 	gl.endTransformFeedback();
282 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndTransformFeedback() failed");
283 
284 	/* Retrieve the data generated by XFB */
285 	int			bo_size  = getXFBBufferSize();
286 	const void* xfb_data = NULL;
287 
288 	xfb_data = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0 /* offset */, bo_size, GL_MAP_READ_BIT);
289 
290 	GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange() failed");
291 
292 	/* Verify the data */
293 	bool is_xfb_data_valid = verifyXFBBuffer(xfb_data);
294 
295 	/* Unmap the buffer object */
296 	gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
297 
298 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer() failed");
299 
300 	/* Set the test result, depending on the verification outcome */
301 	if (is_xfb_data_valid)
302 	{
303 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
304 	}
305 	else
306 	{
307 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
308 	}
309 
310 	return STOP;
311 }
312 
313 /** Constructor
314  *
315  * @param context Test context
316  **/
TessellationShaderBarrier1(Context & context,const ExtParameters & extParams)317 TessellationShaderBarrier1::TessellationShaderBarrier1(Context& context, const ExtParameters& extParams)
318 	: TessellationShaderBarrierTestCase(context, extParams, "barrier_guarded_read_calls",
319 										"Verifies invocation A can correctly read a per-vertex and"
320 										" per-patch attribute modified by invocation B after a barrier() call")
321 	, m_n_result_vertices(2048)
322 {
323 	m_n_input_vertices = (m_n_result_vertices / 2 /* result points per isoline */) * 4 /* vertices per patch */;
324 }
325 
326 /** Retrieves arguments to be used for the rendering process.
327  *
328  *  @param out_mode             Deref will be used to store draw call mode. Must not be NULL.
329  *  @param out_count            Deref will be used to store count argument to be used for the draw call.
330  *                              Must not be NULL.
331  *  @param out_tf_mode          Deref will be used to store transform feed-back mode to be used for
332  *                              glBeginTransformFeedback() call, prior to issuing the draw call. Must
333  *                              not be NULL.
334  *  @param out_n_patch_vertices Deref will be used to store GL_PATCH_VERTICES_EXT pname value, to be set with
335  *                              glPatchParameteriEXT() call prior to issuing the draw call. Must not be NULL.
336  *  @param out_n_instances      Deref will be used to store amount of instances to use for the draw call.
337  *                              Using a value of 1 will result in a glDrawArrays() call. Using values larger
338  *                              than 1 will trigger glDrawArraysInstanced() call. Values smaller than 1 are
339  *                              forbidden.
340  **/
getDrawCallArgs(glw::GLenum * out_mode,glw::GLint * out_count,glw::GLenum * out_tf_mode,glw::GLint * out_n_patch_vertices,glw::GLint * out_n_instances)341 void TessellationShaderBarrier1::getDrawCallArgs(glw::GLenum* out_mode, glw::GLint* out_count, glw::GLenum* out_tf_mode,
342 												 glw::GLint* out_n_patch_vertices, glw::GLint* out_n_instances)
343 {
344 	*out_count			  = m_n_input_vertices;
345 	*out_mode			  = GL_PATCHES_EXT;
346 	*out_n_instances	  = 1;
347 	*out_n_patch_vertices = 4;
348 	*out_tf_mode		  = GL_POINTS;
349 }
350 
351 /** Retrieves tessellation control shader body.
352  *
353  *  @return TC stage shader body.
354  **/
getTCSCode()355 const char* TessellationShaderBarrier1::getTCSCode()
356 {
357 	static const char* tcs_code =
358 		"${VERSION}\n"
359 		"\n"
360 		"${TESSELLATION_SHADER_REQUIRE}\n"
361 		"\n"
362 		"layout (vertices = 4) out;\n"
363 		"\n"
364 		"flat  in  int   vertex_id[];\n"
365 		"\n"
366 		"patch out int   test_patch_value;\n"
367 		"      out ivec4 test_vector [];\n"
368 		"      out ivec4 test_vector2[];\n"
369 		"\n"
370 		"void main()\n"
371 		"{\n"
372 		"    if (gl_InvocationID == 0)\n"
373 		"    {\n"
374 		"        test_patch_value = vertex_id[0];\n"
375 		"    }\n"
376 		"\n"
377 		"    test_vector[gl_InvocationID] = ivec4(vertex_id[gl_InvocationID],\n"
378 		"                                         vertex_id[gl_InvocationID] + 1,\n"
379 		"                                         vertex_id[gl_InvocationID] + 2,\n"
380 		"                                         vertex_id[gl_InvocationID] + 3);\n"
381 		"\n"
382 		"    barrier();\n"
383 		"\n"
384 		"    int next_invocation = (gl_InvocationID + 1) % 4;\n"
385 		"\n"
386 		"    test_vector2[gl_InvocationID] = ivec4(test_vector[next_invocation].xyz, test_patch_value);\n"
387 		"\n"
388 		"    gl_TessLevelOuter[0] = 1.0;\n"
389 		"    gl_TessLevelOuter[1] = 1.0;\n"
390 		"}\n";
391 
392 	return tcs_code;
393 }
394 
395 /** Retrieves tessellation evaluation shader body.
396  *
397  *  @return TE stage shader body.
398  **/
getTESCode()399 const char* TessellationShaderBarrier1::getTESCode()
400 {
401 	static const char* tes_code = "${VERSION}\n"
402 								  "\n"
403 								  "${TESSELLATION_SHADER_REQUIRE}\n"
404 								  "\n"
405 								  "layout(isolines, point_mode) in;\n"
406 								  "\n"
407 								  "in ivec4 test_vector2[];\n"
408 								  "\n"
409 								  "out ivec4 result_vector2;\n"
410 								  "\n"
411 								  "void main()\n"
412 								  "{\n"
413 								  "    int base = gl_PrimitiveID * 4;\n"
414 								  "\n"
415 								  "    if (test_vector2[0].x == (base + 1) && test_vector2[0].y == (base + 2) && "
416 								  "test_vector2[0].z == (base + 3) && test_vector2[0].w == (base + 0)  &&\n"
417 								  "        test_vector2[1].x == (base + 2) && test_vector2[1].y == (base + 3) && "
418 								  "test_vector2[1].z == (base + 4) && test_vector2[1].w == (base + 0)  &&\n"
419 								  "        test_vector2[2].x == (base + 3) && test_vector2[2].y == (base + 4) && "
420 								  "test_vector2[2].z == (base + 5) && test_vector2[2].w == (base + 0)  &&\n"
421 								  "        test_vector2[3].x == (base + 0) && test_vector2[3].y == (base + 1) && "
422 								  "test_vector2[3].z == (base + 2) && test_vector2[3].w == (base + 0) )\n"
423 								  "    {\n"
424 								  "        result_vector2 = ivec4(1);\n"
425 								  "    }\n"
426 								  "    else\n"
427 								  "    {\n"
428 								  "        result_vector2 = ivec4(0);\n"
429 								  "    }\n"
430 								  "}\n";
431 
432 	return tes_code;
433 }
434 
435 /** Retrieves vertex shader body.
436  *
437  *  @return Vertex shader body.
438  **/
getVSCode()439 const char* TessellationShaderBarrier1::getVSCode()
440 {
441 	static const char* vs_code = "${VERSION}\n"
442 								 "\n"
443 								 "flat out int vertex_id;\n"
444 								 "\n"
445 								 "void main()\n"
446 								 "{\n"
447 								 "    vertex_id = gl_VertexID;\n"
448 								 "}\n";
449 
450 	return vs_code;
451 }
452 
453 /** Retrieves amount of bytes that should be used for allocating storage space for
454  *  a buffer object that will later be used to hold XFB result data.
455  *
456  *  @return Amount of bytes required by the test.
457  */
getXFBBufferSize()458 int TessellationShaderBarrier1::getXFBBufferSize()
459 {
460 	return static_cast<int>(m_n_result_vertices * sizeof(int) * 4 /* components */ * 2 /* points per isoline */);
461 }
462 
463 /** Retrieves names of transform feedback varyings and amount of those. These should be used
464  *  prior to link the test program object.
465  *
466  *  @param out_n_names Deref will be used to store the number of names that @param out_names array
467  *                     holds. Must not be NULL.
468  *  @param out_names   Deref will be used to store a pointer to an array holding TF varying names;
469  *                     Must not be NULL.
470  **/
getXFBProperties(int * out_n_names,const char *** out_names)471 void TessellationShaderBarrier1::getXFBProperties(int* out_n_names, const char*** out_names)
472 {
473 	static const char* names[1] = { "result_vector2" };
474 
475 	*out_n_names = 1;
476 	*out_names   = names;
477 }
478 
479 /** Verifies data captured by XFB is correct.
480  *
481  *  @param data Buffer holding the result XFB data. Must not be NULL.
482  *
483  *  @return true if the result data is confirmed to be valid, false otherwise.
484  **/
verifyXFBBuffer(const void * data)485 bool TessellationShaderBarrier1::verifyXFBBuffer(const void* data)
486 {
487 	int* data_int = (int*)data;
488 
489 	/* Run through all vertices */
490 	for (unsigned int n_vertex = 0; n_vertex < m_n_result_vertices; ++n_vertex)
491 	{
492 		int retrieved_x = data_int[n_vertex * 4];
493 		int retrieved_y = data_int[n_vertex * 4 + 1];
494 		int retrieved_z = data_int[n_vertex * 4 + 2];
495 		int retrieved_w = data_int[n_vertex * 4 + 3];
496 
497 		if (retrieved_x != 1 || retrieved_y != 1 || retrieved_z != 1 || retrieved_w != 1)
498 		{
499 			m_testCtx.getLog() << tcu::TestLog::Message << "Invalid value returned: expected:[1, 1, 1, 1]"
500 							   << " retrieved: "
501 							   << "[" << retrieved_x << ", " << retrieved_y << ", " << retrieved_z << ", "
502 							   << retrieved_w << tcu::TestLog::EndMessage;
503 
504 			TCU_FAIL("Invalid rendering result");
505 		}
506 	}
507 
508 	return true;
509 }
510 
511 /** Constructor
512  *
513  * @param context Test context
514  **/
TessellationShaderBarrier2(Context & context,const ExtParameters & extParams)515 TessellationShaderBarrier2::TessellationShaderBarrier2(Context& context, const ExtParameters& extParams)
516 	: TessellationShaderBarrierTestCase(context, extParams, "barrier_guarded_write_calls",
517 										"Verifies it is safe to write to the same per-patch output "
518 										"from multiple TC invocations, as long as each write happens "
519 										"in a separate phase.")
520 	, m_n_result_vertices(2048)
521 {
522 	m_n_input_vertices = (m_n_result_vertices / 2 /* result points per isoline */) * 4 /* vertices per patch */;
523 }
524 
525 /** Retrieves arguments to be used for the rendering process.
526  *
527  *  @param out_mode             Deref will be used to store draw call mode. Must not be NULL.
528  *  @param out_count            Deref will be used to store count argument to be used for the draw call.
529  *                              Must not be NULL.
530  *  @param out_tf_mode          Deref will be used to store transform feed-back mode to be used for
531  *                              glBeginTransformFeedback() call, prior to issuing the draw call. Must
532  *                              not be NULL.
533  *  @param out_n_patch_vertices Deref will be used to store GL_PATCH_VERTICES_EXT pname value, to be set with
534  *                              glPatchParameteriEXT() call prior to issuing the draw call. Must not be NULL.
535  *  @param out_n_instances      Deref will be used to store amount of instances to use for the draw call.
536  *                              Using a value of 1 will result in a glDrawArrays() call. Using values larger
537  *                              than 1 will trigger glDrawArraysInstanced() call. Values smaller than 1 are
538  *                              forbidden.
539  **/
getDrawCallArgs(glw::GLenum * out_mode,glw::GLint * out_count,glw::GLenum * out_tf_mode,glw::GLint * out_n_patch_vertices,glw::GLint * out_n_instances)540 void TessellationShaderBarrier2::getDrawCallArgs(glw::GLenum* out_mode, glw::GLint* out_count, glw::GLenum* out_tf_mode,
541 												 glw::GLint* out_n_patch_vertices, glw::GLint* out_n_instances)
542 {
543 	*out_count			  = m_n_input_vertices;
544 	*out_mode			  = GL_PATCHES_EXT;
545 	*out_n_instances	  = 1;
546 	*out_n_patch_vertices = 4;
547 	*out_tf_mode		  = GL_POINTS;
548 }
549 
550 /** Retrieves tessellation control shader body.
551  *
552  *  @return TC stage shader body.
553  **/
getTCSCode()554 const char* TessellationShaderBarrier2::getTCSCode()
555 {
556 	static const char* tcs_code = "${VERSION}\n"
557 								  "\n"
558 								  "${TESSELLATION_SHADER_REQUIRE}\n"
559 								  "\n"
560 								  "layout (vertices = 4) out;\n"
561 								  "\n"
562 								  "      out float tcs_result[];\n"
563 								  "patch out int   test_patch_value;\n"
564 								  "\n"
565 								  "void main()\n"
566 								  "{\n"
567 								  /* Four invocations per input patch will be executed. Have the first one write its
568 		 * secret value to the output per-patch attribute.
569 		 */
570 								  "    if (gl_InvocationID == 0)\n"
571 								  "    {\n"
572 								  "        test_patch_value = 123;\n"
573 								  "    }\n"
574 								  "\n"
575 								  "    barrier();\n"
576 								  "\n"
577 								  /* Let's have the second invocation update the value at this point */
578 								  "    if (gl_InvocationID == 1)\n"
579 								  "    {\n"
580 								  "        test_patch_value = 234;\n"
581 								  "    }\n"
582 								  "\n"
583 								  "    barrier();\n"
584 								  "\n"
585 								  /* Finally, if this is invocation number one, check if test_patch_value
586 		 * stores a correct value.
587 		 */
588 								  "    tcs_result[gl_InvocationID] = 2.0;\n"
589 								  "\n"
590 								  "    if (gl_InvocationID == 0)\n"
591 								  "    {\n"
592 								  "        if (test_patch_value == 234)\n"
593 								  "        {\n"
594 								  "            tcs_result[gl_InvocationID] = 1.0;\n"
595 								  "        }\n"
596 								  "    }\n"
597 								  "\n"
598 								  "    gl_TessLevelOuter[0] = 1.0;\n"
599 								  "    gl_TessLevelOuter[1] = 1.0;\n"
600 								  "}\n";
601 
602 	return tcs_code;
603 }
604 
605 /** Retrieves tessellation evaluation shader body.
606  *
607  *  @return TE stage shader body.
608  **/
getTESCode()609 const char* TessellationShaderBarrier2::getTESCode()
610 {
611 	static const char* tes_code = "${VERSION}\n"
612 								  "\n"
613 								  "${TESSELLATION_SHADER_REQUIRE}\n"
614 								  "\n"
615 								  "layout(isolines, point_mode) in;\n"
616 								  "\n"
617 								  "      in float tcs_result[];\n"
618 								  "\n"
619 								  "out float tes_result;\n"
620 								  "\n"
621 								  "void main()\n"
622 								  "{\n"
623 								  /* TCS invocation order is undefined so take a maximum of all values we received */
624 								  "    if (tcs_result[0] == 1.0 &&\n"
625 								  "        tcs_result[1] == 2.0 &&\n"
626 								  "        tcs_result[2] == 2.0 &&\n"
627 								  "        tcs_result[3] == 2.0)\n"
628 								  "    {\n"
629 								  "        tes_result = 1.0;\n"
630 								  "    }\n"
631 								  "    else\n"
632 								  "    {\n"
633 								  "        tes_result = 0.0;\n"
634 								  "    }\n"
635 								  "}\n";
636 
637 	return tes_code;
638 }
639 
640 /** Retrieves vertex shader body.
641  *
642  *  @return Vertex shader body.
643  **/
getVSCode()644 const char* TessellationShaderBarrier2::getVSCode()
645 {
646 	static const char* vs_code = "${VERSION}\n"
647 								 "\n"
648 								 "void main()\n"
649 								 "{\n"
650 								 "}\n";
651 
652 	return vs_code;
653 }
654 
655 /** Retrieves amount of bytes that should be used for allocating storage space for
656  *  a buffer object that will later be used to hold XFB result data.
657  *
658  *  @return Amount of bytes required by the test.
659  */
getXFBBufferSize()660 int TessellationShaderBarrier2::getXFBBufferSize()
661 {
662 	return static_cast<int>(m_n_result_vertices * sizeof(float) * 2 /* points per isoline */);
663 }
664 
665 /** Retrieves names of transform feedback varyings and amount of those. These should be used
666  *  prior to link the test program object.
667  *
668  *  @param out_n_names Deref will be used to store the number of names that @param out_names array
669  *                     holds. Must not be NULL.
670  *  @param out_names   Deref will be used to store a pointer to an array holding TF varying names;
671  *                     Must not be NULL.
672  **/
getXFBProperties(int * out_n_names,const char *** out_names)673 void TessellationShaderBarrier2::getXFBProperties(int* out_n_names, const char*** out_names)
674 {
675 	static const char* names[1] = { "tes_result" };
676 
677 	*out_n_names = 1;
678 	*out_names   = names;
679 }
680 
681 /** Verifies data captured by XFB is correct.
682  *
683  *  @param data Buffer holding the result XFB data. Must not be NULL.
684  *
685  *  @return true if the result data is confirmed to be valid, false otherwise.
686  **/
verifyXFBBuffer(const void * data)687 bool TessellationShaderBarrier2::verifyXFBBuffer(const void* data)
688 {
689 	float*		data_float = (float*)data;
690 	const float epsilon	= (float)1e-5;
691 
692 	/* Run through all vertices */
693 	for (unsigned int n_vertex = 0; n_vertex < m_n_result_vertices; ++n_vertex)
694 	{
695 		if (de::abs(data_float[n_vertex] - 1.0f /* valid result value */) > epsilon)
696 		{
697 			TCU_FAIL("Invalid data retrieved");
698 		}
699 	}
700 
701 	return true;
702 }
703 
704 /** Constructor
705  *
706  * @param context Test context
707  **/
TessellationShaderBarrier3(Context & context,const ExtParameters & extParams)708 TessellationShaderBarrier3::TessellationShaderBarrier3(Context& context, const ExtParameters& extParams)
709 	: TessellationShaderBarrierTestCase(context, extParams, "barrier_guarded_read_write_calls",
710 										"Verifies it is safe to write to the same per-patch output "
711 										"from multiple TC invocations, as long as each write happens "
712 										"in a separate phase.")
713 	, m_n_instances(10)				/* as per test spec */
714 	, m_n_invocations(16)			/* as per test spec */
715 	, m_n_patch_vertices(8)			/* as per test spec */
716 	, m_n_patches_per_invocation(2) /* as per test spec */
717 	, m_n_result_vertices(2 /* result points per isoline */ * m_n_patches_per_invocation * m_n_invocations *
718 						  m_n_instances)
719 {
720 	m_n_input_vertices = (m_n_result_vertices / 2 /* result points per isoline */) * 4 /* vertices per patch */;
721 }
722 
723 /** Retrieves arguments to be used for the rendering process.
724  *
725  *  @param out_mode             Deref will be used to store draw call mode. Must not be NULL.
726  *  @param out_count            Deref will be used to store count argument to be used for the draw call.
727  *                              Must not be NULL.
728  *  @param out_tf_mode          Deref will be used to store transform feed-back mode to be used for
729  *                              glBeginTransformFeedback() call, prior to issuing the draw call. Must
730  *                              not be NULL.
731  *  @param out_n_patch_vertices Deref will be used to store GL_PATCH_VERTICES_EXT pname value, to be set with
732  *                              glPatchParameteriEXT() call prior to issuing the draw call. Must not be NULL.
733  *  @param out_n_instances      Deref will be used to store amount of instances to use for the draw call.
734  *                              Using a value of 1 will result in a glDrawArrays() call. Using values larger
735  *                              than 1 will trigger glDrawArraysInstanced() call. Values smaller than 1 are
736  *                              forbidden.
737  **/
getDrawCallArgs(glw::GLenum * out_mode,glw::GLint * out_count,glw::GLenum * out_tf_mode,glw::GLint * out_n_patch_vertices,glw::GLint * out_n_instances)738 void TessellationShaderBarrier3::getDrawCallArgs(glw::GLenum* out_mode, glw::GLint* out_count, glw::GLenum* out_tf_mode,
739 												 glw::GLint* out_n_patch_vertices, glw::GLint* out_n_instances)
740 {
741 	*out_count			  = m_n_patches_per_invocation * m_n_patch_vertices * m_n_instances;
742 	*out_mode			  = GL_PATCHES_EXT;
743 	*out_n_instances	  = m_n_instances;
744 	*out_n_patch_vertices = m_n_patch_vertices;
745 	*out_tf_mode		  = GL_POINTS;
746 }
747 
748 /** Retrieves tessellation control shader body.
749  *
750  *  @return TC stage shader body.
751  **/
getTCSCode()752 const char* TessellationShaderBarrier3::getTCSCode()
753 {
754 	static const char* tcs_code =
755 		"${VERSION}\n"
756 		"\n"
757 		"${TESSELLATION_SHADER_REQUIRE}\n"
758 		"\n"
759 		"layout (vertices = 16) out;\n"
760 		"\n"
761 		"      out int tcs_data        [];\n"
762 		"patch out int tcs_patch_result[16];\n"
763 		"\n"
764 		"void main()\n"
765 		"{\n"
766 		/* Even invocations should write their gl_InvocationID value to their per-vertex output. */
767 		"    if ((gl_InvocationID % 2) == 0)\n"
768 		"    {\n"
769 		"        tcs_data[gl_InvocationID] = gl_InvocationID;\n"
770 		"    }\n"
771 		"\n"
772 		"    barrier();\n"
773 		"\n"
774 		/* Odd invocations should read values stored by preceding even invocation,
775 		 * add current invocation's ID to that value, and then write it to its per-vertex
776 		 * output.
777 		 */
778 		"    if ((gl_InvocationID % 2) == 1)\n"
779 		"    {\n"
780 		"        tcs_data[gl_InvocationID] = tcs_data[gl_InvocationID - 1] + gl_InvocationID;\n"
781 		"    }\n"
782 		"\n"
783 		"    barrier();\n"
784 		"\n"
785 		/* Every fourth invocation should now read & sum up per-vertex outputs for four invocations
786 		 * following it (including the one discussed), and store it in a per-patch variable */
787 		"    tcs_patch_result[gl_InvocationID] = 0;\n"
788 		"\n"
789 		"    if ((gl_InvocationID % 4) == 0)\n"
790 		"    {\n"
791 		"        tcs_patch_result[gl_InvocationID] += tcs_data[gl_InvocationID];\n"
792 		"        tcs_patch_result[gl_InvocationID] += tcs_data[gl_InvocationID+1];\n"
793 		"        tcs_patch_result[gl_InvocationID] += tcs_data[gl_InvocationID+2];\n"
794 		"        tcs_patch_result[gl_InvocationID] += tcs_data[gl_InvocationID+3];\n"
795 		"    }\n"
796 		"\n"
797 		"    gl_TessLevelOuter[0] = 1.0;\n"
798 		"    gl_TessLevelOuter[1] = 1.0;\n"
799 		"}\n";
800 
801 	return tcs_code;
802 }
803 
804 /** Retrieves tessellation evaluation shader body.
805  *
806  *  @return TC stage shader body.
807  **/
getTESCode()808 const char* TessellationShaderBarrier3::getTESCode()
809 {
810 	static const char* tes_code = "${VERSION}\n"
811 								  "\n"
812 								  "${TESSELLATION_SHADER_REQUIRE}\n"
813 								  "\n"
814 								  "layout(isolines, point_mode) in;\n"
815 								  "\n"
816 								  "patch in int tcs_patch_result[16];\n"
817 								  "\n"
818 								  "flat out ivec4 tes_result1;\n"
819 								  "flat out ivec4 tes_result2;\n"
820 								  "flat out ivec4 tes_result3;\n"
821 								  "flat out ivec4 tes_result4;\n"
822 								  "\n"
823 								  "void main()\n"
824 								  "{\n"
825 								  "    tes_result1 = ivec4(tcs_patch_result[0],  tcs_patch_result[1],  "
826 								  "tcs_patch_result[2],  tcs_patch_result[3]);\n"
827 								  "    tes_result2 = ivec4(tcs_patch_result[4],  tcs_patch_result[5],  "
828 								  "tcs_patch_result[6],  tcs_patch_result[7]);\n"
829 								  "    tes_result3 = ivec4(tcs_patch_result[8],  tcs_patch_result[9],  "
830 								  "tcs_patch_result[10], tcs_patch_result[11]);\n"
831 								  "    tes_result4 = ivec4(tcs_patch_result[12], tcs_patch_result[13], "
832 								  "tcs_patch_result[14], tcs_patch_result[15]);\n"
833 								  "}\n";
834 
835 	return tes_code;
836 }
837 
838 /** Retrieves vertex shader body.
839  *
840  *  @return Vertex shader body.
841  **/
getVSCode()842 const char* TessellationShaderBarrier3::getVSCode()
843 {
844 	static const char* vs_code = "${VERSION}\n"
845 								 "\n"
846 								 "void main()\n"
847 								 "{\n"
848 								 "}\n";
849 
850 	return vs_code;
851 }
852 
853 /** Retrieves amount of bytes that should be used for allocating storage space for
854  *  a buffer object that will later be used to hold XFB result data.
855  *
856  *  @return Amount of bytes required by the test.
857  */
getXFBBufferSize()858 int TessellationShaderBarrier3::getXFBBufferSize()
859 {
860 	return static_cast<int>(m_n_instances * m_n_result_vertices * sizeof(int) * 4 /* ivec4 */ *
861 							2 /* points per isoline */);
862 }
863 
864 /** Retrieves names of transform feedback varyings and amount of those. These should be used
865  *  prior to link the test program object.
866  *
867  *  @param out_n_names Deref will be used to store the number of names that @param out_names array
868  *                     holds. Must not be NULL.
869  *  @param out_names   Deref will be used to store a pointer to an array holding TF varying names;
870  *                     Must not be NULL.
871  **/
getXFBProperties(int * out_n_names,const char *** out_names)872 void TessellationShaderBarrier3::getXFBProperties(int* out_n_names, const char*** out_names)
873 {
874 	static const char* names[] = { "tes_result1", "tes_result2", "tes_result3", "tes_result4" };
875 
876 	*out_n_names = 4;
877 	*out_names   = names;
878 }
879 
880 /** Verifies data captured by XFB is correct.
881  *
882  *  @param data Buffer holding the result XFB data. Must not be NULL.
883  *
884  *  @return true if the result data is confirmed to be valid, false otherwise.
885  **/
verifyXFBBuffer(const void * data)886 bool TessellationShaderBarrier3::verifyXFBBuffer(const void* data)
887 {
888 	const int*		 data_int = (const int*)data;
889 	std::vector<int> tcs_data(m_n_invocations, 0);
890 	std::vector<int> tcs_patch_result(m_n_invocations, 0);
891 
892 	/* This is a simple C++ port of the TCS used for the test.
893 	 *
894 	 * Note: We only need to consider a single set of values stored by TES
895 	 *       for a single result point, as the same set of values will be
896 	 *       reported for the other point. Owing to the fact gl_InvocationID
897 	 *       in TCS will iterate from 0 to 15 for all input patches and instances,
898 	 *       we can re-use the data for all subsequent input patches. */
899 	/* Phase 1 */
900 	for (unsigned int n = 0; n < m_n_invocations; n += 2)
901 	{
902 		tcs_data[n] = n;
903 	}
904 
905 	/* Phase 2 */
906 	for (unsigned int n = 1; n < m_n_invocations; n += 2)
907 	{
908 		tcs_data[n] = tcs_data[n - 1] + n;
909 	}
910 
911 	/* Phase 3 */
912 	for (unsigned int n_patch_vertex = 0; n_patch_vertex < m_n_invocations; ++n_patch_vertex)
913 	{
914 		const unsigned int invocation_id = n_patch_vertex;
915 
916 		tcs_patch_result[invocation_id] = 0;
917 
918 		if ((invocation_id % 4) == 0)
919 		{
920 			tcs_patch_result[invocation_id] += tcs_data[invocation_id];
921 			tcs_patch_result[invocation_id] += tcs_data[invocation_id + 1];
922 			tcs_patch_result[invocation_id] += tcs_data[invocation_id + 2];
923 			tcs_patch_result[invocation_id] += tcs_data[invocation_id + 3];
924 		}
925 	} /* for (all patch vertices) */
926 
927 	/* Time to do the actual comparison. */
928 	for (unsigned int n_patch = 0; n_patch < m_n_result_vertices / m_n_invocations; ++n_patch)
929 	{
930 		bool	   are_equal				 = true;
931 		const int  n_points_per_line_segment = 2;
932 		const int* patch_data_int			 = data_int + n_patch * m_n_invocations * n_points_per_line_segment;
933 
934 		for (unsigned int n_invocation = 0; n_invocation < m_n_invocations; ++n_invocation)
935 		{
936 			if (patch_data_int[n_invocation] != tcs_patch_result[n_invocation])
937 			{
938 				are_equal = false;
939 
940 				break;
941 			}
942 		} /* for (all patch vertices which have contributed for given input patch being considered) */
943 
944 		if (!are_equal)
945 		{
946 			std::stringstream logMessage;
947 
948 			logMessage << "Result data for patch [" << n_patch << "]: (";
949 
950 			for (unsigned int n_patch_vertex = 0; n_patch_vertex < m_n_patch_vertices; ++n_patch_vertex)
951 			{
952 				logMessage << patch_data_int[n_patch_vertex];
953 
954 				if (n_patch_vertex == (m_n_patch_vertices - 1))
955 				{
956 					logMessage << "), ";
957 				}
958 				else
959 				{
960 					logMessage << ", ";
961 				}
962 			} /* for (all patch vertices) */
963 
964 			logMessage << "expected: ";
965 
966 			for (unsigned int n_patch_vertex = 0; n_patch_vertex < m_n_patch_vertices; ++n_patch_vertex)
967 			{
968 				logMessage << tcs_patch_result[n_patch_vertex];
969 
970 				if (n_patch_vertex == (m_n_patch_vertices - 1))
971 				{
972 					logMessage << "). ";
973 				}
974 				else
975 				{
976 					logMessage << ", ";
977 				}
978 			} /* for (all patch vertices) */
979 
980 			/* Log the message */
981 			m_testCtx.getLog() << tcu::TestLog::Message << logMessage.str().c_str() << tcu::TestLog::EndMessage;
982 
983 			/* Bail out */
984 			TCU_FAIL("Invalid data captured");
985 		} /* if (!are_equal) */
986 	}	 /* for (all patches) */
987 
988 	return true;
989 }
990 
991 } /* namespace glcts */
992