| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL ES 3.1 Module |
| * ------------------------------------------------- |
| * |
| * Copyright 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Indexed blend operation tests (GL_EXT_draw_buffers_indexed) |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es31fDrawBuffersIndexedTests.hpp" |
| |
| #include "gluContextInfo.hpp" |
| #include "gluDrawUtil.hpp" |
| #include "gluObjectWrapper.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluShaderProgram.hpp" |
| #include "gluStrUtil.hpp" |
| #include "gluTextureUtil.hpp" |
| |
| #include "sglrReferenceUtils.hpp" |
| |
| #include "rrMultisamplePixelBufferAccess.hpp" |
| #include "rrRenderer.hpp" |
| |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| |
| #include "tcuEither.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuMaybe.hpp" |
| #include "tcuResultCollector.hpp" |
| #include "tcuStringTemplate.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuTexture.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuVector.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "tcuFloat.hpp" |
| |
| #include "deRandom.hpp" |
| #include "deArrayUtil.hpp" |
| #include "deStringUtil.hpp" |
| #include "deUniquePtr.hpp" |
| |
| #include "deInt32.h" |
| |
| #include <string> |
| #include <vector> |
| #include <map> |
| |
| using tcu::BVec4; |
| using tcu::Either; |
| using tcu::IVec2; |
| using tcu::IVec4; |
| using tcu::Maybe; |
| using tcu::TestLog; |
| using tcu::TextureFormat; |
| using tcu::TextureLevel; |
| using tcu::UVec4; |
| using tcu::Vec2; |
| using tcu::Vec4; |
| using tcu::just; |
| |
| using std::string; |
| using std::vector; |
| using std::map; |
| |
| using sglr::rr_util::mapGLBlendEquation; |
| using sglr::rr_util::mapGLBlendFunc; |
| using sglr::rr_util::mapGLBlendEquationAdvanced; |
| |
| namespace deqp |
| { |
| namespace gles31 |
| { |
| namespace Functional |
| { |
| namespace |
| { |
| |
| typedef deUint32 BlendEq; |
| |
| bool isAdvancedBlendEq (BlendEq eq) |
| { |
| switch (eq) |
| { |
| case GL_MULTIPLY: return true; |
| case GL_SCREEN: return true; |
| case GL_OVERLAY: return true; |
| case GL_DARKEN: return true; |
| case GL_LIGHTEN: return true; |
| case GL_COLORDODGE: return true; |
| case GL_COLORBURN: return true; |
| case GL_HARDLIGHT: return true; |
| case GL_SOFTLIGHT: return true; |
| case GL_DIFFERENCE: return true; |
| case GL_EXCLUSION: return true; |
| case GL_HSL_HUE: return true; |
| case GL_HSL_SATURATION: return true; |
| case GL_HSL_COLOR: return true; |
| case GL_HSL_LUMINOSITY: return true; |
| default: |
| return false; |
| } |
| } |
| |
| struct SeparateBlendEq |
| { |
| SeparateBlendEq (BlendEq rgb_, BlendEq alpha_) |
| : rgb (rgb_) |
| , alpha (alpha_) |
| { |
| } |
| |
| BlendEq rgb; |
| BlendEq alpha; |
| }; |
| |
| struct BlendFunc |
| { |
| BlendFunc (deUint32 src_, deUint32 dst_) |
| : src (src_) |
| , dst (dst_) |
| { |
| } |
| |
| deUint32 src; |
| deUint32 dst; |
| }; |
| |
| struct SeparateBlendFunc |
| { |
| SeparateBlendFunc (BlendFunc rgb_, BlendFunc alpha_) |
| : rgb (rgb_) |
| , alpha (alpha_) |
| { |
| } |
| |
| BlendFunc rgb; |
| BlendFunc alpha; |
| }; |
| |
| typedef deUint32 DrawBuffer; |
| |
| struct BlendState |
| { |
| BlendState (void) {} |
| |
| BlendState (const Maybe<bool>& enableBlend_, |
| const Maybe<Either<BlendEq, SeparateBlendEq> >& blendEq_, |
| const Maybe<Either<BlendFunc, SeparateBlendFunc> >& blendFunc_, |
| const Maybe<BVec4>& colorMask_) |
| : enableBlend (enableBlend_) |
| , blendEq (blendEq_) |
| , blendFunc (blendFunc_) |
| , colorMask (colorMask_) |
| { |
| } |
| |
| bool isEmpty (void) const |
| { |
| return (!enableBlend) && (!blendEq) && (!blendFunc) && (!colorMask); |
| } |
| |
| Maybe<bool> enableBlend; |
| Maybe<Either<BlendEq, SeparateBlendEq> > blendEq; |
| Maybe<Either<BlendFunc, SeparateBlendFunc> > blendFunc; |
| Maybe<BVec4> colorMask; |
| }; |
| |
| void setCommonBlendState (const glw::Functions& gl, const BlendState& blend) |
| { |
| if (blend.enableBlend) |
| { |
| if (*blend.enableBlend) |
| gl.enable(GL_BLEND); |
| else |
| gl.disable(GL_BLEND); |
| } |
| |
| if (blend.colorMask) |
| { |
| const BVec4& mask = *blend.colorMask; |
| |
| gl.colorMask(mask.x(), mask.y(), mask.z(), mask.w()); |
| } |
| |
| if (blend.blendEq) |
| { |
| const Either<BlendEq, SeparateBlendEq>& blendEq = *blend.blendEq; |
| |
| if (blendEq.is<BlendEq>()) |
| gl.blendEquation(blendEq.get<BlendEq>()); |
| else if (blendEq.is<SeparateBlendEq>()) |
| gl.blendEquationSeparate(blendEq.get<SeparateBlendEq>().rgb, blendEq.get<SeparateBlendEq>().alpha); |
| else |
| DE_ASSERT(false); |
| } |
| |
| if (blend.blendFunc) |
| { |
| const Either<BlendFunc, SeparateBlendFunc>& blendFunc = *blend.blendFunc; |
| |
| if (blendFunc.is<BlendFunc>()) |
| gl.blendFunc(blendFunc.get<BlendFunc>().src, blendFunc.get<BlendFunc>().dst); |
| else if (blendFunc.is<SeparateBlendFunc>()) |
| gl.blendFuncSeparate(blendFunc.get<SeparateBlendFunc>().rgb.src, blendFunc.get<SeparateBlendFunc>().rgb.dst, blendFunc.get<SeparateBlendFunc>().alpha.src, blendFunc.get<SeparateBlendFunc>().alpha.dst); |
| else |
| DE_ASSERT(false); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set common blend state."); |
| } |
| |
| void setIndexedBlendState (const glw::Functions& gl, const BlendState& blend, deUint32 index) |
| { |
| if (blend.enableBlend) |
| { |
| if (*blend.enableBlend) |
| gl.enablei(GL_BLEND, index); |
| else |
| gl.disablei(GL_BLEND, index); |
| } |
| |
| if (blend.colorMask) |
| { |
| const BVec4 mask = *blend.colorMask; |
| |
| gl.colorMaski(index, mask.x(), mask.y(), mask.z(), mask.w()); |
| } |
| |
| if (blend.blendEq) |
| { |
| const Either<BlendEq, SeparateBlendEq>& blendEq = *blend.blendEq; |
| |
| if (blendEq.is<BlendEq>()) |
| gl.blendEquationi(index, blendEq.get<BlendEq>()); |
| else if (blendEq.is<SeparateBlendEq>()) |
| gl.blendEquationSeparatei(index, blendEq.get<SeparateBlendEq>().rgb, blendEq.get<SeparateBlendEq>().alpha); |
| else |
| DE_ASSERT(false); |
| } |
| |
| if (blend.blendFunc) |
| { |
| const Either<BlendFunc, SeparateBlendFunc>& blendFunc = *blend.blendFunc; |
| |
| if (blendFunc.is<BlendFunc>()) |
| gl.blendFunci(index, blendFunc.get<BlendFunc>().src, blendFunc.get<BlendFunc>().dst); |
| else if (blendFunc.is<SeparateBlendFunc>()) |
| gl.blendFuncSeparatei(index, blendFunc.get<SeparateBlendFunc>().rgb.src, blendFunc.get<SeparateBlendFunc>().rgb.dst, blendFunc.get<SeparateBlendFunc>().alpha.src, blendFunc.get<SeparateBlendFunc>().alpha.dst); |
| else |
| DE_ASSERT(false); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set draw buffer specifig blend state."); |
| } |
| |
| class DrawBufferInfo |
| { |
| public: |
| DrawBufferInfo (bool render, |
| const IVec2& size, |
| const BlendState& blendState, |
| const TextureFormat& format); |
| |
| const TextureFormat& getFormat (void) const { return m_format; } |
| const IVec2& getSize (void) const { return m_size; } |
| const BlendState& getBlendState (void) const { return m_blendState; } |
| bool getRender (void) const { return m_render; } |
| |
| private: |
| bool m_render; |
| IVec2 m_size; |
| TextureFormat m_format; |
| BlendState m_blendState; |
| }; |
| |
| DrawBufferInfo::DrawBufferInfo (bool render, const IVec2& size, const BlendState& blendState, const TextureFormat& format) |
| : m_render (render) |
| , m_size (size) |
| , m_format (format) |
| , m_blendState (blendState) |
| { |
| } |
| |
| void clearRenderbuffer (const glw::Functions& gl, |
| const tcu::TextureFormat& format, |
| int renderbufferNdx, |
| int renderbufferCount, |
| tcu::TextureLevel& refRenderbuffer) |
| { |
| const tcu::TextureFormatInfo info = tcu::getTextureFormatInfo(format); |
| |
| // Clear each buffer to different color |
| const float redScale = float(renderbufferNdx + 1) / float(renderbufferCount); |
| const float blueScale = float(renderbufferCount - renderbufferNdx) / float(renderbufferCount); |
| const float greenScale = float(((renderbufferCount/2) + renderbufferNdx) % renderbufferCount) / float(renderbufferCount); |
| // Alpha should never be zero as advanced blend equations assume premultiplied alpha. |
| const float alphaScale = float(1 + (((renderbufferCount/2) + renderbufferCount - renderbufferNdx) % renderbufferCount)) / float(renderbufferCount); |
| |
| switch (tcu::getTextureChannelClass(format.type)) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| { |
| const float red = -1000.0f + 2000.0f * redScale; |
| const float green = -1000.0f + 2000.0f * greenScale; |
| const float blue = -1000.0f + 2000.0f * blueScale; |
| const float alpha = -1000.0f + 2000.0f * alphaScale; |
| const Vec4 color (red, green, blue, alpha); |
| |
| tcu::clear(refRenderbuffer, color); |
| gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr()); |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| { |
| const deInt32 red = deInt32(info.valueMin.x() + (info.valueMax.x() - info.valueMin.x()) * redScale); |
| const deInt32 green = deInt32(info.valueMin.y() + (info.valueMax.y() - info.valueMin.y()) * greenScale); |
| const deInt32 blue = deInt32(info.valueMin.z() + (info.valueMax.z() - info.valueMin.z()) * blueScale); |
| const deInt32 alpha = deInt32(info.valueMin.w() + (info.valueMax.w() - info.valueMin.w()) * alphaScale); |
| const IVec4 color (red, green, blue, alpha); |
| |
| tcu::clear(refRenderbuffer, color); |
| gl.clearBufferiv(GL_COLOR, renderbufferNdx, color.getPtr()); |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| { |
| const deUint32 red = deUint32(info.valueMax.x() * redScale); |
| const deUint32 green = deUint32(info.valueMax.y() * greenScale); |
| const deUint32 blue = deUint32(info.valueMax.z() * blueScale); |
| const deUint32 alpha = deUint32(info.valueMax.w() * alphaScale); |
| const UVec4 color (red, green, blue, alpha); |
| |
| tcu::clear(refRenderbuffer, color); |
| gl.clearBufferuiv(GL_COLOR, renderbufferNdx, color.getPtr()); |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| { |
| const float red = info.valueMin.x() + (info.valueMax.x() - info.valueMin.x()) * redScale; |
| const float green = info.valueMin.y() + (info.valueMax.y() - info.valueMin.y()) * greenScale; |
| const float blue = info.valueMin.z() + (info.valueMax.z() - info.valueMin.z()) * blueScale; |
| const float alpha = info.valueMin.w() + (info.valueMax.w() - info.valueMin.w()) * alphaScale; |
| const Vec4 color (red, green, blue, alpha); |
| |
| tcu::clear(refRenderbuffer, color); |
| gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr()); |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| { |
| const float red = info.valueMax.x() * redScale; |
| const float green = info.valueMax.y() * greenScale; |
| const float blue = info.valueMax.z() * blueScale; |
| const float alpha = info.valueMax.w() * alphaScale; |
| const Vec4 color (red, green, blue, alpha); |
| |
| tcu::clear(refRenderbuffer, color); |
| gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr()); |
| break; |
| } |
| |
| default: |
| DE_ASSERT(DE_FALSE); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear renderbuffer."); |
| } |
| |
| void genRenderbuffers (const glw::Functions& gl, |
| const vector<DrawBufferInfo>& drawBuffers, |
| const glu::Framebuffer& framebuffer, |
| const glu::RenderbufferVector& renderbuffers, |
| vector<TextureLevel>& refRenderbuffers) |
| { |
| vector<deUint32> bufs; |
| |
| bufs.resize(drawBuffers.size()); |
| |
| DE_ASSERT(drawBuffers.size() == renderbuffers.size()); |
| DE_ASSERT(drawBuffers.size() == refRenderbuffers.size()); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer); |
| |
| for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++) |
| { |
| const DrawBufferInfo& drawBuffer = drawBuffers[renderbufferNdx]; |
| const TextureFormat& format = drawBuffer.getFormat(); |
| const IVec2& size = drawBuffer.getSize(); |
| const deUint32 glFormat = glu::getInternalFormat(format); |
| |
| bufs[renderbufferNdx] = GL_COLOR_ATTACHMENT0 + renderbufferNdx; |
| refRenderbuffers[renderbufferNdx] = TextureLevel(drawBuffer.getFormat(), size.x(), size.y()); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffers[renderbufferNdx]); |
| gl.renderbufferStorage(GL_RENDERBUFFER, glFormat, size.x(), size.y()); |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + renderbufferNdx, GL_RENDERBUFFER, renderbuffers[renderbufferNdx]); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create renderbuffer."); |
| } |
| |
| gl.drawBuffers((glw::GLsizei)bufs.size(), &(bufs[0])); |
| |
| for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++) |
| { |
| const DrawBufferInfo& drawBuffer = drawBuffers[renderbufferNdx]; |
| const TextureFormat& format = drawBuffer.getFormat(); |
| |
| clearRenderbuffer(gl, format, renderbufferNdx, (int)refRenderbuffers.size(), refRenderbuffers[renderbufferNdx]); |
| } |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, 0); |
| gl.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| } |
| |
| Vec4 getFixedPointFormatThreshold (const tcu::TextureFormat& sourceFormat, const tcu::TextureFormat& readPixelsFormat) |
| { |
| DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT); |
| DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT); |
| |
| DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER); |
| DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER); |
| |
| DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER); |
| DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER); |
| |
| const tcu::IVec4 srcBits = tcu::getTextureFormatBitDepth(sourceFormat); |
| const tcu::IVec4 readBits = tcu::getTextureFormatBitDepth(readPixelsFormat); |
| |
| return Vec4(3.0f) / ((tcu::Vector<deUint64, 4>(1) << (tcu::min(srcBits, readBits).cast<deUint64>())) - tcu::Vector<deUint64, 4>(1)).cast<float>(); |
| } |
| |
| UVec4 getFloatULPThreshold (const tcu::TextureFormat& sourceFormat, const tcu::TextureFormat& readPixelsFormat) |
| { |
| const tcu::IVec4 srcMantissaBits = tcu::getTextureFormatMantissaBitDepth(sourceFormat); |
| const tcu::IVec4 readMantissaBits = tcu::getTextureFormatMantissaBitDepth(readPixelsFormat); |
| tcu::IVec4 ULPDiff(0); |
| |
| for (int i = 0; i < 4; i++) |
| if (readMantissaBits[i] >= srcMantissaBits[i]) |
| ULPDiff[i] = readMantissaBits[i] - srcMantissaBits[i]; |
| |
| return UVec4(4) * (UVec4(1) << (ULPDiff.cast<deUint32>())); |
| } |
| |
| void verifyRenderbuffer (TestLog& log, |
| tcu::ResultCollector& results, |
| const tcu::TextureFormat& format, |
| int renderbufferNdx, |
| const tcu::TextureLevel& refRenderbuffer, |
| const tcu::TextureLevel& result) |
| { |
| switch (tcu::getTextureChannelClass(format.type)) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| { |
| const string name = "Renderbuffer" + de::toString(renderbufferNdx); |
| const string desc = "Compare renderbuffer " + de::toString(renderbufferNdx); |
| const UVec4 threshold = getFloatULPThreshold(format, result.getFormat()); |
| |
| if (!tcu::floatUlpThresholdCompare(log, name.c_str(), desc.c_str(), refRenderbuffer, result, threshold, tcu::COMPARE_LOG_RESULT)) |
| results.fail("Verification of renderbuffer " + de::toString(renderbufferNdx) + " failed."); |
| |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| { |
| const string name = "Renderbuffer" + de::toString(renderbufferNdx); |
| const string desc = "Compare renderbuffer " + de::toString(renderbufferNdx); |
| const UVec4 threshold (1, 1, 1, 1); |
| |
| if (!tcu::intThresholdCompare(log, name.c_str(), desc.c_str(), refRenderbuffer, result, threshold, tcu::COMPARE_LOG_RESULT)) |
| results.fail("Verification of renderbuffer " + de::toString(renderbufferNdx) + " failed."); |
| |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| { |
| const string name = "Renderbuffer" + de::toString(renderbufferNdx); |
| const string desc = "Compare renderbuffer " + de::toString(renderbufferNdx); |
| const Vec4 threshold = getFixedPointFormatThreshold(format, result.getFormat()); |
| |
| if (!tcu::floatThresholdCompare(log, name.c_str(), desc.c_str(), refRenderbuffer, result, threshold, tcu::COMPARE_LOG_RESULT)) |
| results.fail("Verification of renderbuffer " + de::toString(renderbufferNdx) + " failed."); |
| |
| break; |
| } |
| |
| default: |
| DE_ASSERT(DE_FALSE); |
| } |
| } |
| |
| TextureFormat getReadPixelFormat (const TextureFormat& format) |
| { |
| switch (tcu::getTextureChannelClass(format.type)) |
| { |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| return TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32); |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| return TextureFormat(TextureFormat::RGBA, TextureFormat::SIGNED_INT32); |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8); |
| |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| return TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT); |
| |
| default: |
| DE_ASSERT(false); |
| return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8); |
| } |
| } |
| |
| void verifyRenderbuffers (TestLog& log, |
| tcu::ResultCollector& results, |
| glu::RenderContext& renderContext, |
| const glu::RenderbufferVector& renderbuffers, |
| const glu::Framebuffer& framebuffer, |
| const vector<TextureLevel>& refRenderbuffers) |
| { |
| const glw::Functions& gl = renderContext.getFunctions(); |
| |
| DE_ASSERT(renderbuffers.size() == refRenderbuffers.size()); |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer); |
| |
| for (int renderbufferNdx = 0; renderbufferNdx < (int)renderbuffers.size(); renderbufferNdx++) |
| { |
| const TextureLevel& refRenderbuffer = refRenderbuffers[renderbufferNdx]; |
| const int width = refRenderbuffer.getWidth(); |
| const int height = refRenderbuffer.getHeight(); |
| const TextureFormat format = refRenderbuffer.getFormat(); |
| |
| tcu::TextureLevel result (getReadPixelFormat(format), width, height); |
| |
| gl.readBuffer(GL_COLOR_ATTACHMENT0 + renderbufferNdx); |
| glu::readPixels(renderContext, 0, 0, result.getAccess()); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels from renderbuffer failed."); |
| |
| verifyRenderbuffer(log, results, format, renderbufferNdx, refRenderbuffer, result); |
| } |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| } |
| |
| static const float s_quadCoords[] = |
| { |
| -0.5f, -0.5f, |
| 0.5f, -0.5f, |
| 0.5f, 0.5f, |
| |
| 0.5f, 0.5f, |
| -0.5f, 0.5f, |
| -0.5f, -0.5f |
| }; |
| |
| void setBlendState (rr::FragmentOperationState& fragOps, const BlendState& state) |
| { |
| if (state.blendEq) |
| { |
| if (state.blendEq->is<BlendEq>()) |
| { |
| if (isAdvancedBlendEq(state.blendEq->get<BlendEq>())) |
| { |
| const rr::BlendEquationAdvanced equation = mapGLBlendEquationAdvanced(state.blendEq->get<BlendEq>()); |
| |
| fragOps.blendMode = rr::BLENDMODE_ADVANCED; |
| fragOps.blendEquationAdvaced = equation; |
| } |
| else |
| { |
| const rr::BlendEquation equation = mapGLBlendEquation(state.blendEq->get<BlendEq>()); |
| |
| fragOps.blendMode = rr::BLENDMODE_STANDARD; |
| fragOps.blendRGBState.equation = equation; |
| fragOps.blendAState.equation = equation; |
| } |
| } |
| else |
| { |
| DE_ASSERT(state.blendEq->is<SeparateBlendEq>()); |
| |
| fragOps.blendMode = rr::BLENDMODE_STANDARD; |
| fragOps.blendRGBState.equation = mapGLBlendEquation(state.blendEq->get<SeparateBlendEq>().rgb); |
| fragOps.blendAState.equation = mapGLBlendEquation(state.blendEq->get<SeparateBlendEq>().alpha); |
| } |
| } |
| |
| if (state.blendFunc) |
| { |
| if (state.blendFunc->is<BlendFunc>()) |
| { |
| const rr::BlendFunc srcFunction = mapGLBlendFunc(state.blendFunc->get<BlendFunc>().src); |
| const rr::BlendFunc dstFunction = mapGLBlendFunc(state.blendFunc->get<BlendFunc>().dst); |
| |
| fragOps.blendRGBState.srcFunc = srcFunction; |
| fragOps.blendRGBState.dstFunc = dstFunction; |
| |
| fragOps.blendAState.srcFunc = srcFunction; |
| fragOps.blendAState.dstFunc = dstFunction; |
| } |
| else |
| { |
| DE_ASSERT(state.blendFunc->is<SeparateBlendFunc>()); |
| |
| fragOps.blendRGBState.srcFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().rgb.src); |
| fragOps.blendRGBState.dstFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().rgb.dst); |
| |
| fragOps.blendAState.srcFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().alpha.src); |
| fragOps.blendAState.dstFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().alpha.dst); |
| } |
| } |
| |
| if (state.colorMask) |
| fragOps.colorMask = *state.colorMask; |
| } |
| |
| rr::RenderState createRenderState (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const DrawBufferInfo& info, int subpixelBits) |
| { |
| const IVec2 size = info.getSize(); |
| rr::RenderState state (rr::ViewportState(rr::WindowRectangle(0, 0, size.x(), size.y())), subpixelBits); |
| |
| state.fragOps.blendMode = rr::BLENDMODE_STANDARD; |
| |
| setBlendState(state.fragOps, preCommonBlendState); |
| setBlendState(state.fragOps, info.getBlendState()); |
| setBlendState(state.fragOps, postCommonBlendState); |
| |
| if (postCommonBlendState.enableBlend) |
| state.fragOps.blendMode = (*(postCommonBlendState.enableBlend) ? state.fragOps.blendMode : rr::BLENDMODE_NONE); |
| else if (info.getBlendState().enableBlend) |
| state.fragOps.blendMode = (*(info.getBlendState().enableBlend) ? state.fragOps.blendMode : rr::BLENDMODE_NONE); |
| else if (preCommonBlendState.enableBlend) |
| state.fragOps.blendMode = (*(preCommonBlendState.enableBlend) ? state.fragOps.blendMode : rr::BLENDMODE_NONE); |
| else |
| state.fragOps.blendMode = rr::BLENDMODE_NONE; |
| |
| if (tcu::getTextureChannelClass(info.getFormat().type) != tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT |
| && tcu::getTextureChannelClass(info.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT |
| && tcu::getTextureChannelClass(info.getFormat().type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT) |
| state.fragOps.blendMode = rr::BLENDMODE_NONE; |
| |
| return state; |
| } |
| |
| class VertexShader : public rr::VertexShader |
| { |
| public: |
| VertexShader (void); |
| virtual void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const; |
| }; |
| |
| VertexShader::VertexShader (void) |
| : rr::VertexShader (1, 1) |
| { |
| m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| } |
| |
| void VertexShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| { |
| rr::VertexPacket& packet = *packets[packetNdx]; |
| |
| packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx); |
| packet.outputs[0] = 0.5f * (Vec4(1.0f) + rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx)); |
| } |
| } |
| |
| class FragmentShader : public rr::FragmentShader |
| { |
| public: |
| FragmentShader (int drawBufferNdx, const DrawBufferInfo& info); |
| void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const; |
| |
| private: |
| const int m_drawBufferNdx; |
| const DrawBufferInfo m_info; |
| }; |
| |
| FragmentShader::FragmentShader (int drawBufferNdx, const DrawBufferInfo& info) |
| : rr::FragmentShader (1, 1) |
| , m_drawBufferNdx (drawBufferNdx) |
| , m_info (info) |
| { |
| m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| |
| switch (tcu::getTextureChannelClass(m_info.getFormat().type)) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| m_outputs[0].type = rr::GENERICVECTYPE_UINT32; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| m_outputs[0].type = rr::GENERICVECTYPE_INT32; |
| break; |
| |
| default: |
| DE_ASSERT(false); |
| }; |
| } |
| |
| void FragmentShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| { |
| rr::FragmentPacket& packet = packets[packetNdx]; |
| |
| DE_ASSERT(m_drawBufferNdx >= 0); |
| DE_UNREF(m_info); |
| |
| for (int fragNdx = 0; fragNdx < 4; ++fragNdx) |
| { |
| const Vec2 vColor = rr::readVarying<float>(packet, context, 0, fragNdx).xy(); |
| const float values[] = |
| { |
| vColor.x(), |
| vColor.y(), |
| (1.0f - vColor.x()), |
| (1.0f - vColor.y()) |
| }; |
| |
| switch (tcu::getTextureChannelClass(m_info.getFormat().type)) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| { |
| const Vec4 color (values[(m_drawBufferNdx + 0) % 4], |
| values[(m_drawBufferNdx + 1) % 4], |
| values[(m_drawBufferNdx + 2) % 4], |
| values[(m_drawBufferNdx + 3) % 4]); |
| |
| rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color); |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| { |
| const UVec4 color ((deUint32)(values[(m_drawBufferNdx + 0) % 4]), |
| (deUint32)(values[(m_drawBufferNdx + 1) % 4]), |
| (deUint32)(values[(m_drawBufferNdx + 2) % 4]), |
| (deUint32)(values[(m_drawBufferNdx + 3) % 4])); |
| |
| rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color); |
| break; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| { |
| const IVec4 color ((deInt32)(values[(m_drawBufferNdx + 0) % 4]), |
| (deInt32)(values[(m_drawBufferNdx + 1) % 4]), |
| (deInt32)(values[(m_drawBufferNdx + 2) % 4]), |
| (deInt32)(values[(m_drawBufferNdx + 3) % 4])); |
| |
| rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color); |
| break; |
| } |
| |
| default: |
| DE_ASSERT(DE_FALSE); |
| }; |
| } |
| } |
| } |
| |
| rr::VertexAttrib createVertexAttrib (const float* coords) |
| { |
| rr::VertexAttrib attrib; |
| |
| attrib.type = rr::VERTEXATTRIBTYPE_FLOAT; |
| attrib.size = 2; |
| attrib.pointer = coords; |
| |
| return attrib; |
| } |
| |
| void renderRefQuad (const BlendState& preCommonBlendState, |
| const BlendState& postCommonBlendState, |
| const vector<DrawBufferInfo>& drawBuffers, |
| const int subpixelBits, |
| vector<TextureLevel>& refRenderbuffers) |
| { |
| const rr::Renderer renderer; |
| const rr::PrimitiveList primitives (rr::PRIMITIVETYPE_TRIANGLES, 6, 0); |
| const rr::VertexAttrib vertexAttribs[] = |
| { |
| createVertexAttrib(s_quadCoords) |
| }; |
| |
| for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++) |
| { |
| if (drawBuffers[drawBufferNdx].getRender()) |
| { |
| const rr::RenderState renderState (createRenderState(preCommonBlendState, postCommonBlendState, drawBuffers[drawBufferNdx], subpixelBits)); |
| const rr::RenderTarget renderTarget (rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(refRenderbuffers[drawBufferNdx].getAccess())); |
| const VertexShader vertexShader; |
| const FragmentShader fragmentShader (drawBufferNdx, drawBuffers[drawBufferNdx]); |
| const rr::Program program (&vertexShader, &fragmentShader); |
| const rr::DrawCommand command (renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs), vertexAttribs, primitives); |
| |
| renderer.draw(command); |
| } |
| } |
| } |
| |
| bool requiresAdvancedBlendEq (const BlendState& pre, const BlendState post, const vector<DrawBufferInfo>& drawBuffers) |
| { |
| bool requiresAdvancedBlendEq = false; |
| |
| if (pre.blendEq && pre.blendEq->is<BlendEq>()) |
| requiresAdvancedBlendEq |= isAdvancedBlendEq(pre.blendEq->get<BlendEq>()); |
| |
| if (post.blendEq && post.blendEq->is<BlendEq>()) |
| requiresAdvancedBlendEq |= isAdvancedBlendEq(post.blendEq->get<BlendEq>()); |
| |
| for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++) |
| { |
| const BlendState& drawBufferBlendState = drawBuffers[drawBufferNdx].getBlendState(); |
| |
| if (drawBufferBlendState.blendEq && drawBufferBlendState.blendEq->is<BlendEq>()) |
| requiresAdvancedBlendEq |= isAdvancedBlendEq(drawBufferBlendState.blendEq->get<BlendEq>()); |
| } |
| |
| return requiresAdvancedBlendEq; |
| } |
| |
| glu::VertexSource genVertexSource (glu::RenderContext& renderContext) |
| { |
| const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)); |
| |
| const char* const vertexSource = |
| "${GLSL_VERSION_DECL}\n" |
| "layout(location=0) in highp vec2 i_coord;\n" |
| "out highp vec2 v_color;\n" |
| "void main (void)\n" |
| "{\n" |
| "\tv_color = 0.5 * (vec2(1.0) + i_coord);\n" |
| "\tgl_Position = vec4(i_coord, 0.0, 1.0);\n" |
| "}"; |
| |
| map<string, string> args; |
| args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES); |
| |
| return glu::VertexSource(tcu::StringTemplate(vertexSource).specialize(args)); |
| } |
| |
| glu::FragmentSource genFragmentSource (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const vector<DrawBufferInfo>& drawBuffers, glu::RenderContext& renderContext) |
| { |
| std::ostringstream stream; |
| const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2)); |
| |
| stream << "${GLSL_VERSION_DECL}\n"; |
| |
| if (requiresAdvancedBlendEq(preCommonBlendState, postCommonBlendState, drawBuffers)) |
| { |
| stream << "${GLSL_EXTENSION}" |
| << "layout(blend_support_all_equations) out;\n"; |
| } |
| |
| stream << "in highp vec2 v_color;\n"; |
| |
| for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++) |
| { |
| const DrawBufferInfo& drawBuffer = drawBuffers[drawBufferNdx]; |
| const TextureFormat& format = drawBuffer.getFormat(); |
| |
| stream << "layout(location=" << drawBufferNdx << ") out highp "; |
| |
| switch (tcu::getTextureChannelClass(format.type)) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| stream << "vec4"; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| stream << "uvec4"; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| stream << "ivec4"; |
| break; |
| |
| default: |
| DE_ASSERT(DE_FALSE); |
| }; |
| |
| stream << " o_drawBuffer" << drawBufferNdx << ";\n"; |
| } |
| |
| stream << "void main (void)\n" |
| << "{\n"; |
| |
| for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++) |
| { |
| const DrawBufferInfo& drawBuffer = drawBuffers[drawBufferNdx]; |
| const TextureFormat& format = drawBuffer.getFormat(); |
| const char* const values[] = |
| { |
| "v_color.x", |
| "v_color.y", |
| "(1.0 - v_color.x)", |
| "(1.0 - v_color.y)" |
| }; |
| |
| stream << "\to_drawBuffer" << drawBufferNdx; |
| |
| switch (tcu::getTextureChannelClass(format.type)) |
| { |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| stream << " = vec4(" << values[(drawBufferNdx + 0) % 4] |
| << ", " << values[(drawBufferNdx + 1) % 4] |
| << ", " << values[(drawBufferNdx + 2) % 4] |
| << ", " << values[(drawBufferNdx + 3) % 4] << ");\n"; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| stream << " = uvec4(uint(" << values[(drawBufferNdx + 0) % 4] |
| << "), uint(" << values[(drawBufferNdx + 1) % 4] |
| << "), uint(" << values[(drawBufferNdx + 2) % 4] |
| << "), uint(" << values[(drawBufferNdx + 3) % 4] << "));\n"; |
| break; |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| stream << " = ivec4(int(" << values[(drawBufferNdx + 0) % 4] |
| << "), int(" << values[(drawBufferNdx + 1) % 4] |
| << "), int(" << values[(drawBufferNdx + 2) % 4] |
| << "), int(" << values[(drawBufferNdx + 3) % 4] << "));\n"; |
| break; |
| |
| default: |
| DE_ASSERT(DE_FALSE); |
| }; |
| } |
| |
| stream << "}"; |
| |
| map<string, string> args; |
| args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES); |
| args["GLSL_EXTENSION"] = supportsES32 ? "\n" : "#extension GL_KHR_blend_equation_advanced : require\n"; |
| |
| return glu::FragmentSource(tcu::StringTemplate(stream.str()).specialize(args)); |
| } |
| |
| glu::ProgramSources genShaderSources (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const vector<DrawBufferInfo>& drawBuffers, glu::RenderContext& renderContext) |
| { |
| return glu::ProgramSources() << genVertexSource(renderContext) << genFragmentSource(preCommonBlendState, postCommonBlendState, drawBuffers, renderContext); |
| } |
| |
| void renderGLQuad (glu::RenderContext& renderContext, |
| const glu::ShaderProgram& program) |
| { |
| const glu::VertexArrayBinding vertexArrays[] = |
| { |
| glu::VertexArrayBinding(glu::BindingPoint(0), glu::VertexArrayPointer(glu::VTX_COMP_FLOAT, glu::VTX_COMP_CONVERT_NONE, 2, 6, 0, s_quadCoords)) |
| }; |
| |
| glu::draw(renderContext, program.getProgram(), 1, vertexArrays, glu::pr::Triangles(6)); |
| } |
| |
| void renderQuad (TestLog& log, |
| glu::RenderContext& renderContext, |
| const BlendState& preCommonBlendState, |
| const BlendState& postCommonBlendState, |
| const vector<DrawBufferInfo>& drawBuffers, |
| const glu::Framebuffer& framebuffer, |
| vector<TextureLevel>& refRenderbuffers) |
| { |
| const glw::Functions& gl = renderContext.getFunctions(); |
| const glu::ShaderProgram program (gl, genShaderSources(preCommonBlendState, postCommonBlendState, drawBuffers, renderContext)); |
| const IVec2 size = drawBuffers[0].getSize(); |
| const bool requiresBlendBarriers = requiresAdvancedBlendEq(preCommonBlendState, postCommonBlendState, drawBuffers); |
| |
| vector<deUint32> bufs; |
| |
| bufs.resize(drawBuffers.size()); |
| |
| for (int bufNdx = 0; bufNdx < (int)bufs.size(); bufNdx++) |
| bufs[bufNdx] = (drawBuffers[bufNdx].getRender() ? GL_COLOR_ATTACHMENT0 + bufNdx : GL_NONE); |
| |
| log << program; |
| |
| gl.viewport(0, 0, size.x(), size.y()); |
| gl.useProgram(program.getProgram()); |
| gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer); |
| |
| setCommonBlendState(gl, preCommonBlendState); |
| |
| for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++) |
| setIndexedBlendState(gl, drawBuffers[renderbufferNdx].getBlendState(), renderbufferNdx); |
| |
| setCommonBlendState(gl, postCommonBlendState); |
| |
| gl.drawBuffers((glw::GLsizei)bufs.size(), &(bufs[0])); |
| |
| if (requiresBlendBarriers) |
| gl.blendBarrier(); |
| |
| renderGLQuad(renderContext, program); |
| |
| if (requiresBlendBarriers) |
| gl.blendBarrier(); |
| |
| gl.drawBuffers(0, 0); |
| gl.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| gl.useProgram(0); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render"); |
| |
| int subpixelBits = 0; |
| gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits); |
| |
| renderRefQuad(preCommonBlendState, postCommonBlendState, drawBuffers, subpixelBits, refRenderbuffers); |
| } |
| |
| void logBlendState (TestLog& log, |
| const BlendState& blend) |
| { |
| if (blend.enableBlend) |
| { |
| if (*blend.enableBlend) |
| log << TestLog::Message << "Enable blending." << TestLog::EndMessage; |
| else |
| log << TestLog::Message << "Disable blending." << TestLog::EndMessage; |
| } |
| |
| if (blend.colorMask) |
| { |
| const BVec4 mask = *blend.colorMask; |
| |
| log << TestLog::Message << "Set color mask: " << mask << "." << TestLog::EndMessage; |
| } |
| |
| if (blend.blendEq) |
| { |
| const Either<BlendEq, SeparateBlendEq>& blendEq = *blend.blendEq; |
| |
| if (blendEq.is<BlendEq>()) |
| log << TestLog::Message << "Set blend equation: " << glu::getBlendEquationStr(blendEq.get<BlendEq>()) << "." << TestLog::EndMessage; |
| else if (blendEq.is<SeparateBlendEq>()) |
| log << TestLog::Message << "Set blend equation rgb: " << glu::getBlendEquationStr(blendEq.get<SeparateBlendEq>().rgb) << ", alpha: " << glu::getBlendEquationStr(blendEq.get<SeparateBlendEq>().alpha) << "." << TestLog::EndMessage; |
| else |
| DE_ASSERT(false); |
| } |
| |
| if (blend.blendFunc) |
| { |
| const Either<BlendFunc, SeparateBlendFunc>& blendFunc = *blend.blendFunc; |
| |
| if (blendFunc.is<BlendFunc>()) |
| log << TestLog::Message << "Set blend function source: " << glu::getBlendFactorStr(blendFunc.get<BlendFunc>().src) << ", destination: " << glu::getBlendFactorStr(blendFunc.get<BlendFunc>().dst) << "." << TestLog::EndMessage; |
| else if (blendFunc.is<SeparateBlendFunc>()) |
| { |
| log << TestLog::Message << "Set blend function rgb source: " << glu::getBlendFactorStr(blendFunc.get<SeparateBlendFunc>().rgb.src) << ", destination: " << glu::getBlendFactorStr(blendFunc.get<SeparateBlendFunc>().rgb.dst) << "." << TestLog::EndMessage; |
| log << TestLog::Message << "Set blend function alpha source: " << glu::getBlendFactorStr(blendFunc.get<SeparateBlendFunc>().alpha.src) << ", destination: " << glu::getBlendFactorStr(blendFunc.get<SeparateBlendFunc>().alpha.dst) << "." << TestLog::EndMessage; |
| } |
| else |
| DE_ASSERT(false); |
| } |
| } |
| |
| void logTestCaseInfo (TestLog& log, |
| const BlendState& preCommonBlendState, |
| const BlendState& postCommonBlendState, |
| const vector<DrawBufferInfo>& drawBuffers) |
| { |
| { |
| tcu::ScopedLogSection drawBuffersSection(log, "DrawBuffers", "Draw buffers"); |
| |
| for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++) |
| { |
| const tcu::ScopedLogSection drawBufferSection (log, "DrawBuffer" + de::toString(drawBufferNdx), "Draw Buffer " + de::toString(drawBufferNdx)); |
| const DrawBufferInfo& drawBuffer = drawBuffers[drawBufferNdx]; |
| |
| log << TestLog::Message << "Format: " << drawBuffer.getFormat() << TestLog::EndMessage; |
| log << TestLog::Message << "Size: " << drawBuffer.getSize() << TestLog::EndMessage; |
| log << TestLog::Message << "Render: " << (drawBuffer.getRender() ? "true" : "false") << TestLog::EndMessage; |
| } |
| } |
| |
| if (!preCommonBlendState.isEmpty()) |
| { |
| tcu::ScopedLogSection s(log, "PreCommonState", "First set common blend state"); |
| logBlendState(log, preCommonBlendState); |
| } |
| |
| for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++) |
| { |
| if (!drawBuffers[drawBufferNdx].getBlendState().isEmpty()) |
| { |
| const tcu::ScopedLogSection s(log, "DrawBufferState" + de::toString(drawBufferNdx), "Set DrawBuffer " + de::toString(drawBufferNdx) + " state to"); |
| |
| logBlendState(log, drawBuffers[drawBufferNdx].getBlendState()); |
| } |
| } |
| |
| if (!postCommonBlendState.isEmpty()) |
| { |
| tcu::ScopedLogSection s(log, "PostCommonState", "After set common blend state"); |
| logBlendState(log, postCommonBlendState); |
| } |
| } |
| |
| void runTest (TestLog& log, |
| tcu::ResultCollector& results, |
| glu::RenderContext& renderContext, |
| |
| const BlendState& preCommonBlendState, |
| const BlendState& postCommonBlendState, |
| const vector<DrawBufferInfo>& drawBuffers) |
| { |
| const glw::Functions& gl = renderContext.getFunctions(); |
| glu::RenderbufferVector renderbuffers (gl, drawBuffers.size()); |
| glu::Framebuffer framebuffer (gl); |
| vector<TextureLevel> refRenderbuffers (drawBuffers.size()); |
| |
| logTestCaseInfo(log, preCommonBlendState, postCommonBlendState, drawBuffers); |
| |
| genRenderbuffers(gl, drawBuffers, framebuffer, renderbuffers, refRenderbuffers); |
| |
| renderQuad(log, renderContext, preCommonBlendState, postCommonBlendState, drawBuffers, framebuffer, refRenderbuffers); |
| |
| verifyRenderbuffers(log, results, renderContext, renderbuffers, framebuffer, refRenderbuffers); |
| } |
| |
| class DrawBuffersIndexedTest : public TestCase |
| { |
| public: |
| DrawBuffersIndexedTest (Context& context, |
| const BlendState& preCommonBlendState, |
| const BlendState& postCommonBlendState, |
| const vector<DrawBufferInfo>& drawBuffers, |
| const string& name, |
| const string& description); |
| |
| void init (void); |
| IterateResult iterate (void); |
| |
| private: |
| const BlendState m_preCommonBlendState; |
| const BlendState m_postCommonBlendState; |
| const vector<DrawBufferInfo> m_drawBuffers; |
| }; |
| |
| DrawBuffersIndexedTest::DrawBuffersIndexedTest (Context& context, |
| const BlendState& preCommonBlendState, |
| const BlendState& postCommonBlendState, |
| const vector<DrawBufferInfo>& drawBuffers, |
| const string& name, |
| const string& description) |
| : TestCase (context, name.c_str(), description.c_str()) |
| , m_preCommonBlendState (preCommonBlendState) |
| , m_postCommonBlendState (postCommonBlendState) |
| , m_drawBuffers (drawBuffers) |
| { |
| } |
| |
| void DrawBuffersIndexedTest::init (void) |
| { |
| const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); |
| |
| if (!supportsES32) |
| { |
| if (requiresAdvancedBlendEq(m_preCommonBlendState, m_postCommonBlendState, m_drawBuffers) && !m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced")) |
| TCU_THROW(NotSupportedError, "Extension GL_KHR_blend_equation_advanced not supported"); |
| |
| if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed")) |
| TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported"); |
| } |
| } |
| |
| TestCase::IterateResult DrawBuffersIndexedTest::iterate (void) |
| { |
| TestLog& log = m_testCtx.getLog(); |
| tcu::ResultCollector results (log); |
| |
| runTest(log, results, m_context.getRenderContext(), m_preCommonBlendState, m_postCommonBlendState, m_drawBuffers); |
| |
| results.setTestContextResult(m_testCtx); |
| |
| return STOP; |
| } |
| |
| BlendEq getRandomBlendEq (de::Random& rng) |
| { |
| const BlendEq eqs[] = |
| { |
| GL_FUNC_ADD, |
| GL_FUNC_SUBTRACT, |
| GL_FUNC_REVERSE_SUBTRACT, |
| GL_MIN, |
| GL_MAX |
| }; |
| |
| return de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(eqs)>(eqs, rng.getUint32() % DE_LENGTH_OF_ARRAY(eqs)); |
| } |
| |
| BlendFunc getRandomBlendFunc (de::Random& rng) |
| { |
| const deUint32 funcs[] = |
| { |
| GL_ZERO, |
| GL_ONE, |
| GL_SRC_COLOR, |
| GL_ONE_MINUS_SRC_COLOR, |
| GL_DST_COLOR, |
| GL_ONE_MINUS_DST_COLOR, |
| GL_SRC_ALPHA, |
| GL_ONE_MINUS_SRC_ALPHA, |
| GL_DST_ALPHA, |
| GL_ONE_MINUS_DST_ALPHA, |
| GL_CONSTANT_COLOR, |
| GL_ONE_MINUS_CONSTANT_COLOR, |
| GL_CONSTANT_ALPHA, |
| GL_ONE_MINUS_CONSTANT_ALPHA, |
| GL_SRC_ALPHA_SATURATE |
| }; |
| |
| const deUint32 src = de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(funcs)>(funcs, rng.getUint32() % DE_LENGTH_OF_ARRAY(funcs)); |
| const deUint32 dst = de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(funcs)>(funcs, rng.getUint32() % DE_LENGTH_OF_ARRAY(funcs)); |
| |
| return BlendFunc(src, dst); |
| } |
| |
| void genRandomBlendState (de::Random& rng, BlendState& blendState) |
| { |
| if (rng.getBool()) |
| blendState.enableBlend = rng.getBool(); |
| |
| if (rng.getBool()) |
| { |
| if (rng.getBool()) |
| blendState.blendEq = getRandomBlendEq(rng); |
| else |
| { |
| const BlendEq rgb = getRandomBlendEq(rng); |
| const BlendEq alpha = getRandomBlendEq(rng); |
| |
| blendState.blendEq = SeparateBlendEq(rgb, alpha); |
| } |
| } |
| |
| if (rng.getBool()) |
| { |
| if (rng.getBool()) |
| blendState.blendFunc = getRandomBlendFunc(rng); |
| else |
| { |
| const BlendFunc rgb = getRandomBlendFunc(rng); |
| const BlendFunc alpha = getRandomBlendFunc(rng); |
| |
| blendState.blendFunc = SeparateBlendFunc(rgb, alpha); |
| } |
| } |
| |
| if (rng.getBool()) |
| { |
| const bool red = rng.getBool(); |
| const bool green = rng.getBool(); |
| const bool blue = rng.getBool(); |
| const bool alpha = rng.getBool(); |
| |
| blendState.colorMask = BVec4(red, blue, green, alpha); |
| } |
| } |
| |
| TextureFormat getRandomFormat (de::Random& rng, Context& context) |
| { |
| const bool supportsES32 = glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2)); |
| |
| const deUint32 glFormats[] = |
| { |
| GL_R8, |
| GL_RG8, |
| GL_RGB8, |
| GL_RGB565, |
| GL_RGBA4, |
| GL_RGB5_A1, |
| GL_RGBA8, |
| GL_RGB10_A2, |
| GL_RGB10_A2UI, |
| 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, |
| GL_RGBA16F, |
| GL_R32F, |
| GL_RG32F, |
| GL_RGBA32F, |
| GL_R11F_G11F_B10F |
| }; |
| |
| if (supportsES32) |
| return glu::mapGLInternalFormat(de::getArrayElement(glFormats, rng.getUint32() % DE_LENGTH_OF_ARRAY(glFormats))); |
| else |
| { |
| DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(glFormats) == 32); |
| return glu::mapGLInternalFormat(de::getArrayElement(glFormats, rng.getUint32() % (DE_LENGTH_OF_ARRAY(glFormats) - 5))); |
| } |
| } |
| |
| void genRandomTest (de::Random& rng, BlendState& preCommon, BlendState& postCommon, vector<DrawBufferInfo>& drawBuffers, int maxDrawBufferCount, Context& context) |
| { |
| genRandomBlendState(rng, preCommon); |
| genRandomBlendState(rng, postCommon); |
| |
| for (int drawBufferNdx = 0; drawBufferNdx < maxDrawBufferCount; drawBufferNdx++) |
| { |
| const bool render = rng.getFloat() > 0.1f; |
| const IVec2 size (64, 64); |
| const TextureFormat format (getRandomFormat(rng, context)); |
| BlendState blendState; |
| |
| genRandomBlendState(rng, blendState); |
| |
| // 32bit float formats don't support blending in GLES32 |
| if (format.type == tcu::TextureFormat::FLOAT) |
| { |
| // If format is 32bit float post common can't enable blending |
| if (postCommon.enableBlend && *postCommon.enableBlend) |
| { |
| // Either don't set enable blend or disable blending |
| if (rng.getBool()) |
| postCommon.enableBlend = tcu::nothing<bool>(); |
| else |
| postCommon.enableBlend = tcu::just(false); |
| } |
| |
| // If post common doesn't disable blending, per attachment state or |
| // pre common must. |
| if (!postCommon.enableBlend) |
| { |
| // If pre common enables blend per attachment must disable it |
| // If per attachment state changes blend state it must disable it |
| if ((preCommon.enableBlend && *preCommon.enableBlend) |
| || blendState.enableBlend) |
| blendState.enableBlend = tcu::just(false); |
| } |
| } |
| |
| drawBuffers.push_back(DrawBufferInfo(render, size, blendState, format)); |
| } |
| } |
| |
| class MaxDrawBuffersIndexedTest : public TestCase |
| { |
| public: |
| MaxDrawBuffersIndexedTest (Context& contet, int seed); |
| |
| void init (void); |
| IterateResult iterate (void); |
| |
| private: |
| const int m_seed; |
| }; |
| |
| MaxDrawBuffersIndexedTest::MaxDrawBuffersIndexedTest (Context& context, int seed) |
| : TestCase (context, de::toString(seed).c_str(), de::toString(seed).c_str()) |
| , m_seed (deInt32Hash(seed) ^ 1558001307u) |
| { |
| } |
| |
| void MaxDrawBuffersIndexedTest::init (void) |
| { |
| const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); |
| |
| if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed")) |
| TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported"); |
| } |
| |
| TestCase::IterateResult MaxDrawBuffersIndexedTest::iterate (void) |
| { |
| TestLog& log = m_testCtx.getLog(); |
| tcu::ResultCollector results (log); |
| de::Random rng (m_seed); |
| BlendState preCommonBlendState; |
| BlendState postCommonBlendState; |
| vector<DrawBufferInfo> drawBuffers; |
| |
| genRandomTest(rng, preCommonBlendState, postCommonBlendState, drawBuffers, 4, m_context); |
| |
| runTest(log, results, m_context.getRenderContext(), preCommonBlendState, postCommonBlendState, drawBuffers); |
| |
| results.setTestContextResult(m_testCtx); |
| |
| return STOP; |
| } |
| |
| class ImplMaxDrawBuffersIndexedTest : public TestCase |
| { |
| public: |
| ImplMaxDrawBuffersIndexedTest (Context& contet, int seed); |
| |
| void init (void); |
| IterateResult iterate (void); |
| |
| private: |
| const int m_seed; |
| }; |
| |
| ImplMaxDrawBuffersIndexedTest::ImplMaxDrawBuffersIndexedTest (Context& context, int seed) |
| : TestCase (context, de::toString(seed).c_str(), de::toString(seed).c_str()) |
| , m_seed (deInt32Hash(seed) ^ 2686315738u) |
| { |
| } |
| |
| void ImplMaxDrawBuffersIndexedTest::init (void) |
| { |
| const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); |
| |
| if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed")) |
| TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported"); |
| } |
| |
| TestCase::IterateResult ImplMaxDrawBuffersIndexedTest::iterate (void) |
| { |
| TestLog& log = m_testCtx.getLog(); |
| tcu::ResultCollector results (log); |
| const glw::Functions& gl = m_context.getRenderContext().getFunctions(); |
| de::Random rng (m_seed); |
| deInt32 maxDrawBuffers = 0; |
| BlendState preCommonBlendState; |
| BlendState postCommonBlendState; |
| vector<DrawBufferInfo> drawBuffers; |
| |
| gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_DRAW_BUFFERS) failed"); |
| |
| TCU_CHECK(maxDrawBuffers > 0); |
| |
| genRandomTest(rng, preCommonBlendState, postCommonBlendState, drawBuffers, maxDrawBuffers, m_context); |
| |
| runTest(log, results, m_context.getRenderContext(), preCommonBlendState, postCommonBlendState, drawBuffers); |
| |
| results.setTestContextResult(m_testCtx); |
| |
| return STOP; |
| } |
| |
| enum PrePost |
| { |
| PRE, |
| POST |
| }; |
| |
| TestCase* createDiffTest (Context& context, PrePost prepost, const char* name, const BlendState& commonState, const BlendState& drawBufferState) |
| { |
| const BlendState emptyState = BlendState(tcu::nothing<bool>(), tcu::nothing<Either<BlendEq, SeparateBlendEq> >(), tcu::nothing<Either<BlendFunc, SeparateBlendFunc> >(), tcu::nothing<BVec4>()); |
| |
| if (prepost == PRE) |
| { |
| const BlendState preState = BlendState((commonState.enableBlend ? commonState.enableBlend : just(true)), |
| commonState.blendEq, |
| (commonState.blendFunc ? commonState.blendFunc : just(Either<BlendFunc, SeparateBlendFunc>(BlendFunc(GL_ONE, GL_ONE)))), |
| tcu::nothing<BVec4>()); |
| vector<DrawBufferInfo> drawBuffers; |
| |
| drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), emptyState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8))); |
| drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8))); |
| |
| return new DrawBuffersIndexedTest(context, preState, emptyState, drawBuffers, name, name); |
| } |
| else if (prepost == POST) |
| { |
| const BlendState preState = BlendState(just(true), |
| tcu::nothing<Either<BlendEq, SeparateBlendEq> >(), |
| Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_ONE, GL_ONE)), |
| tcu::nothing<BVec4>()); |
| vector<DrawBufferInfo> drawBuffers; |
| |
| drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), emptyState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8))); |
| drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8))); |
| |
| return new DrawBuffersIndexedTest(context, preState, commonState, drawBuffers, name, name); |
| } |
| else |
| { |
| DE_ASSERT(false); |
| return DE_NULL; |
| } |
| } |
| |
| TestCase* createAdvancedEqDiffTest (Context& context, PrePost prepost, const char* name, const BlendState& commonState, const BlendState& drawBufferState) |
| { |
| const BlendState emptyState = BlendState(tcu::nothing<bool>(), tcu::nothing<Either<BlendEq, SeparateBlendEq> >(), tcu::nothing<Either<BlendFunc, SeparateBlendFunc> >(), tcu::nothing<BVec4>()); |
| |
| if (prepost == PRE) |
| { |
| const BlendState preState = BlendState((commonState.enableBlend ? commonState.enableBlend : just(true)), |
| commonState.blendEq, |
| (commonState.blendFunc ? commonState.blendFunc : just(Either<BlendFunc, SeparateBlendFunc>(BlendFunc(GL_ONE, GL_ONE)))), |
| tcu::nothing<BVec4>()); |
| vector<DrawBufferInfo> drawBuffers; |
| |
| drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8))); |
| |
| return new DrawBuffersIndexedTest(context, preState, emptyState, drawBuffers, name, name); |
| } |
| else if (prepost == POST) |
| { |
| const BlendState preState = BlendState(just(true), |
| tcu::nothing<Either<BlendEq, SeparateBlendEq> >(), |
| Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_ONE, GL_ONE)), |
| tcu::nothing<BVec4>()); |
| vector<DrawBufferInfo> drawBuffers; |
| |
| drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8))); |
| |
| return new DrawBuffersIndexedTest(context, preState, commonState, drawBuffers, name, name); |
| } |
| else |
| { |
| DE_ASSERT(false); |
| return DE_NULL; |
| } |
| } |
| |
| void addDrawBufferCommonTests (TestCaseGroup* root, PrePost prepost) |
| { |
| const BlendState emptyState = BlendState(Maybe<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| |
| { |
| const BlendState disableState = BlendState(just(false), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| const BlendState enableState = BlendState(just(true), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_enable_buffer_enable", enableState, enableState)); |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_disable_buffer_disable", disableState, disableState)); |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_disable_buffer_enable", disableState, enableState)); |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_enable_buffer_disable", enableState, disableState)); |
| } |
| |
| { |
| const BlendState eqStateA = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(GL_FUNC_ADD), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| const BlendState eqStateB = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(GL_FUNC_SUBTRACT), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| |
| const BlendState separateEqStateA = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(SeparateBlendEq(GL_FUNC_ADD, GL_FUNC_SUBTRACT)), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| const BlendState separateEqStateB = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(SeparateBlendEq(GL_FUNC_SUBTRACT, GL_FUNC_ADD)), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| |
| const BlendState advancedEqStateA = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(GL_DIFFERENCE), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| const BlendState advancedEqStateB = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(GL_SCREEN), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_eq_buffer_blend_eq", eqStateA, eqStateB)); |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_eq_buffer_separate_blend_eq", eqStateA, separateEqStateB)); |
| root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_blend_eq_buffer_advanced_blend_eq", eqStateA, advancedEqStateB)); |
| |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_eq_buffer_blend_eq", separateEqStateA, eqStateB)); |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_eq_buffer_separate_blend_eq", separateEqStateA, separateEqStateB)); |
| root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_separate_blend_eq_buffer_advanced_blend_eq", separateEqStateA, advancedEqStateB)); |
| |
| root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_advanced_blend_eq_buffer_blend_eq", advancedEqStateA, eqStateB)); |
| root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_advanced_blend_eq_buffer_separate_blend_eq", advancedEqStateA, separateEqStateB)); |
| root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_advanced_blend_eq_buffer_advanced_blend_eq", advancedEqStateA, advancedEqStateB)); |
| } |
| |
| { |
| const BlendState funcStateA = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA)), Maybe<BVec4>()); |
| const BlendState funcStateB = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA)), Maybe<BVec4>()); |
| const BlendState separateFuncStateA = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(SeparateBlendFunc(BlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA), BlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA))), Maybe<BVec4>()); |
| const BlendState separateFuncStateB = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(SeparateBlendFunc(BlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA), BlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA))), Maybe<BVec4>()); |
| |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_func_buffer_blend_func", funcStateA, funcStateB)); |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_func_buffer_separate_blend_func", funcStateA, separateFuncStateB)); |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_func_buffer_blend_func", separateFuncStateA, funcStateB)); |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_func_buffer_separate_blend_func", separateFuncStateA, separateFuncStateB)); |
| } |
| |
| { |
| const BlendState commonColorMaskState = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>(BVec4(true, false, true, false))); |
| const BlendState bufferColorMaskState = BlendState(tcu::nothing<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>(BVec4(false, true, false, true))); |
| |
| root->addChild(createDiffTest(root->getContext(), prepost, "common_color_mask_buffer_color_mask", commonColorMaskState, bufferColorMaskState)); |
| } |
| } |
| |
| void addRandomMaxTest (TestCaseGroup* root) |
| { |
| for (int i = 0; i < 20; i++) |
| root->addChild(new MaxDrawBuffersIndexedTest(root->getContext(), i)); |
| } |
| |
| void addRandomImplMaxTest (TestCaseGroup* root) |
| { |
| for (int i = 0; i < 20; i++) |
| root->addChild(new ImplMaxDrawBuffersIndexedTest(root->getContext(), i)); |
| } |
| |
| } // anonymous |
| |
| TestCaseGroup* createDrawBuffersIndexedTests (Context& context) |
| { |
| const BlendState emptyState = BlendState(Maybe<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>()); |
| TestCaseGroup* const group = new TestCaseGroup(context, "draw_buffers_indexed", "Test for indexed draw buffers. GL_EXT_draw_buffers_indexed."); |
| |
| TestCaseGroup* const preGroup = new TestCaseGroup(context, "overwrite_common", "Set common state and overwrite it with draw buffer blend state."); |
| TestCaseGroup* const postGroup = new TestCaseGroup(context, "overwrite_indexed", "Set indexed blend state and overwrite it with common state."); |
| TestCaseGroup* const randomGroup = new TestCaseGroup(context, "random", "Random indexed blend state tests."); |
| TestCaseGroup* const maxGroup = new TestCaseGroup(context, "max_required_draw_buffers", "Random tests using minimum maximum number of draw buffers."); |
| TestCaseGroup* const maxImplGroup = new TestCaseGroup(context, "max_implementation_draw_buffers", "Random tests using maximum number of draw buffers reported by implementation."); |
| |
| group->addChild(preGroup); |
| group->addChild(postGroup); |
| group->addChild(randomGroup); |
| |
| randomGroup->addChild(maxGroup); |
| randomGroup->addChild(maxImplGroup); |
| |
| addDrawBufferCommonTests(preGroup, PRE); |
| addDrawBufferCommonTests(postGroup, POST); |
| addRandomMaxTest(maxGroup); |
| addRandomImplMaxTest(maxImplGroup); |
| |
| return group; |
| } |
| |
| } // Functional |
| } // gles31 |
| } // deqp |