--- /dev/null
+/*-------------------------------------------------------------------------
+ * 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 EXT Shader Framebuffer Fetch Tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "es31fShaderFramebufferFetchTests.hpp"
+#include "es31fFboTestUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuSurface.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuImageCompare.hpp"
+#include "tcuVectorUtil.hpp"
+
+#include "gluShaderProgram.hpp"
+#include "gluPixelTransfer.hpp"
+#include "gluTextureUtil.hpp"
+#include "gluContextInfo.hpp"
+#include "gluObjectWrapper.hpp"
+
+#include "glwFunctions.hpp"
+#include "glwEnums.hpp"
+
+#include "deStringUtil.hpp"
+
+#include <vector>
+
+namespace deqp
+{
+namespace gles31
+{
+namespace Functional
+{
+namespace
+{
+
+using std::vector;
+using std::string;
+using tcu::TestLog;
+
+using namespace glw;
+using namespace FboTestUtil;
+
+static void checkExtensionSupport (Context& context, const char* extName)
+{
+ if (!context.getContextInfo().isExtensionSupported(extName))
+ throw tcu::NotSupportedError(string(extName) + " not supported");
+}
+
+static void checkFramebufferFetchSupport (Context& context)
+{
+ checkExtensionSupport(context, "GL_EXT_shader_framebuffer_fetch");
+}
+
+static bool isRequiredFormat (deUint32 format, glu::RenderContext& renderContext)
+{
+ const bool isES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
+ switch (format)
+ {
+ // Color-renderable formats
+ case GL_RGBA32I:
+ case GL_RGBA32UI:
+ case GL_RGBA16I:
+ case GL_RGBA16UI:
+ case GL_RGBA8:
+ case GL_RGBA8I:
+ case GL_RGBA8UI:
+ case GL_SRGB8_ALPHA8:
+ case GL_RGB10_A2:
+ case GL_RGB10_A2UI:
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB8:
+ case GL_RGB565:
+ case GL_RG32I:
+ case GL_RG32UI:
+ case GL_RG16I:
+ case GL_RG16UI:
+ case GL_RG8:
+ case GL_RG8I:
+ case GL_RG8UI:
+ case GL_R32I:
+ case GL_R32UI:
+ case GL_R16I:
+ case GL_R16UI:
+ case GL_R8:
+ case GL_R8I:
+ case GL_R8UI:
+ return true;
+
+ // Float format
+ case GL_RGBA32F:
+ case GL_RGB32F:
+ case GL_R11F_G11F_B10F:
+ case GL_RG32F:
+ case GL_R32F:
+ return isES32;
+
+ default:
+ return false;
+ }
+}
+
+tcu::TextureFormat getReadPixelFormat (const tcu::TextureFormat& format)
+{
+ switch (tcu::getTextureChannelClass(format.type))
+ {
+ case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+ return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32);
+
+ case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+ return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32);
+
+ case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+ case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+ return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
+
+ case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+ return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
+
+ default:
+ DE_ASSERT(false);
+ return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
+ }
+}
+
+tcu::Vec4 getFixedPointFormatThreshold (const tcu::TextureFormat& sourceFormat, const tcu::TextureFormat& readPixelsFormat)
+{
+ DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
+ DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
+
+ DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
+ DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
+
+ DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
+ DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
+
+ const tcu::IVec4 srcBits = tcu::getTextureFormatBitDepth(sourceFormat);
+ const tcu::IVec4 readBits = tcu::getTextureFormatBitDepth(readPixelsFormat);
+
+ return tcu::Vec4(3.0f) / ((tcu::Vector<deUint64, 4>(1) << (tcu::min(srcBits, readBits).cast<deUint64>())) - tcu::Vector<deUint64, 4>(1)).cast<float>();
+}
+
+tcu::UVec4 getFloatULPThreshold (const tcu::TextureFormat& sourceFormat, const tcu::TextureFormat& readPixelsFormat)
+{
+ const tcu::IVec4 srcMantissaBits = tcu::getTextureFormatMantissaBitDepth(sourceFormat);
+ const tcu::IVec4 readMantissaBits = tcu::getTextureFormatMantissaBitDepth(readPixelsFormat);
+ tcu::IVec4 ULPDiff(0);
+
+ for (int i = 0; i < 4; i++)
+ if (readMantissaBits[i] >= srcMantissaBits[i])
+ ULPDiff[i] = readMantissaBits[i] - srcMantissaBits[i];
+
+ return tcu::UVec4(4) * (tcu::UVec4(1) << (ULPDiff.cast<deUint32>()));
+}
+
+static bool isAnyExtensionSupported (Context& context, const std::vector<std::string>& requiredExts)
+{
+ for (std::vector<std::string>::const_iterator iter = requiredExts.begin(); iter != requiredExts.end(); iter++)
+ {
+ const std::string& extension = *iter;
+
+ if (context.getContextInfo().isExtensionSupported(extension.c_str()))
+ return true;
+ }
+
+ return false;
+}
+
+static std::string getColorOutputType(tcu::TextureFormat format)
+{
+ switch (tcu::getTextureChannelClass(format.type))
+ {
+ case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: return "uvec4";
+ case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: return "ivec4";
+ case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+ case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+ case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: return "vec4";
+ default:
+ DE_FATAL("Unsupported TEXTURECHANNELCLASS");
+ return "";
+ }
+}
+
+static std::vector<std::string> getEnablingExtensions (deUint32 format, glu::RenderContext& renderContext)
+{
+ const bool isES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
+ std::vector<std::string> out;
+
+ DE_ASSERT(!isRequiredFormat(format, renderContext));
+
+ switch (format)
+ {
+ case GL_RGB16F:
+ out.push_back("GL_EXT_color_buffer_half_float");
+ break;
+
+ case GL_RGBA16F:
+ case GL_RG16F:
+ case GL_R16F:
+ out.push_back("GL_EXT_color_buffer_half_float");
+
+ case GL_RGBA32F:
+ case GL_RGB32F:
+ case GL_R11F_G11F_B10F:
+ case GL_RG32F:
+ case GL_R32F:
+ if (!isES32)
+ out.push_back("GL_EXT_color_buffer_float");
+ break;
+
+ default:
+ break;
+ }
+
+ return out;
+}
+
+void checkFormatSupport (Context& context, deUint32 sizedFormat)
+{
+ const bool isCoreFormat = isRequiredFormat(sizedFormat, context.getRenderContext());
+ const std::vector<std::string> requiredExts = (!isCoreFormat) ? getEnablingExtensions(sizedFormat, context.getRenderContext()) : std::vector<std::string>();
+
+ // Check that we don't try to use invalid formats.
+ DE_ASSERT(isCoreFormat || !requiredExts.empty());
+
+ if (!requiredExts.empty() && !isAnyExtensionSupported(context, requiredExts))
+ throw tcu::NotSupportedError("Format not supported");
+}
+
+tcu::Vec4 scaleColorValue (tcu::TextureFormat format, const tcu::Vec4& color)
+{
+ const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(format);
+ const tcu::Vec4 cScale = fmtInfo.valueMax-fmtInfo.valueMin;
+ const tcu::Vec4 cBias = fmtInfo.valueMin;
+
+ return tcu::RGBA(color).toVec() * cScale + cBias;
+}
+
+// Base class for framebuffer fetch test cases
+
+class FramebufferFetchTestCase : public TestCase
+{
+public:
+ FramebufferFetchTestCase (Context& context, const char* name, const char* desc, deUint32 format);
+ ~FramebufferFetchTestCase (void);
+
+ void init (void);
+ void deinit (void);
+
+protected:
+ string genPassThroughVertSource (void);
+ virtual glu::ProgramSources genShaderSources (void);
+
+ void genFramebufferWithTexture (const tcu::Vec4& color);
+ void genAttachementTexture (const tcu::Vec4& color);
+ void genUniformColor (const tcu::Vec4& color);
+
+ void render (void);
+ void verifyRenderbuffer (TestLog& log, const tcu::TextureFormat& format, const tcu::TextureLevel& reference, const tcu::TextureLevel& result);
+
+ const glw::Functions& m_gl;
+ const deUint32 m_format;
+
+ glu::ShaderProgram* m_program;
+ GLuint m_framebuffer;
+ GLuint m_texColorBuffer;
+
+ tcu::TextureFormat m_texFmt;
+ glu::TransferFormat m_transferFmt;
+ bool m_isFilterable;
+
+ enum
+ {
+ VIEWPORT_WIDTH = 64,
+ VIEWPORT_HEIGHT = 64,
+ };
+};
+
+FramebufferFetchTestCase::FramebufferFetchTestCase (Context& context, const char* name, const char* desc, deUint32 format)
+ : TestCase (context, name, desc)
+ , m_gl (m_context.getRenderContext().getFunctions())
+ , m_format (format)
+ , m_program (DE_NULL)
+ , m_framebuffer (0)
+ , m_texColorBuffer (0)
+ , m_texFmt (glu::mapGLInternalFormat(m_format))
+ , m_transferFmt (glu::getTransferFormat(m_texFmt))
+ , m_isFilterable (glu::isGLInternalColorFormatFilterable(m_format))
+{
+}
+
+FramebufferFetchTestCase::~FramebufferFetchTestCase (void)
+{
+ FramebufferFetchTestCase::deinit();
+}
+
+void FramebufferFetchTestCase::init (void)
+{
+ checkFramebufferFetchSupport (m_context);
+ checkFormatSupport(m_context, m_format);
+
+ DE_ASSERT(!m_program);
+ m_program = new glu::ShaderProgram(m_context.getRenderContext(), genShaderSources());
+
+ m_testCtx.getLog() << *m_program;
+
+ if (!m_program->isOk())
+ {
+ delete m_program;
+ m_program = DE_NULL;
+ TCU_FAIL("Failed to compile shader program");
+ }
+
+ m_gl.useProgram(m_program->getProgram());
+}
+
+void FramebufferFetchTestCase::deinit (void)
+{
+ delete m_program;
+ m_program = DE_NULL;
+
+ if (m_framebuffer)
+ {
+ m_gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
+ m_gl.deleteFramebuffers(1, &m_framebuffer);
+ m_framebuffer = 0;
+ }
+
+ if (m_texColorBuffer)
+ {
+ m_gl.deleteTextures(1, &m_texColorBuffer);
+ m_texColorBuffer = 0;
+ }
+}
+
+string FramebufferFetchTestCase::genPassThroughVertSource (void)
+{
+ std::ostringstream vertShaderSource;
+
+ vertShaderSource << "#version 310 es\n"
+ << "in highp vec4 a_position;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = a_position;\n"
+ << "}\n";
+
+ return vertShaderSource.str();
+}
+
+glu::ProgramSources FramebufferFetchTestCase::genShaderSources (void)
+{
+ const string vecType = getColorOutputType(m_texFmt);
+ std::ostringstream fragShaderSource;
+
+ fragShaderSource << "#version 310 es\n"
+ << "#extension GL_EXT_shader_framebuffer_fetch : require\n"
+ << "layout(location = 0) inout highp " << vecType << " o_color;\n"
+ << "uniform highp " << vecType << " u_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " o_color += u_color;\n"
+ << "}\n";
+
+ return glu::makeVtxFragSources(genPassThroughVertSource(), fragShaderSource.str());
+}
+
+void FramebufferFetchTestCase::genFramebufferWithTexture (const tcu::Vec4& color)
+{
+ m_gl.genFramebuffers(1, &m_framebuffer);
+ m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
+
+ genAttachementTexture(color);
+ GLU_EXPECT_NO_ERROR(m_gl.getError(), "genAttachementTexture()");
+
+ m_gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texColorBuffer, 0);
+ TCU_CHECK(m_gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+}
+
+void FramebufferFetchTestCase::genAttachementTexture (const tcu::Vec4& color)
+{
+ tcu::TextureLevel data (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+
+ m_gl.genTextures(1, &m_texColorBuffer);
+ m_gl.bindTexture(GL_TEXTURE_2D, m_texColorBuffer);
+
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isFilterable ? GL_LINEAR : GL_NEAREST);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isFilterable ? GL_LINEAR : GL_NEAREST);
+
+ clear(data.getAccess(), color);
+
+ m_gl.texImage2D(GL_TEXTURE_2D, 0, m_format, VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 0, m_transferFmt.format, m_transferFmt.dataType, data.getAccess().getDataPtr());
+ m_gl.bindTexture(GL_TEXTURE_2D, 0);
+}
+
+void FramebufferFetchTestCase::verifyRenderbuffer (TestLog& log, const tcu::TextureFormat& format, const tcu::TextureLevel& reference, const tcu::TextureLevel& result)
+{
+ m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+
+ switch (tcu::getTextureChannelClass(format.type))
+ {
+ case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+ {
+ const string name = "Renderbuffer";
+ const string desc = "Compare renderbuffer (floating_point)";
+ const tcu::UVec4 threshold = getFloatULPThreshold(format, result.getFormat());
+
+ if (!tcu::floatUlpThresholdCompare(log, name.c_str(), desc.c_str(), reference, result, threshold, tcu::COMPARE_LOG_RESULT))
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+
+ break;
+ }
+
+ case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+ case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+ {
+ const string name = "Renderbuffer";
+ const string desc = "Compare renderbuffer (integer)";
+ const tcu::UVec4 threshold (1, 1, 1, 1);
+
+ if (!tcu::intThresholdCompare(log, name.c_str(), desc.c_str(), reference, result, threshold, tcu::COMPARE_LOG_RESULT))
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+
+ break;
+ }
+
+ case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+ case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+ {
+ const string name = "Renderbuffer";
+ const string desc = "Compare renderbuffer (fixed point)";
+ const tcu::Vec4 threshold = getFixedPointFormatThreshold(format, result.getFormat());
+
+ if (!tcu::floatThresholdCompare(log, name.c_str(), desc.c_str(), reference, result, threshold, tcu::COMPARE_LOG_RESULT))
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+
+ break;
+ }
+
+ default:
+ {
+ DE_ASSERT(DE_FALSE);
+ m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
+ }
+ }
+}
+
+void FramebufferFetchTestCase::genUniformColor (const tcu::Vec4& color)
+{
+ const GLuint colorLocation = m_gl.getUniformLocation(m_program->getProgram(), "u_color");
+
+ switch (tcu::getTextureChannelClass(m_texFmt.type))
+ {
+ case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+ {
+ m_gl.uniform4uiv(colorLocation, 1, color.asUint().getPtr());
+ break;
+ }
+
+ case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+ {
+ m_gl.uniform4iv(colorLocation, 1, color.asInt().getPtr());
+ break;
+ }
+ case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+ case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+ case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+ {
+ m_gl.uniform4fv(colorLocation, 1, color.asFloat().getPtr());
+ break;
+ }
+ default:
+ DE_ASSERT(DE_FALSE);
+ }
+
+ GLU_EXPECT_NO_ERROR(m_gl.getError(), "genUniformColor()");
+}
+
+void FramebufferFetchTestCase::render (void)
+{
+ const GLfloat coords[] =
+ {
+ -1.0f, -1.0f,
+ +1.0f, -1.0f,
+ +1.0f, +1.0f,
+ -1.0f, +1.0f,
+ };
+
+ const GLushort indices[] =
+ {
+ 0, 1, 2, 2, 3, 0,
+ };
+
+ const GLuint coordLocation = m_gl.getAttribLocation(m_program->getProgram(), "a_position");
+
+ m_gl.viewport(0, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+
+ glu::Buffer coordinatesBuffer(m_context.getRenderContext());
+ glu::Buffer elementsBuffer(m_context.getRenderContext());
+
+ m_gl.bindBuffer(GL_ARRAY_BUFFER, *coordinatesBuffer);
+ m_gl.bufferData(GL_ARRAY_BUFFER, (GLsizeiptr)sizeof(coords), coords, GL_STATIC_DRAW);
+ m_gl.enableVertexAttribArray(coordLocation);
+ m_gl.vertexAttribPointer(coordLocation, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL);
+
+ m_gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *elementsBuffer);
+ m_gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)sizeof(indices), &indices[0], GL_STATIC_DRAW);
+
+ m_gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL);
+ GLU_EXPECT_NO_ERROR(m_gl.getError(), "render()");
+}
+
+// Test description:
+// - Attach texture containing solid color to framebuffer.
+// - Draw full quad covering the entire viewport.
+// - Sum framebuffer read color with passed in uniform color.
+// - Compare resulting surface with reference.
+
+class TextureFormatTestCase : public FramebufferFetchTestCase
+{
+public:
+ TextureFormatTestCase (Context& context, const char* name, const char* desc, deUint32 format);
+ ~TextureFormatTestCase (void) {};
+
+ IterateResult iterate (void);
+
+private:
+ tcu::TextureLevel genReferenceTexture (const tcu::Vec4& fbColor, const tcu::Vec4& uniformColor);
+};
+
+TextureFormatTestCase::TextureFormatTestCase (Context& context, const char* name, const char* desc, deUint32 format)
+ : FramebufferFetchTestCase(context, name, desc, format)
+{
+}
+
+tcu::TextureLevel TextureFormatTestCase::genReferenceTexture (const tcu::Vec4& fbColor, const tcu::Vec4& uniformColor)
+{
+ tcu::TextureLevel reference (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+ tcu::clear(reference.getAccess(), fbColor + uniformColor);
+
+ return reference;
+}
+
+TextureFormatTestCase::IterateResult TextureFormatTestCase::iterate (void)
+{
+ const tcu::Vec4 uniformColor = scaleColorValue(m_texFmt, tcu::Vec4(0.1f, 0.1f, 0.1f, 1.0f));
+ const tcu::Vec4 fbColor = scaleColorValue(m_texFmt, tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f));
+
+ tcu::TextureLevel reference = genReferenceTexture(fbColor, uniformColor);
+ tcu::TextureLevel result (getReadPixelFormat(m_texFmt), VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+
+ genFramebufferWithTexture(fbColor);
+ genUniformColor(uniformColor);
+ render();
+
+ glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
+ verifyRenderbuffer(m_testCtx.getLog(), m_texFmt, reference, result);
+
+ return STOP;
+}
+
+// Test description:
+// - Attach multiple textures containing solid colors to framebuffer.
+// - Draw full quad covering the entire viewport.
+// - For each render target sum framebuffer read color with passed in uniform color.
+// - Compare resulting surfaces with references.
+
+class MultipleRenderTargetsTestCase : public FramebufferFetchTestCase
+{
+public:
+ MultipleRenderTargetsTestCase (Context& context, const char* name, const char* desc, deUint32 format);
+ ~MultipleRenderTargetsTestCase (void);
+
+ IterateResult iterate (void);
+ void deinit (void);
+
+private:
+ void genFramebufferWithTextures (const vector<tcu::Vec4>& colors);
+ void genAttachementTextures (const vector<tcu::Vec4>& colors);
+ tcu::TextureLevel genReferenceTexture (const tcu::Vec4& fbColor, const tcu::Vec4& uniformColor);
+ glu::ProgramSources genShaderSources (void);
+
+ enum
+ {
+ MAX_COLOR_BUFFERS = 4
+ };
+
+ GLuint m_texColorBuffers [MAX_COLOR_BUFFERS];
+ GLenum m_colorBuffers [MAX_COLOR_BUFFERS];
+};
+
+MultipleRenderTargetsTestCase::MultipleRenderTargetsTestCase (Context& context, const char* name, const char* desc, deUint32 format)
+ : FramebufferFetchTestCase(context, name, desc, format)
+ , m_texColorBuffers ()
+{
+ m_colorBuffers[0] = GL_COLOR_ATTACHMENT0;
+ m_colorBuffers[1] = GL_COLOR_ATTACHMENT1;
+ m_colorBuffers[2] = GL_COLOR_ATTACHMENT2;
+ m_colorBuffers[3] = GL_COLOR_ATTACHMENT3;
+}
+
+MultipleRenderTargetsTestCase::~MultipleRenderTargetsTestCase (void)
+{
+ MultipleRenderTargetsTestCase::deinit();
+}
+
+void MultipleRenderTargetsTestCase::deinit (void)
+{
+ // Clean up texture data
+ for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_texColorBuffers); ++i)
+ {
+ if (m_texColorBuffers[i])
+ m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texColorBuffers[i]);
+ }
+
+ FramebufferFetchTestCase::deinit();
+}
+
+void MultipleRenderTargetsTestCase::genFramebufferWithTextures (const vector<tcu::Vec4>& colors)
+{
+ m_gl.genFramebuffers(1, &m_framebuffer);
+ m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
+
+ genAttachementTextures(colors);
+
+ for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_texColorBuffers); ++i)
+ m_gl.framebufferTexture2D(GL_FRAMEBUFFER, m_colorBuffers[i], GL_TEXTURE_2D, m_texColorBuffers[i], 0);
+
+ TCU_CHECK(m_gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+
+ m_gl.drawBuffers((glw::GLsizei)MAX_COLOR_BUFFERS, &m_colorBuffers[0]);
+ GLU_EXPECT_NO_ERROR(m_gl.getError(), "genFramebufferWithTextures()");
+}
+
+void MultipleRenderTargetsTestCase::genAttachementTextures (const vector<tcu::Vec4>& colors)
+{
+ tcu::TextureLevel data (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+
+ m_gl.genTextures(MAX_COLOR_BUFFERS, m_texColorBuffers);
+
+ for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_texColorBuffers); ++i)
+ {
+ m_gl.bindTexture(GL_TEXTURE_2D, m_texColorBuffers[i]);
+
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isFilterable ? GL_LINEAR : GL_NEAREST);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isFilterable ? GL_LINEAR : GL_NEAREST);
+
+ clear(data.getAccess(), colors[i]);
+ m_gl.texImage2D(GL_TEXTURE_2D, 0, m_format, VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 0, m_transferFmt.format, m_transferFmt.dataType, data.getAccess().getDataPtr());
+ }
+
+ m_gl.bindTexture(GL_TEXTURE_2D, 0);
+ GLU_EXPECT_NO_ERROR(m_gl.getError(), "genAttachementTextures()");
+}
+
+tcu::TextureLevel MultipleRenderTargetsTestCase::genReferenceTexture (const tcu::Vec4& fbColor, const tcu::Vec4& uniformColor)
+{
+ tcu::TextureLevel reference (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+ tcu::clear(reference.getAccess(), fbColor + uniformColor);
+
+ return reference;
+}
+
+glu::ProgramSources MultipleRenderTargetsTestCase::genShaderSources (void)
+{
+ const string vecType = getColorOutputType(m_texFmt);
+ std::ostringstream fragShaderSource;
+
+ fragShaderSource << "#version 310 es\n"
+ << "#extension GL_EXT_shader_framebuffer_fetch : require\n"
+ << "layout(location = 0) inout highp " << vecType << " o_color0;\n"
+ << "layout(location = 1) inout highp " << vecType << " o_color1;\n"
+ << "layout(location = 2) inout highp " << vecType << " o_color2;\n"
+ << "layout(location = 3) inout highp " << vecType << " o_color3;\n"
+ << "uniform highp " << vecType << " u_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " o_color0 += u_color;\n"
+ << " o_color1 += u_color;\n"
+ << " o_color2 += u_color;\n"
+ << " o_color3 += u_color;\n"
+ << "}\n";
+
+ return glu::makeVtxFragSources(genPassThroughVertSource(), fragShaderSource.str());
+}
+
+MultipleRenderTargetsTestCase::IterateResult MultipleRenderTargetsTestCase::iterate (void)
+{
+ const tcu::Vec4 uniformColor = scaleColorValue(m_texFmt, tcu::Vec4(0.1f, 0.1f, 0.1f, 1.0f));
+ tcu::TextureLevel result (getReadPixelFormat(m_texFmt), VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+
+ vector<tcu::Vec4> colors;
+ colors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.9f, 0.0f, 0.0f, 1.0f)));
+ colors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.0f, 0.9f, 0.0f, 1.0f)));
+ colors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.0f, 0.0f, 0.9f, 1.0f)));
+ colors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.0f, 0.9f, 0.9f, 1.0f)));
+
+ genFramebufferWithTextures(colors);
+ genUniformColor(uniformColor);
+ render();
+
+ for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_colorBuffers); ++i)
+ {
+ tcu::TextureLevel reference = genReferenceTexture(colors[i], uniformColor);
+
+ m_gl.readBuffer(m_colorBuffers[i]);
+ glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
+ verifyRenderbuffer(m_testCtx.getLog(), m_texFmt, reference, result);
+ }
+
+ return STOP;
+}
+
+// Test description:
+// - Same as TextureFormatTestCase except uses built-in fragment output of ES 2.0
+
+class LastFragDataTestCase : public FramebufferFetchTestCase
+{
+public:
+ LastFragDataTestCase (Context& context, const char* name, const char* desc, deUint32 format);
+ ~LastFragDataTestCase (void) {};
+
+ IterateResult iterate (void);
+
+private:
+ glu::ProgramSources genShaderSources (void);
+ tcu::TextureLevel genReferenceTexture (const tcu::Vec4& fbColor, const tcu::Vec4& uniformColor);
+};
+
+LastFragDataTestCase::LastFragDataTestCase (Context& context, const char* name, const char* desc, deUint32 format)
+ : FramebufferFetchTestCase(context, name, desc, format)
+{
+}
+
+glu::ProgramSources LastFragDataTestCase::genShaderSources (void)
+{
+ const string vecType = getColorOutputType(m_texFmt);
+ std::ostringstream vertShaderSource;
+ std::ostringstream fragShaderSource;
+
+ vertShaderSource << "#version 100\n"
+ << "attribute vec4 a_position;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = a_position;\n"
+ << "}\n";
+
+ fragShaderSource << "#version 100\n"
+ << "#extension GL_EXT_shader_framebuffer_fetch : require\n"
+ << "uniform highp " << vecType << " u_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_FragColor = u_color + gl_LastFragData[0];\n"
+ << "}\n";
+
+ return glu::makeVtxFragSources(vertShaderSource.str(), fragShaderSource.str());
+}
+
+tcu::TextureLevel LastFragDataTestCase::genReferenceTexture (const tcu::Vec4& fbColor, const tcu::Vec4& uniformColor)
+{
+ tcu::TextureLevel reference (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+ tcu::clear(reference.getAccess(), fbColor + uniformColor);
+
+ return reference;
+}
+
+LastFragDataTestCase::IterateResult LastFragDataTestCase::iterate (void)
+{
+ const tcu::Vec4 uniformColor = scaleColorValue(m_texFmt, tcu::Vec4(0.1f, 0.1f, 0.1f, 1.0f));
+ const tcu::Vec4 fbColor = scaleColorValue(m_texFmt, tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f));
+
+ tcu::TextureLevel reference = genReferenceTexture(fbColor, uniformColor);
+ tcu::TextureLevel result (getReadPixelFormat(m_texFmt), VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+
+ genFramebufferWithTexture(fbColor);
+ genUniformColor(uniformColor);
+ render();
+
+ glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
+ verifyRenderbuffer(m_testCtx.getLog(), m_texFmt, reference, result);
+
+ return STOP;
+}
+
+// Test description:
+// - Attach texture containing solid color to framebuffer.
+// - Create one 2D texture for sampler with a grid pattern
+// - Draw full screen quad covering the entire viewport.
+// - Sum color values taken from framebuffer texture and sampled texture
+// - Compare resulting surface with reference.
+
+class TexelFetchTestCase : public FramebufferFetchTestCase
+{
+public:
+ TexelFetchTestCase (Context& context, const char* name, const char* desc, deUint32 format);
+ ~TexelFetchTestCase (void) {}
+
+ IterateResult iterate (void);
+
+private:
+ glu::ProgramSources genShaderSources (void);
+ tcu::TextureLevel genReferenceTexture (const tcu::Vec4& colorEven, const tcu::Vec4& colorOdd, const tcu::Vec4& fbColor);
+ void genSamplerTexture (const tcu::Vec4& colorEven, const tcu::Vec4& colorOdd);
+
+ GLuint m_samplerTexture;
+};
+
+TexelFetchTestCase::TexelFetchTestCase (Context& context, const char* name, const char* desc, deUint32 format)
+ : FramebufferFetchTestCase(context, name, desc, format)
+ , m_samplerTexture(0)
+{
+}
+
+void TexelFetchTestCase::genSamplerTexture (const tcu::Vec4& colorEven, const tcu::Vec4& colorOdd)
+{
+ tcu::TextureLevel data (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+
+ m_gl.activeTexture(GL_TEXTURE1);
+
+ m_gl.genTextures(1, &m_samplerTexture);
+ m_gl.bindTexture(GL_TEXTURE_2D, m_texColorBuffer);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ m_gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ tcu::fillWithGrid(data.getAccess(), 8, colorEven, colorOdd);
+
+ m_gl.texImage2D(GL_TEXTURE_2D, 0, m_format, VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 0, m_transferFmt.format, m_transferFmt.dataType, data.getAccess().getDataPtr());
+ m_gl.bindTexture(GL_TEXTURE_2D, 0);
+
+ const GLuint samplerLocation = m_gl.getUniformLocation(m_program->getProgram(), "u_sampler");
+ m_gl.uniform1i(samplerLocation, 1);
+
+ GLU_EXPECT_NO_ERROR(m_gl.getError(), "genSamplerTexture()");
+}
+
+glu::ProgramSources TexelFetchTestCase::genShaderSources (void)
+{
+ const string vecType = getColorOutputType(m_texFmt);
+ std::ostringstream fragShaderSource;
+
+ fragShaderSource << "#version 310 es\n"
+ << "#extension GL_EXT_shader_framebuffer_fetch : require\n"
+ << "layout(location = 0) inout highp " << vecType << " o_color;\n"
+ << "\n"
+ << "uniform sampler2D u_sampler;\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " o_color += texelFetch(u_sampler, ivec2(gl_FragCoord), 0);\n"
+ << "}\n";
+
+ return glu::makeVtxFragSources(genPassThroughVertSource(), fragShaderSource.str());
+}
+
+tcu::TextureLevel TexelFetchTestCase::genReferenceTexture (const tcu::Vec4& colorEven, const tcu::Vec4& colorOdd, const tcu::Vec4& fbColor)
+{
+ tcu::TextureLevel reference (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+ tcu::fillWithGrid(reference.getAccess(), 8, colorEven + fbColor, colorOdd + fbColor);
+
+ return reference;
+}
+
+TexelFetchTestCase::IterateResult TexelFetchTestCase::iterate (void)
+{
+ const tcu::Vec4 fbColor = scaleColorValue(m_texFmt, tcu::Vec4(0.5f, 0.0f, 0.5f, 1.0f));
+ const tcu::Vec4 colorEven = scaleColorValue(m_texFmt, tcu::Vec4(0.5f, 0.5f, 0.0f, 1.0f));
+ const tcu::Vec4 colorOdd = scaleColorValue(m_texFmt, tcu::Vec4(0.5f, 0.0f, 0.5f, 1.0f));
+
+ genSamplerTexture(colorEven, colorOdd);
+ tcu::TextureLevel reference = genReferenceTexture(colorEven, colorOdd, fbColor);
+ tcu::TextureLevel result (getReadPixelFormat(m_texFmt), VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+
+ genFramebufferWithTexture(fbColor);
+ render();
+
+ glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
+ verifyRenderbuffer(m_testCtx.getLog(), m_texFmt, reference, result);
+
+ // cleanup
+ m_gl.deleteTextures(1, &m_samplerTexture);
+
+ return STOP;
+}
+
+// Test description:
+// - Attach texture containing solid color to framebuffer.
+// - Draw full screen quad covering the entire viewport.
+// - Multiple assignments are made to the output color for fragments on the right vertical half of the screen.
+// - A single assignment is made to the output color for fragments on the left vertical centre of the screen.
+// - Values are calculated using the sum of the passed in uniform color and the previous framebuffer color.
+// - Compare resulting surface with reference.
+
+class MultipleAssignmentTestCase : public FramebufferFetchTestCase
+{
+public:
+ MultipleAssignmentTestCase (Context& context, const char* name, const char* desc, deUint32 format);
+ ~MultipleAssignmentTestCase (void) {}
+
+ IterateResult iterate (void);
+
+private:
+ glu::ProgramSources genShaderSources (void);
+ tcu::TextureLevel genReferenceTexture (const tcu::Vec4& fbColor, const tcu::Vec4& uniformColor);
+};
+
+MultipleAssignmentTestCase::MultipleAssignmentTestCase (Context& context, const char* name, const char* desc, deUint32 format)
+ : FramebufferFetchTestCase(context, name, desc, format)
+{
+}
+
+glu::ProgramSources MultipleAssignmentTestCase::genShaderSources (void)
+{
+ const string vecType = getColorOutputType(m_texFmt);
+ std::ostringstream vertShaderSource;
+ std::ostringstream fragShaderSource;
+
+ vertShaderSource << "#version 310 es\n"
+ << "in highp vec4 a_position;\n"
+ << "out highp vec4 v_position;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = a_position;\n"
+ << " v_position = gl_Position;\n"
+ << "}\n";
+
+ fragShaderSource << "#version 310 es\n"
+ << "#extension GL_EXT_shader_framebuffer_fetch : require\n"
+ << "in highp vec4 v_position;\n"
+ << "layout(location = 0) inout highp " << vecType << " o_color;\n"
+ << "uniform highp " << vecType << " u_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " if (v_position.x > 0.0f)\n"
+ << " o_color += u_color;\n"
+ << "\n"
+ << " o_color += u_color;\n"
+ << "}\n";
+
+ return glu::makeVtxFragSources(vertShaderSource.str(), fragShaderSource.str());
+}
+
+tcu::TextureLevel MultipleAssignmentTestCase::genReferenceTexture (const tcu::Vec4& fbColor, const tcu::Vec4& uniformColor)
+{
+ tcu::TextureLevel reference (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+
+ int width = reference.getAccess().getWidth();
+ int height = reference.getAccess().getHeight();
+ int left = width /2;
+ int top = height/2;
+
+ tcu::Vec4 compositeColor(uniformColor * 2.0f);
+
+ tcu::clear(getSubregion(reference.getAccess(), left, 0, 0, width-left, top, 1), fbColor + compositeColor);
+ tcu::clear(getSubregion(reference.getAccess(), 0, top, 0, left, height-top, 1), fbColor + uniformColor);
+ tcu::clear(getSubregion(reference.getAccess(), left, top, 0, width-left, height-top, 1), fbColor + compositeColor);
+ tcu::clear(getSubregion(reference.getAccess(), 0, 0, 0, left, top, 1), fbColor + uniformColor);
+
+ return reference;
+}
+
+MultipleAssignmentTestCase::IterateResult MultipleAssignmentTestCase::iterate (void)
+{
+ const tcu::Vec4 fbColor = scaleColorValue(m_texFmt, tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f));
+ const tcu::Vec4 uniformColor = scaleColorValue(m_texFmt, tcu::Vec4(0.25f, 0.0f, 0.0f, 1.0f));
+
+ tcu::TextureLevel reference = genReferenceTexture(fbColor, uniformColor);
+ tcu::TextureLevel result (getReadPixelFormat(m_texFmt), VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+
+ genFramebufferWithTexture(fbColor);
+ genUniformColor(uniformColor);
+ render();
+
+ glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
+ verifyRenderbuffer(m_testCtx.getLog(), m_texFmt, reference, result);
+
+ return STOP;
+}
+
+// Test description:
+// - Attach texture containing grid pattern to framebuffer.
+// - Using framebuffer reads discard odd squares in the grid.
+// - The even squares framebuffer color is added to the passed in uniform color.
+
+class FragmentDiscardTestCase : public FramebufferFetchTestCase
+{
+public:
+ FragmentDiscardTestCase (Context& context, const char* name, const char* desc, deUint32 format);
+ ~FragmentDiscardTestCase (void) {}
+
+ IterateResult iterate (void);
+
+private:
+ glu::ProgramSources genShaderSources (void);
+ void genFramebufferWithGrid (const tcu::Vec4& fbColorEven, const tcu::Vec4& fbColorOdd);
+ tcu::TextureLevel genReferenceTexture (const tcu::Vec4& fbColorEven, const tcu::Vec4& fbColorOdd);
+};
+
+FragmentDiscardTestCase::FragmentDiscardTestCase (Context& context, const char* name, const char* desc, deUint32 format)
+ : FramebufferFetchTestCase(context, name, desc, format)
+{
+}
+
+glu::ProgramSources FragmentDiscardTestCase::genShaderSources (void)
+{
+ const string vecType = getColorOutputType(m_texFmt);
+ std::ostringstream fragShaderSource;
+
+ fragShaderSource << "#version 310 es\n"
+ << "#extension GL_EXT_shader_framebuffer_fetch : require\n"
+ << "layout(location = 0) inout highp " << vecType << " o_color;\n"
+ << "uniform highp " << vecType << " u_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " const highp float threshold = 0.0005f;\n"
+ << " bool valuesEqual = all(lessThan(abs(o_color - u_color), vec4(threshold)));\n\n"
+ << " if (valuesEqual)\n"
+ << " o_color += u_color;\n"
+ << " else\n"
+ << " discard;\n"
+ << "}\n";
+
+ return glu::makeVtxFragSources(genPassThroughVertSource(), fragShaderSource.str());
+}
+
+void FragmentDiscardTestCase::genFramebufferWithGrid (const tcu::Vec4& fbColorEven, const tcu::Vec4& fbColorOdd)
+{
+ tcu::TextureLevel data (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+
+ m_gl.genFramebuffers(1, &m_framebuffer);
+ m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
+
+ m_gl.genTextures(1, &m_texColorBuffer);
+ m_gl.bindTexture(GL_TEXTURE_2D, m_texColorBuffer);
+
+ tcu::fillWithGrid(data.getAccess(), 8, fbColorEven, fbColorOdd);
+
+ m_gl.texImage2D(GL_TEXTURE_2D, 0, m_format, VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 0, m_transferFmt.format, m_transferFmt.dataType, data.getAccess().getDataPtr());
+ m_gl.bindTexture(GL_TEXTURE_2D, 0);
+
+ m_gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texColorBuffer, 0);
+ TCU_CHECK(m_gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+}
+
+tcu::TextureLevel FragmentDiscardTestCase::genReferenceTexture (const tcu::Vec4& fbColorEven, const tcu::Vec4& fbColorOdd)
+{
+ tcu::TextureLevel reference (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+ tcu::fillWithGrid(reference.getAccess(), 8, fbColorEven + fbColorEven, fbColorOdd);
+
+ return reference;
+}
+
+FragmentDiscardTestCase::IterateResult FragmentDiscardTestCase::iterate (void)
+{
+ const tcu::Vec4 fbColorEven = scaleColorValue(m_texFmt, tcu::Vec4(0.5f, 0.0f, 1.0f, 1.0f));
+ const tcu::Vec4 fbColorOdd = scaleColorValue(m_texFmt, tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f));
+
+ tcu::TextureLevel reference = genReferenceTexture(fbColorEven, fbColorOdd);
+ tcu::TextureLevel result (getReadPixelFormat(m_texFmt), VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+ genFramebufferWithGrid(fbColorEven, fbColorOdd);
+
+ genUniformColor(fbColorEven);
+ render();
+
+ glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
+ verifyRenderbuffer(m_testCtx.getLog(), m_texFmt, reference, result);
+
+ return STOP;
+}
+
+// Test description:
+// - Create 2D texture array containing three mipmaps.
+// - Each mipmap level is assigned a different color.
+// - Attach single mipmap level to framebuffer and draw full screen quad.
+// - Sum framebuffer read color with passed in uniform color.
+// - Compare resulting surface with reference.
+// - Repeat for subsequent mipmap levels.
+
+class TextureLevelTestCase : public FramebufferFetchTestCase
+{
+public:
+ TextureLevelTestCase (Context& context, const char* name, const char* desc, deUint32 format);
+ ~TextureLevelTestCase (void) {}
+
+ IterateResult iterate (void);
+
+private:
+ void create2DTextureArrayMipMaps (const vector<tcu::Vec4>& colors);
+ tcu::TextureLevel genReferenceTexture (int level, const vector<tcu::Vec4>& colors, const tcu::Vec4& uniformColor);
+ void genReferenceMipmap (int level, const tcu::Vec4& color, tcu::TextureLevel& reference);
+};
+
+TextureLevelTestCase::TextureLevelTestCase (Context& context, const char* name, const char* desc, deUint32 format)
+ : FramebufferFetchTestCase(context, name, desc, format)
+{
+}
+
+void TextureLevelTestCase::create2DTextureArrayMipMaps (const vector<tcu::Vec4>& colors)
+{
+ int numLevels = (int)colors.size();
+ tcu::TextureLevel levelData (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType));
+
+ m_gl.genTextures(1, &m_texColorBuffer);
+ m_gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_texColorBuffer);
+
+ m_gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, m_format, VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1, 0, m_transferFmt.format, m_transferFmt.dataType, DE_NULL);
+ m_gl.generateMipmap(GL_TEXTURE_2D_ARRAY);
+
+ for (int level = 0; level < numLevels; level++)
+ {
+ int levelW = de::max(1, VIEWPORT_WIDTH >> level);
+ int levelH = de::max(1, VIEWPORT_HEIGHT >> level);
+
+ levelData.setSize(levelW, levelH, 1);
+
+ clear(levelData.getAccess(), colors[level]);
+ m_gl.texImage3D(GL_TEXTURE_2D_ARRAY, level, m_format, levelW, levelH, 1, 0, m_transferFmt.format, m_transferFmt.dataType, levelData.getAccess().getDataPtr());
+ }
+
+ m_gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
+ GLU_EXPECT_NO_ERROR(m_gl.getError(), "create2DTextureArrayMipMaps()");
+}
+
+tcu::TextureLevel TextureLevelTestCase::genReferenceTexture (int level, const vector<tcu::Vec4>& colors, const tcu::Vec4& uniformColor)
+{
+ tcu::TextureLevel reference (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+
+ // calculate reference image based on current mipmap level and previously
+ // rendered mipmaps in framebuffer
+ for (int ndx = 0; ndx <= level; ++ndx)
+ genReferenceMipmap(ndx, colors[ndx] + uniformColor, reference);
+
+ return reference;
+}
+
+void TextureLevelTestCase::genReferenceMipmap (int level, const tcu::Vec4& color, tcu::TextureLevel& reference)
+{
+ int width = reference.getAccess().getWidth();
+ int height = reference.getAccess().getHeight();
+ int left = width /2;
+ int top = height/2;
+
+ for (int i = 0; i < level; ++i)
+ {
+ width = de::max(1, width / 2);
+ height = de::max(1, height / 2);
+ left = width /2;
+ top = height/2;
+ }
+
+ clear(getSubregion(reference.getAccess(), left, 0, 0, width-left, top, 1), color);
+ clear(getSubregion(reference.getAccess(), 0, top, 0, left, height-top, 1), color);
+ clear(getSubregion(reference.getAccess(), left, top, 0, width-left, height-top, 1), color);
+ clear(getSubregion(reference.getAccess(), 0, 0, 0, left, top, 1), color);
+}
+
+TextureLevelTestCase::IterateResult TextureLevelTestCase::iterate (void)
+{
+ const tcu::Vec4 uniformColor = scaleColorValue(m_texFmt, tcu::Vec4(0.1f, 0.0f, 0.0f, 1.0f));
+ tcu::TextureLevel result (getReadPixelFormat(m_texFmt), VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+ vector<tcu::Vec4> levelColors;
+
+ levelColors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.4f, 0.0f, 0.0f, 1.0f)));
+ levelColors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.2f, 0.0f, 0.0f, 1.0f)));
+ levelColors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)));
+
+ m_gl.genFramebuffers(1, &m_framebuffer);
+ m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
+
+ create2DTextureArrayMipMaps(levelColors);
+
+ // attach successive mipmap layers to framebuffer and render
+ for (int level = 0; level < (int)levelColors.size(); ++level)
+ {
+ std::ostringstream name, desc;
+ name << "Level " << level;
+ desc << "Mipmap level " << level;
+
+ const tcu::ScopedLogSection section (m_testCtx.getLog(), name.str(), desc.str());
+ tcu::TextureLevel reference = genReferenceTexture(level, levelColors, uniformColor);
+
+ m_gl.framebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texColorBuffer, level);
+
+ genUniformColor(uniformColor);
+ render();
+
+ glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
+ verifyRenderbuffer(m_testCtx.getLog(), m_texFmt, reference, result);
+
+ if (m_testCtx.getTestResult() != QP_TEST_RESULT_PASS)
+ return STOP;
+ }
+
+ return STOP;
+}
+
+class TextureLayerTestCase : public FramebufferFetchTestCase
+{
+public:
+ TextureLayerTestCase (Context& context, const char* name, const char* desc, deUint32 format);
+ ~TextureLayerTestCase (void) {}
+
+ IterateResult iterate (void);
+
+private:
+ void create2DTextureArrayLayers (const vector<tcu::Vec4>& colors);
+ tcu::TextureLevel genReferenceTexture (int layer, const vector<tcu::Vec4>& colors, const tcu::Vec4& uniformColor);
+};
+
+TextureLayerTestCase::TextureLayerTestCase (Context& context, const char* name, const char* desc, deUint32 format)
+ : FramebufferFetchTestCase(context, name, desc, format)
+{
+}
+
+void TextureLayerTestCase::create2DTextureArrayLayers (const vector<tcu::Vec4>& colors)
+{
+ int numLayers = (int)colors.size();
+ tcu::TextureLevel layerData (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType));
+
+ m_gl.genTextures(1, &m_texColorBuffer);
+ m_gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_texColorBuffer);
+ m_gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, m_format, VIEWPORT_WIDTH, VIEWPORT_HEIGHT, numLayers);
+ m_gl.bindImageTexture(0, m_texColorBuffer, 0, GL_FALSE, 0, GL_READ_ONLY, m_format);
+
+ layerData.setSize(VIEWPORT_WIDTH, VIEWPORT_HEIGHT, numLayers);
+
+ for (int layer = 0; layer < numLayers; layer++)
+ {
+ clear(layerData.getAccess(), colors[layer]);
+ m_gl.texSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, layer, VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1, m_transferFmt.format, m_transferFmt.dataType, layerData.getAccess().getDataPtr());
+ }
+
+ m_gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
+ GLU_EXPECT_NO_ERROR(m_gl.getError(), "create2DTextureArrayLayers()");
+}
+
+tcu::TextureLevel TextureLayerTestCase::genReferenceTexture (int layer, const vector<tcu::Vec4>& colors, const tcu::Vec4& uniformColor)
+{
+ tcu::TextureLevel reference (glu::mapGLTransferFormat(m_transferFmt.format, m_transferFmt.dataType), VIEWPORT_WIDTH, VIEWPORT_HEIGHT, 1);
+ clear(reference.getAccess(), colors[layer] + uniformColor);
+
+ return reference;
+}
+
+// Test description
+// - Create 2D texture array containing three layers.
+// - Each layer is assigned a different color.
+// - Attach single layer to framebuffer and draw full screen quad.
+// - Sum framebuffer read color with passed in uniform color.
+// - Compare resulting surface with reference.
+// - Repeat for subsequent texture layers.
+
+TextureLayerTestCase::IterateResult TextureLayerTestCase::iterate (void)
+{
+ const tcu::Vec4 uniformColor = scaleColorValue(m_texFmt, tcu::Vec4(0.1f, 0.1f, 0.1f, 1.0f));
+ tcu::TextureLevel result (getReadPixelFormat(m_texFmt), VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+ vector<tcu::Vec4> layerColors;
+
+ layerColors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.4f, 0.0f, 0.0f, 1.0f)));
+ layerColors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.2f, 0.0f, 0.0f, 1.0f)));
+ layerColors.push_back(scaleColorValue(m_texFmt, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)));
+
+ m_gl.genFramebuffers(1, &m_framebuffer);
+ m_gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
+
+ create2DTextureArrayLayers(layerColors);
+
+ for (int layer = 0; layer < (int)layerColors.size(); ++layer)
+ {
+ std::ostringstream name, desc;
+ name << "Layer " << layer;
+ desc << "Layer " << layer;
+
+ const tcu::ScopedLogSection section (m_testCtx.getLog(), name.str(), desc.str());
+ tcu::TextureLevel reference = genReferenceTexture(layer, layerColors, uniformColor);
+
+ m_gl.framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texColorBuffer, 0, layer);
+
+ genUniformColor(uniformColor);
+ render();
+
+ glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess());
+ verifyRenderbuffer(m_testCtx.getLog(), m_texFmt, reference, result);
+
+ if (m_testCtx.getTestResult() != QP_TEST_RESULT_PASS)
+ return STOP;
+ }
+
+ return STOP;
+}
+
+} // Anonymous
+
+ShaderFramebufferFetchTests::ShaderFramebufferFetchTests (Context& context)
+ : TestCaseGroup (context, "framebuffer_fetch", "GL_EXT_shader_framebuffer_fetch tests")
+{
+}
+
+ShaderFramebufferFetchTests::~ShaderFramebufferFetchTests (void)
+{
+}
+
+void ShaderFramebufferFetchTests::init (void)
+{
+ tcu::TestCaseGroup* const basicTestGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic framebuffer shader fetch tests");
+ tcu::TestCaseGroup* const framebufferFormatTestGroup = new tcu::TestCaseGroup(m_testCtx, "framebuffer_format", "Texture render target formats tests");
+
+ // basic
+ {
+ basicTestGroup->addChild(new TexelFetchTestCase (m_context, "texel_fetch", "Framebuffer fetches in conjunction with shader texel fetches", GL_RGBA8));
+ basicTestGroup->addChild(new LastFragDataTestCase (m_context, "last_frag_data", "Framebuffer fetches with built-in fragment output of ES 2.0", GL_RGBA8));
+ basicTestGroup->addChild(new FragmentDiscardTestCase (m_context, "fragment_discard", "Framebuffer fetches in combination with fragment discards", GL_RGBA8));
+ basicTestGroup->addChild(new MultipleAssignmentTestCase (m_context, "multiple_assignment", "Multiple assignments to fragment color inout", GL_RGBA8));
+ basicTestGroup->addChild(new MultipleRenderTargetsTestCase (m_context, "multiple_render_targets", "Framebuffer fetches used in combination with multiple render targets", GL_RGBA8));
+ basicTestGroup->addChild(new TextureLevelTestCase (m_context, "framebuffer_texture_level", "Framebuffer fetches with individual texture render target mipmaps", GL_RGBA8));
+ basicTestGroup->addChild(new TextureLayerTestCase (m_context, "framebuffer_texture_layer", "Framebuffer fetches with individual texture render target layers", GL_RGBA8));
+ }
+
+ // framebuffer formats
+ {
+ static const deUint32 colorFormats[] =
+ {
+ // RGBA formats
+ GL_RGBA32I,
+ GL_RGBA32UI,
+ GL_RGBA16I,
+ GL_RGBA16UI,
+ GL_RGBA8,
+ GL_RGBA8I,
+ GL_RGBA8UI,
+ GL_SRGB8_ALPHA8,
+ GL_RGB10_A2,
+ GL_RGB10_A2UI, GL_RGBA4, GL_RGB5_A1,
+
+ // RGB formats
+ GL_RGB8,
+ GL_RGB565,
+
+ // RG formats
+ GL_RG32I,
+ GL_RG32UI,
+ GL_RG16I,
+ GL_RG16UI,
+ GL_RG8,
+ GL_RG8I,
+ GL_RG8UI,
+
+ // R formats
+ GL_R32I,
+ GL_R32UI,
+ GL_R16I,
+ GL_R16UI,
+ GL_R8,
+ GL_R8I,
+ GL_R8UI,
+
+ // GL_EXT_color_buffer_float
+ GL_RGBA32F,
+ GL_RGBA16F,
+ GL_R11F_G11F_B10F,
+ GL_RG32F,
+ GL_RG16F,
+ GL_R32F,
+ GL_R16F,
+
+ // GL_EXT_color_buffer_half_float
+ GL_RGB16F
+ };
+
+ for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorFormats); ndx++)
+ framebufferFormatTestGroup->addChild(new TextureFormatTestCase(m_context, getFormatName(colorFormats[ndx]), "Framebuffer fetches from texture attachments with varying formats", colorFormats[ndx]));
+ }
+
+ addChild(basicTestGroup);
+ addChild(framebufferFormatTestGroup);
+}
+
+} // Functional
+} // gles31
+} // deqp