| /*------------------------------------------------------------------------- |
| * OpenGL Conformance Test Suite |
| * ----------------------------- |
| * |
| * Copyright (c) 2015-2016 The Khronos Group Inc. |
| * |
| * 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 |
| */ /*-------------------------------------------------------------------*/ |
| |
| /** |
| */ /*! |
| * \file gl4cDirectStateAccessFramebuffersAndRenderbuffersTests.cpp |
| * \brief Conformance tests for the Direct State Access feature functionality (Framebuffers and Renderbuffer access part). |
| */ /*------------------------------------------------------------------------------------------------------------------------*/ |
| |
| /* Includes. */ |
| #include "gl4cDirectStateAccessTests.hpp" |
| |
| #include "deSharedPtr.hpp" |
| |
| #include "gluContextInfo.hpp" |
| #include "gluDefs.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluStrUtil.hpp" |
| |
| #include "tcuFuzzyImageCompare.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "tcuSurface.hpp" |
| #include "tcuTestLog.hpp" |
| |
| #include "glw.h" |
| #include "glwFunctions.hpp" |
| |
| #include <algorithm> |
| #include <climits> |
| #include <cmath> |
| #include <set> |
| #include <sstream> |
| #include <stack> |
| #include <string> |
| #include <vector> |
| |
| namespace gl4cts |
| { |
| namespace DirectStateAccess |
| { |
| namespace Framebuffers |
| { |
| /******************************** Framebuffer Creation Test Implementation ********************************/ |
| |
| /** @brief Creation Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| CreationTest::CreationTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_creation", "Framebuffer Objects Creation Test") |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Creation Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult CreationTest::iterate() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| /* Framebuffers' objects */ |
| static const glw::GLuint framebuffers_count = 2; |
| |
| glw::GLuint framebuffers_legacy[framebuffers_count] = {}; |
| glw::GLuint framebuffers_dsa[framebuffers_count] = {}; |
| |
| try |
| { |
| /* Check legacy state creation. */ |
| gl.genFramebuffers(framebuffers_count, framebuffers_legacy); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers has failed"); |
| |
| for (glw::GLuint i = 0; i < framebuffers_count; ++i) |
| { |
| if (gl.isFramebuffer(framebuffers_legacy[i])) |
| { |
| is_ok = false; |
| |
| /* Log. */ |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "GenFramebuffers has created default objects, but it should create only a names." |
| << tcu::TestLog::EndMessage; |
| } |
| } |
| |
| /* Check direct state creation. */ |
| gl.createFramebuffers(framebuffers_count, framebuffers_dsa); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateFramebuffers has failed"); |
| |
| for (glw::GLuint i = 0; i < framebuffers_count; ++i) |
| { |
| if (!gl.isFramebuffer(framebuffers_dsa[i])) |
| { |
| is_ok = false; |
| |
| /* Log. */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message |
| << "CreateFramebuffers has not created default objects." |
| << tcu::TestLog::EndMessage; |
| } |
| } |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| for (glw::GLuint i = 0; i < framebuffers_count; ++i) |
| { |
| if (framebuffers_legacy[i]) |
| { |
| gl.deleteFramebuffers(1, &framebuffers_legacy[i]); |
| |
| framebuffers_legacy[i] = 0; |
| } |
| |
| if (framebuffers_dsa[i]) |
| { |
| gl.deleteFramebuffers(1, &framebuffers_dsa[i]); |
| |
| framebuffers_dsa[i] = 0; |
| } |
| } |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| /******************************** Framebuffer Renderbuffer Attachment Test Implementation ********************************/ |
| |
| /** @brief Framebuffer Renderbuffer Attachment Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| RenderbufferAttachmentTest::RenderbufferAttachmentTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_renderbuffer_attachment", "Framebuffer Renderbuffer Attachment Test") |
| , m_fbo(0) |
| , m_rbo(0) |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Framebuffer Renderbuffer Attachment Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult RenderbufferAttachmentTest::iterate() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| try |
| { |
| glw::GLint max_color_attachments = 8 /* Specification minimum OpenGL 4.5 Core Profile p. 627 */; |
| |
| gl.getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv has failed"); |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| is_ok &= Test(GL_COLOR_ATTACHMENT0 + i, GL_RGBA8); |
| Clean(); |
| } |
| |
| is_ok &= Test(GL_DEPTH_ATTACHMENT, GL_DEPTH_COMPONENT24); |
| Clean(); |
| |
| is_ok &= Test(GL_STENCIL_ATTACHMENT, GL_STENCIL_INDEX8); |
| Clean(); |
| |
| is_ok &= Test(GL_DEPTH_STENCIL_ATTACHMENT, GL_DEPTH24_STENCIL8); |
| Clean(); |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| Clean(); |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| /** @brief Test functionality. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * @param [in] internalformat Internal format. |
| * |
| * @return True if test succeeded, false otherwise. |
| */ |
| bool RenderbufferAttachmentTest::Test(glw::GLenum attachment, glw::GLenum internalformat) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* RBO creation. */ |
| gl.genRenderbuffers(1, &m_rbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, internalformat, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| /* FBO creation. */ |
| gl.createFramebuffers(1, &m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateFramebuffers has failed"); |
| |
| gl.namedFramebufferRenderbuffer(m_fbo, attachment, GL_RENDERBUFFER, m_rbo); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "NamedFramebufferRenderbuffer for " |
| << glu::getFramebufferAttachmentStr(attachment) |
| << " attachment failed with error value " << glu::getErrorStr(error) << "." |
| << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| glw::GLenum status = gl.checkFramebufferStatus(GL_FRAMEBUFFER); |
| |
| if (GL_FRAMEBUFFER_COMPLETE != status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Named Framebuffer Renderbuffer Attachment test failed because of framebuffer " |
| << glu::getFramebufferStatusStr(status) << " with renderbuffer set up as " |
| << glu::getFramebufferAttachmentStr(attachment) << " attachment." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Clean up GL state. |
| */ |
| void RenderbufferAttachmentTest::Clean() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Cleanup. */ |
| if (m_fbo) |
| { |
| gl.deleteFramebuffers(1, &m_fbo); |
| |
| m_fbo = 0; |
| } |
| |
| if (m_rbo) |
| { |
| gl.deleteRenderbuffers(1, &m_rbo); |
| |
| m_rbo = 0; |
| } |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| } |
| |
| /******************************** Framebuffer Texture Attachment Test Implementation ********************************/ |
| |
| /** @brief Creation Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| TextureAttachmentTest::TextureAttachmentTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_texture_attachment", "Framebuffer Texture Attachment Test") |
| , m_fbo(0) |
| , m_to(0) |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Creation Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult TextureAttachmentTest::iterate() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| try |
| { |
| glw::GLint max_color_attachments = 8 /* Specification minimum OpenGL 4.5 Core Profile p. 627 */; |
| |
| gl.getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv has failed"); |
| |
| for (glw::GLuint i = 0; i < s_targets_count; ++i) |
| { |
| for (glw::GLuint j = 1; j <= MaxTextureLevels(s_targets[i]); ++j) |
| { |
| for (glw::GLint k = 0; k < max_color_attachments; ++k) |
| { |
| is_ok &= Test(GL_COLOR_ATTACHMENT0 + k, true, s_targets[i], GL_RGBA8, j); |
| Clean(); |
| } |
| |
| is_ok &= Test(GL_DEPTH_ATTACHMENT, false, s_targets[i], GL_DEPTH_COMPONENT24, j); |
| Clean(); |
| |
| is_ok &= Test(GL_STENCIL_ATTACHMENT, false, s_targets[i], GL_STENCIL_INDEX8, j); |
| Clean(); |
| |
| is_ok &= Test(GL_DEPTH_STENCIL_ATTACHMENT, false, s_targets[i], GL_DEPTH24_STENCIL8, j); |
| Clean(); |
| } |
| } |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| Clean(); |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| /** @brief Test functionality. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * @param [in] is_color_attachment Is color attachment tested. |
| * @param [in] texture_target Texture target. |
| * @param [in] internalformat Internal format ot be tested. |
| * @param [in] levels Number of levels. |
| * |
| * @return True if test succeeded, false otherwise. |
| */ |
| bool TextureAttachmentTest::Test(glw::GLenum attachment, bool is_color_attachment, glw::GLenum texture_target, |
| glw::GLenum internalformat, glw::GLuint levels) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* RBO creation. */ |
| gl.genTextures(1, &m_to); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures has failed"); |
| |
| gl.bindTexture(texture_target, m_to); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture has failed"); |
| |
| if (GL_TEXTURE_2D_MULTISAMPLE == texture_target) |
| { |
| gl.texStorage2DMultisample(texture_target, 1, internalformat, (glw::GLuint)std::pow((double)2, (double)levels), |
| (glw::GLuint)std::pow((double)2, (double)levels), GL_FALSE); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| } |
| else |
| { |
| gl.texStorage2D(texture_target, levels, internalformat, (glw::GLuint)std::pow((double)2, (double)levels), |
| (glw::GLuint)std::pow((double)2, (double)levels)); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| } |
| |
| gl.bindTexture(texture_target, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| /* FBO creation. */ |
| gl.createFramebuffers(1, &m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateFramebuffers has failed"); |
| |
| for (glw::GLuint i = 0; i < levels; ++i) |
| { |
| gl.namedFramebufferTexture(m_fbo, attachment, m_to, i); |
| |
| SubTestAttachmentError(attachment, texture_target, i, levels); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| if (is_color_attachment) |
| { |
| gl.drawBuffer(attachment); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawBuffer has failed"); |
| |
| gl.readBuffer(attachment); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadBuffer has failed"); |
| } |
| |
| SubTestStatus(attachment, texture_target, i, levels); |
| |
| if (GL_TEXTURE_2D_MULTISAMPLE != texture_target) |
| { |
| Clear(); |
| |
| if (!SubTestContent(attachment, texture_target, internalformat, i, levels)) |
| { |
| return false; |
| } |
| } |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| } |
| |
| return true; |
| } |
| |
| /** @brief Check error and log. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * @param [in] texture_target Texture target. |
| * @param [in] level Tested level. |
| * @param [in] levels Number of levels. |
| * |
| * @return True if no error, false otherwise. |
| */ |
| bool TextureAttachmentTest::SubTestAttachmentError(glw::GLenum attachment, glw::GLenum texture_target, |
| glw::GLuint level, glw::GLuint levels) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "NamedFramebufferTexture for " << glu::getFramebufferAttachmentStr(attachment) |
| << " attachment of " << glu::getTextureTargetStr(texture_target) << " texture and texture level " << level |
| << " of texture with " << levels << " levels failed with error value " << glu::getErrorStr(error) << "." |
| << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Check status and log. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * @param [in] texture_target Texture target. |
| * @param [in] level Tested level. |
| * @param [in] levels Number of levels. |
| * |
| * @return True if FRAMEBUFFER_COMPLETE, false otherwise. |
| */ |
| bool TextureAttachmentTest::SubTestStatus(glw::GLenum attachment, glw::GLenum texture_target, glw::GLuint level, |
| glw::GLuint levels) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| glw::GLenum status = gl.checkFramebufferStatus(GL_FRAMEBUFFER); |
| |
| if (GL_FRAMEBUFFER_COMPLETE != status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Named Framebuffer Texture Attachment test failed because of framebuffer " |
| << glu::getFramebufferStatusStr(status) << " status with " << glu::getTextureTargetStr(texture_target) |
| << " texture set up as " << glu::getFramebufferAttachmentStr(attachment) << " attachment and texture level " |
| << level << " of texture with " << levels << " levels." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Check framebuffer content and log. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * @param [in] texture_target Texture target. |
| * @param [in] internalformat Tested internal format. |
| * @param [in] level Tested level. |
| * @param [in] levels Number of levels. |
| * |
| * @return True if FRAMEBUFFER_COMPLETE, false otherwise. |
| */ |
| bool TextureAttachmentTest::SubTestContent(glw::GLenum attachment, glw::GLenum texture_target, |
| glw::GLenum internalformat, glw::GLuint level, glw::GLuint levels) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check framebuffer's color content. */ |
| if (GL_RGBA8 == internalformat) |
| { |
| glw::GLfloat color[4] = { 0.f }; |
| |
| gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, color); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| for (int i = 0; i < 4 /* color components */; ++i) |
| { |
| if (de::abs(s_reference_color[i] - color[i]) > 0.0625 /* precision */) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Named Framebuffer Texture Layer Attachment test failed with " |
| << glu::getTextureTargetStr(texture_target) << " texture set up as " |
| << glu::getFramebufferAttachmentStr(attachment) << " attachment and texture level " << level |
| << " of texture with " << levels << " levels. The color content of the framebuffer was [" |
| << color[0] << ", " << color[1] << ", " << color[2] << ", " << color[3] << "], but [" |
| << s_reference_color[0] << ", " << s_reference_color[1] << ", " << s_reference_color[2] << ", " |
| << s_reference_color[3] << "] was expected." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| } |
| |
| /* Check framebuffer's depth content. */ |
| if ((GL_DEPTH_COMPONENT24 == internalformat) || (GL_DEPTH24_STENCIL8 == internalformat)) |
| { |
| glw::GLfloat depth = 0.f; |
| |
| gl.readPixels(0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| if (de::abs(s_reference_depth - depth) > 0.0625 /* precision */) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Named Framebuffer Texture Layer Attachment test failed " |
| << "with texture set up as " << glu::getFramebufferAttachmentStr(attachment) |
| << " attachment and texture level " << level << " of texture with " << levels |
| << " levels. The depth content of the framebuffer was [" << depth << "], but [" << s_reference_depth |
| << "] was expected." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| |
| /* Check framebuffer's stencil content. */ |
| if ((GL_STENCIL_INDEX8 == internalformat) || (GL_DEPTH24_STENCIL8 == internalformat)) |
| { |
| glw::GLint stencil = 0; |
| |
| gl.readPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_INT, &stencil); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| if (s_reference_stencil != stencil) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Named Framebuffer Texture Layer Attachment test failed " |
| << "with texture set up as " << glu::getFramebufferAttachmentStr(attachment) |
| << " attachment and texture level " << level << " of texture with " << levels |
| << " levels. The stencil content of the framebuffer was [" << stencil << "], but [" |
| << s_reference_stencil << "] was expected." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** @brief Query max texture levels. |
| * |
| * @param [in] texture_target Texture target. |
| * |
| * @return Max texture levels. |
| */ |
| glw::GLuint TextureAttachmentTest::MaxTextureLevels(glw::GLenum texture_target) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| glw::GLint max_texture_size = 1024 /* Specification default. */; |
| |
| switch (texture_target) |
| { |
| case GL_TEXTURE_RECTANGLE: |
| case GL_TEXTURE_2D_MULTISAMPLE: |
| return 1; |
| |
| case GL_TEXTURE_2D: |
| gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| return (glw::GLuint)std::log((double)max_texture_size); |
| |
| case GL_TEXTURE_CUBE_MAP: |
| gl.getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &max_texture_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| return (glw::GLuint)std::log((double)max_texture_size); |
| |
| default: |
| throw 0; |
| } |
| |
| /* For compiler warnings only. */ |
| return 0; |
| } |
| |
| /** @brief Clear texture. |
| */ |
| void TextureAttachmentTest::Clear() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Setup clear values. */ |
| gl.clearColor(s_reference_color[0], s_reference_color[1], s_reference_color[2], s_reference_color[3]); |
| gl.clearDepth(s_reference_depth); |
| gl.clearStencil(s_reference_stencil); |
| |
| /* Clear rbo/fbo. */ |
| gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| } |
| |
| /** @brief Clean up GL state. |
| */ |
| void TextureAttachmentTest::Clean() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Cleanup. */ |
| if (m_fbo) |
| { |
| gl.deleteFramebuffers(1, &m_fbo); |
| |
| m_fbo = 0; |
| } |
| |
| if (m_to) |
| { |
| gl.deleteTextures(1, &m_to); |
| |
| m_to = 0; |
| } |
| |
| /* Returning to default clear values. */ |
| gl.clearColor(0.f, 0.f, 0.f, 0.f); |
| gl.clearDepth(1.f); |
| gl.clearStencil(0); |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| } |
| |
| /** Tested targets. */ |
| const glw::GLenum TextureAttachmentTest::s_targets[] = { GL_TEXTURE_RECTANGLE, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE, |
| GL_TEXTURE_CUBE_MAP }; |
| |
| /** Tested targets count. */ |
| const glw::GLuint TextureAttachmentTest::s_targets_count = sizeof(s_targets) / sizeof(s_targets[0]); |
| |
| const glw::GLfloat TextureAttachmentTest::s_reference_color[4] = { 0.25, 0.5, 0.75, 1.0 }; //!< Reference color. |
| const glw::GLint TextureAttachmentTest::s_reference_color_integer[4] = { 1, 2, 3, |
| 4 }; //!< Reference color for integer format. |
| const glw::GLfloat TextureAttachmentTest::s_reference_depth = 0.5; //!< Reference depth value. |
| const glw::GLint TextureAttachmentTest::s_reference_stencil = 7; //!< Reference stencil value. |
| |
| /******************************** Framebuffer Texture Layer Attachment Test Implementation ********************************/ |
| |
| /** @brief Framebuffer Texture Layer Attachment Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| TextureLayerAttachmentTest::TextureLayerAttachmentTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_texture_layer_attachment", "Framebuffer Texture Layer Attachment Test") |
| , m_fbo(0) |
| , m_to(0) |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Framebuffer Texture Layer Attachment Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult TextureLayerAttachmentTest::iterate() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| try |
| { |
| glw::GLint max_color_attachments = 8 /* Specification minimum OpenGL 4.5 Core Profile p. 627 */; |
| |
| gl.getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv has failed"); |
| |
| for (glw::GLuint i = 0; i < s_targets_count; ++i) |
| { |
| glw::GLuint layers_counts[] = { (GL_TEXTURE_CUBE_MAP_ARRAY == (glw::GLuint)s_targets[i]) ? 6u : 1u, |
| (GL_TEXTURE_CUBE_MAP_ARRAY == (glw::GLuint)s_targets[i]) ? 192u : 192u, |
| MaxTextureLayers(s_targets[i]) }; |
| |
| glw::GLuint layers_counts_count = sizeof(layers_counts) / sizeof(layers_counts[0]); |
| |
| for (glw::GLuint j = 1; j <= MaxTextureLevels(s_targets[i]); ++j) |
| { |
| for (glw::GLuint k = 0; k < layers_counts_count; ++k) |
| { |
| for (glw::GLint l = 0; l < max_color_attachments; ++l) |
| { |
| is_ok &= Test(GL_COLOR_ATTACHMENT0 + l, true, s_targets[i], GL_RGBA8, j, layers_counts[k]); |
| Clean(); |
| } |
| |
| if (GL_TEXTURE_3D != s_targets[i]) |
| { |
| is_ok &= |
| Test(GL_DEPTH_ATTACHMENT, false, s_targets[i], GL_DEPTH_COMPONENT24, j, layers_counts[k]); |
| Clean(); |
| |
| is_ok &= Test(GL_DEPTH_STENCIL_ATTACHMENT, false, s_targets[i], GL_DEPTH24_STENCIL8, j, |
| layers_counts[k]); |
| Clean(); |
| |
| is_ok &= |
| Test(GL_STENCIL_ATTACHMENT, false, s_targets[i], GL_STENCIL_INDEX8, j, layers_counts[k]); |
| Clean(); |
| } |
| } |
| } |
| } |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| Clean(); |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| /** @brief Test texture layer attachment. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * @param [in] is_color_attachment Is color attachment tested. |
| * @param [in] texture_target Texture target. |
| * @param [in] internalformat Tested internal format. |
| * @param [in] level Tested level. |
| * @param [in] levels Number of levels. |
| * @param [in] layers Number of layers. |
| * |
| * @return True if test succeeded, false otherwise. |
| */ |
| bool TextureLayerAttachmentTest::Test(glw::GLenum attachment, bool is_color_attachment, glw::GLenum texture_target, |
| glw::GLenum internalformat, glw::GLuint levels, glw::GLint layers) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* RBO creation. */ |
| gl.genTextures(1, &m_to); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures has failed"); |
| |
| gl.bindTexture(texture_target, m_to); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture has failed"); |
| |
| // Lower the layers count when multiple levels are requested to limit the amount of memory required |
| layers = deMax32(1, (glw::GLint)((deUint64)layers / (1ull<<(deUint64)(2*(levels-1))))); |
| if (GL_TEXTURE_CUBE_MAP_ARRAY == texture_target) |
| { |
| layers = deMax32(6, (layers / 6) * 6); |
| } |
| |
| if (GL_TEXTURE_2D_MULTISAMPLE_ARRAY == texture_target) |
| { |
| gl.texStorage3DMultisample(texture_target, 1, internalformat, (glw::GLuint)std::pow((double)2, (double)levels), |
| (glw::GLuint)std::pow((double)2, (double)levels), layers, GL_FALSE); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| } |
| else |
| { |
| gl.texStorage3D(texture_target, levels, internalformat, (glw::GLuint)std::pow((double)2, (double)levels), |
| (glw::GLuint)std::pow((double)2, (double)levels), layers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| } |
| |
| gl.bindTexture(texture_target, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| /* FBO creation. */ |
| gl.createFramebuffers(1, &m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glCreateFramebuffers has failed"); |
| |
| for (glw::GLuint i = 0; i < levels; ++i) |
| { |
| glw::GLuint j = 0; |
| glw::GLuint k = 1; |
| |
| /* 3D textures are mipmapped also in depth directio, so number of layers to be tested must be limited. */ |
| glw::GLuint layers_at_level = (GL_TEXTURE_3D == texture_target) ? |
| (de::min(layers, layers / (glw::GLint)std::pow(2.0, (double)i))) : |
| layers; |
| |
| while (j < layers_at_level) /* Only layers with Fibonacci number index are tested to reduce the test time. */ |
| { |
| /* Attach texture layer. */ |
| gl.namedFramebufferTextureLayer(m_fbo, attachment, m_to, i, j); |
| |
| if (!SubTestAttachmentError(attachment, texture_target, i, j, levels, layers)) |
| { |
| return false; |
| } |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| if (is_color_attachment) |
| { |
| gl.drawBuffer(attachment); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawBuffer has failed"); |
| |
| gl.readBuffer(attachment); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadBuffer has failed"); |
| } |
| |
| if (!SubTestStatus(attachment, texture_target, i, j, levels, layers)) |
| { |
| return false; |
| } |
| |
| if (GL_TEXTURE_2D_MULTISAMPLE_ARRAY != texture_target) |
| { |
| Clear(); |
| |
| if (!SubTestContent(attachment, texture_target, internalformat, i, j, levels, layers)) |
| { |
| return false; |
| } |
| } |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| /* Fibonacci number iteration. */ |
| int l = j; |
| j = j + k; |
| k = l; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** @brief Check error and log. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * @param [in] texture_target Texture target. |
| * @param [in] level Tested level. |
| * @param [in] layer Tested layer. |
| * @param [in] levels Number of levels. |
| * @param [in] layers Number of layers. |
| * |
| * @return True if no error, false otherwise. |
| */ |
| bool TextureLayerAttachmentTest::SubTestAttachmentError(glw::GLenum attachment, glw::GLenum texture_target, |
| glw::GLuint level, glw::GLint layer, glw::GLuint levels, |
| glw::GLint layers) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check and log. */ |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "NamedFramebufferTexture for " << glu::getFramebufferAttachmentStr(attachment) |
| << " attachment of " << glu::getTextureTargetStr(texture_target) << " texture at level " << level |
| << " and at layer " << layer << " where texture has " << levels << " levels and " << layers |
| << " layers failed with error value " << glu::getErrorStr(error) << "." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Check framebuffer completness. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * @param [in] texture_target Texture target. |
| * @param [in] level Tested level. |
| * @param [in] layer Tested layer. |
| * @param [in] levels Number of levels. |
| * @param [in] layers Number of layers. |
| * |
| * @return True if framebuffer is complete, false otherwise. |
| */ |
| bool TextureLayerAttachmentTest::SubTestStatus(glw::GLenum attachment, glw::GLenum texture_target, glw::GLuint level, |
| glw::GLint layer, glw::GLuint levels, glw::GLint layers) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check framebuffer status. */ |
| glw::GLenum status = gl.checkFramebufferStatus(GL_FRAMEBUFFER); |
| |
| if (GL_FRAMEBUFFER_COMPLETE != status) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Named Framebuffer Texture Layer Attachment test failed because of framebuffer " |
| << glu::getFramebufferStatusStr(status) << " with " << glu::getTextureTargetStr(texture_target) |
| << " texture set up as " << glu::getFramebufferAttachmentStr(attachment) << " attachment and texture level " |
| << level << " and texture layer " << layer << " of texture with " << levels << " levels and " << layers |
| << " layers." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Check framebuffer cntent. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * @param [in] texture_target Texture target. |
| * @param [in] internalformat Tested internal format. |
| * @param [in] level Tested level. |
| * @param [in] layer Tested layer. |
| * @param [in] levels Number of levels. |
| * @param [in] layers Number of layers. |
| * |
| * @return True if framebuffer content is equal to the reference, false otherwise. |
| */ |
| bool TextureLayerAttachmentTest::SubTestContent(glw::GLenum attachment, glw::GLenum texture_target, |
| glw::GLenum internalformat, glw::GLuint level, glw::GLint layer, |
| glw::GLuint levels, glw::GLint layers) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check framebuffer's color content. */ |
| if (GL_RGBA8 == internalformat) |
| { |
| glw::GLfloat color[4] = { 0.f }; |
| |
| gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, color); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| for (int i = 0; i < 4 /* color components */; ++i) |
| { |
| if (de::abs(s_reference_color[i] - color[i]) > 0.0625 /* precision */) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Named Framebuffer Texture Layer Attachment test failed with " |
| << glu::getTextureTargetStr(texture_target) << " texture set up as " |
| << glu::getFramebufferAttachmentStr(attachment) << " attachment and texture level " << level |
| << " and texture layer " << layer << " of texture with " << levels << " levels and " << layers |
| << " layers. The color content of the framebuffer was [" << color[0] << ", " << color[1] << ", " |
| << color[2] << ", " << color[3] << "], but [" << s_reference_color[0] << ", " |
| << s_reference_color[1] << ", " << s_reference_color[2] << ", " << s_reference_color[3] |
| << "] was expected." << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| } |
| |
| /* Check framebuffer's depth content. */ |
| if ((GL_DEPTH_COMPONENT24 == internalformat) || (GL_DEPTH24_STENCIL8 == internalformat)) |
| { |
| glw::GLfloat depth = 0.f; |
| |
| gl.readPixels(0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| if (de::abs(s_reference_depth - depth) > 0.0625 /* precision */) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Named Framebuffer Texture Layer Attachment test failed " |
| << "with texture set up as " << glu::getFramebufferAttachmentStr(attachment) |
| << " attachment and texture level " << level << " and texture layer " << layer << " of texture with " |
| << levels << " levels and " << layers << " layers. The depth content of the framebuffer was [" << depth |
| << "], but [" << s_reference_depth << "] was expected." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| |
| /* Check framebuffer's stencil content. */ |
| if ((GL_STENCIL_INDEX8 == internalformat) || (GL_DEPTH24_STENCIL8 == internalformat)) |
| { |
| glw::GLint stencil = 0; |
| |
| gl.readPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_INT, &stencil); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| if (s_reference_stencil != stencil) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Named Framebuffer Texture Layer Attachment test failed " |
| << "with texture set up as " << glu::getFramebufferAttachmentStr(attachment) |
| << " attachment and texture level " << level << " and texture layer " << layer << " of texture with " |
| << levels << " levels and " << layers << " layers. The stencil content of the framebuffer was [" |
| << stencil << "], but [" << s_reference_stencil << "] was expected." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** @brief Clear framebuffer. |
| */ |
| void TextureLayerAttachmentTest::Clear() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Setup clear values. */ |
| gl.clearColor(s_reference_color[0], s_reference_color[1], s_reference_color[2], s_reference_color[3]); |
| gl.clearDepth(s_reference_depth); |
| gl.clearStencil(s_reference_stencil); |
| |
| /* Clear rbo/fbo. */ |
| gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| } |
| |
| /** @brief Query maximum number of texture levels. |
| * |
| * @return True if max number of texture levels, false otherwise. |
| */ |
| glw::GLuint TextureLayerAttachmentTest::MaxTextureLevels(glw::GLenum texture_target) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| glw::GLint max_texture_size = 1024 /* Specification default. */; |
| |
| switch (texture_target) |
| { |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| return 1; |
| |
| case GL_TEXTURE_2D_ARRAY: |
| |
| gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| return (glw::GLuint)std::log((double)max_texture_size); |
| |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| |
| gl.getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE , &max_texture_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| return (glw::GLuint)std::log((double)max_texture_size); |
| |
| case GL_TEXTURE_3D: |
| |
| gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max_texture_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| return (glw::GLuint)std::log((double)max_texture_size); |
| default: |
| throw 0; |
| } |
| |
| /* For compiler warnings only. */ |
| return 0; |
| } |
| |
| /** @brief Query maximum number of texture layers. |
| * |
| * @return True if max number of texture layers, false otherwise. |
| */ |
| glw::GLuint TextureLayerAttachmentTest::MaxTextureLayers(glw::GLenum texture_target) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| glw::GLint max_texture_size = 1024 /* Specification default. */; |
| |
| switch (texture_target) |
| { |
| case GL_TEXTURE_3D: |
| gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max_texture_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| return max_texture_size; |
| |
| case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: |
| case GL_TEXTURE_2D_ARRAY: |
| |
| gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &max_texture_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| return max_texture_size; |
| |
| case GL_TEXTURE_CUBE_MAP_ARRAY: |
| gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &max_texture_size); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| return (max_texture_size / 6) * 6; /* Make sure that max_texture_size is dividable by 6 */ |
| |
| default: |
| throw 0; |
| } |
| |
| /* For compiler warnings only. */ |
| return 0; |
| } |
| |
| /** @brief Clean up GL state. |
| */ |
| void TextureLayerAttachmentTest::Clean() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Cleanup. */ |
| if (m_fbo) |
| { |
| gl.deleteFramebuffers(1, &m_fbo); |
| |
| m_fbo = 0; |
| } |
| |
| if (m_to) |
| { |
| gl.deleteTextures(1, &m_to); |
| |
| m_to = 0; |
| } |
| |
| /* Returning to default clear values. */ |
| gl.clearColor(0.f, 0.f, 0.f, 0.f); |
| gl.clearDepth(1.f); |
| gl.clearStencil(0); |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| } |
| |
| const glw::GLenum TextureLayerAttachmentTest::s_targets[] = //!< Targets to be tested. |
| { GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_3D }; |
| |
| const glw::GLuint TextureLayerAttachmentTest::s_targets_count = |
| sizeof(s_targets) / sizeof(s_targets[0]); //!< Number of tested targets. |
| |
| const glw::GLfloat TextureLayerAttachmentTest::s_reference_color[4] = { 0.25, 0.5, 0.75, 1.0 }; //!< Reference color. |
| const glw::GLint TextureLayerAttachmentTest::s_reference_color_integer[4] = { 1, 2, 3, |
| 4 }; //!< Reference integer color. |
| const glw::GLfloat TextureLayerAttachmentTest::s_reference_depth = 0.5; //!< Reference depth. |
| const glw::GLint TextureLayerAttachmentTest::s_reference_stencil = 7; //!< Reference stencil index. |
| |
| /******************************** Named Framebuffer Read / Draw Buffer Test Implementation ********************************/ |
| |
| /** @brief Named Framebuffer Read / Draw Buffer Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| DrawReadBufferTest::DrawReadBufferTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_read_draw_buffer", "Framebuffer Read and Draw Buffer Test") |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Named Framebuffer Read / Draw Buffer Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult DrawReadBufferTest::iterate() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| /* Framebuffers' objects */ |
| glw::GLuint framebuffer = 0; |
| |
| /* Get number of color attachments. */ |
| glw::GLint max_color_attachments = 8 /* Specification minimum OpenGL 4.5 Core Profile p. 627 */; |
| |
| gl.getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv has failed"); |
| |
| std::vector<glw::GLuint> renderbuffers(max_color_attachments); |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| renderbuffers[i] = 0; |
| } |
| |
| try |
| { |
| /* Prepare framebuffer... */ |
| gl.genFramebuffers(1, &framebuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers has failed"); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffers has failed"); |
| |
| gl.genRenderbuffers(max_color_attachments, &(renderbuffers[0])); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| /* .. with renderbuffer color attachments. */ |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| } |
| |
| /* Check that framebuffer is complete. */ |
| if (GL_FRAMEBUFFER_COMPLETE != gl.checkFramebufferStatus(GL_FRAMEBUFFER)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Framebuffer is unexpectedly incomplete." |
| << tcu::TestLog::EndMessage; |
| |
| throw 0; |
| } |
| |
| /* Clear each of the framebuffer's attachments with unique color using NamedFramebufferDrawBuffer for attachment selection. */ |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.clearColor((float)i / (float)max_color_attachments, (float)i / (float)max_color_attachments, |
| (float)i / (float)max_color_attachments, (float)i / (float)max_color_attachments); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor has failed"); |
| |
| gl.namedFramebufferDrawBuffer(framebuffer, GL_COLOR_ATTACHMENT0 + i); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "NamedFramebufferDrawBuffer unexpectedly generated " |
| << glu::getErrorStr(error) << " error with GL_COLOR_ATTACHMENT" << i << ". Test fails." |
| << tcu::TestLog::EndMessage; |
| is_ok = false; |
| } |
| |
| gl.clear(GL_COLOR_BUFFER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glClear has failed"); |
| } |
| |
| /* Fetch framebuffer's content and compare it with reference using NamedFramebufferReadBuffer for attachment selection. */ |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.namedFramebufferReadBuffer(framebuffer, GL_COLOR_ATTACHMENT0 + i); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "NamedFramebufferReadBuffer unexpectedly generated " |
| << glu::getErrorStr(error) << " error with GL_COLOR_ATTACHMENT" << i << ". Test fails." |
| << tcu::TestLog::EndMessage; |
| is_ok = false; |
| } |
| |
| glw::GLfloat rgba[4] = { -1.f, -1.f, -1.f, -1.f }; |
| |
| gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, rgba); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| float expected_value = (float)i / (float)max_color_attachments; |
| |
| for (glw::GLuint j = 0; j < 4 /* number of components */; ++j) |
| { |
| if (de::abs(expected_value - rgba[j]) > 0.0001 /* Precision */) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "Named Framebuffer Draw And Read Buffer failed because resulting color value was [" |
| << rgba[0] << ", " << rgba[1] << ", " << rgba[2] << ", " << rgba[3] << "] but [" |
| << expected_value << ", " << expected_value << ", " << expected_value << ", " << expected_value |
| << "] had been expected." << tcu::TestLog::EndMessage; |
| |
| is_ok = false; |
| |
| break; |
| } |
| } |
| } |
| |
| /* Check that NamedFramebufferDrawBuffer accepts GL_NONE as mode. */ |
| gl.namedFramebufferDrawBuffer(framebuffer, GL_NONE); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "NamedFramebufferDrawBuffer unexpectedly generated " |
| << glu::getErrorStr(error) << " error with GL_NONE mode. Test fails." << tcu::TestLog::EndMessage; |
| is_ok = false; |
| } |
| |
| /* Check that NamedFramebufferReadBuffer accepts GL_NONE as mode. */ |
| gl.namedFramebufferReadBuffer(framebuffer, GL_NONE); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "NamedFramebufferReadBuffer unexpectedly generated " |
| << glu::getErrorStr(error) << " error with GL_NONE mode. Test fails." << tcu::TestLog::EndMessage; |
| is_ok = false; |
| } |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| if (framebuffer) |
| { |
| gl.deleteFramebuffers(1, &framebuffer); |
| |
| framebuffer = 0; |
| } |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| if (renderbuffers[i]) |
| { |
| gl.deleteRenderbuffers(1, &(renderbuffers[i])); |
| } |
| } |
| |
| gl.clearColor(0.f, 0.f, 0.f, 0.f); |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| /******************************** Named Framebuffer Draw Buffers Test Implementation ********************************/ |
| |
| /** @brief Named Framebuffer Draw Buffers Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| DrawBuffersTest::DrawBuffersTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_draw_buffers", "Framebuffer Draw Buffers Test") |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Named Framebuffer Read / Draw Buffer Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult DrawBuffersTest::iterate() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| /* Framebuffers' objects */ |
| glw::GLuint framebuffer = 0; |
| |
| /* Get number of color attachments. */ |
| glw::GLint max_color_attachments = 8 /* Specification minimum OpenGL 4.5 Core Profile p. 627 */; |
| |
| gl.getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv has failed"); |
| |
| std::vector<glw::GLuint> renderbuffers(max_color_attachments); |
| std::vector<glw::GLuint> color_attachments(max_color_attachments); |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| renderbuffers[i] = 0; |
| color_attachments[i] = GL_COLOR_ATTACHMENT0 + i; |
| } |
| |
| try |
| { |
| /* Prepare framebuffer... */ |
| gl.genFramebuffers(1, &framebuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers has failed"); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffers has failed"); |
| |
| gl.genRenderbuffers(max_color_attachments, &(renderbuffers[0])); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| /* .. with renderbuffer color attachments. */ |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| } |
| |
| /* Check that framebuffer is complete. */ |
| if (GL_FRAMEBUFFER_COMPLETE != gl.checkFramebufferStatus(GL_FRAMEBUFFER)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Framebuffer is unexpectedly incomplete." |
| << tcu::TestLog::EndMessage; |
| |
| throw 0; |
| } |
| |
| /* Set up all attachments as draw buffer. */ |
| gl.namedFramebufferDrawBuffers(framebuffer, max_color_attachments, &(color_attachments[0])); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "NamedFramebufferDrawBuffers unexpectedly generated " |
| << glu::getErrorStr(error) << " error. Test fails." << tcu::TestLog::EndMessage; |
| is_ok = false; |
| } |
| |
| /* Clear each of the framebuffer's attachments with unique color using NamedFramebufferDrawBuffer for attachment selection. */ |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.clearColor(s_rgba[0], s_rgba[1], s_rgba[2], s_rgba[3]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor has failed"); |
| |
| gl.clear(GL_COLOR_BUFFER_BIT); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glClear has failed"); |
| } |
| |
| /* Fetch framebuffer's content and compare it with reference using NamedFramebufferReadBuffer for attachment selection. */ |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.readBuffer(GL_COLOR_ATTACHMENT0 + i); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadBuffer has failed"); |
| |
| glw::GLfloat rgba[4] = { -1.f, -1.f, -1.f, -1.f }; |
| |
| gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, rgba); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| for (glw::GLuint j = 0; j < 4 /* number of components */; ++j) |
| { |
| if (de::abs(s_rgba[j] - rgba[j]) > 0.0001 /* Precision */) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "Named Framebuffer Draw Buffers test have failed because resulting color value was [" |
| << rgba[0] << ", " << rgba[1] << ", " << rgba[2] << ", " << rgba[3] << "] but [" << s_rgba[0] |
| << ", " << s_rgba[1] << ", " << s_rgba[2] << ", " << s_rgba[3] << "] had been expected." |
| << tcu::TestLog::EndMessage; |
| |
| is_ok = false; |
| |
| break; |
| } |
| } |
| } |
| |
| /* Check that NamedFramebufferDrawBuffers accepts GL_NONE as mode. */ |
| glw::GLenum none_bufs = GL_NONE; |
| gl.namedFramebufferDrawBuffers(framebuffer, 1, &none_bufs); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "NamedFramebufferDrawBuffers unexpectedly generated " |
| << glu::getErrorStr(error) << " error with GL_NONE mode. Test fails." << tcu::TestLog::EndMessage; |
| is_ok = false; |
| } |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| if (framebuffer) |
| { |
| gl.deleteFramebuffers(1, &framebuffer); |
| |
| framebuffer = 0; |
| } |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| if (renderbuffers[i]) |
| { |
| gl.deleteRenderbuffers(1, &(renderbuffers[i])); |
| } |
| } |
| |
| gl.clearColor(0.f, 0.f, 0.f, 0.f); |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| const glw::GLfloat DrawBuffersTest::s_rgba[4] = { 0.f, 0.25f, 0.5f, 0.75f }; |
| |
| /******************************** Named Framebuffer Invalidate Data Test Implementation ********************************/ |
| |
| /** @brief Named Framebuffer Invalidate Data Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| InvalidateDataTest::InvalidateDataTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_invalidate_data", "Framebuffer Invalidate Data Test") |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Named Framebuffer Read / Draw Buffer Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult InvalidateDataTest::iterate() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| /* Framebuffers' objects */ |
| glw::GLuint framebuffer = 0; |
| |
| /* Get number of color attachments. */ |
| glw::GLint max_color_attachments = 8 /* Specification minimum OpenGL 4.5 Core Profile p. 627 */; |
| |
| gl.getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv has failed"); |
| |
| std::vector<glw::GLuint> renderbuffers(max_color_attachments); |
| std::vector<glw::GLuint> color_attachments(max_color_attachments); |
| static const glw::GLenum default_attachments[] = { GL_COLOR, GL_DEPTH, GL_STENCIL }; |
| static const glw::GLuint default_attachments_count = sizeof(default_attachments) / sizeof(default_attachments[0]); |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| renderbuffers[i] = 0; |
| color_attachments[i] = GL_COLOR_ATTACHMENT0 + i; |
| } |
| |
| try |
| { |
| /* Invalidate Default Framebuffer data */ |
| gl.invalidateNamedFramebufferData(0, default_attachments_count, &(default_attachments[0])); |
| is_ok &= CheckErrorAndLog(default_attachments, default_attachments_count); |
| |
| for (glw::GLuint i = 0; i < default_attachments_count; ++i) |
| { |
| gl.invalidateNamedFramebufferData(0, 1, &(default_attachments[i])); |
| is_ok &= CheckErrorAndLog(default_attachments[i]); |
| } |
| |
| /* Prepare framebuffer... */ |
| gl.genFramebuffers(1, &framebuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers has failed"); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffers has failed"); |
| |
| gl.genRenderbuffers(max_color_attachments, &(renderbuffers[0])); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| /* .. with renderbuffer color attachments. */ |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| } |
| |
| /* Check that framebuffer is complete. */ |
| if (GL_FRAMEBUFFER_COMPLETE != gl.checkFramebufferStatus(GL_FRAMEBUFFER)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Framebuffer is unexpectedly incomplete." |
| << tcu::TestLog::EndMessage; |
| |
| throw 0; |
| } |
| |
| gl.invalidateNamedFramebufferData(framebuffer, max_color_attachments, &(color_attachments[0])); |
| is_ok &= CheckErrorAndLog(&(color_attachments[0]), max_color_attachments); |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.invalidateNamedFramebufferData(framebuffer, 1, &(color_attachments[i])); |
| is_ok &= CheckErrorAndLog(color_attachments[i]); |
| } |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| if (framebuffer) |
| { |
| gl.deleteFramebuffers(1, &framebuffer); |
| |
| framebuffer = 0; |
| } |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| if (renderbuffers[i]) |
| { |
| gl.deleteRenderbuffers(1, &(renderbuffers[i])); |
| } |
| } |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| /** @brief Check error and log. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * |
| * @return True if no error, false otherwise. |
| */ |
| bool InvalidateDataTest::CheckErrorAndLog(const glw::GLenum attachment) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check error. */ |
| if (glw::GLenum error = gl.getError()) |
| { |
| /* There is an error. Log. */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "InvalidateDataTest unexpectedly generated " |
| << glu::getErrorStr(error) << " error for attachment " |
| << glu::getFramebufferAttachmentStr(attachment) << ". Test fails." |
| << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Check error and log. |
| * |
| * @param [in] attachments Framebuffer attachments. |
| * @param [in] attachments_count Framebuffer attachments count. |
| * |
| * @return True if no error, false otherwise. |
| */ |
| bool InvalidateDataTest::CheckErrorAndLog(const glw::GLenum attachments[], glw::GLuint count) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check error. */ |
| if (glw::GLenum error = gl.getError()) |
| { |
| /* There is an error. Log. */ |
| std::string attachments_names = ""; |
| |
| for (glw::GLuint i = 0; i < count; ++i) |
| { |
| attachments_names.append(glu::getFramebufferAttachmentStr(attachments[i]).toString()); |
| |
| if ((count - 1) != i) |
| { |
| attachments_names.append(", "); |
| } |
| } |
| |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "InvalidateDataTest unexpectedly generated " |
| << glu::getErrorStr(error) << " error for following attachments [" |
| << attachments_names << "]. Test fails." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /******************************** Named Framebuffer Invalidate Sub Data Test Implementation ********************************/ |
| |
| /** @brief Named Framebuffer Invalidate Sub Data Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| InvalidateSubDataTest::InvalidateSubDataTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_invalidate_subdata", "Framebuffer Invalidate Sub Data Test") |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Named Framebuffer Read / Draw Buffer Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult InvalidateSubDataTest::iterate() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| /* Framebuffers' objects */ |
| glw::GLuint framebuffer = 0; |
| |
| /* Get number of color attachments. */ |
| glw::GLint max_color_attachments = 8 /* Specification minimum OpenGL 4.5 Core Profile p. 627 */; |
| |
| gl.getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv has failed"); |
| |
| std::vector<glw::GLuint> renderbuffers(max_color_attachments); |
| std::vector<glw::GLuint> color_attachments(max_color_attachments); |
| static const glw::GLenum default_attachments[] = { GL_COLOR, GL_DEPTH, GL_STENCIL }; |
| static const glw::GLuint default_attachments_count = sizeof(default_attachments) / sizeof(default_attachments[0]); |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| renderbuffers[i] = 0; |
| color_attachments[i] = GL_COLOR_ATTACHMENT0 + i; |
| } |
| |
| try |
| { |
| /* Invalidate Default Framebuffer data */ |
| gl.invalidateNamedFramebufferSubData(0, default_attachments_count, &(default_attachments[0]), 0, 0, 1, 1); |
| is_ok &= CheckErrorAndLog(default_attachments, default_attachments_count); |
| |
| for (glw::GLuint i = 0; i < default_attachments_count; ++i) |
| { |
| gl.invalidateNamedFramebufferSubData(0, 1, &(default_attachments[i]), 0, 0, 1, 1); |
| is_ok &= CheckErrorAndLog(default_attachments[i]); |
| } |
| |
| /* Prepare framebuffer... */ |
| gl.genFramebuffers(1, &framebuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers has failed"); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffers has failed"); |
| |
| gl.genRenderbuffers(max_color_attachments, &(renderbuffers[0])); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| /* .. with renderbuffer color attachments. */ |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, 4, 4); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| } |
| |
| /* Check that framebuffer is complete. */ |
| if (GL_FRAMEBUFFER_COMPLETE != gl.checkFramebufferStatus(GL_FRAMEBUFFER)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Framebuffer is unexpectedly incomplete." |
| << tcu::TestLog::EndMessage; |
| |
| throw 0; |
| } |
| |
| gl.invalidateNamedFramebufferSubData(framebuffer, max_color_attachments, &(color_attachments[0]), 1, 1, 2, 2); |
| is_ok &= CheckErrorAndLog(&(color_attachments[0]), max_color_attachments); |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.invalidateNamedFramebufferSubData(framebuffer, 1, &(color_attachments[i]), 1, 1, 2, 2); |
| is_ok &= CheckErrorAndLog(color_attachments[i]); |
| } |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| if (framebuffer) |
| { |
| gl.deleteFramebuffers(1, &framebuffer); |
| |
| framebuffer = 0; |
| } |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| if (renderbuffers[i]) |
| { |
| gl.deleteRenderbuffers(1, &(renderbuffers[i])); |
| } |
| } |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| /** @brief Check error and log. |
| * |
| * @param [in] attachment Framebuffer attachment. |
| * |
| * @return True if no error, false otherwise. |
| */ |
| bool InvalidateSubDataTest::CheckErrorAndLog(const glw::GLenum attachment) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check error. */ |
| if (glw::GLenum error = gl.getError()) |
| { |
| /* There is an error. Log. */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "InvalidateSubDataTest unexpectedly generated " |
| << glu::getErrorStr(error) << " error for attachment " |
| << glu::getFramebufferAttachmentStr(attachment) << ". Test fails." |
| << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Check error and log. |
| * |
| * @param [in] attachments Framebuffer attachments. |
| * @param [in] attachments_count Framebuffer attachments count. |
| * |
| * @return True if no error, false otherwise. |
| */ |
| bool InvalidateSubDataTest::CheckErrorAndLog(const glw::GLenum attachments[], glw::GLuint count) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check error. */ |
| if (glw::GLenum error = gl.getError()) |
| { |
| /* There is an error. Log. */ |
| std::string attachments_names = ""; |
| |
| for (glw::GLuint i = 0; i < count; ++i) |
| { |
| attachments_names.append(glu::getFramebufferAttachmentStr(attachments[i]).toString()); |
| |
| if ((count - 1) != i) |
| { |
| attachments_names.append(", "); |
| } |
| } |
| |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "InvalidateSubDataTest unexpectedly generated " |
| << glu::getErrorStr(error) << " error for following attachments [" |
| << attachments_names << "]. Test fails." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /******************************** Clear Named Framebuffer Test Implementation ********************************/ |
| |
| /** @brief Clear Named Framebuffer Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| ClearTest::ClearTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_clear", "Clear Named Framebuffer Test") |
| , m_fbo(0) |
| , m_renderbuffers(0) |
| , m_renderbuffers_count(0) |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Compare two floats (template specialization). |
| * |
| * @param [in] first First float to be compared. |
| * @param [in] second Second float to be compared. |
| * |
| * @return True if floats are equal within +-(1.f/64.f) precision range, false otherwise. |
| */ |
| template <> |
| bool ClearTest::Compare<glw::GLfloat>(const glw::GLfloat first, const glw::GLfloat second) |
| { |
| return (de::abs(first - second) < (1.f / 64.f) /* Precission. */); |
| } |
| |
| /** @brief Compare two objects (template general specialization). |
| * |
| * @param [in] first First objetc to be compared. |
| * @param [in] second Second object to be compared. |
| * |
| * @return True if floats are equal, false otherwise. |
| */ |
| template <typename T> |
| bool ClearTest::Compare(const T first, const T second) |
| { |
| return (first == second); |
| } |
| |
| /** @brief Clear color buffer (float specialization), check errors and log. |
| * |
| * @param [in] buffer Buffer to be cleared. |
| * @param [in] drawbuffer Drawbuffer to be cleared. |
| * @param [in] value Value to be cleared with. |
| * |
| * @return True if succeeded without errors, false otherwise. |
| */ |
| template <> |
| bool ClearTest::ClearColor<glw::GLfloat>(glw::GLenum buffer, glw::GLint drawbuffer, glw::GLfloat value) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| glw::GLfloat value_vector[4] = { value, 0, 0, 0 }; |
| |
| gl.clearNamedFramebufferfv(m_fbo, buffer, drawbuffer, value_vector); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "ClearNamedFramebufferfv unexpectedly generated " << glu::getErrorStr(error) |
| << " error. Test fails." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Clear color buffer (int specialization), check errors and log. |
| * |
| * @param [in] buffer Buffer to be cleared. |
| * @param [in] drawbuffer Drawbuffer to be cleared. |
| * @param [in] value Value to be cleared with. |
| * |
| * @return True if succeeded without errors, false otherwise. |
| */ |
| template <> |
| bool ClearTest::ClearColor<glw::GLint>(glw::GLenum buffer, glw::GLint drawbuffer, glw::GLint value) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| glw::GLint value_vector[4] = { value, 0, 0, 0 }; |
| |
| gl.clearNamedFramebufferiv(m_fbo, buffer, drawbuffer, value_vector); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "ClearNamedFramebufferiv unexpectedly generated " << glu::getErrorStr(error) |
| << " error. Test fails." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Clear color buffer (uint specialization), check errors and log. |
| * |
| * @param [in] buffer Buffer to be cleared. |
| * @param [in] drawbuffer Drawbuffer to be cleared. |
| * @param [in] value Value to be cleared with. |
| * |
| * @return True if succeeded without errors, false otherwise. |
| */ |
| template <> |
| bool ClearTest::ClearColor<glw::GLuint>(glw::GLenum buffer, glw::GLint drawbuffer, glw::GLuint value) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| glw::GLuint value_vector[4] = { value, 0, 0, 0 }; |
| |
| gl.clearNamedFramebufferuiv(m_fbo, buffer, drawbuffer, value_vector); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "ClearNamedFramebufferuiv unexpectedly generated " << glu::getErrorStr(error) |
| << " error. Test fails." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** @brief Format of the buffer (float specialization). |
| * |
| * @return Format. |
| */ |
| template <> |
| glw::GLenum ClearTest::Format<GLfloat>() |
| { |
| return GL_RED; |
| } |
| |
| /** @brief Format of the buffer (int and uint specialization). |
| * |
| * @return Format. |
| */ |
| template <typename T> |
| glw::GLenum ClearTest::Format() |
| { |
| return GL_RED_INTEGER; |
| } |
| |
| /** @brief Type of the buffer (float specialization). |
| * |
| * @return Type. |
| */ |
| template <> |
| glw::GLenum ClearTest::Type<glw::GLfloat>() |
| { |
| return GL_FLOAT; |
| } |
| |
| /** @brief Type of the buffer (int specialization). |
| * |
| * @return Type. |
| */ |
| template <> |
| glw::GLenum ClearTest::Type<glw::GLint>() |
| { |
| return GL_INT; |
| } |
| |
| /** @brief Type of the buffer (uint specialization). |
| * |
| * @return Type. |
| */ |
| template <> |
| glw::GLenum ClearTest::Type<glw::GLuint>() |
| { |
| return GL_UNSIGNED_INT; |
| } |
| |
| /** @brief Test DSA Clear function (color). |
| * |
| * @param [in] buffer Buffer to be cleared. |
| * @param [in] attachment Attachment to be tested. |
| * @param [in] value Value to be cleared with. |
| * |
| * @return True if test succeeded, false otherwise. |
| */ |
| template <typename T> |
| bool ClearTest::TestClearColor(glw::GLenum buffer, glw::GLenum attachment, T value) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.drawBuffer(attachment); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawBuffer has failed"); |
| |
| /* Clear. */ |
| if (ClearColor<T>(buffer, 0, value)) |
| { |
| /* Fetching framebuffer content. */ |
| T pixel = (T)0; |
| |
| gl.readBuffer(attachment); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadBuffer has failed"); |
| |
| gl.readPixels(0, 0, 1, 1, Format<T>(), Type<T>(), &pixel); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixel has failed"); |
| |
| /* Comparison with reference value. */ |
| if (Compare(pixel, value)) |
| { |
| return true; |
| } |
| |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "ClearNamedFramebuffer did not cleared color attachment " |
| << glu::getFramebufferAttachmentStr(attachment) << " of the framebuffer." << tcu::TestLog::EndMessage; |
| } |
| |
| return false; |
| } |
| |
| /** @brief Test DSA Clear function (depth/stencil). |
| * |
| * @param [in] stencil Stencil value to be cleared with. |
| * @param [in] depth Depth value to be cleared with. |
| * |
| * @return True if test succeeded, false otherwise. |
| */ |
| bool ClearTest::TestClearDepthAndStencil(glw::GLfloat depth, glw::GLint stencil) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Clearing depth and stencil. */ |
| gl.clearNamedFramebufferfi(m_fbo, GL_DEPTH_STENCIL, 0, depth, stencil); |
| |
| if (glw::GLenum error = gl.getError()) |
| { |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "ClearNamedFramebufferufi unexpectedly generated " << glu::getErrorStr(error) |
| << " error. Test fails." << tcu::TestLog::EndMessage; |
| |
| return false; |
| } |
| |
| /* Clear. */ |
| /* Fetching framebuffer content. */ |
| glw::GLfloat the_depth = 0.f; |
| glw::GLint the_stencil = 0; |
| |
| gl.readPixels(0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &the_depth); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixel has failed"); |
| |
| gl.readPixels(0, 0, 1, 1, GL_STENCIL_INDEX, GL_INT, &the_stencil); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixel has failed"); |
| |
| /* Comparison with reference value. */ |
| if (Compare(the_depth, depth) || Compare(the_stencil, stencil)) |
| { |
| return true; |
| } |
| |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message |
| << "ClearNamedFramebufferfi did not cleared depth/stencil attachment of the framebuffer." |
| << tcu::TestLog::EndMessage; |
| |
| return true; |
| } |
| |
| /** @brief Iterate Clear Named Framebuffer Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult ClearTest::iterate() |
| { |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| try |
| { |
| /* Fixed point color test. */ |
| PrepareFramebuffer(GL_COLOR, GL_R8); |
| |
| for (glw::GLint i = 0; i < (glw::GLint)m_renderbuffers_count; ++i) |
| { |
| is_ok &= TestClearColor<glw::GLfloat>(GL_COLOR, GL_COLOR_ATTACHMENT0 + i, 0.5); |
| } |
| |
| Clean(); |
| |
| /* Floating point color test. */ |
| PrepareFramebuffer(GL_COLOR, GL_R32F); |
| |
| for (glw::GLint i = 0; i < (glw::GLint)m_renderbuffers_count; ++i) |
| { |
| is_ok &= TestClearColor<glw::GLfloat>(GL_COLOR, GL_COLOR_ATTACHMENT0 + i, 0.5); |
| } |
| |
| Clean(); |
| |
| /* Signed integer color test. */ |
| PrepareFramebuffer(GL_COLOR, GL_R8I); |
| |
| for (glw::GLint i = 0; i < (glw::GLint)m_renderbuffers_count; ++i) |
| { |
| is_ok &= TestClearColor<glw::GLint>(GL_COLOR, GL_COLOR_ATTACHMENT0 + i, -16); |
| } |
| |
| Clean(); |
| |
| /* Unsigned integer color test. */ |
| PrepareFramebuffer(GL_COLOR, GL_R8UI); |
| |
| for (glw::GLint i = 0; i < (glw::GLint)m_renderbuffers_count; ++i) |
| { |
| is_ok &= TestClearColor<glw::GLuint>(GL_COLOR, GL_COLOR_ATTACHMENT0 + i, 16); |
| } |
| |
| Clean(); |
| |
| /* Depth / stencil test. */ |
| PrepareFramebuffer(GL_DEPTH_STENCIL, GL_DEPTH24_STENCIL8); |
| |
| is_ok &= TestClearDepthAndStencil(1, 1); |
| |
| Clean(); |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| Clean(); |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| /** @brief Prepare framebuffer. |
| * |
| * @param [in] buffer Buffer to be prepared. |
| * @param [in] internalformat Internal format to be prepared |
| */ |
| void ClearTest::PrepareFramebuffer(glw::GLenum buffer, glw::GLenum internalformat) |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Check that ther is no other fbo. */ |
| if ((0 != m_fbo) || (DE_NULL != m_renderbuffers)) |
| { |
| throw 0; |
| } |
| |
| /* Prepare framebuffer... */ |
| gl.genFramebuffers(1, &m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers has failed"); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffers has failed"); |
| |
| if (buffer == GL_COLOR) |
| { |
| glw::GLint max_color_attachments = |
| 8; /* OpenGL 4.5 specification default (see Implementation Dependent Values tables). */ |
| |
| gl.getIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv has failed"); |
| |
| m_renderbuffers = new glw::GLuint[max_color_attachments]; |
| |
| if (m_renderbuffers) |
| { |
| /* ... with renderbuffer color attachments. */ |
| |
| gl.genRenderbuffers(max_color_attachments, m_renderbuffers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| m_renderbuffers_count = max_color_attachments; |
| |
| for (glw::GLint i = 0; i < max_color_attachments; ++i) |
| { |
| gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, internalformat, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, |
| m_renderbuffers[i]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| } |
| } |
| } |
| |
| if (buffer == GL_DEPTH_STENCIL) |
| { |
| /* ... with depth and stencil attachments. */ |
| |
| m_renderbuffers = new glw::GLuint[1]; |
| |
| if (m_renderbuffers) |
| { |
| gl.genRenderbuffers(1, m_renderbuffers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers[0]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer has failed"); |
| |
| m_renderbuffers_count = 1; |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, internalformat, 1, 1); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, |
| m_renderbuffers[0]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| } |
| } |
| |
| /* Check that framebuffer is complete. */ |
| if (GL_FRAMEBUFFER_COMPLETE != gl.checkFramebufferStatus(GL_FRAMEBUFFER)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Framebuffer is unexpectedly incomplete." |
| << tcu::TestLog::EndMessage; |
| |
| throw 0; |
| } |
| } |
| |
| /** @brief Clean up GL state. |
| */ |
| void ClearTest::Clean() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Releasing objects. */ |
| if (m_fbo) |
| { |
| gl.deleteFramebuffers(1, &m_fbo); |
| |
| m_fbo = 0; |
| } |
| |
| if (DE_NULL != m_renderbuffers) |
| { |
| if (m_renderbuffers_count) |
| { |
| gl.deleteRenderbuffers(m_renderbuffers_count, m_renderbuffers); |
| } |
| |
| delete[] m_renderbuffers; |
| |
| m_renderbuffers = DE_NULL; |
| m_renderbuffers_count = 0; |
| } |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| } |
| |
| /******************************** Blit Named Framebuffer Test Implementation ********************************/ |
| |
| /** @brief Named Framebuffer blit Test constructor. |
| * |
| * @param [in] context OpenGL context. |
| */ |
| BlitTest::BlitTest(deqp::Context& context) |
| : deqp::TestCase(context, "framebuffers_blit", "Framebuffer Blit Test") |
| , m_fbo_src(0) |
| , m_rbo_color_src(0) |
| , m_rbo_depth_stencil_src(0) |
| , m_fbo_dst(0) |
| , m_rbo_color_dst(0) |
| , m_rbo_depth_stencil_dst(0) |
| { |
| /* Intentionally left blank. */ |
| } |
| |
| /** @brief Iterate Named Framebuffer Blit Test cases. |
| * |
| * @return Iteration result. |
| */ |
| tcu::TestNode::IterateResult BlitTest::iterate() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Get context setup. */ |
| bool is_at_least_gl_45 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5))); |
| bool is_arb_direct_state_access = m_context.getContextInfo().isExtensionSupported("GL_ARB_direct_state_access"); |
| |
| if ((!is_at_least_gl_45) && (!is_arb_direct_state_access)) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported"); |
| |
| return STOP; |
| } |
| |
| /* Running tests. */ |
| bool is_ok = true; |
| bool is_error = false; |
| |
| try |
| { |
| PrepareFramebuffers(); |
| |
| is_ok = Test(); |
| } |
| catch (...) |
| { |
| is_ok = false; |
| is_error = true; |
| } |
| |
| /* Cleanup. */ |
| Clean(); |
| |
| /* Errors clean up. */ |
| while (gl.getError()) |
| ; |
| |
| /* Result's setup. */ |
| if (is_ok) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| } |
| else |
| { |
| if (is_error) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Error"); |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| } |
| } |
| |
| return STOP; |
| } |
| |
| /** @brief Prepare framebuffer. |
| */ |
| void BlitTest::PrepareFramebuffers() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Prepare source framebuffer */ |
| gl.genFramebuffers(1, &m_fbo_src); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers has failed"); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_src); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffers has failed"); |
| |
| gl.genRenderbuffers(1, &m_rbo_color_src); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo_color_src); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffers has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 2, 2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo_color_src); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| |
| gl.genRenderbuffers(1, &m_rbo_depth_stencil_src); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo_depth_stencil_src); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffers has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 2, 2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_rbo_depth_stencil_src); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| |
| /* Check that framebuffer is complete. */ |
| if (GL_FRAMEBUFFER_COMPLETE != gl.checkFramebufferStatus(GL_FRAMEBUFFER)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Framebuffer is unexpectedly incomplete." |
| << tcu::TestLog::EndMessage; |
| |
| throw 0; |
| } |
| |
| /* Prepare destination framebuffer */ |
| gl.genFramebuffers(1, &m_fbo_dst); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers has failed"); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_dst); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffers has failed"); |
| |
| gl.genRenderbuffers(1, &m_rbo_color_dst); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo_color_dst); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffers has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 3, 2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo_color_dst); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| |
| gl.genRenderbuffers(1, &m_rbo_depth_stencil_dst); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers has failed"); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo_depth_stencil_dst); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffers has failed"); |
| |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 3, 2); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage has failed"); |
| |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_rbo_depth_stencil_dst); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer has failed"); |
| |
| /* Check that framebuffer is complete. */ |
| if (GL_FRAMEBUFFER_COMPLETE != gl.checkFramebufferStatus(GL_FRAMEBUFFER)) |
| { |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "Framebuffer is unexpectedly incomplete." |
| << tcu::TestLog::EndMessage; |
| |
| throw 0; |
| } |
| } |
| |
| /** @brief Do the blit test. |
| */ |
| bool BlitTest::Test() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_src); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| ClearFramebuffer(1.f, 0.f, 0.f, 0.5f, 1); |
| |
| gl.blitNamedFramebuffer(m_fbo_src, m_fbo_dst, 0, 0, 1, 1, 0, 0, 1, 1, |
| GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| if (CheckErrorAndLog()) |
| { |
| ClearFramebuffer(0.f, 1.f, 0.f, 0.25f, 2); |
| |
| gl.blitNamedFramebuffer(m_fbo_src, m_fbo_dst, 0, 0, 1, 1, 1, 0, 2, 1, GL_COLOR_BUFFER_BIT, GL_LINEAR); |
| gl.blitNamedFramebuffer(m_fbo_src, m_fbo_dst, 0, 0, 1, 1, 1, 0, 2, 1, |
| GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| if (CheckErrorAndLog()) |
| { |
| ClearFramebuffer(0.f, 0.f, 1.f, 0.125f, 3); |
| |
| gl.blitNamedFramebuffer(m_fbo_src, m_fbo_dst, 0, 0, 2, 2, 2, 0, 3, 1, |
| GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| if (CheckErrorAndLog()) |
| { |
| ClearFramebuffer(1.f, 1.f, 0.f, 0.0625f, 4); |
| |
| gl.blitNamedFramebuffer(m_fbo_src, m_fbo_dst, 0, 0, 1, 1, 0, 1, 3, 2, |
| GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); |
| |
| if (CheckErrorAndLog()) |
| { |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo_dst); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer has failed"); |
| |
| if (CheckColor() && CheckDepth() && CheckStencil()) |
| { |
| return true; |
| } |
| } |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| /** @brief Check error and log. |
| * |
| * @return true if no error, false otherwise. |
| */ |
| bool BlitTest::CheckErrorAndLog() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Error query. */ |
| if (glw::GLenum error = gl.getError()) |
| { |
| /* Log. */ |
| m_context.getTestContext().getLog() << tcu::TestLog::Message << "BlitNamedFramebuffer unexpectedly generated " |
| << glu::getErrorStr(error) << " error." << tcu::TestLog::EndMessage; |
| |
| /* Returning result. */ |
| return false; |
| } |
| |
| /* Returning result. */ |
| return true; |
| } |
| |
| /** @brief Check color and log. |
| * |
| * @return true if color matches reference, false otherwise. |
| */ |
| bool BlitTest::CheckColor() |
| { |
| /* Shortcut for GL functionality. */ |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| /* Reference values. */ |
| static const glw::GLfloat reference[2][3][4] = { |
| { { 1.f, 0.f, 0.f, 1.f }, { 0.f, 1.f, 0.f, 1.f }, { 0.f, 0.f, 1.f, 1.f } }, |
| { { 1.f, 1.f, 0.f, 1.f }, { 1.f, 1.f, 0.f, 1.f }, { 1.f, 1.f, 0.f, 1.f } } |
| }; |
| |
| /* Copy buffer. */ |
| glw::GLfloat color[2][3][4] = { { { 0 } } }; |
| |
| /* Reading from GL. */ |
| gl.readPixels(0, 0, 3, 2, GL_RGBA, GL_FLOAT, color); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels has failed"); |
| |
| /* Comparison against the reference. */ |
| for (glw::GLuint j = 0; j < 2; ++j) |
| { |
| for (glw::GLuint i = 0; i < 3; ++i) |
| { |
| for (glw::GLuint k = 0; k < 4; ++k) |
| { |
| if (de::abs(reference[j][i][k] - color[j][i][k]) > (1.f / 64.f) /* Precision. */) |
| { |
| /* Log. */ |
| m_context.getTestContext().getLog() |
| << tcu::TestLog::Message << "Blitted framebuffer color buffer contains [[" << color[0][0][0] |
| << ", " << color[0][0][1] << ", " << color[0][0][2] << ", " << color[0][0][3] << "], [" |
| << color[0][1][0] << ", " << color[0][1][1] << ", " << color[0][1][2] << ", " << color[0][1][3] |
| << "], [" << color[0][2][0] << ", " << color[0][2][1] << ", " << color[0][2][2] << ", " |
| << color[0][2][3] << "],\n[" << color[1][0][0] << ", " << color[1][0][1] << ", " |
| << color[1][0][2] << ", " << color[1][0][3] << "], [" << color[1][1][0] << ", " |
| << color[1][1][1] << ", " << color[1][1][2] << ", " << color[1][1][3] << "], [" |
| << color[1][2][0] << ", " << color[1][2][1] << ", " << color[1][2][2] << ", " << color[1][2][3] |
| << "]], but\n" |
| << reference[0][0][0] << ", " << reference[0][0][1] << ", " << reference[0][0][2] << ", " |
| << reference[0][0][3] << "], [" << reference[0][1][0] << ", " << reference[0][1][1] << ", " |
| << reference[0][1][2] << ", " << reference[ |