blob: 37aa5b223d738f0293d5d970d9f964d7be38ae76 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2014-2016 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/ /*!
* \file
* \brief
*/ /*-------------------------------------------------------------------*/
#include "gl4cES31CompatibilityTests.hpp"
#include "gluContextInfo.hpp"
#include "glwEnums.hpp"
#include "tcuMatrix.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuVectorUtil.hpp"
#include <assert.h>
#include <cstdarg>
#include <map>
namespace gl4cts
{
namespace es31compatibility
{
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 deqp::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 required)
{
GLint blocksVS, blocksFS;
glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &blocksVS);
glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &blocksFS);
if (blocksVS >= required && blocksFS >= required)
return true;
else
{
std::ostringstream reason;
reason << "Required " << required << " VS storage blocks but only " << blocksVS << " available."
<< std::endl
<< "Required " << required << " FS storage blocks but only " << blocksFS << " available."
<< std::endl;
OutputNotSupported(reason.str());
return false;
}
}
bool IsImageAtomicSupported()
{
bool is_at_least_gl_45 =
(glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5)));
bool is_arb_es31_compatibility = m_context.getContextInfo().isExtensionSupported("GL_ARB_ES3_1_compatibility");
if (!(is_at_least_gl_45 || is_arb_es31_compatibility))
{
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]).c_str()
<< ". Value should be: " << ToString(expected_value).c_str() << "." << 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]).c_str()
<< ". Value should be: " << ToString(expected_value).c_str() << "." << 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 / (float)(1 << pixelFormat.redBits), 1.f / (float)(1 << pixelFormat.greenBits),
1.f / (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 << "Shader 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 << hvs.c_str() << src_vs << tcu::TestLog::EndMessage;
if (src_fs)
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << hfs.c_str() << 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.c_str() << cs.c_str() << 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"
<< 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 (static_cast<GLint>(f) < min_value)
return false;
glGetInteger64v(pname, &i64);
if (static_cast<GLint>(i64) < 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]).c_str()
<< ". Value should be: " << ToString(expected_value).c_str()
<< ". Format is: " << FormatEnumToString(internalformat).c_str() << ". 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]).c_str()
<< ". Value should be: " << ToString(expected_value).c_str()
<< ". Format is: " << FormatEnumToString(internalformat).c_str() << ". 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(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]).c_str()
<< ". Value should be: " << ToString(expected_value).c_str()
<< ". Format is: " << FormatEnumToString(internalformat).c_str() << ". 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]).c_str()
<< ". Value should be: " << ToString(expected_value).c_str()
<< ". Format is: " << FormatEnumToString(internalformat).c_str() << ". 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]).c_str()
<< ". Value should be: " << ToString(expected_value).c_str()
<< ". Format is: " << FormatEnumToString(internalformat).c_str() << "." << 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).c_str()
<< " 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).c_str()
<< " 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(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).c_str()
<< " format failed." << tcu::TestLog::EndMessage;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
glUseProgram(0);
glDeleteProgram(program);
glDeleteTextures(8, textures);
glDeleteBuffers(4, m_buffer);