/*------------------------------------------------------------------------- * OpenGL Conformance Test Suite * ----------------------------- * * Copyright (c) 2020 The Khronos Group Inc. * Copyright (c) 2020 Intel Corporation * * 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 glcPixelStorageModesTests.cpp * \brief Conformance tests for usage of pixel storage modes. */ /*-------------------------------------------------------------------*/ #include "stdlib.h" #include "tcuRenderTarget.hpp" #include "tcuSurface.hpp" #include "tcuTextureUtil.hpp" #include "tcuTestCase.hpp" #include "tcuTestLog.hpp" #include "tcuDefs.hpp" #include "tcuFloat.hpp" #include "tcuStringTemplate.hpp" #include "gluRenderContext.hpp" #include "gluShaderProgram.hpp" #include "gluShaderUtil.hpp" #include "gluContextInfo.hpp" #include "gluObjectWrapper.hpp" #include "gluCallLogWrapper.hpp" #include "gluPixelTransfer.hpp" #include "gluTexture.hpp" #include "gluTextureUtil.hpp" #include "gluDrawUtil.hpp" #include "gluDefs.hpp" #include "sglrGLContext.hpp" #include "sglrContextWrapper.hpp" #include "sglrContextUtil.hpp" #include "glwFunctions.hpp" #include "glwEnums.hpp" #include "deStringUtil.hpp" #include "deUniquePtr.hpp" #include "glsTextureTestUtil.hpp" #include "glcPixelStorageModesTests.hpp" #include namespace glcts { static const char* const vs_template_src = "${GLSL_VERSION}\n" "in highp vec4 pos;\n" "out highp ${TEXCOORDS_TYPE} texcoords;\n" "${LAYER}\n" "void main (void)\n" "{\n" " texcoords = ${TEXCOORDS};\n" " gl_Position = pos;\n" "}\n"; static const char* const fs_template_src = "${GLSL_VERSION}\n" "precision highp float;\n" "precision highp int;\n" "out vec4 fragColour;\n" "in ${TEXCOORDS_TYPE} texcoords;\n" "uniform highp ${SAMPLER_TYPE} sampler;\n" "uniform ${COL_TYPE} refcolour;\n" "void main (void)\n" "{\n" " ${COL_TYPE} colour = texelFetch(sampler, i${TEXCOORDS_TYPE}(texcoords), 0);\n" " if (${CONDITION})\n" " fragColour = vec4(0.0, 1.0, 0.0, 1.0);\n" " else\n" " fragColour = vec4(colour);\n" "}\n"; double getEps(deUint32 internalFormat) { double eps = 0.0; switch (internalFormat) { case GL_RGBA4: eps = 1.0 / (double)(1 << 4); break; case GL_RGB565: case GL_RGB5_A1: case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: eps = 1.0 / (double)(1 << 5); break; case GL_R8: case GL_R8_SNORM: case GL_RG8: case GL_RG8_SNORM: case GL_RGB8: case GL_SRGB8: case GL_RGB8_SNORM: case GL_RGBA8: case GL_SRGB8_ALPHA8: case GL_RGBA8_SNORM: eps = 1.0 / (double)(1 << 8); break; case GL_RGB9_E5: eps = 1.0 / (double)(1 << 9); break; case GL_R11F_G11F_B10F: case GL_RGB10_A2: eps = 1.0 / (double)(1 << 10); break; case GL_R16F: case GL_RG16F: case GL_RGB16F: case GL_RGBA16F: case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: eps = 1.0 / (double)(1 << 16); break; case GL_R32F: case GL_RG32F: case GL_RGB32F: case GL_RGBA32F: eps = 1.0 / (double)(1 << 31); break; default: TCU_FAIL("Invalid internal format"); } return std::max(0.01, eps); } bool inrange(int x, int left, int right) { return (x >= left && x < right); } class TexImageUtils { public: TexImageUtils(deUint32 internalFormat, int cuboid_w, int cuboid_h, int cuboid_d, int subcuboid_x0, int subcuboid_y0, int subcuboid_z0, int subcuboid_w, int subcuboid_h, int subcuboid_d, glu::GLSLVersion glsl_version); ~TexImageUtils (void); protected: void writePixel(glw::GLubyte *p, glw::GLdouble col); void writeChannel(glw::GLubyte *p, int channel, glw::GLdouble col); template void writeToUnsignedChannel(glw::GLubyte *p, int channel, glw::GLdouble col); template void writeToSignedChannel(glw::GLubyte *p, int channel, glw::GLdouble col); void writeToFloatChannel(glw::GLubyte *p, int channel, glw::GLdouble col); void writeToHalfFloatChannel(glw::GLubyte *p, int channel, glw::GLdouble col); template void write3Channel(glw::GLubyte *p, int channel, glw::GLdouble col); template void write4Channel(glw::GLubyte *p, int channel, glw::GLdouble col); void write11F_11F_10F_Channel(glw::GLubyte *p, int channel, glw::GLdouble col); void setRefcolour (glu::CallLogWrapper gl, glw::GLdouble col); template void setUnsignedRefcolour(glu::CallLogWrapper gl, glw::GLdouble col); template void setSignedRefcolour(glu::CallLogWrapper gl, glw::GLdouble col); void setRGB10A2Refcolour (glu::CallLogWrapper gl, glw::GLdouble col); bool verify(tcu::Surface dst, tcu::Surface *errMask); glw::GLubyte *m_src_data; deUint32 tex; glu::ShaderProgram* prog; deUint32 m_internalFormat; deUint32 m_format; deUint32 m_type; int m_pixelsize; int m_num_channels; int m_cuboid_w; int m_cuboid_h; int m_cuboid_d; int m_subcuboid_x0; int m_subcuboid_y0; int m_subcuboid_z0; int m_subcuboid_w; int m_subcuboid_h; int m_subcuboid_d; glu::GLSLVersion m_glsl_version; }; TexImageUtils::TexImageUtils (deUint32 internalFormat, int cuboid_w, int cuboid_h, int cuboid_d, int subcuboid_x0, int subcuboid_y0, int subcuboid_z0, int subcuboid_w, int subcuboid_h, int subcuboid_d, glu::GLSLVersion glsl_version) : m_src_data(0) , tex(0) , prog(0) , m_internalFormat(internalFormat) , m_format(glu::getTransferFormat(glu::mapGLInternalFormat(internalFormat)).format) , m_type(glu::getTransferFormat(glu::mapGLInternalFormat(internalFormat)).dataType) , m_pixelsize(tcu::getPixelSize(glu::mapGLInternalFormat(internalFormat))) , m_num_channels(tcu::getNumUsedChannels(glu::mapGLInternalFormat(internalFormat).order)) , m_cuboid_w(cuboid_w) , m_cuboid_h(cuboid_h) , m_cuboid_d(cuboid_d) , m_subcuboid_x0(subcuboid_x0) , m_subcuboid_y0(subcuboid_y0) , m_subcuboid_z0(subcuboid_z0) , m_subcuboid_w(subcuboid_w) , m_subcuboid_h(subcuboid_h) , m_subcuboid_d(subcuboid_d) , m_glsl_version(glsl_version) { } TexImageUtils::~TexImageUtils (void) { } void TexImageUtils::writePixel(glw::GLubyte *p, glw::GLdouble col) { for (int ch = 0; ch < m_num_channels; ch++) writeChannel(p, ch, (ch == 3) ? 1.0 : col); } void TexImageUtils::writeChannel(glw::GLubyte *p, int channel, glw::GLdouble col) { switch (m_type) { case GL_UNSIGNED_BYTE: writeToUnsignedChannel(p, channel, col); break; case GL_BYTE: writeToSignedChannel(p, channel, col); break; case GL_UNSIGNED_SHORT: writeToUnsignedChannel(p, channel, col); break; case GL_UNSIGNED_SHORT_5_6_5: write3Channel(p, channel, col); break; case GL_SHORT: writeToSignedChannel(p, channel, col); break; case GL_UNSIGNED_INT: writeToUnsignedChannel(p, channel, col); break; case GL_UNSIGNED_INT_2_10_10_10_REV: write4Channel(p, 3 - channel, col); break; case GL_UNSIGNED_INT_10F_11F_11F_REV: write11F_11F_10F_Channel(p, channel, col); break; case GL_UNSIGNED_SHORT_4_4_4_4: write4Channel(p, channel, col); break; case GL_UNSIGNED_SHORT_5_5_5_1: write4Channel(p, channel, col); break; case GL_INT: writeToSignedChannel(p, channel, col); break; case GL_HALF_FLOAT: writeToHalfFloatChannel(p, channel, col); break; case GL_FLOAT: writeToFloatChannel(p, channel, col); break; default: TCU_FAIL("Invalid type"); } } template void TexImageUtils::writeToUnsignedChannel(glw::GLubyte *p, int channel, glw::GLdouble col) { static const T max = -1; const glw::GLdouble d_max = (glw::GLdouble)max; const glw::GLdouble d_value = col * d_max; const T t_value = (T)d_value; T* ptr = (T*)p; ptr[channel] = t_value; } template void TexImageUtils::writeToSignedChannel(glw::GLubyte *p, int channel, glw::GLdouble col) { static const T max = (T)((1u << (sizeof(T) * 8u - 1u)) - 1u); const glw::GLdouble d_max = (glw::GLdouble)max; const glw::GLdouble d_value = col * d_max; const T t_value = (T)d_value; T* ptr = (T*)p; ptr[channel] = t_value; } void TexImageUtils::writeToFloatChannel(glw::GLubyte *p, int channel, glw::GLdouble col) { const glw::GLfloat t_value = (glw::GLfloat)col; glw::GLfloat *ptr = (glw::GLfloat*)p; ptr[channel] = t_value; } void TexImageUtils::writeToHalfFloatChannel(glw::GLubyte *p, int channel, glw::GLdouble col) { deUint16* ptr = (deUint16*)p; tcu::Float16 val(col); ptr[channel] = val.bits(); } template void TexImageUtils::write3Channel(glw::GLubyte *p, int channel, glw::GLdouble col) { T mask = 0; T max = 0; T off = 0; T* ptr = (T*)p; T result = 0; const T max_1 = (1 << size_1) - 1; const T max_2 = (1 << size_2) - 1; const T max_3 = (1 << size_3) - 1; switch (channel) { case 0: mask = max_1; max = max_1; off = off_1; break; case 1: mask = max_2; max = max_2; off = off_2; break; case 2: mask = max_3; max = max_3; off = off_3; break; default: TCU_FAIL("Invalid channel"); break; } const glw::GLdouble d_max = (glw::GLdouble)max; const glw::GLdouble d_value = col * d_max; const T t_value = (T)d_value; result = (T)((t_value & mask) << off); *ptr |= result; } template void TexImageUtils::write4Channel(glw::GLubyte *p, int channel, glw::GLdouble col) { T mask = 0; T max = 0; T off = 0; T* ptr = (T*)p; T result = 0; T max_1 = (1 << size_1) - 1; T max_2 = (1 << size_2) - 1; T max_3 = (1 << size_3) - 1; T max_4 = (1 << size_4) - 1; switch (channel) { case 0: mask = max_1; max = max_1; off = off_1; break; case 1: mask = max_2; max = max_2; off = off_2; break; case 2: mask = max_3; max = max_3; off = off_3; break; case 3: mask = max_4; max = max_4; off = off_4; break; default: TCU_FAIL("Invalid channel"); break; } const glw::GLdouble d_max = (glw::GLdouble)max; const glw::GLdouble d_value = col * d_max; const T t_value = (T)d_value; result = (T)((t_value & mask) << off); *ptr |= result; } void TexImageUtils::write11F_11F_10F_Channel(glw::GLubyte *p, int channel, glw::GLdouble col) { deUint32* ptr = (deUint32*)p; switch (channel) { case 0: { tcu::Float val(col); deUint32 bits = val.bits(); *ptr |= bits; } break; case 1: { tcu::Float val(col); deUint32 bits = val.bits(); *ptr |= (bits << 11); } break; case 2: { tcu::Float val(col); deUint32 bits = val.bits(); *ptr |= (bits << 22); } break; default: TCU_FAIL("Invalid channel"); } } void TexImageUtils::setRefcolour (glu::CallLogWrapper gl, glw::GLdouble col) { switch (m_format) { case GL_RED: case GL_RG: case GL_RGB: case GL_RGBA: gl.glUniform4f(gl.glGetUniformLocation(prog->getProgram(), "refcolour"), m_num_channels > 0 ? col : 0.0f, m_num_channels > 1 ? col : 0.0f, m_num_channels > 2 ? col : 0.0f, 1.0f); break; default: switch (m_type) { case GL_UNSIGNED_BYTE: setUnsignedRefcolour(gl, col); break; case GL_BYTE: setSignedRefcolour(gl, col); break; case GL_UNSIGNED_SHORT: case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_5_5_5_1: setUnsignedRefcolour(gl, col); break; case GL_SHORT: setSignedRefcolour(gl, col); break; case GL_UNSIGNED_INT: setUnsignedRefcolour(gl, col); break; case GL_UNSIGNED_INT_2_10_10_10_REV: setRGB10A2Refcolour(gl, col); break; case GL_INT: setSignedRefcolour(gl, col); break; default: TCU_FAIL("Invalid type"); } } } template void TexImageUtils::setUnsignedRefcolour (glu::CallLogWrapper gl, glw::GLdouble col) { static const T max = -1; const glw::GLdouble d_max = (glw::GLdouble)max; const glw::GLdouble d_value = d_max * col; const T t_value = (T)d_value; unsigned int refcol[4] = { m_num_channels > 0 ? t_value : 0u, m_num_channels > 1 ? t_value : 0u, m_num_channels > 2 ? t_value : 0u, 255u, }; gl.glUniform4uiv(gl.glGetUniformLocation(prog->getProgram(), "refcolour"), 1, refcol); } template void TexImageUtils::setSignedRefcolour (glu::CallLogWrapper gl, glw::GLdouble col) { static const T umax = -1; static const T max = umax >> 1; const glw::GLdouble d_max = (glw::GLdouble)max; const glw::GLdouble d_value = d_max * col; const T t_value = (T)d_value; int refcol[4] = { (m_num_channels > 0 ? (int)t_value : 0), (m_num_channels > 1 ? (int)t_value : 0), (m_num_channels > 2 ? (int)t_value : 0), 255, }; gl.glUniform4iv(gl.glGetUniformLocation(prog->getProgram(), "refcolour"), 1, refcol); } void TexImageUtils::setRGB10A2Refcolour (glu::CallLogWrapper gl, glw::GLdouble col) { unsigned int max_channel_value = 1023u; const glw::GLdouble d_max_channel_value = (glw::GLdouble)max_channel_value; const glw::GLdouble d_value = (glw::GLdouble)d_max_channel_value * col; unsigned int t_value = (unsigned int)d_value; unsigned int refcol[4] = { (m_num_channels > 0 ? t_value : 0u), (m_num_channels > 1 ? t_value : 0u), (m_num_channels > 2 ? t_value : 0u), 255u, }; gl.glUniform4uiv(gl.glGetUniformLocation(prog->getProgram(), "refcolour"), 1, refcol); } bool TexImageUtils::verify(tcu::Surface dst, tcu::Surface *errMask) { *errMask = tcu::Surface (dst.getWidth(), dst.getHeight()); tcu::clear(errMask->getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); bool pass = true; for (int y = 0; y < dst.getHeight(); y++) { for (int x = 0; x < dst.getWidth(); x++) { if (dst.getPixel(x, y) != tcu::RGBA::green()) { pass = false; errMask->setPixel(x, y, tcu::RGBA::red()); } } } return pass; } class TexImage2DCase : public deqp::TestCase , public sglr::ContextWrapper , public TexImageUtils { public: TexImage2DCase (deqp::Context& context, const char* name, const char* desc, deUint32 internalFormat, int rect_w, int rect_h, int subrect_x0, int subrect_y0, int subrect_w, int subrect_h, glu::GLSLVersion glsl_version); ~TexImage2DCase (void); IterateResult iterate (void); protected: void generateSrcData(); void createTexture (void); void createShader (void); tcu::Surface renderToSurf (void); void cleanup (void); }; TexImage2DCase::TexImage2DCase (deqp::Context& context, const char* name, const char* desc, deUint32 internalFormat, int rect_w, int rect_h, int subrect_x0, int subrect_y0, int subrect_w, int subrect_h, glu::GLSLVersion glsl_version) : TestCase(context, name, desc) , TexImageUtils(internalFormat, rect_w, rect_h, 1, subrect_x0, subrect_y0, 0, subrect_w, subrect_h, 1, glsl_version) { } TexImage2DCase::~TexImage2DCase(void) { } TexImage2DCase::IterateResult TexImage2DCase::iterate(void) { glu::RenderContext& renderCtx = TestCase::m_context.getRenderContext(); tcu::TestLog& log = m_testCtx.getLog(); tcu::Surface dst, errMask; bool pass = true; sglr::GLContext gl_ctx (renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, m_subcuboid_w, m_subcuboid_h)); setContext((sglr::Context*)&gl_ctx); generateSrcData(); createTexture(); createShader(); dst = renderToSurf(); pass = verify(dst, &errMask); cleanup(); if (pass) { m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid" << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("ImageVerification", "Image verification") << tcu::TestLog::Image("Result", "Rendered result", dst.getAccess()) << tcu::TestLog::EndImageSet; } else { m_testCtx.getLog() << tcu::TestLog::Message << "Image is invalid" << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("ErrorVerification", "Image verification") << tcu::TestLog::Image("Result", "Rendered result", dst.getAccess()) << tcu::TestLog::Image("ErrorMask", "Error mask", errMask.getAccess()) << tcu::TestLog::EndImageSet; } m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail"); return STOP; } void TexImage2DCase::generateSrcData() { m_src_data = new glw::GLubyte[m_cuboid_w * m_cuboid_h * m_pixelsize](); glw::GLdouble col = 0.0; for (int y = 0; y < m_cuboid_h; y++) { for (int x = 0; x < m_cuboid_w; x++) { if (inrange(y, m_subcuboid_y0, m_subcuboid_y0 + m_subcuboid_h) && inrange(x, m_subcuboid_x0, m_subcuboid_x0 + m_subcuboid_w)) col = 1.0; else col = 0.0; int offset = y * m_cuboid_w * m_pixelsize + x * m_pixelsize; writePixel(m_src_data + offset, col); } } } void TexImage2DCase::createTexture (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glGenTextures(1, &tex); gl.glBindTexture(GL_TEXTURE_2D, tex); gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl.glPixelStorei(GL_UNPACK_ROW_LENGTH, m_cuboid_w); gl.glPixelStorei(GL_UNPACK_SKIP_ROWS, m_subcuboid_y0); gl.glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_subcuboid_x0); gl.glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_subcuboid_w, m_subcuboid_h, 0, m_format, m_type, m_src_data); gl.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl.glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); gl.glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); } void TexImage2DCase::createShader (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); const tcu::StringTemplate vs_src (vs_template_src); const tcu::StringTemplate fs_src (fs_template_src); std::map params; params["GLSL_VERSION"] = getGLSLVersionDeclaration(m_glsl_version); params["TEXCOORDS_TYPE"] = "vec2"; params["LAYER"] = ""; params["TEXCOORDS"] = "pos.xy"; params["CONDITION"] = "colour.rgb == refcolour.rgb"; switch (m_format) { case GL_RED_INTEGER: case GL_RG_INTEGER: case GL_RGB_INTEGER: case GL_RGBA_INTEGER: switch (m_type) { case GL_BYTE: case GL_SHORT: case GL_INT: params["SAMPLER_TYPE"] = "isampler2D"; params["COL_TYPE"] = "ivec4"; break; default: params["SAMPLER_TYPE"] = "usampler2D"; params["COL_TYPE"] = "uvec4"; break; } break; default: params["SAMPLER_TYPE"] = "sampler2D"; params["COL_TYPE"] = "vec4"; break; } prog = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vs_src.specialize(params)) << glu::FragmentSource(fs_src.specialize(params))); if (!prog->isOk()) { m_testCtx.getLog() << tcu::TestLog::Message << "" << tcu::TestLog::EndMessage << tcu::TestLog::ShaderProgram(false, "") << tcu::TestLog::Shader(QP_SHADER_TYPE_VERTEX, prog->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).source, false, prog->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).infoLog) << tcu::TestLog::Shader(QP_SHADER_TYPE_FRAGMENT, prog->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).source, false, prog->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).infoLog) << tcu::TestLog::EndShaderProgram; TCU_FAIL("Shader creation failed"); } gl.glUseProgram(prog->getProgram()); gl.glUniform1i(gl.glGetUniformLocation(prog->getProgram(), "sampler"), 0); } tcu::Surface TexImage2DCase::renderToSurf (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glClearColor(0.3f, 0.3f, 0.3f, 1.0f); gl.glClear(GL_COLOR_BUFFER_BIT); static const float vertexPositions[4*3] = { -1.0, -1.0, -1.0f, 1.0, -1.0, 0.0f, -1.0, 1.0, 0.0f, 1.0, 1.0, 1.0f, }; static const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 }; const glu::VertexArrayBinding attrBindings[] = { glu::va::Float("pos", 3, 4, 0, &vertexPositions[0]) }; gl.glViewport(0, 0, m_subcuboid_w, m_subcuboid_h); setRefcolour(gl, 1.0); glu::draw(m_context.getRenderContext(), prog->getProgram(), DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0], glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); tcu::Surface dst; dst.setSize(m_subcuboid_w, m_subcuboid_h); glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); return dst; } void TexImage2DCase::cleanup (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glDeleteTextures(1, &tex); delete[] m_src_data; delete prog; } class TexImage3DCase : public deqp::TestCase , public sglr::ContextWrapper , public TexImageUtils { public: TexImage3DCase (deqp::Context& context, const char* name, const char* desc, deUint32 internalFormat, int cuboid_w, int cuboid_h, int cuboid_d, int subcuboid_x0, int subrect_y0, int subcuboid_z0, int subcuboid_w, int subcuboid_h, int subcuboid_d, glu::GLSLVersion glsl_version); ~TexImage3DCase (void); IterateResult iterate (void); protected: void generateSrcData(); void createTexture (void); void createShader (void); tcu::Surface renderToSurf (int layer); void cleanup (void); }; TexImage3DCase::TexImage3DCase (deqp::Context& context, const char* name, const char* desc, deUint32 internalFormat, int cuboid_w, int cuboid_h, int cuboid_d, int subcuboid_x0, int subcuboid_y0, int subcuboid_z0, int subcuboid_w, int subcuboid_h, int subcuboid_d, glu::GLSLVersion glsl_version) : TestCase(context, name, desc) , TexImageUtils(internalFormat, cuboid_w, cuboid_h, cuboid_d, subcuboid_x0, subcuboid_y0, subcuboid_z0, subcuboid_w, subcuboid_h, subcuboid_d, glsl_version) { } TexImage3DCase::~TexImage3DCase(void) { } TexImage3DCase::IterateResult TexImage3DCase::iterate(void) { glu::RenderContext& renderCtx = TestCase::m_context.getRenderContext(); tcu::TestLog& log = m_testCtx.getLog(); tcu::Surface dst, errMask; bool pass = true; sglr::GLContext gl_ctx (renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, m_subcuboid_w, m_subcuboid_h)); setContext((sglr::Context*)&gl_ctx); generateSrcData(); createTexture(); createShader(); for (int z = 0; z < m_subcuboid_d; z++) { dst = renderToSurf(z); bool layer_pass = verify(dst, &errMask); if (layer_pass) { m_testCtx.getLog() << tcu::TestLog::Message << "Layer " << z << " is valid" << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("LayerVerification", "Layer verification") << tcu::TestLog::Image("Result", "Rendered result", dst.getAccess()) << tcu::TestLog::EndImageSet; } else { m_testCtx.getLog() << tcu::TestLog::Message << "Layer " << z << " is invalid" << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("ErrorVerification", "Layer verification") << tcu::TestLog::Image("Result", "Rendered result", dst.getAccess()) << tcu::TestLog::Image("ErrorMask", "Error mask", errMask.getAccess()) << tcu::TestLog::EndImageSet; } pass &= layer_pass; } cleanup(); if (pass) { m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid" << tcu::TestLog::EndMessage; } else { m_testCtx.getLog() << tcu::TestLog::Message << "Image is invalid" << tcu::TestLog::EndMessage; } m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail"); return STOP; } void TexImage3DCase::generateSrcData() { m_src_data = new glw::GLubyte[m_cuboid_w * m_cuboid_h * m_cuboid_d * m_pixelsize](); glw::GLdouble col = 0.0; for (int z = 0; z < m_cuboid_d; z++) { for (int y = 0; y < m_cuboid_h; y++) { for (int x = 0; x < m_cuboid_w; x++) { if (inrange(z, m_subcuboid_z0, m_subcuboid_z0 + m_subcuboid_d) && inrange(y, m_subcuboid_y0, m_subcuboid_y0 + m_subcuboid_h) && inrange(x, m_subcuboid_x0, m_subcuboid_x0 + m_subcuboid_w)) col = 0.125 + (z - m_subcuboid_z0) * 0.125; /* [0.125, 0.250..1.0] */ else col = 0.0; int offset = z * m_cuboid_h * m_cuboid_w * m_pixelsize + y * m_cuboid_w * m_pixelsize + x * m_pixelsize; writePixel(m_src_data + offset, col); } } } } void TexImage3DCase::createTexture (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glGenTextures(1, &tex); gl.glBindTexture(GL_TEXTURE_2D_ARRAY, tex); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl.glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_cuboid_h); gl.glPixelStorei(GL_UNPACK_ROW_LENGTH, m_cuboid_w); gl.glPixelStorei(GL_UNPACK_SKIP_IMAGES, m_subcuboid_z0); gl.glPixelStorei(GL_UNPACK_SKIP_ROWS, m_subcuboid_y0); gl.glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_subcuboid_x0); gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, m_internalFormat, m_subcuboid_w, m_subcuboid_h, m_subcuboid_d, 0, m_format, m_type, m_src_data); gl.glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); gl.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl.glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); gl.glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); gl.glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); } void TexImage3DCase::createShader (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); const tcu::StringTemplate vs_src (vs_template_src); const tcu::StringTemplate fs_src (fs_template_src); std::map params; params["GLSL_VERSION"] = getGLSLVersionDeclaration(m_glsl_version); params["TEXCOORDS_TYPE"] = "vec3"; params["LAYER"] = "uniform int layer;"; params["TEXCOORDS"] = "vec3(pos.xy, layer)"; switch (m_format) { case GL_RED_INTEGER: case GL_RG_INTEGER: case GL_RGB_INTEGER: case GL_RGBA_INTEGER: switch (m_type) { case GL_BYTE: case GL_SHORT: case GL_INT: params["SAMPLER_TYPE"] = "isampler2DArray"; params["COL_TYPE"] = "ivec4"; params["CONDITION"] = "all(lessThan(uvec4(abs(colour - refcolour)).rgb, uvec3(2u)))"; break; default: params["SAMPLER_TYPE"] = "usampler2DArray"; params["COL_TYPE"] = "uvec4"; params["CONDITION"] = "all(lessThan(uvec4(abs(ivec4(colour) - ivec4(refcolour))).rgb, uvec3(2u)))"; break; } break; default: const tcu::StringTemplate fs_condition ("all(lessThan((abs(colour - refcolour)).rgb, vec3(${EPS})))"); std::map fs_condition_params; fs_condition_params["EPS"] = std::to_string(getEps(m_internalFormat)); params["SAMPLER_TYPE"] = "sampler2DArray"; params["COL_TYPE"] = "vec4"; params["CONDITION"] = fs_condition.specialize(fs_condition_params); break; } prog = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vs_src.specialize(params)) << glu::FragmentSource(fs_src.specialize(params))); if (!prog->isOk()) { m_testCtx.getLog() << tcu::TestLog::Message << "" << tcu::TestLog::EndMessage << tcu::TestLog::ShaderProgram(false, "") << tcu::TestLog::Shader(QP_SHADER_TYPE_VERTEX, prog->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).source, false, prog->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).infoLog) << tcu::TestLog::Shader(QP_SHADER_TYPE_FRAGMENT, prog->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).source, false, prog->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).infoLog) << tcu::TestLog::EndShaderProgram; TCU_FAIL("Shader creation failed"); } gl.glUseProgram(prog->getProgram()); gl.glUniform1i(gl.glGetUniformLocation(prog->getProgram(), "sampler"), 0); } tcu::Surface TexImage3DCase::renderToSurf (int layer) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glClearColor(0.3f, 0.3f, 0.3f, 1.0f); gl.glClear(GL_COLOR_BUFFER_BIT); static const float vertexPositions[4*3] = { -1.0, -1.0, -1.0f, 1.0, -1.0, 0.0f, -1.0, 1.0, 0.0f, 1.0, 1.0, 1.0f, }; static const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 }; const glu::VertexArrayBinding attrBindings[] = { glu::va::Float("pos", 3, 4, 0, &vertexPositions[0]) }; gl.glViewport(0, 0, m_subcuboid_w, m_subcuboid_h); gl.glUniform1i(gl.glGetUniformLocation(prog->getProgram(), "layer"), layer); glw::GLfloat refcol = 0.125 + layer * 0.125; setRefcolour(gl, refcol); glu::draw(m_context.getRenderContext(), prog->getProgram(), DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0], glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); tcu::Surface dst; dst.setSize(m_subcuboid_w, m_subcuboid_h); glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); return dst; } void TexImage3DCase::cleanup (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glDeleteTextures(1, &tex); delete[] m_src_data; delete prog; } class CompressedTexImageUtils { public: CompressedTexImageUtils (deUint32 internalFormat, int cuboid_w, int cuboid_h, int cuboid_d, int subcuboid_x0, int subcuboid_y0, int subcuboid_z0, int subcuboid_w, int subcuboid_h, int subcuboid_d, glu::GLSLVersion glsl_version); ~CompressedTexImageUtils (void); protected: int getImageSize (int width, int height, int depth); bool verify(tcu::Surface dst, tcu::Surface *errMask); glw::GLubyte *m_src_data; deUint32 tex; glu::ShaderProgram *prog; int m_bw; /* block width */ int m_bh; /* block height */ int m_bd; /* block depth */ int m_bs; /* block size */ deUint32 m_internalFormat; int m_cuboid_w; int m_cuboid_h; int m_cuboid_d; int m_subcuboid_x0; int m_subcuboid_y0; int m_subcuboid_z0; int m_subcuboid_w; int m_subcuboid_h; int m_subcuboid_d; glu::GLSLVersion m_glsl_version; }; CompressedTexImageUtils::CompressedTexImageUtils (deUint32 internalFormat, int cuboid_w, int cuboid_h, int cuboid_d, int subcuboid_x0, int subcuboid_y0, int subcuboid_z0, int subcuboid_w, int subcuboid_h, int subcuboid_d, glu::GLSLVersion glsl_version) : m_internalFormat(internalFormat) , m_cuboid_w(cuboid_w) , m_cuboid_h(cuboid_h) , m_cuboid_d(cuboid_d) , m_subcuboid_x0(subcuboid_x0) , m_subcuboid_y0(subcuboid_y0) , m_subcuboid_z0(subcuboid_z0) , m_subcuboid_w(subcuboid_w) , m_subcuboid_h(subcuboid_h) , m_subcuboid_d(subcuboid_d) , m_glsl_version(glsl_version) { } CompressedTexImageUtils::~CompressedTexImageUtils(void) { } int CompressedTexImageUtils::getImageSize (int width, int height, int depth) { return (width / m_bw + (width % m_bw > 0)) * (height / m_bh + (height % m_bh > 0)) * (depth / m_bd + (depth % m_bd > 0)) * m_bs; } bool CompressedTexImageUtils::verify(tcu::Surface dst, tcu::Surface *errMask) { *errMask = tcu::Surface (dst.getWidth(), dst.getHeight()); tcu::clear(errMask->getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); bool pass = true; for (int y = 0; y < dst.getHeight(); y++) { for (int x = 0; x < dst.getWidth(); x++) { if (dst.getPixel(x, y) != tcu::RGBA::green()) { pass = false; errMask->setPixel(x, y, tcu::RGBA::red()); } } } return pass; } class CompressedTexImage2DCase : public deqp::TestCase , public sglr::ContextWrapper , public CompressedTexImageUtils { public: CompressedTexImage2DCase (deqp::Context& context, const char *name, const char *desc, deUint32 internalFormat, int cuboid_w, int cuboid_h, int subcuboid_x0, int subcuboid_y0, int subcuboid_w, int subcuboid_h, glu::GLSLVersion glsl_version); ~CompressedTexImage2DCase (void); IterateResult iterate (void); protected: void generateSrcData_s3tc (void); void generateSrcData_astc (void); void createTexture (void); void createShader (void); tcu::Surface renderToSurf (void); void cleanup (void); }; CompressedTexImage2DCase::CompressedTexImage2DCase (deqp::Context& context, const char *name, const char *desc, deUint32 internalFormat, int cuboid_w, int cuboid_h, int subcuboid_x0, int subcuboid_y0, int subcuboid_w, int subcuboid_h, glu::GLSLVersion glsl_version) : TestCase(context, name, desc) , CompressedTexImageUtils(internalFormat, cuboid_w, cuboid_h, 1, subcuboid_x0, subcuboid_y0, 0, subcuboid_w, subcuboid_h, 1, glsl_version) { } CompressedTexImage2DCase::~CompressedTexImage2DCase (void) { } CompressedTexImage2DCase::IterateResult CompressedTexImage2DCase::iterate (void) { glu::RenderContext& renderCtx = TestCase::m_context.getRenderContext(); const glu::ContextInfo& ctxInfo = m_context.getContextInfo(); tcu::TestLog& log = m_testCtx.getLog(); tcu::Surface dst, errMask; bool pass = true; sglr::GLContext gl_ctx (renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, m_subcuboid_w, m_subcuboid_h)); setContext((sglr::Context*)&gl_ctx); if (!glu::contextSupports(renderCtx.getType(), glu::ApiType::core(4, 2)) && !ctxInfo.isExtensionSupported("GL_ARB_compressed_texture_pixel_storage")) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_ARB_compressed_texture_pixel_storage extension is not supported"); return STOP; } switch (m_internalFormat) { case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: if (!ctxInfo.isExtensionSupported("GL_EXT_texture_compression_s3tc")) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_EXT_texture_compression_s3tc extension is not supported"); return STOP; } m_bw = 4; m_bh = 4; m_bd = 1; m_bs = 8; generateSrcData_s3tc(); break; case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: if (!ctxInfo.isExtensionSupported("GL_KHR_texture_compression_astc_ldr")) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_texture_compression_astc_ldr extension is not supported"); return STOP; } m_bw = 8; m_bh = 5; m_bd = 1; m_bs = 16; generateSrcData_astc(); break; default: TCU_FAIL("Invalid internal format"); } createTexture(); createShader(); dst = renderToSurf(); pass = verify(dst, &errMask); cleanup(); if (pass) { m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid" << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("ImageVerification", "Image verification") << tcu::TestLog::Image("Result", "Rendered result", dst.getAccess()) << tcu::TestLog::EndImageSet; } else { m_testCtx.getLog() << tcu::TestLog::Message << "Image is invalid" << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("ErrorVerification", "Image verification") << tcu::TestLog::Image("Result", "Rendered result", dst.getAccess()) << tcu::TestLog::Image("ErrorMask", "Error mask", errMask.getAccess()) << tcu::TestLog::EndImageSet; } m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail"); return STOP; } void CompressedTexImage2DCase::generateSrcData_s3tc (void) { deUint64 *src = new deUint64[m_cuboid_w / m_bw * m_cuboid_h / m_bh]; deUint64 col = 0x0; for (int y = 0; y < m_cuboid_h; y += m_bh) { for (int x = 0; x < m_cuboid_w; x += m_bw) { if (inrange(x, m_subcuboid_x0, m_subcuboid_x0 + m_subcuboid_w) && inrange(y, m_subcuboid_y0, m_subcuboid_y0 + m_subcuboid_h)) { col = 0xffff; } else { col = 0x0; } int index = (y / m_bh) * (m_cuboid_w / m_bw) + (x / m_bw); src[index] = col; } } m_src_data = (glw::GLubyte*)src; } void CompressedTexImage2DCase::generateSrcData_astc (void) { deUint64 col = 0x0; deUint64 mask = 0xfffffffffffffdfc; int img_size = 2 * (m_cuboid_w / m_bw + (m_cuboid_w % m_bw > 0)) * (m_cuboid_h / m_bh + (m_cuboid_h % m_bh > 0)); deUint64 *src = new deUint64[img_size]; for (int y = 0; y < m_cuboid_h; y += m_bh) { for (int x = 0; x < m_cuboid_w; x += m_bw) { if (inrange(x, m_subcuboid_x0, m_subcuboid_x0 + m_subcuboid_w) && inrange(y, m_subcuboid_y0, m_subcuboid_y0 + m_subcuboid_h)) { col = 0xffffffffffffffff; /* (1.0, 1.0, 1.0) */ } else { col = 0x0; /* (0.0, 0.0, 0.0) */ } int index = (y / m_bh) * (m_cuboid_w / m_bw + (m_cuboid_w % m_bw > 0)) + (x / m_bw); src[2 * index] = mask; src[2 * index + 1] = col; } } m_src_data = (glw::GLubyte*)src; } void CompressedTexImage2DCase::createTexture (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glGenTextures(1, &tex); gl.glBindTexture(GL_TEXTURE_2D, tex); gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, m_bs); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, m_bw); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, m_bh); gl.glPixelStorei(GL_UNPACK_ROW_LENGTH, m_cuboid_w); gl.glPixelStorei(GL_UNPACK_SKIP_ROWS, m_subcuboid_y0); gl.glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_subcuboid_x0); gl.glCompressedTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_subcuboid_w, m_subcuboid_h, 0, getImageSize(m_subcuboid_w, m_subcuboid_h, m_subcuboid_d), m_src_data); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, 0); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, 0); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, 0); gl.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl.glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); gl.glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); } void CompressedTexImage2DCase::createShader (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); const tcu::StringTemplate vs_src (vs_template_src); const tcu::StringTemplate fs_src (fs_template_src); std::map params; params["GLSL_VERSION"] = getGLSLVersionDeclaration(m_glsl_version); params["TEXCOORDS_TYPE"] = "vec2"; params["LAYER"] = ""; params["TEXCOORDS"] = "pos.xy"; params["SAMPLER_TYPE"] = "sampler2D"; params["COL_TYPE"] = "vec4"; params["CONDITION"] = "colour.rgb == refcolour.rgb"; prog = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vs_src.specialize(params)) << glu::FragmentSource(fs_src.specialize(params))); if (!prog->isOk()) { m_testCtx.getLog() << tcu::TestLog::Message << "" << tcu::TestLog::EndMessage << tcu::TestLog::ShaderProgram(false, "") << tcu::TestLog::Shader(QP_SHADER_TYPE_VERTEX, prog->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).source, false, prog->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).infoLog) << tcu::TestLog::Shader(QP_SHADER_TYPE_FRAGMENT, prog->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).source, false, prog->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).infoLog) << tcu::TestLog::EndShaderProgram; TCU_FAIL("Shader creation failed"); } gl.glUseProgram(prog->getProgram()); gl.glUniform1i(gl.glGetUniformLocation(prog->getProgram(), "sampler"), 0); } tcu::Surface CompressedTexImage2DCase::renderToSurf (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glClearColor(0.3f, 0.3f, 0.3f, 1.0f); gl.glClear(GL_COLOR_BUFFER_BIT); static const float vertexPositions[4*3] = { -1.0, -1.0, -1.0f, 1.0, -1.0, 0.0f, -1.0, 1.0, 0.0f, 1.0, 1.0, 1.0f, }; static const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 }; const glu::VertexArrayBinding attrBindings[] = { glu::va::Float("pos", 3, 4, 0, &vertexPositions[0]) }; gl.glViewport(0, 0, m_subcuboid_w, m_subcuboid_h); glw::GLfloat refcol = 1.0f; gl.glUniform4f(gl.glGetUniformLocation(prog->getProgram(), "refcolour"), refcol, refcol, refcol, 1.0f); glu::draw(m_context.getRenderContext(), prog->getProgram(), DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0], glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); tcu::Surface dst; dst.setSize(m_subcuboid_w, m_subcuboid_h); glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); return dst; } void CompressedTexImage2DCase::cleanup (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glDeleteTextures(1, &tex); delete[] m_src_data; delete prog; } class CompressedTexImage3DCase : public deqp::TestCase , public sglr::ContextWrapper , public CompressedTexImageUtils { public: CompressedTexImage3DCase (deqp::Context& context, const char *name, const char *desc, deUint32 internalFormat, int cuboid_w, int cuboid_h, int cuboid_d, int subcuboid_x0, int subcuboid_y0, int subcuboid_z0, int subcuboid_w, int subcuboid_h, int subcuboid_d, glu::GLSLVersion glsl_version); ~CompressedTexImage3DCase (void); IterateResult iterate (void); protected: void generateSrcData_s3tc (void); void generateSrcData_astc (void); void createTexture (void); void createShader (void); tcu::Surface renderToSurf (int layer); void cleanup (void); }; CompressedTexImage3DCase::CompressedTexImage3DCase (deqp::Context& context, const char *name, const char *desc, deUint32 internalFormat, int cuboid_w, int cuboid_h, int cuboid_d, int subcuboid_x0, int subcuboid_y0, int subcuboid_z0, int subcuboid_w, int subcuboid_h, int subcuboid_d, glu::GLSLVersion glsl_version) : TestCase(context, name, desc) , CompressedTexImageUtils(internalFormat, cuboid_w, cuboid_h, cuboid_d, subcuboid_x0, subcuboid_y0, subcuboid_z0, subcuboid_w, subcuboid_h, subcuboid_d, glsl_version) { } CompressedTexImage3DCase::~CompressedTexImage3DCase (void) { } CompressedTexImage3DCase::IterateResult CompressedTexImage3DCase::iterate (void) { glu::RenderContext& renderCtx = TestCase::m_context.getRenderContext(); const glu::ContextInfo& ctxInfo = m_context.getContextInfo(); tcu::TestLog& log = m_testCtx.getLog(); tcu::Surface dst, errMask; bool pass = true; sglr::GLContext gl_ctx (renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(0, 0, m_subcuboid_w, m_subcuboid_h)); setContext((sglr::Context*)&gl_ctx); if (!glu::contextSupports(renderCtx.getType(), glu::ApiType::core(4, 2)) && !ctxInfo.isExtensionSupported("GL_ARB_compressed_texture_pixel_storage")) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_ARB_compressed_texture_pixel_storage extension is not supported"); return STOP; } switch (m_internalFormat) { case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: if (!ctxInfo.isExtensionSupported("GL_EXT_texture_compression_s3tc")) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_EXT_texture_compression_s3tc extension is not supported"); return STOP; } m_bw = 4; m_bh = 4; m_bd = 1; m_bs = 8; generateSrcData_s3tc(); break; case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: if (!ctxInfo.isExtensionSupported("GL_KHR_texture_compression_astc_ldr")) { m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_KHR_texture_compression_astc_ldr extension is not supported"); return STOP; } m_bw = 8; m_bh = 5; m_bd = 1; m_bs = 16; generateSrcData_astc(); break; default: TCU_FAIL("Invalid internal format"); } createTexture(); createShader(); for (int z = 0; z < m_subcuboid_d; z++) { dst = renderToSurf(z); bool layer_pass = verify(dst, &errMask); if (layer_pass) { m_testCtx.getLog() << tcu::TestLog::Message << "Layer " << z << " is valid" << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("LayerVerification", "Layer verification") << tcu::TestLog::Image("Result", "Rendered result", dst.getAccess()) << tcu::TestLog::EndImageSet; } else { m_testCtx.getLog() << tcu::TestLog::Message << "Layer " << z << " is invalid" << tcu::TestLog::EndMessage << tcu::TestLog::ImageSet("ErrorVerification", "Layer verification") << tcu::TestLog::Image("Result", "Rendered result", dst.getAccess()) << tcu::TestLog::Image("ErrorMask", "Error mask", errMask.getAccess()) << tcu::TestLog::EndImageSet; } pass &= layer_pass; } cleanup(); if (pass) { m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid" << tcu::TestLog::EndMessage; } else { m_testCtx.getLog() << tcu::TestLog::Message << "Image is invalid" << tcu::TestLog::EndMessage; } m_testCtx.setTestResult(pass ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, pass ? "Pass" : "Fail"); return STOP; } void CompressedTexImage3DCase::generateSrcData_s3tc() { deUint64 *src = new deUint64[m_cuboid_w / m_bw * m_cuboid_h / m_bh * m_cuboid_d / m_bd]; deUint64 col_list[] = { 0x18E3, /* (0.125, 0.125, 0.125) */ 0x39E7, /* (0.250, 0.250, 0.250) */ 0x5AEB, /* (0.375, 0.375, 0.375) */ 0x7BEF, /* (0.500, 0.500, 0.500) */ 0x9CF3, /* (0.625, 0.625, 0.625) */ 0xBDF7, /* (0.750, 0.750, 0.750) */ 0xDEFB, /* (0.875, 0.875, 0.875) */ 0xffff, /* (1.000, 1.000, 1.000) */ }; deUint64 col = 0x0; for (int z = 0; z < m_cuboid_d; z += m_bd) { for (int y = 0; y < m_cuboid_h; y += m_bh) { for (int x = 0; x < m_cuboid_w; x += m_bw) { if (inrange(x, m_subcuboid_x0, m_subcuboid_x0 + m_subcuboid_w) && inrange(y, m_subcuboid_y0, m_subcuboid_y0 + m_subcuboid_h) && inrange(z, m_subcuboid_z0, m_subcuboid_z0 + m_subcuboid_d)) col = col_list[z % 8]; else col = 0x0; int index = (z / m_bd) * (m_cuboid_h / m_bh) * (m_cuboid_w / m_bw) + (y / m_bh) * (m_cuboid_w / m_bw) + (x / m_bw); src[index] = col; } } } m_src_data = (glw::GLubyte*)src; } void CompressedTexImage3DCase::generateSrcData_astc (void) { deUint64 col_list[] = { 0xffff1fff1fff1fff, /* (0.125, 0.125, 0.125) */ 0xffff3fff3fff3fff, /* (0.250, 0.250, 0.250) */ 0xffff5fff5fff5fff, /* (0.375, 0.375, 0.375) */ 0xffff7fff7fff7fff, /* (0.500, 0.500, 0.500) */ 0xffff9fff9fff9fff, /* (0.625, 0.625, 0.625) */ 0xffffbfffbfffbfff, /* (0.750, 0.750, 0.750) */ 0xffffdfffdfffdfff, /* (0.875, 0.875, 0.875) */ 0xffffffffffffffff, /* (1.000, 1.000, 1.000) */ }; deUint64 col = 0x0; deUint64 mask = 0xFFFFFFFFFFFFFDFC; int img_size = 2 * (m_cuboid_w / m_bw + (m_cuboid_w % m_bw > 0)) * (m_cuboid_h / m_bh + (m_cuboid_h % m_bh > 0)) * (m_cuboid_d / m_bd + (m_cuboid_d % m_bd > 0)); deUint64 *src = new deUint64[img_size]; for (int z = 0; z < m_cuboid_d; z += m_bd) { for (int y = 0; y < m_cuboid_h; y += m_bh) { for (int x = 0; x < m_cuboid_w; x += m_bw) { if (inrange(x, m_subcuboid_x0, m_subcuboid_x0 + m_subcuboid_w) && inrange(y, m_subcuboid_y0, m_subcuboid_y0 + m_subcuboid_h) && inrange(z, m_subcuboid_z0, m_subcuboid_z0 + m_subcuboid_d)) col = col_list[z % 8]; else col = 0x0; int index = (z / m_bd) * (m_cuboid_h / m_bh + (m_cuboid_h % m_bh > 0)) * (m_cuboid_w / m_bw + (m_cuboid_w % m_bw > 0)) + (y / m_bh) * (m_cuboid_w / m_bw + (m_cuboid_w % m_bw > 0)) + (x / m_bw); src[2 * index] = mask; src[2 * index + 1] = col; } } } m_src_data = (glw::GLubyte*)src; } void CompressedTexImage3DCase::createTexture (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glGenTextures(1, &tex); gl.glBindTexture(GL_TEXTURE_2D_ARRAY, tex); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, m_bs); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, m_bw); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, m_bh); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, m_bd); gl.glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_cuboid_h); gl.glPixelStorei(GL_UNPACK_ROW_LENGTH, m_cuboid_w); gl.glPixelStorei(GL_UNPACK_SKIP_IMAGES, m_subcuboid_z0); gl.glPixelStorei(GL_UNPACK_SKIP_ROWS, m_subcuboid_y0); gl.glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_subcuboid_x0); gl.glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, m_internalFormat, m_subcuboid_w, m_subcuboid_h, m_subcuboid_d, 0, getImageSize(m_subcuboid_w, m_subcuboid_h, m_subcuboid_d), m_src_data); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, 0); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, 0); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, 0); gl.glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 0); gl.glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); gl.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl.glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); gl.glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); gl.glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); } void CompressedTexImage3DCase::createShader (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); const tcu::StringTemplate vs_src (vs_template_src); const tcu::StringTemplate fs_src (fs_template_src); std::map params; params["GLSL_VERSION"] = getGLSLVersionDeclaration(m_glsl_version); params["TEXCOORDS_TYPE"] = "vec3"; params["LAYER"] = "uniform int layer;"; params["TEXCOORDS"] = "vec3(pos.xy, layer)"; params["SAMPLER_TYPE"] = "sampler2DArray"; params["COL_TYPE"] = "vec4"; const tcu::StringTemplate fs_condition ("all(lessThan((abs(colour - refcolour)).rgb, vec3(${EPS})))"); std::map fs_condition_params; fs_condition_params["EPS"] = std::to_string(getEps(m_internalFormat)); params["CONDITION"] = fs_condition.specialize(fs_condition_params); prog = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vs_src.specialize(params)) << glu::FragmentSource(fs_src.specialize(params))); if (!prog->isOk()) { m_testCtx.getLog() << tcu::TestLog::Message << "" << tcu::TestLog::EndMessage << tcu::TestLog::ShaderProgram(false, "") << tcu::TestLog::Shader(QP_SHADER_TYPE_VERTEX, prog->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).source, false, prog->getShaderInfo(glu::SHADERTYPE_VERTEX, 0).infoLog) << tcu::TestLog::Shader(QP_SHADER_TYPE_FRAGMENT, prog->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).source, false, prog->getShaderInfo(glu::SHADERTYPE_FRAGMENT, 0).infoLog) << tcu::TestLog::EndShaderProgram; TCU_FAIL("Shader creation failed"); } gl.glUseProgram(prog->getProgram()); gl.glUniform1i(gl.glGetUniformLocation(prog->getProgram(), "sampler"), 0); } tcu::Surface CompressedTexImage3DCase::renderToSurf (int layer) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glClearColor(0.3f, 0.3f, 0.3f, 1.0f); gl.glClear(GL_COLOR_BUFFER_BIT); static const float vertexPositions[4*3] = { -1.0, -1.0, -1.0f, 1.0, -1.0, 0.0f, -1.0, 1.0, 0.0f, 1.0, 1.0, 1.0f, }; static const deUint16 indices[6] = { 0, 1, 2, 2, 1, 3 }; const glu::VertexArrayBinding attrBindings[] = { glu::va::Float("pos", 3, 4, 0, &vertexPositions[0]) }; gl.glViewport(0, 0, m_subcuboid_w, m_subcuboid_h); gl.glUniform1i(gl.glGetUniformLocation(prog->getProgram(), "layer"), layer); glw::GLfloat refcols[8] = { 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0 }; glw::GLfloat refcol = refcols[(layer + m_subcuboid_z0 % 8) % 8]; gl.glUniform4f(gl.glGetUniformLocation(prog->getProgram(), "refcolour"), refcol, refcol, refcol, 1.0f); glu::draw(m_context.getRenderContext(), prog->getProgram(), DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0], glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); tcu::Surface dst; dst.setSize(m_subcuboid_w, m_subcuboid_h); glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); return dst; } void CompressedTexImage3DCase::cleanup (void) { glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); gl.glDeleteTextures(1, &tex); delete[] m_src_data; delete prog; } PixelStorageModesTests::PixelStorageModesTests (deqp::Context& context, glu::GLSLVersion glsl_version) : TestCaseGroup(context, "pixelstoragemodes", "Pixel Storage Modes Tests") , m_glsl_version(glsl_version) { } PixelStorageModesTests::~PixelStorageModesTests (void) { } void PixelStorageModesTests::init(void) { const int cuboid_w = 64; const int cuboid_h = 64; const int cuboid_d = 64; const int subcuboid_w = 32; const int subcuboid_h = 32; const int subcuboid_d = 8; struct { const char *name; deUint32 internalFmt; } internalFmts[] = { { "r8", GL_R8, }, { "r8snorm", GL_R8_SNORM, }, { "r16f", GL_R16F, }, { "r32f", GL_R32F, }, { "r8ui", GL_R8UI, }, { "r8i", GL_R8I, }, { "r16ui", GL_R16UI, }, { "r16i", GL_R16I, }, { "r32ui", GL_R32UI, }, { "r32i", GL_R32I, }, { "rg8", GL_RG8, }, { "rg8snorm", GL_RG8_SNORM, }, { "rg16f", GL_RG16F, }, { "rg32f", GL_RG32F, }, { "rg8ui", GL_RG8UI, }, { "rg8i", GL_RG8I, }, { "rg16ui", GL_RG16UI, }, { "rg16i", GL_RG16I, }, { "rg32ui", GL_RG32UI, }, { "rg32i", GL_RG32I, }, { "rgb8", GL_RGB8, }, { "rgb565", GL_RGB565, }, { "rgb8snorm", GL_RGB8_SNORM, }, { "r11g11b10f", GL_R11F_G11F_B10F, }, { "rgb16f", GL_RGB16F, }, { "rgb32f", GL_RGB32F, }, { "rgb8ui", GL_RGB8UI, }, { "rgb8i", GL_RGB8I, }, { "rgb16ui", GL_RGB16UI, }, { "rgb16i", GL_RGB16I, }, { "rgb32ui", GL_RGB32UI, }, { "rgb32i", GL_RGB32I, }, { "rgba8", GL_RGBA8, }, { "rgba8snorm", GL_RGBA8_SNORM, }, { "rgb5a1", GL_RGB5_A1, }, { "rgba4", GL_RGBA4, }, { "rgb10a2", GL_RGB10_A2, }, { "rgba16f", GL_RGBA16F, }, { "rgba32f", GL_RGBA32F, }, { "rgba8ui", GL_RGBA8UI, }, { "rgba8i", GL_RGBA8I, }, { "rgb10a2ui", GL_RGB10_A2UI, }, { "rgba16ui", GL_RGBA16UI, }, { "rgba16i", GL_RGBA16I, }, { "rgba32i", GL_RGBA32I, }, { "rgba32ui", GL_RGBA32UI, }, }; struct { const char *name; deUint32 internalFmt; int bw; int bh; int bd; } internalFmts_compressed[] = { { "rgb_s3tc_dxt1", GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 1 }, { "rgba_astc_8x5", GL_COMPRESSED_RGBA_ASTC_8x5_KHR, 8, 5, 1 }, }; tcu::TestCaseGroup* texImage2DGroup = new tcu::TestCaseGroup(m_testCtx, "teximage2d", "glTexImage2D cases"); addChild(texImage2DGroup); for (int fmts = 0; fmts < DE_LENGTH_OF_ARRAY(internalFmts); fmts++) { tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, internalFmts[fmts].name, ""); texImage2DGroup->addChild(formatsGroup); int bw = 1; int bh = 1; int skip_pixels[3] = { 0, bw, bw * (subcuboid_w / (2 * bw)) }; int skip_rows[3] = { 0, bh, bh * (subcuboid_h / (2 * bh)) }; for (int r = 0; r < 3; r++) { for (int p = r; p < 3; p++) { std::string skip_name = std::to_string(skip_pixels[p]) + "_" + std::to_string(skip_rows[r]); std::string skip_desc = "Skip " + std::to_string(skip_pixels[p]) + " pixels and " + std::to_string(skip_rows[r]) + " rows"; formatsGroup->addChild(new TexImage2DCase(m_context, skip_name.c_str(), skip_desc.c_str(), internalFmts[fmts].internalFmt, cuboid_w, cuboid_h, skip_pixels[p], skip_rows[r], subcuboid_w, subcuboid_h, m_glsl_version)); } } } tcu::TestCaseGroup* texImage3DGroup = new tcu::TestCaseGroup(m_testCtx, "teximage3d", "glTexImage3D cases"); addChild(texImage3DGroup); for (int fmts = 0; fmts < DE_LENGTH_OF_ARRAY(internalFmts); fmts++) { tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, internalFmts[fmts].name, ""); texImage3DGroup->addChild(formatsGroup); int bw = 1; int bh = 1; int bd = 1; int skip_pixels[3] = { 0, bw, bw * (subcuboid_w / (2 * bw)) }; int skip_rows[3] = { 0, bh, bh * (subcuboid_h / (2 * bh)) }; int skip_images[3] = { 0, bd, bd * (subcuboid_d / (2 * bd)) }; for (int i = 0; i < 3; i++) { for (int r = i; r < 3; r++) { for (int p = r; p < 3; p++) { std::string skip_name = std::to_string(skip_pixels[p]) + "_" + std::to_string(skip_rows[r]) + "_" + std::to_string(skip_images[i]); std::string skip_desc = "Skip " + std::to_string(skip_pixels[p]) + " pixels, " + std::to_string(skip_rows[r]) + " rows, and " + std::to_string(skip_images[i]) + " images"; formatsGroup->addChild(new TexImage3DCase(m_context, skip_name.c_str(), skip_desc.c_str(), internalFmts[fmts].internalFmt, cuboid_w, cuboid_h, cuboid_d, skip_pixels[p], skip_rows[r], skip_images[i], subcuboid_w, subcuboid_h, subcuboid_d, m_glsl_version)); } } } } if (!glu::isContextTypeES(m_context.getRenderContext().getType())) { tcu::TestCaseGroup* compressedTexImage2DGroup = new tcu::TestCaseGroup(m_testCtx, "compressedteximage2d", "glCompressedTexImage2D cases"); addChild(compressedTexImage2DGroup); for (int fmts = 0; fmts < DE_LENGTH_OF_ARRAY(internalFmts_compressed); fmts++) { tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, internalFmts_compressed[fmts].name, ""); compressedTexImage2DGroup->addChild(formatsGroup); int bw = internalFmts_compressed[fmts].bw; int bh = internalFmts_compressed[fmts].bh; int skip_pixels[4] = { 0, bw, bw * (subcuboid_w / (2 * bw)), bw * (subcuboid_w / bw) }; int skip_rows[4] = { 0, bh, bh * (subcuboid_h / (2 * bh)), bh * (subcuboid_h / bh) }; for (int r = 0; r < 4; r++) { for (int p = 0; p < 4; p++) { std::string skip_name = std::to_string(skip_pixels[p]) + "_" + std::to_string(skip_rows[r]); std::string skip_desc = "Skip " + std::to_string(skip_pixels[p]) + " pixels and " + std::to_string(skip_rows[r]) + " rows"; formatsGroup->addChild(new CompressedTexImage2DCase( m_context, skip_name.c_str(), skip_desc.c_str(), internalFmts_compressed[fmts].internalFmt, cuboid_w, cuboid_h, skip_pixels[p], skip_rows[r], subcuboid_w, subcuboid_h, m_glsl_version)); } } } tcu::TestCaseGroup* compressedTexImage3DGroup = new tcu::TestCaseGroup(m_testCtx, "compressedteximage3d", "glCompressedTexImage3D cases"); addChild(compressedTexImage3DGroup); for (int fmts = 0; fmts < DE_LENGTH_OF_ARRAY(internalFmts_compressed); fmts++) { tcu::TestCaseGroup* formatsGroup = new tcu::TestCaseGroup(m_testCtx, internalFmts_compressed[fmts].name, ""); compressedTexImage3DGroup->addChild(formatsGroup); int bw = internalFmts_compressed[fmts].bw; int bh = internalFmts_compressed[fmts].bh; int bd = internalFmts_compressed[fmts].bd; int skip_pixels[4] = { 0, bw, bw * (subcuboid_w / (2 * bw)), bw * (subcuboid_w / bw) }; int skip_rows[4] = { 0, bh, bh * (subcuboid_h / (2 * bh)), bh * (subcuboid_h / bh) }; int skip_images[4] = { 0, bd, bd * (subcuboid_d / (2 * bd)), bd * (subcuboid_d / bd) }; for (int i = 0; i < 4; i++) { for (int r = 0; r < 4; r++) { for (int p = 0; p < 4; p++) { std::string skip_name = std::to_string(skip_pixels[p]) + "_" + std::to_string(skip_rows[r]) + "_" + std::to_string(skip_images[i]); std::string skip_desc = "Skip " + std::to_string(skip_pixels[p]) + " pixels, " + std::to_string(skip_rows[r]) + " rows, and " + std::to_string(skip_images[i]) + " images"; formatsGroup->addChild(new CompressedTexImage3DCase( m_context, skip_name.c_str(), skip_desc.c_str(), internalFmts_compressed[fmts].internalFmt, cuboid_w, cuboid_h, cuboid_d, skip_pixels[p], skip_rows[r], skip_images[i], subcuboid_w, subcuboid_h, subcuboid_d, m_glsl_version)); } } } } } } } /* namespace glcts */