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