| /*------------------------------------------------------------------------- |
| * 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 "tcuPlatform.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "vkPlatform.hpp" |
| #include <assert.h> |
| #include <climits> |
| #include <cmath> |
| #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(); |
| } |
| |
| void scaleDimensionsToMemory(int& width, int& height, int devLayers, int sysLayers, int devBPP, int sysBPP) |
| { |
| vk::PlatformMemoryLimits memoryLimits; |
| m_context.getTestContext().getPlatform().getVulkanPlatform().getMemoryLimits(memoryLimits); |
| GLsizeiptr sysSpace = memoryLimits.totalSystemMemory; |
| GLsizeiptr devSpace = memoryLimits.totalDeviceLocalMemory; |
| int devInSysLayers = 0; |
| |
| if (devSpace == 0) |
| { |
| devInSysLayers = devLayers; |
| devLayers = 0; |
| } |
| |
| // Check if available memory is enough |
| GLsizeiptr pixelsPerLayer = width * height; |
| GLsizeiptr sysRequired = pixelsPerLayer * ((sysBPP * sysLayers) + (devBPP * devInSysLayers)); |
| GLsizeiptr devRequired = pixelsPerLayer * devBPP * devLayers; |
| if ((sysRequired <= sysSpace) && (devRequired <= devSpace)) |
| { |
| return; |
| } |
| |
| // Scales the width and height such that the overall texture fits into |
| // the available space for both system and device. |
| GLdouble scale = sqrt(sysSpace / GLdouble(sysRequired)); |
| if (devSpace != 0) |
| { |
| GLdouble devScale = sqrt(devSpace / GLdouble(devRequired)); |
| scale = de::min(devScale, scale); |
| } |
| int newWidth = int(width * scale); |
| int newHeight = int(height * scale); |
| |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Reducing surface dimensions to fit in memory, from " << width << "x" << height |
| << " to " << newWidth << "x" << newHeight << "." << tcu::TestLog::EndMessage; |
| |
| width = newWidth; |
| height = newHeight; |
| } |
| |
| 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<
|