From 50d8f31f524a5f315ba97f366975ccec0b47ef03 Mon Sep 17 00:00:00 2001 From: Michael Hadley Date: Wed, 8 Mar 2017 13:28:09 +0000 Subject: [PATCH] Add sRGB write decode tests New Tests: - dEQP-GLES31.functional.fbo.srgb_write_control.* Change-Id: Ieaaee4c7dc49cc530d8fc42a060e40c706d86e5c --- android/cts/master/gles31-master.txt | 5 + modules/gles31/functional/CMakeLists.txt | 2 + .../functional/es31fFboSRGBWriteControlTests.cpp | 1796 ++++++++++++++++++++ .../functional/es31fFboSRGBWriteControlTests.hpp | 53 + modules/gles31/functional/es31fFunctionalTests.cpp | 2 + 5 files changed, 1858 insertions(+) create mode 100644 modules/gles31/functional/es31fFboSRGBWriteControlTests.cpp create mode 100644 modules/gles31/functional/es31fFboSRGBWriteControlTests.hpp diff --git a/android/cts/master/gles31-master.txt b/android/cts/master/gles31-master.txt index b4f78d9..aeebbe3 100644 --- a/android/cts/master/gles31-master.txt +++ b/android/cts/master/gles31-master.txt @@ -17894,6 +17894,11 @@ dEQP-GLES31.functional.fbo.no_attachments.maximums.size dEQP-GLES31.functional.fbo.no_attachments.maximums.samples dEQP-GLES31.functional.fbo.no_attachments.maximums.all dEQP-GLES31.functional.fbo.completeness.no_attachments +dEQP-GLES31.functional.fbo.srgb_write_control.framebuffer_srgb_enabled +dEQP-GLES31.functional.fbo.srgb_write_control.framebuffer_srgb_enabled_col_attach +dEQP-GLES31.functional.fbo.srgb_write_control.framebuffer_srgb_enabled_blend +dEQP-GLES31.functional.fbo.srgb_write_control.framebuffer_srgb_enabled_render_target_ignore +dEQP-GLES31.functional.fbo.srgb_write_control.framebuffer_srgb_enabled_copy_to_linear dEQP-GLES31.functional.program_interface_query.buffer_limited_query.resource_name_query dEQP-GLES31.functional.program_interface_query.buffer_limited_query.resource_query dEQP-GLES31.functional.program_interface_query.uniform.resource_list.default_block.var diff --git a/modules/gles31/functional/CMakeLists.txt b/modules/gles31/functional/CMakeLists.txt index 2f2429e..0454747 100644 --- a/modules/gles31/functional/CMakeLists.txt +++ b/modules/gles31/functional/CMakeLists.txt @@ -71,6 +71,8 @@ set(DEQP_GLES31_FUNCTIONAL_SRCS es31fFboTestCase.hpp es31fFboTestUtil.cpp es31fFboTestUtil.hpp + es31fFboSRGBWriteControlTests.cpp + es31fFboSRGBWriteControlTests.hpp es31fTextureFilteringTests.cpp es31fTextureFilteringTests.hpp es31fTextureFormatTests.hpp diff --git a/modules/gles31/functional/es31fFboSRGBWriteControlTests.cpp b/modules/gles31/functional/es31fFboSRGBWriteControlTests.cpp new file mode 100644 index 0000000..bd913ec --- /dev/null +++ b/modules/gles31/functional/es31fFboSRGBWriteControlTests.cpp @@ -0,0 +1,1796 @@ +/*------------------------------------------------------------------------- + * 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 FBO sRGB tests. +*//*--------------------------------------------------------------------*/ + +#include "es31fFboSRGBWriteControlTests.hpp" +#include "es31fFboTestUtil.hpp" +#include "gluTextureUtil.hpp" +#include "gluContextInfo.hpp" +#include "tcuTestLog.hpp" +#include "glwEnums.hpp" +#include "sglrContextUtil.hpp" +#include "glwFunctions.hpp" +#include "deUniquePtr.hpp" +#include "deSharedPtr.hpp" +#include "gluObjectWrapper.hpp" +#include "gluPixelTransfer.hpp" +#include "glsTextureTestUtil.hpp" +#include "tcuVectorUtil.hpp" + +namespace deqp +{ +namespace gles31 +{ +namespace Functional +{ +namespace +{ + +tcu::Vec4 getTestColorLinear (void) +{ + return tcu::Vec4(0.2f, 0.3f, 0.4f, 1.0f); +} + +tcu::Vec4 getTestColorSRGB (void) +{ + return linearToSRGB(tcu::Vec4(0.2f, 0.3f, 0.4f, 1.0f)); +} + +tcu::Vec4 getTestColorBlank (void) +{ + return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); +} + +tcu::Vec4 getEpsilonError (void) +{ + return tcu::Vec4(0.005f); +} + +enum QueryType +{ + QUERYTYPE_ISENABLED = 0, + QUERYTYPE_BOOLEAN, + QUERYTYPE_FLOAT, + QUERYTYPE_INT, + QUERYTYPE_INT64, + QUERYTYPE_LAST +}; + +enum DataType +{ + DATATYPE_BOOLEAN = 0, + DATATYPE_FLOAT, + DATATYPE_INT, + DATATYPE_INT64, +}; + +enum FramebufferSRGB +{ + FRAMEBUFFERSRGB_ENABLED = 0, + FRAMEBUFFERSRGB_DISABLED +}; + +enum FramebufferBlend +{ + FRAMEBUFFERBLEND_ENABLED = 0, + FRAMEBUFFERBLEND_DISABLED +}; + +enum TextureSourcesType +{ + TEXTURESOURCESTYPE_RGBA = 0, + TEXTURESOURCESTYPE_SRGBA, + TEXTURESOURCESTYPE_BOTH, + TEXTURESOURCESTYPE_NONE +}; + +enum FboType +{ + FBOTYPE_SOURCE = 0, + FBOTYPE_DESTINATION +}; + +enum RendererTask +{ + RENDERERTASK_DRAW = 0, + RENDERERTASK_COPY +}; + +enum SamplingType +{ + SAMPLINGTYPE_TEXTURE = 0, + SAMPLINGTYPE_TEXTURE_LOD, + SAMPLINGTYPE_TEXTURE_GRAD, + SAMPLINGTYPE_TEXTURE_OFFSET, + SAMPLINGTYPE_TEXTURE_PROJ, +}; + +namespace TestTextureSizes +{ + const int WIDTH = 128; + const int HEIGHT = 128; +} // global test texture sizes + +namespace SampligTypeCount +{ + const int MAX = 5; +} // global max number of sampling types + +std::string buildSamplingPassType (const int samplerTotal) +{ + std::ostringstream shaderFragment; + + const SamplingType samplingTypeList [] = + { + SAMPLINGTYPE_TEXTURE, SAMPLINGTYPE_TEXTURE_LOD, SAMPLINGTYPE_TEXTURE_GRAD, SAMPLINGTYPE_TEXTURE_OFFSET, SAMPLINGTYPE_TEXTURE_PROJ + } ; + + for (int samplerTypeIdx = 0; samplerTypeIdx < DE_LENGTH_OF_ARRAY(samplingTypeList); samplerTypeIdx++) + { + shaderFragment + << " if (uFunctionType == " << samplerTypeIdx << ") \n" + << " { \n"; + + for (int samplerIdx = 0; samplerIdx < samplerTotal; samplerIdx++) + { + switch (static_cast(samplerTypeIdx)) + { + case SAMPLINGTYPE_TEXTURE: + { + shaderFragment + << " texelColor" << samplerIdx << " = texture(uTexture" << samplerIdx << ", vs_aTexCoord); \n"; + break; + } + case SAMPLINGTYPE_TEXTURE_LOD: + { + shaderFragment + << " texelColor" << samplerIdx << " = textureLod(uTexture" << samplerIdx << ", vs_aTexCoord, 0.0f); \n"; + break; + } + case SAMPLINGTYPE_TEXTURE_GRAD: + { + shaderFragment + << " texelColor" << samplerIdx << " = textureGrad(uTexture" << samplerIdx << ", vs_aTexCoord, vec2(0.0f, 0.0f), vec2(0.0f, 0.0f)); \n"; + break; + } + case SAMPLINGTYPE_TEXTURE_OFFSET: + { + shaderFragment + << " texelColor" << samplerIdx << " = textureOffset(uTexture" << samplerIdx << ", vs_aTexCoord, ivec2(0.0f, 0.0f)); \n"; + break; + } + case SAMPLINGTYPE_TEXTURE_PROJ: + { + shaderFragment + << " texelColor" << samplerIdx << " = textureProj(uTexture" << samplerIdx << ", vec3(vs_aTexCoord, 1.0f)); \n"; + break; + } + default: + DE_FATAL("Error: sampling type unrecognised"); + } + } + + shaderFragment + << " } \n"; + } + + return shaderFragment.str(); +} + +void logColor (Context& context, const std::string& colorLogMessage, const tcu::Vec4 resultColor) +{ + tcu::TestLog& log = context.getTestContext().getLog(); + std::ostringstream message; + + message << colorLogMessage << " = (" << resultColor.x() << ", " << resultColor.y() << ", " << resultColor.z() << ", " << resultColor.w() << ")"; + log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage; +} + +struct TestFunction +{ + explicit TestFunction (const bool hasFunctionValue) + : hasFunction (hasFunctionValue) {} + TestFunction (const char* const functionNameValue, const char* const functionDefinition) + : hasFunction (true) + , functionName (functionNameValue) + , functionDefintion (functionDefinition) {} + ~TestFunction (void) {} + + bool hasFunction; + const char* functionName; + const char* functionDefintion; +}; + +TestFunction getFunctionBlendLinearToSRGBCheck (void) +{ + const char* const functionName = "blendPlusLinearToSRGB"; + + const char* const functionDefinition = + "mediump vec4 blendPlusLinearToSRGB(in mediump vec4 colorSrc, in mediump vec4 colorDst) \n" + "{ \n" + " const int MAX_VECTOR_SIZE = 4; \n" + " mediump vec4 colorConverted; \n" + " mediump vec4 colorBlended; \n" + " for (int idx = 0; idx < MAX_VECTOR_SIZE; idx++) \n" + " { \n" + " if (uBlendFunctionType == 0) \n" + " { \n" + " colorBlended[idx] = (colorSrc[idx] * uFactorSrc) + colorDst[idx] * uFactorDst; \n" + " } \n" + " if (uBlendFunctionType == 1) \n" + " { \n" + " colorBlended[idx] = (colorSrc[idx] * uFactorSrc) - (colorDst[idx] * uFactorDst); \n" + " } \n" + "if (uBlendFunctionType == 2) \n" + " { \n" + " colorBlended[idx] = (colorDst[idx] * uFactorDst) - (colorSrc[idx] * uFactorSrc); \n" + " } \n" + " if (colorBlended[idx] < 0.0031308f) \n" + " { \n" + " colorConverted[idx] = 12.92f * colorBlended[idx]; \n" + " } \n" + " else \n" + " { \n" + " colorConverted[idx] = 1.055f * pow(colorBlended[idx], 0.41666f) - 0.055f; \n" + " } \n" + " } \n" + " return colorConverted; \n" + "} \n"; + + TestFunction testFunction(functionName, functionDefinition); + + return testFunction; +} + +struct FBOConfig +{ + FBOConfig (const deUint32 textureInternalFormatValue, + const tcu::Vec4 textureColorValue, + const deUint32 fboTargetTypeValue, + const deUint32 fboColorAttachmentValue, + const FboType fboTypeValue) + : textureInternalFormat (textureInternalFormatValue) + , textureColor (textureColorValue) + , fboTargetType (fboTargetTypeValue) + , fboColorAttachment (fboColorAttachmentValue) + , fboType (fboTypeValue) {} + ~FBOConfig (void) {} + + deUint32 textureInternalFormat; + tcu::Vec4 textureColor; + deUint32 fboTargetType; + deUint32 fboColorAttachment; + FboType fboType; +}; + +struct BlendConfig +{ + deUint32 equation; + deUint32 funcSrc; + deUint32 funcDst; +}; + +std::vector getBlendingConfigList (void) +{ + BlendConfig blendConfigs[12]; + + // add function permutations + blendConfigs[0].equation = GL_FUNC_ADD; + blendConfigs[1].equation = GL_FUNC_ADD; + blendConfigs[2].equation = GL_FUNC_ADD; + blendConfigs[3].equation = GL_FUNC_ADD; + + blendConfigs[0].funcSrc = GL_ONE; + blendConfigs[0].funcDst = GL_ONE; + blendConfigs[1].funcSrc = GL_ONE; + blendConfigs[1].funcDst = GL_ZERO; + blendConfigs[2].funcSrc = GL_ZERO; + blendConfigs[2].funcDst = GL_ONE; + blendConfigs[3].funcSrc = GL_ZERO; + blendConfigs[3].funcDst = GL_ZERO; + + // subtract function permutations + blendConfigs[4].equation = GL_FUNC_SUBTRACT; + blendConfigs[5].equation = GL_FUNC_SUBTRACT; + blendConfigs[6].equation = GL_FUNC_SUBTRACT; + blendConfigs[7].equation = GL_FUNC_SUBTRACT; + + blendConfigs[4].funcSrc = GL_ONE; + blendConfigs[4].funcDst = GL_ONE; + blendConfigs[5].funcSrc = GL_ONE; + blendConfigs[5].funcDst = GL_ZERO; + blendConfigs[6].funcSrc = GL_ZERO; + blendConfigs[6].funcDst = GL_ONE; + blendConfigs[7].funcSrc = GL_ZERO; + blendConfigs[7].funcDst = GL_ZERO; + + // reverse subtract function permutations + blendConfigs[8].equation = GL_FUNC_REVERSE_SUBTRACT; + blendConfigs[9].equation = GL_FUNC_REVERSE_SUBTRACT; + blendConfigs[10].equation = GL_FUNC_REVERSE_SUBTRACT; + blendConfigs[11].equation = GL_FUNC_REVERSE_SUBTRACT; + + blendConfigs[8].funcSrc = GL_ONE; + blendConfigs[8].funcDst = GL_ONE; + blendConfigs[9].funcSrc = GL_ONE; + blendConfigs[9].funcDst = GL_ZERO; + blendConfigs[10].funcSrc = GL_ZERO; + blendConfigs[10].funcDst = GL_ONE; + blendConfigs[11].funcSrc = GL_ZERO; + blendConfigs[11].funcDst = GL_ZERO; + + std::vector configList(blendConfigs, blendConfigs + DE_LENGTH_OF_ARRAY(blendConfigs)); + + return configList; +} + +struct TestRenderPassConfig +{ + TestRenderPassConfig (void) + : testFunction (false) {} + + TestRenderPassConfig (const TextureSourcesType textureSourcesTypeValue, + FBOConfig fboConfigListValue, + const FramebufferSRGB framebufferSRGBValue, + const FramebufferBlend framebufferBendValue, + const RendererTask rendererTaskValue) + : textureSourcesType (textureSourcesTypeValue) + , framebufferSRGB (framebufferSRGBValue) + , frameBufferBlend (framebufferBendValue) + , testFunction (false) + , rendererTask (rendererTaskValue) {fboConfigList.push_back(fboConfigListValue);} + + TestRenderPassConfig (const TextureSourcesType textureSourcesTypeValue, + FBOConfig fboConfigListValue, + const FramebufferSRGB framebufferSRGBValue, + const FramebufferBlend framebufferBendValue, + TestFunction testFunctionValue, + const RendererTask rendererTaskValue) + : textureSourcesType (textureSourcesTypeValue) + , framebufferSRGB (framebufferSRGBValue) + , frameBufferBlend (framebufferBendValue) + , testFunction (testFunctionValue) + , rendererTask (rendererTaskValue) {fboConfigList.push_back(fboConfigListValue);} + + TestRenderPassConfig (const TextureSourcesType textureSourcesTypeValue, + std::vector fboConfigListValue, + const FramebufferSRGB framebufferSRGBValue, + const FramebufferBlend framebufferBendValue, + TestFunction testFunctionValue, + const RendererTask rendererTaskValue) + : textureSourcesType (textureSourcesTypeValue) + , fboConfigList (fboConfigListValue) + , framebufferSRGB (framebufferSRGBValue) + , frameBufferBlend (framebufferBendValue) + , testFunction (testFunctionValue) + , rendererTask (rendererTaskValue) {} + + ~TestRenderPassConfig (void) {} + + TextureSourcesType textureSourcesType; + std::vector fboConfigList; + FramebufferSRGB framebufferSRGB; + FramebufferBlend frameBufferBlend; + TestFunction testFunction; + RendererTask rendererTask; +}; + +class TestVertexData +{ +public: + TestVertexData (Context& context); + ~TestVertexData (void); + + void init (void); + + void bind (void) const; + void unbind (void) const; + +private: + const glw::Functions* m_gl; + std::vector m_data; + glw::GLuint m_vboHandle; + glw::GLuint m_vaoHandle; +}; + +TestVertexData::TestVertexData (Context& context) + : m_gl (&context.getRenderContext().getFunctions()) +{ + const glw::GLfloat vertexData[] = + { + // 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 + }; + + m_data.resize(DE_LENGTH_OF_ARRAY(vertexData)); + for (int idx = 0; idx < (int)m_data.size(); idx++) + m_data[idx] = vertexData[idx]; + + m_gl->genVertexArrays(1, &m_vaoHandle); + m_gl->bindVertexArray(m_vaoHandle); + + m_gl->genBuffers(1, &m_vboHandle); + m_gl->bindBuffer(GL_ARRAY_BUFFER, m_vboHandle); + + m_gl->bufferData(GL_ARRAY_BUFFER, (glw::GLsizei)(m_data.size() * sizeof(glw::GLfloat)), &m_data[0], GL_STATIC_DRAW); + + m_gl->enableVertexAttribArray(0); + m_gl->vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * (glw::GLsizei)sizeof(GL_FLOAT), (glw::GLvoid *)0); + m_gl->enableVertexAttribArray(1); + m_gl->vertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * (glw::GLsizei)sizeof(GL_FLOAT), (glw::GLvoid *)(3 * sizeof(GL_FLOAT))); + + m_gl->bindVertexArray(0); + m_gl->bindBuffer(GL_ARRAY_BUFFER, 0); + GLU_EXPECT_NO_ERROR(m_gl->getError(), "gl error during vertex data setup"); +} + +TestVertexData::~TestVertexData (void) +{ + m_gl->deleteBuffers(1, &m_vboHandle); + m_gl->deleteVertexArrays(1, &m_vaoHandle); +} + +void TestVertexData::bind (void) const +{ + m_gl->bindVertexArray(m_vaoHandle); +} + +void TestVertexData::unbind (void) const +{ + m_gl->bindVertexArray(0); +} + +class TestTexture2D +{ +public: + TestTexture2D (Context& context, const deUint32 internalFormatValue, const deUint32 transferFormatValue, const deUint32 transferTypeValue, const tcu::Vec4 imageColorValue, const int idx); + ~TestTexture2D (void); + + int getTextureUnit (void) const; + deUint32 getHandle (void) const; + int getIdx (void) const; + + void bind (const int textureUnit); + void unbind (void) const; + +private: + const glw::Functions* m_gl; + glw::GLuint m_handle; + const deUint32 m_internalFormat; + tcu::TextureFormat m_transferFormat; + int m_width; + int m_height; + tcu::TextureLevel m_imageData; + int m_textureUnit; + const int m_idx; +}; + +TestTexture2D::TestTexture2D (Context& context, const deUint32 internalFormat, const deUint32 transferFormat, const deUint32 transferType, const tcu::Vec4 imageColor, const int idx) + : m_gl (&context.getRenderContext().getFunctions()) + , m_internalFormat (internalFormat) + , m_transferFormat (tcu::TextureFormat(glu::mapGLTransferFormat(transferFormat, transferType))) + , m_width (TestTextureSizes::WIDTH) + , m_height (TestTextureSizes::HEIGHT) + , m_imageData (tcu::TextureLevel(glu::mapGLInternalFormat(internalFormat), m_width, m_height, 1)) + , m_idx (idx) +{ + // fill image data with a solid test color + tcu::clear(m_imageData.getAccess(), tcu::Vec4(0.0f)); + for (int py = 0; py < m_imageData.getHeight(); py++) + { + for (int px = 0; px < m_imageData.getWidth(); px++) + m_imageData.getAccess().setPixel(imageColor, px, py); + } + + m_gl->genTextures(1, &m_handle); + + m_gl->bindTexture(GL_TEXTURE_2D, m_handle); + m_gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); + m_gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + m_gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + m_gl->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + m_gl->texImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_width, m_height, 0, transferFormat, transferType, m_imageData.getAccess().getDataPtr()); + + m_gl->bindTexture(GL_TEXTURE_2D, 0); +} + +TestTexture2D::~TestTexture2D (void) +{ + m_gl->deleteTextures(1, &m_handle); +} + +int TestTexture2D::getTextureUnit (void) const +{ + return m_textureUnit; +} + +deUint32 TestTexture2D::getHandle (void) const +{ + return m_handle; +} + +int TestTexture2D::getIdx (void) const +{ + return m_idx; +} + +void TestTexture2D::bind (const int textureUnit) +{ + m_textureUnit = textureUnit; + m_gl->activeTexture(GL_TEXTURE0 + m_textureUnit); + m_gl->bindTexture(GL_TEXTURE_2D, m_handle); +} + +void TestTexture2D::unbind (void) const +{ + m_gl->bindTexture(GL_TEXTURE_2D, 0); +} + +class TestFramebuffer +{ +public: + TestFramebuffer (void); + TestFramebuffer (Context& context, const deUint32 targetType, const deUint32 colorAttachment, glw::GLuint textureAttachmentHandle, const bool isSRGB, const FboType fboType, const int idx); + ~TestFramebuffer (void); + + void setTargetType (const deUint32 targetType); + + FboType getType (void) const; + deUint32 getHandle (void) const; + deUint32 getColorAttachment (void) const; + int getIdx (void) const; + deUint32 getTargetType (void) const; + + void bind (void); + void unbind (void); + + typedef de::UniquePtr fboUniquePtr; + +private: + const glw::Functions* m_gl; + fboUniquePtr m_referenceSource; + deUint32 m_targetType; + bool m_bound; + bool m_isSRGB; + FboType m_type; + const int m_idx; + deUint32 m_colorAttachment; +}; + +TestFramebuffer::TestFramebuffer (Context& context, const deUint32 targetType, const deUint32 colorAttachment, glw::GLuint textureAttachmentHandle, const bool isSRGB, const FboType fboType, const int idx) + : m_gl (&context.getRenderContext().getFunctions()) + , m_referenceSource (new glu::Framebuffer(context.getRenderContext())) + , m_targetType (targetType) + , m_bound (false) + , m_isSRGB (isSRGB) + , m_type (fboType) + , m_idx (idx) + , m_colorAttachment (colorAttachment) +{ + m_gl->bindFramebuffer(m_targetType, **m_referenceSource); + + m_gl->framebufferTexture2D(m_targetType, m_colorAttachment, GL_TEXTURE_2D, textureAttachmentHandle, 0); + + TCU_CHECK(m_gl->checkFramebufferStatus(m_targetType) == GL_FRAMEBUFFER_COMPLETE); + + if (targetType == GL_DRAW_BUFFER) + { + glw::GLuint textureAttachments[] = {m_colorAttachment}; + m_gl->drawBuffers(DE_LENGTH_OF_ARRAY(textureAttachments), textureAttachments); + GLU_EXPECT_NO_ERROR(m_gl->getError(), "glDrawBuffer()"); + } + + if (targetType == GL_READ_BUFFER) + { + m_gl->readBuffer(m_colorAttachment); + GLU_EXPECT_NO_ERROR(m_gl->getError(), "glReadBuffer()"); + } + + m_gl->bindFramebuffer(m_targetType, 0); +} + +TestFramebuffer::~TestFramebuffer (void) +{ +} + +void TestFramebuffer::setTargetType (const deUint32 targetType) +{ + m_targetType = targetType; +} + +FboType TestFramebuffer::getType (void) const +{ + return m_type; +} + +deUint32 TestFramebuffer::getHandle (void) const +{ + return **m_referenceSource; +} + +deUint32 TestFramebuffer::getColorAttachment (void) const +{ + return m_colorAttachment; +} + +int TestFramebuffer::getIdx (void) const +{ + return m_idx; +} + +deUint32 TestFramebuffer::getTargetType (void) const +{ + return m_targetType; +} + +void TestFramebuffer::bind (void) +{ + if (!m_bound) + { + m_gl->bindFramebuffer(m_targetType, **m_referenceSource); + m_bound = true; + } +} + +void TestFramebuffer::unbind (void) +{ + if (m_bound) + { + m_gl->bindFramebuffer(m_targetType, 0); + m_bound = false; + } +} + +class TestShaderProgram +{ +public: + TestShaderProgram (Context& context, const int samplerTotal, TestFunction testFunction); + ~TestShaderProgram (void); + + glw::GLuint getHandle (void) const; + int getSamplerTotal (void) const; + + void use (void) const; + void unuse (void) const; + + glu::ShaderProgramInfo getLogInfo (void); + +private: + const glw::Functions* m_gl; + de::MovePtr m_referenceSource; + const int m_samplerTotal; + const int m_shaderStagesTotal; +}; + +TestShaderProgram::TestShaderProgram (Context& context, const int samplerTotal, TestFunction testFunction) + : m_gl (&context.getRenderContext().getFunctions()) + , m_samplerTotal (samplerTotal) + , m_shaderStagesTotal (2) +{ + std::ostringstream shaderFragment; + + const char* const 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.0f); \n" + " vs_aTexCoord = aTexCoord; \n" + "} \n"; + + shaderFragment + << "#version 310 es \n" + << "in mediump vec2 vs_aTexCoord; \n" + << "layout (location = 0) out mediump vec4 fs_aColor0; \n"; + + for (int samplerIdx = 0; samplerIdx < m_samplerTotal; samplerIdx++) + shaderFragment + << "uniform sampler2D uTexture" << samplerIdx << "; \n"; + + shaderFragment + << "uniform int uFunctionType; \n"; + + if (testFunction.hasFunction) + shaderFragment + << "uniform int uBlendFunctionType; \n" + << "uniform mediump float uFactorSrc; \n" + << "uniform mediump float uFactorDst; \n" + << testFunction.functionDefintion; + + shaderFragment + << "void main () \n" + << "{ \n"; + + for (int samplerIdx = 0; samplerIdx < m_samplerTotal; samplerIdx++) + shaderFragment + <<" mediump vec4 texelColor" << samplerIdx << " = vec4(0.0f, 0.0f, 0.0f, 1.0f); \n"; + + shaderFragment + << buildSamplingPassType(m_samplerTotal); + + if (testFunction.hasFunction) + shaderFragment + << " fs_aColor0 = " << testFunction.functionName << "(texelColor0, texelColor1); \n"; + else + shaderFragment + << " fs_aColor0 = texelColor0; \n"; + + shaderFragment + << "} \n"; + + m_referenceSource = de::MovePtr(new glu::ShaderProgram(context.getRenderContext(), glu::makeVtxFragSources(shaderVertex, shaderFragment.str()))); + if (!m_referenceSource->isOk()) + { + tcu::TestLog& log = context.getTestContext().getLog(); + log << this->getLogInfo(); + TCU_FAIL("Failed to compile shaders and link program"); + } +} + +TestShaderProgram::~TestShaderProgram (void) +{ + m_referenceSource = de::MovePtr(DE_NULL); + m_referenceSource.clear(); +} + +deUint32 TestShaderProgram::getHandle (void) const +{ + return m_referenceSource->getProgram(); +} + +int TestShaderProgram::getSamplerTotal (void) const +{ + return m_samplerTotal; +} + +void TestShaderProgram::use (void) const +{ + m_gl->useProgram(this->getHandle()); +} + +void TestShaderProgram::unuse (void) const +{ + m_gl->useProgram(0); +} + +glu::ShaderProgramInfo TestShaderProgram::getLogInfo (void) +{ + glu::ShaderProgramInfo buildInfo; + + // log shader program info. Only vertex and fragment shaders included + buildInfo.program = m_referenceSource->getProgramInfo(); + for (int shaderIdx = 0; shaderIdx < m_shaderStagesTotal; shaderIdx++) + { + glu::ShaderInfo shaderInfo = m_referenceSource->getShaderInfo(static_cast(static_cast(glu::SHADERTYPE_VERTEX) + static_cast(shaderIdx)), 0); + buildInfo.shaders.push_back(shaderInfo); + } + return buildInfo; +} + +class Renderer +{ +public: + Renderer (Context& context); + ~Renderer (void); + + void init (const TestRenderPassConfig& renderPassConfig, const int renderpass); + void deinit (void); + + void setSamplingType (const SamplingType samplerIdx); + void setBlendIteration (const int blendIteration); + void setFramebufferBlend (const bool blend); + void setFramebufferSRGB (const bool sRGB); + + std::vector getResultsPreDraw (void) const; + std::vector getResultsPostDraw (void) const; + int getBlendConfigCount (void) const; + glu::ShaderProgramInfo getShaderProgramInfo (void); + + void copyFrameBufferTexture (const int srcPx, const int srcPy, const int dstPx, const int dstPy); + void draw (void); + void storeShaderProgramInfo (void); + void logShaderProgramInfo (void); + + typedef de::SharedPtr TextureSp; + typedef de::SharedPtr FboSp; + +private: + void createFBOwithColorAttachment (const std::vector fboConfigList); + void setShaderProgramSamplingType (const int samplerIdx); + void setShaderBlendFunctionType (void); + void setShaderBlendSrcDstValues (void); + void bindActiveTexturesSamplers (void); + void bindAllRequiredSourceTextures (const TextureSourcesType texturesRequired); + void unbindAllSourceTextures (void); + void bindFramebuffer (const int framebufferIdx); + void unbindFramebuffer (const int framebufferIdx); + void enableFramebufferSRGB (void); + void enableFramebufferBlend (void); + bool isFramebufferAttachmentSRGB (const deUint32 targetType, const deUint32 attachment) const; + void readTexels (const int px, const int py, const deUint32 attachment, tcu::Vec4& texelData); + void logState (const deUint32 targetType, const deUint32 attachment, const SamplingType samplingType) const; + + // renderer specific constants initialized during constructor + Context& m_context; + const TestVertexData m_vertexData; + const int m_textureSourceTotal; + + // additional resources monitored by the renderer + std::vector m_blendConfigList; + std::vector m_textureSourceList; + TestRenderPassConfig m_renderPassConfig; + std::vector m_fboTextureList; + TestShaderProgram* m_shaderProgram; + std::vector m_framebufferList; + std::vector m_resultsListPreDraw; + std::vector m_resultsListPostDraw; + + // mutable state variables (internal access only) + bool m_hasShaderProgramInfo; + int m_renderPass; + int m_samplersRequired; + bool m_hasFunction; + bool m_blittingEnabled; + glu::ShaderProgramInfo m_shaderProgramInfo; + + // mutable state variables (external access via setters) + SamplingType m_samplingType; + int m_blendIteration; + bool m_framebufferBlendEnabled; + bool m_framebufferSRGBEnabled; +}; + +Renderer::Renderer (Context& context) + : m_context (context) + , m_vertexData (context) + , m_textureSourceTotal (2) + , m_blendConfigList (getBlendingConfigList()) + , m_hasShaderProgramInfo (false) +{ + TextureSp textureLinear(new TestTexture2D(m_context, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, getTestColorLinear(), 0)); + m_textureSourceList.push_back(textureLinear); + + TextureSp textureSRGB(new TestTexture2D(m_context, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, getTestColorLinear(), 1)); + m_textureSourceList.push_back(textureSRGB); +} + +Renderer::~Renderer (void) +{ + m_textureSourceList.clear(); + this->deinit(); +} + +void Renderer::init (const TestRenderPassConfig& renderPassConfig, const int renderpass) +{ + m_renderPassConfig = renderPassConfig; + m_renderPass = renderpass; + + this->createFBOwithColorAttachment(m_renderPassConfig.fboConfigList); + + if (m_renderPassConfig.textureSourcesType != TEXTURESOURCESTYPE_NONE) + { + if (m_renderPassConfig.textureSourcesType == TEXTURESOURCESTYPE_RGBA || m_renderPassConfig.textureSourcesType == TEXTURESOURCESTYPE_SRGBA) + m_samplersRequired = 1; + else if (m_renderPassConfig.textureSourcesType ==TEXTURESOURCESTYPE_BOTH ) + m_samplersRequired = 2; + else + DE_FATAL("Error: Texture source required not recognised"); + + m_shaderProgram = new TestShaderProgram(m_context, m_samplersRequired, m_renderPassConfig.testFunction); + m_hasFunction = m_renderPassConfig.testFunction.hasFunction; + } + else + m_shaderProgram = DE_NULL; +} + +void Renderer::deinit (void) +{ + if (m_shaderProgram != DE_NULL) + { + delete m_shaderProgram; + m_shaderProgram = DE_NULL; + } + + m_fboTextureList.clear(); + m_framebufferList.clear(); +} + +void Renderer::setSamplingType (const SamplingType samplingType) +{ + m_samplingType = samplingType; +} + +void Renderer::setBlendIteration (const int blendIteration) +{ + m_blendIteration = blendIteration; +} + +void Renderer::setFramebufferBlend (const bool blend) +{ + m_framebufferBlendEnabled = blend; +} + +void Renderer::setFramebufferSRGB (const bool sRGB) +{ + m_framebufferSRGBEnabled = sRGB; +} + +std::vector Renderer::getResultsPreDraw (void) const +{ + return m_resultsListPreDraw; +} + +std::vector Renderer::getResultsPostDraw (void) const +{ + return m_resultsListPostDraw; +} + +int Renderer::getBlendConfigCount (void) const +{ + return (int)m_blendConfigList.size(); +} + +void Renderer::copyFrameBufferTexture (const int srcPx, const int srcPy, const int dstPx, const int dstPy) +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + int fboSrcIdx = -1; + int fboDstIdx = -1; + deUint32 fboSrcColAttachment = GL_NONE; + deUint32 fboDstColAttachment = GL_NONE; + + for (int idx = 0; idx < (int)m_framebufferList.size(); idx++) + this->bindFramebuffer(idx); + + // cache fbo attachments and idx locations + for (int idx = 0; idx < (int)m_framebufferList.size(); idx++) + { + if (m_framebufferList[idx]->getType() == FBOTYPE_SOURCE) + { + fboSrcIdx = m_framebufferList[idx]->getIdx(); + fboSrcColAttachment = m_framebufferList[fboSrcIdx]->getColorAttachment(); + } + if (m_framebufferList[idx]->getType() == FBOTYPE_DESTINATION) + { + fboDstIdx = m_framebufferList[idx]->getIdx(); + fboDstColAttachment = m_framebufferList[fboDstIdx]->getColorAttachment(); + } + } + + for (int idx = 0; idx < (int)m_framebufferList.size(); idx++) + m_framebufferList[idx]->unbind(); + + // store texel data from both src and dst before performing the copy + m_resultsListPreDraw.resize(2); + m_framebufferList[fboSrcIdx]->bind(); + this->readTexels(0, 0, fboSrcColAttachment, m_resultsListPreDraw[0]); + m_framebufferList[fboSrcIdx]->unbind(); + m_framebufferList[fboDstIdx]->setTargetType(GL_READ_FRAMEBUFFER); + m_framebufferList[fboDstIdx]->bind(); + this->readTexels(0, 0, fboDstColAttachment, m_resultsListPreDraw[1]); + m_framebufferList[fboDstIdx]->unbind(); + m_framebufferList[fboDstIdx]->setTargetType(GL_DRAW_FRAMEBUFFER); + + m_framebufferList[fboSrcIdx]->bind(); + m_framebufferList[fboDstIdx]->bind(); + + this->enableFramebufferSRGB(); + this->enableFramebufferBlend(); + + gl.blitFramebuffer( srcPx, srcPy, TestTextureSizes::WIDTH, TestTextureSizes::HEIGHT, + dstPx, dstPy, TestTextureSizes::WIDTH, TestTextureSizes::HEIGHT, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + m_resultsListPostDraw.resize(2); + this->readTexels(0, 0, fboSrcColAttachment, m_resultsListPostDraw[0]); + m_framebufferList[fboSrcIdx]->unbind(); + m_framebufferList[fboDstIdx]->unbind(); + + m_framebufferList[fboDstIdx]->setTargetType(GL_READ_FRAMEBUFFER); + m_framebufferList[fboDstIdx]->bind(); + this->readTexels(0, 0, fboDstColAttachment, m_resultsListPostDraw[1]); + m_framebufferList[fboDstIdx]->unbind(); +} + +void Renderer::draw (void) +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + + if (m_renderPassConfig.textureSourcesType == TEXTURESOURCESTYPE_NONE) + DE_FATAL("Error: Attempted to draw with no texture sources"); + + // resize results storage with each render pass + m_resultsListPreDraw.resize(m_renderPass + 1); + m_resultsListPostDraw.resize(m_renderPass + 1); + + m_shaderProgram->use(); + m_vertexData.bind(); + + for (int idx = 0; idx < (int)m_framebufferList.size(); idx++) + this->bindFramebuffer(idx); + + this->bindAllRequiredSourceTextures(m_renderPassConfig.textureSourcesType); + this->bindActiveTexturesSamplers(); + + this->enableFramebufferSRGB(); + this->enableFramebufferBlend(); + + this->readTexels(0, 0, GL_COLOR_ATTACHMENT0, m_resultsListPreDraw[m_renderPass]); + this->setShaderProgramSamplingType(m_samplingType); + if (m_hasFunction) + { + this->setShaderBlendFunctionType(); + this->setShaderBlendSrcDstValues(); + } + + gl.drawArrays(GL_TRIANGLES, 0, 6); + + this->readTexels(0, 0, GL_COLOR_ATTACHMENT0, m_resultsListPostDraw[m_renderPass]); + this->logState(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_samplingType); + + this->unbindAllSourceTextures(); + for (int idx = 0; idx < (int)m_framebufferList.size(); idx++) + this->unbindFramebuffer(idx); + m_vertexData.unbind(); + m_shaderProgram->unuse(); +} + +void Renderer::storeShaderProgramInfo (void) +{ + m_shaderProgramInfo = m_shaderProgram->getLogInfo(); + m_hasShaderProgramInfo = true; +} + +void Renderer::logShaderProgramInfo (void) +{ + tcu::TestLog& log = m_context.getTestContext().getLog(); + + if (m_hasShaderProgramInfo) + log << m_shaderProgramInfo; +} + +void Renderer::createFBOwithColorAttachment (const std::vector fboConfigList) +{ + const int size = (int)fboConfigList.size(); + for (int idx = 0; idx < size; idx++) + { + TextureSp texture(new TestTexture2D(m_context, fboConfigList[idx].textureInternalFormat, GL_RGBA, GL_UNSIGNED_BYTE, fboConfigList[idx].textureColor, idx)); + m_fboTextureList.push_back(texture); + + bool isSRGB; + if (fboConfigList[idx].textureInternalFormat == GL_SRGB8_ALPHA8) + isSRGB = true; + else + isSRGB = false; + + FboSp framebuffer(new TestFramebuffer(m_context, fboConfigList[idx].fboTargetType, fboConfigList[idx].fboColorAttachment, texture->getHandle(), isSRGB, fboConfigList[idx].fboType, idx)); + m_framebufferList.push_back(framebuffer); + } +} + +void Renderer::setShaderProgramSamplingType (const int samplerIdx) +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + + glw::GLuint location = gl.getUniformLocation(m_shaderProgram->getHandle(), "uFunctionType"); + DE_ASSERT(location != (glw::GLuint)-1); + gl.uniform1i(location, samplerIdx); +} + +void Renderer::setShaderBlendFunctionType (void) +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + + int function = -1; + if (m_blendConfigList[m_blendIteration].equation == GL_FUNC_ADD) + function = 0; + else if (m_blendConfigList[m_blendIteration].equation == GL_FUNC_SUBTRACT) + function = 1; + else if (m_blendConfigList[m_blendIteration].equation == GL_FUNC_REVERSE_SUBTRACT) + function = 2; + else + DE_FATAL("Error: Blend function not recognised"); + + glw::GLuint location = gl.getUniformLocation(m_shaderProgram->getHandle(), "uBlendFunctionType"); + DE_ASSERT(location != (glw::GLuint)-1); + gl.uniform1i(location, function); +} + +void Renderer::setShaderBlendSrcDstValues (void) +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + + float funcSrc; + if (m_blendConfigList[m_blendIteration].funcSrc == GL_ONE) + funcSrc = 1.0f; + else + funcSrc = 0.0f; + + float funcDst; + if (m_blendConfigList[m_blendIteration].funcDst == GL_ONE) + funcDst = 1.0f; + else + funcDst = 0.0f; + + glw::GLuint locationSrc = gl.getUniformLocation(m_shaderProgram->getHandle(), "uFactorSrc"); + gl.uniform1f(locationSrc, funcSrc); + GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1f()"); + + glw::GLuint locationDst = gl.getUniformLocation(m_shaderProgram->getHandle(), "uFactorDst"); + gl.uniform1f(locationDst, funcDst); + GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1f()"); +} + +void Renderer::bindActiveTexturesSamplers (void) +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + + for (int idx = 0; idx < m_samplersRequired; idx++) + { + std::ostringstream stream; + stream << "uTexture" << idx; + std::string uniformName(stream.str()); + glw::GLint location = gl.getUniformLocation(m_shaderProgram->getHandle(), uniformName.c_str()); + DE_ASSERT(location != -1); + gl.uniform1i(location, m_textureSourceList[idx]->getTextureUnit()); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGetUniformLocation()"); + } +} + +void Renderer::bindAllRequiredSourceTextures (const TextureSourcesType texturesRequired) +{ + if (texturesRequired == TEXTURESOURCESTYPE_RGBA) + m_textureSourceList[0]->bind(0); + else if (texturesRequired == TEXTURESOURCESTYPE_SRGBA) + m_textureSourceList[1]->bind(0); + else if (texturesRequired == TEXTURESOURCESTYPE_BOTH) + { + m_textureSourceList[0]->bind(0); + m_textureSourceList[1]->bind(1); + } + else + DE_FATAL("Error: Invalid sources requested in bind all"); +} + +void Renderer::unbindAllSourceTextures (void) +{ + for (int idx = 0; idx < (int)m_textureSourceList.size(); idx++) + m_textureSourceList[idx]->unbind(); +} + +void Renderer::bindFramebuffer (const int framebufferIdx) +{ + m_framebufferList[framebufferIdx]->bind(); +} + +void Renderer::unbindFramebuffer (const int framebufferIdx) +{ + m_framebufferList[framebufferIdx]->unbind(); +} + +void Renderer::enableFramebufferSRGB (void) +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + + if (m_framebufferSRGBEnabled) + gl.enable(GL_FRAMEBUFFER_SRGB); + else + gl.disable(GL_FRAMEBUFFER_SRGB); +} + +void Renderer::enableFramebufferBlend (void) +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + tcu::TestLog& log = m_context.getTestContext().getLog(); + std::ostringstream message; + + message << "Blend settings = "; + + if (m_framebufferBlendEnabled) + { + gl.enable(GL_BLEND); + gl.blendEquation(m_blendConfigList[m_blendIteration].equation); + gl.blendFunc(m_blendConfigList[m_blendIteration].funcSrc, m_blendConfigList[m_blendIteration].funcDst); + + std::string equation, src, dst; + if (m_blendConfigList[m_blendIteration].equation == GL_FUNC_ADD) + equation = "GL_FUNC_ADD"; + if (m_blendConfigList[m_blendIteration].equation == GL_FUNC_SUBTRACT) + equation = "GL_FUNC_SUBTRACT"; + if (m_blendConfigList[m_blendIteration].equation == GL_FUNC_REVERSE_SUBTRACT) + equation = "GL_FUNC_REVERSE_SUBTRACT"; + if (m_blendConfigList[m_blendIteration].funcSrc == GL_ONE) + src = "GL_ONE"; + else + src = "GL_ZERO"; + if (m_blendConfigList[m_blendIteration].funcDst == GL_ONE) + dst = "GL_ONE"; + else + dst = "GL_ZERO"; + + message << "Enabled: equation = " << equation << ", func src = " << src << ", func dst = " << dst; + } + else + { + gl.disable(GL_BLEND); + message << "Disabled"; + } + + log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage; +} + +bool Renderer::isFramebufferAttachmentSRGB (const deUint32 targetType, const deUint32 attachment) const +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + glw::GLint encodingType; + + gl.getFramebufferAttachmentParameteriv(targetType, attachment, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &encodingType); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGetNamedFramebufferAttachmentParameteriv()"); + + switch (static_cast(encodingType)) + { + case GL_SRGB: + { + return true; + break; + } + case GL_LINEAR: + { + return false; + break; + } + default: + { + DE_FATAL("Error: Color attachment format not recognised"); + return false; + } + } +} + +void Renderer::readTexels (const int px, const int py, const deUint32 mode, tcu::Vec4& texelData) +{ + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + tcu::TextureLevel textureRead; + + // ensure result sampling coordinates are within range of the result color attachment + DE_ASSERT((px >= 0) && (px < m_context.getRenderTarget().getWidth())); + DE_ASSERT((py >= 0) && (py < m_context.getRenderTarget().getHeight())); + + gl.readBuffer(mode); + textureRead.setStorage(glu::mapGLTransferFormat(GL_RGBA, GL_UNSIGNED_BYTE), TestTextureSizes::WIDTH, TestTextureSizes::HEIGHT); + glu::readPixels(m_context.getRenderContext(), px, py, textureRead.getAccess()); + GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels()"); + texelData = textureRead.getAccess().getPixel(px, py); +} + +void Renderer::logState (const deUint32 targetType, const deUint32 attachment, const SamplingType samplingType) const +{ + tcu::TestLog& log = m_context.getTestContext().getLog(); + std::ostringstream message; + + bool fboAttachmentSRGB = this->isFramebufferAttachmentSRGB(targetType, attachment); + message.str(""); + message << "getFramebufferAttachmentParameteriv() check = "; + if (fboAttachmentSRGB) + message << "GL_SRGB"; + else + message << "GL_LINEAR"; + log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage; + + message.str(""); + message << "Framebuffer color attachment value BEFORE draw call"; + logColor(m_context, message.str(), m_resultsListPreDraw[m_renderPass]); + + message.str(""); + message << "Framebuffer color attachment value AFTER draw call"; + logColor(m_context, message.str(), m_resultsListPostDraw[m_renderPass]); + + message.str(""); + message << "Sampling type = "; + std::string type; + if (samplingType == 0) + type = "texture()"; + else if (samplingType == 1) + type = "textureLOD()"; + else if (samplingType == 2) + type = "textureGrad()"; + else if (samplingType == 3) + type = "textureOffset()"; + else if (samplingType == 4) + type = "textureProj()"; + else + DE_FATAL("Error: Sampling type unregonised"); + message << type; + log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage; + + message.str(""); + if (m_framebufferSRGBEnabled) + message << "Framebuffer SRGB = enabled"; + else + message << "Framebuffer SRGB = disabled"; + log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage; +} + +class FboSRGBTestCase : public TestCase +{ +public: + FboSRGBTestCase (Context& context, const char* const name, const char* const desc); + ~FboSRGBTestCase (void); + + void init (void); + void deinit (void); + IterateResult iterate (void); + + void setTestConfig (std::vector renderPassConfigList); + + virtual void setupTest (void) = 0; + virtual bool verifyResult (void) = 0; + +protected: + bool m_hasTestConfig; + std::vector m_renderPassConfigList; + bool m_testcaseRequiresBlend; + std::vector m_resultsPreDraw; + std::vector m_resultsPostDraw; + +private: + FboSRGBTestCase (const FboSRGBTestCase&); + FboSRGBTestCase& operator= (const FboSRGBTestCase&); +}; + +FboSRGBTestCase::FboSRGBTestCase (Context& context, const char* const name, const char* const desc) + : TestCase (context, name, desc) + , m_hasTestConfig (false) +{ +} + +FboSRGBTestCase::~FboSRGBTestCase (void) +{ + FboSRGBTestCase::deinit(); +} + +void FboSRGBTestCase::init (void) +{ + // extensions requirements for test + if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2))) + TCU_THROW(NotSupportedError, "Test requires a context version equal or higher than 3.2"); + + if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_sRGB_write_control")) + TCU_THROW(NotSupportedError, "Test requires extension GL_EXT_sRGB_write_control"); + + if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_sRGB_decode")) + TCU_THROW(NotSupportedError, "Test requires GL_EXT_texture_sRGB_decode extension"); +} + +void FboSRGBTestCase::deinit (void) +{ +} + +FboSRGBTestCase::IterateResult FboSRGBTestCase::iterate (void) +{ + this->setupTest(); + + DE_ASSERT(m_hasTestConfig && "Error: Renderer was not supplied a test config"); + + Renderer renderer(m_context); + + // loop through each sampling type + for (int samplingIdx = 0; samplingIdx < SampligTypeCount::MAX; samplingIdx++) + { + renderer.setSamplingType(static_cast(samplingIdx)); + + // loop through each blend configuration + const int blendCount = renderer.getBlendConfigCount(); + for (int blendIdx = 0; blendIdx < blendCount; blendIdx++) + { + // loop through each render pass + const int renderPassCount = (int)m_renderPassConfigList.size(); + for (int renderPassIdx = 0; renderPassIdx < renderPassCount; renderPassIdx++) + { + TestRenderPassConfig renderPassConfig = m_renderPassConfigList[renderPassIdx]; + + renderer.init(renderPassConfig, renderPassIdx); + + if (blendIdx == 0 && renderPassConfig.rendererTask == RENDERERTASK_DRAW) + renderer.storeShaderProgramInfo(); + + if (renderPassConfig.frameBufferBlend == FRAMEBUFFERBLEND_ENABLED) + { + renderer.setBlendIteration(blendIdx); + renderer.setFramebufferBlend(true); + } + else + renderer.setFramebufferBlend(false); + + if (renderPassConfig.framebufferSRGB == FRAMEBUFFERSRGB_ENABLED) + renderer.setFramebufferSRGB(true); + else + renderer.setFramebufferSRGB(false); + + if (renderPassConfig.rendererTask == RENDERERTASK_DRAW) + renderer.draw(); + else if (renderPassConfig.rendererTask == RENDERERTASK_COPY) + renderer.copyFrameBufferTexture(0, 0, 0, 0); + else + DE_FATAL("Error: render task not recognised"); + + renderer.deinit(); + + } // render passes + + m_resultsPreDraw = renderer.getResultsPreDraw(); + m_resultsPostDraw = renderer.getResultsPostDraw(); + + bool testPassed = this->verifyResult(); + if (testPassed) + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + else + { + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result verification failed"); + renderer.logShaderProgramInfo(); + return STOP; + } + + if (!m_testcaseRequiresBlend) + break; + } // blend configs + + renderer.logShaderProgramInfo(); + } // sampling types + + return STOP; +} + +void FboSRGBTestCase::setTestConfig (std::vector renderPassConfigList) +{ + m_renderPassConfigList = renderPassConfigList; + m_hasTestConfig = true; + + for (int idx = 0; idx < (int)renderPassConfigList.size(); idx++) + { + if (renderPassConfigList[idx].frameBufferBlend == FRAMEBUFFERBLEND_ENABLED) + { + m_testcaseRequiresBlend = true; + return; + } + } + m_testcaseRequiresBlend = false; +} + +class FboSRGBQueryCase : public TestCase +{ +public: + FboSRGBQueryCase (Context& context, const char* const name, const char* const description); + ~FboSRGBQueryCase (void); + + void init (void); + void deinit (void); + IterateResult iterate (void); +}; + +FboSRGBQueryCase::FboSRGBQueryCase (Context& context, const char* const name, const char* const description) + : TestCase (context, name, description) +{ +} + +FboSRGBQueryCase::~FboSRGBQueryCase (void) +{ + FboSRGBQueryCase::deinit(); +} + +void FboSRGBQueryCase::init (void) +{ + // extension requirements for test + if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) && !m_context.getContextInfo().isExtensionSupported("GL_EXT_sRGB_write_control")) + TCU_THROW(NotSupportedError, "Test requires extension GL_EXT_sRGB_write_control or a context version equal or higher than 3.2"); +} + +void FboSRGBQueryCase::deinit (void) +{ +} + +FboSRGBQueryCase::IterateResult FboSRGBQueryCase::iterate (void) +{ + // TEST INFO: + // API tests which check when querying FRAMEBUFFER_SRGB_EXT capability returns the correct information when using glEnabled() or glDisabled() + + const glw::Functions& gl = m_context.getRenderContext().getFunctions(); + tcu::TestLog& log = m_context.getTestContext().getLog(); + const char* const msgPart = ", after disabling = "; + + for (int idx = 0; idx < static_cast(QUERYTYPE_LAST); idx++) + { + std::ostringstream message; + bool pass = false; + + message << std::string("Results: After Enabling = "); + + gl.enable(GL_FRAMEBUFFER_SRGB); + + switch (static_cast(idx)) + { + case QUERYTYPE_ISENABLED: + { + glw::GLboolean enabled[2]; + enabled[0] = gl.isEnabled(GL_FRAMEBUFFER_SRGB); + gl.disable(GL_FRAMEBUFFER_SRGB); + enabled[1] = gl.isEnabled(GL_FRAMEBUFFER_SRGB); + + message << static_cast(enabled[0]) << msgPart << static_cast(enabled[1]); + pass = (enabled[0] && !(enabled[1])) ? true : false; + break; + } + case QUERYTYPE_BOOLEAN: + { + glw::GLboolean enabled[2]; + gl.getBooleanv(GL_FRAMEBUFFER_SRGB,&enabled[0]); + gl.disable(GL_FRAMEBUFFER_SRGB); + gl.getBooleanv(GL_FRAMEBUFFER_SRGB,&enabled[1]); + + message << static_cast(enabled[0]) << msgPart << static_cast(enabled[1]); + pass = (enabled[0] && !(enabled[1])) ? true : false; + break; + } + case QUERYTYPE_FLOAT: + { + glw::GLfloat enabled[2]; + gl.getFloatv(GL_FRAMEBUFFER_SRGB, &enabled[0]); + gl.disable(GL_FRAMEBUFFER_SRGB); + gl.getFloatv(GL_FRAMEBUFFER_SRGB, &enabled[1]); + + message << static_cast(enabled[0]) << msgPart << static_cast(enabled[1]); + pass = ((int)enabled[0] && !((int)enabled[1])) ? true : false; + break; + } + case QUERYTYPE_INT: + { + glw::GLint enabled[2]; + gl.getIntegerv(GL_FRAMEBUFFER_SRGB, &enabled[0]); + gl.disable(GL_FRAMEBUFFER_SRGB); + gl.getIntegerv(GL_FRAMEBUFFER_SRGB, &enabled[1]); + + message << static_cast(enabled[0]) << msgPart << static_cast(enabled[1]); + pass = (enabled[0] && !(enabled[1])) ? true : false; + break; + } + case QUERYTYPE_INT64: + { + glw::GLint64 enabled[2]; + gl.getInteger64v(GL_FRAMEBUFFER_SRGB, &enabled[0]); + gl.disable(GL_FRAMEBUFFER_SRGB); + gl.getInteger64v(GL_FRAMEBUFFER_SRGB, &enabled[1]); + + message << static_cast(enabled[0]) << msgPart << static_cast(enabled[1]); + pass = (enabled[0] && !(enabled[1])) ? true : false; + break; + } + default: + DE_FATAL("Error: Datatype not recognised"); + } + + log << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage; + + if (pass) + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + else + { + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result verification failed"); + return STOP; + } + } + return STOP; +} + +class FboSRGBColAttachCase : public FboSRGBTestCase +{ +public: + FboSRGBColAttachCase (Context& context, const char* const name, const char* const description) + : FboSRGBTestCase (context, name, description) {} + ~FboSRGBColAttachCase (void) {} + + void setupTest (void); + bool verifyResult (void); +}; + +void FboSRGBColAttachCase::setupTest (void) +{ + // TEST INFO: + // Check if FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING set to SRGB and FRAMEBUFFER_SRGB_EXT enabled, destination colors are converted from SRGB to linear + // before and after blending, finally the result is converted back to SRGB for storage + + // NOTE: + // if fbo pre-draw color set to linaer, color values get linearlized "twice" + // (0.2f, 0.3f, 0.4f, 1.0f) when sampled i.e. converted in shader = (0.0331048f, 0.073239f, 0.132868f) + // resulting in the follolwing blending equation (0.2f, 0.3f, 0.4f 1.0f) + (0.0331048, 0.073239, 0.132868) = (0.521569f, 0.647059f, 0.756863f, 1.0f) + + FBOConfig fboConfig0 = FBOConfig(GL_SRGB8_ALPHA8, getTestColorLinear(), GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FBOTYPE_SOURCE); + FBOConfig fboConfig1 = FBOConfig(GL_RGBA8, getTestColorLinear(), GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FBOTYPE_SOURCE); + + const TestRenderPassConfig renderPassConfigs[] = + { + TestRenderPassConfig(TEXTURESOURCESTYPE_RGBA, fboConfig0, FRAMEBUFFERSRGB_ENABLED, FRAMEBUFFERBLEND_ENABLED, RENDERERTASK_DRAW), + TestRenderPassConfig(TEXTURESOURCESTYPE_BOTH, fboConfig1, FRAMEBUFFERSRGB_DISABLED, FRAMEBUFFERBLEND_DISABLED, getFunctionBlendLinearToSRGBCheck(), RENDERERTASK_DRAW) + }; + std::vector renderPassConfigList(renderPassConfigs, renderPassConfigs + DE_LENGTH_OF_ARRAY(renderPassConfigs)); + + this->setTestConfig(renderPassConfigList); +} + +bool FboSRGBColAttachCase::verifyResult (void) +{ + if (tcu::boolAll(tcu::lessThan(tcu::abs(m_resultsPostDraw[0] - m_resultsPostDraw[1]), getEpsilonError())) || tcu::boolAll(tcu::equal(m_resultsPostDraw[0], m_resultsPostDraw[1]))) + return true; + else + return false; +} + +class FboSRGBToggleBlendCase : public FboSRGBTestCase +{ +public: + FboSRGBToggleBlendCase (Context& context, const char* const name, const char* const description) + : FboSRGBTestCase (context, name, description) {} + ~FboSRGBToggleBlendCase (void) {} + + void setupTest (void); + bool verifyResult (void); +}; + +void FboSRGBToggleBlendCase::setupTest (void) +{ + // TEST INFO: + // Test to check if changing FRAMEBUFFER_SRGB_EXT from enabled to disabled. Enabled should produce SRGB color whilst disabled + // should produce linear color. Test conducted with blending disabled. + + FBOConfig fboConfig0 = FBOConfig(GL_SRGB8_ALPHA8, getTestColorLinear(), GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FBOTYPE_DESTINATION); + + const TestRenderPassConfig renderPassConfigs[] = + { + TestRenderPassConfig(TEXTURESOURCESTYPE_RGBA, fboConfig0, FRAMEBUFFERSRGB_ENABLED, FRAMEBUFFERBLEND_DISABLED, TestFunction(false), RENDERERTASK_DRAW), + TestRenderPassConfig(TEXTURESOURCESTYPE_RGBA, fboConfig0, FRAMEBUFFERSRGB_DISABLED, FRAMEBUFFERBLEND_DISABLED, TestFunction(false), RENDERERTASK_DRAW) + }; + std::vector renderPassConfigList(renderPassConfigs, renderPassConfigs + DE_LENGTH_OF_ARRAY(renderPassConfigs)); + + this->setTestConfig(renderPassConfigList); +} + +bool FboSRGBToggleBlendCase::verifyResult (void) +{ + if (tcu::boolAny(tcu::greaterThan(tcu::abs(m_resultsPostDraw[0] - m_resultsPostDraw[1]), getEpsilonError()))) + return true; + else + return false; +} + +class FboSRGBRenderTargetIgnoreCase : public FboSRGBTestCase +{ +public: + FboSRGBRenderTargetIgnoreCase (Context& context, const char* const name, const char* const description) + : FboSRGBTestCase (context, name, description) {} + ~FboSRGBRenderTargetIgnoreCase (void) {} + + void setupTest (void); + bool verifyResult (void); +}; + +void FboSRGBRenderTargetIgnoreCase::setupTest (void) +{ + // TEST INFO: + // Check if render targets that are non-RGB ignore the state of GL_FRAMEBUFFER_SRGB_EXT. Rendering to an fbo with non-sRGB color + // attachment should ignore color space conversion, producing linear color. + + FBOConfig fboConfig0 = FBOConfig(GL_RGBA8, getTestColorBlank(), GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FBOTYPE_DESTINATION); + + const TestRenderPassConfig renderPassConfigs[] = + { + TestRenderPassConfig(TEXTURESOURCESTYPE_RGBA, fboConfig0, FRAMEBUFFERSRGB_ENABLED, FRAMEBUFFERBLEND_DISABLED, TestFunction(false), RENDERERTASK_DRAW) + + }; + std::vector renderPassConfigList(renderPassConfigs, renderPassConfigs + DE_LENGTH_OF_ARRAY(renderPassConfigs)); + + this->setTestConfig(renderPassConfigList); +} + +bool FboSRGBRenderTargetIgnoreCase::verifyResult (void) +{ + if (tcu::boolAll(tcu::lessThan(tcu::abs(m_resultsPostDraw[0] - getTestColorLinear()), getEpsilonError())) || tcu::boolAll(tcu::equal(m_resultsPostDraw[0], getTestColorLinear()))) + return true; + else + return false; +} + +class FboSRGBCopyToLinearCase : public FboSRGBTestCase +{ +public: + FboSRGBCopyToLinearCase (Context& context, const char* const name, const char* const description) + : FboSRGBTestCase (context, name, description) {} + ~FboSRGBCopyToLinearCase (void) {} + + void setupTest (void); + bool verifyResult (void); +}; + +void FboSRGBCopyToLinearCase::setupTest (void) +{ + // TEST INFO: + // Check if copying from an fbo with an sRGB color attachment to an fbo with a linear color attachment with FRAMEBUFFER_EXT enabled results in + // an sRGB to linear conversion + + FBOConfig fboConfigs[] = + { + FBOConfig(GL_SRGB8_ALPHA8, getTestColorSRGB(), GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FBOTYPE_SOURCE), + FBOConfig(GL_RGBA8, getTestColorBlank(), GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FBOTYPE_DESTINATION) + }; + std::vector fboConfigList(fboConfigs, fboConfigs + DE_LENGTH_OF_ARRAY(fboConfigs)); + + const TestRenderPassConfig renderPassConfigs[] = + { + TestRenderPassConfig(TEXTURESOURCESTYPE_NONE, fboConfigList, FRAMEBUFFERSRGB_ENABLED, FRAMEBUFFERBLEND_DISABLED, TestFunction(false), RENDERERTASK_COPY) + }; + std::vector renderPassConfigList(renderPassConfigs, renderPassConfigs + DE_LENGTH_OF_ARRAY(renderPassConfigs)); + + this->setTestConfig(renderPassConfigList); +} + +bool FboSRGBCopyToLinearCase::verifyResult (void) +{ + logColor(m_context, "pre-copy source fbo color values", m_resultsPreDraw[0]); + logColor(m_context, "pre-copy destination fbo color values", m_resultsPreDraw[1]); + logColor(m_context, "post-copy source fbo color values", m_resultsPostDraw[0]); + logColor(m_context, "post-copy destination fbo color values", m_resultsPostDraw[1]); + + if (tcu::boolAll(tcu::lessThan(tcu::abs(m_resultsPostDraw[1] - getTestColorLinear()), getEpsilonError())) || tcu::boolAll(tcu::equal(m_resultsPostDraw[1], getTestColorLinear()))) + return true; + else + return false; +} + +} // anonymous + +FboSRGBWriteControlTests::FboSRGBWriteControlTests (Context& context) + : TestCaseGroup (context, "srgb_write_control", "Colorbuffer tests") +{ +} + +FboSRGBWriteControlTests::~FboSRGBWriteControlTests (void) +{ +} + +void FboSRGBWriteControlTests::init (void) +{ + this->addChild(new FboSRGBQueryCase (m_context, "framebuffer_srgb_enabled", "srgb enable framebuffer")); + this->addChild(new FboSRGBColAttachCase (m_context, "framebuffer_srgb_enabled_col_attach", "srgb enable color attachment and framebuffer")); + this->addChild(new FboSRGBToggleBlendCase (m_context, "framebuffer_srgb_enabled_blend", "toggle framebuffer srgb settings with blend disabled")); + this->addChild(new FboSRGBRenderTargetIgnoreCase (m_context, "framebuffer_srgb_enabled_render_target_ignore", "enable framebuffer srgb, non-srgb render target should ignore")); + this->addChild(new FboSRGBCopyToLinearCase (m_context, "framebuffer_srgb_enabled_copy_to_linear", "no conversion when blittering between framebuffer srgb and linear")); +} + +} +} // gles31 +} // deqp diff --git a/modules/gles31/functional/es31fFboSRGBWriteControlTests.hpp b/modules/gles31/functional/es31fFboSRGBWriteControlTests.hpp new file mode 100644 index 0000000..a4e0f17 --- /dev/null +++ b/modules/gles31/functional/es31fFboSRGBWriteControlTests.hpp @@ -0,0 +1,53 @@ +#ifndef _ES31FFBOSRGBWRITECONTROLTESTS_HPP +#define _ES31FFBOSRGBWRITECONTROLTESTS_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 FBO sRGB tests. + *//*--------------------------------------------------------------------*/ + +#include "tcuDefs.hpp" +#include "tes31TestCase.hpp" + +namespace deqp +{ +namespace gles31 +{ +namespace Functional +{ + +class FboSRGBWriteControlTests : public TestCaseGroup +{ +public: + FboSRGBWriteControlTests (Context& context); + ~FboSRGBWriteControlTests (void); + + void init (void); + +private: + FboSRGBWriteControlTests (const FboSRGBWriteControlTests & other); + FboSRGBWriteControlTests& operator= (const FboSRGBWriteControlTests & other); +}; + +} // Functional +} // gles31 +} // deqp + +#endif // _ES31FFBOSRGBWRITECONTROLTESTS_HPP \ No newline at end of file diff --git a/modules/gles31/functional/es31fFunctionalTests.cpp b/modules/gles31/functional/es31fFunctionalTests.cpp index b2bdac6..8e2a3c6 100644 --- a/modules/gles31/functional/es31fFunctionalTests.cpp +++ b/modules/gles31/functional/es31fFunctionalTests.cpp @@ -76,6 +76,7 @@ #include "es31fDebugTests.hpp" #include "es31fFboColorbufferTests.hpp" #include "es31fFboNoAttachmentTests.hpp" +#include "es31fFboSRGBWriteControlTests.hpp" #include "es31fProgramInterfaceQueryTests.hpp" #include "es31fTextureGatherTests.hpp" #include "es31fTextureFormatTests.hpp" @@ -294,6 +295,7 @@ public: addChild(new FboColorTests (m_context)); addChild(createFboNoAttachmentTests (m_context)); addChild(createFboNoAttachmentCompletenessTests (m_context)); + addChild(new FboSRGBWriteControlTests (m_context)); } }; -- 2.7.4