blob: 0beeeec1983a1ed09b41c88325167ac4cf8dccd1 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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");
// Fallthrough
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;
tcu::TextureChannelClass textureChannelClass = tcu::getTextureChannelClass(m_texFmt.type);
tcu::Vec4 maxValue = getTextureFormatInfo(m_texFmt).valueMax;
tcu::Vec4 minValue = getTextureFormatInfo(m_texFmt).valueMin;
string maxStr;
string minStr;
if (textureChannelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
{
maxStr = de::toString(maxValue.asUint());
minStr = de::toString(minValue.asUint());
}
else if (textureChannelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
{
maxStr = de::toString(maxValue.asInt());
minStr = de::toString(minValue.asInt());
}
else
{
maxStr = de::toString(maxValue);
minStr = de::toString(minValue);
}
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 = clamp(o_color + u_color, " << vecType << minStr << ", " << vecType << maxStr << ");\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);
tcu::TextureChannelClass textureChannelClass = tcu::getTextureChannelClass(m_texFmt.type);
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);
if (textureChannelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
tcu::clear(data.getAccess(), color.asUint());
else if (textureChannelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
tcu::clear(data.getAccess(), color.asInt());
else
tcu::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,
};
GLuint vaoID;
m_gl.genVertexArrays(1, &vaoID);
m_gl.bindVertexArray(vaoID);
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()");
m_gl.deleteVertexArrays(1, &vaoID);
}
// 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::TextureChannelClass textureChannelClass = tcu::getTextureChannelClass(m_texFmt.type);
tcu::Vec4 formatMaxValue = getTextureFormatInfo(m_texFmt).valueMax;
tcu::Vec4 formatMinValue = getTextureFormatInfo(m_texFmt).valueMin;
if (textureChannelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
{
tcu::clear(reference.getAccess(), tcu::clamp(fbColor.asUint() + uniformColor.asUint(), formatMinValue.asUint(), formatMaxValue.asUint()));
}
else if (textureChannelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)
{
tcu::clear(reference.getAccess(), tcu::clamp(fbColor.asInt() + uniformColor.asInt(), formatMinValue.asInt(), formatMaxValue.asInt()));
}
else
{
if (tcu::isSRGB(m_texFmt))
{
const tcu::Vec4 fragmentColor = tcu::clamp(tcu::sRGBToLinear(fbColor) + uniformColor, formatMinValue, formatMaxValue);
tcu::clear(reference.getAccess(), tcu::linearToSRGB(fragmentColor));
}
else
{
tcu::clear(reference.getAccess(), tcu::clamp(fbColor + uniformColor, formatMinValue, formatMaxValue));
}
}
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 genAttachmentTextures (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);
genAttachmentTextures(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::genAttachmentTextures (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(), "genAttachmentTextures()");
}
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 (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 >> level, VIEWPORT_HEIGHT >> level, 1);
genReferenceMipmap(colors[level] + uniformColor, reference);
return reference;
}
void TextureLevelTestCase::genReferenceMipmap (const tcu::Vec4& color, tcu::TextureLevel& reference)
{
const int width = reference.getAccess().getWidth();
const int height = reference.getAccess().getHeight();
const int left = width / 2;
const int 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));
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 result (getReadPixelFormat(m_texFmt), VIEWPORT_WIDTH >> level, VIEWPORT_HEIGHT >> level);
tcu::TextureLevel reference = genReferenceTexture(level, levelColors, uniformColor);
m_gl.framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texColorBuffer, level, 0);
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