blob: 26244916eb009c8513257bd8c8d3c20b5d1278d0 [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 "es31cShaderImageLoadStoreTests.hpp"
#include "gluContextInfo.hpp"
#include "glwEnums.hpp"
#include "tcuMatrix.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuVectorUtil.hpp"
#include <assert.h>
#include <cstdarg>
#include <map>
namespace glcts
{
using namespace glw;
namespace
{
typedef tcu::Vec2 vec2;
typedef tcu::Vec4 vec4;
typedef tcu::IVec4 ivec4;
typedef tcu::UVec4 uvec4;
typedef tcu::Mat4 mat4;
enum Target
{
T2D = 0,
T3D,
TCM,
T2DA
};
const char* const kGLSLVer = "#version 310 es";
const char* const kGLSLSIA = NL "#extension GL_OES_shader_image_atomic : require";
const char* const kGLSLPrec =
NL "precision highp float;" NL "precision highp int;" NL "precision highp sampler2D;" NL
"precision highp sampler3D;" NL "precision highp samplerCube;" NL "precision highp sampler2DArray;" NL
"precision highp isampler2D;" NL "precision highp isampler3D;" NL "precision highp isamplerCube;" NL
"precision highp isampler2DArray;" NL "precision highp usampler2D;" NL "precision highp usampler3D;" NL
"precision highp usamplerCube;" NL "precision highp usampler2DArray;" NL "precision highp image2D;" NL
"precision highp image3D;" NL "precision highp imageCube;" NL "precision highp image2DArray;" NL
"precision highp iimage2D;" NL "precision highp iimage3D;" NL "precision highp iimageCube;" NL
"precision highp iimage2DArray;" NL "precision highp uimage2D;" NL "precision highp uimage3D;" NL
"precision highp uimageCube;" NL "precision highp uimage2DArray;";
class ShaderImageLoadStoreBase : public glcts::SubcaseBase
{
public:
virtual std::string Title()
{
return "";
}
virtual std::string Purpose()
{
return "";
}
virtual std::string Method()
{
return "";
}
virtual std::string PassCriteria()
{
return "";
}
bool IsVSFSAvailable(int requiredVS, int requiredFS)
{
GLint imagesVS, imagesFS;
glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &imagesVS);
glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &imagesFS);
if (imagesVS >= requiredVS && imagesFS >= requiredFS)
return true;
else
{
std::ostringstream reason;
reason << "Required " << requiredVS << " VS image uniforms but only " << imagesVS << " available."
<< std::endl
<< "Required " << requiredFS << " FS image uniforms but only " << imagesFS << " available."
<< std::endl;
OutputNotSupported(reason.str());
return false;
}
}
bool IsSSBInVSFSAvailable(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;
}
}
bool IsImageAtomicSupported()
{
if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic"))
{
std::ostringstream reason;
reason << "Required GL_OES_shader_image_atomic is not available." << std::endl;
OutputNotSupported(reason.str());
return false;
}
return true;
}
bool AreOutputsAvailable(int required)
{
GLint outputs;
glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &outputs);
if (outputs < required)
{
std::ostringstream reason;
reason << "Required " << required << " shader output resources but only " << outputs << " available."
<< std::endl;
OutputNotSupported(reason.str());
return false;
}
return true;
}
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 vec4& c0, const vec4& 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;
if (fabs(c0[3] - c1[3]) > epsilon[3])
return false;
return true;
}
bool Equal(const vec4& v0, const vec4& v1, GLenum internalformat)
{
if (internalformat == GL_RGBA8_SNORM || internalformat == GL_RGBA8)
{
return ColorEqual(v0, v1, vec4(0.01f));
}
return (v0[0] == v1[0]) && (v0[1] == v1[1]) && (v0[2] == v1[2]) && (v0[3] == v1[3]);
}
bool Equal(const ivec4& a, const ivec4& b, GLenum)
{
return (a[0] == b[0]) && (a[1] == b[1]) && (a[2] == b[2]) && (a[3] == b[3]);
}
bool Equal(const uvec4& a, const uvec4& b, GLenum)
{
return (a[0] == b[0]) && (a[1] == b[1]) && (a[2] == b[2]) && (a[3] == b[3]);
}
template <class T>
std::string ToString(T v)
{
std::ostringstream s;
s << "[";
for (int i = 0; i < 4; ++i)
s << v[i] << (i == 3 ? "" : ",");
s << "]";
return s.str();
}
template <typename T>
bool CompareValues(T* map_data, int kSize, const T& expected_value, GLenum internalformat = 0, int layers = 1)
{
for (int i = 0; i < kSize * kSize * layers; ++i)
{
if (!Equal(map_data[i], expected_value, internalformat))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Value is: " << ToString(map_data[i])
<< ". Value should be: " << ToString(expected_value) << tcu::TestLog::EndMessage;
return false;
}
}
return true;
}
template <typename T>
bool CompareValues(bool always, T* map_data, int kSize, const T& expected_value, GLenum internalformat = 0,
int layers = 1)
{
(void)internalformat;
for (int i = 0; i < kSize * kSize * layers; ++i)
{
if (always)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Value is: " << ToString(map_data[i])
<< ". Value should be: " << ToString(expected_value) << tcu::TestLog::EndMessage;
}
}
return true;
}
bool CheckFB(vec4 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);
vec4 g_color_max = vec4(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 CompileShader(GLuint shader)
{
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLsizei length;
GLchar log[1024];
glGetShaderInfoLog(shader, sizeof(log), &length, log);
if (length > 1)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader Info Log:\n"
<< log << tcu::TestLog::EndMessage;
}
return false;
}
return true;
}
bool LinkProgram(GLuint program)
{
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLsizei length;
GLchar log[1024];
glGetProgramInfoLog(program, sizeof(log), &length, log);
if (length > 1)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n"
<< log << tcu::TestLog::EndMessage;
}
return false;
}
return true;
}
GLuint BuildProgram(const char* src_vs, const char* src_fs, bool SIAvs = false, bool SIAfs = false)
{
std::ostringstream osvs, osfs;
osvs << kGLSLVer << (SIAvs ? kGLSLSIA : "\n") << kGLSLPrec;
osfs << kGLSLVer << (SIAfs ? kGLSLSIA : "\n") << kGLSLPrec;
std::string hvs = osvs.str();
std::string hfs = osfs.str();
const GLuint p = glCreateProgram();
if (src_vs)
{
GLuint sh = glCreateShader(GL_VERTEX_SHADER);
glAttachShader(p, sh);
glDeleteShader(sh);
const char* const src[2] = { hvs.c_str(), src_vs };
glShaderSource(sh, 2, src, NULL);
if (!CompileShader(sh))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << src[0] << src[1] << tcu::TestLog::EndMessage;
return p;
}
}
if (src_fs)
{
GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
glAttachShader(p, sh);
glDeleteShader(sh);
const char* const src[2] = { hfs.c_str(), src_fs };
glShaderSource(sh, 2, src, NULL);
if (!CompileShader(sh))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << src[0] << src[1] << tcu::TestLog::EndMessage;
return p;
}
}
if (!LinkProgram(p))
{
if (src_vs)
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << kGLSLVer << src_vs << tcu::TestLog::EndMessage;
if (src_fs)
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << kGLSLVer << src_fs << tcu::TestLog::EndMessage;
return p;
}
return p;
}
GLuint CreateComputeProgram(const std::string& cs, bool SIA = false)
{
std::ostringstream oscs;
oscs << kGLSLVer << (SIA ? kGLSLSIA : "\n") << kGLSLPrec;
std::string hcs = oscs.str();
const GLuint p = glCreateProgram();
if (!cs.empty())
{
const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
glAttachShader(p, sh);
glDeleteShader(sh);
const char* const src[2] = { hcs.c_str(), cs.c_str() };
glShaderSource(sh, 2, src, NULL);
if (!CompileShader(sh))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << src[0] << src[1] << tcu::TestLog::EndMessage;
return p;
}
}
if (!LinkProgram(p))
{
if (!cs.empty())
m_context.getTestContext().getLog() << tcu::TestLog::Message << hcs << cs << tcu::TestLog::EndMessage;
return p;
}
return p;
}
GLuint BuildShaderProgram(GLenum type, const char* src)
{
const char* const src3[3] = { kGLSLVer, kGLSLPrec, src };
const GLuint p = glCreateShaderProgramv(type, 3, src3);
GLint status;
glGetProgramiv(p, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLchar log[1024];
glGetProgramInfoLog(p, sizeof(log), NULL, log);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n"
<< src3[0] << "\n"
<< src3[1] << "\n"
<< src3[2] << tcu::TestLog::EndMessage;
}
return p;
}
void CreateFullViewportQuad(GLuint* vao, GLuint* vbo, GLuint* ebo)
{
assert(vao && vbo);
// interleaved data (vertex, color0 (green), color1 (blue), color2 (red))
const float v[] = {
-1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f,
};
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
if (ebo)
{
std::vector<GLushort> index_data(4);
for (int i = 0; i < 4; ++i)
{
index_data[i] = static_cast<GLushort>(i);
}
glGenBuffers(1, ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 4, &index_data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
glGenVertexArrays(1, vao);
glBindVertexArray(*vao);
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 2));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 5));
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 8));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
if (ebo)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
}
glBindVertexArray(0);
}
std::string FormatEnumToString(GLenum e)
{
switch (e)
{
case GL_RGBA32F:
return "rgba32f";
case GL_RGBA16F:
return "rgba16f";
case GL_R32F:
return "r32f";
case GL_RGBA32UI:
return "rgba32ui";
case GL_RGBA16UI:
return "rgba16ui";
case GL_RGBA8UI:
return "rgba8ui";
case GL_R32UI:
return "r32ui";
case GL_RGBA32I:
return "rgba32i";
case GL_RGBA16I:
return "rgba16i";
case GL_RGBA8I:
return "rgba8i";
case GL_R32I:
return "r32i";
case GL_RGBA8:
return "rgba8";
case GL_RGBA8_SNORM:
return "rgba8_snorm";
}
assert(0);
return "";
}
template <typename T>
GLenum Format();
template <typename T>
GLenum Type();
template <typename T>
std::string TypePrefix();
template <typename T>
GLenum ImageType(GLenum target);
void ClearBuffer(GLenum buffer, GLint drawbuffer, const vec4& color)
{
glClearBufferfv(buffer, drawbuffer, &color[0]);
}
void ClearBuffer(GLenum buffer, GLint drawbuffer, const ivec4& color)
{
glClearBufferiv(buffer, drawbuffer, &color[0]);
}
void ClearBuffer(GLenum buffer, GLint drawbuffer, const uvec4& color)
{
glClearBufferuiv(buffer, drawbuffer, &color[0]);
}
bool CheckMax(GLenum pname, GLint min_value)
{
GLboolean b;
GLint i;
GLfloat f;
GLint64 i64;
glGetIntegerv(pname, &i);
if (i < min_value)
return false;
glGetBooleanv(pname, &b);
if (b != (i ? GL_TRUE : GL_FALSE))
return false;
glGetFloatv(pname, &f);
if (f < static_cast<GLfloat>(min_value))
return false;
glGetInteger64v(pname, &i64);
if (i64 < static_cast<GLint64>(min_value))
return false;
return true;
}
bool CheckBinding(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
GLenum format)
{
GLint i;
GLboolean b;
glGetIntegeri_v(GL_IMAGE_BINDING_NAME, unit, &i);
if (static_cast<GLuint>(i) != texture)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_IMAGE_BINDING_NAME is " << i
<< " should be " << texture << tcu::TestLog::EndMessage;
return false;
}
glGetIntegeri_v(GL_IMAGE_BINDING_LEVEL, unit, &i);
if (i != level)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_IMAGE_BINDING_LEVEL is " << i
<< " should be " << level << tcu::TestLog::EndMessage;
return false;
}
glGetIntegeri_v(GL_IMAGE_BINDING_LAYERED, unit, &i);
glGetBooleani_v(GL_IMAGE_BINDING_LAYERED, unit, &b);
if (i != layered || b != layered)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_IMAGE_BINDING_LAYERED is " << i
<< " should be " << layered << tcu::TestLog::EndMessage;
return false;
}
glGetIntegeri_v(GL_IMAGE_BINDING_LAYER, unit, &i);
if (i != layer)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_IMAGE_BINDING_LAYER is " << i
<< " should be " << layer << tcu::TestLog::EndMessage;
return false;
}
glGetIntegeri_v(GL_IMAGE_BINDING_ACCESS, unit, &i);
if (static_cast<GLenum>(i) != access)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_IMAGE_BINDING_ACCESS is " << i
<< " should be " << access << tcu::TestLog::EndMessage;
return false;
}
glGetIntegeri_v(GL_IMAGE_BINDING_FORMAT, unit, &i);
if (static_cast<GLenum>(i) != format)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_IMAGE_BINDING_FORMAT is " << i
<< " should be " << format << tcu::TestLog::EndMessage;
return false;
}
return true;
}
const char* EnumToString(GLenum e)
{
switch (e)
{
case GL_TEXTURE_2D:
return "GL_TEXTURE_2D";
case GL_TEXTURE_3D:
return "GL_TEXTURE_3D";
case GL_TEXTURE_CUBE_MAP:
return "GL_TEXTURE_CUBE_MAP";
case GL_TEXTURE_2D_ARRAY:
return "GL_TEXTURE_2D_ARRAY";
default:
assert(0);
break;
}
return NULL;
}
};
template <>
GLenum ShaderImageLoadStoreBase::Format<vec4>()
{
return GL_RGBA;
}
template <>
GLenum ShaderImageLoadStoreBase::Format<ivec4>()
{
return GL_RGBA_INTEGER;
}
template <>
GLenum ShaderImageLoadStoreBase::Format<uvec4>()
{
return GL_RGBA_INTEGER;
}
template <>
GLenum ShaderImageLoadStoreBase::Format<GLint>()
{
return GL_RED_INTEGER;
}
template <>
GLenum ShaderImageLoadStoreBase::Format<GLuint>()
{
return GL_RED_INTEGER;
}
template <>
GLenum ShaderImageLoadStoreBase::Type<vec4>()
{
return GL_FLOAT;
}
template <>
GLenum ShaderImageLoadStoreBase::Type<ivec4>()
{
return GL_INT;
}
template <>
GLenum ShaderImageLoadStoreBase::Type<uvec4>()
{
return GL_UNSIGNED_INT;
}
template <>
GLenum ShaderImageLoadStoreBase::Type<GLint>()
{
return GL_INT;
}
template <>
GLenum ShaderImageLoadStoreBase::Type<GLuint>()
{
return GL_UNSIGNED_INT;
}
template <>
std::string ShaderImageLoadStoreBase::TypePrefix<vec4>()
{
return "";
}
template <>
std::string ShaderImageLoadStoreBase::TypePrefix<ivec4>()
{
return "i";
}
template <>
std::string ShaderImageLoadStoreBase::TypePrefix<uvec4>()
{
return "u";
}
template <>
std::string ShaderImageLoadStoreBase::TypePrefix<GLint>()
{
return "i";
}
template <>
std::string ShaderImageLoadStoreBase::TypePrefix<GLuint>()
{
return "u";
}
template <>
GLenum ShaderImageLoadStoreBase::ImageType<vec4>(GLenum target)
{
switch (target)
{
case GL_TEXTURE_2D:
return GL_IMAGE_2D;
case GL_TEXTURE_3D:
return GL_IMAGE_3D;
case GL_TEXTURE_CUBE_MAP:
return GL_IMAGE_CUBE;
case GL_TEXTURE_2D_ARRAY:
return GL_IMAGE_2D_ARRAY;
}
assert(0);
return 0;
}
template <>
GLenum ShaderImageLoadStoreBase::ImageType<ivec4>(GLenum target)
{
switch (target)
{
case GL_TEXTURE_2D:
return GL_INT_IMAGE_2D;
case GL_TEXTURE_3D:
return GL_INT_IMAGE_3D;
case GL_TEXTURE_CUBE_MAP:
return GL_INT_IMAGE_CUBE;
case GL_TEXTURE_2D_ARRAY:
return GL_INT_IMAGE_2D_ARRAY;
}
assert(0);
return 0;
}
template <>
GLenum ShaderImageLoadStoreBase::ImageType<uvec4>(GLenum target)
{
switch (target)
{
case GL_TEXTURE_2D:
return GL_UNSIGNED_INT_IMAGE_2D;
case GL_TEXTURE_3D:
return GL_UNSIGNED_INT_IMAGE_3D;
case GL_TEXTURE_CUBE_MAP:
return GL_UNSIGNED_INT_IMAGE_CUBE;
case GL_TEXTURE_2D_ARRAY:
return GL_UNSIGNED_INT_IMAGE_2D_ARRAY;
}
assert(0);
return 0;
}
int Components(GLenum e)
{
return (e == GL_RED || e == GL_RED_INTEGER) ? 1 : 4;
}
bool Shorts(GLenum e)
{
return (e == GL_RGBA16I || e == GL_RGBA16UI);
}
bool Bytes(GLenum e)
{
return (e == GL_RGBA8I || e == GL_RGBA8UI || e == GL_RGBA8 || e == GL_RGBA8_SNORM);
}
template <typename T>
class ShortByteData
{
public:
std::vector<T> data;
std::vector<GLshort> datas;
std::vector<GLbyte> datab;
ShortByteData(int size, const T& value, GLenum internalformat, GLenum format)
: data(size * size, value), datas(size * size * 4), datab(size * size * 4)
{
if (Components(format) == 1)
for (unsigned i = 0; i < data.size() / 4; ++i)
{
data[i][0] = data[i * 4][0];
data[i][1] = data[i * 4 + 1][0];
data[i][2] = data[i * 4 + 2][0];
data[i][3] = data[i * 4 + 3][0];
}
if (Shorts(internalformat))
{
for (unsigned i = 0; i < datas.size(); i += 4)
{
datas[i] = static_cast<GLshort>(data[i / 4][0]);
datas[i + 1] = static_cast<GLshort>(data[i / 4][1]);
datas[i + 2] = static_cast<GLshort>(data[i / 4][2]);
datas[i + 3] = static_cast<GLshort>(data[i / 4][3]);
}
}
if (Bytes(internalformat))
{
for (unsigned i = 0; i < datas.size(); i += 4)
{
if (internalformat == GL_RGBA8I || internalformat == GL_RGBA8UI)
{
datab[i] = static_cast<GLbyte>(data[i / 4][0]);
datab[i + 1] = static_cast<GLbyte>(data[i / 4][1]);
datab[i + 2] = static_cast<GLbyte>(data[i / 4][2]);
datab[i + 3] = static_cast<GLbyte>(data[i / 4][3]);
}
else if (internalformat == GL_RGBA8)
{
datab[i] = static_cast<GLbyte>(data[i / 4][0] * 255);
datab[i + 1] = static_cast<GLbyte>(data[i / 4][1] * 255);
datab[i + 2] = static_cast<GLbyte>(data[i / 4][2] * 255);
datab[i + 3] = static_cast<GLbyte>(data[i / 4][3] * 255);
}
else
{ // GL_RGBA8_SNORM
datab[i] = static_cast<GLbyte>(data[i / 4][0] * 127);
datab[i + 1] = static_cast<GLbyte>(data[i / 4][1] * 127);
datab[i + 2] = static_cast<GLbyte>(data[i / 4][2] * 127);
datab[i + 3] = static_cast<GLbyte>(data[i / 4][3] * 127);
}
}
}
}
};
//-----------------------------------------------------------------------------
// 1.1.1 BasicAPIGet
//-----------------------------------------------------------------------------
class BasicAPIGet : public ShaderImageLoadStoreBase
{
virtual long Run()
{
if (!CheckMax(GL_MAX_IMAGE_UNITS, 4))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_IMAGE_UNITS value is invalid." << tcu::TestLog::EndMessage;
return ERROR;
}
if (!CheckMax(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, 4))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES value is invalid."
<< tcu::TestLog::EndMessage;
return ERROR;
}
if (!CheckMax(GL_MAX_VERTEX_IMAGE_UNIFORMS, 0))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_VERTEX_IMAGE_UNIFORMS value is invalid."
<< tcu::TestLog::EndMessage;
return ERROR;
}
if (!CheckMax(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, 0))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_FRAGMENT_IMAGE_UNIFORMS value is invalid."
<< tcu::TestLog::EndMessage;
return ERROR;
}
if (!CheckMax(GL_MAX_COMBINED_IMAGE_UNIFORMS, 4))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_COMBINED_IMAGE_UNIFORMS value is invalid."
<< tcu::TestLog::EndMessage;
return ERROR;
}
if (!CheckMax(GL_MAX_COMPUTE_IMAGE_UNIFORMS, 4))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_COMPUTE_IMAGE_UNIFORMS value is invalid."
<< tcu::TestLog::EndMessage;
return ERROR;
}
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 1.1.2 BasicAPIBind
//-----------------------------------------------------------------------------
class BasicAPIBind : public ShaderImageLoadStoreBase
{
GLuint m_texture;
virtual long Setup()
{
m_texture = 0;
return NO_ERROR;
}
virtual long Run()
{
bool status = true;
for (GLuint index = 0; index < 4; ++index)
{
if (!CheckBinding(index, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Binding point " << index
<< " has invalid default state." << tcu::TestLog::EndMessage;
status = false;
}
}
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 4, GL_RG32F, 16, 16, 4);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
if (!CheckBinding(0, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F))
status = false;
glBindImageTexture(3, m_texture, 1, GL_TRUE, 1, GL_WRITE_ONLY, GL_RGBA8);
if (!CheckBinding(3, m_texture, 1, GL_TRUE, 1, GL_WRITE_ONLY, GL_RGBA8))
status = false;
glBindImageTexture(1, m_texture, 3, GL_FALSE, 2, GL_READ_WRITE, GL_RGBA8UI);
if (!CheckBinding(1, m_texture, 3, GL_FALSE, 2, GL_READ_WRITE, GL_RGBA8UI))
status = false;
glBindImageTexture(2, m_texture, 4, GL_FALSE, 3, GL_READ_ONLY, GL_R32I);
if (!CheckBinding(2, m_texture, 4, GL_FALSE, 3, GL_READ_ONLY, GL_R32I))
status = false;
glDeleteTextures(1, &m_texture);
m_texture = 0;
for (GLuint index = 0; index < 4; ++index)
{
GLint name;
glGetIntegeri_v(GL_IMAGE_BINDING_NAME, index, &name);
if (name != 0)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Binding point " << index
<< " should be set to 0 after texture deletion." << tcu::TestLog::EndMessage;
status = false;
}
if (!CheckBinding(index, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI))
status = false;
}
return status ? NO_ERROR : ERROR;
}
virtual long Cleanup()
{
glDeleteTextures(1, &m_texture);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 1.1.3 BasicAPIBarrier
//-----------------------------------------------------------------------------
class BasicAPIBarrier : public ShaderImageLoadStoreBase
{
virtual long Run()
{
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
glMemoryBarrier(GL_ELEMENT_ARRAY_BARRIER_BIT);
glMemoryBarrier(GL_UNIFORM_BARRIER_BIT);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glMemoryBarrier(GL_COMMAND_BARRIER_BIT);
glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT);
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
glMemoryBarrier(GL_TRANSFORM_FEEDBACK_BARRIER_BIT);
glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | GL_ELEMENT_ARRAY_BARRIER_BIT | GL_UNIFORM_BARRIER_BIT |
GL_TEXTURE_FETCH_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_COMMAND_BARRIER_BIT |
GL_PIXEL_BUFFER_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT |
GL_FRAMEBUFFER_BARRIER_BIT | GL_TRANSFORM_FEEDBACK_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT |
GL_SHADER_STORAGE_BARRIER_BIT);
glMemoryBarrier(GL_ALL_BARRIER_BITS);
return NO_ERROR;
}
};
class BasicAPIBarrierByRegion : public ShaderImageLoadStoreBase
{
virtual long Run()
{
glMemoryBarrierByRegion(GL_UNIFORM_BARRIER_BIT);
glMemoryBarrierByRegion(GL_TEXTURE_FETCH_BARRIER_BIT);
glMemoryBarrierByRegion(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glMemoryBarrierByRegion(GL_FRAMEBUFFER_BARRIER_BIT);
glMemoryBarrierByRegion(GL_ATOMIC_COUNTER_BARRIER_BIT);
glMemoryBarrierByRegion(GL_SHADER_STORAGE_BARRIER_BIT);
glMemoryBarrierByRegion(GL_UNIFORM_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT |
GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT |
GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT);
glMemoryBarrierByRegion(GL_ALL_BARRIER_BITS);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 1.1.4 BasicAPITexParam
//-----------------------------------------------------------------------------
class BasicAPITexParam : public ShaderImageLoadStoreBase
{
GLuint m_texture;
virtual long Setup()
{
m_texture = 0;
return NO_ERROR;
}
virtual long Run()
{
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexStorage2D(GL_TEXTURE_2D, 5, GL_RG32F, 16, 16);
GLint i;
GLfloat f;
glGetTexParameteriv(GL_TEXTURE_2D, GL_IMAGE_FORMAT_COMPATIBILITY_TYPE, &i);
if (i != GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_IMAGE_FORMAT_COMPATIBILITY_TYPE should equal to "
"GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE for textures allocated by the GL."
<< tcu::TestLog::EndMessage;
return ERROR;
}
glGetTexParameterfv(GL_TEXTURE_2D, GL_IMAGE_FORMAT_COMPATIBILITY_TYPE, &f);
if (static_cast<GLenum>(f) != GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_IMAGE_FORMAT_COMPATIBILITY_TYPE should equal to "
"GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE for textures allocated by the GL."
<< tcu::TestLog::EndMessage;
return ERROR;
}
return NO_ERROR;
}
virtual long Cleanup()
{
glDeleteTextures(1, &m_texture);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 1.2.1 BasicAllFormatsStore
//-----------------------------------------------------------------------------
class BasicAllFormatsStoreFS : public ShaderImageLoadStoreBase
{
GLuint m_vao, m_vbo;
virtual long Setup()
{
m_vao = 0;
m_vbo = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(0, 1))
return NOT_SUPPORTED;
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
if (!Write(GL_RGBA32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!Write(GL_R32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!Write(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_R32UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RGBA8, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Write(GL_RGBA8_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f)))
return ERROR;
return NO_ERROR;
}
template <typename T>
bool Write(GLenum internalformat, const T& write_value, const T& expected_value)
{
const char* src_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
GLuint program = BuildProgram(src_vs, GenFS(internalformat, write_value).c_str());
const int kSize = 11;
std::vector<T> data(kSize * kSize);
GLuint texture;
glGenTextures(1, &texture);
glUseProgram(program);
GLuint unit = 2;
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
glBindTexture(GL_TEXTURE_2D, 0);
glViewport(0, 0, kSize, kSize);
glBindImageTexture(unit, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat);
glBindVertexArray(m_vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, texture);
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
GLuint c_program = CreateComputeProgram(GenC(write_value));
std::vector<T> out_data(kSize * kSize);
GLuint m_buffer;
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &out_data[0], GL_STATIC_DRAW);
glUseProgram(c_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
T* map_data = (T*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize * kSize; ++i)
{
if (!Equal(map_data[i], expected_value, internalformat))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Value is: " << ToString(map_data[i])
<< ". Value should be: " << ToString(expected_value)
<< ". Format is: " << FormatEnumToString(internalformat) << ". Unit is: " << unit
<< tcu::TestLog::EndMessage;
glDeleteTextures(1, &texture);
glUseProgram(0);
glDeleteProgram(program);
glDeleteProgram(c_program);
glDeleteBuffers(1, &m_buffer);
return false;
}
}
glDeleteTextures(1, &texture);
glUseProgram(0);
glDeleteProgram(program);
glDeleteProgram(c_program);
glDeleteBuffers(1, &m_buffer);
return true;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
return NO_ERROR;
}
template <typename T>
std::string GenFS(GLenum internalformat, const T& value)
{
std::ostringstream os;
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 2) writeonly uniform "
<< TypePrefix<T>() << "image2D g_image;" NL "void main() {" NL " ivec2 coord = ivec2(gl_FragCoord.xy);" NL
" imageStore(g_image, coord, "
<< TypePrefix<T>() << "vec4" << value << ");" NL " discard;" NL "}";
return os.str();
}
template <typename T>
std::string GenC(const T& value)
{
std::ostringstream os;
os << NL "#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL "uniform "
<< TypePrefix<T>() << "sampler2D g_sampler;" NL "layout(std430) buffer OutputBuffer {" NL " "
<< TypePrefix<T>()
<< "vec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL
" data[gl_LocalInvocationIndex] = texelFetch(g_sampler, ivec2(gl_LocalInvocationID), 0);" NL
" //data[gl_LocalInvocationIndex] = "
<< value << ";" NL "}";
return os.str();
}
};
class BasicAllFormatsStoreCS : public ShaderImageLoadStoreBase
{
virtual long Setup()
{
return NO_ERROR;
}
template <typename T>
std::string GenCS(GLenum internalformat, const T& value)
{
std::ostringstream os;
os << NL "#define KSIZE 4" NL "layout(" << FormatEnumToString(internalformat) << ") writeonly uniform "
<< TypePrefix<T>()
<< "image2D g_image;" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL "void main() {" NL
" ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL " imageStore(g_image, thread_xy, "
<< TypePrefix<T>() << "vec4" << value << ");" NL "}";
return os.str();
}
template <typename T>
std::string GenC(const T& value)
{
std::ostringstream os;
os << NL "#define KSIZE 4" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL "uniform "
<< TypePrefix<T>() << "sampler2D g_sampler;" NL "layout(std430) buffer OutputBuffer {" NL " "
<< TypePrefix<T>()
<< "vec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL
" data[gl_LocalInvocationIndex] = texelFetch(g_sampler, ivec2(gl_LocalInvocationID), 0);" NL
" //data[gl_LocalInvocationIndex] = "
<< TypePrefix<T>() << "vec4" << value << ";" NL "}";
return os.str();
}
template <typename T>
bool WriteCS(GLenum internalformat, const T& write_value, const T& expected_value)
{
const int kSize = 4;
GLuint program = CreateComputeProgram(GenCS(internalformat, write_value));
std::vector<T> data(kSize * kSize);
GLuint texture;
glGenTextures(1, &texture);
GLuint unit = 0;
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
glBindTexture(GL_TEXTURE_2D, 0);
glBindImageTexture(unit, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat);
glUseProgram(program);
glDispatchCompute(1, 1, 1);
glBindTexture(GL_TEXTURE_2D, texture);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
GLuint c_program = CreateComputeProgram(GenC(expected_value));
std::vector<T> out_data(kSize * kSize);
GLuint m_buffer;
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &out_data[0], GL_STATIC_DRAW);
glUseProgram(c_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
T* map_data = (T*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize * kSize; ++i)
{
if (!Equal(map_data[i], expected_value, internalformat))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Value is: " << ToString(map_data[i])
<< ". Value should be: " << ToString(expected_value)
<< ". Format is: " << FormatEnumToString(internalformat) << ". Unit is: " << unit
<< tcu::TestLog::EndMessage;
glDeleteTextures(1, &texture);
glUseProgram(0);
glDeleteProgram(program);
glDeleteProgram(c_program);
glDeleteBuffers(1, &m_buffer);
return false;
}
}
glDeleteTextures(1, &texture);
glUseProgram(0);
glDeleteProgram(program);
glDeleteProgram(c_program);
glDeleteBuffers(1, &m_buffer);
return true;
}
virtual long Run()
{
if (!WriteCS(GL_RGBA32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!WriteCS(GL_R32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!WriteCS(GL_RGBA16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!WriteCS(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!WriteCS(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!WriteCS(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!WriteCS(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!WriteCS(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!WriteCS(GL_R32UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!WriteCS(GL_RGBA16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!WriteCS(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!WriteCS(GL_RGBA8, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!WriteCS(GL_RGBA8_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 1.2.2 BasicAllFormatsLoad
//-----------------------------------------------------------------------------
class BasicAllFormatsLoadFS : public ShaderImageLoadStoreBase
{
GLuint m_vao, m_vbo;
virtual long Setup()
{
m_vao = 0;
m_vbo = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(0, 1) || !IsSSBInVSFSAvailable(0, 1))
return NOT_SUPPORTED;
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
if (!Read(GL_RGBA32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f), GL_RGBA, GL_FLOAT))
return ERROR;
if (!Read(GL_R32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f), GL_RED, GL_FLOAT))
return ERROR;
if (!Read(GL_RGBA16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f), GL_RGBA, GL_FLOAT))
return ERROR;
if (!Read(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1), GL_RED_INTEGER, GL_INT))
return ERROR;
if (!Read(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4), GL_RGBA_INTEGER, GL_SHORT))
return ERROR;
if (!Read(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4), GL_RGBA_INTEGER, GL_BYTE))
return ERROR;
if (!Read(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(GL_R32UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1), GL_RED_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(GL_RGBA16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3), GL_RGBA_INTEGER, GL_UNSIGNED_SHORT))
return ERROR;
if (!Read(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3), GL_RGBA_INTEGER, GL_UNSIGNED_BYTE))
return ERROR;
if (!Read(GL_RGBA8, vec4(1.0f), vec4(1.0f), GL_RGBA, GL_UNSIGNED_BYTE))
return ERROR;
if (!Read(GL_RGBA8_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f), GL_RGBA, GL_BYTE))
return ERROR;
return NO_ERROR;
}
template <typename T>
bool Read(GLenum internalformat, const T& value, const T& expected_value, GLenum format, GLenum type)
{
const char* src_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
GLuint program = BuildProgram(src_vs, GenFS(internalformat, expected_value).c_str());
const int kSize = 11;
ShortByteData<T> d(kSize, value, internalformat, format);
GLuint texture;
glGenTextures(1, &texture);
GLuint unit = 1;
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
if (Shorts(internalformat))
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &d.datas[0]);
else if (Bytes(internalformat))
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &d.datab[0]);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &d.data[0]);
glBindTexture(GL_TEXTURE_2D, 0);
glViewport(0, 0, kSize, kSize);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glBindImageTexture(unit, texture, 0, GL_FALSE, 0, GL_READ_ONLY, internalformat);
glBindVertexArray(m_vao);
std::vector<T> out_data(kSize * kSize);
GLuint m_buffer;
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &out_data[0], GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
T* map_data = (T*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize * kSize; ++i)
{
if (!Equal(map_data[i], expected_value, internalformat))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Value is: " << ToString(map_data[i])
<< ". Value should be: " << ToString(expected_value)
<< ". Format is: " << FormatEnumToString(internalformat) << ". Unit is: " << unit
<< tcu::TestLog::EndMessage;
glUseProgram(0);
glDeleteProgram(program);
glDeleteTextures(1, &texture);
glDeleteBuffers(1, &m_buffer);
return false;
}
}
glUseProgram(0);
glDeleteProgram(program);
glDeleteTextures(1, &texture);
glDeleteBuffers(1, &m_buffer);
return true;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
return NO_ERROR;
}
template <typename T>
std::string GenFS(GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << NL "#define KSIZE 11" NL "layout(" << FormatEnumToString(internalformat)
<< ", binding = 1) readonly uniform " << TypePrefix<T>()
<< "image2D g_image;" NL "layout(std430) buffer OutputBuffer {" NL " " << TypePrefix<T>()
<< "vec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL " ivec2 coord = ivec2(gl_FragCoord.xy);" NL " "
<< TypePrefix<T>() << "vec4 v = imageLoad(g_image, coord);" NL " data[coord.y * KSIZE + coord.x] = v;" NL
" //data[coord.y * KSIZE + coord.x] = "
<< TypePrefix<T>() << "vec4" << expected_value << ";" NL " discard;" NL "}";
return os.str();
}
};
class BasicAllFormatsLoadCS : public ShaderImageLoadStoreBase
{
virtual long Setup()
{
return NO_ERROR;
}
template <typename T>
std::string GenCS(GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << NL "#define KSIZE 4" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL "layout("
<< FormatEnumToString(internalformat) << ", binding = 1) readonly uniform " << TypePrefix<T>()
<< "image2D g_image;" NL "layout(std430) buffer OutputBuffer {" NL " " << TypePrefix<T>()
<< "vec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID);" NL
" "
<< TypePrefix<T>() << "vec4 v = imageLoad(g_image, coord);" NL " data[gl_LocalInvocationIndex] = v;" NL
" //data[gl_LocalInvocationIndex] = "
<< TypePrefix<T>() << "vec4" << expected_value << ";" NL "}";
return os.str();
}
virtual long Run()
{
if (!ReadCS(GL_RGBA32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f), GL_RGBA, GL_FLOAT))
return ERROR;
if (!ReadCS(GL_R32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f), GL_RED, GL_FLOAT))
return ERROR;
if (!ReadCS(GL_RGBA16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f), GL_RGBA, GL_FLOAT))
return ERROR;
if (!ReadCS(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!ReadCS(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1), GL_RED_INTEGER, GL_INT))
return ERROR;
if (!ReadCS(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4), GL_RGBA_INTEGER, GL_SHORT))
return ERROR;
if (!ReadCS(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4), GL_RGBA_INTEGER, GL_BYTE))
return ERROR;
if (!ReadCS(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!ReadCS(GL_R32UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1), GL_RED_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!ReadCS(GL_RGBA16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3), GL_RGBA_INTEGER, GL_UNSIGNED_SHORT))
return ERROR;
if (!ReadCS(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3), GL_RGBA_INTEGER, GL_UNSIGNED_BYTE))
return ERROR;
if (!ReadCS(GL_RGBA8, vec4(1.0f), vec4(1.0f), GL_RGBA, GL_UNSIGNED_BYTE))
return ERROR;
if (!ReadCS(GL_RGBA8_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f), GL_RGBA, GL_BYTE))
return ERROR;
return NO_ERROR;
}
template <typename T>
bool ReadCS(GLenum internalformat, const T& value, const T& expected_value, GLenum format, GLenum type)
{
GLuint program = CreateComputeProgram(GenCS(internalformat, expected_value));
const int kSize = 4;
ShortByteData<T> d(kSize, value, internalformat, format);
GLuint texture;
glGenTextures(1, &texture);
GLuint unit = 1;
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
if (Shorts(internalformat))
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &d.datas[0]);
else if (Bytes(internalformat))
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &d.datab[0]);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &d.data[0]);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(program);
glBindImageTexture(unit, texture, 0, GL_FALSE, 0, GL_READ_ONLY, internalformat);
std::vector<T> out_data(kSize * kSize);
GLuint m_buffer;
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &out_data[0], GL_STATIC_DRAW);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
T* map_data = (T*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize * kSize; ++i)
{
if (!Equal(map_data[i], expected_value, internalformat))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Value is: " << ToString(map_data[i])
<< ". Value should be: " << ToString(expected_value)
<< ". Format is: " << FormatEnumToString(internalformat) << ". Unit is: " << unit
<< tcu::TestLog::EndMessage;
glUseProgram(0);
glDeleteProgram(program);
glDeleteTextures(1, &texture);
glDeleteBuffers(1, &m_buffer);
return false;
}
}
glUseProgram(0);
glDeleteProgram(program);
glDeleteTextures(1, &texture);
glDeleteBuffers(1, &m_buffer);
return true;
}
virtual long Cleanup()
{
return NO_ERROR;
}
};
class BasicAllFormatsLoadStoreComputeStage : public ShaderImageLoadStoreBase
{
virtual long Run()
{
if (!Read(GL_RGBA32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(2.0f, 4.0f, 6.0f, 8.0f), GL_RGBA, GL_FLOAT))
return ERROR;
if (!Read(GL_R32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(2.0f, 0.0f, 0.0f, 1.0f), GL_RED, GL_FLOAT))
return ERROR;
if (!Read(GL_RGBA16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(2.0f, 4.0f, 6.0f, 8.0f), GL_RGBA, GL_FLOAT))
return ERROR;
if (!Read(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(2, -4, 6, -8), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(GL_R32I, ivec4(1, -2, 3, -4), ivec4(2, 0, 0, 1), GL_RED_INTEGER, GL_INT))
return ERROR;
if (!Read(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(2, -4, 6, -8), GL_RGBA_INTEGER, GL_SHORT))
return ERROR;
if (!Read(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(2, -4, 6, -8), GL_RGBA_INTEGER, GL_BYTE))
return ERROR;
if (!Read(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 2, 4, 6), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(GL_R32UI, uvec4(7, 2, 3, 4), uvec4(14, 0, 0, 1), GL_RED_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(GL_RGBA16UI, uvec4(0, 1, 2, 3), uvec4(0, 2, 4, 6), GL_RGBA_INTEGER, GL_UNSIGNED_SHORT))
return ERROR;
if (!Read(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 2, 4, 6), GL_RGBA_INTEGER, GL_UNSIGNED_BYTE))
return ERROR;
if (!Read(GL_RGBA8, vec4(0.5f), vec4(1.0f), GL_RGBA, GL_UNSIGNED_BYTE))
return ERROR;
if (!Read(GL_RGBA8_SNORM, vec4(0.5f, 0.0f, 0.5f, -0.5f), vec4(1.0f, 0.0f, 1.0f, -1.0f), GL_RGBA, GL_BYTE))
return ERROR;
return NO_ERROR;
}
template <typename T>
bool Read(GLenum internalformat, const T& value, const T& expected_value, GLenum format, GLenum type)
{
GLuint program = CreateComputeProgram(GenCS(internalformat, expected_value));
const int kSize = 8;
ShortByteData<T> d(kSize, value, internalformat, format);
GLuint texture[2];
glGenTextures(2, texture);
/* read texture */
{
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
if (Shorts(internalformat))
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &d.datas[0]);
else if (Bytes(internalformat))
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &d.datab[0]);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &d.data[0]);
}
/* write texture */
{
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
}
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(program);
glBindImageTexture(2, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat);
glBindImageTexture(3, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat);
glDispatchCompute(1, 1, 1);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
GLuint c_program = CreateComputeProgram(GenC(expected_value));
std::vector<T> out_data(kSize * kSize);
GLuint m_buffer;
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &out_data[0], GL_STATIC_DRAW);
glUseProgram(c_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
T* map_data = (T*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize * kSize; ++i)
{
if (!Equal(map_data[i], expected_value, internalformat))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Value is: " << ToString(map_data[i])
<< ". Value should be: " << ToString(expected_value)
<< ". Format is: " << FormatEnumToString(internalformat) << tcu::TestLog::EndMessage;
glDeleteTextures(2, texture);
glUseProgram(0);
glDeleteProgram(program);
glDeleteProgram(c_program);
glDeleteBuffers(1, &m_buffer);
return false;
}
}
glDeleteTextures(2, texture);
glUseProgram(0);
glDeleteProgram(program);
glDeleteProgram(c_program);
glDeleteBuffers(1, &m_buffer);
return true;
}
template <typename T>
std::string GenCS(GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << NL "#define KSIZE 8" NL "layout(local_size_x = KSIZE, local_size_y = KSIZE) in;" NL "layout("
<< FormatEnumToString(internalformat) << ", binding = 2) readonly uniform " << TypePrefix<T>()
<< "image2D g_image_read;" NL "layout(" << FormatEnumToString(internalformat)
<< ", binding = 3) writeonly uniform " << TypePrefix<T>()
<< "image2D g_image_write;" NL "void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID);" NL " "
<< TypePrefix<T>() << "vec4 v = imageLoad(g_image_read, coord);" NL
" imageStore(g_image_write, coord, v+v);" NL " //imageStore(g_image_write, coord, "
<< TypePrefix<T>() << "vec4" << expected_value << ");" NL "}";
return os.str();
}
template <typename T>
std::string GenC(const T& value)
{
std::ostringstream os;
os << NL "#define KSIZE 8" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL "uniform "
<< TypePrefix<T>() << "sampler2D g_sampler;" NL "layout(std430) buffer OutputBuffer {" NL " "
<< TypePrefix<T>()
<< "vec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL
" data[gl_LocalInvocationIndex] = texelFetch(g_sampler, ivec2(gl_LocalInvocationID), 0);" NL
" //data[gl_LocalInvocationIndex] = "
<< TypePrefix<T>() << "vec4" << value << ";" NL "}";
return os.str();
}
};
//-----------------------------------------------------------------------------
// 1.3.1 BasicAllTargetsStore
//-----------------------------------------------------------------------------
class BasicAllTargetsStoreFS : public ShaderImageLoadStoreBase
{
GLuint m_vao;
GLuint m_vbo;
virtual long Setup()
{
m_vao = 0;
m_vbo = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(0, 4))
return NOT_SUPPORTED;
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
if (!Write(T2D, GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
if (!Write(T2D, GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(T2D, GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
if (!Write(T3D, GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
if (!Write(T3D, GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(T3D, GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
if (!Write(TCM, GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
if (!Write(TCM, GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(TCM, GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
if (!Write(T2DA, GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
if (!Write(T2DA, GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(T2DA, GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
glActiveTexture(GL_TEXTURE0);
return NO_ERROR;
}
template <typename T>
bool Write(int target, GLenum internalformat, const T& write_value, const T& expected_value)
{
const char* src_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const GLuint program = BuildProgram(src_vs, GenFS(target, internalformat, write_value).c_str());
GLuint textures[8];
glGenTextures(8, textures);
const int kSize = 11;
std::vector<T> data(kSize * kSize * 2);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_3D, textures[2]);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_3D, 1, internalformat, kSize, kSize, 2);
glBindTexture(GL_TEXTURE_3D, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, textures[4]);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, internalformat, kSize, kSize);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, textures[7]);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, internalformat, kSize, kSize, 2);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindImageTexture(0, textures[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat); // 2D
glBindImageTexture(1, textures[2], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat); // 3D
glBindImageTexture(2, textures[4], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat); // Cube
glBindImageTexture(3, textures[7], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat); // 2DArray
glUseProgram(program);
glBindVertexArray(m_vao);
glViewport(0, 0, kSize, kSize);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_3D, textures[2]);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_CUBE_MAP, textures[4]);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D_ARRAY, textures[7]);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
GLuint c_program = CreateComputeProgram(GenC(write_value));
std::vector<T> out_data2D(kSize * kSize * 6);
std::vector<T> out_data3D(kSize * kSize * 6);
std::vector<T> out_dataCube(kSize * kSize * 6);
std::vector<T> out_data2DArray(kSize * kSize * 6);
GLuint m_buffer[4];
glGenBuffers(4, m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_buffer[2]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_buffer[3]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glUseProgram(c_program);
glUniform1i(glGetUniformLocation(c_program, "g_sampler_2d"), 1);
glUniform1i(glGetUniformLocation(c_program, "g_sampler_3d"), 2);
glUniform1i(glGetUniformLocation(c_program, "g_sampler_cube"), 3);
glUniform1i(glGetUniformLocation(c_program, "g_sampler_2darray"), 4);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
bool status = true;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer[target]);
T* map_data = (T*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 6 * kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
int layers = 2;
if (target == T2D)
layers = 1;
if (target == TCM)
layers = 6;
status = CompareValues(map_data, kSize, expected_value, internalformat, layers);
if (!status)
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << target << " target, " << FormatEnumToString(internalformat)
<< ". format failed." << tcu::TestLog::EndMessage;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glDeleteTextures(8, textures);
glUseProgram(0);
glDeleteProgram(program);
glDeleteProgram(c_program);
glDeleteBuffers(4, m_buffer);
return status;
}
template <typename T>
std::string GenFS(int target, GLenum internalformat, const T& write_value)
{
std::ostringstream os;
switch (target)
{
case T2D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 0) writeonly uniform "
<< TypePrefix<T>() << "image2D g_image_2d;";
break;
case T3D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 1) writeonly uniform "
<< TypePrefix<T>() << "image3D g_image_3d;";
break;
case TCM:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 2) writeonly uniform "
<< TypePrefix<T>() << "imageCube g_image_cube;";
break;
case T2DA:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 3) writeonly uniform "
<< TypePrefix<T>() << "image2DArray g_image_2darray;";
break;
}
os << NL "void main() {" NL " ivec2 coord = ivec2(gl_FragCoord.xy);";
switch (target)
{
case T2D:
os << NL " imageStore(g_image_2d, coord, " << TypePrefix<T>() << "vec4" << write_value << ");";
break;
case T3D:
os << NL " imageStore(g_image_3d, ivec3(coord, 0), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_3d, ivec3(coord, 1), " << TypePrefix<T>() << "vec4" << write_value
<< ");";
break;
case TCM:
os << NL " imageStore(g_image_cube, ivec3(coord, 0), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 1), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 2), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 3), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 4), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 5), " << TypePrefix<T>() << "vec4" << write_value
<< ");";
break;
case T2DA:
os << NL " imageStore(g_image_2darray, ivec3(coord, 0), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_2darray, ivec3(coord, 1), " << TypePrefix<T>() << "vec4" << write_value
<< ");";
break;
}
os << NL " discard;" NL "}";
return os.str();
}
template <typename T>
std::string GenC(const T& write_value)
{
std::ostringstream os;
os << NL "#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL "uniform "
<< TypePrefix<T>() << "sampler2D g_sampler_2d;" NL "uniform " << TypePrefix<T>()
<< "sampler3D g_sampler_3d;" NL "uniform " << TypePrefix<T>() << "samplerCube g_sampler_cube;" NL "uniform "
<< TypePrefix<T>()
<< "sampler2DArray g_sampler_2darray;" NL "layout(std430, binding = 1) buffer OutputBuffer2D {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE];" NL "} g_buff_2d;" NL
"layout(std430, binding = 0) buffer OutputBuffer3D {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*2];" NL "} g_buff_3d;" NL
"layout(std430, binding = 3) buffer OutputBufferCube {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*6];" NL "} g_buff_cube;" NL
"layout(std430, binding = 2) buffer OutputBuffer2DArray {" NL " "
<< TypePrefix<T>()
<< "vec4 data[KSIZE*KSIZE*2];" NL "} g_buff_2darray;" NL "void main() {" NL
" int cubemap_i = 2 * int(gl_LocalInvocationID.x) - KSIZE + 1;" NL
" int cubemap_j = 2 * int(gl_LocalInvocationID.y) - KSIZE + 1;" NL
" uint layer = uint(KSIZE * KSIZE);" NL
" g_buff_2d.data[gl_LocalInvocationIndex] = texelFetch(g_sampler_2d, ivec2(gl_LocalInvocationID), 0);" NL
" g_buff_3d.data[gl_LocalInvocationIndex] = texelFetch(g_sampler_3d, ivec3(gl_LocalInvocationID.xy, 0), "
"0);" NL " g_buff_3d.data[gl_LocalInvocationIndex + layer] = texelFetch(g_sampler_3d, "
"ivec3(gl_LocalInvocationID.xy, 1), 0);" NL " g_buff_2darray.data[gl_LocalInvocationIndex] = "
"texelFetch(g_sampler_2darray, "
"ivec3(gl_LocalInvocationID.xy, 0), 0);" NL
" g_buff_2darray.data[gl_LocalInvocationIndex + layer] = texelFetch(g_sampler_2darray, "
"ivec3(gl_LocalInvocationID.xy, 1), 0);" NL " g_buff_cube.data[gl_LocalInvocationIndex] = "
"texture(g_sampler_cube, vec3(KSIZE,cubemap_i,cubemap_j));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + layer] = texture(g_sampler_cube, "
"vec3(KSIZE,cubemap_i,cubemap_j));" NL " g_buff_cube.data[gl_LocalInvocationIndex + 2u * layer] = "
"texture(g_sampler_cube, vec3(cubemap_i,KSIZE,cubemap_j));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + 3u * layer] = texture(g_sampler_cube, "
"vec3(cubemap_i,KSIZE,cubemap_j));" NL " g_buff_cube.data[gl_LocalInvocationIndex + 4u * layer] = "
"texture(g_sampler_cube, vec3(cubemap_i,cubemap_j,KSIZE));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + 5u * layer] = texture(g_sampler_cube, "
"vec3(cubemap_i,cubemap_j,KSIZE));" NL " //g_buff_2d.data[gl_LocalInvocationIndex] = "
<< write_value << ";" NL "}";
return os.str();
}
};
class BasicAllTargetsStoreCS : public ShaderImageLoadStoreBase
{
virtual long Setup()
{
return NO_ERROR;
}
virtual long Run()
{
if (!Write(T2D, GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
if (!Write(T2D, GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(T2D, GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
if (!Write(T3D, GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(T3D, GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
if (!Write(T3D, GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
if (!Write(TCM, GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
if (!Write(TCM, GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
if (!Write(TCM, GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(T2DA, GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
if (!Write(T2DA, GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(T2DA, GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glActiveTexture(GL_TEXTURE0);
return NO_ERROR;
}
template <typename T>
bool Write(int target, GLenum internalformat, const T& write_value, const T& expected_value)
{
const GLuint program = CreateComputeProgram(GenCS(target, internalformat, write_value));
GLuint textures[8];
glGenTextures(8, textures);
const int kSize = 11;
std::vector<T> data(kSize * kSize * 2);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_3D, textures[2]);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_3D, 1, internalformat, kSize, kSize, 2);
glBindTexture(GL_TEXTURE_3D, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, textures[4]);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, internalformat, kSize, kSize);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, textures[7]);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, internalformat, kSize, kSize, 2);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindImageTexture(0, textures[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat); // 2D
glBindImageTexture(1, textures[2], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat); // 3D
glBindImageTexture(2, textures[4], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat); // Cube
glBindImageTexture(3, textures[7], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat); // 2DArray
glUseProgram(program);
glDispatchCompute(1, 1, 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_3D, textures[2]);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_CUBE_MAP, textures[4]);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D_ARRAY, textures[7]);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
GLuint c_program = CreateComputeProgram(GenC(write_value));
std::vector<T> out_data2D(kSize * kSize * 6);
std::vector<T> out_data3D(kSize * kSize * 6);
std::vector<T> out_dataCube(kSize * kSize * 6);
std::vector<T> out_data2DArray(kSize * kSize * 6);
GLuint m_buffer[4];
glGenBuffers(4, m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_buffer[2]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_buffer[3]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glUseProgram(c_program);
glUniform1i(glGetUniformLocation(c_program, "g_sampler_2d"), 1);
glUniform1i(glGetUniformLocation(c_program, "g_sampler_3d"), 2);
glUniform1i(glGetUniformLocation(c_program, "g_sampler_cube"), 3);
glUniform1i(glGetUniformLocation(c_program, "g_sampler_2darray"), 4);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
bool status = true;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer[target]);
T* map_data = (T*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 6 * kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
int layers = 2;
if (target == T2D)
layers = 1;
if (target == TCM)
layers = 6;
status = CompareValues(map_data, kSize, expected_value, internalformat, layers);
if (!status)
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << target << " target, " << FormatEnumToString(internalformat)
<< ". format failed." << tcu::TestLog::EndMessage;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glDeleteTextures(8, textures);
glUseProgram(0);
glDeleteProgram(program);
glDeleteProgram(c_program);
glDeleteBuffers(4, m_buffer);
return status;
}
template <typename T>
std::string GenCS(int target, GLenum internalformat, const T& write_value)
{
std::ostringstream os;
os << NL "#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;";
switch (target)
{
case T2D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 0) writeonly uniform "
<< TypePrefix<T>() << "image2D g_image_2d;";
break;
case T3D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 1) writeonly uniform "
<< TypePrefix<T>() << "image3D g_image_3d;";
break;
case TCM:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 2) writeonly uniform "
<< TypePrefix<T>() << "imageCube g_image_cube;";
break;
case T2DA:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 3) writeonly uniform "
<< TypePrefix<T>() << "image2DArray g_image_2darray;";
break;
}
os << NL "void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID);";
switch (target)
{
case T2D:
os << NL " imageStore(g_image_2d, coord, " << TypePrefix<T>() << "vec4" << write_value << ");";
break;
case T3D:
os << NL " imageStore(g_image_3d, ivec3(coord, 0), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_3d, ivec3(coord, 1), " << TypePrefix<T>() << "vec4" << write_value
<< ");";
break;
case TCM:
os << NL " imageStore(g_image_cube, ivec3(coord, 0), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 1), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 2), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 3), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 4), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_cube, ivec3(coord, 5), " << TypePrefix<T>() << "vec4" << write_value
<< ");";
break;
case T2DA:
os << NL " imageStore(g_image_2darray, ivec3(coord, 0), " << TypePrefix<T>() << "vec4" << write_value
<< ");" NL " imageStore(g_image_2darray, ivec3(coord, 1), " << TypePrefix<T>() << "vec4" << write_value
<< ");";
break;
}
os << NL "}";
return os.str();
}
template <typename T>
std::string GenC(const T& write_value)
{
std::ostringstream os;
os << NL "#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL "uniform "
<< TypePrefix<T>() << "sampler2D g_sampler_2d;" NL "uniform " << TypePrefix<T>()
<< "sampler3D g_sampler_3d;" NL "uniform " << TypePrefix<T>() << "samplerCube g_sampler_cube;" NL "uniform "
<< TypePrefix<T>()
<< "sampler2DArray g_sampler_2darray;" NL "layout(std430, binding = 0) buffer OutputBuffer2D {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE];" NL "} g_buff_2d;" NL
"layout(std430, binding = 1) buffer OutputBuffer3D {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*2];" NL "} g_buff_3d;" NL
"layout(std430, binding = 2) buffer OutputBufferCube {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*6];" NL "} g_buff_cube;" NL
"layout(std430, binding = 3) buffer OutputBuffer2DArray {" NL " "
<< TypePrefix<T>()
<< "vec4 data[KSIZE*KSIZE*2];" NL "} g_buff_2darray;" NL "void main() {" NL
" int cubemap_i = 2 * int(gl_LocalInvocationID.x) - KSIZE + 1;" NL
" int cubemap_j = 2 * int(gl_LocalInvocationID.y) - KSIZE + 1;" NL
" uint layer = uint(KSIZE * KSIZE);" NL
" g_buff_2d.data[gl_LocalInvocationIndex] = texelFetch(g_sampler_2d, ivec2(gl_LocalInvocationID), 0);" NL
" g_buff_3d.data[gl_LocalInvocationIndex] = texelFetch(g_sampler_3d, ivec3(gl_LocalInvocationID.xy, 0), "
"0);" NL " g_buff_3d.data[gl_LocalInvocationIndex + layer] = texelFetch(g_sampler_3d, "
"ivec3(gl_LocalInvocationID.xy, 1), 0);" NL " g_buff_2darray.data[gl_LocalInvocationIndex] = "
"texelFetch(g_sampler_2darray, "
"ivec3(gl_LocalInvocationID.xy, 0), 0);" NL
" g_buff_2darray.data[gl_LocalInvocationIndex + layer] = texelFetch(g_sampler_2darray, "
"ivec3(gl_LocalInvocationID.xy, 1), 0);" NL " g_buff_cube.data[gl_LocalInvocationIndex] = "
"texture(g_sampler_cube, vec3(KSIZE,cubemap_i,cubemap_j));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + layer] = texture(g_sampler_cube, "
"vec3(KSIZE,cubemap_i,cubemap_j));" NL " g_buff_cube.data[gl_LocalInvocationIndex + 2u * layer] = "
"texture(g_sampler_cube, vec3(cubemap_i,KSIZE,cubemap_j));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + 3u * layer] = texture(g_sampler_cube, "
"vec3(cubemap_i,KSIZE,cubemap_j));" NL " g_buff_cube.data[gl_LocalInvocationIndex + 4u * layer] = "
"texture(g_sampler_cube, vec3(cubemap_i,cubemap_j,KSIZE));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + 5u * layer] = texture(g_sampler_cube, "
"vec3(cubemap_i,cubemap_j,KSIZE));" NL " //g_buff_2d.data[gl_LocalInvocationIndex] = "
<< write_value << ";" NL "}";
return os.str();
}
};
//-----------------------------------------------------------------------------
// 1.3.2.1 BasicAllTargetsLoad
//-----------------------------------------------------------------------------
class BasicAllTargetsLoadFS : public ShaderImageLoadStoreBase
{
GLuint m_vao;
GLuint m_vbo;
virtual long Setup()
{
m_vao = 0;
m_vbo = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(0, 4) || !IsSSBInVSFSAvailable(0, 4))
return NOT_SUPPORTED;
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
if (!Read(T2D, GL_RGBA32F, vec4(-1.0f, 10.0f, -200.0f, 3000.0f), vec4(-1.0f, 10.0f, -200.0f, 3000.0f), GL_RGBA,
GL_FLOAT))
return ERROR;
if (!Read(T2D, GL_RGBA32I, ivec4(-1, 10, -200, 3000), ivec4(-1, 10, -200, 3000), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(T2D, GL_RGBA32UI, uvec4(1, 10, 200, 3000), uvec4(1, 10, 200, 3000), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(T3D, GL_RGBA32F, vec4(-1.0f, 10.0f, -200.0f, 3000.0f), vec4(-1.0f, 10.0f, -200.0f, 3000.0f), GL_RGBA,
GL_FLOAT))
return ERROR;
if (!Read(T3D, GL_RGBA32I, ivec4(-1, 10, -200, 3000), ivec4(-1, 10, -200, 3000), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(T3D, GL_RGBA32UI, uvec4(1, 10, 200, 3000), uvec4(1, 10, 200, 3000), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(TCM, GL_RGBA32F, vec4(-1.0f, 10.0f, -200.0f, 3000.0f), vec4(-1.0f, 10.0f, -200.0f, 3000.0f), GL_RGBA,
GL_FLOAT))
return ERROR;
if (!Read(TCM, GL_RGBA32I, ivec4(-1, 10, -200, 3000), ivec4(-1, 10, -200, 3000), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(TCM, GL_RGBA32UI, uvec4(1, 10, 200, 3000), uvec4(1, 10, 200, 3000), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(T2DA, GL_RGBA32F, vec4(-1.0f, 10.0f, -200.0f, 3000.0f), vec4(-1.0f, 10.0f, -200.0f, 3000.0f), GL_RGBA,
GL_FLOAT))
return ERROR;
if (!Read(T2DA, GL_RGBA32I, ivec4(-1, 10, -200, 3000), ivec4(-1, 10, -200, 3000), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(T2DA, GL_RGBA32UI, uvec4(1, 10, 200, 3000), uvec4(1, 10, 200, 3000), GL_RGBA_INTEGER,
GL_UNSIGNED_INT))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
return NO_ERROR;
}
template <typename T>
bool Read(int target, GLenum internalformat, const T& value, const T& expected_value, GLenum format, GLenum type)
{
const char* src_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const GLuint program = BuildProgram(src_vs, GenFS(target, internalformat, expected_value).c_str());
GLuint textures[8];
glGenTextures(8, textures);
const int kSize = 11;
std::vector<T> data(kSize * kSize * 2, value);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_3D, textures[2]);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_3D, 1, internalformat, kSize, kSize, 2);
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kSize, kSize, 2, format, type, &data[0]);
glBindTexture(GL_TEXTURE_3D, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, textures[4]);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, internalformat, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, textures[7]);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, internalformat, kSize, kSize, 2);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kSize, kSize, 2, format, type, &data[0]);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindImageTexture(2, textures[1], 0, GL_FALSE, 0, GL_READ_ONLY, internalformat); // 2D
glBindImageTexture(0, textures[2], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat); // 3D
glBindImageTexture(3, textures[4], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat); // Cube
glBindImageTexture(1, textures[7], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat); // 2DArray
std::vector<T> out_data2D(kSize * kSize * 6);
std::vector<T> out_data3D(kSize * kSize * 6);
std::vector<T> out_dataCube(kSize * kSize * 6);
std::vector<T> out_data2DArray(kSize * kSize * 6);
GLuint m_buffer[4];
glGenBuffers(4, m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_buffer[2]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_buffer[3]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glUseProgram(program);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(m_vao);
glViewport(0, 0, kSize, kSize);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
bool status = true;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer[target]);
T* map_data = (T*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 6 * kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
int layers = 2;
if (target == T2D)
layers = 1;
if (target == TCM)
layers = 6;
status = CompareValues(map_data, kSize, expected_value, internalformat, layers);
if (!status)
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << target << " target, " << FormatEnumToString(internalformat)
<< ". format failed." << tcu::TestLog::EndMessage;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glUseProgram(0);
glDeleteProgram(program);
glDeleteTextures(8, textures);
glDeleteBuffers(4, m_buffer);
return status;
}
template <typename T>
std::string GenFS(int target, GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << NL "#define KSIZE 11";
switch (target)
{
case T2D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 2) readonly uniform "
<< TypePrefix<T>()
<< "image2D g_image_2d;" NL "layout(std430, binding = 1) buffer OutputBuffer2D {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE];" NL "} g_buff_2d;";
break;
case T3D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 0) readonly uniform "
<< TypePrefix<T>()
<< "image3D g_image_3d;" NL "layout(std430, binding = 0) buffer OutputBuffer3D {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*2];" NL "} g_buff_3d;";
break;
case TCM:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 3) readonly uniform "
<< TypePrefix<T>()
<< "imageCube g_image_cube;" NL "layout(std430, binding = 3) buffer OutputBufferCube {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*6];" NL "} g_buff_cube;";
break;
case T2DA:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 1) readonly uniform "
<< TypePrefix<T>()
<< "image2DArray g_image_2darray;" NL "layout(std430, binding = 2) buffer OutputBuffer2DArray {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*2];" NL "} g_buff_2darray;";
break;
}
os << NL "void main() {" NL " ivec2 coord = ivec2(gl_FragCoord.xy);" NL
" int coordIndex = coord.x + KSIZE * coord.y;" NL " int layer = int(KSIZE * KSIZE);" NL " "
<< TypePrefix<T>() << "vec4 v;";
switch (target)
{
case T2D:
os << NL " v = imageLoad(g_image_2d, coord);" NL " g_buff_2d.data[coordIndex] = v;";
break;
case T3D:
os << NL " v = imageLoad(g_image_3d, ivec3(coord.xy, 0));" NL " g_buff_3d.data[coordIndex] = v;" NL
" v = imageLoad(g_image_3d, ivec3(coord.xy, 1));" NL " g_buff_3d.data[coordIndex + layer] = v;";
break;
case TCM:
os << NL
" v = imageLoad(g_image_cube, ivec3(coord, 0));" NL " g_buff_cube.data[coordIndex] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord, 1));" NL " g_buff_cube.data[coordIndex + layer] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord, 2));" NL
" g_buff_cube.data[coordIndex + 2 * layer] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord, 3));" NL
" g_buff_cube.data[coordIndex + 3 * layer] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord, 4));" NL
" g_buff_cube.data[coordIndex + 4 * layer] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord, 5));" NL " g_buff_cube.data[coordIndex + 5 * layer] = v;";
break;
case T2DA:
os << NL " v = imageLoad(g_image_2darray, ivec3(coord, 0));" NL " g_buff_2darray.data[coordIndex] = v;" NL
" v = imageLoad(g_image_2darray, ivec3(coord, 1));" NL
" g_buff_2darray.data[coordIndex + layer] = v;";
break;
}
os << NL " //g_buff_2d.data[coordIndex] = " << expected_value << ";" NL "}";
return os.str();
}
};
class BasicAllTargetsLoadCS : public ShaderImageLoadStoreBase
{
virtual long Setup()
{
return NO_ERROR;
}
virtual long Run()
{
if (!Read(T2D, GL_RGBA32F, vec4(-1.0f, 10.0f, -200.0f, 3000.0f), vec4(-1.0f, 10.0f, -200.0f, 3000.0f), GL_RGBA,
GL_FLOAT))
return ERROR;
if (!Read(T2D, GL_RGBA32I, ivec4(-0x7fffffff, 0x7fffffff, -200, 3000),
ivec4(-0x7fffffff, 0x7fffffff, -200, 3000), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(T2D, GL_RGBA32UI, uvec4(0xffffffffu, 0x7fffffff, 0x80000000, 3000),
uvec4(0xffffffffu, 0x7fffffff, 0x80000000, 3000), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(T3D, GL_RGBA32F, vec4(-1.0f, 10.0f, -200.0f, 3000.0f), vec4(-1.0f, 10.0f, -200.0f, 3000.0f), GL_RGBA,
GL_FLOAT))
return ERROR;
if (!Read(T3D, GL_RGBA32I, ivec4(-0x7fffffff, 0x7fffffff, -200, 3000),
ivec4(-0x7fffffff, 0x7fffffff, -200, 3000), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(T3D, GL_RGBA32UI, uvec4(0xffffffffu, 0x7fffffff, 0x80000000, 3000),
uvec4(0xffffffffu, 0x7fffffff, 0x80000000, 3000), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(TCM, GL_RGBA32F, vec4(-1.0f, 10.0f, -200.0f, 3000.0f), vec4(-1.0f, 10.0f, -200.0f, 3000.0f), GL_RGBA,
GL_FLOAT))
return ERROR;
if (!Read(TCM, GL_RGBA32I, ivec4(-0x7fffffff, 0x7fffffff, -200, 3000),
ivec4(-0x7fffffff, 0x7fffffff, -200, 3000), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(TCM, GL_RGBA32UI, uvec4(0xffffffffu, 0x7fffffff, 0x80000000, 3000),
uvec4(0xffffffffu, 0x7fffffff, 0x80000000, 3000), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
if (!Read(T2DA, GL_RGBA32F, vec4(-1.0f, 10.0f, -200.0f, 3000.0f), vec4(-1.0f, 10.0f, -200.0f, 3000.0f), GL_RGBA,
GL_FLOAT))
return ERROR;
if (!Read(T2DA, GL_RGBA32I, ivec4(-0x7fffffff, 0x7fffffff, -200, 3000),
ivec4(-0x7fffffff, 0x7fffffff, -200, 3000), GL_RGBA_INTEGER, GL_INT))
return ERROR;
if (!Read(T2DA, GL_RGBA32UI, uvec4(0xffffffffu, 0x7fffffff, 0x80000000, 3000),
uvec4(0xffffffffu, 0x7fffffff, 0x80000000, 3000), GL_RGBA_INTEGER, GL_UNSIGNED_INT))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
return NO_ERROR;
}
template <typename T>
bool Read(int target, GLenum internalformat, const T& value, const T& expected_value, GLenum format, GLenum type)
{
const GLuint program = CreateComputeProgram(GenCS(target, internalformat, expected_value));
GLuint textures[8];
glGenTextures(8, textures);
const int kSize = 11;
std::vector<T> data(kSize * kSize * 2, value);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_3D, textures[2]);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_3D, 1, internalformat, kSize, kSize, 2);
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kSize, kSize, 2, format, type, &data[0]);
glBindTexture(GL_TEXTURE_3D, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, textures[4]);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, internalformat, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 0, 0, kSize, kSize, format, type, &data[0]);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, textures[7]);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, internalformat, kSize, kSize, 2);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kSize, kSize, 2, format, type, &data[0]);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindImageTexture(2, textures[1], 0, GL_FALSE, 0, GL_READ_ONLY, internalformat); // 2D
glBindImageTexture(0, textures[2], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat); // 3D
glBindImageTexture(3, textures[4], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat); // Cube
glBindImageTexture(1, textures[7], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat); // 2DArray
std::vector<T> out_data2D(kSize * kSize * 6);
std::vector<T> out_data3D(kSize * kSize * 6);
std::vector<T> out_dataCube(kSize * kSize * 6);
std::vector<T> out_data2DArray(kSize * kSize * 6);
GLuint m_buffer[4];
glGenBuffers(4, m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer[0]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_buffer[1]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_buffer[2]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_buffer[3]);
glBufferData(GL_SHADER_STORAGE_BUFFER, 6 * kSize * kSize * 4 * 4, &out_dataCube[0], GL_STATIC_DRAW);
glUseProgram(program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
bool status = true;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer[target]);
T* map_data = (T*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 6 * kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
int layers = 2;
if (target == T2D)
layers = 1;
if (target == TCM)
layers = 6;
status = CompareValues(map_data, kSize, expected_value, internalformat, layers);
if (!status)
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << target << " target, " << FormatEnumToString(internalformat)
<< ". format failed." << tcu::TestLog::EndMessage;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glUseProgram(0);
glDeleteProgram(program);
glDeleteTextures(8, textures);
glDeleteBuffers(4, m_buffer);
return status;
}
template <typename T>
std::string GenCS(int target, GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << NL "#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;";
switch (target)
{
case T2D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 2) readonly uniform "
<< TypePrefix<T>()
<< "image2D g_image_2d;" NL "layout(std430, binding = 0) buffer OutputBuffer2D {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE];" NL "} g_buff_2d;";
break;
case T3D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 0) readonly uniform "
<< TypePrefix<T>()
<< "image3D g_image_3d;" NL "layout(std430, binding = 1) buffer OutputBuffer3D {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*2];" NL "} g_buff_3d;";
break;
case TCM:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 3) readonly uniform "
<< TypePrefix<T>()
<< "imageCube g_image_cube;" NL "layout(std430, binding = 2) buffer OutputBufferCube {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*6];" NL "} g_buff_cube;";
break;
case T2DA:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 1) readonly uniform "
<< TypePrefix<T>()
<< "image2DArray g_image_2darray;" NL "layout(std430, binding = 3) buffer OutputBuffer2DArray {" NL " "
<< TypePrefix<T>() << "vec4 data[KSIZE*KSIZE*2];" NL "} g_buff_2darray;";
break;
}
os << NL "void main() {" NL " ivec3 coord = ivec3(gl_LocalInvocationID.xy, 0);" NL
" uint layer = uint(KSIZE * KSIZE);" NL " "
<< TypePrefix<T>() << "vec4 v;";
switch (target)
{
case T2D:
os << NL " v = imageLoad(g_image_2d, coord.xy);" NL " g_buff_2d.data[gl_LocalInvocationIndex] = v;";
break;
case T3D:
os << NL " v = imageLoad(g_image_3d, coord);" NL " g_buff_3d.data[gl_LocalInvocationIndex] = v;" NL
" v = imageLoad(g_image_3d, ivec3(coord.xy, 1));" NL
" g_buff_3d.data[gl_LocalInvocationIndex + layer] = v;";
break;
case TCM:
os << NL " v = imageLoad(g_image_cube, coord);" NL " g_buff_cube.data[gl_LocalInvocationIndex] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord.xy, 1));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + layer] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord.xy, 2));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + 2u * layer] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord.xy, 3));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + 3u * layer] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord.xy, 4));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + 4u * layer] = v;" NL
" v = imageLoad(g_image_cube, ivec3(coord.xy, 5));" NL
" g_buff_cube.data[gl_LocalInvocationIndex + 5u * layer] = v;";
break;
case T2DA:
os << NL " v = imageLoad(g_image_2darray, coord);" NL
" g_buff_2darray.data[gl_LocalInvocationIndex] = v;" NL
" v = imageLoad(g_image_2darray, ivec3(coord.xy, 1));" NL
" g_buff_2darray.data[gl_LocalInvocationIndex + layer] = v;";
break;
}
os << NL " //g_buff_2d.data[gl_LocalInvocationIndex] = " << expected_value << ";" NL "}";
return os.str();
}
};
//-----------------------------------------------------------------------------
// 1.3.3 BasicAllTargetsAtomic
//-----------------------------------------------------------------------------
class BasicAllTargetsAtomicFS : public ShaderImageLoadStoreBase
{
GLuint m_vao;
GLuint m_vbo;
virtual long Setup()
{
m_vao = 0;
m_vbo = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsImageAtomicSupported())
return NOT_SUPPORTED;
if (!IsVSFSAvailable(0, 4))
return NOT_SUPPORTED;
if (!AreOutputsAvailable(5))
return NOT_SUPPORTED;
if (!IsSSBInVSFSAvailable(0, 1))
return NOT_SUPPORTED;
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
if (!Atomic<GLint>(GL_R32I))
return ERROR;
if (!Atomic<GLuint>(GL_R32UI))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
return NO_ERROR;
}
template <typename T>
bool Atomic(GLenum internalformat)
{
const char* src_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const GLuint program = BuildProgram(src_vs, GenFS<T>(internalformat).c_str(), false, true);
GLuint textures[8];
GLuint buffer;
glGenTextures(8, textures);
glGenBuffers(1, &buffer);
const int kSize = 11;
std::vector<T> data(kSize * kSize * 3);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, internalformat, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_3D, textures[2]);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_3D, 1, internalformat, kSize, kSize, 3);
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kSize, kSize, 3, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_3D, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, textures[4]);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, internalformat, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 0, 0, kSize, kSize, Format<T>(), Type<T>(), &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 0, 0, kSize, kSize, Format<T>(), Type<T>(), &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 0, 0, kSize, kSize, Format<T>(), Type<T>(), &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 0, 0, kSize, kSize, Format<T>(), Type<T>(), &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 0, 0, kSize, kSize, Format<T>(), Type<T>(), &data[0]);
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 0, 0, kSize, kSize, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, textures[7]);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, internalformat, kSize, kSize, 3);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kSize, kSize, 3, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindImageTexture(1, textures[1], 0, GL_FALSE, 0, GL_READ_WRITE, internalformat); // 2D
glBindImageTexture(2, textures[2], 0, GL_TRUE, 0, GL_READ_WRITE, internalformat); // 3D
glBindImageTexture(0, textures[4], 0, GL_TRUE, 0, GL_READ_WRITE, internalformat); // Cube
glBindImageTexture(3, textures[7], 0, GL_TRUE, 0, GL_READ_WRITE, internalformat); // 2DArray
std::vector<ivec4> o_data(kSize * kSize);
GLuint m_buffer;
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &o_data[0], GL_STATIC_DRAW);
glUseProgram(program);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(m_vao);
glViewport(0, 0, kSize, kSize);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
bool status = true;
ivec4* out_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize * kSize; ++i)
{
if (!Equal(out_data[i], ivec4(10, 10, 10, 10), 0))
{
status = false;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i
<< "] Atomic operation check failed. (operation/target coded: " << ToString(out_data[i]) << ")"
<< tcu::TestLog::EndMessage;
}
}
glUseProgram(0);
glDeleteProgram(program);
glDeleteTextures(8, textures);
glDeleteBuffers(1, &buffer);
glDeleteBuffers(1, &m_buffer);
return status;
}
template <typename T>
std::string GenFS(GLenum internalformat)
{
std::ostringstream os;
os << NL "#define KSIZE 11" NL "layout(" << FormatEnumToString(internalformat)
<< ", binding = 1) coherent uniform " << TypePrefix<T>() << "image2D g_image_2d;" NL "layout("
<< FormatEnumToString(internalformat) << ", binding = 2) coherent uniform " << TypePrefix<T>()
<< "image3D g_image_3d;" NL "layout(" << FormatEnumToString(internalformat)
<< ", binding = 0) coherent uniform " << TypePrefix<T>() << "imageCube g_image_cube;" NL "layout("
<< FormatEnumToString(internalformat) << ", binding = 3) coherent uniform " << TypePrefix<T>()
<< "image2DArray g_image_2darray;" NL "layout(std430) buffer out_data {" NL
" ivec4 o_color[KSIZE*KSIZE];" NL "};" NL
<< TypePrefix<T>() << "vec2 t(int i) {" NL " return " << TypePrefix<T>()
<< "vec2(i);" NL "}" NL "void main() {" NL " ivec2 coord = ivec2(gl_FragCoord.xy);" NL
" int coordIndex = coord.x + KSIZE * coord.y;" NL " o_color[coordIndex] = ivec4(coordIndex);" NL
" if (imageAtomicAdd(g_image_2d, coord, t(2).x) != t(0).x) o_color[coordIndex].x = 1;" NL
" else if (imageAtomicMin(g_image_2d, coord, t(3).x) != t(2).x) o_color[coordIndex].x = 2;" NL
" else if (imageAtomicMax(g_image_2d, coord, t(4).x) != t(2).x) o_color[coordIndex].x = 3;" NL
" else if (imageAtomicAnd(g_image_2d, coord, t(0).x) != t(4).x) o_color[coordIndex].x = 4;" NL
" else if (imageAtomicOr(g_image_2d, coord, t(7).x) != t(0).x) o_color[coordIndex].x = 5;" NL
" else if (imageAtomicXor(g_image_2d, coord, t(4).x) != t(7).x) o_color[coordIndex].x = 6;" NL
" else if (imageAtomicExchange(g_image_2d, coord, t(1).x) != t(3).x) o_color[coordIndex].x = 7;" NL
" else if (imageAtomicCompSwap(g_image_2d, coord, t(1).x, t(6).x) != t(1).x) o_color[coordIndex].x = "
"8;" NL " else o_color[coordIndex].x = 10;" NL
" if (imageAtomicAdd(g_image_3d, ivec3(coord, 2), t(2).x) != t(0).x) o_color[coordIndex].y = 1;" NL
" else if (imageAtomicMin(g_image_3d, ivec3(coord, 2), t(3).x) != t(2).x) o_color[coordIndex].y = 2;" NL
" else if (imageAtomicMax(g_image_3d, ivec3(coord, 2), t(4).x) != t(2).x) o_color[coordIndex].y = 3;" NL
" else if (imageAtomicAnd(g_image_3d, ivec3(coord, 2), t(0).x) != t(4).x) o_color[coordIndex].y = 4;" NL
" else if (imageAtomicOr(g_image_3d, ivec3(coord, 2), t(7).x) != t(0).x) o_color[coordIndex].y = 5;" NL
" else if (imageAtomicXor(g_image_3d, ivec3(coord, 2), t(4).x) != t(7).x) o_color[coordIndex].y = 6;" NL
" else if (imageAtomicExchange(g_image_3d, ivec3(coord, 2), t(1).x) != t(3).x) o_color[coordIndex].y = "
"7;" NL " else if (imageAtomicCompSwap(g_image_3d, ivec3(coord, 2), t(1).x, t(6).x) != t(1).x) "
"o_color[coordIndex].y = 8;" NL " else o_color[coordIndex].y = 10;" NL
" if (imageAtomicAdd(g_image_cube, ivec3(coord, 3), t(2).x) != t(0).x) o_color[coordIndex].z = 1;" NL
" else if (imageAtomicMin(g_image_cube, ivec3(coord, 3), t(3).x) != t(2).x) o_color[coordIndex].z = "
"2;" NL " else if (imageAtomicMax(g_image_cube, ivec3(coord, 3), t(4).x) != t(2).x) "
"o_color[coordIndex].z = 3;" NL " else if (imageAtomicAnd(g_image_cube, ivec3(coord, 3), "
"t(0).x) != t(4).x) o_color[coordIndex].z = 4;" NL
" else if (imageAtomicOr(g_image_cube, ivec3(coord, 3), t(7).x) != t(0).x) o_color[coordIndex].z = 5;" NL
" else if (imageAtomicXor(g_image_cube, ivec3(coord, 3), t(4).x) != t(7).x) o_color[coordIndex].z = "
"6;" NL " else if (imageAtomicExchange(g_image_cube, ivec3(coord, 3), t(1).x) != t(3).x) "
"o_color[coordIndex].z = 7;" NL " else if (imageAtomicCompSwap(g_image_cube, ivec3(coord, 3), "
"t(1).x, t(6).x) != t(1).x) o_color[coordIndex].z = 8;" NL " else o_color[coordIndex].z = 10;" NL
" if (imageAtomicAdd(g_image_2darray, ivec3(coord, 2), t(2).x) != t(0).x) o_color[coordIndex].w = 1;" NL
" else if (imageAtomicMin(g_image_2darray, ivec3(coord, 2), t(3).x) != t(2).x) o_color[coordIndex].w = "
"2;" NL " else if (imageAtomicMax(g_image_2darray, ivec3(coord, 2), t(4).x) != t(2).x) "
"o_color[coordIndex].w = 3;" NL " else if (imageAtomicAnd(g_image_2darray, ivec3(coord, 2), "
"t(0).x) != t(4).x) o_color[coordIndex].w = 4;" NL
" else if (imageAtomicOr(g_image_2darray, ivec3(coord, 2), t(7).x) != t(0).x) o_color[coordIndex].w = "
"5;" NL " else if (imageAtomicXor(g_image_2darray, ivec3(coord, 2), t(4).x) != t(7).x) "
"o_color[coordIndex].w = 6;" NL " else if (imageAtomicExchange(g_image_2darray, ivec3(coord, "
"2), t(1).x) != t(3).x) o_color[coordIndex].w = 7;" NL
" else if (imageAtomicCompSwap(g_image_2darray, ivec3(coord, 2), t(1).x, t(6).x) != t(1).x) "
"o_color[coordIndex].w = 8;" NL " else o_color[coordIndex].w = 10;" NL " discard;" NL "}";
return os.str();
}
};
//-----------------------------------------------------------------------------
// LoadStoreMachine
//-----------------------------------------------------------------------------
class LoadStoreMachine : public ShaderImageLoadStoreBase
{
GLuint m_vao;
GLuint m_buffer;
int m_stage;
virtual long Setup()
{
glEnable(GL_RASTERIZER_DISCARD);
glGenVertexArrays(1, &m_vao);
glGenBuffers(1, &m_buffer);
return NO_ERROR;
}
virtual long Cleanup()
{
glDisable(GL_RASTERIZER_DISCARD);
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_buffer);
return NO_ERROR;
}
template <typename T>
bool Write(GLenum internalformat, const T& write_value, const T& expected_value)
{
const GLenum targets[] = { GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_2D_ARRAY };
const int kTargets = sizeof(targets) / sizeof(targets[0]);
const int kSize = 100;
GLuint program_store = 0;
GLuint program_load = 0;
if (m_stage == 0)
{ // VS
const char* src_fs = NL "void main() {" NL " discard;" NL "}";
program_store = BuildProgram(GenStoreShader(m_stage, internalformat, write_value).c_str(), src_fs);
program_load = BuildProgram(GenLoadShader(m_stage, internalformat, expected_value).c_str(), src_fs);
}
else if (m_stage == 4)
{ // CS
program_store = CreateComputeProgram(GenStoreShader(m_stage, internalformat, write_value));
program_load = CreateComputeProgram(GenLoadShader(m_stage, internalformat, expected_value));
}
GLuint textures[kTargets];
glGenTextures(kTargets, textures);
for (int i = 0; i < kTargets; ++i)
{
glBindTexture(targets[i], textures[i]);
glTexParameteri(targets[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(targets[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (targets[i] == GL_TEXTURE_2D)
{
glTexStorage2D(targets[i], 1, internalformat, kSize, 1);
}
else if (targets[i] == GL_TEXTURE_3D || targets[i] == GL_TEXTURE_2D_ARRAY)
{
glTexStorage3D(targets[i], 1, internalformat, kSize, 1, 2);
}
else if (targets[i] == GL_TEXTURE_CUBE_MAP)
{
glTexStorage2D(targets[i], 1, internalformat, kSize, kSize);
}
}
glBindImageTexture(1, textures[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat); // 2D
glBindImageTexture(2, textures[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat); // 3D
glBindImageTexture(0, textures[2], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat); // Cube
glBindImageTexture(3, textures[3], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat); // 2DArray
std::vector<ivec4> b_data(kSize);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * 4 * 4, &b_data[0], GL_STATIC_DRAW);
glUseProgram(program_store);
glBindVertexArray(m_vao);
if (m_stage == 4)
{ // CS
glDispatchCompute(1, 1, 1);
}
else if (m_stage == 0)
{ // VS
glDrawArrays(GL_POINTS, 0, kSize);
}
bool status = true;
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
glBindImageTexture(3, textures[0], 0, GL_FALSE, 0, GL_READ_ONLY, internalformat); // 2D
glBindImageTexture(2, textures[1], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat); // 3D
glBindImageTexture(1, textures[2], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat); // Cube
glBindImageTexture(0, textures[3], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat); // 2DArray
glUseProgram(program_load);
if (m_stage == 0)
{ // VS
glDrawArrays(GL_POINTS, 0, kSize);
}
else if (m_stage == 4)
{ // CS
glDispatchCompute(1, 1, 1);
}
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
ivec4* out_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize; ++i)
{
if (!Equal(out_data[i], ivec4(0, 1, 0, 1), 0))
{
status = false;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] load/store operation check failed. ("
<< ToString(out_data[i]) << ")" << tcu::TestLog::EndMessage;
}
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glUseProgram(0);
glDeleteProgram(program_store);
glDeleteProgram(program_load);
glDeleteTextures(kTargets, textures);
return status;
}
template <typename T>
std::string GenStoreShader(int stage, GLenum internalformat, const T& write_value)
{
std::ostringstream os;
if (stage == 4)
{ // CS
os << NL "#define KSIZE 100" NL "layout(local_size_x = KSIZE) in;";
}
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 1) writeonly uniform "
<< TypePrefix<T>() << "image2D g_image_2d;" NL "layout(" << FormatEnumToString(internalformat)
<< ", binding = 2) writeonly uniform " << TypePrefix<T>() << "image3D g_image_3d;" NL "layout("
<< FormatEnumToString(internalformat) << ", binding = 0) writeonly uniform " << TypePrefix<T>()
<< "imageCube g_image_cube;" NL "layout(" << FormatEnumToString(internalformat)
<< ", binding = 3) writeonly uniform " << TypePrefix<T>()
<< "image2DArray g_image_2darray;" NL "layout(std430) buffer out_data {" NL " ivec4 o_color;" NL "};" NL
"void main() {" NL " "
<< TypePrefix<T>() << "vec4 g_value = " << TypePrefix<T>() << "vec4(o_color) + " << TypePrefix<T>() << "vec4"
<< write_value
<< ";" NL " int g_index[6] = int[](o_color.x, o_color.y, o_color.z, o_color.w, o_color.r, o_color.g);";
if (stage == 0)
{ // VS
os << NL " ivec2 coord = ivec2(gl_VertexID, g_index[0]);";
}
else if (stage == 4)
{ // CS
os << NL " ivec2 coord = ivec2(gl_GlobalInvocationID.x, g_index[0]);";
}
os << NL " imageStore(g_image_2d, coord, g_value);" NL
" imageStore(g_image_3d, ivec3(coord.xy, g_index[0]), g_value);" NL
" imageStore(g_image_3d, ivec3(coord.xy, g_index[1]), g_value);" NL
" for (int i = 0; i < 6; ++i) {" NL
" imageStore(g_image_cube, ivec3(coord, g_index[i]), g_value);" NL " }" NL
" imageStore(g_image_2darray, ivec3(coord, g_index[0]), g_value);" NL
" imageStore(g_image_2darray, ivec3(coord, g_index[1]), g_value);" NL "}";
return os.str();
}
template <typename T>
std::string GenLoadShader(int stage, GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << NL "#define KSIZE 100";
if (stage == 4)
{ // CS
os << NL "layout(local_size_x = KSIZE) in;";
}
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 3) readonly uniform "
<< TypePrefix<T>() << "image2D g_image_2d;" NL "layout(" << FormatEnumToString(internalformat)
<< ", binding = 2) readonly uniform " << TypePrefix<T>() << "image3D g_image_3d;" NL "layout("
<< FormatEnumToString(internalformat) << ", binding = 1) readonly uniform " << TypePrefix<T>()
<< "imageCube g_image_cube;" NL "layout(" << FormatEnumToString(internalformat)
<< ", binding = 0) readonly uniform " << TypePrefix<T>()
<< "image2DArray g_image_2darray;" NL "layout(std430) buffer out_data {" NL " ivec4 o_color[KSIZE];" NL
"};" NL "void main() {";
if (stage == 0)
{ // VS
os << NL " " << TypePrefix<T>() << "vec4 g_value = " << TypePrefix<T>() << "vec4(o_color[gl_VertexID]) + "
<< TypePrefix<T>() << "vec4" << expected_value << ";";
}
else if (stage == 4)
{ // CS
os << NL " " << TypePrefix<T>() << "vec4 g_value = " << TypePrefix<T>()
<< "vec4(o_color[gl_GlobalInvocationID.x]) + " << TypePrefix<T>() << "vec4" << expected_value << ";";
}
os << NL " int g_index[6] = int[](o_color[0].x, o_color[0].y, o_color[0].z, o_color[0].w, o_color[1].r, "
"o_color[1].g);";
if (stage == 0)
{ // VS
os << NL " ivec2 coord = ivec2(gl_VertexID, g_index[0]);";
}
else if (stage == 4)
{ // CS
os << NL " ivec2 coord = ivec2(gl_GlobalInvocationID.x, g_index[0]);";
}
os << NL " vec4 r = vec4(0.0, 1.0, 0.0, 1.0);" NL " " << TypePrefix<T>()
<< "vec4 v;" NL " v = imageLoad(g_image_2d, coord);" NL
" if (v != g_value) r = vec4(1.0, 0.0, float(coord.x), 2.0);" NL
" v = imageLoad(g_image_3d, ivec3(coord, g_index[0]));" NL
" if (v != g_value) r = vec4(1.0, 0.0, float(coord.x), 3.0);" NL
" v = imageLoad(g_image_cube, ivec3(coord, g_index[0]));" NL
" if (v != g_value) r = vec4(1.0, 0.0, float(coord.x), 6.0);" NL
" v = imageLoad(g_image_2darray, ivec3(coord, g_index[0]));" NL
" if (v != g_value) r = vec4(1.0, 0.0, float(coord.x), 23.0);" NL " o_color[coord.x] = ivec4(r);" NL
"}";
return os.str();
}
protected:
long RunStage(int stage)
{
m_stage = stage;
if (!AreOutputsAvailable(5))
return NOT_SUPPORTED;
if (!Write(GL_RGBA32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!Write(GL_R32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!Write(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_R32UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RGBA8, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Write(GL_RGBA8_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f)))
return ERROR;
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// AtomicMachine
//-----------------------------------------------------------------------------
class AtomicMachine : public ShaderImageLoadStoreBase
{
GLuint m_vao;
GLuint m_buffer;
virtual long Setup()
{
glEnable(GL_RASTERIZER_DISCARD);
glGenVertexArrays(1, &m_vao);
glGenBuffers(1, &m_buffer);
return NO_ERROR;
}
virtual long Cleanup()
{
glDisable(GL_RASTERIZER_DISCARD);
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_buffer);
return NO_ERROR;
}
template <typename T>
bool Atomic(int target, int stage, GLenum internalformat)
{
GLuint program = 0;
if (stage == 0)
{ // VS
const char* src_fs = NL "void main() {" NL " discard;" NL "}";
program = BuildProgram(GenShader<T>(target, stage, internalformat).c_str(), src_fs, true, false);
}
else if (stage == 4)
{ // CS
program = CreateComputeProgram(GenShader<T>(target, stage, internalformat), true);
}
const GLenum targets[] = { GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_2D_ARRAY };
const int kTargets = sizeof(targets) / sizeof(targets[0]);
const int kSize = 100;
GLuint textures[kTargets];
glGenTextures(kTargets, textures);
for (int i = 0; i < kTargets; ++i)
{
glBindTexture(targets[i], textures[i]);
glTexParameteri(targets[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(targets[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
if (targets[i] == GL_TEXTURE_2D)
{
glTexStorage2D(targets[i], 1, internalformat, kSize, 1);
}
else if (targets[i] == GL_TEXTURE_3D || targets[i] == GL_TEXTURE_2D_ARRAY)
{
glTexStorage3D(targets[i], 1, internalformat, kSize, 1, 2);
}
else if (targets[i] == GL_TEXTURE_CUBE_MAP)
{
glTexStorage2D(targets[i], 1, internalformat, kSize, kSize);
}
}
glBindImageTexture(1, textures[0], 0, GL_FALSE, 0, GL_READ_WRITE, internalformat); // 2D
glBindImageTexture(2, textures[1], 0, GL_TRUE, 0, GL_READ_WRITE, internalformat); // 3D
glBindImageTexture(0, textures[2], 0, GL_TRUE, 0, GL_READ_WRITE, internalformat); // Cube
glBindImageTexture(3, textures[3], 0, GL_TRUE, 0, GL_READ_WRITE, internalformat); // 2DArray
std::vector<ivec4> b_data(kSize);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * 4 * 4, &b_data[0], GL_STATIC_DRAW);
glUseProgram(program);
glBindVertexArray(m_vao);
if (stage == 0)
{ // VS
glDrawArrays(GL_POINTS, 0, kSize);
}
else if (stage == 4)
{ // CS
glDispatchCompute(1, 1, 1);
}
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
bool status = true;
ivec4* out_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize; ++i)
{
if (!Equal(out_data[i], ivec4(0, 1, 0, 1), 0))
{
status = false;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Atomic operation check failed. ("
<< ToString(out_data[i]) << ")" << tcu::TestLog::EndMessage;
}
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glUseProgram(0);
glDeleteProgram(program);
glDeleteTextures(kTargets, textures);
return status;
}
template <typename T>
std::string GenShader(int target, int stage, GLenum internalformat)
{
std::ostringstream os;
os << NL "#define KSIZE 100";
if (stage == 4)
{ // CS
os << NL "layout(local_size_x = KSIZE) in;";
}
switch (target)
{
case T2D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 1) coherent uniform "
<< TypePrefix<T>() << "image2D g_image_2d;";
break;
case T3D:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 2) coherent uniform "
<< TypePrefix<T>() << "image3D g_image_3d;";
break;
case TCM:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 0) coherent uniform "
<< TypePrefix<T>() << "imageCube g_image_cube;";
break;
case T2DA:
os << NL "layout(" << FormatEnumToString(internalformat) << ", binding = 3) coherent uniform "
<< TypePrefix<T>() << "image2DArray g_image_2darray;";
break;
}
os << NL "layout(std430) buffer out_data {" NL " ivec4 o_color[KSIZE];" NL "} r;" NL << TypePrefix<T>()
<< "vec2 t(int i) {" NL " return " << TypePrefix<T>()
<< "vec2(i);" NL "}" NL "void main() {" NL " int g_value[6] = int[](r.o_color[0].x, r.o_color[0].y+1, "
"r.o_color[0].z+2, r.o_color[0].w+3, r.o_color[1].r+4, "
"r.o_color[1].g+5);";
if (stage == 0)
{ // VS
os << NL " ivec2 coord = ivec2(gl_VertexID, g_value[0]);";
}
else if (stage == 4)
{ // CS
os << NL " ivec2 coord = ivec2(gl_GlobalInvocationID.x, g_value[0]);";
}
os << NL " ivec4 o_color = ivec4(0, 1, 0, 1);";
switch (target)
{
case T2D:
os << NL " ivec4 i = ivec4(1, 0, 0, 2);" NL " imageAtomicExchange(g_image_2d, coord, t(0).x);" NL
" if (imageAtomicAdd(g_image_2d, coord, t(2).x) != t(0).x) o_color = i;" NL
" if (imageAtomicMin(g_image_2d, coord, t(3).x) != t(2).x) o_color = i;" NL
" if (imageAtomicMax(g_image_2d, coord, t(4).x) != t(2).x) o_color = i;" NL
" if (imageAtomicAnd(g_image_2d, coord, t(0).x) != t(4).x) o_color = i;" NL
" if (imageAtomicOr(g_image_2d, coord, t(7).x) != t(0).x) o_color = i;" NL
" if (imageAtomicXor(g_image_2d, coord, t(4).x) != t(7).x) o_color = i;" NL
" if (imageAtomicExchange(g_image_2d, coord, t(1).x) != t(3).x) o_color = i;" NL
" if (imageAtomicCompSwap(g_image_2d, coord, t(1).x, t(6).x) != t(1).x) o_color = i;" NL
" if (imageAtomicExchange(g_image_2d, coord, t(0).x) != t(6).x) o_color = i;";
break;
case T3D:
os << NL " ivec4 i = ivec4(1, 0, 0, 3);" NL
" imageAtomicExchange(g_image_3d, ivec3(coord, 0), t(0).x);" NL
" if (imageAtomicAdd(g_image_3d, ivec3(coord, 0), t(2).x) != t(0).x) o_color = i;" NL
" if (imageAtomicMin(g_image_3d, ivec3(coord, 0), t(3).x) != t(2).x) o_color = i;" NL
" if (imageAtomicMax(g_image_3d, ivec3(coord, g_value[0]), t(4).x) != t(2).x) o_color = i;" NL
" if (imageAtomicAnd(g_image_3d, ivec3(coord, 0), t(0).x) != t(4).x) o_color = i;" NL
" if (imageAtomicOr(g_image_3d, ivec3(coord, 0), t(7).x) != t(0).x) o_color = i;" NL
" if (imageAtomicXor(g_image_3d, ivec3(coord, 0), t(4).x) != t(7).x) o_color = i;" NL
" if (imageAtomicExchange(g_image_3d, ivec3(coord, 0), t(1).x) != t(3).x) o_color = i;" NL
" if (imageAtomicCompSwap(g_image_3d, ivec3(coord, 0), t(1).x, t(6).x) != t(1).x) o_color = i;" NL
" if (imageAtomicExchange(g_image_3d, ivec3(coord, 0), t(0).x) != t(6).x) o_color = i;";
break;
case TCM:
os << NL
" ivec4 i = ivec4(1, 0, 0, 6);" NL " imageAtomicExchange(g_image_cube, ivec3(coord, 0), t(0).x);" NL
" if (imageAtomicAdd(g_image_cube, ivec3(coord, 0), t(g_value[2]).x) != t(0).x) o_color = i;" NL
" if (imageAtomicMin(g_image_cube, ivec3(coord, 0), t(3).x) != t(2).x) o_color = i;" NL
" if (imageAtomicMax(g_image_cube, ivec3(coord, 0), t(4).x) != t(2).x) o_color = i;" NL
" if (imageAtomicAnd(g_image_cube, ivec3(coord, 0), t(0).x) != t(4).x) o_color = i;" NL
" if (imageAtomicOr(g_image_cube, ivec3(coord, 0), t(7).x) != t(0).x) o_color = i;" NL
" if (imageAtomicXor(g_image_cube, ivec3(coord, 0), t(4).x) != t(7).x) o_color = i;" NL
" if (imageAtomicExchange(g_image_cube, ivec3(coord, 0), t(1).x) != t(3).x) o_color = i;" NL
" if (imageAtomicCompSwap(g_image_cube, ivec3(coord, g_value[0]), t(1).x, t(6).x) != t(1).x) o_color "
"= i;" NL " if (imageAtomicExchange(g_image_cube, ivec3(coord, 0), t(0).x) != t(6).x) o_color = i;";
break;
case T2DA:
os << NL
" ivec4 i = ivec4(1, 0, 0, 23);" NL
" imageAtomicExchange(g_image_2darray, ivec3(coord, 0), t(0).x);" NL
" if (imageAtomicAdd(g_image_2darray, ivec3(coord, 0), t(2).x) != t(0).x) o_color = i;" NL
" if (imageAtomicMin(g_image_2darray, ivec3(coord, 0), t(3).x) != t(2).x) o_color = i;" NL
" if (imageAtomicMax(g_image_2darray, ivec3(coord, 0), t(4).x) != t(2).x) o_color = i;" NL
" if (imageAtomicAnd(g_image_2darray, ivec3(coord, 0), t(0).x) != t(4).x) o_color = i;" NL
" if (imageAtomicOr(g_image_2darray, ivec3(coord, 0), t(7).x) != t(0).x) o_color = i;" NL
" if (imageAtomicXor(g_image_2darray, ivec3(coord, 0), t(g_value[4]).x) != t(7).x) o_color = i;" NL
" if (imageAtomicExchange(g_image_2darray, ivec3(coord, 0), t(1).x) != t(3).x) o_color = i;" NL
" if (imageAtomicCompSwap(g_image_2darray, ivec3(coord, 0), t(1).x, t(6).x) != t(1).x) o_color = i;" NL
" if (imageAtomicExchange(g_image_2darray, ivec3(coord, 0), t(0).x) != t(6).x) o_color = i;";
break;
}
os << NL " r.o_color[coord.x] = o_color;" NL "}";
return os.str();
}
protected:
long RunStage(int stage)
{
if (!IsImageAtomicSupported())
return NOT_SUPPORTED;
if (!Atomic<GLint>(T2D, stage, GL_R32I))
return ERROR;
if (!Atomic<GLuint>(T2D, stage, GL_R32UI))
return ERROR;
if (!Atomic<GLint>(T3D, stage, GL_R32I))
return ERROR;
if (!Atomic<GLuint>(T3D, stage, GL_R32UI))
return ERROR;
if (!Atomic<GLint>(TCM, stage, GL_R32I))
return ERROR;
if (!Atomic<GLuint>(TCM, stage, GL_R32UI))
return ERROR;
if (!Atomic<GLint>(T2DA, stage, GL_R32I))
return ERROR;
if (!Atomic<GLuint>(T2DA, stage, GL_R32UI))
return ERROR;
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 1.3.4 BasicAllTargetsLoadStoreVS
//-----------------------------------------------------------------------------
class BasicAllTargetsLoadStoreVS : public LoadStoreMachine
{
virtual long Run()
{
if (!IsVSFSAvailable(4, 0) || !IsSSBInVSFSAvailable(1, 0))
return NOT_SUPPORTED;
return RunStage(0);
}
};
//-----------------------------------------------------------------------------
// 1.3.8 BasicAllTargetsLoadStoreCS
//-----------------------------------------------------------------------------
class BasicAllTargetsLoadStoreCS : public LoadStoreMachine
{
virtual long Run()
{
return RunStage(4);
}
};
//-----------------------------------------------------------------------------
// 1.3.9 BasicAllTargetsAtomicVS
//-----------------------------------------------------------------------------
class BasicAllTargetsAtomicVS : public AtomicMachine
{
virtual long Run()
{
if (!IsVSFSAvailable(4, 0) || !IsSSBInVSFSAvailable(1, 0))
return NOT_SUPPORTED;
return RunStage(0);
}
};
//-----------------------------------------------------------------------------
// 1.3.13 BasicAllTargetsAtomicCS
//-----------------------------------------------------------------------------
class BasicAllTargetsAtomicCS : public AtomicMachine
{
virtual long Run()
{
return RunStage(4);
}
};
//-----------------------------------------------------------------------------
// 1.4.1 BasicGLSLMisc
//-----------------------------------------------------------------------------
class BasicGLSLMiscFS : public ShaderImageLoadStoreBase
{
GLuint m_texture;
GLuint m_program;
GLuint m_vao, m_vbo;
GLuint m_buffer;
virtual long Setup()
{
m_texture = 0;
m_program = 0;
m_vao = m_vbo = 0;
m_buffer = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(0, 2) || !IsSSBInVSFSAvailable(0, 1))
return NOT_SUPPORTED;
const int kSize = 32;
std::vector<float> data(kSize * kSize * 4);
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32F, kSize, kSize, 4);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kSize, kSize, 4, GL_RED, GL_FLOAT, &data[0]);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
const char* src_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const char* src_fs =
NL "#define KSIZE 32" NL "layout(std430) buffer out_data {" NL " ivec4 o_color[KSIZE*KSIZE];" NL "};" NL
"layout(r32f, binding = 0) coherent restrict uniform image2D g_image_layer0;" NL
"layout(r32f, binding = 1) volatile uniform image2D g_image_layer1;" NL "void main() {" NL
" ivec2 coord = ivec2(gl_FragCoord.xy);" NL " imageStore(g_image_layer0, coord, vec4(1.0));" NL
" memoryBarrier();" NL " imageStore(g_image_layer1, coord, vec4(2.0));" NL " memoryBarrier();" NL
" imageStore(g_image_layer0, coord, vec4(3.0));" NL " memoryBarrier();" NL
" int coordIndex = coord.x + KSIZE * coord.y;" NL
" o_color[coordIndex] = ivec4(imageLoad(g_image_layer0, coord) + imageLoad(g_image_layer1, coord));" NL
"}";
m_program = BuildProgram(src_vs, src_fs);
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
glBindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
glBindImageTexture(1, m_texture, 0, GL_FALSE, 1, GL_READ_WRITE, GL_R32F);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, kSize, kSize);
std::vector<ivec4> o_data(kSize * kSize);
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &o_data[0], GL_STATIC_DRAW);
glUseProgram(m_program);
glBindVertexArray(m_vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
bool status = true;
ivec4* out_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize * kSize; ++i)
{
if (!Equal(out_data[i], ivec4(5, 0, 0, 2), 0))
{
status = false;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Check failed. Received: " << ToString(out_data[i])
<< " instead of: " << ToString(ivec4(5, 0, 0, 2)) << tcu::TestLog::EndMessage;
}
}
if (status)
return NO_ERROR;
else
return ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glDeleteTextures(1, &m_texture);
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
glDeleteBuffers(1, &m_buffer);
glUseProgram(0);
glDeleteProgram(m_program);
return NO_ERROR;
}
};
class BasicGLSLMiscCS : public ShaderImageLoadStoreBase
{
GLuint m_texture;
GLuint m_program;
GLuint m_buffer;
virtual long Setup()
{
m_texture = 0;
m_program = 0;
m_buffer = 0;
return NO_ERROR;
}
virtual long Run()
{
const int kSize = 10;
std::vector<float> data(kSize * kSize * 4);
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32F, kSize, kSize, 4);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kSize, kSize, 4, GL_RED, GL_FLOAT, &data[0]);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
const char* src_cs =
NL "#define KSIZE 10" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(std430) buffer out_data {" NL " ivec4 o_color[KSIZE*KSIZE];" NL "};" NL
"layout(r32f, binding = 0) coherent restrict uniform image2D g_image_layer0;" NL
"layout(r32f, binding = 1) volatile uniform image2D g_image_layer1;" NL "void main() {" NL
" ivec2 coord = ivec2(gl_LocalInvocationID.xy);" NL " imageStore(g_image_layer0, coord, vec4(1.0));" NL
" memoryBarrier();" NL " imageStore(g_image_layer1, coord, vec4(2.0));" NL " memoryBarrier();" NL
" imageStore(g_image_layer0, coord, vec4(3.0));" NL " memoryBarrier();" NL
" o_color[gl_LocalInvocationIndex] = ivec4(imageLoad(g_image_layer0, coord) + "
"imageLoad(g_image_layer1, coord));" NL "}";
m_program = CreateComputeProgram(src_cs);
glBindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
glBindImageTexture(1, m_texture, 0, GL_FALSE, 1, GL_READ_WRITE, GL_R32F);
std::vector<ivec4> o_data(kSize * kSize);
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &o_data[0], GL_STATIC_DRAW);
glUseProgram(m_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
bool status = true;
ivec4* out_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
for (int i = 0; i < kSize * kSize; ++i)
{
if (!Equal(out_data[i], ivec4(5, 0, 0, 2), 0))
{
status = false;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Check failed. Received: " << ToString(out_data[i])
<< " instead of: " << ToString(ivec4(5, 0, 0, 2)) << tcu::TestLog::EndMessage;
}
}
if (status)
return NO_ERROR;
else
return ERROR;
}
virtual long Cleanup()
{
glDeleteTextures(1, &m_texture);
glUseProgram(0);
glDeleteProgram(m_program);
glDeleteBuffers(1, &m_buffer);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 1.4.2 BasicGLSLEarlyFragTests
//-----------------------------------------------------------------------------
class BasicGLSLEarlyFragTests : public ShaderImageLoadStoreBase
{
GLuint m_texture[2];
GLuint m_program[2];
GLuint m_vao, m_vbo;
GLuint c_program;
GLuint m_buffer;
virtual long Setup()
{
m_texture[0] = m_texture[1] = 0;
m_program[0] = m_program[1] = 0;
m_vao = m_vbo = 0;
m_buffer = 0;
c_program = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(0, 1))
return NOT_SUPPORTED;
const int kSize = 8;
std::vector<vec4> data(kSize * kSize);
glGenTextures(2, m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_FLOAT, &data[0]);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_FLOAT, &data[0]);
glBindTexture(GL_TEXTURE_2D, 0);
const char* glsl_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const char* glsl_early_frag_tests_fs =
NL "layout(early_fragment_tests) in;" NL "layout(location = 0) out vec4 o_color;" NL
"layout(rgba32f, binding = 0) writeonly coherent uniform image2D g_image;" NL "void main() {" NL
" ivec2 coord = ivec2(gl_FragCoord.xy);" NL " imageStore(g_image, coord, vec4(17.0));" NL
" o_color = vec4(1.0, 0.0, 0.0, 1.0);" NL "}";
const char* glsl_fs =
NL "layout(location = 0) out vec4 o_color;" NL
"layout(rgba32f, binding = 1) writeonly coherent uniform image2D g_image;" NL "void main() {" NL
" ivec2 coord = ivec2(gl_FragCoord.xy);" NL " imageStore(g_image, coord, vec4(13.0));" NL
" o_color = vec4(1.0, 0.0, 0.0, 1.0);" NL "}";
m_program[0] = BuildProgram(glsl_vs, glsl_early_frag_tests_fs);
m_program[1] = BuildProgram(glsl_vs, glsl_fs);
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glViewport(0, 0, kSize, kSize);
glBindVertexArray(m_vao);
glEnable(GL_DEPTH_TEST);
glClearColor(0.0, 1.0f, 0.0, 1.0f);
glClearDepthf(0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(m_program[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(m_program[1]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
const char* check_cs =
NL "#define KSIZE 8" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"uniform sampler2D g_sampler;" NL "layout(std430) buffer OutputBuffer {" NL
" vec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL
" data[gl_LocalInvocationIndex] = texelFetch(g_sampler, ivec2(gl_LocalInvocationID), 0);" NL "}";
c_program = CreateComputeProgram(check_cs);
std::vector<vec4> out_data(kSize * kSize);
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &out_data[0], GL_STATIC_DRAW);
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, m_texture[0]);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
glUseProgram(c_program);
glUniform1i(glGetUniformLocation(c_program, "g_sampler"), 5);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
vec4* map_data = (vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
float expectedVal = 0.0f;
const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
if (renderTarget.getDepthBits() == 0)
{
expectedVal = 17.0f;
}
if (!CompareValues(map_data, kSize, vec4(expectedVal)))
return ERROR;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
map_data = (vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize, vec4(13.0f)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glDisable(GL_DEPTH_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepthf(1.0f);
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glDeleteTextures(2, m_texture);
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
glUseProgram(0);
glDeleteProgram(m_program[0]);
glDeleteProgram(m_program[1]);
glDeleteProgram(c_program);
glDeleteBuffers(1, &m_buffer);
glActiveTexture(GL_TEXTURE0);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 1.4.3 BasicGLSLConst
//-----------------------------------------------------------------------------
class BasicGLSLConst : public ShaderImageLoadStoreBase
{
GLuint m_program;
GLuint m_buffer;
virtual long Setup()
{
m_program = 0;
m_buffer = 0;
return NO_ERROR;
}
virtual long Run()
{
const char* src_cs =
NL "layout (local_size_x = 1) in;" NL "layout(std430) buffer out_data {" NL " ivec4 o_color;" NL "};" NL
"uniform int MaxImageUnits;" NL "uniform int MaxCombinedShaderOutputResources;" NL
"uniform int MaxVertexImageUniforms;" NL "uniform int MaxFragmentImageUniforms;" NL
"uniform int MaxComputeImageUniforms;" NL "uniform int MaxCombinedImageUniforms;" NL "void main() {" NL
" o_color = ivec4(0, 1, 0, 1);" NL
" if (gl_MaxImageUnits != MaxImageUnits) o_color = ivec4(1, 0, 0, 1);" NL
" if (gl_MaxCombinedShaderOutputResources != MaxCombinedShaderOutputResources) o_color = ivec4(1, 0, "
"0, 2);" NL " if (gl_MaxVertexImageUniforms != MaxVertexImageUniforms) o_color = ivec4(1, 0, 0, 4);" NL
" if (gl_MaxFragmentImageUniforms != MaxFragmentImageUniforms) o_color = ivec4(1, 0, 0, 5);" NL
" if (gl_MaxComputeImageUniforms != MaxComputeImageUniforms) o_color = ivec4(1, 0, 0, 6);" NL
" if (gl_MaxCombinedImageUniforms != MaxCombinedImageUniforms) o_color = ivec4(1, 0, 0, 9);" NL "}";
m_program = CreateComputeProgram(src_cs);
glUseProgram(m_program);
GLint i;
glGetIntegerv(GL_MAX_IMAGE_UNITS, &i);
glUniform1i(glGetUniformLocation(m_program, "MaxImageUnits"), i);
glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &i);
glUniform1i(glGetUniformLocation(m_program, "MaxCombinedShaderOutputResources"), i);
glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &i);
glUniform1i(glGetUniformLocation(m_program, "MaxVertexImageUniforms"), i);
glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &i);
glUniform1i(glGetUniformLocation(m_program, "MaxFragmentImageUniforms"), i);
glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &i);
glUniform1i(glGetUniformLocation(m_program, "MaxComputeImageUniforms"), i);
glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &i);
glUniform1i(glGetUniformLocation(m_program, "MaxCombinedImageUniforms"), i);
std::vector<ivec4> out_data(1);
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * 4, &out_data[0], GL_STATIC_DRAW);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
ivec4* map_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4 * 4, GL_MAP_READ_BIT);
if (!Equal(map_data[0], ivec4(0, 1, 0, 1), 0))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "[" << i << "] Value is: " << ToString(map_data[0])
<< ". Value should be: " << ToString(ivec4(0, 1, 0, 1)) << tcu::TestLog::EndMessage;
return ERROR;
}
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteProgram(m_program);
glDeleteBuffers(1, &m_buffer);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 2.1.1 AdvancedSyncImageAccess
//-----------------------------------------------------------------------------
class AdvancedSyncImageAccess : public ShaderImageLoadStoreBase
{
GLuint m_buffer;
GLuint m_texture;
GLuint m_store_program;
GLuint m_draw_program;
GLuint m_attribless_vao;
virtual long Setup()
{
m_buffer = 0;
m_texture = 0;
m_store_program = 0;
m_draw_program = 0;
m_attribless_vao = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(1, 0) || !IsSSBInVSFSAvailable(1, 0))
return NOT_SUPPORTED;
const int kSize = 44;
const char* const glsl_store_vs =
NL "layout(rgba32f) writeonly uniform image2D g_output_data;" NL "void main() {" NL
" vec2[4] data = vec2[4](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1));" NL
" imageStore(g_output_data, ivec2(gl_VertexID,0), vec4(data[gl_VertexID], 0.0, 1.0));" NL
" gl_PointSize = 1.0;" NL "}";
const char* const glsl_store_fs = NL "void main() {" NL " discard;" NL "}";
const char* const glsl_draw_vs =
NL "out vec4 vs_color;" NL "layout(rgba32f) readonly uniform image2D g_image;" NL
"uniform sampler2D g_sampler;" NL "void main() {" NL
" vec4 pi = imageLoad(g_image, ivec2(gl_VertexID, 0));" NL
" vec4 ps = texelFetch(g_sampler, ivec2(gl_VertexID, 0), 0);" NL
" if (pi != ps) vs_color = vec4(1.0, 0.0, 0.0, 1.0);" NL
" else vs_color = vec4(0.0, 1.0, 0.0, 1.0);" NL " gl_Position = pi;" NL "}";
const char* const glsl_draw_fs =
NL "#define KSIZE 44" NL "in vec4 vs_color;" NL "layout(std430) buffer OutputBuffer {" NL
" vec4 o_color[KSIZE*KSIZE];" NL "};" NL "void main() {" NL " ivec2 coord = ivec2(gl_FragCoord.xy);" NL
" int coordIndex = coord.x + KSIZE * coord.y;" NL " o_color[coordIndex] = vs_color;" NL "}";
m_store_program = BuildProgram(glsl_store_vs, glsl_store_fs);
m_draw_program = BuildProgram(glsl_draw_vs, glsl_draw_fs);
glGenVertexArrays(1, &m_attribless_vao);
glBindVertexArray(m_attribless_vao);
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
std::vector<ivec4> data(4);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 4, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 1, GL_RGBA, GL_FLOAT, &data[0]);
glBindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glUseProgram(m_store_program);
glDrawArrays(GL_POINTS, 0, 4);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT);
glViewport(0, 0, kSize, kSize);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(m_draw_program);
std::vector<vec4> out_data(kSize * kSize);
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &out_data[0], GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
vec4* map_data = (vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize, vec4(0, 1, 0, 1)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteBuffers(1, &m_buffer);
glDeleteTextures(1, &m_texture);
glDeleteProgram(m_store_program);
glDeleteProgram(m_draw_program);
glDeleteVertexArrays(1, &m_attribless_vao);
glViewport(0, 0, getWindowWidth(), getWindowHeight());
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 2.1.2 AdvancedSyncVertexArray
//-----------------------------------------------------------------------------
class AdvancedSyncVertexArray : public ShaderImageLoadStoreBase
{
GLuint m_position_buffer;
GLuint m_color_buffer;
GLuint m_element_buffer;
GLuint m_texture[3];
GLuint m_store_program;
GLuint m_copy_program;
GLuint m_draw_program;
GLuint m_attribless_vao;
GLuint m_draw_vao;
virtual long Setup()
{
m_position_buffer = 0;
m_color_buffer = 0;
m_element_buffer = 0;
m_store_program = 0;
m_draw_program = 0;
m_copy_program = 0;
m_attribless_vao = 0;
m_draw_vao = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(3, 0))
return NOT_SUPPORTED;
const char* const glsl_store_vs =
NL "layout(rgba32f, binding = 0) writeonly uniform image2D g_position_buffer;" NL
"layout(rgba32f, binding = 1) writeonly uniform image2D g_color_buffer;" NL
"layout(r32ui, binding = 2) writeonly uniform uimage2D g_element_buffer;" NL "uniform vec4 g_color;" NL
"void main() {" NL " vec2[4] data = vec2[4](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1));" NL
" imageStore(g_position_buffer, ivec2(gl_VertexID,0), vec4(data[gl_VertexID], 0.0, 1.0));" NL
" imageStore(g_color_buffer, ivec2(gl_VertexID,0), g_color);" NL
" imageStore(g_element_buffer, ivec2(gl_VertexID,0), uvec4(gl_VertexID));" NL "}";
const char* const glsl_store_fs = NL "void main() {" NL " discard;" NL "}";
const char* glsl_copy_cs =
NL "#define KSIZE 4" NL "layout (local_size_x = KSIZE) in;" NL
"layout(rgba32f, binding = 0) readonly uniform image2D g_position_img;" NL
"layout(rgba32f, binding = 1) readonly uniform image2D g_color_img;" NL
"layout(r32ui, binding = 2) readonly uniform uimage2D g_element_img;" NL
"layout(std430, binding = 1) buffer g_position_buf {" NL " vec2 g_pos[KSIZE];" NL "};" NL
"layout(std430, binding = 2) buffer g_color_buf {" NL " vec4 g_col[KSIZE];" NL "};" NL
"layout(std430, binding = 3) buffer g_element_buf {" NL " uint g_elem[KSIZE];" NL "};" NL
"void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID.x, 0);" NL
" g_pos[coord.x] = (imageLoad(g_position_img, coord)).xy;" NL
" g_col[coord.x] = imageLoad(g_color_img, coord);" NL
" g_elem[coord.x] = uint((imageLoad(g_element_img, coord)).x);" NL "}";
const char* const glsl_draw_vs = NL
"layout(location = 0) in vec4 i_position;" NL "layout(location = 1) in vec4 i_color;" NL
"out vec4 vs_color;" NL "void main() {" NL " gl_Position = i_position;" NL " vs_color = i_color;" NL "}";
const char* const glsl_draw_fs = NL "in vec4 vs_color;" NL "layout(location = 0) out vec4 o_color;" NL
"void main() {" NL " o_color = vs_color;" NL "}";
m_store_program = BuildProgram(glsl_store_vs, glsl_store_fs);
m_copy_program = CreateComputeProgram(glsl_copy_cs);
m_draw_program = BuildProgram(glsl_draw_vs, glsl_draw_fs);
glGenTextures(3, m_texture);
std::vector<ivec4> data(4);
glBindTexture(GL_TEXTURE_2D, m_texture[0]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 4, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 4, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, m_texture[2]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 4, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenVertexArrays(1, &m_attribless_vao);
glGenVertexArrays(1, &m_draw_vao);
glBindVertexArray(m_draw_vao);
glGenBuffers(1, &m_position_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_position_buffer);
glBufferData(GL_ARRAY_BUFFER, 4 * 4 * 4, 0, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &m_color_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_color_buffer);
glBufferData(GL_ARRAY_BUFFER, 4 * 4 * 4, 0, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glGenBuffers(1, &m_element_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_element_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * 4 * 4, 0, GL_STATIC_DRAW);
glBindVertexArray(0);
glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(2, m_texture[2], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI);
glUseProgram(m_store_program);
glUniform4f(glGetUniformLocation(m_store_program, "g_color"), 0.0f, 1.0f, 0.0f, 1.0f);
glBindVertexArray(m_attribless_vao);
glDrawArrays(GL_POINTS, 0, 4);
glUseProgram(m_copy_program);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_position_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_color_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_element_buffer);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glDispatchCompute(1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(m_draw_program);
glBindVertexArray(m_draw_vao);
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | GL_ELEMENT_ARRAY_BARRIER_BIT);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0);
if (!CheckFB(vec4(0, 1, 0, 1)))
{
return ERROR;
}
glUseProgram(m_store_program);
glUniform4f(glGetUniformLocation(m_store_program, "g_color"), 0.0f, 0.0f, 1.0f, 1.0f);
glBindVertexArray(m_attribless_vao);
glDrawArrays(GL_POINTS, 0, 4);
glUseProgram(m_copy_program);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glDispatchCompute(1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(m_draw_program);
glBindVertexArray(m_draw_vao);
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | GL_ELEMENT_ARRAY_BARRIER_BIT);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0);
if (!CheckFB(vec4(0, 0, 1, 1)))
{
return ERROR;
}
return NO_ERROR;
}
virtual long Cleanup()
{
glDisable(GL_RASTERIZER_DISCARD);
glUseProgram(0);
glDeleteTextures(3, m_texture);
glDeleteBuffers(1, &m_position_buffer);
glDeleteBuffers(1, &m_color_buffer);
glDeleteBuffers(1, &m_element_buffer);
glDeleteProgram(m_store_program);
glDeleteProgram(m_copy_program);
glDeleteProgram(m_draw_program);
glDeleteVertexArrays(1, &m_attribless_vao);
glDeleteVertexArrays(1, &m_draw_vao);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 2.1.6 AdvancedSyncImageAccess2
//-----------------------------------------------------------------------------
class AdvancedSyncImageAccess2 : public ShaderImageLoadStoreBase
{
GLuint m_texture;
GLuint m_store_program;
GLuint m_draw_program;
GLuint m_vao;
GLuint m_vbo;
GLuint m_buffer;
virtual long Setup()
{
m_texture = 0;
m_store_program = 0;
m_draw_program = 0;
m_vao = 0;
m_vbo = 0;
m_buffer = 0;
return NO_ERROR;
}
virtual long Run()
{
const int kSize = 32;
if (!IsVSFSAvailable(0, 1) || !IsSSBInVSFSAvailable(0, 1))
return NOT_SUPPORTED;
const char* const glsl_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const char* const glsl_store_fs =
NL "layout(rgba32f) writeonly uniform image2D g_image;" NL "uniform vec4 g_color;" NL "void main() {" NL
" imageStore(g_image, ivec2(gl_FragCoord.xy), g_color);" NL " discard;" NL "}";
const char* const glsl_draw_fs =
NL "layout(location = 0) out vec4 o_color;" NL "uniform sampler2D g_sampler;" NL
"layout(std430) buffer OutputBuffer {" NL " uvec4 counter;" NL " vec4 data[];" NL "};" NL
"void main() {" NL " uint idx = atomicAdd(counter[0], 1u);" NL
" data[idx] = texelFetch(g_sampler, ivec2(gl_FragCoord.xy), 0);" NL "}";
m_store_program = BuildProgram(glsl_vs, glsl_store_fs);
m_draw_program = BuildProgram(glsl_vs, glsl_draw_fs);
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, getWindowWidth(), getWindowHeight());
glBindTexture(GL_TEXTURE_2D, 0);
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
glViewport(0, 0, kSize, kSize);
std::vector<vec4> data_b(kSize * kSize + 1);
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, (kSize * kSize + 1) * 4 * 4, &data_b[0], GL_STATIC_DRAW);
glBindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
glUseProgram(m_store_program);
glUniform4f(glGetUniformLocation(m_store_program, "g_color"), 1.0f, 0.0f, 0.0f, 1.0f);
glBindVertexArray(m_vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glUniform4f(glGetUniformLocation(m_store_program, "g_color"), 0.0f, 1.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, m_texture);
glUseProgram(m_draw_program);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
vec4* map_data =
(vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 4 * 4, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize, vec4(0, 1, 0, 1)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glUseProgram(0);
glDeleteBuffers(1, &m_vbo);
glDeleteTextures(1, &m_texture);
glDeleteProgram(m_store_program);
glDeleteProgram(m_draw_program);
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_buffer);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 2.2.1 AdvancedAllStagesOneImage
//-----------------------------------------------------------------------------
class AdvancedAllStagesOneImage : public ShaderImageLoadStoreBase
{
GLuint m_program;
GLuint c_program;
GLuint m_vao;
GLuint m_vbo;
GLuint m_buffer;
GLuint m_texture;
virtual long Setup()
{
m_program = 0;
c_program = 0;
m_vao = 0;
m_vbo = 0;
m_buffer = 0;
m_texture = 0;
return NO_ERROR;
}
virtual long Run()
{
const int kSize = 64;
if (!IsVSFSAvailable(1, 1) || !IsImageAtomicSupported())
return NOT_SUPPORTED;
/* Note that we use imageAtomicCompSwap on the vertex
* shader on purpose, for two reasons:
*
* * Test can't assume that the vertex shader will be
* executed exactly once per vertex. So the test
* can't use imageAtomicAdd as it is not possible to
* known in advance the final value (see khronos
* issue #1910)
*
* * Test can't assume that all the vertex shader
* executions will be executed before rasterization
* (so fragment shader) starts, specially on tile
* based GPUs. So the test can't use
* imageAtomicExchange, as it could happen that a
* vertex shader execution overrides the values
* being updated by the frament shader (see khronos
* issue #1997)
*/
const char* const glsl_vs =
NL "layout(location = 0) in vec4 i_position;" NL
"layout(r32ui, binding = 3) coherent uniform uimage2D g_image;" NL "void main() {" NL
" gl_Position = i_position;" NL " imageAtomicCompSwap(g_image, ivec2(0, gl_VertexID), 0u, 100u);" NL "}";
const char* const glsl_fs =
NL "#define KSIZE 64" NL "layout(r32ui, binding = 3) coherent uniform uimage2D g_image;" NL
"void main() {" NL " imageAtomicAdd(g_image, ivec2(0, int(gl_FragCoord.x) & 0x03), 0x1u);" NL "}";
m_program = BuildProgram(glsl_vs, glsl_fs, true, true);
const char* const glsl_cs =
NL "#define KSIZE 4" NL "layout (local_size_x = KSIZE) in;" NL
"layout(r32ui, binding = 3) uniform uimage2D g_image;" NL "layout(std430) buffer out_data {" NL
" uvec4 data[KSIZE];" NL "};" NL "void main() {" NL
" uvec4 v = imageLoad(g_image, ivec2(0, gl_LocalInvocationID.x));" NL
" data[gl_LocalInvocationIndex] = v;" NL "}";
c_program = CreateComputeProgram(glsl_cs, true);
glUseProgram(m_program);
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
std::vector<uvec4> ui32(16);
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 4, 4);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RED_INTEGER, GL_UNSIGNED_INT, &ui32[0]);
glBindTexture(GL_TEXTURE_2D, 0);
glBindImageTexture(3, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI);
glViewport(0, 0, kSize, kSize);
glBindVertexArray(m_vao);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
std::vector<vec4> data_b(4);
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * 4 * 4, &data_b[0], GL_STATIC_DRAW);
glUseProgram(c_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
uvec4* map_data = (uvec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4 * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, 2, uvec4(1024 + 100, 0, 0, 1)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glUseProgram(0);
glDeleteBuffers(1, &m_buffer);
glDeleteBuffers(1, &m_vbo);
glDeleteTextures(1, &m_texture);
glDeleteProgram(m_program);
glDeleteProgram(c_program);
glDeleteVertexArrays(1, &m_vao);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 2.3.2 AdvancedMemoryOrder
//-----------------------------------------------------------------------------
class AdvancedMemoryOrderVSFS : public ShaderImageLoadStoreBase
{
GLuint m_buffer;
GLuint m_texture[2];
GLuint m_program;
GLuint m_vao;
GLuint m_vbo;
virtual long Setup()
{
m_buffer = 0;
m_program = 0;
m_vao = 0;
m_vbo = 0;
return NO_ERROR;
}
virtual long Run()
{
const int kSize = 11;
if (!IsVSFSAvailable(1, 1) || !IsSSBInVSFSAvailable(1, 1))
return NOT_SUPPORTED;
const char* const glsl_vs = NL
"layout(location = 0) in vec4 i_position;" NL "out vec4 vs_color;" NL
"layout(r32f, binding = 0) uniform image2D g_image_vs;" NL "void main() {" NL
" gl_Position = i_position;" NL " vs_color = vec4(41, 42, 43, 44);" NL
" imageStore(g_image_vs, ivec2(gl_VertexID), vec4(1.0));" NL
" imageStore(g_image_vs, ivec2(gl_VertexID), vec4(2.0));" NL
" imageStore(g_image_vs, ivec2(gl_VertexID), vec4(3.0));" NL
" if (imageLoad(g_image_vs, ivec2(gl_VertexID)) != vec4(3,0,0,1)) vs_color = vec4(21, 22, 23, 24);" NL "}";
const char* const glsl_fs =
NL "#define KSIZE 11" NL "in vec4 vs_color;" NL "layout(r32f, binding = 1) uniform image2D g_image;" NL
"layout(std430) buffer out_data {" NL " vec4 data[KSIZE*KSIZE*4];" NL "};" NL "void main() {" NL
" ivec2 coord = ivec2(gl_FragCoord);" NL " int coordIndex = coord.x + KSIZE * coord.y;" NL
" for (int i = 0; i < 4; ++i) {" NL " data[coordIndex + i * KSIZE*KSIZE] = vs_color;" NL " }" NL
" for (int i = 0; i < 4; ++i) {" NL " imageStore(g_image, coord, vec4(i+50));" NL
" vec4 v = imageLoad(g_image, coord);" NL " if (v.x != float(i+50)) {" NL
" data[coordIndex + i * KSIZE*KSIZE] = vec4(v.xyz, i+10);" NL " break;" NL " }" NL " }" NL
"}";
m_program = BuildProgram(glsl_vs, glsl_fs);
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
std::vector<float> data(kSize * kSize);
glGenTextures(2, m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture[0]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, kSize, kSize);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RED, GL_FLOAT, &data[0]);
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, kSize, kSize);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RED, GL_FLOAT, &data[0]);
glBindTexture(GL_TEXTURE_2D, 0);
glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
std::vector<vec4> data_b(kSize * kSize * 4);
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * kSize * kSize * 4 * 4, &data_b[0], GL_STATIC_DRAW);
glUseProgram(m_program);
glViewport(0, 0, kSize, kSize);
glBindVertexArray(m_vao);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
vec4* map_data =
(vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 4 * kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize * 2, vec4(41, 42, 43, 44)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glUseProgram(0);
glDeleteBuffers(1, &m_vbo);
glDeleteBuffers(1, &m_buffer);
glDeleteTextures(2, m_texture);
glDeleteProgram(m_program);
glDeleteVertexArrays(1, &m_vao);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 2.4.1 AdvancedSSOSimple
//-----------------------------------------------------------------------------
class AdvancedSSOSimple : public ShaderImageLoadStoreBase
{
bool pipeline;
GLuint m_texture;
GLuint m_pipeline[2];
GLuint m_vsp, m_fsp0, m_fsp1;
GLuint m_vao, m_vbo;
GLuint m_program[2];
GLuint c_program;
GLuint m_buffer;
virtual long Setup()
{
c_program = 0;
m_buffer = 0;
CreateFullViewportQuad(&m_vao, &m_vbo, NULL);
glGenTextures(1, &m_texture);
const char* const glsl_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const char* const glsl_fs0 =
NL "layout(rgba32f, binding = 2) writeonly uniform image2D g_image[2];" NL "void main() {" NL
" int i = g_image.length();" NL " imageStore(g_image[0], ivec2(gl_FragCoord), vec4(i+98));" NL
" imageStore(g_image[1], ivec2(gl_FragCoord), vec4(i+99));" NL " discard;" NL "}";
const char* const glsl_fs1 =
NL "layout(rgba32f, binding = 0) writeonly uniform image2D g_image[2];" NL "void main() {" NL
" int i = g_image.length();" NL " imageStore(g_image[0], ivec2(gl_FragCoord), vec4(i+8));" NL
" imageStore(g_image[1], ivec2(gl_FragCoord), vec4(i+9));" NL " discard;" NL "}";
if (pipeline)
{
glGenProgramPipelines(2, m_pipeline);
m_vsp = BuildShaderProgram(GL_VERTEX_SHADER, glsl_vs);
m_fsp0 = BuildShaderProgram(GL_FRAGMENT_SHADER, glsl_fs0);
m_fsp1 = BuildShaderProgram(GL_FRAGMENT_SHADER, glsl_fs1);
}
else
{
m_program[0] = BuildProgram(glsl_vs, glsl_fs0);
m_program[1] = BuildProgram(glsl_vs, glsl_fs1);
}
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(0, 2))
return NOT_SUPPORTED;
const int kSize = 4;
const int textureWidth = 16;
const int textureHeight = 16;
if (pipeline)
{
glUseProgramStages(m_pipeline[0], GL_VERTEX_SHADER_BIT, m_vsp);
glUseProgramStages(m_pipeline[0], GL_FRAGMENT_SHADER_BIT, m_fsp0);
glUseProgramStages(m_pipeline[1], GL_VERTEX_SHADER_BIT, m_vsp);
glUseProgramStages(m_pipeline[1], GL_FRAGMENT_SHADER_BIT, m_fsp1);
}
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA32F, textureWidth, textureHeight, 8);
glBindImageTexture(0, m_texture, 0, GL_FALSE, 6, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(1, m_texture, 0, GL_FALSE, 4, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(2, m_texture, 0, GL_FALSE, 1, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(3, m_texture, 0, GL_FALSE, 3, GL_READ_WRITE, GL_RGBA32F);
glBindVertexArray(m_vao);
if (pipeline)
glBindProgramPipeline(m_pipeline[0]);
else
glUseProgram(m_program[0]);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
if (pipeline)
glBindProgramPipeline(m_pipeline[1]);
else
glUseProgram(m_program[1]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
const char* const glsl_cs =
NL "#define KSIZE 4" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(rgba32f, binding = 0) readonly uniform image2D g_image[4];" NL
"layout(std430) buffer OutputBuffer {" NL " uvec4 counter;" NL " vec4 data[];" NL "};" NL
"void main() {" NL " uint idx = atomicAdd(counter[0], 1u);" NL
" data[idx][0] = (imageLoad(g_image[0], ivec2(gl_GlobalInvocationID))).z;" NL
" data[idx][1] = (imageLoad(g_image[1], ivec2(gl_GlobalInvocationID))).z;" NL
" data[idx][2] = (imageLoad(g_image[2], ivec2(gl_GlobalInvocationID))).z;" NL
" data[idx][3] = (imageLoad(g_image[3], ivec2(gl_GlobalInvocationID))).z;" NL "}";
c_program = CreateComputeProgram(glsl_cs);
glUseProgram(c_program);
int wsx = (textureWidth / kSize) * kSize;
int wsy = (textureHeight / kSize) * kSize;
int minor = wsx > wsy ? wsy : wsx;
std::vector<vec4> data_b(wsx * wsy + 1);
glGenBuffers(1, &m_buffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, (wsx * wsy + 1) * 4 * 4, &data_b[0], GL_STATIC_DRAW);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glDispatchCompute(wsx / kSize, wsy / kSize, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
vec4* map_data = (vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 4 * 4, wsx * wsy * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, minor, vec4(10, 11, 100, 101)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteBuffers(1, &m_vbo);
glDeleteTextures(1, &m_texture);
if (pipeline)
{
glDeleteProgram(m_vsp);
glDeleteProgram(m_fsp0);
glDeleteProgram(m_fsp1);
glDeleteProgramPipelines(2, m_pipeline);
}
else
{
glDeleteProgram(m_program[0]);
glDeleteProgram(m_program[1]);
}
glDeleteProgram(c_program);
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_buffer);
return NO_ERROR;
}
public:
AdvancedSSOSimple() : pipeline(true)
{
}
};
//-----------------------------------------------------------------------------
// 2.5 AdvancedCopyImage
//-----------------------------------------------------------------------------
class AdvancedCopyImageFS : public ShaderImageLoadStoreBase
{
GLuint m_texture[2];
GLuint m_program;
GLuint c_program;
GLuint m_vao, m_vbo, m_ebo;
GLuint m_buffer;
virtual long Setup()
{
glGenTextures(2, m_texture);
CreateFullViewportQuad(&m_vao, &m_vbo, &m_ebo);
glGenBuffers(1, &m_buffer);
const char* const glsl_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const char* const glsl_fs =
NL "layout(rgba32f, binding = 3) readonly uniform image2D g_input_image;" NL
"layout(rgba32f, binding = 1) writeonly uniform image2D g_output_image;" NL "void main() {" NL
" ivec2 coord = ivec2(gl_FragCoord);" NL
" imageStore(g_output_image, coord, imageLoad(g_input_image, coord));" NL " discard;" NL "}";
m_program = BuildProgram(glsl_vs, glsl_fs);
const char* const glsl_cs = NL
"#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(rgba32f, binding = 2) readonly uniform image2D g_image;" NL "layout(std430) buffer out_data {" NL
" vec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID);" NL
" data[gl_LocalInvocationIndex] = imageLoad(g_image, coord);" NL "}";
c_program = CreateComputeProgram(glsl_cs);
return NO_ERROR;
}
virtual long Run()
{
const int kSize = 11;
if (!IsVSFSAvailable(0, 2))
return NOT_SUPPORTED;
std::vector<vec4> data(kSize * kSize, vec4(7.0f));
glBindTexture(GL_TEXTURE_2D, m_texture[0]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, kSize, kSize);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_FLOAT, &data[0]);
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, kSize, kSize);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glBindImageTexture(3, m_texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
glBindImageTexture(2, m_texture[1], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
std::vector<vec4> data_b(kSize * kSize);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &data_b[0], GL_STATIC_DRAW);
glUseProgram(m_program);
glBindVertexArray(m_vao);
glViewport(0, 0, kSize, kSize);
glDrawElementsInstanced(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glUseProgram(c_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
vec4* map_data = (vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize, vec4(7.f)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glUseProgram(0);
glDeleteBuffers(1, &m_vbo);
glDeleteBuffers(1, &m_ebo);
glDeleteBuffers(1, &m_buffer);
glDeleteTextures(2, m_texture);
glDeleteProgram(m_program);
glDeleteProgram(c_program);
glDeleteVertexArrays(1, &m_vao);
return NO_ERROR;
}
};
class AdvancedCopyImageCS : public ShaderImageLoadStoreBase
{
GLuint m_texture[2];
GLuint m_program;
GLuint c_program;
GLuint m_buffer;
virtual long Setup()
{
glGenTextures(2, m_texture);
glGenBuffers(1, &m_buffer);
const char* const glsl_cs =
NL "#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(rgba32f, binding = 3) readonly uniform image2D g_input_image;" NL
"layout(rgba32f, binding = 1) writeonly uniform image2D g_output_image;" NL "void main() {" NL
" ivec2 coord = ivec2(gl_LocalInvocationID);" NL
" imageStore(g_output_image, coord, imageLoad(g_input_image, coord));" NL "}";
m_program = CreateComputeProgram(glsl_cs);
const char* const glsl_cs_c = NL
"#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(rgba32f, binding = 2) readonly uniform image2D g_image;" NL "layout(std430) buffer out_data {" NL
" vec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID);" NL
" data[gl_LocalInvocationIndex] = imageLoad(g_image, coord);" NL "}";
c_program = CreateComputeProgram(glsl_cs_c);
return NO_ERROR;
}
virtual long Run()
{
const int kSize = 11;
std::vector<vec4> data(kSize * kSize, vec4(7.0f));
glBindTexture(GL_TEXTURE_2D, m_texture[0]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, kSize, kSize);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_FLOAT, &data[0]);
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, kSize, kSize);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glBindImageTexture(3, m_texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
glBindImageTexture(2, m_texture[1], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
std::vector<vec4> data_b(kSize * kSize);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &data_b[0], GL_STATIC_DRAW);
glUseProgram(m_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glUseProgram(c_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
vec4* map_data = (vec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize, vec4(7.f)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteBuffers(1, &m_buffer);
glDeleteTextures(2, m_texture);
glDeleteProgram(m_program);
glDeleteProgram(c_program);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 2.6 AdvancedAllMips
//-----------------------------------------------------------------------------
class AdvancedAllMipsFS : public ShaderImageLoadStoreBase
{
GLuint m_texture;
GLuint m_store_program, m_load_program;
GLuint m_vao, m_vbo, m_ebo;
GLuint m_buffer;
virtual long Setup()
{
glGenTextures(1, &m_texture);
CreateFullViewportQuad(&m_vao, &m_vbo, &m_ebo);
glGenBuffers(1, &m_buffer);
const char* const glsl_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const char* const glsl_store_fs =
NL "layout(rgba32f, binding = 0) writeonly uniform image2D g_image[4];" NL "void main() {" NL
" imageStore(g_image[0], ivec2(gl_FragCoord), vec4(23));" NL
" imageStore(g_image[1], ivec2(gl_FragCoord), vec4(24));" NL
" imageStore(g_image[2], ivec2(gl_FragCoord), vec4(25));" NL
" imageStore(g_image[3], ivec2(gl_FragCoord), vec4(26));" NL " discard;" NL "}";
const char* const glsl_load_cs = NL
"#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(rgba32f, binding = 0) readonly uniform image2D g_image[4];" NL "layout(std430) buffer out_data {" NL
" ivec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID);" NL
" data[gl_LocalInvocationIndex] = ivec4(2, 3, 4, 5);" NL " vec4 c0 = imageLoad(g_image[0], coord);" NL
" vec4 c1 = imageLoad(g_image[1], coord);" NL " vec4 c2 = imageLoad(g_image[2], coord);" NL
" vec4 c3 = imageLoad(g_image[3], coord);" NL
" if ((all(lessThan(coord, ivec2(2))) && c0 != vec4(23)) || (any(greaterThanEqual(coord, ivec2(2))) && "
"c0.xyz != vec3(0.0)))" NL " data[gl_LocalInvocationIndex][0] = int(c0.x);" NL
" if ((all(lessThan(coord, ivec2(4))) && c1 != vec4(24)) || (any(greaterThanEqual(coord, ivec2(4))) && "
"c1.xyz != vec3(0.0)))" NL " data[gl_LocalInvocationIndex][1] = int(c1.x);" NL
" if ((all(lessThan(coord, ivec2(8))) && c2 != vec4(25)) || (any(greaterThanEqual(coord, ivec2(8))) && "
"c2.xyz != vec3(0.0)))" NL " data[gl_LocalInvocationIndex][2] = int(c2.x);" NL
" if ((all(lessThan(coord, ivec2(16))) && c3 != vec4(26)) || (any(greaterThanEqual(coord, ivec2(16))) && "
"c3.xyz != vec3(0.0)))" NL " data[gl_LocalInvocationIndex][3] = int(c3.x);" NL "}";
m_store_program = BuildProgram(glsl_vs, glsl_store_fs);
m_load_program = CreateComputeProgram(glsl_load_cs);
return NO_ERROR;
}
virtual long Run()
{
const int kSize = 11;
if (!IsVSFSAvailable(0, 4))
return NOT_SUPPORTED;
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexStorage2D(GL_TEXTURE_2D, 8, GL_RGBA32F, 128, 128);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glBindImageTexture(0, m_texture, 6, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(1, m_texture, 5, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(2, m_texture, 4, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(3, m_texture, 3, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
std::vector<GLubyte> data(kSize * kSize * 4 * 4);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &data[0], GL_STATIC_DRAW);
glViewport(0, 0, kSize, kSize);
glBindVertexArray(m_vao);
glUseProgram(m_store_program);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glUseProgram(m_load_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
ivec4* map_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize, ivec4(2, 3, 4, 5)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glUseProgram(0);
glDeleteBuffers(1, &m_vbo);
glDeleteBuffers(1, &m_ebo);
glDeleteTextures(1, &m_texture);
glDeleteProgram(m_store_program);
glDeleteProgram(m_load_program);
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_buffer);
return NO_ERROR;
}
};
class AdvancedAllMipsCS : public ShaderImageLoadStoreBase
{
GLuint m_texture;
GLuint m_store_program, m_load_program;
GLuint m_buffer;
virtual long Setup()
{
glGenTextures(1, &m_texture);
glGenBuffers(1, &m_buffer);
const char* const glsl_store_cs =
NL "#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(rgba32f, binding = 0) writeonly uniform image2D g_image[4];" NL "void main() {" NL
" ivec2 coord = ivec2(gl_LocalInvocationID);" NL " imageStore(g_image[0], coord, vec4(23));" NL
" imageStore(g_image[1], coord, vec4(24));" NL " imageStore(g_image[2], coord, vec4(25));" NL
" imageStore(g_image[3], coord, vec4(26));" NL "}";
const char* const glsl_load_cs = NL
"#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(rgba32f, binding = 0) readonly uniform image2D g_image[4];" NL "layout(std430) buffer out_data {" NL
" ivec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID);" NL
" data[gl_LocalInvocationIndex] = ivec4(2, 3, 4, 5);" NL " vec4 c0 = imageLoad(g_image[0], coord);" NL
" vec4 c1 = imageLoad(g_image[1], coord);" NL " vec4 c2 = imageLoad(g_image[2], coord);" NL
" vec4 c3 = imageLoad(g_image[3], coord);" NL
" if ((all(lessThan(coord, ivec2(2))) && c0 != vec4(23)) || (any(greaterThanEqual(coord, ivec2(2))) && "
"c0.xyz != vec3(0.0)))" NL " data[gl_LocalInvocationIndex][0] = int(c0.x);" NL
" if ((all(lessThan(coord, ivec2(4))) && c1 != vec4(24)) || (any(greaterThanEqual(coord, ivec2(4))) && "
"c1.xyz != vec3(0.0)))" NL " data[gl_LocalInvocationIndex][1] = int(c1.x);" NL
" if ((all(lessThan(coord, ivec2(8))) && c2 != vec4(25)) || (any(greaterThanEqual(coord, ivec2(8))) && "
"c2.xyz != vec3(0.0)))" NL " data[gl_LocalInvocationIndex][2] = int(c2.x);" NL
" if ((all(lessThan(coord, ivec2(16))) && c3 != vec4(26)) || (any(greaterThanEqual(coord, ivec2(16))) && "
"c3.xyz != vec3(0.0)))" NL " data[gl_LocalInvocationIndex][3] = int(c3.x);" NL "}";
m_store_program = CreateComputeProgram(glsl_store_cs);
m_load_program = CreateComputeProgram(glsl_load_cs);
return NO_ERROR;
}
virtual long Run()
{
const int kSize = 11;
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexStorage2D(GL_TEXTURE_2D, 8, GL_RGBA32F, 128, 128);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
glBindImageTexture(0, m_texture, 6, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(1, m_texture, 5, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(2, m_texture, 4, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
glBindImageTexture(3, m_texture, 3, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
std::vector<GLubyte> data(kSize * kSize * 4 * 4);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &data[0], GL_STATIC_DRAW);
glUseProgram(m_store_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glUseProgram(m_load_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
ivec4* map_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize, ivec4(2, 3, 4, 5)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteTextures(1, &m_texture);
glDeleteProgram(m_store_program);
glDeleteProgram(m_load_program);
glDeleteBuffers(1, &m_buffer);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 2.7 AdvancedCast
//-----------------------------------------------------------------------------
class AdvancedCastFS : public ShaderImageLoadStoreBase
{
GLuint m_texture[2];
GLuint m_program;
GLuint c_program;
GLuint m_vao, m_vbo, m_ebo;
GLuint m_buffer;
virtual long Setup()
{
glGenTextures(2, m_texture);
glGenBuffers(1, &m_buffer);
m_program = 0;
c_program = 0;
return NO_ERROR;
}
virtual long Run()
{
if (!IsVSFSAvailable(0, 2) || !IsImageAtomicSupported())
return NOT_SUPPORTED;
const int kSize = 11;
CreateFullViewportQuad(&m_vao, &m_vbo, &m_ebo);
const char* const glsl_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const char* const glsl_fs =
NL "#define KSIZE 11" NL "layout(r32i, binding = 0) coherent uniform iimage2D g_image0;" NL
"layout(r32ui, binding = 1) coherent uniform uimage2D g_image1;" NL "void main() {" NL
" ivec2 coord = ivec2(gl_FragCoord.xy);" NL " imageAtomicAdd(g_image0, coord, 2);" NL
" imageAtomicAdd(g_image0, coord, -1);" NL " imageAtomicAdd(g_image1, coord, 1u);" NL
" imageAtomicAdd(g_image1, coord, 2u);" NL "}";
m_program = BuildProgram(glsl_vs, glsl_fs, false, true);
const char* const glsl_cs = NL
"#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(r32i, binding = 0) uniform iimage2D gi_image;" NL
"layout(r32ui, binding = 1) uniform uimage2D gu_image;" NL "layout(std430) buffer out_data {" NL
" ivec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID);" NL
" data[gl_LocalInvocationIndex].yx = imageLoad(gi_image, coord).xy;" NL
" data[gl_LocalInvocationIndex].wz = ivec2(imageLoad(gu_image, coord).xz);" NL "}";
c_program = CreateComputeProgram(glsl_cs);
std::vector<GLubyte> data(kSize * kSize * 4 * 4);
glActiveTexture(GL_TEXTURE11);
glBindTexture(GL_TEXTURE_2D, m_texture[0]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glActiveTexture(GL_TEXTURE15);
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32I);
glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &data[0], GL_STATIC_DRAW);
glUseProgram(m_program);
glBindVertexArray(m_vao);
glViewport(0, 0, kSize, kSize);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, 0);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glUseProgram(c_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
ivec4* map_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize, ivec4(0, 1, 0, 3)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glViewport(0, 0, getWindowWidth(), getWindowHeight());
glUseProgram(0);
glDeleteBuffers(1, &m_vbo);
glDeleteBuffers(1, &m_ebo);
glDeleteBuffers(1, &m_buffer);
glDeleteTextures(2, m_texture);
glDeleteProgram(m_program);
glDeleteProgram(c_program);
glDeleteVertexArrays(1, &m_vao);
glActiveTexture(GL_TEXTURE0);
return NO_ERROR;
}
};
class AdvancedCastCS : public ShaderImageLoadStoreBase
{
GLuint m_texture[2];
GLuint m_program;
GLuint c_program;
GLuint m_buffer;
virtual long Setup()
{
glGenTextures(2, m_texture);
glGenBuffers(1, &m_buffer);
m_program = 0;
c_program = 0;
return NO_ERROR;
}
virtual long Run()
{
const int kSize = 11;
if (!IsImageAtomicSupported())
return NO_ERROR;
const char* const glsl_cs =
NL "#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(r32i, binding = 0) coherent uniform iimage2D g_image0;" NL
"layout(r32ui, binding = 1) coherent uniform uimage2D g_image1;" NL "void main() {" NL
" ivec2 coord = ivec2(gl_LocalInvocationID);" NL " imageAtomicAdd(g_image0, coord, 222);" NL
" imageAtomicAdd(g_image0, coord, -11);" NL " imageAtomicAdd(g_image1, coord, 1u);" NL
" imageAtomicAdd(g_image1, coord, 2u);" NL "}";
m_program = CreateComputeProgram(glsl_cs, true);
const char* const glsl_cs_c = NL
"#define KSIZE 11" NL "layout (local_size_x = KSIZE, local_size_y = KSIZE) in;" NL
"layout(r32i, binding = 0) uniform iimage2D gi_image;" NL
"layout(r32ui, binding = 1) uniform uimage2D gu_image;" NL "layout(std430) buffer out_data {" NL
" ivec4 data[KSIZE*KSIZE];" NL "};" NL "void main() {" NL " ivec2 coord = ivec2(gl_LocalInvocationID);" NL
" data[gl_LocalInvocationIndex].yz = imageLoad(gi_image, coord).xw;" NL
" data[gl_LocalInvocationIndex].wx = ivec2(imageLoad(gu_image, coord).xy);" NL "}";
c_program = CreateComputeProgram(glsl_cs_c);
std::vector<GLubyte> data(kSize * kSize * 4 * 4);
glActiveTexture(GL_TEXTURE11);
glBindTexture(GL_TEXTURE_2D, m_texture[0]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glActiveTexture(GL_TEXTURE15);
glBindTexture(GL_TEXTURE_2D, m_texture[1]);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32I);
glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, kSize * kSize * 4 * 4, &data[0], GL_STATIC_DRAW);
glUseProgram(m_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glUseProgram(c_program);
glDispatchCompute(1, 1, 1);
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
ivec4* map_data = (ivec4*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * kSize * 4 * 4, GL_MAP_READ_BIT);
if (!CompareValues(map_data, kSize, ivec4(0, 211, 1, 3)))
return ERROR;
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteBuffers(1, &m_buffer);
glDeleteTextures(2, m_texture);
glDeleteProgram(m_program);
glDeleteProgram(c_program);
glActiveTexture(GL_TEXTURE0);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 4.1 NegativeUniform
//-----------------------------------------------------------------------------
class NegativeUniform : public ShaderImageLoadStoreBase
{
GLuint m_program;
virtual long Setup()
{
m_program = 0;
return NO_ERROR;
}
virtual long Run()
{
const char* glsl_vs =
NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
const char* glsl_fs = NL "layout(rgba32f) writeonly uniform image2D g_image;" NL "void main() {" NL
" ivec2 coord = ivec2(gl_FragCoord.xy);" NL
" imageStore(g_image, coord, vec4(0.0));" NL " discard;" NL "}";
m_program = BuildProgram(glsl_vs, glsl_fs);
GLint max_image_units;
glGetIntegerv(GL_MAX_IMAGE_UNITS, &max_image_units);
glUseProgram(m_program);
bool status = true;
GLint i = 1;
glUniform1i(glGetUniformLocation(m_program, "g_image"), 1);
if (glGetError() != GL_INVALID_OPERATION)
status = false;
glUniform1iv(glGetUniformLocation(m_program, "g_image"), 1, &i);
if (glGetError() != GL_INVALID_OPERATION)
status = false;
glUniform1ui(glGetUniformLocation(m_program, "g_image"), 0);
if (glGetError() != GL_INVALID_OPERATION)
status = false;
glUniform2i(glGetUniformLocation(m_program, "g_image"), 0, 0);
if (glGetError() != GL_INVALID_OPERATION)
status = false;
if (!status)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glUniform* should generate INVALID_OPERATION if the location refers to an image variable."
<< tcu::TestLog::EndMessage;
return ERROR;
}
glUseProgram(0);
glProgramUniform1i(m_program, glGetUniformLocation(m_program, "g_image"), 1);
if (glGetError() != GL_INVALID_OPERATION)
status = false;
glProgramUniform1iv(m_program, glGetUniformLocation(m_program, "g_image"), 1, &i);
if (glGetError() != GL_INVALID_OPERATION)
status = false;
glProgramUniform1ui(m_program, glGetUniformLocation(m_program, "g_image"), 0);
if (glGetError() != GL_INVALID_OPERATION)
status = false;
glProgramUniform2i(m_program, glGetUniformLocation(m_program, "g_image"), 0, 0);
if (glGetError() != GL_INVALID_OPERATION)
status = false;
if (!status)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "glProgramUniform* should generate INVALID_OPERATION if the location refers to an image variable."
<< tcu::TestLog::EndMessage;
return ERROR;
}
return NO_ERROR;
}
virtual long Cleanup()
{
glUseProgram(0);
glDeleteProgram(m_program);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 4.2 NegativeBind
//-----------------------------------------------------------------------------
class NegativeBind : public ShaderImageLoadStoreBase
{
GLuint m_texture, m_texture2;
virtual long Setup()
{
m_texture = 0;
m_texture2 = 0;
return NO_ERROR;
}
virtual long Run()
{
GLint max_image_units;
glGetIntegerv(GL_MAX_IMAGE_UNITS, &max_image_units);
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 64, 64);
glBindImageTexture(max_image_units, m_texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
if (glGetError() != GL_INVALID_VALUE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "BindImageTexture should generate INVALID_VALUE if <unit> is greater than or equal to the value of "
"MAX_IMAGE_UNITS."
<< tcu::TestLog::EndMessage;
return ERROR;
}
glBindImageTexture(0, 123, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
if (glGetError() != GL_INVALID_VALUE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "BindImageTexture should generate INVALID_VALUE if <texture> is not the name of an existing texture "
"object."
<< tcu::TestLog::EndMessage;
return ERROR;
}
glBindImageTexture(1, m_texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA);
if (glGetError() != GL_INVALID_VALUE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "BindImageTexture should generate INVALID_VALUE if <format> is not a legal format."
<< tcu::TestLog::EndMessage;
return ERROR;
}
glBindImageTexture(1, m_texture, -1, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
if (glGetError() != GL_INVALID_VALUE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "BindImageTexture should generate INVALID_VALUE if <level> is less than zero."
<< tcu::TestLog::EndMessage;
return ERROR;
}
glBindImageTexture(1, m_texture, 0, GL_FALSE, -1, GL_READ_ONLY, GL_RGBA32F);
if (glGetError() != GL_INVALID_VALUE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "BindImageTexture should generate INVALID_VALUE if <layer> is less than zero."
<< tcu::TestLog::EndMessage;
return ERROR;
}
glGenTextures(1, &m_texture2);
glBindTexture(GL_TEXTURE_2D, m_texture2);
glBindImageTexture(1, m_texture2, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
if (glGetError() != GL_INVALID_OPERATION)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "BindImageTexture should generate INVALID_OPERATION if <texture> is a mutable texture object."
<< tcu::TestLog::EndMessage;
return ERROR;
}
return NO_ERROR;
}
virtual long Cleanup()
{
glDeleteTextures(1, &m_texture);
glDeleteTextures(1, &m_texture2);
return NO_ERROR;
}
};
//-----------------------------------------------------------------------------
// 4.3 NegativeCompileErrors
//-----------------------------------------------------------------------------
class NegativeCompileErrors : public ShaderImageLoadStoreBase
{
virtual long Run()
{
if (!Compile( // writeonly & readonly qualifiers
NL "layout(rgba32f) writeonly readonly uniform image2D g_image;" NL "void main() {" NL
" vec4 o_color;" NL " o_color = imageLoad(g_image, ivec2(0));" NL "}"))
return ERROR;
if (!Compile( // writeonly && reading
NL "layout(rgba32f) writeonly uniform image2D g_image;" NL "void main() {" NL " vec4 o_color;" NL
" o_color = imageLoad(g_image, ivec2(0));" NL "}"))
return ERROR;
if (!Compile( //readonly && writing
NL "uniform vec4 i_color;" NL "layout(rgba32f) readonly uniform image2D g_image;" NL "void main() {" NL
" vec4 o_color;" NL " imageStore(g_image, ivec2(0), i_color);" NL " o_color = i_color;" NL "}"))
return ERROR;
if (!Compile( // no format layout && load
NL "uniform image2D g_image;" NL "void main() {" NL " vec4 o_color;" NL
" o_color = imageLoad(g_image, ivec2(0));" NL "}"))
return ERROR;
if (!Compile( // no fromat layout && readonly && load
NL "readonly uniform image2D g_image;" NL "void main() {" NL " vec4 o_color;" NL
" o_color = imageLoad(g_image, ivec2(0));" NL "}"))
return ERROR;
if (!Compile( // target type image1D not supported
NL "layout(r32i) uniform image1D g_image;" NL "void main() {" NL " vec4 o_color;" NL
" o_color = vec4(1.0);" NL "}"))
return ERROR;
if (!Compile( // format layout not compatible with type
NL "layout(rgba16) writeonly uniform iimage2D g_image;" NL "void main() {" NL " vec4 o_color;" NL
" o_color = vec4(1.0);" NL "}"))
return ERROR;
if (!Compile( // imageAtomicAdd doesn't support r32f
NL "#extension GL_OES_shader_image_atomic : require" NL
"layout(r32f) coherent uniform image2D g_image;" NL "void main() {" NL " vec4 o_color;" NL
" imageAtomicAdd(g_image, ivec2(1), 10);" NL " o_color = vec4(1.0);" NL "}"))
return ERROR;
if (!Compile( // imageAtomicAdd doesn't support rgba8i
NL "#extension GL_OES_shader_image_atomic : require" NL
"layout(rgba8i) coherent uniform iimage2D g_image;" NL "void main() {" NL " vec4 o_color;" NL
" imageAtomicAdd(g_image, ivec2(1), 1);" NL " o_color = vec4(1.0);" NL "}"))
return ERROR;
if (!Compile( // format layout not compatible with type
NL "layout(r32ui) uniform iimage3D g_image;" NL "void main() {" NL " vec4 o_color;" NL
" imageStore(g_image, ivec3(1), ivec4(1));" NL " o_color = vec4(1.0);" NL "}"))
return ERROR;
if (!Compile( // format layout not compatible with type
NL "layout(r32f) uniform uimage2DArray g_image;" NL "void main() {" NL " vec4 o_color;" NL
" imageStore(g_image, ivec3(0), uvec4(1));" NL " o_color = vec4(1.0);" NL "}"))
return ERROR;
if (!Compile( // wrong function argument type
NL "layout(r32f) coherent uniform image2D g_image;" NL "vec4 Load(iimage2D image) {" NL
" return imageLoad(image, vec2(0));" NL "}" NL "void main() {" NL " vec4 o_color;" NL
" o_color = Load(g_image);" NL "}"))
return ERROR;
return NO_ERROR;
}
bool Compile(const std::string& source)
{
const char* const csVer = "#version 310 es" NL "layout(local_size_x = 1) in;";
const char* const src[3] = { csVer, kGLSLPrec, source.c_str() };
const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(sh, 3, src, NULL);
glCompileShader(sh);
GLchar log[1024];
glGetShaderInfoLog(sh, sizeof(log), NULL, log);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader Info Log:\n"
<< log << tcu::TestLog::EndMessage;
GLint status;
glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
glDeleteShader(sh);
if (status == GL_TRUE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Compilation should fail [compute shader]." << tcu::TestLog::EndMessage;
return false;
}
const char* const fsVer = "#version 310 es" NL "precision highp float;";
const char* const fsrc[3] = { fsVer, kGLSLPrec, source.c_str() };
const GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fsh, 3, fsrc, NULL);
glCompileShader(fsh);
glGetShaderInfoLog(fsh, sizeof(log), NULL, log);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader Info Log:\n"
<< log << tcu::TestLog::EndMessage;
glGetShaderiv(fsh, GL_COMPILE_STATUS, &status);
glDeleteShader(fsh);
if (status == GL_TRUE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Compilation should fail [fragment shader]." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
};
//-----------------------------------------------------------------------------
// 4.4 NegativeLinkErrors
//-----------------------------------------------------------------------------
class NegativeLinkErrors : public ShaderImageLoadStoreBase
{
virtual long Run()
{
if (!IsVSFSAvailable(1, 1))
return NOT_SUPPORTED;
if (!Link(NL "layout(location = 0) in vec4 i_position;" NL
"layout(rgba32f) writeonly uniform highp image3D g_image;" NL "void main() {" NL
" imageStore(g_image, ivec3(gl_VertexID), vec4(0));" NL " gl_Position = i_position;" NL "}",
NL "precision highp float;" NL "layout(location = 0) out vec4 o_color;" NL
"layout(rgba32f) writeonly uniform highp image2D g_image;" NL "void main() {" NL
" imageStore(g_image, ivec2(gl_FragCoord), vec4(1.0));" NL " o_color = vec4(1.0);" NL "}"))
return ERROR;
if (!Link(NL "layout(location = 0) in vec4 i_position;" NL
"layout(rgba32f) writeonly uniform highp image2D g_image;" NL "void main() {" NL
" imageStore(g_image, ivec2(gl_VertexID), vec4(0));" NL " gl_Position = i_position;" NL "}",
NL "precision highp float;" NL "layout(location = 0) out vec4 o_color;" NL
"layout(r32f) writeonly uniform highp image2D g_image;" NL "void main() {" NL
" imageStore(g_image, ivec2(gl_FragCoord), vec4(1.0));" NL " o_color = vec4(1.0);" NL "}"))
return ERROR;
return NO_ERROR;
}
bool Link(const std::string& vs, const std::string& fs)
{
const char* const sVer = "#version 310 es";
const GLuint p = glCreateProgram();
const GLuint vsh = glCreateShader(GL_VERTEX_SHADER);
glAttachShader(p, vsh);
glDeleteShader(vsh);
const char* const vssrc[2] = { sVer, vs.c_str() };
glShaderSource(vsh, 2, vssrc, NULL);
glCompileShader(vsh);
const GLuint fsh = glCreateShader(GL_FRAGMENT_SHADER);
glAttachShader(p, fsh);
glDeleteShader(fsh);
const char* const fssrc[2] = { sVer, fs.c_str() };
glShaderSource(fsh, 2, fssrc, NULL);
glCompileShader(fsh);
GLint status;
glGetShaderiv(vsh, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
glDeleteProgram(p);
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "VS compilation should be ok." << tcu::TestLog::EndMessage;
return false;
}
glGetShaderiv(fsh, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
glDeleteProgram(p);
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "FS compilation should be ok." << tcu::TestLog::EndMessage;
return false;
}
glLinkProgram(p);
GLchar log[1024];
glGetProgramInfoLog(p, sizeof(log), NULL, log);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n"
<< log << tcu::TestLog::EndMessage;
glGetProgramiv(p, GL_LINK_STATUS, &status);
glDeleteProgram(p);
if (status == GL_TRUE)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Link operation should fail." << tcu::TestLog::EndMessage;
return false;
}
return true;
}
};
} // anonymous namespace
ShaderImageLoadStoreTests::ShaderImageLoadStoreTests(glcts::Context& context)
: TestCaseGroup(context, "shader_image_load_store", "")
{
}
ShaderImageLoadStoreTests::~ShaderImageLoadStoreTests(void)
{
}
void ShaderImageLoadStoreTests::init()
{
using namespace glcts;
addChild(new TestSubcase(m_context, "basic-api-get", TestSubcase::Create<BasicAPIGet>));
addChild(new TestSubcase(m_context, "basic-api-bind", TestSubcase::Create<BasicAPIBind>));
addChild(new TestSubcase(m_context, "basic-api-barrier", TestSubcase::Create<BasicAPIBarrier>));
addChild(new TestSubcase(m_context, "basic-api-barrier-byRegion", TestSubcase::Create<BasicAPIBarrierByRegion>));
addChild(new TestSubcase(m_context, "basic-api-texParam", TestSubcase::Create<BasicAPITexParam>));
addChild(new TestSubcase(m_context, "basic-allFormats-store-fs", TestSubcase::Create<BasicAllFormatsStoreFS>));
addChild(new TestSubcase(m_context, "basic-allFormats-store-cs", TestSubcase::Create<BasicAllFormatsStoreCS>));
addChild(new TestSubcase(m_context, "basic-allFormats-load-fs", TestSubcase::Create<BasicAllFormatsLoadFS>));
addChild(new TestSubcase(m_context, "basic-allFormats-load-cs", TestSubcase::Create<BasicAllFormatsLoadCS>));
addChild(new TestSubcase(m_context, "basic-allFormats-loadStoreComputeStage",
TestSubcase::Create<BasicAllFormatsLoadStoreComputeStage>));
addChild(new TestSubcase(m_context, "basic-allTargets-store-fs", TestSubcase::Create<BasicAllTargetsStoreFS>));
addChild(new TestSubcase(m_context, "basic-allTargets-store-cs", TestSubcase::Create<BasicAllTargetsStoreCS>));
addChild(new TestSubcase(m_context, "basic-allTargets-load-fs", TestSubcase::Create<BasicAllTargetsLoadFS>));
addChild(new TestSubcase(m_context, "basic-allTargets-load-cs", TestSubcase::Create<BasicAllTargetsLoadCS>));
addChild(new TestSubcase(m_context, "basic-allTargets-atomicFS", TestSubcase::Create<BasicAllTargetsAtomicFS>));
addChild(
new TestSubcase(m_context, "basic-allTargets-loadStoreVS", TestSubcase::Create<BasicAllTargetsLoadStoreVS>));
addChild(
new TestSubcase(m_context, "basic-allTargets-loadStoreCS", TestSubcase::Create<BasicAllTargetsLoadStoreCS>));
addChild(new TestSubcase(m_context, "basic-allTargets-atomicVS", TestSubcase::Create<BasicAllTargetsAtomicVS>));
addChild(new TestSubcase(m_context, "basic-allTargets-atomicCS", TestSubcase::Create<BasicAllTargetsAtomicCS>));
addChild(new TestSubcase(m_context, "basic-glsl-misc-fs", TestSubcase::Create<BasicGLSLMiscFS>));
addChild(new TestSubcase(m_context, "basic-glsl-misc-cs", TestSubcase::Create<BasicGLSLMiscCS>));
addChild(new TestSubcase(m_context, "basic-glsl-earlyFragTests", TestSubcase::Create<BasicGLSLEarlyFragTests>));
addChild(new TestSubcase(m_context, "basic-glsl-const", TestSubcase::Create<BasicGLSLConst>));
addChild(new TestSubcase(m_context, "advanced-sync-imageAccess", TestSubcase::Create<AdvancedSyncImageAccess>));
addChild(new TestSubcase(m_context, "advanced-sync-vertexArray", TestSubcase::Create<AdvancedSyncVertexArray>));
addChild(new TestSubcase(m_context, "advanced-sync-imageAccess2", TestSubcase::Create<AdvancedSyncImageAccess2>));
addChild(new TestSubcase(m_context, "advanced-allStages-oneImage", TestSubcase::Create<AdvancedAllStagesOneImage>));
addChild(new TestSubcase(m_context, "advanced-memory-order-vsfs", TestSubcase::Create<AdvancedMemoryOrderVSFS>));
addChild(new TestSubcase(m_context, "advanced-sso-simple", TestSubcase::Create<AdvancedSSOSimple>));
addChild(new TestSubcase(m_context, "advanced-copyImage-fs", TestSubcase::Create<AdvancedCopyImageFS>));
addChild(new TestSubcase(m_context, "advanced-copyImage-cs", TestSubcase::Create<AdvancedCopyImageCS>));
addChild(new TestSubcase(m_context, "advanced-allMips-fs", TestSubcase::Create<AdvancedAllMipsFS>));
addChild(new TestSubcase(m_context, "advanced-allMips-cs", TestSubcase::Create<AdvancedAllMipsCS>));
addChild(new TestSubcase(m_context, "advanced-cast-fs", TestSubcase::Create<AdvancedCastFS>));
addChild(new TestSubcase(m_context, "advanced-cast-cs", TestSubcase::Create<AdvancedCastCS>));
addChild(new TestSubcase(m_context, "negative-uniform", TestSubcase::Create<NegativeUniform>));
addChild(new TestSubcase(m_context, "negative-bind", TestSubcase::Create<NegativeBind>));
addChild(new TestSubcase(m_context, "negative-compileErrors", TestSubcase::Create<NegativeCompileErrors>));
addChild(new TestSubcase(m_context, "negative-linkErrors", TestSubcase::Create<NegativeLinkErrors>));
}
}