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 
isAdvancedBlendEq(BlendEq eq)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 {
SeparateBlendEqdeqp::gles31::Functional::__anon169a63d40111::SeparateBlendEq123 	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 {
BlendFuncdeqp::gles31::Functional::__anon169a63d40111::BlendFunc135 	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 {
SeparateBlendFuncdeqp::gles31::Functional::__anon169a63d40111::SeparateBlendFunc147 	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 {
BlendStatedeqp::gles31::Functional::__anon169a63d40111::BlendState161 	BlendState (void) {}
162 
BlendStatedeqp::gles31::Functional::__anon169a63d40111::BlendState163 	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 
isEmptydeqp::gles31::Functional::__anon169a63d40111::BlendState174 	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 
setCommonBlendState(const glw::Functions & gl,const BlendState & blend)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 
setIndexedBlendState(const glw::Functions & gl,const BlendState & blend,deUint32 index)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 
getFormat(void) const281 	const TextureFormat&	getFormat		(void) const { return m_format;		}
getSize(void) const282 	const IVec2&			getSize			(void) const { return m_size;		}
getBlendState(void) const283 	const BlendState&		getBlendState	(void) const { return m_blendState;	}
getRender(void) const284 	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 
DrawBufferInfo(bool render,const IVec2 & size,const BlendState & blendState,const TextureFormat & format)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 
clearRenderbuffer(const glw::Functions & gl,const tcu::TextureFormat & format,int renderbufferNdx,int renderbufferCount,tcu::TextureLevel & refRenderbuffer)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 
genRenderbuffers(const glw::Functions & gl,const vector<DrawBufferInfo> & drawBuffers,const glu::Framebuffer & framebuffer,const glu::RenderbufferVector & renderbuffers,vector<TextureLevel> & refRenderbuffers)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 
getFixedPointFormatThreshold(const tcu::TextureFormat & sourceFormat,const tcu::TextureFormat & readPixelsFormat)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 
getFloatULPThreshold(const tcu::TextureFormat & sourceFormat,const tcu::TextureFormat & readPixelsFormat)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 
verifyRenderbuffer(TestLog & log,tcu::ResultCollector & results,const tcu::TextureFormat & format,int renderbufferNdx,const tcu::TextureLevel & refRenderbuffer,const tcu::TextureLevel & result)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 
getReadPixelFormat(const TextureFormat & format)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 
verifyRenderbuffers(TestLog & log,tcu::ResultCollector & results,glu::RenderContext & renderContext,const glu::RenderbufferVector & renderbuffers,const glu::Framebuffer & framebuffer,const vector<TextureLevel> & refRenderbuffers)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 
setBlendState(rr::FragmentOperationState & fragOps,const BlendState & state)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 
createRenderState(const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const DrawBufferInfo & info)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 
VertexShader(void)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 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const686 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 
FragmentShader(int drawBufferNdx,const DrawBufferInfo & info)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 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const736 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 
createVertexAttrib(const float * coords)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 
renderRefQuad(const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,vector<TextureLevel> & refRenderbuffers)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 
requiresAdvancedBlendEq(const BlendState & pre,const BlendState post,const vector<DrawBufferInfo> & drawBuffers)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 
genVertexSource(glu::RenderContext & renderContext)860 glu::VertexSource genVertexSource (glu::RenderContext& renderContext)
861 {
862 	const bool isES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
863 
864 	const char* const vertexSource =
865 		"${GLSL_VERSION_DECL}\n"
866 		"layout(location=0) in highp vec2 i_coord;\n"
867 		"out highp vec2 v_color;\n"
868 		"void main (void)\n"
869 		"{\n"
870 		"\tv_color = 0.5 * (vec2(1.0) + i_coord);\n"
871 		"\tgl_Position = vec4(i_coord, 0.0, 1.0);\n"
872 		"}";
873 
874 	map<string, string> args;
875 	args["GLSL_VERSION_DECL"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
876 
877 	return glu::VertexSource(tcu::StringTemplate(vertexSource).specialize(args));
878 }
879 
genFragmentSource(const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,glu::RenderContext & renderContext)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 isES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
884 
885 	stream << "${GLSL_VERSION_DECL}\n";
886 
887 	if (requiresAdvancedBlendEq(preCommonBlendState, postCommonBlendState, drawBuffers))
888 	{
889 		stream << "${GLSL_EXTENSION}"
890 			   <<  "layout(blend_support_all_equations) out;\n";
891 	}
892 
893 	stream << "in highp vec2 v_color;\n";
894 
895 	for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
896 	{
897 		const DrawBufferInfo&	drawBuffer			= drawBuffers[drawBufferNdx];
898 		const TextureFormat&	format				= drawBuffer.getFormat();
899 
900 		stream << "layout(location=" << drawBufferNdx << ") out highp ";
901 
902 		switch (tcu::getTextureChannelClass(format.type))
903 		{
904 			case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
905 			case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
906 			case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
907 				stream << "vec4";
908 				break;
909 
910 			case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
911 				stream << "uvec4";
912 				break;
913 
914 			case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
915 				stream << "ivec4";
916 				break;
917 
918 			default:
919 				DE_ASSERT(DE_FALSE);
920 		};
921 
922 		stream << " o_drawBuffer" <<  drawBufferNdx << ";\n";
923 	}
924 
925 	stream << "void main (void)\n"
926 		   << "{\n";
927 
928 	for (int drawBufferNdx = 0; drawBufferNdx < (int)drawBuffers.size(); drawBufferNdx++)
929 	{
930 		const DrawBufferInfo&	drawBuffer		= drawBuffers[drawBufferNdx];
931 		const TextureFormat&	format			= drawBuffer.getFormat();
932 		const char* const		values[]		=
933 		{
934 			"v_color.x",
935 			"v_color.y",
936 			"(1.0 - v_color.x)",
937 			"(1.0 - v_color.y)"
938 		};
939 
940 		stream << "\to_drawBuffer" <<  drawBufferNdx;
941 
942 		switch (tcu::getTextureChannelClass(format.type))
943 		{
944 			case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
945 			case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
946 			case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
947 				stream << " = vec4(" << values[(drawBufferNdx + 0) % 4]
948 					   << ", " << values[(drawBufferNdx + 1) % 4]
949 					   << ", " << values[(drawBufferNdx + 2) % 4]
950 					   << ", " << values[(drawBufferNdx + 3) % 4] << ");\n";
951 				break;
952 
953 			case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
954 				stream << " = uvec4(uint(" << values[(drawBufferNdx + 0) % 4]
955 					   << "), uint(" << values[(drawBufferNdx + 1) % 4]
956 					   << "), uint(" << values[(drawBufferNdx + 2) % 4]
957 					   << "), uint(" << values[(drawBufferNdx + 3) % 4] << "));\n";
958 				break;
959 
960 			case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
961 				stream << " = ivec4(int(" << values[(drawBufferNdx + 0) % 4]
962 					   << "), int(" << values[(drawBufferNdx + 1) % 4]
963 					   << "), int(" << values[(drawBufferNdx + 2) % 4]
964 					   << "), int(" << values[(drawBufferNdx + 3) % 4] << "));\n";
965 				break;
966 
967 			default:
968 				DE_ASSERT(DE_FALSE);
969 		};
970 	}
971 
972 	stream << "}";
973 
974 	map<string, string> args;
975 	args["GLSL_VERSION_DECL"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
976 	args["GLSL_EXTENSION"] = isES32 ? "\n" : "#extension GL_KHR_blend_equation_advanced : require\n";
977 
978 	return glu::FragmentSource(tcu::StringTemplate(stream.str()).specialize(args));
979 }
980 
genShaderSources(const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,glu::RenderContext & renderContext)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 
renderGLQuad(glu::RenderContext & renderContext,const glu::ShaderProgram & program)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 
renderQuad(TestLog & log,glu::RenderContext & renderContext,const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,const glu::Framebuffer & framebuffer,vector<TextureLevel> & refRenderbuffers)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 
logBlendState(TestLog & log,const BlendState & blend)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 
logTestCaseInfo(TestLog & log,const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers)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 
runTest(TestLog & log,tcu::ResultCollector & results,glu::RenderContext & renderContext,const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers)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 
DrawBuffersIndexedTest(Context & context,const BlendState & preCommonBlendState,const BlendState & postCommonBlendState,const vector<DrawBufferInfo> & drawBuffers,const string & name,const string & description)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 
init(void)1191 void DrawBuffersIndexedTest::init (void)
1192 {
1193 	const bool isES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1194 
1195 	if (!isES32)
1196 	{
1197 		if (requiresAdvancedBlendEq(m_preCommonBlendState, m_postCommonBlendState, m_drawBuffers) && !m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"))
1198 			TCU_THROW(NotSupportedError, "Extension GL_KHR_blend_equation_advanced not supported");
1199 
1200 		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1201 			TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1202 	}
1203 }
1204 
iterate(void)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 
getRandomBlendEq(de::Random & rng)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 
getRandomBlendFunc(de::Random & rng)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 
genRandomBlendState(de::Random & rng,BlendState & blendState)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 
getRandomFormat(de::Random & rng,Context & context)1300 TextureFormat getRandomFormat (de::Random& rng, Context& context)
1301 {
1302 	const bool isES32 = glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1303 
1304 	const deUint32 glFormats[] =
1305 	{
1306 		GL_R8,
1307 		GL_RG8,
1308 		GL_RGB8,
1309 		GL_RGB565,
1310 		GL_RGBA4,
1311 		GL_RGB5_A1,
1312 		GL_RGBA8,
1313 		GL_RGB10_A2,
1314 		GL_RGB10_A2UI,
1315 		GL_R8I,
1316 		GL_R8UI,
1317 		GL_R16I,
1318 		GL_R16UI,
1319 		GL_R32I,
1320 		GL_R32UI,
1321 		GL_RG8I,
1322 		GL_RG8UI,
1323 		GL_RG16I,
1324 		GL_RG16UI,
1325 		GL_RG32I,
1326 		GL_RG32UI,
1327 		GL_RGBA8I,
1328 		GL_RGBA8UI,
1329 		GL_RGBA16I,
1330 		GL_RGBA16UI,
1331 		GL_RGBA32I,
1332 		GL_RGBA32UI,
1333 		GL_RGBA16F,
1334 		GL_R32F,
1335 		GL_RG32F,
1336 		GL_RGBA32F,
1337 		GL_R11F_G11F_B10F
1338 	};
1339 
1340 	if (isES32)
1341 		return glu::mapGLInternalFormat(de::getArrayElement(glFormats, rng.getUint32() % DE_LENGTH_OF_ARRAY(glFormats)));
1342 	else
1343 	{
1344 		DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(glFormats) == 32);
1345 		return glu::mapGLInternalFormat(de::getArrayElement(glFormats, rng.getUint32() % (DE_LENGTH_OF_ARRAY(glFormats) - 5)));
1346 	}
1347 }
1348 
genRandomTest(de::Random & rng,BlendState & preCommon,BlendState & postCommon,vector<DrawBufferInfo> & drawBuffers,int maxDrawBufferCount,Context & context)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 
MaxDrawBuffersIndexedTest(Context & context,int seed)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 
init(void)1410 void MaxDrawBuffersIndexedTest::init (void)
1411 {
1412 	const bool isES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1413 
1414 	if (!isES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1415 		TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1416 }
1417 
iterate(void)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 
ImplMaxDrawBuffersIndexedTest(Context & context,int seed)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 
init(void)1454 void ImplMaxDrawBuffersIndexedTest::init (void)
1455 {
1456 	const bool isES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1457 
1458 	if (!isES32 && !m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"))
1459 		TCU_THROW(NotSupportedError, "Extension GL_EXT_draw_buffers_indexed not supported");
1460 }
1461 
iterate(void)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 
createDiffTest(Context & context,PrePost prepost,const char * name,const BlendState & commonState,const BlendState & drawBufferState)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 
createAdvancedEqDiffTest(Context & context,PrePost prepost,const char * name,const BlendState & commonState,const BlendState & drawBufferState)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 
addDrawBufferCommonTests(TestCaseGroup * root,PrePost prepost)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 
addRandomMaxTest(TestCaseGroup * root)1622 void addRandomMaxTest (TestCaseGroup* root)
1623 {
1624 	for (int i = 0; i < 20; i++)
1625 		root->addChild(new MaxDrawBuffersIndexedTest(root->getContext(), i));
1626 }
1627 
addRandomImplMaxTest(TestCaseGroup * root)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 
createDrawBuffersIndexedTests(Context & context)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