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