/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL ES 3.1 Module * ------------------------------------------------- * * Copyright 2017 The Android Open Source Project * * 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 Texture format tests. *//*--------------------------------------------------------------------*/ #include "es31fSRGBDecodeTests.hpp" #include "gluContextInfo.hpp" #include "gluCallLogWrapper.hpp" #include "gluRenderContext.hpp" #include "gluTexture.hpp" #include "glsTextureTestUtil.hpp" #include "tcuPixelFormat.hpp" #include "tcuTestContext.hpp" #include "tcuRenderTarget.hpp" #include "gluTextureUtil.hpp" #include "tcuTextureUtil.hpp" #include "glwFunctions.hpp" #include "gluDefs.hpp" #include "glwEnums.hpp" #include "deUniquePtr.hpp" #include "gluPixelTransfer.hpp" #include "tcuDefs.hpp" #include "tcuVectorUtil.hpp" #include "gluObjectWrapper.hpp" #include "gluStrUtil.hpp" #include "tcuTestLog.hpp" #include "deStringUtil.hpp" namespace deqp { namespace gles31 { namespace Functional { namespace { using glu::TextureTestUtil::TEXTURETYPE_2D; enum SRGBDecode { SRGBDECODE_SKIP_DECODE = 0, SRGBDECODE_DECODE, SRGBDECODE_DECODE_DEFAULT }; enum ShaderOutputs { SHADEROUTPUTS_ONE = 1, SHADEROUTPUTS_TWO, }; enum ShaderUniforms { SHADERUNIFORMS_ONE = 1, SHADERUNIFORMS_TWO, }; enum ShaderSamplingGroup { SHADERSAMPLINGGROUP_TEXTURE = 0, SHADERSAMPLINGGROUP_TEXEL_FETCH }; enum ShaderSamplingType { TEXTURESAMPLING_TEXTURE = 0, TEXTURESAMPLING_TEXTURE_LOD, TEXTURESAMPLING_TEXTURE_GRAD, TEXTURESAMPLING_TEXTURE_OFFSET, TEXTURESAMPLING_TEXTURE_PROJ, TEXTURESAMPLING_TEXELFETCH, TEXTURESAMPLING_TEXELFETCH_OFFSET, // ranges required for looping mechanism in a case nodes iteration function TEXTURESAMPLING_TEXTURE_START = TEXTURESAMPLING_TEXTURE, TEXTURESAMPLING_TEXTURE_END = TEXTURESAMPLING_TEXTURE_PROJ + 1, TEXTURESAMPLING_TEXELFETCH_START = TEXTURESAMPLING_TEXELFETCH, TEXTURESAMPLING_TEXELFETCH_END = TEXTURESAMPLING_TEXELFETCH_OFFSET + 1 }; enum FunctionParameters { FUNCTIONPARAMETERS_ONE = 1, FUNCTIONPARAMETERS_TWO }; enum Blending { BLENDING_REQUIRED = 0, BLENDING_NOT_REQUIRED }; enum Toggling { TOGGLING_REQUIRED = 0, TOGGLING_NOT_REQUIRED }; tcu::Vec4 getColorReferenceLinear(void) { return tcu::Vec4(0.2f, 0.3f, 0.4f, 1.0f); } tcu::Vec4 getColorReferenceSRGB(void) { return tcu::linearToSRGB(tcu::Vec4(0.2f, 0.3f, 0.4f, 1.0f)); } tcu::Vec4 getColorGreenPass(void) { return tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); } namespace TestDimensions { const int WIDTH = 128; const int HEIGHT = 128; } // namespace TestDimensions namespace TestSamplingPositions { const int X_POS = 0; const int Y_POS = 0; } // namespace TestSamplingPositions const char *getFunctionDefinitionSRGBToLinearCheck(void) { static const char *functionDefinition = "mediump vec4 srgbToLinearCheck(in mediump vec4 texelSRGBA, in mediump vec4 texelLinear) \n" "{ \n" " const int NUM_CHANNELS = 4;" " mediump vec4 texelSRGBAConverted; \n" " mediump vec4 epsilonErr = vec4(0.005); \n" " mediump vec4 testResult; \n" " for (int idx = 0; idx < NUM_CHANNELS; idx++) \n" " { \n" " texelSRGBAConverted[idx] = pow( (texelSRGBA[idx] + 0.055) / 1.055, 1.0 / 0.4116); \n" " } \n" " if ( all(lessThan(abs(texelSRGBAConverted - texelLinear), epsilonErr)) || all(equal(texelSRGBAConverted, " "texelLinear)) ) \n" " { \n" " return testResult = vec4(0.0, 1.0, 0.0, 1.0); \n" " } \n" " else \n" " { \n" " return testResult = vec4(1.0, 0.0, 0.0, 1.0); \n" " } \n" "} \n"; return functionDefinition; } const char *getFunctionDefinitionEqualCheck(void) { static const char *functionDefinition = "mediump vec4 colorsEqualCheck(in mediump vec4 colorA, in mediump vec4 colorB) \n" "{ \n" " mediump vec4 epsilonErr = vec4(0.005); \n" " mediump vec4 testResult; \n" " if ( all(lessThan(abs(colorA - colorB), epsilonErr)) || all(equal(colorA, colorB)) ) \n" " { \n" " return testResult = vec4(0.0, 1.0, 0.0, 1.0); \n" " } \n" " else \n" " { \n" " return testResult = vec4(1.0, 0.0, 0.0, 1.0); \n" " } \n" "} \n"; return functionDefinition; } namespace EpsilonError { const float CPU = 0.005f; } struct TestGroupConfig { TestGroupConfig(const char *groupName, const char *groupDescription, const tcu::TextureFormat groupInternalFormat) : name(groupName) , description(groupDescription) , internalFormat(groupInternalFormat) { } ~TestGroupConfig(void) { } const char *name; const char *description; const tcu::TextureFormat internalFormat; }; struct UniformData { UniformData(glw::GLuint uniformLocation, const std::string &uniformName) : location(uniformLocation) , name(uniformName) , toggleDecode(false) { } ~UniformData(void) { } glw::GLuint location; std::string name; bool toggleDecode; }; struct UniformToToggle { UniformToToggle(const int uniformProgramIdx, const std::string &uniformName) : programIdx(uniformProgramIdx) , name(uniformName) { } ~UniformToToggle(void) { } int programIdx; std::string name; }; struct ComparisonFunction { ComparisonFunction(const std::string &funcName, const FunctionParameters funcParameters, const std::string &funcImplementation) : name(funcName) , parameters(funcParameters) , implementation(funcImplementation) { } ~ComparisonFunction(void) { } std::string name; FunctionParameters parameters; std::string implementation; }; struct FragmentShaderParameters { FragmentShaderParameters(const ShaderOutputs outputTotal, const ShaderUniforms uniformTotal, ComparisonFunction *comparisonFunction, Blending blendRequired, Toggling toggleRequired); ~FragmentShaderParameters(void); ShaderOutputs outputTotal; ShaderUniforms uniformTotal; ShaderSamplingType samplingType; std::string functionName; FunctionParameters functionParameters; std::string functionImplementation; bool hasFunction; Blending blendRequired; Toggling toggleRequired; std::vector uniformsToToggle; }; FragmentShaderParameters::FragmentShaderParameters(const ShaderOutputs paramsOutputTotal, const ShaderUniforms paramsUniformTotal, ComparisonFunction *paramsComparisonFunction, Blending paramsBlendRequired, Toggling paramsToggleRequired) : outputTotal(paramsOutputTotal) , uniformTotal(paramsUniformTotal) , samplingType(TEXTURESAMPLING_TEXTURE) , blendRequired(paramsBlendRequired) , toggleRequired(paramsToggleRequired) { if (paramsComparisonFunction != DE_NULL) { functionName = paramsComparisonFunction->name; functionParameters = paramsComparisonFunction->parameters; functionImplementation = paramsComparisonFunction->implementation; hasFunction = true; } else { hasFunction = false; } } FragmentShaderParameters::~FragmentShaderParameters(void) { } class SRGBTestSampler { public: SRGBTestSampler(Context &context, const tcu::Sampler::WrapMode wrapS, const tcu::Sampler::WrapMode wrapT, const tcu::Sampler::FilterMode minFilter, const tcu::Sampler::FilterMode magFilter, const SRGBDecode decoding); ~SRGBTestSampler(void); void setDecode(const SRGBDecode decoding); void setTextureUnit(const uint32_t textureUnit); void setIsActive(const bool isActive); bool getIsActive(void) const; void bindToTexture(void); private: const glw::Functions *m_gl; uint32_t m_samplerHandle; tcu::Sampler::WrapMode m_wrapS; tcu::Sampler::WrapMode m_wrapT; tcu::Sampler::FilterMode m_minFilter; tcu::Sampler::FilterMode m_magFilter; SRGBDecode m_decoding; uint32_t m_textureUnit; bool m_isActive; }; SRGBTestSampler::SRGBTestSampler(Context &context, const tcu::Sampler::WrapMode wrapS, const tcu::Sampler::WrapMode wrapT, const tcu::Sampler::FilterMode minFilter, const tcu::Sampler::FilterMode magFilter, const SRGBDecode decoding) : m_gl(&context.getRenderContext().getFunctions()) , m_wrapS(wrapS) , m_wrapT(wrapT) , m_minFilter(minFilter) , m_magFilter(magFilter) , m_isActive(false) { m_gl->genSamplers(1, &m_samplerHandle); m_gl->samplerParameteri(m_samplerHandle, GL_TEXTURE_WRAP_S, glu::getGLWrapMode(m_wrapS)); m_gl->samplerParameteri(m_samplerHandle, GL_TEXTURE_WRAP_T, glu::getGLWrapMode(m_wrapT)); m_gl->samplerParameteri(m_samplerHandle, GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(m_minFilter)); m_gl->samplerParameteri(m_samplerHandle, GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(m_magFilter)); this->setDecode(decoding); } SRGBTestSampler::~SRGBTestSampler(void) { m_gl->deleteSamplers(1, &m_samplerHandle); } void SRGBTestSampler::setDecode(const SRGBDecode decoding) { if (decoding == SRGBDECODE_SKIP_DECODE) { m_gl->samplerParameteri(m_samplerHandle, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); GLU_EXPECT_NO_ERROR(m_gl->getError(), "samplerParameteri(m_samplerID, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT)"); } else if (decoding == SRGBDECODE_DECODE) { m_gl->samplerParameteri(m_samplerHandle, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT); GLU_EXPECT_NO_ERROR(m_gl->getError(), "samplerParameteri(m_samplerID, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT)"); } else { DE_FATAL("sRGB texture sampler must have either GL_SKIP_DECODE_EXT or GL_DECODE_EXT settings"); } m_decoding = decoding; } void SRGBTestSampler::setTextureUnit(const uint32_t textureUnit) { m_textureUnit = textureUnit; } void SRGBTestSampler::setIsActive(const bool isActive) { m_isActive = isActive; } bool SRGBTestSampler::getIsActive(void) const { return m_isActive; } void SRGBTestSampler::bindToTexture(void) { m_gl->bindSampler(m_textureUnit, m_samplerHandle); } class SRGBTestTexture { public: SRGBTestTexture(Context &context, const glu::TextureTestUtil::TextureType targetType, const tcu::TextureFormat internalFormat, const int width, const int height, const tcu::Vec4 color, const tcu::Sampler::WrapMode wrapS, const tcu::Sampler::WrapMode wrapT, const tcu::Sampler::FilterMode minFilter, const tcu::Sampler::FilterMode magFilter, const SRGBDecode decoding); ~SRGBTestTexture(void); void setParameters(void); void setDecode(const SRGBDecode decoding); void setHasSampler(const bool hasSampler); uint32_t getHandle(void) const; uint32_t getGLTargetType(void) const; SRGBDecode getDecode(void) const; void upload(void); private: void setColor(void); Context &m_context; glu::Texture2D m_source; glu::TextureTestUtil::TextureType m_targetType; const tcu::TextureFormat m_internalFormat; const int m_width; const int m_height; tcu::Vec4 m_color; tcu::Sampler::WrapMode m_wrapS; tcu::Sampler::WrapMode m_wrapT; tcu::Sampler::FilterMode m_minFilter; tcu::Sampler::FilterMode m_magFilter; SRGBDecode m_decoding; bool m_hasSampler; }; SRGBTestTexture::SRGBTestTexture(Context &context, const glu::TextureTestUtil::TextureType targetType, const tcu::TextureFormat internalFormat, const int width, const int height, const tcu::Vec4 color, const tcu::Sampler::WrapMode wrapS, const tcu::Sampler::WrapMode wrapT, const tcu::Sampler::FilterMode minFilter, const tcu::Sampler::FilterMode magFilter, SRGBDecode decoding) : m_context(context) , m_source(context.getRenderContext(), glu::getInternalFormat(internalFormat), width, height) , m_targetType(targetType) , m_internalFormat(internalFormat) , m_width(width) , m_height(height) , m_color(color) , m_wrapS(wrapS) , m_wrapT(wrapT) , m_minFilter(minFilter) , m_magFilter(magFilter) , m_decoding(decoding) , m_hasSampler(false) { this->setColor(); } SRGBTestTexture::~SRGBTestTexture(void) { } void SRGBTestTexture::setParameters(void) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); gl.bindTexture(this->getGLTargetType(), this->getHandle()); gl.texParameteri(this->getGLTargetType(), GL_TEXTURE_WRAP_S, glu::getGLWrapMode(m_wrapS)); gl.texParameteri(this->getGLTargetType(), GL_TEXTURE_WRAP_T, glu::getGLWrapMode(m_wrapT)); gl.texParameteri(this->getGLTargetType(), GL_TEXTURE_MIN_FILTER, glu::getGLFilterMode(m_minFilter)); gl.texParameteri(this->getGLTargetType(), GL_TEXTURE_MAG_FILTER, glu::getGLFilterMode(m_magFilter)); gl.bindTexture(this->getGLTargetType(), 0); setDecode(m_decoding); } void SRGBTestTexture::setDecode(const SRGBDecode decoding) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); gl.bindTexture(this->getGLTargetType(), this->getHandle()); switch (decoding) { case SRGBDECODE_SKIP_DECODE: { gl.texParameteri(this->getGLTargetType(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri(this->getGLTargetType(), GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT)"); break; } case SRGBDECODE_DECODE: { gl.texParameteri(this->getGLTargetType(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT); GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri(this->getGLTargetType(), GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT)"); break; } case SRGBDECODE_DECODE_DEFAULT: { // do not use srgb decode options. Set to default break; } default: DE_FATAL("Error: Decoding option not recognised"); } gl.bindTexture(this->getGLTargetType(), 0); m_decoding = decoding; } void SRGBTestTexture::setHasSampler(const bool hasSampler) { m_hasSampler = hasSampler; } uint32_t SRGBTestTexture::getHandle(void) const { return m_source.getGLTexture(); } uint32_t SRGBTestTexture::getGLTargetType(void) const { switch (m_targetType) { case TEXTURETYPE_2D: { return GL_TEXTURE_2D; } default: { DE_FATAL("Error: Target type not recognised"); return -1; } } } SRGBDecode SRGBTestTexture::getDecode(void) const { return m_decoding; } void SRGBTestTexture::upload(void) { m_source.upload(); } void SRGBTestTexture::setColor(void) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); gl.bindTexture(this->getGLTargetType(), this->getHandle()); m_source.getRefTexture().allocLevel(0); for (int py = 0; py < m_height; py++) { for (int px = 0; px < m_width; px++) { m_source.getRefTexture().getLevel(0).setPixel(m_color, px, py); } } gl.bindTexture(this->getGLTargetType(), 0); } class SRGBTestProgram { public: SRGBTestProgram(Context &context, const FragmentShaderParameters &shaderParameters); ~SRGBTestProgram(void); void setBlendRequired(bool blendRequired); void setToggleRequired(bool toggleRequired); void setUniformToggle(int location, bool toggleDecodeValue); const std::vector &getUniformDataList(void) const; int getUniformLocation(const std::string &name); uint32_t getHandle(void) const; bool getBlendRequired(void) const; private: std::string genFunctionCall(ShaderSamplingType samplingType, const int uniformIdx); void genFragmentShader(void); Context &m_context; de::MovePtr m_program; FragmentShaderParameters m_shaderFragmentParameters; std::string m_shaderVertex; std::string m_shaderFragment; std::vector m_uniformDataList; bool m_blendRequired; bool m_toggleRequired; }; SRGBTestProgram::SRGBTestProgram(Context &context, const FragmentShaderParameters &shaderParameters) : m_context(context) , m_shaderFragmentParameters(shaderParameters) , m_blendRequired(false) , m_toggleRequired(false) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); tcu::TestLog &log = m_context.getTestContext().getLog(); glu::ShaderProgramInfo buildInfo; const int totalShaderStages = 2; // default vertex shader used in all tests std::string ver(glu::isContextTypeGLCore(m_context.getRenderContext().getType()) ? "#version 450\n" : "#version 310 es\n"); m_shaderVertex = ver + "layout (location = 0) in mediump vec3 aPosition; \n" "layout (location = 1) in mediump vec2 aTexCoord; \n" "out mediump vec2 vs_aTexCoord; \n" "void main () \n" "{ \n" " gl_Position = vec4(aPosition, 1.0); \n" " vs_aTexCoord = aTexCoord; \n" "} \n"; this->genFragmentShader(); m_program = de::MovePtr(new glu::ShaderProgram( m_context.getRenderContext(), glu::makeVtxFragSources(m_shaderVertex, m_shaderFragment))); if (!m_program->isOk()) { TCU_FAIL("Failed to compile shaders and link program"); } glw::GLint activeUniforms, maxLen; glw::GLint size, location; glw::GLenum type; gl.getProgramiv(this->getHandle(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen); gl.getProgramiv(this->getHandle(), GL_ACTIVE_UNIFORMS, &activeUniforms); std::vector uniformName(static_cast(maxLen)); for (int idx = 0; idx < activeUniforms; idx++) { gl.getActiveUniform(this->getHandle(), idx, maxLen, NULL, &size, &type, &uniformName[0]); location = gl.getUniformLocation(this->getHandle(), &uniformName[0]); UniformData uniformData(location, std::string(&uniformName[0], strlen(&uniformName[0]))); m_uniformDataList.push_back(uniformData); } // log shader program info. Only vertex and fragment shaders included buildInfo.program = m_program->getProgramInfo(); for (int shaderIdx = 0; shaderIdx < totalShaderStages; shaderIdx++) { glu::ShaderInfo shaderInfo = m_program->getShaderInfo( static_cast(static_cast(glu::SHADERTYPE_VERTEX) + static_cast(shaderIdx)), 0); buildInfo.shaders.push_back(shaderInfo); } log << buildInfo; } SRGBTestProgram::~SRGBTestProgram(void) { m_program = de::MovePtr(DE_NULL); } void SRGBTestProgram::setBlendRequired(bool blendRequired) { m_blendRequired = blendRequired; } void SRGBTestProgram::setToggleRequired(bool toggleRequired) { m_toggleRequired = toggleRequired; } void SRGBTestProgram::setUniformToggle(int location, bool toggleDecodeValue) { if ((m_uniformDataList.empty() == false) && (location >= 0) && (location <= (int)m_uniformDataList.size())) { m_uniformDataList[location].toggleDecode = toggleDecodeValue; } else { TCU_THROW(TestError, "Error: Uniform location not found. glGetActiveUniforms returned uniforms incorrectly "); } } const std::vector &SRGBTestProgram::getUniformDataList(void) const { return m_uniformDataList; } int SRGBTestProgram::getUniformLocation(const std::string &name) { for (std::size_t idx = 0; idx < m_uniformDataList.size(); idx++) { if (m_uniformDataList[idx].name == name) { return m_uniformDataList[idx].location; } } TCU_THROW(TestError, "Error: If name correctly requested then glGetActiveUniforms() returned active uniform data incorrectly"); return -1; } glw::GLuint SRGBTestProgram::getHandle(void) const { return m_program->getProgram(); } bool SRGBTestProgram::getBlendRequired(void) const { return m_blendRequired; } std::string SRGBTestProgram::genFunctionCall(ShaderSamplingType samplingType, const int uniformIdx) { std::ostringstream functionCall; functionCall << " mediump vec4 texelColor" << uniformIdx << " = "; switch (samplingType) { case TEXTURESAMPLING_TEXTURE: { functionCall << "texture(uTexture" << uniformIdx << ", vs_aTexCoord); \n"; break; } case TEXTURESAMPLING_TEXTURE_LOD: { functionCall << "textureLod(uTexture" << uniformIdx << ", vs_aTexCoord, 0.0); \n"; break; } case TEXTURESAMPLING_TEXTURE_GRAD: { functionCall << "textureGrad(uTexture" << uniformIdx << ", vs_aTexCoord, vec2(0.0, 0.0), vec2(0.0, 0.0)); \n"; break; } case TEXTURESAMPLING_TEXTURE_OFFSET: { functionCall << "textureOffset(uTexture" << uniformIdx << ", vs_aTexCoord, ivec2(0.0, 0.0)); \n"; break; } case TEXTURESAMPLING_TEXTURE_PROJ: { functionCall << "textureProj(uTexture" << uniformIdx << ", vec3(vs_aTexCoord, 1.0)); \n"; break; } case TEXTURESAMPLING_TEXELFETCH: { functionCall << "texelFetch(uTexture" << uniformIdx << ", ivec2(vs_aTexCoord), 0); \n"; break; } case TEXTURESAMPLING_TEXELFETCH_OFFSET: { functionCall << "texelFetchOffset(uTexture" << uniformIdx << ", ivec2(vs_aTexCoord), 0, ivec2(0.0, 0.0)); \n"; break; } default: { DE_FATAL("Error: Sampling type not recognised"); } } return functionCall.str(); } void SRGBTestProgram::genFragmentShader(void) { std::ostringstream source; std::ostringstream sampleTexture; std::ostringstream functionParameters; std::ostringstream shaderOutputs; // if comparison function is present resulting shader requires precisely one output DE_ASSERT(!(m_shaderFragmentParameters.hasFunction && (static_cast(m_shaderFragmentParameters.outputTotal) != static_cast(SHADEROUTPUTS_ONE)))); // function parameters must equal the number of uniforms i.e. textures passed into the function DE_ASSERT( !(m_shaderFragmentParameters.hasFunction && (static_cast(m_shaderFragmentParameters.uniformTotal) != static_cast(m_shaderFragmentParameters.functionParameters)))); // fragment shader cannot contain more outputs than the number of texture uniforms DE_ASSERT(!(static_cast(m_shaderFragmentParameters.outputTotal) > static_cast(m_shaderFragmentParameters.uniformTotal))); source << (glu::isContextTypeGLCore(m_context.getRenderContext().getType()) ? "#version 450\n" : "#version 310 es\n") << "in mediump vec2 vs_aTexCoord; \n"; for (int output = 0; output < m_shaderFragmentParameters.outputTotal; output++) { source << "layout (location = " << output << ") out mediump vec4 fs_aColor" << output << "; \n"; } for (int uniform = 0; uniform < m_shaderFragmentParameters.uniformTotal; uniform++) { source << "uniform sampler2D uTexture" << uniform << "; \n"; } if (m_shaderFragmentParameters.hasFunction == true) { source << m_shaderFragmentParameters.functionImplementation; } source << "void main () \n" << "{ \n"; for (int uniformIdx = 0; uniformIdx < m_shaderFragmentParameters.uniformTotal; uniformIdx++) { source << this->genFunctionCall(m_shaderFragmentParameters.samplingType, uniformIdx); } if (m_shaderFragmentParameters.hasFunction == true) { switch (static_cast(m_shaderFragmentParameters.functionParameters)) { case FUNCTIONPARAMETERS_ONE: { functionParameters << "(texelColor0)"; break; } case FUNCTIONPARAMETERS_TWO: { functionParameters << "(texelColor0, texelColor1)"; break; } default: { DE_FATAL("Error: Number of comparison function parameters invalid"); } } shaderOutputs << " fs_aColor0 = " << m_shaderFragmentParameters.functionName << functionParameters.str() << "; \n"; } else { for (int output = 0; output < m_shaderFragmentParameters.outputTotal; output++) { shaderOutputs << " fs_aColor" << output << " = texelColor" << output << "; \n"; } } source << shaderOutputs.str(); source << "} \n"; m_shaderFragment = source.str(); } class SRGBTestCase : public TestCase { public: SRGBTestCase(Context &context, const char *name, const char *description, const tcu::TextureFormat internalFormat); ~SRGBTestCase(void); void init(void); void deinit(void); virtual IterateResult iterate(void); void setSamplingGroup(const ShaderSamplingGroup samplingGroup); void setSamplingLocations(const int px, const int py); void setUniformToggle(const int programIdx, const std::string &uniformName, bool toggleDecode); void addTexture(const glu::TextureTestUtil::TextureType targetType, const int width, const int height, const tcu::Vec4 color, const tcu::Sampler::WrapMode wrapS, const tcu::Sampler::WrapMode wrapT, const tcu::Sampler::FilterMode minFilter, const tcu::Sampler::FilterMode magFilter, const SRGBDecode decoding); void addSampler(const tcu::Sampler::WrapMode wrapS, const tcu::Sampler::WrapMode wrapT, const tcu::Sampler::FilterMode minFilter, const tcu::Sampler::FilterMode magFilter, const SRGBDecode decoding); void addShaderProgram(const FragmentShaderParameters &shaderParameters); void genShaderPrograms(ShaderSamplingType samplingType); void deleteShaderPrograms(void); void readResultTextures(void); void storeResultPixels(std::vector &resultPixelData); void toggleDecode(const std::vector &uniformDataList); void bindSamplerToTexture(const int samplerIdx, const int textureIdx, const uint32_t textureUnit); void activateSampler(const int samplerIdx, const bool active); void logColor(const std::string &colorLogMessage, int colorIdx, tcu::Vec4 color) const; tcu::Vec4 formatReferenceColor(tcu::Vec4 referenceColor); // render function has a default implentation. Can be overriden for special cases virtual void render(void); // following functions must be overidden to perform individual test cases virtual void setupTest(void) = 0; virtual bool verifyResult(void) = 0; protected: de::MovePtr m_framebuffer; std::vector m_textureSourceList; std::vector m_samplerList; std::vector m_renderBufferList; const tcu::Vec4 m_epsilonError; std::vector m_textureResultList; int m_resultOutputTotal; tcu::TextureFormat m_resultTextureFormat; glw::GLuint m_vaoID; glw::GLuint m_vertexDataID; std::vector m_shaderParametersList; std::vector m_shaderProgramList; ShaderSamplingGroup m_samplingGroup; int m_px; int m_py; const tcu::TextureFormat m_internalFormat; private: void uploadTextures(void); void initFrameBuffer(void); void initVertexData(void); SRGBTestCase(const SRGBTestCase &); SRGBTestCase &operator=(const SRGBTestCase &); }; SRGBTestCase::SRGBTestCase(Context &context, const char *name, const char *description, const tcu::TextureFormat internalFormat) : TestCase(context, name, description) , m_epsilonError(EpsilonError::CPU) , m_resultOutputTotal(0) , m_resultTextureFormat(tcu::TextureFormat(tcu::TextureFormat::sRGBA, tcu::TextureFormat::UNORM_INT8)) , m_vaoID(0) , m_vertexDataID(0) , m_samplingGroup(SHADERSAMPLINGGROUP_TEXTURE) , m_px(0) , m_py(0) , m_internalFormat(internalFormat) { } SRGBTestCase::~SRGBTestCase(void) { deinit(); } void SRGBTestCase::init(void) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); // extension requirements for test if ((glu::getInternalFormat(m_internalFormat) == GL_SRGB8_ALPHA8) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_sRGB_decode")) { throw tcu::NotSupportedError("Test requires GL_EXT_texture_sRGB_decode extension"); } if ((glu::getInternalFormat(m_internalFormat) == GL_SRG8_EXT) && !(m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_sRGB_RG8"))) { throw tcu::NotSupportedError("Test requires GL_EXT_texture_sRGB_RG8 extension"); } if ((glu::getInternalFormat(m_internalFormat) == GL_SR8_EXT) && !(m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_sRGB_R8"))) { throw tcu::NotSupportedError("Test requires GL_EXT_texture_sRGB_R8 extension"); } m_framebuffer = de::MovePtr(new glu::Framebuffer(m_context.getRenderContext())); if (glu::isContextTypeGLCore(m_context.getRenderContext().getType())) { gl.enable(GL_FRAMEBUFFER_SRGB); } } void SRGBTestCase::deinit(void) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); m_framebuffer = de::MovePtr(DE_NULL); for (std::size_t renderBufferIdx = 0; renderBufferIdx < m_renderBufferList.size(); renderBufferIdx++) { gl.deleteRenderbuffers(1, &m_renderBufferList[renderBufferIdx]); } m_renderBufferList.clear(); if (glu::isContextTypeGLCore(m_context.getRenderContext().getType())) { gl.disable(GL_FRAMEBUFFER_SRGB); } for (std::size_t textureSourceIdx = 0; textureSourceIdx < m_textureSourceList.size(); textureSourceIdx++) { delete m_textureSourceList[textureSourceIdx]; } m_textureSourceList.clear(); for (std::size_t samplerIdx = 0; samplerIdx < m_samplerList.size(); samplerIdx++) { delete m_samplerList[samplerIdx]; } m_samplerList.clear(); if (m_vaoID != 0) { gl.deleteVertexArrays(1, &m_vaoID); m_vaoID = 0; } if (m_vertexDataID != 0) { gl.deleteBuffers(1, &m_vertexDataID); m_vertexDataID = 0; } } SRGBTestCase::IterateResult SRGBTestCase::iterate(void) { bool result; int startIdx = -1; int endIdx = -1; this->setupTest(); if (m_samplingGroup == SHADERSAMPLINGGROUP_TEXTURE) { startIdx = static_cast(TEXTURESAMPLING_TEXTURE_START); endIdx = static_cast(TEXTURESAMPLING_TEXTURE_END); } else if (m_samplingGroup == SHADERSAMPLINGGROUP_TEXEL_FETCH) { startIdx = static_cast(TEXTURESAMPLING_TEXELFETCH_START); endIdx = static_cast(TEXTURESAMPLING_TEXELFETCH_END); } else { DE_FATAL("Error: Sampling group not defined"); } this->initVertexData(); this->initFrameBuffer(); // loop through all sampling types in the required sampling group, performing individual tests for each for (int samplingTypeIdx = startIdx; samplingTypeIdx < endIdx; samplingTypeIdx++) { this->genShaderPrograms(static_cast(samplingTypeIdx)); this->uploadTextures(); this->render(); result = this->verifyResult(); this->deleteShaderPrograms(); if (result == true) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result verification failed"); return STOP; } } return STOP; } void SRGBTestCase::setSamplingGroup(const ShaderSamplingGroup samplingGroup) { m_samplingGroup = samplingGroup; } void SRGBTestCase::setSamplingLocations(const int px, const int py) { m_px = px; m_py = py; } void SRGBTestCase::addTexture(const glu::TextureTestUtil::TextureType targetType, const int width, const int height, const tcu::Vec4 color, const tcu::Sampler::WrapMode wrapS, const tcu::Sampler::WrapMode wrapT, const tcu::Sampler::FilterMode minFilter, const tcu::Sampler::FilterMode magFilter, const SRGBDecode decoding) { SRGBTestTexture *texture = new SRGBTestTexture(m_context, targetType, m_internalFormat, width, height, color, wrapS, wrapT, minFilter, magFilter, decoding); m_textureSourceList.push_back(texture); } void SRGBTestCase::addSampler(const tcu::Sampler::WrapMode wrapS, const tcu::Sampler::WrapMode wrapT, const tcu::Sampler::FilterMode minFilter, const tcu::Sampler::FilterMode magFilter, const SRGBDecode decoding) { SRGBTestSampler *sampler = new SRGBTestSampler(m_context, wrapS, wrapT, minFilter, magFilter, decoding); m_samplerList.push_back(sampler); } void SRGBTestCase::addShaderProgram(const FragmentShaderParameters &shaderParameters) { m_shaderParametersList.push_back(shaderParameters); m_resultOutputTotal = shaderParameters.outputTotal; } void SRGBTestCase::genShaderPrograms(ShaderSamplingType samplingType) { for (int shaderParamsIdx = 0; shaderParamsIdx < (int)m_shaderParametersList.size(); shaderParamsIdx++) { m_shaderParametersList[shaderParamsIdx].samplingType = samplingType; SRGBTestProgram *shaderProgram = new SRGBTestProgram(m_context, m_shaderParametersList[shaderParamsIdx]); if (m_shaderParametersList[shaderParamsIdx].blendRequired == BLENDING_REQUIRED) { shaderProgram->setBlendRequired(true); } if (m_shaderParametersList[shaderParamsIdx].toggleRequired == TOGGLING_REQUIRED) { shaderProgram->setToggleRequired(true); std::vector uniformsToToggle = m_shaderParametersList[shaderParamsIdx].uniformsToToggle; for (int uniformNameIdx = 0; uniformNameIdx < (int)uniformsToToggle.size(); uniformNameIdx++) { shaderProgram->setUniformToggle(shaderProgram->getUniformLocation(uniformsToToggle[uniformNameIdx]), true); } } m_shaderProgramList.push_back(shaderProgram); } } void SRGBTestCase::deleteShaderPrograms(void) { for (std::size_t idx = 0; idx < m_shaderProgramList.size(); idx++) { delete m_shaderProgramList[idx]; } m_shaderProgramList.clear(); } void SRGBTestCase::readResultTextures(void) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); int width = m_context.getRenderContext().getRenderTarget().getWidth(); int height = m_context.getRenderContext().getRenderTarget().getHeight(); gl.bindFramebuffer(GL_FRAMEBUFFER, **m_framebuffer); m_textureResultList.resize(m_renderBufferList.size()); for (std::size_t renderBufferIdx = 0; renderBufferIdx < m_renderBufferList.size(); renderBufferIdx++) { gl.readBuffer(GL_COLOR_ATTACHMENT0 + (glw::GLenum)renderBufferIdx); m_textureResultList[renderBufferIdx].setStorage(m_resultTextureFormat, width, height); glu::readPixels(m_context.getRenderContext(), 0, 0, m_textureResultList[renderBufferIdx].getAccess()); GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels()"); } gl.bindFramebuffer(GL_FRAMEBUFFER, 0); } void SRGBTestCase::storeResultPixels(std::vector &resultPixelData) { tcu::TestLog &log = m_context.getTestContext().getLog(); std::ostringstream message; int width = m_context.getRenderContext().getRenderTarget().getWidth(); int height = m_context.getRenderContext().getRenderTarget().getHeight(); // ensure result sampling coordinates are within range of the result color attachment DE_ASSERT((m_px >= 0) && (m_px < width)); DE_ASSERT((m_py >= 0) && (m_py < height)); DE_UNREF(width && height); for (int idx = 0; idx < (int)m_textureResultList.size(); idx++) { resultPixelData.push_back(m_textureResultList[idx].getAccess().getPixel(m_px, m_py)); this->logColor(std::string("Result color: "), idx, resultPixelData[idx]); } // log error rate (threshold) message << m_epsilonError; log << tcu::TestLog::Message << std::string("Epsilon error: ") << message.str() << tcu::TestLog::EndMessage; } void SRGBTestCase::toggleDecode(const std::vector &uniformDataList) { DE_ASSERT(uniformDataList.size() <= m_textureSourceList.size()); for (int uniformIdx = 0; uniformIdx < (int)uniformDataList.size(); uniformIdx++) { if (uniformDataList[uniformIdx].toggleDecode == true) { if (m_textureSourceList[uniformIdx]->getDecode() == SRGBDECODE_DECODE_DEFAULT) { // cannot toggle default continue; } // toggle sRGB decode values (ignoring value if set to default) m_textureSourceList[uniformIdx]->setDecode( (SRGBDecode)((m_textureSourceList[uniformIdx]->getDecode() + 1) % SRGBDECODE_DECODE_DEFAULT)); } } } void SRGBTestCase::bindSamplerToTexture(const int samplerIdx, const int textureIdx, const uint32_t textureUnit) { uint32_t enumConversion = textureUnit - GL_TEXTURE0; m_textureSourceList[textureIdx]->setHasSampler(true); m_samplerList[samplerIdx]->setTextureUnit(enumConversion); } void SRGBTestCase::activateSampler(const int samplerIdx, const bool active) { m_samplerList[samplerIdx]->setIsActive(active); } void SRGBTestCase::logColor(const std::string &colorLogMessage, int colorIdx, tcu::Vec4 color) const { tcu::TestLog &log = m_context.getTestContext().getLog(); std::ostringstream message; message << colorLogMessage << colorIdx << " = (" << color.x() << ", " << color.y() << ", " << color.z() << ", " << color.w() << ")"; log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage; } tcu::Vec4 SRGBTestCase::formatReferenceColor(tcu::Vec4 referenceColor) { switch (glu::getInternalFormat(m_internalFormat)) { case GL_SRGB8_ALPHA8: { return referenceColor; } case GL_SRG8_EXT: { // zero unwanted color channels referenceColor.z() = 0; return referenceColor; } case GL_SR8_EXT: { // zero unwanted color channels referenceColor.y() = 0; referenceColor.z() = 0; return referenceColor; } default: { DE_FATAL("Error: Internal format not recognised"); return referenceColor; } } } void SRGBTestCase::render(void) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); // default rendering only uses one program gl.bindFramebuffer(GL_FRAMEBUFFER, **m_framebuffer); gl.bindVertexArray(m_vaoID); gl.useProgram(m_shaderProgramList[0]->getHandle()); for (int textureSourceIdx = 0; textureSourceIdx < (int)m_textureSourceList.size(); textureSourceIdx++) { gl.activeTexture(GL_TEXTURE0 + (glw::GLenum)textureSourceIdx); gl.bindTexture(m_textureSourceList[textureSourceIdx]->getGLTargetType(), m_textureSourceList[textureSourceIdx]->getHandle()); glw::GLuint samplerUniformLocationID = gl.getUniformLocation( m_shaderProgramList[0]->getHandle(), (std::string("uTexture") + de::toString(textureSourceIdx)).c_str()); TCU_CHECK(samplerUniformLocationID != (glw::GLuint)-1); gl.uniform1i(samplerUniformLocationID, (glw::GLenum)textureSourceIdx); } for (int samplerIdx = 0; samplerIdx < (int)m_samplerList.size(); samplerIdx++) { if (m_samplerList[samplerIdx]->getIsActive() == true) { m_samplerList[samplerIdx]->bindToTexture(); } } gl.drawArrays(GL_TRIANGLES, 0, 6); for (std::size_t textureSourceIdx = 0; textureSourceIdx < m_textureSourceList.size(); textureSourceIdx++) { gl.bindTexture(m_textureSourceList[textureSourceIdx]->getGLTargetType(), 0); } gl.bindFramebuffer(GL_FRAMEBUFFER, 0); gl.bindVertexArray(0); gl.bindBuffer(GL_ARRAY_BUFFER, 0); } void SRGBTestCase::uploadTextures(void) { for (std::size_t idx = 0; idx < m_textureSourceList.size(); idx++) { m_textureSourceList[idx]->upload(); m_textureSourceList[idx]->setParameters(); } } void SRGBTestCase::initFrameBuffer(void) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); int width = m_context.getRenderContext().getRenderTarget().getWidth(); int height = m_context.getRenderContext().getRenderTarget().getHeight(); if (m_resultOutputTotal == 0) { throw std::invalid_argument("SRGBTestExecutor must have at least 1 rendered result"); } gl.bindFramebuffer(GL_FRAMEBUFFER, **m_framebuffer); DE_ASSERT(m_renderBufferList.empty()); for (int outputIdx = 0; outputIdx < m_resultOutputTotal; outputIdx++) { glw::GLuint renderBuffer = -1; m_renderBufferList.push_back(renderBuffer); } for (std::size_t renderBufferIdx = 0; renderBufferIdx < m_renderBufferList.size(); renderBufferIdx++) { gl.genRenderbuffers(1, &m_renderBufferList[renderBufferIdx]); gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderBufferList[renderBufferIdx]); gl.renderbufferStorage(GL_RENDERBUFFER, glu::getInternalFormat(m_resultTextureFormat), width, height); gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + (glw::GLenum)renderBufferIdx, GL_RENDERBUFFER, m_renderBufferList[renderBufferIdx]); GLU_EXPECT_NO_ERROR(gl.getError(), "Create and setup renderbuffer object"); } TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); std::vector renderBufferTargets(m_renderBufferList.size()); for (std::size_t renderBufferIdx = 0; renderBufferIdx < m_renderBufferList.size(); renderBufferIdx++) { renderBufferTargets[renderBufferIdx] = GL_COLOR_ATTACHMENT0 + (glw::GLenum)renderBufferIdx; } gl.drawBuffers((glw::GLsizei)renderBufferTargets.size(), &renderBufferTargets[0]); GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawBuffer()"); gl.bindFramebuffer(GL_FRAMEBUFFER, 0); } void SRGBTestCase::initVertexData(void) { const glw::Functions &gl = m_context.getRenderContext().getFunctions(); static const glw::GLfloat squareVertexData[] = { // position // texcoord -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom left corner 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom right corner 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // Top right corner -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top left corner 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // Top right corner -1.0f, -1.0f, 0.0f, 0.0f, 0.0f // bottom left corner }; DE_ASSERT(m_vaoID == 0); gl.genVertexArrays(1, &m_vaoID); gl.bindVertexArray(m_vaoID); gl.genBuffers(1, &m_vertexDataID); gl.bindBuffer(GL_ARRAY_BUFFER, m_vertexDataID); gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizei)sizeof(squareVertexData), squareVertexData, GL_STATIC_DRAW); gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * (glw::GLsizei)sizeof(float), (glw::GLvoid *)0); gl.enableVertexAttribArray(0); gl.vertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * (glw::GLsizei)sizeof(float), (glw::GLvoid *)(3 * sizeof(float))); gl.enableVertexAttribArray(1); gl.bindVertexArray(0); gl.bindBuffer(GL_ARRAY_BUFFER, 0); } class TextureDecodeSkippedCase : public SRGBTestCase { public: TextureDecodeSkippedCase(Context &context, const char *name, const char *description, const tcu::TextureFormat internalFormat) : SRGBTestCase(context, name, description, internalFormat) { } ~TextureDecodeSkippedCase(void) { } void setupTest(void); bool verifyResult(void); }; void TextureDecodeSkippedCase::setupTest(void) { // TEST STEPS: // - create and set texture to DECODE_SKIP_EXT // - store texture on GPU // - in fragment shader, sample the texture using texture*() and render texel values to a color attachment in the FBO // - on the host, read back the pixel values into a tcu::TextureLevel // - analyse the texel values, expecting them in sRGB format i.e. linear space decoding was skipped FragmentShaderParameters shaderParameters(SHADEROUTPUTS_ONE, SHADERUNIFORMS_ONE, NULL, BLENDING_NOT_REQUIRED, TOGGLING_NOT_REQUIRED); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_SKIP_DECODE); this->addShaderProgram(shaderParameters); this->setSamplingLocations(TestSamplingPositions::X_POS, TestSamplingPositions::Y_POS); this->setSamplingGroup(SHADERSAMPLINGGROUP_TEXTURE); } bool TextureDecodeSkippedCase::verifyResult(void) { tcu::TestLog &log = m_context.getTestContext().getLog(); const int resultColorIdx = 0; std::vector pixelResultList; tcu::Vec4 pixelConverted; tcu::Vec4 pixelReference; tcu::Vec4 pixelExpected; this->readResultTextures(); this->storeResultPixels(pixelResultList); pixelConverted = tcu::sRGBToLinear(pixelResultList[resultColorIdx]); pixelReference = this->formatReferenceColor(getColorReferenceLinear()); pixelExpected = this->formatReferenceColor(getColorReferenceSRGB()); this->formatReferenceColor(pixelReference); this->logColor(std::string("Expected color: "), resultColorIdx, pixelExpected); // result color 0 should be sRGB. Compare with linear reference color if ((tcu::boolAll(tcu::lessThan(tcu::abs(pixelConverted - pixelReference), m_epsilonError))) || (tcu::boolAll(tcu::equal(pixelConverted, pixelReference)))) { log << tcu::TestLog::Message << std::string("sRGB as expected") << tcu::TestLog::EndMessage; return true; } else { log << tcu::TestLog::Message << std::string("not sRGB as expected") << tcu::TestLog::EndMessage; return false; } } class TextureDecodeEnabledCase : public SRGBTestCase { public: TextureDecodeEnabledCase(Context &context, const char *name, const char *description, const tcu::TextureFormat internalFormat) : SRGBTestCase(context, name, description, internalFormat) { } ~TextureDecodeEnabledCase(void) { } void setupTest(void); bool verifyResult(void); }; void TextureDecodeEnabledCase::setupTest(void) { // TEST STEPS: // - create and set texture to DECODE_EXT // - store texture on GPU // - in fragment shader, sample the texture using texture*() and render texel values to a color attachment in the FBO // - on the host, read back the pixel values into a tcu::TextureLevel // - analyse the texel values, expecting them in lRGB format i.e. linear space decoding was enabled FragmentShaderParameters shaderParameters(SHADEROUTPUTS_ONE, SHADERUNIFORMS_ONE, NULL, BLENDING_NOT_REQUIRED, TOGGLING_NOT_REQUIRED); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_DECODE); this->addShaderProgram(shaderParameters); this->setSamplingLocations(TestSamplingPositions::X_POS, TestSamplingPositions::Y_POS); this->setSamplingGroup(SHADERSAMPLINGGROUP_TEXTURE); } bool TextureDecodeEnabledCase::verifyResult(void) { tcu::TestLog &log = m_context.getTestContext().getLog(); const int resultColorIdx = 0; std::vector pixelResultList; tcu::Vec4 pixelConverted; tcu::Vec4 pixelReference; tcu::Vec4 pixelExpected; this->readResultTextures(); this->storeResultPixels(pixelResultList); pixelConverted = tcu::linearToSRGB(pixelResultList[resultColorIdx]); pixelReference = this->formatReferenceColor(getColorReferenceSRGB()); pixelExpected = this->formatReferenceColor(getColorReferenceLinear()); this->logColor(std::string("Expected color: "), resultColorIdx, pixelExpected); // result color 0 should be SRGB. Compare with sRGB reference color if ((tcu::boolAll(tcu::lessThan(tcu::abs(pixelConverted - pixelReference), m_epsilonError))) || (tcu::boolAll(tcu::equal(pixelConverted, pixelReference)))) { log << tcu::TestLog::Message << std::string("linear as expected") << tcu::TestLog::EndMessage; return true; } else { log << tcu::TestLog::Message << std::string("not linear as expected") << tcu::TestLog::EndMessage; return false; } } class TexelFetchDecodeSkippedcase : public SRGBTestCase { public: TexelFetchDecodeSkippedcase(Context &context, const char *name, const char *description, const tcu::TextureFormat internalFormat) : SRGBTestCase(context, name, description, internalFormat) { } ~TexelFetchDecodeSkippedcase(void) { } void setupTest(void); bool verifyResult(void); }; void TexelFetchDecodeSkippedcase::setupTest(void) { // TEST STEPS: // - create and set texture to DECODE_SKIP_EXT // - store texture on GPU // - in fragment shader, sample the texture using texelFetch*() and render texel values to a color attachment in the FBO // - on the host, read back the pixel values into a tcu::TextureLevel // - analyse the texel values, expecting them in lRGB format i.e. linear space decoding is always enabled with texelFetch*() FragmentShaderParameters shaderParameters(SHADEROUTPUTS_ONE, SHADERUNIFORMS_ONE, NULL, BLENDING_NOT_REQUIRED, TOGGLING_NOT_REQUIRED); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_SKIP_DECODE); this->addShaderProgram(shaderParameters); this->setSamplingLocations(TestSamplingPositions::X_POS, TestSamplingPositions::Y_POS); this->setSamplingGroup(SHADERSAMPLINGGROUP_TEXEL_FETCH); } bool TexelFetchDecodeSkippedcase::verifyResult(void) { tcu::TestLog &log = m_context.getTestContext().getLog(); const int resultColorIdx = 0; std::vector pixelResultList; tcu::Vec4 pixelReference; tcu::Vec4 pixelExpected; this->readResultTextures(); this->storeResultPixels(pixelResultList); pixelReference = pixelExpected = this->formatReferenceColor(getColorReferenceLinear()); this->logColor(std::string("Expected color: "), resultColorIdx, pixelExpected); // result color 0 should be linear due to automatic conversion via texelFetch*(). Compare with linear reference color if ((tcu::boolAll(tcu::lessThan(tcu::abs(pixelResultList[0] - pixelReference), m_epsilonError))) || (tcu::boolAll(tcu::equal(pixelResultList[0], pixelReference)))) { log << tcu::TestLog::Message << std::string("linear as expected") << tcu::TestLog::EndMessage; return true; } else { log << tcu::TestLog::Message << std::string("not linear as expected") << tcu::TestLog::EndMessage; return false; } } class GPUConversionDecodeEnabledCase : public SRGBTestCase { public: GPUConversionDecodeEnabledCase(Context &context, const char *name, const char *description, const tcu::TextureFormat internalFormat) : SRGBTestCase(context, name, description, internalFormat) { } ~GPUConversionDecodeEnabledCase(void) { } void setupTest(void); bool verifyResult(void); }; void GPUConversionDecodeEnabledCase::setupTest(void) { // TEST STEPS: // - create and set texture_a to DECODE_SKIP_EXT and texture_b to default // - store textures on GPU // - in fragment shader, sample both textures using texture*() and manually perform sRGB to lRGB conversion on texture_b // - in fragment shader, compare converted texture_b with texture_a // - render green image for pass or red for fail ComparisonFunction comparisonFunction("srgbToLinearCheck", FUNCTIONPARAMETERS_TWO, getFunctionDefinitionSRGBToLinearCheck()); FragmentShaderParameters shaderParameters(SHADEROUTPUTS_ONE, SHADERUNIFORMS_TWO, &comparisonFunction, BLENDING_NOT_REQUIRED, TOGGLING_NOT_REQUIRED); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_SKIP_DECODE); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_DECODE_DEFAULT); this->addShaderProgram(shaderParameters); this->setSamplingLocations(TestSamplingPositions::X_POS, TestSamplingPositions::Y_POS); this->setSamplingGroup(SHADERSAMPLINGGROUP_TEXTURE); } bool GPUConversionDecodeEnabledCase::verifyResult(void) { tcu::TestLog &log = m_context.getTestContext().getLog(); const int resultColorIdx = 0; std::vector pixelResultList; this->readResultTextures(); this->storeResultPixels(pixelResultList); this->logColor(std::string("Expected color: "), resultColorIdx, getColorGreenPass()); // result color returned from GPU is either green (pass) or fail (red) if (tcu::boolAll(tcu::equal(pixelResultList[resultColorIdx], getColorGreenPass()))) { log << tcu::TestLog::Message << std::string("returned pass color from GPU") << tcu::TestLog::EndMessage; return true; } else { log << tcu::TestLog::Message << std::string("returned fail color from GPU") << tcu::TestLog::EndMessage; return false; } } class DecodeToggledCase : public SRGBTestCase { public: DecodeToggledCase(Context &context, const char *name, const char *description, const tcu::TextureFormat internalFormat) : SRGBTestCase(context, name, description, internalFormat) { } ~DecodeToggledCase(void) { } void render(void); void setupTest(void); bool verifyResult(void); }; void DecodeToggledCase::render(void) { // override the base SRGBTestCase render function with the purpose of switching between shader programs, // toggling texture sRGB decode state between draw calls const glw::Functions &gl = m_context.getRenderContext().getFunctions(); gl.bindFramebuffer(GL_FRAMEBUFFER, **m_framebuffer); gl.bindVertexArray(m_vaoID); for (std::size_t programIdx = 0; programIdx < m_shaderProgramList.size(); programIdx++) { gl.useProgram(m_shaderProgramList[programIdx]->getHandle()); this->toggleDecode(m_shaderProgramList[programIdx]->getUniformDataList()); for (int textureSourceIdx = 0; textureSourceIdx < (int)m_textureSourceList.size(); textureSourceIdx++) { gl.activeTexture(GL_TEXTURE0 + (glw::GLenum)textureSourceIdx); gl.bindTexture(m_textureSourceList[textureSourceIdx]->getGLTargetType(), m_textureSourceList[textureSourceIdx]->getHandle()); glw::GLuint samplerUniformLocationID = gl.getUniformLocation(m_shaderProgramList[programIdx]->getHandle(), (std::string("uTexture") + de::toString(textureSourceIdx)).c_str()); TCU_CHECK(samplerUniformLocationID != (glw::GLuint)-1); gl.uniform1i(samplerUniformLocationID, (glw::GLenum)textureSourceIdx); } for (int samplerIdx = 0; samplerIdx < (int)m_samplerList.size(); samplerIdx++) { if (m_samplerList[samplerIdx]->getIsActive() == true) { m_samplerList[samplerIdx]->bindToTexture(); } } if (m_shaderProgramList[programIdx]->getBlendRequired() == true) { gl.enable(GL_BLEND); gl.blendEquation(GL_MAX); gl.blendFunc(GL_ONE, GL_ONE); } else { gl.disable(GL_BLEND); } gl.drawArrays(GL_TRIANGLES, 0, 6); // reset sRGB decode state on textures this->toggleDecode(m_shaderProgramList[programIdx]->getUniformDataList()); } for (std::size_t textureSourceIdx = 0; textureSourceIdx < m_textureSourceList.size(); textureSourceIdx++) { gl.bindTexture(m_textureSourceList[textureSourceIdx]->getGLTargetType(), 0); } gl.bindFramebuffer(GL_FRAMEBUFFER, 0); gl.bindVertexArray(0); gl.bindBuffer(GL_ARRAY_BUFFER, 0); } void DecodeToggledCase::setupTest(void) { // TEST STEPS: // - create and set texture_a to DECODE_SKIP_EXT and texture_b to DECODE_EXT // - create and use two seperate shader programs, program_a and program_b, each using different fragment shaders // - store texture_a and texture_b on GPU // FIRST PASS: // - use program_a // - in fragment shader, sample both textures using texture*() and manually perform sRGB to lRGB conversion on texture_a // - in fragment shader, test converted texture_a value with texture_b // - render green image for pass or red for fail // - store result in a color attachement 0 // TOGGLE STAGE // - during rendering, toggle texture_a from DECODE_SKIP_EXT to DECODE_EXT // SECOND PASS: // - use program_b // - in fragment shader, sample both textures using texture*() and manually perform equality check. Both should be linear // - blend first pass result with second pass. Anything but a green result equals fail ComparisonFunction srgbToLinearFunction("srgbToLinearCheck", FUNCTIONPARAMETERS_TWO, getFunctionDefinitionSRGBToLinearCheck()); ComparisonFunction colorsEqualFunction("colorsEqualCheck", FUNCTIONPARAMETERS_TWO, getFunctionDefinitionEqualCheck()); FragmentShaderParameters shaderParametersA(SHADEROUTPUTS_ONE, SHADERUNIFORMS_TWO, &srgbToLinearFunction, BLENDING_NOT_REQUIRED, TOGGLING_NOT_REQUIRED); FragmentShaderParameters shaderParametersB(SHADEROUTPUTS_ONE, SHADERUNIFORMS_TWO, &colorsEqualFunction, BLENDING_REQUIRED, TOGGLING_REQUIRED); // need to specify which texture uniform to toggle DECODE_EXT/SKIP_DECODE_EXT shaderParametersB.uniformsToToggle.push_back("uTexture0"); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_SKIP_DECODE); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_DECODE); this->addShaderProgram(shaderParametersA); this->addShaderProgram(shaderParametersB); this->setSamplingLocations(TestSamplingPositions::X_POS, TestSamplingPositions::Y_POS); this->setSamplingGroup(SHADERSAMPLINGGROUP_TEXTURE); } bool DecodeToggledCase::verifyResult(void) { tcu::TestLog &log = m_context.getTestContext().getLog(); const int resultColorIdx = 0; std::vector pixelResultList; this->readResultTextures(); this->storeResultPixels(pixelResultList); this->logColor(std::string("Expected color: "), resultColorIdx, getColorGreenPass()); // result color is either green (pass) or fail (red) if (tcu::boolAll(tcu::equal(pixelResultList[resultColorIdx], getColorGreenPass()))) { log << tcu::TestLog::Message << std::string("returned pass color from GPU") << tcu::TestLog::EndMessage; return true; } else { log << tcu::TestLog::Message << std::string("returned fail color from GPU") << tcu::TestLog::EndMessage; return false; } } class DecodeMultipleTexturesCase : public SRGBTestCase { public: DecodeMultipleTexturesCase(Context &context, const char *name, const char *description, const tcu::TextureFormat internalFormat) : SRGBTestCase(context, name, description, internalFormat) { } ~DecodeMultipleTexturesCase(void) { } void setupTest(void); bool verifyResult(void); }; void DecodeMultipleTexturesCase::setupTest(void) { // TEST STEPS: // - create and set texture_a to DECODE_SKIP_EXT and texture_b to DECODE_EXT // - upload textures to the GPU and bind to seperate uniform variables // - sample both textures using texture*() // - read texel values back to the CPU // - compare the texel values, both should be different from each other FragmentShaderParameters shaderParameters(SHADEROUTPUTS_TWO, SHADERUNIFORMS_TWO, NULL, BLENDING_NOT_REQUIRED, TOGGLING_NOT_REQUIRED); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_SKIP_DECODE); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_DECODE); this->addShaderProgram(shaderParameters); this->setSamplingLocations(TestSamplingPositions::X_POS, TestSamplingPositions::Y_POS); this->setSamplingGroup(SHADERSAMPLINGGROUP_TEXTURE); } bool DecodeMultipleTexturesCase::verifyResult(void) { tcu::TestLog &log = m_context.getTestContext().getLog(); const int resultColorIdx = 0; std::vector pixelResultList; tcu::Vec4 pixelExpected0; tcu::Vec4 pixelExpected1; this->readResultTextures(); this->storeResultPixels(pixelResultList); pixelExpected0 = this->formatReferenceColor(getColorReferenceSRGB()); pixelExpected1 = this->formatReferenceColor(getColorReferenceLinear()); this->logColor(std::string("Expected color: "), resultColorIdx, pixelExpected0); this->logColor(std::string("Expected color: "), resultColorIdx + 1, pixelExpected1); // check if the two textures have different values i.e. uTexture0 = sRGB and uTexture1 = linear if (!(tcu::boolAll(tcu::equal(pixelResultList[resultColorIdx], pixelResultList[resultColorIdx + 1])))) { log << tcu::TestLog::Message << std::string("texel values are different") << tcu::TestLog::EndMessage; return true; } else { log << tcu::TestLog::Message << std::string("texel values are equal") << tcu::TestLog::EndMessage; return false; } } class DecodeSamplerCase : public SRGBTestCase { public: DecodeSamplerCase(Context &context, const char *name, const char *description, const tcu::TextureFormat internalFormat) : SRGBTestCase(context, name, description, internalFormat) { } ~DecodeSamplerCase(void) { } void setupTest(void); bool verifyResult(void); }; void DecodeSamplerCase::setupTest(void) { // TEST STEPS: // - create and set texture_a to DECODE_SKIP_EXT // - upload texture to the GPU and bind to sampler // - sample texture using texture*() // - read texel values back to the CPU // - compare the texel values, should be in sampler format (linear) FragmentShaderParameters shaderParameters(SHADEROUTPUTS_ONE, SHADERUNIFORMS_ONE, NULL, BLENDING_NOT_REQUIRED, TOGGLING_NOT_REQUIRED); this->addTexture(TEXTURETYPE_2D, TestDimensions::WIDTH, TestDimensions::HEIGHT, getColorReferenceLinear(), tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_SKIP_DECODE); this->addSampler(tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::MIRRORED_REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, SRGBDECODE_DECODE); this->addShaderProgram(shaderParameters); this->bindSamplerToTexture(0, 0, GL_TEXTURE0); this->activateSampler(0, true); this->setSamplingLocations(TestSamplingPositions::X_POS, TestSamplingPositions::Y_POS); this->setSamplingGroup(SHADERSAMPLINGGROUP_TEXTURE); } bool DecodeSamplerCase::verifyResult(void) { tcu::TestLog &log = m_context.getTestContext().getLog(); const int resultColorIdx = 0; std::vector pixelResultList; tcu::Vec4 pixelConverted; tcu::Vec4 pixelReference; tcu::Vec4 pixelExpected; this->readResultTextures(); this->storeResultPixels(pixelResultList); pixelConverted = tcu::linearToSRGB(pixelResultList[resultColorIdx]); pixelReference = this->formatReferenceColor(getColorReferenceSRGB()); pixelExpected = this->formatReferenceColor(getColorReferenceLinear()); this->logColor(std::string("Expected color: "), resultColorIdx, pixelExpected); // texture was rendered using a sampler object with setting DECODE_EXT, therefore, results should be linear if ((tcu::boolAll(tcu::lessThan(tcu::abs(pixelConverted - pixelReference), m_epsilonError))) || (tcu::boolAll(tcu::equal(pixelConverted, pixelReference)))) { log << tcu::TestLog::Message << std::string("linear as expected") << tcu::TestLog::EndMessage; return true; } else { log << tcu::TestLog::Message << std::string("not linear as expected") << tcu::TestLog::EndMessage; return false; } } } // namespace SRGBDecodeTests::SRGBDecodeTests(Context &context) : TestCaseGroup(context, "skip_decode", "sRGB skip decode tests") { } SRGBDecodeTests::~SRGBDecodeTests(void) { } void SRGBDecodeTests::init(void) { const TestGroupConfig testGroupConfigList[] = { TestGroupConfig("srgba8", "srgb decode tests using srgba internal format", tcu::TextureFormat(tcu::TextureFormat::sRGBA, tcu::TextureFormat::UNORM_INT8)), TestGroupConfig("srg8", "srgb decode tests using srg8 internal format", tcu::TextureFormat(tcu::TextureFormat::sRG, tcu::TextureFormat::UNORM_INT8)), TestGroupConfig("sr8", "srgb decode tests using sr8 internal format", tcu::TextureFormat(tcu::TextureFormat::sR, tcu::TextureFormat::UNORM_INT8))}; // create groups for all desired internal formats, adding test cases to each for (std::size_t idx = 0; idx < DE_LENGTH_OF_ARRAY(testGroupConfigList); idx++) { tcu::TestCaseGroup *const testGroup = new tcu::TestCaseGroup(m_testCtx, testGroupConfigList[idx].name, testGroupConfigList[idx].description); tcu::TestNode::addChild(testGroup); testGroup->addChild(new TextureDecodeSkippedCase( m_context, "skipped", "testing for sRGB color values with sRGB texture decoding skipped", testGroupConfigList[idx].internalFormat)); testGroup->addChild(new TextureDecodeEnabledCase( m_context, "enabled", "testing for linear color values with sRGB texture decoding enabled", testGroupConfigList[idx].internalFormat)); testGroup->addChild(new TexelFetchDecodeSkippedcase( m_context, "texel_fetch", "testing for linear color values with sRGB texture decoding skipped", testGroupConfigList[idx].internalFormat)); testGroup->addChild(new GPUConversionDecodeEnabledCase( m_context, "conversion_gpu", "sampling linear values and performing conversion on the gpu", testGroupConfigList[idx].internalFormat)); testGroup->addChild(new DecodeToggledCase(m_context, "toggled", "toggle the sRGB decoding between draw calls", testGroupConfigList[idx].internalFormat)); testGroup->addChild(new DecodeMultipleTexturesCase( m_context, "multiple_textures", "upload multiple textures with different sRGB decode values and sample", testGroupConfigList[idx].internalFormat)); testGroup->addChild(new DecodeSamplerCase(m_context, "using_sampler", "testing that sampler object takes priority over texture state", testGroupConfigList[idx].internalFormat)); } } } // namespace Functional } // namespace gles31 } // namespace deqp