• 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 "gl4cComputeShaderTests.hpp"
25 #include "glwEnums.hpp"
26 #include "glwFunctions.hpp"
27 #include "tcuMatrix.hpp"
28 #include "tcuMatrixUtil.hpp"
29 #include "tcuRenderTarget.hpp"
30 #include <cmath>
31 #include <cstdarg>
32 #include <sstream>
33 
34 namespace gl4cts
35 {
36 
37 using namespace glw;
38 using tcu::Vec2;
39 using tcu::Vec3;
40 using tcu::Vec4;
41 using tcu::UVec4;
42 using tcu::UVec3;
43 using tcu::Mat4;
44 
45 namespace
46 {
47 
48 typedef Vec3  vec2;
49 typedef Vec3  vec3;
50 typedef Vec4  vec4;
51 typedef UVec3 uvec3;
52 typedef UVec4 uvec4;
53 typedef Mat4  mat4;
54 
55 const char* const kGLSLVer = "#version 430 core\n";
56 
57 class ComputeShaderBase : public deqp::SubcaseBase
58 {
59 
60 public:
~ComputeShaderBase()61 	virtual ~ComputeShaderBase()
62 	{
63 	}
64 
ComputeShaderBase()65 	ComputeShaderBase()
66 		: renderTarget(m_context.getRenderContext().getRenderTarget()), pixelFormat(renderTarget.getPixelFormat())
67 	{
68 		float epsilon_zero = 1.f / (1 << 13);
69 		if (pixelFormat.redBits != 0 && pixelFormat.greenBits != 0 && pixelFormat.blueBits != 0 &&
70 			pixelFormat.alphaBits != 0)
71 		{
72 			g_color_eps = vec4(1.f / ((float)(1 << deMin32(8, pixelFormat.redBits)) - 1.0f),
73 							   1.f / ((float)(1 << deMin32(8, pixelFormat.greenBits)) - 1.0f),
74 							   1.f / ((float)(1 << deMin32(8, pixelFormat.blueBits)) - 1.0f),
75 							   1.f / ((float)(1 << pixelFormat.alphaBits) - 1.0f)) +
76 						  vec4(epsilon_zero);
77 		}
78 		else if (pixelFormat.redBits != 0 && pixelFormat.greenBits != 0 && pixelFormat.blueBits != 0)
79 		{
80 			g_color_eps = vec4(1.f / ((float)(1 << pixelFormat.redBits) - 1.0f),
81 							   1.f / ((float)(1 << pixelFormat.greenBits) - 1.0f),
82 							   1.f / ((float)(1 << pixelFormat.blueBits) - 1.0f), 1.f) +
83 						  vec4(epsilon_zero);
84 		}
85 		else
86 		{
87 			g_color_eps = vec4(epsilon_zero);
88 		}
89 	}
90 
91 	const tcu::RenderTarget& renderTarget;
92 	const tcu::PixelFormat&  pixelFormat;
93 	vec4					 g_color_eps;
94 
IndexTo3DCoord(GLuint idx,GLuint max_x,GLuint max_y)95 	uvec3 IndexTo3DCoord(GLuint idx, GLuint max_x, GLuint max_y)
96 	{
97 		const GLuint x = idx % max_x;
98 		idx /= max_x;
99 		const GLuint y = idx % max_y;
100 		idx /= max_y;
101 		const GLuint z = idx;
102 		return uvec3(x, y, z);
103 	}
104 
CheckProgram(GLuint program,bool * compile_error=NULL)105 	bool CheckProgram(GLuint program, bool* compile_error = NULL)
106 	{
107 		GLint compile_status = GL_TRUE;
108 		GLint status		 = GL_TRUE;
109 		glGetProgramiv(program, GL_LINK_STATUS, &status);
110 
111 		if (status == GL_FALSE)
112 		{
113 			GLint attached_shaders;
114 			glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
115 
116 			if (attached_shaders > 0)
117 			{
118 				std::vector<GLuint> shaders(attached_shaders);
119 				glGetAttachedShaders(program, attached_shaders, NULL, &shaders[0]);
120 
121 				for (GLint i = 0; i < attached_shaders; ++i)
122 				{
123 					GLenum type;
124 					glGetShaderiv(shaders[i], GL_SHADER_TYPE, reinterpret_cast<GLint*>(&type));
125 					switch (type)
126 					{
127 					case GL_VERTEX_SHADER:
128 						m_context.getTestContext().getLog()
129 							<< tcu::TestLog::Message << "*** Vertex Shader ***" << tcu::TestLog::EndMessage;
130 						break;
131 					case GL_TESS_CONTROL_SHADER:
132 						m_context.getTestContext().getLog()
133 							<< tcu::TestLog::Message << "*** Tessellation Control Shader ***"
134 							<< tcu::TestLog::EndMessage;
135 						break;
136 					case GL_TESS_EVALUATION_SHADER:
137 						m_context.getTestContext().getLog()
138 							<< tcu::TestLog::Message << "*** Tessellation Evaluation Shader ***"
139 							<< tcu::TestLog::EndMessage;
140 						break;
141 					case GL_GEOMETRY_SHADER:
142 						m_context.getTestContext().getLog()
143 							<< tcu::TestLog::Message << "*** Geometry Shader ***" << tcu::TestLog::EndMessage;
144 						break;
145 					case GL_FRAGMENT_SHADER:
146 						m_context.getTestContext().getLog()
147 							<< tcu::TestLog::Message << "*** Fragment Shader ***" << tcu::TestLog::EndMessage;
148 						break;
149 					case GL_COMPUTE_SHADER:
150 						m_context.getTestContext().getLog()
151 							<< tcu::TestLog::Message << "*** Compute Shader ***" << tcu::TestLog::EndMessage;
152 						break;
153 					default:
154 						m_context.getTestContext().getLog()
155 							<< tcu::TestLog::Message << "*** Unknown Shader ***" << tcu::TestLog::EndMessage;
156 						break;
157 					}
158 
159 					GLint res;
160 					glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &res);
161 					if (res != GL_TRUE)
162 						compile_status = res;
163 
164 					GLint length;
165 					glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &length);
166 					if (length > 0)
167 					{
168 						std::vector<GLchar> source(length);
169 						glGetShaderSource(shaders[i], length, NULL, &source[0]);
170 						m_context.getTestContext().getLog()
171 							<< tcu::TestLog::Message << &source[0] << tcu::TestLog::EndMessage;
172 					}
173 
174 					glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &length);
175 					if (length > 0)
176 					{
177 						std::vector<GLchar> log(length);
178 						glGetShaderInfoLog(shaders[i], length, NULL, &log[0]);
179 						m_context.getTestContext().getLog()
180 							<< tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
181 					}
182 				}
183 			}
184 
185 			GLint length;
186 			glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
187 			if (length > 0)
188 			{
189 				std::vector<GLchar> log(length);
190 				glGetProgramInfoLog(program, length, NULL, &log[0]);
191 				m_context.getTestContext().getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
192 			}
193 		}
194 
195 		if (compile_error)
196 			*compile_error = (compile_status == GL_TRUE ? false : true);
197 		if (compile_status != GL_TRUE)
198 			return false;
199 		return status == GL_TRUE ? true : false;
200 	}
201 
CreateComputeProgram(const std::string & cs)202 	GLuint CreateComputeProgram(const std::string& cs)
203 	{
204 		const GLuint p = glCreateProgram();
205 
206 		if (!cs.empty())
207 		{
208 			const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
209 			glAttachShader(p, sh);
210 			glDeleteShader(sh);
211 			const char* const src[2] = { kGLSLVer, cs.c_str() };
212 			glShaderSource(sh, 2, src, NULL);
213 			glCompileShader(sh);
214 		}
215 
216 		return p;
217 	}
218 
CreateProgram(const std::string & vs,const std::string & fs)219 	GLuint CreateProgram(const std::string& vs, const std::string& fs)
220 	{
221 		const GLuint p = glCreateProgram();
222 
223 		if (!vs.empty())
224 		{
225 			const GLuint sh = glCreateShader(GL_VERTEX_SHADER);
226 			glAttachShader(p, sh);
227 			glDeleteShader(sh);
228 			const char* const src[2] = { kGLSLVer, vs.c_str() };
229 			glShaderSource(sh, 2, src, NULL);
230 			glCompileShader(sh);
231 		}
232 		if (!fs.empty())
233 		{
234 			const GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
235 			glAttachShader(p, sh);
236 			glDeleteShader(sh);
237 			const char* const src[2] = { kGLSLVer, fs.c_str() };
238 			glShaderSource(sh, 2, src, NULL);
239 			glCompileShader(sh);
240 		}
241 
242 		return p;
243 	}
244 
BuildShaderProgram(GLenum type,const std::string & source)245 	GLuint BuildShaderProgram(GLenum type, const std::string& source)
246 	{
247 		const char* const src[2] = { kGLSLVer, source.c_str() };
248 		return glCreateShaderProgramv(type, 2, src);
249 	}
250 
distance(GLfloat p0,GLfloat p1)251 	GLfloat distance(GLfloat p0, GLfloat p1)
252 	{
253 		return de::abs(p0 - p1);
254 	}
255 
ColorEqual(const vec4 & c0,const vec4 & c1,const vec4 & epsilon)256 	inline bool ColorEqual(const vec4& c0, const vec4& c1, const vec4& epsilon)
257 	{
258 		if (distance(c0.x(), c1.x()) > epsilon.x())
259 			return false;
260 		if (distance(c0.y(), c1.y()) > epsilon.y())
261 			return false;
262 		if (distance(c0.z(), c1.z()) > epsilon.z())
263 			return false;
264 		if (distance(c0.w(), c1.w()) > epsilon.w())
265 			return false;
266 		return true;
267 	}
268 
ColorEqual(const vec3 & c0,const vec3 & c1,const vec4 & epsilon)269 	inline bool ColorEqual(const vec3& c0, const vec3& c1, const vec4& epsilon)
270 	{
271 		if (distance(c0.x(), c1.x()) > epsilon.x())
272 			return false;
273 		if (distance(c0.y(), c1.y()) > epsilon.y())
274 			return false;
275 		if (distance(c0.z(), c1.z()) > epsilon.z())
276 			return false;
277 		return true;
278 	}
279 
ValidateReadBuffer(int x,int y,int w,int h,const vec4 & expected)280 	bool ValidateReadBuffer(int x, int y, int w, int h, const vec4& expected)
281 	{
282 		std::vector<vec4> display(w * h);
283 		glReadPixels(x, y, w, h, GL_RGBA, GL_FLOAT, &display[0]);
284 
285 		for (int j = 0; j < h; ++j)
286 		{
287 			for (int i = 0; i < w; ++i)
288 			{
289 				if (!ColorEqual(display[j * w + i], expected, g_color_eps))
290 				{
291 					m_context.getTestContext().getLog()
292 						<< tcu::TestLog::Message << "Color at (" << (x + i) << ", " << (y + j) << ") is ["
293 						<< display[j * w + i].x() << ", " << display[j * w + i].y() << ", " << display[j * w + i].z()
294 						<< ", " << display[j * w + i].w() << "] should be [" << expected.x() << ", " << expected.y()
295 						<< ", " << expected.z() << ", " << expected.w() << "]." << tcu::TestLog::EndMessage;
296 					return false;
297 				}
298 			}
299 		}
300 
301 		return true;
302 	}
303 
ValidateReadBufferCenteredQuad(int width,int height,const vec3 & expected)304 	bool ValidateReadBufferCenteredQuad(int width, int height, const vec3& expected)
305 	{
306 		bool			  result = true;
307 		std::vector<vec3> fb(width * height);
308 		glReadPixels(0, 0, width, height, GL_RGB, GL_FLOAT, &fb[0]);
309 
310 		int startx = int(((float)width * 0.1f) + 1);
311 		int starty = int(((float)height * 0.1f) + 1);
312 		int endx   = int((float)width - 2 * (((float)width * 0.1f) + 1) - 1);
313 		int endy   = int((float)height - 2 * (((float)height * 0.1f) + 1) - 1);
314 
315 		for (int y = starty; y < endy; ++y)
316 		{
317 			for (int x = startx; x < endx; ++x)
318 			{
319 				const int idx = y * width + x;
320 				if (!ColorEqual(fb[idx], expected, g_color_eps))
321 				{
322 					return false;
323 				}
324 			}
325 		}
326 
327 		if (!ColorEqual(fb[2 * width + 2], vec3(0), g_color_eps))
328 		{
329 			result = false;
330 		}
331 		if (!ColorEqual(fb[2 * width + (width - 3)], vec3(0), g_color_eps))
332 		{
333 			result = false;
334 		}
335 		if (!ColorEqual(fb[(height - 3) * width + (width - 3)], vec3(0), g_color_eps))
336 		{
337 			result = false;
338 		}
339 		if (!ColorEqual(fb[(height - 3) * width + 2], vec3(0), g_color_eps))
340 		{
341 			result = false;
342 		}
343 
344 		return result;
345 	}
346 
getWindowWidth()347 	int getWindowWidth()
348 	{
349 		return renderTarget.getWidth();
350 	}
351 
getWindowHeight()352 	int getWindowHeight()
353 	{
354 		return renderTarget.getHeight();
355 	}
356 
ValidateWindow4Quads(const vec3 & lb,const vec3 & rb,const vec3 & rt,const vec3 & lt)357 	bool ValidateWindow4Quads(const vec3& lb, const vec3& rb, const vec3& rt, const vec3& lt)
358 	{
359 		int				  width  = 100;
360 		int				  height = 100;
361 		std::vector<vec3> fb(width * height);
362 		glReadPixels(0, 0, width, height, GL_RGB, GL_FLOAT, &fb[0]);
363 
364 		bool status = true;
365 
366 		// left-bottom quad
367 		for (int y = 10; y < height / 2 - 10; ++y)
368 		{
369 			for (int x = 10; x < width / 2 - 10; ++x)
370 			{
371 				const int idx = y * width + x;
372 				if (!ColorEqual(fb[idx], lb, g_color_eps))
373 				{
374 					m_context.getTestContext().getLog()
375 						<< tcu::TestLog::Message << "First bad color (" << x << ", " << y << "): " << fb[idx].x() << " "
376 						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
377 					status = false;
378 				}
379 			}
380 		}
381 		// right-bottom quad
382 		for (int y = 10; y < height / 2 - 10; ++y)
383 		{
384 			for (int x = width / 2 + 10; x < width - 10; ++x)
385 			{
386 				const int idx = y * width + x;
387 				if (!ColorEqual(fb[idx], rb, g_color_eps))
388 				{
389 					m_context.getTestContext().getLog()
390 						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
391 						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
392 					status = false;
393 				}
394 			}
395 		}
396 		// right-top quad
397 		for (int y = height / 2 + 10; y < height - 10; ++y)
398 		{
399 			for (int x = width / 2 + 10; x < width - 10; ++x)
400 			{
401 				const int idx = y * width + x;
402 				if (!ColorEqual(fb[idx], rt, g_color_eps))
403 				{
404 					m_context.getTestContext().getLog()
405 						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
406 						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
407 					status = false;
408 				}
409 			}
410 		}
411 		// left-top quad
412 		for (int y = height / 2 + 10; y < height - 10; ++y)
413 		{
414 			for (int x = 10; x < width / 2 - 10; ++x)
415 			{
416 				const int idx = y * width + x;
417 				if (!ColorEqual(fb[idx], lt, g_color_eps))
418 				{
419 					m_context.getTestContext().getLog()
420 						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
421 						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
422 					status = false;
423 				}
424 			}
425 		}
426 		// middle horizontal line should be black
427 		for (int y = height / 2 - 2; y < height / 2 + 2; ++y)
428 		{
429 			for (int x = 0; x < width; ++x)
430 			{
431 				const int idx = y * width + x;
432 				if (!ColorEqual(fb[idx], vec3(0), g_color_eps))
433 				{
434 					m_context.getTestContext().getLog()
435 						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
436 						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
437 					status = false;
438 				}
439 			}
440 		}
441 		// middle vertical line should be black
442 		for (int y = 0; y < height; ++y)
443 		{
444 			for (int x = width / 2 - 2; x < width / 2 + 2; ++x)
445 			{
446 				const int idx = y * width + x;
447 				if (!ColorEqual(fb[idx], vec3(0), g_color_eps))
448 				{
449 					m_context.getTestContext().getLog()
450 						<< tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
451 						<< fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
452 					status = false;
453 				}
454 			}
455 		}
456 
457 		return status;
458 	}
459 
IsEqual(vec4 a,vec4 b)460 	bool IsEqual(vec4 a, vec4 b)
461 	{
462 		return (a.x() == b.x()) && (a.y() == b.y()) && (a.z() == b.z()) && (a.w() == b.w());
463 	}
464 
IsEqual(uvec4 a,uvec4 b)465 	bool IsEqual(uvec4 a, uvec4 b)
466 	{
467 		return (a.x() == b.x()) && (a.y() == b.y()) && (a.z() == b.z()) && (a.w() == b.w());
468 	}
469 };
470 
471 class SimpleCompute : public ComputeShaderBase
472 {
473 
Title()474 	virtual std::string Title()
475 	{
476 		return "Simplest possible Compute Shader";
477 	}
478 
Purpose()479 	virtual std::string Purpose()
480 	{
481 		return "1. Verify that CS can be created, compiled and linked.\n"
482 			   "2. Verify that local work size can be queried with GetProgramiv command.\n"
483 			   "3. Verify that CS can be dispatched with DispatchCompute command.\n"
484 			   "4. Verify that CS can write to SSBO.";
485 	}
486 
Method()487 	virtual std::string Method()
488 	{
489 		return "Create and dispatch CS. Verify SSBO content.";
490 	}
491 
PassCriteria()492 	virtual std::string PassCriteria()
493 	{
494 		return "Everything works as expected.";
495 	}
496 
497 	GLuint m_program;
498 	GLuint m_buffer;
499 
Setup()500 	virtual long Setup()
501 	{
502 
503 		const char* const glsl_cs =
504 			NL "layout(local_size_x = 1, local_size_y = 1) in;" NL "layout(std430) buffer Output {" NL "  vec4 data;" NL
505 			   "} g_out;" NL "void main() {" NL "  g_out.data = vec4(1.0, 2.0, 3.0, 4.0);" NL "}";
506 		m_program = CreateComputeProgram(glsl_cs);
507 		glLinkProgram(m_program);
508 		if (!CheckProgram(m_program))
509 			return ERROR;
510 
511 		GLint v[3];
512 		glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
513 		if (v[0] != 1 || v[1] != 1 || v[2] != 1)
514 		{
515 			m_context.getTestContext().getLog()
516 				<< tcu::TestLog::Message << "Got " << v[0] << ", " << v[1] << ", " << v[2]
517 				<< ", expected: 1, 1, 1 in GL_COMPUTE_WORK_GROUP_SIZE check" << tcu::TestLog::EndMessage;
518 			return ERROR;
519 		}
520 
521 		glGenBuffers(1, &m_buffer);
522 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
523 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), NULL, GL_DYNAMIC_DRAW);
524 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
525 
526 		return NO_ERROR;
527 	}
528 
Run()529 	virtual long Run()
530 	{
531 		glUseProgram(m_program);
532 		glDispatchCompute(1, 1, 1);
533 
534 		vec4* data;
535 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
536 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
537 		data	   = static_cast<vec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), GL_MAP_READ_BIT));
538 		long error = NO_ERROR;
539 		if (!IsEqual(data[0], vec4(1.0f, 2.0f, 3.0f, 4.0f)))
540 		{
541 			error = ERROR;
542 		}
543 		glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
544 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
545 		return error;
546 	}
547 
Cleanup()548 	virtual long Cleanup()
549 	{
550 		glUseProgram(0);
551 		glDeleteProgram(m_program);
552 		glDeleteBuffers(1, &m_buffer);
553 		return NO_ERROR;
554 	}
555 };
556 
557 class BasicOneWorkGroup : public ComputeShaderBase
558 {
559 
Title()560 	virtual std::string Title()
561 	{
562 		return "One work group with various local sizes";
563 	}
564 
Purpose()565 	virtual std::string Purpose()
566 	{
567 		return NL "1. Verify that declared local work size has correct effect." NL
568 				  "2. Verify that the number of shader invocations is correct." NL
569 				  "3. Verify that the built-in variables: gl_WorkGroupSize, gl_WorkGroupID, gl_GlobalInvocationID," NL
570 				  "    gl_LocalInvocationID and gl_LocalInvocationIndex has correct values." NL
571 				  "4. Verify that DispatchCompute and DispatchComputeIndirect commands work as expected.";
572 	}
573 
Method()574 	virtual std::string Method()
575 	{
576 		return NL "1. Create several CS with various local sizes." NL
577 				  "2. Dispatch each CS with DispatchCompute and DispatchComputeIndirect commands." NL
578 				  "3. Verify SSBO content.";
579 	}
580 
PassCriteria()581 	virtual std::string PassCriteria()
582 	{
583 		return "Everything works as expected.";
584 	}
585 
586 	GLuint m_program;
587 	GLuint m_storage_buffer;
588 	GLuint m_dispatch_buffer;
589 
GenSource(int x,int y,int z,GLuint binding)590 	std::string GenSource(int x, int y, int z, GLuint binding)
591 	{
592 		std::stringstream ss;
593 		ss << NL "layout(local_size_x = " << x << ", local_size_y = " << y << ", local_size_z = " << z
594 		   << ") in;" NL "layout(std430, binding = " << binding
595 		   << ") buffer Output {" NL "  uvec4 local_id[];" NL "} g_out;" NL "void main() {" NL
596 			  "  if (gl_WorkGroupSize == uvec3("
597 		   << x << ", " << y << ", " << z
598 		   << ") && gl_WorkGroupID == uvec3(0) &&" NL "      gl_GlobalInvocationID == gl_LocalInvocationID) {" NL
599 			  "    g_out.local_id[gl_LocalInvocationIndex] = uvec4(gl_LocalInvocationID, 0);" NL "  } else {" NL
600 			  "    g_out.local_id[gl_LocalInvocationIndex] = uvec4(0xffff);" NL "  }" NL "}";
601 		return ss.str();
602 	}
603 
RunIteration(int local_size_x,int local_size_y,int local_size_z,GLuint binding,bool dispatch_indirect)604 	bool RunIteration(int local_size_x, int local_size_y, int local_size_z, GLuint binding, bool dispatch_indirect)
605 	{
606 		if (m_program != 0)
607 			glDeleteProgram(m_program);
608 		m_program = CreateComputeProgram(GenSource(local_size_x, local_size_y, local_size_z, binding));
609 		glLinkProgram(m_program);
610 		if (!CheckProgram(m_program))
611 			return false;
612 
613 		GLint v[3];
614 		glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
615 		if (v[0] != local_size_x || v[1] != local_size_y || v[2] != local_size_z)
616 		{
617 			m_context.getTestContext().getLog()
618 				<< tcu::TestLog::Message << "GL_COMPUTE_LOCAL_WORK_SIZE is (" << v[0] << " " << v[1] << " " << v[2]
619 				<< ") should be (" << local_size_x << " " << local_size_y << " " << local_size_z << ")"
620 				<< tcu::TestLog::EndMessage;
621 			return false;
622 		}
623 
624 		const int kSize = local_size_x * local_size_y * local_size_z;
625 
626 		if (m_storage_buffer == 0)
627 			glGenBuffers(1, &m_storage_buffer);
628 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, m_storage_buffer);
629 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * kSize, NULL, GL_DYNAMIC_DRAW);
630 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
631 
632 		glUseProgram(m_program);
633 		if (dispatch_indirect)
634 		{
635 			const GLuint num_groups[3] = { 1, 1, 1 };
636 			if (m_dispatch_buffer == 0)
637 				glGenBuffers(1, &m_dispatch_buffer);
638 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
639 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), num_groups, GL_STATIC_DRAW);
640 			glDispatchComputeIndirect(0);
641 		}
642 		else
643 		{
644 			glDispatchCompute(1, 1, 1);
645 		}
646 
647 		uvec4* data;
648 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
649 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
650 		data =
651 			static_cast<uvec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * sizeof(uvec4), GL_MAP_READ_BIT));
652 
653 		bool ret = true;
654 
655 		for (int z = 0; z < local_size_z; ++z)
656 		{
657 			for (int y = 0; y < local_size_y; ++y)
658 			{
659 				for (int x = 0; x < local_size_x; ++x)
660 				{
661 					const int index = z * local_size_x * local_size_y + y * local_size_x + x;
662 					if (!IsEqual(data[index], uvec4(x, y, z, 0)))
663 					{
664 						m_context.getTestContext().getLog()
665 							<< tcu::TestLog::Message << "Invalid data at offset " << index << tcu::TestLog::EndMessage;
666 						ret = false;
667 					}
668 				}
669 			}
670 		}
671 		glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
672 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
673 		return ret;
674 	}
675 
Setup()676 	virtual long Setup()
677 	{
678 		m_program		  = 0;
679 		m_storage_buffer  = 0;
680 		m_dispatch_buffer = 0;
681 		return NO_ERROR;
682 	}
683 
Run()684 	virtual long Run()
685 	{
686 		if (!RunIteration(16, 1, 1, 0, true))
687 			return ERROR;
688 		if (!RunIteration(8, 8, 1, 1, false))
689 			return ERROR;
690 		if (!RunIteration(4, 4, 4, 2, true))
691 			return ERROR;
692 		if (!RunIteration(1, 2, 3, 3, false))
693 			return ERROR;
694 		if (!RunIteration(1024, 1, 1, 3, true))
695 			return ERROR;
696 		if (!RunIteration(16, 8, 8, 3, false))
697 			return ERROR;
698 		if (!RunIteration(32, 1, 32, 7, true))
699 			return ERROR;
700 		return NO_ERROR;
701 	}
702 
Cleanup()703 	virtual long Cleanup()
704 	{
705 		glUseProgram(0);
706 		glDeleteProgram(m_program);
707 		glDeleteBuffers(1, &m_storage_buffer);
708 		glDeleteBuffers(1, &m_dispatch_buffer);
709 		return NO_ERROR;
710 	}
711 };
712 
713 class BasicResourceUBO : public ComputeShaderBase
714 {
715 
Title()716 	virtual std::string Title()
717 	{
718 		return "Compute Shader resources - UBOs";
719 	}
720 
Purpose()721 	virtual std::string Purpose()
722 	{
723 		return "Verify that CS is able to read data from UBOs and write it to SSBO.";
724 	}
725 
Method()726 	virtual std::string Method()
727 	{
728 		return NL "1. Create CS which uses array of UBOs." NL
729 				  "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
730 				  "3. Read data from each UBO and write it to SSBO." NL "4. Verify SSBO content." NL
731 				  "5. Repeat for different buffer and CS work sizes.";
732 	}
733 
PassCriteria()734 	virtual std::string PassCriteria()
735 	{
736 		return "Everything works as expected.";
737 	}
738 
739 	GLuint m_program;
740 	GLuint m_storage_buffer;
741 	GLuint m_uniform_buffer[12];
742 	GLuint m_dispatch_buffer;
743 
GenSource(const uvec3 & local_size,const uvec3 & num_groups)744 	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
745 	{
746 		const uvec3		  global_size = local_size * num_groups;
747 		std::stringstream ss;
748 		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
749 		   << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
750 		   << ", " << global_size.y() << ", " << global_size.z()
751 		   << ");" NL "layout(std140) uniform InputBuffer {" NL "  vec4 data["
752 		   << global_size.x() * global_size.y() * global_size.z()
753 		   << "];" NL "} g_in_buffer[12];" NL "layout(std430) buffer OutputBuffer {" NL "  vec4 data0["
754 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data1["
755 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data2["
756 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data3["
757 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data4["
758 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data5["
759 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data6["
760 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data7["
761 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data8["
762 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data9["
763 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data10["
764 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data11["
765 		   << global_size.x() * global_size.y() * global_size.z()
766 		   << "];" NL "} g_out_buffer;" NL "void main() {" NL "  const uint global_index = gl_GlobalInvocationID.x +" NL
767 			  "                            gl_GlobalInvocationID.y * kGlobalSize.x +" NL
768 			  "                            gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
769 			  "  g_out_buffer.data0[global_index] = g_in_buffer[0].data[global_index];" NL
770 			  "  g_out_buffer.data1[global_index] = g_in_buffer[1].data[global_index];" NL
771 			  "  g_out_buffer.data2[global_index] = g_in_buffer[2].data[global_index];" NL
772 			  "  g_out_buffer.data3[global_index] = g_in_buffer[3].data[global_index];" NL
773 			  "  g_out_buffer.data4[global_index] = g_in_buffer[4].data[global_index];" NL
774 			  "  g_out_buffer.data5[global_index] = g_in_buffer[5].data[global_index];" NL
775 			  "  g_out_buffer.data6[global_index] = g_in_buffer[6].data[global_index];" NL
776 			  "  g_out_buffer.data7[global_index] = g_in_buffer[7].data[global_index];" NL
777 			  "  g_out_buffer.data8[global_index] = g_in_buffer[8].data[global_index];" NL
778 			  "  g_out_buffer.data9[global_index] = g_in_buffer[9].data[global_index];" NL
779 			  "  g_out_buffer.data10[global_index] = g_in_buffer[10].data[global_index];" NL
780 			  "  g_out_buffer.data11[global_index] = g_in_buffer[11].data[global_index];" NL "}";
781 		return ss.str();
782 	}
783 
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)784 	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
785 	{
786 		if (m_program != 0)
787 			glDeleteProgram(m_program);
788 		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
789 		glLinkProgram(m_program);
790 		if (!CheckProgram(m_program))
791 			return false;
792 
793 		for (GLuint i = 0; i < 12; ++i)
794 		{
795 			char name[32];
796 			sprintf(name, "InputBuffer[%u]", i);
797 			const GLuint index = glGetUniformBlockIndex(m_program, name);
798 			glUniformBlockBinding(m_program, index, i);
799 			GLint p = 0;
800 			glGetActiveUniformBlockiv(m_program, index, GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER, &p);
801 			if (p == GL_FALSE)
802 			{
803 				m_context.getTestContext().getLog()
804 					<< tcu::TestLog::Message << "UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER should be TRUE."
805 					<< tcu::TestLog::EndMessage;
806 				return false;
807 			}
808 		}
809 
810 		const GLuint kBufferSize =
811 			local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
812 
813 		if (m_storage_buffer == 0)
814 			glGenBuffers(1, &m_storage_buffer);
815 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
816 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize * 12, NULL, GL_DYNAMIC_DRAW);
817 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
818 
819 		if (m_uniform_buffer[0] == 0)
820 			glGenBuffers(12, m_uniform_buffer);
821 		for (GLuint i = 0; i < 12; ++i)
822 		{
823 			std::vector<vec4> data(kBufferSize);
824 			for (GLuint j = 0; j < kBufferSize; ++j)
825 			{
826 				data[j] = vec4(static_cast<float>(i * kBufferSize + j));
827 			}
828 			glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
829 			glBufferData(GL_UNIFORM_BUFFER, sizeof(vec4) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
830 		}
831 		glBindBuffer(GL_UNIFORM_BUFFER, 0);
832 
833 		glUseProgram(m_program);
834 		if (dispatch_indirect)
835 		{
836 			if (m_dispatch_buffer == 0)
837 				glGenBuffers(1, &m_dispatch_buffer);
838 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
839 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
840 			glDispatchComputeIndirect(0);
841 		}
842 		else
843 		{
844 			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
845 		}
846 
847 		std::vector<vec4> data(kBufferSize * 12);
848 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
849 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
850 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize * 12, &data[0]);
851 
852 		for (GLuint z = 0; z < local_size.z() * num_groups.z(); ++z)
853 		{
854 			for (GLuint y = 0; y < local_size.y() * num_groups.y(); ++y)
855 			{
856 				for (GLuint x = 0; x < local_size.x() * num_groups.x(); ++x)
857 				{
858 					const GLuint index = z * local_size.x() * num_groups.x() * local_size.y() * num_groups.y() +
859 										 y * local_size.x() * num_groups.x() + x;
860 					for (int i = 0; i < 1; ++i)
861 					{
862 						if (!IsEqual(data[index * 12 + i], vec4(static_cast<float>(index * 12 + i))))
863 						{
864 							m_context.getTestContext().getLog() << tcu::TestLog::Message << "Incorrect data at offset "
865 																<< index * 12 + i << "." << tcu::TestLog::EndMessage;
866 							return false;
867 						}
868 					}
869 				}
870 			}
871 		}
872 		return true;
873 	}
874 
Setup()875 	virtual long Setup()
876 	{
877 		m_program		 = 0;
878 		m_storage_buffer = 0;
879 		memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
880 		m_dispatch_buffer = 0;
881 		return NO_ERROR;
882 	}
883 
Run()884 	virtual long Run()
885 	{
886 		if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
887 			return ERROR;
888 		if (!RunIteration(uvec3(2, 2, 2), uvec3(2, 2, 2), true))
889 			return ERROR;
890 		if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
891 			return ERROR;
892 		return NO_ERROR;
893 	}
894 
Cleanup()895 	virtual long Cleanup()
896 	{
897 		glUseProgram(0);
898 		glDeleteProgram(m_program);
899 		glDeleteBuffers(1, &m_storage_buffer);
900 		glDeleteBuffers(12, m_uniform_buffer);
901 		glDeleteBuffers(1, &m_dispatch_buffer);
902 		return NO_ERROR;
903 	}
904 };
905 
906 class BasicResourceTexture : public ComputeShaderBase
907 {
908 
Title()909 	virtual std::string Title()
910 	{
911 		return NL "Compute Shader resources - Textures";
912 	}
913 
Purpose()914 	virtual std::string Purpose()
915 	{
916 		return NL "Verify that texture access works correctly in CS.";
917 	}
918 
Method()919 	virtual std::string Method()
920 	{
921 		return NL "1. Create CS which uses all sampler types (sampler1D, sampler2D, sampler3D, sampler2DRect," NL
922 				  "    sampler1DArray, sampler2DArray, samplerBuffer, sampler2DMS, sampler2DMSArray)." NL
923 				  "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
924 				  "3. Sample each texture and write sampled value to SSBO." NL "4. Verify SSBO content." NL
925 				  "5. Repeat for different texture and CS work sizes.";
926 	}
927 
PassCriteria()928 	virtual std::string PassCriteria()
929 	{
930 		return NL "Everything works as expected.";
931 	}
932 
933 	GLuint m_program;
934 	GLuint m_storage_buffer;
935 	GLuint m_texture[9];
936 	GLuint m_texture_buffer;
937 	GLuint m_dispatch_buffer;
938 
GenSource(const uvec3 & local_size,const uvec3 & num_groups)939 	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
940 	{
941 		const uvec3		  global_size = local_size * num_groups;
942 		std::stringstream ss;
943 		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
944 		   << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
945 		   << ", " << global_size.y() << ", " << global_size.z()
946 		   << ");" NL "uniform sampler1D g_sampler0;" NL "uniform sampler2D g_sampler1;" NL
947 			  "uniform sampler3D g_sampler2;" NL "uniform sampler2DRect g_sampler3;" NL
948 			  "uniform sampler1DArray g_sampler4;" NL "uniform sampler2DArray g_sampler5;" NL
949 			  "uniform samplerBuffer g_sampler6;" NL "uniform sampler2DMS g_sampler7;" NL
950 			  "uniform sampler2DMSArray g_sampler8;" NL "layout(std430) buffer OutputBuffer {" NL "  vec4 data0["
951 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data1["
952 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data2["
953 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data3["
954 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data4["
955 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data5["
956 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data6["
957 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data7["
958 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  vec4 data8["
959 		   << global_size.x() * global_size.y() * global_size.z()
960 		   << "];" NL "} g_out_buffer;" NL "void main() {" NL "  const uint global_index = gl_GlobalInvocationID.x +" NL
961 			  "                            gl_GlobalInvocationID.y * kGlobalSize.x +" NL
962 			  "                            gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
963 			  "  g_out_buffer.data0[global_index] = texelFetch(g_sampler0, int(gl_GlobalInvocationID), 0);" NL
964 			  "  g_out_buffer.data1[global_index] = texture(g_sampler1, vec2(gl_GlobalInvocationID) / "
965 			  "vec2(kGlobalSize));" NL "  g_out_buffer.data2[global_index] = textureProj(g_sampler2, "
966 			  "vec4(vec3(gl_GlobalInvocationID) / vec3(kGlobalSize), 1.0));" NL
967 			  "  g_out_buffer.data3[global_index] = textureProjOffset(g_sampler3, vec3(vec2(gl_GlobalInvocationID), "
968 			  "1.0), ivec2(0));" NL "  g_out_buffer.data4[global_index] = textureLodOffset(g_sampler4, "
969 			  "vec2(gl_GlobalInvocationID.x / kGlobalSize.x, gl_GlobalInvocationID.y), 0.0, "
970 			  "0);" NL "  g_out_buffer.data5[global_index] = texelFetchOffset(g_sampler5, "
971 			  "ivec3(gl_GlobalInvocationID), 0, ivec2(0));" NL
972 			  "  g_out_buffer.data6[global_index] = texelFetch(g_sampler6, int(global_index));" NL
973 			  "  g_out_buffer.data7[global_index] = texelFetch(g_sampler7, ivec2(gl_GlobalInvocationID), 1);" NL
974 			  "  g_out_buffer.data8[global_index] = texelFetch(g_sampler8, ivec3(gl_GlobalInvocationID), 2);" NL "}";
975 		return ss.str();
976 	}
977 
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)978 	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
979 	{
980 		if (m_program != 0)
981 			glDeleteProgram(m_program);
982 		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
983 		glLinkProgram(m_program);
984 		if (!CheckProgram(m_program))
985 			return false;
986 
987 		glUseProgram(m_program);
988 		for (int i = 0; i < 9; ++i)
989 		{
990 			char name[32];
991 			sprintf(name, "g_sampler%d", i);
992 			glUniform1i(glGetUniformLocation(m_program, name), i);
993 		}
994 		glUseProgram(0);
995 
996 		const GLuint kBufferSize =
997 			local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
998 		const GLint kWidth  = static_cast<GLint>(local_size.x() * num_groups.x());
999 		const GLint kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
1000 		const GLint kDepth  = static_cast<GLint>(local_size.z() * num_groups.z());
1001 
1002 		std::vector<vec4> buffer_data(kBufferSize * 9);
1003 		if (m_storage_buffer == 0)
1004 			glGenBuffers(1, &m_storage_buffer);
1005 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
1006 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize * 9, &buffer_data[0], GL_DYNAMIC_DRAW);
1007 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1008 
1009 		std::vector<vec4> texture_data(kBufferSize, vec4(123.0f));
1010 		if (m_texture[0] == 0)
1011 			glGenTextures(9, m_texture);
1012 		if (m_texture_buffer == 0)
1013 			glGenBuffers(1, &m_texture_buffer);
1014 
1015 		glActiveTexture(GL_TEXTURE0);
1016 		glBindTexture(GL_TEXTURE_1D, m_texture[0]);
1017 		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1018 		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1019 		glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, kWidth, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1020 
1021 		glActiveTexture(GL_TEXTURE1);
1022 		glBindTexture(GL_TEXTURE_2D, m_texture[1]);
1023 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1024 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1025 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1026 
1027 		glActiveTexture(GL_TEXTURE2);
1028 		glBindTexture(GL_TEXTURE_3D, m_texture[2]);
1029 		glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1030 		glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1031 		glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1032 
1033 		glActiveTexture(GL_TEXTURE3);
1034 		glBindTexture(GL_TEXTURE_RECTANGLE, m_texture[3]);
1035 		glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1036 		glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1037 		glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1038 
1039 		glActiveTexture(GL_TEXTURE4);
1040 		glBindTexture(GL_TEXTURE_1D_ARRAY, m_texture[4]);
1041 		glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1042 		glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1043 		glTexImage2D(GL_TEXTURE_1D_ARRAY, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1044 
1045 		glActiveTexture(GL_TEXTURE5);
1046 		glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture[5]);
1047 		glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1048 		glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1049 		glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA32F, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_FLOAT,
1050 					 &texture_data[0]);
1051 
1052 		glActiveTexture(GL_TEXTURE6);
1053 		glBindBuffer(GL_TEXTURE_BUFFER, m_texture_buffer);
1054 		glBufferData(GL_TEXTURE_BUFFER, kBufferSize * sizeof(vec4), &texture_data[0], GL_DYNAMIC_DRAW);
1055 		glBindBuffer(GL_TEXTURE_BUFFER, 0);
1056 		glBindTexture(GL_TEXTURE_BUFFER, m_texture[6]);
1057 		glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_texture_buffer);
1058 
1059 		glActiveTexture(GL_TEXTURE7);
1060 		glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texture[7]);
1061 		glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA32F, kWidth, kHeight, GL_FALSE);
1062 
1063 		glActiveTexture(GL_TEXTURE8);
1064 		glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_texture[8]);
1065 		glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 4, GL_RGBA32F, kWidth, kHeight, kDepth, GL_FALSE);
1066 
1067 		// clear MS textures
1068 		GLuint fbo;
1069 		glGenFramebuffers(1, &fbo);
1070 		glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1071 		glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture[7], 0);
1072 		glClearBufferfv(GL_COLOR, 0, &vec4(123.0f)[0]);
1073 		glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture[8], 0);
1074 		glClearBufferfv(GL_COLOR, 0, &vec4(123.0f)[0]);
1075 		glDeleteFramebuffers(1, &fbo);
1076 
1077 		glUseProgram(m_program);
1078 		if (dispatch_indirect)
1079 		{
1080 			if (m_dispatch_buffer == 0)
1081 				glGenBuffers(1, &m_dispatch_buffer);
1082 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1083 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1084 			glDispatchComputeIndirect(0);
1085 		}
1086 		else
1087 		{
1088 			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1089 		}
1090 
1091 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
1092 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1093 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize * 9, &buffer_data[0]);
1094 		for (GLuint index = 0; index < kBufferSize * 9; ++index)
1095 		{
1096 			if (!IsEqual(buffer_data[index], vec4(123.0f)))
1097 			{
1098 				m_context.getTestContext().getLog()
1099 					<< tcu::TestLog::Message << "Incorrect data at index " << index << "." << tcu::TestLog::EndMessage;
1100 				return false;
1101 			}
1102 		}
1103 		return true;
1104 	}
1105 
Setup()1106 	virtual long Setup()
1107 	{
1108 		m_program		 = 0;
1109 		m_storage_buffer = 0;
1110 		memset(m_texture, 0, sizeof(m_texture));
1111 		m_texture_buffer  = 0;
1112 		m_dispatch_buffer = 0;
1113 		return NO_ERROR;
1114 	}
1115 
Run()1116 	virtual long Run()
1117 	{
1118 		if (!RunIteration(uvec3(4, 4, 4), uvec3(8, 1, 1), false))
1119 			return ERROR;
1120 		if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), true))
1121 			return ERROR;
1122 		if (!RunIteration(uvec3(2, 2, 2), uvec3(2, 2, 2), false))
1123 			return ERROR;
1124 		return NO_ERROR;
1125 	}
1126 
Cleanup()1127 	virtual long Cleanup()
1128 	{
1129 		glActiveTexture(GL_TEXTURE0);
1130 		glUseProgram(0);
1131 		glDeleteProgram(m_program);
1132 		glDeleteBuffers(1, &m_storage_buffer);
1133 		glDeleteTextures(9, m_texture);
1134 		glDeleteBuffers(1, &m_texture_buffer);
1135 		glDeleteBuffers(1, &m_dispatch_buffer);
1136 		return NO_ERROR;
1137 	}
1138 };
1139 
1140 class BasicResourceImage : public ComputeShaderBase
1141 {
1142 
Title()1143 	virtual std::string Title()
1144 	{
1145 		return NL "Compute Shader resources - Images";
1146 	}
1147 
Purpose()1148 	virtual std::string Purpose()
1149 	{
1150 		return NL "Verify that reading/writing GPU memory via image variables work as expected.";
1151 	}
1152 
Method()1153 	virtual std::string Method()
1154 	{
1155 		return NL "1. Create CS which uses two image2D variables to read and write underlying GPU memory." NL
1156 				  "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
1157 				  "3. Verify memory content." NL "4. Repeat for different texture and CS work sizes.";
1158 	}
1159 
PassCriteria()1160 	virtual std::string PassCriteria()
1161 	{
1162 		return NL "Everything works as expected.";
1163 	}
1164 
1165 	GLuint m_program;
1166 	GLuint m_draw_program;
1167 	GLuint m_texture[2];
1168 	GLuint m_dispatch_buffer;
1169 	GLuint m_vertex_array;
1170 
GenSource(const uvec3 & local_size,const uvec3 & num_groups)1171 	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
1172 	{
1173 		const uvec3		  global_size = local_size * num_groups;
1174 		std::stringstream ss;
1175 		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
1176 		   << ", local_size_z = " << local_size.z()
1177 		   << ") in;" NL "layout(rgba32f) coherent uniform image2D g_image1;" NL
1178 			  "layout(rgba32f) uniform image2D g_image2;" NL "const uvec3 kGlobalSize = uvec3("
1179 		   << global_size.x() << ", " << global_size.y() << ", " << global_size.z()
1180 		   << ");" NL "void main() {" NL
1181 			  "  if (gl_GlobalInvocationID.x >= kGlobalSize.x || gl_GlobalInvocationID.y >= kGlobalSize.y) return;" NL
1182 			  "  vec4 color = vec4(gl_GlobalInvocationID.x + gl_GlobalInvocationID.y) / 255.0;" NL
1183 			  "  imageStore(g_image1, ivec2(gl_GlobalInvocationID), color);" NL
1184 			  "  vec4 c = imageLoad(g_image1, ivec2(gl_GlobalInvocationID));" NL
1185 			  "  imageStore(g_image2, ivec2(gl_GlobalInvocationID), c);" NL "}";
1186 		return ss.str();
1187 	}
1188 
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)1189 	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
1190 	{
1191 		if (m_program != 0)
1192 			glDeleteProgram(m_program);
1193 		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
1194 		glLinkProgram(m_program);
1195 		if (!CheckProgram(m_program))
1196 			return false;
1197 
1198 		glUseProgram(m_program);
1199 		glUniform1i(glGetUniformLocation(m_program, "g_image1"), 0);
1200 		glUniform1i(glGetUniformLocation(m_program, "g_image2"), 1);
1201 		glUseProgram(0);
1202 
1203 		const GLint  kWidth  = static_cast<GLint>(local_size.x() * num_groups.x());
1204 		const GLint  kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
1205 		const GLint  kDepth  = static_cast<GLint>(local_size.z() * num_groups.z());
1206 		const GLuint kSize   = kWidth * kHeight * kDepth;
1207 
1208 		std::vector<vec4> data(kSize);
1209 		if (m_texture[0] == 0)
1210 			glGenTextures(2, m_texture);
1211 
1212 		for (int i = 0; i < 2; ++i)
1213 		{
1214 			glBindTexture(GL_TEXTURE_2D, m_texture[i]);
1215 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1216 			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &data[0]);
1217 		}
1218 		glBindTexture(GL_TEXTURE_2D, 0);
1219 
1220 		glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
1221 		glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
1222 		glUseProgram(m_program);
1223 		if (dispatch_indirect)
1224 		{
1225 			if (m_dispatch_buffer == 0)
1226 				glGenBuffers(1, &m_dispatch_buffer);
1227 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1228 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1229 			glDispatchComputeIndirect(0);
1230 		}
1231 		else
1232 		{
1233 			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1234 		}
1235 		glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1236 
1237 		glClear(GL_COLOR_BUFFER_BIT);
1238 		glActiveTexture(GL_TEXTURE0);
1239 		glBindTexture(GL_TEXTURE_2D, m_texture[0]);
1240 		glActiveTexture(GL_TEXTURE1);
1241 		glBindTexture(GL_TEXTURE_2D, m_texture[1]);
1242 		glUseProgram(m_draw_program);
1243 		glBindVertexArray(m_vertex_array);
1244 		glViewport(0, 0, kWidth, kHeight);
1245 		glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
1246 
1247 		std::vector<vec4> display(kWidth * kHeight);
1248 		glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_FLOAT, &display[0]);
1249 
1250 		for (int y = 0; y < kHeight; ++y)
1251 		{
1252 			for (int x = 0; x < kWidth; ++x)
1253 			{
1254 				if (y >= getWindowHeight() || x >= getWindowWidth())
1255 				{
1256 					continue;
1257 				}
1258 				const vec4 c = vec4(float(y + x) / 255.0f);
1259 				if (!ColorEqual(display[y * kWidth + x], c, g_color_eps))
1260 				{
1261 					m_context.getTestContext().getLog()
1262 						<< tcu::TestLog::Message << "Got " << display[y * kWidth + x].x() << ", "
1263 						<< display[y * kWidth + x].y() << ", " << display[y * kWidth + x].z() << ", "
1264 						<< display[y * kWidth + x].w() << ", expected " << c.x() << ", " << c.y() << ", " << c.z()
1265 						<< ", " << c.w() << " at " << x << ", " << y << tcu::TestLog::EndMessage;
1266 					return false;
1267 				}
1268 			}
1269 		}
1270 
1271 		return true;
1272 	}
1273 
Setup()1274 	virtual long Setup()
1275 	{
1276 		m_program = 0;
1277 		memset(m_texture, 0, sizeof(m_texture));
1278 		m_dispatch_buffer = 0;
1279 		return NO_ERROR;
1280 	}
1281 
Run()1282 	virtual long Run()
1283 	{
1284 
1285 		const char* const glsl_vs =
1286 			NL "out StageData {" NL "  vec2 texcoord;" NL "} vs_out;" NL
1287 			   "const vec2 g_quad[] = vec2[](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1));" NL "void main() {" NL
1288 			   "  gl_Position = vec4(g_quad[gl_VertexID], 0, 1);" NL
1289 			   "  vs_out.texcoord = 0.5 + 0.5 * g_quad[gl_VertexID];" NL "}";
1290 
1291 		const char* glsl_fs =
1292 			NL "in StageData {" NL "  vec2 texcoord;" NL "} fs_in;" NL "layout(location = 0) out vec4 o_color;" NL
1293 			   "uniform sampler2D g_image1;" NL "uniform sampler2D g_image2;" NL "void main() {" NL
1294 			   "  vec4 c1 = texture(g_image1, fs_in.texcoord);" NL "  vec4 c2 = texture(g_image2, fs_in.texcoord);" NL
1295 			   "  if (c1 == c2) o_color = c1;" NL "  else o_color = vec4(1, 0, 0, 1);" NL "}";
1296 
1297 		m_draw_program = CreateProgram(glsl_vs, glsl_fs);
1298 		glLinkProgram(m_draw_program);
1299 		if (!CheckProgram(m_draw_program))
1300 			return ERROR;
1301 
1302 		glUseProgram(m_draw_program);
1303 		glUniform1i(glGetUniformLocation(m_draw_program, "g_image1"), 0);
1304 		glUniform1i(glGetUniformLocation(m_draw_program, "g_image2"), 1);
1305 		glUseProgram(0);
1306 
1307 		glGenVertexArrays(1, &m_vertex_array);
1308 
1309 		if (!pixelFormat.alphaBits)
1310 		{
1311 			m_context.getTestContext().getLog()
1312 				<< tcu::TestLog::Message << "Test requires default framebuffer alpha bits" << tcu::TestLog::EndMessage;
1313 			return NO_ERROR;
1314 		}
1315 
1316 		if (!RunIteration(uvec3(8, 16, 1), uvec3(8, 4, 1), true))
1317 			return ERROR;
1318 		if (!RunIteration(uvec3(4, 32, 1), uvec3(16, 2, 1), false))
1319 			return ERROR;
1320 		if (!RunIteration(uvec3(16, 4, 1), uvec3(4, 16, 1), false))
1321 			return ERROR;
1322 		if (!RunIteration(uvec3(8, 8, 1), uvec3(8, 8, 1), true))
1323 			return ERROR;
1324 
1325 		return NO_ERROR;
1326 	}
1327 
Cleanup()1328 	virtual long Cleanup()
1329 	{
1330 		glUseProgram(0);
1331 		glDeleteProgram(m_program);
1332 		glDeleteProgram(m_draw_program);
1333 		glDeleteVertexArrays(1, &m_vertex_array);
1334 		glDeleteTextures(2, m_texture);
1335 		glDeleteBuffers(1, &m_dispatch_buffer);
1336 		glViewport(0, 0, getWindowWidth(), getWindowHeight());
1337 		return NO_ERROR;
1338 	}
1339 };
1340 
1341 class BasicResourceAtomicCounter : public ComputeShaderBase
1342 {
1343 
Title()1344 	virtual std::string Title()
1345 	{
1346 		return "Compute Shader resources - Atomic Counters";
1347 	}
1348 
Purpose()1349 	virtual std::string Purpose()
1350 	{
1351 		return NL
1352 			"1. Verify that Atomic Counters work as expected in CS." NL
1353 			"2. Verify that built-in functions: atomicCounterIncrement and atomicCounterDecrement work correctly." NL
1354 			"3. Verify that GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER is accepted by" NL
1355 			"    GetActiveAtomicCounterBufferiv command.";
1356 	}
1357 
Method()1358 	virtual std::string Method()
1359 	{
1360 		return NL
1361 			"1. Create CS which uses two atomic_uint variables." NL
1362 			"2. In CS write values returned by atomicCounterIncrement and atomicCounterDecrement functions to SSBO." NL
1363 			"3. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL "4. Verify SSBO content." NL
1364 			"5. Repeat for different buffer and CS work sizes.";
1365 	}
1366 
PassCriteria()1367 	virtual std::string PassCriteria()
1368 	{
1369 		return "Everything works as expected.";
1370 	}
1371 
1372 	GLuint m_program;
1373 	GLuint m_storage_buffer;
1374 	GLuint m_counter_buffer[2];
1375 	GLuint m_dispatch_buffer;
1376 
GenSource(const uvec3 & local_size,const uvec3 & num_groups)1377 	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
1378 	{
1379 		const uvec3		  global_size = local_size * num_groups;
1380 		std::stringstream ss;
1381 		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
1382 		   << ", local_size_z = " << local_size.z()
1383 		   << ") in;" NL "layout(std430, binding = 0) buffer Output {" NL "  uint inc_data["
1384 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uint dec_data["
1385 		   << global_size.x() * global_size.y() * global_size.z()
1386 		   << "];" NL "};" NL "layout(binding = 0, offset = 0) uniform atomic_uint g_inc_counter;" NL
1387 			  "layout(binding = 1, offset = 0) uniform atomic_uint g_dec_counter;" NL "void main() {" NL
1388 			  "  const uint index = atomicCounterIncrement(g_inc_counter);" NL "  inc_data[index] = index;" NL
1389 			  "  dec_data[index] = atomicCounterDecrement(g_dec_counter);" NL "}";
1390 		return ss.str();
1391 	}
1392 
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)1393 	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
1394 	{
1395 		if (m_program != 0)
1396 			glDeleteProgram(m_program);
1397 		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
1398 		glLinkProgram(m_program);
1399 		if (!CheckProgram(m_program))
1400 			return false;
1401 
1402 		GLint p[2] = { 0 };
1403 		glGetActiveAtomicCounterBufferiv(m_program, 0, GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER, &p[0]);
1404 		glGetActiveAtomicCounterBufferiv(m_program, 1, GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER, &p[1]);
1405 
1406 		if (p[0] == GL_FALSE || p[1] == GL_FALSE)
1407 		{
1408 			m_context.getTestContext().getLog()
1409 				<< tcu::TestLog::Message << "ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER should be TRUE."
1410 				<< tcu::TestLog::EndMessage;
1411 			return false;
1412 		}
1413 
1414 		const GLint  kWidth  = static_cast<GLint>(local_size.x() * num_groups.x());
1415 		const GLint  kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
1416 		const GLint  kDepth  = static_cast<GLint>(local_size.z() * num_groups.z());
1417 		const GLuint kSize   = kWidth * kHeight * kDepth;
1418 
1419 		if (m_storage_buffer == 0)
1420 			glGenBuffers(1, &m_storage_buffer);
1421 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
1422 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kSize * 2, NULL, GL_DYNAMIC_DRAW);
1423 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1424 
1425 		if (m_counter_buffer[0] == 0)
1426 			glGenBuffers(2, m_counter_buffer);
1427 
1428 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_counter_buffer[0]);
1429 		glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_DRAW);
1430 		*static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)) = 0;
1431 		glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1432 
1433 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, m_counter_buffer[1]);
1434 		glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_DRAW);
1435 		*static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)) = kSize;
1436 		glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1437 
1438 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1439 
1440 		glUseProgram(m_program);
1441 		if (dispatch_indirect)
1442 		{
1443 			if (m_dispatch_buffer == 0)
1444 				glGenBuffers(1, &m_dispatch_buffer);
1445 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1446 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1447 			glDispatchComputeIndirect(0);
1448 		}
1449 		else
1450 		{
1451 			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1452 		}
1453 
1454 		std::vector<GLuint> data(kSize);
1455 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
1456 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1457 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kSize, &data[0]);
1458 
1459 		for (GLuint i = 0; i < kSize; ++i)
1460 		{
1461 			if (data[i] != i)
1462 			{
1463 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Value at index " << i << " is "
1464 													<< data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
1465 				return false;
1466 			}
1467 		}
1468 
1469 		GLuint value;
1470 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_counter_buffer[0]);
1471 		glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &value);
1472 		if (value != kSize)
1473 		{
1474 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Final atomic counter value (buffer 0) is "
1475 												<< value << " should be " << kSize << "." << tcu::TestLog::EndMessage;
1476 			return false;
1477 		}
1478 
1479 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_counter_buffer[1]);
1480 		glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &value);
1481 		if (value != 0)
1482 		{
1483 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Final atomic counter value (buffer 1) is "
1484 												<< value << " should be 0." << tcu::TestLog::EndMessage;
1485 			return false;
1486 		}
1487 
1488 		return true;
1489 	}
1490 
Setup()1491 	virtual long Setup()
1492 	{
1493 		m_program		 = 0;
1494 		m_storage_buffer = 0;
1495 		memset(m_counter_buffer, 0, sizeof(m_counter_buffer));
1496 		m_dispatch_buffer = 0;
1497 		return NO_ERROR;
1498 	}
1499 
Run()1500 	virtual long Run()
1501 	{
1502 		if (!RunIteration(uvec3(4, 3, 2), uvec3(2, 3, 4), false))
1503 			return ERROR;
1504 		if (!RunIteration(uvec3(1, 1, 1), uvec3(1, 1, 1), true))
1505 			return ERROR;
1506 		if (!RunIteration(uvec3(1, 6, 1), uvec3(1, 1, 8), false))
1507 			return ERROR;
1508 		if (!RunIteration(uvec3(4, 1, 2), uvec3(10, 3, 4), true))
1509 			return ERROR;
1510 		return NO_ERROR;
1511 	}
1512 
Cleanup()1513 	virtual long Cleanup()
1514 	{
1515 		glUseProgram(0);
1516 		glDeleteProgram(m_program);
1517 		glDeleteBuffers(2, m_counter_buffer);
1518 		glDeleteBuffers(1, &m_dispatch_buffer);
1519 		glDeleteBuffers(1, &m_storage_buffer);
1520 		return NO_ERROR;
1521 	}
1522 };
1523 
1524 class BasicResourceSubroutine : public ComputeShaderBase
1525 {
1526 
Title()1527 	virtual std::string Title()
1528 	{
1529 		return "Compute Shader resources - Subroutines";
1530 	}
1531 
Purpose()1532 	virtual std::string Purpose()
1533 	{
1534 		return NL "1. Verify that subroutines work as expected in CS." NL
1535 				  "2. Verify that subroutines array can be indexed with gl_WorkGroupID built-in variable." NL
1536 				  "3. Verify that atomicCounterIncrement, imageLoad and texelFetch functions" NL
1537 				  "    work as expected when called in CS from subroutine.";
1538 	}
1539 
Method()1540 	virtual std::string Method()
1541 	{
1542 		return NL "1. Create CS which uses array of subroutines." NL
1543 				  "2. In CS index subroutine array with gl_WorkGroupID built-in variable." NL
1544 				  "3. In each subroutine load data from SSBO0 and write it to SSBO1." NL
1545 				  "3. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
1546 				  "4. Verify SSBO1 content." NL "5. Repeat for different buffer and CS work sizes.";
1547 	}
1548 
PassCriteria()1549 	virtual std::string PassCriteria()
1550 	{
1551 		return "Everything works as expected.";
1552 	}
1553 
1554 	GLuint m_program;
1555 	GLuint m_atomic_counter_buffer;
1556 	GLuint m_storage_buffer[2];
1557 	GLuint m_buffer[2];
1558 	GLuint m_texture_buffer[2];
1559 
Setup()1560 	virtual long Setup()
1561 	{
1562 		m_program				= 0;
1563 		m_atomic_counter_buffer = 0;
1564 		memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
1565 		memset(m_buffer, 0, sizeof(m_buffer));
1566 		memset(m_texture_buffer, 0, sizeof(m_texture_buffer));
1567 		return NO_ERROR;
1568 	}
1569 
Run()1570 	virtual long Run()
1571 	{
1572 		const char* const glsl_cs =
1573 			NL "layout(local_size_x = 16) in;" NL "layout(binding = 1, std430) buffer Input {" NL "  uvec4 data[16];" NL
1574 			   "} g_input;" NL "layout(std430, binding = 0) buffer Output {" NL "  uvec4 g_output[64];" NL "};" NL
1575 			   "subroutine void ComputeType();" NL "subroutine uniform ComputeType Compute[4];" NL
1576 			   "layout(binding = 0, offset = 0) uniform atomic_uint g_atomic_counter;" NL
1577 			   "layout(rgba32ui) readonly uniform uimageBuffer g_image_buffer;" NL
1578 			   "uniform usamplerBuffer g_sampler_buffer;" NL "subroutine(ComputeType)" NL "void Compute0() {" NL
1579 			   "  const uint index = atomicCounterIncrement(g_atomic_counter);" NL
1580 			   "  g_output[index] = uvec4(index);" NL "}" NL "subroutine(ComputeType)" NL "void Compute1() {" NL
1581 			   "  g_output[gl_GlobalInvocationID.x] = g_input.data[gl_LocalInvocationIndex];" NL "}" NL
1582 			   "subroutine(ComputeType)" NL "void Compute2() {" NL
1583 			   "  g_output[gl_GlobalInvocationID.x] = imageLoad(g_image_buffer, int(gl_LocalInvocationIndex));" NL
1584 			   "}" NL "subroutine(ComputeType)" NL "void Compute3() {" NL
1585 			   "  g_output[gl_GlobalInvocationID.x] = texelFetch(g_sampler_buffer, int(gl_LocalInvocationIndex));" NL
1586 			   "}" NL "void main() {" NL "  Compute[gl_WorkGroupID.x]();" NL "}";
1587 		m_program = CreateComputeProgram(glsl_cs);
1588 		glLinkProgram(m_program);
1589 		if (!CheckProgram(m_program))
1590 			return ERROR;
1591 
1592 		glGenBuffers(2, m_storage_buffer);
1593 		/* output buffer */
1594 		{
1595 			std::vector<uvec4> data(64, uvec4(0xffff));
1596 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
1597 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * 64, &data[0], GL_DYNAMIC_DRAW);
1598 		}
1599 		/* input buffer */
1600 		{
1601 			std::vector<uvec4> data(16);
1602 			for (GLuint i = 0; i < 16; ++i)
1603 				data[i]   = uvec4(i + 16);
1604 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
1605 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * 16, &data[0], GL_DYNAMIC_DRAW);
1606 		}
1607 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1608 
1609 		glGenBuffers(1, &m_atomic_counter_buffer);
1610 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomic_counter_buffer);
1611 		glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_DRAW);
1612 		*static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)) = 0;
1613 		glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1614 
1615 		glGenBuffers(2, m_buffer);
1616 		/* image buffer */
1617 		{
1618 			std::vector<uvec4> data(16);
1619 			for (GLuint i = 0; i < 16; ++i)
1620 				data[i]   = uvec4(i + 32);
1621 			glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[0]);
1622 			glBufferData(GL_TEXTURE_BUFFER, sizeof(uvec4) * 16, &data[0], GL_STATIC_DRAW);
1623 		}
1624 		/* texture buffer */
1625 		{
1626 			std::vector<uvec4> data(16);
1627 			for (GLuint i = 0; i < 16; ++i)
1628 				data[i]   = uvec4(i + 48);
1629 			glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[1]);
1630 			glBufferData(GL_TEXTURE_BUFFER, sizeof(uvec4) * 16, &data[0], GL_STATIC_DRAW);
1631 		}
1632 		glBindBuffer(GL_TEXTURE_BUFFER, 0);
1633 
1634 		glGenTextures(2, m_texture_buffer);
1635 		glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer[0]);
1636 		glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, m_buffer[0]);
1637 		glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer[1]);
1638 		glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, m_buffer[1]);
1639 		glBindTexture(GL_TEXTURE_BUFFER, 0);
1640 
1641 		const GLuint index_compute0 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute0");
1642 		const GLuint index_compute1 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute1");
1643 		const GLuint index_compute2 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute2");
1644 		const GLuint index_compute3 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute3");
1645 		const GLint  loc_compute0   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[0]");
1646 		const GLint  loc_compute1   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[1]");
1647 		const GLint  loc_compute2   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[2]");
1648 		const GLint  loc_compute3   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[3]");
1649 
1650 		// bind resources
1651 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
1652 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
1653 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomic_counter_buffer);
1654 		glBindImageTexture(0, m_texture_buffer[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32UI);
1655 		glActiveTexture(GL_TEXTURE0);
1656 		glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer[1]);
1657 
1658 		glUseProgram(m_program);
1659 
1660 		// setup subroutines
1661 		GLuint indices[4];
1662 		indices[loc_compute0] = index_compute0;
1663 		indices[loc_compute1] = index_compute1;
1664 		indices[loc_compute2] = index_compute2;
1665 		indices[loc_compute3] = index_compute3;
1666 		glUniformSubroutinesuiv(GL_COMPUTE_SHADER, 4, indices);
1667 
1668 		glDispatchCompute(4, 1, 1);
1669 
1670 		std::vector<uvec4> data(64);
1671 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
1672 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1673 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(uvec4) * 64, &data[0]);
1674 
1675 		for (GLuint i = 0; i < 64; ++i)
1676 		{
1677 			if (!IsEqual(data[i], uvec4(i)))
1678 			{
1679 				m_context.getTestContext().getLog()
1680 					<< tcu::TestLog::Message << "Invalid value at index " << i << "." << tcu::TestLog::EndMessage;
1681 				return ERROR;
1682 			}
1683 		}
1684 
1685 		GLuint value;
1686 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomic_counter_buffer);
1687 		glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &value);
1688 		if (value != 16)
1689 		{
1690 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Final atomic counter value is " << value
1691 												<< " should be 16." << tcu::TestLog::EndMessage;
1692 			return ERROR;
1693 		}
1694 
1695 		return NO_ERROR;
1696 	}
1697 
Cleanup()1698 	virtual long Cleanup()
1699 	{
1700 		glUseProgram(0);
1701 		glDeleteProgram(m_program);
1702 		glDeleteBuffers(1, &m_atomic_counter_buffer);
1703 		glDeleteBuffers(2, m_storage_buffer);
1704 		glDeleteBuffers(2, m_buffer);
1705 		glDeleteTextures(2, m_texture_buffer);
1706 		return NO_ERROR;
1707 	}
1708 };
1709 
1710 class BasicResourceUniform : public ComputeShaderBase
1711 {
1712 
Title()1713 	virtual std::string Title()
1714 	{
1715 		return "Compute Shader resources - Uniforms";
1716 	}
1717 
Purpose()1718 	virtual std::string Purpose()
1719 	{
1720 		return NL "1. Verify that all types of uniform variables work as expected in CS." NL
1721 				  "2. Verify that uniform variables can be updated with Uniform* and ProgramUniform* commands." NL
1722 				  "3. Verify that re-linking CS program works as expected.";
1723 	}
1724 
Method()1725 	virtual std::string Method()
1726 	{
1727 		return NL "1. Create CS which uses all (single precision and integer) types of uniform variables." NL
1728 				  "2. Update uniform variables with ProgramUniform* commands." NL
1729 				  "3. Verify that uniform variables were updated correctly." NL "4. Re-link CS program." NL
1730 				  "5. Update uniform variables with Uniform* commands." NL
1731 				  "6. Verify that uniform variables were updated correctly.";
1732 	}
1733 
PassCriteria()1734 	virtual std::string PassCriteria()
1735 	{
1736 		return "Everything works as expected.";
1737 	}
1738 
1739 	GLuint m_program;
1740 	GLuint m_storage_buffer;
1741 
Setup()1742 	virtual long Setup()
1743 	{
1744 		m_program		 = 0;
1745 		m_storage_buffer = 0;
1746 		return NO_ERROR;
1747 	}
1748 
Run()1749 	virtual long Run()
1750 	{
1751 		const char* const glsl_cs = NL
1752 			"layout(local_size_x = 1) in;" NL "buffer Result {" NL "  int g_result;" NL "};" NL "uniform float g_0;" NL
1753 			"uniform vec2 g_1;" NL "uniform vec3 g_2;" NL "uniform vec4 g_3;" NL "uniform mat2 g_4;" NL
1754 			"uniform mat2x3 g_5;" NL "uniform mat2x4 g_6;" NL "uniform mat3x2 g_7;" NL "uniform mat3 g_8;" NL
1755 			"uniform mat3x4 g_9;" NL "uniform mat4x2 g_10;" NL "uniform mat4x3 g_11;" NL "uniform mat4 g_12;" NL
1756 			"uniform int g_13;" NL "uniform ivec2 g_14;" NL "uniform ivec3 g_15;" NL "uniform ivec4 g_16;" NL
1757 			"uniform uint g_17;" NL "uniform uvec2 g_18;" NL "uniform uvec3 g_19;" NL "uniform uvec4 g_20;" NL NL
1758 			"void main() {" NL "  g_result = 1;" NL NL "  if (g_0 != 1.0) g_result = 0;" NL
1759 			"  if (g_1 != vec2(2.0, 3.0)) g_result = 0;" NL "  if (g_2 != vec3(4.0, 5.0, 6.0)) g_result = 0;" NL
1760 			"  if (g_3 != vec4(7.0, 8.0, 9.0, 10.0)) g_result = 0;" NL NL
1761 			"  if (g_4 != mat2(11.0, 12.0, 13.0, 14.0)) g_result = 0;" NL
1762 			"  if (g_5 != mat2x3(15.0, 16.0, 17.0, 18.0, 19.0, 20.0)) g_result = 0;" NL
1763 			"  if (g_6 != mat2x4(21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0)) g_result = 0;" NL NL
1764 			"  if (g_7 != mat3x2(29.0, 30.0, 31.0, 32.0, 33.0, 34.0)) g_result = 0;" NL
1765 			"  if (g_8 != mat3(35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0)) g_result = 0;" NL
1766 			"  if (g_9 != mat3x4(44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0)) g_result = "
1767 			"0;" NL NL "  if (g_10 != mat4x2(56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0)) g_result = 0;" NL
1768 			"  if (g_11 != mat4x3(63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0)) g_result = "
1769 			"0;" NL "  if (g_12 != mat4(75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, "
1770 			"88.0, 89.0, 90.0)) g_result = 0;" NL NL "  if (g_13 != 91) g_result = 0;" NL
1771 			"  if (g_14 != ivec2(92, 93)) g_result = 0;" NL "  if (g_15 != ivec3(94, 95, 96)) g_result = 0;" NL
1772 			"  if (g_16 != ivec4(97, 98, 99, 100)) g_result = 0;" NL NL "  if (g_17 != 101u) g_result = 0;" NL
1773 			"  if (g_18 != uvec2(102u, 103u)) g_result = 0;" NL
1774 			"  if (g_19 != uvec3(104u, 105u, 106u)) g_result = 0;" NL
1775 			"  if (g_20 != uvec4(107u, 108u, 109u, 110u)) g_result = 0;" NL "}";
1776 		m_program = CreateComputeProgram(glsl_cs);
1777 		glLinkProgram(m_program);
1778 		if (!CheckProgram(m_program))
1779 			return ERROR;
1780 
1781 		glGenBuffers(1, &m_storage_buffer);
1782 		/* create buffer */
1783 		{
1784 			const int data = 123;
1785 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
1786 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
1787 		}
1788 
1789 		glProgramUniform1f(m_program, glGetUniformLocation(m_program, "g_0"), 1.0f);
1790 		glProgramUniform2f(m_program, glGetUniformLocation(m_program, "g_1"), 2.0f, 3.0f);
1791 		glProgramUniform3f(m_program, glGetUniformLocation(m_program, "g_2"), 4.0f, 5.0f, 6.0f);
1792 		glProgramUniform4f(m_program, glGetUniformLocation(m_program, "g_3"), 7.0f, 8.0f, 9.0f, 10.0f);
1793 
1794 		/* mat2 */
1795 		{
1796 			const GLfloat value[4] = { 11.0f, 12.0f, 13.0f, 14.0f };
1797 			glProgramUniformMatrix2fv(m_program, glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
1798 		}
1799 		/* mat2x3 */
1800 		{
1801 			const GLfloat value[6] = { 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f };
1802 			glProgramUniformMatrix2x3fv(m_program, glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
1803 		}
1804 		/* mat2x4 */
1805 		{
1806 			const GLfloat value[8] = { 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f };
1807 			glProgramUniformMatrix2x4fv(m_program, glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
1808 		}
1809 
1810 		/* mat3x2 */
1811 		{
1812 			const GLfloat value[6] = { 29.0f, 30.0f, 31.0f, 32.0f, 33.0f, 34.0f };
1813 			glProgramUniformMatrix3x2fv(m_program, glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
1814 		}
1815 		/* mat3 */
1816 		{
1817 			const GLfloat value[9] = { 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, 42.0f, 43.0f };
1818 			glProgramUniformMatrix3fv(m_program, glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
1819 		}
1820 		/* mat3x4 */
1821 		{
1822 			const GLfloat value[12] = { 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, 49.0f,
1823 										50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f };
1824 			glProgramUniformMatrix3x4fv(m_program, glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
1825 		}
1826 
1827 		/* mat4x2 */
1828 		{
1829 			const GLfloat value[8] = { 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f };
1830 			glProgramUniformMatrix4x2fv(m_program, glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
1831 		}
1832 		/* mat4x3 */
1833 		{
1834 			const GLfloat value[12] = {
1835 				63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, 27.0f, 73, 74.0f
1836 			};
1837 			glProgramUniformMatrix4x3fv(m_program, glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
1838 		}
1839 		/* mat4 */
1840 		{
1841 			const GLfloat value[16] = { 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, 80.0f, 81.0f, 82.0f,
1842 										83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, 90.0f };
1843 			glProgramUniformMatrix4fv(m_program, glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
1844 		}
1845 
1846 		glProgramUniform1i(m_program, glGetUniformLocation(m_program, "g_13"), 91);
1847 		glProgramUniform2i(m_program, glGetUniformLocation(m_program, "g_14"), 92, 93);
1848 		glProgramUniform3i(m_program, glGetUniformLocation(m_program, "g_15"), 94, 95, 96);
1849 		glProgramUniform4i(m_program, glGetUniformLocation(m_program, "g_16"), 97, 98, 99, 100);
1850 
1851 		glProgramUniform1ui(m_program, glGetUniformLocation(m_program, "g_17"), 101);
1852 		glProgramUniform2ui(m_program, glGetUniformLocation(m_program, "g_18"), 102, 103);
1853 		glProgramUniform3ui(m_program, glGetUniformLocation(m_program, "g_19"), 104, 105, 106);
1854 		glProgramUniform4ui(m_program, glGetUniformLocation(m_program, "g_20"), 107, 108, 109, 110);
1855 
1856 		glUseProgram(m_program);
1857 		glDispatchCompute(1, 1, 1);
1858 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1859 
1860 		{
1861 			int data;
1862 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
1863 			if (data != 1)
1864 			{
1865 				m_context.getTestContext().getLog()
1866 					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
1867 				return ERROR;
1868 			}
1869 		}
1870 
1871 		// re-link program (all uniforms will be set to zero)
1872 		glLinkProgram(m_program);
1873 
1874 		{
1875 			const int data = 123;
1876 			glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
1877 		}
1878 
1879 		glUniform1f(glGetUniformLocation(m_program, "g_0"), 1.0f);
1880 		glUniform2f(glGetUniformLocation(m_program, "g_1"), 2.0f, 3.0f);
1881 		glUniform3f(glGetUniformLocation(m_program, "g_2"), 4.0f, 5.0f, 6.0f);
1882 		glUniform4f(glGetUniformLocation(m_program, "g_3"), 7.0f, 8.0f, 9.0f, 10.0f);
1883 
1884 		/* mat2 */
1885 		{
1886 			const GLfloat value[4] = { 11.0f, 12.0f, 13.0f, 14.0f };
1887 			glUniformMatrix2fv(glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
1888 		}
1889 		/* mat2x3 */
1890 		{
1891 			const GLfloat value[6] = { 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f };
1892 			glUniformMatrix2x3fv(glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
1893 		}
1894 		/* mat2x4 */
1895 		{
1896 			const GLfloat value[8] = { 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f };
1897 			glUniformMatrix2x4fv(glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
1898 		}
1899 
1900 		/* mat3x2 */
1901 		{
1902 			const GLfloat value[6] = { 29.0f, 30.0f, 31.0f, 32.0f, 33.0f, 34.0f };
1903 			glUniformMatrix3x2fv(glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
1904 		}
1905 		/* mat3 */
1906 		{
1907 			const GLfloat value[9] = { 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, 42.0f, 43.0f };
1908 			glUniformMatrix3fv(glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
1909 		}
1910 		/* mat3x4 */
1911 		{
1912 			const GLfloat value[12] = { 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, 49.0f,
1913 										50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f };
1914 			glUniformMatrix3x4fv(glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
1915 		}
1916 
1917 		/* mat4x2 */
1918 		{
1919 			const GLfloat value[8] = { 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f };
1920 			glUniformMatrix4x2fv(glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
1921 		}
1922 		/* mat4x3 */
1923 		{
1924 			const GLfloat value[12] = {
1925 				63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, 27.0f, 73, 74.0f
1926 			};
1927 			glUniformMatrix4x3fv(glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
1928 		}
1929 		/* mat4 */
1930 		{
1931 			const GLfloat value[16] = { 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, 80.0f, 81.0f, 82.0f,
1932 										83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, 90.0f };
1933 			glUniformMatrix4fv(glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
1934 		}
1935 
1936 		glUniform1i(glGetUniformLocation(m_program, "g_13"), 91);
1937 		glUniform2i(glGetUniformLocation(m_program, "g_14"), 92, 93);
1938 		glUniform3i(glGetUniformLocation(m_program, "g_15"), 94, 95, 96);
1939 		glUniform4i(glGetUniformLocation(m_program, "g_16"), 97, 98, 99, 100);
1940 
1941 		glUniform1ui(glGetUniformLocation(m_program, "g_17"), 101);
1942 		glUniform2ui(glGetUniformLocation(m_program, "g_18"), 102, 103);
1943 		glUniform3ui(glGetUniformLocation(m_program, "g_19"), 104, 105, 106);
1944 		glUniform4ui(glGetUniformLocation(m_program, "g_20"), 107, 108, 109, 110);
1945 
1946 		glDispatchCompute(1, 1, 1);
1947 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1948 
1949 		/* validate */
1950 		{
1951 			int data;
1952 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
1953 			if (data != 1)
1954 			{
1955 				m_context.getTestContext().getLog()
1956 					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
1957 				return ERROR;
1958 			}
1959 		}
1960 
1961 		return NO_ERROR;
1962 	}
1963 
Cleanup()1964 	virtual long Cleanup()
1965 	{
1966 		glUseProgram(0);
1967 		glDeleteProgram(m_program);
1968 		glDeleteBuffers(1, &m_storage_buffer);
1969 		return NO_ERROR;
1970 	}
1971 };
1972 
1973 class BasicBuiltinVariables : public ComputeShaderBase
1974 {
1975 
Title()1976 	virtual std::string Title()
1977 	{
1978 		return "CS built-in variables";
1979 	}
1980 
Purpose()1981 	virtual std::string Purpose()
1982 	{
1983 		return NL "Verify that all (gl_WorkGroupSize, gl_WorkGroupID, gl_LocalInvocationID," NL
1984 				  "gl_GlobalInvocationID, gl_NumWorkGroups, gl_WorkGroupSize)" NL
1985 				  "CS built-in variables has correct values.";
1986 	}
1987 
Method()1988 	virtual std::string Method()
1989 	{
1990 		return NL "1. Create CS which writes all built-in variables to SSBO." NL
1991 				  "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
1992 				  "3. Verify SSBO content." NL "4. Repeat for several different local and global work sizes.";
1993 	}
1994 
PassCriteria()1995 	virtual std::string PassCriteria()
1996 	{
1997 		return "Everything works as expected.";
1998 	}
1999 
2000 	GLuint m_program;
2001 	GLuint m_storage_buffer;
2002 	GLuint m_dispatch_buffer;
2003 
GenSource(const uvec3 & local_size,const uvec3 & num_groups)2004 	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
2005 	{
2006 		const uvec3		  global_size = local_size * num_groups;
2007 		std::stringstream ss;
2008 		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
2009 		   << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
2010 		   << ", " << global_size.y() << ", " << global_size.z()
2011 		   << ");" NL "layout(std430) buffer OutputBuffer {" NL "  uvec4 num_work_groups["
2012 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 work_group_size["
2013 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 work_group_id["
2014 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 local_invocation_id["
2015 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 global_invocation_id["
2016 		   << global_size.x() * global_size.y() * global_size.z() << "];" NL "  uvec4 local_invocation_index["
2017 		   << global_size.x() * global_size.y() * global_size.z()
2018 		   << "];" NL "} g_out_buffer;" NL "void main() {" NL
2019 			  "  if ((gl_WorkGroupSize * gl_WorkGroupID + gl_LocalInvocationID) != gl_GlobalInvocationID) return;" NL
2020 			  "  const uint global_index = gl_GlobalInvocationID.x +" NL
2021 			  "                            gl_GlobalInvocationID.y * kGlobalSize.x +" NL
2022 			  "                            gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
2023 			  "  g_out_buffer.num_work_groups[global_index] = uvec4(gl_NumWorkGroups, 0);" NL
2024 			  "  g_out_buffer.work_group_size[global_index] = uvec4(gl_WorkGroupSize, 0);" NL
2025 			  "  g_out_buffer.work_group_id[global_index] = uvec4(gl_WorkGroupID, 0);" NL
2026 			  "  g_out_buffer.local_invocation_id[global_index] = uvec4(gl_LocalInvocationID, 0);" NL
2027 			  "  g_out_buffer.global_invocation_id[global_index] = uvec4(gl_GlobalInvocationID, 0);" NL
2028 			  "  g_out_buffer.local_invocation_index[global_index] = uvec4(gl_LocalInvocationIndex);" NL "}";
2029 		return ss.str();
2030 	}
2031 
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)2032 	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
2033 	{
2034 		if (m_program != 0)
2035 			glDeleteProgram(m_program);
2036 		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
2037 		glLinkProgram(m_program);
2038 		if (!CheckProgram(m_program))
2039 			return false;
2040 
2041 		const GLuint kBufferSize =
2042 			local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
2043 
2044 		std::vector<uvec4> data(kBufferSize * 6);
2045 		if (m_storage_buffer == 0)
2046 			glGenBuffers(1, &m_storage_buffer);
2047 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2048 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * kBufferSize * 6, &data[0], GL_DYNAMIC_DRAW);
2049 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2050 
2051 		glUseProgram(m_program);
2052 		if (dispatch_indirect)
2053 		{
2054 			if (m_dispatch_buffer == 0)
2055 				glGenBuffers(1, &m_dispatch_buffer);
2056 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
2057 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
2058 			glDispatchComputeIndirect(0);
2059 		}
2060 		else
2061 		{
2062 			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
2063 		}
2064 
2065 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
2066 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2067 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(uvec4) * kBufferSize * 6, &data[0]);
2068 
2069 		// gl_NumWorkGroups
2070 		for (GLuint index = 0; index < kBufferSize; ++index)
2071 		{
2072 			if (!IsEqual(data[index], uvec4(num_groups.x(), num_groups.y(), num_groups.z(), 0)))
2073 			{
2074 				m_context.getTestContext().getLog()
2075 					<< tcu::TestLog::Message << "gl_NumWorkGroups: Invalid data at index " << index << "."
2076 					<< tcu::TestLog::EndMessage;
2077 				return false;
2078 			}
2079 		}
2080 		// gl_WorkGroupSize
2081 		for (GLuint index = kBufferSize; index < 2 * kBufferSize; ++index)
2082 		{
2083 			if (!IsEqual(data[index], uvec4(local_size.x(), local_size.y(), local_size.z(), 0)))
2084 			{
2085 				m_context.getTestContext().getLog()
2086 					<< tcu::TestLog::Message << "gl_WorkGroupSize: Invalid data at index " << index << "."
2087 					<< tcu::TestLog::EndMessage;
2088 				return false;
2089 			}
2090 		}
2091 		// gl_WorkGroupID
2092 		for (GLuint index = 2 * kBufferSize; index < 3 * kBufferSize; ++index)
2093 		{
2094 			uvec3 expected = IndexTo3DCoord(index - 2 * kBufferSize, local_size.x() * num_groups.x(),
2095 											local_size.y() * num_groups.y());
2096 			expected.x() /= local_size.x();
2097 			expected.y() /= local_size.y();
2098 			expected.z() /= local_size.z();
2099 			if (!IsEqual(data[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
2100 			{
2101 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "gl_WorkGroupID: Invalid data at index "
2102 													<< index << "." << tcu::TestLog::EndMessage;
2103 				return false;
2104 			}
2105 		}
2106 		// gl_LocalInvocationID
2107 		for (GLuint index = 3 * kBufferSize; index < 4 * kBufferSize; ++index)
2108 		{
2109 			uvec3 expected = IndexTo3DCoord(index - 3 * kBufferSize, local_size.x() * num_groups.x(),
2110 											local_size.y() * num_groups.y());
2111 			expected.x() %= local_size.x();
2112 			expected.y() %= local_size.y();
2113 			expected.z() %= local_size.z();
2114 			if (!IsEqual(data[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
2115 			{
2116 				m_context.getTestContext().getLog()
2117 					<< tcu::TestLog::Message << "gl_LocalInvocationID: Invalid data at index " << index << "."
2118 					<< tcu::TestLog::EndMessage;
2119 				return false;
2120 			}
2121 		}
2122 		// gl_GlobalInvocationID
2123 		for (GLuint index = 4 * kBufferSize; index < 5 * kBufferSize; ++index)
2124 		{
2125 			uvec3 expected = IndexTo3DCoord(index - 4 * kBufferSize, local_size.x() * num_groups.x(),
2126 											local_size.y() * num_groups.y());
2127 			if (!IsEqual(data[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
2128 			{
2129 				m_context.getTestContext().getLog()
2130 					<< tcu::TestLog::Message << "gl_GlobalInvocationID: Invalid data at index " << index << "."
2131 					<< tcu::TestLog::EndMessage;
2132 				return false;
2133 			}
2134 		}
2135 		// gl_LocalInvocationIndex
2136 		for (GLuint index = 5 * kBufferSize; index < 6 * kBufferSize; ++index)
2137 		{
2138 			uvec3 coord = IndexTo3DCoord(index - 5 * kBufferSize, local_size.x() * num_groups.x(),
2139 										 local_size.y() * num_groups.y());
2140 			const GLuint expected = (coord.x() % local_size.x()) + (coord.y() % local_size.y()) * local_size.x() +
2141 									(coord.z() % local_size.z()) * local_size.x() * local_size.y();
2142 			if (!IsEqual(data[index], uvec4(expected)))
2143 			{
2144 				m_context.getTestContext().getLog()
2145 					<< tcu::TestLog::Message << "gl_LocalInvocationIndex: Invalid data at index " << index << "."
2146 					<< tcu::TestLog::EndMessage;
2147 				return false;
2148 			}
2149 		}
2150 		return true;
2151 	}
2152 
Setup()2153 	virtual long Setup()
2154 	{
2155 		m_program		  = 0;
2156 		m_storage_buffer  = 0;
2157 		m_dispatch_buffer = 0;
2158 		return NO_ERROR;
2159 	}
2160 
Run()2161 	virtual long Run()
2162 	{
2163 		if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
2164 			return ERROR;
2165 		if (!RunIteration(uvec3(1, 1, 64), uvec3(1, 5, 2), true))
2166 			return ERROR;
2167 		if (!RunIteration(uvec3(1, 1, 4), uvec3(2, 2, 2), false))
2168 			return ERROR;
2169 		if (!RunIteration(uvec3(3, 2, 1), uvec3(1, 2, 3), true))
2170 			return ERROR;
2171 		if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
2172 			return ERROR;
2173 		if (!RunIteration(uvec3(2, 4, 7), uvec3(2, 1, 4), true))
2174 			return ERROR;
2175 		return NO_ERROR;
2176 	}
2177 
Cleanup()2178 	virtual long Cleanup()
2179 	{
2180 		glUseProgram(0);
2181 		glDeleteProgram(m_program);
2182 		glDeleteBuffers(1, &m_storage_buffer);
2183 		glDeleteBuffers(1, &m_dispatch_buffer);
2184 		return NO_ERROR;
2185 	}
2186 };
2187 
2188 class BasicMax : public ComputeShaderBase
2189 {
2190 
Title()2191 	virtual std::string Title()
2192 	{
2193 		return NL "CS max values";
2194 	}
2195 
Purpose()2196 	virtual std::string Purpose()
2197 	{
2198 		return NL "Verify (on the API and GLSL side) that all GL_MAX_COMPUTE_* values are not less than" NL
2199 				  "required by the OpenGL specification.";
2200 	}
2201 
Method()2202 	virtual std::string Method()
2203 	{
2204 		return NL "1. Use all API commands to query all GL_MAX_COMPUTE_* values. Verify that they are correct." NL
2205 				  "2. Verify all gl_MaxCompute* constants in the GLSL.";
2206 	}
2207 
PassCriteria()2208 	virtual std::string PassCriteria()
2209 	{
2210 		return NL "Everything works as expected.";
2211 	}
2212 
2213 	GLuint m_program;
2214 	GLuint m_buffer;
2215 
CheckIndexed(GLenum target,const GLint * min_values)2216 	bool CheckIndexed(GLenum target, const GLint* min_values)
2217 	{
2218 		GLint	 i;
2219 		GLint64   i64;
2220 		GLfloat   f;
2221 		GLdouble  d;
2222 		GLboolean b;
2223 
2224 		for (GLuint c = 0; c < 3; c++)
2225 		{
2226 			glGetIntegeri_v(target, c, &i);
2227 			if (i < min_values[c])
2228 			{
2229 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << i << " should be at least "
2230 													<< min_values[c] << "." << tcu::TestLog::EndMessage;
2231 				return false;
2232 			}
2233 		}
2234 		for (GLuint c = 0; c < 3; c++)
2235 		{
2236 			glGetInteger64i_v(target, c, &i64);
2237 			if (i64 < static_cast<GLint64>(min_values[c]))
2238 			{
2239 				m_context.getTestContext().getLog()
2240 					<< tcu::TestLog::Message << "Is " << i64 << " should be at least "
2241 					<< static_cast<GLint64>(min_values[c]) << "." << tcu::TestLog::EndMessage;
2242 				return false;
2243 			}
2244 		}
2245 		for (GLuint c = 0; c < 3; c++)
2246 		{
2247 			glGetFloati_v(target, c, &f);
2248 			if (f < static_cast<GLfloat>(min_values[c]))
2249 			{
2250 				m_context.getTestContext().getLog()
2251 					<< tcu::TestLog::Message << "Is " << f << " should be at least "
2252 					<< static_cast<GLfloat>(min_values[c]) << "." << tcu::TestLog::EndMessage;
2253 				return false;
2254 			}
2255 		}
2256 		for (GLuint c = 0; c < 3; c++)
2257 		{
2258 			glGetDoublei_v(target, c, &d);
2259 			if (d < static_cast<GLdouble>(min_values[c]))
2260 			{
2261 				m_context.getTestContext().getLog()
2262 					<< tcu::TestLog::Message << "Is " << d << " should be at least "
2263 					<< static_cast<GLdouble>(min_values[c]) << "." << tcu::TestLog::EndMessage;
2264 				return false;
2265 			}
2266 		}
2267 		for (GLuint c = 0; c < 3; c++)
2268 		{
2269 			glGetBooleani_v(target, c, &b);
2270 			if (b != (min_values[c] ? GL_TRUE : GL_FALSE))
2271 			{
2272 				m_context.getTestContext().getLog()
2273 					<< tcu::TestLog::Message << "Is " << b << " should be " << (min_values[c] ? GL_TRUE : GL_FALSE)
2274 					<< "." << tcu::TestLog::EndMessage;
2275 				return false;
2276 			}
2277 		}
2278 
2279 		return true;
2280 	}
2281 
Check(GLenum target,const GLint min_value)2282 	bool Check(GLenum target, const GLint min_value)
2283 	{
2284 		GLint	 i;
2285 		GLint64   i64;
2286 		GLfloat   f;
2287 		GLdouble  d;
2288 		GLboolean b;
2289 
2290 		glGetIntegerv(target, &i);
2291 		if (i < min_value)
2292 		{
2293 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << i << " should be at least "
2294 												<< min_value << "." << tcu::TestLog::EndMessage;
2295 			return false;
2296 		}
2297 		glGetInteger64v(target, &i64);
2298 		if (i64 < static_cast<GLint64>(min_value))
2299 		{
2300 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << i64 << " should be at least "
2301 												<< static_cast<GLint64>(min_value) << "." << tcu::TestLog::EndMessage;
2302 			return false;
2303 		}
2304 		glGetFloatv(target, &f);
2305 		if (f < static_cast<GLfloat>(min_value))
2306 		{
2307 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << f << " should be at least "
2308 												<< static_cast<GLfloat>(min_value) << "." << tcu::TestLog::EndMessage;
2309 			return false;
2310 		}
2311 		glGetDoublev(target, &d);
2312 		if (d < static_cast<GLdouble>(min_value))
2313 		{
2314 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << d << " should be at least "
2315 												<< static_cast<GLdouble>(min_value) << "." << tcu::TestLog::EndMessage;
2316 			return false;
2317 		}
2318 		glGetBooleanv(target, &b);
2319 		if (b != (min_value ? GL_TRUE : GL_FALSE))
2320 		{
2321 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << b << " should be "
2322 												<< (min_value ? GL_TRUE : GL_FALSE) << "." << tcu::TestLog::EndMessage;
2323 			return false;
2324 		}
2325 
2326 		return true;
2327 	}
2328 
Setup()2329 	virtual long Setup()
2330 	{
2331 		m_program = 0;
2332 		m_buffer  = 0;
2333 		return NO_ERROR;
2334 	}
2335 
Run()2336 	virtual long Run()
2337 	{
2338 		const GLint work_group_count[3] = { 65535, 65535, 65535 };
2339 		if (!CheckIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, work_group_count))
2340 			return ERROR;
2341 
2342 		const GLint work_group_size[3] = { 1024, 1024, 64 };
2343 		if (!CheckIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, work_group_size))
2344 			return ERROR;
2345 
2346 		if (!Check(GL_MAX_COMPUTE_UNIFORM_BLOCKS, 12))
2347 			return ERROR;
2348 		if (!Check(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, 16))
2349 			return ERROR;
2350 		if (!Check(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, 8))
2351 			return ERROR;
2352 		if (!Check(GL_MAX_COMPUTE_ATOMIC_COUNTERS, 8))
2353 			return ERROR;
2354 		if (!Check(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, 32768))
2355 			return ERROR;
2356 
2357 		if (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
2358 		{
2359 			if (!Check(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 1024))
2360 				return ERROR;
2361 		}
2362 		else
2363 		{
2364 			if (!Check(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 512))
2365 				return ERROR;
2366 		}
2367 
2368 		if (!Check(GL_MAX_COMPUTE_IMAGE_UNIFORMS, 8))
2369 			return ERROR;
2370 		if (!Check(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, 512))
2371 			return ERROR;
2372 
2373 		const char* const glsl_cs =
2374 			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  int g_output;" NL "};" NL
2375 			   "uniform ivec3 MaxComputeWorkGroupCount;" NL "uniform ivec3 MaxComputeWorkGroupSize;" NL
2376 			   "uniform int MaxComputeUniformComponents;" NL "uniform int MaxComputeTextureImageUnits;" NL
2377 			   "uniform int MaxComputeImageUniforms;" NL "uniform int MaxComputeAtomicCounters;" NL
2378 			   "uniform int MaxComputeAtomicCounterBuffers;" NL "void main() {" NL "  g_output = 1;" NL
2379 			   "  if (MaxComputeWorkGroupCount != gl_MaxComputeWorkGroupCount) g_output = 0;" NL
2380 			   "  if (MaxComputeWorkGroupSize != gl_MaxComputeWorkGroupSize) g_output = 0;" NL
2381 			   "  if (MaxComputeUniformComponents != gl_MaxComputeUniformComponents) g_output = 0;" NL
2382 			   "  if (MaxComputeTextureImageUnits != gl_MaxComputeTextureImageUnits) g_output = 0;" NL
2383 			   "  if (MaxComputeImageUniforms != gl_MaxComputeImageUniforms) g_output = 0;" NL
2384 			   "  if (MaxComputeAtomicCounters != gl_MaxComputeAtomicCounters) g_output = 0;" NL
2385 			   "  if (MaxComputeAtomicCounterBuffers != gl_MaxComputeAtomicCounterBuffers) g_output = 0;" NL "}";
2386 		m_program = CreateComputeProgram(glsl_cs);
2387 		glLinkProgram(m_program);
2388 		if (!CheckProgram(m_program))
2389 			return ERROR;
2390 		glUseProgram(m_program);
2391 
2392 		GLint p[3];
2393 		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &p[0]);
2394 		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &p[1]);
2395 		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &p[2]);
2396 		glUniform3i(glGetUniformLocation(m_program, "MaxComputeWorkGroupCount"), p[0], p[1], p[2]);
2397 
2398 		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &p[0]);
2399 		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &p[1]);
2400 		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &p[2]);
2401 		glUniform3iv(glGetUniformLocation(m_program, "MaxComputeWorkGroupSize"), 1, p);
2402 
2403 		glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, p);
2404 		glUniform1i(glGetUniformLocation(m_program, "MaxComputeUniformComponents"), p[0]);
2405 
2406 		glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, p);
2407 		glUniform1iv(glGetUniformLocation(m_program, "MaxComputeTextureImageUnits"), 1, p);
2408 
2409 		glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, p);
2410 		glUniform1i(glGetUniformLocation(m_program, "MaxComputeImageUniforms"), p[0]);
2411 
2412 		glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, p);
2413 		glUniform1i(glGetUniformLocation(m_program, "MaxComputeAtomicCounters"), p[0]);
2414 
2415 		glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, p);
2416 		glUniform1i(glGetUniformLocation(m_program, "MaxComputeAtomicCounterBuffers"), p[0]);
2417 
2418 		GLint data = 0xffff;
2419 		glGenBuffers(1, &m_buffer);
2420 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
2421 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint), &data, GL_DYNAMIC_DRAW);
2422 
2423 		glDispatchCompute(1, 1, 1);
2424 
2425 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2426 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint), &data);
2427 
2428 		return data == 1 ? NO_ERROR : ERROR;
2429 	}
Cleanup()2430 	virtual long Cleanup()
2431 	{
2432 		glUseProgram(0);
2433 		glDeleteProgram(m_program);
2434 		glDeleteBuffers(1, &m_buffer);
2435 		return NO_ERROR;
2436 	}
2437 };
2438 
2439 class BasicBuildMonolithic : public ComputeShaderBase
2440 {
2441 
Title()2442 	virtual std::string Title()
2443 	{
2444 		return "Building CS monolithic program";
2445 	}
2446 
Purpose()2447 	virtual std::string Purpose()
2448 	{
2449 		return NL "1. Verify that building monolithic CS program works as expected." NL
2450 				  "2. Verify that program consisting from 3 compilation units links as expected." NL
2451 				  "3. Verify that CS consisting from 2 strings compiles as expected.";
2452 	}
2453 
Method()2454 	virtual std::string Method()
2455 	{
2456 		return NL "1. Create, compile and link CS using CreateShader, CompileShader and LinkProgram commands." NL
2457 				  "2. Dispatch and verify CS program.";
2458 	}
2459 
PassCriteria()2460 	virtual std::string PassCriteria()
2461 	{
2462 		return "Everything works as expected.";
2463 	}
2464 
Run()2465 	virtual long Run()
2466 	{
2467 		const char* const cs1[2] = { "#version 430 core",
2468 
2469 									 NL "layout(local_size_x = 1) in;" NL "void Run();" NL "void main() {" NL
2470 										"  Run();" NL "}" };
2471 
2472 		const char* const cs2 =
2473 			"#version 430 core" NL "layout(binding = 0, std430) buffer Output {" NL "  vec4 g_output;" NL "};" NL
2474 			"vec4 CalculateOutput();" NL "void Run() {" NL "  g_output = CalculateOutput();" NL "}";
2475 
2476 		const char* const cs3 =
2477 			"#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(binding = 0, std430) buffer Output {" NL
2478 			"  vec4 g_output;" NL "};" NL "vec4 CalculateOutput() {" NL "  g_output = vec4(0);" NL
2479 			"  return vec4(1, 2, 3, 4);" NL "}";
2480 
2481 		const GLuint sh1 = glCreateShader(GL_COMPUTE_SHADER);
2482 
2483 		GLint type;
2484 		glGetShaderiv(sh1, GL_SHADER_TYPE, &type);
2485 		if (static_cast<GLenum>(type) != GL_COMPUTE_SHADER)
2486 		{
2487 			m_context.getTestContext().getLog()
2488 				<< tcu::TestLog::Message << "SHADER_TYPE should be COMPUTE_SHADER." << tcu::TestLog::EndMessage;
2489 			glDeleteShader(sh1);
2490 			return false;
2491 		}
2492 
2493 		glShaderSource(sh1, 2, cs1, NULL);
2494 		glCompileShader(sh1);
2495 
2496 		const GLuint sh2 = glCreateShader(GL_COMPUTE_SHADER);
2497 		glShaderSource(sh2, 1, &cs2, NULL);
2498 		glCompileShader(sh2);
2499 
2500 		const GLuint sh3 = glCreateShader(GL_COMPUTE_SHADER);
2501 		glShaderSource(sh3, 1, &cs3, NULL);
2502 		glCompileShader(sh3);
2503 
2504 		const GLuint p = glCreateProgram();
2505 		glAttachShader(p, sh1);
2506 		glAttachShader(p, sh2);
2507 		glAttachShader(p, sh3);
2508 		glLinkProgram(p);
2509 
2510 		glDeleteShader(sh1);
2511 		glDeleteShader(sh2);
2512 		glDeleteShader(sh3);
2513 
2514 		bool res = CheckProgram(p);
2515 
2516 		GLuint buffer;
2517 		glGenBuffers(1, &buffer);
2518 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer);
2519 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), &vec4(0.0f)[0], GL_DYNAMIC_DRAW);
2520 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2521 
2522 		glUseProgram(p);
2523 		glDispatchCompute(1, 1, 1);
2524 
2525 		vec4 data;
2526 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
2527 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2528 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &data[0]);
2529 		if (!IsEqual(data, vec4(1.0f, 2.0f, 3.0f, 4.0f)))
2530 		{
2531 			m_context.getTestContext().getLog()
2532 				<< tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
2533 			res = false;
2534 		}
2535 
2536 		glDeleteBuffers(1, &buffer);
2537 		glUseProgram(0);
2538 		glDeleteProgram(p);
2539 
2540 		return res == true ? NO_ERROR : ERROR;
2541 	}
2542 };
2543 
2544 class BasicBuildSeparable : public ComputeShaderBase
2545 {
2546 
Title()2547 	virtual std::string Title()
2548 	{
2549 		return "Building CS separable program";
2550 	}
2551 
Purpose()2552 	virtual std::string Purpose()
2553 	{
2554 		return NL "1. Verify that building separable CS program works as expected." NL
2555 				  "2. Verify that program consisting from 4 strings works as expected.";
2556 	}
2557 
Method()2558 	virtual std::string Method()
2559 	{
2560 		return NL "1. Create, compile and link CS using CreateShaderProgramv command." NL
2561 				  "2. Dispatch and verify CS program.";
2562 	}
2563 
PassCriteria()2564 	virtual std::string PassCriteria()
2565 	{
2566 		return "Everything works as expected.";
2567 	}
2568 
Run()2569 	virtual long Run()
2570 	{
2571 		const char* const cs[4] = {
2572 			"#version 430 core",
2573 
2574 			NL "layout(local_size_x = 1) in;" NL "void Run();" NL "void main() {" NL "  Run();" NL "}",
2575 			NL "layout(binding = 0, std430) buffer Output {" NL "  vec4 g_output;" NL "};" NL
2576 			   "vec4 CalculateOutput();" NL "void Run() {" NL "  g_output = CalculateOutput();" NL "}",
2577 			NL "vec4 CalculateOutput() {" NL "  g_output = vec4(0);" NL "  return vec4(1, 2, 3, 4);" NL "}"
2578 		};
2579 
2580 		const GLuint p   = glCreateShaderProgramv(GL_COMPUTE_SHADER, 4, cs);
2581 		bool		 res = CheckProgram(p);
2582 
2583 		GLuint buffer;
2584 		glGenBuffers(1, &buffer);
2585 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer);
2586 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), &vec4(0.0f)[0], GL_DYNAMIC_DRAW);
2587 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2588 
2589 		glUseProgram(p);
2590 		glDispatchCompute(1, 1, 1);
2591 
2592 		vec4 data;
2593 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
2594 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2595 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &data[0]);
2596 		if (!IsEqual(data, vec4(1.0f, 2.0f, 3.0f, 4.0f)))
2597 		{
2598 			m_context.getTestContext().getLog()
2599 				<< tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
2600 			res = false;
2601 		}
2602 
2603 		glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &vec4(0.0f)[0]);
2604 
2605 		GLuint pipeline;
2606 		glGenProgramPipelines(1, &pipeline);
2607 		glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, p);
2608 
2609 		glUseProgram(0);
2610 		glBindProgramPipeline(pipeline);
2611 		glDispatchCompute(1, 1, 1);
2612 
2613 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2614 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &data[0]);
2615 		if (!IsEqual(data, vec4(1.0f, 2.0f, 3.0f, 4.0f)))
2616 		{
2617 			m_context.getTestContext().getLog()
2618 				<< tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
2619 			res = false;
2620 		}
2621 
2622 		glDeleteProgramPipelines(1, &pipeline);
2623 		glDeleteBuffers(1, &buffer);
2624 		glDeleteProgram(p);
2625 
2626 		return res == true ? NO_ERROR : ERROR;
2627 	}
2628 };
2629 
2630 class BasicSharedSimple : public ComputeShaderBase
2631 {
Title()2632 	virtual std::string Title()
2633 	{
2634 		return "Shared Memory - simple usage";
2635 	}
2636 
Purpose()2637 	virtual std::string Purpose()
2638 	{
2639 		return NL "1. Verify that shared array of uints works as expected." NL
2640 				  "2. Verify that shared memory written by one invocation is observable by other invocations" NL
2641 				  "    when groupMemoryBarrier() and barrier() built-in functions are used.";
2642 	}
2643 
Method()2644 	virtual std::string Method()
2645 	{
2646 		return NL "1. Create and dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
2647 				  "2. Verify results written by CS to SSBO." NL
2648 				  "3. Repeat for several different number of work groups.";
2649 	}
2650 
PassCriteria()2651 	virtual std::string PassCriteria()
2652 	{
2653 		return "Everything works as expected.";
2654 	}
2655 
2656 	GLuint m_program;
2657 	GLuint m_storage_buffer;
2658 	GLuint m_dispatch_buffer;
2659 
RunIteration(const GLuint num_groups,bool dispatch_indirect)2660 	bool RunIteration(const GLuint num_groups, bool dispatch_indirect)
2661 	{
2662 		const GLuint kBufferSize = 256 * num_groups;
2663 
2664 		std::vector<GLuint> data(kBufferSize, 0xffff);
2665 		if (m_storage_buffer == 0)
2666 			glGenBuffers(1, &m_storage_buffer);
2667 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2668 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
2669 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2670 
2671 		glUseProgram(m_program);
2672 		if (dispatch_indirect)
2673 		{
2674 			const GLuint groups[3] = { num_groups, 1, 1 };
2675 			if (m_dispatch_buffer == 0)
2676 				glGenBuffers(1, &m_dispatch_buffer);
2677 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
2678 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(groups), groups, GL_STATIC_DRAW);
2679 			glDispatchComputeIndirect(0);
2680 		}
2681 		else
2682 		{
2683 			glDispatchCompute(num_groups, 1, 1);
2684 		}
2685 
2686 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
2687 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2688 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, &data[0]);
2689 		for (GLuint i = 0; i < kBufferSize; ++i)
2690 		{
2691 			if (data[i] != 1)
2692 			{
2693 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
2694 													<< data[i] << " should be 1." << tcu::TestLog::EndMessage;
2695 				return false;
2696 			}
2697 		}
2698 		return true;
2699 	}
2700 
Setup()2701 	virtual long Setup()
2702 	{
2703 		m_program		  = 0;
2704 		m_storage_buffer  = 0;
2705 		m_dispatch_buffer = 0;
2706 		return NO_ERROR;
2707 	}
2708 
Run()2709 	virtual long Run()
2710 	{
2711 		const char* const glsl_cs =
2712 			NL "layout(local_size_x = 256) in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
2713 			   "shared uint g_shared_data[256];" NL "void main() {" NL
2714 			   "  g_shared_data[gl_LocalInvocationID.x] = gl_LocalInvocationIndex;" NL
2715 			   "  groupMemoryBarrier();" // flush memory stores
2716 			NL "  barrier();"			 // wait for all stores to finish
2717 			NL "  g_output[gl_GlobalInvocationID.x] = 1;" NL "  if (gl_LocalInvocationIndex < 255) {" NL
2718 			   "    const uint res = g_shared_data[gl_LocalInvocationID.x + "
2719 			   "1];" // load data from shared memory filled by other thread
2720 			NL "    if (res != (gl_LocalInvocationIndex + 1)) {" NL "      g_output[gl_GlobalInvocationID.x] = 0;" NL
2721 			   "    }" NL "  }" NL "}";
2722 		m_program = CreateComputeProgram(glsl_cs);
2723 		glLinkProgram(m_program);
2724 		if (!CheckProgram(m_program))
2725 			return ERROR;
2726 
2727 		if (!RunIteration(1, false))
2728 			return ERROR;
2729 		if (!RunIteration(8, true))
2730 			return ERROR;
2731 		if (!RunIteration(13, false))
2732 			return ERROR;
2733 		if (!RunIteration(7, true))
2734 			return ERROR;
2735 		return NO_ERROR;
2736 	}
Cleanup()2737 	virtual long Cleanup()
2738 	{
2739 		glUseProgram(0);
2740 		glDeleteProgram(m_program);
2741 		glDeleteBuffers(1, &m_storage_buffer);
2742 		glDeleteBuffers(1, &m_dispatch_buffer);
2743 		return NO_ERROR;
2744 	}
2745 };
2746 
2747 class BasicSharedStruct : public ComputeShaderBase
2748 {
Title()2749 	virtual std::string Title()
2750 	{
2751 		return "Shared Memory - arrays and structers";
2752 	}
2753 
Purpose()2754 	virtual std::string Purpose()
2755 	{
2756 		return NL "1. Verify that vectors, matrices, structers and arrays of those can be used" NL
2757 				  "    as a shared memory." NL
2758 				  "2. Verify that shared memory can be indexed with constant values, built-in" NL
2759 				  "    variables and dynamic expressions." NL
2760 				  "3. Verify that memoryBarrierAtomicCounter(), memoryBarrierImage(), memoryBarrier()," NL
2761 				  "     memoryBarrierBuffer() and memoryBarrierShared() built-in functions are accepted" NL
2762 				  "     by the GLSL compiler.";
2763 	}
2764 
Method()2765 	virtual std::string Method()
2766 	{
2767 		return NL "1. Create and dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
2768 				  "2. Verify results written by CS to SSBO.";
2769 	}
2770 
PassCriteria()2771 	virtual std::string PassCriteria()
2772 	{
2773 		return "Everything works as expected.";
2774 	}
2775 
2776 	GLuint m_program;
2777 	GLuint m_storage_buffer;
2778 	GLuint m_dispatch_buffer;
2779 
RunIteration(bool dispatch_indirect)2780 	bool RunIteration(bool dispatch_indirect)
2781 	{
2782 		const GLuint kBufferSize = 256;
2783 
2784 		std::vector<vec4> data(kBufferSize);
2785 		if (m_storage_buffer == 0)
2786 			glGenBuffers(1, &m_storage_buffer);
2787 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2788 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
2789 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2790 
2791 		glUseProgram(m_program);
2792 		if (dispatch_indirect)
2793 		{
2794 			const GLuint groups[3] = { 1, 1, 1 };
2795 			if (m_dispatch_buffer == 0)
2796 				glGenBuffers(1, &m_dispatch_buffer);
2797 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
2798 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(groups), groups, GL_STATIC_DRAW);
2799 			glDispatchComputeIndirect(0);
2800 		}
2801 		else
2802 		{
2803 			glDispatchCompute(1, 1, 1);
2804 		}
2805 
2806 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
2807 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2808 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize, &data[0]);
2809 		for (GLuint i = 0; i < kBufferSize; ++i)
2810 		{
2811 			if (!IsEqual(data[i], vec4(static_cast<float>(i))))
2812 			{
2813 				m_context.getTestContext().getLog()
2814 					<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
2815 				return false;
2816 			}
2817 		}
2818 		return true;
2819 	}
2820 
Setup()2821 	virtual long Setup()
2822 	{
2823 		m_program		  = 0;
2824 		m_storage_buffer  = 0;
2825 		m_dispatch_buffer = 0;
2826 		return NO_ERROR;
2827 	}
2828 
Run()2829 	virtual long Run()
2830 	{
2831 		const char* const glsl_cs = NL
2832 			"layout(local_size_x = 128) in;" NL "layout(std430) buffer Output {" NL "  vec4 g_output[256];" NL "};" NL
2833 			"struct SubData {" NL "  mat2x4 data;" NL "};" NL "struct Data {" NL "  uint index;" NL "  vec3 data0;" NL
2834 			"  SubData data1;" NL "};" NL "shared Data g_shared_data[256];" NL "shared int g_shared_buf[2];" NL
2835 			"void main() {" NL "  if (gl_LocalInvocationID.x == 0) {" NL "    g_shared_buf[1] = 1;" NL
2836 			"    g_shared_buf[1 + gl_LocalInvocationID.x] = 0;" NL "    g_shared_buf[0] = 128;" NL
2837 			"    g_output[0] = vec4(g_shared_buf[1]);" NL "    g_output[128] = vec4(g_shared_buf[0]);" NL
2838 			"    memoryBarrierBuffer();" // note: this call is not needed here, just check if compiler accepts it
2839 			NL "  } else {" NL "    const uint index = gl_LocalInvocationIndex;" NL
2840 			"    g_shared_data[index].index = index;" NL "    g_shared_data[index + 128].index = index + 128;" NL
2841 			"    g_shared_data[index].data1.data = mat2x4(0.0);" NL
2842 			"    g_shared_data[index + 128].data1.data = mat2x4(0.0);" NL
2843 			"    g_output[index] = vec4(g_shared_data[index].index);" // load data from shared memory
2844 			NL "    g_output[index + 128] = vec4(g_shared_data[index + 128].index);" NL
2845 			"    memoryBarrierShared();" // note: this call is not needed here, just check if compiler accepts it
2846 			NL "  }" NL "  memoryBarrierAtomicCounter();" NL "  memoryBarrierImage();" NL
2847 			"  memoryBarrier();" // note: these calls are not needed here, just check if compiler accepts them
2848 			NL "}";
2849 		m_program = CreateComputeProgram(glsl_cs);
2850 		glLinkProgram(m_program);
2851 		if (!CheckProgram(m_program))
2852 			return ERROR;
2853 
2854 		if (!RunIteration(false))
2855 			return ERROR;
2856 		if (!RunIteration(true))
2857 			return ERROR;
2858 		return NO_ERROR;
2859 	}
2860 
Cleanup()2861 	virtual long Cleanup()
2862 	{
2863 		glUseProgram(0);
2864 		glDeleteProgram(m_program);
2865 		glDeleteBuffers(1, &m_storage_buffer);
2866 		glDeleteBuffers(1, &m_dispatch_buffer);
2867 		return NO_ERROR;
2868 	}
2869 };
2870 
2871 class BasicDispatchIndirect : public ComputeShaderBase
2872 {
Title()2873 	virtual std::string Title()
2874 	{
2875 		return NL "DispatchComputeIndirect command";
2876 	}
2877 
Purpose()2878 	virtual std::string Purpose()
2879 	{
2880 		return NL
2881 			"1. Verify that DispatchComputeIndirect command works as described in the OpenGL specification." NL
2882 			"2. Verify that <offset> parameter is correctly applied." NL
2883 			"3. Verify that updating dispatch buffer with different methods (BufferData, BufferSubData, MapBuffer)" NL
2884 			"    just before DispatchComputeIndirect call works as expected." NL
2885 			"4. Verify that GL_DISPATCH_INDIRECT_BUFFER_BINDING binding point is set correctly.";
2886 	}
2887 
Method()2888 	virtual std::string Method()
2889 	{
2890 		return NL
2891 			"1. Create CS and dispatch indirect buffer." NL "2. Dispatch CS with DispatchComputeIndirect command." NL
2892 			"3. Update dispatch indirect buffer." NL
2893 			"4. Repeat several times updating dispatch buffer with different methods and changing <offset> parameter.";
2894 	}
2895 
PassCriteria()2896 	virtual std::string PassCriteria()
2897 	{
2898 		return NL "Everything works as expected.";
2899 	}
2900 
2901 	GLuint m_program;
2902 	GLuint m_storage_buffer;
2903 	GLuint m_dispatch_buffer[2];
2904 
RunIteration(GLintptr offset,GLuint buffer_size)2905 	bool RunIteration(GLintptr offset, GLuint buffer_size)
2906 	{
2907 		std::vector<GLuint> data(buffer_size);
2908 		if (m_storage_buffer == 0)
2909 			glGenBuffers(1, &m_storage_buffer);
2910 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2911 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * buffer_size, &data[0], GL_DYNAMIC_DRAW);
2912 
2913 		glDispatchComputeIndirect(offset);
2914 
2915 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2916 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * buffer_size, &data[0]);
2917 		for (GLuint i = 0; i < buffer_size; ++i)
2918 		{
2919 			if (data[i] != i)
2920 			{
2921 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
2922 													<< data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
2923 				return false;
2924 			}
2925 		}
2926 		return true;
2927 	}
2928 
CheckBinding(GLuint expected)2929 	bool CheckBinding(GLuint expected)
2930 	{
2931 		GLint	 i;
2932 		GLint64   i64;
2933 		GLfloat   f;
2934 		GLdouble  d;
2935 		GLboolean b;
2936 
2937 		glGetIntegerv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &i);
2938 		if (i != static_cast<GLint>(expected))
2939 		{
2940 			return false;
2941 		}
2942 		glGetInteger64v(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &i64);
2943 		if (i64 != static_cast<GLint64>(expected))
2944 		{
2945 			return false;
2946 		}
2947 		glGetFloatv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &f);
2948 		if (f != static_cast<GLfloat>(expected))
2949 		{
2950 			return false;
2951 		}
2952 		glGetDoublev(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &d);
2953 		if (d != static_cast<GLdouble>(expected))
2954 		{
2955 			return false;
2956 		}
2957 		glGetBooleanv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &b);
2958 		if (b != (expected ? GL_TRUE : GL_FALSE))
2959 		{
2960 			return false;
2961 		}
2962 
2963 		return true;
2964 	}
2965 
Setup()2966 	virtual long Setup()
2967 	{
2968 		m_program		 = 0;
2969 		m_storage_buffer = 0;
2970 		memset(m_dispatch_buffer, 0, sizeof(m_dispatch_buffer));
2971 		return NO_ERROR;
2972 	}
2973 
Run()2974 	virtual long Run()
2975 	{
2976 		const char* const glsl_cs =
2977 			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
2978 			   "uniform uvec3 g_global_size;" NL "void main() {" NL
2979 			   "  const uint global_index = gl_GlobalInvocationID.x +" NL
2980 			   "                            gl_GlobalInvocationID.y * g_global_size.x +" NL
2981 			   "                            gl_GlobalInvocationID.z * g_global_size.x * g_global_size.y;" NL
2982 			   "  if (gl_NumWorkGroups != g_global_size) {" NL "    g_output[global_index] = 0xffff;" NL
2983 			   "    return;" NL "  }" NL "  g_output[global_index] = global_index;" NL "}";
2984 		m_program = CreateComputeProgram(glsl_cs);
2985 		glLinkProgram(m_program);
2986 		if (!CheckProgram(m_program))
2987 			return ERROR;
2988 
2989 		if (!CheckBinding(0))
2990 			return ERROR;
2991 
2992 		glGenBuffers(2, m_dispatch_buffer);
2993 
2994 		const GLuint data[]  = { 1, 2, 3, 4, 5, 6, 7, 8 };
2995 		const GLuint data2[] = { 3, 1, 4, 4 };
2996 
2997 		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[0]);
2998 		glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), data, GL_STREAM_DRAW);
2999 		if (!CheckBinding(m_dispatch_buffer[0]))
3000 			return ERROR;
3001 
3002 		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[1]);
3003 		glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data2), data2, GL_STREAM_READ);
3004 		if (!CheckBinding(m_dispatch_buffer[1]))
3005 			return ERROR;
3006 
3007 		glUseProgram(m_program);
3008 		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[0]);
3009 
3010 		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 2, 3);
3011 		if (!RunIteration(0, 6))
3012 			return ERROR;
3013 
3014 		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 2, 3, 4);
3015 		if (!RunIteration(4, 24))
3016 			return ERROR;
3017 
3018 		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 4, 5, 6);
3019 		if (!RunIteration(12, 120))
3020 			return ERROR;
3021 
3022 		glBufferSubData(GL_DISPATCH_INDIRECT_BUFFER, 20, 12, data);
3023 		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 2, 3);
3024 		if (!RunIteration(20, 6))
3025 			return ERROR;
3026 
3027 		GLuint* ptr = static_cast<GLuint*>(glMapBuffer(GL_DISPATCH_INDIRECT_BUFFER, GL_WRITE_ONLY));
3028 		*ptr++		= 4;
3029 		*ptr++		= 4;
3030 		*ptr++		= 4;
3031 		glUnmapBuffer(GL_DISPATCH_INDIRECT_BUFFER);
3032 
3033 		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 4, 4, 4);
3034 		if (!RunIteration(0, 64))
3035 			return ERROR;
3036 
3037 		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[1]);
3038 
3039 		glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 4, 4);
3040 		if (!RunIteration(4, 16))
3041 			return ERROR;
3042 
3043 		glDeleteBuffers(2, m_dispatch_buffer);
3044 		memset(m_dispatch_buffer, 0, sizeof(m_dispatch_buffer));
3045 
3046 		if (!CheckBinding(0))
3047 			return ERROR;
3048 
3049 		return NO_ERROR;
3050 	}
Cleanup()3051 	virtual long Cleanup()
3052 	{
3053 		glUseProgram(0);
3054 		glDeleteProgram(m_program);
3055 		glDeleteBuffers(1, &m_storage_buffer);
3056 		glDeleteBuffers(2, m_dispatch_buffer);
3057 		return NO_ERROR;
3058 	}
3059 };
3060 
3061 class BasicSSOComputePipeline : public ComputeShaderBase
3062 {
Title()3063 	virtual std::string Title()
3064 	{
3065 		return NL "Separable CS Programs - Compute and non-compute stages (1)";
3066 	}
Purpose()3067 	virtual std::string Purpose()
3068 	{
3069 		return NL "1. Verify that compute and non-compute stages can be attached to one pipeline object." NL
3070 				  "2. Verify that DrawArrays and ComputeDispatch commands works as expected in this case.";
3071 	}
Method()3072 	virtual std::string Method()
3073 	{
3074 		return NL "1. Create VS, FS and CS. Attach all created stages to one pipeline object." NL
3075 				  "2. Bind pipeline object." NL "3. Invoke compute stage with DispatchCompute commmand." NL
3076 				  "4. Issue MemoryBarrier command." NL
3077 				  "5. Issue DrawArrays command which uses data written by the compute stage." NL "6. Verify result.";
3078 	}
PassCriteria()3079 	virtual std::string PassCriteria()
3080 	{
3081 		return NL "Everything works as expected.";
3082 	}
3083 
3084 	GLuint m_vsp, m_fsp, m_csp;
3085 	GLuint m_storage_buffer;
3086 	GLuint m_vertex_array;
3087 	GLuint m_pipeline;
3088 
Setup()3089 	virtual long Setup()
3090 	{
3091 		m_vsp = m_fsp = m_csp = 0;
3092 		m_storage_buffer	  = 0;
3093 		m_vertex_array		  = 0;
3094 		m_pipeline			  = 0;
3095 		return NO_ERROR;
3096 	}
Run()3097 	virtual long Run()
3098 	{
3099 		const char* const glsl_cs =
3100 			NL "layout(local_size_x = 4) in;" NL "layout(std430) buffer Output {" NL "  vec4 g_output[4];" NL "};" NL
3101 			   "void main() {" NL "  const vec2 quad[4] = { vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1) };" NL
3102 			   "  g_output[gl_GlobalInvocationID.x] = vec4(quad[gl_GlobalInvocationID.x], 0, 1);" NL "}";
3103 
3104 		m_csp = CreateComputeProgram(glsl_cs);
3105 		glProgramParameteri(m_csp, GL_PROGRAM_SEPARABLE, GL_TRUE);
3106 		glLinkProgram(m_csp);
3107 		if (!CheckProgram(m_csp))
3108 			return ERROR;
3109 
3110 		const char* const glsl_vs =
3111 			NL "layout(location = 0) in vec4 i_position;" NL "out gl_PerVertex {" NL "  vec4 gl_Position;" NL "};" NL
3112 			   "void main() {" NL "  gl_Position = i_position;" NL "}";
3113 		m_vsp = BuildShaderProgram(GL_VERTEX_SHADER, glsl_vs);
3114 		if (!CheckProgram(m_vsp))
3115 			return ERROR;
3116 
3117 		const char* const glsl_fs =
3118 			NL "layout(location = 0) out vec4 o_color;" NL "void main() {" NL "  o_color = vec4(0, 1, 0, 1);" NL "}";
3119 		m_fsp = BuildShaderProgram(GL_FRAGMENT_SHADER, glsl_fs);
3120 		if (!CheckProgram(m_fsp))
3121 			return ERROR;
3122 
3123 		glGenProgramPipelines(1, &m_pipeline);
3124 		glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, m_vsp);
3125 		glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, m_fsp);
3126 		glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_csp);
3127 
3128 		glGenBuffers(1, &m_storage_buffer);
3129 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
3130 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * 4, NULL, GL_DYNAMIC_DRAW);
3131 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3132 
3133 		glGenVertexArrays(1, &m_vertex_array);
3134 		glBindVertexArray(m_vertex_array);
3135 		glBindBuffer(GL_ARRAY_BUFFER, m_storage_buffer);
3136 		glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
3137 		glBindBuffer(GL_ARRAY_BUFFER, 0);
3138 		glEnableVertexAttribArray(0);
3139 		glBindVertexArray(0);
3140 
3141 		glBindProgramPipeline(m_pipeline);
3142 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
3143 		glDispatchCompute(1, 1, 1);
3144 
3145 		glClear(GL_COLOR_BUFFER_BIT);
3146 		glBindVertexArray(m_vertex_array);
3147 		glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
3148 		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3149 
3150 		if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
3151 			return ERROR;
3152 		return NO_ERROR;
3153 	}
3154 
Cleanup()3155 	virtual long Cleanup()
3156 	{
3157 		glDeleteProgram(m_vsp);
3158 		glDeleteProgram(m_fsp);
3159 		glDeleteProgram(m_csp);
3160 		glDeleteBuffers(1, &m_storage_buffer);
3161 		glDeleteVertexArrays(1, &m_vertex_array);
3162 		glDeleteProgramPipelines(1, &m_pipeline);
3163 		return NO_ERROR;
3164 	}
3165 };
3166 
3167 class BasicSSOCase2 : public ComputeShaderBase
3168 {
Title()3169 	virtual std::string Title()
3170 	{
3171 		return NL "Separable CS Programs - Compute and non-compute stages (2)";
3172 	}
Purpose()3173 	virtual std::string Purpose()
3174 	{
3175 		return NL "1. Verify that data computed by the compute stage is visible to non-compute stage after "
3176 				  "MemoryBarrier command." NL "2. Verify that ProgramParameteri(program, GL_PROGRAM_SEPARABLE, "
3177 				  "GL_TRUE) command works correctly for CS." NL
3178 				  "3. Verify that gl_WorkGroupSize built-in variable is a contant and can be used as an array size.";
3179 	}
Method()3180 	virtual std::string Method()
3181 	{
3182 		return NL "1. Create VS, FS and CS. Attach all created stages to one pipeline object." NL
3183 				  "2. Bind pipeline object." NL "3. Invoke compute stage with DispatchCompute commmand." NL
3184 				  "4. Issue MemoryBarrier command." NL
3185 				  "5. Issue DrawArrays command which uses data written to the buffer object by the compute stage." NL
3186 				  "6. Verify result.";
3187 	}
PassCriteria()3188 	virtual std::string PassCriteria()
3189 	{
3190 		return NL "Everything works as expected.";
3191 	}
3192 
3193 	GLuint m_program_ab;
3194 	GLuint m_program_c;
3195 	GLuint m_pipeline;
3196 	GLuint m_storage_buffer;
3197 	GLuint m_vao;
3198 
Setup()3199 	virtual long Setup()
3200 	{
3201 		m_program_ab	 = 0;
3202 		m_program_c		 = 0;
3203 		m_pipeline		 = 0;
3204 		m_storage_buffer = 0;
3205 		m_vao			 = 0;
3206 		return NO_ERROR;
3207 	}
Run()3208 	virtual long Run()
3209 	{
3210 		GLint res;
3211 		glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
3212 		if (res <= 0)
3213 		{
3214 			OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
3215 			return NO_ERROR;
3216 		}
3217 
3218 		const char* const glsl_a =
3219 			"#version 430 core" NL "layout(binding = 1, std430) buffer Input {" NL "  vec2 g_input[4];" NL "};" NL
3220 			"out StageData {" NL "  vec3 color;" NL "} g_vs_out;" NL "out gl_PerVertex {" NL "  vec4 gl_Position;" NL
3221 			"};" NL "void main() {" NL "  gl_Position = vec4(g_input[gl_VertexID], 0, 1);" NL
3222 			"  g_vs_out.color = vec3(0, 1, 0);" NL "}";
3223 
3224 		const char* const glsl_b =
3225 			"#version 430 core" NL "in StageData {" NL "  vec3 color;" NL "} g_fs_in;" NL
3226 			"layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(g_fs_in.color, 1);" NL "}";
3227 
3228 		const char* const glsl_c =
3229 			"#version 430 core" NL "layout(local_size_x = 4) in;" NL "layout(binding = 1, std430) buffer Output {" NL
3230 			"  vec2 g_output[gl_WorkGroupSize.x];" NL "};" NL "void main() {" NL
3231 			"  if (gl_GlobalInvocationID.x == 0) {" NL "    g_output[0] = vec2(-0.8, -0.8);" NL
3232 			"  } else if (gl_GlobalInvocationID.x == 1) {" NL "    g_output[1] = vec2(0.8, -0.8);" NL
3233 			"  } else if (gl_GlobalInvocationID.x == 2) {" NL "    g_output[2] = vec2(-0.8, 0.8);" NL
3234 			"  } else if (gl_GlobalInvocationID.x == 3) {" NL "    g_output[3] = vec2(0.8, 0.8);" NL "  }" NL "}";
3235 
3236 		m_program_ab = glCreateProgram();
3237 		GLuint sh	= glCreateShader(GL_VERTEX_SHADER);
3238 		glAttachShader(m_program_ab, sh);
3239 		glDeleteShader(sh);
3240 		glShaderSource(sh, 1, &glsl_a, NULL);
3241 		glCompileShader(sh);
3242 
3243 		sh = glCreateShader(GL_FRAGMENT_SHADER);
3244 		glAttachShader(m_program_ab, sh);
3245 		glDeleteShader(sh);
3246 		glShaderSource(sh, 1, &glsl_b, NULL);
3247 		glCompileShader(sh);
3248 
3249 		glProgramParameteri(m_program_ab, GL_PROGRAM_SEPARABLE, GL_TRUE);
3250 		glLinkProgram(m_program_ab);
3251 
3252 		m_program_c = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_c);
3253 		glGenVertexArrays(1, &m_vao);
3254 		glGenProgramPipelines(1, &m_pipeline);
3255 		glUseProgramStages(m_pipeline, GL_ALL_SHADER_BITS, m_program_ab);
3256 		glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program_c);
3257 
3258 		glGenBuffers(1, &m_storage_buffer);
3259 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer);
3260 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec2) * 4, NULL, GL_STREAM_DRAW);
3261 
3262 		glClear(GL_COLOR_BUFFER_BIT);
3263 		glBindProgramPipeline(m_pipeline);
3264 		glDispatchCompute(1, 1, 1);
3265 		glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
3266 		glBindVertexArray(m_vao);
3267 		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3268 
3269 		if (getWindowWidth() < 500 &&
3270 			!ValidateReadBufferCenteredQuad(getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)))
3271 		{
3272 			return ERROR;
3273 		}
3274 		return NO_ERROR;
3275 	}
Cleanup()3276 	virtual long Cleanup()
3277 	{
3278 		glDeleteProgram(m_program_ab);
3279 		glDeleteProgram(m_program_c);
3280 		glDeleteProgramPipelines(1, &m_pipeline);
3281 		glDeleteBuffers(1, &m_storage_buffer);
3282 		glDeleteVertexArrays(1, &m_vao);
3283 		return NO_ERROR;
3284 	}
3285 };
3286 
3287 class BasicSSOCase3 : public ComputeShaderBase
3288 {
Title()3289 	virtual std::string Title()
3290 	{
3291 		return NL "Separable CS Programs - Compute stage";
3292 	}
Purpose()3293 	virtual std::string Purpose()
3294 	{
3295 		return NL "Verify that compute shader stage selected with UseProgram command has precedence" NL
3296 				  "over compute shader stage selected with BindProgramPipeline command.";
3297 	}
Method()3298 	virtual std::string Method()
3299 	{
3300 		return NL "1. Create CS0 with CreateProgram command. Create CS1 with CreateShaderProgramv command." NL
3301 				  "2. Verify that CS program selected with UseProgram is dispatched even if there is active" NL
3302 				  "    compute stage bound by BindProgramPipeline.";
3303 	}
PassCriteria()3304 	virtual std::string PassCriteria()
3305 	{
3306 		return NL "Everything works as expected.";
3307 	}
3308 
3309 	GLuint m_program_a;
3310 	GLuint m_program_b;
3311 	GLuint m_pipeline;
3312 	GLuint m_storage_buffer;
3313 
Setup()3314 	virtual long Setup()
3315 	{
3316 		m_program_a		 = 0;
3317 		m_program_b		 = 0;
3318 		m_pipeline		 = 0;
3319 		m_storage_buffer = 0;
3320 		return NO_ERROR;
3321 	}
Run()3322 	virtual long Run()
3323 	{
3324 		const char* const glsl_a =
3325 			"#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(binding = 3, std430) buffer Output {" NL
3326 			"  int g_output;" NL "};" NL "void main() {" NL "  g_output = 1;" NL "}";
3327 
3328 		const char* const glsl_b =
3329 			"#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(binding = 3, std430) buffer Output {" NL
3330 			"  int g_output;" NL "};" NL "void main() {" NL "  g_output = 2;" NL "}";
3331 
3332 		/* create program A */
3333 		{
3334 			m_program_a = glCreateProgram();
3335 			GLuint sh   = glCreateShader(GL_COMPUTE_SHADER);
3336 			glAttachShader(m_program_a, sh);
3337 			glDeleteShader(sh);
3338 			glShaderSource(sh, 1, &glsl_a, NULL);
3339 			glCompileShader(sh);
3340 			glProgramParameteri(m_program_a, GL_PROGRAM_SEPARABLE, GL_TRUE);
3341 			glLinkProgram(m_program_a);
3342 		}
3343 		m_program_b = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_b);
3344 
3345 		/* create storage buffer */
3346 		{
3347 			int data = 0;
3348 			glGenBuffers(1, &m_storage_buffer);
3349 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_storage_buffer);
3350 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int), &data, GL_STREAM_READ);
3351 		}
3352 
3353 		glGenProgramPipelines(1, &m_pipeline);
3354 		glUseProgramStages(m_pipeline, GL_ALL_SHADER_BITS, m_program_b);
3355 
3356 		glUseProgram(m_program_a);
3357 		glBindProgramPipeline(m_pipeline);
3358 		glDispatchCompute(1, 1, 1);
3359 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3360 
3361 		/* validate */
3362 		{
3363 			int data;
3364 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
3365 			if (data != 1)
3366 			{
3367 				m_context.getTestContext().getLog()
3368 					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
3369 				return ERROR;
3370 			}
3371 		}
3372 
3373 		glUseProgram(0);
3374 		glDispatchCompute(1, 1, 1);
3375 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3376 
3377 		/* validate */
3378 		{
3379 			int data;
3380 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
3381 			if (data != 2)
3382 			{
3383 				m_context.getTestContext().getLog()
3384 					<< tcu::TestLog::Message << "Data is " << data << " should be 2." << tcu::TestLog::EndMessage;
3385 				return ERROR;
3386 			}
3387 		}
3388 
3389 		glUseProgram(m_program_b);
3390 		glDispatchCompute(1, 1, 1);
3391 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3392 
3393 		/* validate */
3394 		{
3395 			int data;
3396 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
3397 			if (data != 2)
3398 			{
3399 				m_context.getTestContext().getLog()
3400 					<< tcu::TestLog::Message << "Data is " << data << " should be 2." << tcu::TestLog::EndMessage;
3401 				return ERROR;
3402 			}
3403 		}
3404 
3405 		glUseProgram(0);
3406 		glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program_a);
3407 		glDispatchCompute(1, 1, 1);
3408 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3409 
3410 		/* validate */
3411 		{
3412 			int data;
3413 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
3414 			if (data != 1)
3415 			{
3416 				m_context.getTestContext().getLog()
3417 					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
3418 				return ERROR;
3419 			}
3420 		}
3421 
3422 		return NO_ERROR;
3423 	}
Cleanup()3424 	virtual long Cleanup()
3425 	{
3426 		glDeleteProgram(m_program_a);
3427 		glDeleteProgram(m_program_b);
3428 		glDeleteProgramPipelines(1, &m_pipeline);
3429 		glDeleteBuffers(1, &m_storage_buffer);
3430 		return NO_ERROR;
3431 	}
3432 };
3433 
3434 class BasicAtomicCase1 : public ComputeShaderBase
3435 {
Title()3436 	virtual std::string Title()
3437 	{
3438 		return NL "Atomic functions";
3439 	}
Purpose()3440 	virtual std::string Purpose()
3441 	{
3442 		return NL "1. Verify that atomicAdd function works as expected with int and uint parameters." NL
3443 				  "2. Verify that shared memory can be used with atomic functions." NL
3444 				  "3. Verify that groupMemoryBarrier() and barrier() built-in functions work as expected.";
3445 	}
Method()3446 	virtual std::string Method()
3447 	{
3448 		return NL "1. Use shared memory as a 'counter' with-in one CS work group." NL
3449 				  "2. Each shader invocation increments/decrements 'counter' value using atomicAdd function." NL
3450 				  "3. Values returned by atomicAdd function are written to SSBO." NL
3451 				  "4. Verify SSBO content (values from 0 to 7 should be written).";
3452 	}
PassCriteria()3453 	virtual std::string PassCriteria()
3454 	{
3455 		return NL "Everything works as expected.";
3456 	}
3457 
3458 	GLuint m_program;
3459 	GLuint m_storage_buffer;
3460 
Setup()3461 	virtual long Setup()
3462 	{
3463 		m_program		 = 0;
3464 		m_storage_buffer = 0;
3465 		return NO_ERROR;
3466 	}
Run()3467 	virtual long Run()
3468 	{
3469 		const char* const glsl_cs =
3470 			NL "layout(local_size_x = 8) in;" NL "layout(std430, binding = 0) buffer Output {" NL
3471 			   "  uint g_add_output[8];" NL "  int g_sub_output[8];" NL "};" NL "shared uint g_add_value;" NL
3472 			   "shared int g_sub_value;" NL "void main() {" NL "  if (gl_LocalInvocationIndex == 0) {" NL
3473 			   "    g_add_value = 0u;" NL "    g_sub_value = 7;" NL "  }" NL
3474 			   "  g_add_output[gl_LocalInvocationIndex] = 0u;" NL "  g_sub_output[gl_LocalInvocationIndex] = 0;" NL
3475 			   "  groupMemoryBarrier();" NL "  barrier();" NL
3476 			   "  g_add_output[gl_LocalInvocationIndex] = atomicAdd(g_add_value, 1u);" NL
3477 			   "  g_sub_output[gl_LocalInvocationIndex] = atomicAdd(g_sub_value, -1);" NL "}";
3478 		m_program = CreateComputeProgram(glsl_cs);
3479 		glLinkProgram(m_program);
3480 		if (!CheckProgram(m_program))
3481 			return ERROR;
3482 
3483 		glGenBuffers(1, &m_storage_buffer);
3484 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
3485 		glBufferData(GL_SHADER_STORAGE_BUFFER, 16 * sizeof(int), NULL, GL_STATIC_DRAW);
3486 
3487 		glUseProgram(m_program);
3488 		glDispatchCompute(1, 1, 1);
3489 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3490 
3491 		std::vector<int> data(8);
3492 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int) * 8, &data[0]);
3493 		std::sort(data.begin(), data.end());
3494 		for (int i = 0; i < 8; ++i)
3495 		{
3496 			if (data[i] != i)
3497 			{
3498 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3499 													<< data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
3500 				return ERROR;
3501 			}
3502 		}
3503 
3504 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(int) * 8, sizeof(int) * 8, &data[0]);
3505 		std::sort(data.begin(), data.end());
3506 		for (int i = 0; i < 8; ++i)
3507 		{
3508 			if (data[i] != i)
3509 			{
3510 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3511 													<< data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
3512 				return ERROR;
3513 			}
3514 		}
3515 
3516 		return NO_ERROR;
3517 	}
Cleanup()3518 	virtual long Cleanup()
3519 	{
3520 		glUseProgram(0);
3521 		glDeleteProgram(m_program);
3522 		glDeleteBuffers(1, &m_storage_buffer);
3523 		return NO_ERROR;
3524 	}
3525 };
3526 
3527 class BasicAtomicCase2 : public ComputeShaderBase
3528 {
Title()3529 	virtual std::string Title()
3530 	{
3531 		return NL "Atomic functions - buffer variables";
3532 	}
Purpose()3533 	virtual std::string Purpose()
3534 	{
3535 		return NL "1. Verify that all atomic functions (atomicExchange, atomicMin, atomicMax," NL
3536 				  "    atomicAnd, atomicOr, atomicXor and atomicCompSwap) works as expected with buffer variables." NL
3537 				  "2. Verify that atomic functions work with parameters being constants and" NL
3538 				  "    with parameters being uniforms." NL
3539 				  "3. Verify that barrier() built-in function can be used in a control flow.";
3540 	}
Method()3541 	virtual std::string Method()
3542 	{
3543 		return NL "1. Create CS that uses all atomic functions. Values returned by the atomic functions are written to "
3544 				  "SSBO." NL "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
3545 				  "3. Verify SSBO content." NL
3546 				  "4. Repeat for different number of work groups and different work group sizes.";
3547 	}
PassCriteria()3548 	virtual std::string PassCriteria()
3549 	{
3550 		return NL "Everything works as expected.";
3551 	}
3552 
3553 	GLuint m_program;
3554 	GLuint m_storage_buffer[2];
3555 	GLuint m_dispatch_buffer;
3556 
GenSource(const uvec3 & local_size,const uvec3 & num_groups)3557 	std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
3558 	{
3559 		const uvec3		  global_size = local_size * num_groups;
3560 		std::stringstream ss;
3561 		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
3562 		   << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
3563 		   << ", " << global_size.y() << ", " << global_size.z()
3564 		   << ");" NL "layout(std430, binding = 0) buffer OutputU {" NL "  uint g_uint_out["
3565 		   << global_size.x() * global_size.y() * global_size.z()
3566 		   << "];" NL "};" NL "layout(std430, binding = 1) buffer OutputI {" NL "  int data["
3567 		   << global_size.x() * global_size.y() * global_size.z()
3568 		   << "];" NL "} g_int_out;" NL
3569 			  "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL "void main() {" NL
3570 			  "  const uint global_index = gl_GlobalInvocationID.x +" NL
3571 			  "                            gl_GlobalInvocationID.y * kGlobalSize.x +" NL
3572 			  "                            gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
3573 			  "  atomicExchange(g_uint_out[global_index], g_uint_value[0]);" NL
3574 			  "  atomicMin(g_uint_out[global_index], g_uint_value[1]);" NL
3575 			  "  atomicMax(g_uint_out[global_index], g_uint_value[2]);" NL
3576 			  "  atomicAnd(g_uint_out[global_index], g_uint_value[3]);" NL
3577 			  "  atomicOr(g_uint_out[global_index], g_uint_value[4]);" NL "  if (g_uint_value[0] > 0u) {" NL
3578 			  "    barrier();" // not needed here, just check if compiler accepts it in a control flow
3579 			NL "    atomicXor(g_uint_out[global_index], g_uint_value[5]);" NL "  }" NL
3580 			  "  atomicCompSwap(g_uint_out[global_index], g_uint_value[6], g_uint_value[7]);" NL NL
3581 			  "  atomicExchange(g_int_out.data[global_index], 3);" NL "  atomicMin(g_int_out.data[global_index], 1);" NL
3582 			  "  atomicMax(g_int_out.data[global_index], 2);" NL "  atomicAnd(g_int_out.data[global_index], 0x1);" NL
3583 			  "  atomicOr(g_int_out.data[global_index], 0x3);" NL "  atomicXor(g_int_out.data[global_index], 0x1);" NL
3584 			  "  atomicCompSwap(g_int_out.data[global_index], 0x2, 0x7);" NL "}";
3585 		return ss.str();
3586 	}
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)3587 	bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
3588 	{
3589 		if (m_program != 0)
3590 			glDeleteProgram(m_program);
3591 		m_program = CreateComputeProgram(GenSource(local_size, num_groups));
3592 		glLinkProgram(m_program);
3593 		if (!CheckProgram(m_program))
3594 			return false;
3595 
3596 		const GLuint kBufferSize =
3597 			local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
3598 
3599 		if (m_storage_buffer[0] == 0)
3600 			glGenBuffers(2, m_storage_buffer);
3601 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
3602 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, NULL, GL_DYNAMIC_DRAW);
3603 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
3604 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint) * kBufferSize, NULL, GL_DYNAMIC_DRAW);
3605 
3606 		glUseProgram(m_program);
3607 		if (dispatch_indirect)
3608 		{
3609 			if (m_dispatch_buffer == 0)
3610 				glGenBuffers(1, &m_dispatch_buffer);
3611 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
3612 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
3613 			glDispatchComputeIndirect(0);
3614 		}
3615 		else
3616 		{
3617 			glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
3618 		}
3619 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3620 
3621 		std::vector<GLuint> udata(kBufferSize);
3622 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
3623 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, &udata[0]);
3624 		for (GLuint i = 0; i < kBufferSize; ++i)
3625 		{
3626 			if (udata[i] != 7)
3627 			{
3628 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is "
3629 													<< udata[i] << " should be 7." << tcu::TestLog::EndMessage;
3630 				return false;
3631 			}
3632 		}
3633 
3634 		std::vector<GLint> idata(kBufferSize);
3635 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
3636 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint) * kBufferSize, &idata[0]);
3637 		for (GLint i = 0; i < static_cast<GLint>(kBufferSize); ++i)
3638 		{
3639 			if (idata[i] != 7)
3640 			{
3641 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3642 													<< idata[i] << " should be 7." << tcu::TestLog::EndMessage;
3643 				return false;
3644 			}
3645 		}
3646 
3647 		return true;
3648 	}
Setup()3649 	virtual long Setup()
3650 	{
3651 		m_program			= 0;
3652 		m_storage_buffer[0] = m_storage_buffer[1] = 0;
3653 		m_dispatch_buffer						  = 0;
3654 		return NO_ERROR;
3655 	}
Run()3656 	virtual long Run()
3657 	{
3658 		if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
3659 			return ERROR;
3660 		if (!RunIteration(uvec3(1, 1, 64), uvec3(1, 5, 2), true))
3661 			return ERROR;
3662 		if (!RunIteration(uvec3(1, 1, 4), uvec3(2, 2, 2), false))
3663 			return ERROR;
3664 		if (!RunIteration(uvec3(3, 2, 1), uvec3(1, 2, 3), true))
3665 			return ERROR;
3666 		if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
3667 			return ERROR;
3668 		if (!RunIteration(uvec3(2, 4, 7), uvec3(2, 1, 4), true))
3669 			return ERROR;
3670 		return NO_ERROR;
3671 	}
Cleanup()3672 	virtual long Cleanup()
3673 	{
3674 		glUseProgram(0);
3675 		glDeleteProgram(m_program);
3676 		glDeleteBuffers(2, m_storage_buffer);
3677 		glDeleteBuffers(1, &m_dispatch_buffer);
3678 		return NO_ERROR;
3679 	}
3680 };
3681 
3682 class BasicAtomicCase3 : public ComputeShaderBase
3683 {
Title()3684 	virtual std::string Title()
3685 	{
3686 		return NL "Atomic functions - shared variables";
3687 	}
Purpose()3688 	virtual std::string Purpose()
3689 	{
3690 		return NL "1. Verify that all atomic functions (atomicExchange, atomicMin, atomicMax," NL
3691 				  "    atomicAnd, atomicOr, atomicXor and atomicCompSwap) works as expected with shared variables." NL
3692 				  "2. Verify that atomic functions work with parameters being constants and" NL
3693 				  "    with parameters being uniforms." NL
3694 				  "3. Verify that atomic functions can be used in a control flow.";
3695 	}
Method()3696 	virtual std::string Method()
3697 	{
3698 		return NL "1. Create CS that uses all atomic functions. Values returned by the atomic functions are written to "
3699 				  "SSBO." NL "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
3700 				  "3. Verify SSBO content." NL
3701 				  "4. Repeat for different number of work groups and different work group sizes.";
3702 	}
PassCriteria()3703 	virtual std::string PassCriteria()
3704 	{
3705 		return NL "Everything works as expected.";
3706 	}
3707 
3708 	GLuint m_program;
3709 	GLuint m_storage_buffer;
3710 	GLuint m_dispatch_buffer;
3711 
GenSource(const uvec3 & local_size)3712 	std::string GenSource(const uvec3& local_size)
3713 	{
3714 		std::stringstream ss;
3715 		ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
3716 		   << ", local_size_z = " << local_size.z()
3717 		   << ") in;" NL "layout(std430, binding = 0) buffer Output {" NL "  uint g_uint_out["
3718 		   << local_size.x() * local_size.y() * local_size.z() << "];" NL "  int g_int_out["
3719 		   << local_size.x() * local_size.y() * local_size.z() << "];" NL "};" NL "shared uint g_shared_uint["
3720 		   << local_size.x() * local_size.y() * local_size.z() << "];" NL "shared int g_shared_int["
3721 		   << local_size.x() * local_size.y() * local_size.z()
3722 		   << "];" NL "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL
3723 			  "void main() {" NL "  atomicExchange(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[0]);" NL
3724 			  "  atomicMin(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[1]);" NL
3725 			  "  atomicMax(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[2]);" NL
3726 			  "  atomicAnd(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[3]);" NL
3727 			  "  atomicOr(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[4]);" NL
3728 			  "  atomicXor(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[5]);" NL
3729 			  "  atomicCompSwap(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[6], g_uint_value[7]);" NL NL
3730 			  "  atomicExchange(g_shared_int[gl_LocalInvocationIndex], 3);" NL
3731 			  "  atomicMin(g_shared_int[gl_LocalInvocationIndex], 1);" NL
3732 			  "  atomicMax(g_shared_int[gl_LocalInvocationIndex], 2);" NL
3733 			  "  atomicAnd(g_shared_int[gl_LocalInvocationIndex], 0x1);" NL "  if (g_uint_value[1] > 0u) {" NL
3734 			  "    atomicOr(g_shared_int[gl_LocalInvocationIndex], 0x3);" NL
3735 			  "    atomicXor(g_shared_int[gl_LocalInvocationIndex], 0x1);" NL
3736 			  "    atomicCompSwap(g_shared_int[gl_LocalInvocationIndex], 0x2, 0x7);" NL "  }" NL NL
3737 			  "  g_uint_out[gl_LocalInvocationIndex] = g_shared_uint[gl_LocalInvocationIndex];" NL
3738 			  "  g_int_out[gl_LocalInvocationIndex] = g_shared_int[gl_LocalInvocationIndex];" NL "}";
3739 		return ss.str();
3740 	}
RunIteration(const uvec3 & local_size,bool dispatch_indirect)3741 	bool RunIteration(const uvec3& local_size, bool dispatch_indirect)
3742 	{
3743 		if (m_program != 0)
3744 			glDeleteProgram(m_program);
3745 		m_program = CreateComputeProgram(GenSource(local_size));
3746 		glLinkProgram(m_program);
3747 		if (!CheckProgram(m_program))
3748 			return false;
3749 
3750 		const GLuint kBufferSize = local_size.x() * local_size.y() * local_size.z();
3751 
3752 		if (m_storage_buffer == 0)
3753 			glGenBuffers(1, &m_storage_buffer);
3754 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
3755 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize * 2, NULL, GL_DYNAMIC_DRAW);
3756 
3757 		glUseProgram(m_program);
3758 		if (dispatch_indirect)
3759 		{
3760 			const GLuint num_groups[3] = { 1, 1, 1 };
3761 			if (m_dispatch_buffer == 0)
3762 				glGenBuffers(1, &m_dispatch_buffer);
3763 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
3764 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
3765 			glDispatchComputeIndirect(0);
3766 		}
3767 		else
3768 		{
3769 			glDispatchCompute(1, 1, 1);
3770 		}
3771 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3772 
3773 		std::vector<GLuint> udata(kBufferSize);
3774 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, &udata[0]);
3775 		for (GLuint i = 0; i < kBufferSize; ++i)
3776 		{
3777 			if (udata[i] != 7)
3778 			{
3779 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is "
3780 													<< udata[i] << " should be 7." << tcu::TestLog::EndMessage;
3781 				return false;
3782 			}
3783 		}
3784 
3785 		std::vector<GLint> idata(kBufferSize);
3786 		glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, sizeof(GLint) * kBufferSize,
3787 						   &idata[0]);
3788 		for (GLint i = 0; i < static_cast<GLint>(kBufferSize); ++i)
3789 		{
3790 			if (idata[i] != 7)
3791 			{
3792 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "iData at index " << i << " is "
3793 													<< idata[i] << " should be 7." << tcu::TestLog::EndMessage;
3794 				return false;
3795 			}
3796 		}
3797 
3798 		return true;
3799 	}
Setup()3800 	virtual long Setup()
3801 	{
3802 		m_program		  = 0;
3803 		m_storage_buffer  = 0;
3804 		m_dispatch_buffer = 0;
3805 		return NO_ERROR;
3806 	}
Run()3807 	virtual long Run()
3808 	{
3809 		if (!RunIteration(uvec3(64, 1, 1), false))
3810 			return ERROR;
3811 		if (!RunIteration(uvec3(1, 1, 64), true))
3812 			return ERROR;
3813 		if (!RunIteration(uvec3(1, 1, 4), false))
3814 			return ERROR;
3815 		if (!RunIteration(uvec3(3, 2, 1), true))
3816 			return ERROR;
3817 		if (!RunIteration(uvec3(2, 4, 2), false))
3818 			return ERROR;
3819 		if (!RunIteration(uvec3(2, 4, 7), true))
3820 			return ERROR;
3821 		return NO_ERROR;
3822 	}
Cleanup()3823 	virtual long Cleanup()
3824 	{
3825 		glUseProgram(0);
3826 		glDeleteProgram(m_program);
3827 		glDeleteBuffers(1, &m_storage_buffer);
3828 		glDeleteBuffers(1, &m_dispatch_buffer);
3829 		return NO_ERROR;
3830 	}
3831 };
3832 
3833 class AdvancedCopyImage : public ComputeShaderBase
3834 {
Title()3835 	virtual std::string Title()
3836 	{
3837 		return NL "Copy Image";
3838 	}
Purpose()3839 	virtual std::string Purpose()
3840 	{
3841 		return NL "Verify that copying two textures using CS works as expected.";
3842 	}
Method()3843 	virtual std::string Method()
3844 	{
3845 		return NL "Use shader image load and store operations to copy two textures in the CS.";
3846 	}
PassCriteria()3847 	virtual std::string PassCriteria()
3848 	{
3849 		return NL "Everything works as expected.";
3850 	}
3851 
3852 	GLuint m_program;
3853 	GLuint m_texture[2];
3854 
Setup()3855 	virtual long Setup()
3856 	{
3857 		m_program = 0;
3858 		memset(m_texture, 0, sizeof(m_texture));
3859 		return NO_ERROR;
3860 	}
3861 
Run()3862 	virtual long Run()
3863 	{
3864 		const char* const glsl_cs = NL "#define TILE_WIDTH 16" NL "#define TILE_HEIGHT 16" NL
3865 									   "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
3866 									   "layout(binding = 0, rgba8) uniform image2D g_input_image;" NL
3867 									   "layout(binding = 1, rgba8) uniform image2D g_output_image;" NL	NL
3868 									   "layout(local_size_x=TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL
3869 									   "void main() {" NL "  const ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL
3870 									   "  const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
3871 									   "  const ivec2 pixel_xy = tile_xy * kTileSize + thread_xy;" NL NL
3872 									   "  vec4 pixel = imageLoad(g_input_image, pixel_xy);" NL
3873 									   "  imageStore(g_output_image, pixel_xy, pixel);" NL "}";
3874 		m_program = CreateComputeProgram(glsl_cs);
3875 		glLinkProgram(m_program);
3876 		if (!CheckProgram(m_program))
3877 			return ERROR;
3878 
3879 		std::vector<GLubyte> in_image(64 * 64 * 4, 0x0f);
3880 		std::vector<GLubyte> out_image(64 * 64 * 4, 0x00);
3881 
3882 		glGenTextures(2, m_texture);
3883 		glBindTexture(GL_TEXTURE_2D, m_texture[0]);
3884 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3885 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, &in_image[0]);
3886 
3887 		glBindTexture(GL_TEXTURE_2D, m_texture[1]);
3888 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3889 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, &out_image[0]);
3890 
3891 		glUseProgram(m_program);
3892 		glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
3893 		glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
3894 		glDispatchCompute(5, 4,
3895 						  1); // 5 is on purpose, to ensure that out of bounds image load and stores have no effect
3896 		glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
3897 
3898 		std::vector<GLubyte> data(64 * 64 * 4);
3899 		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
3900 		for (std::size_t i = 0; i < data.size(); ++i)
3901 		{
3902 			if (getWindowWidth() > 100 && data[i] != 0x0f)
3903 			{
3904 				m_context.getTestContext().getLog()
3905 					<< tcu::TestLog::Message << "Data at index " << i << " is " << data[i] << " should be " << 0x0f
3906 					<< "." << tcu::TestLog::EndMessage;
3907 				return ERROR;
3908 			}
3909 		}
3910 
3911 		return NO_ERROR;
3912 	}
Cleanup()3913 	virtual long Cleanup()
3914 	{
3915 		glUseProgram(0);
3916 		glDeleteProgram(m_program);
3917 		glDeleteTextures(2, m_texture);
3918 		return NO_ERROR;
3919 	}
3920 };
3921 
3922 class AdvancedPipelinePreVS : public ComputeShaderBase
3923 {
Title()3924 	virtual std::string Title()
3925 	{
3926 		return NL "CS as an additional pipeline stage - Before VS (1)";
3927 	}
Purpose()3928 	virtual std::string Purpose()
3929 	{
3930 		return NL "Verify that CS which runs just before VS and modifies VBO content works as expected.";
3931 	}
Method()3932 	virtual std::string Method()
3933 	{
3934 		return NL "1. Prepare VBO and VAO for a drawing operation." NL "2. Run CS to modify existing VBO content." NL
3935 				  "3. Issue MemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT) command." NL
3936 				  "4. Issue draw call command." NL "5. Verify that the framebuffer content is as expected.";
3937 	}
PassCriteria()3938 	virtual std::string PassCriteria()
3939 	{
3940 		return NL "Everything works as expected.";
3941 	}
3942 
3943 	GLuint m_program[2];
3944 	GLuint m_vertex_buffer;
3945 	GLuint m_vertex_array;
3946 
Setup()3947 	virtual long Setup()
3948 	{
3949 		memset(m_program, 0, sizeof(m_program));
3950 		m_vertex_buffer = 0;
3951 		m_vertex_array  = 0;
3952 		return NO_ERROR;
3953 	}
Run()3954 	virtual long Run()
3955 	{
3956 		const char* const glsl_cs =
3957 			NL "layout(local_size_x = 4) in;" NL "struct Vertex {" NL "  vec4 position;" NL "  vec4 color;" NL "};" NL
3958 			   "layout(binding = 0, std430) buffer VertexBuffer {" NL "  Vertex g_vertex[];" NL "};" NL
3959 			   "uniform float g_scale = 0.8;" NL "void main() {" NL
3960 			   "  g_vertex[gl_GlobalInvocationID.x].position.xyz *= g_scale;" NL
3961 			   "  g_vertex[gl_GlobalInvocationID.x].color *= vec4(0, 1, 0, 1);" NL "}";
3962 		m_program[0] = CreateComputeProgram(glsl_cs);
3963 		glLinkProgram(m_program[0]);
3964 		if (!CheckProgram(m_program[0]))
3965 			return ERROR;
3966 
3967 		const char* const glsl_vs =
3968 			NL "layout(location = 0) in vec4 g_position;" NL "layout(location = 1) in vec4 g_color;" NL
3969 			   "out StageData {" NL "  vec4 color;" NL "} g_vs_out;" NL "void main() {" NL
3970 			   "  gl_Position = g_position;" NL "  g_vs_out.color = g_color;" NL "}";
3971 
3972 		const char* const glsl_fs =
3973 			NL "in StageData {" NL "  vec4 color;" NL "} g_fs_in;" NL "layout(location = 0) out vec4 g_color;" NL
3974 			   "void main() {" NL "  g_color = g_fs_in.color;" NL "}";
3975 		m_program[1] = CreateProgram(glsl_vs, glsl_fs);
3976 		glLinkProgram(m_program[1]);
3977 		if (!CheckProgram(m_program[1]))
3978 			return ERROR;
3979 
3980 		/* vertex buffer */
3981 		{
3982 			const float data[] = { -1, -1, 0, 1, 1, 1, 1, 1, 1, -1, 0, 1, 1, 1, 1, 1,
3983 								   -1, 1,  0, 1, 1, 1, 1, 1, 1, 1,  0, 1, 1, 1, 1, 1 };
3984 			glGenBuffers(1, &m_vertex_buffer);
3985 			glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
3986 			glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
3987 			glBindBuffer(GL_ARRAY_BUFFER, 0);
3988 		}
3989 
3990 		glGenVertexArrays(1, &m_vertex_array);
3991 		glBindVertexArray(m_vertex_array);
3992 		glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
3993 		glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), 0);
3994 		glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), reinterpret_cast<void*>(sizeof(vec4)));
3995 		glBindBuffer(GL_ARRAY_BUFFER, 0);
3996 		glEnableVertexAttribArray(0);
3997 		glEnableVertexAttribArray(1);
3998 		glBindVertexArray(0);
3999 
4000 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_vertex_buffer);
4001 		glUseProgram(m_program[0]);
4002 		glDispatchCompute(1, 1, 1);
4003 
4004 		glClear(GL_COLOR_BUFFER_BIT);
4005 		glUseProgram(m_program[1]);
4006 		glBindVertexArray(m_vertex_array);
4007 		glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
4008 		glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
4009 
4010 		if (getWindowWidth() < 500 &&
4011 			!ValidateReadBufferCenteredQuad(getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)))
4012 		{
4013 			return ERROR;
4014 		}
4015 		return NO_ERROR;
4016 	}
Cleanup()4017 	virtual long Cleanup()
4018 	{
4019 		glUseProgram(0);
4020 		for (int i = 0; i < 2; ++i)
4021 			glDeleteProgram(m_program[i]);
4022 		glDeleteBuffers(1, &m_vertex_buffer);
4023 		glDeleteVertexArrays(1, &m_vertex_array);
4024 		return NO_ERROR;
4025 	}
4026 };
4027 
4028 class AdvancedPipelineGenDrawCommands : public ComputeShaderBase
4029 {
Title()4030 	virtual std::string Title()
4031 	{
4032 		return NL "CS as an additional pipeline stage - Before VS (2)";
4033 	}
Purpose()4034 	virtual std::string Purpose()
4035 	{
4036 		return NL "Verify that a complex scenario where CS is used to generate drawing commands" NL
4037 				  "and write them to a draw indirect buffer works as expected. This is a practial usage of CS." NL
4038 				  "CS is used for culling objects which are outside of the viewing frustum.";
4039 	}
Method()4040 	virtual std::string Method()
4041 	{
4042 		return NL "1. Run CS which will generate four sets of draw call parameters and write them to the draw indirect "
4043 				  "buffer." NL "2. One set of draw call parameters will be: 0, 0, 0, 0" NL
4044 				  "    (which means that an object is outside of the viewing frustum and should not be drawn)." NL
4045 				  "3. Issue MemoryBarrier(GL_COMMAND_BARRIER_BIT) command." NL
4046 				  "4. Issue four draw indirect commands." NL "5. Verify that the framebuffer content is as expected.";
4047 	}
PassCriteria()4048 	virtual std::string PassCriteria()
4049 	{
4050 		return NL "Everything works as expected.";
4051 	}
4052 
4053 	GLuint m_program[2];
4054 	GLuint m_vertex_buffer;
4055 	GLuint m_index_buffer;
4056 	GLuint m_vertex_array;
4057 	GLuint m_draw_buffer;
4058 	GLuint m_object_buffer;
4059 
Setup()4060 	virtual long Setup()
4061 	{
4062 		memset(m_program, 0, sizeof(m_program));
4063 		m_vertex_buffer = 0;
4064 		m_index_buffer  = 0;
4065 		m_vertex_array  = 0;
4066 		m_draw_buffer   = 0;
4067 		m_object_buffer = 0;
4068 		return NO_ERROR;
4069 	}
Run()4070 	virtual long Run()
4071 	{
4072 		GLint res;
4073 		glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
4074 		if (res <= 0)
4075 		{
4076 			OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
4077 			return NO_ERROR;
4078 		}
4079 
4080 		const char* const glsl_cs =
4081 			NL "layout(local_size_x = 4) in;" NL "struct DrawCommand {" NL "  uint count;" NL
4082 			   "  uint instance_count;" NL "  uint first_index;" NL "  int base_vertex;" NL "  uint base_instance;" NL
4083 			   "};" NL "layout(std430) buffer;" NL "layout(binding = 0) readonly buffer ObjectBuffer {" NL
4084 			   "  mat4 transform[4];" NL "  uint count[4];" NL "  uint first_index[4];" NL "} g_objects;" NL
4085 			   "layout(binding = 1) writeonly buffer DrawCommandBuffer {" NL "  DrawCommand g_command[4];" NL "};" NL
4086 			   "bool IsObjectVisible(uint id) {" NL
4087 			   "  if (g_objects.transform[id][3].x < -1.0 || g_objects.transform[id][3].x > 1.0) return false;" NL
4088 			   "  if (g_objects.transform[id][3][1] < -1.0 || g_objects.transform[id][3][1] > 1.0) return false;" NL
4089 			   "  if (g_objects.transform[id][3][2] < -1.0 || g_objects.transform[id][3].z > 1.0) return false;" NL
4090 			   "  return true;" NL "}" NL "void main() {" NL "  uint id = gl_GlobalInvocationID.x;" NL
4091 			   "  g_command[id].count = 0;" NL "  g_command[id].instance_count = 0;" NL
4092 			   "  g_command[id].first_index = 0;" NL "  g_command[id].base_vertex = 0;" NL
4093 			   "  g_command[id].base_instance = 0;" NL "  if (IsObjectVisible(id)) {" NL
4094 			   "    g_command[id].count = g_objects.count[id];" NL "    g_command[id].instance_count = 1;" NL
4095 			   "    g_command[id].first_index = g_objects.first_index[id];" NL "  }" NL "}";
4096 		m_program[0] = CreateComputeProgram(glsl_cs);
4097 		glLinkProgram(m_program[0]);
4098 		if (!CheckProgram(m_program[0]))
4099 			return ERROR;
4100 
4101 		const char* const glsl_vs =
4102 			NL "layout(location = 0) in vec4 g_position;" NL "layout(location = 1) in vec3 g_color;" NL
4103 			   "out StageData {" NL "  vec3 color;" NL "} g_vs_out;" NL
4104 			   "layout(binding = 0, std430) buffer ObjectBuffer {" NL "  mat4 transform[4];" NL "  uint count[4];" NL
4105 			   "  uint first_index[4];" NL "} g_objects;" NL "uniform int g_object_id;" NL "void main() {" NL
4106 			   "  gl_Position = g_objects.transform[g_object_id] * g_position;" NL "  g_vs_out.color = g_color;" NL "}";
4107 
4108 		const char* const glsl_fs =
4109 			NL "in StageData {" NL "  vec3 color;" NL "} g_fs_in;" NL "layout(location = 0) out vec4 g_color;" NL
4110 			   "void main() {" NL "  g_color = vec4(g_fs_in.color, 1);" NL "}";
4111 		m_program[1] = CreateProgram(glsl_vs, glsl_fs);
4112 		glLinkProgram(m_program[1]);
4113 		if (!CheckProgram(m_program[1]))
4114 			return ERROR;
4115 		glViewport(0, 0, 100, 100);
4116 
4117 		/* object buffer */
4118 		{
4119 			struct
4120 			{
4121 				mat4   transform[4];
4122 				GLuint count[4];
4123 				GLuint first_index[4];
4124 			} data = {
4125 				{ tcu::translationMatrix(vec3(-1.5f, -0.5f, 0.0f)), tcu::translationMatrix(vec3(0.5f, -0.5f, 0.0f)),
4126 				  tcu::translationMatrix(vec3(-0.5f, 0.5f, 0.0f)), tcu::translationMatrix(vec3(0.5f, 0.5f, 0.0f)) },
4127 				{ 4, 4, 4, 4 },
4128 				{ 0, 4, 8, 12 }
4129 			};
4130 			glGenBuffers(1, &m_object_buffer);
4131 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_object_buffer);
4132 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
4133 		}
4134 		/* vertex buffer */
4135 		{
4136 			const vec3 data[] = { vec3(-0.4f, -0.4f, 0.0f), vec3(1, 0, 0), vec3(0.4f, -0.4f, 0.0f), vec3(1, 0, 0),
4137 								  vec3(-0.4f, 0.4f, 0.0f),  vec3(1, 0, 0), vec3(0.4f, 0.4f, 0.0f),  vec3(1, 0, 0),
4138 								  vec3(-0.4f, -0.4f, 0.0f), vec3(0, 1, 0), vec3(0.4f, -0.4f, 0.0f), vec3(0, 1, 0),
4139 								  vec3(-0.4f, 0.4f, 0.0f),  vec3(0, 1, 0), vec3(0.4f, 0.4f, 0.0f),  vec3(0, 1, 0),
4140 								  vec3(-0.4f, -0.4f, 0.0f), vec3(0, 0, 1), vec3(0.4f, -0.4f, 0.0f), vec3(0, 0, 1),
4141 								  vec3(-0.4f, 0.4f, 0.0f),  vec3(0, 0, 1), vec3(0.4f, 0.4f, 0.0f),  vec3(0, 0, 1),
4142 								  vec3(-0.4f, -0.4f, 0.0f), vec3(1, 1, 0), vec3(0.4f, -0.4f, 0.0f), vec3(1, 1, 0),
4143 								  vec3(-0.4f, 0.4f, 0.0f),  vec3(1, 1, 0), vec3(0.4f, 0.4f, 0.0f),  vec3(1, 1, 0) };
4144 			glGenBuffers(1, &m_vertex_buffer);
4145 			glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4146 			glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
4147 			glBindBuffer(GL_ARRAY_BUFFER, 0);
4148 		}
4149 		/* index buffer */
4150 		{
4151 			const GLushort data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
4152 			glGenBuffers(1, &m_index_buffer);
4153 			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
4154 			glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW);
4155 			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
4156 		}
4157 		glGenBuffers(1, &m_draw_buffer);
4158 		glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_buffer);
4159 		glBufferData(GL_DRAW_INDIRECT_BUFFER, 4 * sizeof(GLuint) * 5, NULL, GL_DYNAMIC_DRAW);
4160 		glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
4161 
4162 		glGenVertexArrays(1, &m_vertex_array);
4163 		glBindVertexArray(m_vertex_array);
4164 		glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4165 		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(vec3), 0);
4166 		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(vec3), reinterpret_cast<void*>(sizeof(vec3)));
4167 		glBindBuffer(GL_ARRAY_BUFFER, 0);
4168 		glEnableVertexAttribArray(0);
4169 		glEnableVertexAttribArray(1);
4170 		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
4171 		glBindVertexArray(0);
4172 
4173 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_draw_buffer);
4174 		glUseProgram(m_program[0]);
4175 		glDispatchCompute(1, 1, 1);
4176 
4177 		glClear(GL_COLOR_BUFFER_BIT);
4178 		glUseProgram(m_program[1]);
4179 		glBindVertexArray(m_vertex_array);
4180 		glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_buffer);
4181 		glMemoryBarrier(GL_COMMAND_BARRIER_BIT);
4182 		/* draw (CPU draw calls dispatch, could be done by the GPU with ARB_multi_draw_indirect) */
4183 		{
4184 			GLsizeiptr offset = 0;
4185 			for (int i = 0; i < 4; ++i)
4186 			{
4187 				glUniform1i(glGetUniformLocation(m_program[1], "g_object_id"), i);
4188 				glDrawElementsIndirect(GL_TRIANGLE_STRIP, GL_UNSIGNED_SHORT, reinterpret_cast<void*>(offset));
4189 				offset += 5 * sizeof(GLuint);
4190 			}
4191 		}
4192 		if (getWindowWidth() >= 100 && getWindowHeight() >= 100 &&
4193 			!ValidateWindow4Quads(vec3(0), vec3(0, 1, 0), vec3(1, 1, 0), vec3(0, 0, 1)))
4194 		{
4195 			return ERROR;
4196 		}
4197 		return NO_ERROR;
4198 	}
Cleanup()4199 	virtual long Cleanup()
4200 	{
4201 		glUseProgram(0);
4202 		for (int i = 0; i < 2; ++i)
4203 			glDeleteProgram(m_program[i]);
4204 		glDeleteBuffers(1, &m_vertex_buffer);
4205 		glDeleteBuffers(1, &m_index_buffer);
4206 		glDeleteVertexArrays(1, &m_vertex_array);
4207 		glDeleteBuffers(1, &m_draw_buffer);
4208 		glDeleteBuffers(1, &m_object_buffer);
4209 		glViewport(0, 0, getWindowWidth(), getWindowHeight());
4210 		return NO_ERROR;
4211 	}
4212 };
4213 
4214 class AdvancedPipelineComputeChain : public ComputeShaderBase
4215 {
Title()4216 	virtual std::string Title()
4217 	{
4218 		return NL "Compute Chain";
4219 	}
Purpose()4220 	virtual std::string Purpose()
4221 	{
4222 		return NL "1. Verify that dispatching several compute kernels that work in a sequence" NL
4223 				  "    with a common set of resources works as expected." NL
4224 				  "2. Verify that indexing nested structures with built-in variables work as expected." NL
4225 				  "3. Verify that two kernels can write to the same resource without MemoryBarrier" NL
4226 				  "    command if target regions of memory do not overlap.";
4227 	}
Method()4228 	virtual std::string Method()
4229 	{
4230 		return NL "1. Create a set of GPU resources (buffers, images, atomic counters)." NL
4231 				  "2. Dispatch Kernel0 that write to these resources." NL "3. Issue MemoryBarrier command." NL
4232 				  "4. Dispatch Kernel1 that read/write from/to these resources." NL "5. Issue MemoryBarrier command." NL
4233 				  "6. Dispatch Kernel2 that read/write from/to these resources." NL
4234 				  "7. Verify that content of all resources is as expected.";
4235 	}
PassCriteria()4236 	virtual std::string PassCriteria()
4237 	{
4238 		return NL "Everything works as expected.";
4239 	}
4240 
4241 	GLuint m_program[3];
4242 	GLuint m_storage_buffer[4];
4243 	GLuint m_counter_buffer;
4244 	GLuint m_texture;
4245 	GLuint m_fbo;
4246 
Common()4247 	std::string Common()
4248 	{
4249 		return NL "struct S0 {" NL "  int m0[8];" NL "};" NL "struct S1 {" NL "  S0 m0[8];" NL "};" NL
4250 				  "layout(binding = 0, std430) buffer Buffer0 {" NL "  int m0[5];" NL "  S1 m1[8];" NL "} g_buffer0;" NL
4251 				  "layout(binding = 1, std430) buffer Buffer1 {" NL "  uint data[8];" NL "} g_buffer1;" NL
4252 				  "layout(binding = 2, std430) buffer Buffer2 {" NL "  int data[256];" NL "} g_buffer2;" NL
4253 				  "layout(binding = 3, std430) buffer Buffer3 {" NL "  int data[256];" NL "} g_buffer3;" NL
4254 				  "layout(binding = 4, std430) buffer Buffer4 {" NL "  mat4 data0;" NL "  mat4 data1;" NL
4255 				  "} g_buffer4;" NL "layout(binding = 0, rgba32f) uniform image2D g_image0;" NL
4256 				  "layout(binding = 1, offset = 8) uniform atomic_uint g_counter[2];";
4257 	}
GenGLSL(int p)4258 	std::string GenGLSL(int p)
4259 	{
4260 		std::stringstream ss;
4261 		ss << Common();
4262 		if (p == 0)
4263 		{
4264 			ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;" NL
4265 					 "void UpdateBuffer0(uvec3 id, int add_val) {" NL "  if (id.x < 8 && id.y < 8 && id.z < 8) {" NL
4266 					 "    g_buffer0.m1[id.z].m0[id.y].m0[id.x] += add_val;" NL "  }" NL "}" NL
4267 					 "uniform int g_add_value = 1;" NL "uniform uint g_counter_y = 1;" NL
4268 					 "uniform vec4 g_image_value = vec4(0.125, 0.25, 0.375, 0.5);" NL "void main() {" NL
4269 					 "  uvec3 id = gl_GlobalInvocationID;" NL "  UpdateBuffer0(id, 1);" NL
4270 					 "  UpdateBuffer0(id, g_add_value);" NL "  if (id == uvec3(1, g_counter_y, 1)) {" NL
4271 					 "    uint idx = atomicCounterIncrement(g_counter[1]);" NL "    g_buffer1.data[idx] = idx;" NL
4272 					 "    idx = atomicCounterIncrement(g_counter[1]);" NL "    g_buffer1.data[idx] = idx;" NL "  }" NL
4273 					 "  if (id.x < 4 && id.y < 4 && id.z == 0) {" NL
4274 					 "    vec4 v = imageLoad(g_image0, ivec2(id.xy));" NL
4275 					 "    imageStore(g_image0, ivec2(id.xy), v + g_image_value);" NL "  }" NL
4276 					 "  if (id.x < 2 && id.y == 0 && id.z == 0) {" NL "    g_buffer2.data[id.x] -= int(g_counter_y);" NL
4277 					 "  }" NL "}";
4278 		}
4279 		else if (p == 1)
4280 		{
4281 			ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 1) in;"
4282 				// translation matrix
4283 				NL "uniform mat4 g_mvp = mat4(1.0, 0.0, 0.0, 0.0,  0.0, 1.0, 0.0, 0.0,  0.0, 0.0, 1.0, 0.0,  10.0, "
4284 					 "20.0, 30.0, 1.0);" NL "void main() {" NL "  if (gl_GlobalInvocationID == uvec3(0)) {" NL
4285 					 "    g_buffer4.data0 *= g_mvp;" NL "  }" NL "  if (gl_WorkGroupID == uvec3(0)) {" NL
4286 					 "    g_buffer4.data1[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = "
4287 					 "g_mvp[gl_LocalInvocationID.x][gl_LocalInvocationID.y];" NL "  }" NL "}";
4288 		}
4289 		else if (p == 2)
4290 		{
4291 			ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;" NL "void main() {" NL "}";
4292 		}
4293 		return ss.str();
4294 	}
Setup()4295 	virtual long Setup()
4296 	{
4297 		memset(m_program, 0, sizeof(m_program));
4298 		memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
4299 		m_counter_buffer = 0;
4300 		m_texture		 = 0;
4301 		return NO_ERROR;
4302 	}
Run()4303 	virtual long Run()
4304 	{
4305 		using namespace tcu;
4306 
4307 		for (int i = 0; i < 3; ++i)
4308 		{
4309 			m_program[i] = CreateComputeProgram(GenGLSL(i));
4310 			glLinkProgram(m_program[i]);
4311 			if (!CheckProgram(m_program[i]))
4312 				return ERROR;
4313 		}
4314 
4315 		glGenBuffers(4, m_storage_buffer);
4316 		/* storage buffer 0 */
4317 		{
4318 			std::vector<int> data(5 + 8 * 8 * 8);
4319 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
4320 			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(int)), &data[0], GL_STATIC_COPY);
4321 		}
4322 		/* storage buffer 1 */
4323 		{
4324 			const GLuint data[8] = { 0 };
4325 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
4326 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_STATIC_COPY);
4327 		}
4328 		/* storage buffer 2 & 3 */
4329 		{
4330 			std::vector<GLint> data(512, 7);
4331 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[2]);
4332 			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(GLint)), &data[0], GL_STATIC_COPY);
4333 
4334 			glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 2, m_storage_buffer[2], 0,
4335 							  (GLsizeiptr)(sizeof(GLint) * data.size() / 2));
4336 			glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, m_storage_buffer[2],
4337 							  (GLintptr)(sizeof(GLint) * data.size() / 2),
4338 							  (GLsizeiptr)(sizeof(GLint) * data.size() / 2));
4339 		}
4340 		/* storage buffer 4 */
4341 		{
4342 			std::vector<mat4> data(2);
4343 			data[0] = mat4(1);
4344 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_storage_buffer[3]);
4345 			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(mat4)), &data[0], GL_STATIC_COPY);
4346 		}
4347 		/* counter buffer */
4348 		{
4349 			GLuint data[4] = { 0 };
4350 			glGenBuffers(1, &m_counter_buffer);
4351 			glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, m_counter_buffer);
4352 			glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), data, GL_STATIC_COPY);
4353 		}
4354 		/* texture */
4355 		{
4356 			std::vector<vec4> data(4 * 4, vec4(0.0f));
4357 			glGenTextures(1, &m_texture);
4358 			glBindTexture(GL_TEXTURE_2D, m_texture);
4359 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4360 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4361 			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 4, 4, 0, GL_RGBA, GL_FLOAT, &data[0]);
4362 			glBindTexture(GL_TEXTURE_2D, 0);
4363 		}
4364 
4365 		glUseProgram(m_program[0]);
4366 		glBindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
4367 		glDispatchCompute(2, 2, 2);
4368 		glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4369 		glDispatchCompute(3, 2, 2);
4370 
4371 		glUseProgram(m_program[1]);
4372 		glDispatchCompute(4, 3, 7);
4373 
4374 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT |
4375 						GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4376 
4377 		/* validate texture */
4378 		{
4379 			std::vector<vec4> data(4 * 4);
4380 			glBindTexture(GL_TEXTURE_2D, m_texture);
4381 			glGenFramebuffers(1, &m_fbo);
4382 			glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
4383 			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
4384 			std::vector<GLubyte> colorData(4 * 4 * 4);
4385 			glReadPixels(0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, &colorData[0]);
4386 			for (int i = 0; i < 4 * 4 * 4; i += 4)
4387 			{
4388 				data[i / 4] =
4389 					vec4(static_cast<GLfloat>(colorData[i] / 255.), static_cast<GLfloat>(colorData[i + 1] / 255.),
4390 						 static_cast<GLfloat>(colorData[i + 2] / 255.), static_cast<GLfloat>(colorData[i + 3] / 255.));
4391 			}
4392 			for (std::size_t i = 0; i < data.size(); ++i)
4393 			{
4394 				if (!ColorEqual(data[i], vec4(0.25f, 0.5f, 0.75f, 1.0f), g_color_eps))
4395 				{
4396 					m_context.getTestContext().getLog()
4397 						<< tcu::TestLog::Message << "Invalid data at texture." << tcu::TestLog::EndMessage;
4398 					return ERROR;
4399 				}
4400 			}
4401 		}
4402 		/* validate storage buffer 0 */
4403 		{
4404 			std::vector<int> data(5 + 8 * 8 * 8);
4405 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
4406 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(data.size() * sizeof(int)), &data[0]);
4407 			for (std::size_t i = 5; i < data.size(); ++i)
4408 			{
4409 				if (data[i] != 4)
4410 				{
4411 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data[i]
4412 														<< " should be 2." << tcu::TestLog::EndMessage;
4413 					return ERROR;
4414 				}
4415 			}
4416 		}
4417 		/* validate storage buffer 1 */
4418 		{
4419 			GLuint data[8];
4420 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
4421 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data);
4422 			for (GLuint i = 0; i < 4; ++i)
4423 			{
4424 				if (data[i] != i)
4425 				{
4426 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data[i]
4427 														<< " should be " << i << "." << tcu::TestLog::EndMessage;
4428 					return ERROR;
4429 				}
4430 			}
4431 		}
4432 		/* validate storage buffer 2 & 3 */
4433 		{
4434 			std::vector<GLint> data(512);
4435 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[2]);
4436 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(sizeof(GLint) * data.size()), &data[0]);
4437 			for (int i = 0; i < 2; ++i)
4438 			{
4439 				if (data[i] != 5)
4440 				{
4441 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i]
4442 														<< " should be: 5." << tcu::TestLog::EndMessage;
4443 					return ERROR;
4444 				}
4445 				if (data[i + 256] != 7)
4446 				{
4447 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i + 256]
4448 														<< " should be: 7." << tcu::TestLog::EndMessage;
4449 					return ERROR;
4450 				}
4451 			}
4452 		}
4453 		/* validate storage buffer 4 */
4454 		{
4455 			mat4 data[2];
4456 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[3]);
4457 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data[0](0, 0));
4458 			if (data[0] != translationMatrix(vec3(10.0f, 20.0f, 30.0f)))
4459 			{
4460 				m_context.getTestContext().getLog()
4461 					<< tcu::TestLog::Message << "Data is incorrect." << tcu::TestLog::EndMessage;
4462 				return ERROR;
4463 			}
4464 			if (data[1] != transpose(translationMatrix(vec3(10.0f, 20.0f, 30.0f))))
4465 			{
4466 				m_context.getTestContext().getLog()
4467 					<< tcu::TestLog::Message << "Data is incorrect." << tcu::TestLog::EndMessage;
4468 				return ERROR;
4469 			}
4470 		}
4471 		/* validate counter buffer */
4472 		{
4473 			GLuint data[4] = { 0 };
4474 			glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(data), data);
4475 			if (data[3] != 4)
4476 			{
4477 				m_context.getTestContext().getLog()
4478 					<< tcu::TestLog::Message << "Data is: " << data[3] << " should be: 4." << tcu::TestLog::EndMessage;
4479 				return ERROR;
4480 			}
4481 		}
4482 
4483 		return NO_ERROR;
4484 	}
Cleanup()4485 	virtual long Cleanup()
4486 	{
4487 		glUseProgram(0);
4488 		for (int i = 0; i < 3; ++i)
4489 			glDeleteProgram(m_program[i]);
4490 		glDeleteBuffers(4, m_storage_buffer);
4491 		glDeleteBuffers(1, &m_counter_buffer);
4492 		glDeleteTextures(1, &m_texture);
4493 		glDeleteFramebuffers(1, &m_fbo);
4494 		return NO_ERROR;
4495 	}
4496 };
4497 
4498 class AdvancedPipelinePostFS : public ComputeShaderBase
4499 {
Title()4500 	virtual std::string Title()
4501 	{
4502 		return NL "CS as an additional pipeline stage - After FS";
4503 	}
Purpose()4504 	virtual std::string Purpose()
4505 	{
4506 		return NL "1. Verify that CS which runs just after FS to do a post-processing on a rendered image works as "
4507 				  "expected." NL "2. Verify that CS used as a post-processing filter works as expected." NL
4508 				  "3. Verify that several CS kernels which run in a sequence to do a post-processing on a rendered "
4509 				  "image works as expected.";
4510 	}
Method()4511 	virtual std::string Method()
4512 	{
4513 		return NL
4514 			"1. Render image to Texture0 using VS and FS." NL
4515 			"2. Use Texture0 as an input to Kernel0 which performs post-processing and writes result to Texture1." NL
4516 			"3. Issue MemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) command." NL
4517 			"4. Use Texture1 as an input to Kernel1 which performs post-processing and writes result to Texture0." NL
4518 			"5. Issue MemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) command." NL
4519 			"6. Verify content of the final post-processed image (Texture0).";
4520 	}
PassCriteria()4521 	virtual std::string PassCriteria()
4522 	{
4523 		return NL "Everything works as expected.";
4524 	}
4525 
4526 	GLuint m_program[3];
4527 	GLuint m_render_target[2];
4528 	GLuint m_framebuffer;
4529 	GLuint m_vertex_array;
4530 
Setup()4531 	virtual long Setup()
4532 	{
4533 		memset(m_program, 0, sizeof(m_program));
4534 		memset(m_render_target, 0, sizeof(m_render_target));
4535 		m_framebuffer  = 0;
4536 		m_vertex_array = 0;
4537 		return NO_ERROR;
4538 	}
4539 
Run()4540 	virtual long Run()
4541 	{
4542 		const char* const glsl_vs =
4543 			NL "const vec2 g_vertex[4] = vec2[4](vec2(0), vec2(-1, -1), vec2(3, -1), vec2(-1, 3));" NL
4544 			   "void main() {" NL "  gl_Position = vec4(g_vertex[gl_VertexID], 0, 1);" NL "}";
4545 
4546 		const char* const glsl_fs =
4547 			NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(1, 0, 0, 1);" NL "}";
4548 
4549 		m_program[0] = CreateProgram(glsl_vs, glsl_fs);
4550 		glLinkProgram(m_program[0]);
4551 		if (!CheckProgram(m_program[0]))
4552 			return ERROR;
4553 
4554 		const char* const glsl_cs =
4555 			NL "#define TILE_WIDTH 16" NL "#define TILE_HEIGHT 16" NL
4556 			   "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
4557 			   "layout(binding = 0, rgba32f) uniform image2D g_input_image;" NL
4558 			   "layout(binding = 1, rgba32f) uniform image2D g_output_image;" NL	NL
4559 			   "layout(local_size_x = TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL "void main() {" NL
4560 			   "  const ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL
4561 			   "  const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL NL "  if (thread_xy == ivec2(0)) {" NL
4562 			   "    const ivec2 pixel_xy = tile_xy * kTileSize;" NL "    for (int y = 0; y < TILE_HEIGHT; ++y) {" NL
4563 			   "      for (int x = 0; x < TILE_WIDTH; ++x) {" NL
4564 			   "        imageStore(g_output_image, pixel_xy + ivec2(x, y), vec4(0, 1, 0, 1));" NL "      }" NL
4565 			   "    }" NL "  }" NL "}";
4566 
4567 		m_program[1] = CreateComputeProgram(glsl_cs);
4568 		glLinkProgram(m_program[1]);
4569 		if (!CheckProgram(m_program[1]))
4570 			return ERROR;
4571 
4572 		const char* const glsl_cs2 = NL "#define TILE_WIDTH 32" NL "#define TILE_HEIGHT 32" NL
4573 										"const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
4574 										"layout(binding = 0, rgba32f) uniform image2D g_input_image;" NL
4575 										"layout(binding = 1, rgba32f) uniform image2D g_output_image;" NL	NL
4576 										"layout(local_size_x = TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL
4577 										"vec4 Process(vec4 ic) {" NL "  return ic + vec4(1, 0, 0, 0);" NL "}" NL
4578 										"void main() {" NL "  const ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL
4579 										"  const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
4580 										"  const ivec2 pixel_xy = tile_xy * kTileSize + thread_xy;" NL
4581 										"  vec4 ic = imageLoad(g_input_image, pixel_xy);" NL
4582 										"  imageStore(g_output_image, pixel_xy, Process(ic));" NL "}";
4583 		m_program[2] = CreateComputeProgram(glsl_cs2);
4584 		glLinkProgram(m_program[2]);
4585 		if (!CheckProgram(m_program[2]))
4586 			return ERROR;
4587 
4588 		glGenVertexArrays(1, &m_vertex_array);
4589 
4590 		/* init render targets */
4591 		{
4592 			std::vector<vec4> data(128 * 128);
4593 			glGenTextures(2, m_render_target);
4594 			for (int i = 0; i < 2; ++i)
4595 			{
4596 				glBindTexture(GL_TEXTURE_2D, m_render_target[i]);
4597 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
4598 				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 128, 128, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
4599 			}
4600 			glBindTexture(GL_TEXTURE_2D, 0);
4601 		}
4602 
4603 		glGenFramebuffers(1, &m_framebuffer);
4604 		glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
4605 		glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_render_target[0], 0);
4606 		glBindFramebuffer(GL_FRAMEBUFFER, 0);
4607 
4608 		glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
4609 		glUseProgram(m_program[0]);
4610 		glBindVertexArray(m_vertex_array);
4611 		glClear(GL_COLOR_BUFFER_BIT);
4612 		glViewport(0, 0, 128, 128);
4613 		// draw full-viewport triangle
4614 		glDrawArrays(GL_TRIANGLES, 1,
4615 					 3); // note: <first> is 1 this means that gl_VertexID in the VS will be: 1, 2 and 3
4616 		glBindFramebuffer(GL_FRAMEBUFFER, 0);
4617 
4618 		glBindImageTexture(0, m_render_target[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);  // input
4619 		glBindImageTexture(1, m_render_target[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); // output
4620 		glUseProgram(m_program[1]);
4621 		glDispatchCompute(128 / 16, 128 / 16, 1);
4622 
4623 		glBindImageTexture(0, m_render_target[1], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);  // input
4624 		glBindImageTexture(1, m_render_target[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); // output
4625 		glUseProgram(m_program[2]);
4626 		glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4627 		glDispatchCompute(128 / 32, 128 / 32, 1);
4628 
4629 		/* validate render target */
4630 		{
4631 			std::vector<vec4> data(128 * 128);
4632 			glBindTexture(GL_TEXTURE_2D, m_render_target[0]);
4633 			glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
4634 			glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
4635 			for (std::size_t i = 0; i < data.size(); ++i)
4636 			{
4637 				if (!IsEqual(data[i], vec4(1, 1, 0, 1)))
4638 				{
4639 					m_context.getTestContext().getLog()
4640 						<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
4641 					return ERROR;
4642 				}
4643 			}
4644 		}
4645 		return NO_ERROR;
4646 	}
4647 
Cleanup()4648 	virtual long Cleanup()
4649 	{
4650 		glViewport(0, 0, getWindowWidth(), getWindowHeight());
4651 		glUseProgram(0);
4652 		for (int i = 0; i < 3; ++i)
4653 			glDeleteProgram(m_program[i]);
4654 		glDeleteTextures(2, m_render_target);
4655 		glDeleteVertexArrays(1, &m_vertex_array);
4656 		glDeleteFramebuffers(1, &m_framebuffer);
4657 		return NO_ERROR;
4658 	}
4659 };
4660 
4661 class AdvancedPipelinePostXFB : public ComputeShaderBase
4662 {
Title()4663 	virtual std::string Title()
4664 	{
4665 		return NL "CS as an additional pipeline stage - After XFB";
4666 	}
Purpose()4667 	virtual std::string Purpose()
4668 	{
4669 		return NL "1. Verify that CS which process data fedback by VS works as expected." NL
4670 				  "2. Verify that XFB and SSBO works correctly together in one shader." NL
4671 				  "3. Verify that 'switch' statment which selects different execution path for each CS thread works as "
4672 				  "expected.";
4673 	}
Method()4674 	virtual std::string Method()
4675 	{
4676 		return NL "1. Draw triangle with XFB enabled. Some data is written to the XFB buffer." NL
4677 				  "2. Use XFB buffer as 'input SSBO' in CS. Process data and write it to 'output SSBO'." NL
4678 				  "3. Verify 'output SSBO' content.";
4679 	}
PassCriteria()4680 	virtual std::string PassCriteria()
4681 	{
4682 		return NL "Everything works as expected.";
4683 	}
4684 
4685 	GLuint m_program[2];
4686 	GLuint m_storage_buffer;
4687 	GLuint m_xfb_buffer;
4688 	GLuint m_vertex_buffer;
4689 	GLuint m_vertex_array;
4690 
Setup()4691 	virtual long Setup()
4692 	{
4693 		memset(m_program, 0, sizeof(m_program));
4694 		m_storage_buffer = 0;
4695 		m_xfb_buffer	 = 0;
4696 		m_vertex_buffer  = 0;
4697 		m_vertex_array   = 0;
4698 		return NO_ERROR;
4699 	}
Run()4700 	virtual long Run()
4701 	{
4702 		GLint res;
4703 		glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
4704 		if (res <= 0)
4705 		{
4706 			OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
4707 			return NO_ERROR;
4708 		}
4709 
4710 		const char* const glsl_vs =
4711 			NL "layout(location = 0) in vec4 g_position;" NL "layout(location = 1) in vec4 g_color;" NL
4712 			   "struct Vertex {" NL "  vec4 position;" NL "  vec4 color;" NL "};" NL "out StageData {" NL
4713 			   "  vec4 color;" NL "} g_vs_out;" NL "layout(binding = 0, std430) buffer StageData {" NL
4714 			   "  Vertex vertex[];" NL "} g_vs_buffer;" NL "void main() {" NL "  gl_Position = g_position;" NL
4715 			   "  g_vs_out.color = g_color;" NL "  g_vs_buffer.vertex[gl_VertexID].position = g_position;" NL
4716 			   "  g_vs_buffer.vertex[gl_VertexID].color = g_color;" NL "}";
4717 
4718 		const char* const glsl_fs =
4719 			NL "in StageData {" NL "  vec4 color;" NL "} g_fs_in;" NL "layout(location = 0) out vec4 g_color;" NL
4720 			   "void main() {" NL "  g_color = g_fs_in.color;" NL "}";
4721 
4722 		m_program[0] = CreateProgram(glsl_vs, glsl_fs);
4723 		/* setup xfb varyings */
4724 		{
4725 			const char* const var[2] = { "gl_Position", "StageData.color" };
4726 			glTransformFeedbackVaryings(m_program[0], 2, var, GL_INTERLEAVED_ATTRIBS);
4727 		}
4728 		glLinkProgram(m_program[0]);
4729 		if (!CheckProgram(m_program[0]))
4730 			return ERROR;
4731 
4732 		const char* const glsl_cs =
4733 			NL "layout(local_size_x = 3) in;" NL "struct Vertex {" NL "  vec4 position;" NL "  vec4 color;" NL "};" NL
4734 			   "layout(binding = 3, std430) buffer Buffer {" NL "  Vertex g_vertex[3];" NL "};" NL
4735 			   "uniform vec4 g_color1 = vec4(0, 0, 1, 0);" NL "uniform int g_two = 2;" NL
4736 			   "void UpdateVertex2(int i) {" NL "  g_vertex[i].color -= vec4(-1, 1, 0, 0);" NL "}" NL "void main() {" NL
4737 			   "  switch (gl_GlobalInvocationID.x) {" NL
4738 			   "    case 0: g_vertex[gl_GlobalInvocationID.x].color += vec4(1, 0, 0, 0); break;" NL
4739 			   "    case 1: g_vertex[1].color += g_color1; break;" NL "    case 2: UpdateVertex2(g_two); break;" NL
4740 			   "    default: return;" NL "  }" NL "}";
4741 		m_program[1] = CreateComputeProgram(glsl_cs);
4742 		glLinkProgram(m_program[1]);
4743 		if (!CheckProgram(m_program[1]))
4744 			return ERROR;
4745 
4746 		glGenBuffers(1, &m_storage_buffer);
4747 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
4748 		glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * sizeof(vec4) * 2, NULL, GL_STATIC_COPY);
4749 
4750 		glGenBuffers(1, &m_xfb_buffer);
4751 		glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_xfb_buffer);
4752 		glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 3 * sizeof(vec4) * 2, NULL, GL_STREAM_COPY);
4753 
4754 		const float in_data[3 * 8] = { -1, -1, 0, 1, 0, 1, 0, 1, 3, -1, 0, 1, 0, 1, 0, 1, -1, 3, 0, 1, 0, 1, 0, 1 };
4755 		glGenBuffers(1, &m_vertex_buffer);
4756 		glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4757 		glBufferData(GL_ARRAY_BUFFER, sizeof(in_data), in_data, GL_STATIC_DRAW);
4758 		glBindBuffer(GL_ARRAY_BUFFER, 0);
4759 
4760 		glGenVertexArrays(1, &m_vertex_array);
4761 		glBindVertexArray(m_vertex_array);
4762 		glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4763 		glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), 0);
4764 		glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), reinterpret_cast<void*>(sizeof(vec4)));
4765 		glBindBuffer(GL_ARRAY_BUFFER, 0);
4766 		glEnableVertexAttribArray(0);
4767 		glEnableVertexAttribArray(1);
4768 		glBindVertexArray(0);
4769 
4770 		glClear(GL_COLOR_BUFFER_BIT);
4771 		glUseProgram(m_program[0]);
4772 		glBindVertexArray(m_vertex_array);
4773 		glBeginTransformFeedback(GL_TRIANGLES);
4774 		glDrawArrays(GL_TRIANGLES, 0, 3);
4775 		glEndTransformFeedback();
4776 
4777 		glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
4778 
4779 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_xfb_buffer);
4780 		glUseProgram(m_program[1]);
4781 		glDispatchCompute(1, 1, 1);
4782 
4783 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4784 
4785 		/* validate storage buffer */
4786 		{
4787 			float data[3 * 8];
4788 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
4789 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data);
4790 			if (memcmp(data, in_data, sizeof(data)) != 0)
4791 			{
4792 				m_context.getTestContext().getLog()
4793 					<< tcu::TestLog::Message << "Data in shader storage buffer is incorrect."
4794 					<< tcu::TestLog::EndMessage;
4795 				return ERROR;
4796 			}
4797 		}
4798 		/* validate xfb buffer */
4799 		{
4800 			const float ref_data[3 * 8] = {
4801 				-1, -1, 0, 1, 1, 1, 0, 1, 3, -1, 0, 1, 0, 1, 1, 1, -1, 3, 0, 1, 1, 0, 0, 1
4802 			};
4803 
4804 			float data[3 * 8];
4805 			glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), data);
4806 			if (memcmp(data, ref_data, sizeof(data)) != 0)
4807 			{
4808 				m_context.getTestContext().getLog()
4809 					<< tcu::TestLog::Message << "Data in xfb buffer is incorrect." << tcu::TestLog::EndMessage;
4810 				return ERROR;
4811 			}
4812 		}
4813 		if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
4814 		{
4815 			return ERROR;
4816 		}
4817 		return NO_ERROR;
4818 	}
4819 
Cleanup()4820 	virtual long Cleanup()
4821 	{
4822 		glUseProgram(0);
4823 		for (int i = 0; i < 2; ++i)
4824 			glDeleteProgram(m_program[i]);
4825 		glDeleteBuffers(1, &m_vertex_buffer);
4826 		glDeleteBuffers(1, &m_storage_buffer);
4827 		glDeleteBuffers(1, &m_xfb_buffer);
4828 		glDeleteVertexArrays(1, &m_vertex_array);
4829 		return NO_ERROR;
4830 	}
4831 };
4832 
4833 class AdvancedSharedIndexing : public ComputeShaderBase
4834 {
Title()4835 	virtual std::string Title()
4836 	{
4837 		return NL "Shared Memory - Indexing";
4838 	}
Purpose()4839 	virtual std::string Purpose()
4840 	{
4841 		return NL "1. Verify that indexing various types of shared memory works as expected." NL
4842 				  "2. Verify that indexing shared memory with different types of expressions work as expected." NL
4843 				  "3. Verify that all declaration types of shared structures are supported by the GLSL compiler.";
4844 	}
Method()4845 	virtual std::string Method()
4846 	{
4847 		return NL "1. Create CS which uses shared memory in many different ways." NL
4848 				  "2. Write to shared memory using different expressions." NL "3. Validate shared memory content." NL
4849 				  "4. Use synchronization primitives (barrier, groupMemoryBarrier) where applicable.";
4850 	}
PassCriteria()4851 	virtual std::string PassCriteria()
4852 	{
4853 		return NL "Everyting works as expected.";
4854 	}
4855 
4856 	GLuint m_program;
4857 	GLuint m_texture;
4858 
Setup()4859 	virtual long Setup()
4860 	{
4861 		m_program = 0;
4862 		m_texture = 0;
4863 		return NO_ERROR;
4864 	}
Run()4865 	virtual long Run()
4866 	{
4867 		const char* const glsl_cs = NL
4868 			"layout(binding = 3, rgba32f) uniform image2D g_result_image;" NL
4869 			"layout (local_size_x = 4,local_size_y=4 ) in;" NL "shared vec4 g_shared1[4];" NL
4870 			"shared mat4 g_shared2;" NL "shared struct {" NL "  float data[4];" NL "} g_shared3[4];" NL
4871 			"shared struct Type { float data[4]; } g_shared4[4];" NL "shared Type g_shared5[4];" NL
4872 			"uniform bool g_true = true;" NL
4873 			"uniform float g_values[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };" NL NL
4874 			"void Sync() {" NL "  groupMemoryBarrier();" NL "  barrier();" NL "}" NL
4875 			"void SetMemory(ivec2 xy, float value) {" NL "  g_shared1[xy.y][gl_LocalInvocationID.x] = value;" NL
4876 			"  g_shared2[xy.y][xy.x] = value;" NL "  g_shared3[xy[1]].data[xy[0]] = value;" NL
4877 			"  g_shared4[xy.y].data[xy[0]] = value;" NL
4878 			"  g_shared5[gl_LocalInvocationID.y].data[gl_LocalInvocationID.x] = value;" NL "}" NL
4879 			"bool CheckMemory(ivec2 xy, float expected) {" NL
4880 			"  if (g_shared1[xy.y][xy[0]] != expected) return false;" NL
4881 			"  if (g_shared2[xy[1]][xy[0]] != expected) return false;" NL
4882 			"  if (g_shared3[gl_LocalInvocationID.y].data[gl_LocalInvocationID.x] != expected) return false;" NL
4883 			"  if (g_shared4[gl_LocalInvocationID.y].data[xy.x] != expected) return false;" NL
4884 			"  if (g_shared5[xy.y].data[xy.x] != expected) return false;" NL "  return true;" NL "}" NL
4885 			"void main() {" NL "  const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
4886 			"  vec4 result = vec4(0, 1, 0, 1);" NL NL
4887 			"  SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 1.0);" NL "  Sync();" NL
4888 			"  if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 1.0)) result = vec4(1, 0, 0, 1);" NL NL
4889 			"  SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * -1.0);" NL "  Sync();" NL
4890 			"  if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * -1.0)) result = vec4(1, 0, 0, 1);" NL NL
4891 			"  if (g_true && gl_LocalInvocationID.x < 10) {" NL
4892 			"    SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 7.0);" NL "    Sync();" NL
4893 			"    if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 7.0)) result = vec4(1, 0, 0, 1);" NL
4894 			"  }" NL NL "  imageStore(g_result_image, thread_xy, result);" NL "}";
4895 		m_program = CreateComputeProgram(glsl_cs);
4896 		glLinkProgram(m_program);
4897 		if (!CheckProgram(m_program))
4898 			return ERROR;
4899 
4900 		/* init texture */
4901 		{
4902 			std::vector<vec4> data(4 * 4);
4903 			glGenTextures(1, &m_texture);
4904 			glBindTexture(GL_TEXTURE_2D, m_texture);
4905 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
4906 			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 4, 4, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
4907 			glBindTexture(GL_TEXTURE_2D, 0);
4908 		}
4909 
4910 		glBindImageTexture(3, m_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
4911 		glUseProgram(m_program);
4912 		glDispatchCompute(1, 1, 1);
4913 
4914 		/* validate render target */
4915 		{
4916 			std::vector<vec4> data(4 * 4);
4917 			glBindTexture(GL_TEXTURE_2D, m_texture);
4918 			glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
4919 			glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
4920 			for (std::size_t i = 0; i < data.size(); ++i)
4921 			{
4922 				if (!IsEqual(data[i], vec4(0, 1, 0, 1)))
4923 				{
4924 					m_context.getTestContext().getLog()
4925 						<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
4926 					return ERROR;
4927 				}
4928 			}
4929 		}
4930 		return NO_ERROR;
4931 	}
Cleanup()4932 	virtual long Cleanup()
4933 	{
4934 		glUseProgram(0);
4935 		glDeleteProgram(m_program);
4936 		glDeleteTextures(1, &m_texture);
4937 		return NO_ERROR;
4938 	}
4939 };
4940 
4941 class AdvancedSharedMax : public ComputeShaderBase
4942 {
Title()4943 	virtual std::string Title()
4944 	{
4945 		return NL "Shared Memory - 32K";
4946 	}
Purpose()4947 	virtual std::string Purpose()
4948 	{
4949 		return NL "Support for 32K of shared memory is required by the OpenGL specifaction. Verify if an "
4950 				  "implementation supports it.";
4951 	}
Method()4952 	virtual std::string Method()
4953 	{
4954 		return NL "Create and dispatch CS which uses 32K of shared memory.";
4955 	}
PassCriteria()4956 	virtual std::string PassCriteria()
4957 	{
4958 		return NL "Everything works as expected.";
4959 	}
4960 
4961 	GLuint m_program;
4962 	GLuint m_buffer;
4963 
Setup()4964 	virtual long Setup()
4965 	{
4966 		m_program = 0;
4967 		m_buffer  = 0;
4968 		return NO_ERROR;
4969 	}
Run()4970 	virtual long Run()
4971 	{
4972 		const char* const glsl_cs =
4973 			NL "layout(local_size_x = 1024) in;" NL
4974 			   "shared struct Type { vec4 v[2]; } g_shared[1024];" // 32768 bytes of shared memory
4975 			NL "layout(std430) buffer Output {" NL "  Type g_output[1024];" NL "};" NL NL "void main() {" NL
4976 			   "  const int id = int(gl_GlobalInvocationID.x);" NL
4977 			   "  g_shared[id].v = vec4[2](vec4(1.0), vec4(1.0));" NL "  memoryBarrierShared();" NL "  barrier();" NL NL
4978 			   "  vec4 sum = vec4(0.0);" NL "  int sum_count = 0;" NL "  for (int i = id - 3; i < id + 4; ++i) {" NL
4979 			   "    if (id >= 0 && id < g_shared.length()) {" NL "      sum += g_shared[id].v[0];" NL
4980 			   "      sum += g_shared[id].v[1];" NL "      sum_count += 2;" NL "    }" NL "  }" NL
4981 			   "  if (any(greaterThan(abs((sum / sum_count) - vec4(1.0)), vec4(0.0000001f)))) return;" NL NL
4982 			   "  g_output[id] = g_shared[id];" NL "}";
4983 		m_program = CreateComputeProgram(glsl_cs);
4984 		glLinkProgram(m_program);
4985 		if (!CheckProgram(m_program))
4986 			return ERROR;
4987 
4988 		/* init buffer */
4989 		{
4990 			std::vector<vec4> data(1024 * 2);
4991 			glGenBuffers(1, &m_buffer);
4992 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
4993 			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0],
4994 						 GL_DYNAMIC_COPY);
4995 		}
4996 
4997 		glUseProgram(m_program);
4998 		glDispatchCompute(1, 1, 1);
4999 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5000 
5001 		/* validate buffer */
5002 		{
5003 			std::vector<vec4> data(1024 * 2);
5004 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0]);
5005 			for (std::size_t i = 0; i < data.size(); ++i)
5006 			{
5007 				if (!IsEqual(data[i], vec4(1.0f)))
5008 				{
5009 					m_context.getTestContext().getLog()
5010 						<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
5011 					return ERROR;
5012 				}
5013 			}
5014 		}
5015 		return NO_ERROR;
5016 	}
Cleanup()5017 	virtual long Cleanup()
5018 	{
5019 		glUseProgram(0);
5020 		glDeleteProgram(m_program);
5021 		glDeleteBuffers(1, &m_buffer);
5022 		return NO_ERROR;
5023 	}
5024 };
5025 
5026 class AdvancedDynamicPaths : public ComputeShaderBase
5027 {
Title()5028 	virtual std::string Title()
5029 	{
5030 		return NL "Dynamic execution paths";
5031 	}
Purpose()5032 	virtual std::string Purpose()
5033 	{
5034 		return NL "1. Verify case where each of the four threads takes different execution path in the CS." NL
5035 				  "2. Execution path for each thread is not known at the compilation time." NL
5036 				  "    Selection is made based on the result of the texture sampling." NL
5037 				  "3. Verify that memory synchronization primitives (memoryBarrier* functions) are accepted" NL
5038 				  "    in the control flow.";
5039 	}
Method()5040 	virtual std::string Method()
5041 	{
5042 		return NL "1. Create and dispatch CS that takes different execution paths based on the result of the texture "
5043 				  "sampling." NL "2. In each execution path use different resources (buffers, samplers, uniform "
5044 				  "arrays) to compute output value.";
5045 	}
PassCriteria()5046 	virtual std::string PassCriteria()
5047 	{
5048 		return NL "Everything works as expected.";
5049 	}
5050 
5051 	GLuint m_program;
5052 	GLuint m_buffer[4];
5053 	GLuint m_texture[2];
5054 
Setup()5055 	virtual long Setup()
5056 	{
5057 		m_program = 0;
5058 		memset(m_buffer, 0, sizeof(m_buffer));
5059 		memset(m_texture, 0, sizeof(m_texture));
5060 		return NO_ERROR;
5061 	}
Run()5062 	virtual long Run()
5063 	{
5064 		const char* const glsl_cs =
5065 			NL "layout(local_size_x = 4) in;" NL "layout(std140, binding = 0) buffer Output {" NL
5066 			   "  vec4 g_output[4];" NL "};" NL "uniform isamplerBuffer g_path_buffer;" NL
5067 			   "uniform vec4[4] g_input0 = vec4[4](vec4(100), vec4(200), vec4(300), vec4(400));" NL
5068 			   "uniform samplerBuffer g_input1;" NL "layout(binding = 1, std430) buffer Input2 {" NL
5069 			   "  vec4[4] g_input2;" NL "};" NL NL "void Path2(int id) {" NL
5070 			   "  g_output[id] = texelFetch(g_input1, int(gl_LocalInvocationIndex));" NL "}" NL "void main() {" NL
5071 			   "  const int id = int(gl_GlobalInvocationID.x);" NL
5072 			   "  const int path = texelFetch(g_path_buffer, id).x;" NL NL "  if (path == 0) {" NL
5073 			   "    g_output[id] = g_input0[gl_LocalInvocationID.x];" NL "    memoryBarrier();" NL
5074 			   "  } else if (path == 1) {" NL "    return;" NL "  } else if (path == 2) {" NL "    Path2(id);" NL
5075 			   "    return;" NL "  } else if (path == 3) {" NL "    g_output[id] = g_input2[path - 1];" NL
5076 			   "    memoryBarrierBuffer();" NL "  }" NL "}";
5077 		m_program = CreateComputeProgram(glsl_cs);
5078 		glLinkProgram(m_program);
5079 		if (!CheckProgram(m_program))
5080 			return ERROR;
5081 
5082 		glGenBuffers(4, m_buffer);
5083 		glGenTextures(2, m_texture);
5084 
5085 		/* init 'output' buffer */
5086 		{
5087 			std::vector<vec4> data(4, vec4(-100.0f));
5088 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[0]);
5089 			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0],
5090 						 GL_DYNAMIC_COPY);
5091 		}
5092 		/* init 'input2' buffer */
5093 		{
5094 			const vec4 data[4] = { vec4(1.0f), vec4(2.0f), vec4(3.0f), vec4(4.0f) };
5095 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[1]);
5096 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data[0][0], GL_DYNAMIC_COPY);
5097 		}
5098 		/* init 'path' buffer */
5099 		{
5100 			const int data[4] = { 3, 2, 1, 0 };
5101 			glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[2]);
5102 			glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data[0], GL_STATIC_DRAW);
5103 			glBindBuffer(GL_TEXTURE_BUFFER, 0);
5104 			glBindTexture(GL_TEXTURE_BUFFER, m_texture[0]);
5105 			glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, m_buffer[2]);
5106 			glBindTexture(GL_TEXTURE_BUFFER, 0);
5107 		}
5108 		/* init 'input1' buffer */
5109 		{
5110 			const vec4 data[4] = { vec4(10.0f), vec4(20.0f), vec4(30.0f), vec4(40.0f) };
5111 			glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[3]);
5112 			glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data[0], GL_STATIC_DRAW);
5113 			glBindBuffer(GL_TEXTURE_BUFFER, 0);
5114 			glBindTexture(GL_TEXTURE_BUFFER, m_texture[1]);
5115 			glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_buffer[3]);
5116 			glBindTexture(GL_TEXTURE_BUFFER, 0);
5117 		}
5118 
5119 		glUseProgram(m_program);
5120 		glUniform1i(glGetUniformLocation(m_program, "g_path_buffer"), 0);
5121 		glUniform1i(glGetUniformLocation(m_program, "g_input1"), 1);
5122 		glActiveTexture(GL_TEXTURE0);
5123 		glBindTexture(GL_TEXTURE_BUFFER, m_texture[0]);
5124 		glActiveTexture(GL_TEXTURE1);
5125 		glBindTexture(GL_TEXTURE_BUFFER, m_texture[1]);
5126 		glDispatchCompute(1, 1, 1);
5127 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5128 
5129 		/* validate 'output' buffer */
5130 		{
5131 			vec4 data[4];
5132 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer[0]);
5133 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data[0][0]);
5134 
5135 			const vec4 expected[4] = { vec4(3.0f), vec4(20.0f), vec4(-100.0f), vec4(400.0f) };
5136 			for (int i = 0; i < 4; ++i)
5137 			{
5138 				if (!IsEqual(data[i], expected[i]))
5139 				{
5140 					m_context.getTestContext().getLog()
5141 						<< tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
5142 					return ERROR;
5143 				}
5144 			}
5145 		}
5146 		return NO_ERROR;
5147 	}
Cleanup()5148 	virtual long Cleanup()
5149 	{
5150 		glUseProgram(0);
5151 		glDeleteProgram(m_program);
5152 		glDeleteBuffers(4, m_buffer);
5153 		glDeleteTextures(2, m_texture);
5154 		return NO_ERROR;
5155 	}
5156 };
5157 
5158 class AdvancedResourcesMax : public ComputeShaderBase
5159 {
Title()5160 	virtual std::string Title()
5161 	{
5162 		return NL "Maximum number of resources in one shader";
5163 	}
Purpose()5164 	virtual std::string Purpose()
5165 	{
5166 		return NL "1. Verify that using 8 SSBOs, 12 UBOs, 8 atomic counters, 16 samplers" NL
5167 				  "    and 8 images in one CS works as expected.";
5168 	}
Method()5169 	virtual std::string Method()
5170 	{
5171 		return NL "Create and dispatch CS. Verify result.";
5172 	}
PassCriteria()5173 	virtual std::string PassCriteria()
5174 	{
5175 		return NL "Everything works as expected.";
5176 	}
5177 
5178 	GLuint m_program;
5179 	GLuint m_storage_buffer[8];
5180 	GLuint m_uniform_buffer[12];
5181 	GLuint m_atomic_buffer[8];
5182 	GLuint m_texture_buffer[16];
5183 	GLuint m_texture[16];
5184 	GLuint m_image_buffer[8];
5185 	GLuint m_image[8];
5186 
RunIteration(GLuint index)5187 	bool RunIteration(GLuint index)
5188 	{
5189 		for (GLuint i = 0; i < 8; ++i)
5190 		{
5191 			const GLuint data = i + 1;
5192 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_storage_buffer[i]);
5193 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5194 		}
5195 		for (GLuint i = 0; i < 12; ++i)
5196 		{
5197 			const GLuint data = i + 1;
5198 			glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
5199 			glBufferData(GL_UNIFORM_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5200 		}
5201 		for (GLuint i = 0; i < 8; ++i)
5202 		{
5203 			const GLuint data = i + 1;
5204 			glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, m_atomic_buffer[i]);
5205 			glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5206 		}
5207 		for (GLuint i = 0; i < 16; ++i)
5208 		{
5209 			const GLuint data = i + 1;
5210 			glBindBuffer(GL_TEXTURE_BUFFER, m_texture_buffer[i]);
5211 			glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data, GL_DYNAMIC_READ);
5212 			glBindBuffer(GL_TEXTURE_BUFFER, 0);
5213 
5214 			glActiveTexture(GL_TEXTURE0 + i);
5215 			glBindTexture(GL_TEXTURE_BUFFER, m_texture[i]);
5216 			glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_texture_buffer[i]);
5217 		}
5218 		for (GLuint i = 0; i < 8; ++i)
5219 		{
5220 			const GLuint data = i + 1;
5221 			glBindBuffer(GL_TEXTURE_BUFFER, m_image_buffer[i]);
5222 			glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data, GL_DYNAMIC_COPY);
5223 			glBindBuffer(GL_TEXTURE_BUFFER, 0);
5224 
5225 			glBindTexture(GL_TEXTURE_BUFFER, m_image[i]);
5226 			glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_image_buffer[i]);
5227 			glBindTexture(GL_TEXTURE_BUFFER, 0);
5228 
5229 			glBindImageTexture(i, m_image[i], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
5230 		}
5231 
5232 		glUseProgram(m_program);
5233 		glUniform1ui(glGetUniformLocation(m_program, "g_index"), index);
5234 		/* uniform array */
5235 		{
5236 			std::vector<GLuint> data(480);
5237 			for (GLuint i = 0; i < static_cast<GLuint>(data.size()); ++i)
5238 				data[i]   = i + 1;
5239 			glUniform1uiv(glGetUniformLocation(m_program, "g_uniform_def"), static_cast<GLsizei>(data.size()),
5240 						  &data[0]);
5241 		}
5242 		glDispatchCompute(1, 1, 1);
5243 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5244 
5245 		bool result = true;
5246 		/* validate buffer */
5247 		{
5248 			GLuint data;
5249 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[index]);
5250 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5251 
5252 			if (data != (index + 1) * 6)
5253 			{
5254 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data << " should be "
5255 													<< (index + 1) * 6 << "." << tcu::TestLog::EndMessage;
5256 				result = false;
5257 			}
5258 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
5259 		}
5260 		return result;
5261 	}
Setup()5262 	virtual long Setup()
5263 	{
5264 		m_program = 0;
5265 		memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
5266 		memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
5267 		memset(m_atomic_buffer, 0, sizeof(m_atomic_buffer));
5268 		memset(m_texture_buffer, 0, sizeof(m_texture_buffer));
5269 		memset(m_texture, 0, sizeof(m_texture));
5270 		memset(m_image_buffer, 0, sizeof(m_image_buffer));
5271 		memset(m_image, 0, sizeof(m_image));
5272 		return NO_ERROR;
5273 	}
Run()5274 	virtual long Run()
5275 	{
5276 		const char* const glsl_cs =
5277 			NL "layout(local_size_x = 1) in;" NL "layout(std140, binding = 0) buffer ShaderStorageBlock {" NL
5278 			   "  uint data;" NL "} g_shader_storage[8];" NL "layout(std140, binding = 0) uniform UniformBlock {" NL
5279 			   "  uint data;" NL "} g_uniform[12];" NL "layout(binding = 0) uniform usamplerBuffer g_sampler[16];" NL
5280 			   "layout(binding = 0, r32ui) uniform uimageBuffer g_image[8];" NL
5281 			   "layout(binding = 0, offset = 0) uniform atomic_uint g_atomic_counter0;" NL
5282 			   "layout(binding = 1, offset = 0) uniform atomic_uint g_atomic_counter1;" NL
5283 			   "layout(binding = 2, offset = 0) uniform atomic_uint g_atomic_counter2;" NL
5284 			   "layout(binding = 3, offset = 0) uniform atomic_uint g_atomic_counter3;" NL
5285 			   "layout(binding = 4, offset = 0) uniform atomic_uint g_atomic_counter4;" NL
5286 			   "layout(binding = 5, offset = 0) uniform atomic_uint g_atomic_counter5;" NL
5287 			   "layout(binding = 6, offset = 0) uniform atomic_uint g_atomic_counter6;" NL
5288 			   "layout(binding = 7, offset = 0) uniform atomic_uint g_atomic_counter7;" NL
5289 			   "uniform uint g_uniform_def[480];" NL "uniform uint g_index = 0u;" NL NL "uint Add() {" NL
5290 			   "  switch (g_index) {" NL "    case 0: return atomicCounter(g_atomic_counter0);" NL
5291 			   "    case 1: return atomicCounter(g_atomic_counter1);" NL
5292 			   "    case 2: return atomicCounter(g_atomic_counter2);" NL
5293 			   "    case 3: return atomicCounter(g_atomic_counter3);" NL
5294 			   "    case 4: return atomicCounter(g_atomic_counter4);" NL
5295 			   "    case 5: return atomicCounter(g_atomic_counter5);" NL
5296 			   "    case 6: return atomicCounter(g_atomic_counter6);" NL
5297 			   "    case 7: return atomicCounter(g_atomic_counter7);" NL "  }" NL "}" NL "void main() {" NL
5298 			   "  g_shader_storage[g_index].data += g_uniform[g_index].data;" NL
5299 			   "  g_shader_storage[g_index].data += texelFetch(g_sampler[g_index], 0).x;" NL
5300 			   "  g_shader_storage[g_index].data += imageLoad(g_image[g_index], 0).x;" NL
5301 			   "  g_shader_storage[g_index].data += Add();" NL
5302 			   "  g_shader_storage[g_index].data += g_uniform_def[g_index];" NL "}";
5303 		m_program = CreateComputeProgram(glsl_cs);
5304 		glLinkProgram(m_program);
5305 		if (!CheckProgram(m_program))
5306 			return ERROR;
5307 
5308 		glGenBuffers(16, m_storage_buffer);
5309 		glGenBuffers(12, m_uniform_buffer);
5310 		glGenBuffers(8, m_atomic_buffer);
5311 		glGenBuffers(16, m_texture_buffer);
5312 		glGenTextures(16, m_texture);
5313 		glGenBuffers(8, m_image_buffer);
5314 		glGenTextures(8, m_image);
5315 
5316 		if (!RunIteration(0))
5317 			return ERROR;
5318 		if (!RunIteration(1))
5319 			return ERROR;
5320 		if (!RunIteration(5))
5321 			return ERROR;
5322 
5323 		return NO_ERROR;
5324 	}
Cleanup()5325 	virtual long Cleanup()
5326 	{
5327 		glUseProgram(0);
5328 		glDeleteProgram(m_program);
5329 		glDeleteBuffers(16, m_storage_buffer);
5330 		glDeleteBuffers(12, m_uniform_buffer);
5331 		glDeleteBuffers(8, m_atomic_buffer);
5332 		glDeleteBuffers(16, m_texture_buffer);
5333 		glDeleteTextures(16, m_texture);
5334 		glDeleteBuffers(8, m_image_buffer);
5335 		glDeleteTextures(8, m_image);
5336 		return NO_ERROR;
5337 	}
5338 };
5339 
5340 class AdvancedFP64Case1 : public ComputeShaderBase
5341 {
Title()5342 	virtual std::string Title()
5343 	{
5344 		return NL "FP64 support - built-in math functions";
5345 	}
Purpose()5346 	virtual std::string Purpose()
5347 	{
5348 		return NL "Verify that selected double precision math functions works as expected in the CS.";
5349 	}
Method()5350 	virtual std::string Method()
5351 	{
5352 		return NL "Create and dispatch CS which uses double precision math functions. Verify results.";
5353 	}
PassCriteria()5354 	virtual std::string PassCriteria()
5355 	{
5356 		return NL "Everything works as expected.";
5357 	}
5358 
5359 	GLuint m_program;
5360 	GLuint m_storage_buffer[4];
5361 	GLuint m_uniform_buffer[2];
5362 
Setup()5363 	virtual long Setup()
5364 	{
5365 		m_program = 0;
5366 		memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
5367 		memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
5368 		return NO_ERROR;
5369 	}
Run()5370 	virtual long Run()
5371 	{
5372 		const char* const glsl_cs =
5373 			NL "layout(local_size_x = 4) in;" NL "layout(std140, binding = 0) buffer ShaderStorageBlock {" NL
5374 			   "  double data;" NL "} g_shader_storage[4];" NL "layout(std140, binding = 0) uniform UniformBlock {" NL
5375 			   "  double data;" NL "} g_uniform[2];" NL "uniform dvec2 g_uniform_def;" NL NL "void main() {" NL
5376 			   "  if (gl_GlobalInvocationID.x == 0) {" NL
5377 			   "    g_shader_storage[0].data = floor(g_uniform[0].data + 0.1LF);" // floor(1.1LF) == 1.0LF
5378 			NL "  } else if (gl_GlobalInvocationID.x == 1) {" NL
5379 			   "    g_shader_storage[1].data = ceil(g_uniform[1].data + 0.2LF);" // ceil(2.2LF) == 3.0LF
5380 			NL "  } else if (gl_GlobalInvocationID.x == 2) {" NL
5381 			   "    g_shader_storage[2].data = min(g_uniform_def[0] + 0.1LF, 1.0LF);" // min(1.1LF, 1.0LF) == 1.0LF
5382 			NL "  } else if (gl_GlobalInvocationID.x == 3) {" NL
5383 			   "    g_shader_storage[3].data = max(g_uniform_def[0], g_uniform_def.y);" // max(1.0LF, 2.0LF) == 2.0LF
5384 			NL "  }" NL "}";
5385 		m_program = CreateComputeProgram(glsl_cs);
5386 		glLinkProgram(m_program);
5387 		if (!CheckProgram(m_program))
5388 			return ERROR;
5389 
5390 		glGenBuffers(4, m_storage_buffer);
5391 		for (GLuint i = 0; i < 4; ++i)
5392 		{
5393 			const GLdouble data = static_cast<GLdouble>(i + 1);
5394 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_storage_buffer[i]);
5395 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5396 		}
5397 
5398 		glGenBuffers(2, m_uniform_buffer);
5399 		for (GLuint i = 0; i < 2; ++i)
5400 		{
5401 			const GLdouble data = static_cast<GLdouble>(i + 1);
5402 			glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
5403 			glBufferData(GL_UNIFORM_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5404 		}
5405 
5406 		glUseProgram(m_program);
5407 		glUniform2d(glGetUniformLocation(m_program, "g_uniform_def"), 1.0, 2.0);
5408 		glDispatchCompute(1, 1, 1);
5409 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5410 
5411 		/* validate */
5412 		{
5413 			const GLdouble expected[4] = { 1.0, 3.0, 1.0, 2.0 };
5414 			for (int i = 0; i < 4; ++i)
5415 			{
5416 				GLdouble data;
5417 				glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[i]);
5418 				glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5419 				if (data != expected[i])
5420 				{
5421 					m_context.getTestContext().getLog()
5422 						<< tcu::TestLog::Message << "Data at index " << i << " is " << data << " should be "
5423 						<< expected[i] << "." << tcu::TestLog::EndMessage;
5424 					return ERROR;
5425 				}
5426 			}
5427 		}
5428 		return NO_ERROR;
5429 	}
Cleanup()5430 	virtual long Cleanup()
5431 	{
5432 		glUseProgram(0);
5433 		glDeleteProgram(m_program);
5434 		glDeleteBuffers(4, m_storage_buffer);
5435 		glDeleteBuffers(2, m_uniform_buffer);
5436 		return NO_ERROR;
5437 	}
5438 };
5439 
5440 class AdvancedFP64Case2 : public ComputeShaderBase
5441 {
Title()5442 	virtual std::string Title()
5443 	{
5444 		return NL "FP64 support - uniform variables";
5445 	}
Purpose()5446 	virtual std::string Purpose()
5447 	{
5448 		return NL "1. Verify that all types of double precision uniform variables work as expected in CS." NL
5449 				  "2. Verify that all double precision uniform variables can be updated with Uniform* and "
5450 				  "ProgramUniform* commands." NL "3. Verify that re-linking CS program works as expected.";
5451 	}
Method()5452 	virtual std::string Method()
5453 	{
5454 		return NL "1. Create CS which uses all (double precision) types of uniform variables." NL
5455 				  "2. Update uniform variables with ProgramUniform* commands." NL
5456 				  "3. Verify that uniform variables were updated correctly." NL "4. Re-link CS program." NL
5457 				  "5. Update uniform variables with Uniform* commands." NL
5458 				  "6. Verify that uniform variables were updated correctly.";
5459 	}
PassCriteria()5460 	virtual std::string PassCriteria()
5461 	{
5462 		return NL "Everything works as expected.";
5463 	}
5464 
5465 	GLuint m_program;
5466 	GLuint m_storage_buffer;
5467 
Setup()5468 	virtual long Setup()
5469 	{
5470 		m_program		 = 0;
5471 		m_storage_buffer = 0;
5472 		return NO_ERROR;
5473 	}
Run()5474 	virtual long Run()
5475 	{
5476 		const char* const glsl_cs = NL
5477 			"layout(local_size_x = 1) in;" NL "buffer Result {" NL "  int g_result;" NL "};" NL "uniform double g_0;" NL
5478 			"uniform dvec2 g_1;" NL "uniform dvec3 g_2;" NL "uniform dvec4 g_3;" NL "uniform dmat2 g_4;" NL
5479 			"uniform dmat2x3 g_5;" NL "uniform dmat2x4 g_6;" NL "uniform dmat3x2 g_7;" NL "uniform dmat3 g_8;" NL
5480 			"uniform dmat3x4 g_9;" NL "uniform dmat4x2 g_10;" NL "uniform dmat4x3 g_11;" NL "uniform dmat4 g_12;" NL NL
5481 			"void main() {" NL "  g_result = 1;" NL NL "  if (g_0 != 1.0LF) g_result = 0;" NL
5482 			"  if (g_1 != dvec2(2.0LF, 3.0LF)) g_result = 0;" NL
5483 			"  if (g_2 != dvec3(4.0LF, 5.0LF, 6.0LF)) g_result = 0;" NL
5484 			"  if (g_3 != dvec4(7.0LF, 8.0LF, 9.0LF, 10.0LF)) g_result = 0;" NL NL
5485 			"  if (g_4 != dmat2(11.0LF, 12.0LF, 13.0LF, 14.0LF)) g_result = 0;" NL
5486 			"  if (g_5 != dmat2x3(15.0LF, 16.0LF, 17.0LF, 18.0LF, 19.0LF, 20.0LF)) g_result = 0;" NL
5487 			"  if (g_6 != dmat2x4(21.0LF, 22.0LF, 23.0LF, 24.0LF, 25.0LF, 26.0LF, 27.0LF, 28.0LF)) g_result = 0;" NL NL
5488 			"  if (g_7 != dmat3x2(29.0LF, 30.0LF, 31.0LF, 32.0LF, 33.0LF, 34.0LF)) g_result = 0;" NL
5489 			"  if (g_8 != dmat3(35.0LF, 36.0LF, 37.0LF, 38.0LF, 39.0LF, 40.0LF, 41.0LF, 42.0LF, 43.0LF)) g_result = "
5490 			"0;" NL "  if (g_9 != dmat3x4(44.0LF, 45.0LF, 46.0LF, 47.0LF, 48.0LF, 49.0LF, 50.0LF, 51.0LF, 52.0LF, "
5491 			"53.0LF, 54.0LF, 55.0LF)) g_result = 0;" NL NL
5492 			"  if (g_10 != dmat4x2(56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0)) g_result = 0;" NL
5493 			"  if (g_11 != dmat4x3(63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0)) g_result = "
5494 			"0;" NL "  if (g_12 != dmat4(75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, "
5495 			"88.0, 89.0, 90.0)) g_result = 0;" NL "}";
5496 		m_program = CreateComputeProgram(glsl_cs);
5497 		glLinkProgram(m_program);
5498 		if (!CheckProgram(m_program))
5499 			return ERROR;
5500 
5501 		glGenBuffers(1, &m_storage_buffer);
5502 		/* create buffer */
5503 		{
5504 			const int data = 123;
5505 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
5506 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5507 		}
5508 
5509 		glProgramUniform1d(m_program, glGetUniformLocation(m_program, "g_0"), 1.0);
5510 		glProgramUniform2d(m_program, glGetUniformLocation(m_program, "g_1"), 2.0, 3.0);
5511 		glProgramUniform3d(m_program, glGetUniformLocation(m_program, "g_2"), 4.0, 5.0, 6.0);
5512 		glProgramUniform4d(m_program, glGetUniformLocation(m_program, "g_3"), 7.0, 8.0, 9.0, 10.0);
5513 
5514 		/* mat2 */
5515 		{
5516 			const GLdouble value[4] = { 11.0, 12.0, 13.0, 14.0 };
5517 			glProgramUniformMatrix2dv(m_program, glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
5518 		}
5519 		/* mat2x3 */
5520 		{
5521 			const GLdouble value[6] = { 15.0, 16.0, 17.0, 18.0, 19.0, 20.0 };
5522 			glProgramUniformMatrix2x3dv(m_program, glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
5523 		}
5524 		/* mat2x4 */
5525 		{
5526 			const GLdouble value[8] = { 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0 };
5527 			glProgramUniformMatrix2x4dv(m_program, glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
5528 		}
5529 
5530 		/* mat3x2 */
5531 		{
5532 			const GLdouble value[6] = { 29.0, 30.0, 31.0, 32.0, 33.0, 34.0 };
5533 			glProgramUniformMatrix3x2dv(m_program, glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
5534 		}
5535 		/* mat3 */
5536 		{
5537 			const GLdouble value[9] = { 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0 };
5538 			glProgramUniformMatrix3dv(m_program, glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
5539 		}
5540 		/* mat3x4 */
5541 		{
5542 			const GLdouble value[12] = { 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0 };
5543 			glProgramUniformMatrix3x4dv(m_program, glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
5544 		}
5545 
5546 		/* mat4x2 */
5547 		{
5548 			const GLdouble value[8] = { 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0 };
5549 			glProgramUniformMatrix4x2dv(m_program, glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
5550 		}
5551 		/* mat4x3 */
5552 		{
5553 			const GLdouble value[12] = { 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0 };
5554 			glProgramUniformMatrix4x3dv(m_program, glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
5555 		}
5556 		/* mat4 */
5557 		{
5558 			const GLdouble value[16] = { 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0,
5559 										 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0 };
5560 			glProgramUniformMatrix4dv(m_program, glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
5561 		}
5562 
5563 		glUseProgram(m_program);
5564 		glDispatchCompute(1, 1, 1);
5565 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5566 
5567 		/* validate */
5568 		{
5569 			int data;
5570 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5571 			if (data != 1)
5572 			{
5573 				m_context.getTestContext().getLog()
5574 					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
5575 				return ERROR;
5576 			}
5577 		}
5578 
5579 		// re-link program (all uniforms will be set to zero)
5580 		glLinkProgram(m_program);
5581 
5582 		/* clear buffer */
5583 		{
5584 			const int data = 123;
5585 			glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5586 		}
5587 
5588 		glUniform1d(glGetUniformLocation(m_program, "g_0"), 1.0);
5589 		glUniform2d(glGetUniformLocation(m_program, "g_1"), 2.0, 3.0);
5590 		glUniform3d(glGetUniformLocation(m_program, "g_2"), 4.0, 5.0, 6.0);
5591 		glUniform4d(glGetUniformLocation(m_program, "g_3"), 7.0, 8.0, 9.0, 10.0);
5592 
5593 		/* mat2 */
5594 		{
5595 			const GLdouble value[4] = { 11.0, 12.0, 13.0, 14.0 };
5596 			glUniformMatrix2dv(glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
5597 		}
5598 		/* mat2x3 */
5599 		{
5600 			const GLdouble value[6] = { 15.0, 16.0, 17.0, 18.0, 19.0, 20.0 };
5601 			glUniformMatrix2x3dv(glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
5602 		}
5603 		/* mat2x4 */
5604 		{
5605 			const GLdouble value[8] = { 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0 };
5606 			glUniformMatrix2x4dv(glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
5607 		}
5608 
5609 		/* mat3x2 */
5610 		{
5611 			const GLdouble value[6] = { 29.0, 30.0, 31.0, 32.0, 33.0, 34.0 };
5612 			glUniformMatrix3x2dv(glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
5613 		}
5614 		/* mat3 */
5615 		{
5616 			const GLdouble value[9] = { 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0 };
5617 			glUniformMatrix3dv(glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
5618 		}
5619 		/* mat3x4 */
5620 		{
5621 			const GLdouble value[12] = { 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0 };
5622 			glUniformMatrix3x4dv(glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
5623 		}
5624 
5625 		/* mat4x2 */
5626 		{
5627 			const GLdouble value[8] = { 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0 };
5628 			glUniformMatrix4x2dv(glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
5629 		}
5630 		/* mat4x3 */
5631 		{
5632 			const GLdouble value[12] = { 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0 };
5633 			glUniformMatrix4x3dv(glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
5634 		}
5635 		/* mat4 */
5636 		{
5637 			const GLdouble value[16] = { 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0,
5638 										 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0 };
5639 			glUniformMatrix4dv(glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
5640 		}
5641 
5642 		glDispatchCompute(1, 1, 1);
5643 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5644 
5645 		/* validate */
5646 		{
5647 			int data;
5648 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5649 			if (data != 1)
5650 			{
5651 				m_context.getTestContext().getLog()
5652 					<< tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
5653 				return ERROR;
5654 			}
5655 		}
5656 
5657 		return NO_ERROR;
5658 	}
Cleanup()5659 	virtual long Cleanup()
5660 	{
5661 		glUseProgram(0);
5662 		glDeleteProgram(m_program);
5663 		glDeleteBuffers(1, &m_storage_buffer);
5664 		return NO_ERROR;
5665 	}
5666 };
5667 
5668 class AdvancedFP64Case3 : public ComputeShaderBase
5669 {
Title()5670 	virtual std::string Title()
5671 	{
5672 		return NL "FP64 support - subroutines";
5673 	}
Purpose()5674 	virtual std::string Purpose()
5675 	{
5676 		return NL "Verify that subroutines that performs double precision computation works as expected in the CS.";
5677 	}
Method()5678 	virtual std::string Method()
5679 	{
5680 		return NL
5681 			"Create and dispatch CS that uses double precision math functions in subroutines to compute output values.";
5682 	}
PassCriteria()5683 	virtual std::string PassCriteria()
5684 	{
5685 		return NL "Everything works as expected.";
5686 	}
5687 
5688 	GLuint m_program;
5689 	GLuint m_storage_buffer;
5690 
Setup()5691 	virtual long Setup()
5692 	{
5693 		m_program		 = 0;
5694 		m_storage_buffer = 0;
5695 		return NO_ERROR;
5696 	}
Run()5697 	virtual long Run()
5698 	{
5699 		const char* const glsl_cs =
5700 			NL "layout(local_size_x = 1) in;" NL "uniform double[4] g_input;" NL "uniform int index;" NL
5701 			   "layout(std430, binding = 0) buffer Output {" NL "  double g_output[4];" NL "};" NL
5702 			   "subroutine double MathFunc(double x);" NL "subroutine uniform MathFunc g_func[4];" NL
5703 			   "subroutine(MathFunc)" NL "double Func0(double x) {" NL "  return abs(x);" // abs(-1.0LF) == 1.0LF
5704 			NL "}" NL "subroutine(MathFunc)" NL "double Func1(double x) {" NL
5705 			   "  return round(x);" // round(2.2LF) == 2.0LF
5706 			NL "}" NL "subroutine(MathFunc)" NL "double Func2(double x) {" NL
5707 			   "  return sign(x);" // sign(3.0LF) == 1.0LF
5708 			NL "}" NL "subroutine(MathFunc)" NL "double Func3(double x) {" NL
5709 			   "  return fract(x);" // fract(4.1LF) == 0.1LF
5710 			NL "}" NL "void main() {" NL "  int i = index;" NL "  g_output[i] = g_func[i](g_input[i]);" NL "}";
5711 		m_program = CreateComputeProgram(glsl_cs);
5712 		glLinkProgram(m_program);
5713 		if (!CheckProgram(m_program))
5714 			return ERROR;
5715 
5716 		glGenBuffers(1, &m_storage_buffer);
5717 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
5718 		glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(double), NULL, GL_STATIC_DRAW);
5719 
5720 		const GLuint index_compute0 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func0");
5721 		const GLuint index_compute1 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func1");
5722 		const GLuint index_compute2 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func2");
5723 		const GLuint index_compute3 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func3");
5724 		const GLint  loc_compute0   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[0]");
5725 		const GLint  loc_compute1   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[1]");
5726 		const GLint  loc_compute2   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[2]");
5727 		const GLint  loc_compute3   = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[3]");
5728 
5729 		glUseProgram(m_program);
5730 
5731 		// setup subroutines
5732 		GLuint indices[4];
5733 		indices[loc_compute0] = index_compute0;
5734 		indices[loc_compute1] = index_compute1;
5735 		indices[loc_compute2] = index_compute2;
5736 		indices[loc_compute3] = index_compute3;
5737 		glUniformSubroutinesuiv(GL_COMPUTE_SHADER, 4, indices);
5738 
5739 		/* set uniforms */
5740 		{
5741 			const GLdouble data[4] = { -1.0, 2.2, 3.0, 4.1 };
5742 			glUniform1dv(glGetUniformLocation(m_program, "g_input"), 4, data);
5743 		}
5744 		glUniform1i(glGetUniformLocation(m_program, "index"), 0);
5745 		glDispatchCompute(1, 1, 1);
5746 		glUniform1i(glGetUniformLocation(m_program, "index"), 1);
5747 		glDispatchCompute(1, 1, 1);
5748 		glUniform1i(glGetUniformLocation(m_program, "index"), 2);
5749 		glDispatchCompute(1, 1, 1);
5750 		glUniform1i(glGetUniformLocation(m_program, "index"), 3);
5751 		glDispatchCompute(1, 1, 1);
5752 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5753 
5754 		/* validate */
5755 		{
5756 			const GLdouble expected[4] = { 1.0, 2.0, 1.0, 0.1 };
5757 			GLdouble	   data[4];
5758 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
5759 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5760 			for (int i = 0; i < 4; ++i)
5761 			{
5762 				if (fabs(data[i] - expected[i]) > g_color_eps.x())
5763 				{
5764 					m_context.getTestContext().getLog()
5765 						<< tcu::TestLog::Message << "Data at index " << i << " is " << data[i] << " should be "
5766 						<< expected[i] << "." << tcu::TestLog::EndMessage;
5767 					return ERROR;
5768 				}
5769 			}
5770 		}
5771 		return NO_ERROR;
5772 	}
Cleanup()5773 	virtual long Cleanup()
5774 	{
5775 		glUseProgram(0);
5776 		glDeleteProgram(m_program);
5777 		glDeleteBuffers(1, &m_storage_buffer);
5778 		return NO_ERROR;
5779 	}
5780 };
5781 
5782 class AdvancedConditionalDispatching : public ComputeShaderBase
5783 {
Title()5784 	virtual std::string Title()
5785 	{
5786 		return NL "Conditional Dispatching";
5787 	}
Purpose()5788 	virtual std::string Purpose()
5789 	{
5790 		return NL "Verify that DispatchCompute and DispatchComputeIndirect commands work as expected inside "
5791 				  "conditional blocks.";
5792 	}
Method()5793 	virtual std::string Method()
5794 	{
5795 		return NL "1. Render two quads. One will pass depth-test and the second one will not." NL
5796 				  "2. Use GL_ANY_SAMPLES_PASSED query objects to 'remember' these results." NL
5797 				  "3. Use DispatchCompute and DispatchComputeIndirect commands inside conditional blocks using both "
5798 				  "query objects." NL
5799 				  "4. Verify that DispatchCompute and DispatchComputeIndirect commands are only executed in" NL
5800 				  "    the conditional block that uses query object that has passed depth-test.";
5801 	}
PassCriteria()5802 	virtual std::string PassCriteria()
5803 	{
5804 		return NL "Everything works as expected.";
5805 	}
5806 
5807 	GLuint m_program_vsfs;
5808 	GLuint m_program_cs;
5809 	GLuint m_vertex_array;
5810 	GLuint m_query[2];
5811 	GLuint m_storage_buffer;
5812 	GLuint m_dispatch_buffer;
5813 
Setup()5814 	virtual long Setup()
5815 	{
5816 		m_program_vsfs = 0;
5817 		m_program_cs   = 0;
5818 		m_vertex_array = 0;
5819 		memset(m_query, 0, sizeof(m_query));
5820 		m_storage_buffer  = 0;
5821 		m_dispatch_buffer = 0;
5822 		return NO_ERROR;
5823 	}
Run()5824 	virtual long Run()
5825 	{
5826 		const char* const glsl_vs = NL
5827 			"uniform float g_depth;" NL "uniform vec2[3] g_vertex = vec2[3](vec2(-1, -1), vec2(3, -1), vec2(-1, 3));" NL
5828 			"void main() {" NL "  gl_Position = vec4(g_vertex[gl_VertexID], g_depth, 1);" NL "}";
5829 
5830 		const char* const glsl_fs =
5831 			NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(0, 1, 0, 1);" NL "}";
5832 
5833 		m_program_vsfs = CreateProgram(glsl_vs, glsl_fs);
5834 		glLinkProgram(m_program_vsfs);
5835 		if (!CheckProgram(m_program_vsfs))
5836 			return ERROR;
5837 
5838 		const char* const glsl_cs =
5839 			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  int g_output;" NL "};" NL
5840 			   "void main() {" NL "  atomicAdd(g_output, 1);" NL "}";
5841 		m_program_cs = CreateComputeProgram(glsl_cs);
5842 		glLinkProgram(m_program_cs);
5843 		if (!CheckProgram(m_program_cs))
5844 			return ERROR;
5845 
5846 		/* create storage buffer */
5847 		{
5848 			const int data = 0;
5849 			glGenBuffers(1, &m_storage_buffer);
5850 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
5851 			glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_DYNAMIC_COPY);
5852 		}
5853 		/* create dispatch buffer */
5854 		{
5855 			const GLuint data[3] = { 2, 2, 2 };
5856 			glGenBuffers(1, &m_dispatch_buffer);
5857 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
5858 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
5859 		}
5860 
5861 		glGenVertexArrays(1, &m_vertex_array);
5862 		glGenQueries(2, m_query);
5863 
5864 		glEnable(GL_DEPTH_TEST);
5865 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
5866 
5867 		glUseProgram(m_program_vsfs);
5868 		glBindVertexArray(m_vertex_array);
5869 
5870 		// this draw call will pass depth test
5871 		glBeginQuery(GL_ANY_SAMPLES_PASSED, m_query[0]);
5872 		glUniform1f(glGetUniformLocation(m_program_vsfs, "g_depth"), 0.0f);
5873 		glDrawArrays(GL_TRIANGLES, 0, 3);
5874 		glEndQuery(GL_ANY_SAMPLES_PASSED);
5875 
5876 		// this draw call will NOT pass depth test
5877 		glBeginQuery(GL_ANY_SAMPLES_PASSED, m_query[1]);
5878 		glUniform1f(glGetUniformLocation(m_program_vsfs, "g_depth"), 0.5f);
5879 		glDrawArrays(GL_TRIANGLES, 0, 3);
5880 		glEndQuery(GL_ANY_SAMPLES_PASSED);
5881 
5882 		glDisable(GL_DEPTH_TEST);
5883 
5884 		glUseProgram(m_program_cs);
5885 
5886 		// these commands should be executed normally
5887 		glBeginConditionalRender(m_query[0], GL_QUERY_WAIT);
5888 		glDispatchCompute(2, 2, 2);
5889 		glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
5890 		glDispatchComputeIndirect(0);
5891 		glEndConditionalRender();
5892 
5893 		/* validate */
5894 		{
5895 			int data;
5896 			glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
5897 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5898 			if (data != 16)
5899 			{
5900 				m_context.getTestContext().getLog()
5901 					<< tcu::TestLog::Message << "Data is " << data << " should be 16." << tcu::TestLog::EndMessage;
5902 				return ERROR;
5903 			}
5904 		}
5905 
5906 		// these commands should be discarded
5907 		glBeginConditionalRender(m_query[1], GL_QUERY_WAIT);
5908 		glDispatchCompute(2, 2, 2);
5909 		glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
5910 		glDispatchComputeIndirect(0);
5911 		glEndConditionalRender();
5912 
5913 		/* validate */
5914 		{
5915 			int data;
5916 			glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
5917 			glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5918 			if (data != 16 && m_context.getRenderContext().getRenderTarget().getDepthBits() != 0)
5919 			{
5920 				m_context.getTestContext().getLog()
5921 					<< tcu::TestLog::Message << "Data is " << data << " should be 16." << tcu::TestLog::EndMessage;
5922 				return ERROR;
5923 			}
5924 			else if (data != 32 && m_context.getRenderContext().getRenderTarget().getDepthBits() == 0)
5925 			{
5926 				m_context.getTestContext().getLog()
5927 					<< tcu::TestLog::Message << "Data is " << data << " should be 32." << tcu::TestLog::EndMessage;
5928 				return ERROR;
5929 			}
5930 		}
5931 
5932 		if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
5933 		{
5934 			return ERROR;
5935 		}
5936 
5937 		return NO_ERROR;
5938 	}
Cleanup()5939 	virtual long Cleanup()
5940 	{
5941 		glUseProgram(0);
5942 		glDeleteProgram(m_program_vsfs);
5943 		glDeleteProgram(m_program_cs);
5944 		glDeleteVertexArrays(1, &m_vertex_array);
5945 		glDeleteQueries(2, m_query);
5946 		glDeleteBuffers(1, &m_storage_buffer);
5947 		glDeleteBuffers(1, &m_dispatch_buffer);
5948 		return NO_ERROR;
5949 	}
5950 };
5951 
5952 class NegativeAPINoActiveProgram : public ComputeShaderBase
5953 {
Title()5954 	virtual std::string Title()
5955 	{
5956 		return NL "API errors - no active program";
5957 	}
Purpose()5958 	virtual std::string Purpose()
5959 	{
5960 		return NL "Verify that appropriate errors are generated by the OpenGL API.";
5961 	}
Method()5962 	virtual std::string Method()
5963 	{
5964 		return NL "";
5965 	}
PassCriteria()5966 	virtual std::string PassCriteria()
5967 	{
5968 		return NL "";
5969 	}
5970 
5971 	GLuint m_program;
5972 
Setup()5973 	virtual long Setup()
5974 	{
5975 		m_program = 0;
5976 		return NO_ERROR;
5977 	}
Run()5978 	virtual long Run()
5979 	{
5980 		glDispatchCompute(1, 2, 3);
5981 		if (glGetError() != GL_INVALID_OPERATION)
5982 		{
5983 			m_context.getTestContext().getLog()
5984 				<< tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
5985 				<< "DispatchComputeIndirect if there is no active program for the compute\n"
5986 				<< "shader stage." << tcu::TestLog::EndMessage;
5987 			return ERROR;
5988 		}
5989 
5990 		/* indirect dispatch */
5991 		{
5992 			GLuint		 buffer;
5993 			const GLuint num_group[3] = { 3, 2, 1 };
5994 			glGenBuffers(1, &buffer);
5995 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
5996 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_group), num_group, GL_STATIC_DRAW);
5997 			glDispatchComputeIndirect(0);
5998 			glDeleteBuffers(1, &buffer);
5999 			if (glGetError() != GL_INVALID_OPERATION)
6000 			{
6001 				m_context.getTestContext().getLog()
6002 					<< tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
6003 					<< "DispatchComputeIndirect if there is no active program for the compute\n"
6004 					<< "shader stage." << tcu::TestLog::EndMessage;
6005 				return ERROR;
6006 			}
6007 		}
6008 
6009 		const char* const glsl_vs =
6010 			NL "layout(location = 0) in vec4 g_position;" NL "void main() {" NL "  gl_Position = g_position;" NL "}";
6011 
6012 		const char* const glsl_fs =
6013 			NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(1);" NL "}";
6014 
6015 		m_program = CreateProgram(glsl_vs, glsl_fs);
6016 		glLinkProgram(m_program);
6017 		if (!CheckProgram(m_program))
6018 			return ERROR;
6019 
6020 		glUseProgram(m_program);
6021 
6022 		glDispatchCompute(1, 2, 3);
6023 		if (glGetError() != GL_INVALID_OPERATION)
6024 		{
6025 			m_context.getTestContext().getLog()
6026 				<< tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
6027 				<< "DispatchComputeIndirect if there is no active program for the compute\n"
6028 				<< "shader stage." << tcu::TestLog::EndMessage;
6029 			return ERROR;
6030 		}
6031 
6032 		/* indirect dispatch */
6033 		{
6034 			GLuint		 buffer;
6035 			const GLuint num_group[3] = { 3, 2, 1 };
6036 			glGenBuffers(1, &buffer);
6037 			glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
6038 			glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_group), num_group, GL_STATIC_DRAW);
6039 			glDispatchComputeIndirect(0);
6040 			glDeleteBuffers(1, &buffer);
6041 			if (glGetError() != GL_INVALID_OPERATION)
6042 			{
6043 				m_context.getTestContext().getLog()
6044 					<< tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
6045 					<< "DispatchComputeIndirect if there is no active program for the compute\n"
6046 					<< "shader stage." << tcu::TestLog::EndMessage;
6047 				return ERROR;
6048 			}
6049 		}
6050 
6051 		return NO_ERROR;
6052 	}
Cleanup()6053 	virtual long Cleanup()
6054 	{
6055 		glUseProgram(0);
6056 		glDeleteProgram(m_program);
6057 		return NO_ERROR;
6058 	}
6059 };
6060 
6061 class NegativeAPIWorkGroupCount : public ComputeShaderBase
6062 {
Title()6063 	virtual std::string Title()
6064 	{
6065 		return NL "API errors - invalid work group count";
6066 	}
Purpose()6067 	virtual std::string Purpose()
6068 	{
6069 		return NL "Verify that appropriate errors are generated by the OpenGL API.";
6070 	}
Method()6071 	virtual std::string Method()
6072 	{
6073 		return NL "";
6074 	}
PassCriteria()6075 	virtual std::string PassCriteria()
6076 	{
6077 		return NL "";
6078 	}
6079 
6080 	GLuint m_program;
6081 	GLuint m_storage_buffer;
6082 
Setup()6083 	virtual long Setup()
6084 	{
6085 		m_program		 = 0;
6086 		m_storage_buffer = 0;
6087 		return NO_ERROR;
6088 	}
Run()6089 	virtual long Run()
6090 	{
6091 		const char* const glsl_cs =
6092 			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
6093 			   "void main() {" NL
6094 			   "  g_output[gl_GlobalInvocationID.x * gl_GlobalInvocationID.y * gl_GlobalInvocationID.z] = 0;" NL "}";
6095 		m_program = CreateComputeProgram(glsl_cs);
6096 		glLinkProgram(m_program);
6097 		if (!CheckProgram(m_program))
6098 			return ERROR;
6099 
6100 		glGenBuffers(1, &m_storage_buffer);
6101 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
6102 		glBufferData(GL_SHADER_STORAGE_BUFFER, 100000, NULL, GL_DYNAMIC_DRAW);
6103 
6104 		GLint x, y, z;
6105 		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &x);
6106 		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &y);
6107 		glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &z);
6108 
6109 		glUseProgram(m_program);
6110 
6111 		glDispatchCompute(x + 1, 1, 1);
6112 		if (glGetError() != GL_INVALID_VALUE)
6113 		{
6114 			m_context.getTestContext().getLog()
6115 				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
6116 				<< "<num_groups_y> or <num_groups_z> is greater than the value of\n"
6117 				<< "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension." << tcu::TestLog::EndMessage;
6118 			return ERROR;
6119 		}
6120 
6121 		glDispatchCompute(1, y + 1, 1);
6122 		if (glGetError() != GL_INVALID_VALUE)
6123 		{
6124 			m_context.getTestContext().getLog()
6125 				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
6126 				<< "<num_groups_y> or <num_groups_z> is greater than the value of\n"
6127 				<< "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension." << tcu::TestLog::EndMessage;
6128 			return ERROR;
6129 		}
6130 
6131 		glDispatchCompute(1, 1, z + 1);
6132 		if (glGetError() != GL_INVALID_VALUE)
6133 		{
6134 			m_context.getTestContext().getLog()
6135 				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
6136 				<< "<num_groups_y> or <num_groups_z> is greater than the value of\n"
6137 				<< "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension." << tcu::TestLog::EndMessage;
6138 			return ERROR;
6139 		}
6140 
6141 		return NO_ERROR;
6142 	}
Cleanup()6143 	virtual long Cleanup()
6144 	{
6145 		glUseProgram(0);
6146 		glDeleteProgram(m_program);
6147 		glDeleteBuffers(1, &m_storage_buffer);
6148 		return NO_ERROR;
6149 	}
6150 };
6151 
6152 class NegativeAPIIndirect : public ComputeShaderBase
6153 {
Title()6154 	virtual std::string Title()
6155 	{
6156 		return NL "API errors - incorrect DispatchComputeIndirect usage";
6157 	}
Purpose()6158 	virtual std::string Purpose()
6159 	{
6160 		return NL "Verify that appropriate errors are generated by the OpenGL API.";
6161 	}
Method()6162 	virtual std::string Method()
6163 	{
6164 		return NL "";
6165 	}
PassCriteria()6166 	virtual std::string PassCriteria()
6167 	{
6168 		return NL "";
6169 	}
6170 
6171 	GLuint m_program;
6172 	GLuint m_storage_buffer;
6173 	GLuint m_dispatch_buffer;
6174 
Setup()6175 	virtual long Setup()
6176 	{
6177 		m_program		  = 0;
6178 		m_storage_buffer  = 0;
6179 		m_dispatch_buffer = 0;
6180 		return NO_ERROR;
6181 	}
6182 
Run()6183 	virtual long Run()
6184 	{
6185 		const char* const glsl_cs =
6186 			NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
6187 			   "void main() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
6188 		m_program = CreateComputeProgram(glsl_cs);
6189 		glLinkProgram(m_program);
6190 		if (!CheckProgram(m_program))
6191 			return ERROR;
6192 
6193 		glGenBuffers(1, &m_storage_buffer);
6194 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
6195 		glBufferData(GL_SHADER_STORAGE_BUFFER, 100000, NULL, GL_DYNAMIC_DRAW);
6196 
6197 		const GLuint num_groups[6] = { 1, 1, 1, 1, 1, 1 };
6198 		glGenBuffers(1, &m_dispatch_buffer);
6199 		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
6200 		glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), num_groups, GL_STATIC_COPY);
6201 
6202 		glUseProgram(m_program);
6203 
6204 		glDispatchComputeIndirect(-2);
6205 		if (glGetError() != GL_INVALID_VALUE)
6206 		{
6207 			m_context.getTestContext().getLog()
6208 				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchComputeIndirect if <indirect> is\n"
6209 				<< "less than zero or not a multiple of four." << tcu::TestLog::EndMessage;
6210 			return ERROR;
6211 		}
6212 
6213 		glDispatchComputeIndirect(3);
6214 		if (glGetError() != GL_INVALID_VALUE)
6215 		{
6216 			m_context.getTestContext().getLog()
6217 				<< tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchComputeIndirect if <indirect> is\n"
6218 				<< "less than zero or not a multiple of four." << tcu::TestLog::EndMessage;
6219 			return ERROR;
6220 		}
6221 
6222 		glDispatchComputeIndirect(16);
6223 		if (glGetError() != GL_INVALID_OPERATION)
6224 		{
6225 			m_context.getTestContext().getLog()
6226 				<< tcu::TestLog::Message
6227 				<< "INVALID_OPERATION is generated by DispatchComputeIndirect if no buffer is\n"
6228 				<< "bound to DISPATCH_INDIRECT_BUFFER or if the command would source data\n"
6229 				<< "beyond the end of the bound buffer object." << tcu::TestLog::EndMessage;
6230 			return ERROR;
6231 		}
6232 
6233 		glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
6234 		glDispatchComputeIndirect(0);
6235 		if (glGetError() != GL_INVALID_OPERATION)
6236 		{
6237 			m_context.getTestContext().getLog()
6238 				<< tcu::TestLog::Message
6239 				<< "INVALID_OPERATION is generated by DispatchComputeIndirect if no buffer is\n"
6240 				<< "bound to DISPATCH_INDIRECT_BUFFER or if the command would source data\n"
6241 				<< "beyond the end of the bound buffer object." << tcu::TestLog::EndMessage;
6242 			return ERROR;
6243 		}
6244 
6245 		return NO_ERROR;
6246 	}
Cleanup()6247 	virtual long Cleanup()
6248 	{
6249 		glUseProgram(0);
6250 		glDeleteProgram(m_program);
6251 		glDeleteBuffers(1, &m_storage_buffer);
6252 		glDeleteBuffers(1, &m_dispatch_buffer);
6253 		return NO_ERROR;
6254 	}
6255 };
6256 
6257 class NegativeAPIProgram : public ComputeShaderBase
6258 {
Title()6259 	virtual std::string Title()
6260 	{
6261 		return NL "API errors - program state";
6262 	}
Purpose()6263 	virtual std::string Purpose()
6264 	{
6265 		return NL "Verify that appropriate errors are generated by the OpenGL API.";
6266 	}
Method()6267 	virtual std::string Method()
6268 	{
6269 		return NL "";
6270 	}
PassCriteria()6271 	virtual std::string PassCriteria()
6272 	{
6273 		return NL "";
6274 	}
6275 
6276 	GLuint m_program;
6277 	GLuint m_storage_buffer;
6278 
Setup()6279 	virtual long Setup()
6280 	{
6281 		m_program		 = 0;
6282 		m_storage_buffer = 0;
6283 		return NO_ERROR;
6284 	}
Run()6285 	virtual long Run()
6286 	{
6287 		const char* const glsl_vs =
6288 			NL "layout(location = 0) in vec4 g_position;" NL "void main() {" NL "  gl_Position = g_position;" NL "}";
6289 
6290 		const char* const glsl_fs =
6291 			NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL "  g_color = vec4(1);" NL "}";
6292 		m_program = CreateProgram(glsl_vs, glsl_fs);
6293 
6294 		GLint v[3];
6295 		glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
6296 		if (glGetError() != GL_INVALID_OPERATION)
6297 		{
6298 			m_context.getTestContext().getLog()
6299 				<< tcu::TestLog::Message << "INVALID_OPERATION is generated by GetProgramiv if <pname> is\n"
6300 				<< "COMPUTE_LOCAL_WORK_SIZE and either the program has not been linked\n"
6301 				<< "successfully, or has been linked but contains no compute shaders." << tcu::TestLog::EndMessage;
6302 			return ERROR;
6303 		}
6304 
6305 		glLinkProgram(m_program);
6306 		if (!CheckProgram(m_program))
6307 			return ERROR;
6308 
6309 		glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
6310 		if (glGetError() != GL_INVALID_OPERATION)
6311 		{
6312 			m_context.getTestContext().getLog()
6313 				<< tcu::TestLog::Message << "INVALID_OPERATION is generated by GetProgramiv if <pname> is\n"
6314 				<< "COMPUTE_LOCAL_WORK_SIZE and either the program has not been linked\n"
6315 				<< "successfully, or has been linked but contains no compute shaders." << tcu::TestLog::EndMessage;
6316 			return ERROR;
6317 		}
6318 		glDeleteProgram(m_program);
6319 
6320 		const char* const glsl_cs =
6321 			"#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
6322 			"  uint g_output[];" NL "};" NL "void main() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
6323 		m_program = glCreateProgram();
6324 
6325 		GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
6326 		glAttachShader(m_program, sh);
6327 		glDeleteShader(sh);
6328 		glShaderSource(sh, 1, &glsl_cs, NULL);
6329 		glCompileShader(sh);
6330 
6331 		sh = glCreateShader(GL_VERTEX_SHADER);
6332 		glAttachShader(m_program, sh);
6333 		glDeleteShader(sh);
6334 		glShaderSource(sh, 1, &glsl_vs, NULL);
6335 		glCompileShader(sh);
6336 
6337 		sh = glCreateShader(GL_FRAGMENT_SHADER);
6338 		glAttachShader(m_program, sh);
6339 		glDeleteShader(sh);
6340 		glShaderSource(sh, 1, &glsl_fs, NULL);
6341 		glCompileShader(sh);
6342 
6343 		glLinkProgram(m_program);
6344 		GLint status;
6345 		glGetProgramiv(m_program, GL_LINK_STATUS, &status);
6346 		if (status == GL_TRUE)
6347 		{
6348 			m_context.getTestContext().getLog()
6349 				<< tcu::TestLog::Message << "LinkProgram will fail if <program> contains a combination"
6350 				<< " of compute and\n non-compute shaders.\n"
6351 				<< tcu::TestLog::EndMessage;
6352 			return ERROR;
6353 		}
6354 
6355 		return NO_ERROR;
6356 	}
Cleanup()6357 	virtual long Cleanup()
6358 	{
6359 		glUseProgram(0);
6360 		glDeleteProgram(m_program);
6361 		glDeleteBuffers(1, &m_storage_buffer);
6362 		return NO_ERROR;
6363 	}
6364 };
6365 
6366 class NegativeGLSLCompileTimeErrors : public ComputeShaderBase
6367 {
Title()6368 	virtual std::string Title()
6369 	{
6370 		return NL "Compile-time errors";
6371 	}
Purpose()6372 	virtual std::string Purpose()
6373 	{
6374 		return NL "Verify that appropriate errors are generated by the GLSL compiler.";
6375 	}
Method()6376 	virtual std::string Method()
6377 	{
6378 		return NL "";
6379 	}
PassCriteria()6380 	virtual std::string PassCriteria()
6381 	{
6382 		return NL "";
6383 	}
6384 
Shader1(int x,int y,int z)6385 	static std::string Shader1(int x, int y, int z)
6386 	{
6387 		std::stringstream ss;
6388 		ss << "#version 430 core" NL "layout(local_size_x = " << x << ", local_size_y = " << y
6389 		   << ", local_size_z = " << z << ") in;" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
6390 										  "void main() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
6391 		return ss.str();
6392 	}
Run()6393 	virtual long Run()
6394 	{
6395 		// gl_GlobalInvocationID requires "#version 430" or later or GL_ARB_compute_shader
6396 		// extension enabled
6397 		if (!Compile("#version 420 core" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
6398 					 "  uint g_output[];" NL "};" NL "void main() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL
6399 					 "}"))
6400 			return ERROR;
6401 
6402 		if (!Compile("#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(local_size_x = 2) in;" NL
6403 					 "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL "void main() {" NL
6404 					 "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
6405 			return ERROR;
6406 
6407 		if (!Compile("#version 430 core" NL "layout(local_size_x = 1) in;" NL "in uint x;" NL
6408 					 "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL "void main() {" NL
6409 					 "  g_output[gl_GlobalInvocationID.x] = x;" NL "}"))
6410 			return ERROR;
6411 
6412 		if (!Compile("#version 430 core" NL "layout(local_size_x = 1) in;" NL "out uint x;" NL
6413 					 "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL "void main() {" NL
6414 					 "  g_output[gl_GlobalInvocationID.x] = 0;" NL "  x = 0;" NL "}"))
6415 			return ERROR;
6416 
6417 		{
6418 			GLint x, y, z;
6419 			glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &x);
6420 			glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &y);
6421 			glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &z);
6422 
6423 			if (!Compile(Shader1(x + 1, 1, 1)))
6424 				return ERROR;
6425 			if (!Compile(Shader1(1, y + 1, 1)))
6426 				return ERROR;
6427 			if (!Compile(Shader1(1, 1, z + 1)))
6428 				return ERROR;
6429 		}
6430 
6431 		return NO_ERROR;
6432 	}
6433 
Compile(const std::string & source)6434 	bool Compile(const std::string& source)
6435 	{
6436 		const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
6437 
6438 		const char* const src = source.c_str();
6439 		glShaderSource(sh, 1, &src, NULL);
6440 		glCompileShader(sh);
6441 
6442 		GLchar log[1024];
6443 		glGetShaderInfoLog(sh, sizeof(log), NULL, log);
6444 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader Info Log:\n"
6445 											<< log << tcu::TestLog::EndMessage;
6446 
6447 		GLint status;
6448 		glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
6449 		glDeleteShader(sh);
6450 
6451 		if (status == GL_TRUE)
6452 		{
6453 			m_context.getTestContext().getLog()
6454 				<< tcu::TestLog::Message << "Compilation should fail." << tcu::TestLog::EndMessage;
6455 			return false;
6456 		}
6457 
6458 		return true;
6459 	}
6460 };
6461 
6462 class NegativeGLSLLinkTimeErrors : public ComputeShaderBase
6463 {
Title()6464 	virtual std::string Title()
6465 	{
6466 		return NL "Link-time errors";
6467 	}
Purpose()6468 	virtual std::string Purpose()
6469 	{
6470 		return NL "Verify that appropriate errors are generated by the GLSL linker.";
6471 	}
Method()6472 	virtual std::string Method()
6473 	{
6474 		return NL "";
6475 	}
PassCriteria()6476 	virtual std::string PassCriteria()
6477 	{
6478 		return NL "";
6479 	}
6480 
Run()6481 	virtual long Run()
6482 	{
6483 		// no layout
6484 		if (!Link("#version 430 core" NL "void Run();" NL "void main() {" NL "  Run();" NL "}",
6485 				  "#version 430 core" NL "layout(std430) buffer Output {" NL "  uint g_output[];" NL "};" NL
6486 				  "void Run() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
6487 			return ERROR;
6488 
6489 		if (!Link("#version 430 core" NL "layout(local_size_x = 2) in;" NL "void Run();" NL "void main() {" NL
6490 				  "  Run();" NL "}",
6491 				  "#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
6492 				  "  uint g_output[];" NL "};" NL "void Run() {" NL "  g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
6493 			return ERROR;
6494 
6495 		return NO_ERROR;
6496 	}
6497 
Link(const std::string & cs0,const std::string & cs1)6498 	bool Link(const std::string& cs0, const std::string& cs1)
6499 	{
6500 		const GLuint p = glCreateProgram();
6501 
6502 		/* shader 0 */
6503 		{
6504 			GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
6505 			glAttachShader(p, sh);
6506 			glDeleteShader(sh);
6507 			const char* const src = cs0.c_str();
6508 			glShaderSource(sh, 1, &src, NULL);
6509 			glCompileShader(sh);
6510 
6511 			GLint status;
6512 			glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
6513 			if (status == GL_FALSE)
6514 			{
6515 				glDeleteProgram(p);
6516 				m_context.getTestContext().getLog()
6517 					<< tcu::TestLog::Message << "CS0 compilation should be ok." << tcu::TestLog::EndMessage;
6518 				return false;
6519 			}
6520 		}
6521 		/* shader 1 */
6522 		{
6523 			GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
6524 			glAttachShader(p, sh);
6525 			glDeleteShader(sh);
6526 			const char* const src = cs1.c_str();
6527 			glShaderSource(sh, 1, &src, NULL);
6528 			glCompileShader(sh);
6529 
6530 			GLint status;
6531 			glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
6532 			if (status == GL_FALSE)
6533 			{
6534 				glDeleteProgram(p);
6535 				m_context.getTestContext().getLog()
6536 					<< tcu::TestLog::Message << "CS1 compilation should be ok." << tcu::TestLog::EndMessage;
6537 				return false;
6538 			}
6539 		}
6540 
6541 		glLinkProgram(p);
6542 
6543 		GLchar log[1024];
6544 		glGetProgramInfoLog(p, sizeof(log), NULL, log);
6545 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n"
6546 											<< log << tcu::TestLog::EndMessage;
6547 
6548 		GLint status;
6549 		glGetProgramiv(p, GL_LINK_STATUS, &status);
6550 		glDeleteProgram(p);
6551 
6552 		if (status == GL_TRUE)
6553 		{
6554 			m_context.getTestContext().getLog()
6555 				<< tcu::TestLog::Message << "Link operation should fail." << tcu::TestLog::EndMessage;
6556 			return false;
6557 		}
6558 
6559 		return true;
6560 	}
6561 };
6562 
6563 class BasicWorkGroupSizeIsConst : public ComputeShaderBase
6564 {
Title()6565 	virtual std::string Title()
6566 	{
6567 		return NL "gl_WorkGroupSize is an constant";
6568 	}
Purpose()6569 	virtual std::string Purpose()
6570 	{
6571 		return NL "Verify that gl_WorkGroupSize can be used as an constant expression.";
6572 	}
Method()6573 	virtual std::string Method()
6574 	{
6575 		return NL "";
6576 	}
PassCriteria()6577 	virtual std::string PassCriteria()
6578 	{
6579 		return NL "";
6580 	}
6581 
6582 	GLuint m_program;
6583 	GLuint m_storage_buffer;
6584 
Setup()6585 	virtual long Setup()
6586 	{
6587 		m_program		 = 0;
6588 		m_storage_buffer = 0;
6589 		return NO_ERROR;
6590 	}
6591 
Run()6592 	virtual long Run()
6593 	{
6594 		const char* const glsl_cs =
6595 			NL "layout(local_size_x = 2, local_size_y = 3, local_size_z = 4) in;" NL
6596 			   "layout(std430, binding = 0) buffer Output {" NL "  uint g_buffer[22 + gl_WorkGroupSize.x];" NL "};" NL
6597 			   "shared uint g_shared[gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z];" NL
6598 			   "uniform uint g_uniform[gl_WorkGroupSize.z + 20] = { "
6599 			   "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 };" NL "void main() {" NL
6600 			   "  g_shared[gl_LocalInvocationIndex] = 1U;" NL "  groupMemoryBarrier();" NL "  barrier();" NL
6601 			   "  uint sum = 0;" NL
6602 			   "  for (uint i = 0; i < gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z; ++i) {" NL
6603 			   "    sum += g_shared[i];" NL "  }" NL "  sum += g_uniform[gl_LocalInvocationIndex];" NL
6604 			   "  g_buffer[gl_LocalInvocationIndex] = sum;" NL "}";
6605 		m_program = CreateComputeProgram(glsl_cs);
6606 		glLinkProgram(m_program);
6607 		if (!CheckProgram(m_program))
6608 			return ERROR;
6609 
6610 		glGenBuffers(1, &m_storage_buffer);
6611 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
6612 		glBufferData(GL_SHADER_STORAGE_BUFFER, 24 * sizeof(GLuint), NULL, GL_STATIC_DRAW);
6613 
6614 		glUseProgram(m_program);
6615 		glDispatchCompute(1, 1, 1);
6616 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
6617 
6618 		long	error = NO_ERROR;
6619 		GLuint* data;
6620 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
6621 		data =
6622 			static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * 24, GL_MAP_READ_BIT));
6623 		for (GLuint i = 0; i < 24; ++i)
6624 		{
6625 			if (data[i] != (i + 25))
6626 			{
6627 				m_context.getTestContext().getLog()
6628 					<< tcu::TestLog::Message << "Data at index " << i << " is " << data[i] << " should be " << i + 25
6629 					<< "." << tcu::TestLog::EndMessage;
6630 				error = ERROR;
6631 			}
6632 		}
6633 		glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
6634 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
6635 		return error;
6636 	}
6637 
Cleanup()6638 	virtual long Cleanup()
6639 	{
6640 		glUseProgram(0);
6641 		glDeleteProgram(m_program);
6642 		glDeleteBuffers(1, &m_storage_buffer);
6643 		return NO_ERROR;
6644 	}
6645 };
6646 
6647 } // anonymous namespace
6648 
ComputeShaderTests(deqp::Context & context)6649 ComputeShaderTests::ComputeShaderTests(deqp::Context& context) : TestCaseGroup(context, "compute_shader", "")
6650 {
6651 }
6652 
~ComputeShaderTests(void)6653 ComputeShaderTests::~ComputeShaderTests(void)
6654 {
6655 }
6656 
init()6657 void ComputeShaderTests::init()
6658 {
6659 	using namespace deqp;
6660 	addChild(new TestSubcase(m_context, "simple-compute", TestSubcase::Create<SimpleCompute>));
6661 	addChild(new TestSubcase(m_context, "one-work-group", TestSubcase::Create<BasicOneWorkGroup>));
6662 	addChild(new TestSubcase(m_context, "resource-ubo", TestSubcase::Create<BasicResourceUBO>));
6663 	addChild(new TestSubcase(m_context, "resource-texture", TestSubcase::Create<BasicResourceTexture>));
6664 	addChild(new TestSubcase(m_context, "resource-image", TestSubcase::Create<BasicResourceImage>));
6665 	addChild(new TestSubcase(m_context, "resource-atomic-counter", TestSubcase::Create<BasicResourceAtomicCounter>));
6666 	addChild(new TestSubcase(m_context, "resource-subroutine", TestSubcase::Create<BasicResourceSubroutine>));
6667 	addChild(new TestSubcase(m_context, "resource-uniform", TestSubcase::Create<BasicResourceUniform>));
6668 	addChild(new TestSubcase(m_context, "built-in-variables", TestSubcase::Create<BasicBuiltinVariables>));
6669 	addChild(new TestSubcase(m_context, "max", TestSubcase::Create<BasicMax>));
6670 	addChild(new TestSubcase(m_context, "work-group-size", TestSubcase::Create<BasicWorkGroupSizeIsConst>));
6671 	addChild(new TestSubcase(m_context, "build-monolithic", TestSubcase::Create<BasicBuildMonolithic>));
6672 	addChild(new TestSubcase(m_context, "build-separable", TestSubcase::Create<BasicBuildSeparable>));
6673 	addChild(new TestSubcase(m_context, "shared-simple", TestSubcase::Create<BasicSharedSimple>));
6674 	addChild(new TestSubcase(m_context, "shared-struct", TestSubcase::Create<BasicSharedStruct>));
6675 	addChild(new TestSubcase(m_context, "dispatch-indirect", TestSubcase::Create<BasicDispatchIndirect>));
6676 	addChild(new TestSubcase(m_context, "sso-compute-pipeline", TestSubcase::Create<BasicSSOComputePipeline>));
6677 	addChild(new TestSubcase(m_context, "sso-case2", TestSubcase::Create<BasicSSOCase2>));
6678 	addChild(new TestSubcase(m_context, "sso-case3", TestSubcase::Create<BasicSSOCase3>));
6679 	addChild(new TestSubcase(m_context, "atomic-case1", TestSubcase::Create<BasicAtomicCase1>));
6680 	addChild(new TestSubcase(m_context, "atomic-case2", TestSubcase::Create<BasicAtomicCase2>));
6681 	addChild(new TestSubcase(m_context, "atomic-case3", TestSubcase::Create<BasicAtomicCase3>));
6682 	addChild(new TestSubcase(m_context, "copy-image", TestSubcase::Create<AdvancedCopyImage>));
6683 	addChild(new TestSubcase(m_context, "pipeline-pre-vs", TestSubcase::Create<AdvancedPipelinePreVS>));
6684 	addChild(
6685 		new TestSubcase(m_context, "pipeline-gen-draw-commands", TestSubcase::Create<AdvancedPipelineGenDrawCommands>));
6686 	addChild(new TestSubcase(m_context, "pipeline-compute-chain", TestSubcase::Create<AdvancedPipelineComputeChain>));
6687 	addChild(new TestSubcase(m_context, "pipeline-post-fs", TestSubcase::Create<AdvancedPipelinePostFS>));
6688 	addChild(new TestSubcase(m_context, "pipeline-post-xfb", TestSubcase::Create<AdvancedPipelinePostXFB>));
6689 	addChild(new TestSubcase(m_context, "shared-indexing", TestSubcase::Create<AdvancedSharedIndexing>));
6690 	addChild(new TestSubcase(m_context, "shared-max", TestSubcase::Create<AdvancedSharedMax>));
6691 	addChild(new TestSubcase(m_context, "dynamic-paths", TestSubcase::Create<AdvancedDynamicPaths>));
6692 	addChild(new TestSubcase(m_context, "resources-max", TestSubcase::Create<AdvancedResourcesMax>));
6693 	addChild(new TestSubcase(m_context, "fp64-case1", TestSubcase::Create<AdvancedFP64Case1>));
6694 	addChild(new TestSubcase(m_context, "fp64-case2", TestSubcase::Create<AdvancedFP64Case2>));
6695 	addChild(new TestSubcase(m_context, "fp64-case3", TestSubcase::Create<AdvancedFP64Case3>));
6696 	addChild(
6697 		new TestSubcase(m_context, "conditional-dispatching", TestSubcase::Create<AdvancedConditionalDispatching>));
6698 	addChild(new TestSubcase(m_context, "api-no-active-program", TestSubcase::Create<NegativeAPINoActiveProgram>));
6699 	addChild(new TestSubcase(m_context, "api-work-group-count", TestSubcase::Create<NegativeAPIWorkGroupCount>));
6700 	addChild(new TestSubcase(m_context, "api-indirect", TestSubcase::Create<NegativeAPIIndirect>));
6701 	addChild(new TestSubcase(m_context, "api-program", TestSubcase::Create<NegativeAPIProgram>));
6702 	addChild(
6703 		new TestSubcase(m_context, "glsl-compile-time-errors", TestSubcase::Create<NegativeGLSLCompileTimeErrors>));
6704 	addChild(new TestSubcase(m_context, "glsl-link-time-errors", TestSubcase::Create<NegativeGLSLLinkTimeErrors>));
6705 }
6706 } // gl4cts namespace
6707