| /*------------------------------------------------------------------------- |
| * 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 esextcDrawBuffersIndexedColorMasks.hpp |
| * \brief Draw Buffers Indexed tests 4. Color masks |
| */ /*-------------------------------------------------------------------*/ |
| |
| #include "esextcDrawBuffersIndexedColorMasks.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluShaderProgram.hpp" |
| #include "tcuTestLog.hpp" |
| #include <cmath> |
| |
| namespace glcts |
| { |
| |
| /** Constructor |
| * |
| * @param context Test context |
| * @param name Test case's name |
| * @param description Test case's description |
| **/ |
| DrawBuffersIndexedColorMasks::DrawBuffersIndexedColorMasks(Context& context, const ExtParameters& extParams, |
| const char* name, const char* description) |
| : DrawBuffersIndexedBase(context, extParams, name, description) |
| , m_fbo(0) |
| { |
| /* Left blank on purpose */ |
| } |
| |
| void DrawBuffersIndexedColorMasks::prepareFramebuffer() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| glw::GLint maxDrawBuffers = 0; |
| gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| if (maxDrawBuffers < 4) |
| { |
| throw tcu::ResourceError("Minimum number of draw buffers too low"); |
| } |
| |
| gl.genFramebuffers(1, &m_fbo); |
| gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); |
| |
| std::vector<glw::GLenum> bufs(maxDrawBuffers); |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| bufs[i] = GL_COLOR_ATTACHMENT0 + i; |
| } |
| gl.drawBuffers(maxDrawBuffers, &bufs[0]); |
| |
| gl.disable(GL_DITHER); |
| } |
| |
| void DrawBuffersIndexedColorMasks::releaseFramebuffer() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| glw::GLint maxDrawBuffers = 0; |
| gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| if (maxDrawBuffers < 4) |
| { |
| throw tcu::ResourceError("Minimum number of draw buffers too low"); |
| } |
| |
| BlendMaskStateMachine state(m_context, m_testCtx.getLog(), maxDrawBuffers); |
| state.SetDefaults(); |
| gl.deleteFramebuffers(1, &m_fbo); |
| gl.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| glw::GLenum bufs[1] = { GL_BACK }; |
| gl.drawBuffers(1, bufs); |
| gl.readBuffer(GL_BACK); |
| } |
| |
| tcu::TestNode::IterateResult DrawBuffersIndexedColorMasks::iterate() |
| { |
| static const glw::GLenum WriteMasksFormats[] = { GL_R8, GL_RG8, GL_RGB8, GL_RGB565, GL_RGBA4, |
| GL_RGB5_A1, GL_RGBA8, GL_R8I, GL_R8UI, GL_R16I, |
| GL_R16UI, GL_R32I, GL_R32UI, GL_RG8I, GL_RG8UI, |
| GL_RG16I, GL_RG16UI, GL_RG32I, GL_RG32UI, GL_RGBA8I, |
| GL_RGBA8UI, GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI }; |
| static const int kSize = 32; |
| static unsigned int formatId = 0; |
| |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| glw::GLenum format = WriteMasksFormats[formatId]; |
| |
| prepareFramebuffer(); |
| |
| // Check number of available draw buffers |
| glw::GLint maxDrawBuffers = 0; |
| gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| if (maxDrawBuffers < 4) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Minimum number of draw buffers too low"); |
| return STOP; |
| } |
| |
| // Prepare render targets |
| glw::GLuint tex; |
| gl.genTextures(1, &tex); |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, tex); |
| gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, format, kSize, kSize, maxDrawBuffers); |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, tex, 0, i); |
| } |
| |
| // Clear all buffers |
| switch (ReadableType(format)) |
| { |
| case GL_UNSIGNED_BYTE: |
| { |
| tcu::Vec4 c0(0.15f, 0.3f, 0.45f, 0.6f); |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| gl.clearBufferfv(GL_COLOR, i, &c0[0]); |
| } |
| break; |
| } |
| case GL_UNSIGNED_INT: |
| { |
| tcu::UVec4 c0(2, 3, 4, 5); |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| gl.clearBufferuiv(GL_COLOR, i, &c0[0]); |
| } |
| break; |
| } |
| case GL_INT: |
| { |
| tcu::IVec4 c0(2, 3, 4, 5); |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| gl.clearBufferiv(GL_COLOR, i, &c0[0]); |
| } |
| break; |
| } |
| } |
| |
| // Set color masks for each buffer |
| BlendMaskStateMachine state(m_context, m_testCtx.getLog(), maxDrawBuffers); |
| |
| glw::GLboolean mask[] = { GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE }; |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| mask[i % 4] = GL_TRUE; |
| state.SetColorMaski(i, mask[0], mask[1], mask[2], mask[3]); |
| mask[i % 4] = GL_FALSE; |
| } |
| |
| // Clear all buffers |
| switch (ReadableType(format)) |
| { |
| case GL_UNSIGNED_BYTE: |
| { |
| tcu::Vec4 c1(0.85f, 0.85f, 0.85f, 0.85f); |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| gl.clearBufferfv(GL_COLOR, i, &c1[0]); |
| } |
| break; |
| } |
| case GL_UNSIGNED_INT: |
| { |
| tcu::UVec4 c1(23, 23, 23, 23); |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| gl.clearBufferuiv(GL_COLOR, i, &c1[0]); |
| } |
| break; |
| } |
| case GL_INT: |
| { |
| tcu::IVec4 c1(23, 23, 23, 23); |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| gl.clearBufferiv(GL_COLOR, i, &c1[0]); |
| } |
| break; |
| } |
| } |
| |
| // Verify color |
| int numComponents = NumComponents(format); |
| tcu::RGBA epsilon = GetEpsilon(); |
| bool success = true; |
| |
| for (int i = 0; i < maxDrawBuffers; ++i) |
| { |
| gl.readBuffer(GL_COLOR_ATTACHMENT0 + i); |
| |
| switch (ReadableType(format)) |
| { |
| case GL_UNSIGNED_BYTE: |
| { |
| tcu::UVec4 e(static_cast<unsigned int>(0.15f * 255), static_cast<unsigned int>(0.30f * 255), |
| static_cast<unsigned int>(0.45f * 255), static_cast<unsigned int>(0.60f * 255)); |
| e[i % 4] = static_cast<unsigned int>(0.85f * 255); |
| e = tcu::UVec4(e.x(), numComponents >= 2 ? e.y() : 0, numComponents >= 3 ? e.z() : 0, |
| numComponents == 4 ? e.w() : 255); |
| tcu::RGBA expected(e.x(), e.y(), e.z(), e.w()); |
| |
| std::vector<unsigned char> rendered(kSize * kSize * 4, 45); |
| |
| tcu::TextureLevel textureLevel(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), |
| kSize, kSize); |
| glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess()); |
| |
| if (!VerifyImg(textureLevel, expected, epsilon)) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Write mask error in texture format " << format |
| << " occurred for buffer #" << i << "\n" |
| << tcu::TestLog::EndMessage; |
| m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess()); |
| success = false; |
| } |
| break; |
| } |
| case GL_UNSIGNED_INT: |
| { |
| tcu::UVec4 e(2, 3, 4, 5); |
| e[i % 4] = 23; |
| e = tcu::UVec4(e.x(), numComponents >= 2 ? e.y() : 0, numComponents >= 3 ? e.z() : 0, |
| numComponents == 4 ? e.w() : 1); |
| tcu::RGBA expected(e.x(), e.y(), e.z(), e.w()); |
| |
| tcu::TextureLevel textureLevel( |
| tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32), kSize, kSize); |
| glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess()); |
| |
| if (!VerifyImg(textureLevel, expected, epsilon)) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Write mask error in texture format " << format |
| << " occurred for buffer #" << i << "\n" |
| << tcu::TestLog::EndMessage; |
| m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess()); |
| success = false; |
| } |
| break; |
| } |
| case GL_INT: |
| { |
| tcu::UVec4 e(2, 3, 4, 5); |
| e[i % 4] = 23; |
| e = tcu::UVec4(e.x(), numComponents >= 2 ? e.y() : 0, numComponents >= 3 ? e.z() : 0, |
| numComponents == 4 ? e.w() : 1); |
| tcu::RGBA expected(e.x(), e.y(), e.z(), e.w()); |
| |
| tcu::TextureLevel textureLevel( |
| tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32), kSize, kSize); |
| glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess()); |
| |
| if (!VerifyImg(textureLevel, expected, epsilon)) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Write mask error in texture format " << format |
| << " occurred for buffer #" << i << "\n" |
| << tcu::TestLog::EndMessage; |
| m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess()); |
| success = false; |
| } |
| break; |
| } |
| } |
| } |
| |
| gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0); |
| gl.deleteTextures(1, &tex); |
| releaseFramebuffer(); |
| |
| // Check for error |
| glw::GLenum error_code = gl.getError(); |
| if (error_code != GL_NO_ERROR) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Some functions generated error"); |
| formatId = 0; |
| return STOP; |
| } |
| |
| if (!success) |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Write mask error occurred"); |
| formatId = 0; |
| return STOP; |
| } |
| else |
| { |
| ++formatId; |
| if (formatId < (sizeof(WriteMasksFormats) / sizeof(WriteMasksFormats[0]))) |
| { |
| return CONTINUE; |
| } |
| else |
| { |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| formatId = 0; |
| return STOP; |
| } |
| } |
| } |
| |
| unsigned int DrawBuffersIndexedColorMasks::NumComponents(glw::GLenum format) |
| { |
| switch (format) |
| { |
| case GL_R8: |
| case GL_R8I: |
| case GL_R8UI: |
| case GL_R16I: |
| case GL_R16UI: |
| case GL_R32I: |
| case GL_R32UI: |
| return 1; |
| case GL_RG8: |
| case GL_RG8I: |
| case GL_RG8UI: |
| case GL_RG16I: |
| case GL_RG16UI: |
| case GL_RG32I: |
| case GL_RG32UI: |
| return 2; |
| case GL_RGB8: |
| case GL_RGB565: |
| return 3; |
| case GL_RGBA4: |
| case GL_RGB5_A1: |
| case GL_RGBA8: |
| case GL_RGB10_A2: |
| case GL_RGBA8I: |
| case GL_RGBA8UI: |
| case GL_RGBA16I: |
| case GL_RGBA16UI: |
| case GL_RGBA32I: |
| case GL_RGBA32UI: |
| return 4; |
| default: |
| return 0; |
| } |
| } |
| |
| glw::GLenum DrawBuffersIndexedColorMasks::ReadableType(glw::GLenum format) |
| { |
| switch (format) |
| { |
| case GL_R8: |
| case GL_RG8: |
| case GL_RGB8: |
| case GL_RGB565: |
| case GL_RGBA4: |
| case GL_RGB5_A1: |
| case GL_RGBA8: |
| case GL_RGB10_A2: |
| return GL_UNSIGNED_BYTE; |
| |
| case GL_R8I: |
| case GL_R16I: |
| case GL_R32I: |
| case GL_RG8I: |
| case GL_RG16I: |
| case GL_RG32I: |
| case GL_RGBA8I: |
| case GL_RGBA16I: |
| case GL_RGBA32I: |
| return GL_INT; |
| |
| case GL_R8UI: |
| case GL_R16UI: |
| case GL_R32UI: |
| case GL_RG8UI: |
| case GL_RG16UI: |
| case GL_RG32UI: |
| case GL_RGB10_A2UI: |
| case GL_RGBA8UI: |
| case GL_RGBA16UI: |
| case GL_RGBA32UI: |
| return GL_UNSIGNED_INT; |
| |
| default: |
| return 0; |
| } |
| } |
| |
| tcu::RGBA DrawBuffersIndexedColorMasks::GetEpsilon() |
| { |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| |
| tcu::IVec4 bits; |
| tcu::UVec4 epsilon; |
| |
| for (int i = 0; i < 4; ++i) |
| { |
| gl.getIntegerv(GL_RED_BITS + i, &bits[i]); |
| epsilon[i] = de::min( |
| 255u, static_cast<unsigned int>(ceil(1.0 + 255.0 * (1.0 / pow(2.0, static_cast<double>(bits[i])))))); |
| } |
| |
| return tcu::RGBA(epsilon.x(), epsilon.y(), epsilon.z(), epsilon.w()); |
| } |
| |
| bool DrawBuffersIndexedColorMasks::VerifyImg(const tcu::TextureLevel& textureLevel, tcu::RGBA expectedColor, |
| tcu::RGBA epsilon) |
| { |
| for (int y = 0; y < textureLevel.getHeight(); ++y) |
| { |
| for (int x = 0; x < textureLevel.getWidth(); ++x) |
| { |
| tcu::IVec4 color(textureLevel.getAccess().getPixelInt(x, y)); |
| tcu::RGBA pixel(color.x(), color.y(), color.z(), color.w()); |
| |
| if (!tcu::compareThreshold(pixel, expectedColor, epsilon)) |
| { |
| m_testCtx.getLog() << tcu::TestLog::Message << "Expected value: " << expectedColor << "\n" |
| << "Read value: " << pixel << "\n" |
| << "Epsilon: " << epsilon << tcu::TestLog::EndMessage; |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| } // namespace glcts |