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