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