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