blob: 950df6fa410d10e636f4d4824f912a86dd9d9519 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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;