Merge vk-gl-cts/opengl-es-cts-3.2.8 into vk-gl-cts/main
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fDrawBuffersIndexedTests.cpp
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::Maybe;
70 using tcu::TestLog;
71 using tcu::TextureFormat;
72 using tcu::TextureLevel;
73 using tcu::UVec4;
74 using tcu::Vec2;
75 using tcu::Vec4;
76 using tcu::just;
77
78 using std::string;
79 using std::vector;
80 using std::map;
81
82 using sglr::rr_util::mapGLBlendEquation;
83 using sglr::rr_util::mapGLBlendFunc;
84 using sglr::rr_util::mapGLBlendEquationAdvanced;
85
86 namespace deqp
87 {
88 namespace gles3
89 {
90 namespace Functional
91 {
92 namespace
93 {
94
95 typedef deUint32 BlendEq;
96
97 bool isAdvancedBlendEq (BlendEq eq)
98 {
99         switch (eq)
100         {
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;
116                 default:
117                         return false;
118         }
119 }
120
121 struct SeparateBlendEq
122 {
123         SeparateBlendEq (BlendEq rgb_, BlendEq alpha_)
124                 : rgb   (rgb_)
125                 , alpha (alpha_)
126         {
127         }
128
129         BlendEq rgb;
130         BlendEq alpha;
131 };
132
133 struct BlendFunc
134 {
135         BlendFunc (deUint32 src_, deUint32 dst_)
136                 : src (src_)
137                 , dst (dst_)
138         {
139         }
140
141         deUint32 src;
142         deUint32 dst;
143 };
144
145 struct SeparateBlendFunc
146 {
147         SeparateBlendFunc (BlendFunc rgb_, BlendFunc alpha_)
148                 : rgb   (rgb_)
149                 , alpha (alpha_)
150         {
151         }
152
153         BlendFunc rgb;
154         BlendFunc alpha;
155 };
156
157 typedef deUint32 DrawBuffer;
158
159 struct BlendState
160 {
161         BlendState (void) {}
162
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_)
168                 , blendEq               (blendEq_)
169                 , blendFunc             (blendFunc_)
170                 , colorMask             (colorMask_)
171         {
172         }
173
174         bool isEmpty (void) const
175         {
176                 return (!enableBlend) && (!blendEq) && (!blendFunc) && (!colorMask);
177         }
178
179         Maybe<bool>                                                                             enableBlend;
180         Maybe<Either<BlendEq, SeparateBlendEq> >                blendEq;
181         Maybe<Either<BlendFunc, SeparateBlendFunc> >    blendFunc;
182         Maybe<BVec4>                                                                    colorMask;
183 };
184
185 static bool checkES32orGL45Support(Context& ctx)
186 {
187         auto ctxType = ctx.getRenderContext().getType();
188         return contextSupports(ctxType, glu::ApiType::es(3, 2)) ||
189                    contextSupports(ctxType, glu::ApiType::core(4, 5));
190 }
191
192 void setCommonBlendState (const glw::Functions& gl, const BlendState& blend)
193 {
194         if (blend.enableBlend)
195         {
196                 if (*blend.enableBlend)
197                         gl.enable(GL_BLEND);
198                 else
199                         gl.disable(GL_BLEND);
200         }
201
202         if (blend.colorMask)
203         {
204                 const BVec4& mask = *blend.colorMask;
205
206                 gl.colorMask(mask.x(), mask.y(), mask.z(), mask.w());
207         }
208
209         if (blend.blendEq)
210         {
211                 const Either<BlendEq, SeparateBlendEq>& blendEq = *blend.blendEq;
212
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);
217                 else
218                         DE_ASSERT(false);
219         }
220
221         if (blend.blendFunc)
222         {
223                 const Either<BlendFunc, SeparateBlendFunc>& blendFunc = *blend.blendFunc;
224
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);
229                 else
230                         DE_ASSERT(false);
231         }
232
233         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set common blend state.");
234 }
235
236 void setIndexedBlendState (const glw::Functions& gl, const BlendState& blend, deUint32 index)
237 {
238         if (blend.enableBlend)
239         {
240                 if (*blend.enableBlend)
241                         gl.enablei(GL_BLEND, index);
242                 else
243                         gl.disablei(GL_BLEND, index);
244         }
245
246         if (blend.colorMask)
247         {
248                 const BVec4 mask = *blend.colorMask;
249
250                 gl.colorMaski(index, mask.x(), mask.y(), mask.z(), mask.w());
251         }
252
253         if (blend.blendEq)
254         {
255                 const Either<BlendEq, SeparateBlendEq>& blendEq = *blend.blendEq;
256
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);
261                 else
262                         DE_ASSERT(false);
263         }
264
265         if (blend.blendFunc)
266         {
267                 const Either<BlendFunc, SeparateBlendFunc>& blendFunc = *blend.blendFunc;
268
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);
273                 else
274                         DE_ASSERT(false);
275         }
276
277         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set draw buffer specifig blend state.");
278 }
279
280 class DrawBufferInfo
281 {
282 public:
283                                                         DrawBufferInfo  (bool                                   render,
284                                                                                          const IVec2&                   size,
285                                                                                          const BlendState&              blendState,
286                                                                                          const TextureFormat&   format);
287
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;         }
292
293 private:
294         bool                                    m_render;
295         IVec2                                   m_size;
296         TextureFormat                   m_format;
297         BlendState                              m_blendState;
298 };
299
300 DrawBufferInfo::DrawBufferInfo (bool render, const IVec2& size, const BlendState& blendState, const TextureFormat& format)
301         : m_render              (render)
302         , m_size                (size)
303         , m_format              (format)
304         , m_blendState  (blendState)
305 {
306 }
307
308 void clearRenderbuffer (const glw::Functions&                   gl,
309                                                 const tcu::TextureFormat&               format,
310                                                 int                                                             renderbufferNdx,
311                                                 int                                                             renderbufferCount,
312                                                 tcu::TextureLevel&                              refRenderbuffer)
313 {
314         const tcu::TextureFormatInfo    info            = tcu::getTextureFormatInfo(format);
315
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);
322
323         switch (tcu::getTextureChannelClass(format.type))
324         {
325                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
326                 {
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);
332
333                         tcu::clear(refRenderbuffer, color);
334                         gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr());
335                         break;
336                 }
337
338                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
339                 {
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);
345
346                         tcu::clear(refRenderbuffer, color);
347                         gl.clearBufferiv(GL_COLOR, renderbufferNdx, color.getPtr());
348                         break;
349                 }
350
351                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
352                 {
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);
358
359                         tcu::clear(refRenderbuffer, color);
360                         gl.clearBufferuiv(GL_COLOR, renderbufferNdx, color.getPtr());
361                         break;
362                 }
363
364                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
365                 {
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);
371
372                         tcu::clear(refRenderbuffer, color);
373                         gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr());
374                         break;
375                 }
376
377                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
378                 {
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);
384
385                         tcu::clear(refRenderbuffer, color);
386                         gl.clearBufferfv(GL_COLOR, renderbufferNdx, color.getPtr());
387                         break;
388                 }
389
390                 default:
391                         DE_ASSERT(DE_FALSE);
392         }
393
394         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear renderbuffer.");
395 }
396
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)
402 {
403         vector<deUint32> bufs;
404
405         bufs.resize(drawBuffers.size());
406
407         DE_ASSERT(drawBuffers.size() == renderbuffers.size());
408         DE_ASSERT(drawBuffers.size() == refRenderbuffers.size());
409
410         gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
411
412         for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++)
413         {
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);
418
419                 bufs[renderbufferNdx]                                   = GL_COLOR_ATTACHMENT0 + renderbufferNdx;
420                 refRenderbuffers[renderbufferNdx]               = TextureLevel(drawBuffer.getFormat(), size.x(), size.y());
421
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.");
426         }
427
428         gl.drawBuffers((glw::GLsizei)bufs.size(), &(bufs[0]));
429
430         for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++)
431         {
432                 const DrawBufferInfo&           drawBuffer      = drawBuffers[renderbufferNdx];
433                 const TextureFormat&            format          = drawBuffer.getFormat();
434
435                 clearRenderbuffer(gl, format, renderbufferNdx, (int)refRenderbuffers.size(),  refRenderbuffers[renderbufferNdx]);
436         }
437
438         gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
439         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
440 }
441
442 Vec4 getFixedPointFormatThreshold (const tcu::TextureFormat& sourceFormat, const tcu::TextureFormat& readPixelsFormat)
443 {
444         DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
445         DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_FLOATING_POINT);
446
447         DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
448         DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER);
449
450         DE_ASSERT(tcu::getTextureChannelClass(sourceFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
451         DE_ASSERT(tcu::getTextureChannelClass(readPixelsFormat.type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
452
453         const tcu::IVec4        srcBits         = tcu::getTextureFormatBitDepth(sourceFormat);
454         const tcu::IVec4        readBits        = tcu::getTextureFormatBitDepth(readPixelsFormat);
455
456         Vec4                            threshold       = Vec4(0.0f);
457
458         for (int i = 0; i < 4; i++)
459         {
460                 const int bits = de::min(srcBits[i], readBits[i]);
461
462                 if (bits > 0)
463                 {
464                         threshold[i] = 3.0f / static_cast<float>(((1ul << bits) - 1ul));
465                 }
466         }
467
468         return threshold;
469 }
470
471 UVec4 getFloatULPThreshold (const tcu::TextureFormat& sourceFormat, const tcu::TextureFormat& readPixelsFormat)
472 {
473         const tcu::IVec4        srcMantissaBits         = tcu::getTextureFormatMantissaBitDepth(sourceFormat);
474         const tcu::IVec4        readMantissaBits        = tcu::getTextureFormatMantissaBitDepth(readPixelsFormat);
475         tcu::IVec4                      ULPDiff(0);
476
477         for (int i = 0; i < 4; i++)
478                 if (readMantissaBits[i] >= srcMantissaBits[i])
479                         ULPDiff[i] = readMantissaBits[i] - srcMantissaBits[i];
480
481         return UVec4(4) * (UVec4(1) << (ULPDiff.cast<deUint32>()));
482 }
483
484 void verifyRenderbuffer (TestLog&                                       log,
485                                                  tcu::ResultCollector&          results,
486                                                  const tcu::TextureFormat&      format,
487                                                  int                                            renderbufferNdx,
488                                                  const tcu::TextureLevel&       refRenderbuffer,
489                                                  const tcu::TextureLevel&       result)
490 {
491         switch (tcu::getTextureChannelClass(format.type))
492         {
493                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
494                 {
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());
498
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.");
501
502                         break;
503                 }
504
505                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
506                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
507                 {
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);
511
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.");
514
515                         break;
516                 }
517
518                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
519                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
520                 {
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());
524
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.");
527
528                         break;
529                 }
530
531                 default:
532                         DE_ASSERT(DE_FALSE);
533         }
534 }
535
536 TextureFormat getReadPixelFormat (const TextureFormat& format)
537 {
538         switch (tcu::getTextureChannelClass(format.type))
539         {
540                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
541                         return TextureFormat(TextureFormat::RGBA, TextureFormat::UNSIGNED_INT32);
542
543                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
544                         return TextureFormat(TextureFormat::RGBA, TextureFormat::SIGNED_INT32);
545
546                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
547                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
548                         return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8);
549
550                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
551                         return TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT);
552
553                 default:
554                         DE_ASSERT(false);
555                         return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8);
556         }
557 }
558
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)
565 {
566         const glw::Functions& gl = renderContext.getFunctions();
567
568         DE_ASSERT(renderbuffers.size() == refRenderbuffers.size());
569
570         gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
571
572         for (int renderbufferNdx = 0; renderbufferNdx < (int)renderbuffers.size(); renderbufferNdx++)
573         {
574                 const TextureLevel&     refRenderbuffer = refRenderbuffers[renderbufferNdx];
575                 const int                       width                   = refRenderbuffer.getWidth();
576                 const int                       height                  = refRenderbuffer.getHeight();
577                 const TextureFormat     format                  = refRenderbuffer.getFormat();
578
579                 tcu::TextureLevel       result                  (getReadPixelFormat(format), width, height);
580
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.");
584
585                 verifyRenderbuffer(log, results, format, renderbufferNdx, refRenderbuffer, result);
586         }
587
588         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
589 }
590
591 static const float s_quadCoords[] =
592 {
593         -0.5f, -0.5f,
594          0.5f, -0.5f,
595          0.5f,  0.5f,
596
597          0.5f,  0.5f,
598         -0.5f,  0.5f,
599         -0.5f, -0.5f
600 };
601
602 void setBlendState (rr::FragmentOperationState& fragOps, const BlendState& state)
603 {
604         if (state.blendEq)
605         {
606                 if (state.blendEq->is<BlendEq>())
607                 {
608                         if (isAdvancedBlendEq(state.blendEq->get<BlendEq>()))
609                         {
610                                 const rr::BlendEquationAdvanced equation = mapGLBlendEquationAdvanced(state.blendEq->get<BlendEq>());
611
612                                 fragOps.blendMode                               = rr::BLENDMODE_ADVANCED;
613                                 fragOps.blendEquationAdvaced    = equation;
614                         }
615                         else
616                         {
617                                 const rr::BlendEquation equation = mapGLBlendEquation(state.blendEq->get<BlendEq>());
618
619                                 fragOps.blendMode                               = rr::BLENDMODE_STANDARD;
620                                 fragOps.blendRGBState.equation  = equation;
621                                 fragOps.blendAState.equation    = equation;
622                         }
623                 }
624                 else
625                 {
626                         DE_ASSERT(state.blendEq->is<SeparateBlendEq>());
627
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);
631                 }
632         }
633
634         if (state.blendFunc)
635         {
636                 if (state.blendFunc->is<BlendFunc>())
637                 {
638                         const rr::BlendFunc srcFunction = mapGLBlendFunc(state.blendFunc->get<BlendFunc>().src);
639                         const rr::BlendFunc dstFunction = mapGLBlendFunc(state.blendFunc->get<BlendFunc>().dst);
640
641                         fragOps.blendRGBState.srcFunc   = srcFunction;
642                         fragOps.blendRGBState.dstFunc   = dstFunction;
643
644                         fragOps.blendAState.srcFunc             = srcFunction;
645                         fragOps.blendAState.dstFunc             = dstFunction;
646                 }
647                 else
648                 {
649                         DE_ASSERT(state.blendFunc->is<SeparateBlendFunc>());
650
651                         fragOps.blendRGBState.srcFunc   = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().rgb.src);
652                         fragOps.blendRGBState.dstFunc   = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().rgb.dst);
653
654                         fragOps.blendAState.srcFunc             = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().alpha.src);
655                         fragOps.blendAState.dstFunc             = mapGLBlendFunc(state.blendFunc->get<SeparateBlendFunc>().alpha.dst);
656                 }
657         }
658
659         if (state.colorMask)
660                 fragOps.colorMask = *state.colorMask;
661 }
662
663 rr::RenderState createRenderState (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const DrawBufferInfo& info, int subpixelBits)
664 {
665         const IVec2             size    = info.getSize();
666         rr::RenderState state   (rr::ViewportState(rr::WindowRectangle(0, 0, size.x(), size.y())), subpixelBits);
667
668         state.fragOps.blendMode = rr::BLENDMODE_STANDARD;
669
670         setBlendState(state.fragOps, preCommonBlendState);
671         setBlendState(state.fragOps, info.getBlendState());
672         setBlendState(state.fragOps, postCommonBlendState);
673
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);
680         else
681                 state.fragOps.blendMode = rr::BLENDMODE_NONE;
682
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;
687
688         return state;
689 }
690
691 class VertexShader : public rr::VertexShader
692 {
693 public:
694                                         VertexShader    (void);
695         virtual void    shadeVertices   (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
696 };
697
698 VertexShader::VertexShader (void)
699         : rr::VertexShader      (1, 1)
700 {
701         m_inputs[0].type        = rr::GENERICVECTYPE_FLOAT;
702         m_outputs[0].type       = rr::GENERICVECTYPE_FLOAT;
703 }
704
705 void VertexShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
706 {
707         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
708         {
709                 rr::VertexPacket& packet = *packets[packetNdx];
710
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));
713         }
714 }
715
716 class FragmentShader : public rr::FragmentShader
717 {
718 public:
719                         FragmentShader  (int drawBufferNdx, const DrawBufferInfo& info);
720         void    shadeFragments  (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
721
722 private:
723         const int                               m_drawBufferNdx;
724         const DrawBufferInfo    m_info;
725 };
726
727 FragmentShader::FragmentShader (int drawBufferNdx, const DrawBufferInfo& info)
728         : rr::FragmentShader    (1, 1)
729         , m_drawBufferNdx               (drawBufferNdx)
730         , m_info                                (info)
731 {
732         m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
733
734         switch (tcu::getTextureChannelClass(m_info.getFormat().type))
735         {
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;
740                         break;
741
742                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
743                         m_outputs[0].type = rr::GENERICVECTYPE_UINT32;
744                         break;
745
746                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
747                         m_outputs[0].type = rr::GENERICVECTYPE_INT32;
748                         break;
749
750                 default:
751                         DE_ASSERT(false);
752         }
753 }
754
755 void FragmentShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
756 {
757         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
758         {
759                 rr::FragmentPacket& packet = packets[packetNdx];
760
761                 DE_ASSERT(m_drawBufferNdx >= 0);
762                 DE_UNREF(m_info);
763
764                 for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
765                 {
766                         const Vec2      vColor          = rr::readVarying<float>(packet, context, 0, fragNdx).xy();
767                         const float     values[]        =
768                         {
769                                 vColor.x(),
770                                 vColor.y(),
771                                 (1.0f - vColor.x()),
772                                 (1.0f - vColor.y())
773                         };
774
775                         switch (tcu::getTextureChannelClass(m_info.getFormat().type))
776                         {
777                                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
778                                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
779                                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
780                                 {
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]);
785
786                                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
787                                         break;
788                                 }
789
790                                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
791                                 {
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]));
796
797                                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
798                                         break;
799                                 }
800
801                                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
802                                 {
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]));
807
808                                         rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
809                                         break;
810                                 }
811
812                                 default:
813                                         DE_ASSERT(DE_FALSE);
814                         }
815                 }
816         }
817 }
818
819 rr::VertexAttrib createVertexAttrib (const float* coords)
820 {
821         rr::VertexAttrib attrib;
822
823         attrib.type             = rr::VERTEXATTRIBTYPE_FLOAT;
824         attrib.size             = 2;
825         attrib.pointer  = coords;
826
827         return attrib;
828 }
829
830 void renderRefQuad (const BlendState&                           preCommonBlendState,
831                                         const BlendState&                               postCommonBlendState,
832                                         const vector<DrawBufferInfo>&   drawBuffers,
833                                         const int                                               subpixelBits,
834                                         vector<TextureLevel>&                   refRenderbuffers)
835 {
836         const rr::Renderer                      renderer;
837         const rr::PrimitiveList         primitives              (rr::PRIMITIVETYPE_TRIANGLES, 6, 0);
838         const rr::VertexAttrib          vertexAttribs[] =
839         {
840                 createVertexAttrib(s_quadCoords)
841         };
842
843         for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
844         {
845                 if (drawBuffers[drawBufferNdx].getRender())
846                 {
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);
853
854                         renderer.draw(command);
855                 }
856         }
857 }
858
859 bool requiresAdvancedBlendEq (const BlendState& pre, const BlendState post, const vector<DrawBufferInfo>& drawBuffers)
860 {
861         bool requiresAdvancedBlendEq = false;
862
863         if (pre.blendEq && pre.blendEq->is<BlendEq>())
864                 requiresAdvancedBlendEq |= isAdvancedBlendEq(pre.blendEq->get<BlendEq>());
865
866         if (post.blendEq && post.blendEq->is<BlendEq>())
867                 requiresAdvancedBlendEq |= isAdvancedBlendEq(post.blendEq->get<BlendEq>());
868
869         for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
870         {
871                 const BlendState& drawBufferBlendState = drawBuffers[drawBufferNdx].getBlendState();
872
873                 if (drawBufferBlendState.blendEq && drawBufferBlendState.blendEq->is<BlendEq>())
874                         requiresAdvancedBlendEq |= isAdvancedBlendEq(drawBufferBlendState.blendEq->get<BlendEq>());
875         }
876
877         return requiresAdvancedBlendEq;
878 }
879
880 glu::VertexSource genVertexSource (glu::RenderContext& renderContext)
881 {
882         const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
883
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"
888                 "void main (void)\n"
889                 "{\n"
890                 "\tv_color = 0.5 * (vec2(1.0) + i_coord);\n"
891                 "\tgl_Position = vec4(i_coord, 0.0, 1.0);\n"
892                 "}";
893
894         map<string, string> args;
895         args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_300_ES);
896
897         return glu::VertexSource(tcu::StringTemplate(vertexSource).specialize(args));
898 }
899
900 glu::FragmentSource genFragmentSource (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const vector<DrawBufferInfo>& drawBuffers, glu::RenderContext& renderContext)
901 {
902         std::ostringstream stream;
903         const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
904
905         stream << "${GLSL_VERSION_DECL}\n";
906
907         if (requiresAdvancedBlendEq(preCommonBlendState, postCommonBlendState, drawBuffers))
908         {
909                 stream << "${GLSL_EXTENSION}"
910                            <<  "layout(blend_support_all_equations) out;\n";
911         }
912
913         stream << "in highp vec2 v_color;\n";
914
915         for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
916         {
917                 const DrawBufferInfo&   drawBuffer                      = drawBuffers[drawBufferNdx];
918                 const TextureFormat&    format                          = drawBuffer.getFormat();
919
920                 stream << "layout(location=" << drawBufferNdx << ") out highp ";
921
922                 switch (tcu::getTextureChannelClass(format.type))
923                 {
924                         case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
925                         case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
926                         case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
927                                 stream << "vec4";
928                                 break;
929
930                         case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
931                                 stream << "uvec4";
932                                 break;
933
934                         case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
935                                 stream << "ivec4";
936                                 break;
937
938                         default:
939                                 DE_ASSERT(DE_FALSE);
940                 }
941
942                 stream << " o_drawBuffer" <<  drawBufferNdx << ";\n";
943         }
944
945         stream << "void main (void)\n"
946                    << "{\n";
947
948         for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
949         {
950                 const DrawBufferInfo&   drawBuffer              = drawBuffers[drawBufferNdx];
951                 const TextureFormat&    format                  = drawBuffer.getFormat();
952                 const char* const               values[]                =
953                 {
954                         "v_color.x",
955                         "v_color.y",
956                         "(1.0 - v_color.x)",
957                         "(1.0 - v_color.y)"
958                 };
959
960                 stream << "\to_drawBuffer" <<  drawBufferNdx;
961
962                 switch (tcu::getTextureChannelClass(format.type))
963                 {
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";
971                                 break;
972
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";
978                                 break;
979
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";
985                                 break;
986
987                         default:
988                                 DE_ASSERT(DE_FALSE);
989                 }
990         }
991
992         stream << "}";
993
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";
997
998         return glu::FragmentSource(tcu::StringTemplate(stream.str()).specialize(args));
999 }
1000
1001 glu::ProgramSources genShaderSources (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const vector<DrawBufferInfo>& drawBuffers, glu::RenderContext& renderContext)
1002 {
1003         return glu::ProgramSources() << genVertexSource(renderContext) << genFragmentSource(preCommonBlendState, postCommonBlendState, drawBuffers, renderContext);
1004 }
1005
1006 void renderGLQuad (glu::RenderContext&                  renderContext,
1007                                    const glu::ShaderProgram&    program)
1008 {
1009         const glu::VertexArrayBinding vertexArrays[] =
1010         {
1011                 glu::VertexArrayBinding(glu::BindingPoint(0), glu::VertexArrayPointer(glu::VTX_COMP_FLOAT, glu::VTX_COMP_CONVERT_NONE, 2, 6, 0, s_quadCoords))
1012         };
1013
1014         glu::draw(renderContext, program.getProgram(), 1, vertexArrays, glu::pr::Triangles(6));
1015 }
1016
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)
1024 {
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);
1029
1030         vector<deUint32> bufs;
1031
1032         bufs.resize(drawBuffers.size());
1033
1034         for (int bufNdx = 0; bufNdx < (int)bufs.size(); bufNdx++)
1035                 bufs[bufNdx] = (drawBuffers[bufNdx].getRender() ? GL_COLOR_ATTACHMENT0 + bufNdx : GL_NONE);
1036
1037         log << program;
1038
1039         gl.viewport(0, 0, size.x(), size.y());
1040         gl.useProgram(program.getProgram());
1041         gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
1042
1043         setCommonBlendState(gl, preCommonBlendState);
1044
1045         for (int renderbufferNdx = 0; renderbufferNdx < (int)drawBuffers.size(); renderbufferNdx++)
1046                 setIndexedBlendState(gl, drawBuffers[renderbufferNdx].getBlendState(), renderbufferNdx);
1047
1048         setCommonBlendState(gl, postCommonBlendState);
1049
1050         gl.drawBuffers((glw::GLsizei)bufs.size(), &(bufs[0]));
1051
1052         if (requiresBlendBarriers)
1053                 gl.blendBarrier();
1054
1055         renderGLQuad(renderContext, program);
1056
1057         if (requiresBlendBarriers)
1058                 gl.blendBarrier();
1059
1060         gl.drawBuffers(0, 0);
1061         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1062         gl.useProgram(0);
1063
1064         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render");
1065
1066         int subpixelBits = 0;
1067         gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits);
1068
1069         renderRefQuad(preCommonBlendState, postCommonBlendState, drawBuffers, subpixelBits, refRenderbuffers);
1070 }
1071
1072 void logBlendState (TestLog&                    log,
1073                                         const BlendState&       blend)
1074 {
1075         if (blend.enableBlend)
1076         {
1077                 if (*blend.enableBlend)
1078                         log << TestLog::Message << "Enable blending." << TestLog::EndMessage;
1079                 else
1080                         log << TestLog::Message << "Disable blending." << TestLog::EndMessage;
1081         }
1082
1083         if (blend.colorMask)
1084         {
1085                 const BVec4 mask = *blend.colorMask;
1086
1087                 log << TestLog::Message << "Set color mask: " << mask << "." << TestLog::EndMessage;
1088         }
1089
1090         if (blend.blendEq)
1091         {
1092                 const Either<BlendEq, SeparateBlendEq>& blendEq = *blend.blendEq;
1093
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;
1098                 else
1099                         DE_ASSERT(false);
1100         }
1101
1102         if (blend.blendFunc)
1103         {
1104                 const Either<BlendFunc, SeparateBlendFunc>& blendFunc = *blend.blendFunc;
1105
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>())
1109                 {
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;
1112                 }
1113                 else
1114                         DE_ASSERT(false);
1115         }
1116 }
1117
1118 void logTestCaseInfo (TestLog&                                          log,
1119                                           const BlendState&                             preCommonBlendState,
1120                                           const BlendState&                             postCommonBlendState,
1121                                           const vector<DrawBufferInfo>& drawBuffers)
1122 {
1123         {
1124                 tcu::ScopedLogSection drawBuffersSection(log, "DrawBuffers", "Draw buffers");
1125
1126                 for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
1127                 {
1128                         const tcu::ScopedLogSection     drawBufferSection       (log, "DrawBuffer" + de::toString(drawBufferNdx), "Draw Buffer " + de::toString(drawBufferNdx));
1129                         const DrawBufferInfo&           drawBuffer                      = drawBuffers[drawBufferNdx];
1130
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;
1134                 }
1135         }
1136
1137         if (!preCommonBlendState.isEmpty())
1138         {
1139                 tcu::ScopedLogSection s(log, "PreCommonState", "First set common blend state");
1140                 logBlendState(log, preCommonBlendState);
1141         }
1142
1143         for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
1144         {
1145                 if (!drawBuffers[drawBufferNdx].getBlendState().isEmpty())
1146                 {
1147                         const tcu::ScopedLogSection s(log, "DrawBufferState" + de::toString(drawBufferNdx), "Set DrawBuffer " + de::toString(drawBufferNdx) + " state to");
1148
1149                         logBlendState(log, drawBuffers[drawBufferNdx].getBlendState());
1150                 }
1151         }
1152
1153         if (!postCommonBlendState.isEmpty())
1154         {
1155                 tcu::ScopedLogSection s(log, "PostCommonState", "After set common blend state");
1156                 logBlendState(log, postCommonBlendState);
1157         }
1158 }
1159
1160 void runTest (TestLog&                                          log,
1161                           tcu::ResultCollector&                 results,
1162                           glu::RenderContext&                   renderContext,
1163
1164                           const BlendState&                             preCommonBlendState,
1165                           const BlendState&                             postCommonBlendState,
1166                           const vector<DrawBufferInfo>& drawBuffers)
1167 {
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());
1172
1173         logTestCaseInfo(log, preCommonBlendState, postCommonBlendState, drawBuffers);
1174
1175         genRenderbuffers(gl, drawBuffers, framebuffer, renderbuffers, refRenderbuffers);
1176
1177         renderQuad(log, renderContext, preCommonBlendState, postCommonBlendState, drawBuffers, framebuffer, refRenderbuffers);
1178
1179         verifyRenderbuffers(log, results, renderContext, renderbuffers, framebuffer, refRenderbuffers);
1180 }
1181
1182 class DrawBuffersIndexedTest : public TestCase
1183 {
1184 public:
1185                                         DrawBuffersIndexedTest (Context&                                                context,
1186                                                                                         const BlendState&                               preCommonBlendState,
1187                                                                                         const BlendState&                               postCommonBlendState,
1188                                                                                         const vector<DrawBufferInfo>&   drawBuffers,
1189                                                                                         const string&                                   name,
1190                                                                                         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
1201 DrawBuffersIndexedTest::DrawBuffersIndexedTest (Context&                                                context,
1202                                                                                                 const BlendState&                               preCommonBlendState,
1203                                                                                                 const BlendState&                               postCommonBlendState,
1204                                                                                                 const vector<DrawBufferInfo>&   drawBuffers,
1205                                                                                                 const string&                                   name,
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)
1211 {
1212 }
1213
1214 void DrawBuffersIndexedTest::init (void)
1215 {
1216         const bool supportsES32orGL45 = checkES32orGL45Support(m_context);
1217
1218         if (!supportsES32orGL45)
1219         {
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");
1222
1223                 if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1224                         TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1225         }
1226 }
1227
1228 TestCase::IterateResult DrawBuffersIndexedTest::iterate (void)
1229 {
1230         TestLog&                                log             = m_testCtx.getLog();
1231         tcu::ResultCollector    results (log);
1232
1233         runTest(log, results, m_context.getRenderContext(), m_preCommonBlendState, m_postCommonBlendState, m_drawBuffers);
1234
1235         results.setTestContextResult(m_testCtx);
1236
1237         return STOP;
1238 }
1239
1240 BlendEq getRandomBlendEq (de::Random& rng)
1241 {
1242         const BlendEq eqs[] =
1243         {
1244                 GL_FUNC_ADD,
1245                 GL_FUNC_SUBTRACT,
1246                 GL_FUNC_REVERSE_SUBTRACT,
1247                 GL_MIN,
1248                 GL_MAX
1249         };
1250
1251         return de::getSizedArrayElement<DE_LENGTH_OF_ARRAY(eqs)>(eqs, rng.getUint32() % DE_LENGTH_OF_ARRAY(eqs));
1252 }
1253
1254 BlendFunc getRandomBlendFunc (de::Random& rng)
1255 {
1256         const deUint32 funcs[] =
1257         {
1258                 GL_ZERO,
1259                 GL_ONE,
1260                 GL_SRC_COLOR,
1261                 GL_ONE_MINUS_SRC_COLOR,
1262                 GL_DST_COLOR,
1263                 GL_ONE_MINUS_DST_COLOR,
1264                 GL_SRC_ALPHA,
1265                 GL_ONE_MINUS_SRC_ALPHA,
1266                 GL_DST_ALPHA,
1267                 GL_ONE_MINUS_DST_ALPHA,
1268                 GL_CONSTANT_COLOR,
1269                 GL_ONE_MINUS_CONSTANT_COLOR,
1270                 GL_CONSTANT_ALPHA,
1271                 GL_ONE_MINUS_CONSTANT_ALPHA,
1272                 GL_SRC_ALPHA_SATURATE
1273         };
1274
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));
1277
1278         return BlendFunc(src, dst);
1279 }
1280
1281 void genRandomBlendState (de::Random& rng, BlendState& blendState)
1282 {
1283         if (rng.getBool())
1284                 blendState.enableBlend = rng.getBool();
1285
1286         if (rng.getBool())
1287         {
1288                 if (rng.getBool())
1289                         blendState.blendEq = getRandomBlendEq(rng);
1290                 else
1291                 {
1292                         const BlendEq   rgb             = getRandomBlendEq(rng);
1293                         const BlendEq   alpha   = getRandomBlendEq(rng);
1294
1295                         blendState.blendEq              = SeparateBlendEq(rgb, alpha);
1296                 }
1297         }
1298
1299         if (rng.getBool())
1300         {
1301                 if (rng.getBool())
1302                         blendState.blendFunc = getRandomBlendFunc(rng);
1303                 else
1304                 {
1305                         const BlendFunc rgb             = getRandomBlendFunc(rng);
1306                         const BlendFunc alpha   = getRandomBlendFunc(rng);
1307
1308                         blendState.blendFunc    = SeparateBlendFunc(rgb, alpha);
1309                 }
1310         }
1311
1312         if (rng.getBool())
1313         {
1314                 const bool red          = rng.getBool();
1315                 const bool green        = rng.getBool();
1316                 const bool blue         = rng.getBool();
1317                 const bool alpha        = rng.getBool();
1318
1319                 blendState.colorMask = BVec4(red, blue, green, alpha);
1320         }
1321 }
1322
1323 TextureFormat getRandomFormat (de::Random& rng, Context& context)
1324 {
1325         const bool supportsES32orGL45 = checkES32orGL45Support(context);
1326
1327         const deUint32 glFormats[] =
1328         {
1329                 GL_R8,
1330                 GL_RG8,
1331                 GL_RGB8,
1332                 GL_RGB565,
1333                 GL_RGBA4,
1334                 GL_RGB5_A1,
1335                 GL_RGBA8,
1336                 GL_RGB10_A2,
1337                 GL_RGB10_A2UI,
1338                 GL_R8I,
1339                 GL_R8UI,
1340                 GL_R16I,
1341                 GL_R16UI,
1342                 GL_R32I,
1343                 GL_R32UI,
1344                 GL_RG8I,
1345                 GL_RG8UI,
1346                 GL_RG16I,
1347                 GL_RG16UI,
1348                 GL_RG32I,
1349                 GL_RG32UI,
1350                 GL_RGBA8I,
1351                 GL_RGBA8UI,
1352                 GL_RGBA16I,
1353                 GL_RGBA16UI,
1354                 GL_RGBA32I,
1355                 GL_RGBA32UI,
1356                 GL_RGBA16F,
1357                 GL_R32F,
1358                 GL_RG32F,
1359                 GL_RGBA32F,
1360                 GL_R11F_G11F_B10F
1361         };
1362
1363         if (supportsES32orGL45)
1364                 return glu::mapGLInternalFormat(de::getArrayElement(glFormats, rng.getUint32() % DE_LENGTH_OF_ARRAY(glFormats)));
1365         else
1366         {
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)));
1369         }
1370 }
1371
1372 void genRandomTest (de::Random& rng, BlendState& preCommon, BlendState& postCommon, vector<DrawBufferInfo>& drawBuffers, int maxDrawBufferCount, Context& context)
1373 {
1374         genRandomBlendState(rng, preCommon);
1375         genRandomBlendState(rng, postCommon);
1376
1377         for (int drawBufferNdx = 0; drawBufferNdx < maxDrawBufferCount; drawBufferNdx++)
1378         {
1379                 const bool                      render          = rng.getFloat() > 0.1f;
1380                 const IVec2                     size            (64, 64);
1381                 const TextureFormat     format          (getRandomFormat(rng, context));
1382                 BlendState                      blendState;
1383
1384                 genRandomBlendState(rng, blendState);
1385
1386                 // 32bit float formats don't support blending in GLES32
1387                 if (format.type == tcu::TextureFormat::FLOAT)
1388                 {
1389                         // If format is 32bit float post common can't enable blending
1390                         if (postCommon.enableBlend && *postCommon.enableBlend)
1391                         {
1392                                 // Either don't set enable blend or disable blending
1393                                 if (rng.getBool())
1394                                         postCommon.enableBlend = tcu::Nothing;
1395                                 else
1396                                         postCommon.enableBlend = tcu::just(false);
1397                         }
1398
1399                         // If post common doesn't disable blending, per attachment state or
1400                         // pre common must.
1401                         if (!postCommon.enableBlend)
1402                         {
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);
1408                         }
1409                 }
1410
1411                 drawBuffers.push_back(DrawBufferInfo(render, size, blendState, format));
1412         }
1413 }
1414
1415 class MaxDrawBuffersIndexedTest : public TestCase
1416 {
1417 public:
1418                                         MaxDrawBuffersIndexedTest       (Context& contet, int seed);
1419
1420         void                    init                                            (void);
1421         IterateResult   iterate                                         (void);
1422
1423 private:
1424         const int               m_seed;
1425 };
1426
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)
1430 {
1431 }
1432
1433 void MaxDrawBuffersIndexedTest::init (void)
1434 {
1435         const bool supportsES32orGL45 = checkES32orGL45Support(m_context);
1436
1437         if (!supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1438                 TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1439 }
1440
1441 TestCase::IterateResult MaxDrawBuffersIndexedTest::iterate (void)
1442 {
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;
1449
1450         genRandomTest(rng, preCommonBlendState, postCommonBlendState, drawBuffers, 4, m_context);
1451
1452         runTest(log, results, m_context.getRenderContext(), preCommonBlendState, postCommonBlendState, drawBuffers);
1453
1454         results.setTestContextResult(m_testCtx);
1455
1456         return STOP;
1457 }
1458
1459 class ImplMaxDrawBuffersIndexedTest : public TestCase
1460 {
1461 public:
1462                                         ImplMaxDrawBuffersIndexedTest   (Context& contet, int seed);
1463
1464         void                    init                                                    (void);
1465         IterateResult   iterate                                                 (void);
1466
1467 private:
1468         const int               m_seed;
1469 };
1470
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)
1474 {
1475 }
1476
1477 void ImplMaxDrawBuffersIndexedTest::init (void)
1478 {
1479         const bool supportsES32orGL45 = checkES32orGL45Support(m_context);
1480
1481         if (!supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1482                 TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1483 }
1484
1485 TestCase::IterateResult ImplMaxDrawBuffersIndexedTest::iterate (void)
1486 {
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;
1495
1496         gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
1497         GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv(GL_MAX_DRAW_BUFFERS) failed");
1498
1499         TCU_CHECK(maxDrawBuffers > 0);
1500
1501         genRandomTest(rng, preCommonBlendState, postCommonBlendState, drawBuffers, maxDrawBuffers, m_context);
1502
1503         runTest(log, results, m_context.getRenderContext(), preCommonBlendState, postCommonBlendState, drawBuffers);
1504
1505         results.setTestContextResult(m_testCtx);
1506
1507         return STOP;
1508 }
1509
1510 enum PrePost
1511 {
1512         PRE,
1513         POST
1514 };
1515
1516 TestCase* createDiffTest (Context& context, PrePost prepost, const char* name, const BlendState& commonState, const BlendState& drawBufferState)
1517 {
1518         const BlendState emptyState = BlendState(tcu::Nothing, tcu::Nothing, tcu::Nothing, tcu::Nothing);
1519
1520         if (prepost == PRE)
1521         {
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)))),
1525                                                                                                                  tcu::Nothing);
1526                 vector<DrawBufferInfo>  drawBuffers;
1527
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)));
1530
1531                 return new DrawBuffersIndexedTest(context, preState, emptyState, drawBuffers, name, name);
1532         }
1533         else if (prepost == POST)
1534         {
1535                 const BlendState                preState        = BlendState(just(true),
1536                                                                                                                  tcu::Nothing,
1537                                                                                                                  Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_ONE, GL_ONE)),
1538                                                                                                                  tcu::Nothing);
1539                 vector<DrawBufferInfo>  drawBuffers;
1540
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)));
1543
1544                 return new DrawBuffersIndexedTest(context, preState, commonState, drawBuffers, name, name);
1545         }
1546         else
1547         {
1548                 DE_ASSERT(false);
1549                 return DE_NULL;
1550         }
1551 }
1552
1553 TestCase* createAdvancedEqDiffTest (Context& context, PrePost prepost, const char* name, const BlendState& commonState, const BlendState& drawBufferState)
1554 {
1555         const BlendState emptyState = BlendState(tcu::Nothing, tcu::Nothing, tcu::Nothing, tcu::Nothing);
1556
1557         if (prepost == PRE)
1558         {
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)))),
1562                                                                                                                  tcu::Nothing);
1563                 vector<DrawBufferInfo>  drawBuffers;
1564
1565                 drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1566
1567                 return new DrawBuffersIndexedTest(context, preState, emptyState, drawBuffers, name, name);
1568         }
1569         else if (prepost == POST)
1570         {
1571                 const BlendState                preState        = BlendState(just(true),
1572                                                                                                                  tcu::Nothing,
1573                                                                                                                  Maybe<Either<BlendFunc, SeparateBlendFunc> >(BlendFunc(GL_ONE, GL_ONE)),
1574                                                                                                                  tcu::Nothing);
1575                 vector<DrawBufferInfo>  drawBuffers;
1576
1577                 drawBuffers.push_back(DrawBufferInfo(true, IVec2(64, 64), drawBufferState, TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)));
1578
1579                 return new DrawBuffersIndexedTest(context, preState, commonState, drawBuffers, name, name);
1580         }
1581         else
1582         {
1583                 DE_ASSERT(false);
1584                 return DE_NULL;
1585         }
1586 }
1587
1588 void addDrawBufferCommonTests (TestCaseGroup* root, PrePost prepost)
1589 {
1590         const BlendState                emptyState      = BlendState(Maybe<bool>(), Maybe<Either<BlendEq, SeparateBlendEq> >(), Maybe<Either<BlendFunc, SeparateBlendFunc> >(), Maybe<BVec4>());
1591
1592         {
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>());
1595
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));
1600         }
1601
1602         {
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>());
1605
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>());
1608
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>());
1611
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));
1615
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));
1619
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));
1623         }
1624
1625         {
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>());
1630
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));
1635         }
1636
1637         {
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)));
1640
1641                 root->addChild(createDiffTest(root->getContext(), prepost, "common_color_mask_buffer_color_mask", commonColorMaskState, bufferColorMaskState));
1642         }
1643 }
1644
1645 void addRandomMaxTest (TestCaseGroup* root)
1646 {
1647         for (int i = 0; i < 20; i++)
1648                 root->addChild(new MaxDrawBuffersIndexedTest(root->getContext(), i));
1649 }
1650
1651 void addRandomImplMaxTest (TestCaseGroup* root)
1652 {
1653         for (int i = 0; i < 20; i++)
1654                 root->addChild(new ImplMaxDrawBuffersIndexedTest(root->getContext(), i));
1655 }
1656
1657 } // anonymous
1658
1659 TestCaseGroup* createDrawBuffersIndexedTests (Context& context)
1660 {
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.");
1663
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.");
1669
1670         group->addChild(preGroup);
1671         group->addChild(postGroup);
1672         group->addChild(randomGroup);
1673
1674         randomGroup->addChild(maxGroup);
1675         randomGroup->addChild(maxImplGroup);
1676
1677         addDrawBufferCommonTests(preGroup, PRE);
1678         addDrawBufferCommonTests(postGroup, POST);
1679         addRandomMaxTest(maxGroup);
1680         addRandomImplMaxTest(maxImplGroup);
1681
1682         return group;
1683 }
1684
1685 } // Functional
1686 } // gles3
1687 } // deqp