blob: 12ce1317d32b525d7e79b76439e94338d2944cc9 [file] [log] [blame]
/*-------------------------------------------------------------------------
* drawElements Quality Program OpenGL ES 3.1 Module
* -------------------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief FBO colorbuffer tests.
*//*--------------------------------------------------------------------*/
#include "es31fFboColorbufferTests.hpp"
#include "es31fFboTestCase.hpp"
#include "es31fFboTestUtil.hpp"
#include "gluTextureUtil.hpp"
#include "gluContextInfo.hpp"
#include "tcuCommandLine.hpp"
#include "tcuImageCompare.hpp"
#include "tcuRGBA.hpp"
#include "tcuTestLog.hpp"
#include "tcuTextureUtil.hpp"
#include "sglrContextUtil.hpp"
#include "deRandom.hpp"
#include "deString.h"
#include "glwEnums.hpp"
namespace deqp
{
namespace gles31
{
namespace Functional
{
using std::string;
using tcu::IVec2;
using tcu::IVec3;
using tcu::IVec4;
using tcu::TestLog;
using tcu::UVec4;
using tcu::Vec2;
using tcu::Vec3;
using tcu::Vec4;
using namespace FboTestUtil;
const tcu::RGBA MIN_THRESHOLD(12, 12, 12, 12);
static tcu::Vec4 generateRandomColor(de::Random &random)
{
tcu::Vec4 retVal;
retVal[0] = random.getFloat();
retVal[1] = random.getFloat();
retVal[2] = random.getFloat();
retVal[3] = 1.0f;
return retVal;
}
static tcu::CubeFace getCubeFaceFromNdx(int ndx)
{
switch (ndx)
{
case 0:
return tcu::CUBEFACE_POSITIVE_X;
case 1:
return tcu::CUBEFACE_NEGATIVE_X;
case 2:
return tcu::CUBEFACE_POSITIVE_Y;
case 3:
return tcu::CUBEFACE_NEGATIVE_Y;
case 4:
return tcu::CUBEFACE_POSITIVE_Z;
case 5:
return tcu::CUBEFACE_NEGATIVE_Z;
default:
DE_ASSERT(false);
return tcu::CUBEFACE_LAST;
}
}
class FboColorbufferCase : public FboTestCase
{
public:
FboColorbufferCase(Context &context, const char *name, const char *desc, const uint32_t format)
: FboTestCase(context, name, desc)
, m_format(format)
{
}
bool compare(const tcu::Surface &reference, const tcu::Surface &result)
{
const tcu::RGBA threshold(tcu::max(getFormatThreshold(m_format), MIN_THRESHOLD));
m_testCtx.getLog() << TestLog::Message << "Comparing images, threshold: " << threshold << TestLog::EndMessage;
return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(),
result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
}
protected:
const uint32_t m_format;
};
class FboColorTex2DCase : public FboColorbufferCase
{
public:
FboColorTex2DCase(Context &context, const char *name, const char *description, uint32_t texFmt,
const IVec2 &texSize)
: FboColorbufferCase(context, name, description, texFmt)
, m_texFmt(texFmt)
, m_texSize(texSize)
{
}
protected:
void preCheck(void)
{
checkFormatSupport(m_texFmt);
}
void render(tcu::Surface &dst)
{
tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_texFmt);
tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
Texture2DShader texToFboShader(DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt),
fmtInfo.valueMax - fmtInfo.valueMin, fmtInfo.valueMin);
uint32_t texToFboShaderID = getCurrentContext()->createProgram(&texToFboShader);
uint32_t fbo;
uint32_t tex;
// Setup shader
texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
// Generate fbo
{
glu::TransferFormat transferFmt = glu::getTransferFormat(texFmt);
uint32_t format = m_texFmt;
const IVec2 &size = m_texSize;
glGenFramebuffers(1, &fbo);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, format, size.x(), size.y(), 0, transferFmt.format, transferFmt.dataType,
DE_NULL);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
checkError();
checkFramebufferStatus(GL_FRAMEBUFFER);
}
// Render texture to fbo
{
const uint32_t format = GL_RGBA;
const uint32_t dataType = GL_UNSIGNED_BYTE;
const int texW = 128;
const int texH = 128;
uint32_t tmpTex = 0;
const IVec2 &viewport = m_texSize;
tcu::TextureLevel data(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
tcu::fillWithComponentGradients(data.getAccess(), Vec4(0.0f), Vec4(1.0f));
glGenTextures(1, &tmpTex);
glBindTexture(GL_TEXTURE_2D, tmpTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, viewport.x(), viewport.y());
sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
}
readPixels(dst, 0, 0, getWidth(), getHeight(), texFmt, fmtInfo.lookupScale, fmtInfo.lookupBias);
checkError();
}
private:
uint32_t m_texFmt;
IVec2 m_texSize;
};
class FboColorTexCubeArrayCase : public FboColorbufferCase
{
public:
FboColorTexCubeArrayCase(Context &context, const char *name, const char *description, uint32_t texFmt,
const IVec3 &texSize)
: FboColorbufferCase(context, name, description, texFmt)
, m_texSize(texSize)
{
DE_ASSERT(texSize.z() % 6 == 0);
}
protected:
void preCheck(void)
{
auto ctxType = m_context.getRenderContext().getType();
if (!glu::contextSupports(ctxType, glu::ApiType::core(4, 5)) &&
!glu::contextSupports(ctxType, glu::ApiType::es(3, 2)) &&
!m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
TCU_THROW(
NotSupportedError,
"Test requires extension GL_EXT_texture_cube_map_array or a context version equal or higher than 3.2");
checkFormatSupport(m_format);
}
void render(tcu::Surface &dst)
{
TestLog &log = m_testCtx.getLog();
de::Random rnd(deStringHash(getName()) ^ 0xed607a89 ^ m_testCtx.getCommandLine().getBaseSeed());
tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_format);
tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
Texture2DShader texToFboShader(DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt),
fmtInfo.valueMax - fmtInfo.valueMin, fmtInfo.valueMin);
TextureCubeArrayShader arrayTexShader(glu::getSamplerCubeArrayType(texFmt), glu::TYPE_FLOAT_VEC4,
glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()));
uint32_t texToFboShaderID = getCurrentContext()->createProgram(&texToFboShader);
uint32_t arrayTexShaderID = getCurrentContext()->createProgram(&arrayTexShader);
// Setup textures
texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
arrayTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias);
// Framebuffers.
std::vector<uint32_t> fbos;
uint32_t tex;
{
glu::TransferFormat transferFmt = glu::getTransferFormat(texFmt);
bool isFilterable = glu::isGLInternalColorFormatFilterable(m_format);
const IVec3 &size = m_texSize;
log << TestLog::Message << "Creating a cube map array texture (" << size.x() << "x" << size.y()
<< ", depth: " << size.z() << ")" << TestLog::EndMessage;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST);
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, m_format, size.x(), size.y(), size.z(), 0, transferFmt.format,
transferFmt.dataType, DE_NULL);
log << TestLog::Message << "Creating a framebuffer object for each layer-face" << TestLog::EndMessage;
// Generate an FBO for each layer-face
for (int ndx = 0; ndx < m_texSize.z(); ndx++)
{
uint32_t layerFbo;
glGenFramebuffers(1, &layerFbo);
glBindFramebuffer(GL_FRAMEBUFFER, layerFbo);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, ndx);
checkError();
checkFramebufferStatus(GL_FRAMEBUFFER);
fbos.push_back(layerFbo);
}
}
log << TestLog::Message << "Rendering test images to layer-faces in randomized order" << TestLog::EndMessage;
{
std::vector<int> order(fbos.size());
for (size_t n = 0; n < order.size(); n++)
order[n] = (int)n;
rnd.shuffle(order.begin(), order.end());
for (size_t ndx = 0; ndx < order.size(); ndx++)
{
const int layerFace = order[ndx];
const uint32_t format = GL_RGBA;
const uint32_t dataType = GL_UNSIGNED_BYTE;
const int texW = 128;
const int texH = 128;
uint32_t tmpTex = 0;
const uint32_t fbo = fbos[layerFace];
const IVec3 &viewport = m_texSize;
tcu::TextureLevel data(glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f));
glGenTextures(1, &tmpTex);
glBindTexture(GL_TEXTURE_2D, tmpTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, viewport.x(), viewport.y());
sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f),
Vec3(1.0f, 1.0f, 0.0f));
checkError();
// Render to framebuffer
{
const Vec3 p0 = Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f);
const Vec3 p1 = p0 + Vec3(1.0f, 1.0f, 0.0f);
const int layer = layerFace / 6;
const tcu::CubeFace face = getCubeFaceFromNdx(layerFace % 6);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, getWidth(), getHeight());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex);
arrayTexShader.setLayer(layer);
arrayTexShader.setFace(face);
arrayTexShader.setUniforms(*getCurrentContext(), arrayTexShaderID);
sglr::drawQuad(*getCurrentContext(), arrayTexShaderID, p0, p1);
checkError();
}
}
}
readPixels(dst, 0, 0, getWidth(), getHeight());
}
private:
IVec3 m_texSize;
};
FboColorTests::FboColorTests(Context &context) : TestCaseGroup(context, "color", "Colorbuffer tests")
{
}
FboColorTests::~FboColorTests(void)
{
}
void FboColorTests::init(void)
{
static const uint32_t 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};
static const uint32_t unorm16ColorFormats[] = {GL_R16, GL_RG16, GL_RGBA16};
// .texcubearray
{
tcu::TestCaseGroup *texCubeArrayGroup =
new tcu::TestCaseGroup(m_testCtx, "texcubearray", "Cube map array texture tests");
addChild(texCubeArrayGroup);
for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
texCubeArrayGroup->addChild(new FboColorTexCubeArrayCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
colorFormats[fmtNdx], IVec3(128, 128, 12)));
}
// .tex2d
{
tcu::TestCaseGroup *tex2dGroup = new tcu::TestCaseGroup(m_testCtx, "tex2d", "Render to texture");
addChild(tex2dGroup);
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(unorm16ColorFormats); ndx++)
tex2dGroup->addChild(new FboColorTex2DCase(m_context, getFormatName(unorm16ColorFormats[ndx]), "",
unorm16ColorFormats[ndx], IVec2(129, 117)));
}
}
} // namespace Functional
} // namespace gles31
} // namespace deqp