| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2014-2016 The Khronos Group Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ /*! |
| * \file |
| * \brief |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "gl4cShaderStorageBufferObjectTests.hpp" |
| #include "glwEnums.hpp" |
| #include "tcuMatrix.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include <assert.h> |
| #include <cmath> |
| #include <cstdarg> |
| |
| namespace gl4cts |
| { |
| using namespace glw; |
| |
| namespace |
| { |
| typedef tcu::Vec2 vec2; |
| typedef tcu::Vec3 vec3; |
| typedef tcu::Vec4 vec4; |
| typedef tcu::IVec4 ivec4; |
| typedef tcu::UVec4 uvec4; |
| typedef tcu::Mat4 mat4; |
| |
| enum ShaderStage |
| { |
| vertex, |
| fragment, |
| compute |
| }; |
| |
| enum BufferLayout |
| { |
| std140, |
| std430, |
| shared, |
| packed |
| }; |
| |
| enum ElementType |
| { |
| vector, |
| matrix_cm, |
| matrix_rm, |
| structure |
| }; |
| |
| enum BindingSeq |
| { |
| bindbasebefore, |
| bindbaseafter, |
| bindrangeoffset, |
| bindrangesize |
| }; |
| |
| const char* const kGLSLVer = "#version 430 core\n"; |
| |
| class ShaderStorageBufferObjectBase : public deqp::SubcaseBase |
| { |
| virtual std::string Title() |
| { |
| return ""; |
| } |
| |
| virtual std::string Purpose() |
| { |
| return ""; |
| } |
| |
| virtual std::string Method() |
| { |
| return ""; |
| } |
| |
| virtual std::string PassCriteria() |
| { |
| return ""; |
| } |
| |
| public: |
| bool SupportedInVS(int requiredVS) |
| { |
| GLint blocksVS; |
| glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &blocksVS); |
| if (blocksVS >= requiredVS) |
| return true; |
| else |
| { |
| std::ostringstream reason; |
| reason << "Required " << requiredVS << " VS storage blocks but only " << blocksVS << " available." |
| << std::endl; |
| OutputNotSupported(reason.str()); |
| return false; |
| } |
| } |
| |
| bool SupportedInTCS(int requiredTCS) |
| { |
| GLint blocksTCS; |
| glGetIntegerv(GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, &blocksTCS); |
| if (blocksTCS >= requiredTCS) |
| return true; |
| else |
| { |
| std::ostringstream reason; |
| reason << "Required " << requiredTCS << " TCS storage blocks but only " << blocksTCS << " available." |
| << std::endl; |
| OutputNotSupported(reason.str()); |
| return false; |
| } |
| } |
| |
| bool SupportedInTES(int requiredTES) |
| { |
| GLint blocksTES; |
| glGetIntegerv(GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, &blocksTES); |
| if (blocksTES >= requiredTES) |
| return true; |
| else |
| { |
| std::ostringstream reason; |
| reason << "Required " << requiredTES << " TES storage blocks but only " << blocksTES << " available." |
| << std::endl; |
| OutputNotSupported(reason.str()); |
| return false; |
| } |
| } |
| |
| bool SupportedInGS(int requiredGS) |
| { |
| GLint blocksGS; |
| glGetIntegerv(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, &blocksGS); |
| if (blocksGS >= requiredGS) |
| return true; |
| else |
| { |
| std::ostringstream reason; |
| reason << "Required " << requiredGS << " GS storage blocks but only " << blocksGS << " available." |
| << std::endl; |
| OutputNotSupported(reason.str()); |
| return false; |
| } |
| } |
| |
| int getWindowWidth() |
| { |
| const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); |
| return renderTarget.getWidth(); |
| } |
| |
| int getWindowHeight() |
| { |
| const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); |
| return renderTarget.getHeight(); |
| } |
| |
| inline bool ColorEqual(const vec3& c0, const vec3& c1, const vec4& epsilon) |
| { |
| if (fabs(c0[0] - c1[0]) > epsilon[0]) |
| return false; |
| if (fabs(c0[1] - c1[1]) > epsilon[1]) |
| return false; |
| if (fabs(c0[2] - c1[2]) > epsilon[2]) |
| return false; |
| return true; |
| } |
| |
| bool CheckProgram(GLuint program) |
| { |
| GLint status; |
| glGetProgramiv(program, GL_LINK_STATUS, &status); |
| |
| if (status == GL_FALSE) |
| { |
| GLint attached_shaders; |
| glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders); |
| |
| if (attached_shaders > 0) |
| { |
| std::vector<GLuint> shaders(attached_shaders); |
| glGetAttachedShaders(program, attached_shaders, NULL, &shaders[0]); |
| |
| for (GLint i = 0; i < attached_shaders; ++i) |
| { |
| GLenum type; |
| glGetShaderiv(shaders[i], GL_SHADER_TYPE, reinterpret_cast<GLint*>(&type)); |
| |
| switch (type) |
| { |
| case GL_VERTEX_SHADER: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Vertex Shader ***" << tcu::TestLog::EndMessage; |
| break; |
| case GL_TESS_CONTROL_SHADER: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Tessellation Control Shader ***" |
| << tcu::TestLog::EndMessage; |
| break; |
| case GL_TESS_EVALUATION_SHADER: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Tessellation Evaluation Shader ***" |
| << tcu::TestLog::EndMessage; |
| break; |
| case GL_GEOMETRY_SHADER: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Geometry Shader ***" << tcu::TestLog::EndMessage; |
| break; |
| case GL_FRAGMENT_SHADER: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Fragment Shader ***" << tcu::TestLog::EndMessage; |
| break; |
| case GL_COMPUTE_SHADER: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Compute Shader ***" << tcu::TestLog::EndMessage; |
| break; |
| default: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Unknown Shader ***" << tcu::TestLog::EndMessage; |
| break; |
| } |
| |
| GLint length; |
| glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &length); |
| if (length > 0) |
| { |
| std::vector<GLchar> source(length); |
| glGetShaderSource(shaders[i], length, NULL, &source[0]); |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << &source[0] << tcu::TestLog::EndMessage; |
| } |
| glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &length); |
| if (length > 0) |
| { |
| std::vector<GLchar> log(length); |
| glGetShaderInfoLog(shaders[i], length, NULL, &log[0]); |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage; |
| } |
| } |
| } |
| GLint length; |
| glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); |
| if (length > 0) |
| { |
| std::vector<GLchar> log(length); |
| glGetProgramInfoLog(program, length, NULL, &log[0]); |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage; |
| } |
| } |
| |
| return status == GL_TRUE ? true : false; |
| } |
| |
| GLuint CreateProgram(const std::string& vs, const std::string& tcs, const std::string& tes, const std::string& gs, |
| const std::string& fs) |
| { |
| const GLuint p = glCreateProgram(); |
| if (!vs.empty()) |
| { |
| const GLuint sh = glCreateShader(GL_VERTEX_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, vs.c_str() }; |
| glShaderSource(sh, 2, src, NULL); |
| glCompileShader(sh); |
| } |
| if (!tcs.empty()) |
| { |
| const GLuint sh = glCreateShader(GL_TESS_CONTROL_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, tcs.c_str() }; |
| glShaderSource(sh, 2, src, NULL); |
| glCompileShader(sh); |
| } |
| if (!tes.empty()) |
| { |
| const GLuint sh = glCreateShader(GL_TESS_EVALUATION_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, tes.c_str() }; |
| glShaderSource(sh, 2, src, NULL); |
| glCompileShader(sh); |
| } |
| if (!gs.empty()) |
| { |
| const GLuint sh = glCreateShader(GL_GEOMETRY_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, gs.c_str() }; |
| glShaderSource(sh, 2, src, NULL); |
| glCompileShader(sh); |
| } |
| if (!fs.empty()) |
| { |
| const GLuint sh = glCreateShader(GL_FRAGMENT_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, fs.c_str() }; |
| glShaderSource(sh, 2, src, NULL); |
| glCompileShader(sh); |
| } |
| return p; |
| } |
| |
| GLuint CreateProgram(const std::string& vs, const std::string& fs) |
| { |
| const GLuint p = glCreateProgram(); |
| |
| if (!vs.empty()) |
| { |
| const GLuint sh = glCreateShader(GL_VERTEX_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, vs.c_str() }; |
| glShaderSource(sh, 2, src, NULL); |
| glCompileShader(sh); |
| } |
| if (!fs.empty()) |
| { |
| const GLuint sh = glCreateShader(GL_FRAGMENT_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, fs.c_str() }; |
| glShaderSource(sh, 2, src, NULL); |
| glCompileShader(sh); |
| } |
| |
| return p; |
| } |
| |
| GLuint CreateProgramCS(const std::string& cs) |
| { |
| const GLuint p = glCreateProgram(); |
| |
| if (!cs.empty()) |
| { |
| const GLuint sh = glCreateShader(GL_COMPUTE_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, cs.c_str() }; |
| glShaderSource(sh, 2, src, NULL); |
| glCompileShader(sh); |
| } |
| return p; |
| } |
| |
| GLuint BuildShaderProgram(GLenum type, const std::string& source) |
| { |
| if (type == GL_COMPUTE_SHADER) |
| { |
| const char* const src[3] = { kGLSLVer, "#extension GL_ARB_compute_shader : require\n", source.c_str() }; |
| return glCreateShaderProgramv(type, 3, src); |
| } |
| |
| const char* const src[2] = { kGLSLVer, source.c_str() }; |
| return glCreateShaderProgramv(type, 2, src); |
| } |
| |
| bool ValidateReadBuffer(int x, int y, int w, int h, const vec3& expected) |
| { |
| const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); |
| const tcu::PixelFormat& pixelFormat = renderTarget.getPixelFormat(); |
| vec4 g_color_eps = vec4( |
| 1.f / static_cast<float>(1 << pixelFormat.redBits), 1.f / static_cast<float>(1 << pixelFormat.greenBits), |
| 1.f / static_cast<float>(1 << pixelFormat.blueBits), 1.f / static_cast<float>(1 << pixelFormat.alphaBits)); |
| |
| std::vector<vec3> display(w * h); |
| glReadPixels(x, y, w, h, GL_RGB, GL_FLOAT, &display[0]); |
| |
| bool result = true; |
| for (int j = 0; j < h; ++j) |
| { |
| for (int i = 0; i < w; ++i) |
| { |
| if (!ColorEqual(display[j * w + i], expected, g_color_eps)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Color at (" << x + i << ", " << y + j << ") is (" |
| << display[j * w + i][0] << " " << display[j * w + i][1] << " " << display[j * w + i][2] |
| << ") should be (" << expected[0] << " " << expected[1] << " " << expected[2] << ")." |
| << tcu::TestLog::EndMessage; |
| result = false; |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| bool ValidateWindow4Quads(const vec3& lb, const vec3& rb, const vec3& rt, const vec3& lt, int* bad_pixels = NULL) |
| { |
| const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); |
| const tcu::PixelFormat& pixelFormat = renderTarget.getPixelFormat(); |
| vec4 g_color_eps = vec4( |
| 1.f / static_cast<float>(1 << pixelFormat.redBits), 1.f / static_cast<float>(1 << pixelFormat.greenBits), |
| 1.f / static_cast<float>(1 << pixelFormat.blueBits), 1.f / static_cast<float>(1 << pixelFormat.alphaBits)); |
| |
| const int width = 100; |
| const int height = 100; |
| std::vector<vec3> fb(width * height); |
| glReadPixels(0, 0, width, height, GL_RGB, GL_FLOAT, &fb[0]); |
| |
| bool status = true; |
| int bad = 0; |
| |
| // left-bottom quad |
| for (int y = 10; y < height / 2 - 10; ++y) |
| { |
| for (int x = 10; x < width / 2 - 10; ++x) |
| { |
| const int idx = y * width + x; |
| if (!ColorEqual(fb[idx], lb, g_color_eps)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "First bad color (" << x << ", " << y << "): " << fb[idx][0] << " " |
| << fb[idx][1] << " " << fb[idx][2] << tcu::TestLog::EndMessage; |
| status = false; |
| bad++; |
| } |
| } |
| } |
| if (!status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Left-bottom quad checking failed. Bad pixels: " << bad |
| << tcu::TestLog::EndMessage; |
| //return status; |
| } |
| // right-bottom quad |
| for (int y = 10; y < height / 2 - 10; ++y) |
| { |
| for (int x = width / 2 + 10; x < width - 10; ++x) |
| { |
| const int idx = y * width + x; |
| if (!ColorEqual(fb[idx], rb, g_color_eps)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx][0] << " " |
| << fb[idx][1] << " " << fb[idx][2] << tcu::TestLog::EndMessage; |
| status = false; |
| bad++; |
| } |
| } |
| } |
| if (!status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "right-bottom quad checking failed. Bad pixels: " << bad |
| << tcu::TestLog::EndMessage; |
| //return status; |
| } |
| // right-top quad |
| for (int y = height / 2 + 10; y < height - 10; ++y) |
| { |
| for (int x = width / 2 + 10; x < width - 10; ++x) |
| { |
| const int idx = y * width + x; |
| if (!ColorEqual(fb[idx], rt, g_color_eps)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx][0] << " " |
| << fb[idx][1] << " " << fb[idx][2] << tcu::TestLog::EndMessage; |
| status = false; |
| bad++; |
| } |
| } |
| } |
| if (!status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "right-top quad checking failed. Bad pixels: " << bad |
| << tcu::TestLog::EndMessage; |
| //return status; |
| } |
| // left-top quad |
| for (int y = height / 2 + 10; y < height - 10; ++y) |
| { |
| for (int x = 10; x < width / 2 - 10; ++x) |
| { |
| const int idx = y * width + x; |
| if (!ColorEqual(fb[idx], lt, g_color_eps)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx][0] << " " |
| << fb[idx][1] << " " << fb[idx][2] << tcu::TestLog::EndMessage; |
| status = false; |
| bad++; |
| } |
| } |
| } |
| if (!status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "left-top quad checking failed. Bad pixels: " << bad |
| << tcu::TestLog::EndMessage; |
| //return status; |
| } |
| // middle horizontal line should be black |
| for (int y = height / 2 - 2; y < height / 2 + 2; ++y) |
| { |
| for (int x = 0; x < width; ++x) |
| { |
| const int idx = y * width + x; |
| if (!ColorEqual(fb[idx], vec3(0), g_color_eps)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx][0] << " " |
| << fb[idx][1] << " " << fb[idx][2] << tcu::TestLog::EndMessage; |
| status = false; |
| bad++; |
| } |
| } |
| } |
| if (!status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "middle horizontal line checking failed. Bad pixels: " << bad |
| << tcu::TestLog::EndMessage; |
| //return status; |
| } |
| // middle vertical line should be black |
| for (int y = 0; y < height; ++y) |
| { |
| for (int x = width / 2 - 2; x < width / 2 + 2; ++x) |
| { |
| const int idx = y * width + x; |
| if (!ColorEqual(fb[idx], vec3(0), g_color_eps)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx][0] << " " |
| << fb[idx][1] << " " << fb[idx][2] << tcu::TestLog::EndMessage; |
| status = false; |
| bad++; |
| } |
| } |
| } |
| if (!status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "middle vertical line checking failed. Bad pixels: " << bad |
| << tcu::TestLog::EndMessage; |
| //return status; |
| } |
| |
| if (bad_pixels) |
| *bad_pixels = bad; |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Bad pixels: " << (bad_pixels == NULL ? 0 : *bad_pixels) |
| << ", counted bad: " << bad << tcu::TestLog::EndMessage; |
| return status; |
| } |
| |
| const mat4 Translation(float tx, float ty, float tz) |
| { |
| float d[] = { 1.0f, 0.0f, 0.0f, tx, 0.0f, 1.0f, 0.0f, ty, 0.0f, 0.0f, 1.0f, tz, 0.0f, 0.0f, 0.0f, 1.0f }; |
| return mat4(d); |
| } |
| |
| const char* GLenumToString(GLenum e) |
| { |
| switch (e) |
| { |
| case GL_SHADER_STORAGE_BUFFER_BINDING: |
| return "GL_SHADER_STORAGE_BUFFER_BINDING"; |
| case GL_SHADER_STORAGE_BUFFER_START: |
| return "GL_SHADER_STORAGE_BUFFER_START"; |
| case GL_SHADER_STORAGE_BUFFER_SIZE: |
| return "GL_SHADER_STORAGE_BUFFER_SIZE"; |
| case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: |
| return "GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS"; |
| case GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS: |
| return "GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS"; |
| case GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS: |
| return "GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS"; |
| case GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS: |
| return "GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS"; |
| case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS: |
| return "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS"; |
| case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: |
| return "GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS"; |
| case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: |
| return "GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS"; |
| case GL_MAX_SHADER_STORAGE_BLOCK_SIZE: |
| return "GL_MAX_SHADER_STORAGE_BLOCK_SIZE"; |
| case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: |
| return "GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS"; |
| case GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES: |
| return "GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES"; |
| case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: |
| return "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT"; |
| |
| default: |
| assert(0); |
| break; |
| } |
| return NULL; |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.1 BasicBasic |
| //----------------------------------------------------------------------------- |
| |
| class BasicBasic : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_program; |
| GLuint m_buffer; |
| GLuint m_vertex_array; |
| |
| bool RunIteration(GLuint index) |
| { |
| glClear(GL_COLOR_BUFFER_BIT); |
| glShaderStorageBlockBinding(m_program, 0, index); |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, index, m_buffer); |
| glDrawArraysInstancedBaseInstance(GL_TRIANGLES, 0, 3, 1, 0); |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, index, 0); |
| |
| return ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)); |
| } |
| |
| virtual long Setup() |
| { |
| m_program = 0; |
| m_buffer = 0; |
| m_vertex_array = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| if (!SupportedInVS(1)) |
| return NOT_SUPPORTED; |
| |
| const char* const glsl_vs = |
| NL "layout(std430, binding = 1) buffer InputBuffer {" NL " vec4 position[3];" NL "} g_input_buffer;" NL |
| "void main() {" NL " gl_Position = g_input_buffer.position[gl_VertexID];" NL "}"; |
| |
| const char* const glsl_fs = NL "layout(location = 0) out vec4 o_color;" NL "void main() {" NL |
| " o_color = vec4(0.0, 1.0, 0.0, 1.0);" NL "}"; |
| |
| m_program = CreateProgram(glsl_vs, glsl_fs); |
| glLinkProgram(m_program); |
| if (!CheckProgram(m_program)) |
| return ERROR; |
| |
| const float data[12] = { -1.0f, -1.0f, 0.0f, 1.0f, 3.0f, -1.0f, 0.0f, 1.0f, -1.0f, 3.0f, 0.0f, 1.0f }; |
| glGenBuffers(1, &m_buffer); |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_STATIC_DRAW); |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); |
| |
| glGenVertexArrays(1, &m_vertex_array); |
| glBindVertexArray(m_vertex_array); |
| |
| glUseProgram(m_program); |
| |
| for (GLuint i = 0; i < 8; ++i) |
| { |
| if (!RunIteration(i)) |
| return ERROR; |
| } |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glUseProgram(0); |
| glDeleteProgram(m_program); |
| glDeleteBuffers(1, &m_buffer); |
| glDeleteVertexArrays(1, &m_vertex_array); |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicBasicCS : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_program; |
| GLuint m_buffer; |
| |
| virtual long Setup() |
| { |
| m_program = 0; |
| m_buffer = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| const char* const glsl_cs = NL "layout(local_size_x = 1) in;" NL "buffer Buffer {" NL " int result;" NL "};" NL |
| "void main() {" NL " result = 7;" NL "}"; |
| m_program = CreateProgramCS(glsl_cs); |
| glLinkProgram(m_program); |
| if (!CheckProgram(m_program)) |
| return ERROR; |
| |
| glGenBuffers(1, &m_buffer); |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, 4, 0, GL_STATIC_READ); |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer); |
| |
| glUseProgram(m_program); |
| glDispatchCompute(1, 1, 1); |
| glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| |
| GLint* out_data = (GLint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4, GL_MAP_READ_BIT); |
| if (!out_data) |
| return ERROR; |
| if (*out_data == 7) |
| return NO_ERROR; |
| else |
| return ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glUseProgram(0); |
| glDeleteProgram(m_program); |
| glDeleteBuffers(1, &m_buffer); |
| return NO_ERROR; |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.2 BasicMax |
| //----------------------------------------------------------------------------- |
| |
| class BasicMax : public ShaderStorageBufferObjectBase |
| { |
| bool Check(GLenum e, GLint64 value, bool max_value) |
| { |
| GLint i; |
| GLint64 i64; |
| GLfloat f; |
| GLdouble d; |
| GLboolean b; |
| |
| glGetIntegerv(e, &i); |
| glGetInteger64v(e, &i64); |
| glGetFloatv(e, &f); |
| glGetDoublev(e, &d); |
| glGetBooleanv(e, &b); |
| |
| bool status = true; |
| if (max_value) |
| { |
| if (static_cast<GLint64>(i) < value) |
| status = false; |
| if (i64 < value) |
| status = false; |
| if (static_cast<GLint64>(f) < value) |
| status = false; |
| if (static_cast<GLint64>(d) < value) |
| status = false; |
| |
| if (!status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " is " << i << " should be at least " |
| << static_cast<GLint>(value) << tcu::TestLog::EndMessage; |
| } |
| } |
| else |
| { |
| if (static_cast<GLint64>(i) > value) |
| status = false; |
| if (i64 > value) |
| status = false; |
| if (static_cast<GLint64>(f) > value) |
| status = false; |
| if (static_cast<GLint64>(d) > value) |
| status = false; |
| |
| if (!status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << GLenumToString(e) << " is " << i << " should be at most " |
| << static_cast<GLint>(value) << tcu::TestLog::EndMessage; |
| } |
| } |
| return status; |
| } |
| |
| virtual long Run() |
| { |
| if (!Check(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, 0, true)) |
| return ERROR; |
| if (!Check(GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, 0, true)) |
| return ERROR; |
| if (!Check(GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, 0, true)) |
| return ERROR; |
| if (!Check(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, 0, true)) |
| return ERROR; |
| if (!Check(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, 8, true)) |
| return ERROR; |
| if (!Check(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, 8, true)) |
| return ERROR; |
| if (!Check(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, 8, true)) |
| return ERROR; |
| if (!Check(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, 16777216 /* 2^24 */, true)) |
| return ERROR; |
| if (!Check(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, 8, true)) |
| return ERROR; |
| if (!Check(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, 8, true)) |
| return ERROR; |
| if (!Check(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, 256, false)) |
| return ERROR; |
| return NO_ERROR; |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.3 BasicBinding |
| //----------------------------------------------------------------------------- |
| |
| class BasicBinding : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_buffer[4]; |
| |
| bool Check(GLenum e, GLuint expected) |
| { |
| GLint i; |
| GLint64 i64; |
| GLfloat f; |
| GLdouble d; |
| GLboolean b; |
| |
| glGetIntegerv(e, &i); |
| glGetInteger64v(e, &i64); |
| glGetFloatv(e, &f); |
| glGetDoublev(e, &d); |
| glGetBooleanv(e, &b); |
| |
| bool status = true; |
| if (static_cast<GLuint>(i) != expected) |
| status = false; |
| if (static_cast<GLuint>(i64) != expected) |
| status = false; |
| if (static_cast<GLuint>(f) != expected) |
| status = false; |
| if (static_cast<GLuint>(d) != expected) |
| status = false; |
| if (b != (expected != 0 ? GL_TRUE : GL_FALSE)) |
| status = false; |
| |
| if (!status) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << GLenumToString(e) << " is " << i |
| << " should be " << expected << tcu::TestLog::EndMessage; |
| } |
| return status; |
| } |
| |
| bool CheckIndexed(GLenum e, GLuint index, GLuint expected) |
| { |
| GLint i; |
| GLint64 i64; |
| GLfloat f; |
| GLdouble d; |
| GLboolean b; |
| |
| glGetIntegeri_v(e, index, &i); |
| glGetInteger64i_v(e, index, &i64); |
| glGetFloati_v(e, index, &f); |
| glGetDoublei_v(e, index, &d); |
| glGetBooleani_v(e, index, &b); |
| |
| bool status = true; |
| if (static_cast<GLuint>(i) != expected) |
| status = false; |
| if (static_cast<GLuint>(i64) != expected) |
| status = false; |
| if (static_cast<GLuint>(f) != expected) |
| status = false; |
| if (static_cast<GLuint>(d) != expected) |
| status = false; |
| if (b != (expected != 0 ? GL_TRUE : GL_FALSE)) |
| status = false; |
| |
| if (!status) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << GLenumToString(e) << " at index " << index |
| << " is " << i << " should be " << expected << tcu::TestLog::EndMessage; |
| } |
| return status; |
| } |
| |
| virtual long Setup() |
| { |
| memset(m_buffer, 0, sizeof(m_buffer)); |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| // check default state |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, 0)) |
| return ERROR; |
| for (GLuint i = 0; i < 8; ++i) |
| { |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, i, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_START, i, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_SIZE, i, 0)) |
| return ERROR; |
| } |
| |
| glGenBuffers(4, m_buffer); |
| for (GLuint i = 0; i < 8; ++i) |
| { |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_buffer[0]); |
| |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, m_buffer[0])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, i, m_buffer[0])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_START, i, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_SIZE, i, 0)) |
| return ERROR; |
| |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, 0); |
| |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, i, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_START, i, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_SIZE, i, 0)) |
| return ERROR; |
| } |
| |
| for (GLuint i = 0; i < 8; ++i) |
| { |
| glBindBufferRange(GL_SHADER_STORAGE_BUFFER, i, m_buffer[0], 256, 512); |
| |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, m_buffer[0])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, i, m_buffer[0])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_START, i, 256)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_SIZE, i, 512)) |
| return ERROR; |
| |
| glBindBufferRange(GL_SHADER_STORAGE_BUFFER, i, 0, 512, 128); |
| |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, i, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_START, i, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_SIZE, i, 0)) |
| return ERROR; |
| |
| glBindBufferRange(GL_SHADER_STORAGE_BUFFER, i, 0, 0, 0); |
| |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, i, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_START, i, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_SIZE, i, 0)) |
| return ERROR; |
| } |
| |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[2]); |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, m_buffer[2])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, 0, m_buffer[2])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_START, 0, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_SIZE, 0, 0)) |
| return ERROR; |
| |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, m_buffer[3]); |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, m_buffer[3])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, 5, m_buffer[3])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_START, 5, 0)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_SIZE, 5, 0)) |
| return ERROR; |
| |
| glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 7, m_buffer[1], 2048, 1000); |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, m_buffer[1])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, 7, m_buffer[1])) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_START, 7, 2048)) |
| return ERROR; |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_SIZE, 7, 1000)) |
| return ERROR; |
| |
| glDeleteBuffers(4, m_buffer); |
| memset(m_buffer, 0, sizeof(m_buffer)); |
| |
| if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, 0)) |
| return ERROR; |
| for (GLuint i = 0; i < 8; ++i) |
| { |
| if (!CheckIndexed(GL_SHADER_STORAGE_BUFFER_BINDING, i, 0)) |
| return ERROR; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteBuffers(4, m_buffer); |
| return NO_ERROR; |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.4 BasicSyntax |
| //----------------------------------------------------------------------------- |
| |
| class BasicSyntax : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_program; |
| GLuint m_buffer; |
| GLuint m_vertex_array; |
| |
| bool RunIteration(const char* vs, const char* fs) |
| { |
| if (m_program != 0) |
| glDeleteProgram(m_program); |
| m_program = CreateProgram(vs, fs); |
| glLinkProgram(m_program); |
| if (!CheckProgram(m_program)) |
| return false; |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| glUseProgram(m_program); |
| glDrawArrays(GL_TRIANGLES, 0, 3); |
| |
| return ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)); |
| } |
| |
| virtual long Setup() |
| { |
| m_program = 0; |
| m_buffer = 0; |
| m_vertex_array = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| if (!SupportedInVS(1)) |
| return NOT_SUPPORTED; |
| |
| const int kCount = 8; |
| const char* const glsl_vs[kCount] = { |
| NL "layout(std430) buffer Buffer {" NL " vec4 position[3];" NL "} g_input_buffer;" NL "void main() {" NL |
| " gl_Position = g_input_buffer.position[gl_VertexID];" NL "}", |
| NL "coherent buffer Buffer {" NL " buffer vec4 position0;" NL " coherent vec4 position1;" NL |
| " restrict readonly vec4 position2;" NL "} g_input_buffer;" NL "void main() {" NL |
| " if (gl_VertexID == 0) gl_Position = g_input_buffer.position0;" NL |
| " if (gl_VertexID == 1) gl_Position = g_input_buffer.position1;" NL |
| " if (gl_VertexID == 2) gl_Position = g_input_buffer.position2;" NL "}", |
| NL "layout(std140, binding = 0) readonly buffer Buffer {" NL " readonly vec4 position[];" NL "};" NL |
| "void main() {" NL " gl_Position = position[gl_VertexID];" NL "}", |
| NL "layout(std430, column_major, std140, std430, row_major, packed, shared) buffer;" NL |
| "layout(std430) buffer;" NL "coherent restrict volatile buffer Buffer {" NL |
| " restrict coherent vec4 position[];" NL "} g_buffer;" NL "void main() {" NL |
| " gl_Position = g_buffer.position[gl_VertexID];" NL "}", |
| NL "buffer Buffer {" NL " vec4 position[3];" NL "} g_buffer[1];" NL "void main() {" NL |
| " gl_Position = g_buffer[0].position[gl_VertexID];" NL "}", |
| NL "layout(shared) coherent buffer Buffer {" NL " restrict volatile vec4 position0;" NL |
| " buffer readonly vec4 position1;" NL " vec4 position2;" NL "} g_buffer[1];" NL "void main() {" NL |
| " if (gl_VertexID == 0) gl_Position = g_buffer[0].position0;" NL |
| " else if (gl_VertexID == 1) gl_Position = g_buffer[0].position1;" NL |
| " else if (gl_VertexID == 2) gl_Position = g_buffer[0].position2;" NL "}", |
| NL "layout(packed) coherent buffer Buffer {" NL " vec4 position01[];" NL " vec4 position2;" NL |
| "} g_buffer;" NL "void main() {" NL " if (gl_VertexID == 0) gl_Position = g_buffer.position01[0];" NL |
| " else if (gl_VertexID == 1) gl_Position = g_buffer.position01[1];" NL |
| " else if (gl_VertexID == 2) gl_Position = g_buffer.position2;" NL "}", |
| NL "layout(std430) coherent buffer Buffer {" NL " coherent vec4 position01[];" NL " vec4 position2[];" NL |
| "} g_buffer;" NL "void main() {" NL " switch (gl_VertexID) {" NL |
| " case 0: gl_Position = g_buffer.position01[0]; break;" NL |
| " case 1: gl_Position = g_buffer.position01[1]; break;" NL |
| " case 2: gl_Position = g_buffer.position2[gl_VertexID - 2]; break;" NL " }" NL "}", |
| }; |
| const char* const glsl_fs = NL "layout(location = 0) out vec4 o_color;" NL "void main() {" NL |
| " o_color = vec4(0.0, 1.0, 0.0, 1.0);" NL "}"; |
| |
| // full viewport triangle |
| const float data[12] = { -1.0f, -1.0f, 0.0f, 1.0f, 3.0f, -1.0f, 0.0f, 1.0f, -1.0f, 3.0f, 0.0f, 1.0f }; |
| glGenBuffers(1, &m_buffer); |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_STATIC_DRAW); |
| |
| glGenVertexArrays(1, &m_vertex_array); |
| glBindVertexArray(m_vertex_array); |
| |
| for (int i = 0; i < kCount; ++i) |
| { |
| if (!RunIteration(glsl_vs[i], glsl_fs)) |
| return ERROR; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glUseProgram(0); |
| glDeleteProgram(m_program); |
| glDeleteBuffers(1, &m_buffer); |
| glDeleteVertexArrays(1, &m_vertex_array); |
| return NO_ERROR; |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.5 BasicSyntaxSSO |
| //----------------------------------------------------------------------------- |
| |
| class BasicSyntaxSSO : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_pipeline; |
| GLuint m_vsp, m_fsp; |
| GLuint m_buffer; |
| GLuint m_vertex_array; |
| |
| bool RunIteration(const char* vs) |
| { |
| if (m_vsp != 0) |
| glDeleteProgram(m_vsp); |
| m_vsp = BuildShaderProgram(GL_VERTEX_SHADER, vs); |
| if (!CheckProgram(m_vsp)) |
| return false; |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, m_vsp); |
| glDrawArrays(GL_TRIANGLES, 0, 3); |
| |
| return ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)); |
| } |
| |
| virtual long Setup() |
| { |
| m_pipeline = 0; |
| m_vsp = m_fsp = 0; |
| m_buffer = 0; |
| m_vertex_array = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| if (!SupportedInVS(1)) |
| return NOT_SUPPORTED; |
| const int kCount = 8; |
| const char* const glsl_vs[kCount] = { |
| NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL "};" NL "layout(std430) buffer Buffer {" NL |
| " vec4 position[3];" NL "} g_input_buffer;" NL "void main() {" NL |
| " gl_Position = g_input_buffer.position[gl_VertexID];" NL "}", |
| NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL "};" NL "coherent buffer Buffer {" NL |
| " vec4 position0;" NL " coherent vec4 position1;" NL " restrict readonly vec4 position2;" NL |
| "} g_input_buffer;" NL "void main() {" NL |
| " if (gl_VertexID == 0) gl_Position = g_input_buffer.position0;" NL |
| " if (gl_VertexID == 1) gl_Position = g_input_buffer.position1;" NL |
| " if (gl_VertexID == 2) gl_Position = g_input_buffer.position2;" NL "}", |
| NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL "};" NL |
| "layout(std140, binding = 0) readonly buffer Buffer {" NL " readonly vec4 position[];" NL "};" NL |
| "void main() {" NL " gl_Position = position[gl_VertexID];" NL "}", |
| NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL "};" NL |
| "layout(std430, column_major, std140, std430, row_major, packed, shared) buffer;" NL |
| "layout(std430) buffer;" NL "coherent restrict volatile buffer Buffer {" NL |
| " restrict coherent vec4 position[];" NL "} g_buffer;" NL "void main() {" NL |
| " gl_Position = g_buffer.position[gl_VertexID];" NL "}", |
| NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL "};" NL "buffer Buffer {" NL " vec4 position[3];" NL |
| "} g_buffer[1];" NL "void main() {" NL " gl_Position = g_buffer[0].position[gl_VertexID];" NL "}", |
| NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL "};" NL "layout(shared) coherent buffer Buffer {" NL |
| " restrict volatile vec4 position0;" NL " readonly vec4 position1;" NL " vec4 position2;" NL |
| "} g_buffer[1];" NL "void main() {" NL " if (gl_VertexID == 0) gl_Position = g_buffer[0].position0;" NL |
| " else if (gl_VertexID == 1) gl_Position = g_buffer[0].position1;" NL |
| " else if (gl_VertexID == 2) gl_Position = g_buffer[0].position2;" NL "}", |
| NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL "};" NL "layout(packed) coherent buffer Buffer {" NL |
| " vec4 position01[];" NL " vec4 position2;" NL "} g_buffer;" NL "void main() {" NL |
| " if (gl_VertexID == 0) gl_Position = g_buffer.position01[0];" NL |
| " else if (gl_VertexID == 1) gl_Position = g_buffer.position01[1];" NL |
| " else if (gl_VertexID == 2) gl_Position = g_buffer.position2;" NL "}", |
| NL "out gl_PerVertex {" NL " vec4 gl_Position;" NL "};" NL "layout(std430) coherent buffer Buffer {" NL |
| " coherent vec4 position01[];" NL " vec4 position2[];" NL "} g_buffer;" NL "void main() {" NL |
| " switch (gl_VertexID) {" NL " case 0: gl_Position = g_buffer.position01[0]; break;" NL |
| " case 1: gl_Position = g_buffer.position01[1]; break;" NL |
| " case 2: gl_Position = g_buffer.position2[gl_VertexID - 2]; break;" NL " }" NL "}", |
| }; |
| const char* const glsl_fs = NL "layout(location = 0) out vec4 o_color;" NL "void main() {" NL |
| " o_color = vec4(0.0, 1.0, 0.0, 1.0);" NL "}"; |
| m_fsp = BuildShaderProgram(GL_FRAGMENT_SHADER, glsl_fs); |
| if (!CheckProgram(m_fsp)) |
| return ERROR; |
| |
| glGenProgramPipelines(1, &m_pipeline); |
| glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, m_fsp); |
| |
| // full viewport triangle |
| const float data[12] = { -1.0f, -1.0f, 0.0f, 1.0f, 3.0f, -1.0f, 0.0f, 1.0f, -1.0f, 3.0f, 0.0f, 1.0f }; |
| glGenBuffers(1, &m_buffer); |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_STATIC_DRAW); |
| |
| glBindProgramPipeline(m_pipeline); |
| |
| glGenVertexArrays(1, &m_vertex_array); |
| glBindVertexArray(m_vertex_array); |
| |
| for (int i = 0; i < kCount; ++i) |
| { |
| if (!RunIteration(glsl_vs[i])) |
| return ERROR; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDeleteProgramPipelines(1, &m_pipeline); |
| glDeleteProgram(m_vsp); |
| glDeleteProgram(m_fsp); |
| glDeleteBuffers(1, &m_buffer); |
| glDeleteVertexArrays(1, &m_vertex_array); |
| return NO_ERROR; |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.6.x BasicStdLayoutBase |
| //----------------------------------------------------------------------------- |
| |
| class BasicStdLayoutBaseVS : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_program; |
| GLuint m_buffer[2]; |
| GLuint m_vertex_array; |
| |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) = 0; |
| |
| virtual long Setup() |
| { |
| m_program = 0; |
| memset(m_buffer, 0, sizeof(m_buffer)); |
| m_vertex_array = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| if (!SupportedInVS(2)) |
| return NOT_SUPPORTED; |
| std::vector<GLubyte> in_data; |
| const char* glsl_vs = GetInput(in_data); |
| |
| m_program = CreateProgram(glsl_vs, ""); |
| glLinkProgram(m_program); |
| if (!CheckProgram(m_program)) |
| return ERROR; |
| |
| glGenBuffers(2, m_buffer); |
| |
| // output buffer |
| std::vector<GLubyte> out_data(in_data.size()); |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[1]); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)in_data.size(), &out_data[0], GL_STATIC_DRAW); |
| |
| // input buffer |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[0]); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)in_data.size(), &in_data[0], GL_STATIC_DRAW); |
| |
| glGenVertexArrays(1, &m_vertex_array); |
| glEnable(GL_RASTERIZER_DISCARD); |
| |
| glUseProgram(m_program); |
| glBindVertexArray(m_vertex_array); |
| glDrawArrays(GL_POINTS, 0, 1); |
| |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer[1]); |
| glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)in_data.size(), &out_data[0]); |
| |
| bool status = true; |
| for (size_t i = 0; i < in_data.size(); ++i) |
| { |
| if (in_data[i] != out_data[i]) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Byte at index " << static_cast<int>(i) << " is " |
| << tcu::toHex(out_data[i]) << " should be " << tcu::toHex(in_data[i]) << tcu::TestLog::EndMessage; |
| status = false; |
| } |
| } |
| if (!status) |
| return ERROR; |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glDisable(GL_RASTERIZER_DISCARD); |
| glUseProgram(0); |
| glDeleteProgram(m_program); |
| glDeleteBuffers(2, m_buffer); |
| glDeleteVertexArrays(1, &m_vertex_array); |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicStdLayoutBaseCS : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_program; |
| GLuint m_buffer[2]; |
| |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) = 0; |
| |
| virtual long Setup() |
| { |
| m_program = 0; |
| memset(m_buffer, 0, sizeof(m_buffer)); |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| std::vector<GLubyte> in_data; |
| std::stringstream ss; |
| ss << "layout(local_size_x = 1) in;\n" << GetInput(in_data); |
| |
| m_program = CreateProgramCS(ss.str()); |
| glLinkProgram(m_program); |
| if (!CheckProgram(m_program)) |
| return ERROR; |
| |
| glGenBuffers(2, m_buffer); |
| |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[0]); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)in_data.size(), &in_data[0], GL_STATIC_DRAW); |
| std::vector<GLubyte> out_d(in_data.size()); |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[1]); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)out_d.size(), &out_d[0], GL_STATIC_DRAW); |
| |
| glUseProgram(m_program); |
| glDispatchCompute(1, 1, 1); |
| |
| glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| GLubyte* out_data = |
| (GLubyte*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, (GLsizeiptr)in_data.size(), GL_MAP_READ_BIT); |
| if (!out_data) |
| return ERROR; |
| |
| bool status = true; |
| |
| for (size_t i = 0; i < in_data.size(); ++i) |
| { |
| if (in_data[i] != out_data[i]) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Byte at index " << static_cast<int>(i) << " is " |
| << tcu::toHex(out_data[i]) << " should be " << tcu::toHex(in_data[i]) << tcu::TestLog::EndMessage; |
| status = false; |
| } |
| } |
| glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
| if (!status) |
| return ERROR; |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glUseProgram(0); |
| glDeleteProgram(m_program); |
| glDeleteBuffers(2, m_buffer); |
| return NO_ERROR; |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.6.1 BasicStd430LayoutCase1 |
| //----------------------------------------------------------------------------- |
| const char* GetInput430c1(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(6 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| int* ip = reinterpret_cast<int*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 2.0f; |
| fp[2] = 3.0f; |
| fp[3] = 4.0f; |
| ip[4] = 5; |
| ip[5] = 6; |
| |
| return NL "layout(std430, binding = 0) buffer Input {" NL " float data0;" NL " float data1[3];" NL |
| " ivec2 data2;" NL "} g_input;" NL "layout(std430, binding = 1) buffer Output {" NL " float data0;" NL |
| " float data1[3];" NL " ivec2 data2;" NL "} g_output;" NL "void main() {" NL |
| " g_output.data0 = g_input.data0;" NL |
| " for (int i = 0; i < g_input.data1.length(); ++i) g_output.data1[i] = g_input.data1[i];" NL |
| " g_output.data2 = g_input.data2;" NL "}"; |
| } |
| |
| class BasicStd430LayoutCase1VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c1(in_data); |
| } |
| }; |
| |
| class BasicStd430LayoutCase1CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c1(in_data); |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.6.2 BasicStd430LayoutCase2 |
| //----------------------------------------------------------------------------- |
| const char* GetInput430c2(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(20 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 2.0f; |
| fp[2] = 3.0f; |
| fp[3] = 4.0f; |
| fp[4] = 5.0f; |
| fp[5] = 6.0f; |
| fp[8] = 7.0f; |
| fp[9] = 8.0f; |
| fp[10] = 9.0f; |
| fp[12] = 10.0f; |
| fp[13] = 11.0f; |
| fp[14] = 12.0f; |
| fp[16] = 13.0f; |
| |
| return NL "layout(std430, binding = 0) buffer Input {" NL " float data0;" NL " float data1[3];" NL |
| " vec2 data2;" NL " readonly vec3 data3[2];" NL " float data4;" NL "} g_input;" NL |
| "layout(std430, binding = 1) buffer Output {" NL " float data0;" NL " float data1[3];" NL |
| " vec2 data2;" NL " vec3 data3[2];" NL " float data4;" NL "} g_output;" NL "void main() {" NL |
| " g_output.data0 = g_input.data0;" NL |
| " for (int i = 0; i < g_input.data1.length(); ++i) g_output.data1[i] = g_input.data1[i];" NL |
| " g_output.data2 = g_input.data2;" NL |
| " for (int i = 0; i < g_input.data3.length(); ++i) g_output.data3[i] = g_input.data3[i];" NL |
| " g_output.data4 = g_input.data4;" NL "}"; |
| } |
| |
| class BasicStd430LayoutCase2VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c2(in_data); |
| } |
| }; |
| |
| class BasicStd430LayoutCase2CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c2(in_data); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.6.3 BasicStd430LayoutCase3 |
| //----------------------------------------------------------------------------- |
| const char* GetInput430c3(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(16 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 2.0f; |
| fp[2] = 3.0f; |
| fp[3] = 0.0f; |
| fp[4] = 4.0f; |
| fp[5] = 5.0f; |
| fp[6] = 6.0f; |
| fp[7] = 0.0f; |
| fp[8] = 7.0f; |
| fp[9] = 8.0f; |
| fp[10] = 9.0f; |
| fp[11] = 10.0f; |
| fp[12] = 11.0f; |
| fp[13] = 12.0f; |
| fp[14] = 13.0f; |
| fp[15] = 14.0f; |
| |
| return NL "layout(std430, binding = 0) buffer Input {" NL " layout(column_major) mat2x3 data0;" NL |
| " layout(row_major) mat4x2 data1;" NL "} g_input;" NL "layout(std430, binding = 1) buffer Output {" NL |
| " layout(column_major) mat2x3 data0;" NL " layout(row_major) mat4x2 data1;" NL "} g_output;" NL |
| "void main() {" NL " g_output.data0 = g_input.data0;" NL " g_output.data1 = g_input.data1;" NL "}"; |
| } |
| |
| class BasicStd430LayoutCase3VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c3(in_data); |
| } |
| }; |
| |
| class BasicStd430LayoutCase3CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c3(in_data); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.6.4 BasicStd430LayoutCase4 |
| //----------------------------------------------------------------------------- |
| const char* GetInput430c4(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(20 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 2.0f; |
| fp[2] = 3.0f; |
| fp[3] = 4.0f; |
| fp[4] = 5.0f; |
| fp[5] = 6.0f; |
| fp[6] = 7.0f; |
| fp[7] = 8.0f; |
| fp[8] = 9.0f; |
| fp[9] = 10.0f; |
| fp[10] = 11.0f; |
| fp[12] = 12.0f; |
| fp[13] = 13.0f; |
| fp[14] = 14.0f; |
| fp[16] = 15.0f; |
| |
| return NL "layout(std430, binding = 0) buffer Input {" NL " mat4x2 data0;" NL " mat2x3 data1;" NL |
| " float data2;" NL "} g_input;" NL "layout(std430, binding = 1) buffer Output {" NL " mat4x2 data0;" NL |
| " mat2x3 data1;" NL " float data2;" NL "} g_output;" NL "void main() {" NL |
| " g_output.data0 = g_input.data0;" NL " g_output.data1 = g_input.data1;" NL |
| " g_output.data2 = g_input.data2;" NL "}"; |
| } |
| |
| class BasicStd430LayoutCase4VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c4(in_data); |
| } |
| }; |
| |
| class BasicStd430LayoutCase4CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c4(in_data); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.6.5 BasicStd430LayoutCase5 |
| //----------------------------------------------------------------------------- |
| const char* GetInput430c5(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(8 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 3.0f; |
| fp[2] = 5.0f; |
| fp[3] = 7.0f; |
| fp[4] = 2.0f; |
| fp[5] = 4.0f; |
| fp[6] = 6.0f; |
| fp[7] = 8.0f; |
| |
| return NL "layout(std430, binding = 0, row_major) buffer Input {" NL " mat4x2 data0;" NL "} g_input;" NL |
| "layout(std430, binding = 1, row_major) buffer Output {" NL " mat4x2 data0;" NL "} g_output;" NL |
| "void main() {" NL " g_output.data0 = g_input.data0;" NL "}"; |
| } |
| |
| class BasicStd430LayoutCase5VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c5(in_data); |
| } |
| }; |
| |
| class BasicStd430LayoutCase5CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c5(in_data); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.6.6 BasicStd430LayoutCase6 |
| //----------------------------------------------------------------------------- |
| const char* GetInput430c6(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(92 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 2.0f; |
| fp[2] = 3.0f; |
| fp[3] = 4.0f; |
| fp[4] = 5.0f; |
| fp[5] = 0.0f; |
| fp[6] = 6.0f; |
| fp[7] = 7.0f; |
| fp[8] = 8.0f; |
| fp[9] = 9.0f; |
| fp[10] = 10.0f; |
| fp[11] = 11.0f; |
| fp[12] = 12.0f; |
| fp[13] = 0.0f; |
| fp[14] = 0.0f; |
| fp[15] = 0.0f; |
| fp[16] = 13.0f; |
| fp[17] = 14.0f; |
| fp[18] = 15.0f; |
| fp[19] = 0.0f; |
| fp[20] = 16.0f; |
| fp[21] = 17.0f; |
| fp[22] = 18.0f; |
| fp[23] = 0.0f; |
| fp[24] = 19.0f; |
| fp[25] = 20.0f; |
| fp[26] = 21.0f; |
| fp[27] = 22.0f; |
| fp[28] = 23.0f; |
| fp[29] = 24.0f; |
| fp[30] = 25.0f; |
| fp[31] = 26.0f; |
| fp[32] = 27.0f; |
| fp[33] = 28.0f; |
| fp[34] = 0.0f; |
| fp[35] = 0.0f; |
| fp[36] = 29.0f; |
| fp[37] = 30.0f; |
| fp[38] = 31.0f; |
| fp[39] = 0.0f; |
| fp[40] = 32.0f; |
| fp[41] = 33.0f; |
| fp[42] = 34.0f; |
| fp[43] = 0.0f; |
| fp[44] = 35.0f; |
| fp[45] = 36.0f; |
| fp[46] = 37.0f; |
| fp[47] = 0.0f; |
| fp[48] = 38.0f; |
| fp[49] = 39.0f; |
| fp[50] = 40.0f; |
| fp[51] = 0.0f; |
| fp[52] = 41.0f; |
| fp[53] = 42.0f; |
| fp[54] = 43.0f; |
| fp[55] = 0.0f; |
| fp[56] = 44.0f; |
| fp[57] = 45.0f; |
| fp[58] = 46.0f; |
| fp[59] = 0.0f; |
| fp[60] = 47.0f; |
| fp[61] = 48.0f; |
| fp[62] = 49.0f; |
| fp[63] = 50.0f; |
| fp[64] = 51.0f; |
| fp[65] = 52.0f; |
| fp[66] = 53.0f; |
| fp[67] = 54.0f; |
| fp[68] = 55.0f; |
| fp[69] = 56.0f; |
| fp[70] = 57.0f; |
| fp[71] = 58.0f; |
| fp[72] = 59.0f; |
| fp[73] = 60.0f; |
| fp[74] = 61.0f; |
| fp[75] = 62.0f; |
| fp[76] = 63.0f; |
| fp[77] = 64.0f; |
| fp[78] = 65.0f; |
| fp[79] = 66.0f; |
| fp[80] = 67.0f; |
| fp[81] = 68.0f; |
| fp[82] = 69.0f; |
| fp[83] = 70.0f; |
| fp[84] = 71.0f; |
| fp[85] = 72.0f; |
| fp[86] = 73.0f; |
| fp[87] = 74.0f; |
| fp[88] = 75.0f; |
| fp[89] = 76.0f; |
| fp[90] = 77.0f; |
| fp[91] = 78.0f; |
| |
| return NL "layout(std430, binding = 0) buffer Input {" NL " float data0[2];" NL " float data1[3];" NL |
| " vec2 data2;" NL " float data3[5];" NL " vec3 data4[2];" NL " float data5[2];" NL |
| " mat2 data6[2];" NL " mat3 data7[2];" NL " mat4 data8[2];" NL "} g_input;" NL |
| "layout(std430, binding = 1) buffer Output {" NL " float data0[2];" NL " float data1[3];" NL |
| " vec2 data2;" NL " float data3[5];" NL " vec3 data4[2];" NL " float data5[2];" NL |
| " mat2 data6[2];" NL " mat3 data7[2];" NL " mat4 data8[2];" NL "} g_output;" NL "void main() {" NL |
| " for (int i = 0; i < g_input.data0.length(); ++i) g_output.data0[i] = g_input.data0[i];" NL |
| " for (int i = 0; i < g_input.data1.length(); ++i) g_output.data1[i] = g_input.data1[i];" NL |
| " g_output.data2 = g_input.data2;" NL |
| " for (int i = 0; i < g_input.data3.length(); ++i) g_output.data3[i] = g_input.data3[i];" NL |
| " for (int i = 0; i < g_input.data4.length(); ++i) g_output.data4[i] = g_input.data4[i];" NL |
| " for (int i = 0; i < g_input.data5.length(); ++i) g_output.data5[i] = g_input.data5[i];" NL |
| " for (int i = 0; i < g_input.data6.length(); ++i) g_output.data6[i] = g_input.data6[i];" NL |
| " for (int i = 0; i < g_input.data7.length(); ++i) g_output.data7[i] = g_input.data7[i];" NL |
| " for (int i = 0; i < g_input.data8.length(); ++i) g_output.data8[i] = g_input.data8[i];" NL "}"; |
| } |
| |
| class BasicStd430LayoutCase6VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c6(in_data); |
| } |
| }; |
| |
| class BasicStd430LayoutCase6CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c6(in_data); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.6.7 BasicStd430LayoutCase7 |
| //----------------------------------------------------------------------------- |
| const char* GetInput430c7(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(36 * 4); |
| int* ip = reinterpret_cast<int*>(&in_data[0]); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| ip[0] = 1; |
| ip[1] = 0; |
| ip[2] = 2; |
| ip[3] = 3; |
| fp[4] = 4.0f; |
| fp[5] = 0.0f; |
| fp[6] = 0.0f; |
| fp[7] = 0.0f; |
| fp[8] = 5.0f; |
| fp[9] = 6.0f; |
| fp[10] = 7.0f; |
| fp[11] = 0.0f; |
| fp[12] = 8.0f; |
| fp[13] = 0.0f; |
| fp[14] = 0.0f; |
| fp[15] = 0.0f; |
| fp[16] = 9.0f; |
| fp[17] = 10.0f; |
| fp[18] = 11.0f; |
| fp[19] = 0.0f; |
| ip[20] = 12; |
| ip[21] = 13; |
| ip[22] = 14; |
| ip[23] = 15; |
| fp[24] = 16.0f; |
| fp[25] = 0.0f; |
| fp[26] = 0.0f; |
| fp[27] = 0.0f; |
| fp[28] = 17.0f; |
| fp[29] = 18.0f; |
| fp[30] = 19.0f; |
| fp[31] = 0.0f; |
| ip[32] = 20; |
| ip[33] = 21; |
| ip[34] = 22; |
| ip[35] = 23; |
| |
| return NL "struct Struct0 {" NL " ivec2 m0;" NL "};" NL "struct Struct1 {" NL " vec3 m0;" NL "};" NL |
| "struct Struct3 {" NL " int m0;" NL "};" NL "struct Struct2 {" NL " float m0;" NL " Struct1 m1;" NL |
| " Struct0 m2;" NL " int m3;" NL " Struct3 m4;" NL "};" NL |
| "layout(std430, binding = 0) buffer Input {" NL " int data0;" NL " Struct0 data1;" NL |
| " float data2;" NL " Struct1 data3;" NL " Struct2 data4[2];" NL "} g_input;" NL |
| "layout(std430, binding = 1) buffer Output {" NL " int data0;" NL " Struct0 data1;" NL |
| " float data2;" NL " Struct1 data3;" NL " Struct2 data4[2];" NL "} g_output;" NL "void main() {" NL |
| " g_output.data0 = g_input.data0;" NL " g_output.data1 = g_input.data1;" NL |
| " g_output.data2 = g_input.data2;" NL " g_output.data3 = g_input.data3;" NL |
| " for (int i = 0; i < g_input.data4.length(); ++i) g_output.data4[i] = g_input.data4[i];" NL "}"; |
| } |
| |
| class BasicStd430LayoutCase7VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c7(in_data); |
| } |
| }; |
| |
| class BasicStd430LayoutCase7CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput430c7(in_data); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.7.1 BasicStd140LayoutCase1 |
| //----------------------------------------------------------------------------- |
| const char* GetInput140c1(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(8 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 0.0f; |
| fp[2] = 0.0f; |
| fp[3] = 0.0f; |
| fp[4] = 2.0f; |
| |
| return NL "layout(std140, binding = 0) buffer Input {" NL " float data0[2];" NL "} g_input;" NL |
| "layout(std140, binding = 1) buffer Output {" NL " float data0[2];" NL "} g_output;" NL |
| "void main() {" NL |
| " for (int i = 0; i < g_input.data0.length(); ++i) g_output.data0[i] = g_input.data0[i];" NL "}"; |
| } |
| |
| class BasicStd140LayoutCase1VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c1(in_data); |
| } |
| }; |
| |
| class BasicStd140LayoutCase1CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c1(in_data); |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.7.2 BasicStd140LayoutCase2 |
| //----------------------------------------------------------------------------- |
| const char* GetInput140c2(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(20 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| int* ip = reinterpret_cast<int*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 0.0f; |
| fp[2] = 0.0f; |
| fp[3] = 0.0f; |
| fp[4] = 2.0f; |
| fp[5] = 0.0f; |
| fp[6] = 0.0f; |
| fp[7] = 0.0f; |
| fp[8] = 3.0f; |
| fp[9] = 0.0f; |
| fp[10] = 0.0f; |
| fp[11] = 0.0f; |
| fp[12] = 4.0f; |
| fp[13] = 0.0f; |
| fp[14] = 0.0f; |
| fp[15] = 0.0f; |
| ip[16] = 5; |
| ip[17] = 6; |
| |
| return NL "layout(std140, binding = 0) buffer Input {" NL " float data0;" NL " float data1[3];" NL |
| " ivec2 data2;" NL "} g_input;" NL "layout(std140, binding = 1) buffer Output {" NL " float data0;" NL |
| " float data1[3];" NL " ivec2 data2;" NL "} g_output;" NL "void main() {" NL |
| " g_output.data0 = g_input.data0;" NL |
| " for (int i = 0; i < g_input.data1.length(); ++i) g_output.data1[i] = g_input.data1[i];" NL |
| " g_output.data2 = g_input.data2;" NL "}"; |
| } |
| |
| class BasicStd140LayoutCase2VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c2(in_data); |
| } |
| }; |
| |
| class BasicStd140LayoutCase2CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c2(in_data); |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.7.3 BasicStd140LayoutCase3 |
| //----------------------------------------------------------------------------- |
| const char* GetInput140c3(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(32 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 0.0f; |
| fp[2] = 0.0f; |
| fp[3] = 0.0f; |
| fp[4] = 2.0f; |
| fp[5] = 0.0f; |
| fp[6] = 0.0f; |
| fp[7] = 0.0f; |
| fp[8] = 3.0f; |
| fp[9] = 0.0f; |
| fp[10] = 0.0f; |
| fp[11] = 0.0f; |
| fp[12] = 4.0f; |
| fp[13] = 0.0f; |
| fp[14] = 0.0f; |
| fp[15] = 0.0f; |
| fp[16] = 5.0f; |
| fp[17] = 6.0f; |
| fp[18] = 0.0f; |
| fp[19] = 0.0f; |
| fp[20] = 7.0f; |
| fp[21] = 8.0f; |
| fp[22] = 9.0f; |
| fp[23] = 0.0f; |
| fp[24] = 10.0f; |
| fp[25] = 11.0f; |
| fp[26] = 12.0f; |
| fp[27] = 0.0f; |
| fp[28] = 13.0f; |
| |
| return NL "layout(std140, binding = 0) buffer Input {" NL " float data0;" NL " float data1[3];" NL |
| " vec2 data2;" NL " readonly vec3 data3[2];" NL " float data4;" NL "} g_input;" NL |
| "layout(std140, binding = 1) buffer Output {" NL " float data0;" NL " float data1[3];" NL |
| " vec2 data2;" NL " vec3 data3[2];" NL " float data4;" NL "} g_output;" NL "void main() {" NL |
| " g_output.data0 = g_input.data0;" NL |
| " for (int i = 0; i < g_input.data1.length(); ++i) g_output.data1[i] = g_input.data1[i];" NL |
| " g_output.data2 = g_input.data2;" NL |
| " for (int i = 0; i < g_input.data3.length(); ++i) g_output.data3[i] = g_input.data3[i];" NL |
| " g_output.data4 = g_input.data4;" NL "}"; |
| } |
| |
| class BasicStd140LayoutCase3VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c3(in_data); |
| } |
| }; |
| |
| class BasicStd140LayoutCase3CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c3(in_data); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.7.4 BasicStd140LayoutCase4 |
| //----------------------------------------------------------------------------- |
| const char* GetInput140c4(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(28 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 2.0f; |
| fp[2] = 0.0f; |
| fp[3] = 0.0f; |
| fp[4] = 3.0f; |
| fp[5] = 4.0f; |
| fp[6] = 0.0f; |
| fp[7] = 0.0f; |
| fp[8] = 5.0f; |
| fp[9] = 6.0f; |
| fp[10] = 0.0f; |
| fp[11] = 0.0f; |
| fp[12] = 7.0f; |
| fp[13] = 8.0f; |
| fp[14] = 0.0f; |
| fp[15] = 0.0f; |
| fp[16] = 9.0f; |
| fp[17] = 10.0f; |
| fp[18] = 11.0f; |
| fp[19] = 0.0f; |
| fp[20] = 12.0f; |
| fp[21] = 13.0f; |
| fp[22] = 14.0f; |
| fp[23] = 0.0f; |
| fp[24] = 15.0f; |
| |
| return NL "layout(std140, binding = 0) buffer Input {" NL " mat4x2 data0;" NL " mat2x3 data1;" NL |
| " float data2;" NL "} g_input;" NL "layout(std140, binding = 1) buffer Output {" NL " mat4x2 data0;" NL |
| " mat2x3 data1;" NL " float data2;" NL "} g_output;" NL "void main() {" NL |
| " g_output.data0 = g_input.data0;" NL " g_output.data1 = g_input.data1;" NL |
| " g_output.data2 = g_input.data2;" NL "}"; |
| } |
| |
| class BasicStd140LayoutCase4VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c4(in_data); |
| } |
| }; |
| |
| class BasicStd140LayoutCase4CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c4(in_data); |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.7.5 BasicStd140LayoutCase5 |
| //----------------------------------------------------------------------------- |
| const char* GetInput140c5(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(8 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 2.0f; |
| fp[2] = 3.0f; |
| fp[3] = 4.0f; |
| fp[4] = 5.0f; |
| fp[5] = 6.0f; |
| fp[6] = 7.0f; |
| fp[7] = 8.0f; |
| |
| return NL "layout(std140, binding = 0, row_major) buffer Input {" NL " mat4x2 data0;" NL "} g_input;" NL |
| "layout(std140, binding = 1, row_major) buffer Output {" NL " mat4x2 data0;" NL "} g_output;" NL |
| "void main() {" NL " g_output.data0 = g_input.data0;" NL "}"; |
| } |
| |
| class BasicStd140LayoutCase5VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c5(in_data); |
| } |
| }; |
| |
| class BasicStd140LayoutCase5CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c5(in_data); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.7.6 BasicStd140LayoutCase6 |
| //----------------------------------------------------------------------------- |
| const char* GetInput140c6(std::vector<GLubyte>& in_data) |
| { |
| in_data.resize(96 * 4); |
| float* fp = reinterpret_cast<float*>(&in_data[0]); |
| fp[0] = 1.0f; |
| fp[1] = 0.0f; |
| fp[2] = 0.0f; |
| fp[3] = 0.0f; |
| fp[4] = 2.0f; |
| fp[5] = 0.0f; |
| fp[6] = 0.0f; |
| fp[7] = 0.0f; |
| fp[8] = 3.0f; |
| fp[9] = 0.0f; |
| fp[10] = 0.0f; |
| fp[11] = 0.0f; |
| fp[12] = 4.0f; |
| fp[13] = 0.0f; |
| fp[14] = 0.0f; |
| fp[15] = 0.0f; |
| fp[16] = 5.0f; |
| fp[17] = 0.0f; |
| fp[18] = 0.0f; |
| fp[19] = 0.0f; |
| fp[20] = 6.0f; |
| fp[21] = 7.0f; |
| fp[22] = 8.0f; |
| fp[23] = 9.0f; |
| fp[24] = 10.0f; |
| fp[25] = 11.0f; |
| fp[26] = 0.0f; |
| fp[27] = 0.0f; |
| fp[28] = 12.0f; |
| fp[29] = 13.0f; |
| fp[30] = 0.0f; |
| fp[31] = 0.0f; |
| fp[32] = 14.0f; |
| fp[33] = 15.0f; |
| fp[34] = 0.0f; |
| fp[35] = 0.0f; |
| fp[36] = 16.0f; |
| fp[37] = 17.0f; |
| fp[38] = 0.0f; |
| fp[39] = 0.0f; |
| fp[40] = 18.0f; |
| fp[41] = 19.0f; |
| fp[42] = 20.0f; |
| fp[43] = 0.0f; |
| fp[44] = 21.0f; |
| fp[45] = 22.0f; |
| fp[46] = 23.0f; |
| fp[47] = 0.0f; |
| fp[48] = 24.0f; |
| fp[49] = 25.0f; |
| fp[50] = 26.0f; |
| fp[51] = 0.0f; |
| fp[52] = 27.0f; |
| fp[53] = 28.0f; |
| fp[54] = 29.0f; |
| fp[55] = 0.0f; |
| fp[56] = 30.0f; |
| fp[57] = 31.0f; |
| fp[58] = 32.0f; |
| fp[59] = 0.0f; |
| fp[60] = 33.0f; |
| fp[61] = 34.0f; |
| fp[62] = 35.0f; |
| fp[63] = 0.0f; |
| fp[64] = 36.0f; |
| fp[65] = 37.0f; |
| fp[66] = 38.0f; |
| fp[67] = 39.0f; |
| fp[68] = 40.0f; |
| fp[69] = 41.0f; |
| fp[70] = 42.0f; |
| fp[71] = 43.0f; |
| fp[72] = 44.0f; |
| fp[73] = 45.0f; |
| fp[74] = 46.0f; |
| fp[75] = 47.0f; |
| fp[76] = 48.0f; |
| fp[77] = 49.0f; |
| fp[78] = 50.0f; |
| fp[79] = 51.0f; |
| fp[80] = 52.0f; |
| fp[81] = 68.0f; |
| fp[82] = 69.0f; |
| fp[83] = 70.0f; |
| fp[84] = 56.0f; |
| fp[85] = 72.0f; |
| fp[86] = 73.0f; |
| fp[87] = 74.0f; |
| fp[88] = 60.0f; |
| fp[89] = 76.0f; |
| fp[90] = 77.0f; |
| fp[91] = 78.0f; |
| fp[92] = 64.0f; |
| fp[93] = 80.0f; |
| fp[94] = 81.0f; |
| fp[95] = 82.0f; |
| |
| return NL "layout(std140, binding = 0) buffer Input {" NL " float data0[2];" NL " float data1[3];" NL |
| " vec2 data2;" NL " vec2 data3;" NL " mat2 data4[2];" NL " mat3 data5[2];" NL " mat4 data6[2];" NL |
| "} g_input;" NL "layout(std140, binding = 1) buffer Output {" NL " float data0[2];" NL |
| " float data1[3];" NL " vec2 data2;" NL " vec2 data3;" NL " mat2 data4[2];" NL " mat3 data5[2];" NL |
| " mat4 data6[2];" NL "} g_output;" NL "void main() {" NL |
| " for (int i = 0; i < g_input.data0.length(); ++i) g_output.data0[i] = g_input.data0[i];" NL |
| " for (int i = 0; i < g_input.data1.length(); ++i) g_output.data1[i] = g_input.data1[i];" NL |
| " g_output.data2 = g_input.data2;" NL " g_output.data3 = g_input.data3;" NL |
| " for (int i = 0; i < g_input.data4.length(); ++i) g_output.data4[i] = g_input.data4[i];" NL |
| " for (int i = 0; i < g_input.data5.length(); ++i) g_output.data5[i] = g_input.data5[i];" NL |
| " for (int i = 0; i < g_input.data6.length(); ++i) g_output.data6[i] = g_input.data6[i];" NL "}"; |
| } |
| |
| class BasicStd140LayoutCase6VS : public BasicStdLayoutBaseVS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c6(in_data); |
| } |
| }; |
| |
| class BasicStd140LayoutCase6CS : public BasicStdLayoutBaseCS |
| { |
| virtual const char* GetInput(std::vector<GLubyte>& in_data) |
| { |
| return GetInput140c6(in_data); |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.8.1 BasicAtomicCase1 |
| //----------------------------------------------------------------------------- |
| class BasicAtomicCase1 : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_program; |
| GLuint m_storage_buffer[6]; |
| GLuint m_vertex_array; |
| GLuint m_vertex_buffer; |
| |
| virtual long Setup() |
| { |
| m_program = 0; |
| memset(m_storage_buffer, 0, sizeof(m_storage_buffer)); |
| m_vertex_array = 0; |
| m_vertex_buffer = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| if (!SupportedInVS(2)) |
| return NOT_SUPPORTED; |
| if (!SupportedInGS(2)) |
| return NOT_SUPPORTED; |
| |
| const char* const glsl_vs = |
| NL "layout(location = 0) in vec4 g_in_position;" NL |
| "layout(std430, binding = 0) coherent buffer VSuint {" NL " uint g_uint_out[4];" NL "};" NL |
| "layout(std430, binding = 1) coherent buffer VSint {" NL " int data[4];" NL "} g_int_out;" NL |
| "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL "void main() {" NL |
| " gl_Position = g_in_position;" NL NL |
| " if (atomicExchange(g_uint_out[gl_VertexID], g_uint_value[1]) != 0u) return;" NL |
| " if (atomicAdd(g_uint_out[gl_VertexID], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicMin(g_uint_out[gl_VertexID], g_uint_value[1]) != 3u) return;" NL |
| " if (atomicMax(g_uint_out[gl_VertexID], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicAnd(g_uint_out[gl_VertexID], g_uint_value[3]) != 2u) return;" NL |
| " if (atomicOr(g_uint_out[gl_VertexID], g_uint_value[4]) != 0u) return;" NL |
| " if (g_uint_value[0] > 0u) {" NL |
| " if (atomicXor(g_uint_out[gl_VertexID], g_uint_value[5]) != 3u) return;" NL " }" NL |
| " if (atomicCompSwap(g_uint_out[gl_VertexID], g_uint_value[6], g_uint_value[7]) != 2u) {" NL |
| " g_uint_out[gl_VertexID] = 1u;" NL " return;" NL " }" NL NL |
| " if (atomicExchange(g_int_out.data[gl_VertexID], 1) != 0) return;" NL |
| " if (atomicAdd(g_int_out.data[gl_VertexID], 2) != 1) return;" NL |
| " if (atomicMin(g_int_out.data[gl_VertexID], 1) != 3) return;" NL |
| " if (atomicMax(g_int_out.data[gl_VertexID], 2) != 1) return;" NL |
| " if (atomicAnd(g_int_out.data[gl_VertexID], 0x1) != 2) return;" NL |
| " if (atomicOr(g_int_out.data[gl_VertexID], 0x3) != 0) return;" NL |
| " if (atomicXor(g_int_out.data[gl_VertexID], 0x1) != 3) return;" NL |
| " if (atomicCompSwap(g_int_out.data[gl_VertexID], 0x2, 0x7) != 2) {" NL |
| " g_int_out.data[gl_VertexID] = 1;" NL " return;" NL " }" NL "}"; |
| |
| const char* const glsl_gs = NL |
| "layout(points) in;" NL "layout(points, max_vertices = 1) out;" NL |
| "layout(std430, binding = 2) coherent buffer GSuint {" NL " uint data[4];" NL "} g_uint_gs;" NL |
| "layout(std430, binding = 3) coherent buffer GSint {" NL " int data[4];" NL "} g_int_gs;" NL |
| "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL "void main() {" NL |
| " gl_Position = gl_in[0].gl_Position;" NL " gl_PrimitiveID = gl_PrimitiveIDIn;" NL " EmitVertex();" NL NL |
| " if (atomicExchange(g_uint_gs.data[gl_PrimitiveIDIn], g_uint_value[1]) != 0u) return;" NL |
| " if (atomicAdd(g_uint_gs.data[gl_PrimitiveIDIn], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicMin(g_uint_gs.data[gl_PrimitiveIDIn], g_uint_value[1]) != 3u) return;" NL |
| " if (atomicMax(g_uint_gs.data[gl_PrimitiveIDIn], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicAnd(g_uint_gs.data[gl_PrimitiveIDIn], g_uint_value[3]) != 2u) return;" NL |
| " if (atomicOr(g_uint_gs.data[gl_PrimitiveIDIn], g_uint_value[4]) != 0u) return;" NL |
| " if (g_uint_value[0] > 0u) {" NL |
| " if (atomicXor(g_uint_gs.data[gl_PrimitiveIDIn], g_uint_value[5]) != 3u) return;" NL " }" NL |
| " if (atomicCompSwap(g_uint_gs.data[gl_PrimitiveIDIn], g_uint_value[6], g_uint_value[7]) != 2u) {" NL |
| " g_uint_gs.data[gl_PrimitiveIDIn] = 1u;" NL " return;" NL " }" NL NL |
| " if (atomicExchange(g_int_gs.data[gl_PrimitiveIDIn], 1) != 0) return;" NL |
| " if (atomicAdd(g_int_gs.data[gl_PrimitiveIDIn], 2) != 1) return;" NL |
| " if (atomicMin(g_int_gs.data[gl_PrimitiveIDIn], 1) != 3) return;" NL |
| " if (atomicMax(g_int_gs.data[gl_PrimitiveIDIn], 2) != 1) return;" NL |
| " if (atomicAnd(g_int_gs.data[gl_PrimitiveIDIn], 0x1) != 2) return;" NL |
| " if (atomicOr(g_int_gs.data[gl_PrimitiveIDIn], 0x3) != 0) return;" NL |
| " if (atomicXor(g_int_gs.data[gl_PrimitiveIDIn], 0x1) != 3) return;" NL |
| " if (atomicCompSwap(g_int_gs.data[gl_PrimitiveIDIn], 0x2, 0x7) != 2) {" NL |
| " g_int_gs.data[gl_PrimitiveIDIn] = 1;" NL " return;" NL " }" NL "}"; |
| |
| const char* const glsl_fs = |
| NL "layout(location = 0) out vec4 g_fs_out;" NL "layout(std430, binding = 4) coherent buffer FSuint {" NL |
| " uint data[4];" NL "} g_uint_fs;" NL "layout(std430, binding = 5) coherent buffer FSint {" NL |
| " int data[4];" NL "} g_int_fs;" NL |
| "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL "void main() {" NL |
| " g_fs_out = vec4(0, 1, 0, 1);" NL NL |
| " if (atomicExchange(g_uint_fs.data[gl_PrimitiveID], g_uint_value[1]) != 0u) return;" NL |
| " if (atomicAdd(g_uint_fs.data[gl_PrimitiveID], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicMin(g_uint_fs.data[gl_PrimitiveID], g_uint_value[1]) != 3u) return;" NL |
| " if (atomicMax(g_uint_fs.data[gl_PrimitiveID], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicAnd(g_uint_fs.data[gl_PrimitiveID], g_uint_value[3]) != 2u) return;" NL |
| " if (atomicOr(g_uint_fs.data[gl_PrimitiveID], g_uint_value[4]) != 0u) return;" NL |
| " if (g_uint_value[0] > 0u) {" NL |
| " if (atomicXor(g_uint_fs.data[gl_PrimitiveID], g_uint_value[5]) != 3u) return;" NL " }" NL |
| " if (atomicCompSwap(g_uint_fs.data[gl_PrimitiveID], g_uint_value[6], g_uint_value[7]) != 2u) {" NL |
| " g_uint_fs.data[gl_PrimitiveID] = 1u;" NL " return;" NL " }" NL NL |
| " if (atomicExchange(g_int_fs.data[gl_PrimitiveID], 1) != 0) return;" NL |
| " if (atomicAdd(g_int_fs.data[gl_PrimitiveID], 2) != 1) return;" NL |
| " if (atomicMin(g_int_fs.data[gl_PrimitiveID], 1) != 3) return;" NL |
| " if (atomicMax(g_int_fs.data[gl_PrimitiveID], 2) != 1) return;" NL |
| " if (atomicAnd(g_int_fs.data[gl_PrimitiveID], 0x1) != 2) return;" NL |
| " if (atomicOr(g_int_fs.data[gl_PrimitiveID], 0x3) != 0) return;" NL |
| " if (atomicXor(g_int_fs.data[gl_PrimitiveID], 0x1) != 3) return;" NL |
| " if (atomicCompSwap(g_int_fs.data[gl_PrimitiveID], 0x2, 0x7) != 2) {" NL |
| " g_int_fs.data[gl_PrimitiveID] = 1;" NL " return;" NL " }" NL "}"; |
| m_program = CreateProgram(glsl_vs, "", "", glsl_gs, glsl_fs); |
| glLinkProgram(m_program); |
| if (!CheckProgram(m_program)) |
| return ERROR; |
| |
| glGenBuffers(6, m_storage_buffer); |
| for (GLuint i = 0; i < 6; ++i) |
| { |
| const int data[4] = { 0 }; |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_storage_buffer[i]); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW); |
| } |
| |
| /* vertex buffer */ |
| { |
| const float data[] = { -0.8f, -0.8f, 0.8f, -0.8f, -0.8f, 0.8f, 0.8f, 0.8f }; |
| glGenBuffers(1, &m_vertex_buffer); |
| glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| } |
| |
| glGenVertexArrays(1, &m_vertex_array); |
| glBindVertexArray(m_vertex_array); |
| glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer); |
| glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| glEnableVertexAttribArray(0); |
| glBindVertexArray(0); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| glUseProgram(m_program); |
| glBindVertexArray(m_vertex_array); |
| glDrawArrays(GL_POINTS, 0, 4); |
| glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| |
| for (int ii = 0; ii < 3; ++ii) |
| { |
| /* uint data */ |
| { |
| GLuint data[4]; |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[ii * 2 + 0]); |
| glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data); |
| for (GLuint i = 0; i < 4; ++i) |
| { |
| if (data[i] != 7) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is " |
| << data[i] << " should be 7." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| } |
| /* int data */ |
| { |
| GLint data[4]; |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[ii * 2 + 1]); |
| glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data); |
| for (GLint i = 0; i < 4; ++i) |
| { |
| if (data[i] != 7) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "iData at index " << i << " is " |
| << data[i] << " should be 7." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| } |
| } |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glUseProgram(0); |
| glDeleteProgram(m_program); |
| glDeleteBuffers(6, m_storage_buffer); |
| glDeleteBuffers(1, &m_vertex_buffer); |
| glDeleteVertexArrays(1, &m_vertex_array); |
| return NO_ERROR; |
| } |
| }; |
| |
| class BasicAtomicCase1CS : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_program; |
| GLuint m_storage_buffer[2]; |
| |
| virtual long Setup() |
| { |
| m_program = 0; |
| memset(m_storage_buffer, 0, sizeof(m_storage_buffer)); |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| const char* const glsl_cs = |
| NL "layout(local_size_x = 4) in;" NL "layout(std430, binding = 2) coherent buffer FSuint {" NL |
| " uint data[4];" NL "} g_uint_fs;" NL "layout(std430, binding = 3) coherent buffer FSint {" NL |
| " int data[4];" NL "} g_int_fs;" NL "uniform uint g_uint_value[8];" NL "void main() {" NL |
| " if (atomicExchange(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[1]) != 0u) return;" NL |
| " if (atomicAdd(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicMin(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[1]) != 3u) return;" NL |
| " if (atomicMax(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicAnd(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[3]) != 2u) return;" NL |
| " if (atomicOr(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[4]) != 0u) return;" NL |
| " if (g_uint_value[0] > 0u) {" NL |
| " if (atomicXor(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[5]) != 3u) return;" NL " }" NL |
| " if (atomicCompSwap(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[6], g_uint_value[7]) != 2u) " |
| "{" NL " g_uint_fs.data[gl_LocalInvocationIndex] = 1u;" NL " return;" NL " }" NL |
| " if (atomicExchange(g_int_fs.data[gl_LocalInvocationIndex], 1) != 0) return;" NL |
| " if (atomicAdd(g_int_fs.data[gl_LocalInvocationIndex], 2) != 1) return;" NL |
| " if (atomicMin(g_int_fs.data[gl_LocalInvocationIndex], 1) != 3) return;" NL |
| " if (atomicMax(g_int_fs.data[gl_LocalInvocationIndex], 2) != 1) return;" NL |
| " if (atomicAnd(g_int_fs.data[gl_LocalInvocationIndex], 0x1) != 2) return;" NL |
| " if (atomicOr(g_int_fs.data[gl_LocalInvocationIndex], 0x3) != 0) return;" NL |
| " if (atomicXor(g_int_fs.data[gl_LocalInvocationIndex], 0x1) != 3) return;" NL |
| " if (atomicCompSwap(g_int_fs.data[gl_LocalInvocationIndex], 0x2, 0x7) != 2) {" NL |
| " g_int_fs.data[gl_LocalInvocationIndex] = 1;" NL " return;" NL " }" NL "}"; |
| m_program = CreateProgramCS(glsl_cs); |
| glLinkProgram(m_program); |
| if (!CheckProgram(m_program)) |
| return ERROR; |
| |
| glGenBuffers(2, m_storage_buffer); |
| for (GLuint i = 0; i < 2; ++i) |
| { |
| const int data[4] = { 0 }; |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i + 2, m_storage_buffer[i]); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW); |
| } |
| |
| glUseProgram(m_program); |
| GLuint unif[8] = { 3, 1, 2, 1, 3, 1, 2, 7 }; |
| glUniform1uiv(glGetUniformLocation(m_program, "g_uint_value[0]"), 8, unif); |
| glDispatchCompute(1, 1, 1); |
| glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| |
| /* uint data */ |
| { |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]); |
| GLuint* data = (GLuint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 16, GL_MAP_READ_BIT); |
| if (!data) |
| return ERROR; |
| for (GLuint i = 0; i < 4; ++i) |
| { |
| if (data[i] != 7) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is " |
| << data[i] << " should be 7." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
| } |
| /* int data */ |
| { |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]); |
| GLint* data = (GLint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 16, GL_MAP_READ_BIT); |
| if (!data) |
| return ERROR; |
| for (GLint i = 0; i < 4; ++i) |
| { |
| if (data[i] != 7) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "iData at index " << i << " is " |
| << data[i] << " should be 7." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); |
| } |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glUseProgram(0); |
| glDeleteProgram(m_program); |
| glDeleteBuffers(2, m_storage_buffer); |
| return NO_ERROR; |
| } |
| }; |
| //----------------------------------------------------------------------------- |
| // 1.8.2 BasicAtomicCase2 |
| //----------------------------------------------------------------------------- |
| class BasicAtomicCase2 : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_program; |
| GLuint m_storage_buffer[4]; |
| GLuint m_vertex_array; |
| GLuint m_vertex_buffer; |
| |
| virtual long Setup() |
| { |
| m_program = 0; |
| memset(m_storage_buffer, 0, sizeof(m_storage_buffer)); |
| m_vertex_array = 0; |
| m_vertex_buffer = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| if (!SupportedInTCS(2)) |
| return NOT_SUPPORTED; |
| if (!SupportedInTES(2)) |
| return NOT_SUPPORTED; |
| |
| const char* const glsl_vs = NL "layout(location = 0) in vec4 g_in_position;" NL "void main() {" NL |
| " gl_Position = g_in_position;" NL "}"; |
| |
| const char* const glsl_tcs = NL |
| "layout(vertices = 1) out;" NL "layout(std430, binding = 0) buffer TCSuint {" NL " uint g_uint_out[1];" NL |
| "};" NL "layout(std430, binding = 1) buffer TCSint {" NL " int data[1];" NL "} g_int_out;" NL |
| "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL "void main() {" NL |
| " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;" NL |
| " if (gl_InvocationID == 0) {" NL " gl_TessLevelInner[0] = 1.0;" NL " gl_TessLevelInner[1] = 1.0;" NL |
| " gl_TessLevelOuter[0] = 1.0;" NL " gl_TessLevelOuter[1] = 1.0;" NL |
| " gl_TessLevelOuter[2] = 1.0;" NL " gl_TessLevelOuter[3] = 1.0;" NL " }" NL |
| " if (atomicAdd(g_uint_out[gl_InvocationID], g_uint_value[0]) != 0u) return;" NL |
| " if (atomicExchange(g_uint_out[gl_InvocationID], g_uint_value[0]) != 3u) return;" NL |
| " if (atomicMin(g_uint_out[gl_InvocationID], g_uint_value[1]) != 3u) return;" NL |
| " if (atomicMax(g_uint_out[gl_InvocationID], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicAnd(g_uint_out[gl_InvocationID], g_uint_value[3]) != 2u) return;" NL |
| " if (atomicOr(g_uint_out[gl_InvocationID], g_uint_value[4]) != 0u) return;" NL |
| " if (g_uint_value[0] > 0u) {" NL |
| " if (atomicXor(g_uint_out[gl_InvocationID], g_uint_value[5]) != 3u) return;" NL " }" NL |
| " if (atomicCompSwap(g_uint_out[gl_InvocationID], g_uint_value[6], g_uint_value[7]) != 2u) {" NL |
| " g_uint_out[gl_InvocationID] = 1u;" NL " return;" NL " }" NL NL |
| " if (atomicAdd(g_int_out.data[gl_InvocationID], 3) != 0) return;" NL |
| " if (atomicExchange(g_int_out.data[gl_InvocationID], 3) != 3) return;" NL |
| " if (atomicMin(g_int_out.data[gl_InvocationID], 1) != 3) return;" NL |
| " if (atomicMax(g_int_out.data[gl_InvocationID], 2) != 1) return;" NL |
| " if (atomicAnd(g_int_out.data[gl_InvocationID], 0x1) != 2) return;" NL |
| " if (atomicOr(g_int_out.data[gl_InvocationID], 0x3) != 0) return;" NL |
| " if (atomicXor(g_int_out.data[gl_InvocationID], 0x1) != 3) return;" NL |
| " if (atomicCompSwap(g_int_out.data[gl_InvocationID], 0x2, 0x7) != 2) {" NL |
| " g_int_out.data[gl_InvocationID] = 1;" NL " return;" NL " }" NL "}"; |
| |
| const char* const glsl_tes = |
| NL "layout(quads, point_mode) in;" NL "layout(std430, binding = 2) buffer TESuint {" NL " uint data[1];" NL |
| "} g_uint_tes;" NL "layout(std430, binding = 3) buffer TESint {" NL " int data[1];" NL "} g_int_tes;" NL |
| "uniform uint g_uint_value[8] = uint[8](3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u);" NL "void main() {" NL |
| " gl_Position = gl_in[0].gl_Position;" NL NL |
| " if (atomicExchange(g_uint_tes.data[gl_PrimitiveID], g_uint_value[1]) != 0u) return;" NL |
| " if (atomicAdd(g_uint_tes.data[gl_PrimitiveID], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicMin(g_uint_tes.data[gl_PrimitiveID], g_uint_value[1]) != 3u) return;" NL |
| " if (atomicMax(g_uint_tes.data[gl_PrimitiveID], g_uint_value[2]) != 1u) return;" NL |
| " if (atomicAnd(g_uint_tes.data[gl_PrimitiveID], g_uint_value[3]) != 2u) return;" NL |
| " if (atomicOr(g_uint_tes.data[gl_PrimitiveID], g_uint_value[4]) != 0u) return;" NL |
| " if (g_uint_value[0] > 0u) {" NL |
| " if (atomicXor(g_uint_tes.data[gl_PrimitiveID], g_uint_value[5]) != 3u) return;" NL " }" NL |
| " if (atomicCompSwap(g_uint_tes.data[gl_PrimitiveID], g_uint_value[6], g_uint_value[7]) != 2u) {" NL |
| " g_uint_tes.data[gl_PrimitiveID] = 1u;" NL " return;" NL " }" NL NL |
| " if (atomicExchange(g_int_tes.data[gl_PrimitiveID], 1) != 0) return;" NL |
| " if (atomicAdd(g_int_tes.data[gl_PrimitiveID], 2) != 1) return;" NL |
| " if (atomicMin(g_int_tes.data[gl_PrimitiveID], 1) != 3) return;" NL |
| " if (atomicMax(g_int_tes.data[gl_PrimitiveID], 2) != 1) return;" NL |
| " if (atomicAnd(g_int_tes.data[gl_PrimitiveID], 0x1) != 2) return;" NL |
| " if (atomicOr(g_int_tes.data[gl_PrimitiveID], 0x3) != 0) return;" NL |
| " if (atomicXor(g_int_tes.data[gl_PrimitiveID], 0x1) != 3) return;" NL |
| " if (atomicCompSwap(g_int_tes.data[gl_PrimitiveID], 0x2, 0x7) != 2) {" NL |
| " g_int_tes.data[gl_PrimitiveID] = 1;" NL " return;" NL " }" NL "}"; |
| |
| const char* const glsl_fs = |
| NL "layout(location = 0) out vec4 g_fs_out;" NL "void main() {" NL " g_fs_out = vec4(0, 1, 0, 1);" NL "}"; |
| |
| m_program = CreateProgram(glsl_vs, glsl_tcs, glsl_tes, "", glsl_fs); |
| glLinkProgram(m_program); |
| if (!CheckProgram(m_program)) |
| return ERROR; |
| |
| glGenBuffers(4, m_storage_buffer); |
| for (GLuint i = 0; i < 4; ++i) |
| { |
| const int data[1] = { 0 }; |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_storage_buffer[i]); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW); |
| } |
| |
| /* vertex buffer */ |
| { |
| const float data[2] = { 0.0f, 0.0f }; |
| glGenBuffers(1, &m_vertex_buffer); |
| glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| } |
| |
| glGenVertexArrays(1, &m_vertex_array); |
| glBindVertexArray(m_vertex_array); |
| glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer); |
| glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| glEnableVertexAttribArray(0); |
| glBindVertexArray(0); |
| |
| glClear(GL_COLOR_BUFFER_BIT); |
| glUseProgram(m_program); |
| glBindVertexArray(m_vertex_array); |
| glPatchParameteri(GL_PATCH_VERTICES, 1); |
| glDrawArrays(GL_PATCHES, 0, 1); |
| glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| |
| for (int ii = 0; ii < 2; ++ii) |
| { |
| /* uint data */ |
| { |
| GLuint data[1]; |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[ii * 2 + 0]); |
| glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data); |
| for (GLuint i = 0; i < 1; ++i) |
| { |
| if (data[i] != 7) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is " |
| << data[i] << " should be 7." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| } |
| /* int data */ |
| { |
| GLint data[1]; |
| glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[ii * 2 + 1]); |
| glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(data), data); |
| for (GLint i = 0; i < 1; ++i) |
| { |
| if (data[i] != 7) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "iData at index " << i << " is " |
| << data[i] << " should be 7." << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| } |
| } |
| return NO_ERROR; |
| } |
| |
| virtual long Cleanup() |
| { |
| glPatchParameteri(GL_PATCH_VERTICES, 3); |
| glUseProgram(0); |
| glDeleteProgram(m_program); |
| glDeleteBuffers(4, m_storage_buffer); |
| glDeleteBuffers(1, &m_vertex_buffer); |
| glDeleteVertexArrays(1, &m_vertex_array); |
| return NO_ERROR; |
| } |
| }; |
| |
| //----------------------------------------------------------------------------- |
| // 1.8.3 BasicAtomicCase3 |
| //----------------------------------------------------------------------------- |
| class BasicAtomicCase3 : public ShaderStorageBufferObjectBase |
| { |
| GLuint m_program; |
| GLuint m_storage_buffer; |
| GLuint m_vertex_array; |
| GLuint m_vertex_buffer; |
| |
| virtual long Setup() |
| { |
| m_program = 0; |
| m_storage_buffer = 0; |
| m_vertex_array = 0; |
| m_vertex_buffer = 0; |
| return NO_ERROR; |
| } |
| |
| virtual long Run() |
| { |
| if (!SupportedInVS(1)) |
| return NOT_SUPPORTED; |
| if (!SupportedInGS(1)) |
| return NOT_SUPPORTED; |
| |
| const char* const glsl_vs = |
| NL "layout(location = 0) in vec4 g_in_position;" NL "layout(std430, binding = 0) buffer Buffer {" NL |
| " uvec4 u[4];" NL " ivec3 i[4];" NL "} g_vs_buffer;" NL "void main() {" NL |
| " gl_Position = g_in_position;" NL " atomicAdd(g_vs_buffer.u[0].x, g_vs_buffer.u[gl_VertexID][1]);" NL |
| " atomicAdd(g_vs_buffer.u[0][0], g_vs_buffer.u[gl_VertexID].z);" NL |
| " atomicAdd(g_vs_buffer.i[0].x, g_vs_buffer.i[gl_VertexID][1]);" NL |
| " atomicAdd(g_vs_buffer.i[0][0], g_vs_buffer.i[gl_VertexID].z);" NL "}"; |
| |
| const char* const glsl_gs = NL |
| "layout(points) in;" NL "layout(points, max_vertices = 1) out;" NL |
| "layout(std430, binding = 0) buffer Buffer {" NL " uvec4 u[4];" NL " ivec3 i[4];" NL "} g_gs_buffer;" NL |
| "void main() {" NL " gl_Position = gl_in[0].gl_Position;" NL " gl_PrimitiveID = gl_PrimitiveIDIn;" NL |
| " EmitVertex();" NL " atomicAdd(g_gs_buffer.u[0].x, g_gs_buffer.u[gl_PrimitiveIDIn][1]);" NL |
| " atomicAdd(g_gs_buffer.i[0].x, g_gs_buffer.i[gl_PrimitiveIDIn][1]);" NL "}"; |
| |
| const char* const glsl_fs = NL |
| "layout(location = 0) out vec4 g_fs_out;" NL "layout(std430, binding = 0) buffer Buffer {" NL |
| " uvec4 u[4];" NL " ivec3 i[4];" NL "} g_fs_buffer;" NL "void main() {" NL |
| " g_fs_out = vec4(0, 1, 0, 1);" NL " atomicAdd(g_fs_buffer.u[0].x, g_fs_buffer.u[gl_PrimitiveID][1]);" NL |
| " atomicAdd(g_fs_buffer.i[0].x, g_fs_buffer.i[gl_PrimitiveID][1]);" NL "}"; |
| |
| m_program = CreateProgram(glsl_vs, "", "", glsl_gs, glsl_fs); |
| glLinkProgram(m_program); |
| if (!CheckProgram(m_program)) |
| return ERROR; |
| |
| /* init storage buffer */ |
| { |
| glGenBuffers(1, &m_storage_buffer); |
| glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer); |
| glBufferData(GL_SHADER_STORAGE_BUFFER, 8 * sizeof(int) * 4, NULL, GL_DYNAMIC_DRAW); |
| ivec4* ptr = reinterpret_cast<ivec4*>(glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY)); |
| if (!ptr) |
| return ERROR; |
| for (int i = 0; i < 4; |