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