| /*------------------------------------------------------------------------- |
| * 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 "es31cShaderImageSizeTests.hpp" |
| #include "gluContextInfo.hpp" |
| #include "glwEnums.hpp" |
| #include "tcuMatrix.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include <assert.h> |
| #include <cstdarg> |
| |
| namespace glcts |
| { |
| using namespace glw; |
| |
| namespace |
| { |
| typedef tcu::Vec2 vec2; |
| typedef tcu::Vec3 vec3; |
| typedef tcu::Vec4 vec4; |
| typedef tcu::IVec4 ivec4; |
| typedef tcu::UVec4 uvec4; |
| |
| const char* const kGLSLVer = |
| "#version 310 es\n" NL "precision highp float;" NL "precision highp int;" NL "precision highp image2D;" NL |
| "precision highp image3D;" NL "precision highp imageCube;" NL "precision highp image2DArray;" NL |
| "precision highp iimage2D;" NL "precision highp iimage3D;" NL "precision highp iimageCube;" NL |
| "precision highp iimage2DArray;" NL "precision highp uimage2D;" NL "precision highp uimage3D;" NL |
| "precision highp uimageCube;" NL "precision highp uimage2DArray;"; |
| |
| class ShaderImageSizeBase : public glcts::SubcaseBase |
| { |
| public: |
| virtual std::string Title() |
| { |
| return NL ""; |
| } |
| virtual std::string Purpose() |
| { |
| return NL ""; |
| } |
| virtual std::string Method() |
| { |
| return NL ""; |
| } |
| virtual std::string PassCriteria() |
| { |
| return NL ""; |
| } |
| bool IsVSFSAvailable(int requiredVS, int requiredFS) |
| { |
| GLint imagesVS, imagesFS; |
| glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &imagesVS); |
| glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &imagesFS); |
| if (imagesVS >= requiredVS && imagesFS >= requiredFS) |
| return true; |
| else |
| { |
| std::ostringstream reason; |
| reason << "Required " << requiredVS << " VS storage blocks but only " << imagesVS << " available." |
| << std::endl |
| << "Required " << requiredFS << " FS storage blocks but only " << imagesFS << " available." |
| << std::endl; |
| OutputNotSupported(reason.str()); |
| return false; |
| } |
| } |
| }; |
| |
| template <typename T> |
| std::string ImageTypePrefix(); |
| |
| template <> |
| std::string ImageTypePrefix<vec4>() |
| { |
| return ""; |
| } |
| |
| template <> |
| std::string ImageTypePrefix<ivec4>() |
| { |
| return "i"; |
| } |
| |
| template <> |
| std::string ImageTypePrefix<uvec4>() |
| { |
| return "u"; |
| } |
| |
| template <typename T> |
| std::string ImageFormatPostfix(); |
| |
| template <> |
| std::string ImageFormatPostfix<vec4>() |
| { |
| return "f"; |
| } |
| |
| template <> |
| std::string ImageFormatPostfix<ivec4>() |
| { |
| return "i"; |
| } |
| |
| template <> |
| std::string ImageFormatPostfix<uvec4>() |
| { |
| return "ui"; |
| } |
| |
| template <typename T> |
| GLenum TexInternalFormat(); |
| |
| template <> |
| GLenum TexInternalFormat<vec4>() |
| { |
| return GL_RGBA32F; |
| } |
| |
| template <> |
| GLenum TexInternalFormat<ivec4>() |
| { |
| return GL_RGBA32I; |
| } |
| |
| template <> |
| GLenum TexInternalFormat<uvec4>() |
| { |
| return GL_RGBA32UI; |
| } |
| |
| template <typename T> |
| GLenum TexType(); |
| |
| template <typename T> |
| GLenum TexFormat(); |
| |
| //============================================================================= |
| // ImageSizeMachine |
| //----------------------------------------------------------------------------- |
| class ImageSizeMachine : public glcts::GLWrapper |
| { |
| GLuint m_pipeline; |
| GLuint m_program[3]; |
| GLuint m_vertex_array; |
| GLuint m_buffer; |
| bool pipeline; |
| GLuint m_xfb_id; |
| |
| bool CheckProgram(GLuint program) |
| { |
| if (program == 0) |
| return true; |
| GLint status; |
| glGetProgramiv(program, GL_LINK_STATUS, &status); |
| |
| if (status == GL_FALSE) |
| { |
| GLint attached_shaders; |
| glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders); |
| |
| if (attached_shaders > 0) |
| { |
| std::vector<GLuint> shaders(attached_shaders); |
| glGetAttachedShaders(program, attached_shaders, NULL, &shaders[0]); |
| |
| for (GLint i = 0; i < attached_shaders; ++i) |
| { |
| GLenum type; |
| glGetShaderiv(shaders[i], GL_SHADER_TYPE, reinterpret_cast<GLint*>(&type)); |
| switch (type) |
| { |
| case GL_VERTEX_SHADER: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Vertex Shader ***" << tcu::TestLog::EndMessage; |
| break; |
| case GL_FRAGMENT_SHADER: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Fragment Shader ***" << tcu::TestLog::EndMessage; |
| break; |
| case GL_COMPUTE_SHADER: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Compute Shader ***" << tcu::TestLog::EndMessage; |
| break; |
| default: |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "*** Unknown Shader ***" << tcu::TestLog::EndMessage; |
| break; |
| } |
| |
| GLint length; |
| glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &length); |
| if (length > 0) |
| { |
| std::vector<GLchar> source(length); |
| glGetShaderSource(shaders[i], length, NULL, &source[0]); |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << &source[0] << tcu::TestLog::EndMessage; |
| } |
| glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &length); |
| if (length > 0) |
| { |
| std::vector<GLchar> log(length); |
| glGetShaderInfoLog(shaders[i], length, NULL, &log[0]); |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage; |
| } |
| } |
| } |
| GLint length; |
| glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); |
| if (length > 0) |
| { |
| std::vector<GLchar> log(length); |
| glGetProgramInfoLog(program, length, NULL, &log[0]); |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage; |
| } |
| } |
| return status == GL_TRUE ? true : false; |
| } |
| |
| 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 CreateComputeProgram(const std::string& cs) |
| { |
| const GLuint p = glCreateProgram(); |
| |
| if (!cs.empty()) |
| { |
| const GLuint sh = glCreateShader(GL_COMPUTE_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, cs.c_str() }; |
| glShaderSource(sh, 2, src, NULL); |
| if (!CompileShader(sh)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << src[0] << src[1] << tcu::TestLog::EndMessage; |
| return p; |
| } |
| } |
| if (!LinkProgram(p)) |
| { |
| if (!cs.empty()) |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << kGLSLVer << cs << tcu::TestLog::EndMessage; |
| return p; |
| } |
| |
| return p; |
| } |
| |
| GLuint BuildProgram(const char* src_vs, const char* src_fs, bool use_xfb, bool* result = NULL) |
| { |
| const GLuint p = glCreateProgram(); |
| |
| if (src_vs) |
| { |
| GLuint sh = glCreateShader(GL_VERTEX_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, src_vs }; |
| glShaderSource(sh, 2, src, NULL); |
| if (!CompileShader(sh)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << src[0] << src[1] << tcu::TestLog::EndMessage; |
| if (result) |
| *result = false; |
| return p; |
| } |
| } |
| if (src_fs) |
| { |
| GLuint sh = glCreateShader(GL_FRAGMENT_SHADER); |
| glAttachShader(p, sh); |
| glDeleteShader(sh); |
| const char* const src[2] = { kGLSLVer, src_fs }; |
| glShaderSource(sh, 2, src, NULL); |
| if (!CompileShader(sh)) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << src[0] << src[1] << tcu::TestLog::EndMessage; |
| if (result) |
| *result = false; |
| return p; |
| } |
| } |
| if (use_xfb) |
| SetupTransformFeedback(p); |
| if (!LinkProgram(p)) |
| { |
| if (src_vs) |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << kGLSLVer << src_vs << tcu::TestLog::EndMessage; |
| if (src_fs) |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << kGLSLVer << src_fs << tcu::TestLog::EndMessage; |
| if (result) |
| *result = false; |
| return p; |
| } |
| |
| return p; |
| } |
| |
| void SetupTransformFeedback(GLuint program) |
| { |
| const char* const varying_name = "count"; |
| glTransformFeedbackVaryings(program, 1, &varying_name, GL_INTERLEAVED_ATTRIBS); |
| } |
| |
| inline bool Equal(const ivec4& result, const ivec4& expected) |
| { |
| if (expected[0] != result[0]) |
| return false; |
| if (expected[1] != result[1]) |
| return false; |
| if (expected[2] != result[2]) |
| return false; |
| if (expected[3] != result[3]) |
| return false; |
| return true; |
| } |
| |
| template <typename T> |
| std::string GenShader(int stage) |
| { |
| std::ostringstream os; |
| os << NL "#define KSIZE 4"; |
| if (stage == 0) |
| { // VS uses transform feedback |
| os << NL "flat out ivec4 count[KSIZE];"; |
| } |
| else |
| { // CS + FS use SSBO |
| os << NL "layout(std430) buffer OutputBuffer {" NL " ivec4 count[KSIZE];" NL "};"; |
| } |
| os << NL "layout(binding = 0, rgba32" << ImageFormatPostfix<T>() << ") readonly writeonly uniform highp " |
| << ImageTypePrefix<T>() << "image2D g_image_2d;" NL "layout(binding = 1, rgba32" << ImageFormatPostfix<T>() |
| << ") readonly writeonly uniform highp " << ImageTypePrefix<T>() |
| << "image3D g_image_3d;" NL "layout(binding = 2, rgba32" << ImageFormatPostfix<T>() |
| << ") readonly writeonly uniform highp " << ImageTypePrefix<T>() |
| << "imageCube g_image_cube;" NL "layout(binding = 3, rgba32" << ImageFormatPostfix<T>() |
| << ") readonly writeonly uniform highp " << ImageTypePrefix<T>() << "image2DArray g_image_2d_array;"; |
| if (stage == 0) |
| { // VS |
| os << NL "void main() {" NL " int coord = gl_VertexID;" NL "#ifdef GL_ES" NL " gl_PointSize = 1.0;" NL |
| "#endif"; |
| } |
| else if (stage == 4) |
| { // CS |
| os << NL "layout(local_size_x = 1) in;" NL "void main() {" NL " int coord = int(gl_GlobalInvocationID.x);"; |
| } |
| else if (stage == 5) |
| { // FS |
| os << NL "uniform int fakePrimitiveID;" NL "void main() {" NL " int coord = fakePrimitiveID;"; |
| } |
| os << NL " count[coord + 0] = ivec4(imageSize(g_image_2d), 0, 0);" NL |
| " count[coord + 1] = ivec4(imageSize(g_image_3d), 0);" NL |
| " count[coord + 2] = ivec4(imageSize(g_image_cube), 0, 0);" NL |
| " count[coord + 3] = ivec4(imageSize(g_image_2d_array), 0);" NL "}"; |
| return os.str(); |
| } |
| |
| public: |
| ImageSizeMachine() : pipeline(false) |
| { |
| if (pipeline) |
| glGenProgramPipelines(1, &m_pipeline); |
| memset(m_program, 0, sizeof(m_program)); |
| glGenVertexArrays(1, &m_vertex_array); |
| glGenBuffers(1, &m_buffer); |
| glGenTransformFeedbacks(1, &m_xfb_id); |
| } |
| |
| ~ImageSizeMachine() |
| { |
| if (pipeline) |
| { |
| glDeleteProgramPipelines(1, &m_pipeline); |
| for (int i = 0; i < 3; ++i) |
| glDeleteProgram(m_program[i]); |
| } |
| else |
| { |
| glDeleteProgram(m_program[0]); |
| } |
| glDeleteVertexArrays(1, &m_vertex_array); |
| glDeleteBuffers(1, &m_buffer); |
| glDeleteTransformFeedbacks(1, &m_xfb_id); |
| } |
| |
| template <typename T> |
| long Run(int stage, ivec4 expected_result[4]) |
| { |
| const int kSize = 4; |
| if (stage == 0) |
| { // VS |
| glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_xfb_id); |
| const char* const glsl_fs = NL "void main() {" NL " discard;" NL "}"; |
| std::string vs = GenShader<T>(stage); |
| const char* const glsl_vs = vs.c_str(); |
| if (pipeline) |
| { |
| m_program[0] = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vs); |
| m_program[1] = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fs); |
| glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, m_program[0]); |
| glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, m_program[1]); |
| } |
| else |
| { |
| m_program[0] = BuildProgram(glsl_vs, glsl_fs, true); |
| } |
| } |
| else if (stage == 4) |
| { // CS |
| std::string cs = GenShader<T>(stage); |
| const char* const glsl_cs = cs.c_str(); |
| if (pipeline) |
| { |
| m_program[0] = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_cs); |
| glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program[0]); |
| } |
| else |
| { |
| m_program[0] = CreateComputeProgram(glsl_cs); |
| } |
| } |
| else if (stage == 5) |
| { // FS |
| const char* const glsl_vs = |
| NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL |
| "#ifdef GL_ES" NL " gl_PointSize = 1.0;" NL "#endif" NL "}"; |
| std::string fs = GenShader<T>(stage); |
| const char* const glsl_fs = fs.c_str(); |
| if (pipeline) |
| { |
| m_program[0] = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vs); |
| m_program[1] = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fs); |
| glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, m_program[0]); |
| glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, m_program[1]); |
| } |
| else |
| { |
| m_program[0] = BuildProgram(glsl_vs, glsl_fs, false); |
| } |
| } |
| if (!CheckProgram(m_program[0])) |
| return ERROR; |
| if (pipeline) |
| if (!CheckProgram(m_program[1])) |
| return ERROR; |
| |
| ivec4 data[kSize]; |
| for (int i = 0; i < kSize; ++i) |
| data[i] = ivec4(100000); |
| |
| GLenum output_buffer_type = (stage == 0) ? GL_TRANSFORM_FEEDBACK_BUFFER : GL_SHADER_STORAGE_BUFFER; |
| |
| glBindBufferBase(output_buffer_type, 0, m_buffer); |
| glBufferData(output_buffer_type, kSize * 4 * 4, &data[0], GL_STATIC_DRAW); |
| |
| if (pipeline) |
| glBindProgramPipeline(m_pipeline); |
| else |
| glUseProgram(m_program[0]); |
| glBindVertexArray(m_vertex_array); |
| |
| if (stage == 0) |
| glBeginTransformFeedback(GL_POINTS); |
| |
| if (stage == 4) |
| glDispatchCompute(1, 1, 1); |
| else |
| glDrawArrays(GL_POINTS, 0, 1); |
| |
| glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| |
| if (stage == 0) |
| glEndTransformFeedback(); |
| |
| ivec4* map_data = (ivec4*)glMapBufferRange(output_buffer_type, 0, kSize * 4 * 4, GL_MAP_READ_BIT); |
| for (int i = 0; i < kSize; ++i) |
| { |
| if (!Equal(map_data[i], expected_result[i])) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Returned value is: (" << map_data[i][0] << " " << map_data[i][1] << " " |
| << map_data[i][2] << " " << map_data[i][3] << "). Expected value is: (" << expected_result[i][0] |
| << " " << expected_result[i][1] << " " << expected_result[i][2] << " " << expected_result[i][3] |
| << "). Image unit is: " << i << tcu::TestLog::EndMessage; |
| return ERROR; |
| } |
| } |
| glUnmapBuffer(output_buffer_type); |
| |
| if (stage == 0) |
| glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); |
| |
| return NO_ERROR; |
| } |
| }; |
| |
| //============================================================================= |
| // 1.1.x.y BasicNonMS |
| //----------------------------------------------------------------------------- |
| template <typename T, int STAGE> |
| class BasicNonMS : public ShaderImageSizeBase |
| { |
| GLuint m_texture[4]; |
| |
| virtual long Setup() |
| { |
| glGenTextures(4, m_texture); |
| return NO_ERROR; |
| } |
| virtual long Run() |
| { |
| if (STAGE == 0 && !IsVSFSAvailable(4, 0)) |
| return NOT_SUPPORTED; |
| if (STAGE == 5 && !IsVSFSAvailable(0, 4)) |
| return NOT_SUPPORTED; |
| |
| const GLenum target[4] = { GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_2D_ARRAY }; |
| for (int i = 0; i < 4; ++i) |
| { |
| glBindTexture(target[i], m_texture[i]); |
| glTexParameteri(target[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(target[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| if (i == 0) |
| { |
| glTexStorage2D(target[i], 10, TexInternalFormat<T>(), 512, 128); |
| glBindImageTexture(0, m_texture[i], 1, GL_FALSE, 0, GL_READ_ONLY, TexInternalFormat<T>()); |
| } |
| else if (i == 1) |
| { |
| glTexStorage3D(target[i], 3, TexInternalFormat<T>(), 8, 8, 4); |
| glBindImageTexture(1, m_texture[i], 0, GL_TRUE, 0, GL_READ_ONLY, TexInternalFormat<T>()); |
| } |
| else if (i == 2) |
| { |
| glTexStorage2D(target[i], 4, TexInternalFormat<T>(), 16, 16); |
| glBindImageTexture(2, m_texture[i], 0, GL_TRUE, 0, GL_READ_WRITE, TexInternalFormat<T>()); |
| } |
| else if (i == 3) |
| { |
| glTexStorage3D(target[i], 3, TexInternalFormat<T>(), 127, 39, 12); |
| glBindImageTexture(3, m_texture[i], 2, GL_TRUE, 0, GL_READ_ONLY, TexInternalFormat<T>()); |
| } |
| } |
| ImageSizeMachine machine; |
| ivec4 res[4] = { ivec4(256, 64, 0, 0), ivec4(8, 8, 4, 0), ivec4(16, 16, 0, 0), ivec4(31, 9, 12, 0) }; |
| return machine.Run<T>(STAGE, res); |
| } |
| virtual long Cleanup() |
| { |
| glDeleteTextures(4, m_texture); |
| return NO_ERROR; |
| } |
| }; |
| //============================================================================= |
| // 2.2.x.y AdvancedNonMS |
| //----------------------------------------------------------------------------- |
| template <typename T, int STAGE> |
| class AdvancedNonMS : public ShaderImageSizeBase |
| { |
| GLuint m_texture[4]; |
| |
| virtual long Setup() |
| { |
| glGenTextures(4, m_texture); |
| return NO_ERROR; |
| } |
| virtual long Run() |
| { |
| if (STAGE == 0 && !IsVSFSAvailable(4, 0)) |
| return NOT_SUPPORTED; |
| if (STAGE == 5 && !IsVSFSAvailable(0, 4)) |
| return NOT_SUPPORTED; |
| |
| const GLenum target[4] = { GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_2D_ARRAY }; |
| for (int i = 0; i < 4; ++i) |
| { |
| glBindTexture(target[i], m_texture[i]); |
| glTexParameteri(target[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(target[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| if (i == 0) |
| { |
| glTexStorage3D(target[i], 2, TexInternalFormat<T>(), 2, 2, 7); |
| glBindImageTexture(0, m_texture[i], 1, GL_FALSE, 3, GL_READ_ONLY, TexInternalFormat<T>()); |
| } |
| else if (i == 1) |
| { |
| glTexStorage3D(target[i], 3, TexInternalFormat<T>(), 4, 4, 2); |
| glBindImageTexture(1, m_texture[i], 1, GL_TRUE, 0, GL_READ_ONLY, TexInternalFormat<T>()); |
| } |
| else if (i == 2) |
| { |
| glTexStorage2D(target[i], 2, TexInternalFormat<T>(), 2, 2); |
| glBindImageTexture(2, m_texture[i], 0, GL_TRUE, 0, GL_READ_WRITE, TexInternalFormat<T>()); |
| } |
| else if (i == 3) |
| { |
| glTexStorage3D(target[i], 4, TexInternalFormat<T>(), 13, 7, 4); |
| glBindImageTexture(3, m_texture[i], 1, GL_TRUE, 0, GL_READ_ONLY, TexInternalFormat<T>()); |
| } |
| } |
| ImageSizeMachine machine; |
| ivec4 res[4] = { ivec4(1, 1, 0, 0), ivec4(2, 2, 1, 0), ivec4(2, 2, 0, 0), ivec4(6, 3, 4, 0) }; |
| return machine.Run<T>(STAGE, res); |
| } |
| virtual long Cleanup() |
| { |
| glDeleteTextures(4, m_texture); |
| return NO_ERROR; |
| } |
| }; |
| //============================================================================= |
| // 4.1 NegativeCompileTime |
| //----------------------------------------------------------------------------- |
| class NegativeCompileTime : public ShaderImageSizeBase |
| { |
| virtual long Run() |
| { |
| if (!Compile( // imagesize return type check |
| "#version 310 es" NL "precision highp float;" NL "precision highp int;" NL |
| "layout(local_size_x = 1) in;" NL "layout(r32f) uniform image2D g_image;" NL |
| "layout(std430) buffer OutputBuffer { vec4 g_color; };" NL "void main() {" NL |
| " if (imageSize(g_image) == ivec3(5)) g_color = vec4(0, 1, 0, 1);" NL |
| " else g_color = vec4(1, 0, 0, 1);" NL "}")) |
| { |
| return ERROR; |
| } |
| if (!Compile( // imageSize(samplertype) |
| "#version 310 es" NL "precision highp float;" NL "precision highp int;" NL |
| "layout(local_size_x = 1) in;" NL "layout(r32f) uniform sampler2D g_image;" NL |
| "layout(std430) buffer OutputBuffer { vec4 g_color; };" NL "void main() {" NL |
| " if (imageSize(g_image) == ivec2(5)) g_color = vec4(0, 1, 0, 1);" NL |
| " else g_color = vec4(1, 0, 0, 1);" NL "}")) |
| { |
| return ERROR; |
| } |
| return NO_ERROR; |
| } |
| |
| bool Compile(const std::string& source) |
| { |
| const GLuint sh = glCreateShader(GL_COMPUTE_SHADER); |
| |
| const char* const src = source.c_str(); |
| glShaderSource(sh, 1, &src, NULL); |
| glCompileShader(sh); |
| |
| GLchar log[1024]; |
| glGetShaderInfoLog(sh, sizeof(log), NULL, log); |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader Info Log:\n" |
| << log << tcu::TestLog::EndMessage; |
| |
| GLint status; |
| glGetShaderiv(sh, GL_COMPILE_STATUS, &status); |
| glDeleteShader(sh); |
| |
| if (status == GL_TRUE) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Compilation should fail." << tcu::TestLog::EndMessage; |
| return false; |
| } |
| return true; |
| } |
| }; |
| |
| } // anonymous namespace |
| |
| ShaderImageSizeTests::ShaderImageSizeTests(glcts::Context& context) : TestCaseGroup(context, "shader_image_size", "") |
| { |
| } |
| |
| ShaderImageSizeTests::~ShaderImageSizeTests(void) |
| { |
| } |
| |
| void ShaderImageSizeTests::init() |
| { |
| using namespace glcts; |
| addChild(new TestSubcase(m_context, "basic-nonMS-vs-float", TestSubcase::Create<BasicNonMS<vec4, 0> >)); |
| addChild(new TestSubcase(m_context, "basic-nonMS-vs-int", TestSubcase::Create<BasicNonMS<ivec4, 0> >)); |
| addChild(new TestSubcase(m_context, "basic-nonMS-vs-uint", TestSubcase::Create<BasicNonMS<uvec4, 0> >)); |
| addChild(new TestSubcase(m_context, "basic-nonMS-fs-float", TestSubcase::Create<BasicNonMS<vec4, 5> >)); |
| addChild(new TestSubcase(m_context, "basic-nonMS-fs-int", TestSubcase::Create<BasicNonMS<ivec4, 5> >)); |
| addChild(new TestSubcase(m_context, "basic-nonMS-fs-uint", TestSubcase::Create<BasicNonMS<uvec4, 5> >)); |
| addChild(new TestSubcase(m_context, "basic-nonMS-cs-float", TestSubcase::Create<BasicNonMS<vec4, 4> >)); |
| addChild(new TestSubcase(m_context, "basic-nonMS-cs-int", TestSubcase::Create<BasicNonMS<ivec4, 4> >)); |
| addChild(new TestSubcase(m_context, "basic-nonMS-cs-uint", TestSubcase::Create<BasicNonMS<uvec4, 4> >)); |
| addChild(new TestSubcase(m_context, "advanced-nonMS-vs-float", TestSubcase::Create<AdvancedNonMS<vec4, 0> >)); |
| addChild(new TestSubcase(m_context, "advanced-nonMS-vs-int", TestSubcase::Create<AdvancedNonMS<ivec4, 0> >)); |
| addChild(new TestSubcase(m_context, "advanced-nonMS-vs-uint", TestSubcase::Create<AdvancedNonMS<uvec4, 0> >)); |
| addChild(new TestSubcase(m_context, "advanced-nonMS-fs-float", TestSubcase::Create<AdvancedNonMS<vec4, 5> >)); |
| addChild(new TestSubcase(m_context, "advanced-nonMS-fs-int", TestSubcase::Create<AdvancedNonMS<ivec4, 5> >)); |
| addChild(new TestSubcase(m_context, "advanced-nonMS-fs-uint", TestSubcase::Create<AdvancedNonMS<uvec4, 5> >)); |
| addChild(new TestSubcase(m_context, "advanced-nonMS-cs-float", TestSubcase::Create<AdvancedNonMS<vec4, 4> >)); |
| addChild(new TestSubcase(m_context, "advanced-nonMS-cs-int", TestSubcase::Create<AdvancedNonMS<ivec4, 4> >)); |
| addChild(new TestSubcase(m_context, "advanced-nonMS-cs-uint", TestSubcase::Create<AdvancedNonMS<uvec4, 4> >)); |
| addChild(new TestSubcase(m_context, "negative-compileTime", TestSubcase::Create<NegativeCompileTime>)); |
| } |
| } |