From b4d41f1ef041179f927a6a04a8fd5913cdf590bb Mon Sep 17 00:00:00 2001 From: Michael Hadley Date: Wed, 1 Feb 2017 12:48:08 +0000 Subject: [PATCH] Add sRGB skip decode test New Tests: - deqp-case=dEQP-GLES31.functional.srgb_texture_decode.* Change-Id: I0257e63b15ee0334efad985411d8070ddecdd51a --- Android.mk | 1 + android/cts/master/gles31-master.txt | 14 + modules/gles31/functional/CMakeLists.txt | 2 + modules/gles31/functional/es31fFunctionalTests.cpp | 16 + modules/gles31/functional/es31fSRGBDecodeTests.cpp | 2039 ++++++++++++++++++++ modules/gles31/functional/es31fSRGBDecodeTests.hpp | 54 + 6 files changed, 2126 insertions(+) create mode 100644 modules/gles31/functional/es31fSRGBDecodeTests.cpp create mode 100644 modules/gles31/functional/es31fSRGBDecodeTests.hpp diff --git a/Android.mk b/Android.mk index 1551102..7c29c09 100644 --- a/Android.mk +++ b/Android.mk @@ -640,6 +640,7 @@ LOCAL_SRC_FILES := \ modules/gles31/functional/es31fVertexAttributeBindingTests.cpp \ modules/gles31/functional/es31fCopyImageTests.cpp \ modules/gles31/functional/es31fDrawBuffersIndexedTests.cpp \ + modules/gles31/functional/es31fSRGBDecodeTests.cpp \ modules/gles31/stress/es31sDrawTests.cpp \ modules/gles31/stress/es31sStressTests.cpp \ modules/gles31/stress/es31sTessellationGeometryInteractionTests.cpp \ diff --git a/android/cts/master/gles31-master.txt b/android/cts/master/gles31-master.txt index 845e873..b4f78d9 100644 --- a/android/cts/master/gles31-master.txt +++ b/android/cts/master/gles31-master.txt @@ -35550,3 +35550,17 @@ dEQP-GLES31.functional.draw_buffers_indexed.random.max_implementation_draw_buffe dEQP-GLES31.functional.draw_buffers_indexed.random.max_implementation_draw_buffers.18 dEQP-GLES31.functional.draw_buffers_indexed.random.max_implementation_draw_buffers.19 dEQP-GLES31.functional.default_vertex_array_object.vertex_attrib_divisor +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.srgba8.skipped +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.srgba8.enabled +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.srgba8.texel_fetch +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.srgba8.conversion_gpu +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.srgba8.toggled +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.srgba8.multiple_textures +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.srgba8.using_sampler +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.sr8.skipped +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.sr8.enabled +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.sr8.texel_fetch +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.sr8.conversion_gpu +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.sr8.toggled +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.sr8.multiple_textures +dEQP-GLES31.functional.srgb_texture_decode.skip_decode.sr8.using_sampler diff --git a/modules/gles31/functional/CMakeLists.txt b/modules/gles31/functional/CMakeLists.txt index 8c6edea..2f2429e 100644 --- a/modules/gles31/functional/CMakeLists.txt +++ b/modules/gles31/functional/CMakeLists.txt @@ -43,6 +43,8 @@ set(DEQP_GLES31_FUNCTIONAL_SRCS es31fShaderAtomicOpTests.hpp es31fShaderImageLoadStoreTests.cpp es31fShaderImageLoadStoreTests.hpp + es31fSRGBDecodeTests.cpp + es31fSRGBDecodeTests.hpp es31fSSBOLayoutCase.cpp es31fSSBOLayoutCase.hpp es31fSSBOLayoutTests.cpp diff --git a/modules/gles31/functional/es31fFunctionalTests.cpp b/modules/gles31/functional/es31fFunctionalTests.cpp index 784e70c..b2bdac6 100644 --- a/modules/gles31/functional/es31fFunctionalTests.cpp +++ b/modules/gles31/functional/es31fFunctionalTests.cpp @@ -88,6 +88,7 @@ #include "es31fCopyImageTests.hpp" #include "es31fDrawBuffersIndexedTests.hpp" #include "es31fDefaultVertexArrayObjectTests.hpp" +#include "es31fSRGBDecodeTests.hpp" namespace deqp { @@ -296,6 +297,20 @@ public: } }; +class SRGBTextureDecodeTests : public TestCaseGroup +{ +public: + SRGBTextureDecodeTests (Context& context) + : TestCaseGroup (context, "srgb_texture_decode", "GL_EXT_texture_sRGB_decode tests") + { + } + + void init (void) + { + addChild(new SRGBDecodeTests (m_context)); + } +}; + FunctionalTests::FunctionalTests (Context& context) : TestCaseGroup(context, "functional", "Functionality Tests") { @@ -337,6 +352,7 @@ void FunctionalTests::init (void) addChild(createCopyImageTests (m_context)); addChild(createDrawBuffersIndexedTests (m_context)); addChild(new DefaultVertexArrayObjectTests (m_context)); + addChild(new SRGBTextureDecodeTests (m_context)); } } // Functional diff --git a/modules/gles31/functional/es31fSRGBDecodeTests.cpp b/modules/gles31/functional/es31fSRGBDecodeTests.cpp new file mode 100644 index 0000000..20bbe6e --- /dev/null +++ b/modules/gles31/functional/es31fSRGBDecodeTests.cpp @@ -0,0 +1,2039 @@ +/*------------------------------------------------------------------------- + * 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" + +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; +} // global test texture dimensions + +namespace TestSamplingPositions +{ + const int X_POS = 0; + const int Y_POS = 0; +} // global test sampling positions + +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) + , 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 deUint32 textureUnit); + void setIsActive (const bool isActive); + + deUint32 getHandle (void) const; + bool getIsActive (void) const; + + void bindToTexture (void); + void unbindFromTexture (void); + +private: + const glw::Functions* m_gl; + deUint32 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; + deUint32 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) +{ +} + +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 deUint32 textureUnit) +{ + m_textureUnit = textureUnit; +} + +void SRGBTestSampler::setIsActive (const bool isActive) +{ + m_isActive = isActive; +} + +deUint32 SRGBTestSampler::getHandle (void) const +{ + return m_samplerHandle; +} + +bool SRGBTestSampler::getIsActive (void) const +{ + return m_isActive; +} + +void SRGBTestSampler::bindToTexture (void) +{ + m_gl->bindSampler(m_textureUnit, m_samplerHandle); +} + +void SRGBTestSampler::unbindFromTexture (void) +{ + m_gl->bindSampler(m_textureUnit, 0); +} + +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); + + deUint32 getHandle (void) const; + deUint32 getGLTargetType (void) const; + SRGBDecode getDecode (void) const; + bool getHasSampler (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; +} + +deUint32 SRGBTestTexture::getHandle (void) const +{ + return m_source.getGLTexture(); +} + +deUint32 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; +} + +bool SRGBTestTexture::getHasSampler (void) const +{ + return m_hasSampler; +} + +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); + + int getUniformTotal (void) const; + const std::vector& getUniformDataList (void) const; + const UniformData& getUniformAtLocation (int location) const; + int getUniformLocation (const std::string& name); + deUint32 getHandle (void) const; + bool getBlendRequired (void) const; + bool getToggleRequired (void) const; + const std::string& getFragmentShader (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 + m_shaderVertex = "#version 310 es \n" + "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[idx]); + + 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 "); + } +} + +int SRGBTestProgram::getUniformTotal (void) const +{ + return (int)m_uniformDataList.size(); +} + +const std::vector& SRGBTestProgram::getUniformDataList (void) const +{ + return m_uniformDataList; +} + +const UniformData& SRGBTestProgram::getUniformAtLocation (int location) const +{ + return m_uniformDataList[location]; +} + +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; +} + +bool SRGBTestProgram::getToggleRequired (void) const +{ + return m_toggleRequired; +} + +const std::string& SRGBTestProgram::getFragmentShader (void) const +{ + return m_shaderFragment; +} + +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 << "#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 setShaderProgramBlendRequired (const int programIdx, const bool blend); + void setShaderProgramToggleRequired (const int programIdx, const bool toggle); + void setUniformToggle (const int programIdx, const std::string& uniformName, bool toggleDecode); + + deUint32 getShaderProgramHandle (const int programIdx) const; + deUint32 getTextureHandle (const int textureIdx) const; + + 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 deUint32 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; + 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_resultTextureFormat (tcu::TextureFormat(tcu::TextureFormat::sRGBA, tcu::TextureFormat::UNORM_INT8)) + , m_samplingGroup (SHADERSAMPLINGGROUP_TEXTURE) + , m_internalFormat (internalFormat) +{ +} + +SRGBTestCase::~SRGBTestCase (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]); + } + + for (std::size_t textureSourceIdx = 0; textureSourceIdx < m_textureSourceList.size(); textureSourceIdx++) + { + delete m_textureSourceList[textureSourceIdx]; + } + + SRGBTestCase::deinit(); +} + +void SRGBTestCase::init (void) +{ + // 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_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())); +} + +void SRGBTestCase::deinit (void) +{ +} + +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"); + } + + // 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->initFrameBuffer(); + this->initVertexData(); + 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::setShaderProgramBlendRequired (const int programIdx, const bool blend) +{ + m_shaderProgramList[programIdx]->setBlendRequired(blend); +} + +void SRGBTestCase::setShaderProgramToggleRequired (const int programIdx, const bool toggle) +{ + m_shaderProgramList[programIdx]->setToggleRequired(toggle); +} + +void SRGBTestCase::setUniformToggle (const int programIdx, const std::string& uniformName, bool toggleDecodeValue) +{ + int uniformLocation = m_shaderProgramList[programIdx]->getUniformLocation(uniformName); + m_shaderProgramList[programIdx]->setUniformToggle(uniformLocation, toggleDecodeValue); +} + +deUint32 SRGBTestCase::getShaderProgramHandle (const int programIdx) const +{ + return m_shaderProgramList[programIdx]->getHandle(); +} + +deUint32 SRGBTestCase::getTextureHandle (const int textureIdx) const +{ + return m_textureSourceList[textureIdx]->getHandle(); +} + +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(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 deUint32 textureUnit) +{ + deUint32 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_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 + this->uploadTextures(); + this->initFrameBuffer(); + this->initVertexData(); + + 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(), m_shaderProgramList[0]->getUniformAtLocation(textureSourceIdx).name.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); + + if ((int)m_renderBufferList.size() != m_resultOutputTotal) + { + 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(); + glw::GLuint vertexDataID = (glw::GLuint)-1; + + 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 + }; + + gl.genVertexArrays(1, &m_vaoID); + gl.bindVertexArray(m_vaoID); + + gl.genBuffers(1, &vertexDataID); + gl.bindBuffer(GL_ARRAY_BUFFER, 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(GL_FLOAT), (glw::GLvoid *)0); + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * (glw::GLsizei)sizeof(GL_FLOAT), (glw::GLvoid *)(3 * sizeof(GL_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(), m_shaderProgramList[programIdx]->getUniformAtLocation(textureSourceIdx).name.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; + } +} + +} // anonymous + +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("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)); + } +} + +} // Functional +} // gles31 +} // deqp diff --git a/modules/gles31/functional/es31fSRGBDecodeTests.hpp b/modules/gles31/functional/es31fSRGBDecodeTests.hpp new file mode 100644 index 0000000..8be5da7 --- /dev/null +++ b/modules/gles31/functional/es31fSRGBDecodeTests.hpp @@ -0,0 +1,54 @@ +#ifndef _ES31FSRGBDECODETESTS_HPP +#define _ES31FSRGBDECODETESTS_HPP +/*------------------------------------------------------------------------- + * 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 sRGB decode tests. + *//*--------------------------------------------------------------------*/ + +#include "tcuDefs.hpp" +#include "tes31TestCase.hpp" + +namespace deqp +{ +namespace gles31 +{ +namespace Functional +{ + +class SRGBDecodeTests : public TestCaseGroup +{ +public: + SRGBDecodeTests (Context& context); + ~SRGBDecodeTests (void); + +private: + void init (void); + + SRGBDecodeTests (const SRGBDecodeTests& other); + SRGBDecodeTests& operator= (const SRGBDecodeTests& other); +}; + +} // Functional +} // gles31 +} // deqp + + +#endif // _ES31FSRGBDECODETESTS_HPP \ No newline at end of file -- 2.7.4