Home | History | Annotate | Download | only in functional
      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 
     65 using tcu::BVec4;
     66 using tcu::Either;
     67 using tcu::IVec2;
     68 using tcu::IVec4;
     69 using tcu::Maybe;
     70 using tcu::TestLog;
     71 using tcu::TextureFormat;
     72 using tcu::TextureLevel;
     73 using tcu::UVec4;
     74 using tcu::Vec2;
     75 using tcu::Vec4;
     76 using tcu::just;
     77 
     78 using std::string;
     79 using std::vector;
     80 using std::map;
     81 
     82 using sglr::rr_util::mapGLBlendEquation;
     83 using sglr::rr_util::mapGLBlendFunc;
     84 using sglr::rr_util::mapGLBlendEquationAdvanced;
     85 
     86 namespace deqp
     87 {
     88 namespace gles31
     89 {
     90 namespace Functional
     91 {
     92 namespace
     93 {
     94 
     95 typedef deUint32 BlendEq;
     96 
     97 bool isAdvancedBlendEq (BlendEq eq)
     98 {
     99 	switch (eq)
    100 	{
    101 		case GL_MULTIPLY:		return true;
    102 		case GL_SCREEN:			return true;
    103 		case GL_OVERLAY:		return true;
    104 		case GL_DARKEN:			return true;
    105 		case GL_LIGHTEN:		return true;
    106 		case GL_COLORDODGE:		return true;
    107 		case GL_COLORBURN:		return true;
    108 		case GL_HARDLIGHT:		return true;
    109 		case GL_SOFTLIGHT:		return true;
    110 		case GL_DIFFERENCE:		return true;
    111 		case GL_EXCLUSION:		return true;
    112 		case GL_HSL_HUE:		return true;
    113 		case GL_HSL_SATURATION:	return true;
    114 		case GL_HSL_COLOR:		return true;
    115 		case GL_HSL_LUMINOSITY:	return true;
    116 		default:
    117 			return false;
    118 	}
    119 }
    120 
    121 struct SeparateBlendEq
    122 {
    123 	SeparateBlendEq (BlendEq rgb_, BlendEq alpha_)
    124 		: rgb	(rgb_)
    125 		, alpha	(alpha_)
    126 	{
    127 	}
    128 
    129 	BlendEq rgb;
    130 	BlendEq alpha;
    131 };
    132 
    133 struct BlendFunc
    134 {
    135 	BlendFunc (deUint32 src_, deUint32 dst_)
    136 		: src (src_)
    137 		, dst (dst_)
    138 	{
    139 	}
    140 
    141 	deUint32 src;
    142 	deUint32 dst;
    143 };
    144 
    145 struct SeparateBlendFunc
    146 {
    147 	SeparateBlendFunc (BlendFunc rgb_, BlendFunc alpha_)
    148 		: rgb	(rgb_)
    149 		, alpha	(alpha_)
    150 	{
    151 	}
    152 
    153 	BlendFunc rgb;
    154 	BlendFunc alpha;
    155 };
    156 
    157 typedef deUint32 DrawBuffer;
    158 
    159 struct BlendState
    160 {
    161 	BlendState (void) {}
    162 
    163 	BlendState (const Maybe<bool>&									enableBlend_,
    164 				const Maybe<Either<BlendEq, SeparateBlendEq> >&		blendEq_,
    165 				const Maybe<Either<BlendFunc, SeparateBlendFunc> >&	blendFunc_,
    166 				const Maybe<BVec4>&									colorMask_)
    167 		: enableBlend	(enableBlend_)
    168 		, blendEq		(blendEq_)
    169 		, blendFunc		(blendFunc_)
    170 		, colorMask		(colorMask_)
    171 	{
    172 	}
    173 
    174 	bool isEmpty (void) const
    175 	{
    176 		return (!enableBlend) && (!blendEq) && (!blendFunc) && (!colorMask);
    177 	}
    178 
    179 	Maybe<bool>										enableBlend;
    180 	Maybe<Either<BlendEq, SeparateBlendEq> >		blendEq;
    181 	Maybe<Either<BlendFunc, SeparateBlendFunc> >	blendFunc;
    182 	Maybe<BVec4>									colorMask;
    183 };
    184 
    185 void 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 
    229 void 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 
    273 class DrawBufferInfo
    274 {
    275 public:
    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 
    286 private:
    287 	bool					m_render;
    288 	IVec2					m_size;
    289 	TextureFormat			m_format;
    290 	BlendState				m_blendState;
    291 };
    292 
    293 DrawBufferInfo::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 
    301 void 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 
    390 void 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 
    435 Vec4 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 
    452 UVec4 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 
    465 void 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 
    517 TextureFormat 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 
    540 void 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 
    572 static 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 
    583 void 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 
    644 rr::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 
    672 class VertexShader : public rr::VertexShader
    673 {
    674 public:
    675 					VertexShader	(void);
    676 	virtual void	shadeVertices	(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
    677 };
    678 
    679 VertexShader::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 
    686 void 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 
    697 class FragmentShader : public rr::FragmentShader
    698 {
    699 public:
    700 			FragmentShader	(int drawBufferNdx, const DrawBufferInfo& info);
    701 	void	shadeFragments	(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
    702 
    703 private:
    704 	const int				m_drawBufferNdx;
    705 	const DrawBufferInfo	m_info;
    706 };
    707 
    708 FragmentShader::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 
    736 void 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 
    800 rr::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 
    811 void 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 
    839 bool 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 
    860 glu::VertexSource genVertexSource (glu::RenderContext& renderContext)
    861 {
    862 	const bool supportsES32 = 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"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
    876 
    877 	return glu::VertexSource(tcu::StringTemplate(vertexSource).specialize(args));
    878 }
    879 
    880 glu::FragmentSource genFragmentSource (const BlendState& preCommonBlendState, const BlendState& postCommonBlendState, const vector<DrawBufferInfo>& drawBuffers, glu::RenderContext& renderContext)
    881 {
    882 	std::ostringstream stream;
    883 	const bool supportsES32 = 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"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
    976 	args["GLSL_EXTENSION"] = supportsES32 ? "\n" : "#extension GL_KHR_blend_equation_advanced : require\n";
    977 
    978 	return glu::FragmentSource(tcu::StringTemplate(stream.str()).specialize(args));
    979 }
    980 
    981 glu::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 
    986 void 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 
    997 void 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 
   1049 void 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 
   1095 void 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 
   1137 void 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 
   1159 class DrawBuffersIndexedTest : public TestCase
   1160 {
   1161 public:
   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 
   1172 private:
   1173 	const BlendState				m_preCommonBlendState;
   1174 	const BlendState				m_postCommonBlendState;
   1175 	const vector<DrawBufferInfo>	m_drawBuffers;
   1176 };
   1177 
   1178 DrawBuffersIndexedTest::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 
   1191 void DrawBuffersIndexedTest::init (void)
   1192 {
   1193 	const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
   1194 
   1195 	if (!supportsES32)
   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 
   1205 TestCase::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 
   1217 BlendEq 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 
   1231 BlendFunc 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 
   1258 void 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 
   1300 TextureFormat getRandomFormat (de::Random& rng, Context& context)
   1301 {
   1302 	const bool supportsES32 = 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 (supportsES32)
   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 
   1349 void 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 
   1392 class MaxDrawBuffersIndexedTest : public TestCase
   1393 {
   1394 public:
   1395 					MaxDrawBuffersIndexedTest	(Context& contet, int seed);
   1396 
   1397 	void			init						(void);
   1398 	IterateResult	iterate						(void);
   1399 
   1400 private:
   1401 	const int		m_seed;
   1402 };
   1403 
   1404 MaxDrawBuffersIndexedTest::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 
   1410 void MaxDrawBuffersIndexedTest::init (void)
   1411 {
   1412 	const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
   1413 
   1414 	if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
   1415 		TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
   1416 }
   1417 
   1418 TestCase::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 
   1436 class ImplMaxDrawBuffersIndexedTest : public TestCase
   1437 {
   1438 public:
   1439 					ImplMaxDrawBuffersIndexedTest	(Context& contet, int seed);
   1440 
   1441 	void			init							(void);
   1442 	IterateResult	iterate							(void);
   1443 
   1444 private:
   1445 	const int		m_seed;
   1446 };
   1447 
   1448 ImplMaxDrawBuffersIndexedTest::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 
   1454 void ImplMaxDrawBuffersIndexedTest::init (void)
   1455 {
   1456 	const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
   1457 
   1458 	if (!supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
   1459 		TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
   1460 }
   1461 
   1462 TestCase::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 
   1487 enum PrePost
   1488 {
   1489 	PRE,
   1490 	POST
   1491 };
   1492 
   1493 TestCase* 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 
   1530 TestCase* 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 
   1565 void 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 
   1622 void addRandomMaxTest (TestCaseGroup* root)
   1623 {
   1624 	for (int i = 0; i < 20; i++)
   1625 		root->addChild(new MaxDrawBuffersIndexedTest(root->getContext(), i));
   1626 }
   1627 
   1628 void 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 
   1636 TestCaseGroup* 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