blob: d5906448ba7b6ec80329cb2544bf1e29ec862a08 [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 "gl4cES31CompatibilityTests.hpp"
#include "glwEnums.hpp"
#include "tcuMatrix.hpp"
#include "tcuRenderTarget.hpp"
#include <assert.h>
#include <cmath>
#include <cstdarg>
namespace gl4cts
{
namespace es31compatibility
{
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 310 es" NL "precision highp float;" NL "precision highp int;";
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 IsVSFSAvailable(int requiredVS, int requiredFS)
{
GLint blocksVS, blocksFS;
glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &blocksVS);
glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &blocksFS);
if (blocksVS >= requiredVS && blocksFS >= requiredFS)
return true;
else
{
std::ostringstream reason;
reason << "Required " << requiredVS << " VS storage blocks but only " << blocksVS << " available."
<< std::endl
<< "Required " << requiredFS << " FS storage blocks but only " << blocksFS << " 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();
}
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_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;
}
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& 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)
{
const char* const src[2] = { kGLSLVer, source.c_str() };
return glCreateShaderProgramv(type, 2, src);
}
bool ColorEqual(int x, int y, const vec3& c0, const vec3& expected, const vec3& epsilon, const vec3& color_max)
{
bool status = true;
if (fabs(c0[0] / color_max[0] - expected[0]) > epsilon[0])
status = false;
if (fabs(c0[1] / color_max[1] - expected[1]) > epsilon[1])
status = false;
if (fabs(c0[2] / color_max[2] - expected[2]) > epsilon[2])
status = false;
if (!status)
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Incorrect framebuffer color at pixel (" << x << " " << y << "). Color is ("
<< c0[0] / color_max[0] << " " << c0[1] / color_max[1] << " " << c0[2] / color_max[2]
<< "). Color should be (" << expected[0] << " " << expected[1] << " " << expected[2] << ")."
<< tcu::TestLog::EndMessage;
return status;
}
bool CheckFB(vec3 expected)
{
const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
const tcu::PixelFormat& pixelFormat = renderTarget.getPixelFormat();
vec3 g_color_eps = vec3(1.f / (float)(1 << pixelFormat.redBits), 1.f / (float)(1 << pixelFormat.greenBits),
1.f / (float)(1 << pixelFormat.blueBits));
vec3 g_color_max = vec3(255);
std::vector<GLubyte> fb(getWindowWidth() * getWindowHeight() * 4);
int fb_w = getWindowWidth();
int fb_h = getWindowHeight();
glReadPixels(0, 0, fb_w, fb_h, GL_RGBA, GL_UNSIGNED_BYTE, &fb[0]);
for (GLint i = 0, y = 0; y < fb_h; ++y)
for (GLint x = 0; x < fb_w; ++x, i += 4)
{
if (fabs(fb[i + 0] / g_color_max[0] - expected[0]) > g_color_eps[0] ||
fabs(fb[i + 1] / g_color_max[1] - expected[1]) > g_color_eps[1] ||
fabs(fb[i + 2] / g_color_max[2] - expected[2]) > g_color_eps[2])
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Incorrect framebuffer color at pixel (" << x << " " << y
<< "). Color is (" << fb[i + 0] / g_color_max[0] << " " << fb[i + 1] / g_color_max[1] << " "
<< fb[i + 2] / g_color_max[2] << "). Color should be (" << expected[0] << " " << expected[1]
<< " " << expected[2] << ")." << tcu::TestLog::EndMessage;
return false;
}
}
return true;
}
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();
vec3 g_color_eps = vec3(1.f / (float)(1 << pixelFormat.redBits), 1.f / (float)(1 << pixelFormat.greenBits),
1.f / (float)(1 << pixelFormat.blueBits));
vec3 g_color_max = vec3(255);
const int width = 100;
const int height = 100;
std::vector<GLubyte> fb(width * height * 4);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &fb[0]);
bool status = true;
int bad = 0;
// left-bottom quad
for (int y = 10, i = (100 * 10 + 10) * 4; y < height / 2 - 10; ++y, i += 70 * 4)
{
for (int x = 10; x < width / 2 - 10; ++x, i += 4)
{
const vec3 c = vec3(fb[i], fb[i + 1], fb[i + 2]);
if (!ColorEqual(x, y, c, lb, g_color_eps, g_color_max))
{
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, i = (100 * 10 + 60) * 4; y < height / 2 - 10; ++y, i += 70 * 4)
{
for (int x = width / 2 + 10; x < width - 10; ++x, i += 4)
{
const vec3 c = vec3(fb[i], fb[i + 1], fb[i + 2]);
if (!ColorEqual(x, y, c, rb, g_color_eps, g_color_max))
{
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, i = (100 * 60 + 60) * 4; y < height - 10; ++y, i += 70 * 4)
{
for (int x = width / 2 + 10; x < width - 10; ++x, i += 4)
{
const vec3 c = vec3(fb[i], fb[i + 1], fb[i + 2]);
if (!ColorEqual(x, y, c, rt, g_color_eps, g_color_max))
{
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, i = (100 * 60 + 10) * 4; y < height - 10; ++y, i += 70 * 4)
{
for (int x = 10; x < width / 2 - 10; ++x, i += 4)
{
const vec3 c = vec3(fb[i], fb[i + 1], fb[i + 2]);
if (!ColorEqual(x, y, c, lt, g_color_eps, g_color_max))
{
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, i = (100 * 48) * 4; y < height / 2 + 2; ++y)
{
for (int x = 0; x < width; ++x, i += 4)
{
const vec3 c = vec3(fb[i], fb[i + 1], fb[i + 2]);
if (!ColorEqual(x, y, c, vec3(0), g_color_eps, g_color_max))
{
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, i = 48 * 4; y < height; ++y, i += 96 * 4)
{
for (int x = width / 2 - 2; x < width / 2 + 2; ++x, i += 4)
{
const vec3 c = vec3(fb[i], fb[i + 1], fb[i + 2]);
if (!ColorEqual(x, y, c, vec3(0), g_color_eps, g_color_max))
{
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, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, tx, ty, tz, 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_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 BasicBasicVS : public ShaderStorageBufferObjectBase
{
GLuint m_program;
GLuint m_buffer;
GLuint m_vertex_array;
virtual long Setup()
{
m_program = 0;
m_buffer = 0;
m_vertex_array = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(1, 0))
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);
glClear(GL_COLOR_BUFFER_BIT);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer);
glDrawArraysInstanced(GL_TRIANGLES, 0, 3, 1);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, 0);
if (!CheckFB(vec3(0, 1, 0)))
return ERROR;
else
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;
GLboolean b;
glGetIntegerv(e, &i);
glGetInteger64v(e, &i64);
glGetFloatv(e, &f);
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 (!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 (!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_FRAGMENT_SHADER_STORAGE_BLOCKS, 0, true))
return ERROR;
if (!Check(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, 4, true))
return ERROR;
if (!Check(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, 4, true))
return ERROR;
if (!Check(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, 134217728 /* 2^27 */, true))
return ERROR;
if (!Check(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, 4, true))
return ERROR;
if (!Check(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, 4, 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;
GLboolean b;
GLfloat expectedFloat = static_cast<GLfloat>(expected);
glGetIntegerv(e, &i);
glGetInteger64v(e, &i64);
glGetFloatv(e, &f);
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) != expectedFloat)
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;
glGetIntegeri_v(e, index, &i);
glGetInteger64i_v(e, index, &i64);
bool status = true;
if (static_cast<GLuint>(i) != expected)
status = false;
if (static_cast<GLuint>(i64) != expected)
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()
{
GLint maxShaderStorageBufferBindings = 0;
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxShaderStorageBufferBindings);
// check default state
if (!Check(GL_SHADER_STORAGE_BUFFER_BINDING, 0))
return ERROR;
for (GLint i = 0; i < maxShaderStorageBufferBindings; ++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 (GLint i = 0; i < maxShaderStorageBufferBindings; ++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 (GLint i = 0; i < maxShaderStorageBufferBindings; ++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 (GLint i = 0; i < maxShaderStorageBufferBindings; ++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 BasicSyntaxVS : 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 CheckFB(vec3(0, 1, 0));
}
virtual long Setup()
{
m_program = 0;
m_buffer = 0;
m_vertex_array = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(1, 0))
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[2];" 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[2];" 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 "}";
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;
}
};
class BasicSyntaxCS : public ShaderStorageBufferObjectBase
{
GLuint m_program;
GLuint m_buffer[2];
bool RunIteration(const char* cs)
{
std::stringstream ss;
ss << "layout(local_size_x = 3) in;" NL "layout (std430) buffer Result {" NL " int result[3];" NL "};" << cs;
if (m_program != 0)
glDeleteProgram(m_program);
m_program = CreateProgramCS(ss.str());
glLinkProgram(m_program);
if (!CheckProgram(m_program))
return false;
glUseProgram(m_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer[0]);
GLint* out_data = (GLint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4 * 3, GL_MAP_READ_BIT);
if (!out_data)
return false;
bool result = out_data[0] == 7 && out_data[1] == 17 && out_data[2] == 23;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
GLint data[3] = { 0 };
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * 3, data, GL_STATIC_READ);
return result;
}
virtual long Setup()
{
m_program = 0;
memset(m_buffer, 0, sizeof(m_buffer));
return NO_ERROR;
}
virtual long Run()
{
const int kCount = 8;
const char* const glsl_cs[kCount] = {
NL "layout(std430, binding = 1) buffer Buffer {" NL " vec4 indata[3];" NL "} g_input_buffer;" NL
"void main() {" NL
" result[gl_LocalInvocationIndex] = int(g_input_buffer.indata[gl_LocalInvocationID.x].z);" NL "}",
NL "layout(binding = 1) coherent buffer Buffer {" NL " buffer vec4 indata0;" NL
" coherent vec4 indata1;" NL " restrict readonly vec4 indata2;" NL "} g_input_buffer;" NL
"void main() {" NL
" if (gl_LocalInvocationID.x == 0u) result[gl_LocalInvocationIndex] = int(g_input_buffer.indata0.z);" NL
" if (gl_LocalInvocationID.x == 1u) result[gl_LocalInvocationIndex] = int(g_input_buffer.indata1.z);" NL
" if (gl_LocalInvocationID.x == 2u) result[gl_LocalInvocationIndex] = int(g_input_buffer.indata2.z);" NL
"}",
NL "layout(std140, binding = 1) readonly buffer Buffer {" NL " readonly vec4 indata[];" NL "};" NL
"void main() {" NL " result[gl_LocalInvocationIndex] = int(indata[gl_LocalInvocationID.x].z);" NL "}",
NL "layout(std430, column_major, std140, std430, row_major, packed, shared) buffer;" NL
"layout(std430) buffer;" NL "layout(binding = 1) coherent restrict volatile buffer Buffer {" NL
" restrict coherent vec4 indata[];" NL "} g_buffer;" NL "void main() {" NL
" result[gl_LocalInvocationIndex] = int(g_buffer.indata[gl_LocalInvocationID.x].z);" NL "}",
NL "layout(binding = 1) buffer Buffer {" NL " vec4 indata[3];" //
NL "} g_buffer[1];" NL "void main() {" NL
" result[gl_LocalInvocationIndex] = int(g_buffer[0].indata[gl_LocalInvocationID.x].z);" NL "}",
NL
"layout(shared, binding = 1) coherent buffer Buffer {" NL " restrict volatile vec4 indata0;" NL
" buffer readonly vec4 indata1;" NL " vec4 indata2;" NL "} g_buffer[1];" NL "void main() {" NL
" if (gl_LocalInvocationID.x == 0u) result[gl_LocalInvocationIndex] = int(g_buffer[0].indata0.z);" NL
" else if (gl_LocalInvocationID.x == 1u) result[gl_LocalInvocationIndex] = int(g_buffer[0].indata1.z);" NL
" else if (gl_LocalInvocationID.x == 2u) result[gl_LocalInvocationIndex] = int(g_buffer[0].indata2.z);" NL
"}",
NL
"layout(packed, binding = 1) coherent buffer Buffer {" NL " vec4 indata01[2];" NL " vec4 indata2;" NL
"} g_buffer;" NL "void main() {" NL
" if (gl_LocalInvocationID.x == 0u) result[gl_LocalInvocationIndex] = int(g_buffer.indata01[0].z);" NL
" else if (gl_LocalInvocationID.x == 1u) result[gl_LocalInvocationIndex] = int(g_buffer.indata01[1].z);" NL
" else if (gl_LocalInvocationID.x == 2u) result[gl_LocalInvocationIndex] = int(g_buffer.indata2.z);" NL
"}",
NL "layout(std430, binding = 1) coherent buffer Buffer {" NL " coherent vec4 indata01[2];" NL
" vec4 indata2[];" NL "} g_buffer;" NL "void main() {" NL " switch (gl_LocalInvocationID.x) {" NL
" case 0u: result[gl_LocalInvocationIndex] = int(g_buffer.indata01[0].z); break;" NL
" case 1u: result[gl_LocalInvocationIndex] = int(g_buffer.indata01[1].z); break;" NL
" case 2u: result[gl_LocalInvocationIndex] = int(g_buffer.indata2[gl_LocalInvocationIndex-2u].z); "
"break;" NL " }" NL "}",
};
glGenBuffers(2, m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * 3, 0, GL_STATIC_READ);
const float data[12] = { -1.0f, -1.0f, 7.0f, 1.0f, 3.0f, -1.0f, 17.0f, 1.0f, -1.0f, 3.0f, 23.0f, 1.0f };
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
for (int i = 0; i < kCount; ++i)
{
if (!RunIteration(glsl_cs[i]))
return ERROR;
}
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteProgram(m_program);
glDeleteBuffers(2, m_buffer);
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 CheckFB(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 (!IsVSFSAvailable(1, 0))
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 " 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
" 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[2];" 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[2];" 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);
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 (!IsVSFSAvailable(2, 0))
return NOT_SUPPORTED;
std::vector<GLubyte> in_data;
const char* glsl_vs = GetInput(in_data);
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;
glGenBuffers(2, m_buffer);
std::vector<GLubyte> out_d(in_data.size());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)in_data.size(), &out_d[0], GL_STATIC_DRAW);
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);
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()
{
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;
}
else
{
}
}
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(17 * 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(17 * 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;" // offset = 0
NL " Struct1 m1;" // offset = 16
NL " Struct0 m2;" // offset = 32
NL " int m3;" // offset = 40
NL " Struct3 m4;" // offset = 44
NL "};" NL "layout(std430, binding = 0) buffer Input {" NL " int data0;" // offset = 0
NL " Struct0 data1;" // offset = 8
NL " float data2;" // offset = 16
NL " Struct1 data3;" // offset = 32
NL " Struct2 data4[2];" // offset = 48
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(5 * 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(18 * 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(29 * 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(25 * 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 BasicAtomicCase1VSFS : 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 (!IsVSFSAvailable(2, 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];" NL "flat out int vertexid;" NL
"void main() {" NL " gl_Position = g_in_position;" NL " vertexid = gl_VertexID;" NL "#ifdef GL_ES" NL
" gl_PointSize = 1.0f;" NL "#endif" NL NL
" // 0 is the initial value of g_uint_out while 7 is the value at the end shader execution." NL
" // Since vertex shader can be executed multiple times due to implementation dependent reasons," NL
" // initial validation should consider both value as possibility." NL
" uint ret = atomicExchange(g_uint_out[gl_VertexID], g_uint_value[1]);" NL
" if ((ret != 0u) && (ret != 7u)) 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
" int ret2 = atomicExchange(g_int_out.data[gl_VertexID], 1);" NL
" if ((ret2 != 0) && (ret2 != 7)) 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_fs = NL
"flat in int vertexid;" NL "layout(location = 0) out vec4 g_fs_out;" 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 " g_fs_out = vec4(0, 1, 0, 1);" NL NL
" if (atomicExchange(g_uint_fs.data[vertexid], g_uint_value[1]) != 0u) return;" // 0, 1
NL " if (atomicAdd(g_uint_fs.data[vertexid], g_uint_value[2]) != 1u) return;" // 1, 2
NL " if (atomicMin(g_uint_fs.data[vertexid], g_uint_value[1]) != 3u) return;" // 3, 1
NL " if (atomicMax(g_uint_fs.data[vertexid], g_uint_value[2]) != 1u) return;" // 1, 2
NL " if (atomicAnd(g_uint_fs.data[vertexid], g_uint_value[3]) != 2u) return;" // 2, 0x1
NL " if (atomicOr(g_uint_fs.data[vertexid], g_uint_value[4]) != 0u) return;" // 0, 0x3
NL " if (g_uint_value[0] > 0u) {" NL
" if (atomicXor(g_uint_fs.data[vertexid], g_uint_value[5]) != 3u) return;" // 0x3, 0x1
NL " }" NL
" if (atomicCompSwap(g_uint_fs.data[vertexid], g_uint_value[6], g_uint_value[7]) != 2u) {" // 2, 0x2, 0x7
NL " g_uint_fs.data[vertexid] = 1u;" NL " return;" NL " }" NL NL
" if (atomicExchange(g_int_fs.data[vertexid], 1) != 0) return;" NL
" if (atomicAdd(g_int_fs.data[vertexid], 2) != 1) return;" NL
" if (atomicMin(g_int_fs.data[vertexid], 1) != 3) return;" NL
" if (atomicMax(g_int_fs.data[vertexid], 2) != 1) return;" NL
" if (atomicAnd(g_int_fs.data[vertexid], 0x1) != 2) return;" NL
" if (atomicOr(g_int_fs.data[vertexid], 0x3) != 0) return;" NL
" if (atomicXor(g_int_fs.data[vertexid], 0x1) != 3) return;" NL
" if (atomicCompSwap(g_int_fs.data[vertexid], 0x2, 0x7) != 2) {" NL " g_int_fs.data[vertexid] = 1;" NL
" return;" NL " }" NL "}";
m_program = CreateProgram(glsl_vs, 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[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);
GLuint unif[8] = { 3, 1, 2, 1, 3, 1, 2, 7 };
glUniform1uiv(glGetUniformLocation(m_program, "g_uint_value[0]"), 8, unif);
glBindVertexArray(m_vertex_array);
glDrawArrays(GL_POINTS, 0, 4);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
for (int ii = 0; ii < 2; ++ii)
{
/* uint data */
{
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[ii * 2 + 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[ii * 2 + 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(4, 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;" // 0, 1
NL " if (atomicAdd(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[2]) != 1u) return;" // 1, 2
NL " if (atomicMin(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[1]) != 3u) return;" // 3, 1
NL " if (atomicMax(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[2]) != 1u) return;" // 1, 2
NL " if (atomicAnd(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[3]) != 2u) return;" // 2, 0x1
NL " if (atomicOr(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[4]) != 0u) return;" // 0, 0x3
NL " if (g_uint_value[0] > 0u) {" NL
" if (atomicXor(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[5]) != 3u) return;" // 0x3, 0x1
NL " }" NL " if (atomicCompSwap(g_uint_fs.data[gl_LocalInvocationIndex], g_uint_value[6], "
"g_uint_value[7]) != 2u) {" // 2, 0x2, 0x7
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.3 BasicAtomicCase3
//-----------------------------------------------------------------------------
class BasicAtomicCase3VSFS : 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 (!IsVSFSAvailable(1, 1))
return NOT_SUPPORTED;
const char* const glsl_vs = NL
"layout(location = 0) in vec4 g_in_position;" NL "layout(std430, binding = 0) coherent buffer Buffer {" NL
" uvec4 u[4];" NL " ivec3 i[4];" NL "} g_vs_buffer;" NL "flat out int vertexid;" NL "void main() {" NL
" vertexid = gl_VertexID;" NL " gl_Position = g_in_position;" NL "#ifdef GL_ES" NL
" gl_PointSize = 1.0f;" NL "#endif" 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_fs =
NL "layout(location = 0) out vec4 g_fs_out;" NL "layout(std430, binding = 0) coherent buffer Buffer {" NL
" uvec4 u[4];" NL " ivec3 i[4];" NL "} g_fs_buffer;" NL "flat in int vertexid;" NL "void main() {" NL
" g_fs_out = vec4(0, 1, 0, 1);" NL " atomicAdd(g_fs_buffer.u[0].x, g_fs_buffer.u[vertexid][1]);" NL
" atomicAdd(g_fs_buffer.i[0].x, g_fs_buffer.i[vertexid][1]);" NL "}";
m_program = CreateProgram(glsl_vs, 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*>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 8 * sizeof(int) * 4, GL_MAP_WRITE_BIT));
if (!ptr)
return ERROR;
for (int i = 0; i < 4; ++i)
{
ptr[i * 2] = ivec4(0, 1, 2, 0);
ptr[i * 2 + 1] = ivec4(0, 1, 2, 0);
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
/* init 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);
GLuint* u = (GLuint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4, GL_MAP_READ_BIT);
if (!u)
return ERROR;
if (*u != 16)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at offset 0 is " << *u
<< " should be 16." << tcu::TestLog::EndMessage;
return ERROR;
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
GLint* i = (GLint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64, 4, GL_MAP_READ_BIT);
if (!i)
return ERROR;
if (*i != 16)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at offset 0 is " << *i
<< " should be 16." << tcu::TestLog::EndMessage;
return ERROR;
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteProgram(m_program);
glDeleteBuffers(1, &m_storage_buffer);
glDeleteBuffers(1, &m_vertex_buffer);
glDeleteVertexArrays(1, &m_vertex_array);
return NO_ERROR;
}
};
class BasicAtomicCase3CS : public ShaderStorageBufferObjectBase
{
GLuint m_program;
GLuint m_storage_buffer;
virtual long Setup()
{
m_program = 0;
m_storage_buffer = 0;
return NO_ERROR;
}
virtual long Run()
{
const char* const glsl_cs =
NL "layout(local_size_y = 4) in;" NL "layout(std430) coherent buffer Buffer {" NL " uvec4 u[4];" NL
" ivec3 i[4];" NL "} g_fs_buffer;" NL "void main() {" NL
" atomicAdd(g_fs_buffer.u[0].x, g_fs_buffer.u[gl_LocalInvocationID.y][2]);" NL
" atomicAdd(g_fs_buffer.i[0].x, 2 * g_fs_buffer.i[gl_LocalInvocationID.y][1]);" NL
" atomicAdd(g_fs_buffer.u[0].x, g_fs_buffer.u[gl_LocalInvocationID.y].z);" NL
" atomicAdd(g_fs_buffer.i[0].x, 2 * g_fs_buffer.i[gl_LocalInvocationID.y].y);" NL "}";
m_program = CreateProgramCS(glsl_cs);
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*>(
glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 8 * sizeof(int) * 4, GL_MAP_WRITE_BIT));
if (!ptr)
return ERROR;
for (int i = 0; i < 4; ++i)
{
ptr[i * 2] = ivec4(0, 1, 2, 0);
ptr[i * 2 + 1] = ivec4(0, 1, 2, 0);
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
glUseProgram(m_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
GLuint* u = (GLuint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4, GL_MAP_READ_BIT);
if (!u)
return ERROR;
if (*u != 16)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at offset 0 is " << *u
<< " should be 16." << tcu::TestLog::EndMessage;
return ERROR;
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
GLint* i = (GLint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64, 4, GL_MAP_READ_BIT);
if (!i)
return ERROR;
if (*i != 16)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at offset 0 is " << *i
<< " should be 16." << tcu::TestLog::EndMessage;
return ERROR;
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteProgram(m_program);
glDeleteBuffers(1, &m_storage_buffer);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 1.8.4 BasicAtomicCase4
//-----------------------------------------------------------------------------
class BasicAtomicCase4VSFS : public ShaderStorageBufferObjectBase
{
GLuint m_program;
GLuint m_storage_buffer[2];
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 (!IsVSFSAvailable(2, 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 Counters {" NL " uint g_uint_counter;" NL
" int g_int_counter;" NL "};" NL "layout(std430, binding = 1) buffer Output {" NL " uint udata[8];" NL
" int idata[8];" NL "} g_output;" NL "void main() {" NL " gl_Position = g_in_position;" NL
"#ifdef GL_ES" NL " gl_PointSize = 1.0f;" NL "#endif" NL
" uint uidx = atomicAdd(g_uint_counter, 1u);" NL " int iidx = atomicAdd(g_int_counter, -1);" NL
" g_output.udata[uidx] = uidx;" NL " g_output.idata[iidx] = iidx;" NL "}";
const char* const glsl_fs =
NL "layout(location = 0) out vec4 g_fs_out;" NL "layout(std430, binding = 0) coherent buffer Counters {" NL
" uint g_uint_counter;" NL " int g_int_counter;" NL "};" NL
"layout(std430, binding = 1) buffer Output {" NL " uint udata[8];" NL " int idata[8];" NL
"} g_output;" NL "void main() {" NL " g_fs_out = vec4(0, 1, 0, 1);" NL
" uint uidx = atomicAdd(g_uint_counter, 1u);" NL " int iidx = atomicAdd(g_int_counter, -1);" NL
" g_output.udata[uidx] = uidx;" NL " g_output.idata[iidx] = iidx;" NL "}";
m_program = CreateProgram(glsl_vs, glsl_fs);
glLinkProgram(m_program);
if (!CheckProgram(m_program))
return ERROR;
glGenBuffers(2, m_storage_buffer);
/* counter buffer */
{
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 2 * sizeof(int), NULL, GL_DYNAMIC_DRAW);
int* ptr = reinterpret_cast<int*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 8, GL_MAP_WRITE_BIT));
if (!ptr)
return ERROR;
*ptr++ = 0;
*ptr++ = 7;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
/* output buffer */
{
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 16 * sizeof(int), NULL, 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);
GLuint* udata = (GLuint*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 32, GL_MAP_READ_BIT);
if (!udata)
return ERROR;
for (GLuint i = 0; i < 8; ++i)
{