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