xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fDrawBuffersIndexedTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2015 The Android Open Source Project
6  *
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  *//*!
20  * \file
21  * \brief Indexed blend operation tests (GL_EXT_draw_buffers_indexed)
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fDrawBuffersIndexedTests.hpp"
25 
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"
33 
34 #include "sglrReferenceUtils.hpp"
35 
36 #include "rrMultisamplePixelBufferAccess.hpp"
37 #include "rrRenderer.hpp"
38 
39 #include "glwEnums.hpp"
40 #include "glwFunctions.hpp"
41 
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"
53 
54 #include "deRandom.hpp"
55 #include "deArrayUtil.hpp"
56 #include "deStringUtil.hpp"
57 #include "deUniquePtr.hpp"
58 
59 #include "deInt32.h"
60 
61 #include <string>
62 #include <vector>
63 #include <map>
64 
65 using tcu::BVec4;
66 using tcu::Either;
67 using tcu::IVec2;
68 using tcu::IVec4;
69 using tcu::just;
70 using tcu::Maybe;
71 using tcu::TestLog;
72 using tcu::TextureFormat;
73 using tcu::TextureLevel;
74 using tcu::UVec4;
75 using tcu::Vec2;
76 using tcu::Vec4;
77 
78 using std::map;
79 using std::string;
80 using std::vector;
81 
82 using sglr::rr_util::mapGLBlendEquation;
83 using sglr::rr_util::mapGLBlendEquationAdvanced;
84 using sglr::rr_util::mapGLBlendFunc;
85 
86 namespace deqp
87 {
88 namespace gles3
89 {
90 namespace Functional
91 {
92 namespace
93 {
94 
95 typedef uint32_t BlendEq;
96 
isAdvancedBlendEq(BlendEq eq)97 bool isAdvancedBlendEq(BlendEq eq)
98 {
99     switch (eq)
100     {
101     case GL_MULTIPLY:
102         return true;
103     case GL_SCREEN:
104         return true;
105     case GL_OVERLAY:
106         return true;
107     case GL_DARKEN:
108         return true;
109     case GL_LIGHTEN:
110         return true;
111     case GL_COLORDODGE:
112         return true;
113     case GL_COLORBURN:
114         return true;
115     case GL_HARDLIGHT:
116         return true;
117     case GL_SOFTLIGHT:
118         return true;
119     case GL_DIFFERENCE:
120         return true;
121     case GL_EXCLUSION:
122         return true;
123     case GL_HSL_HUE:
124         return true;
125     case GL_HSL_SATURATION:
126         return true;
127     case GL_HSL_COLOR:
128         return true;
129     case GL_HSL_LUMINOSITY:
130         return true;
131     default:
132         return false;
133     }
134 }
135 
136 struct SeparateBlendEq
137 {
SeparateBlendEqdeqp::gles3::Functional::__anon92c96ea80111::SeparateBlendEq138     SeparateBlendEq(BlendEq rgb_, BlendEq alpha_) : rgb(rgb_), alpha(alpha_)
139     {
140     }
141 
142     BlendEq rgb;
143     BlendEq alpha;
144 };
145 
146 struct BlendFunc
147 {
BlendFuncdeqp::gles3::Functional::__anon92c96ea80111::BlendFunc148     BlendFunc(uint32_t src_, uint32_t dst_) : src(src_), dst(dst_)
149     {
150     }
151 
152     uint32_t src;
153     uint32_t dst;
154 };
155 
156 struct SeparateBlendFunc
157 {
SeparateBlendFuncdeqp::gles3::Functional::__anon92c96ea80111::SeparateBlendFunc158     SeparateBlendFunc(BlendFunc rgb_, BlendFunc alpha_) : rgb(rgb_), alpha(alpha_)
159     {
160     }
161 
162     BlendFunc rgb;
163     BlendFunc alpha;
164 };
165 
166 typedef uint32_t DrawBuffer;
167 
168 struct BlendState
169 {
BlendStatedeqp::gles3::Functional::__anon92c96ea80111::BlendState170     BlendState(void)
171     {
172     }
173 
BlendStatedeqp::gles3::Functional::__anon92c96ea80111::BlendState174     BlendState(const Maybe<bool> &enableBlend_, const Maybe<Either<BlendEq, SeparateBlendEq>> &blendEq_,
175                const Maybe<Either<BlendFunc, SeparateBlendFunc>> &blendFunc_, const Maybe<BVec4> &colorMask_)
176         : enableBlend(enableBlend_)
177         , blendEq(blendEq_)
178         , blendFunc(blendFunc_)
179         , colorMask(colorMask_)
180     {
181     }
182 
isEmptydeqp::gles3::Functional::__anon92c96ea80111::BlendState183     bool isEmpty(void) const
184     {
185         return (!enableBlend) && (!blendEq) && (!blendFunc) && (!colorMask);
186     }
187 
188     Maybe<bool> enableBlend;
189     Maybe<Either<BlendEq, SeparateBlendEq>> blendEq;
190     Maybe<Either<BlendFunc, SeparateBlendFunc>> blendFunc;
191     Maybe<BVec4> colorMask;
192 };
193 
checkES32orGL45Support(Context & ctx)194 static bool checkES32orGL45Support(Context &ctx)
195 {
196     auto ctxType = ctx.getRenderContext().getType();
197     return contextSupports(ctxType, glu::ApiType::es(3, 2)) || contextSupports(ctxType, glu::ApiType::core(4, 5));
198 }
199 
setCommonBlendState(const glw::Functions & gl,const BlendState & blend)200 void setCommonBlendState(const glw::Functions &gl, const BlendState &blend)
201 {
202     if (blend.enableBlend)
203     {
204         if (*blend.enableBlend)
205             gl.enable(GL_BLEND);
206         else
207             gl.disable(GL_BLEND);
208     }
209 
210     if (blend.colorMask)
211     {
212         const BVec4 &mask = *blend.colorMask;
213 
214         gl.colorMask(mask.x(), mask.y(), mask.z(), mask.w());
215     }
216 
217     if (blend.blendEq)
218     {
219         const Either<BlendEq, SeparateBlendEq> &blendEq = *blend.blendEq;
220 
221         if (blendEq.is<BlendEq>())
222             gl.blendEquation(blendEq.get<BlendEq>());
223         else if (blendEq.is<SeparateBlendEq>())
224             gl.blendEquationSeparate(blendEq.get<SeparateBlendEq>().rgb, blendEq.get<SeparateBlendEq>().alpha);
225         else
226             DE_ASSERT(false);
227     }
228 
229     if (blend.blendFunc)
230     {
231         const Either<BlendFunc, SeparateBlendFunc> &blendFunc = *blend.blendFunc;
232 
233         if (blendFunc.is<BlendFunc>())
234             gl.blendFunc(blendFunc.get<BlendFunc>().src, blendFunc.get<BlendFunc>().dst);
235         else if (blendFunc.is<SeparateBlendFunc>())
236             gl.blendFuncSeparate(blendFunc.get<SeparateBlendFunc>().rgb.src, blendFunc.get<SeparateBlendFunc>().rgb.dst,
237                                  blendFunc.get<SeparateBlendFunc>().alpha.src,
238                                  blendFunc.get<SeparateBlendFunc>().alpha.dst);
239         else
240             DE_ASSERT(false);
241     }
242 
243     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set common blend state.");
244 }
245 
setIndexedBlendState(const glw::Functions & gl,const BlendState & blend,uint32_t index)246 void setIndexedBlendState(const glw::Functions &gl, const BlendState &blend, uint32_t index)
247 {
248     if (blend.enableBlend)
249     {
250         if (*blend.enableBlend)
251             gl.enablei(GL_BLEND, index);
252         else
253             gl.disablei(GL_BLEND, index);
254     }
255 
256     if (blend.colorMask)
257     {
258         const BVec4 mask = *blend.colorMask;
259 
260         gl.colorMaski(index, mask.x(), mask.y(), mask.z(), mask.w());
261     }
262 
263     if (blend.blendEq)
264     {
265         const Either<BlendEq, SeparateBlendEq> &blendEq = *blend.blendEq;
266 
267         if (blendEq.is<BlendEq>())
268             gl.blendEquationi(index, blendEq.get<BlendEq>());
269         else if (blendEq.is<SeparateBlendEq>())
270             gl.blendEquationSeparatei(index, blendEq.get<SeparateBlendEq>().rgb, blendEq.get<SeparateBlendEq>().alpha);
271         else
272             DE_ASSERT(false);
273     }
274 
275     if (blend.blendFunc)
276     {
277         const Either<BlendFunc, SeparateBlendFunc> &blendFunc = *blend.blendFunc;
278 
279         if (blendFunc.is<BlendFunc>())
280             gl.blendFunci(index, blendFunc.get<BlendFunc>().src, blendFunc.get<BlendFunc>().dst);
281         else if (blendFunc.is<SeparateBlendFunc>())
282             gl.blendFuncSeparatei(
283                 index, blendFunc.get<SeparateBlendFunc>().rgb.src, blendFunc.get<SeparateBlendFunc>().rgb.dst,
284                 blendFunc.get<SeparateBlendFunc>().alpha.src, blendFunc.get<SeparateBlendFunc>().alpha.dst);
285         else
286             DE_ASSERT(false);
287     }
288 
289     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set draw buffer specifig blend state.");
290 }
291 
292 class DrawBufferInfo
293 {
294 public:
295     DrawBufferInfo(bool render, const IVec2 &size, const BlendState &blendState, const TextureFormat &format);
296 
getFormat(void) const297     const TextureFormat &getFormat(void) const
298     {
299         return m_format;
300     }
getSize(void) const301     const IVec2 &getSize(void) const
302     {
303         return m_size;
304     }
getBlendState(void) const305     const BlendState &getBlendState(void) const
306     {
307         return m_blendState;
308     }
getRender(void) const309     bool getRender(void) const
310     {
311         return m_render;
312     }
313 
314 private:
315     bool m_render;
316     IVec2 m_size;
317     TextureFormat m_format;
318     BlendState m_blendState;
319 };
320 
DrawBufferInfo(bool render,const IVec2 & size,const BlendState & blendState,const TextureFormat & format)321 DrawBufferInfo::DrawBufferInfo(bool render, const IVec2 &size, const BlendState &blendState,
322                                const TextureFormat &format)
323     : m_render(render)
324     , m_size(size)
325     , m_format(format)
326     , m_blendState(blendState)
327 {
328 }
329 
clearRenderbuffer(const glw::Functions & gl,const tcu::TextureFormat & format,int renderbufferNdx,int renderbufferCount,tcu::TextureLevel & refRenderbuffer)330 void clearRenderbuffer(const glw::Functions &gl, const tcu::TextureFormat &format, int renderbufferNdx,
331                        int renderbufferCount, tcu::TextureLevel &refRenderbuffer)
332 {
333     const tcu::TextureFormatInfo info = tcu::getTextureFormatInfo(format);
334 
335     // Clear each buffer to different color
336     const float redScale  = float(renderbufferNdx + 1) / float(renderbufferCount);
337     const float blueScale = float(renderbufferCount - renderbufferNdx) / float(renderbufferCount);
338     const float greenScale =
339         float(((renderbufferCount / 2) + renderbufferNdx) % renderbufferCount) / float(renderbufferCount);
340     // Alpha should never be zero as advanced blend equations assume premultiplied alpha.
341     const float alphaScale =
342         float(1 + (((renderbufferCount / 2) + renderbufferCount - renderbufferNdx) % renderbufferCount)) /
343         float(renderbufferCount);
344 
345     switch (tcu::getTextureChannelClass(format.type))
346     {
347     case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
348     {
349         const float red   = -1000.0f + 2000.0f * redScale;
350         const float green = -1000.0f + 2000.0f * greenScale;
351         const float blue  = -1000.0f + 2000.0f * blueScale;
352         const float alpha = -1000.0f + 2000.0f * alphaScale;
353         const Vec4 color(red, green, blue, alpha);
354 
355         tcu::clear(refRenderbuffer, color);
356         gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr());
357         break;
358     }
359 
360     case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
361     {
362         const int32_t red   = int32_t(info.valueMin.x() + (info.valueMax.x() - info.valueMin.x()) * redScale);
363         const int32_t green = int32_t(info.valueMin.y() + (info.valueMax.y() - info.valueMin.y()) * greenScale);
364         const int32_t blue  = int32_t(info.valueMin.z() + (info.valueMax.z() - info.valueMin.z()) * blueScale);
365         const int32_t alpha = int32_t(info.valueMin.w() + (info.valueMax.w() - info.valueMin.w()) * alphaScale);
366         const IVec4 color(red, green, blue, alpha);
367 
368         tcu::clear(refRenderbuffer, color);
369         gl.clearBufferiv(GL_COLOR, renderbufferNdx, color.getPtr());
370         break;
371     }
372 
373     case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
374     {
375         const uint32_t red   = uint32_t(info.valueMax.x() * redScale);
376         const uint32_t green = uint32_t(info.valueMax.y() * greenScale);
377         const uint32_t blue  = uint32_t(info.valueMax.z() * blueScale);
378         const uint32_t alpha = uint32_t(info.valueMax.w() * alphaScale);
379         const UVec4 color(red, green, blue, alpha);
380 
381         tcu::clear(refRenderbuffer, color);
382         gl.clearBufferuiv(GL_COLOR, renderbufferNdx, color.getPtr());
383         break;
384     }
385 
386     case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
387     {
388         const float red   = info.valueMin.x() + (info.valueMax.x() - info.valueMin.x()) * redScale;
389         const float green = info.valueMin.y() + (info.valueMax.y() - info.valueMin.y()) * greenScale;
390         const float blue  = info.valueMin.z() + (info.valueMax.z() - info.valueMin.z()) * blueScale;
391         const float alpha = info.valueMin.w() + (info.valueMax.w() - info.valueMin.w()) * alphaScale;
392         const Vec4 color(red, green, blue, alpha);
393 
394         tcu::clear(refRenderbuffer, color);
395         gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr());
396         break;
397     }
398 
399     case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
400     {
401         const float red   = info.valueMax.x() * redScale;
402         const float green = info.valueMax.y() * greenScale;
403         const float blue  = info.valueMax.z() * blueScale;
404         const float alpha = info.valueMax.w() * alphaScale;
405         const Vec4 color(red, green, blue, alpha);
406 
407         tcu::clear(refRenderbuffer, color);
408         gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr());
409         break;
410     }
411 
412     default:
413         DE_ASSERT(false);
414     }
415 
416     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear renderbuffer.");
417 }
418 
genRenderbuffers(const glw::Functions & gl,const vector<DrawBufferInfo> & drawBuffers,const glu::Framebuffer & framebuffer,const glu::RenderbufferVector & renderbuffers,vector<TextureLevel> & refRenderbuffers)419 void genRenderbuffers(const glw::Functions &gl, const vector<DrawBufferInfo> &drawBuffers,
420                       const glu::Framebuffer &framebuffer, const glu::RenderbufferVector &renderbuffers,
421                       vector<TextureLevel> &refRenderbuffers)
422 {
423     vector<uint32_t> bufs;
424 
425     bufs.resize(drawBuffers.size());
426 
427     DE_ASSERT(drawBuffers.size() == renderbuffers.size());
428     DE_ASSERT(drawBuffers.size() == refRenderbuffers.size());
429 
430     gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
431 
432     for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++)
433     {
434         const DrawBufferInfo &drawBuffer = drawBuffers[renderbufferNdx];
435         const TextureFormat &format      = drawBuffer.getFormat();
436         const IVec2 &size                = drawBuffer.getSize();
437         const uint32_t glFormat          = glu::getInternalFormat(format);
438 
439         bufs[renderbufferNdx]             = GL_COLOR_ATTACHMENT0 + renderbufferNdx;
440         refRenderbuffers[renderbufferNdx] = TextureLevel(drawBuffer.getFormat(), size.x(), size.y());
441 
442         gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffers[renderbufferNdx]);
443         gl.renderbufferStorage(GL_RENDERBUFFER, glFormat, size.x(), size.y());
444         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + renderbufferNdx, GL_RENDERBUFFER,
445                                    renderbuffers[renderbufferNdx]);
446         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create renderbuffer.");
447     }
448 
449     gl.drawBuffers((glw::GLsizei)bufs.size(), &(bufs[0]));
450 
451     for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++)
452     {
453         const DrawBufferInfo &drawBuffer = drawBuffers[renderbufferNdx];
454         const TextureFormat &format      = drawBuffer.getFormat();
455 
456         clearRenderbuffer(gl, format, renderbufferNdx, (int)refRenderbuffers.size(), refRenderbuffers[renderbufferNdx]);
457     }
458 
459     gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
460     gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
461 }
462 
getFixedPointFormatThreshold(const tcu::TextureFormat & sourceFormat,const tcu::TextureFormat & readPixelsFormat)463 Vec4 getFixedPointFormatThreshold(const tcu::TextureFormat &sourceFormat, const tcu::TextureFormat &readPixelsFormat)
464 {
465     DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
466     DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
467 
468     DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
469     DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
470 
471     DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
472     DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
473 
474     const tcu::IVec4 srcBits  = tcu::getTextureFormatBitDepth(sourceFormat);
475     const tcu::IVec4 readBits = tcu::getTextureFormatBitDepth(readPixelsFormat);
476 
477     Vec4 threshold = Vec4(0.0f);
478 
479     for (int i = 0; i < 4; i++)
480     {
481         const int bits = de::min(srcBits[i], readBits[i]);
482 
483         if (bits > 0)
484         {
485             threshold[i] = 3.0f / static_cast<float>(((1ul << bits) - 1ul));
486         }
487     }
488 
489     return threshold;
490 }
491 
getFloatULPThreshold(const tcu::TextureFormat & sourceFormat,const tcu::TextureFormat & readPixelsFormat)492 UVec4 getFloatULPThreshold(const tcu::TextureFormat &sourceFormat, const tcu::TextureFormat &readPixelsFormat)
493 {
494     const tcu::IVec4 srcMantissaBits  = tcu::getTextureFormatMantissaBitDepth(sourceFormat);
495     const tcu::IVec4 readMantissaBits = tcu::getTextureFormatMantissaBitDepth(readPixelsFormat);
496     tcu::IVec4 ULPDiff(0);
497 
498     for (int i = 0; i < 4; i++)
499         if (readMantissaBits[i] >= srcMantissaBits[i])
500             ULPDiff[i] = readMantissaBits[i] - srcMantissaBits[i];
501 
502     return UVec4(4) * (UVec4(1) << (ULPDiff.cast<uint32_t>()));
503 }
504 
verifyRenderbuffer(TestLog & log,tcu::ResultCollector & results,const tcu::TextureFormat & format,int renderbufferNdx,const tcu::TextureLevel & refRenderbuffer,const tcu::TextureLevel & result)505 void verifyRenderbuffer(TestLog &log, tcu::ResultCollector &results, const tcu::TextureFormat &format,
506                         int renderbufferNdx, const tcu::TextureLevel &refRenderbuffer, const tcu::TextureLevel &result)
507 {
508     switch (tcu::getTextureChannelClass(format.type))
509     {
510     case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
511     {
512         const string name     = "Renderbuffer" + de::toString(renderbufferNdx);
513         const string desc     = "Compare renderbuffer " + de::toString(renderbufferNdx);
514         const UVec4 threshold = getFloatULPThreshold(format, result.getFormat());
515 
516         if (!tcu::floatUlpThresholdCompare(log, name.c_str(), desc.c_str(), refRenderbuffer, result, threshold,
517                                            tcu::COMPARE_LOG_RESULT))
518             results.fail("Verification of renderbuffer " + de::toString(renderbufferNdx) + " failed.");
519 
520         break;
521     }
522 
523     case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
524     case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
525     {
526         const string name = "Renderbuffer" + de::toString(renderbufferNdx);
527         const string desc = "Compare renderbuffer " + de::toString(renderbufferNdx);
528         const UVec4 threshold(1, 1, 1, 1);
529 
530         if (!tcu::intThresholdCompare(log, name.c_str(), desc.c_str(), refRenderbuffer, result, threshold,
531                                       tcu::COMPARE_LOG_RESULT))
532             results.fail("Verification of renderbuffer " + de::toString(renderbufferNdx) + " failed.");
533 
534         break;
535     }
536 
537     case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
538     case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
539     {
540         const string name    = "Renderbuffer" + de::toString(renderbufferNdx);
541         const string desc    = "Compare renderbuffer " + de::toString(renderbufferNdx);
542         const Vec4 threshold = getFixedPointFormatThreshold(format, result.getFormat());
543 
544         if (!tcu::floatThresholdCompare(log, name.c_str(), desc.c_str(), refRenderbuffer, result, threshold,
545                                         tcu::COMPARE_LOG_RESULT))
546             results.fail("Verification of renderbuffer " + de::toString(renderbufferNdx) + " failed.");
547 
548         break;
549     }
550 
551     default:
552         DE_ASSERT(false);
553     }
554 }
555 
getReadPixelFormat(const TextureFormat & format)556 TextureFormat getReadPixelFormat(const TextureFormat &format)
557 {
558     switch (tcu::getTextureChannelClass(format.type))
559     {
560     case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
561         return TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32);
562 
563     case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
564         return TextureFormat(TextureFormat::RGBA, TextureFormat::SIGNED_INT32);
565 
566     case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
567     case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
568         return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8);
569 
570     case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
571         return TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT);
572 
573     default:
574         DE_ASSERT(false);
575         return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8);
576     }
577 }
578 
verifyRenderbuffers(TestLog & log,tcu::ResultCollector & results,glu::RenderContext & renderContext,const glu::RenderbufferVector & renderbuffers,const glu::Framebuffer & framebuffer,const vector<TextureLevel> & refRenderbuffers)579 void verifyRenderbuffers(TestLog &log, tcu::ResultCollector &results, glu::RenderContext &renderContext,
580                          const glu::RenderbufferVector &renderbuffers, const glu::Framebuffer &framebuffer,
581                          const vector<TextureLevel> &refRenderbuffers)
582 {
583     const glw::Functions &gl = renderContext.getFunctions();
584 
585     DE_ASSERT(renderbuffers.size() == refRenderbuffers.size());
586 
587     gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
588 
589     for (int renderbufferNdx = 0; renderbufferNdx < (int)renderbuffers.size(); renderbufferNdx++)
590     {
591         const TextureLevel &refRenderbuffer = refRenderbuffers[renderbufferNdx];
592         const int width                     = refRenderbuffer.getWidth();
593         const int height                    = refRenderbuffer.getHeight();
594         const TextureFormat format          = refRenderbuffer.getFormat();
595 
596         tcu::TextureLevel result(getReadPixelFormat(format), width, height);
597 
598         gl.readBuffer(GL_COLOR_ATTACHMENT0 + renderbufferNdx);
599         glu::readPixels(renderContext, 0, 0, result.getAccess());
600         GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels from renderbuffer failed.");
601 
602         verifyRenderbuffer(log, results, format, renderbufferNdx, refRenderbuffer, result);
603     }
604 
605     gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
606 }
607 
608 static const float s_quadCoords[] = {-0.5f, -0.5f, 0.5f,  -0.5f, 0.5f,  0.5f,
609 
610                                      0.5f,  0.5f,  -0.5f, 0.5f,  -0.5f, -0.5f};
611 
setBlendState(rr::FragmentOperationState & fragOps,const BlendState & state)612 void setBlendState(rr::FragmentOperationState &fragOps, const BlendState &state)
613 {
614     if (state.blendEq)
615     {
616         if (state.blendEq->is<BlendEq>())
617         {
618             if (isAdvancedBlendEq(state.blendEq->get<BlendEq>()))
619             {
620                 const rr::BlendEquationAdvanced equation = mapGLBlendEquationAdvanced(state.blendEq->get<BlendEq>());
621 
622                 fragOps.blendMode            = rr::BLENDMODE_ADVANCED;
623                 fragOps.blendEquationAdvaced = equation;
624             }
625             else
626             {
627                 const rr::BlendEquation equation = mapGLBlendEquation(state.blendEq->get<BlendEq>());
628 
629                 fragOps.blendMode              = rr::BLENDMODE_STANDARD;
630                 fragOps.blendRGBState.equation = equation;
631                 fragOps.blendAState.equation   = equation;
632             }
633         }
634         else
635         {
636             DE_ASSERT(state.blendEq->is<SeparateBlendEq>());
637 
638             fragOps.blendMode              = rr::BLENDMODE_STANDARD;
639             fragOps.blendRGBState.equation = mapGLBlendEquation(state.blendEq->get<SeparateBlendEq>().rgb);
640             fragOps.blendAState.equation   = mapGLBlendEquation(state.blendEq->get<SeparateBlendEq>().alpha);
641         }
642     }
643 
644     if (state.blendFunc)
645     {
646         if (state.blendFunc->is<BlendFunc>())
647         {
648             const rr::BlendFunc srcFunction = mapGLBlendFunc(state.blendFunc->get<BlendFunc>().src);
649             const rr::BlendFunc dstFunction = mapGLBlendFunc(state.blendFunc->get<BlendFunc>().dst);
650 
651             fragOps.blendRGBState.srcFunc = srcFunction;
652             fragOps.blendRGBState.dstFunc = dstFunction;
653 
654             fragOps.blendAState.srcFunc = srcFunction;
655             fragOps.blendAState.dstFunc = dstFunction;
656         }
657         else
658         {
659             DE_ASSERT(state.blendFunc->is<SeparateBlendFunc>());
660 
661             fragOps.blendRGBState.srcFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().rgb.src);
662             fragOps.blendRGBState.dstFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().rgb.dst);
663 
664             fragOps.blendAState.srcFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().alpha.src);
665             fragOps.blendAState.dstFunc = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().alpha.dst);
666         }
667     }
668 
669     if (state.colorMask)
670         fragOps.colorMask = *state.colorMask;
671 }
672 
createRenderState(const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const DrawBufferInfo & info,int subpixelBits)673 rr::RenderState createRenderState(const BlendState &preCommonBlendState, const BlendState &postCommonBlendState,
674                                   const DrawBufferInfo &info, int subpixelBits)
675 {
676     const IVec2 size = info.getSize();
677     rr::RenderState state(rr::ViewportState(rr::WindowRectangle(0, 0, size.x(), size.y())), subpixelBits);
678 
679     state.fragOps.blendMode = rr::BLENDMODE_STANDARD;
680 
681     setBlendState(state.fragOps, preCommonBlendState);
682     setBlendState(state.fragOps, info.getBlendState());
683     setBlendState(state.fragOps, postCommonBlendState);
684 
685     if (postCommonBlendState.enableBlend)
686         state.fragOps.blendMode = (*(postCommonBlendState.enableBlend) ? state.fragOps.blendMode : rr::BLENDMODE_NONE);
687     else if (info.getBlendState().enableBlend)
688         state.fragOps.blendMode = (*(info.getBlendState().enableBlend) ? state.fragOps.blendMode : rr::BLENDMODE_NONE);
689     else if (preCommonBlendState.enableBlend)
690         state.fragOps.blendMode = (*(preCommonBlendState.enableBlend) ? state.fragOps.blendMode : rr::BLENDMODE_NONE);
691     else
692         state.fragOps.blendMode = rr::BLENDMODE_NONE;
693 
694     if (tcu::getTextureChannelClass(info.getFormat().type) != tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT &&
695         tcu::getTextureChannelClass(info.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT &&
696         tcu::getTextureChannelClass(info.getFormat().type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
697         state.fragOps.blendMode = rr::BLENDMODE_NONE;
698 
699     return state;
700 }
701 
702 class VertexShader : public rr::VertexShader
703 {
704 public:
705     VertexShader(void);
706     virtual void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
707                                const int numPackets) const;
708 };
709 
VertexShader(void)710 VertexShader::VertexShader(void) : rr::VertexShader(1, 1)
711 {
712     m_inputs[0].type  = rr::GENERICVECTYPE_FLOAT;
713     m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
714 }
715 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const716 void VertexShader::shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets,
717                                  const int numPackets) const
718 {
719     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
720     {
721         rr::VertexPacket &packet = *packets[packetNdx];
722 
723         packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx);
724         packet.outputs[0] =
725             0.5f * (Vec4(1.0f) + rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx));
726     }
727 }
728 
729 class FragmentShader : public rr::FragmentShader
730 {
731 public:
732     FragmentShader(int drawBufferNdx, const DrawBufferInfo &info);
733     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
734                         const rr::FragmentShadingContext &context) const;
735 
736 private:
737     const int m_drawBufferNdx;
738     const DrawBufferInfo m_info;
739 };
740 
FragmentShader(int drawBufferNdx,const DrawBufferInfo & info)741 FragmentShader::FragmentShader(int drawBufferNdx, const DrawBufferInfo &info)
742     : rr::FragmentShader(1, 1)
743     , m_drawBufferNdx(drawBufferNdx)
744     , m_info(info)
745 {
746     m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
747 
748     switch (tcu::getTextureChannelClass(m_info.getFormat().type))
749     {
750     case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
751     case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
752     case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
753         m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
754         break;
755 
756     case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
757         m_outputs[0].type = rr::GENERICVECTYPE_UINT32;
758         break;
759 
760     case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
761         m_outputs[0].type = rr::GENERICVECTYPE_INT32;
762         break;
763 
764     default:
765         DE_ASSERT(false);
766     }
767 }
768 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const769 void FragmentShader::shadeFragments(rr::FragmentPacket *packets, const int numPackets,
770                                     const rr::FragmentShadingContext &context) const
771 {
772     for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
773     {
774         rr::FragmentPacket &packet = packets[packetNdx];
775 
776         DE_ASSERT(m_drawBufferNdx >= 0);
777         DE_UNREF(m_info);
778 
779         for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
780         {
781             const Vec2 vColor    = rr::readVarying<float>(packet, context, 0, fragNdx).xy();
782             const float values[] = {vColor.x(), vColor.y(), (1.0f - vColor.x()), (1.0f - vColor.y())};
783 
784             switch (tcu::getTextureChannelClass(m_info.getFormat().type))
785             {
786             case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
787             case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
788             case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
789             {
790                 const Vec4 color(values[(m_drawBufferNdx + 0) % 4], values[(m_drawBufferNdx + 1) % 4],
791                                  values[(m_drawBufferNdx + 2) % 4], values[(m_drawBufferNdx + 3) % 4]);
792 
793                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
794                 break;
795             }
796 
797             case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
798             {
799                 const UVec4 color(
800                     (uint32_t)(values[(m_drawBufferNdx + 0) % 4]), (uint32_t)(values[(m_drawBufferNdx + 1) % 4]),
801                     (uint32_t)(values[(m_drawBufferNdx + 2) % 4]), (uint32_t)(values[(m_drawBufferNdx + 3) % 4]));
802 
803                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
804                 break;
805             }
806 
807             case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
808             {
809                 const IVec4 color(
810                     (int32_t)(values[(m_drawBufferNdx + 0) % 4]), (int32_t)(values[(m_drawBufferNdx + 1) % 4]),
811                     (int32_t)(values[(m_drawBufferNdx + 2) % 4]), (int32_t)(values[(m_drawBufferNdx + 3) % 4]));
812 
813                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
814                 break;
815             }
816 
817             default:
818                 DE_ASSERT(false);
819             }
820         }
821     }
822 }
823 
createVertexAttrib(const float * coords)824 rr::VertexAttrib createVertexAttrib(const float *coords)
825 {
826     rr::VertexAttrib attrib;
827 
828     attrib.type    = rr::VERTEXATTRIBTYPE_FLOAT;
829     attrib.size    = 2;
830     attrib.pointer = coords;
831 
832     return attrib;
833 }
834 
renderRefQuad(const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,const int subpixelBits,vector<TextureLevel> & refRenderbuffers)835 void renderRefQuad(const BlendState &preCommonBlendState, const BlendState &postCommonBlendState,
836                    const vector<DrawBufferInfo> &drawBuffers, const int subpixelBits,
837                    vector<TextureLevel> &refRenderbuffers)
838 {
839     const rr::Renderer renderer;
840     const rr::PrimitiveList primitives(rr::PRIMITIVETYPE_TRIANGLES, 6, 0);
841     const rr::VertexAttrib vertexAttribs[] = {createVertexAttrib(s_quadCoords)};
842 
843     for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
844     {
845         if (drawBuffers[drawBufferNdx].getRender())
846         {
847             const rr::RenderState renderState(
848                 createRenderState(preCommonBlendState, postCommonBlendState, drawBuffers[drawBufferNdx], subpixelBits));
849             const rr::RenderTarget renderTarget(
850                 rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(refRenderbuffers[drawBufferNdx].getAccess()));
851             const VertexShader vertexShader;
852             const FragmentShader fragmentShader(drawBufferNdx, drawBuffers[drawBufferNdx]);
853             const rr::Program program(&vertexShader, &fragmentShader);
854             const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs),
855                                           vertexAttribs, primitives);
856 
857             renderer.draw(command);
858         }
859     }
860 }
861 
requiresAdvancedBlendEq(const BlendState & pre,const BlendState post,const vector<DrawBufferInfo> & drawBuffers)862 bool requiresAdvancedBlendEq(const BlendState &pre, const BlendState post, const vector<DrawBufferInfo> &drawBuffers)
863 {
864     bool requiresAdvancedBlendEq = false;
865 
866     if (pre.blendEq && pre.blendEq->is<BlendEq>())
867         requiresAdvancedBlendEq |= isAdvancedBlendEq(pre.blendEq->get<BlendEq>());
868 
869     if (post.blendEq && post.blendEq->is<BlendEq>())
870         requiresAdvancedBlendEq |= isAdvancedBlendEq(post.blendEq->get<BlendEq>());
871 
872     for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
873     {
874         const BlendState &drawBufferBlendState = drawBuffers[drawBufferNdx].getBlendState();
875 
876         if (drawBufferBlendState.blendEq && drawBufferBlendState.blendEq->is<BlendEq>())
877             requiresAdvancedBlendEq |= isAdvancedBlendEq(drawBufferBlendState.blendEq->get<BlendEq>());
878     }
879 
880     return requiresAdvancedBlendEq;
881 }
882 
genVertexSource(glu::RenderContext & renderContext)883 glu::VertexSource genVertexSource(glu::RenderContext &renderContext)
884 {
885     const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
886 
887     const char *const vertexSource = "${GLSL_VERSION_DECL}\n"
888                                      "layout(location=0) in highp vec2 i_coord;\n"
889                                      "out highp vec2 v_color;\n"
890                                      "void main (void)\n"
891                                      "{\n"
892                                      "\tv_color = 0.5 * (vec2(1.0) + i_coord);\n"
893                                      "\tgl_Position = vec4(i_coord, 0.0, 1.0);\n"
894                                      "}";
895 
896     map<string, string> args;
897     args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) :
898                                                getGLSLVersionDeclaration(glu::GLSL_VERSION_300_ES);
899 
900     return glu::VertexSource(tcu::StringTemplate(vertexSource).specialize(args));
901 }
902 
genFragmentSource(const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,glu::RenderContext & renderContext)903 glu::FragmentSource genFragmentSource(const BlendState &preCommonBlendState, const BlendState &postCommonBlendState,
904                                       const vector<DrawBufferInfo> &drawBuffers, glu::RenderContext &renderContext)
905 {
906     std::ostringstream stream;
907     const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
908 
909     stream << "${GLSL_VERSION_DECL}\n";
910 
911     if (requiresAdvancedBlendEq(preCommonBlendState, postCommonBlendState, drawBuffers))
912     {
913         stream << "${GLSL_EXTENSION}"
914                << "layout(blend_support_all_equations) out;\n";
915     }
916 
917     stream << "in highp vec2 v_color;\n";
918 
919     for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
920     {
921         const DrawBufferInfo &drawBuffer = drawBuffers[drawBufferNdx];
922         const TextureFormat &format      = drawBuffer.getFormat();
923 
924         stream << "layout(location=" << drawBufferNdx << ") out highp ";
925 
926         switch (tcu::getTextureChannelClass(format.type))
927         {
928         case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
929         case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
930         case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
931             stream << "vec4";
932             break;
933 
934         case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
935             stream << "uvec4";
936             break;
937 
938         case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
939             stream << "ivec4";
940             break;
941 
942         default:
943             DE_ASSERT(false);
944         }
945 
946         stream << " o_drawBuffer" << drawBufferNdx << ";\n";
947     }
948 
949     stream << "void main (void)\n"
950            << "{\n";
951 
952     for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
953     {
954         const DrawBufferInfo &drawBuffer = drawBuffers[drawBufferNdx];
955         const TextureFormat &format      = drawBuffer.getFormat();
956         const char *const values[]       = {"v_color.x", "v_color.y", "(1.0 - v_color.x)", "(1.0 - v_color.y)"};
957 
958         stream << "\to_drawBuffer" << drawBufferNdx;
959 
960         switch (tcu::getTextureChannelClass(format.type))
961         {
962         case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
963         case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
964         case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
965             stream << " = vec4(" << values[(drawBufferNdx + 0) % 4] << ", " << values[(drawBufferNdx + 1) % 4] << ", "
966                    << values[(drawBufferNdx + 2) % 4] << ", " << values[(drawBufferNdx + 3) % 4] << ");\n";
967             break;
968 
969         case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
970             stream << " = uvec4(uint(" << values[(drawBufferNdx + 0) % 4] << "), uint("
971                    << values[(drawBufferNdx + 1) % 4] << "), uint(" << values[(drawBufferNdx + 2) % 4] << "), uint("
972                    << values[(drawBufferNdx + 3) % 4] << "));\n";
973             break;
974 
975         case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
976             stream << " = ivec4(int(" << values[(drawBufferNdx + 0) % 4] << "), int(" << values[(drawBufferNdx + 1) % 4]
977                    << "), int(" << values[(drawBufferNdx + 2) % 4] << "), int(" << values[(drawBufferNdx + 3) % 4]
978                    << "));\n";
979             break;
980 
981         default:
982             DE_ASSERT(false);
983         }
984     }
985 
986     stream << "}";
987 
988     map<string, string> args;
989     args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) :
990                                                getGLSLVersionDeclaration(glu::GLSL_VERSION_300_ES);
991     args["GLSL_EXTENSION"]    = supportsES32 ? "\n" : "#extension GL_KHR_blend_equation_advanced : require\n";
992 
993     return glu::FragmentSource(tcu::StringTemplate(stream.str()).specialize(args));
994 }
995 
genShaderSources(const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,glu::RenderContext & renderContext)996 glu::ProgramSources genShaderSources(const BlendState &preCommonBlendState, const BlendState &postCommonBlendState,
997                                      const vector<DrawBufferInfo> &drawBuffers, glu::RenderContext &renderContext)
998 {
999     return glu::ProgramSources() << genVertexSource(renderContext)
1000                                  << genFragmentSource(preCommonBlendState, postCommonBlendState, drawBuffers,
1001                                                       renderContext);
1002 }
1003 
renderGLQuad(glu::RenderContext & renderContext,const glu::ShaderProgram & program)1004 void renderGLQuad(glu::RenderContext &renderContext, const glu::ShaderProgram &program)
1005 {
1006     const glu::VertexArrayBinding vertexArrays[] = {glu::VertexArrayBinding(
1007         glu::BindingPoint(0),
1008         glu::VertexArrayPointer(glu::VTX_COMP_FLOAT, glu::VTX_COMP_CONVERT_NONE, 2, 6, 0, s_quadCoords))};
1009 
1010     glu::draw(renderContext, program.getProgram(), 1, vertexArrays, glu::pr::Triangles(6));
1011 }
1012 
renderQuad(TestLog & log,glu::RenderContext & renderContext,const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,const glu::Framebuffer & framebuffer,vector<TextureLevel> & refRenderbuffers)1013 void renderQuad(TestLog &log, glu::RenderContext &renderContext, const BlendState &preCommonBlendState,
1014                 const BlendState &postCommonBlendState, const vector<DrawBufferInfo> &drawBuffers,
1015                 const glu::Framebuffer &framebuffer, vector<TextureLevel> &refRenderbuffers)
1016 {
1017     const glw::Functions &gl = renderContext.getFunctions();
1018     const glu::ShaderProgram program(
1019         gl, genShaderSources(preCommonBlendState, postCommonBlendState, drawBuffers, renderContext));
1020     const IVec2 size                 = drawBuffers[0].getSize();
1021     const bool requiresBlendBarriers = requiresAdvancedBlendEq(preCommonBlendState, postCommonBlendState, drawBuffers);
1022 
1023     vector<uint32_t> bufs;
1024 
1025     bufs.resize(drawBuffers.size());
1026 
1027     for (int bufNdx = 0; bufNdx < (int)bufs.size(); bufNdx++)
1028         bufs[bufNdx] = (drawBuffers[bufNdx].getRender() ? GL_COLOR_ATTACHMENT0 + bufNdx : GL_NONE);
1029 
1030     log << program;
1031 
1032     gl.viewport(0, 0, size.x(), size.y());
1033     gl.useProgram(program.getProgram());
1034     gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
1035 
1036     setCommonBlendState(gl, preCommonBlendState);
1037 
1038     for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++)
1039         setIndexedBlendState(gl, drawBuffers[renderbufferNdx].getBlendState(), renderbufferNdx);
1040 
1041     setCommonBlendState(gl, postCommonBlendState);
1042 
1043     gl.drawBuffers((glw::GLsizei)bufs.size(), &(bufs[0]));
1044 
1045     if (requiresBlendBarriers)
1046         gl.blendBarrier();
1047 
1048     renderGLQuad(renderContext, program);
1049 
1050     if (requiresBlendBarriers)
1051         gl.blendBarrier();
1052 
1053     gl.drawBuffers(0, 0);
1054     gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1055     gl.useProgram(0);
1056 
1057     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render");
1058 
1059     int subpixelBits = 0;
1060     gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits);
1061 
1062     renderRefQuad(preCommonBlendState, postCommonBlendState, drawBuffers, subpixelBits, refRenderbuffers);
1063 }
1064 
logBlendState(TestLog & log,const BlendState & blend)1065 void logBlendState(TestLog &log, const BlendState &blend)
1066 {
1067     if (blend.enableBlend)
1068     {
1069         if (*blend.enableBlend)
1070             log << TestLog::Message << "Enable blending." << TestLog::EndMessage;
1071         else
1072             log << TestLog::Message << "Disable blending." << TestLog::EndMessage;
1073     }
1074 
1075     if (blend.colorMask)
1076     {
1077         const BVec4 mask = *blend.colorMask;
1078 
1079         log << TestLog::Message << "Set color mask: " << mask << "." << TestLog::EndMessage;
1080     }
1081 
1082     if (blend.blendEq)
1083     {
1084         const Either<BlendEq, SeparateBlendEq> &blendEq = *blend.blendEq;
1085 
1086         if (blendEq.is<BlendEq>())
1087             log << TestLog::Message << "Set blend equation: " << glu::getBlendEquationStr(blendEq.get<BlendEq>()) << "."
1088                 << TestLog::EndMessage;
1089         else if (blendEq.is<SeparateBlendEq>())
1090             log << TestLog::Message
1091                 << "Set blend equation rgb: " << glu::getBlendEquationStr(blendEq.get<SeparateBlendEq>().rgb)
1092                 << ", alpha: " << glu::getBlendEquationStr(blendEq.get<SeparateBlendEq>().alpha) << "."
1093                 << TestLog::EndMessage;
1094         else
1095             DE_ASSERT(false);
1096     }
1097 
1098     if (blend.blendFunc)
1099     {
1100         const Either<BlendFunc, SeparateBlendFunc> &blendFunc = *blend.blendFunc;
1101 
1102         if (blendFunc.is<BlendFunc>())
1103             log << TestLog::Message
1104                 << "Set blend function source: " << glu::getBlendFactorStr(blendFunc.get<BlendFunc>().src)
1105                 << ", destination: " << glu::getBlendFactorStr(blendFunc.get<BlendFunc>().dst) << "."
1106                 << TestLog::EndMessage;
1107         else if (blendFunc.is<SeparateBlendFunc>())
1108         {
1109             log << TestLog::Message << "Set blend function rgb source: "
1110                 << glu::getBlendFactorStr(blendFunc.get<SeparateBlendFunc>().rgb.src)
1111                 << ", destination: " << glu::getBlendFactorStr(blendFunc.get<SeparateBlendFunc>().rgb.dst) << "."
1112                 << TestLog::EndMessage;
1113             log << TestLog::Message << "Set blend function alpha source: "
1114                 << glu::getBlendFactorStr(blendFunc.get<SeparateBlendFunc>().alpha.src)
1115                 << ", destination: " << glu::getBlendFactorStr(blendFunc.get<SeparateBlendFunc>().alpha.dst) << "."
1116                 << TestLog::EndMessage;
1117         }
1118         else
1119             DE_ASSERT(false);
1120     }
1121 }
1122 
logTestCaseInfo(TestLog & log,const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers)1123 void logTestCaseInfo(TestLog &log, const BlendState &preCommonBlendState, const BlendState &postCommonBlendState,
1124                      const vector<DrawBufferInfo> &drawBuffers)
1125 {
1126     {
1127         tcu::ScopedLogSection drawBuffersSection(log, "DrawBuffers", "Draw buffers");
1128 
1129         for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
1130         {
1131             const tcu::ScopedLogSection drawBufferSection(log, "DrawBuffer" + de::toString(drawBufferNdx),
1132                                                           "Draw Buffer " + de::toString(drawBufferNdx));
1133             const DrawBufferInfo &drawBuffer = drawBuffers[drawBufferNdx];
1134 
1135             log << TestLog::Message << "Format: " << drawBuffer.getFormat() << TestLog::EndMessage;
1136             log << TestLog::Message << "Size: " << drawBuffer.getSize() << TestLog::EndMessage;
1137             log << TestLog::Message << "Render: " << (drawBuffer.getRender() ? "true" : "false") << TestLog::EndMessage;
1138         }
1139     }
1140 
1141     if (!preCommonBlendState.isEmpty())
1142     {
1143         tcu::ScopedLogSection s(log, "PreCommonState", "First set common blend state");
1144         logBlendState(log, preCommonBlendState);
1145     }
1146 
1147     for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
1148     {
1149         if (!drawBuffers[drawBufferNdx].getBlendState().isEmpty())
1150         {
1151             const tcu::ScopedLogSection s(log, "DrawBufferState" + de::toString(drawBufferNdx),
1152                                           "Set DrawBuffer " + de::toString(drawBufferNdx) + " state to");
1153 
1154             logBlendState(log, drawBuffers[drawBufferNdx].getBlendState());
1155         }
1156     }
1157 
1158     if (!postCommonBlendState.isEmpty())
1159     {
1160         tcu::ScopedLogSection s(log, "PostCommonState", "After set common blend state");
1161         logBlendState(log, postCommonBlendState);
1162     }
1163 }
1164 
runTest(TestLog & log,tcu::ResultCollector & results,glu::RenderContext & renderContext,const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers)1165 void runTest(TestLog &log, tcu::ResultCollector &results, glu::RenderContext &renderContext,
1166 
1167              const BlendState &preCommonBlendState, const BlendState &postCommonBlendState,
1168              const vector<DrawBufferInfo> &drawBuffers)
1169 {
1170     const glw::Functions &gl = renderContext.getFunctions();
1171     glu::RenderbufferVector renderbuffers(gl, drawBuffers.size());
1172     glu::Framebuffer framebuffer(gl);
1173     vector<TextureLevel> refRenderbuffers(drawBuffers.size());
1174 
1175     logTestCaseInfo(log, preCommonBlendState, postCommonBlendState, drawBuffers);
1176 
1177     genRenderbuffers(gl, drawBuffers, framebuffer, renderbuffers, refRenderbuffers);
1178 
1179     renderQuad(log, renderContext, preCommonBlendState, postCommonBlendState, drawBuffers, framebuffer,
1180                refRenderbuffers);
1181 
1182     verifyRenderbuffers(log, results, renderContext, renderbuffers, framebuffer, refRenderbuffers);
1183 }
1184 
1185 class DrawBuffersIndexedTest : public TestCase
1186 {
1187 public:
1188     DrawBuffersIndexedTest(Context &context, const BlendState &preCommonBlendState,
1189                            const BlendState &postCommonBlendState, const vector<DrawBufferInfo> &drawBuffers,
1190                            const string &name, const string &description);
1191 
1192     void init(void);
1193     IterateResult iterate(void);
1194 
1195 private:
1196     const BlendState m_preCommonBlendState;
1197     const BlendState m_postCommonBlendState;
1198     const vector<DrawBufferInfo> m_drawBuffers;
1199 };
1200 
DrawBuffersIndexedTest(Context & context,const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,const string & name,const string & description)1201 DrawBuffersIndexedTest::DrawBuffersIndexedTest(Context &context, const BlendState &preCommonBlendState,
1202                                                const BlendState &postCommonBlendState,
1203                                                const vector<DrawBufferInfo> &drawBuffers, const string &name,
1204                                                const string &description)
1205     : TestCase(context, name.c_str(), description.c_str())
1206     , m_preCommonBlendState(preCommonBlendState)
1207     , m_postCommonBlendState(postCommonBlendState)
1208     , m_drawBuffers(drawBuffers)
1209 {
1210 }
1211 
init(void)1212 void DrawBuffersIndexedTest::init(void)
1213 {
1214     const bool supportsES32orGL45 = checkES32orGL45Support(m_context);
1215 
1216     if (!supportsES32orGL45)
1217     {
1218         if (requiresAdvancedBlendEq(m_preCommonBlendState, m_postCommonBlendState, m_drawBuffers) &&
1219             !m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"))
1220             TCU_THROW(NotSupportedError, "Extension GL_KHR_blend_equation_advanced not supported");
1221 
1222         if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1223             TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1224     }
1225 }
1226 
iterate(void)1227 TestCase::IterateResult DrawBuffersIndexedTest::iterate(void)
1228 {
1229     TestLog &log = m_testCtx.getLog();
1230     tcu::ResultCollector results(log);
1231 
1232     runTest(log, results, m_context.getRenderContext(), m_preCommonBlendState, m_postCommonBlendState, m_drawBuffers);
1233 
1234     results.setTestContextResult(m_testCtx);
1235 
1236     return STOP;
1237 }
1238 
getRandomBlendEq(de::Random & rng)1239 BlendEq getRandomBlendEq(de::Random &rng)
1240 {
1241     const BlendEq eqs[] = {GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, GL_MIN, GL_MAX};
1242 
1243     return de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(eqs)>(eqs, rng.getUint32() % DE_LENGTH_OF_ARRAY(eqs));
1244 }
1245 
getRandomBlendFunc(de::Random & rng)1246 BlendFunc getRandomBlendFunc(de::Random &rng)
1247 {
1248     const uint32_t funcs[] = {GL_ZERO,
1249                               GL_ONE,
1250                               GL_SRC_COLOR,
1251                               GL_ONE_MINUS_SRC_COLOR,
1252                               GL_DST_COLOR,
1253                               GL_ONE_MINUS_DST_COLOR,
1254                               GL_SRC_ALPHA,
1255                               GL_ONE_MINUS_SRC_ALPHA,
1256                               GL_DST_ALPHA,
1257                               GL_ONE_MINUS_DST_ALPHA,
1258                               GL_CONSTANT_COLOR,
1259                               GL_ONE_MINUS_CONSTANT_COLOR,
1260                               GL_CONSTANT_ALPHA,
1261                               GL_ONE_MINUS_CONSTANT_ALPHA,
1262                               GL_SRC_ALPHA_SATURATE};
1263 
1264     const uint32_t src =
1265         de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(funcs)>(funcs, rng.getUint32() % DE_LENGTH_OF_ARRAY(funcs));
1266     const uint32_t dst =
1267         de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(funcs)>(funcs, rng.getUint32() % DE_LENGTH_OF_ARRAY(funcs));
1268 
1269     return BlendFunc(src, dst);
1270 }
1271 
genRandomBlendState(de::Random & rng,BlendState & blendState)1272 void genRandomBlendState(de::Random &rng, BlendState &blendState)
1273 {
1274     if (rng.getBool())
1275         blendState.enableBlend = rng.getBool();
1276 
1277     if (rng.getBool())
1278     {
1279         if (rng.getBool())
1280             blendState.blendEq = getRandomBlendEq(rng);
1281         else
1282         {
1283             const BlendEq rgb   = getRandomBlendEq(rng);
1284             const BlendEq alpha = getRandomBlendEq(rng);
1285 
1286             blendState.blendEq = SeparateBlendEq(rgb, alpha);
1287         }
1288     }
1289 
1290     if (rng.getBool())
1291     {
1292         if (rng.getBool())
1293             blendState.blendFunc = getRandomBlendFunc(rng);
1294         else
1295         {
1296             const BlendFunc rgb   = getRandomBlendFunc(rng);
1297             const BlendFunc alpha = getRandomBlendFunc(rng);
1298 
1299             blendState.blendFunc = SeparateBlendFunc(rgb, alpha);
1300         }
1301     }
1302 
1303     if (rng.getBool())
1304     {
1305         const bool red   = rng.getBool();
1306         const bool green = rng.getBool();
1307         const bool blue  = rng.getBool();
1308         const bool alpha = rng.getBool();
1309 
1310         blendState.colorMask = BVec4(red, blue, green, alpha);
1311     }
1312 }
1313 
getRandomFormat(de::Random & rng,Context & context)1314 TextureFormat getRandomFormat(de::Random &rng, Context &context)
1315 {
1316     const bool supportsES32orGL45 = checkES32orGL45Support(context);
1317 
1318     const uint32_t glFormats[] = {
1319         GL_R8,         GL_RG8,     GL_RGB8,     GL_RGB565,  GL_RGBA4,  GL_RGB5_A1, GL_RGBA8,   GL_RGB10_A2,
1320         GL_RGB10_A2UI, GL_R8I,     GL_R8UI,     GL_R16I,    GL_R16UI,  GL_R32I,    GL_R32UI,   GL_RG8I,
1321         GL_RG8UI,      GL_RG16I,   GL_RG16UI,   GL_RG32I,   GL_RG32UI, GL_RGBA8I,  GL_RGBA8UI, GL_RGBA16I,
1322         GL_RGBA16UI,   GL_RGBA32I, GL_RGBA32UI, GL_RGBA16F, GL_R32F,   GL_RG32F,   GL_RGBA32F, GL_R11F_G11F_B10F};
1323 
1324     if (supportsES32orGL45)
1325         return glu::mapGLInternalFormat(
1326             de::getArrayElement(glFormats, rng.getUint32() % DE_LENGTH_OF_ARRAY(glFormats)));
1327     else
1328     {
1329         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(glFormats) == 32);
1330         return glu::mapGLInternalFormat(
1331             de::getArrayElement(glFormats, rng.getUint32() % (DE_LENGTH_OF_ARRAY(glFormats) - 5)));
1332     }
1333 }
1334 
genRandomTest(de::Random & rng,BlendState & preCommon,BlendState & postCommon,vector<DrawBufferInfo> & drawBuffers,int maxDrawBufferCount,Context & context)1335 void genRandomTest(de::Random &rng, BlendState &preCommon, BlendState &postCommon, vector<DrawBufferInfo> &drawBuffers,
1336                    int maxDrawBufferCount, Context &context)
1337 {
1338     genRandomBlendState(rng, preCommon);
1339     genRandomBlendState(rng, postCommon);
1340 
1341     for (int drawBufferNdx = 0; drawBufferNdx < maxDrawBufferCount; drawBufferNdx++)
1342     {
1343         const bool render = rng.getFloat() > 0.1f;
1344         const IVec2 size(64, 64);
1345         const TextureFormat format(getRandomFormat(rng, context));
1346         BlendState blendState;
1347 
1348         genRandomBlendState(rng, blendState);
1349 
1350         // 32bit float formats don't support blending in GLES32
1351         if (format.type == tcu::TextureFormat::FLOAT)
1352         {
1353             // If format is 32bit float post common can't enable blending
1354             if (postCommon.enableBlend && *postCommon.enableBlend)
1355             {
1356                 // Either don't set enable blend or disable blending
1357                 if (rng.getBool())
1358                     postCommon.enableBlend = tcu::Nothing;
1359                 else
1360                     postCommon.enableBlend = tcu::just(false);
1361             }
1362 
1363             // If post common doesn't disable blending, per attachment state or
1364             // pre common must.
1365             if (!postCommon.enableBlend)
1366             {
1367                 // If pre common enables blend per attachment must disable it
1368                 // If per attachment state changes blend state it must disable it
1369                 if ((preCommon.enableBlend && *preCommon.enableBlend) || blendState.enableBlend)
1370                     blendState.enableBlend = tcu::just(false);
1371             }
1372         }
1373 
1374         drawBuffers.push_back(DrawBufferInfo(render, size, blendState, format));
1375     }
1376 }
1377 
1378 class MaxDrawBuffersIndexedTest : public TestCase
1379 {
1380 public:
1381     MaxDrawBuffersIndexedTest(Context &contet, int seed);
1382 
1383     void init(void);
1384     IterateResult iterate(void);
1385 
1386 private:
1387     const int m_seed;
1388 };
1389 
MaxDrawBuffersIndexedTest(Context & context,int seed)1390 MaxDrawBuffersIndexedTest::MaxDrawBuffersIndexedTest(Context &context, int seed)
1391     : TestCase(context, de::toString(seed).c_str(), de::toString(seed).c_str())
1392     , m_seed(deInt32Hash(seed) ^ 1558001307u)
1393 {
1394 }
1395 
init(void)1396 void MaxDrawBuffersIndexedTest::init(void)
1397 {
1398     const bool supportsES32orGL45 = checkES32orGL45Support(m_context);
1399 
1400     if (!supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1401         TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1402 }
1403 
iterate(void)1404 TestCase::IterateResult MaxDrawBuffersIndexedTest::iterate(void)
1405 {
1406     TestLog &log = m_testCtx.getLog();
1407     tcu::ResultCollector results(log);
1408     de::Random rng(m_seed);
1409     BlendState preCommonBlendState;
1410     BlendState postCommonBlendState;
1411     vector<DrawBufferInfo> drawBuffers;
1412 
1413     genRandomTest(rng, preCommonBlendState, postCommonBlendState, drawBuffers, 4, m_context);
1414 
1415     runTest(log, results, m_context.getRenderContext(), preCommonBlendState, postCommonBlendState, drawBuffers);
1416 
1417     results.setTestContextResult(m_testCtx);
1418 
1419     return STOP;
1420 }
1421 
1422 class ImplMaxDrawBuffersIndexedTest : public TestCase
1423 {
1424 public:
1425     ImplMaxDrawBuffersIndexedTest(Context &contet, int seed);
1426 
1427     void init(void);
1428     IterateResult iterate(void);
1429 
1430 private:
1431     const int m_seed;
1432 };
1433 
ImplMaxDrawBuffersIndexedTest(Context & context,int seed)1434 ImplMaxDrawBuffersIndexedTest::ImplMaxDrawBuffersIndexedTest(Context &context, int seed)
1435     : TestCase(context, de::toString(seed).c_str(), de::toString(seed).c_str())
1436     , m_seed(deInt32Hash(seed) ^ 2686315738u)
1437 {
1438 }
1439 
init(void)1440 void ImplMaxDrawBuffersIndexedTest::init(void)
1441 {
1442     const bool supportsES32orGL45 = checkES32orGL45Support(m_context);
1443 
1444     if (!supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1445         TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1446 }
1447 
iterate(void)1448 TestCase::IterateResult ImplMaxDrawBuffersIndexedTest::iterate(void)
1449 {
1450     TestLog &log = m_testCtx.getLog();
1451     tcu::ResultCollector results(log);
1452     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
1453     de::Random rng(m_seed);
1454     int32_t maxDrawBuffers = 0;
1455     BlendState preCommonBlendState;
1456     BlendState postCommonBlendState;
1457     vector<DrawBufferInfo> drawBuffers;
1458 
1459     gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
1460     GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_DRAW_BUFFERS) failed");
1461 
1462     TCU_CHECK(maxDrawBuffers > 0);
1463 
1464     genRandomTest(rng, preCommonBlendState, postCommonBlendState, drawBuffers, maxDrawBuffers, m_context);
1465 
1466     runTest(log, results, m_context.getRenderContext(), preCommonBlendState, postCommonBlendState, drawBuffers);
1467 
1468     results.setTestContextResult(m_testCtx);
1469 
1470     return STOP;
1471 }
1472 
1473 enum PrePost
1474 {
1475     PRE,
1476     POST
1477 };
1478 
createDiffTest(Context & context,PrePost prepost,const char * name,const BlendState & commonState,const BlendState & drawBufferState)1479 TestCase *createDiffTest(Context &context, PrePost prepost, const char *name, const BlendState &commonState,
1480                          const BlendState &drawBufferState)
1481 {
1482     const BlendState emptyState = BlendState(tcu::Nothing, tcu::Nothing, tcu::Nothing, tcu::Nothing);
1483 
1484     if (prepost == PRE)
1485     {
1486         const BlendState preState =
1487             BlendState((commonState.enableBlend ? commonState.enableBlend : just(true)), commonState.blendEq,
1488                        (commonState.blendFunc ? commonState.blendFunc :
1489                                                 just(Either<BlendFunc, SeparateBlendFunc>(BlendFunc(GL_ONE, GL_ONE)))),
1490                        tcu::Nothing);
1491         vector<DrawBufferInfo> drawBuffers;
1492 
1493         drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), emptyState,
1494                                              TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1495         drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState,
1496                                              TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1497 
1498         return new DrawBuffersIndexedTest(context, preState, emptyState, drawBuffers, name, name);
1499     }
1500     else if (prepost == POST)
1501     {
1502         const BlendState preState =
1503             BlendState(just(true), tcu::Nothing, Maybe<Either<BlendFunc, SeparateBlendFunc>>(BlendFunc(GL_ONE, GL_ONE)),
1504                        tcu::Nothing);
1505         vector<DrawBufferInfo> drawBuffers;
1506 
1507         drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), emptyState,
1508                                              TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1509         drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState,
1510                                              TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1511 
1512         return new DrawBuffersIndexedTest(context, preState, commonState, drawBuffers, name, name);
1513     }
1514     else
1515     {
1516         DE_ASSERT(false);
1517         return DE_NULL;
1518     }
1519 }
1520 
createAdvancedEqDiffTest(Context & context,PrePost prepost,const char * name,const BlendState & commonState,const BlendState & drawBufferState)1521 TestCase *createAdvancedEqDiffTest(Context &context, PrePost prepost, const char *name, const BlendState &commonState,
1522                                    const BlendState &drawBufferState)
1523 {
1524     const BlendState emptyState = BlendState(tcu::Nothing, tcu::Nothing, tcu::Nothing, tcu::Nothing);
1525 
1526     if (prepost == PRE)
1527     {
1528         const BlendState preState =
1529             BlendState((commonState.enableBlend ? commonState.enableBlend : just(true)), commonState.blendEq,
1530                        (commonState.blendFunc ? commonState.blendFunc :
1531                                                 just(Either<BlendFunc, SeparateBlendFunc>(BlendFunc(GL_ONE, GL_ONE)))),
1532                        tcu::Nothing);
1533         vector<DrawBufferInfo> drawBuffers;
1534 
1535         drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState,
1536                                              TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1537 
1538         return new DrawBuffersIndexedTest(context, preState, emptyState, drawBuffers, name, name);
1539     }
1540     else if (prepost == POST)
1541     {
1542         const BlendState preState =
1543             BlendState(just(true), tcu::Nothing, Maybe<Either<BlendFunc, SeparateBlendFunc>>(BlendFunc(GL_ONE, GL_ONE)),
1544                        tcu::Nothing);
1545         vector<DrawBufferInfo> drawBuffers;
1546 
1547         drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState,
1548                                              TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1549 
1550         return new DrawBuffersIndexedTest(context, preState, commonState, drawBuffers, name, name);
1551     }
1552     else
1553     {
1554         DE_ASSERT(false);
1555         return DE_NULL;
1556     }
1557 }
1558 
addDrawBufferCommonTests(TestCaseGroup * root,PrePost prepost)1559 void addDrawBufferCommonTests(TestCaseGroup *root, PrePost prepost)
1560 {
1561     const BlendState emptyState = BlendState(Maybe<bool>(), Maybe<Either<BlendEq, SeparateBlendEq>>(),
1562                                              Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1563 
1564     {
1565         const BlendState disableState = BlendState(just(false), Maybe<Either<BlendEq, SeparateBlendEq>>(),
1566                                                    Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1567         const BlendState enableState  = BlendState(just(true), Maybe<Either<BlendEq, SeparateBlendEq>>(),
1568                                                    Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1569 
1570         root->addChild(
1571             createDiffTest(root->getContext(), prepost, "common_enable_buffer_enable", enableState, enableState));
1572         root->addChild(
1573             createDiffTest(root->getContext(), prepost, "common_disable_buffer_disable", disableState, disableState));
1574         root->addChild(
1575             createDiffTest(root->getContext(), prepost, "common_disable_buffer_enable", disableState, enableState));
1576         root->addChild(
1577             createDiffTest(root->getContext(), prepost, "common_enable_buffer_disable", enableState, disableState));
1578     }
1579 
1580     {
1581         const BlendState eqStateA = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(GL_FUNC_ADD),
1582                                                Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1583         const BlendState eqStateB = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(GL_FUNC_SUBTRACT),
1584                                                Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1585 
1586         const BlendState separateEqStateA = BlendState(
1587             tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(SeparateBlendEq(GL_FUNC_ADD, GL_FUNC_SUBTRACT)),
1588             Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1589         const BlendState separateEqStateB = BlendState(
1590             tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(SeparateBlendEq(GL_FUNC_SUBTRACT, GL_FUNC_ADD)),
1591             Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1592 
1593         const BlendState advancedEqStateA =
1594             BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(GL_DIFFERENCE),
1595                        Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1596         const BlendState advancedEqStateB = BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(GL_SCREEN),
1597                                                        Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1598 
1599         root->addChild(
1600             createDiffTest(root->getContext(), prepost, "common_blend_eq_buffer_blend_eq", eqStateA, eqStateB));
1601         root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_eq_buffer_separate_blend_eq", eqStateA,
1602                                       separateEqStateB));
1603         root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_blend_eq_buffer_advanced_blend_eq",
1604                                                 eqStateA, advancedEqStateB));
1605 
1606         root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_eq_buffer_blend_eq",
1607                                       separateEqStateA, eqStateB));
1608         root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_eq_buffer_separate_blend_eq",
1609                                       separateEqStateA, separateEqStateB));
1610         root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost,
1611                                                 "common_separate_blend_eq_buffer_advanced_blend_eq", separateEqStateA,
1612                                                 advancedEqStateB));
1613 
1614         root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost, "common_advanced_blend_eq_buffer_blend_eq",
1615                                                 advancedEqStateA, eqStateB));
1616         root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost,
1617                                                 "common_advanced_blend_eq_buffer_separate_blend_eq", advancedEqStateA,
1618                                                 separateEqStateB));
1619         root->addChild(createAdvancedEqDiffTest(root->getContext(), prepost,
1620                                                 "common_advanced_blend_eq_buffer_advanced_blend_eq", advancedEqStateA,
1621                                                 advancedEqStateB));
1622     }
1623 
1624     {
1625         const BlendState funcStateA = BlendState(
1626             tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(),
1627             Maybe<Either<BlendFunc, SeparateBlendFunc>>(BlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA)), Maybe<BVec4>());
1628         const BlendState funcStateB = BlendState(
1629             tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(),
1630             Maybe<Either<BlendFunc, SeparateBlendFunc>>(BlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA)), Maybe<BVec4>());
1631         const BlendState separateFuncStateA = BlendState(
1632             tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(),
1633             Maybe<Either<BlendFunc, SeparateBlendFunc>>(SeparateBlendFunc(
1634                 BlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA), BlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA))),
1635             Maybe<BVec4>());
1636         const BlendState separateFuncStateB = BlendState(
1637             tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(),
1638             Maybe<Either<BlendFunc, SeparateBlendFunc>>(SeparateBlendFunc(
1639                 BlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA), BlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA))),
1640             Maybe<BVec4>());
1641 
1642         root->addChild(
1643             createDiffTest(root->getContext(), prepost, "common_blend_func_buffer_blend_func", funcStateA, funcStateB));
1644         root->addChild(createDiffTest(root->getContext(), prepost, "common_blend_func_buffer_separate_blend_func",
1645                                       funcStateA, separateFuncStateB));
1646         root->addChild(createDiffTest(root->getContext(), prepost, "common_separate_blend_func_buffer_blend_func",
1647                                       separateFuncStateA, funcStateB));
1648         root->addChild(createDiffTest(root->getContext(), prepost,
1649                                       "common_separate_blend_func_buffer_separate_blend_func", separateFuncStateA,
1650                                       separateFuncStateB));
1651     }
1652 
1653     {
1654         const BlendState commonColorMaskState =
1655             BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(),
1656                        Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>(BVec4(true, false, true, false)));
1657         const BlendState bufferColorMaskState =
1658             BlendState(tcu::Nothing, Maybe<Either<BlendEq, SeparateBlendEq>>(),
1659                        Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>(BVec4(false, true, false, true)));
1660 
1661         root->addChild(createDiffTest(root->getContext(), prepost, "common_color_mask_buffer_color_mask",
1662                                       commonColorMaskState, bufferColorMaskState));
1663     }
1664 }
1665 
addRandomMaxTest(TestCaseGroup * root)1666 void addRandomMaxTest(TestCaseGroup *root)
1667 {
1668     for (int i = 0; i < 20; i++)
1669         root->addChild(new MaxDrawBuffersIndexedTest(root->getContext(), i));
1670 }
1671 
addRandomImplMaxTest(TestCaseGroup * root)1672 void addRandomImplMaxTest(TestCaseGroup *root)
1673 {
1674     for (int i = 0; i < 20; i++)
1675         root->addChild(new ImplMaxDrawBuffersIndexedTest(root->getContext(), i));
1676 }
1677 
1678 } // namespace
1679 
createDrawBuffersIndexedTests(Context & context)1680 TestCaseGroup *createDrawBuffersIndexedTests(Context &context)
1681 {
1682     const BlendState emptyState = BlendState(Maybe<bool>(), Maybe<Either<BlendEq, SeparateBlendEq>>(),
1683                                              Maybe<Either<BlendFunc, SeparateBlendFunc>>(), Maybe<BVec4>());
1684     TestCaseGroup *const group  = new TestCaseGroup(context, "draw_buffers_indexed",
1685                                                     "Test for indexed draw buffers. GL_EXT_draw_buffers_indexed.");
1686 
1687     TestCaseGroup *const preGroup = new TestCaseGroup(
1688         context, "overwrite_common", "Set common state and overwrite it with draw buffer blend state.");
1689     TestCaseGroup *const postGroup =
1690         new TestCaseGroup(context, "overwrite_indexed", "Set indexed blend state and overwrite it with common state.");
1691     TestCaseGroup *const randomGroup = new TestCaseGroup(context, "random", "Random indexed blend state tests.");
1692     TestCaseGroup *const maxGroup    = new TestCaseGroup(context, "max_required_draw_buffers",
1693                                                          "Random tests using minimum maximum number of draw buffers.");
1694     TestCaseGroup *const maxImplGroup =
1695         new TestCaseGroup(context, "max_implementation_draw_buffers",
1696                           "Random tests using maximum number of draw buffers reported by implementation.");
1697 
1698     group->addChild(preGroup);
1699     group->addChild(postGroup);
1700     group->addChild(randomGroup);
1701 
1702     randomGroup->addChild(maxGroup);
1703     randomGroup->addChild(maxImplGroup);
1704 
1705     addDrawBufferCommonTests(preGroup, PRE);
1706     addDrawBufferCommonTests(postGroup, POST);
1707     addRandomMaxTest(maxGroup);
1708     addRandomImplMaxTest(maxImplGroup);
1709 
1710     return group;
1711 }
1712 
1713 } // namespace Functional
1714 } // namespace gles3
1715 } // namespace deqp
1716