1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3 Module
3 * -------------------------------------------------
5 * Copyright 2015 The Android Open Source Project
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 * \brief Indexed blend operation tests (GL_EXT_draw_buffers_indexed)
22 *//*--------------------------------------------------------------------*/
24 #include "es3fDrawBuffersIndexedTests.hpp"
26 #include "gluContextInfo.hpp"
27 #include "gluDrawUtil.hpp"
28 #include "gluObjectWrapper.hpp"
29 #include "gluPixelTransfer.hpp"
30 #include "gluShaderProgram.hpp"
31 #include "gluStrUtil.hpp"
32 #include "gluTextureUtil.hpp"
34 #include "sglrReferenceUtils.hpp"
36 #include "rrMultisamplePixelBufferAccess.hpp"
37 #include "rrRenderer.hpp"
39 #include "glwEnums.hpp"
40 #include "glwFunctions.hpp"
42 #include "tcuEither.hpp"
43 #include "tcuImageCompare.hpp"
44 #include "tcuMaybe.hpp"
45 #include "tcuResultCollector.hpp"
46 #include "tcuStringTemplate.hpp"
47 #include "tcuTestLog.hpp"
48 #include "tcuTexture.hpp"
49 #include "tcuTextureUtil.hpp"
50 #include "tcuVector.hpp"
51 #include "tcuVectorUtil.hpp"
52 #include "tcuFloat.hpp"
54 #include "deRandom.hpp"
55 #include "deArrayUtil.hpp"
56 #include "deStringUtil.hpp"
57 #include "deUniquePtr.hpp"
71 using tcu::TextureFormat;
72 using tcu::TextureLevel;
82 using sglr::rr_util::mapGLBlendEquation;
83 using sglr::rr_util::mapGLBlendFunc;
84 using sglr::rr_util::mapGLBlendEquationAdvanced;
95 typedef deUint32 BlendEq;
97 bool isAdvancedBlendEq (BlendEq eq)
101 case GL_MULTIPLY: return true;
102 case GL_SCREEN: return true;
103 case GL_OVERLAY: return true;
104 case GL_DARKEN: return true;
105 case GL_LIGHTEN: return true;
106 case GL_COLORDODGE: return true;
107 case GL_COLORBURN: return true;
108 case GL_HARDLIGHT: return true;
109 case GL_SOFTLIGHT: return true;
110 case GL_DIFFERENCE: return true;
111 case GL_EXCLUSION: return true;
112 case GL_HSL_HUE: return true;
113 case GL_HSL_SATURATION: return true;
114 case GL_HSL_COLOR: return true;
115 case GL_HSL_LUMINOSITY: return true;
121 struct SeparateBlendEq
123 SeparateBlendEq (BlendEq rgb_, BlendEq alpha_)
135 BlendFunc (deUint32 src_, deUint32 dst_)
145 struct SeparateBlendFunc
147 SeparateBlendFunc (BlendFunc rgb_, BlendFunc alpha_)
157 typedef deUint32 DrawBuffer;
163 BlendState (const Maybe<bool>& enableBlend_,
164 const Maybe<Either<BlendEq, SeparateBlendEq> >& blendEq_,
165 const Maybe<Either<BlendFunc, SeparateBlendFunc> >& blendFunc_,
166 const Maybe<BVec4>& colorMask_)
167 : enableBlend (enableBlend_)
169 , blendFunc (blendFunc_)
170 , colorMask (colorMask_)
174 bool isEmpty (void) const
176 return (!enableBlend) && (!blendEq) && (!blendFunc) && (!colorMask);
179 Maybe<bool> enableBlend;
180 Maybe<Either<BlendEq, SeparateBlendEq> > blendEq;
181 Maybe<Either<BlendFunc, SeparateBlendFunc> > blendFunc;
182 Maybe<BVec4> colorMask;
185 static bool checkES32orGL45Support(Context& ctx)
187 auto ctxType = ctx.getRenderContext().getType();
188 return contextSupports(ctxType, glu::ApiType::es(3, 2)) ||
189 contextSupports(ctxType, glu::ApiType::core(4, 5));
192 void setCommonBlendState (const glw::Functions& gl, const BlendState& blend)
194 if (blend.enableBlend)
196 if (*blend.enableBlend)
199 gl.disable(GL_BLEND);
204 const BVec4& mask = *blend.colorMask;
206 gl.colorMask(mask.x(), mask.y(), mask.z(), mask.w());
211 const Either<BlendEq, SeparateBlendEq>& blendEq = *blend.blendEq;
213 if (blendEq.is<BlendEq>())
214 gl.blendEquation(blendEq.get<BlendEq>());
215 else if (blendEq.is<SeparateBlendEq>())
216 gl.blendEquationSeparate(blendEq.get<SeparateBlendEq>().rgb, blendEq.get<SeparateBlendEq>().alpha);
223 const Either<BlendFunc, SeparateBlendFunc>& blendFunc = *blend.blendFunc;
225 if (blendFunc.is<BlendFunc>())
226 gl.blendFunc(blendFunc.get<BlendFunc>().src, blendFunc.get<BlendFunc>().dst);
227 else if (blendFunc.is<SeparateBlendFunc>())
228 gl.blendFuncSeparate(blendFunc.get<SeparateBlendFunc>().rgb.src, blendFunc.get<SeparateBlendFunc>().rgb.dst, blendFunc.get<SeparateBlendFunc>().alpha.src, blendFunc.get<SeparateBlendFunc>().alpha.dst);
233 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set common blend state.");
236 void setIndexedBlendState (const glw::Functions& gl, const BlendState& blend, deUint32 index)
238 if (blend.enableBlend)
240 if (*blend.enableBlend)
241 gl.enablei(GL_BLEND, index);
243 gl.disablei(GL_BLEND, index);
248 const BVec4 mask = *blend.colorMask;
250 gl.colorMaski(index, mask.x(), mask.y(), mask.z(), mask.w());
255 const Either<BlendEq, SeparateBlendEq>& blendEq = *blend.blendEq;
257 if (blendEq.is<BlendEq>())
258 gl.blendEquationi(index, blendEq.get<BlendEq>());
259 else if (blendEq.is<SeparateBlendEq>())
260 gl.blendEquationSeparatei(index, blendEq.get<SeparateBlendEq>().rgb, blendEq.get<SeparateBlendEq>().alpha);
267 const Either<BlendFunc, SeparateBlendFunc>& blendFunc = *blend.blendFunc;
269 if (blendFunc.is<BlendFunc>())
270 gl.blendFunci(index, blendFunc.get<BlendFunc>().src, blendFunc.get<BlendFunc>().dst);
271 else if (blendFunc.is<SeparateBlendFunc>())
272 gl.blendFuncSeparatei(index, blendFunc.get<SeparateBlendFunc>().rgb.src, blendFunc.get<SeparateBlendFunc>().rgb.dst, blendFunc.get<SeparateBlendFunc>().alpha.src, blendFunc.get<SeparateBlendFunc>().alpha.dst);
277 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set draw buffer specifig blend state.");
283 DrawBufferInfo (bool render,
285 const BlendState& blendState,
286 const TextureFormat& format);
288 const TextureFormat& getFormat (void) const { return m_format; }
289 const IVec2& getSize (void) const { return m_size; }
290 const BlendState& getBlendState (void) const { return m_blendState; }
291 bool getRender (void) const { return m_render; }
296 TextureFormat m_format;
297 BlendState m_blendState;
300 DrawBufferInfo::DrawBufferInfo (bool render, const IVec2& size, const BlendState& blendState, const TextureFormat& format)
304 , m_blendState (blendState)
308 void clearRenderbuffer (const glw::Functions& gl,
309 const tcu::TextureFormat& format,
311 int renderbufferCount,
312 tcu::TextureLevel& refRenderbuffer)
314 const tcu::TextureFormatInfo info = tcu::getTextureFormatInfo(format);
316 // Clear each buffer to different color
317 const float redScale = float(renderbufferNdx + 1) / float(renderbufferCount);
318 const float blueScale = float(renderbufferCount - renderbufferNdx) / float(renderbufferCount);
319 const float greenScale = float(((renderbufferCount/2) + renderbufferNdx) % renderbufferCount) / float(renderbufferCount);
320 // Alpha should never be zero as advanced blend equations assume premultiplied alpha.
321 const float alphaScale = float(1 + (((renderbufferCount/2) + renderbufferCount - renderbufferNdx) % renderbufferCount)) / float(renderbufferCount);
323 switch (tcu::getTextureChannelClass(format.type))
325 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
327 const float red = -1000.0f + 2000.0f * redScale;
328 const float green = -1000.0f + 2000.0f * greenScale;
329 const float blue = -1000.0f + 2000.0f * blueScale;
330 const float alpha = -1000.0f + 2000.0f * alphaScale;
331 const Vec4 color (red, green, blue, alpha);
333 tcu::clear(refRenderbuffer, color);
334 gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr());
338 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
340 const deInt32 red = deInt32(info.valueMin.x() + (info.valueMax.x() - info.valueMin.x()) * redScale);
341 const deInt32 green = deInt32(info.valueMin.y() + (info.valueMax.y() - info.valueMin.y()) * greenScale);
342 const deInt32 blue = deInt32(info.valueMin.z() + (info.valueMax.z() - info.valueMin.z()) * blueScale);
343 const deInt32 alpha = deInt32(info.valueMin.w() + (info.valueMax.w() - info.valueMin.w()) * alphaScale);
344 const IVec4 color (red, green, blue, alpha);
346 tcu::clear(refRenderbuffer, color);
347 gl.clearBufferiv(GL_COLOR, renderbufferNdx, color.getPtr());
351 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
353 const deUint32 red = deUint32(info.valueMax.x() * redScale);
354 const deUint32 green = deUint32(info.valueMax.y() * greenScale);
355 const deUint32 blue = deUint32(info.valueMax.z() * blueScale);
356 const deUint32 alpha = deUint32(info.valueMax.w() * alphaScale);
357 const UVec4 color (red, green, blue, alpha);
359 tcu::clear(refRenderbuffer, color);
360 gl.clearBufferuiv(GL_COLOR, renderbufferNdx, color.getPtr());
364 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
366 const float red = info.valueMin.x() + (info.valueMax.x() - info.valueMin.x()) * redScale;
367 const float green = info.valueMin.y() + (info.valueMax.y() - info.valueMin.y()) * greenScale;
368 const float blue = info.valueMin.z() + (info.valueMax.z() - info.valueMin.z()) * blueScale;
369 const float alpha = info.valueMin.w() + (info.valueMax.w() - info.valueMin.w()) * alphaScale;
370 const Vec4 color (red, green, blue, alpha);
372 tcu::clear(refRenderbuffer, color);
373 gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr());
377 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
379 const float red = info.valueMax.x() * redScale;
380 const float green = info.valueMax.y() * greenScale;
381 const float blue = info.valueMax.z() * blueScale;
382 const float alpha = info.valueMax.w() * alphaScale;
383 const Vec4 color (red, green, blue, alpha);
385 tcu::clear(refRenderbuffer, color);
386 gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr());
394 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear renderbuffer.");
397 void genRenderbuffers (const glw::Functions& gl,
398 const vector<DrawBufferInfo>& drawBuffers,
399 const glu::Framebuffer& framebuffer,
400 const glu::RenderbufferVector& renderbuffers,
401 vector<TextureLevel>& refRenderbuffers)
403 vector<deUint32> bufs;
405 bufs.resize(drawBuffers.size());
407 DE_ASSERT(drawBuffers.size() == renderbuffers.size());
408 DE_ASSERT(drawBuffers.size() == refRenderbuffers.size());
410 gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
412 for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++)
414 const DrawBufferInfo& drawBuffer = drawBuffers[renderbufferNdx];
415 const TextureFormat& format = drawBuffer.getFormat();
416 const IVec2& size = drawBuffer.getSize();
417 const deUint32 glFormat = glu::getInternalFormat(format);
419 bufs[renderbufferNdx] = GL_COLOR_ATTACHMENT0 + renderbufferNdx;
420 refRenderbuffers[renderbufferNdx] = TextureLevel(drawBuffer.getFormat(), size.x(), size.y());
422 gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffers[renderbufferNdx]);
423 gl.renderbufferStorage(GL_RENDERBUFFER, glFormat, size.x(), size.y());
424 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + renderbufferNdx, GL_RENDERBUFFER, renderbuffers[renderbufferNdx]);
425 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create renderbuffer.");
428 gl.drawBuffers((glw::GLsizei)bufs.size(), &(bufs[0]));
430 for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++)
432 const DrawBufferInfo& drawBuffer = drawBuffers[renderbufferNdx];
433 const TextureFormat& format = drawBuffer.getFormat();
435 clearRenderbuffer(gl, format, renderbufferNdx, (int)refRenderbuffers.size(), refRenderbuffers[renderbufferNdx]);
438 gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
439 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
442 Vec4 getFixedPointFormatThreshold (const tcu::TextureFormat& sourceFormat, const tcu::TextureFormat& readPixelsFormat)
444 DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
445 DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
447 DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
448 DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
450 DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
451 DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
453 const tcu::IVec4 srcBits = tcu::getTextureFormatBitDepth(sourceFormat);
454 const tcu::IVec4 readBits = tcu::getTextureFormatBitDepth(readPixelsFormat);
456 Vec4 threshold = Vec4(0.0f);
458 for (int i = 0; i < 4; i++)
460 const int bits = de::min(srcBits[i], readBits[i]);
464 threshold[i] = 3.0f / static_cast<float>(((1ul << bits) - 1ul));
471 UVec4 getFloatULPThreshold (const tcu::TextureFormat& sourceFormat, const tcu::TextureFormat& readPixelsFormat)
473 const tcu::IVec4 srcMantissaBits = tcu::getTextureFormatMantissaBitDepth(sourceFormat);
474 const tcu::IVec4 readMantissaBits = tcu::getTextureFormatMantissaBitDepth(readPixelsFormat);
475 tcu::IVec4 ULPDiff(0);
477 for (int i = 0; i < 4; i++)
478 if (readMantissaBits[i] >= srcMantissaBits[i])
479 ULPDiff[i] = readMantissaBits[i] - srcMantissaBits[i];
481 return UVec4(4) * (UVec4(1) << (ULPDiff.cast<deUint32>()));
484 void verifyRenderbuffer (TestLog& log,
485 tcu::ResultCollector& results,
486 const tcu::TextureFormat& format,
488 const tcu::TextureLevel& refRenderbuffer,
489 const tcu::TextureLevel& result)
491 switch (tcu::getTextureChannelClass(format.type))
493 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
495 const string name = "Renderbuffer" + de::toString(renderbufferNdx);
496 const string desc = "Compare renderbuffer " + de::toString(renderbufferNdx);
497 const UVec4 threshold = getFloatULPThreshold(format, result.getFormat());
499 if (!tcu::floatUlpThresholdCompare(log, name.c_str(), desc.c_str(), refRenderbuffer, result, threshold, tcu::COMPARE_LOG_RESULT))
500 results.fail("Verification of renderbuffer " + de::toString(renderbufferNdx) + " failed.");
505 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
506 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
508 const string name = "Renderbuffer" + de::toString(renderbufferNdx);
509 const string desc = "Compare renderbuffer " + de::toString(renderbufferNdx);
510 const UVec4 threshold (1, 1, 1, 1);
512 if (!tcu::intThresholdCompare(log, name.c_str(), desc.c_str(), refRenderbuffer, result, threshold, tcu::COMPARE_LOG_RESULT))
513 results.fail("Verification of renderbuffer " + de::toString(renderbufferNdx) + " failed.");
518 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
519 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
521 const string name = "Renderbuffer" + de::toString(renderbufferNdx);
522 const string desc = "Compare renderbuffer " + de::toString(renderbufferNdx);
523 const Vec4 threshold = getFixedPointFormatThreshold(format, result.getFormat());
525 if (!tcu::floatThresholdCompare(log, name.c_str(), desc.c_str(), refRenderbuffer, result, threshold, tcu::COMPARE_LOG_RESULT))
526 results.fail("Verification of renderbuffer " + de::toString(renderbufferNdx) + " failed.");
536 TextureFormat getReadPixelFormat (const TextureFormat& format)
538 switch (tcu::getTextureChannelClass(format.type))
540 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
541 return TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32);
543 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
544 return TextureFormat(TextureFormat::RGBA, TextureFormat::SIGNED_INT32);
546 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
547 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
548 return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8);
550 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
551 return TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT);
555 return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8);
559 void verifyRenderbuffers (TestLog& log,
560 tcu::ResultCollector& results,
561 glu::RenderContext& renderContext,
562 const glu::RenderbufferVector& renderbuffers,
563 const glu::Framebuffer& framebuffer,
564 const vector<TextureLevel>& refRenderbuffers)
566 const glw::Functions& gl = renderContext.getFunctions();
568 DE_ASSERT(renderbuffers.size() == refRenderbuffers.size());
570 gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
572 for (int renderbufferNdx = 0; renderbufferNdx < (int)renderbuffers.size(); renderbufferNdx++)
574 const TextureLevel& refRenderbuffer = refRenderbuffers[renderbufferNdx];
575 const int width = refRenderbuffer.getWidth();
576 const int height = refRenderbuffer.getHeight();
577 const TextureFormat format = refRenderbuffer.getFormat();
579 tcu::TextureLevel result (getReadPixelFormat(format), width, height);
581 gl.readBuffer(GL_COLOR_ATTACHMENT0 + renderbufferNdx);
582 glu::readPixels(renderContext, 0, 0, result.getAccess());
583 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels from renderbuffer failed.");
585 verifyRenderbuffer(log, results, format, renderbufferNdx, refRenderbuffer, result);
588 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
591 static const float s_quadCoords[] =
602 void setBlendState (rr::FragmentOperationState& fragOps, const BlendState& state)
606 if (state.blendEq->is<BlendEq>())
608 if (isAdvancedBlendEq(state.blendEq->get<BlendEq>()))
610 const rr::BlendEquationAdvanced equation = mapGLBlendEquationAdvanced(state.blendEq->get<BlendEq>());
612 fragOps.blendMode = rr::BLENDMODE_ADVANCED;
613 fragOps.blendEquationAdvaced = equation;
617 const rr::BlendEquation equation = mapGLBlendEquation(state.blendEq->get<BlendEq>());
619 fragOps.blendMode = rr::BLENDMODE_STANDARD;
620 fragOps.blendRGBState.equation = equation;
621 fragOps.blendAState.equation = equation;
626 DE_ASSERT(state.blendEq->is<SeparateBlendEq>());
628 fragOps.blendMode = rr::BLENDMODE_STANDARD;
629 fragOps.blendRGBState.equation = mapGLBlendEquation(state.blendEq->get<SeparateBlendEq>().rgb);
630 fragOps.blendAState.equation = mapGLBlendEquation(state.blendEq->get<SeparateBlendEq>().alpha);
636 if (state.blendFunc->is<BlendFunc>())
638 const rr::BlendFunc srcFunction = mapGLBlendFunc(state.blendFunc->get<BlendFunc>().src);
639 const rr::BlendFunc dstFunction = mapGLBlendFunc(state.blendFunc->get<BlendFunc>().dst);
641 fragOps.blendRGBState.srcFunc = srcFunction;
642 fragOps.blendRGBState.dstFunc = dstFunction;
644 fragOps.blendAState.srcFunc = srcFunction;
645 fragOps.blendAState.dstFunc = dstFunction;
649 DE_ASSERT(state.blendFunc->is<SeparateBlendFunc>());
651 fragOps.blendRGBState.srcFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().rgb.src);
652 fragOps.blendRGBState.dstFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().rgb.dst);
654 fragOps.blendAState.srcFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().alpha.src);
655 fragOps.blendAState.dstFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().alpha.dst);
660 fragOps.colorMask = *state.colorMask;
663 rr::RenderState createRenderState (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const DrawBufferInfo& info, int subpixelBits)
665 const IVec2 size = info.getSize();
666 rr::RenderState state (rr::ViewportState(rr::WindowRectangle(0, 0, size.x(), size.y())), subpixelBits);
668 state.fragOps.blendMode = rr::BLENDMODE_STANDARD;
670 setBlendState(state.fragOps, preCommonBlendState);
671 setBlendState(state.fragOps, info.getBlendState());
672 setBlendState(state.fragOps, postCommonBlendState);
674 if (postCommonBlendState.enableBlend)
675 state.fragOps.blendMode = (*(postCommonBlendState.enableBlend) ? state.fragOps.blendMode : rr::BLENDMODE_NONE);
676 else if (info.getBlendState().enableBlend)
677 state.fragOps.blendMode = (*(info.getBlendState().enableBlend) ? state.fragOps.blendMode : rr::BLENDMODE_NONE);
678 else if (preCommonBlendState.enableBlend)
679 state.fragOps.blendMode = (*(preCommonBlendState.enableBlend) ? state.fragOps.blendMode : rr::BLENDMODE_NONE);
681 state.fragOps.blendMode = rr::BLENDMODE_NONE;
683 if (tcu::getTextureChannelClass(info.getFormat().type) != tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT
684 && tcu::getTextureChannelClass(info.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT
685 && tcu::getTextureChannelClass(info.getFormat().type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
686 state.fragOps.blendMode = rr::BLENDMODE_NONE;
691 class VertexShader : public rr::VertexShader
695 virtual void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
698 VertexShader::VertexShader (void)
699 : rr::VertexShader (1, 1)
701 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
702 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
705 void VertexShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
707 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
709 rr::VertexPacket& packet = *packets[packetNdx];
711 packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
712 packet.outputs[0] = 0.5f * (Vec4(1.0f) + rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx));
716 class FragmentShader : public rr::FragmentShader
719 FragmentShader (int drawBufferNdx, const DrawBufferInfo& info);
720 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
723 const int m_drawBufferNdx;
724 const DrawBufferInfo m_info;
727 FragmentShader::FragmentShader (int drawBufferNdx, const DrawBufferInfo& info)
728 : rr::FragmentShader (1, 1)
729 , m_drawBufferNdx (drawBufferNdx)
732 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
734 switch (tcu::getTextureChannelClass(m_info.getFormat().type))
736 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
737 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
738 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
739 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
742 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
743 m_outputs[0].type = rr::GENERICVECTYPE_UINT32;
746 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
747 m_outputs[0].type = rr::GENERICVECTYPE_INT32;
755 void FragmentShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
757 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
759 rr::FragmentPacket& packet = packets[packetNdx];
761 DE_ASSERT(m_drawBufferNdx >= 0);
764 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
766 const Vec2 vColor = rr::readVarying<float>(packet, context, 0, fragNdx).xy();
767 const float values[] =
775 switch (tcu::getTextureChannelClass(m_info.getFormat().type))
777 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
778 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
779 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
781 const Vec4 color (values[(m_drawBufferNdx + 0) % 4],
782 values[(m_drawBufferNdx + 1) % 4],
783 values[(m_drawBufferNdx + 2) % 4],
784 values[(m_drawBufferNdx + 3) % 4]);
786 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
790 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
792 const UVec4 color ((deUint32)(values[(m_drawBufferNdx + 0) % 4]),
793 (deUint32)(values[(m_drawBufferNdx + 1) % 4]),
794 (deUint32)(values[(m_drawBufferNdx + 2) % 4]),
795 (deUint32)(values[(m_drawBufferNdx + 3) % 4]));
797 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
801 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
803 const IVec4 color ((deInt32)(values[(m_drawBufferNdx + 0) % 4]),
804 (deInt32)(values[(m_drawBufferNdx + 1) % 4]),
805 (deInt32)(values[(m_drawBufferNdx + 2) % 4]),
806 (deInt32)(values[(m_drawBufferNdx + 3) % 4]));
808 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
819 rr::VertexAttrib createVertexAttrib (const float* coords)
821 rr::VertexAttrib attrib;
823 attrib.type = rr::VERTEXATTRIBTYPE_FLOAT;
825 attrib.pointer = coords;
830 void renderRefQuad (const BlendState& preCommonBlendState,
831 const BlendState& postCommonBlendState,
832 const vector<DrawBufferInfo>& drawBuffers,
833 const int subpixelBits,
834 vector<TextureLevel>& refRenderbuffers)
836 const rr::Renderer renderer;
837 const rr::PrimitiveList primitives (rr::PRIMITIVETYPE_TRIANGLES, 6, 0);
838 const rr::VertexAttrib vertexAttribs[] =
840 createVertexAttrib(s_quadCoords)
843 for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
845 if (drawBuffers[drawBufferNdx].getRender())
847 const rr::RenderState renderState (createRenderState(preCommonBlendState, postCommonBlendState, drawBuffers[drawBufferNdx], subpixelBits));
848 const rr::RenderTarget renderTarget (rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(refRenderbuffers[drawBufferNdx].getAccess()));
849 const VertexShader vertexShader;
850 const FragmentShader fragmentShader (drawBufferNdx, drawBuffers[drawBufferNdx]);
851 const rr::Program program (&vertexShader, &fragmentShader);
852 const rr::DrawCommand command (renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs), vertexAttribs, primitives);
854 renderer.draw(command);
859 bool requiresAdvancedBlendEq (const BlendState& pre, const BlendState post, const vector<DrawBufferInfo>& drawBuffers)
861 bool requiresAdvancedBlendEq = false;
863 if (pre.blendEq && pre.blendEq->is<BlendEq>())
864 requiresAdvancedBlendEq |= isAdvancedBlendEq(pre.blendEq->get<BlendEq>());
866 if (post.blendEq && post.blendEq->is<BlendEq>())
867 requiresAdvancedBlendEq |= isAdvancedBlendEq(post.blendEq->get<BlendEq>());
869 for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
871 const BlendState& drawBufferBlendState = drawBuffers[drawBufferNdx].getBlendState();
873 if (drawBufferBlendState.blendEq && drawBufferBlendState.blendEq->is<BlendEq>())
874 requiresAdvancedBlendEq |= isAdvancedBlendEq(drawBufferBlendState.blendEq->get<BlendEq>());
877 return requiresAdvancedBlendEq;
880 glu::VertexSource genVertexSource (glu::RenderContext& renderContext)
882 const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
884 const char* const vertexSource =
885 "${GLSL_VERSION_DECL}\n"
886 "layout(location=0) in highp vec2 i_coord;\n"
887 "out highp vec2 v_color;\n"
890 "\tv_color = 0.5 * (vec2(1.0) + i_coord);\n"
891 "\tgl_Position = vec4(i_coord, 0.0, 1.0);\n"
894 map<string, string> args;
895 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_300_ES);
897 return glu::VertexSource(tcu::StringTemplate(vertexSource).specialize(args));
900 glu::FragmentSource genFragmentSource (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const vector<DrawBufferInfo>& drawBuffers, glu::RenderContext& renderContext)
902 std::ostringstream stream;
903 const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
905 stream << "${GLSL_VERSION_DECL}\n";
907 if (requiresAdvancedBlendEq(preCommonBlendState, postCommonBlendState, drawBuffers))
909 stream << "${GLSL_EXTENSION}"
910 << "layout(blend_support_all_equations) out;\n";
913 stream << "in highp vec2 v_color;\n";
915 for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
917 const DrawBufferInfo& drawBuffer = drawBuffers[drawBufferNdx];
918 const TextureFormat& format = drawBuffer.getFormat();
920 stream << "layout(location=" << drawBufferNdx << ") out highp ";
922 switch (tcu::getTextureChannelClass(format.type))
924 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
925 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
926 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
930 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
934 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
942 stream << " o_drawBuffer" << drawBufferNdx << ";\n";
945 stream << "void main (void)\n"
948 for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
950 const DrawBufferInfo& drawBuffer = drawBuffers[drawBufferNdx];
951 const TextureFormat& format = drawBuffer.getFormat();
952 const char* const values[] =
960 stream << "\to_drawBuffer" << drawBufferNdx;
962 switch (tcu::getTextureChannelClass(format.type))
964 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
965 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
966 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
967 stream << " = vec4(" << values[(drawBufferNdx + 0) % 4]
968 << ", " << values[(drawBufferNdx + 1) % 4]
969 << ", " << values[(drawBufferNdx + 2) % 4]
970 << ", " << values[(drawBufferNdx + 3) % 4] << ");\n";
973 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
974 stream << " = uvec4(uint(" << values[(drawBufferNdx + 0) % 4]
975 << "), uint(" << values[(drawBufferNdx + 1) % 4]
976 << "), uint(" << values[(drawBufferNdx + 2) % 4]
977 << "), uint(" << values[(drawBufferNdx + 3) % 4] << "));\n";
980 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
981 stream << " = ivec4(int(" << values[(drawBufferNdx + 0) % 4]
982 << "), int(" << values[(drawBufferNdx + 1) % 4]
983 << "), int(" << values[(drawBufferNdx + 2) % 4]
984 << "), int(" << values[(drawBufferNdx + 3) % 4] << "));\n";
994 map<string, string> args;
995 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_300_ES);
996 args["GLSL_EXTENSION"] = supportsES32 ? "\n" : "#extension GL_KHR_blend_equation_advanced : require\n";
998 return glu::FragmentSource(tcu::StringTemplate(stream.str()).specialize(args));
1001 glu::ProgramSources genShaderSources (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const vector<DrawBufferInfo>& drawBuffers, glu::RenderContext& renderContext)
1003 return glu::ProgramSources() << genVertexSource(renderContext) << genFragmentSource(preCommonBlendState, postCommonBlendState, drawBuffers, renderContext);
1006 void renderGLQuad (glu::RenderContext& renderContext,
1007 const glu::ShaderProgram& program)
1009 const glu::VertexArrayBinding vertexArrays[] =
1011 glu::VertexArrayBinding(glu::BindingPoint(0), glu::VertexArrayPointer(glu::VTX_COMP_FLOAT, glu::VTX_COMP_CONVERT_NONE, 2, 6, 0, s_quadCoords))
1014 glu::draw(renderContext, program.getProgram(), 1, vertexArrays, glu::pr::Triangles(6));
1017 void renderQuad (TestLog& log,
1018 glu::RenderContext& renderContext,
1019 const BlendState& preCommonBlendState,
1020 const BlendState& postCommonBlendState,
1021 const vector<DrawBufferInfo>& drawBuffers,
1022 const glu::Framebuffer& framebuffer,
1023 vector<TextureLevel>& refRenderbuffers)
1025 const glw::Functions& gl = renderContext.getFunctions();
1026 const glu::ShaderProgram program (gl, genShaderSources(preCommonBlendState, postCommonBlendState, drawBuffers, renderContext));
1027 const IVec2 size = drawBuffers[0].getSize();
1028 const bool requiresBlendBarriers = requiresAdvancedBlendEq(preCommonBlendState, postCommonBlendState, drawBuffers);
1030 vector<deUint32> bufs;
1032 bufs.resize(drawBuffers.size());
1034 for (int bufNdx = 0; bufNdx < (int)bufs.size(); bufNdx++)
1035 bufs[bufNdx] = (drawBuffers[bufNdx].getRender() ? GL_COLOR_ATTACHMENT0 + bufNdx : GL_NONE);
1039 gl.viewport(0, 0, size.x(), size.y());
1040 gl.useProgram(program.getProgram());
1041 gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
1043 setCommonBlendState(gl, preCommonBlendState);
1045 for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++)
1046 setIndexedBlendState(gl, drawBuffers[renderbufferNdx].getBlendState(), renderbufferNdx);
1048 setCommonBlendState(gl, postCommonBlendState);
1050 gl.drawBuffers((glw::GLsizei)bufs.size(), &(bufs[0]));
1052 if (requiresBlendBarriers)
1055 renderGLQuad(renderContext, program);
1057 if (requiresBlendBarriers)
1060 gl.drawBuffers(0, 0);
1061 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1064 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render");
1066 int subpixelBits = 0;
1067 gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits);
1069 renderRefQuad(preCommonBlendState, postCommonBlendState, drawBuffers, subpixelBits, refRenderbuffers);
1072 void logBlendState (TestLog& log,
1073 const BlendState& blend)
1075 if (blend.enableBlend)
1077 if (*blend.enableBlend)
1078 log << TestLog::Message << "Enable blending." << TestLog::EndMessage;
1080 log << TestLog::Message << "Disable blending." << TestLog::EndMessage;
1083 if (blend.colorMask)
1085 const BVec4 mask = *blend.colorMask;
1087 log << TestLog::Message << "Set color mask: " << mask << "." << TestLog::EndMessage;
1092 const Either<BlendEq, SeparateBlendEq>& blendEq = *blend.blendEq;
1094 if (blendEq.is<BlendEq>())
1095 log << TestLog::Message << "Set blend equation: " << glu::getBlendEquationStr(blendEq.get<BlendEq>()) << "." << TestLog::EndMessage;
1096 else if (blendEq.is<SeparateBlendEq>())
1097 log << TestLog::Message << "Set blend equation rgb: " << glu::getBlendEquationStr(blendEq.get<SeparateBlendEq>().rgb) << ", alpha: " << glu::getBlendEquationStr(blendEq.get<SeparateBlendEq>().alpha) << "." << TestLog::EndMessage;
1102 if (blend.blendFunc)
1104 const Either<BlendFunc, SeparateBlendFunc>& blendFunc = *blend.blendFunc;
1106 if (blendFunc.is<BlendFunc>())
1107 log << TestLog::Message << "Set blend function source: " << glu::getBlendFactorStr(blendFunc.get<BlendFunc>().src) << ", destination: " << glu::getBlendFactorStr(blendFunc.get<BlendFunc>().dst) << "." << TestLog::EndMessage;
1108 else if (blendFunc.is<SeparateBlendFunc>())
1110 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;
1111 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;
1118 void logTestCaseInfo (TestLog& log,
1119 const BlendState& preCommonBlendState,
1120 const BlendState& postCommonBlendState,
1121 const vector<DrawBufferInfo>& drawBuffers)
1124 tcu::ScopedLogSection drawBuffersSection(log, "DrawBuffers", "Draw buffers");
1126 for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
1128 const tcu::ScopedLogSection drawBufferSection (log, "DrawBuffer" + de::toString(drawBufferNdx), "Draw Buffer " + de::toString(drawBufferNdx));
1129 const DrawBufferInfo& drawBuffer = drawBuffers[drawBufferNdx];
1131 log << TestLog::Message << "Format: " << drawBuffer.getFormat() << TestLog::EndMessage;
1132 log << TestLog::Message << "Size: " << drawBuffer.getSize() << TestLog::EndMessage;
1133 log << TestLog::Message << "Render: " << (drawBuffer.getRender() ? "true" : "false") << TestLog::EndMessage;
1137 if (!preCommonBlendState.isEmpty())
1139 tcu::ScopedLogSection s(log, "PreCommonState", "First set common blend state");
1140 logBlendState(log, preCommonBlendState);
1143 for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
1145 if (!drawBuffers[drawBufferNdx].getBlendState().isEmpty())
1147 const tcu::ScopedLogSection s(log, "DrawBufferState" + de::toString(drawBufferNdx), "Set DrawBuffer " + de::toString(drawBufferNdx) + " state to");
1149 logBlendState(log, drawBuffers[drawBufferNdx].getBlendState());
1153 if (!postCommonBlendState.isEmpty())
1155 tcu::ScopedLogSection s(log, "PostCommonState", "After set common blend state");
1156 logBlendState(log, postCommonBlendState);
1160 void runTest (TestLog& log,
1161 tcu::ResultCollector& results,
1162 glu::RenderContext& renderContext,
1164 const BlendState& preCommonBlendState,
1165 const BlendState& postCommonBlendState,
1166 const vector<DrawBufferInfo>& drawBuffers)
1168 const glw::Functions& gl = renderContext.getFunctions();
1169 glu::RenderbufferVector renderbuffers (gl, drawBuffers.size());
1170 glu::Framebuffer framebuffer (gl);
1171 vector<TextureLevel> refRenderbuffers (drawBuffers.size());
1173 logTestCaseInfo(log, preCommonBlendState, postCommonBlendState, drawBuffers);
1175 genRenderbuffers(gl, drawBuffers, framebuffer, renderbuffers, refRenderbuffers);
1177 renderQuad(log, renderContext, preCommonBlendState, postCommonBlendState, drawBuffers, framebuffer, refRenderbuffers);
1179 verifyRenderbuffers(log, results, renderContext, renderbuffers, framebuffer, refRenderbuffers);
1182 class DrawBuffersIndexedTest : public TestCase
1185 DrawBuffersIndexedTest (Context& context,
1186 const BlendState& preCommonBlendState,
1187 const BlendState& postCommonBlendState,
1188 const vector<DrawBufferInfo>& drawBuffers,
1190 const string& description);
1193 IterateResult iterate (void);
1196 const BlendState m_preCommonBlendState;
1197 const BlendState m_postCommonBlendState;
1198 const vector<DrawBufferInfo> m_drawBuffers;
1201 DrawBuffersIndexedTest::DrawBuffersIndexedTest (Context& context,
1202 const BlendState& preCommonBlendState,
1203 const BlendState& postCommonBlendState,
1204 const vector<DrawBufferInfo>& drawBuffers,
1206 const string& description)
1207 : TestCase (context, name.c_str(), description.c_str())
1208 , m_preCommonBlendState (preCommonBlendState)
1209 , m_postCommonBlendState (postCommonBlendState)
1210 , m_drawBuffers (drawBuffers)
1214 void DrawBuffersIndexedTest::init (void)
1216 const bool supportsES32orGL45 = checkES32orGL45Support(m_context);
1218 if (!supportsES32orGL45)
1220 if (requiresAdvancedBlendEq(m_preCommonBlendState, m_postCommonBlendState, m_drawBuffers) && !m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"))
1221 TCU_THROW(NotSupportedError, "Extension GL_KHR_blend_equation_advanced not supported");
1223 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1224 TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1228 TestCase::IterateResult DrawBuffersIndexedTest::iterate (void)
1230 TestLog& log = m_testCtx.getLog();
1231 tcu::ResultCollector results (log);
1233 runTest(log, results, m_context.getRenderContext(), m_preCommonBlendState, m_postCommonBlendState, m_drawBuffers);
1235 results.setTestContextResult(m_testCtx);
1240 BlendEq getRandomBlendEq (de::Random& rng)
1242 const BlendEq eqs[] =
1246 GL_FUNC_REVERSE_SUBTRACT,
1251 return de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(eqs)>(eqs, rng.getUint32() % DE_LENGTH_OF_ARRAY(eqs));
1254 BlendFunc getRandomBlendFunc (de::Random& rng)
1256 const deUint32 funcs[] =
1261 GL_ONE_MINUS_SRC_COLOR,
1263 GL_ONE_MINUS_DST_COLOR,
1265 GL_ONE_MINUS_SRC_ALPHA,
1267 GL_ONE_MINUS_DST_ALPHA,
1269 GL_ONE_MINUS_CONSTANT_COLOR,
1271 GL_ONE_MINUS_CONSTANT_ALPHA,
1272 GL_SRC_ALPHA_SATURATE
1275 const deUint32 src = de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(funcs)>(funcs, rng.getUint32() % DE_LENGTH_OF_ARRAY(funcs));
1276 const deUint32 dst = de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(funcs)>(funcs, rng.getUint32() % DE_LENGTH_OF_ARRAY(funcs));
1278 return BlendFunc(src, dst);
1281 void genRandomBlendState (de::Random& rng, BlendState& blendState)
1284 blendState.enableBlend = rng.getBool();
1289 blendState.blendEq = getRandomBlendEq(rng);
1292 const BlendEq rgb = getRandomBlendEq(rng);
1293 const BlendEq alpha = getRandomBlendEq(rng);
1295 blendState.blendEq = SeparateBlendEq(rgb, alpha);
1302 blendState.blendFunc = getRandomBlendFunc(rng);
1305 const BlendFunc rgb = getRandomBlendFunc(rng);
1306 const BlendFunc alpha = getRandomBlendFunc(rng);
1308 blendState.blendFunc = SeparateBlendFunc(rgb, alpha);
1314 const bool red = rng.getBool();
1315 const bool green = rng.getBool();
1316 const bool blue = rng.getBool();
1317 const bool alpha = rng.getBool();
1319 blendState.colorMask = BVec4(red, blue, green, alpha);
1323 TextureFormat getRandomFormat (de::Random& rng, Context& context)
1325 const bool supportsES32orGL45 = checkES32orGL45Support(context);
1327 const deUint32 glFormats[] =
1363 if (supportsES32orGL45)
1364 return glu::mapGLInternalFormat(de::getArrayElement(glFormats, rng.getUint32() % DE_LENGTH_OF_ARRAY(glFormats)));
1367 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(glFormats) == 32);
1368 return glu::mapGLInternalFormat(de::getArrayElement(glFormats, rng.getUint32() % (DE_LENGTH_OF_ARRAY(glFormats) - 5)));
1372 void genRandomTest (de::Random& rng, BlendState& preCommon, BlendState& postCommon, vector<DrawBufferInfo>& drawBuffers, int maxDrawBufferCount, Context& context)
1374 genRandomBlendState(rng, preCommon);
1375 genRandomBlendState(rng, postCommon);
1377 for (int drawBufferNdx = 0; drawBufferNdx < maxDrawBufferCount; drawBufferNdx++)
1379 const bool render = rng.getFloat() > 0.1f;
1380 const IVec2 size (64, 64);
1381 const TextureFormat format (getRandomFormat(rng, context));
1382 BlendState blendState;
1384 genRandomBlendState(rng, blendState);
1386 // 32bit float formats don't support blending in GLES32
1387 if (format.type == tcu::TextureFormat::FLOAT)
1389 // If format is 32bit float post common can't enable blending
1390 if (postCommon.enableBlend && *postCommon.enableBlend)
1392 // Either don't set enable blend or disable blending
1394 postCommon.enableBlend = tcu::Nothing;
1396 postCommon.enableBlend = tcu::just(false);
1399 // If post common doesn't disable blending, per attachment state or
1401 if (!postCommon.enableBlend)
1403 // If pre common enables blend per attachment must disable it
1404 // If per attachment state changes blend state it must disable it
1405 if ((preCommon.enableBlend && *preCommon.enableBlend)
1406 || blendState.enableBlend)
1407 blendState.enableBlend = tcu::just(false);
1411 drawBuffers.push_back(DrawBufferInfo(render, size, blendState, format));
1415 class MaxDrawBuffersIndexedTest : public TestCase
1418 MaxDrawBuffersIndexedTest (Context& contet, int seed);
1421 IterateResult iterate (void);
1427 MaxDrawBuffersIndexedTest::MaxDrawBuffersIndexedTest (Context& context, int seed)
1428 : TestCase (context, de::toString(seed).c_str(), de::toString(seed).c_str())
1429 , m_seed (deInt32Hash(seed) ^ 1558001307u)
1433 void MaxDrawBuffersIndexedTest::init (void)
1435 const bool supportsES32orGL45 = checkES32orGL45Support(m_context);
1437 if (!supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1438 TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1441 TestCase::IterateResult MaxDrawBuffersIndexedTest::iterate (void)
1443 TestLog& log = m_testCtx.getLog();
1444 tcu::ResultCollector results (log);
1445 de::Random rng (m_seed);
1446 BlendState preCommonBlendState;
1447 BlendState postCommonBlendState;
1448 vector<DrawBufferInfo> drawBuffers;
1450 genRandomTest(rng, preCommonBlendState, postCommonBlendState, drawBuffers, 4, m_context);
1452 runTest(log, results, m_context.getRenderContext(), preCommonBlendState, postCommonBlendState, drawBuffers);
1454 results.setTestContextResult(m_testCtx);
1459 class ImplMaxDrawBuffersIndexedTest : public TestCase
1462 ImplMaxDrawBuffersIndexedTest (Context& contet, int seed);
1465 IterateResult iterate (void);
1471 ImplMaxDrawBuffersIndexedTest::ImplMaxDrawBuffersIndexedTest (Context& context, int seed)
1472 : TestCase (context, de::toString(seed).c_str(), de::toString(seed).c_str())
1473 , m_seed (deInt32Hash(seed) ^ 2686315738u)
1477 void ImplMaxDrawBuffersIndexedTest::init (void)
1479 const bool supportsES32orGL45 = checkES32orGL45Support(m_context);
1481 if (!supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1482 TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1485 TestCase::IterateResult ImplMaxDrawBuffersIndexedTest::iterate (void)
1487 TestLog& log = m_testCtx.getLog();
1488 tcu::ResultCollector results (log);
1489 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1490 de::Random rng (m_seed);
1491 deInt32 maxDrawBuffers = 0;
1492 BlendState preCommonBlendState;
1493 BlendState postCommonBlendState;
1494 vector<DrawBufferInfo> drawBuffers;
1496 gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
1497 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_DRAW_BUFFERS) failed");
1499 TCU_CHECK(maxDrawBuffers > 0);
1501 genRandomTest(rng, preCommonBlendState, postCommonBlendState, drawBuffers, maxDrawBuffers, m_context);
1503 runTest(log, results, m_context.getRenderContext(), preCommonBlendState, postCommonBlendState, drawBuffers);
1505 results.setTestContextResult(m_testCtx);
1516 TestCase* createDiffTest (Context& context, PrePost prepost, const char* name, const BlendState& commonState, const BlendState& drawBufferState)
1518 const BlendState emptyState = BlendState(tcu::Nothing, tcu::Nothing, tcu::Nothing, tcu::Nothing);
1522 const BlendState preState = BlendState((commonState.enableBlend ? commonState.enableBlend : just(true)),
1523 commonState.blendEq,
1524 (commonState.blendFunc ? commonState.blendFunc : just(Either<BlendFunc, SeparateBlendFunc>(BlendFunc(GL_ONE, GL_ONE)))),
1526 vector<DrawBufferInfo> drawBuffers;
1528 drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), emptyState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1529 drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1531 return new DrawBuffersIndexedTest(context, preState, emptyState, drawBuffers, name, name);
1533 else if (prepost == POST)
1535 const BlendState preState = BlendState(just(true),
1537 Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_ONE, GL_ONE)),
1539 vector<DrawBufferInfo> drawBuffers;
1541 drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), emptyState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1542 drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1544 return new DrawBuffersIndexedTest(context, preState, commonState, drawBuffers, name, name);
1553 TestCase* createAdvancedEqDiffTest (Context& context, PrePost prepost, const char* name, const BlendState& commonState, const BlendState& drawBufferState)
1555 const BlendState emptyState = BlendState(tcu::Nothing, tcu::Nothing, tcu::Nothing, tcu::Nothing);
1559 const BlendState preState = BlendState((commonState.enableBlend ? commonState.enableBlend : just(true)),
1560 commonState.blendEq,
1561 (commonState.blendFunc ? commonState.blendFunc : just(Either<BlendFunc, SeparateBlendFunc>(BlendFunc(GL_ONE, GL_ONE)))),
1563 vector<DrawBufferInfo> drawBuffers;
1565 drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1567 return new DrawBuffersIndexedTest(context, preState, emptyState, drawBuffers, name, name);
1569 else if (prepost == POST)
1571 const BlendState preState = BlendState(just(true),
1573 Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_ONE, GL_ONE)),
1575 vector<DrawBufferInfo> drawBuffers;
1577 drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1579 return new DrawBuffersIndexedTest(context, preState, commonState, drawBuffers, name, name);
1588 void addDrawBufferCommonTests (TestCaseGroup* root, PrePost prepost)
1590 const BlendState emptyState = BlendState(Maybe<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1593 const BlendState disableState = BlendState(just(false), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1594 const BlendState enableState = BlendState(just(true), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1596 root->addChild(createDiffTest(root->getContext(), prepost, "common_enable_buffer_enable", enableState, enableState));
1597 root->addChild(createDiffTest(root->getContext(), prepost, "common_disable_buffer_disable", disableState, disableState));
1598 root->addChild(createDiffTest(root->getContext(), prepost, "common_disable_buffer_enable", disableState, enableState));
1599 root->addChild(createDiffTest(root->getContext(), prepost, "common_enable_buffer_disable", enableState, disableState));
1603 const BlendState eqStateA = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(GL_FUNC_ADD), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1604 const BlendState eqStateB = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(GL_FUNC_SUBTRACT), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1606 const BlendState separateEqStateA = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(SeparateBlendEq(GL_FUNC_ADD, GL_FUNC_SUBTRACT)), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1607 const BlendState separateEqStateB = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(SeparateBlendEq(GL_FUNC_SUBTRACT, GL_FUNC_ADD)), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1609 const BlendState advancedEqStateA = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(GL_DIFFERENCE), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1610 const BlendState advancedEqStateB = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(GL_SCREEN), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1612 root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_eq_buffer_blend_eq", eqStateA, eqStateB));
1613 root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_eq_buffer_separate_blend_eq", eqStateA, separateEqStateB));
1614 root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_blend_eq_buffer_advanced_blend_eq", eqStateA, advancedEqStateB));
1616 root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_eq_buffer_blend_eq", separateEqStateA, eqStateB));
1617 root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_eq_buffer_separate_blend_eq", separateEqStateA, separateEqStateB));
1618 root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_separate_blend_eq_buffer_advanced_blend_eq", separateEqStateA, advancedEqStateB));
1620 root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_advanced_blend_eq_buffer_blend_eq", advancedEqStateA, eqStateB));
1621 root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_advanced_blend_eq_buffer_separate_blend_eq", advancedEqStateA, separateEqStateB));
1622 root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_advanced_blend_eq_buffer_advanced_blend_eq", advancedEqStateA, advancedEqStateB));
1626 const BlendState funcStateA = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA)), Maybe<BVec4>());
1627 const BlendState funcStateB = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA)), Maybe<BVec4>());
1628 const BlendState separateFuncStateA = BlendState(tcu::Nothing, 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>());
1629 const BlendState separateFuncStateB = BlendState(tcu::Nothing, 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>());
1631 root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_func_buffer_blend_func", funcStateA, funcStateB));
1632 root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_func_buffer_separate_blend_func", funcStateA, separateFuncStateB));
1633 root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_func_buffer_blend_func", separateFuncStateA, funcStateB));
1634 root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_func_buffer_separate_blend_func", separateFuncStateA, separateFuncStateB));
1638 const BlendState commonColorMaskState = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>(BVec4(true, false, true, false)));
1639 const BlendState bufferColorMaskState = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>(BVec4(false, true, false, true)));
1641 root->addChild(createDiffTest(root->getContext(), prepost, "common_color_mask_buffer_color_mask", commonColorMaskState, bufferColorMaskState));
1645 void addRandomMaxTest (TestCaseGroup* root)
1647 for (int i = 0; i < 20; i++)
1648 root->addChild(new MaxDrawBuffersIndexedTest(root->getContext(), i));
1651 void addRandomImplMaxTest (TestCaseGroup* root)
1653 for (int i = 0; i < 20; i++)
1654 root->addChild(new ImplMaxDrawBuffersIndexedTest(root->getContext(), i));
1659 TestCaseGroup* createDrawBuffersIndexedTests (Context& context)
1661 const BlendState emptyState = BlendState(Maybe<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1662 TestCaseGroup* const group = new TestCaseGroup(context, "draw_buffers_indexed", "Test for indexed draw buffers. GL_EXT_draw_buffers_indexed.");
1664 TestCaseGroup* const preGroup = new TestCaseGroup(context, "overwrite_common", "Set common state and overwrite it with draw buffer blend state.");
1665 TestCaseGroup* const postGroup = new TestCaseGroup(context, "overwrite_indexed", "Set indexed blend state and overwrite it with common state.");
1666 TestCaseGroup* const randomGroup = new TestCaseGroup(context, "random", "Random indexed blend state tests.");
1667 TestCaseGroup* const maxGroup = new TestCaseGroup(context, "max_required_draw_buffers", "Random tests using minimum maximum number of draw buffers.");
1668 TestCaseGroup* const maxImplGroup = new TestCaseGroup(context, "max_implementation_draw_buffers", "Random tests using maximum number of draw buffers reported by implementation.");
1670 group->addChild(preGroup);
1671 group->addChild(postGroup);
1672 group->addChild(randomGroup);
1674 randomGroup->addChild(maxGroup);
1675 randomGroup->addChild(maxImplGroup);
1677 addDrawBufferCommonTests(preGroup, PRE);
1678 addDrawBufferCommonTests(postGroup, POST);
1679 addRandomMaxTest(maxGroup);
1680 addRandomImplMaxTest(maxImplGroup);