blob: 5efc4b52d1fc9f1e75f359dc0bcd042d4afafd91 [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 "gl4cShaderImageLoadStoreTests.hpp"
#include "gluContextInfo.hpp"
#include "glwEnums.hpp"
#include "tcuMatrix.hpp"
#include "tcuRenderTarget.hpp"
#include "tcuVectorUtil.hpp"
#include <assert.h>
#include <climits>
#include <cstdarg>
#include <deque>
#include <iomanip>
#include <map>
#include <sstream>
#include <tcuFloat.hpp>
namespace gl4cts
{
using namespace glw;
namespace
{
typedef tcu::Vec2 vec2;
typedef tcu::Vec4 vec4;
typedef tcu::IVec4 ivec4;
typedef tcu::UVec4 uvec4;
typedef tcu::Mat4 mat4;
class ShaderImageLoadStoreBase : public deqp::SubcaseBase
{
virtual std::string Title()
{
return "";
}
virtual std::string Purpose()
{
return "";
}
virtual std::string Method()
{
return "";
}
virtual std::string PassCriteria()
{
return "";
}
public:
bool SupportedInVS(int requiredVS)
{
GLint imagesVS;
glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &imagesVS);
if (imagesVS >= requiredVS)
return true;
else
{
std::ostringstream reason;
reason << "Required " << requiredVS << " VS image uniforms but only " << imagesVS << " available."
<< std::endl;
OutputNotSupported(reason.str());
return false;
}
}
bool SupportedInTCS(int requiredTCS)
{
GLint imagesTCS;
glGetIntegerv(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, &imagesTCS);
if (imagesTCS >= requiredTCS)
return true;
else
{
std::ostringstream reason;
reason << "Required " << requiredTCS << " TCS image uniforms but only " << imagesTCS << " available."
<< std::endl;
OutputNotSupported(reason.str());
return false;
}
}
bool SupportedInTES(int requiredTES)
{
GLint imagesTES;
glGetIntegerv(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, &imagesTES);
if (imagesTES >= requiredTES)
return true;
else
{
std::ostringstream reason;
reason << "Required " << requiredTES << " TES image uniforms but only " << imagesTES << " available."
<< std::endl;
OutputNotSupported(reason.str());
return false;
}
}
bool SupportedInGS(int requiredGS)
{
GLint imagesGS;
glGetIntegerv(GL_MAX_GEOMETRY_IMAGE_UNIFORMS, &imagesGS);
if (imagesGS >= requiredGS)
return true;
else
{
std::ostringstream reason;
reason << "Required " << requiredGS << " GS image uniforms but only " << imagesGS << " available."
<< std::endl;
OutputNotSupported(reason.str());
return false;
}
}
bool SupportedInGeomStages(int required)
{
return SupportedInVS(required) && SupportedInTCS(required) && SupportedInTES(required) &&
SupportedInGS(required);
}
bool SupportedInStage(int stage, int required)
{
switch (stage)
{
case 0:
return SupportedInVS(required);
case 1:
return SupportedInTCS(required);
case 2:
return SupportedInTES(required);
case 3:
return SupportedInGS(required);
default:
return true;
}
}
bool SupportedSamples(int required)
{
int i;
glGetIntegerv(GL_MAX_IMAGE_SAMPLES, &i);
if (i >= required)
return true;
else
{
std::ostringstream reason;
reason << "Required " << required << " image samples but only " << i << " available." << std::endl;
OutputNotSupported(reason.str());
return false;
}
}
int getWindowWidth()
{
const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
return renderTarget.getWidth();
}
int getWindowHeight()
{
const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
return renderTarget.getHeight();
}
inline bool ColorEqual(const 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 IsEqual(vec4 a, vec4 b)
{
return (a[0] == b[0]) && (a[1] == b[1]) && (a[2] == b[2]) && (a[3] == b[3]);
}
bool Equal(const vec4& v0, const vec4& v1, GLenum internalformat)
{
if (internalformat == GL_RGBA16_SNORM || internalformat == GL_RG16_SNORM || internalformat == GL_R16_SNORM)
{
return ColorEqual(v0, v1, vec4(0.0001f));
}
else if (internalformat == GL_RGBA8_SNORM || internalformat == GL_RG8_SNORM || internalformat == GL_R8_SNORM)
{
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();
}
bool ValidateReadBuffer(int x, int y, int w, int h, const vec4& expected)
{
bool status = true;
const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
const tcu::PixelFormat& pixelFormat = renderTarget.getPixelFormat();
vec4 g_color_eps = vec4(
1.f / static_cast<float>(1 << pixelFormat.redBits), 1.f / static_cast<float>(1 << pixelFormat.greenBits),
1.f / static_cast<float>(1 << pixelFormat.blueBits), 1.f / static_cast<float>(1 << pixelFormat.alphaBits));
std::vector<vec4> fb(w * h);
glReadPixels(x, y, w, h, GL_RGBA, GL_FLOAT, &fb[0]);
for (int yy = 0; yy < h; ++yy)
{
for (int xx = 0; xx < w; ++xx)
{
const int idx = yy * w + xx;
if (!ColorEqual(fb[idx], expected, g_color_eps))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "First bad color: " << ToString(fb[idx])
<< tcu::TestLog::EndMessage;
status = false;
return status;
}
}
}
return status;
}
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_tcs, const char* src_tes, const char* src_gs,
const char* src_fs, bool* result = NULL)
{
const GLuint p = glCreateProgram();
if (src_vs)
{
GLuint sh = glCreateShader(GL_VERTEX_SHADER);
glAttachShader(p, sh);
glDeleteShader(sh);
glShaderSource(sh, 1, &src_vs, NULL);
if (!CompileShader(sh))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_vs << tcu::TestLog::EndMessage;
if (result)
*result = false;
return p;
}
}
if (src_tcs)
{
GLuint sh = glCreateShader(GL_TESS_CONTROL_SHADER);
glAttachShader(p, sh);
glDeleteShader(sh);
glShaderSource(sh, 1, &src_tcs, NULL);
if (!CompileShader(sh))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_tcs << tcu::TestLog::EndMessage;
if (result)
*result = false;
return p;
}
}
if (src_tes)
{
GLuint sh = glCreateShader(GL_TESS_EVALUATION_SHADER);
glAttachShader(p, sh);
glDeleteShader(sh);
glShaderSource(sh, 1, &src_tes, NULL);
if (!CompileShader(sh))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_tes << tcu::TestLog::EndMessage;
if (result)
*result = false;
return p;
}
}
if (src_gs)
{
GLuint sh = glCreateShader(GL_GEOMETRY_SHADER);
glAttachShader(p, sh);
glDeleteShader(sh);
glShaderSource(sh, 1, &src_gs, NULL);
if (!CompileShader(sh))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_gs << tcu::TestLog::EndMessage;
if (result)
*result = false;
return p;
}
}
if (src_fs)
{
GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
glAttachShader(p, sh);
glDeleteShader(sh);
glShaderSource(sh, 1, &src_fs, NULL);
if (!CompileShader(sh))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_fs << tcu::TestLog::EndMessage;
if (result)
*result = false;
return p;
}
}
if (!LinkProgram(p))
{
if (src_vs)
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_vs << tcu::TestLog::EndMessage;
if (src_tcs)
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_tcs << tcu::TestLog::EndMessage;
if (src_tes)
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_tes << tcu::TestLog::EndMessage;
if (src_gs)
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_gs << tcu::TestLog::EndMessage;
if (src_fs)
m_context.getTestContext().getLog() << tcu::TestLog::Message << src_fs << tcu::TestLog::EndMessage;
if (result)
*result = false;
return p;
}
return p;
}
GLuint BuildShaderProgram(GLenum type, const char* src)
{
const GLuint p = glCreateShaderProgramv(type, 1, &src);
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"
<< src << 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_RG32F:
return "rg32f";
case GL_RG16F:
return "rg16f";
case GL_R11F_G11F_B10F:
return "r11f_g11f_b10f";
case GL_R32F:
return "r32f";
case GL_R16F:
return "r16f";
case GL_RGBA32UI:
return "rgba32ui";
case GL_RGBA16UI:
return "rgba16ui";
case GL_RGB10_A2UI:
return "rgb10_a2ui";
case GL_RGBA8UI:
return "rgba8ui";
case GL_RG32UI:
return "rg32ui";
case GL_RG16UI:
return "rg16ui";
case GL_RG8UI:
return "rg8ui";
case GL_R32UI:
return "r32ui";
case GL_R16UI:
return "r16ui";
case GL_R8UI:
return "r8ui";
case GL_RGBA32I:
return "rgba32i";
case GL_RGBA16I:
return "rgba16i";
case GL_RGBA8I:
return "rgba8i";
case GL_RG32I:
return "rg32i";
case GL_RG16I:
return "rg16i";
case GL_RG8I:
return "rg8i";
case GL_R32I:
return "r32i";
case GL_R16I:
return "r16i";
case GL_R8I:
return "r8i";
case GL_RGBA16:
return "rgba16";
case GL_RGB10_A2:
return "rgb10_a2";
case GL_RGBA8:
return "rgba8";
case GL_RG16:
return "rg16";
case GL_RG8:
return "rg8";
case GL_R16:
return "r16";
case GL_R8:
return "r8";
case GL_RGBA16_SNORM:
return "rgba16_snorm";
case GL_RGBA8_SNORM:
return "rgba8_snorm";
case GL_RG16_SNORM:
return "rg16_snorm";
case GL_RG8_SNORM:
return "rg8_snorm";
case GL_R16_SNORM:
return "r16_snorm";
case GL_R8_SNORM:
return "r8_snorm";
}
assert(0);
return "";
}
const char* StageName(int stage)
{
switch (stage)
{
case 0:
return "Vertex Shader";
case 1:
return "Tessellation Control Shader";
case 2:
return "Tessellation Evaluation Shader";
case 3:
return "Geometry Shader";
case 4:
return "Compute Shader";
}
assert(0);
return NULL;
}
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 CheckUniform(GLuint program, const std::string& name, const std::map<std::string, GLuint>& name_index_map,
GLint size, GLenum type)
{
std::map<std::string, GLuint>::const_iterator iter = name_index_map.find(name);
assert(iter != name_index_map.end());
GLchar name_gl[32];
GLsizei length_gl;
GLint size_gl;
GLenum type_gl;
glGetActiveUniform(program, iter->second, sizeof(name_gl), &length_gl, &size_gl, &type_gl, name_gl);
if (std::string(name_gl) != name)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform name is " << name_gl
<< " should be " << name << tcu::TestLog::EndMessage;
return false;
}
if (length_gl != static_cast<GLsizei>(name.length()))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Uniform length is " << length_gl << " should be " << name << "(" << name_gl
<< ")" << tcu::TestLog::EndMessage;
return false;
}
if (size_gl != size)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Uniform size is " << size_gl << " should be " << size << "(" << name_gl
<< ")" << tcu::TestLog::EndMessage;
return false;
}
if (type_gl != type)
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Uniform type is " << type_gl << " should be " << type << "(" << name_gl
<< ")" << tcu::TestLog::EndMessage;
return false;
}
return true;
}
bool CheckMax(GLenum pname, GLint min_value)
{
GLboolean b;
GLint i;
GLfloat f;
GLdouble d;
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;
glGetDoublev(pname, &d);
if (static_cast<GLint>(d) < 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;
}
glGetBooleani_v(GL_IMAGE_BINDING_NAME, unit, &b);
if (b != (i ? GL_TRUE : GL_FALSE))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_IMAGE_BINDING_NAME (as boolean) is " << b << " should be "
<< (i ? GL_TRUE : GL_FALSE) << 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;
}
glGetBooleani_v(GL_IMAGE_BINDING_LEVEL, unit, &b);
if (b != (i ? GL_TRUE : GL_FALSE))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_IMAGE_BINDING_LEVEL (as boolean) is " << b << " should be "
<< (i ? GL_TRUE : GL_FALSE) << tcu::TestLog::EndMessage;
return false;
}
glGetIntegeri_v(GL_IMAGE_BINDING_LAYERED, unit, &i);
if (i != layered)
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_IMAGE_BINDING_LAYERED is " << i
<< " should be " << layered << tcu::TestLog::EndMessage;
return false;
}
glGetBooleani_v(GL_IMAGE_BINDING_LAYERED, unit, &b);
if (b != (i ? GL_TRUE : GL_FALSE))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_IMAGE_BINDING_LAYERED (as boolean) is " << b << " should be "
<< (i ? GL_TRUE : GL_FALSE) << 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;
}
glGetBooleani_v(GL_IMAGE_BINDING_LAYER, unit, &b);
if (b != (i ? GL_TRUE : GL_FALSE))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_IMAGE_BINDING_LAYER (as boolean) is " << b << " should be "
<< (i ? GL_TRUE : GL_FALSE) << 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;
}
glGetBooleani_v(GL_IMAGE_BINDING_ACCESS, unit, &b);
if (b != (i ? GL_TRUE : GL_FALSE))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_IMAGE_BINDING_ACCESS (as boolean) is " << b << " should be "
<< (i ? GL_TRUE : GL_FALSE) << 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;
}
glGetBooleani_v(GL_IMAGE_BINDING_FORMAT, unit, &b);
if (b != (i ? GL_TRUE : GL_FALSE))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_IMAGE_BINDING_FORMAT (as boolean) is " << b << " should be "
<< (i ? GL_TRUE : GL_FALSE) << tcu::TestLog::EndMessage;
return false;
}
return true;
}
const char* EnumToString(GLenum e)
{
switch (e)
{
case GL_TEXTURE_1D:
return "GL_TEXTURE_1D";
case GL_TEXTURE_2D:
return "GL_TEXTURE_2D";
case GL_TEXTURE_3D:
return "GL_TEXTURE_3D";
case GL_TEXTURE_RECTANGLE:
return "GL_TEXTURE_RECTANGLE";
case GL_TEXTURE_CUBE_MAP:
return "GL_TEXTURE_CUBE_MAP";
case GL_TEXTURE_1D_ARRAY:
return "GL_TEXTURE_1D_ARRAY";
case GL_TEXTURE_2D_ARRAY:
return "GL_TEXTURE_2D_ARRAY";
case GL_TEXTURE_CUBE_MAP_ARRAY:
return "GL_TEXTURE_CUBE_MAP_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_1D:
return GL_IMAGE_1D;
case GL_TEXTURE_2D:
return GL_IMAGE_2D;
case GL_TEXTURE_3D:
return GL_IMAGE_3D;
case GL_TEXTURE_RECTANGLE:
return GL_IMAGE_2D_RECT;
case GL_TEXTURE_CUBE_MAP:
return GL_IMAGE_CUBE;
case GL_TEXTURE_BUFFER:
return GL_IMAGE_BUFFER;
case GL_TEXTURE_1D_ARRAY:
return GL_IMAGE_1D_ARRAY;
case GL_TEXTURE_2D_ARRAY:
return GL_IMAGE_2D_ARRAY;
case GL_TEXTURE_CUBE_MAP_ARRAY:
return GL_IMAGE_CUBE_MAP_ARRAY;
case GL_TEXTURE_2D_MULTISAMPLE:
return GL_IMAGE_2D_MULTISAMPLE;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
return GL_IMAGE_2D_MULTISAMPLE_ARRAY;
}
assert(0);
return 0;
}
template <>
GLenum ShaderImageLoadStoreBase::ImageType<ivec4>(GLenum target)
{
switch (target)
{
case GL_TEXTURE_1D:
return GL_INT_IMAGE_1D;
case GL_TEXTURE_2D:
return GL_INT_IMAGE_2D;
case GL_TEXTURE_3D:
return GL_INT_IMAGE_3D;
case GL_TEXTURE_RECTANGLE:
return GL_INT_IMAGE_2D_RECT;
case GL_TEXTURE_CUBE_MAP:
return GL_INT_IMAGE_CUBE;
case GL_TEXTURE_BUFFER:
return GL_INT_IMAGE_BUFFER;
case GL_TEXTURE_1D_ARRAY:
return GL_INT_IMAGE_1D_ARRAY;
case GL_TEXTURE_2D_ARRAY:
return GL_INT_IMAGE_2D_ARRAY;
case GL_TEXTURE_CUBE_MAP_ARRAY:
return GL_INT_IMAGE_CUBE_MAP_ARRAY;
case GL_TEXTURE_2D_MULTISAMPLE:
return GL_INT_IMAGE_2D_MULTISAMPLE;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
return GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY;
}
assert(0);
return 0;
}
template <>
GLenum ShaderImageLoadStoreBase::ImageType<uvec4>(GLenum target)
{
switch (target)
{
case GL_TEXTURE_1D:
return GL_UNSIGNED_INT_IMAGE_1D;
case GL_TEXTURE_2D:
return GL_UNSIGNED_INT_IMAGE_2D;
case GL_TEXTURE_3D:
return GL_UNSIGNED_INT_IMAGE_3D;
case GL_TEXTURE_RECTANGLE:
return GL_UNSIGNED_INT_IMAGE_2D_RECT;
case GL_TEXTURE_CUBE_MAP:
return GL_UNSIGNED_INT_IMAGE_CUBE;
case GL_TEXTURE_BUFFER:
return GL_UNSIGNED_INT_IMAGE_BUFFER;
case GL_TEXTURE_1D_ARRAY:
return GL_UNSIGNED_INT_IMAGE_1D_ARRAY;
case GL_TEXTURE_2D_ARRAY:
return GL_UNSIGNED_INT_IMAGE_2D_ARRAY;
case GL_TEXTURE_CUBE_MAP_ARRAY:
return GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY;
case GL_TEXTURE_2D_MULTISAMPLE:
return GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
return GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY;
}
assert(0);
return 0;
}
//-----------------------------------------------------------------------------
// 1.1.1 BasicAPIGet
//-----------------------------------------------------------------------------
class BasicAPIGet : public ShaderImageLoadStoreBase
{
virtual long Run()
{
if (!CheckMax(GL_MAX_IMAGE_UNITS, 8))
{
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, 8))
{
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_IMAGE_SAMPLES, 0))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_IMAGE_SAMPLES 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_TESS_EVALUATION_IMAGE_UNIFORMS, 0))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS value is invalid."
<< tcu::TestLog::EndMessage;
return ERROR;
}
if (!CheckMax(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, 0))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS value is invalid."
<< tcu::TestLog::EndMessage;
return ERROR;
}
if (!CheckMax(GL_MAX_GEOMETRY_IMAGE_UNIFORMS, 0))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_GEOMETRY_IMAGE_UNIFORMS value is invalid."
<< tcu::TestLog::EndMessage;
return ERROR;
}
if (!CheckMax(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, 8))
{
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, 8))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_MAX_COMBINED_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()
{
for (GLuint index = 0; index < 8; ++index)
{
if (!CheckBinding(index, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8))
{
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Binding point " << index
<< " has invalid default state." << tcu::TestLog::EndMessage;
return ERROR;
}
}
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R32F, 16, 16, 4, 0, GL_RED, GL_FLOAT, NULL);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32F, 8, 8, 4, 0, GL_RED, GL_FLOAT, NULL);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 2, GL_R32F, 4, 4, 4, 0, GL_RED, GL_FLOAT, NULL);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 3, GL_R32F, 2, 2, 4, 0, GL_RED, GL_FLOAT, NULL);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 4, GL_R32F, 1, 1, 4, 0, GL_RED, GL_FLOAT, NULL);
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))
return ERROR;
glBindImageTexture(1, m_texture, 1, GL_TRUE, 1, GL_WRITE_ONLY, GL_RGBA8);
if (!CheckBinding(1, m_texture, 1, GL_TRUE, 1, GL_WRITE_ONLY, GL_RGBA8))
return ERROR;
glBindImageTexture(4, m_texture, 3, GL_FALSE, 2, GL_READ_ONLY, GL_RG16);
if (!CheckBinding(4, m_texture, 3, GL_FALSE, 2, GL_READ_ONLY, GL_RG16))
return ERROR;
glBindImageTexture(7, m_texture, 4, GL_FALSE, 3, GL_READ_ONLY, GL_R32I);
if (!CheckBinding(7, m_texture, 4, GL_FALSE, 3, GL_READ_ONLY, GL_R32I))
return ERROR;
glDeleteTextures(1, &m_texture);
m_texture = 0;
for (GLuint index = 0; index < 8; ++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;
return ERROR;
}
}
return NO_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_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);
glMemoryBarrier(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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, 16, 16, 0, GL_RED, GL_FLOAT, NULL);
GLint i;
GLfloat f;
GLuint ui;
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;
}
glGetTexParameterIiv(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;
}
glGetTexParameterIuiv(GL_TEXTURE_2D, GL_IMAGE_FORMAT_COMPATIBILITY_TYPE, &ui);
if (ui != 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 BasicAllFormatsStore : public ShaderImageLoadStoreBase
{
GLuint m_vao;
GLuint m_vbo;
virtual long Setup()
{
m_vao = 0;
m_vbo = 0;
return NO_ERROR;
}
virtual long Run()
{
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_RG32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.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_RG16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RG32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Write(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Write(GL_R11F_G11F_B10F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RG16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Write(GL_R16I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RG8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Write(GL_R8I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RGB10_A2UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RG32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
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_RG16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Write(GL_R16UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RG8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Write(GL_R8UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA16, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Write(GL_RGB10_A2, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Write(GL_RG16, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R16, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA8, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Write(GL_RG8, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R8, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA16_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f)))
return ERROR;
if (!Write(GL_RG16_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R16_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.0f, 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;
if (!Write(GL_RG8_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R8_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.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 = "#version 420 core" NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL
" gl_Position = i_position;" NL "}";
const GLuint program = BuildProgram(src_vs, NULL, NULL, NULL, GenFS(internalformat, write_value).c_str());
const int kSize = 16;
std::vector<T> data(kSize * kSize);
GLuint texture;
glGenTextures(1, &texture);
for (GLuint unit = 0; unit < 8; ++unit)
{
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);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_2D, 0);
glViewport(0, 0, kSize, kSize);
glUseProgram(program);
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);
glGetTexImage(GL_TEXTURE_2D, 0, Format<T>(), Type<T>(), &data[0]);
for (int i = 0; i < kSize * kSize; ++i)
{
if (!Equal(data[i], expected_value, internalformat))
{
glDeleteTextures(1, &texture);
glUseProgram(0);
glDeleteProgram(program);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Value is: " << ToString(data[i])
<< ". Value should be: " << ToString(expected_value)
<< ". Format is: " << FormatEnumToString(internalformat)
<< ". Unit is: " << unit << tcu::TestLog::EndMessage;
return false;
}
}
if (unit < 7)
{
glUniform1i(glGetUniformLocation(program, "g_image"), static_cast<GLint>(unit + 1));
}
}
glDeleteTextures(1, &texture);
glUseProgram(0);
glDeleteProgram(program);
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 << "#version 420 core" NL "layout(" << FormatEnumToString(internalformat) << ") 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();
}
};
//-----------------------------------------------------------------------------
// 1.2.2 BasicAllFormatsLoad
//-----------------------------------------------------------------------------
class BasicAllFormatsLoad : public ShaderImageLoadStoreBase
{
GLuint m_vao;
GLuint m_vbo;
virtual long Setup()
{
m_vao = 0;
m_vbo = 0;
return NO_ERROR;
}
virtual long Run()
{
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)))
return ERROR;
if (!Read(GL_RG32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!Read(GL_RG16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Read(GL_RG32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Read(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Read(GL_R11F_G11F_B10F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Read(GL_RG16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Read(GL_R16I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Read(GL_RG8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Read(GL_R8I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RGB10_A2UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RG32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Read(GL_R32UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RG16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Read(GL_R16UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RG8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Read(GL_R8UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA16, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Read(GL_RGB10_A2, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Read(GL_RG16, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R16, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA8, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Read(GL_RG8, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R8, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA16_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f)))
return ERROR;
if (!Read(GL_RG16_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R16_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.0f, 1.0f)))
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)))
return ERROR;
if (!Read(GL_RG8_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R8_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
return NO_ERROR;
}
template <typename T>
bool Read(GLenum internalformat, const T& value, const T& expected_value)
{
const char* src_vs = "#version 420 core" NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL
" gl_Position = i_position;" NL "}";
const GLuint program = BuildProgram(src_vs, NULL, NULL, NULL, GenFS(internalformat, expected_value).c_str());
const int kSize = 16;
std::vector<T> data(kSize * kSize, value);
GLuint texture;
glGenTextures(1, &texture);
for (GLuint unit = 0; unit < 8; ++unit)
{
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);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(), &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);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
if (!ValidateReadBuffer(0, 0, kSize, kSize, vec4(0, 1, 0, 1)))
{
glDeleteTextures(1, &texture);
glUseProgram(0);
glDeleteProgram(program);
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Bad load value. Format is: " << FormatEnumToString(internalformat)
<< ". Unit is: " << unit << tcu::TestLog::EndMessage;
return false;
}
if (unit < 7)
{
glUniform1i(glGetUniformLocation(program, "g_image"), static_cast<GLint>(unit + 1));
}
}
glDeleteTextures(1, &texture);
glUseProgram(0);
glDeleteProgram(program);
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 << "#version 420 core" NL "layout(location = 0) out vec4 o_color;" NL "layout("
<< FormatEnumToString(internalformat) << ") readonly uniform " << TypePrefix<T>()
<< "image2D g_image;" NL "void main() {" NL " ivec2 coord = ivec2(gl_FragCoord.xy);" NL " "
<< TypePrefix<T>() << "vec4 v = imageLoad(g_image, coord);" NL " if (v != " << TypePrefix<T>() << "vec4"
<< expected_value
<< ") o_color = vec4(1.0, 0.0, 0.0, 1.0);" NL " else o_color = vec4(0.0, 1.0, 0.0, 1.0);" NL "}";
return os.str();
}
};
//-----------------------------------------------------------------------------
// 1.2.3 BasicAllFormatsStoreGeometryStages
//-----------------------------------------------------------------------------
class BasicAllFormatsStoreGeometryStages : public ShaderImageLoadStoreBase
{
GLuint m_vao;
virtual long Setup()
{
glGenVertexArrays(1, &m_vao);
return NO_ERROR;
}
virtual long Run()
{
if (!SupportedInGeomStages(1))
return NOT_SUPPORTED;
glEnable(GL_RASTERIZER_DISCARD);
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_RG32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.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_RG16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RG32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Write(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Write(GL_R11F_G11F_B10F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RG16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Write(GL_R16I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RG8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Write(GL_R8I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RGB10_A2UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RG32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
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_RG16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Write(GL_R16UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Write(GL_RG8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Write(GL_R8UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Write(GL_RGBA16, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Write(GL_RGB10_A2, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Write(GL_RG16, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R16, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA8, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Write(GL_RG8, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R8, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_RGBA16_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f)))
return ERROR;
if (!Write(GL_RG16_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R16_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.0f, 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;
if (!Write(GL_RG8_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Write(GL_R8_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
return NO_ERROR;
}
template <typename T>
bool Write(GLenum internalformat, const T& write_value, const T& expected_value)
{
const GLuint program =
BuildProgram(GenVS(internalformat, write_value).c_str(), GenTCS(internalformat, write_value).c_str(),
GenTES(internalformat, write_value).c_str(), GenGS(internalformat, write_value).c_str(), NULL);
const int kSize = 1;
std::vector<T> data(kSize * kSize);
GLuint texture[4];
glGenTextures(4, texture);
for (int i = 0; i < 4; ++i)
{
glBindTexture(GL_TEXTURE_2D_ARRAY, texture[i]);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, internalformat, kSize, kSize, 1, 0, Format<T>(), Type<T>(), &data[0]);
}
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glUseProgram(program);
glUniform1i(glGetUniformLocation(program, "g_image0"), 0);
glUniform1i(glGetUniformLocation(program, "g_image1"), 1);
glUniform1i(glGetUniformLocation(program, "g_image2"), 2);
glUniform1i(glGetUniformLocation(program, "g_image3"), 3);
for (GLuint i = 0; i < 4; ++i)
{
glBindImageTexture(i, texture[i], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat);
}
glBindVertexArray(m_vao);
glPatchParameteri(GL_PATCH_VERTICES, 1);
glDrawArrays(GL_PATCHES, 0, 1);
glPatchParameteri(GL_PATCH_VERTICES, 3);
for (int i = 0; i < 4; ++i)
{
glBindTexture(GL_TEXTURE_2D_ARRAY, texture[i]);
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, Format<T>(), Type<T>(), &data[0]);
if (!Equal(data[0], expected_value, internalformat))
{
glDeleteTextures(4, texture);
glUseProgram(0);
glDeleteProgram(program);
m_context.getTestContext().getLog() << tcu::TestLog::Message << "Value is: " << ToString(data[0])
<< ". Value should be: " << ToString(expected_value)
<< ". Format is: " << FormatEnumToString(internalformat)
<< ". Stage is: " << StageName(i) << tcu::TestLog::EndMessage;
return false;
}
}
glDeleteTextures(4, texture);
glUseProgram(0);
glDeleteProgram(program);
return true;
}
virtual long Cleanup()
{
glDisable(GL_RASTERIZER_DISCARD);
glDeleteVertexArrays(1, &m_vao);
return NO_ERROR;
}
template <typename T>
std::string GenVS(GLenum internalformat, const T& value)
{
std::ostringstream os;
os << "#version 420 core" NL "layout(" << FormatEnumToString(internalformat) << ") writeonly uniform "
<< TypePrefix<T>() << "image2DArray g_image0;" NL "void main() {" NL
" ivec3 coord = ivec3(gl_VertexID, 0, 0);" NL " imageStore(g_image0, coord, "
<< TypePrefix<T>() << "vec4" << value << ");" NL "}";
return os.str();
}
template <typename T>
std::string GenTCS(GLenum internalformat, const T& value)
{
std::ostringstream os;
os << "#version 420 core" NL "layout(vertices = 1) out;" NL "layout(" << FormatEnumToString(internalformat)
<< ") writeonly uniform " << TypePrefix<T>()
<< "image2DArray g_image1;" NL "void main() {" NL " gl_TessLevelInner[0] = 1;" NL
" gl_TessLevelInner[1] = 1;" NL " gl_TessLevelOuter[0] = 1;" NL " gl_TessLevelOuter[1] = 1;" NL
" gl_TessLevelOuter[2] = 1;" NL " gl_TessLevelOuter[3] = 1;" NL
" ivec3 coord = ivec3(gl_PrimitiveID, 0, 0);" NL " imageStore(g_image1, coord, "
<< TypePrefix<T>() << "vec4" << value << ");" NL "}";
return os.str();
}
template <typename T>
std::string GenTES(GLenum internalformat, const T& value)
{
std::ostringstream os;
os << "#version 420 core" NL "layout(triangles, point_mode) in;" NL "layout("
<< FormatEnumToString(internalformat) << ") writeonly uniform " << TypePrefix<T>()
<< "image2DArray g_image2;" NL "void main() {" NL " ivec3 coord = ivec3(gl_PrimitiveID, 0, 0);" NL
" imageStore(g_image2, coord, "
<< TypePrefix<T>() << "vec4" << value << ");" NL "}";
return os.str();
}
template <typename T>
std::string GenGS(GLenum internalformat, const T& value)
{
std::ostringstream os;
os << "#version 420 core" NL "layout(points) in;" NL "layout(points, max_vertices = 1) out;" NL "layout("
<< FormatEnumToString(internalformat) << ") writeonly uniform " << TypePrefix<T>()
<< "image2DArray g_image3;" NL "void main() {" NL " ivec3 coord = ivec3(gl_PrimitiveIDIn, 0, 0);" NL
" imageStore(g_image3, coord, "
<< TypePrefix<T>() << "vec4" << value << ");" NL "}";
return os.str();
}
};
//-----------------------------------------------------------------------------
// 1.2.4 BasicAllFormatsLoadGeometryStages
//-----------------------------------------------------------------------------
class BasicAllFormatsLoadGeometryStages : public ShaderImageLoadStoreBase
{
GLuint m_vao;
virtual long Setup()
{
glGenVertexArrays(1, &m_vao);
return NO_ERROR;
}
virtual long Run()
{
if (!SupportedInGeomStages(2))
return NOT_SUPPORTED;
glEnable(GL_RASTERIZER_DISCARD);
if (!Read(GL_RGBA32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!Read(GL_RG32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!Read(GL_RG16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Read(GL_RG32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Read(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Read(GL_R11F_G11F_B10F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Read(GL_RG16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Read(GL_R16I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Read(GL_RG8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Read(GL_R8I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RGB10_A2UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RG32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Read(GL_R32UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RG16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Read(GL_R16UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RG8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Read(GL_R8UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA16, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Read(GL_RGB10_A2, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Read(GL_RG16, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R16, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA8, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Read(GL_RG8, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R8, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA16_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f)))
return ERROR;
if (!Read(GL_RG16_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R16_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.0f, 1.0f)))
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)))
return ERROR;
if (!Read(GL_RG8_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R8_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
return NO_ERROR;
}
template <typename T>
bool Read(GLenum internalformat, const T& value, const T& expected_value)
{
const GLuint program = BuildProgram(
GenVS(internalformat, expected_value).c_str(), GenTCS(internalformat, expected_value).c_str(),
GenTES(internalformat, expected_value).c_str(), GenGS(internalformat, expected_value).c_str(), NULL);
const int kSize = 1;
std::vector<T> data(kSize * kSize, value);
GLuint texture[8];
glGenTextures(8, texture);
for (int i = 0; i < 4; ++i)
{
glBindTexture(GL_TEXTURE_2D_ARRAY, texture[i]);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, internalformat, kSize, kSize, 1, 0, Format<T>(), Type<T>(), &data[0]);
}
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
vec4 zero(0);
for (int i = 4; i < 8; ++i)
{
glBindTexture(GL_TEXTURE_2D, texture[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kSize, kSize, 0, GL_RGBA, GL_FLOAT, &zero);
}
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(program);
glUniform1i(glGetUniformLocation(program, "g_image0"), 0);
glUniform1i(glGetUniformLocation(program, "g_image1"), 1);
glUniform1i(glGetUniformLocation(program, "g_image2"), 2);
glUniform1i(glGetUniformLocation(program, "g_image3"), 3);
glUniform1i(glGetUniformLocation(program, "g_image0_result"), 4);
glUniform1i(glGetUniformLocation(program, "g_image1_result"), 5);
glUniform1i(glGetUniformLocation(program, "g_image2_result"), 6);
glUniform1i(glGetUniformLocation(program, "g_image3_result"), 7);
for (GLuint i = 0; i < 4; ++i)
{
glBindImageTexture(i, texture[i], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat);
}
for (GLuint i = 4; i < 8; ++i)
{
glBindImageTexture(i, texture[i], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
}
glBindVertexArray(m_vao);
glPatchParameteri(GL_PATCH_VERTICES, 1);
glDrawArrays(GL_PATCHES, 0, 1);
glPatchParameteri(GL_PATCH_VERTICES, 3);
const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
const tcu::PixelFormat& pixelFormat = renderTarget.getPixelFormat();
vec4 g_color_eps = vec4(
1.f / static_cast<float>(1 << pixelFormat.redBits), 1.f / static_cast<float>(1 << pixelFormat.greenBits),
1.f / static_cast<float>(1 << pixelFormat.blueBits), 1.f / static_cast<float>(1 << pixelFormat.alphaBits));
for (int i = 0; i < 4; ++i)
{
glBindTexture(GL_TEXTURE_2D, texture[i + 4]);
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
vec4 result;
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &result[0]);
if (!ColorEqual(result, vec4(0, 1, 0, 1), g_color_eps))
{
glDeleteTextures(8, texture);
glUseProgram(0);
glDeleteProgram(program);
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Bad load value. Format is: " << FormatEnumToString(internalformat)
<< ". Stage is: " << StageName(i) << tcu::TestLog::EndMessage;
return false;
}
}
glDeleteTextures(8, texture);
glUseProgram(0);
glDeleteProgram(program);
return true;
}
virtual long Cleanup()
{
glDisable(GL_RASTERIZER_DISCARD);
glDeleteVertexArrays(1, &m_vao);
return NO_ERROR;
}
template <typename T>
std::string GenVS(GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << "#version 420 core" NL "layout(" << FormatEnumToString(internalformat) << ") readonly uniform "
<< TypePrefix<T>()
<< "image2DArray g_image0;" NL "layout(rgba32f) writeonly uniform image2D g_image0_result;" NL
"void main() {" NL " ivec3 coord = ivec3(gl_VertexID, 0, 0);" NL " "
<< TypePrefix<T>() << "vec4 v = imageLoad(g_image0, coord);" NL " if (v != " << TypePrefix<T>() << "vec4"
<< expected_value << ") imageStore(g_image0_result, coord.xy, vec4(1.0, 0.0, 0.0, 1.0));" NL
" else imageStore(g_image0_result, coord.xy, vec4(0.0, 1.0, 0.0, 1.0));" NL "}";
return os.str();
}
template <typename T>
std::string GenTCS(GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << "#version 420 core" NL "layout(vertices = 1) out;" NL "layout(" << FormatEnumToString(internalformat)
<< ") readonly uniform " << TypePrefix<T>()
<< "image2DArray g_image1;" NL "layout(rgba32f) writeonly uniform image2D g_image1_result;" NL
"void main() {" NL " gl_TessLevelInner[0] = 1;" NL " gl_TessLevelInner[1] = 1;" NL
" gl_TessLevelOuter[0] = 1;" NL " gl_TessLevelOuter[1] = 1;" NL " gl_TessLevelOuter[2] = 1;" NL
" gl_TessLevelOuter[3] = 1;" NL " ivec3 coord = ivec3(gl_PrimitiveID, 0, 0);" NL " "
<< TypePrefix<T>() << "vec4 v = imageLoad(g_image1, coord);" NL " if (v != " << TypePrefix<T>() << "vec4"
<< expected_value << ") imageStore(g_image1_result, coord.xy, vec4(1.0, 0.0, 0.0, 1.0));" NL
" else imageStore(g_image1_result, coord.xy, vec4(0.0, 1.0, 0.0, 1.0));" NL "}";
return os.str();
}
template <typename T>
std::string GenTES(GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << "#version 420 core" NL "layout(triangles, point_mode) in;" NL "layout("
<< FormatEnumToString(internalformat) << ") readonly uniform " << TypePrefix<T>()
<< "image2DArray g_image2;" NL "layout(rgba32f) writeonly uniform image2D g_image2_result;" NL
"void main() {" NL " ivec3 coord = ivec3(gl_PrimitiveID, 0, 0);" NL " "
<< TypePrefix<T>() << "vec4 v = imageLoad(g_image2, coord);" NL " if (v != " << TypePrefix<T>() << "vec4"
<< expected_value << ") imageStore(g_image2_result, coord.xy, vec4(1.0, 0.0, 0.0, 1.0));" NL
" else imageStore(g_image2_result, coord.xy, vec4(0.0, 1.0, 0.0, 1.0));" NL "}";
return os.str();
}
template <typename T>
std::string GenGS(GLenum internalformat, const T& expected_value)
{
std::ostringstream os;
os << "#version 420 core" NL "layout(points) in;" NL "layout(points, max_vertices = 1) out;" NL "layout("
<< FormatEnumToString(internalformat) << ") readonly uniform " << TypePrefix<T>()
<< "image2DArray g_image3;" NL "layout(rgba32f) writeonly uniform image2D g_image3_result;" NL
"void main() {" NL " ivec3 coord = ivec3(gl_PrimitiveIDIn, 0, 0);" NL " "
<< TypePrefix<T>() << "vec4 v = imageLoad(g_image3, coord);" NL " if (v != " << TypePrefix<T>() << "vec4"
<< expected_value << ") imageStore(g_image3_result, coord.xy, vec4(1.0, 0.0, 0.0, 1.0));" NL
" else imageStore(g_image3_result, coord.xy, vec4(0.0, 1.0, 0.0, 1.0));" NL "}";
return os.str();
}
};
//-----------------------------------------------------------------------------
// 1.2.5 BasicAllFormatsLoadStoreComputeStage
//-----------------------------------------------------------------------------
class BasicAllFormatsLoadStoreComputeStage : public ShaderImageLoadStoreBase
{
virtual long Run()
{
if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_compute_shader"))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "GL_ARB_compute_shader not supported, skipping test"
<< tcu::TestLog::EndMessage;
return NOT_SUPPORTED;
}
if (!Read(GL_RGBA32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!Read(GL_RG32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R32F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 4.0f)))
return ERROR;
if (!Read(GL_RG16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R16F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Read(GL_RG32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Read(GL_R32I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Read(GL_R11F_G11F_B10F, vec4(1.0f, 2.0f, 3.0f, 4.0f), vec4(1.0f, 2.0f, 3.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Read(GL_RG16I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Read(GL_R16I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Read(GL_RG8I, ivec4(1, -2, 3, -4), ivec4(1, -2, 0, 1)))
return ERROR;
if (!Read(GL_R8I, ivec4(1, -2, 3, -4), ivec4(1, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RGB10_A2UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RG32UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Read(GL_R32UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RG16UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Read(GL_R16UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 2, 3)))
return ERROR;
if (!Read(GL_RG8UI, uvec4(0, 1, 2, 3), uvec4(0, 1, 0, 1)))
return ERROR;
if (!Read(GL_R8UI, uvec4(7, 2, 3, 4), uvec4(7, 0, 0, 1)))
return ERROR;
if (!Read(GL_RGBA16, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Read(GL_RGB10_A2, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Read(GL_RG16, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R16, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA8, vec4(1.0f), vec4(1.0f)))
return ERROR;
if (!Read(GL_RG8, vec4(1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R8, vec4(1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_RGBA16_SNORM, vec4(1.0f, -1.0f, 1.0f, -1.0f), vec4(1.0f, -1.0f, 1.0f, -1.0f)))
return ERROR;
if (!Read(GL_RG16_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R16_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.0f, 1.0f)))
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)))
return ERROR;
if (!Read(GL_RG8_SNORM, vec4(-1.0f), vec4(-1.0f, -1.0f, 0.0f, 1.0f)))
return ERROR;
if (!Read(GL_R8_SNORM, vec4(-1.0f, 1.0f, -1.0f, 1.0f), vec4(-1.0f, 0.0f, 0.0f, 1.0f)))
return ERROR;
return NO_ERROR;
}
template <typename T>
bool Read(GLenum internalformat, const T& value, const T& expected_value)
{
GLuint program;
std::string source = GenCS<T>(internalformat);
const char* const src = source.c_str();
GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(sh, 1, &src, NULL);
glCompileShader(sh);
program = glCreateProgram();
glAttachShader(program, sh);
glLinkProgram(program);
glDeleteShader(sh);
const int kSize = 1;
std::vector<T> data(kSize * kSize, value);
GLuint texture[2];
glGenTextures(2, 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);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(), &data[0]);
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);
vec4 zero(0);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(), &zero);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(program);
glUniform1i(glGetUniformLocation(program, "g_image_read"), 0);
glUniform1i(glGetUniformLocation(program, "g_image_write"), 1);
glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, internalformat);
glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat);
glDispatchCompute(1, 1, 1);
for (int i = 0; i < 2; ++i)
{
glBindTexture(GL_TEXTURE_2D, texture[i]);
glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
glGetTexImage(GL_TEXTURE_2D, 0, Format<T>(), Type<T>(), &data[0]);
if (!Equal(data[0], expected_value, internalformat))
{
glDeleteTextures(4, texture);
glUseProgram(0);
glDeleteProgram(program);
m_context.getTestContext().getLog()
<< tcu::TestLog::Message << "Value is: " << ToString(data[0])
<< ". Value should be: " << ToString(expected_value)
<< ". Format is: " << FormatEnumToString(internalformat) << tcu::TestLog::EndMessage;
return false;
}
}
glDeleteTextures(2, texture);
glUseProgram(0);
glDeleteProgram(program);
return true;
}
template <typename T>
std::string GenCS(GLenum internalformat)
{
std::ostringstream os;
os << "#version 420 core" NL "#extension GL_ARB_compute_shader : require" NL "layout(local_size_x = 1) in;" NL
"layout("
<< FormatEnumToString(internalformat) << ") readonly uniform " << TypePrefix<T>()
<< "image2D g_image_read;" NL "layout(" << FormatEnumToString(internalformat) << ") writeonly uniform "
<< TypePrefix<T>() << "image2D g_image_write;" NL "void main() {" NL
" ivec2 coord = ivec2(int(gl_GlobalInvocationID.x), 0);" NL " "
<< TypePrefix<T>()
<< "vec4 v = imageLoad(g_image_read, coord);" NL " imageStore(g_image_write, coord, v);" NL "}";
return os.str();
}
};
//-----------------------------------------------------------------------------
// 1.3.1 BasicAllTargetsStore
//-----------------------------------------------------------------------------
class BasicAllTargetsStore : public ShaderImageLoadStoreBase
{
GLuint m_vao;
GLuint m_vbo;
virtual long Setup()
{
m_vao = 0;
m_vbo = 0;
return NO_ERROR;
}
virtual long Run()
{
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_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!Write(GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
if (!WriteCubeArray(GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
if (!WriteCubeArray(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!WriteCubeArray(GL_RGBA32UI, uvec4(1, 2, 3, 4), uvec4(1, 2, 3, 4)))
return ERROR;
if (SupportedSamples(4))
{
if (!WriteMS(GL_RGBA32F, vec4(-1.0f, 2.0f, 3.0f, -4.0f), vec4(-1.0f, 2.0f, 3.0f, -4.0f)))
return ERROR;
GLint isamples;
glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &isamples);
if (isamples >= 4)
{
if (!WriteMS(GL_RGBA32I, ivec4(1, -2, 3, -4), ivec4(1, -2, 3, -4)))
return ERROR;
if (!WriteMS(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);
return NO_ERROR;
}
template <typename T>
bool Write(GLenum internalformat, const T& write_value, const T& expected_value)
{
const char* src_vs = "#version 420 core" NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL
" gl_Position = i_position;" NL "}";
const GLuint program = BuildProgram(src_vs, NULL, NULL, NULL, GenFS(internalformat, write_value).c_str());
GLuint textures[8];
GLuint buffer;
glGenTextures(8, textures);
glGenBuffers(1, &buffer);
const int kSize = 16;
std::vector<T> data(kSize * kSize * 2);
glBindTexture(GL_TEXTURE_1D, textures[0]);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage1D(GL_TEXTURE_1D, 0, internalformat, kSize, 0, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_1D, 0);
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);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, kSize, kSize, 0, 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);
glTexImage3D(GL_TEXTURE_3D, 0, internalformat, kSize, kSize, 2, 0, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_3D, 0);
glBindTexture(GL_TEXTURE_RECTANGLE, textures[3]);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_RECTANGLE, 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);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(),
&data[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(),
&data[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(),
&data[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(),
&data[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(),
&data[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalformat, kSize, kSize, 0, Format<T>(), Type<T>(),
&data[0]);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glBindBuffer(GL_TEXTURE_BUFFER, buffer);
glBufferData(GL_TEXTURE_BUFFER, kSize * sizeof(T), &data[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
glBindTexture(GL_TEXTURE_BUFFER, textures[5]);
glTexBuffer(GL_TEXTURE_BUFFER, internalformat, buffer);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindTexture(GL_TEXTURE_1D_ARRAY, textures[6]);
glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_1D_ARRAY, 0, internalformat, kSize, 2, 0, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_1D_ARRAY, 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);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, internalformat, kSize, kSize, 2, 0, Format<T>(), Type<T>(), &data[0]);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindImageTexture(0, textures[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat);
glBindImageTexture(1, textures[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat);
glBindImageTexture(2, textures[2], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat);
glBindImageTexture(3, textures[3], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat);
glBindImageTexture(4, textures[4], 0, GL_TRUE, 0, GL_WRITE_ONLY, internalformat);
glBindImageTexture(5, textures[5], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalformat