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