/*------------------------------------------------------------------------- * 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) { 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; default: return false; } } static std::vector<std::string> getEnablingExtensions (deUint32 format) { std::vector<std::string> out; DE_ASSERT(!isRequiredFormat(format)); 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"); case GL_RGBA32F: case GL_RGB32F: case GL_R11F_G11F_B10F: case GL_RG32F: case GL_R32F: out.push_back("GL_EXT_color_buffer_float"); 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); const std::vector<std::string> requiredExts = (!isCoreFormat) ? getEnablingExtensions(sizedFormat) : 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_ASSERT(!"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