blob: 2aa857ddbd91fa4a2262c70187d8ffa7df106923 [file] [log] [blame] [edit]
/*-------------------------------------------------------------------------
* 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::Vec2;
using tcu::Vec3;
using tcu::Vec4;
using tcu::IVec2;
using tcu::IVec3;
using tcu::IVec4;
using tcu::UVec4;
using tcu::TestLog;
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 deUint32 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 deUint32 m_format;
};
class FboColorTex2DCase : public FboColorbufferCase
{
public:
FboColorTex2DCase (Context& context, const char* name, const char* description, deUint32 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);
deUint32 texToFboShaderID = getCurrentContext()->createProgram(&texToFboShader);
deUint32 fbo;
deUint32 tex;
// Setup shader
texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
// Generate fbo
{
glu::TransferFormat transferFmt = glu::getTransferFormat(texFmt);
deUint32 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 deUint32 format = GL_RGBA;
const deUint32 dataType = GL_UNSIGNED_BYTE;
const int texW = 128;
const int texH = 128;
deUint32 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:
deUint32 m_texFmt;
IVec2 m_texSize;
};
class FboColorTexCubeArrayCase : public FboColorbufferCase
{
public:
FboColorTexCubeArrayCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec3& texSize)
: FboColorbufferCase (context, name, description, texFmt)
, m_texSize (texSize)
{
DE_ASSERT(texSize.z() % 6 == 0);
}
protected:
void preCheck (void)
{
if (!glu::contextSupports(m_context.getRenderContext().getType(), 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()));
deUint32 texToFboShaderID = getCurrentContext()->createProgram(&texToFboShader);
deUint32 arrayTexShaderID = getCurrentContext()->createProgram(&arrayTexShader);
// Setup textures
texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
arrayTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias);
// Framebuffers.
std::vector<deUint32> fbos;
deUint32 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++)
{
deUint32 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 deUint32 format = GL_RGBA;
const deUint32 dataType = GL_UNSIGNED_BYTE;
const int texW = 128;
const int texH = 128;
deUint32 tmpTex = 0;
const deUint32 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 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
};
static const deUint32 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)));
}
}
} // Functional
} // gles31
} // deqp