| /*------------------------------------------------------------------------- |
| * 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 Base class for FBO tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es3fFboTestCase.hpp" |
| #include "es3fFboTestUtil.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "sglrGLContext.hpp" |
| #include "sglrReferenceContext.hpp" |
| #include "gluStrUtil.hpp" |
| #include "gluContextInfo.hpp" |
| #include "deRandom.hpp" |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| |
| #include <algorithm> |
| |
| namespace deqp |
| { |
| namespace gles3 |
| { |
| namespace Functional |
| { |
| |
| using tcu::TestLog; |
| using std::string; |
| |
| FboTestCase::FboTestCase (Context& context, const char* name, const char* description, bool useScreenSizedViewport) |
| : TestCase (context, name, description) |
| , m_viewportWidth (useScreenSizedViewport ? context.getRenderTarget().getWidth() : 128) |
| , m_viewportHeight (useScreenSizedViewport ? context.getRenderTarget().getHeight() : 128) |
| { |
| } |
| |
| FboTestCase::~FboTestCase (void) |
| { |
| } |
| |
| FboTestCase::IterateResult FboTestCase::iterate (void) |
| { |
| glu::RenderContext& renderCtx = TestCase::m_context.getRenderContext(); |
| const tcu::RenderTarget& renderTarget = renderCtx.getRenderTarget(); |
| TestLog& log = m_testCtx.getLog(); |
| |
| // Viewport. |
| de::Random rnd (deStringHash(getName())); |
| int width = deMin32(renderTarget.getWidth(), m_viewportWidth); |
| int height = deMin32(renderTarget.getHeight(), m_viewportHeight); |
| int x = rnd.getInt(0, renderTarget.getWidth() - width); |
| int y = rnd.getInt(0, renderTarget.getHeight() - height); |
| |
| // Surface format and storage is choosen by render(). |
| tcu::Surface reference; |
| tcu::Surface result; |
| |
| // Call preCheck() that can throw exception if some requirement is not met. |
| preCheck(); |
| |
| // Render using GLES3. |
| try |
| { |
| sglr::GLContext context(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(x, y, width, height)); |
| setContext(&context); |
| render(result); |
| |
| // Check error. |
| deUint32 err = glGetError(); |
| if (err != GL_NO_ERROR) |
| throw glu::Error(err, glu::getErrorStr(err).toString().c_str(), DE_NULL, __FILE__, __LINE__); |
| |
| setContext(DE_NULL); |
| } |
| catch (const FboTestUtil::FboIncompleteException& e) |
| { |
| if (e.getReason() == GL_FRAMEBUFFER_UNSUPPORTED) |
| { |
| log << e; |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported"); |
| return STOP; |
| } |
| else |
| throw; |
| } |
| |
| // Render reference. |
| { |
| sglr::ReferenceContextBuffers buffers (tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), renderTarget.getDepthBits(), renderTarget.getStencilBits(), width, height); |
| sglr::ReferenceContext context (sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); |
| |
| setContext(&context); |
| render(reference); |
| setContext(DE_NULL); |
| } |
| |
| bool isOk = compare(reference, result); |
| m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
| isOk ? "Pass" : "Image comparison failed"); |
| return STOP; |
| } |
| |
| bool FboTestCase::compare (const tcu::Surface& reference, const tcu::Surface& result) |
| { |
| return tcu::fuzzyCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, 0.05f, tcu::COMPARE_LOG_RESULT); |
| } |
| |
| void FboTestCase::readPixels (tcu::Surface& dst, int x, int y, int width, int height, const tcu::TextureFormat& format, const tcu::Vec4& scale, const tcu::Vec4& bias) |
| { |
| FboTestUtil::readPixels(*getCurrentContext(), dst, x, y, width, height, format, scale, bias); |
| } |
| |
| void FboTestCase::readPixels (tcu::Surface& dst, int x, int y, int width, int height) |
| { |
| getCurrentContext()->readPixels(dst, x, y, width, height); |
| } |
| |
| void FboTestCase::checkFramebufferStatus (deUint32 target) |
| { |
| deUint32 status = glCheckFramebufferStatus(target); |
| if (status != GL_FRAMEBUFFER_COMPLETE) |
| throw FboTestUtil::FboIncompleteException(status, __FILE__, __LINE__); |
| } |
| |
| void FboTestCase::checkError (void) |
| { |
| deUint32 err = glGetError(); |
| if (err != GL_NO_ERROR) |
| throw glu::Error((int)err, (string("Got ") + glu::getErrorStr(err).toString()).c_str(), DE_NULL, __FILE__, __LINE__); |
| } |
| |
| static bool isRequiredFormat (deUint32 format, glu::RenderContext& renderContext) |
| { |
| 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; |
| |
| // Depth formats |
| case GL_DEPTH_COMPONENT32F: |
| case GL_DEPTH_COMPONENT24: |
| case GL_DEPTH_COMPONENT16: |
| return true; |
| |
| // Depth+stencil formats |
| case GL_DEPTH32F_STENCIL8: |
| case GL_DEPTH24_STENCIL8: |
| return true; |
| |
| // Stencil formats |
| case GL_STENCIL_INDEX8: |
| return true; |
| |
| // Float formats |
| case GL_RGBA32F: |
| case GL_RGB32F: |
| case GL_R11F_G11F_B10F: |
| case GL_RG32F: |
| case GL_R32F: |
| return glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));; |
| |
| default: |
| return false; |
| } |
| } |
| |
| 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; |
| } |
| |
| 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; |
| } |
| |
| void FboTestCase::checkFormatSupport (deUint32 sizedFormat) |
| { |
| const bool isCoreFormat = isRequiredFormat(sizedFormat, m_context.getRenderContext()); |
| const std::vector<std::string> requiredExts = (!isCoreFormat) ? getEnablingExtensions(sizedFormat, m_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(m_context, requiredExts)) |
| throw tcu::NotSupportedError("Format not supported"); |
| } |
| |
| static int getMinimumSampleCount (deUint32 format) |
| { |
| switch (format) |
| { |
| // Core 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: |
| case GL_DEPTH_COMPONENT32F: |
| case GL_DEPTH_COMPONENT24: |
| case GL_DEPTH_COMPONENT16: |
| case GL_DEPTH32F_STENCIL8: |
| case GL_DEPTH24_STENCIL8: |
| case GL_STENCIL_INDEX8: |
| return 4; |
| |
| // GL_EXT_color_buffer_float |
| case GL_R11F_G11F_B10F: |
| case GL_RG16F: |
| case GL_R16F: |
| return 4; |
| |
| case GL_RGBA32F: |
| case GL_RGBA16F: |
| case GL_RG32F: |
| case GL_R32F: |
| return 0; |
| |
| // GL_EXT_color_buffer_half_float |
| case GL_RGB16F: |
| return 0; |
| |
| default: |
| DE_FATAL("Unknown format"); |
| return 0; |
| } |
| } |
| |
| static std::vector<int> querySampleCounts (const glw::Functions& gl, deUint32 format) |
| { |
| int numSampleCounts = 0; |
| std::vector<int> sampleCounts; |
| |
| gl.getInternalformativ(GL_RENDERBUFFER, format, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); |
| |
| if (numSampleCounts > 0) |
| { |
| sampleCounts.resize(numSampleCounts); |
| gl.getInternalformativ(GL_RENDERBUFFER, format, GL_SAMPLES, (glw::GLsizei)sampleCounts.size(), &sampleCounts[0]); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to query sample counts for format"); |
| |
| return sampleCounts; |
| } |
| |
| void FboTestCase::checkSampleCount (deUint32 sizedFormat, int numSamples) |
| { |
| const int minSampleCount = getMinimumSampleCount(sizedFormat); |
| |
| if (numSamples > minSampleCount) |
| { |
| // Exceeds spec-mandated minimum - need to check. |
| const std::vector<int> supportedSampleCounts = querySampleCounts(m_context.getRenderContext().getFunctions(), sizedFormat); |
| |
| if (std::find(supportedSampleCounts.begin(), supportedSampleCounts.end(), numSamples) == supportedSampleCounts.end()) |
| throw tcu::NotSupportedError("Sample count not supported"); |
| } |
| } |
| |
| void FboTestCase::clearColorBuffer (const tcu::TextureFormat& format, const tcu::Vec4& value) |
| { |
| FboTestUtil::clearColorBuffer(*getCurrentContext(), format, value); |
| } |
| |
| } // Functional |
| } // gles3 |
| } // deqp |