1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 */ /*-------------------------------------------------------------------*/
24 #include "gl4cComputeShaderTests.hpp"
25 #include "glwEnums.hpp"
26 #include "glwFunctions.hpp"
27 #include "tcuMatrix.hpp"
28 #include "tcuMatrixUtil.hpp"
29 #include "tcuRenderTarget.hpp"
55 const char* const kGLSLVer = "#version 430 core\n";
57 class ComputeShaderBase : public deqp::SubcaseBase
61 virtual ~ComputeShaderBase()
66 : renderTarget(m_context.getRenderContext().getRenderTarget()), pixelFormat(renderTarget.getPixelFormat())
68 float epsilon_zero = 1.f / (1 << 13);
69 if (pixelFormat.redBits != 0 && pixelFormat.greenBits != 0 && pixelFormat.blueBits != 0 &&
70 pixelFormat.alphaBits != 0)
72 g_color_eps = vec4(1.f / ((float)(1 << pixelFormat.redBits) - 1.0f),
73 1.f / ((float)(1 << pixelFormat.greenBits) - 1.0f),
74 1.f / ((float)(1 << pixelFormat.blueBits) - 1.0f),
75 1.f / ((float)(1 << pixelFormat.alphaBits) - 1.0f)) +
78 else if (pixelFormat.redBits != 0 && pixelFormat.greenBits != 0 && pixelFormat.blueBits != 0)
80 g_color_eps = vec4(1.f / ((float)(1 << pixelFormat.redBits) - 1.0f),
81 1.f / ((float)(1 << pixelFormat.greenBits) - 1.0f),
82 1.f / ((float)(1 << pixelFormat.blueBits) - 1.0f), 1.f) +
87 g_color_eps = vec4(epsilon_zero);
91 const tcu::RenderTarget& renderTarget;
92 const tcu::PixelFormat& pixelFormat;
95 uvec3 IndexTo3DCoord(GLuint idx, GLuint max_x, GLuint max_y)
97 const GLuint x = idx % max_x;
99 const GLuint y = idx % max_y;
101 const GLuint z = idx;
102 return uvec3(x, y, z);
105 bool CheckProgram(GLuint program, bool* compile_error = NULL)
107 GLint compile_status = GL_TRUE;
108 GLint status = GL_TRUE;
109 glGetProgramiv(program, GL_LINK_STATUS, &status);
111 if (status == GL_FALSE)
113 GLint attached_shaders;
114 glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
116 if (attached_shaders > 0)
118 std::vector<GLuint> shaders(attached_shaders);
119 glGetAttachedShaders(program, attached_shaders, NULL, &shaders[0]);
121 for (GLint i = 0; i < attached_shaders; ++i)
124 glGetShaderiv(shaders[i], GL_SHADER_TYPE, reinterpret_cast<GLint*>(&type));
127 case GL_VERTEX_SHADER:
128 m_context.getTestContext().getLog()
129 << tcu::TestLog::Message << "*** Vertex Shader ***" << tcu::TestLog::EndMessage;
131 case GL_TESS_CONTROL_SHADER:
132 m_context.getTestContext().getLog()
133 << tcu::TestLog::Message << "*** Tessellation Control Shader ***"
134 << tcu::TestLog::EndMessage;
136 case GL_TESS_EVALUATION_SHADER:
137 m_context.getTestContext().getLog()
138 << tcu::TestLog::Message << "*** Tessellation Evaluation Shader ***"
139 << tcu::TestLog::EndMessage;
141 case GL_GEOMETRY_SHADER:
142 m_context.getTestContext().getLog()
143 << tcu::TestLog::Message << "*** Geometry Shader ***" << tcu::TestLog::EndMessage;
145 case GL_FRAGMENT_SHADER:
146 m_context.getTestContext().getLog()
147 << tcu::TestLog::Message << "*** Fragment Shader ***" << tcu::TestLog::EndMessage;
149 case GL_COMPUTE_SHADER:
150 m_context.getTestContext().getLog()
151 << tcu::TestLog::Message << "*** Compute Shader ***" << tcu::TestLog::EndMessage;
154 m_context.getTestContext().getLog()
155 << tcu::TestLog::Message << "*** Unknown Shader ***" << tcu::TestLog::EndMessage;
160 glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &res);
162 compile_status = res;
165 glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &length);
168 std::vector<GLchar> source(length);
169 glGetShaderSource(shaders[i], length, NULL, &source[0]);
170 m_context.getTestContext().getLog()
171 << tcu::TestLog::Message << &source[0] << tcu::TestLog::EndMessage;
174 glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &length);
177 std::vector<GLchar> log(length);
178 glGetShaderInfoLog(shaders[i], length, NULL, &log[0]);
179 m_context.getTestContext().getLog()
180 << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
186 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
189 std::vector<GLchar> log(length);
190 glGetProgramInfoLog(program, length, NULL, &log[0]);
191 m_context.getTestContext().getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
196 *compile_error = (compile_status == GL_TRUE ? false : true);
197 if (compile_status != GL_TRUE)
199 return status == GL_TRUE ? true : false;
202 GLuint CreateComputeProgram(const std::string& cs)
204 const GLuint p = glCreateProgram();
208 const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
209 glAttachShader(p, sh);
211 const char* const src[2] = { kGLSLVer, cs.c_str() };
212 glShaderSource(sh, 2, src, NULL);
219 GLuint CreateProgram(const std::string& vs, const std::string& fs)
221 const GLuint p = glCreateProgram();
225 const GLuint sh = glCreateShader(GL_VERTEX_SHADER);
226 glAttachShader(p, sh);
228 const char* const src[2] = { kGLSLVer, vs.c_str() };
229 glShaderSource(sh, 2, src, NULL);
234 const GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
235 glAttachShader(p, sh);
237 const char* const src[2] = { kGLSLVer, fs.c_str() };
238 glShaderSource(sh, 2, src, NULL);
245 GLuint BuildShaderProgram(GLenum type, const std::string& source)
247 const char* const src[2] = { kGLSLVer, source.c_str() };
248 return glCreateShaderProgramv(type, 2, src);
251 GLfloat distance(GLfloat p0, GLfloat p1)
253 return de::abs(p0 - p1);
256 inline bool ColorEqual(const vec4& c0, const vec4& c1, const vec4& epsilon)
258 if (distance(c0.x(), c1.x()) > epsilon.x())
260 if (distance(c0.y(), c1.y()) > epsilon.y())
262 if (distance(c0.z(), c1.z()) > epsilon.z())
264 if (distance(c0.w(), c1.w()) > epsilon.w())
269 inline bool ColorEqual(const vec3& c0, const vec3& c1, const vec4& epsilon)
271 if (distance(c0.x(), c1.x()) > epsilon.x())
273 if (distance(c0.y(), c1.y()) > epsilon.y())
275 if (distance(c0.z(), c1.z()) > epsilon.z())
280 bool ValidateReadBuffer(int x, int y, int w, int h, const vec4& expected)
282 std::vector<vec4> display(w * h);
283 glReadPixels(x, y, w, h, GL_RGBA, GL_FLOAT, &display[0]);
285 for (int j = 0; j < h; ++j)
287 for (int i = 0; i < w; ++i)
289 if (!ColorEqual(display[j * w + i], expected, g_color_eps))
291 m_context.getTestContext().getLog()
292 << tcu::TestLog::Message << "Color at (" << (x + i) << ", " << (y + j) << ") is ["
293 << display[j * w + i].x() << ", " << display[j * w + i].y() << ", " << display[j * w + i].z()
294 << ", " << display[j * w + i].w() << "] should be [" << expected.x() << ", " << expected.y()
295 << ", " << expected.z() << ", " << expected.w() << "]." << tcu::TestLog::EndMessage;
304 bool ValidateReadBufferCenteredQuad(int width, int height, const vec3& expected)
307 std::vector<vec3> fb(width * height);
308 glReadPixels(0, 0, width, height, GL_RGB, GL_FLOAT, &fb[0]);
310 int startx = int(((float)width * 0.1f) + 1);
311 int starty = int(((float)height * 0.1f) + 1);
312 int endx = int((float)width - 2 * (((float)width * 0.1f) + 1) - 1);
313 int endy = int((float)height - 2 * (((float)height * 0.1f) + 1) - 1);
315 for (int y = starty; y < endy; ++y)
317 for (int x = startx; x < endx; ++x)
319 const int idx = y * width + x;
320 if (!ColorEqual(fb[idx], expected, g_color_eps))
327 if (!ColorEqual(fb[2 * width + 2], vec3(0), g_color_eps))
331 if (!ColorEqual(fb[2 * width + (width - 3)], vec3(0), g_color_eps))
335 if (!ColorEqual(fb[(height - 3) * width + (width - 3)], vec3(0), g_color_eps))
339 if (!ColorEqual(fb[(height - 3) * width + 2], vec3(0), g_color_eps))
349 return renderTarget.getWidth();
352 int getWindowHeight()
354 return renderTarget.getHeight();
357 bool ValidateWindow4Quads(const vec3& lb, const vec3& rb, const vec3& rt, const vec3& lt)
361 std::vector<vec3> fb(width * height);
362 glReadPixels(0, 0, width, height, GL_RGB, GL_FLOAT, &fb[0]);
367 for (int y = 10; y < height / 2 - 10; ++y)
369 for (int x = 10; x < width / 2 - 10; ++x)
371 const int idx = y * width + x;
372 if (!ColorEqual(fb[idx], lb, g_color_eps))
374 m_context.getTestContext().getLog()
375 << tcu::TestLog::Message << "First bad color (" << x << ", " << y << "): " << fb[idx].x() << " "
376 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
382 for (int y = 10; y < height / 2 - 10; ++y)
384 for (int x = width / 2 + 10; x < width - 10; ++x)
386 const int idx = y * width + x;
387 if (!ColorEqual(fb[idx], rb, g_color_eps))
389 m_context.getTestContext().getLog()
390 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
391 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
397 for (int y = height / 2 + 10; y < height - 10; ++y)
399 for (int x = width / 2 + 10; x < width - 10; ++x)
401 const int idx = y * width + x;
402 if (!ColorEqual(fb[idx], rt, g_color_eps))
404 m_context.getTestContext().getLog()
405 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
406 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
412 for (int y = height / 2 + 10; y < height - 10; ++y)
414 for (int x = 10; x < width / 2 - 10; ++x)
416 const int idx = y * width + x;
417 if (!ColorEqual(fb[idx], lt, g_color_eps))
419 m_context.getTestContext().getLog()
420 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
421 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
426 // middle horizontal line should be black
427 for (int y = height / 2 - 2; y < height / 2 + 2; ++y)
429 for (int x = 0; x < width; ++x)
431 const int idx = y * width + x;
432 if (!ColorEqual(fb[idx], vec3(0), g_color_eps))
434 m_context.getTestContext().getLog()
435 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
436 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
441 // middle vertical line should be black
442 for (int y = 0; y < height; ++y)
444 for (int x = width / 2 - 2; x < width / 2 + 2; ++x)
446 const int idx = y * width + x;
447 if (!ColorEqual(fb[idx], vec3(0), g_color_eps))
449 m_context.getTestContext().getLog()
450 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
451 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
460 bool IsEqual(vec4 a, vec4 b)
462 return (a.x() == b.x()) && (a.y() == b.y()) && (a.z() == b.z()) && (a.w() == b.w());
465 bool IsEqual(uvec4 a, uvec4 b)
467 return (a.x() == b.x()) && (a.y() == b.y()) && (a.z() == b.z()) && (a.w() == b.w());
471 class SimpleCompute : public ComputeShaderBase
474 virtual std::string Title()
476 return "Simplest possible Compute Shader";
479 virtual std::string Purpose()
481 return "1. Verify that CS can be created, compiled and linked.\n"
482 "2. Verify that local work size can be queried with GetProgramiv command.\n"
483 "3. Verify that CS can be dispatched with DispatchCompute command.\n"
484 "4. Verify that CS can write to SSBO.";
487 virtual std::string Method()
489 return "Create and dispatch CS. Verify SSBO content.";
492 virtual std::string PassCriteria()
494 return "Everything works as expected.";
503 const char* const glsl_cs =
504 NL "layout(local_size_x = 1, local_size_y = 1) in;" NL "layout(std430) buffer Output {" NL " vec4 data;" NL
505 "} g_out;" NL "void main() {" NL " g_out.data = vec4(1.0, 2.0, 3.0, 4.0);" NL "}";
506 m_program = CreateComputeProgram(glsl_cs);
507 glLinkProgram(m_program);
508 if (!CheckProgram(m_program))
512 glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
513 if (v[0] != 1 || v[1] != 1 || v[2] != 1)
515 m_context.getTestContext().getLog()
516 << tcu::TestLog::Message << "Got " << v[0] << ", " << v[1] << ", " << v[2]
517 << ", expected: 1, 1, 1 in GL_COMPUTE_WORK_GROUP_SIZE check" << tcu::TestLog::EndMessage;
521 glGenBuffers(1, &m_buffer);
522 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
523 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), NULL, GL_DYNAMIC_DRAW);
524 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
531 glUseProgram(m_program);
532 glDispatchCompute(1, 1, 1);
535 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
536 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
537 data = static_cast<vec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), GL_MAP_READ_BIT));
538 long error = NO_ERROR;
539 if (!IsEqual(data[0], vec4(1.0f, 2.0f, 3.0f, 4.0f)))
543 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
544 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
548 virtual long Cleanup()
551 glDeleteProgram(m_program);
552 glDeleteBuffers(1, &m_buffer);
557 class BasicOneWorkGroup : public ComputeShaderBase
560 virtual std::string Title()
562 return "One work group with various local sizes";
565 virtual std::string Purpose()
567 return NL "1. Verify that declared local work size has correct effect." NL
568 "2. Verify that the number of shader invocations is correct." NL
569 "3. Verify that the built-in variables: gl_WorkGroupSize, gl_WorkGroupID, gl_GlobalInvocationID," NL
570 " gl_LocalInvocationID and gl_LocalInvocationIndex has correct values." NL
571 "4. Verify that DispatchCompute and DispatchComputeIndirect commands work as expected.";
574 virtual std::string Method()
576 return NL "1. Create several CS with various local sizes." NL
577 "2. Dispatch each CS with DispatchCompute and DispatchComputeIndirect commands." NL
578 "3. Verify SSBO content.";
581 virtual std::string PassCriteria()
583 return "Everything works as expected.";
587 GLuint m_storage_buffer;
588 GLuint m_dispatch_buffer;
590 std::string GenSource(int x, int y, int z, GLuint binding)
592 std::stringstream ss;
593 ss << NL "layout(local_size_x = " << x << ", local_size_y = " << y << ", local_size_z = " << z
594 << ") in;" NL "layout(std430, binding = " << binding
595 << ") buffer Output {" NL " uvec4 local_id[];" NL "} g_out;" NL "void main() {" NL
596 " if (gl_WorkGroupSize == uvec3("
597 << x << ", " << y << ", " << z
598 << ") && gl_WorkGroupID == uvec3(0) &&" NL " gl_GlobalInvocationID == gl_LocalInvocationID) {" NL
599 " g_out.local_id[gl_LocalInvocationIndex] = uvec4(gl_LocalInvocationID, 0);" NL " } else {" NL
600 " g_out.local_id[gl_LocalInvocationIndex] = uvec4(0xffff);" NL " }" NL "}";
604 bool RunIteration(int local_size_x, int local_size_y, int local_size_z, GLuint binding, bool dispatch_indirect)
607 glDeleteProgram(m_program);
608 m_program = CreateComputeProgram(GenSource(local_size_x, local_size_y, local_size_z, binding));
609 glLinkProgram(m_program);
610 if (!CheckProgram(m_program))
614 glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
615 if (v[0] != local_size_x || v[1] != local_size_y || v[2] != local_size_z)
617 m_context.getTestContext().getLog()
618 << tcu::TestLog::Message << "GL_COMPUTE_LOCAL_WORK_SIZE is (" << v[0] << " " << v[1] << " " << v[2]
619 << ") should be (" << local_size_x << " " << local_size_y << " " << local_size_z << ")"
620 << tcu::TestLog::EndMessage;
624 const int kSize = local_size_x * local_size_y * local_size_z;
626 if (m_storage_buffer == 0)
627 glGenBuffers(1, &m_storage_buffer);
628 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, m_storage_buffer);
629 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * kSize, NULL, GL_DYNAMIC_DRAW);
630 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
632 glUseProgram(m_program);
633 if (dispatch_indirect)
635 const GLuint num_groups[3] = { 1, 1, 1 };
636 if (m_dispatch_buffer == 0)
637 glGenBuffers(1, &m_dispatch_buffer);
638 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
639 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), num_groups, GL_STATIC_DRAW);
640 glDispatchComputeIndirect(0);
644 glDispatchCompute(1, 1, 1);
648 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
649 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
651 static_cast<uvec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * sizeof(uvec4), GL_MAP_READ_BIT));
655 for (int z = 0; z < local_size_z; ++z)
657 for (int y = 0; y < local_size_y; ++y)
659 for (int x = 0; x < local_size_x; ++x)
661 const int index = z * local_size_x * local_size_y + y * local_size_x + x;
662 if (!IsEqual(data[index], uvec4(x, y, z, 0)))
664 m_context.getTestContext().getLog()
665 << tcu::TestLog::Message << "Invalid data at offset " << index << tcu::TestLog::EndMessage;
671 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
672 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
679 m_storage_buffer = 0;
680 m_dispatch_buffer = 0;
686 if (!RunIteration(16, 1, 1, 0, true))
688 if (!RunIteration(8, 8, 1, 1, false))
690 if (!RunIteration(4, 4, 4, 2, true))
692 if (!RunIteration(1, 2, 3, 3, false))
694 if (!RunIteration(1024, 1, 1, 3, true))
696 if (!RunIteration(16, 8, 8, 3, false))
698 if (!RunIteration(32, 1, 32, 7, true))
703 virtual long Cleanup()
706 glDeleteProgram(m_program);
707 glDeleteBuffers(1, &m_storage_buffer);
708 glDeleteBuffers(1, &m_dispatch_buffer);
713 class BasicResourceUBO : public ComputeShaderBase
716 virtual std::string Title()
718 return "Compute Shader resources - UBOs";
721 virtual std::string Purpose()
723 return "Verify that CS is able to read data from UBOs and write it to SSBO.";
726 virtual std::string Method()
728 return NL "1. Create CS which uses array of UBOs." NL
729 "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
730 "3. Read data from each UBO and write it to SSBO." NL "4. Verify SSBO content." NL
731 "5. Repeat for different buffer and CS work sizes.";
734 virtual std::string PassCriteria()
736 return "Everything works as expected.";
740 GLuint m_storage_buffer;
741 GLuint m_uniform_buffer[12];
742 GLuint m_dispatch_buffer;
744 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
746 const uvec3 global_size = local_size * num_groups;
747 std::stringstream ss;
748 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
749 << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
750 << ", " << global_size.y() << ", " << global_size.z()
751 << ");" NL "layout(std140) uniform InputBuffer {" NL " vec4 data["
752 << global_size.x() * global_size.y() * global_size.z()
753 << "];" NL "} g_in_buffer[12];" NL "layout(std430) buffer OutputBuffer {" NL " vec4 data0["
754 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data1["
755 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data2["
756 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data3["
757 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data4["
758 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data5["
759 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data6["
760 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data7["
761 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data8["
762 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data9["
763 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data10["
764 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data11["
765 << global_size.x() * global_size.y() * global_size.z()
766 << "];" NL "} g_out_buffer;" NL "void main() {" NL " const uint global_index = gl_GlobalInvocationID.x +" NL
767 " gl_GlobalInvocationID.y * kGlobalSize.x +" NL
768 " gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
769 " g_out_buffer.data0[global_index] = g_in_buffer[0].data[global_index];" NL
770 " g_out_buffer.data1[global_index] = g_in_buffer[1].data[global_index];" NL
771 " g_out_buffer.data2[global_index] = g_in_buffer[2].data[global_index];" NL
772 " g_out_buffer.data3[global_index] = g_in_buffer[3].data[global_index];" NL
773 " g_out_buffer.data4[global_index] = g_in_buffer[4].data[global_index];" NL
774 " g_out_buffer.data5[global_index] = g_in_buffer[5].data[global_index];" NL
775 " g_out_buffer.data6[global_index] = g_in_buffer[6].data[global_index];" NL
776 " g_out_buffer.data7[global_index] = g_in_buffer[7].data[global_index];" NL
777 " g_out_buffer.data8[global_index] = g_in_buffer[8].data[global_index];" NL
778 " g_out_buffer.data9[global_index] = g_in_buffer[9].data[global_index];" NL
779 " g_out_buffer.data10[global_index] = g_in_buffer[10].data[global_index];" NL
780 " g_out_buffer.data11[global_index] = g_in_buffer[11].data[global_index];" NL "}";
784 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
787 glDeleteProgram(m_program);
788 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
789 glLinkProgram(m_program);
790 if (!CheckProgram(m_program))
793 for (GLuint i = 0; i < 12; ++i)
796 sprintf(name, "InputBuffer[%u]", i);
797 const GLuint index = glGetUniformBlockIndex(m_program, name);
798 glUniformBlockBinding(m_program, index, i);
800 glGetActiveUniformBlockiv(m_program, index, GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER, &p);
803 m_context.getTestContext().getLog()
804 << tcu::TestLog::Message << "UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER should be TRUE."
805 << tcu::TestLog::EndMessage;
810 const GLuint kBufferSize =
811 local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
813 if (m_storage_buffer == 0)
814 glGenBuffers(1, &m_storage_buffer);
815 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
816 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize * 12, NULL, GL_DYNAMIC_DRAW);
817 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
819 if (m_uniform_buffer[0] == 0)
820 glGenBuffers(12, m_uniform_buffer);
821 for (GLuint i = 0; i < 12; ++i)
823 std::vector<vec4> data(kBufferSize);
824 for (GLuint j = 0; j < kBufferSize; ++j)
826 data[j] = vec4(static_cast<float>(i * kBufferSize + j));
828 glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
829 glBufferData(GL_UNIFORM_BUFFER, sizeof(vec4) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
831 glBindBuffer(GL_UNIFORM_BUFFER, 0);
833 glUseProgram(m_program);
834 if (dispatch_indirect)
836 if (m_dispatch_buffer == 0)
837 glGenBuffers(1, &m_dispatch_buffer);
838 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
839 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
840 glDispatchComputeIndirect(0);
844 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
847 std::vector<vec4> data(kBufferSize * 12);
848 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
849 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
850 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize * 12, &data[0]);
852 for (GLuint z = 0; z < local_size.z() * num_groups.z(); ++z)
854 for (GLuint y = 0; y < local_size.y() * num_groups.y(); ++y)
856 for (GLuint x = 0; x < local_size.x() * num_groups.x(); ++x)
858 const GLuint index = z * local_size.x() * num_groups.x() * local_size.y() * num_groups.y() +
859 y * local_size.x() * num_groups.x() + x;
860 for (int i = 0; i < 1; ++i)
862 if (!IsEqual(data[index * 12 + i], vec4(static_cast<float>(index * 12 + i))))
864 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Incorrect data at offset "
865 << index * 12 + i << "." << tcu::TestLog::EndMessage;
878 m_storage_buffer = 0;
879 memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
880 m_dispatch_buffer = 0;
886 if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
888 if (!RunIteration(uvec3(2, 2, 2), uvec3(2, 2, 2), true))
890 if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
895 virtual long Cleanup()
898 glDeleteProgram(m_program);
899 glDeleteBuffers(1, &m_storage_buffer);
900 glDeleteBuffers(12, m_uniform_buffer);
901 glDeleteBuffers(1, &m_dispatch_buffer);
906 class BasicResourceTexture : public ComputeShaderBase
909 virtual std::string Title()
911 return NL "Compute Shader resources - Textures";
914 virtual std::string Purpose()
916 return NL "Verify that texture access works correctly in CS.";
919 virtual std::string Method()
921 return NL "1. Create CS which uses all sampler types (sampler1D, sampler2D, sampler3D, sampler2DRect," NL
922 " sampler1DArray, sampler2DArray, samplerBuffer, sampler2DMS, sampler2DMSArray)." NL
923 "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
924 "3. Sample each texture and write sampled value to SSBO." NL "4. Verify SSBO content." NL
925 "5. Repeat for different texture and CS work sizes.";
928 virtual std::string PassCriteria()
930 return NL "Everything works as expected.";
934 GLuint m_storage_buffer;
936 GLuint m_texture_buffer;
937 GLuint m_dispatch_buffer;
939 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
941 const uvec3 global_size = local_size * num_groups;
942 std::stringstream ss;
943 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
944 << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
945 << ", " << global_size.y() << ", " << global_size.z()
946 << ");" NL "uniform sampler1D g_sampler0;" NL "uniform sampler2D g_sampler1;" NL
947 "uniform sampler3D g_sampler2;" NL "uniform sampler2DRect g_sampler3;" NL
948 "uniform sampler1DArray g_sampler4;" NL "uniform sampler2DArray g_sampler5;" NL
949 "uniform samplerBuffer g_sampler6;" NL "uniform sampler2DMS g_sampler7;" NL
950 "uniform sampler2DMSArray g_sampler8;" NL "layout(std430) buffer OutputBuffer {" NL " vec4 data0["
951 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data1["
952 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data2["
953 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data3["
954 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data4["
955 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data5["
956 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data6["
957 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data7["
958 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data8["
959 << global_size.x() * global_size.y() * global_size.z()
960 << "];" NL "} g_out_buffer;" NL "void main() {" NL " const uint global_index = gl_GlobalInvocationID.x +" NL
961 " gl_GlobalInvocationID.y * kGlobalSize.x +" NL
962 " gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
963 " g_out_buffer.data0[global_index] = texelFetch(g_sampler0, int(gl_GlobalInvocationID), 0);" NL
964 " g_out_buffer.data1[global_index] = texture(g_sampler1, vec2(gl_GlobalInvocationID) / "
965 "vec2(kGlobalSize));" NL " g_out_buffer.data2[global_index] = textureProj(g_sampler2, "
966 "vec4(vec3(gl_GlobalInvocationID) / vec3(kGlobalSize), 1.0));" NL
967 " g_out_buffer.data3[global_index] = textureProjOffset(g_sampler3, vec3(vec2(gl_GlobalInvocationID), "
968 "1.0), ivec2(0));" NL " g_out_buffer.data4[global_index] = textureLodOffset(g_sampler4, "
969 "vec2(gl_GlobalInvocationID.x / kGlobalSize.x, gl_GlobalInvocationID.y), 0.0, "
970 "0);" NL " g_out_buffer.data5[global_index] = texelFetchOffset(g_sampler5, "
971 "ivec3(gl_GlobalInvocationID), 0, ivec2(0));" NL
972 " g_out_buffer.data6[global_index] = texelFetch(g_sampler6, int(global_index));" NL
973 " g_out_buffer.data7[global_index] = texelFetch(g_sampler7, ivec2(gl_GlobalInvocationID), 1);" NL
974 " g_out_buffer.data8[global_index] = texelFetch(g_sampler8, ivec3(gl_GlobalInvocationID), 2);" NL "}";
978 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
981 glDeleteProgram(m_program);
982 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
983 glLinkProgram(m_program);
984 if (!CheckProgram(m_program))
987 glUseProgram(m_program);
988 for (int i = 0; i < 9; ++i)
991 sprintf(name, "g_sampler%d", i);
992 glUniform1i(glGetUniformLocation(m_program, name), i);
996 const GLuint kBufferSize =
997 local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
998 const GLint kWidth = static_cast<GLint>(local_size.x() * num_groups.x());
999 const GLint kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
1000 const GLint kDepth = static_cast<GLint>(local_size.z() * num_groups.z());
1002 std::vector<vec4> buffer_data(kBufferSize * 9);
1003 if (m_storage_buffer == 0)
1004 glGenBuffers(1, &m_storage_buffer);
1005 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
1006 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize * 9, &buffer_data[0], GL_DYNAMIC_DRAW);
1007 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1009 std::vector<vec4> texture_data(kBufferSize, vec4(123.0f));
1010 if (m_texture[0] == 0)
1011 glGenTextures(9, m_texture);
1012 if (m_texture_buffer == 0)
1013 glGenBuffers(1, &m_texture_buffer);
1015 glActiveTexture(GL_TEXTURE0);
1016 glBindTexture(GL_TEXTURE_1D, m_texture[0]);
1017 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1018 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1019 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, kWidth, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1021 glActiveTexture(GL_TEXTURE1);
1022 glBindTexture(GL_TEXTURE_2D, m_texture[1]);
1023 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1024 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1025 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1027 glActiveTexture(GL_TEXTURE2);
1028 glBindTexture(GL_TEXTURE_3D, m_texture[2]);
1029 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1030 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1031 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1033 glActiveTexture(GL_TEXTURE3);
1034 glBindTexture(GL_TEXTURE_RECTANGLE, m_texture[3]);
1035 glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1036 glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1037 glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1039 glActiveTexture(GL_TEXTURE4);
1040 glBindTexture(GL_TEXTURE_1D_ARRAY, m_texture[4]);
1041 glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1042 glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1043 glTexImage2D(GL_TEXTURE_1D_ARRAY, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1045 glActiveTexture(GL_TEXTURE5);
1046 glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture[5]);
1047 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1048 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1049 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA32F, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_FLOAT,
1052 glActiveTexture(GL_TEXTURE6);
1053 glBindBuffer(GL_TEXTURE_BUFFER, m_texture_buffer);
1054 glBufferData(GL_TEXTURE_BUFFER, kBufferSize * sizeof(vec4), &texture_data[0], GL_DYNAMIC_DRAW);
1055 glBindBuffer(GL_TEXTURE_BUFFER, 0);
1056 glBindTexture(GL_TEXTURE_BUFFER, m_texture[6]);
1057 glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_texture_buffer);
1059 glActiveTexture(GL_TEXTURE7);
1060 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_texture[7]);
1061 glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA32F, kWidth, kHeight, GL_FALSE);
1063 glActiveTexture(GL_TEXTURE8);
1064 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_texture[8]);
1065 glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 4, GL_RGBA32F, kWidth, kHeight, kDepth, GL_FALSE);
1067 // clear MS textures
1069 glGenFramebuffers(1, &fbo);
1070 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1071 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture[7], 0);
1072 glClearBufferfv(GL_COLOR, 0, &vec4(123.0f)[0]);
1073 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture[8], 0);
1074 glClearBufferfv(GL_COLOR, 0, &vec4(123.0f)[0]);
1075 glDeleteFramebuffers(1, &fbo);
1077 glUseProgram(m_program);
1078 if (dispatch_indirect)
1080 if (m_dispatch_buffer == 0)
1081 glGenBuffers(1, &m_dispatch_buffer);
1082 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1083 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1084 glDispatchComputeIndirect(0);
1088 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1091 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
1092 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1093 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize * 9, &buffer_data[0]);
1094 for (GLuint index = 0; index < kBufferSize * 9; ++index)
1096 if (!IsEqual(buffer_data[index], vec4(123.0f)))
1098 m_context.getTestContext().getLog()
1099 << tcu::TestLog::Message << "Incorrect data at index " << index << "." << tcu::TestLog::EndMessage;
1106 virtual long Setup()
1109 m_storage_buffer = 0;
1110 memset(m_texture, 0, sizeof(m_texture));
1111 m_texture_buffer = 0;
1112 m_dispatch_buffer = 0;
1118 if (!RunIteration(uvec3(4, 4, 4), uvec3(8, 1, 1), false))
1120 if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), true))
1122 if (!RunIteration(uvec3(2, 2, 2), uvec3(2, 2, 2), false))
1127 virtual long Cleanup()
1129 glActiveTexture(GL_TEXTURE0);
1131 glDeleteProgram(m_program);
1132 glDeleteBuffers(1, &m_storage_buffer);
1133 glDeleteTextures(9, m_texture);
1134 glDeleteBuffers(1, &m_texture_buffer);
1135 glDeleteBuffers(1, &m_dispatch_buffer);
1140 class BasicResourceImage : public ComputeShaderBase
1143 virtual std::string Title()
1145 return NL "Compute Shader resources - Images";
1148 virtual std::string Purpose()
1150 return NL "Verify that reading/writing GPU memory via image variables work as expected.";
1153 virtual std::string Method()
1155 return NL "1. Create CS which uses two image2D variables to read and write underlying GPU memory." NL
1156 "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
1157 "3. Verify memory content." NL "4. Repeat for different texture and CS work sizes.";
1160 virtual std::string PassCriteria()
1162 return NL "Everything works as expected.";
1166 GLuint m_draw_program;
1167 GLuint m_texture[2];
1168 GLuint m_dispatch_buffer;
1169 GLuint m_vertex_array;
1171 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
1173 const uvec3 global_size = local_size * num_groups;
1174 std::stringstream ss;
1175 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
1176 << ", local_size_z = " << local_size.z()
1177 << ") in;" NL "layout(rgba32f) coherent uniform image2D g_image1;" NL
1178 "layout(rgba32f) uniform image2D g_image2;" NL "const uvec3 kGlobalSize = uvec3("
1179 << global_size.x() << ", " << global_size.y() << ", " << global_size.z()
1180 << ");" NL "void main() {" NL
1181 " if (gl_GlobalInvocationID.x >= kGlobalSize.x || gl_GlobalInvocationID.y >= kGlobalSize.y) return;" NL
1182 " vec4 color = vec4(gl_GlobalInvocationID.x + gl_GlobalInvocationID.y) / 255.0;" NL
1183 " imageStore(g_image1, ivec2(gl_GlobalInvocationID), color);" NL
1184 " vec4 c = imageLoad(g_image1, ivec2(gl_GlobalInvocationID));" NL
1185 " imageStore(g_image2, ivec2(gl_GlobalInvocationID), c);" NL "}";
1189 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
1192 glDeleteProgram(m_program);
1193 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
1194 glLinkProgram(m_program);
1195 if (!CheckProgram(m_program))
1198 glUseProgram(m_program);
1199 glUniform1i(glGetUniformLocation(m_program, "g_image1"), 0);
1200 glUniform1i(glGetUniformLocation(m_program, "g_image2"), 1);
1203 const GLint kWidth = static_cast<GLint>(local_size.x() * num_groups.x());
1204 const GLint kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
1205 const GLint kDepth = static_cast<GLint>(local_size.z() * num_groups.z());
1206 const GLuint kSize = kWidth * kHeight * kDepth;
1208 std::vector<vec4> data(kSize);
1209 if (m_texture[0] == 0)
1210 glGenTextures(2, m_texture);
1212 for (int i = 0; i < 2; ++i)
1214 glBindTexture(GL_TEXTURE_2D, m_texture[i]);
1215 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1216 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &data[0]);
1218 glBindTexture(GL_TEXTURE_2D, 0);
1220 glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
1221 glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
1222 glUseProgram(m_program);
1223 if (dispatch_indirect)
1225 if (m_dispatch_buffer == 0)
1226 glGenBuffers(1, &m_dispatch_buffer);
1227 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1228 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1229 glDispatchComputeIndirect(0);
1233 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1235 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1237 glClear(GL_COLOR_BUFFER_BIT);
1238 glActiveTexture(GL_TEXTURE0);
1239 glBindTexture(GL_TEXTURE_2D, m_texture[0]);
1240 glActiveTexture(GL_TEXTURE1);
1241 glBindTexture(GL_TEXTURE_2D, m_texture[1]);
1242 glUseProgram(m_draw_program);
1243 glBindVertexArray(m_vertex_array);
1244 glViewport(0, 0, kWidth, kHeight);
1245 glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
1247 std::vector<vec4> display(kWidth * kHeight);
1248 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_FLOAT, &display[0]);
1250 for (int y = 0; y < kHeight; ++y)
1252 for (int x = 0; x < kWidth; ++x)
1254 if (y >= getWindowHeight() || x >= getWindowWidth())
1258 const vec4 c = vec4(float(y + x) / 255.0f);
1259 if (!ColorEqual(display[y * kWidth + x], c, g_color_eps))
1261 m_context.getTestContext().getLog()
1262 << tcu::TestLog::Message << "Got " << display[y * kWidth + x].x() << ", "
1263 << display[y * kWidth + x].y() << ", " << display[y * kWidth + x].z() << ", "
1264 << display[y * kWidth + x].w() << ", expected " << c.x() << ", " << c.y() << ", " << c.z()
1265 << ", " << c.w() << " at " << x << ", " << y << tcu::TestLog::EndMessage;
1274 virtual long Setup()
1277 memset(m_texture, 0, sizeof(m_texture));
1278 m_dispatch_buffer = 0;
1285 const char* const glsl_vs =
1286 NL "out StageData {" NL " vec2 texcoord;" NL "} vs_out;" NL
1287 "const vec2 g_quad[] = vec2[](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1));" NL "void main() {" NL
1288 " gl_Position = vec4(g_quad[gl_VertexID], 0, 1);" NL
1289 " vs_out.texcoord = 0.5 + 0.5 * g_quad[gl_VertexID];" NL "}";
1291 const char* glsl_fs =
1292 NL "in StageData {" NL " vec2 texcoord;" NL "} fs_in;" NL "layout(location = 0) out vec4 o_color;" NL
1293 "uniform sampler2D g_image1;" NL "uniform sampler2D g_image2;" NL "void main() {" NL
1294 " vec4 c1 = texture(g_image1, fs_in.texcoord);" NL " vec4 c2 = texture(g_image2, fs_in.texcoord);" NL
1295 " if (c1 == c2) o_color = c1;" NL " else o_color = vec4(1, 0, 0, 1);" NL "}";
1297 m_draw_program = CreateProgram(glsl_vs, glsl_fs);
1298 glLinkProgram(m_draw_program);
1299 if (!CheckProgram(m_draw_program))
1302 glUseProgram(m_draw_program);
1303 glUniform1i(glGetUniformLocation(m_draw_program, "g_image1"), 0);
1304 glUniform1i(glGetUniformLocation(m_draw_program, "g_image2"), 1);
1307 glGenVertexArrays(1, &m_vertex_array);
1309 if (!pixelFormat.alphaBits)
1311 m_context.getTestContext().getLog()
1312 << tcu::TestLog::Message << "Test requires default framebuffer alpha bits" << tcu::TestLog::EndMessage;
1316 if (!RunIteration(uvec3(8, 16, 1), uvec3(8, 4, 1), true))
1318 if (!RunIteration(uvec3(4, 32, 1), uvec3(16, 2, 1), false))
1320 if (!RunIteration(uvec3(16, 4, 1), uvec3(4, 16, 1), false))
1322 if (!RunIteration(uvec3(8, 8, 1), uvec3(8, 8, 1), true))
1328 virtual long Cleanup()
1331 glDeleteProgram(m_program);
1332 glDeleteProgram(m_draw_program);
1333 glDeleteVertexArrays(1, &m_vertex_array);
1334 glDeleteTextures(2, m_texture);
1335 glDeleteBuffers(1, &m_dispatch_buffer);
1336 glViewport(0, 0, getWindowWidth(), getWindowHeight());
1341 class BasicResourceAtomicCounter : public ComputeShaderBase
1344 virtual std::string Title()
1346 return "Compute Shader resources - Atomic Counters";
1349 virtual std::string Purpose()
1352 "1. Verify that Atomic Counters work as expected in CS." NL
1353 "2. Verify that built-in functions: atomicCounterIncrement and atomicCounterDecrement work correctly." NL
1354 "3. Verify that GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER is accepted by" NL
1355 " GetActiveAtomicCounterBufferiv command.";
1358 virtual std::string Method()
1361 "1. Create CS which uses two atomic_uint variables." NL
1362 "2. In CS write values returned by atomicCounterIncrement and atomicCounterDecrement functions to SSBO." NL
1363 "3. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL "4. Verify SSBO content." NL
1364 "5. Repeat for different buffer and CS work sizes.";
1367 virtual std::string PassCriteria()
1369 return "Everything works as expected.";
1373 GLuint m_storage_buffer;
1374 GLuint m_counter_buffer[2];
1375 GLuint m_dispatch_buffer;
1377 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
1379 const uvec3 global_size = local_size * num_groups;
1380 std::stringstream ss;
1381 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
1382 << ", local_size_z = " << local_size.z()
1383 << ") in;" NL "layout(std430, binding = 0) buffer Output {" NL " uint inc_data["
1384 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uint dec_data["
1385 << global_size.x() * global_size.y() * global_size.z()
1386 << "];" NL "};" NL "layout(binding = 0, offset = 0) uniform atomic_uint g_inc_counter;" NL
1387 "layout(binding = 1, offset = 0) uniform atomic_uint g_dec_counter;" NL "void main() {" NL
1388 " const uint index = atomicCounterIncrement(g_inc_counter);" NL " inc_data[index] = index;" NL
1389 " dec_data[index] = atomicCounterDecrement(g_dec_counter);" NL "}";
1393 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
1396 glDeleteProgram(m_program);
1397 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
1398 glLinkProgram(m_program);
1399 if (!CheckProgram(m_program))
1403 glGetActiveAtomicCounterBufferiv(m_program, 0, GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER, &p[0]);
1404 glGetActiveAtomicCounterBufferiv(m_program, 1, GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER, &p[1]);
1406 if (p[0] == GL_FALSE || p[1] == GL_FALSE)
1408 m_context.getTestContext().getLog()
1409 << tcu::TestLog::Message << "ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER should be TRUE."
1410 << tcu::TestLog::EndMessage;
1414 const GLint kWidth = static_cast<GLint>(local_size.x() * num_groups.x());
1415 const GLint kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
1416 const GLint kDepth = static_cast<GLint>(local_size.z() * num_groups.z());
1417 const GLuint kSize = kWidth * kHeight * kDepth;
1419 if (m_storage_buffer == 0)
1420 glGenBuffers(1, &m_storage_buffer);
1421 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
1422 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kSize * 2, NULL, GL_DYNAMIC_DRAW);
1423 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1425 if (m_counter_buffer[0] == 0)
1426 glGenBuffers(2, m_counter_buffer);
1428 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_counter_buffer[0]);
1429 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_DRAW);
1430 *static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)) = 0;
1431 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1433 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, m_counter_buffer[1]);
1434 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_DRAW);
1435 *static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)) = kSize;
1436 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1438 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1440 glUseProgram(m_program);
1441 if (dispatch_indirect)
1443 if (m_dispatch_buffer == 0)
1444 glGenBuffers(1, &m_dispatch_buffer);
1445 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1446 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1447 glDispatchComputeIndirect(0);
1451 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1454 std::vector<GLuint> data(kSize);
1455 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
1456 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1457 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kSize, &data[0]);
1459 for (GLuint i = 0; i < kSize; ++i)
1463 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Value at index " << i << " is "
1464 << data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
1470 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_counter_buffer[0]);
1471 glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &value);
1474 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Final atomic counter value (buffer 0) is "
1475 << value << " should be " << kSize << "." << tcu::TestLog::EndMessage;
1479 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_counter_buffer[1]);
1480 glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &value);
1483 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Final atomic counter value (buffer 1) is "
1484 << value << " should be 0." << tcu::TestLog::EndMessage;
1491 virtual long Setup()
1494 m_storage_buffer = 0;
1495 memset(m_counter_buffer, 0, sizeof(m_counter_buffer));
1496 m_dispatch_buffer = 0;
1502 if (!RunIteration(uvec3(4, 3, 2), uvec3(2, 3, 4), false))
1504 if (!RunIteration(uvec3(1, 1, 1), uvec3(1, 1, 1), true))
1506 if (!RunIteration(uvec3(1, 6, 1), uvec3(1, 1, 8), false))
1508 if (!RunIteration(uvec3(4, 1, 2), uvec3(10, 3, 4), true))
1513 virtual long Cleanup()
1516 glDeleteProgram(m_program);
1517 glDeleteBuffers(2, m_counter_buffer);
1518 glDeleteBuffers(1, &m_dispatch_buffer);
1519 glDeleteBuffers(1, &m_storage_buffer);
1524 class BasicResourceSubroutine : public ComputeShaderBase
1527 virtual std::string Title()
1529 return "Compute Shader resources - Subroutines";
1532 virtual std::string Purpose()
1534 return NL "1. Verify that subroutines work as expected in CS." NL
1535 "2. Verify that subroutines array can be indexed with gl_WorkGroupID built-in variable." NL
1536 "3. Verify that atomicCounterIncrement, imageLoad and texelFetch functions" NL
1537 " work as expected when called in CS from subroutine.";
1540 virtual std::string Method()
1542 return NL "1. Create CS which uses array of subroutines." NL
1543 "2. In CS index subroutine array with gl_WorkGroupID built-in variable." NL
1544 "3. In each subroutine load data from SSBO0 and write it to SSBO1." NL
1545 "3. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
1546 "4. Verify SSBO1 content." NL "5. Repeat for different buffer and CS work sizes.";
1549 virtual std::string PassCriteria()
1551 return "Everything works as expected.";
1555 GLuint m_atomic_counter_buffer;
1556 GLuint m_storage_buffer[2];
1558 GLuint m_texture_buffer[2];
1560 virtual long Setup()
1563 m_atomic_counter_buffer = 0;
1564 memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
1565 memset(m_buffer, 0, sizeof(m_buffer));
1566 memset(m_texture_buffer, 0, sizeof(m_texture_buffer));
1572 const char* const glsl_cs =
1573 NL "layout(local_size_x = 16) in;" NL "layout(binding = 1, std430) buffer Input {" NL " uvec4 data[16];" NL
1574 "} g_input;" NL "layout(std430, binding = 0) buffer Output {" NL " uvec4 g_output[64];" NL "};" NL
1575 "subroutine void ComputeType();" NL "subroutine uniform ComputeType Compute[4];" NL
1576 "layout(binding = 0, offset = 0) uniform atomic_uint g_atomic_counter;" NL
1577 "layout(rgba32ui) readonly uniform uimageBuffer g_image_buffer;" NL
1578 "uniform usamplerBuffer g_sampler_buffer;" NL "subroutine(ComputeType)" NL "void Compute0() {" NL
1579 " const uint index = atomicCounterIncrement(g_atomic_counter);" NL
1580 " g_output[index] = uvec4(index);" NL "}" NL "subroutine(ComputeType)" NL "void Compute1() {" NL
1581 " g_output[gl_GlobalInvocationID.x] = g_input.data[gl_LocalInvocationIndex];" NL "}" NL
1582 "subroutine(ComputeType)" NL "void Compute2() {" NL
1583 " g_output[gl_GlobalInvocationID.x] = imageLoad(g_image_buffer, int(gl_LocalInvocationIndex));" NL
1584 "}" NL "subroutine(ComputeType)" NL "void Compute3() {" NL
1585 " g_output[gl_GlobalInvocationID.x] = texelFetch(g_sampler_buffer, int(gl_LocalInvocationIndex));" NL
1586 "}" NL "void main() {" NL " Compute[gl_WorkGroupID.x]();" NL "}";
1587 m_program = CreateComputeProgram(glsl_cs);
1588 glLinkProgram(m_program);
1589 if (!CheckProgram(m_program))
1592 glGenBuffers(2, m_storage_buffer);
1595 std::vector<uvec4> data(64, uvec4(0xffff));
1596 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
1597 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * 64, &data[0], GL_DYNAMIC_DRAW);
1601 std::vector<uvec4> data(16);
1602 for (GLuint i = 0; i < 16; ++i)
1603 data[i] = uvec4(i + 16);
1604 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
1605 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * 16, &data[0], GL_DYNAMIC_DRAW);
1607 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1609 glGenBuffers(1, &m_atomic_counter_buffer);
1610 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomic_counter_buffer);
1611 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_STREAM_DRAW);
1612 *static_cast<GLuint*>(glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY)) = 0;
1613 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1615 glGenBuffers(2, m_buffer);
1618 std::vector<uvec4> data(16);
1619 for (GLuint i = 0; i < 16; ++i)
1620 data[i] = uvec4(i + 32);
1621 glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[0]);
1622 glBufferData(GL_TEXTURE_BUFFER, sizeof(uvec4) * 16, &data[0], GL_STATIC_DRAW);
1624 /* texture buffer */
1626 std::vector<uvec4> data(16);
1627 for (GLuint i = 0; i < 16; ++i)
1628 data[i] = uvec4(i + 48);
1629 glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[1]);
1630 glBufferData(GL_TEXTURE_BUFFER, sizeof(uvec4) * 16, &data[0], GL_STATIC_DRAW);
1632 glBindBuffer(GL_TEXTURE_BUFFER, 0);
1634 glGenTextures(2, m_texture_buffer);
1635 glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer[0]);
1636 glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, m_buffer[0]);
1637 glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer[1]);
1638 glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, m_buffer[1]);
1639 glBindTexture(GL_TEXTURE_BUFFER, 0);
1641 const GLuint index_compute0 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute0");
1642 const GLuint index_compute1 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute1");
1643 const GLuint index_compute2 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute2");
1644 const GLuint index_compute3 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Compute3");
1645 const GLint loc_compute0 = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[0]");
1646 const GLint loc_compute1 = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[1]");
1647 const GLint loc_compute2 = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[2]");
1648 const GLint loc_compute3 = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "Compute[3]");
1651 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
1652 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
1653 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomic_counter_buffer);
1654 glBindImageTexture(0, m_texture_buffer[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32UI);
1655 glActiveTexture(GL_TEXTURE0);
1656 glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer[1]);
1658 glUseProgram(m_program);
1660 // setup subroutines
1662 indices[loc_compute0] = index_compute0;
1663 indices[loc_compute1] = index_compute1;
1664 indices[loc_compute2] = index_compute2;
1665 indices[loc_compute3] = index_compute3;
1666 glUniformSubroutinesuiv(GL_COMPUTE_SHADER, 4, indices);
1668 glDispatchCompute(4, 1, 1);
1670 std::vector<uvec4> data(64);
1671 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
1672 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1673 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(uvec4) * 64, &data[0]);
1675 for (GLuint i = 0; i < 64; ++i)
1677 if (!IsEqual(data[i], uvec4(i)))
1679 m_context.getTestContext().getLog()
1680 << tcu::TestLog::Message << "Invalid value at index " << i << "." << tcu::TestLog::EndMessage;
1686 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomic_counter_buffer);
1687 glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &value);
1690 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Final atomic counter value is " << value
1691 << " should be 16." << tcu::TestLog::EndMessage;
1698 virtual long Cleanup()
1701 glDeleteProgram(m_program);
1702 glDeleteBuffers(1, &m_atomic_counter_buffer);
1703 glDeleteBuffers(2, m_storage_buffer);
1704 glDeleteBuffers(2, m_buffer);
1705 glDeleteTextures(2, m_texture_buffer);
1710 class BasicResourceUniform : public ComputeShaderBase
1713 virtual std::string Title()
1715 return "Compute Shader resources - Uniforms";
1718 virtual std::string Purpose()
1720 return NL "1. Verify that all types of uniform variables work as expected in CS." NL
1721 "2. Verify that uniform variables can be updated with Uniform* and ProgramUniform* commands." NL
1722 "3. Verify that re-linking CS program works as expected.";
1725 virtual std::string Method()
1727 return NL "1. Create CS which uses all (single precision and integer) types of uniform variables." NL
1728 "2. Update uniform variables with ProgramUniform* commands." NL
1729 "3. Verify that uniform variables were updated correctly." NL "4. Re-link CS program." NL
1730 "5. Update uniform variables with Uniform* commands." NL
1731 "6. Verify that uniform variables were updated correctly.";
1734 virtual std::string PassCriteria()
1736 return "Everything works as expected.";
1740 GLuint m_storage_buffer;
1742 virtual long Setup()
1745 m_storage_buffer = 0;
1751 const char* const glsl_cs = NL
1752 "layout(local_size_x = 1) in;" NL "buffer Result {" NL " int g_result;" NL "};" NL "uniform float g_0;" NL
1753 "uniform vec2 g_1;" NL "uniform vec3 g_2;" NL "uniform vec4 g_3;" NL "uniform mat2 g_4;" NL
1754 "uniform mat2x3 g_5;" NL "uniform mat2x4 g_6;" NL "uniform mat3x2 g_7;" NL "uniform mat3 g_8;" NL
1755 "uniform mat3x4 g_9;" NL "uniform mat4x2 g_10;" NL "uniform mat4x3 g_11;" NL "uniform mat4 g_12;" NL
1756 "uniform int g_13;" NL "uniform ivec2 g_14;" NL "uniform ivec3 g_15;" NL "uniform ivec4 g_16;" NL
1757 "uniform uint g_17;" NL "uniform uvec2 g_18;" NL "uniform uvec3 g_19;" NL "uniform uvec4 g_20;" NL NL
1758 "void main() {" NL " g_result = 1;" NL NL " if (g_0 != 1.0) g_result = 0;" NL
1759 " if (g_1 != vec2(2.0, 3.0)) g_result = 0;" NL " if (g_2 != vec3(4.0, 5.0, 6.0)) g_result = 0;" NL
1760 " if (g_3 != vec4(7.0, 8.0, 9.0, 10.0)) g_result = 0;" NL NL
1761 " if (g_4 != mat2(11.0, 12.0, 13.0, 14.0)) g_result = 0;" NL
1762 " if (g_5 != mat2x3(15.0, 16.0, 17.0, 18.0, 19.0, 20.0)) g_result = 0;" NL
1763 " if (g_6 != mat2x4(21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0)) g_result = 0;" NL NL
1764 " if (g_7 != mat3x2(29.0, 30.0, 31.0, 32.0, 33.0, 34.0)) g_result = 0;" NL
1765 " if (g_8 != mat3(35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0)) g_result = 0;" NL
1766 " if (g_9 != mat3x4(44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0)) g_result = "
1767 "0;" NL NL " if (g_10 != mat4x2(56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0)) g_result = 0;" NL
1768 " if (g_11 != mat4x3(63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0)) g_result = "
1769 "0;" NL " if (g_12 != mat4(75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, "
1770 "88.0, 89.0, 90.0)) g_result = 0;" NL NL " if (g_13 != 91) g_result = 0;" NL
1771 " if (g_14 != ivec2(92, 93)) g_result = 0;" NL " if (g_15 != ivec3(94, 95, 96)) g_result = 0;" NL
1772 " if (g_16 != ivec4(97, 98, 99, 100)) g_result = 0;" NL NL " if (g_17 != 101u) g_result = 0;" NL
1773 " if (g_18 != uvec2(102u, 103u)) g_result = 0;" NL
1774 " if (g_19 != uvec3(104u, 105u, 106u)) g_result = 0;" NL
1775 " if (g_20 != uvec4(107u, 108u, 109u, 110u)) g_result = 0;" NL "}";
1776 m_program = CreateComputeProgram(glsl_cs);
1777 glLinkProgram(m_program);
1778 if (!CheckProgram(m_program))
1781 glGenBuffers(1, &m_storage_buffer);
1784 const int data = 123;
1785 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
1786 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
1789 glProgramUniform1f(m_program, glGetUniformLocation(m_program, "g_0"), 1.0f);
1790 glProgramUniform2f(m_program, glGetUniformLocation(m_program, "g_1"), 2.0f, 3.0f);
1791 glProgramUniform3f(m_program, glGetUniformLocation(m_program, "g_2"), 4.0f, 5.0f, 6.0f);
1792 glProgramUniform4f(m_program, glGetUniformLocation(m_program, "g_3"), 7.0f, 8.0f, 9.0f, 10.0f);
1796 const GLfloat value[4] = { 11.0f, 12.0f, 13.0f, 14.0f };
1797 glProgramUniformMatrix2fv(m_program, glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
1801 const GLfloat value[6] = { 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f };
1802 glProgramUniformMatrix2x3fv(m_program, glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
1806 const GLfloat value[8] = { 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f };
1807 glProgramUniformMatrix2x4fv(m_program, glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
1812 const GLfloat value[6] = { 29.0f, 30.0f, 31.0f, 32.0f, 33.0f, 34.0f };
1813 glProgramUniformMatrix3x2fv(m_program, glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
1817 const GLfloat value[9] = { 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, 42.0f, 43.0f };
1818 glProgramUniformMatrix3fv(m_program, glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
1822 const GLfloat value[12] = { 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, 49.0f,
1823 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f };
1824 glProgramUniformMatrix3x4fv(m_program, glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
1829 const GLfloat value[8] = { 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f };
1830 glProgramUniformMatrix4x2fv(m_program, glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
1834 const GLfloat value[12] = {
1835 63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, 27.0f, 73, 74.0f
1837 glProgramUniformMatrix4x3fv(m_program, glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
1841 const GLfloat value[16] = { 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, 80.0f, 81.0f, 82.0f,
1842 83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, 90.0f };
1843 glProgramUniformMatrix4fv(m_program, glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
1846 glProgramUniform1i(m_program, glGetUniformLocation(m_program, "g_13"), 91);
1847 glProgramUniform2i(m_program, glGetUniformLocation(m_program, "g_14"), 92, 93);
1848 glProgramUniform3i(m_program, glGetUniformLocation(m_program, "g_15"), 94, 95, 96);
1849 glProgramUniform4i(m_program, glGetUniformLocation(m_program, "g_16"), 97, 98, 99, 100);
1851 glProgramUniform1ui(m_program, glGetUniformLocation(m_program, "g_17"), 101);
1852 glProgramUniform2ui(m_program, glGetUniformLocation(m_program, "g_18"), 102, 103);
1853 glProgramUniform3ui(m_program, glGetUniformLocation(m_program, "g_19"), 104, 105, 106);
1854 glProgramUniform4ui(m_program, glGetUniformLocation(m_program, "g_20"), 107, 108, 109, 110);
1856 glUseProgram(m_program);
1857 glDispatchCompute(1, 1, 1);
1858 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1862 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
1865 m_context.getTestContext().getLog()
1866 << tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
1871 // re-link program (all uniforms will be set to zero)
1872 glLinkProgram(m_program);
1875 const int data = 123;
1876 glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
1879 glUniform1f(glGetUniformLocation(m_program, "g_0"), 1.0f);
1880 glUniform2f(glGetUniformLocation(m_program, "g_1"), 2.0f, 3.0f);
1881 glUniform3f(glGetUniformLocation(m_program, "g_2"), 4.0f, 5.0f, 6.0f);
1882 glUniform4f(glGetUniformLocation(m_program, "g_3"), 7.0f, 8.0f, 9.0f, 10.0f);
1886 const GLfloat value[4] = { 11.0f, 12.0f, 13.0f, 14.0f };
1887 glUniformMatrix2fv(glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
1891 const GLfloat value[6] = { 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f };
1892 glUniformMatrix2x3fv(glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
1896 const GLfloat value[8] = { 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f };
1897 glUniformMatrix2x4fv(glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
1902 const GLfloat value[6] = { 29.0f, 30.0f, 31.0f, 32.0f, 33.0f, 34.0f };
1903 glUniformMatrix3x2fv(glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
1907 const GLfloat value[9] = { 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, 42.0f, 43.0f };
1908 glUniformMatrix3fv(glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
1912 const GLfloat value[12] = { 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, 49.0f,
1913 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f };
1914 glUniformMatrix3x4fv(glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
1919 const GLfloat value[8] = { 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f };
1920 glUniformMatrix4x2fv(glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
1924 const GLfloat value[12] = {
1925 63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, 27.0f, 73, 74.0f
1927 glUniformMatrix4x3fv(glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
1931 const GLfloat value[16] = { 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, 80.0f, 81.0f, 82.0f,
1932 83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, 90.0f };
1933 glUniformMatrix4fv(glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
1936 glUniform1i(glGetUniformLocation(m_program, "g_13"), 91);
1937 glUniform2i(glGetUniformLocation(m_program, "g_14"), 92, 93);
1938 glUniform3i(glGetUniformLocation(m_program, "g_15"), 94, 95, 96);
1939 glUniform4i(glGetUniformLocation(m_program, "g_16"), 97, 98, 99, 100);
1941 glUniform1ui(glGetUniformLocation(m_program, "g_17"), 101);
1942 glUniform2ui(glGetUniformLocation(m_program, "g_18"), 102, 103);
1943 glUniform3ui(glGetUniformLocation(m_program, "g_19"), 104, 105, 106);
1944 glUniform4ui(glGetUniformLocation(m_program, "g_20"), 107, 108, 109, 110);
1946 glDispatchCompute(1, 1, 1);
1947 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1952 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
1955 m_context.getTestContext().getLog()
1956 << tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
1964 virtual long Cleanup()
1967 glDeleteProgram(m_program);
1968 glDeleteBuffers(1, &m_storage_buffer);
1973 class BasicBuiltinVariables : public ComputeShaderBase
1976 virtual std::string Title()
1978 return "CS built-in variables";
1981 virtual std::string Purpose()
1983 return NL "Verify that all (gl_WorkGroupSize, gl_WorkGroupID, gl_LocalInvocationID," NL
1984 "gl_GlobalInvocationID, gl_NumWorkGroups, gl_WorkGroupSize)" NL
1985 "CS built-in variables has correct values.";
1988 virtual std::string Method()
1990 return NL "1. Create CS which writes all built-in variables to SSBO." NL
1991 "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
1992 "3. Verify SSBO content." NL "4. Repeat for several different local and global work sizes.";
1995 virtual std::string PassCriteria()
1997 return "Everything works as expected.";
2001 GLuint m_storage_buffer;
2002 GLuint m_dispatch_buffer;
2004 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
2006 const uvec3 global_size = local_size * num_groups;
2007 std::stringstream ss;
2008 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
2009 << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
2010 << ", " << global_size.y() << ", " << global_size.z()
2011 << ");" NL "layout(std430) buffer OutputBuffer {" NL " uvec4 num_work_groups["
2012 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 work_group_size["
2013 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 work_group_id["
2014 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 local_invocation_id["
2015 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 global_invocation_id["
2016 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 local_invocation_index["
2017 << global_size.x() * global_size.y() * global_size.z()
2018 << "];" NL "} g_out_buffer;" NL "void main() {" NL
2019 " if ((gl_WorkGroupSize * gl_WorkGroupID + gl_LocalInvocationID) != gl_GlobalInvocationID) return;" NL
2020 " const uint global_index = gl_GlobalInvocationID.x +" NL
2021 " gl_GlobalInvocationID.y * kGlobalSize.x +" NL
2022 " gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
2023 " g_out_buffer.num_work_groups[global_index] = uvec4(gl_NumWorkGroups, 0);" NL
2024 " g_out_buffer.work_group_size[global_index] = uvec4(gl_WorkGroupSize, 0);" NL
2025 " g_out_buffer.work_group_id[global_index] = uvec4(gl_WorkGroupID, 0);" NL
2026 " g_out_buffer.local_invocation_id[global_index] = uvec4(gl_LocalInvocationID, 0);" NL
2027 " g_out_buffer.global_invocation_id[global_index] = uvec4(gl_GlobalInvocationID, 0);" NL
2028 " g_out_buffer.local_invocation_index[global_index] = uvec4(gl_LocalInvocationIndex);" NL "}";
2032 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
2035 glDeleteProgram(m_program);
2036 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
2037 glLinkProgram(m_program);
2038 if (!CheckProgram(m_program))
2041 const GLuint kBufferSize =
2042 local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
2044 std::vector<uvec4> data(kBufferSize * 6);
2045 if (m_storage_buffer == 0)
2046 glGenBuffers(1, &m_storage_buffer);
2047 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2048 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * kBufferSize * 6, &data[0], GL_DYNAMIC_DRAW);
2049 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2051 glUseProgram(m_program);
2052 if (dispatch_indirect)
2054 if (m_dispatch_buffer == 0)
2055 glGenBuffers(1, &m_dispatch_buffer);
2056 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
2057 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
2058 glDispatchComputeIndirect(0);
2062 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
2065 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
2066 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2067 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(uvec4) * kBufferSize * 6, &data[0]);
2070 for (GLuint index = 0; index < kBufferSize; ++index)
2072 if (!IsEqual(data[index], uvec4(num_groups.x(), num_groups.y(), num_groups.z(), 0)))
2074 m_context.getTestContext().getLog()
2075 << tcu::TestLog::Message << "gl_NumWorkGroups: Invalid data at index " << index << "."
2076 << tcu::TestLog::EndMessage;
2081 for (GLuint index = kBufferSize; index < 2 * kBufferSize; ++index)
2083 if (!IsEqual(data[index], uvec4(local_size.x(), local_size.y(), local_size.z(), 0)))
2085 m_context.getTestContext().getLog()
2086 << tcu::TestLog::Message << "gl_WorkGroupSize: Invalid data at index " << index << "."
2087 << tcu::TestLog::EndMessage;
2092 for (GLuint index = 2 * kBufferSize; index < 3 * kBufferSize; ++index)
2094 uvec3 expected = IndexTo3DCoord(index - 2 * kBufferSize, local_size.x() * num_groups.x(),
2095 local_size.y() * num_groups.y());
2096 expected.x() /= local_size.x();
2097 expected.y() /= local_size.y();
2098 expected.z() /= local_size.z();
2099 if (!IsEqual(data[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
2101 m_context.getTestContext().getLog() << tcu::TestLog::Message << "gl_WorkGroupID: Invalid data at index "
2102 << index << "." << tcu::TestLog::EndMessage;
2106 // gl_LocalInvocationID
2107 for (GLuint index = 3 * kBufferSize; index < 4 * kBufferSize; ++index)
2109 uvec3 expected = IndexTo3DCoord(index - 3 * kBufferSize, local_size.x() * num_groups.x(),
2110 local_size.y() * num_groups.y());
2111 expected.x() %= local_size.x();
2112 expected.y() %= local_size.y();
2113 expected.z() %= local_size.z();
2114 if (!IsEqual(data[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
2116 m_context.getTestContext().getLog()
2117 << tcu::TestLog::Message << "gl_LocalInvocationID: Invalid data at index " << index << "."
2118 << tcu::TestLog::EndMessage;
2122 // gl_GlobalInvocationID
2123 for (GLuint index = 4 * kBufferSize; index < 5 * kBufferSize; ++index)
2125 uvec3 expected = IndexTo3DCoord(index - 4 * kBufferSize, local_size.x() * num_groups.x(),
2126 local_size.y() * num_groups.y());
2127 if (!IsEqual(data[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
2129 m_context.getTestContext().getLog()
2130 << tcu::TestLog::Message << "gl_GlobalInvocationID: Invalid data at index " << index << "."
2131 << tcu::TestLog::EndMessage;
2135 // gl_LocalInvocationIndex
2136 for (GLuint index = 5 * kBufferSize; index < 6 * kBufferSize; ++index)
2138 uvec3 coord = IndexTo3DCoord(index - 5 * kBufferSize, local_size.x() * num_groups.x(),
2139 local_size.y() * num_groups.y());
2140 const GLuint expected = (coord.x() % local_size.x()) + (coord.y() % local_size.y()) * local_size.x() +
2141 (coord.z() % local_size.z()) * local_size.x() * local_size.y();
2142 if (!IsEqual(data[index], uvec4(expected)))
2144 m_context.getTestContext().getLog()
2145 << tcu::TestLog::Message << "gl_LocalInvocationIndex: Invalid data at index " << index << "."
2146 << tcu::TestLog::EndMessage;
2153 virtual long Setup()
2156 m_storage_buffer = 0;
2157 m_dispatch_buffer = 0;
2163 if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
2165 if (!RunIteration(uvec3(1, 1, 64), uvec3(1, 5, 2), true))
2167 if (!RunIteration(uvec3(1, 1, 4), uvec3(2, 2, 2), false))
2169 if (!RunIteration(uvec3(3, 2, 1), uvec3(1, 2, 3), true))
2171 if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
2173 if (!RunIteration(uvec3(2, 4, 7), uvec3(2, 1, 4), true))
2178 virtual long Cleanup()
2181 glDeleteProgram(m_program);
2182 glDeleteBuffers(1, &m_storage_buffer);
2183 glDeleteBuffers(1, &m_dispatch_buffer);
2188 class BasicMax : public ComputeShaderBase
2191 virtual std::string Title()
2193 return NL "CS max values";
2196 virtual std::string Purpose()
2198 return NL "Verify (on the API and GLSL side) that all GL_MAX_COMPUTE_* values are not less than" NL
2199 "required by the OpenGL specification.";
2202 virtual std::string Method()
2204 return NL "1. Use all API commands to query all GL_MAX_COMPUTE_* values. Verify that they are correct." NL
2205 "2. Verify all gl_MaxCompute* constants in the GLSL.";
2208 virtual std::string PassCriteria()
2210 return NL "Everything works as expected.";
2216 bool CheckIndexed(GLenum target, const GLint* min_values)
2224 for (GLuint c = 0; c < 3; c++)
2226 glGetIntegeri_v(target, c, &i);
2227 if (i < min_values[c])
2229 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << i << " should be at least "
2230 << min_values[c] << "." << tcu::TestLog::EndMessage;
2234 for (GLuint c = 0; c < 3; c++)
2236 glGetInteger64i_v(target, c, &i64);
2237 if (i64 < static_cast<GLint64>(min_values[c]))
2239 m_context.getTestContext().getLog()
2240 << tcu::TestLog::Message << "Is " << static_cast<GLint>(i64) << " should be at least "
2241 << min_values[c] << "." << tcu::TestLog::EndMessage;
2245 for (GLuint c = 0; c < 3; c++)
2247 glGetFloati_v(target, c, &f);
2248 if (f < static_cast<GLfloat>(min_values[c]))
2250 m_context.getTestContext().getLog()
2251 << tcu::TestLog::Message << "Is " << static_cast<GLint>(f) << " should be at least "
2252 << min_values[c] << "." << tcu::TestLog::EndMessage;
2256 for (GLuint c = 0; c < 3; c++)
2258 glGetDoublei_v(target, c, &d);
2259 if (d < static_cast<GLdouble>(min_values[c]))
2261 m_context.getTestContext().getLog()
2262 << tcu::TestLog::Message << "Is " << static_cast<GLint>(d) << " should be at least "
2263 << min_values[c] << "." << tcu::TestLog::EndMessage;
2267 for (GLuint c = 0; c < 3; c++)
2269 glGetBooleani_v(target, c, &b);
2272 m_context.getTestContext().getLog()
2273 << tcu::TestLog::Message << "Is GL_FALSE should be at least GL_TRUE." << tcu::TestLog::EndMessage;
2281 bool Check(GLenum target, const GLint min_value)
2289 glGetIntegerv(target, &i);
2292 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << i << " should be at least "
2293 << min_value << "." << tcu::TestLog::EndMessage;
2296 glGetInteger64v(target, &i64);
2297 if (static_cast<GLint>(i64) < min_value)
2299 m_context.getTestContext().getLog()
2300 << tcu::TestLog::Message << "Is " << static_cast<GLint>(i64) << " should be at least " << min_value
2301 << "." << tcu::TestLog::EndMessage;
2304 glGetFloatv(target, &f);
2305 if (f < static_cast<GLfloat>(min_value))
2307 m_context.getTestContext().getLog()
2308 << tcu::TestLog::Message << "Is " << static_cast<GLint>(f) << " should be at least " << min_value << "."
2309 << tcu::TestLog::EndMessage;
2312 glGetDoublev(target, &d);
2313 if (d < static_cast<GLdouble>(min_value))
2315 m_context.getTestContext().getLog()
2316 << tcu::TestLog::Message << "Is " << static_cast<GLint>(d) << " should be at least " << min_value << "."
2317 << tcu::TestLog::EndMessage;
2320 glGetBooleanv(target, &b);
2321 if (b != (min_value ? GL_TRUE : GL_FALSE))
2323 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << b << " should be "
2324 << (min_value ? GL_TRUE : GL_FALSE) << "." << tcu::TestLog::EndMessage;
2331 virtual long Setup()
2340 const GLint work_group_count[3] = { 65535, 65535, 65535 };
2341 if (!CheckIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, work_group_count))
2344 const GLint work_group_size[3] = { 1024, 1024, 64 };
2345 if (!CheckIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, work_group_size))
2348 if (!Check(GL_MAX_COMPUTE_UNIFORM_BLOCKS, 12))
2350 if (!Check(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, 16))
2352 if (!Check(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, 8))
2354 if (!Check(GL_MAX_COMPUTE_ATOMIC_COUNTERS, 8))
2356 if (!Check(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, 32768))
2359 if (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)))
2361 if (!Check(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 1024))
2366 if (!Check(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 512))
2370 if (!Check(GL_MAX_COMPUTE_IMAGE_UNIFORMS, 8))
2372 if (!Check(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, 512))
2375 const char* const glsl_cs =
2376 NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL " int g_output;" NL "};" NL
2377 "uniform ivec3 MaxComputeWorkGroupCount;" NL "uniform ivec3 MaxComputeWorkGroupSize;" NL
2378 "uniform int MaxComputeUniformComponents;" NL "uniform int MaxComputeTextureImageUnits;" NL
2379 "uniform int MaxComputeImageUniforms;" NL "uniform int MaxComputeAtomicCounters;" NL
2380 "uniform int MaxComputeAtomicCounterBuffers;" NL "void main() {" NL " g_output = 1;" NL
2381 " if (MaxComputeWorkGroupCount != gl_MaxComputeWorkGroupCount) g_output = 0;" NL
2382 " if (MaxComputeWorkGroupSize != gl_MaxComputeWorkGroupSize) g_output = 0;" NL
2383 " if (MaxComputeUniformComponents != gl_MaxComputeUniformComponents) g_output = 0;" NL
2384 " if (MaxComputeTextureImageUnits != gl_MaxComputeTextureImageUnits) g_output = 0;" NL
2385 " if (MaxComputeImageUniforms != gl_MaxComputeImageUniforms) g_output = 0;" NL
2386 " if (MaxComputeAtomicCounters != gl_MaxComputeAtomicCounters) g_output = 0;" NL
2387 " if (MaxComputeAtomicCounterBuffers != gl_MaxComputeAtomicCounterBuffers) g_output = 0;" NL "}";
2388 m_program = CreateComputeProgram(glsl_cs);
2389 glLinkProgram(m_program);
2390 if (!CheckProgram(m_program))
2392 glUseProgram(m_program);
2395 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &p[0]);
2396 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &p[1]);
2397 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &p[2]);
2398 glUniform3i(glGetUniformLocation(m_program, "MaxComputeWorkGroupCount"), p[0], p[1], p[2]);
2400 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &p[0]);
2401 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &p[1]);
2402 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &p[2]);
2403 glUniform3iv(glGetUniformLocation(m_program, "MaxComputeWorkGroupSize"), 1, p);
2405 glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, p);
2406 glUniform1i(glGetUniformLocation(m_program, "MaxComputeUniformComponents"), p[0]);
2408 glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, p);
2409 glUniform1iv(glGetUniformLocation(m_program, "MaxComputeTextureImageUnits"), 1, p);
2411 glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, p);
2412 glUniform1i(glGetUniformLocation(m_program, "MaxComputeImageUniforms"), p[0]);
2414 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, p);
2415 glUniform1i(glGetUniformLocation(m_program, "MaxComputeAtomicCounters"), p[0]);
2417 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, p);
2418 glUniform1i(glGetUniformLocation(m_program, "MaxComputeAtomicCounterBuffers"), p[0]);
2420 GLint data = 0xffff;
2421 glGenBuffers(1, &m_buffer);
2422 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
2423 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint), &data, GL_DYNAMIC_DRAW);
2425 glDispatchCompute(1, 1, 1);
2427 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2428 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint), &data);
2430 return data == 1 ? NO_ERROR : ERROR;
2432 virtual long Cleanup()
2435 glDeleteProgram(m_program);
2436 glDeleteBuffers(1, &m_buffer);
2441 class BasicBuildMonolithic : public ComputeShaderBase
2444 virtual std::string Title()
2446 return "Building CS monolithic program";
2449 virtual std::string Purpose()
2451 return NL "1. Verify that building monolithic CS program works as expected." NL
2452 "2. Verify that program consisting from 3 compilation units links as expected." NL
2453 "3. Verify that CS consisting from 2 strings compiles as expected.";
2456 virtual std::string Method()
2458 return NL "1. Create, compile and link CS using CreateShader, CompileShader and LinkProgram commands." NL
2459 "2. Dispatch and verify CS program.";
2462 virtual std::string PassCriteria()
2464 return "Everything works as expected.";
2469 const char* const cs1[2] = { "#version 430 core",
2471 NL "layout(local_size_x = 1) in;" NL "void Run();" NL "void main() {" NL
2474 const char* const cs2 =
2475 "#version 430 core" NL "layout(binding = 0, std430) buffer Output {" NL " vec4 g_output;" NL "};" NL
2476 "vec4 CalculateOutput();" NL "void Run() {" NL " g_output = CalculateOutput();" NL "}";
2478 const char* const cs3 =
2479 "#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(binding = 0, std430) buffer Output {" NL
2480 " vec4 g_output;" NL "};" NL "vec4 CalculateOutput() {" NL " g_output = vec4(0);" NL
2481 " return vec4(1, 2, 3, 4);" NL "}";
2483 const GLuint sh1 = glCreateShader(GL_COMPUTE_SHADER);
2486 glGetShaderiv(sh1, GL_SHADER_TYPE, &type);
2487 if (static_cast<GLenum>(type) != GL_COMPUTE_SHADER)
2489 m_context.getTestContext().getLog()
2490 << tcu::TestLog::Message << "SHADER_TYPE should be COMPUTE_SHADER." << tcu::TestLog::EndMessage;
2491 glDeleteShader(sh1);
2495 glShaderSource(sh1, 2, cs1, NULL);
2496 glCompileShader(sh1);
2498 const GLuint sh2 = glCreateShader(GL_COMPUTE_SHADER);
2499 glShaderSource(sh2, 1, &cs2, NULL);
2500 glCompileShader(sh2);
2502 const GLuint sh3 = glCreateShader(GL_COMPUTE_SHADER);
2503 glShaderSource(sh3, 1, &cs3, NULL);
2504 glCompileShader(sh3);
2506 const GLuint p = glCreateProgram();
2507 glAttachShader(p, sh1);
2508 glAttachShader(p, sh2);
2509 glAttachShader(p, sh3);
2512 glDeleteShader(sh1);
2513 glDeleteShader(sh2);
2514 glDeleteShader(sh3);
2516 bool res = CheckProgram(p);
2519 glGenBuffers(1, &buffer);
2520 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer);
2521 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), &vec4(0.0f)[0], GL_DYNAMIC_DRAW);
2522 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2525 glDispatchCompute(1, 1, 1);
2528 glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
2529 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2530 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &data[0]);
2531 if (!IsEqual(data, vec4(1.0f, 2.0f, 3.0f, 4.0f)))
2533 m_context.getTestContext().getLog()
2534 << tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
2538 glDeleteBuffers(1, &buffer);
2542 return res == true ? NO_ERROR : ERROR;
2546 class BasicBuildSeparable : public ComputeShaderBase
2549 virtual std::string Title()
2551 return "Building CS separable program";
2554 virtual std::string Purpose()
2556 return NL "1. Verify that building separable CS program works as expected." NL
2557 "2. Verify that program consisting from 4 strings works as expected.";
2560 virtual std::string Method()
2562 return NL "1. Create, compile and link CS using CreateShaderProgramv command." NL
2563 "2. Dispatch and verify CS program.";
2566 virtual std::string PassCriteria()
2568 return "Everything works as expected.";
2573 const char* const cs[4] = {
2574 "#version 430 core",
2576 NL "layout(local_size_x = 1) in;" NL "void Run();" NL "void main() {" NL " Run();" NL "}",
2577 NL "layout(binding = 0, std430) buffer Output {" NL " vec4 g_output;" NL "};" NL
2578 "vec4 CalculateOutput();" NL "void Run() {" NL " g_output = CalculateOutput();" NL "}",
2579 NL "vec4 CalculateOutput() {" NL " g_output = vec4(0);" NL " return vec4(1, 2, 3, 4);" NL "}"
2582 const GLuint p = glCreateShaderProgramv(GL_COMPUTE_SHADER, 4, cs);
2583 bool res = CheckProgram(p);
2586 glGenBuffers(1, &buffer);
2587 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer);
2588 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), &vec4(0.0f)[0], GL_DYNAMIC_DRAW);
2589 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2592 glDispatchCompute(1, 1, 1);
2595 glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
2596 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2597 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &data[0]);
2598 if (!IsEqual(data, vec4(1.0f, 2.0f, 3.0f, 4.0f)))
2600 m_context.getTestContext().getLog()
2601 << tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
2605 glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &vec4(0.0f)[0]);
2608 glGenProgramPipelines(1, &pipeline);
2609 glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, p);
2612 glBindProgramPipeline(pipeline);
2613 glDispatchCompute(1, 1, 1);
2615 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2616 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &data[0]);
2617 if (!IsEqual(data, vec4(1.0f, 2.0f, 3.0f, 4.0f)))
2619 m_context.getTestContext().getLog()
2620 << tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
2624 glDeleteProgramPipelines(1, &pipeline);
2625 glDeleteBuffers(1, &buffer);
2628 return res == true ? NO_ERROR : ERROR;
2632 class BasicSharedSimple : public ComputeShaderBase
2634 virtual std::string Title()
2636 return "Shared Memory - simple usage";
2639 virtual std::string Purpose()
2641 return NL "1. Verify that shared array of uints works as expected." NL
2642 "2. Verify that shared memory written by one invocation is observable by other invocations" NL
2643 " when groupMemoryBarrier() and barrier() built-in functions are used.";
2646 virtual std::string Method()
2648 return NL "1. Create and dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
2649 "2. Verify results written by CS to SSBO." NL
2650 "3. Repeat for several different number of work groups.";
2653 virtual std::string PassCriteria()
2655 return "Everything works as expected.";
2659 GLuint m_storage_buffer;
2660 GLuint m_dispatch_buffer;
2662 bool RunIteration(const GLuint num_groups, bool dispatch_indirect)
2664 const GLuint kBufferSize = 256 * num_groups;
2666 std::vector<GLuint> data(kBufferSize, 0xffff);
2667 if (m_storage_buffer == 0)
2668 glGenBuffers(1, &m_storage_buffer);
2669 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2670 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
2671 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2673 glUseProgram(m_program);
2674 if (dispatch_indirect)
2676 const GLuint groups[3] = { num_groups, 1, 1 };
2677 if (m_dispatch_buffer == 0)
2678 glGenBuffers(1, &m_dispatch_buffer);
2679 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
2680 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(groups), groups, GL_STATIC_DRAW);
2681 glDispatchComputeIndirect(0);
2685 glDispatchCompute(num_groups, 1, 1);
2688 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
2689 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2690 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, &data[0]);
2691 for (GLuint i = 0; i < kBufferSize; ++i)
2695 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
2696 << data[i] << " should be 1." << tcu::TestLog::EndMessage;
2703 virtual long Setup()
2706 m_storage_buffer = 0;
2707 m_dispatch_buffer = 0;
2713 const char* const glsl_cs =
2714 NL "layout(local_size_x = 256) in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
2715 "shared uint g_shared_data[256];" NL "void main() {" NL
2716 " g_shared_data[gl_LocalInvocationID.x] = gl_LocalInvocationIndex;" NL
2717 " groupMemoryBarrier();" // flush memory stores
2718 NL " barrier();" // wait for all stores to finish
2719 NL " g_output[gl_GlobalInvocationID.x] = 1;" NL " if (gl_LocalInvocationIndex < 255) {" NL
2720 " const uint res = g_shared_data[gl_LocalInvocationID.x + "
2721 "1];" // load data from shared memory filled by other thread
2722 NL " if (res != (gl_LocalInvocationIndex + 1)) {" NL " g_output[gl_GlobalInvocationID.x] = 0;" NL
2723 " }" NL " }" NL "}";
2724 m_program = CreateComputeProgram(glsl_cs);
2725 glLinkProgram(m_program);
2726 if (!CheckProgram(m_program))
2729 if (!RunIteration(1, false))
2731 if (!RunIteration(8, true))
2733 if (!RunIteration(13, false))
2735 if (!RunIteration(7, true))
2739 virtual long Cleanup()
2742 glDeleteProgram(m_program);
2743 glDeleteBuffers(1, &m_storage_buffer);
2744 glDeleteBuffers(1, &m_dispatch_buffer);
2749 class BasicSharedStruct : public ComputeShaderBase
2751 virtual std::string Title()
2753 return "Shared Memory - arrays and structers";
2756 virtual std::string Purpose()
2758 return NL "1. Verify that vectors, matrices, structers and arrays of those can be used" NL
2759 " as a shared memory." NL
2760 "2. Verify that shared memory can be indexed with constant values, built-in" NL
2761 " variables and dynamic expressions." NL
2762 "3. Verify that memoryBarrierAtomicCounter(), memoryBarrierImage(), memoryBarrier()," NL
2763 " memoryBarrierBuffer() and memoryBarrierShared() built-in functions are accepted" NL
2764 " by the GLSL compiler.";
2767 virtual std::string Method()
2769 return NL "1. Create and dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
2770 "2. Verify results written by CS to SSBO.";
2773 virtual std::string PassCriteria()
2775 return "Everything works as expected.";
2779 GLuint m_storage_buffer;
2780 GLuint m_dispatch_buffer;
2782 bool RunIteration(bool dispatch_indirect)
2784 const GLuint kBufferSize = 256;
2786 std::vector<vec4> data(kBufferSize);
2787 if (m_storage_buffer == 0)
2788 glGenBuffers(1, &m_storage_buffer);
2789 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2790 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
2791 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2793 glUseProgram(m_program);
2794 if (dispatch_indirect)
2796 const GLuint groups[3] = { 1, 1, 1 };
2797 if (m_dispatch_buffer == 0)
2798 glGenBuffers(1, &m_dispatch_buffer);
2799 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
2800 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(groups), groups, GL_STATIC_DRAW);
2801 glDispatchComputeIndirect(0);
2805 glDispatchCompute(1, 1, 1);
2808 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
2809 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2810 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize, &data[0]);
2811 for (GLuint i = 0; i < kBufferSize; ++i)
2813 if (!IsEqual(data[i], vec4(static_cast<float>(i))))
2815 m_context.getTestContext().getLog()
2816 << tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
2823 virtual long Setup()
2826 m_storage_buffer = 0;
2827 m_dispatch_buffer = 0;
2833 const char* const glsl_cs = NL
2834 "layout(local_size_x = 128) in;" NL "layout(std430) buffer Output {" NL " vec4 g_output[256];" NL "};" NL
2835 "struct SubData {" NL " mat2x4 data;" NL "};" NL "struct Data {" NL " uint index;" NL " vec3 data0;" NL
2836 " SubData data1;" NL "};" NL "shared Data g_shared_data[256];" NL "shared int g_shared_buf[2];" NL
2837 "void main() {" NL " if (gl_LocalInvocationID.x == 0) {" NL " g_shared_buf[1] = 1;" NL
2838 " g_shared_buf[1 + gl_LocalInvocationID.x] = 0;" NL " g_shared_buf[0] = 128;" NL
2839 " g_output[0] = vec4(g_shared_buf[1]);" NL " g_output[128] = vec4(g_shared_buf[0]);" NL
2840 " memoryBarrierBuffer();" // note: this call is not needed here, just check if compiler accepts it
2841 NL " } else {" NL " const uint index = gl_LocalInvocationIndex;" NL
2842 " g_shared_data[index].index = index;" NL " g_shared_data[index + 128].index = index + 128;" NL
2843 " g_shared_data[index].data1.data = mat2x4(0.0);" NL
2844 " g_shared_data[index + 128].data1.data = mat2x4(0.0);" NL
2845 " g_output[index] = vec4(g_shared_data[index].index);" // load data from shared memory
2846 NL " g_output[index + 128] = vec4(g_shared_data[index + 128].index);" NL
2847 " memoryBarrierShared();" // note: this call is not needed here, just check if compiler accepts it
2848 NL " }" NL " memoryBarrierAtomicCounter();" NL " memoryBarrierImage();" NL
2849 " memoryBarrier();" // note: these calls are not needed here, just check if compiler accepts them
2851 m_program = CreateComputeProgram(glsl_cs);
2852 glLinkProgram(m_program);
2853 if (!CheckProgram(m_program))
2856 if (!RunIteration(false))
2858 if (!RunIteration(true))
2863 virtual long Cleanup()
2866 glDeleteProgram(m_program);
2867 glDeleteBuffers(1, &m_storage_buffer);
2868 glDeleteBuffers(1, &m_dispatch_buffer);
2873 class BasicDispatchIndirect : public ComputeShaderBase
2875 virtual std::string Title()
2877 return NL "DispatchComputeIndirect command";
2880 virtual std::string Purpose()
2883 "1. Verify that DispatchComputeIndirect command works as described in the OpenGL specification." NL
2884 "2. Verify that <offset> parameter is correctly applied." NL
2885 "3. Verify that updating dispatch buffer with different methods (BufferData, BufferSubData, MapBuffer)" NL
2886 " just before DispatchComputeIndirect call works as expected." NL
2887 "4. Verify that GL_DISPATCH_INDIRECT_BUFFER_BINDING binding point is set correctly.";
2890 virtual std::string Method()
2893 "1. Create CS and dispatch indirect buffer." NL "2. Dispatch CS with DispatchComputeIndirect command." NL
2894 "3. Update dispatch indirect buffer." NL
2895 "4. Repeat several times updating dispatch buffer with different methods and changing <offset> parameter.";
2898 virtual std::string PassCriteria()
2900 return NL "Everything works as expected.";
2904 GLuint m_storage_buffer;
2905 GLuint m_dispatch_buffer[2];
2907 bool RunIteration(GLintptr offset, GLuint buffer_size)
2909 std::vector<GLuint> data(buffer_size);
2910 if (m_storage_buffer == 0)
2911 glGenBuffers(1, &m_storage_buffer);
2912 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2913 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * buffer_size, &data[0], GL_DYNAMIC_DRAW);
2915 glDispatchComputeIndirect(offset);
2917 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2918 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * buffer_size, &data[0]);
2919 for (GLuint i = 0; i < buffer_size; ++i)
2923 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
2924 << data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
2931 bool CheckBinding(GLuint expected)
2939 glGetIntegerv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &i);
2940 if (static_cast<GLuint>(i) != expected)
2944 glGetInteger64v(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &i64);
2945 if (static_cast<GLuint>(i64) != expected)
2949 glGetFloatv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &f);
2950 if (static_cast<GLuint>(f) != expected)
2954 glGetDoublev(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &d);
2955 if (static_cast<GLuint>(d) != expected)
2959 glGetBooleanv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &b);
2960 if (b != (expected != 0 ? GL_TRUE : GL_FALSE))
2968 virtual long Setup()
2971 m_storage_buffer = 0;
2972 memset(m_dispatch_buffer, 0, sizeof(m_dispatch_buffer));
2978 const char* const glsl_cs =
2979 NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
2980 "uniform uvec3 g_global_size;" NL "void main() {" NL
2981 " const uint global_index = gl_GlobalInvocationID.x +" NL
2982 " gl_GlobalInvocationID.y * g_global_size.x +" NL
2983 " gl_GlobalInvocationID.z * g_global_size.x * g_global_size.y;" NL
2984 " if (gl_NumWorkGroups != g_global_size) {" NL " g_output[global_index] = 0xffff;" NL
2985 " return;" NL " }" NL " g_output[global_index] = global_index;" NL "}";
2986 m_program = CreateComputeProgram(glsl_cs);
2987 glLinkProgram(m_program);
2988 if (!CheckProgram(m_program))
2991 if (!CheckBinding(0))
2994 glGenBuffers(2, m_dispatch_buffer);
2996 const GLuint data[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
2997 const GLuint data2[] = { 3, 1, 4, 4 };
2999 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[0]);
3000 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), data, GL_STREAM_DRAW);
3001 if (!CheckBinding(m_dispatch_buffer[0]))
3004 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[1]);
3005 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data2), data2, GL_STREAM_READ);
3006 if (!CheckBinding(m_dispatch_buffer[1]))
3009 glUseProgram(m_program);
3010 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[0]);
3012 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 2, 3);
3013 if (!RunIteration(0, 6))
3016 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 2, 3, 4);
3017 if (!RunIteration(4, 24))
3020 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 4, 5, 6);
3021 if (!RunIteration(12, 120))
3024 glBufferSubData(GL_DISPATCH_INDIRECT_BUFFER, 20, 12, data);
3025 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 2, 3);
3026 if (!RunIteration(20, 6))
3029 GLuint* ptr = static_cast<GLuint*>(glMapBuffer(GL_DISPATCH_INDIRECT_BUFFER, GL_WRITE_ONLY));
3033 glUnmapBuffer(GL_DISPATCH_INDIRECT_BUFFER);
3035 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 4, 4, 4);
3036 if (!RunIteration(0, 64))
3039 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[1]);
3041 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 4, 4);
3042 if (!RunIteration(4, 16))
3045 glDeleteBuffers(2, m_dispatch_buffer);
3046 memset(m_dispatch_buffer, 0, sizeof(m_dispatch_buffer));
3048 if (!CheckBinding(0))
3053 virtual long Cleanup()
3056 glDeleteProgram(m_program);
3057 glDeleteBuffers(1, &m_storage_buffer);
3058 glDeleteBuffers(2, m_dispatch_buffer);
3063 class BasicSSOComputePipeline : public ComputeShaderBase
3065 virtual std::string Title()
3067 return NL "Separable CS Programs - Compute and non-compute stages (1)";
3069 virtual std::string Purpose()
3071 return NL "1. Verify that compute and non-compute stages can be attached to one pipeline object." NL
3072 "2. Verify that DrawArrays and ComputeDispatch commands works as expected in this case.";
3074 virtual std::string Method()
3076 return NL "1. Create VS, FS and CS. Attach all created stages to one pipeline object." NL
3077 "2. Bind pipeline object." NL "3. Invoke compute stage with DispatchCompute commmand." NL
3078 "4. Issue MemoryBarrier command." NL
3079 "5. Issue DrawArrays command which uses data written by the compute stage." NL "6. Verify result.";
3081 virtual std::string PassCriteria()
3083 return NL "Everything works as expected.";
3086 GLuint m_vsp, m_fsp, m_csp;
3087 GLuint m_storage_buffer;
3088 GLuint m_vertex_array;
3091 virtual long Setup()
3093 m_vsp = m_fsp = m_csp = 0;
3094 m_storage_buffer = 0;
3101 const char* const glsl_cs =
3102 NL "layout(local_size_x = 4) in;" NL "layout(std430) buffer Output {" NL " vec4 g_output[4];" NL "};" NL
3103 "void main() {" NL " const vec2 quad[4] = { vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1) };" NL
3104 " g_output[gl_GlobalInvocationID.x] = vec4(quad[gl_GlobalInvocationID.x], 0, 1);" NL "}";
3106 m_csp = CreateComputeProgram(glsl_cs);
3107 glProgramParameteri(m_csp, GL_PROGRAM_SEPARABLE, GL_TRUE);
3108 glLinkProgram(m_csp);
3109 if (!CheckProgram(m_csp))
3112 const char* const glsl_vs =
3113 NL "layout(location = 0) in vec4 i_position;" NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL "};" NL
3114 "void main() {" NL " gl_Position = i_position;" NL "}";
3115 m_vsp = BuildShaderProgram(GL_VERTEX_SHADER, glsl_vs);
3116 if (!CheckProgram(m_vsp))
3119 const char* const glsl_fs =
3120 NL "layout(location = 0) out vec4 o_color;" NL "void main() {" NL " o_color = vec4(0, 1, 0, 1);" NL "}";
3121 m_fsp = BuildShaderProgram(GL_FRAGMENT_SHADER, glsl_fs);
3122 if (!CheckProgram(m_fsp))
3125 glGenProgramPipelines(1, &m_pipeline);
3126 glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, m_vsp);
3127 glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, m_fsp);
3128 glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_csp);
3130 glGenBuffers(1, &m_storage_buffer);
3131 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
3132 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * 4, NULL, GL_DYNAMIC_DRAW);
3133 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3135 glGenVertexArrays(1, &m_vertex_array);
3136 glBindVertexArray(m_vertex_array);
3137 glBindBuffer(GL_ARRAY_BUFFER, m_storage_buffer);
3138 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
3139 glBindBuffer(GL_ARRAY_BUFFER, 0);
3140 glEnableVertexAttribArray(0);
3141 glBindVertexArray(0);
3143 glBindProgramPipeline(m_pipeline);
3144 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
3145 glDispatchCompute(1, 1, 1);
3147 glClear(GL_COLOR_BUFFER_BIT);
3148 glBindVertexArray(m_vertex_array);
3149 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
3150 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3152 if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
3157 virtual long Cleanup()
3159 glDeleteProgram(m_vsp);
3160 glDeleteProgram(m_fsp);
3161 glDeleteProgram(m_csp);
3162 glDeleteBuffers(1, &m_storage_buffer);
3163 glDeleteVertexArrays(1, &m_vertex_array);
3164 glDeleteProgramPipelines(1, &m_pipeline);
3169 class BasicSSOCase2 : public ComputeShaderBase
3171 virtual std::string Title()
3173 return NL "Separable CS Programs - Compute and non-compute stages (2)";
3175 virtual std::string Purpose()
3177 return NL "1. Verify that data computed by the compute stage is visible to non-compute stage after "
3178 "MemoryBarrier command." NL "2. Verify that ProgramParameteri(program, GL_PROGRAM_SEPARABLE, "
3179 "GL_TRUE) command works correctly for CS." NL
3180 "3. Verify that gl_WorkGroupSize built-in variable is a contant and can be used as an array size.";
3182 virtual std::string Method()
3184 return NL "1. Create VS, FS and CS. Attach all created stages to one pipeline object." NL
3185 "2. Bind pipeline object." NL "3. Invoke compute stage with DispatchCompute commmand." NL
3186 "4. Issue MemoryBarrier command." NL
3187 "5. Issue DrawArrays command which uses data written to the buffer object by the compute stage." NL
3188 "6. Verify result.";
3190 virtual std::string PassCriteria()
3192 return NL "Everything works as expected.";
3195 GLuint m_program_ab;
3198 GLuint m_storage_buffer;
3201 virtual long Setup()
3206 m_storage_buffer = 0;
3213 glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
3216 OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
3220 const char* const glsl_a =
3221 "#version 430 core" NL "layout(binding = 1, std430) buffer Input {" NL " vec2 g_input[4];" NL "};" NL
3222 "out StageData {" NL " vec3 color;" NL "} g_vs_out;" NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL
3223 "};" NL "void main() {" NL " gl_Position = vec4(g_input[gl_VertexID], 0, 1);" NL
3224 " g_vs_out.color = vec3(0, 1, 0);" NL "}";
3226 const char* const glsl_b =
3227 "#version 430 core" NL "in StageData {" NL " vec3 color;" NL "} g_fs_in;" NL
3228 "layout(location = 0) out vec4 g_color;" NL "void main() {" NL " g_color = vec4(g_fs_in.color, 1);" NL "}";
3230 const char* const glsl_c =
3231 "#version 430 core" NL "layout(local_size_x = 4) in;" NL "layout(binding = 1, std430) buffer Output {" NL
3232 " vec2 g_output[gl_WorkGroupSize.x];" NL "};" NL "void main() {" NL
3233 " if (gl_GlobalInvocationID.x == 0) {" NL " g_output[0] = vec2(-0.8, -0.8);" NL
3234 " } else if (gl_GlobalInvocationID.x == 1) {" NL " g_output[1] = vec2(0.8, -0.8);" NL
3235 " } else if (gl_GlobalInvocationID.x == 2) {" NL " g_output[2] = vec2(-0.8, 0.8);" NL
3236 " } else if (gl_GlobalInvocationID.x == 3) {" NL " g_output[3] = vec2(0.8, 0.8);" NL " }" NL "}";
3238 m_program_ab = glCreateProgram();
3239 GLuint sh = glCreateShader(GL_VERTEX_SHADER);
3240 glAttachShader(m_program_ab, sh);
3242 glShaderSource(sh, 1, &glsl_a, NULL);
3243 glCompileShader(sh);
3245 sh = glCreateShader(GL_FRAGMENT_SHADER);
3246 glAttachShader(m_program_ab, sh);
3248 glShaderSource(sh, 1, &glsl_b, NULL);
3249 glCompileShader(sh);
3251 glProgramParameteri(m_program_ab, GL_PROGRAM_SEPARABLE, GL_TRUE);
3252 glLinkProgram(m_program_ab);
3254 m_program_c = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_c);
3255 glGenVertexArrays(1, &m_vao);
3256 glGenProgramPipelines(1, &m_pipeline);
3257 glUseProgramStages(m_pipeline, GL_ALL_SHADER_BITS, m_program_ab);
3258 glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program_c);
3260 glGenBuffers(1, &m_storage_buffer);
3261 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer);
3262 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec2) * 4, NULL, GL_STREAM_DRAW);
3264 glClear(GL_COLOR_BUFFER_BIT);
3265 glBindProgramPipeline(m_pipeline);
3266 glDispatchCompute(1, 1, 1);
3267 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
3268 glBindVertexArray(m_vao);
3269 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3271 if (getWindowWidth() < 500 &&
3272 !ValidateReadBufferCenteredQuad(getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)))
3278 virtual long Cleanup()
3280 glDeleteProgram(m_program_ab);
3281 glDeleteProgram(m_program_c);
3282 glDeleteProgramPipelines(1, &m_pipeline);
3283 glDeleteBuffers(1, &m_storage_buffer);
3284 glDeleteVertexArrays(1, &m_vao);
3289 class BasicSSOCase3 : public ComputeShaderBase
3291 virtual std::string Title()
3293 return NL "Separable CS Programs - Compute stage";
3295 virtual std::string Purpose()
3297 return NL "Verify that compute shader stage selected with UseProgram command has precedence" NL
3298 "over compute shader stage selected with BindProgramPipeline command.";
3300 virtual std::string Method()
3302 return NL "1. Create CS0 with CreateProgram command. Create CS1 with CreateShaderProgramv command." NL
3303 "2. Verify that CS program selected with UseProgram is dispatched even if there is active" NL
3304 " compute stage bound by BindProgramPipeline.";
3306 virtual std::string PassCriteria()
3308 return NL "Everything works as expected.";
3314 GLuint m_storage_buffer;
3316 virtual long Setup()
3321 m_storage_buffer = 0;
3326 const char* const glsl_a =
3327 "#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(binding = 3, std430) buffer Output {" NL
3328 " int g_output;" NL "};" NL "void main() {" NL " g_output = 1;" NL "}";
3330 const char* const glsl_b =
3331 "#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(binding = 3, std430) buffer Output {" NL
3332 " int g_output;" NL "};" NL "void main() {" NL " g_output = 2;" NL "}";
3334 /* create program A */
3336 m_program_a = glCreateProgram();
3337 GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
3338 glAttachShader(m_program_a, sh);
3340 glShaderSource(sh, 1, &glsl_a, NULL);
3341 glCompileShader(sh);
3342 glProgramParameteri(m_program_a, GL_PROGRAM_SEPARABLE, GL_TRUE);
3343 glLinkProgram(m_program_a);
3345 m_program_b = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_b);
3347 /* create storage buffer */
3350 glGenBuffers(1, &m_storage_buffer);
3351 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_storage_buffer);
3352 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int), &data, GL_STREAM_READ);
3355 glGenProgramPipelines(1, &m_pipeline);
3356 glUseProgramStages(m_pipeline, GL_ALL_SHADER_BITS, m_program_b);
3358 glUseProgram(m_program_a);
3359 glBindProgramPipeline(m_pipeline);
3360 glDispatchCompute(1, 1, 1);
3361 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3366 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
3369 m_context.getTestContext().getLog()
3370 << tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
3376 glDispatchCompute(1, 1, 1);
3377 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3382 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
3385 m_context.getTestContext().getLog()
3386 << tcu::TestLog::Message << "Data is " << data << " should be 2." << tcu::TestLog::EndMessage;
3391 glUseProgram(m_program_b);
3392 glDispatchCompute(1, 1, 1);
3393 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3398 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
3401 m_context.getTestContext().getLog()
3402 << tcu::TestLog::Message << "Data is " << data << " should be 2." << tcu::TestLog::EndMessage;
3408 glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program_a);
3409 glDispatchCompute(1, 1, 1);
3410 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3415 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), &data);
3418 m_context.getTestContext().getLog()
3419 << tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
3426 virtual long Cleanup()
3428 glDeleteProgram(m_program_a);
3429 glDeleteProgram(m_program_b);
3430 glDeleteProgramPipelines(1, &m_pipeline);
3431 glDeleteBuffers(1, &m_storage_buffer);
3436 class BasicAtomicCase1 : public ComputeShaderBase
3438 virtual std::string Title()
3440 return NL "Atomic functions";
3442 virtual std::string Purpose()
3444 return NL "1. Verify that atomicAdd function works as expected with int and uint parameters." NL
3445 "2. Verify that shared memory can be used with atomic functions." NL
3446 "3. Verify that groupMemoryBarrier() and barrier() built-in functions work as expected.";
3448 virtual std::string Method()
3450 return NL "1. Use shared memory as a 'counter' with-in one CS work group." NL
3451 "2. Each shader invocation increments/decrements 'counter' value using atomicAdd function." NL
3452 "3. Values returned by atomicAdd function are written to SSBO." NL
3453 "4. Verify SSBO content (values from 0 to 7 should be written).";
3455 virtual std::string PassCriteria()
3457 return NL "Everything works as expected.";
3461 GLuint m_storage_buffer;
3463 virtual long Setup()
3466 m_storage_buffer = 0;
3471 const char* const glsl_cs =
3472 NL "layout(local_size_x = 8) in;" NL "layout(std430, binding = 0) buffer Output {" NL
3473 " uint g_add_output[8];" NL " int g_sub_output[8];" NL "};" NL "shared uint g_add_value;" NL
3474 "shared int g_sub_value;" NL "void main() {" NL " if (gl_LocalInvocationIndex == 0) {" NL
3475 " g_add_value = 0u;" NL " g_sub_value = 7;" NL " }" NL
3476 " g_add_output[gl_LocalInvocationIndex] = 0u;" NL " g_sub_output[gl_LocalInvocationIndex] = 0;" NL
3477 " groupMemoryBarrier();" NL " barrier();" NL
3478 " g_add_output[gl_LocalInvocationIndex] = atomicAdd(g_add_value, 1u);" NL
3479 " g_sub_output[gl_LocalInvocationIndex] = atomicAdd(g_sub_value, -1);" NL "}";
3480 m_program = CreateComputeProgram(glsl_cs);
3481 glLinkProgram(m_program);
3482 if (!CheckProgram(m_program))
3485 glGenBuffers(1, &m_storage_buffer);
3486 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
3487 glBufferData(GL_SHADER_STORAGE_BUFFER, 16 * sizeof(int), NULL, GL_STATIC_DRAW);
3489 glUseProgram(m_program);
3490 glDispatchCompute(1, 1, 1);
3491 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3493 std::vector<int> data(8);
3494 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int) * 8, &data[0]);
3495 std::sort(data.begin(), data.end());
3496 for (int i = 0; i < 8; ++i)
3500 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3501 << data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
3506 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(int) * 8, sizeof(int) * 8, &data[0]);
3507 std::sort(data.begin(), data.end());
3508 for (int i = 0; i < 8; ++i)
3512 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3513 << data[i] << " should be " << i << "." << tcu::TestLog::EndMessage;
3520 virtual long Cleanup()
3523 glDeleteProgram(m_program);
3524 glDeleteBuffers(1, &m_storage_buffer);
3529 class BasicAtomicCase2 : public ComputeShaderBase
3531 virtual std::string Title()
3533 return NL "Atomic functions - buffer variables";
3535 virtual std::string Purpose()
3537 return NL "1. Verify that all atomic functions (atomicExchange, atomicMin, atomicMax," NL
3538 " atomicAnd, atomicOr, atomicXor and atomicCompSwap) works as expected with buffer variables." NL
3539 "2. Verify that atomic functions work with parameters being constants and" NL
3540 " with parameters being uniforms." NL
3541 "3. Verify that barrier() built-in function can be used in a control flow.";
3543 virtual std::string Method()
3545 return NL "1. Create CS that uses all atomic functions. Values returned by the atomic functions are written to "
3546 "SSBO." NL "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
3547 "3. Verify SSBO content." NL
3548 "4. Repeat for different number of work groups and different work group sizes.";
3550 virtual std::string PassCriteria()
3552 return NL "Everything works as expected.";
3556 GLuint m_storage_buffer[2];
3557 GLuint m_dispatch_buffer;
3559 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
3561 const uvec3 global_size = local_size * num_groups;
3562 std::stringstream ss;
3563 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
3564 << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
3565 << ", " << global_size.y() << ", " << global_size.z()
3566 << ");" NL "layout(std430, binding = 0) buffer OutputU {" NL " uint g_uint_out["
3567 << global_size.x() * global_size.y() * global_size.z()
3568 << "];" NL "};" NL "layout(std430, binding = 1) buffer OutputI {" NL " int data["
3569 << global_size.x() * global_size.y() * global_size.z()
3570 << "];" NL "} g_int_out;" NL
3571 "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL "void main() {" NL
3572 " const uint global_index = gl_GlobalInvocationID.x +" NL
3573 " gl_GlobalInvocationID.y * kGlobalSize.x +" NL
3574 " gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
3575 " atomicExchange(g_uint_out[global_index], g_uint_value[0]);" NL
3576 " atomicMin(g_uint_out[global_index], g_uint_value[1]);" NL
3577 " atomicMax(g_uint_out[global_index], g_uint_value[2]);" NL
3578 " atomicAnd(g_uint_out[global_index], g_uint_value[3]);" NL
3579 " atomicOr(g_uint_out[global_index], g_uint_value[4]);" NL " if (g_uint_value[0] > 0u) {" NL
3580 " barrier();" // not needed here, just check if compiler accepts it in a control flow
3581 NL " atomicXor(g_uint_out[global_index], g_uint_value[5]);" NL " }" NL
3582 " atomicCompSwap(g_uint_out[global_index], g_uint_value[6], g_uint_value[7]);" NL NL
3583 " atomicExchange(g_int_out.data[global_index], 3);" NL " atomicMin(g_int_out.data[global_index], 1);" NL
3584 " atomicMax(g_int_out.data[global_index], 2);" NL " atomicAnd(g_int_out.data[global_index], 0x1);" NL
3585 " atomicOr(g_int_out.data[global_index], 0x3);" NL " atomicXor(g_int_out.data[global_index], 0x1);" NL
3586 " atomicCompSwap(g_int_out.data[global_index], 0x2, 0x7);" NL "}";
3589 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
3592 glDeleteProgram(m_program);
3593 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
3594 glLinkProgram(m_program);
3595 if (!CheckProgram(m_program))
3598 const GLuint kBufferSize =
3599 local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
3601 if (m_storage_buffer[0] == 0)
3602 glGenBuffers(2, m_storage_buffer);
3603 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
3604 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, NULL, GL_DYNAMIC_DRAW);
3605 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
3606 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint) * kBufferSize, NULL, GL_DYNAMIC_DRAW);
3608 glUseProgram(m_program);
3609 if (dispatch_indirect)
3611 if (m_dispatch_buffer == 0)
3612 glGenBuffers(1, &m_dispatch_buffer);
3613 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
3614 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
3615 glDispatchComputeIndirect(0);
3619 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
3621 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3623 std::vector<GLuint> udata(kBufferSize);
3624 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
3625 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, &udata[0]);
3626 for (GLuint i = 0; i < kBufferSize; ++i)
3630 m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is "
3631 << udata[i] << " should be 7." << tcu::TestLog::EndMessage;
3636 std::vector<GLint> idata(kBufferSize);
3637 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
3638 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint) * kBufferSize, &idata[0]);
3639 for (GLint i = 0; i < static_cast<GLint>(kBufferSize); ++i)
3643 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3644 << idata[i] << " should be 7." << tcu::TestLog::EndMessage;
3651 virtual long Setup()
3654 m_storage_buffer[0] = m_storage_buffer[1] = 0;
3655 m_dispatch_buffer = 0;
3660 if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
3662 if (!RunIteration(uvec3(1, 1, 64), uvec3(1, 5, 2), true))
3664 if (!RunIteration(uvec3(1, 1, 4), uvec3(2, 2, 2), false))
3666 if (!RunIteration(uvec3(3, 2, 1), uvec3(1, 2, 3), true))
3668 if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
3670 if (!RunIteration(uvec3(2, 4, 7), uvec3(2, 1, 4), true))
3674 virtual long Cleanup()
3677 glDeleteProgram(m_program);
3678 glDeleteBuffers(2, m_storage_buffer);
3679 glDeleteBuffers(1, &m_dispatch_buffer);
3684 class BasicAtomicCase3 : public ComputeShaderBase
3686 virtual std::string Title()
3688 return NL "Atomic functions - shared variables";
3690 virtual std::string Purpose()
3692 return NL "1. Verify that all atomic functions (atomicExchange, atomicMin, atomicMax," NL
3693 " atomicAnd, atomicOr, atomicXor and atomicCompSwap) works as expected with shared variables." NL
3694 "2. Verify that atomic functions work with parameters being constants and" NL
3695 " with parameters being uniforms." NL
3696 "3. Verify that atomic functions can be used in a control flow.";
3698 virtual std::string Method()
3700 return NL "1. Create CS that uses all atomic functions. Values returned by the atomic functions are written to "
3701 "SSBO." NL "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
3702 "3. Verify SSBO content." NL
3703 "4. Repeat for different number of work groups and different work group sizes.";
3705 virtual std::string PassCriteria()
3707 return NL "Everything works as expected.";
3711 GLuint m_storage_buffer;
3712 GLuint m_dispatch_buffer;
3714 std::string GenSource(const uvec3& local_size)
3716 std::stringstream ss;
3717 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
3718 << ", local_size_z = " << local_size.z()
3719 << ") in;" NL "layout(std430, binding = 0) buffer Output {" NL " uint g_uint_out["
3720 << local_size.x() * local_size.y() * local_size.z() << "];" NL " int g_int_out["
3721 << local_size.x() * local_size.y() * local_size.z() << "];" NL "};" NL "shared uint g_shared_uint["
3722 << local_size.x() * local_size.y() * local_size.z() << "];" NL "shared int g_shared_int["
3723 << local_size.x() * local_size.y() * local_size.z()
3724 << "];" NL "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL
3725 "void main() {" NL " atomicExchange(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[0]);" NL
3726 " atomicMin(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[1]);" NL
3727 " atomicMax(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[2]);" NL
3728 " atomicAnd(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[3]);" NL
3729 " atomicOr(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[4]);" NL
3730 " atomicXor(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[5]);" NL
3731 " atomicCompSwap(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[6], g_uint_value[7]);" NL NL
3732 " atomicExchange(g_shared_int[gl_LocalInvocationIndex], 3);" NL
3733 " atomicMin(g_shared_int[gl_LocalInvocationIndex], 1);" NL
3734 " atomicMax(g_shared_int[gl_LocalInvocationIndex], 2);" NL
3735 " atomicAnd(g_shared_int[gl_LocalInvocationIndex], 0x1);" NL " if (g_uint_value[1] > 0u) {" NL
3736 " atomicOr(g_shared_int[gl_LocalInvocationIndex], 0x3);" NL
3737 " atomicXor(g_shared_int[gl_LocalInvocationIndex], 0x1);" NL
3738 " atomicCompSwap(g_shared_int[gl_LocalInvocationIndex], 0x2, 0x7);" NL " }" NL NL
3739 " g_uint_out[gl_LocalInvocationIndex] = g_shared_uint[gl_LocalInvocationIndex];" NL
3740 " g_int_out[gl_LocalInvocationIndex] = g_shared_int[gl_LocalInvocationIndex];" NL "}";
3743 bool RunIteration(const uvec3& local_size, bool dispatch_indirect)
3746 glDeleteProgram(m_program);
3747 m_program = CreateComputeProgram(GenSource(local_size));
3748 glLinkProgram(m_program);
3749 if (!CheckProgram(m_program))
3752 const GLuint kBufferSize = local_size.x() * local_size.y() * local_size.z();
3754 if (m_storage_buffer == 0)
3755 glGenBuffers(1, &m_storage_buffer);
3756 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
3757 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize * 2, NULL, GL_DYNAMIC_DRAW);
3759 glUseProgram(m_program);
3760 if (dispatch_indirect)
3762 const GLuint num_groups[3] = { 1, 1, 1 };
3763 if (m_dispatch_buffer == 0)
3764 glGenBuffers(1, &m_dispatch_buffer);
3765 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
3766 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
3767 glDispatchComputeIndirect(0);
3771 glDispatchCompute(1, 1, 1);
3773 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3775 std::vector<GLuint> udata(kBufferSize);
3776 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, &udata[0]);
3777 for (GLuint i = 0; i < kBufferSize; ++i)
3781 m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is "
3782 << udata[i] << " should be 7." << tcu::TestLog::EndMessage;
3787 std::vector<GLint> idata(kBufferSize);
3788 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, sizeof(GLint) * kBufferSize,
3790 for (GLint i = 0; i < static_cast<GLint>(kBufferSize); ++i)
3794 m_context.getTestContext().getLog() << tcu::TestLog::Message << "iData at index " << i << " is "
3795 << idata[i] << " should be 7." << tcu::TestLog::EndMessage;
3802 virtual long Setup()
3805 m_storage_buffer = 0;
3806 m_dispatch_buffer = 0;
3811 if (!RunIteration(uvec3(64, 1, 1), false))
3813 if (!RunIteration(uvec3(1, 1, 64), true))
3815 if (!RunIteration(uvec3(1, 1, 4), false))
3817 if (!RunIteration(uvec3(3, 2, 1), true))
3819 if (!RunIteration(uvec3(2, 4, 2), false))
3821 if (!RunIteration(uvec3(2, 4, 7), true))
3825 virtual long Cleanup()
3828 glDeleteProgram(m_program);
3829 glDeleteBuffers(1, &m_storage_buffer);
3830 glDeleteBuffers(1, &m_dispatch_buffer);
3835 class AdvancedCopyImage : public ComputeShaderBase
3837 virtual std::string Title()
3839 return NL "Copy Image";
3841 virtual std::string Purpose()
3843 return NL "Verify that copying two textures using CS works as expected.";
3845 virtual std::string Method()
3847 return NL "Use shader image load and store operations to copy two textures in the CS.";
3849 virtual std::string PassCriteria()
3851 return NL "Everything works as expected.";
3855 GLuint m_texture[2];
3857 virtual long Setup()
3860 memset(m_texture, 0, sizeof(m_texture));
3866 const char* const glsl_cs = NL "#define TILE_WIDTH 16" NL "#define TILE_HEIGHT 16" NL
3867 "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
3868 "layout(binding = 0, rgba8) uniform image2D g_input_image;" NL
3869 "layout(binding = 1, rgba8) uniform image2D g_output_image;" NL NL
3870 "layout(local_size_x=TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL
3871 "void main() {" NL " const ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL
3872 " const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
3873 " const ivec2 pixel_xy = tile_xy * kTileSize + thread_xy;" NL NL
3874 " vec4 pixel = imageLoad(g_input_image, pixel_xy);" NL
3875 " imageStore(g_output_image, pixel_xy, pixel);" NL "}";
3876 m_program = CreateComputeProgram(glsl_cs);
3877 glLinkProgram(m_program);
3878 if (!CheckProgram(m_program))
3881 std::vector<GLubyte> in_image(64 * 64 * 4, 0x0f);
3882 std::vector<GLubyte> out_image(64 * 64 * 4, 0x00);
3884 glGenTextures(2, m_texture);
3885 glBindTexture(GL_TEXTURE_2D, m_texture[0]);
3886 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3887 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, &in_image[0]);
3889 glBindTexture(GL_TEXTURE_2D, m_texture[1]);
3890 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3891 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, &out_image[0]);
3893 glUseProgram(m_program);
3894 glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
3895 glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
3896 glDispatchCompute(5, 4,
3897 1); // 5 is on purpose, to ensure that out of bounds image load and stores have no effect
3898 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
3900 std::vector<GLubyte> data(64 * 64 * 4);
3901 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
3902 for (std::size_t i = 0; i < data.size(); ++i)
3904 if (getWindowWidth() > 100 && data[i] != 0x0f)
3906 m_context.getTestContext().getLog()
3907 << tcu::TestLog::Message << "Data at index " << i << " is " << data[i] << " should be " << 0x0f
3908 << "." << tcu::TestLog::EndMessage;
3915 virtual long Cleanup()
3918 glDeleteProgram(m_program);
3919 glDeleteTextures(2, m_texture);
3924 class AdvancedPipelinePreVS : public ComputeShaderBase
3926 virtual std::string Title()
3928 return NL "CS as an additional pipeline stage - Before VS (1)";
3930 virtual std::string Purpose()
3932 return NL "Verify that CS which runs just before VS and modifies VBO content works as expected.";
3934 virtual std::string Method()
3936 return NL "1. Prepare VBO and VAO for a drawing operation." NL "2. Run CS to modify existing VBO content." NL
3937 "3. Issue MemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT) command." NL
3938 "4. Issue draw call command." NL "5. Verify that the framebuffer content is as expected.";
3940 virtual std::string PassCriteria()
3942 return NL "Everything works as expected.";
3945 GLuint m_program[2];
3946 GLuint m_vertex_buffer;
3947 GLuint m_vertex_array;
3949 virtual long Setup()
3951 memset(m_program, 0, sizeof(m_program));
3952 m_vertex_buffer = 0;
3958 const char* const glsl_cs =
3959 NL "layout(local_size_x = 4) in;" NL "struct Vertex {" NL " vec4 position;" NL " vec4 color;" NL "};" NL
3960 "layout(binding = 0, std430) buffer VertexBuffer {" NL " Vertex g_vertex[];" NL "};" NL
3961 "uniform float g_scale = 0.8;" NL "void main() {" NL
3962 " g_vertex[gl_GlobalInvocationID.x].position.xyz *= g_scale;" NL
3963 " g_vertex[gl_GlobalInvocationID.x].color *= vec4(0, 1, 0, 1);" NL "}";
3964 m_program[0] = CreateComputeProgram(glsl_cs);
3965 glLinkProgram(m_program[0]);
3966 if (!CheckProgram(m_program[0]))
3969 const char* const glsl_vs =
3970 NL "layout(location = 0) in vec4 g_position;" NL "layout(location = 1) in vec4 g_color;" NL
3971 "out StageData {" NL " vec4 color;" NL "} g_vs_out;" NL "void main() {" NL
3972 " gl_Position = g_position;" NL " g_vs_out.color = g_color;" NL "}";
3974 const char* const glsl_fs =
3975 NL "in StageData {" NL " vec4 color;" NL "} g_fs_in;" NL "layout(location = 0) out vec4 g_color;" NL
3976 "void main() {" NL " g_color = g_fs_in.color;" NL "}";
3977 m_program[1] = CreateProgram(glsl_vs, glsl_fs);
3978 glLinkProgram(m_program[1]);
3979 if (!CheckProgram(m_program[1]))
3984 const float data[] = { -1, -1, 0, 1, 1, 1, 1, 1, 1, -1, 0, 1, 1, 1, 1, 1,
3985 -1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 };
3986 glGenBuffers(1, &m_vertex_buffer);
3987 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
3988 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
3989 glBindBuffer(GL_ARRAY_BUFFER, 0);
3992 glGenVertexArrays(1, &m_vertex_array);
3993 glBindVertexArray(m_vertex_array);
3994 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
3995 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), 0);
3996 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), reinterpret_cast<void*>(sizeof(vec4)));
3997 glBindBuffer(GL_ARRAY_BUFFER, 0);
3998 glEnableVertexAttribArray(0);
3999 glEnableVertexAttribArray(1);
4000 glBindVertexArray(0);
4002 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_vertex_buffer);
4003 glUseProgram(m_program[0]);
4004 glDispatchCompute(1, 1, 1);
4006 glClear(GL_COLOR_BUFFER_BIT);
4007 glUseProgram(m_program[1]);
4008 glBindVertexArray(m_vertex_array);
4009 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
4010 glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
4012 if (getWindowWidth() < 500 &&
4013 !ValidateReadBufferCenteredQuad(getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)))
4019 virtual long Cleanup()
4022 for (int i = 0; i < 2; ++i)
4023 glDeleteProgram(m_program[i]);
4024 glDeleteBuffers(1, &m_vertex_buffer);
4025 glDeleteVertexArrays(1, &m_vertex_array);
4030 class AdvancedPipelineGenDrawCommands : public ComputeShaderBase
4032 virtual std::string Title()
4034 return NL "CS as an additional pipeline stage - Before VS (2)";
4036 virtual std::string Purpose()
4038 return NL "Verify that a complex scenario where CS is used to generate drawing commands" NL
4039 "and write them to a draw indirect buffer works as expected. This is a practial usage of CS." NL
4040 "CS is used for culling objects which are outside of the viewing frustum.";
4042 virtual std::string Method()
4044 return NL "1. Run CS which will generate four sets of draw call parameters and write them to the draw indirect "
4045 "buffer." NL "2. One set of draw call parameters will be: 0, 0, 0, 0" NL
4046 " (which means that an object is outside of the viewing frustum and should not be drawn)." NL
4047 "3. Issue MemoryBarrier(GL_COMMAND_BARRIER_BIT) command." NL
4048 "4. Issue four draw indirect commands." NL "5. Verify that the framebuffer content is as expected.";
4050 virtual std::string PassCriteria()
4052 return NL "Everything works as expected.";
4055 GLuint m_program[2];
4056 GLuint m_vertex_buffer;
4057 GLuint m_index_buffer;
4058 GLuint m_vertex_array;
4059 GLuint m_draw_buffer;
4060 GLuint m_object_buffer;
4062 virtual long Setup()
4064 memset(m_program, 0, sizeof(m_program));
4065 m_vertex_buffer = 0;
4069 m_object_buffer = 0;
4075 glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
4078 OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
4082 const char* const glsl_cs =
4083 NL "layout(local_size_x = 4) in;" NL "struct DrawCommand {" NL " uint count;" NL
4084 " uint instance_count;" NL " uint first_index;" NL " int base_vertex;" NL " uint base_instance;" NL
4085 "};" NL "layout(std430) buffer;" NL "layout(binding = 0) readonly buffer ObjectBuffer {" NL
4086 " mat4 transform[4];" NL " uint count[4];" NL " uint first_index[4];" NL "} g_objects;" NL
4087 "layout(binding = 1) writeonly buffer DrawCommandBuffer {" NL " DrawCommand g_command[4];" NL "};" NL
4088 "bool IsObjectVisible(uint id) {" NL
4089 " if (g_objects.transform[id][3].x < -1.0 || g_objects.transform[id][3].x > 1.0) return false;" NL
4090 " if (g_objects.transform[id][3][1] < -1.0 || g_objects.transform[id][3][1] > 1.0) return false;" NL
4091 " if (g_objects.transform[id][3][2] < -1.0 || g_objects.transform[id][3].z > 1.0) return false;" NL
4092 " return true;" NL "}" NL "void main() {" NL " uint id = gl_GlobalInvocationID.x;" NL
4093 " g_command[id].count = 0;" NL " g_command[id].instance_count = 0;" NL
4094 " g_command[id].first_index = 0;" NL " g_command[id].base_vertex = 0;" NL
4095 " g_command[id].base_instance = 0;" NL " if (IsObjectVisible(id)) {" NL
4096 " g_command[id].count = g_objects.count[id];" NL " g_command[id].instance_count = 1;" NL
4097 " g_command[id].first_index = g_objects.first_index[id];" NL " }" NL "}";
4098 m_program[0] = CreateComputeProgram(glsl_cs);
4099 glLinkProgram(m_program[0]);
4100 if (!CheckProgram(m_program[0]))
4103 const char* const glsl_vs =
4104 NL "layout(location = 0) in vec4 g_position;" NL "layout(location = 1) in vec3 g_color;" NL
4105 "out StageData {" NL " vec3 color;" NL "} g_vs_out;" NL
4106 "layout(binding = 0, std430) buffer ObjectBuffer {" NL " mat4 transform[4];" NL " uint count[4];" NL
4107 " uint first_index[4];" NL "} g_objects;" NL "uniform int g_object_id;" NL "void main() {" NL
4108 " gl_Position = g_objects.transform[g_object_id] * g_position;" NL " g_vs_out.color = g_color;" NL "}";
4110 const char* const glsl_fs =
4111 NL "in StageData {" NL " vec3 color;" NL "} g_fs_in;" NL "layout(location = 0) out vec4 g_color;" NL
4112 "void main() {" NL " g_color = vec4(g_fs_in.color, 1);" NL "}";
4113 m_program[1] = CreateProgram(glsl_vs, glsl_fs);
4114 glLinkProgram(m_program[1]);
4115 if (!CheckProgram(m_program[1]))
4117 glViewport(0, 0, 100, 100);
4125 GLuint first_index[4];
4127 { tcu::translationMatrix(vec3(-1.5f, -0.5f, 0.0f)), tcu::translationMatrix(vec3(0.5f, -0.5f, 0.0f)),
4128 tcu::translationMatrix(vec3(-0.5f, 0.5f, 0.0f)), tcu::translationMatrix(vec3(0.5f, 0.5f, 0.0f)) },
4132 glGenBuffers(1, &m_object_buffer);
4133 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_object_buffer);
4134 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
4138 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),
4139 vec3(-0.4f, 0.4f, 0.0f), vec3(1, 0, 0), vec3(0.4f, 0.4f, 0.0f), vec3(1, 0, 0),
4140 vec3(-0.4f, -0.4f, 0.0f), vec3(0, 1, 0), vec3(0.4f, -0.4f, 0.0f), vec3(0, 1, 0),
4141 vec3(-0.4f, 0.4f, 0.0f), vec3(0, 1, 0), vec3(0.4f, 0.4f, 0.0f), vec3(0, 1, 0),
4142 vec3(-0.4f, -0.4f, 0.0f), vec3(0, 0, 1), vec3(0.4f, -0.4f, 0.0f), vec3(0, 0, 1),
4143 vec3(-0.4f, 0.4f, 0.0f), vec3(0, 0, 1), vec3(0.4f, 0.4f, 0.0f), vec3(0, 0, 1),
4144 vec3(-0.4f, -0.4f, 0.0f), vec3(1, 1, 0), vec3(0.4f, -0.4f, 0.0f), vec3(1, 1, 0),
4145 vec3(-0.4f, 0.4f, 0.0f), vec3(1, 1, 0), vec3(0.4f, 0.4f, 0.0f), vec3(1, 1, 0) };
4146 glGenBuffers(1, &m_vertex_buffer);
4147 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4148 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
4149 glBindBuffer(GL_ARRAY_BUFFER, 0);
4153 const GLushort data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
4154 glGenBuffers(1, &m_index_buffer);
4155 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
4156 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW);
4157 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
4159 glGenBuffers(1, &m_draw_buffer);
4160 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_buffer);
4161 glBufferData(GL_DRAW_INDIRECT_BUFFER, 4 * sizeof(GLuint) * 5, NULL, GL_DYNAMIC_DRAW);
4162 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
4164 glGenVertexArrays(1, &m_vertex_array);
4165 glBindVertexArray(m_vertex_array);
4166 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4167 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(vec3), 0);
4168 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(vec3), reinterpret_cast<void*>(sizeof(vec3)));
4169 glBindBuffer(GL_ARRAY_BUFFER, 0);
4170 glEnableVertexAttribArray(0);
4171 glEnableVertexAttribArray(1);
4172 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
4173 glBindVertexArray(0);
4175 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_draw_buffer);
4176 glUseProgram(m_program[0]);
4177 glDispatchCompute(1, 1, 1);
4179 glClear(GL_COLOR_BUFFER_BIT);
4180 glUseProgram(m_program[1]);
4181 glBindVertexArray(m_vertex_array);
4182 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_buffer);
4183 glMemoryBarrier(GL_COMMAND_BARRIER_BIT);
4184 /* draw (CPU draw calls dispatch, could be done by the GPU with ARB_multi_draw_indirect) */
4186 GLsizeiptr offset = 0;
4187 for (int i = 0; i < 4; ++i)
4189 glUniform1i(glGetUniformLocation(m_program[1], "g_object_id"), i);
4190 glDrawElementsIndirect(GL_TRIANGLE_STRIP, GL_UNSIGNED_SHORT, reinterpret_cast<void*>(offset));
4191 offset += 5 * sizeof(GLuint);
4194 if (getWindowWidth() >= 100 && getWindowHeight() >= 100 &&
4195 !ValidateWindow4Quads(vec3(0), vec3(0, 1, 0), vec3(1, 1, 0), vec3(0, 0, 1)))
4201 virtual long Cleanup()
4204 for (int i = 0; i < 2; ++i)
4205 glDeleteProgram(m_program[i]);
4206 glDeleteBuffers(1, &m_vertex_buffer);
4207 glDeleteBuffers(1, &m_index_buffer);
4208 glDeleteVertexArrays(1, &m_vertex_array);
4209 glDeleteBuffers(1, &m_draw_buffer);
4210 glDeleteBuffers(1, &m_object_buffer);
4211 glViewport(0, 0, getWindowWidth(), getWindowHeight());
4216 class AdvancedPipelineComputeChain : public ComputeShaderBase
4218 virtual std::string Title()
4220 return NL "Compute Chain";
4222 virtual std::string Purpose()
4224 return NL "1. Verify that dispatching several compute kernels that work in a sequence" NL
4225 " with a common set of resources works as expected." NL
4226 "2. Verify that indexing nested structures with built-in variables work as expected." NL
4227 "3. Verify that two kernels can write to the same resource without MemoryBarrier" NL
4228 " command if target regions of memory do not overlap.";
4230 virtual std::string Method()
4232 return NL "1. Create a set of GPU resources (buffers, images, atomic counters)." NL
4233 "2. Dispatch Kernel0 that write to these resources." NL "3. Issue MemoryBarrier command." NL
4234 "4. Dispatch Kernel1 that read/write from/to these resources." NL "5. Issue MemoryBarrier command." NL
4235 "6. Dispatch Kernel2 that read/write from/to these resources." NL
4236 "7. Verify that content of all resources is as expected.";
4238 virtual std::string PassCriteria()
4240 return NL "Everything works as expected.";
4243 GLuint m_program[3];
4244 GLuint m_storage_buffer[4];
4245 GLuint m_counter_buffer;
4249 std::string Common()
4251 return NL "struct S0 {" NL " int m0[8];" NL "};" NL "struct S1 {" NL " S0 m0[8];" NL "};" NL
4252 "layout(binding = 0, std430) buffer Buffer0 {" NL " int m0[5];" NL " S1 m1[8];" NL "} g_buffer0;" NL
4253 "layout(binding = 1, std430) buffer Buffer1 {" NL " uint data[8];" NL "} g_buffer1;" NL
4254 "layout(binding = 2, std430) buffer Buffer2 {" NL " int data[256];" NL "} g_buffer2;" NL
4255 "layout(binding = 3, std430) buffer Buffer3 {" NL " int data[256];" NL "} g_buffer3;" NL
4256 "layout(binding = 4, std430) buffer Buffer4 {" NL " mat4 data0;" NL " mat4 data1;" NL
4257 "} g_buffer4;" NL "layout(binding = 0, rgba32f) uniform image2D g_image0;" NL
4258 "layout(binding = 1, offset = 8) uniform atomic_uint g_counter[2];";
4260 std::string GenGLSL(int p)
4262 std::stringstream ss;
4266 ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;" NL
4267 "void UpdateBuffer0(uvec3 id, int add_val) {" NL " if (id.x < 8 && id.y < 8 && id.z < 8) {" NL
4268 " g_buffer0.m1[id.z].m0[id.y].m0[id.x] += add_val;" NL " }" NL "}" NL
4269 "uniform int g_add_value = 1;" NL "uniform uint g_counter_y = 1;" NL
4270 "uniform vec4 g_image_value = vec4(0.125, 0.25, 0.375, 0.5);" NL "void main() {" NL
4271 " uvec3 id = gl_GlobalInvocationID;" NL " UpdateBuffer0(id, 1);" NL
4272 " UpdateBuffer0(id, g_add_value);" NL " if (id == uvec3(1, g_counter_y, 1)) {" NL
4273 " uint idx = atomicCounterIncrement(g_counter[1]);" NL " g_buffer1.data[idx] = idx;" NL
4274 " idx = atomicCounterIncrement(g_counter[1]);" NL " g_buffer1.data[idx] = idx;" NL " }" NL
4275 " if (id.x < 4 && id.y < 4 && id.z == 0) {" NL
4276 " vec4 v = imageLoad(g_image0, ivec2(id.xy));" NL
4277 " imageStore(g_image0, ivec2(id.xy), v + g_image_value);" NL " }" NL
4278 " if (id.x < 2 && id.y == 0 && id.z == 0) {" NL " g_buffer2.data[id.x] -= int(g_counter_y);" NL
4283 ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 1) in;"
4284 // translation matrix
4285 NL "uniform mat4 g_mvp = mat4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 10.0, "
4286 "20.0, 30.0, 1.0);" NL "void main() {" NL " if (gl_GlobalInvocationID == uvec3(0)) {" NL
4287 " g_buffer4.data0 *= g_mvp;" NL " }" NL " if (gl_WorkGroupID == uvec3(0)) {" NL
4288 " g_buffer4.data1[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = "
4289 "g_mvp[gl_LocalInvocationID.x][gl_LocalInvocationID.y];" NL " }" NL "}";
4293 ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;" NL "void main() {" NL "}";
4297 virtual long Setup()
4299 memset(m_program, 0, sizeof(m_program));
4300 memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
4301 m_counter_buffer = 0;
4307 using namespace tcu;
4309 for (int i = 0; i < 3; ++i)
4311 m_program[i] = CreateComputeProgram(GenGLSL(i));
4312 glLinkProgram(m_program[i]);
4313 if (!CheckProgram(m_program[i]))
4317 glGenBuffers(4, m_storage_buffer);
4318 /* storage buffer 0 */
4320 std::vector<int> data(5 + 8 * 8 * 8);
4321 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
4322 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(int)), &data[0], GL_STATIC_COPY);
4324 /* storage buffer 1 */
4326 const GLuint data[8] = { 0 };
4327 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
4328 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_STATIC_COPY);
4330 /* storage buffer 2 & 3 */
4332 std::vector<GLint> data(512, 7);
4333 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[2]);
4334 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(GLint)), &data[0], GL_STATIC_COPY);
4336 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 2, m_storage_buffer[2], 0,
4337 (GLsizeiptr)(sizeof(GLint) * data.size() / 2));
4338 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, m_storage_buffer[2],
4339 (GLintptr)(sizeof(GLint) * data.size() / 2),
4340 (GLsizeiptr)(sizeof(GLint) * data.size() / 2));
4342 /* storage buffer 4 */
4344 std::vector<mat4> data(2);
4346 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_storage_buffer[3]);
4347 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(mat4)), &data[0], GL_STATIC_COPY);
4349 /* counter buffer */
4351 GLuint data[4] = { 0 };
4352 glGenBuffers(1, &m_counter_buffer);
4353 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, m_counter_buffer);
4354 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), data, GL_STATIC_COPY);
4358 std::vector<vec4> data(4 * 4, vec4(0.0f));
4359 glGenTextures(1, &m_texture);
4360 glBindTexture(GL_TEXTURE_2D, m_texture);
4361 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4362 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4363 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 4, 4, 0, GL_RGBA, GL_FLOAT, &data[0]);
4364 glBindTexture(GL_TEXTURE_2D, 0);
4367 glUseProgram(m_program[0]);
4368 glBindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
4369 glDispatchCompute(2, 2, 2);
4370 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4371 glDispatchCompute(3, 2, 2);
4373 glUseProgram(m_program[1]);
4374 glDispatchCompute(4, 3, 7);
4376 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT |
4377 GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4379 /* validate texture */
4381 std::vector<vec4> data(4 * 4);
4382 glBindTexture(GL_TEXTURE_2D, m_texture);
4383 glGenFramebuffers(1, &m_fbo);
4384 glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
4385 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
4386 std::vector<GLubyte> colorData(4 * 4 * 4);
4387 glReadPixels(0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, &colorData[0]);
4388 for (int i = 0; i < 4 * 4 * 4; i += 4)
4391 vec4(static_cast<GLfloat>(colorData[i] / 255.), static_cast<GLfloat>(colorData[i + 1] / 255.),
4392 static_cast<GLfloat>(colorData[i + 2] / 255.), static_cast<GLfloat>(colorData[i + 3] / 255.));
4394 for (std::size_t i = 0; i < data.size(); ++i)
4396 if (!ColorEqual(data[i], vec4(0.25f, 0.5f, 0.75f, 1.0f), g_color_eps))
4398 m_context.getTestContext().getLog()
4399 << tcu::TestLog::Message << "Invalid data at texture." << tcu::TestLog::EndMessage;
4404 /* validate storage buffer 0 */
4406 std::vector<int> data(5 + 8 * 8 * 8);
4407 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
4408 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(data.size() * sizeof(int)), &data[0]);
4409 for (std::size_t i = 5; i < data.size(); ++i)
4413 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data[i]
4414 << " should be 2." << tcu::TestLog::EndMessage;
4419 /* validate storage buffer 1 */
4422 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
4423 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data);
4424 for (GLuint i = 0; i < 4; ++i)
4428 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data[i]
4429 << " should be " << i << "." << tcu::TestLog::EndMessage;
4434 /* validate storage buffer 2 & 3 */
4436 std::vector<GLint> data(512);
4437 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[2]);
4438 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(sizeof(GLint) * data.size()), &data[0]);
4439 for (int i = 0; i < 2; ++i)
4443 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i]
4444 << " should be: 5." << tcu::TestLog::EndMessage;
4447 if (data[i + 256] != 7)
4449 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i + 256]
4450 << " should be: 7." << tcu::TestLog::EndMessage;
4455 /* validate storage buffer 4 */
4458 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[3]);
4459 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data[0](0, 0));
4460 if (data[0] != translationMatrix(vec3(10.0f, 20.0f, 30.0f)))
4462 m_context.getTestContext().getLog()
4463 << tcu::TestLog::Message << "Data is incorrect." << tcu::TestLog::EndMessage;
4466 if (data[1] != transpose(translationMatrix(vec3(10.0f, 20.0f, 30.0f))))
4468 m_context.getTestContext().getLog()
4469 << tcu::TestLog::Message << "Data is incorrect." << tcu::TestLog::EndMessage;
4473 /* validate counter buffer */
4475 GLuint data[4] = { 0 };
4476 glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(data), data);
4479 m_context.getTestContext().getLog()
4480 << tcu::TestLog::Message << "Data is: " << data[3] << " should be: 4." << tcu::TestLog::EndMessage;
4487 virtual long Cleanup()
4490 for (int i = 0; i < 3; ++i)
4491 glDeleteProgram(m_program[i]);
4492 glDeleteBuffers(4, m_storage_buffer);
4493 glDeleteBuffers(1, &m_counter_buffer);
4494 glDeleteTextures(1, &m_texture);
4495 glDeleteFramebuffers(1, &m_fbo);
4500 class AdvancedPipelinePostFS : public ComputeShaderBase
4502 virtual std::string Title()
4504 return NL "CS as an additional pipeline stage - After FS";
4506 virtual std::string Purpose()
4508 return NL "1. Verify that CS which runs just after FS to do a post-processing on a rendered image works as "
4509 "expected." NL "2. Verify that CS used as a post-processing filter works as expected." NL
4510 "3. Verify that several CS kernels which run in a sequence to do a post-processing on a rendered "
4511 "image works as expected.";
4513 virtual std::string Method()
4516 "1. Render image to Texture0 using VS and FS." NL
4517 "2. Use Texture0 as an input to Kernel0 which performs post-processing and writes result to Texture1." NL
4518 "3. Issue MemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) command." NL
4519 "4. Use Texture1 as an input to Kernel1 which performs post-processing and writes result to Texture0." NL
4520 "5. Issue MemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) command." NL
4521 "6. Verify content of the final post-processed image (Texture0).";
4523 virtual std::string PassCriteria()
4525 return NL "Everything works as expected.";
4528 GLuint m_program[3];
4529 GLuint m_render_target[2];
4530 GLuint m_framebuffer;
4531 GLuint m_vertex_array;
4533 virtual long Setup()
4535 memset(m_program, 0, sizeof(m_program));
4536 memset(m_render_target, 0, sizeof(m_render_target));
4544 const char* const glsl_vs =
4545 NL "const vec2 g_vertex[4] = vec2[4](vec2(0), vec2(-1, -1), vec2(3, -1), vec2(-1, 3));" NL
4546 "void main() {" NL " gl_Position = vec4(g_vertex[gl_VertexID], 0, 1);" NL "}";
4548 const char* const glsl_fs =
4549 NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL " g_color = vec4(1, 0, 0, 1);" NL "}";
4551 m_program[0] = CreateProgram(glsl_vs, glsl_fs);
4552 glLinkProgram(m_program[0]);
4553 if (!CheckProgram(m_program[0]))
4556 const char* const glsl_cs =
4557 NL "#define TILE_WIDTH 16" NL "#define TILE_HEIGHT 16" NL
4558 "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
4559 "layout(binding = 0, rgba32f) uniform image2D g_input_image;" NL
4560 "layout(binding = 1, rgba32f) uniform image2D g_output_image;" NL NL
4561 "layout(local_size_x = TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL "void main() {" NL
4562 " const ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL
4563 " const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL NL " if (thread_xy == ivec2(0)) {" NL
4564 " const ivec2 pixel_xy = tile_xy * kTileSize;" NL " for (int y = 0; y < TILE_HEIGHT; ++y) {" NL
4565 " for (int x = 0; x < TILE_WIDTH; ++x) {" NL
4566 " imageStore(g_output_image, pixel_xy + ivec2(x, y), vec4(0, 1, 0, 1));" NL " }" NL
4567 " }" NL " }" NL "}";
4569 m_program[1] = CreateComputeProgram(glsl_cs);
4570 glLinkProgram(m_program[1]);
4571 if (!CheckProgram(m_program[1]))
4574 const char* const glsl_cs2 = NL "#define TILE_WIDTH 32" NL "#define TILE_HEIGHT 32" NL
4575 "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
4576 "layout(binding = 0, rgba32f) uniform image2D g_input_image;" NL
4577 "layout(binding = 1, rgba32f) uniform image2D g_output_image;" NL NL
4578 "layout(local_size_x = TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL
4579 "vec4 Process(vec4 ic) {" NL " return ic + vec4(1, 0, 0, 0);" NL "}" NL
4580 "void main() {" NL " const ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL
4581 " const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
4582 " const ivec2 pixel_xy = tile_xy * kTileSize + thread_xy;" NL
4583 " vec4 ic = imageLoad(g_input_image, pixel_xy);" NL
4584 " imageStore(g_output_image, pixel_xy, Process(ic));" NL "}";
4585 m_program[2] = CreateComputeProgram(glsl_cs2);
4586 glLinkProgram(m_program[2]);
4587 if (!CheckProgram(m_program[2]))
4590 glGenVertexArrays(1, &m_vertex_array);
4592 /* init render targets */
4594 std::vector<vec4> data(128 * 128);
4595 glGenTextures(2, m_render_target);
4596 for (int i = 0; i < 2; ++i)
4598 glBindTexture(GL_TEXTURE_2D, m_render_target[i]);
4599 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
4600 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 128, 128, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
4602 glBindTexture(GL_TEXTURE_2D, 0);
4605 glGenFramebuffers(1, &m_framebuffer);
4606 glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
4607 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_render_target[0], 0);
4608 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4610 glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
4611 glUseProgram(m_program[0]);
4612 glBindVertexArray(m_vertex_array);
4613 glClear(GL_COLOR_BUFFER_BIT);
4614 glViewport(0, 0, 128, 128);
4615 // draw full-viewport triangle
4616 glDrawArrays(GL_TRIANGLES, 1,
4617 3); // note: <first> is 1 this means that gl_VertexID in the VS will be: 1, 2 and 3
4618 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4620 glBindImageTexture(0, m_render_target[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); // input
4621 glBindImageTexture(1, m_render_target[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); // output
4622 glUseProgram(m_program[1]);
4623 glDispatchCompute(128 / 16, 128 / 16, 1);
4625 glBindImageTexture(0, m_render_target[1], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); // input
4626 glBindImageTexture(1, m_render_target[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); // output
4627 glUseProgram(m_program[2]);
4628 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4629 glDispatchCompute(128 / 32, 128 / 32, 1);
4631 /* validate render target */
4633 std::vector<vec4> data(128 * 128);
4634 glBindTexture(GL_TEXTURE_2D, m_render_target[0]);
4635 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
4636 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
4637 for (std::size_t i = 0; i < data.size(); ++i)
4639 if (!IsEqual(data[i], vec4(1, 1, 0, 1)))
4641 m_context.getTestContext().getLog()
4642 << tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
4650 virtual long Cleanup()
4652 glViewport(0, 0, getWindowWidth(), getWindowHeight());
4654 for (int i = 0; i < 3; ++i)
4655 glDeleteProgram(m_program[i]);
4656 glDeleteTextures(2, m_render_target);
4657 glDeleteVertexArrays(1, &m_vertex_array);
4658 glDeleteFramebuffers(1, &m_framebuffer);
4663 class AdvancedPipelinePostXFB : public ComputeShaderBase
4665 virtual std::string Title()
4667 return NL "CS as an additional pipeline stage - After XFB";
4669 virtual std::string Purpose()
4671 return NL "1. Verify that CS which process data fedback by VS works as expected." NL
4672 "2. Verify that XFB and SSBO works correctly together in one shader." NL
4673 "3. Verify that 'switch' statment which selects different execution path for each CS thread works as "
4676 virtual std::string Method()
4678 return NL "1. Draw triangle with XFB enabled. Some data is written to the XFB buffer." NL
4679 "2. Use XFB buffer as 'input SSBO' in CS. Process data and write it to 'output SSBO'." NL
4680 "3. Verify 'output SSBO' content.";
4682 virtual std::string PassCriteria()
4684 return NL "Everything works as expected.";
4687 GLuint m_program[2];
4688 GLuint m_storage_buffer;
4689 GLuint m_xfb_buffer;
4690 GLuint m_vertex_buffer;
4691 GLuint m_vertex_array;
4693 virtual long Setup()
4695 memset(m_program, 0, sizeof(m_program));
4696 m_storage_buffer = 0;
4698 m_vertex_buffer = 0;
4705 glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
4708 OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
4712 const char* const glsl_vs =
4713 NL "layout(location = 0) in vec4 g_position;" NL "layout(location = 1) in vec4 g_color;" NL
4714 "struct Vertex {" NL " vec4 position;" NL " vec4 color;" NL "};" NL "out StageData {" NL
4715 " vec4 color;" NL "} g_vs_out;" NL "layout(binding = 0, std430) buffer StageData {" NL
4716 " Vertex vertex[];" NL "} g_vs_buffer;" NL "void main() {" NL " gl_Position = g_position;" NL
4717 " g_vs_out.color = g_color;" NL " g_vs_buffer.vertex[gl_VertexID].position = g_position;" NL
4718 " g_vs_buffer.vertex[gl_VertexID].color = g_color;" NL "}";
4720 const char* const glsl_fs =
4721 NL "in StageData {" NL " vec4 color;" NL "} g_fs_in;" NL "layout(location = 0) out vec4 g_color;" NL
4722 "void main() {" NL " g_color = g_fs_in.color;" NL "}";
4724 m_program[0] = CreateProgram(glsl_vs, glsl_fs);
4725 /* setup xfb varyings */
4727 const char* const var[2] = { "gl_Position", "StageData.color" };
4728 glTransformFeedbackVaryings(m_program[0], 2, var, GL_INTERLEAVED_ATTRIBS);
4730 glLinkProgram(m_program[0]);
4731 if (!CheckProgram(m_program[0]))
4734 const char* const glsl_cs =
4735 NL "layout(local_size_x = 3) in;" NL "struct Vertex {" NL " vec4 position;" NL " vec4 color;" NL "};" NL
4736 "layout(binding = 3, std430) buffer Buffer {" NL " Vertex g_vertex[3];" NL "};" NL
4737 "uniform vec4 g_color1 = vec4(0, 0, 1, 0);" NL "uniform int g_two = 2;" NL
4738 "void UpdateVertex2(int i) {" NL " g_vertex[i].color -= vec4(-1, 1, 0, 0);" NL "}" NL "void main() {" NL
4739 " switch (gl_GlobalInvocationID.x) {" NL
4740 " case 0: g_vertex[gl_GlobalInvocationID.x].color += vec4(1, 0, 0, 0); break;" NL
4741 " case 1: g_vertex[1].color += g_color1; break;" NL " case 2: UpdateVertex2(g_two); break;" NL
4742 " default: return;" NL " }" NL "}";
4743 m_program[1] = CreateComputeProgram(glsl_cs);
4744 glLinkProgram(m_program[1]);
4745 if (!CheckProgram(m_program[1]))
4748 glGenBuffers(1, &m_storage_buffer);
4749 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
4750 glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * sizeof(vec4) * 2, NULL, GL_STATIC_COPY);
4752 glGenBuffers(1, &m_xfb_buffer);
4753 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_xfb_buffer);
4754 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 3 * sizeof(vec4) * 2, NULL, GL_STREAM_COPY);
4756 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 };
4757 glGenBuffers(1, &m_vertex_buffer);
4758 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4759 glBufferData(GL_ARRAY_BUFFER, sizeof(in_data), in_data, GL_STATIC_DRAW);
4760 glBindBuffer(GL_ARRAY_BUFFER, 0);
4762 glGenVertexArrays(1, &m_vertex_array);
4763 glBindVertexArray(m_vertex_array);
4764 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4765 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), 0);
4766 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), reinterpret_cast<void*>(sizeof(vec4)));
4767 glBindBuffer(GL_ARRAY_BUFFER, 0);
4768 glEnableVertexAttribArray(0);
4769 glEnableVertexAttribArray(1);
4770 glBindVertexArray(0);
4772 glClear(GL_COLOR_BUFFER_BIT);
4773 glUseProgram(m_program[0]);
4774 glBindVertexArray(m_vertex_array);
4775 glBeginTransformFeedback(GL_TRIANGLES);
4776 glDrawArrays(GL_TRIANGLES, 0, 3);
4777 glEndTransformFeedback();
4779 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_xfb_buffer);
4780 glUseProgram(m_program[1]);
4781 glDispatchCompute(1, 1, 1);
4783 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4785 /* validate storage buffer */
4788 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
4789 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data);
4790 if (memcmp(data, in_data, sizeof(data)) != 0)
4792 m_context.getTestContext().getLog()
4793 << tcu::TestLog::Message << "Data in shader storage buffer is incorrect."
4794 << tcu::TestLog::EndMessage;
4798 /* validate xfb buffer */
4800 const float ref_data[3 * 8] = {
4801 -1, -1, 0, 1, 1, 1, 0, 1, 3, -1, 0, 1, 0, 1, 1, 1, -1, 3, 0, 1, 1, 0, 0, 1
4805 glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(data), data);
4806 if (memcmp(data, ref_data, sizeof(data)) != 0)
4808 m_context.getTestContext().getLog()
4809 << tcu::TestLog::Message << "Data in xfb buffer is incorrect." << tcu::TestLog::EndMessage;
4813 if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
4820 virtual long Cleanup()
4823 for (int i = 0; i < 2; ++i)
4824 glDeleteProgram(m_program[i]);
4825 glDeleteBuffers(1, &m_vertex_buffer);
4826 glDeleteBuffers(1, &m_storage_buffer);
4827 glDeleteBuffers(1, &m_xfb_buffer);
4828 glDeleteVertexArrays(1, &m_vertex_array);
4833 class AdvancedSharedIndexing : public ComputeShaderBase
4835 virtual std::string Title()
4837 return NL "Shared Memory - Indexing";
4839 virtual std::string Purpose()
4841 return NL "1. Verify that indexing various types of shared memory works as expected." NL
4842 "2. Verify that indexing shared memory with different types of expressions work as expected." NL
4843 "3. Verify that all declaration types of shared structures are supported by the GLSL compiler.";
4845 virtual std::string Method()
4847 return NL "1. Create CS which uses shared memory in many different ways." NL
4848 "2. Write to shared memory using different expressions." NL "3. Validate shared memory content." NL
4849 "4. Use synchronization primitives (barrier, groupMemoryBarrier) where applicable.";
4851 virtual std::string PassCriteria()
4853 return NL "Everyting works as expected.";
4859 virtual long Setup()
4867 const char* const glsl_cs = NL
4868 "layout(binding = 3, rgba32f) uniform image2D g_result_image;" NL
4869 "layout (local_size_x = 4,local_size_y=4 ) in;" NL "shared vec4 g_shared1[4];" NL
4870 "shared mat4 g_shared2;" NL "shared struct {" NL " float data[4];" NL "} g_shared3[4];" NL
4871 "shared struct Type { float data[4]; } g_shared4[4];" NL "shared Type g_shared5[4];" NL
4872 "uniform bool g_true = true;" NL
4873 "uniform float g_values[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };" NL NL
4874 "void Sync() {" NL " groupMemoryBarrier();" NL " barrier();" NL "}" NL
4875 "void SetMemory(ivec2 xy, float value) {" NL " g_shared1[xy.y][gl_LocalInvocationID.x] = value;" NL
4876 " g_shared2[xy.y][xy.x] = value;" NL " g_shared3[xy[1]].data[xy[0]] = value;" NL
4877 " g_shared4[xy.y].data[xy[0]] = value;" NL
4878 " g_shared5[gl_LocalInvocationID.y].data[gl_LocalInvocationID.x] = value;" NL "}" NL
4879 "bool CheckMemory(ivec2 xy, float expected) {" NL
4880 " if (g_shared1[xy.y][xy[0]] != expected) return false;" NL
4881 " if (g_shared2[xy[1]][xy[0]] != expected) return false;" NL
4882 " if (g_shared3[gl_LocalInvocationID.y].data[gl_LocalInvocationID.x] != expected) return false;" NL
4883 " if (g_shared4[gl_LocalInvocationID.y].data[xy.x] != expected) return false;" NL
4884 " if (g_shared5[xy.y].data[xy.x] != expected) return false;" NL " return true;" NL "}" NL
4885 "void main() {" NL " const ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
4886 " vec4 result = vec4(0, 1, 0, 1);" NL NL
4887 " SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 1.0);" NL " Sync();" NL
4888 " if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 1.0)) result = vec4(1, 0, 0, 1);" NL NL
4889 " SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * -1.0);" NL " Sync();" NL
4890 " if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * -1.0)) result = vec4(1, 0, 0, 1);" NL NL
4891 " if (g_true && gl_LocalInvocationID.x < 10) {" NL
4892 " SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 7.0);" NL " Sync();" NL
4893 " if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 7.0)) result = vec4(1, 0, 0, 1);" NL
4894 " }" NL NL " imageStore(g_result_image, thread_xy, result);" NL "}";
4895 m_program = CreateComputeProgram(glsl_cs);
4896 glLinkProgram(m_program);
4897 if (!CheckProgram(m_program))
4902 std::vector<vec4> data(4 * 4);
4903 glGenTextures(1, &m_texture);
4904 glBindTexture(GL_TEXTURE_2D, m_texture);
4905 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
4906 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 4, 4, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
4907 glBindTexture(GL_TEXTURE_2D, 0);
4910 glBindImageTexture(3, m_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
4911 glUseProgram(m_program);
4912 glDispatchCompute(1, 1, 1);
4914 /* validate render target */
4916 std::vector<vec4> data(4 * 4);
4917 glBindTexture(GL_TEXTURE_2D, m_texture);
4918 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
4919 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &data[0][0]);
4920 for (std::size_t i = 0; i < data.size(); ++i)
4922 if (!IsEqual(data[i], vec4(0, 1, 0, 1)))
4924 m_context.getTestContext().getLog()
4925 << tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
4932 virtual long Cleanup()
4935 glDeleteProgram(m_program);
4936 glDeleteTextures(1, &m_texture);
4941 class AdvancedSharedMax : public ComputeShaderBase
4943 virtual std::string Title()
4945 return NL "Shared Memory - 32K";
4947 virtual std::string Purpose()
4949 return NL "Support for 32K of shared memory is required by the OpenGL specifaction. Verify if an "
4950 "implementation supports it.";
4952 virtual std::string Method()
4954 return NL "Create and dispatch CS which uses 32K of shared memory.";
4956 virtual std::string PassCriteria()
4958 return NL "Everything works as expected.";
4964 virtual long Setup()
4972 const char* const glsl_cs =
4973 NL "layout(local_size_x = 1024) in;" NL
4974 "shared struct Type { vec4 v[2]; } g_shared[1024];" // 32768 bytes of shared memory
4975 NL "layout(std430) buffer Output {" NL " Type g_output[1024];" NL "};" NL NL "void main() {" NL
4976 " const int id = int(gl_GlobalInvocationID.x);" NL
4977 " g_shared[id].v = vec4[2](vec4(1.0), vec4(1.0));" NL " memoryBarrierShared();" NL " barrier();" NL NL
4978 " vec4 sum = vec4(0.0);" NL " int sum_count = 0;" NL " for (int i = id - 3; i < id + 4; ++i) {" NL
4979 " if (id >= 0 && id < g_shared.length()) {" NL " sum += g_shared[id].v[0];" NL
4980 " sum += g_shared[id].v[1];" NL " sum_count += 2;" NL " }" NL " }" NL
4981 " if (any(greaterThan(abs((sum / sum_count) - vec4(1.0)), vec4(0.0000001f)))) return;" NL NL
4982 " g_output[id] = g_shared[id];" NL "}";
4983 m_program = CreateComputeProgram(glsl_cs);
4984 glLinkProgram(m_program);
4985 if (!CheckProgram(m_program))
4990 std::vector<vec4> data(1024 * 2);
4991 glGenBuffers(1, &m_buffer);
4992 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
4993 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0],
4997 glUseProgram(m_program);
4998 glDispatchCompute(1, 1, 1);
4999 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5001 /* validate buffer */
5003 std::vector<vec4> data(1024 * 2);
5004 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0]);
5005 for (std::size_t i = 0; i < data.size(); ++i)
5007 if (!IsEqual(data[i], vec4(1.0f)))
5009 m_context.getTestContext().getLog()
5010 << tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
5017 virtual long Cleanup()
5020 glDeleteProgram(m_program);
5021 glDeleteBuffers(1, &m_buffer);
5026 class AdvancedDynamicPaths : public ComputeShaderBase
5028 virtual std::string Title()
5030 return NL "Dynamic execution paths";
5032 virtual std::string Purpose()
5034 return NL "1. Verify case where each of the four threads takes different execution path in the CS." NL
5035 "2. Execution path for each thread is not known at the compilation time." NL
5036 " Selection is made based on the result of the texture sampling." NL
5037 "3. Verify that memory synchronization primitives (memoryBarrier* functions) are accepted" NL
5038 " in the control flow.";
5040 virtual std::string Method()
5042 return NL "1. Create and dispatch CS that takes different execution paths based on the result of the texture "
5043 "sampling." NL "2. In each execution path use different resources (buffers, samplers, uniform "
5044 "arrays) to compute output value.";
5046 virtual std::string PassCriteria()
5048 return NL "Everything works as expected.";
5053 GLuint m_texture[2];
5055 virtual long Setup()
5058 memset(m_buffer, 0, sizeof(m_buffer));
5059 memset(m_texture, 0, sizeof(m_texture));
5064 const char* const glsl_cs =
5065 NL "layout(local_size_x = 4) in;" NL "layout(std140, binding = 0) buffer Output {" NL
5066 " vec4 g_output[4];" NL "};" NL "uniform isamplerBuffer g_path_buffer;" NL
5067 "uniform vec4[4] g_input0 = vec4[4](vec4(100), vec4(200), vec4(300), vec4(400));" NL
5068 "uniform samplerBuffer g_input1;" NL "layout(binding = 1, std430) buffer Input2 {" NL
5069 " vec4[4] g_input2;" NL "};" NL NL "void Path2(int id) {" NL
5070 " g_output[id] = texelFetch(g_input1, int(gl_LocalInvocationIndex));" NL "}" NL "void main() {" NL
5071 " const int id = int(gl_GlobalInvocationID.x);" NL
5072 " const int path = texelFetch(g_path_buffer, id).x;" NL NL " if (path == 0) {" NL
5073 " g_output[id] = g_input0[gl_LocalInvocationID.x];" NL " memoryBarrier();" NL
5074 " } else if (path == 1) {" NL " return;" NL " } else if (path == 2) {" NL " Path2(id);" NL
5075 " return;" NL " } else if (path == 3) {" NL " g_output[id] = g_input2[path - 1];" NL
5076 " memoryBarrierBuffer();" NL " }" NL "}";
5077 m_program = CreateComputeProgram(glsl_cs);
5078 glLinkProgram(m_program);
5079 if (!CheckProgram(m_program))
5082 glGenBuffers(4, m_buffer);
5083 glGenTextures(2, m_texture);
5085 /* init 'output' buffer */
5087 std::vector<vec4> data(4, vec4(-100.0f));
5088 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[0]);
5089 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0],
5092 /* init 'input2' buffer */
5094 const vec4 data[4] = { vec4(1.0f), vec4(2.0f), vec4(3.0f), vec4(4.0f) };
5095 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[1]);
5096 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data[0][0], GL_DYNAMIC_COPY);
5098 /* init 'path' buffer */
5100 const int data[4] = { 3, 2, 1, 0 };
5101 glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[2]);
5102 glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data[0], GL_STATIC_DRAW);
5103 glBindBuffer(GL_TEXTURE_BUFFER, 0);
5104 glBindTexture(GL_TEXTURE_BUFFER, m_texture[0]);
5105 glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, m_buffer[2]);
5106 glBindTexture(GL_TEXTURE_BUFFER, 0);
5108 /* init 'input1' buffer */
5110 const vec4 data[4] = { vec4(10.0f), vec4(20.0f), vec4(30.0f), vec4(40.0f) };
5111 glBindBuffer(GL_TEXTURE_BUFFER, m_buffer[3]);
5112 glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data[0], GL_STATIC_DRAW);
5113 glBindBuffer(GL_TEXTURE_BUFFER, 0);
5114 glBindTexture(GL_TEXTURE_BUFFER, m_texture[1]);
5115 glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_buffer[3]);
5116 glBindTexture(GL_TEXTURE_BUFFER, 0);
5119 glUseProgram(m_program);
5120 glUniform1i(glGetUniformLocation(m_program, "g_path_buffer"), 0);
5121 glUniform1i(glGetUniformLocation(m_program, "g_input1"), 1);
5122 glActiveTexture(GL_TEXTURE0);
5123 glBindTexture(GL_TEXTURE_BUFFER, m_texture[0]);
5124 glActiveTexture(GL_TEXTURE1);
5125 glBindTexture(GL_TEXTURE_BUFFER, m_texture[1]);
5126 glDispatchCompute(1, 1, 1);
5127 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5129 /* validate 'output' buffer */
5132 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer[0]);
5133 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data[0][0]);
5135 const vec4 expected[4] = { vec4(3.0f), vec4(20.0f), vec4(-100.0f), vec4(400.0f) };
5136 for (int i = 0; i < 4; ++i)
5138 if (!IsEqual(data[i], expected[i]))
5140 m_context.getTestContext().getLog()
5141 << tcu::TestLog::Message << "Invalid data at index " << i << "." << tcu::TestLog::EndMessage;
5148 virtual long Cleanup()
5151 glDeleteProgram(m_program);
5152 glDeleteBuffers(4, m_buffer);
5153 glDeleteTextures(2, m_texture);
5158 class AdvancedResourcesMax : public ComputeShaderBase
5160 virtual std::string Title()
5162 return NL "Maximum number of resources in one shader";
5164 virtual std::string Purpose()
5166 return NL "1. Verify that using 8 SSBOs, 12 UBOs, 8 atomic counters, 16 samplers" NL
5167 " and 8 images in one CS works as expected.";
5169 virtual std::string Method()
5171 return NL "Create and dispatch CS. Verify result.";
5173 virtual std::string PassCriteria()
5175 return NL "Everything works as expected.";
5179 GLuint m_storage_buffer[8];
5180 GLuint m_uniform_buffer[12];
5181 GLuint m_atomic_buffer[8];
5182 GLuint m_texture_buffer[16];
5183 GLuint m_texture[16];
5184 GLuint m_image_buffer[8];
5187 bool RunIteration(GLuint index)
5189 for (GLuint i = 0; i < 8; ++i)
5191 const GLuint data = i + 1;
5192 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_storage_buffer[i]);
5193 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5195 for (GLuint i = 0; i < 12; ++i)
5197 const GLuint data = i + 1;
5198 glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
5199 glBufferData(GL_UNIFORM_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5201 for (GLuint i = 0; i < 8; ++i)
5203 const GLuint data = i + 1;
5204 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, m_atomic_buffer[i]);
5205 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5207 for (GLuint i = 0; i < 16; ++i)
5209 const GLuint data = i + 1;
5210 glBindBuffer(GL_TEXTURE_BUFFER, m_texture_buffer[i]);
5211 glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data, GL_DYNAMIC_READ);
5212 glBindBuffer(GL_TEXTURE_BUFFER, 0);
5214 glActiveTexture(GL_TEXTURE0 + i);
5215 glBindTexture(GL_TEXTURE_BUFFER, m_texture[i]);
5216 glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_texture_buffer[i]);
5218 for (GLuint i = 0; i < 8; ++i)
5220 const GLuint data = i + 1;
5221 glBindBuffer(GL_TEXTURE_BUFFER, m_image_buffer[i]);
5222 glBufferData(GL_TEXTURE_BUFFER, sizeof(data), &data, GL_DYNAMIC_COPY);
5223 glBindBuffer(GL_TEXTURE_BUFFER, 0);
5225 glBindTexture(GL_TEXTURE_BUFFER, m_image[i]);
5226 glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_image_buffer[i]);
5227 glBindTexture(GL_TEXTURE_BUFFER, 0);
5229 glBindImageTexture(i, m_image[i], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
5232 glUseProgram(m_program);
5233 glUniform1ui(glGetUniformLocation(m_program, "g_index"), index);
5236 std::vector<GLuint> data(480);
5237 for (GLuint i = 0; i < static_cast<GLuint>(data.size()); ++i)
5239 glUniform1uiv(glGetUniformLocation(m_program, "g_uniform_def"), static_cast<GLsizei>(data.size()),
5242 glDispatchCompute(1, 1, 1);
5243 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5246 /* validate buffer */
5249 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[index]);
5250 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5252 if (data != (index + 1) * 6)
5254 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data << " should be "
5255 << (index + 1) * 6 << "." << tcu::TestLog::EndMessage;
5258 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
5262 virtual long Setup()
5265 memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
5266 memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
5267 memset(m_atomic_buffer, 0, sizeof(m_atomic_buffer));
5268 memset(m_texture_buffer, 0, sizeof(m_texture_buffer));
5269 memset(m_texture, 0, sizeof(m_texture));
5270 memset(m_image_buffer, 0, sizeof(m_image_buffer));
5271 memset(m_image, 0, sizeof(m_image));
5276 const char* const glsl_cs =
5277 NL "layout(local_size_x = 1) in;" NL "layout(std140, binding = 0) buffer ShaderStorageBlock {" NL
5278 " uint data;" NL "} g_shader_storage[8];" NL "layout(std140, binding = 0) uniform UniformBlock {" NL
5279 " uint data;" NL "} g_uniform[12];" NL "layout(binding = 0) uniform usamplerBuffer g_sampler[16];" NL
5280 "layout(binding = 0, r32ui) uniform uimageBuffer g_image[8];" NL
5281 "layout(binding = 0, offset = 0) uniform atomic_uint g_atomic_counter0;" NL
5282 "layout(binding = 1, offset = 0) uniform atomic_uint g_atomic_counter1;" NL
5283 "layout(binding = 2, offset = 0) uniform atomic_uint g_atomic_counter2;" NL
5284 "layout(binding = 3, offset = 0) uniform atomic_uint g_atomic_counter3;" NL
5285 "layout(binding = 4, offset = 0) uniform atomic_uint g_atomic_counter4;" NL
5286 "layout(binding = 5, offset = 0) uniform atomic_uint g_atomic_counter5;" NL
5287 "layout(binding = 6, offset = 0) uniform atomic_uint g_atomic_counter6;" NL
5288 "layout(binding = 7, offset = 0) uniform atomic_uint g_atomic_counter7;" NL
5289 "uniform uint g_uniform_def[480];" NL "uniform uint g_index = 0u;" NL NL "uint Add() {" NL
5290 " switch (g_index) {" NL " case 0: return atomicCounter(g_atomic_counter0);" NL
5291 " case 1: return atomicCounter(g_atomic_counter1);" NL
5292 " case 2: return atomicCounter(g_atomic_counter2);" NL
5293 " case 3: return atomicCounter(g_atomic_counter3);" NL
5294 " case 4: return atomicCounter(g_atomic_counter4);" NL
5295 " case 5: return atomicCounter(g_atomic_counter5);" NL
5296 " case 6: return atomicCounter(g_atomic_counter6);" NL
5297 " case 7: return atomicCounter(g_atomic_counter7);" NL " }" NL "}" NL "void main() {" NL
5298 " g_shader_storage[g_index].data += g_uniform[g_index].data;" NL
5299 " g_shader_storage[g_index].data += texelFetch(g_sampler[g_index], 0).x;" NL
5300 " g_shader_storage[g_index].data += imageLoad(g_image[g_index], 0).x;" NL
5301 " g_shader_storage[g_index].data += Add();" NL
5302 " g_shader_storage[g_index].data += g_uniform_def[g_index];" NL "}";
5303 m_program = CreateComputeProgram(glsl_cs);
5304 glLinkProgram(m_program);
5305 if (!CheckProgram(m_program))
5308 glGenBuffers(16, m_storage_buffer);
5309 glGenBuffers(12, m_uniform_buffer);
5310 glGenBuffers(8, m_atomic_buffer);
5311 glGenBuffers(16, m_texture_buffer);
5312 glGenTextures(16, m_texture);
5313 glGenBuffers(8, m_image_buffer);
5314 glGenTextures(8, m_image);
5316 if (!RunIteration(0))
5318 if (!RunIteration(1))
5320 if (!RunIteration(5))
5325 virtual long Cleanup()
5328 glDeleteProgram(m_program);
5329 glDeleteBuffers(16, m_storage_buffer);
5330 glDeleteBuffers(12, m_uniform_buffer);
5331 glDeleteBuffers(8, m_atomic_buffer);
5332 glDeleteBuffers(16, m_texture_buffer);
5333 glDeleteTextures(16, m_texture);
5334 glDeleteBuffers(8, m_image_buffer);
5335 glDeleteTextures(8, m_image);
5340 class AdvancedFP64Case1 : public ComputeShaderBase
5342 virtual std::string Title()
5344 return NL "FP64 support - built-in math functions";
5346 virtual std::string Purpose()
5348 return NL "Verify that selected double precision math functions works as expected in the CS.";
5350 virtual std::string Method()
5352 return NL "Create and dispatch CS which uses double precision math functions. Verify results.";
5354 virtual std::string PassCriteria()
5356 return NL "Everything works as expected.";
5360 GLuint m_storage_buffer[4];
5361 GLuint m_uniform_buffer[2];
5363 virtual long Setup()
5366 memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
5367 memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
5372 const char* const glsl_cs =
5373 NL "layout(local_size_x = 4) in;" NL "layout(std140, binding = 0) buffer ShaderStorageBlock {" NL
5374 " double data;" NL "} g_shader_storage[4];" NL "layout(std140, binding = 0) uniform UniformBlock {" NL
5375 " double data;" NL "} g_uniform[2];" NL "uniform dvec2 g_uniform_def;" NL NL "void main() {" NL
5376 " if (gl_GlobalInvocationID.x == 0) {" NL
5377 " g_shader_storage[0].data = floor(g_uniform[0].data + 0.1LF);" // floor(1.1LF) == 1.0LF
5378 NL " } else if (gl_GlobalInvocationID.x == 1) {" NL
5379 " g_shader_storage[1].data = ceil(g_uniform[1].data + 0.2LF);" // ceil(2.2LF) == 3.0LF
5380 NL " } else if (gl_GlobalInvocationID.x == 2) {" NL
5381 " g_shader_storage[2].data = min(g_uniform_def[0] + 0.1LF, 1.0LF);" // min(1.1LF, 1.0LF) == 1.0LF
5382 NL " } else if (gl_GlobalInvocationID.x == 3) {" NL
5383 " g_shader_storage[3].data = max(g_uniform_def[0], g_uniform_def.y);" // max(1.0LF, 2.0LF) == 2.0LF
5385 m_program = CreateComputeProgram(glsl_cs);
5386 glLinkProgram(m_program);
5387 if (!CheckProgram(m_program))
5390 glGenBuffers(4, m_storage_buffer);
5391 for (GLuint i = 0; i < 4; ++i)
5393 const GLdouble data = static_cast<GLdouble>(i + 1);
5394 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_storage_buffer[i]);
5395 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5398 glGenBuffers(2, m_uniform_buffer);
5399 for (GLuint i = 0; i < 2; ++i)
5401 const GLdouble data = static_cast<GLdouble>(i + 1);
5402 glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
5403 glBufferData(GL_UNIFORM_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5406 glUseProgram(m_program);
5407 glUniform2d(glGetUniformLocation(m_program, "g_uniform_def"), 1.0, 2.0);
5408 glDispatchCompute(1, 1, 1);
5409 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5413 const GLdouble expected[4] = { 1.0, 3.0, 1.0, 2.0 };
5414 for (int i = 0; i < 4; ++i)
5417 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[i]);
5418 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5419 if (data != expected[i])
5421 m_context.getTestContext().getLog()
5422 << tcu::TestLog::Message << "Data at index " << i << " is " << data << " should be "
5423 << expected[i] << "." << tcu::TestLog::EndMessage;
5430 virtual long Cleanup()
5433 glDeleteProgram(m_program);
5434 glDeleteBuffers(4, m_storage_buffer);
5435 glDeleteBuffers(2, m_uniform_buffer);
5440 class AdvancedFP64Case2 : public ComputeShaderBase
5442 virtual std::string Title()
5444 return NL "FP64 support - uniform variables";
5446 virtual std::string Purpose()
5448 return NL "1. Verify that all types of double precision uniform variables work as expected in CS." NL
5449 "2. Verify that all double precision uniform variables can be updated with Uniform* and "
5450 "ProgramUniform* commands." NL "3. Verify that re-linking CS program works as expected.";
5452 virtual std::string Method()
5454 return NL "1. Create CS which uses all (double precision) types of uniform variables." NL
5455 "2. Update uniform variables with ProgramUniform* commands." NL
5456 "3. Verify that uniform variables were updated correctly." NL "4. Re-link CS program." NL
5457 "5. Update uniform variables with Uniform* commands." NL
5458 "6. Verify that uniform variables were updated correctly.";
5460 virtual std::string PassCriteria()
5462 return NL "Everything works as expected.";
5466 GLuint m_storage_buffer;
5468 virtual long Setup()
5471 m_storage_buffer = 0;
5476 const char* const glsl_cs = NL
5477 "layout(local_size_x = 1) in;" NL "buffer Result {" NL " int g_result;" NL "};" NL "uniform double g_0;" NL
5478 "uniform dvec2 g_1;" NL "uniform dvec3 g_2;" NL "uniform dvec4 g_3;" NL "uniform dmat2 g_4;" NL
5479 "uniform dmat2x3 g_5;" NL "uniform dmat2x4 g_6;" NL "uniform dmat3x2 g_7;" NL "uniform dmat3 g_8;" NL
5480 "uniform dmat3x4 g_9;" NL "uniform dmat4x2 g_10;" NL "uniform dmat4x3 g_11;" NL "uniform dmat4 g_12;" NL NL
5481 "void main() {" NL " g_result = 1;" NL NL " if (g_0 != 1.0LF) g_result = 0;" NL
5482 " if (g_1 != dvec2(2.0LF, 3.0LF)) g_result = 0;" NL
5483 " if (g_2 != dvec3(4.0LF, 5.0LF, 6.0LF)) g_result = 0;" NL
5484 " if (g_3 != dvec4(7.0LF, 8.0LF, 9.0LF, 10.0LF)) g_result = 0;" NL NL
5485 " if (g_4 != dmat2(11.0LF, 12.0LF, 13.0LF, 14.0LF)) g_result = 0;" NL
5486 " if (g_5 != dmat2x3(15.0LF, 16.0LF, 17.0LF, 18.0LF, 19.0LF, 20.0LF)) g_result = 0;" NL
5487 " if (g_6 != dmat2x4(21.0LF, 22.0LF, 23.0LF, 24.0LF, 25.0LF, 26.0LF, 27.0LF, 28.0LF)) g_result = 0;" NL NL
5488 " if (g_7 != dmat3x2(29.0LF, 30.0LF, 31.0LF, 32.0LF, 33.0LF, 34.0LF)) g_result = 0;" NL
5489 " if (g_8 != dmat3(35.0LF, 36.0LF, 37.0LF, 38.0LF, 39.0LF, 40.0LF, 41.0LF, 42.0LF, 43.0LF)) g_result = "
5490 "0;" NL " if (g_9 != dmat3x4(44.0LF, 45.0LF, 46.0LF, 47.0LF, 48.0LF, 49.0LF, 50.0LF, 51.0LF, 52.0LF, "
5491 "53.0LF, 54.0LF, 55.0LF)) g_result = 0;" NL NL
5492 " if (g_10 != dmat4x2(56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0)) g_result = 0;" NL
5493 " if (g_11 != dmat4x3(63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0)) g_result = "
5494 "0;" NL " if (g_12 != dmat4(75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, "
5495 "88.0, 89.0, 90.0)) g_result = 0;" NL "}";
5496 m_program = CreateComputeProgram(glsl_cs);
5497 glLinkProgram(m_program);
5498 if (!CheckProgram(m_program))
5501 glGenBuffers(1, &m_storage_buffer);
5504 const int data = 123;
5505 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
5506 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
5509 glProgramUniform1d(m_program, glGetUniformLocation(m_program, "g_0"), 1.0);
5510 glProgramUniform2d(m_program, glGetUniformLocation(m_program, "g_1"), 2.0, 3.0);
5511 glProgramUniform3d(m_program, glGetUniformLocation(m_program, "g_2"), 4.0, 5.0, 6.0);
5512 glProgramUniform4d(m_program, glGetUniformLocation(m_program, "g_3"), 7.0, 8.0, 9.0, 10.0);
5516 const GLdouble value[4] = { 11.0, 12.0, 13.0, 14.0 };
5517 glProgramUniformMatrix2dv(m_program, glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
5521 const GLdouble value[6] = { 15.0, 16.0, 17.0, 18.0, 19.0, 20.0 };
5522 glProgramUniformMatrix2x3dv(m_program, glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
5526 const GLdouble value[8] = { 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0 };
5527 glProgramUniformMatrix2x4dv(m_program, glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
5532 const GLdouble value[6] = { 29.0, 30.0, 31.0, 32.0, 33.0, 34.0 };
5533 glProgramUniformMatrix3x2dv(m_program, glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
5537 const GLdouble value[9] = { 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0 };
5538 glProgramUniformMatrix3dv(m_program, glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
5542 const GLdouble value[12] = { 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0 };
5543 glProgramUniformMatrix3x4dv(m_program, glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
5548 const GLdouble value[8] = { 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0 };
5549 glProgramUniformMatrix4x2dv(m_program, glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
5553 const GLdouble value[12] = { 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0 };
5554 glProgramUniformMatrix4x3dv(m_program, glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
5558 const GLdouble value[16] = { 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0,
5559 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0 };
5560 glProgramUniformMatrix4dv(m_program, glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
5563 glUseProgram(m_program);
5564 glDispatchCompute(1, 1, 1);
5565 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5570 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5573 m_context.getTestContext().getLog()
5574 << tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
5579 // re-link program (all uniforms will be set to zero)
5580 glLinkProgram(m_program);
5584 const int data = 123;
5585 glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5588 glUniform1d(glGetUniformLocation(m_program, "g_0"), 1.0);
5589 glUniform2d(glGetUniformLocation(m_program, "g_1"), 2.0, 3.0);
5590 glUniform3d(glGetUniformLocation(m_program, "g_2"), 4.0, 5.0, 6.0);
5591 glUniform4d(glGetUniformLocation(m_program, "g_3"), 7.0, 8.0, 9.0, 10.0);
5595 const GLdouble value[4] = { 11.0, 12.0, 13.0, 14.0 };
5596 glUniformMatrix2dv(glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
5600 const GLdouble value[6] = { 15.0, 16.0, 17.0, 18.0, 19.0, 20.0 };
5601 glUniformMatrix2x3dv(glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
5605 const GLdouble value[8] = { 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0 };
5606 glUniformMatrix2x4dv(glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
5611 const GLdouble value[6] = { 29.0, 30.0, 31.0, 32.0, 33.0, 34.0 };
5612 glUniformMatrix3x2dv(glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
5616 const GLdouble value[9] = { 35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0 };
5617 glUniformMatrix3dv(glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
5621 const GLdouble value[12] = { 44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0 };
5622 glUniformMatrix3x4dv(glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
5627 const GLdouble value[8] = { 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0 };
5628 glUniformMatrix4x2dv(glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
5632 const GLdouble value[12] = { 63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0 };
5633 glUniformMatrix4x3dv(glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
5637 const GLdouble value[16] = { 75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0,
5638 83.0, 84.0, 85.0, 86.0, 87.0, 88.0, 89.0, 90.0 };
5639 glUniformMatrix4dv(glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
5642 glDispatchCompute(1, 1, 1);
5643 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5648 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5651 m_context.getTestContext().getLog()
5652 << tcu::TestLog::Message << "Data is " << data << " should be 1." << tcu::TestLog::EndMessage;
5659 virtual long Cleanup()
5662 glDeleteProgram(m_program);
5663 glDeleteBuffers(1, &m_storage_buffer);
5668 class AdvancedFP64Case3 : public ComputeShaderBase
5670 virtual std::string Title()
5672 return NL "FP64 support - subroutines";
5674 virtual std::string Purpose()
5676 return NL "Verify that subroutines that performs double precision computation works as expected in the CS.";
5678 virtual std::string Method()
5681 "Create and dispatch CS that uses double precision math functions in subroutines to compute output values.";
5683 virtual std::string PassCriteria()
5685 return NL "Everything works as expected.";
5689 GLuint m_storage_buffer;
5691 virtual long Setup()
5694 m_storage_buffer = 0;
5699 const char* const glsl_cs =
5700 NL "layout(local_size_x = 1) in;" NL "uniform double[4] g_input;" NL "uniform int index;" NL
5701 "layout(std430, binding = 0) buffer Output {" NL " double g_output[4];" NL "};" NL
5702 "subroutine double MathFunc(double x);" NL "subroutine uniform MathFunc g_func[4];" NL
5703 "subroutine(MathFunc)" NL "double Func0(double x) {" NL " return abs(x);" // abs(-1.0LF) == 1.0LF
5704 NL "}" NL "subroutine(MathFunc)" NL "double Func1(double x) {" NL
5705 " return round(x);" // round(2.2LF) == 2.0LF
5706 NL "}" NL "subroutine(MathFunc)" NL "double Func2(double x) {" NL
5707 " return sign(x);" // sign(3.0LF) == 1.0LF
5708 NL "}" NL "subroutine(MathFunc)" NL "double Func3(double x) {" NL
5709 " return fract(x);" // fract(4.1LF) == 0.1LF
5710 NL "}" NL "void main() {" NL " int i = index;" NL " g_output[i] = g_func[i](g_input[i]);" NL "}";
5711 m_program = CreateComputeProgram(glsl_cs);
5712 glLinkProgram(m_program);
5713 if (!CheckProgram(m_program))
5716 glGenBuffers(1, &m_storage_buffer);
5717 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
5718 glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * sizeof(double), NULL, GL_STATIC_DRAW);
5720 const GLuint index_compute0 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func0");
5721 const GLuint index_compute1 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func1");
5722 const GLuint index_compute2 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func2");
5723 const GLuint index_compute3 = glGetSubroutineIndex(m_program, GL_COMPUTE_SHADER, "Func3");
5724 const GLint loc_compute0 = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[0]");
5725 const GLint loc_compute1 = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[1]");
5726 const GLint loc_compute2 = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[2]");
5727 const GLint loc_compute3 = glGetSubroutineUniformLocation(m_program, GL_COMPUTE_SHADER, "g_func[3]");
5729 glUseProgram(m_program);
5731 // setup subroutines
5733 indices[loc_compute0] = index_compute0;
5734 indices[loc_compute1] = index_compute1;
5735 indices[loc_compute2] = index_compute2;
5736 indices[loc_compute3] = index_compute3;
5737 glUniformSubroutinesuiv(GL_COMPUTE_SHADER, 4, indices);
5741 const GLdouble data[4] = { -1.0, 2.2, 3.0, 4.1 };
5742 glUniform1dv(glGetUniformLocation(m_program, "g_input"), 4, data);
5744 glUniform1i(glGetUniformLocation(m_program, "index"), 0);
5745 glDispatchCompute(1, 1, 1);
5746 glUniform1i(glGetUniformLocation(m_program, "index"), 1);
5747 glDispatchCompute(1, 1, 1);
5748 glUniform1i(glGetUniformLocation(m_program, "index"), 2);
5749 glDispatchCompute(1, 1, 1);
5750 glUniform1i(glGetUniformLocation(m_program, "index"), 3);
5751 glDispatchCompute(1, 1, 1);
5752 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5756 const GLdouble expected[4] = { 1.0, 2.0, 1.0, 0.1 };
5758 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
5759 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5760 for (int i = 0; i < 4; ++i)
5762 if (fabs(data[i] - expected[i]) > g_color_eps.x())
5764 m_context.getTestContext().getLog()
5765 << tcu::TestLog::Message << "Data at index " << i << " is " << data[i] << " should be "
5766 << expected[i] << "." << tcu::TestLog::EndMessage;
5773 virtual long Cleanup()
5776 glDeleteProgram(m_program);
5777 glDeleteBuffers(1, &m_storage_buffer);
5782 class AdvancedConditionalDispatching : public ComputeShaderBase
5784 virtual std::string Title()
5786 return NL "Conditional Dispatching";
5788 virtual std::string Purpose()
5790 return NL "Verify that DispatchCompute and DispatchComputeIndirect commands work as expected inside "
5791 "conditional blocks.";
5793 virtual std::string Method()
5795 return NL "1. Render two quads. One will pass depth-test and the second one will not." NL
5796 "2. Use GL_ANY_SAMPLES_PASSED query objects to 'remember' these results." NL
5797 "3. Use DispatchCompute and DispatchComputeIndirect commands inside conditional blocks using both "
5799 "4. Verify that DispatchCompute and DispatchComputeIndirect commands are only executed in" NL
5800 " the conditional block that uses query object that has passed depth-test.";
5802 virtual std::string PassCriteria()
5804 return NL "Everything works as expected.";
5807 GLuint m_program_vsfs;
5808 GLuint m_program_cs;
5809 GLuint m_vertex_array;
5811 GLuint m_storage_buffer;
5812 GLuint m_dispatch_buffer;
5814 virtual long Setup()
5819 memset(m_query, 0, sizeof(m_query));
5820 m_storage_buffer = 0;
5821 m_dispatch_buffer = 0;
5826 const char* const glsl_vs = NL
5827 "uniform float g_depth;" NL "uniform vec2[3] g_vertex = vec2[3](vec2(-1, -1), vec2(3, -1), vec2(-1, 3));" NL
5828 "void main() {" NL " gl_Position = vec4(g_vertex[gl_VertexID], g_depth, 1);" NL "}";
5830 const char* const glsl_fs =
5831 NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL " g_color = vec4(0, 1, 0, 1);" NL "}";
5833 m_program_vsfs = CreateProgram(glsl_vs, glsl_fs);
5834 glLinkProgram(m_program_vsfs);
5835 if (!CheckProgram(m_program_vsfs))
5838 const char* const glsl_cs =
5839 NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL " int g_output;" NL "};" NL
5840 "void main() {" NL " atomicAdd(g_output, 1);" NL "}";
5841 m_program_cs = CreateComputeProgram(glsl_cs);
5842 glLinkProgram(m_program_cs);
5843 if (!CheckProgram(m_program_cs))
5846 /* create storage buffer */
5849 glGenBuffers(1, &m_storage_buffer);
5850 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
5851 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_DYNAMIC_COPY);
5853 /* create dispatch buffer */
5855 const GLuint data[3] = { 2, 2, 2 };
5856 glGenBuffers(1, &m_dispatch_buffer);
5857 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
5858 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
5861 glGenVertexArrays(1, &m_vertex_array);
5862 glGenQueries(2, m_query);
5864 glEnable(GL_DEPTH_TEST);
5865 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
5867 glUseProgram(m_program_vsfs);
5868 glBindVertexArray(m_vertex_array);
5870 // this draw call will pass depth test
5871 glBeginQuery(GL_ANY_SAMPLES_PASSED, m_query[0]);
5872 glUniform1f(glGetUniformLocation(m_program_vsfs, "g_depth"), 0.0f);
5873 glDrawArrays(GL_TRIANGLES, 0, 3);
5874 glEndQuery(GL_ANY_SAMPLES_PASSED);
5876 // this draw call will NOT pass depth test
5877 glBeginQuery(GL_ANY_SAMPLES_PASSED, m_query[1]);
5878 glUniform1f(glGetUniformLocation(m_program_vsfs, "g_depth"), 0.5f);
5879 glDrawArrays(GL_TRIANGLES, 0, 3);
5880 glEndQuery(GL_ANY_SAMPLES_PASSED);
5882 glDisable(GL_DEPTH_TEST);
5884 glUseProgram(m_program_cs);
5886 // these commands should be executed normally
5887 glBeginConditionalRender(m_query[0], GL_QUERY_WAIT);
5888 glDispatchCompute(2, 2, 2);
5889 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
5890 glDispatchComputeIndirect(0);
5891 glEndConditionalRender();
5896 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
5897 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5900 m_context.getTestContext().getLog()
5901 << tcu::TestLog::Message << "Data is " << data << " should be 16." << tcu::TestLog::EndMessage;
5906 // these commands should be discarded
5907 glBeginConditionalRender(m_query[1], GL_QUERY_WAIT);
5908 glDispatchCompute(2, 2, 2);
5909 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
5910 glDispatchComputeIndirect(0);
5911 glEndConditionalRender();
5916 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
5917 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), &data);
5918 if (data != 16 && m_context.getRenderContext().getRenderTarget().getDepthBits() != 0)
5920 m_context.getTestContext().getLog()
5921 << tcu::TestLog::Message << "Data is " << data << " should be 16." << tcu::TestLog::EndMessage;
5924 else if (data != 32 && m_context.getRenderContext().getRenderTarget().getDepthBits() == 0)
5926 m_context.getTestContext().getLog()
5927 << tcu::TestLog::Message << "Data is " << data << " should be 32." << tcu::TestLog::EndMessage;
5932 if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
5939 virtual long Cleanup()
5942 glDeleteProgram(m_program_vsfs);
5943 glDeleteProgram(m_program_cs);
5944 glDeleteVertexArrays(1, &m_vertex_array);
5945 glDeleteQueries(2, m_query);
5946 glDeleteBuffers(1, &m_storage_buffer);
5947 glDeleteBuffers(1, &m_dispatch_buffer);
5952 class NegativeAPINoActiveProgram : public ComputeShaderBase
5954 virtual std::string Title()
5956 return NL "API errors - no active program";
5958 virtual std::string Purpose()
5960 return NL "Verify that appropriate errors are generated by the OpenGL API.";
5962 virtual std::string Method()
5966 virtual std::string PassCriteria()
5973 virtual long Setup()
5980 glDispatchCompute(1, 2, 3);
5981 if (glGetError() != GL_INVALID_OPERATION)
5983 m_context.getTestContext().getLog()
5984 << tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
5985 << "DispatchComputeIndirect if there is no active program for the compute\n"
5986 << "shader stage." << tcu::TestLog::EndMessage;
5990 /* indirect dispatch */
5993 const GLuint num_group[3] = { 3, 2, 1 };
5994 glGenBuffers(1, &buffer);
5995 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
5996 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_group), num_group, GL_STATIC_DRAW);
5997 glDispatchComputeIndirect(0);
5998 glDeleteBuffers(1, &buffer);
5999 if (glGetError() != GL_INVALID_OPERATION)
6001 m_context.getTestContext().getLog()
6002 << tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
6003 << "DispatchComputeIndirect if there is no active program for the compute\n"
6004 << "shader stage." << tcu::TestLog::EndMessage;
6009 const char* const glsl_vs =
6010 NL "layout(location = 0) in vec4 g_position;" NL "void main() {" NL " gl_Position = g_position;" NL "}";
6012 const char* const glsl_fs =
6013 NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL " g_color = vec4(1);" NL "}";
6015 m_program = CreateProgram(glsl_vs, glsl_fs);
6016 glLinkProgram(m_program);
6017 if (!CheckProgram(m_program))
6020 glUseProgram(m_program);
6022 glDispatchCompute(1, 2, 3);
6023 if (glGetError() != GL_INVALID_OPERATION)
6025 m_context.getTestContext().getLog()
6026 << tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
6027 << "DispatchComputeIndirect if there is no active program for the compute\n"
6028 << "shader stage." << tcu::TestLog::EndMessage;
6032 /* indirect dispatch */
6035 const GLuint num_group[3] = { 3, 2, 1 };
6036 glGenBuffers(1, &buffer);
6037 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
6038 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_group), num_group, GL_STATIC_DRAW);
6039 glDispatchComputeIndirect(0);
6040 glDeleteBuffers(1, &buffer);
6041 if (glGetError() != GL_INVALID_OPERATION)
6043 m_context.getTestContext().getLog()
6044 << tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
6045 << "DispatchComputeIndirect if there is no active program for the compute\n"
6046 << "shader stage." << tcu::TestLog::EndMessage;
6053 virtual long Cleanup()
6056 glDeleteProgram(m_program);
6061 class NegativeAPIWorkGroupCount : public ComputeShaderBase
6063 virtual std::string Title()
6065 return NL "API errors - invalid work group count";
6067 virtual std::string Purpose()
6069 return NL "Verify that appropriate errors are generated by the OpenGL API.";
6071 virtual std::string Method()
6075 virtual std::string PassCriteria()
6081 GLuint m_storage_buffer;
6083 virtual long Setup()
6086 m_storage_buffer = 0;
6091 const char* const glsl_cs =
6092 NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
6094 " g_output[gl_GlobalInvocationID.x * gl_GlobalInvocationID.y * gl_GlobalInvocationID.z] = 0;" NL "}";
6095 m_program = CreateComputeProgram(glsl_cs);
6096 glLinkProgram(m_program);
6097 if (!CheckProgram(m_program))
6100 glGenBuffers(1, &m_storage_buffer);
6101 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
6102 glBufferData(GL_SHADER_STORAGE_BUFFER, 100000, NULL, GL_DYNAMIC_DRAW);
6105 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &x);
6106 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &y);
6107 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &z);
6109 glUseProgram(m_program);
6111 glDispatchCompute(x + 1, 1, 1);
6112 if (glGetError() != GL_INVALID_VALUE)
6114 m_context.getTestContext().getLog()
6115 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
6116 << "<num_groups_y> or <num_groups_z> is greater than the value of\n"
6117 << "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension." << tcu::TestLog::EndMessage;
6121 glDispatchCompute(1, y + 1, 1);
6122 if (glGetError() != GL_INVALID_VALUE)
6124 m_context.getTestContext().getLog()
6125 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
6126 << "<num_groups_y> or <num_groups_z> is greater than the value of\n"
6127 << "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension." << tcu::TestLog::EndMessage;
6131 glDispatchCompute(1, 1, z + 1);
6132 if (glGetError() != GL_INVALID_VALUE)
6134 m_context.getTestContext().getLog()
6135 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
6136 << "<num_groups_y> or <num_groups_z> is greater than the value of\n"
6137 << "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension." << tcu::TestLog::EndMessage;
6143 virtual long Cleanup()
6146 glDeleteProgram(m_program);
6147 glDeleteBuffers(1, &m_storage_buffer);
6152 class NegativeAPIIndirect : public ComputeShaderBase
6154 virtual std::string Title()
6156 return NL "API errors - incorrect DispatchComputeIndirect usage";
6158 virtual std::string Purpose()
6160 return NL "Verify that appropriate errors are generated by the OpenGL API.";
6162 virtual std::string Method()
6166 virtual std::string PassCriteria()
6172 GLuint m_storage_buffer;
6173 GLuint m_dispatch_buffer;
6175 virtual long Setup()
6178 m_storage_buffer = 0;
6179 m_dispatch_buffer = 0;
6185 const char* const glsl_cs =
6186 NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
6187 "void main() {" NL " g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
6188 m_program = CreateComputeProgram(glsl_cs);
6189 glLinkProgram(m_program);
6190 if (!CheckProgram(m_program))
6193 glGenBuffers(1, &m_storage_buffer);
6194 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
6195 glBufferData(GL_SHADER_STORAGE_BUFFER, 100000, NULL, GL_DYNAMIC_DRAW);
6197 const GLuint num_groups[6] = { 1, 1, 1, 1, 1, 1 };
6198 glGenBuffers(1, &m_dispatch_buffer);
6199 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
6200 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), num_groups, GL_STATIC_COPY);
6202 glUseProgram(m_program);
6204 glDispatchComputeIndirect(-2);
6205 if (glGetError() != GL_INVALID_VALUE)
6207 m_context.getTestContext().getLog()
6208 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchComputeIndirect if <indirect> is\n"
6209 << "less than zero or not a multiple of four." << tcu::TestLog::EndMessage;
6213 glDispatchComputeIndirect(3);
6214 if (glGetError() != GL_INVALID_VALUE)
6216 m_context.getTestContext().getLog()
6217 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchComputeIndirect if <indirect> is\n"
6218 << "less than zero or not a multiple of four." << tcu::TestLog::EndMessage;
6222 glDispatchComputeIndirect(16);
6223 if (glGetError() != GL_INVALID_OPERATION)
6225 m_context.getTestContext().getLog()
6226 << tcu::TestLog::Message
6227 << "INVALID_OPERATION is generated by DispatchComputeIndirect if no buffer is\n"
6228 << "bound to DISPATCH_INDIRECT_BUFFER or if the command would source data\n"
6229 << "beyond the end of the bound buffer object." << tcu::TestLog::EndMessage;
6233 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
6234 glDispatchComputeIndirect(0);
6235 if (glGetError() != GL_INVALID_OPERATION)
6237 m_context.getTestContext().getLog()
6238 << tcu::TestLog::Message
6239 << "INVALID_OPERATION is generated by DispatchComputeIndirect if no buffer is\n"
6240 << "bound to DISPATCH_INDIRECT_BUFFER or if the command would source data\n"
6241 << "beyond the end of the bound buffer object." << tcu::TestLog::EndMessage;
6247 virtual long Cleanup()
6250 glDeleteProgram(m_program);
6251 glDeleteBuffers(1, &m_storage_buffer);
6252 glDeleteBuffers(1, &m_dispatch_buffer);
6257 class NegativeAPIProgram : public ComputeShaderBase
6259 virtual std::string Title()
6261 return NL "API errors - program state";
6263 virtual std::string Purpose()
6265 return NL "Verify that appropriate errors are generated by the OpenGL API.";
6267 virtual std::string Method()
6271 virtual std::string PassCriteria()
6277 GLuint m_storage_buffer;
6279 virtual long Setup()
6282 m_storage_buffer = 0;
6287 const char* const glsl_vs =
6288 NL "layout(location = 0) in vec4 g_position;" NL "void main() {" NL " gl_Position = g_position;" NL "}";
6290 const char* const glsl_fs =
6291 NL "layout(location = 0) out vec4 g_color;" NL "void main() {" NL " g_color = vec4(1);" NL "}";
6292 m_program = CreateProgram(glsl_vs, glsl_fs);
6295 glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
6296 if (glGetError() != GL_INVALID_OPERATION)
6298 m_context.getTestContext().getLog()
6299 << tcu::TestLog::Message << "INVALID_OPERATION is generated by GetProgramiv if <pname> is\n"
6300 << "COMPUTE_LOCAL_WORK_SIZE and either the program has not been linked\n"
6301 << "successfully, or has been linked but contains no compute shaders." << tcu::TestLog::EndMessage;
6305 glLinkProgram(m_program);
6306 if (!CheckProgram(m_program))
6309 glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
6310 if (glGetError() != GL_INVALID_OPERATION)
6312 m_context.getTestContext().getLog()
6313 << tcu::TestLog::Message << "INVALID_OPERATION is generated by GetProgramiv if <pname> is\n"
6314 << "COMPUTE_LOCAL_WORK_SIZE and either the program has not been linked\n"
6315 << "successfully, or has been linked but contains no compute shaders." << tcu::TestLog::EndMessage;
6318 glDeleteProgram(m_program);
6320 const char* const glsl_cs =
6321 "#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
6322 " uint g_output[];" NL "};" NL "void main() {" NL " g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
6323 m_program = glCreateProgram();
6325 GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
6326 glAttachShader(m_program, sh);
6328 glShaderSource(sh, 1, &glsl_cs, NULL);
6329 glCompileShader(sh);
6331 sh = glCreateShader(GL_VERTEX_SHADER);
6332 glAttachShader(m_program, sh);
6334 glShaderSource(sh, 1, &glsl_vs, NULL);
6335 glCompileShader(sh);
6337 sh = glCreateShader(GL_FRAGMENT_SHADER);
6338 glAttachShader(m_program, sh);
6340 glShaderSource(sh, 1, &glsl_fs, NULL);
6341 glCompileShader(sh);
6343 glLinkProgram(m_program);
6345 glGetProgramiv(m_program, GL_LINK_STATUS, &status);
6346 if (status == GL_TRUE)
6348 m_context.getTestContext().getLog()
6349 << tcu::TestLog::Message << "LinkProgram will fail if <program> contains a combination"
6350 << " of compute and\n non-compute shaders.\n"
6351 << tcu::TestLog::EndMessage;
6357 virtual long Cleanup()
6360 glDeleteProgram(m_program);
6361 glDeleteBuffers(1, &m_storage_buffer);
6366 class NegativeGLSLCompileTimeErrors : public ComputeShaderBase
6368 virtual std::string Title()
6370 return NL "Compile-time errors";
6372 virtual std::string Purpose()
6374 return NL "Verify that appropriate errors are generated by the GLSL compiler.";
6376 virtual std::string Method()
6380 virtual std::string PassCriteria()
6385 static std::string Shader1(int x, int y, int z)
6387 std::stringstream ss;
6388 ss << "#version 430 core" NL "layout(local_size_x = " << x << ", local_size_y = " << y
6389 << ", local_size_z = " << z << ") in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
6390 "void main() {" NL " g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
6395 // gl_GlobalInvocationID requires "#version 430" or later or GL_ARB_compute_shader
6396 // extension enabled
6397 if (!Compile("#version 420 core" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
6398 " uint g_output[];" NL "};" NL "void main() {" NL " g_output[gl_GlobalInvocationID.x] = 0;" NL
6402 if (!Compile("#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(local_size_x = 2) in;" NL
6403 "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL "void main() {" NL
6404 " g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
6407 if (!Compile("#version 430 core" NL "layout(local_size_x = 1) in;" NL "in uint x;" NL
6408 "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL "void main() {" NL
6409 " g_output[gl_GlobalInvocationID.x] = x;" NL "}"))
6412 if (!Compile("#version 430 core" NL "layout(local_size_x = 1) in;" NL "out uint x;" NL
6413 "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL "void main() {" NL
6414 " g_output[gl_GlobalInvocationID.x] = 0;" NL " x = 0;" NL "}"))
6419 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &x);
6420 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &y);
6421 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &z);
6423 if (!Compile(Shader1(x + 1, 1, 1)))
6425 if (!Compile(Shader1(1, y + 1, 1)))
6427 if (!Compile(Shader1(1, 1, z + 1)))
6434 bool Compile(const std::string& source)
6436 const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
6438 const char* const src = source.c_str();
6439 glShaderSource(sh, 1, &src, NULL);
6440 glCompileShader(sh);
6443 glGetShaderInfoLog(sh, sizeof(log), NULL, log);
6444 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader Info Log:\n"
6445 << log << tcu::TestLog::EndMessage;
6448 glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
6451 if (status == GL_TRUE)
6453 m_context.getTestContext().getLog()
6454 << tcu::TestLog::Message << "Compilation should fail." << tcu::TestLog::EndMessage;
6462 class NegativeGLSLLinkTimeErrors : public ComputeShaderBase
6464 virtual std::string Title()
6466 return NL "Link-time errors";
6468 virtual std::string Purpose()
6470 return NL "Verify that appropriate errors are generated by the GLSL linker.";
6472 virtual std::string Method()
6476 virtual std::string PassCriteria()
6484 if (!Link("#version 430 core" NL "void Run();" NL "void main() {" NL " Run();" NL "}",
6485 "#version 430 core" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
6486 "void Run() {" NL " g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
6489 if (!Link("#version 430 core" NL "layout(local_size_x = 2) in;" NL "void Run();" NL "void main() {" NL
6491 "#version 430 core" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
6492 " uint g_output[];" NL "};" NL "void Run() {" NL " g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
6498 bool Link(const std::string& cs0, const std::string& cs1)
6500 const GLuint p = glCreateProgram();
6504 GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
6505 glAttachShader(p, sh);
6507 const char* const src = cs0.c_str();
6508 glShaderSource(sh, 1, &src, NULL);
6509 glCompileShader(sh);
6512 glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
6513 if (status == GL_FALSE)
6516 m_context.getTestContext().getLog()
6517 << tcu::TestLog::Message << "CS0 compilation should be ok." << tcu::TestLog::EndMessage;
6523 GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
6524 glAttachShader(p, sh);
6526 const char* const src = cs1.c_str();
6527 glShaderSource(sh, 1, &src, NULL);
6528 glCompileShader(sh);
6531 glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
6532 if (status == GL_FALSE)
6535 m_context.getTestContext().getLog()
6536 << tcu::TestLog::Message << "CS1 compilation should be ok." << tcu::TestLog::EndMessage;
6544 glGetProgramInfoLog(p, sizeof(log), NULL, log);
6545 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n"
6546 << log << tcu::TestLog::EndMessage;
6549 glGetProgramiv(p, GL_LINK_STATUS, &status);
6552 if (status == GL_TRUE)
6554 m_context.getTestContext().getLog()
6555 << tcu::TestLog::Message << "Link operation should fail." << tcu::TestLog::EndMessage;
6563 class BasicWorkGroupSizeIsConst : public ComputeShaderBase
6565 virtual std::string Title()
6567 return NL "gl_WorkGroupSize is an constant";
6569 virtual std::string Purpose()
6571 return NL "Verify that gl_WorkGroupSize can be used as an constant expression.";
6573 virtual std::string Method()
6577 virtual std::string PassCriteria()
6583 GLuint m_storage_buffer;
6585 virtual long Setup()
6588 m_storage_buffer = 0;
6594 const char* const glsl_cs =
6595 NL "layout(local_size_x = 2, local_size_y = 3, local_size_z = 4) in;" NL
6596 "layout(std430, binding = 0) buffer Output {" NL " uint g_buffer[22 + gl_WorkGroupSize.x];" NL "};" NL
6597 "shared uint g_shared[gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z];" NL
6598 "uniform uint g_uniform[gl_WorkGroupSize.z + 20] = { "
6599 "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 };" NL "void main() {" NL
6600 " g_shared[gl_LocalInvocationIndex] = 1U;" NL " groupMemoryBarrier();" NL " barrier();" NL
6602 " for (uint i = 0; i < gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z; ++i) {" NL
6603 " sum += g_shared[i];" NL " }" NL " sum += g_uniform[gl_LocalInvocationIndex];" NL
6604 " g_buffer[gl_LocalInvocationIndex] = sum;" NL "}";
6605 m_program = CreateComputeProgram(glsl_cs);
6606 glLinkProgram(m_program);
6607 if (!CheckProgram(m_program))
6610 glGenBuffers(1, &m_storage_buffer);
6611 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
6612 glBufferData(GL_SHADER_STORAGE_BUFFER, 24 * sizeof(GLuint), NULL, GL_STATIC_DRAW);
6614 glUseProgram(m_program);
6615 glDispatchCompute(1, 1, 1);
6616 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
6618 long error = NO_ERROR;
6620 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
6622 static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * 24, GL_MAP_READ_BIT));
6623 for (GLuint i = 0; i < 24; ++i)
6625 if (data[i] != (i + 25))
6627 m_context.getTestContext().getLog()
6628 << tcu::TestLog::Message << "Data at index " << i << " is " << data[i] << " should be " << i + 25
6629 << "." << tcu::TestLog::EndMessage;
6633 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
6634 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
6638 virtual long Cleanup()
6641 glDeleteProgram(m_program);
6642 glDeleteBuffers(1, &m_storage_buffer);
6647 } // anonymous namespace
6649 ComputeShaderTests::ComputeShaderTests(deqp::Context& context) : TestCaseGroup(context, "compute_shader", "")
6653 ComputeShaderTests::~ComputeShaderTests(void)
6657 void ComputeShaderTests::init()
6659 using namespace deqp;
6660 addChild(new TestSubcase(m_context, "simple-compute", TestSubcase::Create<SimpleCompute>));
6661 addChild(new TestSubcase(m_context, "one-work-group", TestSubcase::Create<BasicOneWorkGroup>));
6662 addChild(new TestSubcase(m_context, "resource-ubo", TestSubcase::Create<BasicResourceUBO>));
6663 addChild(new TestSubcase(m_context, "resource-texture", TestSubcase::Create<BasicResourceTexture>));
6664 addChild(new TestSubcase(m_context, "resource-image", TestSubcase::Create<BasicResourceImage>));
6665 addChild(new TestSubcase(m_context, "resource-atomic-counter", TestSubcase::Create<BasicResourceAtomicCounter>));
6666 addChild(new TestSubcase(m_context, "resource-subroutine", TestSubcase::Create<BasicResourceSubroutine>));
6667 addChild(new TestSubcase(m_context, "resource-uniform", TestSubcase::Create<BasicResourceUniform>));
6668 addChild(new TestSubcase(m_context, "built-in-variables", TestSubcase::Create<BasicBuiltinVariables>));
6669 addChild(new TestSubcase(m_context, "max", TestSubcase::Create<BasicMax>));
6670 addChild(new TestSubcase(m_context, "work-group-size", TestSubcase::Create<BasicWorkGroupSizeIsConst>));
6671 addChild(new TestSubcase(m_context, "build-monolithic", TestSubcase::Create<BasicBuildMonolithic>));
6672 addChild(new TestSubcase(m_context, "build-separable", TestSubcase::Create<BasicBuildSeparable>));
6673 addChild(new TestSubcase(m_context, "shared-simple", TestSubcase::Create<BasicSharedSimple>));
6674 addChild(new TestSubcase(m_context, "shared-struct", TestSubcase::Create<BasicSharedStruct>));
6675 addChild(new TestSubcase(m_context, "dispatch-indirect", TestSubcase::Create<BasicDispatchIndirect>));
6676 addChild(new TestSubcase(m_context, "sso-compute-pipeline", TestSubcase::Create<BasicSSOComputePipeline>));
6677 addChild(new TestSubcase(m_context, "sso-case2", TestSubcase::Create<BasicSSOCase2>));
6678 addChild(new TestSubcase(m_context, "sso-case3", TestSubcase::Create<BasicSSOCase3>));
6679 addChild(new TestSubcase(m_context, "atomic-case1", TestSubcase::Create<BasicAtomicCase1>));
6680 addChild(new TestSubcase(m_context, "atomic-case2", TestSubcase::Create<BasicAtomicCase2>));
6681 addChild(new TestSubcase(m_context, "atomic-case3", TestSubcase::Create<BasicAtomicCase3>));
6682 addChild(new TestSubcase(m_context, "copy-image", TestSubcase::Create<AdvancedCopyImage>));
6683 addChild(new TestSubcase(m_context, "pipeline-pre-vs", TestSubcase::Create<AdvancedPipelinePreVS>));
6685 new TestSubcase(m_context, "pipeline-gen-draw-commands", TestSubcase::Create<AdvancedPipelineGenDrawCommands>));
6686 addChild(new TestSubcase(m_context, "pipeline-compute-chain", TestSubcase::Create<AdvancedPipelineComputeChain>));
6687 addChild(new TestSubcase(m_context, "pipeline-post-fs", TestSubcase::Create<AdvancedPipelinePostFS>));
6688 addChild(new TestSubcase(m_context, "pipeline-post-xfb", TestSubcase::Create<AdvancedPipelinePostXFB>));
6689 addChild(new TestSubcase(m_context, "shared-indexing", TestSubcase::Create<AdvancedSharedIndexing>));
6690 addChild(new TestSubcase(m_context, "shared-max", TestSubcase::Create<AdvancedSharedMax>));
6691 addChild(new TestSubcase(m_context, "dynamic-paths", TestSubcase::Create<AdvancedDynamicPaths>));
6692 addChild(new TestSubcase(m_context, "resources-max", TestSubcase::Create<AdvancedResourcesMax>));
6693 addChild(new TestSubcase(m_context, "fp64-case1", TestSubcase::Create<AdvancedFP64Case1>));
6694 addChild(new TestSubcase(m_context, "fp64-case2", TestSubcase::Create<AdvancedFP64Case2>));
6695 addChild(new TestSubcase(m_context, "fp64-case3", TestSubcase::Create<AdvancedFP64Case3>));
6697 new TestSubcase(m_context, "conditional-dispatching", TestSubcase::Create<AdvancedConditionalDispatching>));
6698 addChild(new TestSubcase(m_context, "api-no-active-program", TestSubcase::Create<NegativeAPINoActiveProgram>));
6699 addChild(new TestSubcase(m_context, "api-work-group-count", TestSubcase::Create<NegativeAPIWorkGroupCount>));
6700 addChild(new TestSubcase(m_context, "api-indirect", TestSubcase::Create<NegativeAPIIndirect>));
6701 addChild(new TestSubcase(m_context, "api-program", TestSubcase::Create<NegativeAPIProgram>));
6703 new TestSubcase(m_context, "glsl-compile-time-errors", TestSubcase::Create<NegativeGLSLCompileTimeErrors>));
6704 addChild(new TestSubcase(m_context, "glsl-link-time-errors", TestSubcase::Create<NegativeGLSLLinkTimeErrors>));
6706 } // gl4cts namespace