| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL ES 3.0 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 stencilbuffer tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es3fFramebufferBlitTests.hpp" |
| #include "es3fFboTestCase.hpp" |
| #include "es3fFboTestUtil.hpp" |
| #include "gluTextureUtil.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "sglrContextUtil.hpp" |
| #include "glwEnums.hpp" |
| #include "deStringUtil.hpp" |
| |
| namespace deqp |
| { |
| namespace gles3 |
| { |
| namespace Functional |
| { |
| |
| using std::string; |
| using tcu::TestLog; |
| using tcu::Vec2; |
| using tcu::Vec3; |
| using tcu::Vec4; |
| using tcu::IVec2; |
| using tcu::IVec3; |
| using tcu::IVec4; |
| using tcu::UVec4; |
| using namespace FboTestUtil; |
| |
| class BlitRectCase : public FboTestCase |
| { |
| public: |
| BlitRectCase (Context& context, const char* name, const char* desc, deUint32 filter, const IVec2& srcSize, const IVec4& srcRect, const IVec2& dstSize, const IVec4& dstRect, int cellSize = 8) |
| : FboTestCase (context, name, desc) |
| , m_filter (filter) |
| , m_srcSize (srcSize) |
| , m_srcRect (srcRect) |
| , m_dstSize (dstSize) |
| , m_dstRect (dstRect) |
| , m_cellSize (cellSize) |
| , m_gridCellColorA (0.2f, 0.7f, 0.1f, 1.0f) |
| , m_gridCellColorB (0.7f, 0.1f, 0.5f, 0.8f) |
| { |
| } |
| |
| void render (tcu::Surface& dst) |
| { |
| const deUint32 colorFormat = GL_RGBA8; |
| |
| GradientShader gradShader (glu::TYPE_FLOAT_VEC4); |
| Texture2DShader texShader (DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4); |
| deUint32 gradShaderID = getCurrentContext()->createProgram(&gradShader); |
| deUint32 texShaderID = getCurrentContext()->createProgram(&texShader); |
| |
| deUint32 srcFbo, dstFbo; |
| deUint32 srcRbo, dstRbo; |
| |
| // Setup shaders |
| gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f)); |
| texShader.setUniforms(*getCurrentContext(), texShaderID); |
| |
| // Create framebuffers. |
| for (int ndx = 0; ndx < 2; ndx++) |
| { |
| deUint32& fbo = ndx ? dstFbo : srcFbo; |
| deUint32& rbo = ndx ? dstRbo : srcRbo; |
| const IVec2& size = ndx ? m_dstSize : m_srcSize; |
| |
| glGenFramebuffers(1, &fbo); |
| glGenRenderbuffers(1, &rbo); |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, size.x(), size.y()); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| checkError(); |
| checkFramebufferStatus(GL_FRAMEBUFFER); |
| } |
| |
| // Fill destination with gradient. |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFbo); |
| glViewport(0, 0, m_dstSize.x(), m_dstSize.y()); |
| |
| sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Fill source with grid pattern. |
| { |
| const deUint32 format = GL_RGBA; |
| const deUint32 dataType = GL_UNSIGNED_BYTE; |
| const int texW = m_srcSize.x(); |
| const int texH = m_srcSize.y(); |
| deUint32 gridTex = 0; |
| tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), texW, texH, 1); |
| |
| tcu::fillWithGrid(data.getAccess(), m_cellSize, m_gridCellColorA, m_gridCellColorB); |
| |
| glGenTextures(1, &gridTex); |
| glBindTexture(GL_TEXTURE_2D, gridTex); |
| 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_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFbo); |
| glViewport(0, 0, m_srcSize.x(), m_srcSize.y()); |
| sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| } |
| |
| // Perform copy. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo); |
| glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(), m_dstRect.z(), m_dstRect.w(), GL_COLOR_BUFFER_BIT, m_filter); |
| |
| // Read back results. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, dstFbo); |
| readPixels(dst, 0, 0, m_dstSize.x(), m_dstSize.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f)); |
| } |
| |
| virtual bool compare (const tcu::Surface& reference, const tcu::Surface& result) |
| { |
| // Use pixel-threshold compare for rect cases since 1px off will mean failure. |
| tcu::RGBA threshold = TestCase::m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7,7,7,7); |
| return tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, tcu::COMPARE_LOG_RESULT); |
| } |
| |
| protected: |
| const deUint32 m_filter; |
| const IVec2 m_srcSize; |
| const IVec4 m_srcRect; |
| const IVec2 m_dstSize; |
| const IVec4 m_dstRect; |
| const int m_cellSize; |
| const Vec4 m_gridCellColorA; |
| const Vec4 m_gridCellColorB; |
| }; |
| |
| class BlitNearestFilterConsistencyCase : public BlitRectCase |
| { |
| public: |
| BlitNearestFilterConsistencyCase (Context& context, const char* name, const char* desc, const IVec2& srcSize, const IVec4& srcRect, const IVec2& dstSize, const IVec4& dstRect); |
| |
| bool compare (const tcu::Surface& reference, const tcu::Surface& result); |
| }; |
| |
| BlitNearestFilterConsistencyCase::BlitNearestFilterConsistencyCase (Context& context, const char* name, const char* desc, const IVec2& srcSize, const IVec4& srcRect, const IVec2& dstSize, const IVec4& dstRect) |
| : BlitRectCase(context, name, desc, GL_NEAREST, srcSize, srcRect, dstSize, dstRect, 1) |
| { |
| } |
| |
| bool BlitNearestFilterConsistencyCase::compare (const tcu::Surface& reference, const tcu::Surface& result) |
| { |
| DE_ASSERT(reference.getWidth() == result.getWidth()); |
| DE_ASSERT(reference.getHeight() == result.getHeight()); |
| DE_UNREF(reference); |
| |
| // Image origin must be visible (for baseColor) |
| DE_ASSERT(de::min(m_dstRect.x(), m_dstRect.z()) >= 0); |
| DE_ASSERT(de::min(m_dstRect.y(), m_dstRect.w()) >= 0); |
| |
| const tcu::RGBA cellColorA (m_gridCellColorA); |
| const tcu::RGBA cellColorB (m_gridCellColorB); |
| const tcu::RGBA threshold = TestCase::m_context.getRenderTarget().getPixelFormat().getColorThreshold() + tcu::RGBA(7,7,7,7); |
| const tcu::IVec4 destinationArea = tcu::IVec4(de::clamp(de::min(m_dstRect.x(), m_dstRect.z()), 0, result.getWidth()), |
| de::clamp(de::min(m_dstRect.y(), m_dstRect.w()), 0, result.getHeight()), |
| de::clamp(de::max(m_dstRect.x(), m_dstRect.z()), 0, result.getWidth()), |
| de::clamp(de::max(m_dstRect.y(), m_dstRect.w()), 0, result.getHeight())); |
| const tcu::RGBA baseColor = result.getPixel(destinationArea.x(), destinationArea.y()); |
| const bool signConfig = tcu::compareThreshold(baseColor, cellColorA, threshold); |
| |
| bool error = false; |
| tcu::Surface errorMask (result.getWidth(), result.getHeight()); |
| std::vector<bool> horisontalSign (destinationArea.z() - destinationArea.x()); |
| std::vector<bool> verticalSign (destinationArea.w() - destinationArea.y()); |
| |
| tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); |
| |
| // Checking only area in our destination rect |
| |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Verifying consistency of NEAREST filtering. Verifying rect " << m_dstRect << ".\n" |
| << "Rounding direction of the NEAREST filter at the horisontal texel edge (x = n + 0.5) should not depend on the y-coordinate.\n" |
| << "Rounding direction of the NEAREST filter at the vertical texel edge (y = n + 0.5) should not depend on the x-coordinate.\n" |
| << "Blitting a grid (with uniform sized cells) should result in a grid (with non-uniform sized cells)." |
| << tcu::TestLog::EndMessage; |
| |
| // Verify that destination only contains valid colors |
| |
| for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy) |
| for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx) |
| { |
| const tcu::RGBA color = result.getPixel(destinationArea.x() + dx, destinationArea.y() + dy); |
| const bool isValidColor = tcu::compareThreshold(color, cellColorA, threshold) || tcu::compareThreshold(color, cellColorB, threshold); |
| |
| if (!isValidColor) |
| { |
| errorMask.setPixel(destinationArea.x() + dx, destinationArea.y() + dy, tcu::RGBA::red()); |
| error = true; |
| } |
| } |
| if (error) |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Image verification failed, destination rect contains unexpected values. " |
| << "Expected either " << cellColorA << " or " << cellColorB << "." |
| << tcu::TestLog::EndMessage |
| << tcu::TestLog::ImageSet("Result", "Image verification result") |
| << tcu::TestLog::Image("Result", "Result", result) |
| << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask) |
| << tcu::TestLog::EndImageSet; |
| return false; |
| } |
| |
| // Detect result edges by reading the first row and first column of the blitted area. |
| // Blitting a grid should result in a grid-like image. ("sign changes" should be consistent) |
| |
| for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx) |
| { |
| const tcu::RGBA color = result.getPixel(destinationArea.x() + dx, destinationArea.y()); |
| |
| if (tcu::compareThreshold(color, cellColorA, threshold)) |
| horisontalSign[dx] = true; |
| else if (tcu::compareThreshold(color, cellColorB, threshold)) |
| horisontalSign[dx] = false; |
| else |
| DE_ASSERT(DE_FALSE); |
| } |
| for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy) |
| { |
| const tcu::RGBA color = result.getPixel(destinationArea.x(), destinationArea.y() + dy); |
| |
| if (tcu::compareThreshold(color, cellColorA, threshold)) |
| verticalSign[dy] = true; |
| else if (tcu::compareThreshold(color, cellColorB, threshold)) |
| verticalSign[dy] = false; |
| else |
| DE_ASSERT(DE_FALSE); |
| } |
| |
| // Verify grid-like image |
| |
| for (int dy = 0; dy < destinationArea.w() - destinationArea.y(); ++dy) |
| for (int dx = 0; dx < destinationArea.z() - destinationArea.x(); ++dx) |
| { |
| const tcu::RGBA color = result.getPixel(destinationArea.x() + dx, destinationArea.y() + dy); |
| const bool resultSign = tcu::compareThreshold(cellColorA, color, threshold); |
| const bool correctSign = (horisontalSign[dx] == verticalSign[dy]) == signConfig; |
| |
| if (resultSign != correctSign) |
| { |
| errorMask.setPixel(destinationArea.x() + dx, destinationArea.y() + dy, tcu::RGBA::red()); |
| error = true; |
| } |
| } |
| |
| // Report result |
| |
| if (error) |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Image verification failed, nearest filter is not consistent." |
| << tcu::TestLog::EndMessage |
| << tcu::TestLog::ImageSet("Result", "Image verification result") |
| << tcu::TestLog::Image("Result", "Result", result) |
| << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask) |
| << tcu::TestLog::EndImageSet; |
| } |
| else |
| { |
| m_testCtx.getLog() |
| << tcu::TestLog::Message |
| << "Image verification passed." |
| << tcu::TestLog::EndMessage |
| << tcu::TestLog::ImageSet("Result", "Image verification result") |
| << tcu::TestLog::Image("Result", "Result", result) |
| << tcu::TestLog::EndImageSet; |
| } |
| |
| return !error; |
| } |
| |
| static tcu::BVec4 getChannelMask (tcu::TextureFormat::ChannelOrder order) |
| { |
| switch (order) |
| { |
| case tcu::TextureFormat::R: return tcu::BVec4(true, false, false, false); |
| case tcu::TextureFormat::RG: return tcu::BVec4(true, true, false, false); |
| case tcu::TextureFormat::RGB: return tcu::BVec4(true, true, true, false); |
| case tcu::TextureFormat::RGBA: return tcu::BVec4(true, true, true, true); |
| case tcu::TextureFormat::sRGB: return tcu::BVec4(true, true, true, false); |
| case tcu::TextureFormat::sRGBA: return tcu::BVec4(true, true, true, true); |
| default: |
| DE_ASSERT(false); |
| return tcu::BVec4(false); |
| } |
| } |
| |
| class BlitColorConversionCase : public FboTestCase |
| { |
| public: |
| BlitColorConversionCase (Context& context, const char* name, const char* desc, deUint32 srcFormat, deUint32 dstFormat, const IVec2& size) |
| : FboTestCase (context, name, desc) |
| , m_srcFormat (srcFormat) |
| , m_dstFormat (dstFormat) |
| , m_size (size) |
| { |
| } |
| |
| protected: |
| void preCheck (void) |
| { |
| checkFormatSupport(m_srcFormat); |
| checkFormatSupport(m_dstFormat); |
| } |
| |
| void render (tcu::Surface& dst) |
| { |
| tcu::TextureFormat srcFormat = glu::mapGLInternalFormat(m_srcFormat); |
| tcu::TextureFormat dstFormat = glu::mapGLInternalFormat(m_dstFormat); |
| glu::DataType srcOutputType = getFragmentOutputType(srcFormat); |
| glu::DataType dstOutputType = getFragmentOutputType(dstFormat); |
| |
| // Compute ranges \note Doesn't handle case where src or dest is not subset of the another! |
| tcu::TextureFormatInfo srcFmtRangeInfo = tcu::getTextureFormatInfo(srcFormat); |
| tcu::TextureFormatInfo dstFmtRangeInfo = tcu::getTextureFormatInfo(dstFormat); |
| tcu::BVec4 copyMask = tcu::logicalAnd(getChannelMask(srcFormat.order), getChannelMask(dstFormat.order)); |
| tcu::BVec4 srcIsGreater = tcu::greaterThan(srcFmtRangeInfo.valueMax-srcFmtRangeInfo.valueMin, dstFmtRangeInfo.valueMax-dstFmtRangeInfo.valueMin); |
| tcu::TextureFormatInfo srcRangeInfo (tcu::select(dstFmtRangeInfo.valueMin, srcFmtRangeInfo.valueMin, tcu::logicalAnd(copyMask, srcIsGreater)), |
| tcu::select(dstFmtRangeInfo.valueMax, srcFmtRangeInfo.valueMax, tcu::logicalAnd(copyMask, srcIsGreater)), |
| tcu::select(dstFmtRangeInfo.lookupScale, srcFmtRangeInfo.lookupScale, tcu::logicalAnd(copyMask, srcIsGreater)), |
| tcu::select(dstFmtRangeInfo.lookupBias, srcFmtRangeInfo.lookupBias, tcu::logicalAnd(copyMask, srcIsGreater))); |
| tcu::TextureFormatInfo dstRangeInfo (tcu::select(dstFmtRangeInfo.valueMin, srcFmtRangeInfo.valueMin, tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)), |
| tcu::select(dstFmtRangeInfo.valueMax, srcFmtRangeInfo.valueMax, tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)), |
| tcu::select(dstFmtRangeInfo.lookupScale, srcFmtRangeInfo.lookupScale, tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater)), |
| tcu::select(dstFmtRangeInfo.lookupBias, srcFmtRangeInfo.lookupBias, tcu::logicalOr(tcu::logicalNot(copyMask), srcIsGreater))); |
| |
| // Shaders. |
| GradientShader gradientToSrcShader (srcOutputType); |
| GradientShader gradientToDstShader (dstOutputType); |
| |
| deUint32 gradShaderSrcID = getCurrentContext()->createProgram(&gradientToSrcShader); |
| deUint32 gradShaderDstID = getCurrentContext()->createProgram(&gradientToDstShader); |
| |
| deUint32 srcFbo, dstFbo; |
| deUint32 srcRbo, dstRbo; |
| |
| // Create framebuffers. |
| for (int ndx = 0; ndx < 2; ndx++) |
| { |
| deUint32& fbo = ndx ? dstFbo : srcFbo; |
| deUint32& rbo = ndx ? dstRbo : srcRbo; |
| deUint32 format = ndx ? m_dstFormat : m_srcFormat; |
| |
| glGenFramebuffers(1, &fbo); |
| glGenRenderbuffers(1, &rbo); |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, format, m_size.x(), m_size.y()); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| checkError(); |
| checkFramebufferStatus(GL_FRAMEBUFFER); |
| } |
| |
| glViewport(0, 0, m_size.x(), m_size.y()); |
| |
| // Render gradients. |
| for (int ndx = 0; ndx < 2; ndx++) |
| { |
| glBindFramebuffer(GL_FRAMEBUFFER, ndx ? dstFbo : srcFbo); |
| |
| if (ndx) |
| { |
| gradientToDstShader.setGradient(*getCurrentContext(), gradShaderDstID, dstRangeInfo.valueMax, dstRangeInfo.valueMin); |
| sglr::drawQuad(*getCurrentContext(), gradShaderDstID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| } |
| else |
| { |
| gradientToSrcShader.setGradient(*getCurrentContext(), gradShaderSrcID, srcRangeInfo.valueMin, dstRangeInfo.valueMax); |
| sglr::drawQuad(*getCurrentContext(), gradShaderSrcID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| } |
| } |
| |
| // Execute copy. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo); |
| glBlitFramebuffer(0, 0, m_size.x(), m_size.y(), 0, 0, m_size.x(), m_size.y(), GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| checkError(); |
| |
| // Read results. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, dstFbo); |
| readPixels(dst, 0, 0, m_size.x(), m_size.y(), dstFormat, dstRangeInfo.lookupScale, dstRangeInfo.lookupBias); |
| } |
| |
| bool compare (const tcu::Surface& reference, const tcu::Surface& result) |
| { |
| const tcu::TextureFormat srcFormat = glu::mapGLInternalFormat(m_srcFormat); |
| const tcu::TextureFormat dstFormat = glu::mapGLInternalFormat(m_dstFormat); |
| const bool srcIsSRGB = tcu::isSRGB(srcFormat); |
| const bool dstIsSRGB = tcu::isSRGB(dstFormat); |
| |
| tcu::RGBA threshold; |
| |
| if (dstIsSRGB) |
| { |
| threshold = getToSRGBConversionThreshold(srcFormat, dstFormat); |
| } |
| else |
| { |
| const tcu::RGBA srcMaxDiff = getFormatThreshold(srcFormat) * (srcIsSRGB ? 2 : 1); |
| const tcu::RGBA dstMaxDiff = getFormatThreshold(dstFormat); |
| |
| threshold = tcu::max(srcMaxDiff, dstMaxDiff); |
| } |
| |
| m_testCtx.getLog() << tcu::TestLog::Message << "threshold = " << threshold << tcu::TestLog::EndMessage; |
| return tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, tcu::COMPARE_LOG_RESULT); |
| } |
| |
| private: |
| deUint32 m_srcFormat; |
| deUint32 m_dstFormat; |
| IVec2 m_size; |
| }; |
| |
| class BlitDepthStencilCase : public FboTestCase |
| { |
| public: |
| BlitDepthStencilCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 srcBuffers, const IVec2& srcSize, const IVec4& srcRect, deUint32 dstBuffers, const IVec2& dstSize, const IVec4& dstRect, deUint32 copyBuffers) |
| : FboTestCase (context, name, desc) |
| , m_format (format) |
| , m_srcBuffers (srcBuffers) |
| , m_srcSize (srcSize) |
| , m_srcRect (srcRect) |
| , m_dstBuffers (dstBuffers) |
| , m_dstSize (dstSize) |
| , m_dstRect (dstRect) |
| , m_copyBuffers (copyBuffers) |
| { |
| } |
| |
| protected: |
| void preCheck (void) |
| { |
| checkFormatSupport(m_format); |
| } |
| |
| void render (tcu::Surface& dst) |
| { |
| const deUint32 colorFormat = GL_RGBA8; |
| |
| GradientShader gradShader (glu::TYPE_FLOAT_VEC4); |
| Texture2DShader texShader (DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4); |
| FlatColorShader flatShader (glu::TYPE_FLOAT_VEC4); |
| |
| deUint32 flatShaderID = getCurrentContext()->createProgram(&flatShader); |
| deUint32 texShaderID = getCurrentContext()->createProgram(&texShader); |
| deUint32 gradShaderID = getCurrentContext()->createProgram(&gradShader); |
| |
| deUint32 srcFbo = 0; |
| deUint32 dstFbo = 0; |
| deUint32 srcColorRbo = 0; |
| deUint32 dstColorRbo = 0; |
| deUint32 srcDepthStencilRbo = 0; |
| deUint32 dstDepthStencilRbo = 0; |
| |
| // setup shaders |
| gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f)); |
| texShader.setUniforms(*getCurrentContext(), texShaderID); |
| |
| // Create framebuffers. |
| for (int ndx = 0; ndx < 2; ndx++) |
| { |
| deUint32& fbo = ndx ? dstFbo : srcFbo; |
| deUint32& colorRbo = ndx ? dstColorRbo : srcColorRbo; |
| deUint32& depthStencilRbo = ndx ? dstDepthStencilRbo : srcDepthStencilRbo; |
| deUint32 bufs = ndx ? m_dstBuffers : m_srcBuffers; |
| const IVec2& size = ndx ? m_dstSize : m_srcSize; |
| |
| glGenFramebuffers(1, &fbo); |
| glGenRenderbuffers(1, &colorRbo); |
| glGenRenderbuffers(1, &depthStencilRbo); |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, colorRbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, size.x(), size.y()); |
| |
| glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo); |
| glRenderbufferStorage(GL_RENDERBUFFER, m_format, size.x(), size.y()); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo); |
| |
| if (bufs & GL_DEPTH_BUFFER_BIT) |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo); |
| if (bufs & GL_STENCIL_BUFFER_BIT) |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo); |
| |
| checkError(); |
| checkFramebufferStatus(GL_FRAMEBUFFER); |
| |
| // Clear depth to 1 and stencil to 0. |
| glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0); |
| } |
| |
| // Fill source with gradient, depth = [-1..1], stencil = 7 |
| glBindFramebuffer(GL_FRAMEBUFFER, srcFbo); |
| glViewport(0, 0, m_srcSize.x(), m_srcSize.y()); |
| glEnable(GL_DEPTH_TEST); |
| glEnable(GL_STENCIL_TEST); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); |
| glStencilFunc(GL_ALWAYS, 7, 0xffu); |
| |
| sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f)); |
| |
| // Fill destination with grid pattern, depth = 0 and stencil = 1 |
| { |
| const deUint32 format = GL_RGBA; |
| const deUint32 dataType = GL_UNSIGNED_BYTE; |
| const int texW = m_srcSize.x(); |
| const int texH = m_srcSize.y(); |
| deUint32 gridTex = 0; |
| tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), texW, texH, 1); |
| |
| tcu::fillWithGrid(data.getAccess(), 8, Vec4(0.2f, 0.7f, 0.1f, 1.0f), Vec4(0.7f, 0.1f, 0.5f, 0.8f)); |
| |
| glGenTextures(1, &gridTex); |
| glBindTexture(GL_TEXTURE_2D, gridTex); |
| 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_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr()); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFbo); |
| glViewport(0, 0, m_dstSize.x(), m_dstSize.y()); |
| glStencilFunc(GL_ALWAYS, 1, 0xffu); |
| sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| } |
| |
| // Perform copy. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFbo); |
| glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(), m_dstRect.z(), m_dstRect.w(), m_copyBuffers, GL_NEAREST); |
| |
| // Render blue color where depth < 0, decrement on depth failure. |
| glBindFramebuffer(GL_FRAMEBUFFER, dstFbo); |
| glViewport(0, 0, m_dstSize.x(), m_dstSize.y()); |
| glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); |
| glStencilFunc(GL_ALWAYS, 0, 0xffu); |
| |
| flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f)); |
| sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| if (m_dstBuffers & GL_STENCIL_BUFFER_BIT) |
| { |
| // Render green color where stencil == 6. |
| glDisable(GL_DEPTH_TEST); |
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| glStencilFunc(GL_EQUAL, 6, 0xffu); |
| |
| flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f)); |
| sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| } |
| |
| readPixels(dst, 0, 0, m_dstSize.x(), m_dstSize.y(), glu::mapGLInternalFormat(colorFormat), Vec4(1.0f), Vec4(0.0f)); |
| } |
| |
| private: |
| deUint32 m_format; |
| deUint32 m_srcBuffers; |
| IVec2 m_srcSize; |
| IVec4 m_srcRect; |
| deUint32 m_dstBuffers; |
| IVec2 m_dstSize; |
| IVec4 m_dstRect; |
| deUint32 m_copyBuffers; |
| }; |
| |
| class BlitDefaultFramebufferCase : public FboTestCase |
| { |
| public: |
| BlitDefaultFramebufferCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 filter) |
| : FboTestCase (context, name, desc) |
| , m_format (format) |
| , m_filter (filter) |
| { |
| } |
| |
| protected: |
| void preCheck (void) |
| { |
| if (m_context.getRenderTarget().getNumSamples() > 0) |
| throw tcu::NotSupportedError("Not supported in MSAA config"); |
| |
| checkFormatSupport(m_format); |
| } |
| |
| virtual void render (tcu::Surface& dst) |
| { |
| tcu::TextureFormat colorFormat = glu::mapGLInternalFormat(m_format); |
| glu::TransferFormat transferFmt = glu::getTransferFormat(colorFormat); |
| GradientShader gradShader (glu::TYPE_FLOAT_VEC4); |
| Texture2DShader texShader (DataTypes() << glu::getSampler2DType(colorFormat), glu::TYPE_FLOAT_VEC4); |
| deUint32 gradShaderID = getCurrentContext()->createProgram(&gradShader); |
| deUint32 texShaderID = getCurrentContext()->createProgram(&texShader); |
| deUint32 fbo = 0; |
| deUint32 tex = 0; |
| const int texW = 128; |
| const int texH = 128; |
| |
| // Setup shaders |
| gradShader.setGradient(*getCurrentContext(), gradShaderID, Vec4(0.0f), Vec4(1.0f)); |
| texShader.setUniforms(*getCurrentContext(), texShaderID); |
| |
| // FBO |
| 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, m_filter); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_filter); |
| glTexImage2D(GL_TEXTURE_2D, 0, m_format, texW, texH, 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 gradient to screen. |
| glBindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer()); |
| |
| sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Blit gradient from screen to fbo. |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| glBlitFramebuffer(0, 0, getWidth(), getHeight(), 0, 0, texW, texH, GL_COLOR_BUFFER_BIT, m_filter); |
| |
| // Fill left half of viewport with quad that uses texture. |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer()); |
| glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr()); |
| sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f)); |
| |
| // Blit fbo to right half. |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| glBlitFramebuffer(0, 0, texW, texH, getWidth()/2, 0, getWidth(), getHeight(), GL_COLOR_BUFFER_BIT, m_filter); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer()); |
| readPixels(dst, 0, 0, getWidth(), getHeight()); |
| } |
| |
| bool compare (const tcu::Surface& reference, const tcu::Surface& result) |
| { |
| const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_format), tcu::RGBA(12, 12, 12, 12))); |
| |
| 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; |
| const deUint32 m_filter; |
| }; |
| |
| class DefaultFramebufferBlitCase : public BlitDefaultFramebufferCase |
| { |
| public: |
| enum BlitDirection |
| { |
| BLIT_DEFAULT_TO_TARGET, |
| BLIT_TO_DEFAULT_FROM_TARGET, |
| |
| BLIT_LAST |
| }; |
| enum BlitArea |
| { |
| AREA_SCALE, |
| AREA_OUT_OF_BOUNDS, |
| |
| AREA_LAST |
| }; |
| |
| DefaultFramebufferBlitCase (Context& context, const char* name, const char* desc, deUint32 format, deUint32 filter, BlitDirection dir, BlitArea area) |
| : BlitDefaultFramebufferCase (context, name, desc, format, filter) |
| , m_blitDir (dir) |
| , m_blitArea (area) |
| , m_srcRect (-1, -1, -1, -1) |
| , m_dstRect (-1, -1, -1, -1) |
| , m_interestingArea (-1, -1, -1, -1) |
| { |
| DE_ASSERT(dir < BLIT_LAST); |
| DE_ASSERT(area < AREA_LAST); |
| } |
| |
| void init (void) |
| { |
| // requirements |
| const int minViewportSize = 128; |
| if (m_context.getRenderTarget().getWidth() < minViewportSize || m_context.getRenderTarget().getHeight() < minViewportSize) |
| throw tcu::NotSupportedError("Viewport size " + de::toString(minViewportSize) + "x" + de::toString(minViewportSize) + " required"); |
| |
| // prevent viewport randoming |
| m_viewportWidth = m_context.getRenderTarget().getWidth(); |
| m_viewportHeight = m_context.getRenderTarget().getHeight(); |
| |
| // set proper areas |
| if (m_blitArea == AREA_SCALE) |
| { |
| m_srcRect = IVec4( 10, 20, 65, 100); |
| m_dstRect = IVec4( 25, 30, 125, 94); |
| m_interestingArea = IVec4(0, 0, 128, 128); |
| } |
| else if (m_blitArea == AREA_OUT_OF_BOUNDS) |
| { |
| const tcu::IVec2 ubound = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (tcu::IVec2(128, 128)) : (tcu::IVec2(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight())); |
| |
| m_srcRect = IVec4(-10, -15, 100, 63); |
| m_dstRect = ubound.swizzle(0, 1, 0, 1) + IVec4(-75, -99, 8, 16); |
| m_interestingArea = IVec4(ubound.x() - 128, ubound.y() - 128, ubound.x(), ubound.y()); |
| } |
| else |
| DE_ASSERT(false); |
| } |
| |
| void render (tcu::Surface& dst) |
| { |
| const tcu::TextureFormat colorFormat = glu::mapGLInternalFormat(m_format); |
| const glu::TransferFormat transferFmt = glu::getTransferFormat(colorFormat); |
| const tcu::TextureChannelClass targetClass = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (tcu::getTextureChannelClass(colorFormat.type)) : (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT); |
| deUint32 fbo = 0; |
| deUint32 fboTex = 0; |
| const int fboTexW = 128; |
| const int fboTexH = 128; |
| const int sourceWidth = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (getWidth()) : (fboTexW); |
| const int sourceHeight = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (getHeight()) : (fboTexH); |
| const int gridRenderWidth = de::min(256, sourceWidth); |
| const int gridRenderHeight= de::min(256, sourceHeight); |
| |
| int targetFbo = -1; |
| int sourceFbo = -1; |
| |
| // FBO |
| glGenFramebuffers(1, &fbo); |
| glGenTextures(1, &fboTex); |
| |
| glBindTexture(GL_TEXTURE_2D, fboTex); |
| 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, m_filter); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_filter); |
| glTexImage2D(GL_TEXTURE_2D, 0, m_format, fboTexW, fboTexH, 0, transferFmt.format, transferFmt.dataType, DE_NULL); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0); |
| checkError(); |
| checkFramebufferStatus(GL_FRAMEBUFFER); |
| |
| targetFbo = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (fbo) : (m_context.getRenderContext().getDefaultFramebuffer()); |
| sourceFbo = (m_blitDir == BLIT_DEFAULT_TO_TARGET) ? (m_context.getRenderContext().getDefaultFramebuffer()) : (fbo); |
| |
| // Render grid to source framebuffer |
| { |
| Texture2DShader texShader (DataTypes() << glu::TYPE_SAMPLER_2D, glu::TYPE_FLOAT_VEC4); |
| const deUint32 texShaderID = getCurrentContext()->createProgram(&texShader); |
| const deUint32 internalFormat = GL_RGBA8; |
| const deUint32 format = GL_RGBA; |
| const deUint32 dataType = GL_UNSIGNED_BYTE; |
| const int gridTexW = 128; |
| const int gridTexH = 128; |
| deUint32 gridTex = 0; |
| tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), gridTexW, gridTexH, 1); |
| |
| tcu::fillWithGrid(data.getAccess(), 9, tcu::Vec4(0.9f, 0.5f, 0.1f, 0.9f), tcu::Vec4(0.2f, 0.8f, 0.2f, 0.7f)); |
| |
| glGenTextures(1, &gridTex); |
| glBindTexture(GL_TEXTURE_2D, gridTex); |
| 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_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, gridTexW, gridTexH, 0, format, dataType, data.getAccess().getDataPtr()); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, sourceFbo); |
| glViewport(0, 0, gridRenderWidth, gridRenderHeight); |
| glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 0.0f, 0.0f, 1.0f).getPtr()); |
| |
| texShader.setUniforms(*getCurrentContext(), texShaderID); |
| sglr::drawQuad(*getCurrentContext(), texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| glUseProgram(0); |
| } |
| |
| // Blit source framebuffer to destination |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFbo); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFbo); |
| checkError(); |
| |
| if (targetClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || targetClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || targetClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT) |
| glClearBufferfv(GL_COLOR, 0, Vec4(1.0f, 1.0f, 0.0f, 1.0f).getPtr()); |
| else if (targetClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER) |
| glClearBufferiv(GL_COLOR, 0, IVec4(0, 0, 0, 0).getPtr()); |
| else if (targetClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) |
| glClearBufferuiv(GL_COLOR, 0, UVec4(0, 0, 0, 0).getPtr()); |
| else |
| DE_ASSERT(false); |
| |
| glBlitFramebuffer(m_srcRect.x(), m_srcRect.y(), m_srcRect.z(), m_srcRect.w(), m_dstRect.x(), m_dstRect.y(), m_dstRect.z(), m_dstRect.w(), GL_COLOR_BUFFER_BIT, m_filter); |
| checkError(); |
| |
| // Read target |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, targetFbo); |
| |
| if (m_blitDir == BLIT_TO_DEFAULT_FROM_TARGET) |
| readPixels(dst, m_interestingArea.x(), m_interestingArea.y(), m_interestingArea.z() - m_interestingArea.x(), m_interestingArea.w() - m_interestingArea.y()); |
| else |
| readPixels(dst, m_interestingArea.x(), m_interestingArea.y(), m_interestingArea.z() - m_interestingArea.x(), m_interestingArea.w() - m_interestingArea.y(), colorFormat, tcu::Vec4(1.0f), tcu::Vec4(0.0f)); |
| |
| checkError(); |
| } |
| |
| private: |
| const BlitDirection m_blitDir; |
| const BlitArea m_blitArea; |
| tcu::IVec4 m_srcRect; |
| tcu::IVec4 m_dstRect; |
| tcu::IVec4 m_interestingArea; |
| }; |
| |
| FramebufferBlitTests::FramebufferBlitTests (Context& context) |
| : TestCaseGroup(context, "blit", "Framebuffer blit tests") |
| { |
| } |
| |
| FramebufferBlitTests::~FramebufferBlitTests (void) |
| { |
| } |
| |
| void FramebufferBlitTests::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 |
| }; |
| |
| static const deUint32 depthStencilFormats[] = |
| { |
| GL_DEPTH_COMPONENT32F, |
| GL_DEPTH_COMPONENT24, |
| GL_DEPTH_COMPONENT16, |
| GL_DEPTH32F_STENCIL8, |
| GL_DEPTH24_STENCIL8, |
| GL_STENCIL_INDEX8 |
| }; |
| |
| // .rect |
| { |
| static const struct |
| { |
| const char* name; |
| IVec4 srcRect; |
| IVec4 dstRect; |
| } copyRects[] = |
| { |
| { "basic", IVec4( 10, 20, 65, 100), IVec4( 45, 5, 100, 85) }, |
| { "scale", IVec4( 10, 20, 65, 100), IVec4( 25, 30, 125, 94) }, |
| { "out_of_bounds", IVec4(-10, -15, 100, 63), IVec4( 50, 30, 136, 144) }, |
| }; |
| |
| static const struct |
| { |
| const char* name; |
| IVec4 srcRect; |
| IVec4 dstRect; |
| } filterConsistencyRects[] = |
| { |
| { "mag", IVec4( 20, 10, 74, 88), IVec4( 10, 10, 91, 101) }, |
| { "min", IVec4( 10, 20, 78, 100), IVec4( 20, 20, 71, 80) }, |
| { "out_of_bounds_mag", IVec4( 21, 10, 73, 82), IVec4( 11, 43, 141, 151) }, |
| { "out_of_bounds_min", IVec4( 11, 21, 77, 97), IVec4( 80, 82, 135, 139) }, |
| }; |
| |
| static const struct |
| { |
| const char* name; |
| IVec4 srcSwizzle; |
| IVec4 dstSwizzle; |
| } swizzles[] = |
| { |
| { DE_NULL, IVec4(0,1,2,3), IVec4(0,1,2,3) }, |
| { "reverse_src_x", IVec4(2,1,0,3), IVec4(0,1,2,3) }, |
| { "reverse_src_y", IVec4(0,3,2,1), IVec4(0,1,2,3) }, |
| { "reverse_dst_x", IVec4(0,1,2,3), IVec4(2,1,0,3) }, |
| { "reverse_dst_y", IVec4(0,1,2,3), IVec4(0,3,2,1) }, |
| { "reverse_src_dst_x", IVec4(2,1,0,3), IVec4(2,1,0,3) }, |
| { "reverse_src_dst_y", IVec4(0,3,2,1), IVec4(0,3,2,1) } |
| }; |
| |
| const IVec2 srcSize(127, 119); |
| const IVec2 dstSize(132, 128); |
| |
| // Blit rectangle tests. |
| tcu::TestCaseGroup* rectGroup = new tcu::TestCaseGroup(m_testCtx, "rect", "Blit rectangle tests"); |
| addChild(rectGroup); |
| for (int rectNdx = 0; rectNdx < DE_LENGTH_OF_ARRAY(copyRects); rectNdx++) |
| { |
| for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++) |
| { |
| string name = string(copyRects[rectNdx].name) + (swizzles[swzNdx].name ? (string("_") + swizzles[swzNdx].name) : string()); |
| IVec4 srcSwz = swizzles[swzNdx].srcSwizzle; |
| IVec4 dstSwz = swizzles[swzNdx].dstSwizzle; |
| IVec4 srcRect = copyRects[rectNdx].srcRect.swizzle(srcSwz[0], srcSwz[1], srcSwz[2], srcSwz[3]); |
| IVec4 dstRect = copyRects[rectNdx].dstRect.swizzle(dstSwz[0], dstSwz[1], dstSwz[2], dstSwz[3]); |
| |
| rectGroup->addChild(new BlitRectCase(m_context, (name + "_nearest").c_str(), "", GL_NEAREST, srcSize, srcRect, dstSize, dstRect)); |
| rectGroup->addChild(new BlitRectCase(m_context, (name + "_linear").c_str(), "", GL_LINEAR, srcSize, srcRect, dstSize, dstRect)); |
| } |
| } |
| |
| // Nearest filter tests |
| for (int rectNdx = 0; rectNdx < DE_LENGTH_OF_ARRAY(filterConsistencyRects); rectNdx++) |
| { |
| for (int swzNdx = 0; swzNdx < DE_LENGTH_OF_ARRAY(swizzles); swzNdx++) |
| { |
| string name = string("nearest_consistency_") + filterConsistencyRects[rectNdx].name + (swizzles[swzNdx].name ? (string("_") + swizzles[swzNdx].name) : string()); |
| IVec4 srcSwz = swizzles[swzNdx].srcSwizzle; |
| IVec4 dstSwz = swizzles[swzNdx].dstSwizzle; |
| IVec4 srcRect = filterConsistencyRects[rectNdx].srcRect.swizzle(srcSwz[0], srcSwz[1], srcSwz[2], srcSwz[3]); |
| IVec4 dstRect = filterConsistencyRects[rectNdx].dstRect.swizzle(dstSwz[0], dstSwz[1], dstSwz[2], dstSwz[3]); |
| |
| rectGroup->addChild(new BlitNearestFilterConsistencyCase(m_context, name.c_str(), "Test consistency of the nearest filter", srcSize, srcRect, dstSize, dstRect)); |
| } |
| } |
| } |
| |
| // .conversion |
| { |
| tcu::TestCaseGroup* conversionGroup = new tcu::TestCaseGroup(m_testCtx, "conversion", "Color conversion tests"); |
| addChild(conversionGroup); |
| |
| for (int srcFmtNdx = 0; srcFmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); srcFmtNdx++) |
| { |
| for (int dstFmtNdx = 0; dstFmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); dstFmtNdx++) |
| { |
| deUint32 srcFormat = colorFormats[srcFmtNdx]; |
| tcu::TextureFormat srcTexFmt = glu::mapGLInternalFormat(srcFormat); |
| tcu::TextureChannelClass srcType = tcu::getTextureChannelClass(srcTexFmt.type); |
| deUint32 dstFormat = colorFormats[dstFmtNdx]; |
| tcu::TextureFormat dstTexFmt = glu::mapGLInternalFormat(dstFormat); |
| tcu::TextureChannelClass dstType = tcu::getTextureChannelClass(dstTexFmt.type); |
| |
| if (((srcType == tcu::TEXTURECHANNELCLASS_FLOATING_POINT || srcType == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) != |
| (dstType == tcu::TEXTURECHANNELCLASS_FLOATING_POINT || dstType == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT)) || |
| ((srcType == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER) != (dstType == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER)) || |
| ((srcType == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) != (dstType == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER))) |
| continue; // Conversion not supported. |
| |
| string name = string(getFormatName(srcFormat)) + "_to_" + getFormatName(dstFormat); |
| |
| conversionGroup->addChild(new BlitColorConversionCase(m_context, name.c_str(), "", srcFormat, dstFormat, IVec2(127, 113))); |
| } |
| } |
| } |
| |
| // .depth_stencil |
| { |
| tcu::TestCaseGroup* depthStencilGroup = new tcu::TestCaseGroup(m_testCtx, "depth_stencil", "Depth and stencil blits"); |
| addChild(depthStencilGroup); |
| |
| for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); fmtNdx++) |
| { |
| deUint32 format = depthStencilFormats[fmtNdx]; |
| tcu::TextureFormat texFmt = glu::mapGLInternalFormat(format); |
| string fmtName = getFormatName(format); |
| bool depth = texFmt.order == tcu::TextureFormat::D || texFmt.order == tcu::TextureFormat::DS; |
| bool stencil = texFmt.order == tcu::TextureFormat::S || texFmt.order == tcu::TextureFormat::DS; |
| deUint32 buffers = (depth ? GL_DEPTH_BUFFER_BIT : 0) | (stencil ? GL_STENCIL_BUFFER_BIT : 0); |
| |
| depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_basic").c_str(), "", format, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers)); |
| depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_scale").c_str(), "", format, buffers, IVec2(127, 119), IVec4(10, 30, 100, 70), buffers, IVec2(111, 130), IVec4(20, 5, 80, 130), buffers)); |
| |
| if (depth && stencil) |
| { |
| depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_depth_only").c_str(), "", format, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), GL_DEPTH_BUFFER_BIT)); |
| depthStencilGroup->addChild(new BlitDepthStencilCase(m_context, (fmtName + "_stencil_only").c_str(), "", format, buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), buffers, IVec2(128, 128), IVec4(0, 0, 128, 128), GL_STENCIL_BUFFER_BIT)); |
| } |
| } |
| } |
| |
| // .default_framebuffer |
| { |
| static const struct |
| { |
| const char* name; |
| DefaultFramebufferBlitCase::BlitArea area; |
| } areas[] = |
| { |
| { "scale", DefaultFramebufferBlitCase::AREA_SCALE }, |
| { "out_of_bounds", DefaultFramebufferBlitCase::AREA_OUT_OF_BOUNDS }, |
| }; |
| |
| tcu::TestCaseGroup* defaultFbGroup = new tcu::TestCaseGroup(m_testCtx, "default_framebuffer", "Blits with default framebuffer"); |
| addChild(defaultFbGroup); |
| |
| for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++) |
| { |
| const deUint32 format = colorFormats[fmtNdx]; |
| const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(format); |
| const tcu::TextureChannelClass fmtClass = tcu::getTextureChannelClass(texFmt.type); |
| const deUint32 filter = glu::isGLInternalColorFormatFilterable(format) ? GL_LINEAR : GL_NEAREST; |
| const bool filterable = glu::isGLInternalColorFormatFilterable(format); |
| |
| if (fmtClass != tcu::TEXTURECHANNELCLASS_FLOATING_POINT && |
| fmtClass != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT && |
| fmtClass != tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT) |
| continue; // Conversion not supported. |
| |
| defaultFbGroup->addChild(new BlitDefaultFramebufferCase(m_context, getFormatName(format), "", format, filter)); |
| |
| for (int areaNdx = 0; areaNdx < DE_LENGTH_OF_ARRAY(areas); areaNdx++) |
| { |
| const string name = string(areas[areaNdx].name); |
| const bool addLinear = filterable; |
| const bool addNearest = !addLinear || (areas[areaNdx].area != DefaultFramebufferBlitCase::AREA_OUT_OF_BOUNDS); // No need to check out-of-bounds with different filtering |
| |
| if (addNearest) |
| { |
| defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_nearest_" + name + "_blit_from_default").c_str(), "", format, GL_NEAREST, DefaultFramebufferBlitCase::BLIT_DEFAULT_TO_TARGET, areas[areaNdx].area)); |
| defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_nearest_" + name + "_blit_to_default").c_str(), "", format, GL_NEAREST, DefaultFramebufferBlitCase::BLIT_TO_DEFAULT_FROM_TARGET, areas[areaNdx].area)); |
| } |
| |
| if (addLinear) |
| { |
| defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_linear_" + name + "_blit_from_default").c_str(), "", format, GL_LINEAR, DefaultFramebufferBlitCase::BLIT_DEFAULT_TO_TARGET, areas[areaNdx].area)); |
| defaultFbGroup->addChild(new DefaultFramebufferBlitCase(m_context, (std::string(getFormatName(format)) + "_linear_" + name + "_blit_to_default").c_str(), "", format, GL_LINEAR, DefaultFramebufferBlitCase::BLIT_TO_DEFAULT_FROM_TARGET, areas[areaNdx].area)); |
| } |
| } |
| } |
| } |
| } |
| |
| } // Functional |
| } // gles3 |
| } // deqp |