| /*------------------------------------------------------------------------- |
| * 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 |