1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 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 Advanced blending (GL_KHR_blend_equation_advanced) tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fAdvancedBlendTests.hpp"
25#include "gluStrUtil.hpp"
26#include "glsFragmentOpUtil.hpp"
27#include "gluPixelTransfer.hpp"
28#include "gluObjectWrapper.hpp"
29#include "gluContextInfo.hpp"
30#include "gluShaderProgram.hpp"
31#include "tcuPixelFormat.hpp"
32#include "tcuTexture.hpp"
33#include "tcuTextureUtil.hpp"
34#include "tcuImageCompare.hpp"
35#include "tcuRenderTarget.hpp"
36#include "tcuTestLog.hpp"
37#include "tcuStringTemplate.hpp"
38#include "deRandom.hpp"
39#include "rrFragmentOperations.hpp"
40#include "sglrReferenceUtils.hpp"
41#include "glwEnums.hpp"
42#include "glwFunctions.hpp"
43
44#include <string>
45#include <vector>
46
47namespace deqp
48{
49
50using gls::FragmentOpUtil::IntegerQuad;
51using gls::FragmentOpUtil::ReferenceQuadRenderer;
52using tcu::TextureLevel;
53using tcu::Vec2;
54using tcu::Vec4;
55using tcu::UVec4;
56using tcu::TestLog;
57using tcu::TextureFormat;
58using std::string;
59using std::vector;
60using std::map;
61
62namespace gles31
63{
64namespace Functional
65{
66
67namespace
68{
69
70enum
71{
72	MAX_VIEWPORT_WIDTH		= 128,
73	MAX_VIEWPORT_HEIGHT		= 128
74};
75
76enum RenderTargetType
77{
78	RENDERTARGETTYPE_DEFAULT	= 0,	//!< Default framebuffer
79	RENDERTARGETTYPE_SRGB_FBO,
80	RENDERTARGETTYPE_MSAA_FBO,
81
82	RENDERTARGETTYPE_LAST
83};
84
85class AdvancedBlendCase : public TestCase
86{
87public:
88							AdvancedBlendCase	(Context& context, const char* name, const char* desc, deUint32 mode, int overdrawCount, bool coherent, RenderTargetType rtType);
89
90							~AdvancedBlendCase	(void);
91
92	void					init				(void);
93	void					deinit				(void);
94
95	IterateResult			iterate		(void);
96
97private:
98							AdvancedBlendCase	(const AdvancedBlendCase&);
99	AdvancedBlendCase&		operator=			(const AdvancedBlendCase&);
100
101	const deUint32			m_blendMode;
102	const int				m_overdrawCount;
103	const bool				m_coherentBlending;
104	const RenderTargetType	m_rtType;
105	const int				m_numIters;
106
107	deUint32				m_colorRbo;
108	deUint32				m_fbo;
109
110	deUint32				m_resolveColorRbo;
111	deUint32				m_resolveFbo;
112
113	glu::ShaderProgram*		m_program;
114
115	ReferenceQuadRenderer*	m_referenceRenderer;
116	TextureLevel*			m_refColorBuffer;
117
118	const int				m_renderWidth;
119	const int				m_renderHeight;
120	const int				m_viewportWidth;
121	const int				m_viewportHeight;
122
123	int						m_iterNdx;
124};
125
126AdvancedBlendCase::AdvancedBlendCase (Context&			context,
127									  const char*		name,
128									  const char*		desc,
129									  deUint32			mode,
130									  int				overdrawCount,
131									  bool				coherent,
132									  RenderTargetType	rtType)
133	: TestCase				(context, name, desc)
134	, m_blendMode			(mode)
135	, m_overdrawCount		(overdrawCount)
136	, m_coherentBlending	(coherent)
137	, m_rtType				(rtType)
138	, m_numIters			(5)
139	, m_colorRbo			(0)
140	, m_fbo					(0)
141	, m_resolveColorRbo		(0)
142	, m_resolveFbo			(0)
143	, m_program				(DE_NULL)
144	, m_referenceRenderer	(DE_NULL)
145	, m_refColorBuffer		(DE_NULL)
146	, m_renderWidth			(rtType != RENDERTARGETTYPE_DEFAULT ? 2*MAX_VIEWPORT_WIDTH	: m_context.getRenderTarget().getWidth())
147	, m_renderHeight		(rtType != RENDERTARGETTYPE_DEFAULT ? 2*MAX_VIEWPORT_HEIGHT	: m_context.getRenderTarget().getHeight())
148	, m_viewportWidth		(de::min<int>(m_renderWidth,	MAX_VIEWPORT_WIDTH))
149	, m_viewportHeight		(de::min<int>(m_renderHeight,	MAX_VIEWPORT_HEIGHT))
150	, m_iterNdx				(0)
151{
152}
153
154const char* getBlendLayoutQualifier (rr::BlendEquationAdvanced equation)
155{
156	static const char* s_qualifiers[] =
157	{
158		"blend_support_multiply",
159		"blend_support_screen",
160		"blend_support_overlay",
161		"blend_support_darken",
162		"blend_support_lighten",
163		"blend_support_colordodge",
164		"blend_support_colorburn",
165		"blend_support_hardlight",
166		"blend_support_softlight",
167		"blend_support_difference",
168		"blend_support_exclusion",
169		"blend_support_hsl_hue",
170		"blend_support_hsl_saturation",
171		"blend_support_hsl_color",
172		"blend_support_hsl_luminosity",
173	};
174	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qualifiers) == rr::BLENDEQUATION_ADVANCED_LAST);
175	DE_ASSERT(de::inBounds<int>(equation, 0, rr::BLENDEQUATION_ADVANCED_LAST));
176	return s_qualifiers[equation];
177}
178
179glu::ProgramSources getBlendProgramSrc (rr::BlendEquationAdvanced equation)
180{
181	static const char*	s_vertSrc	= "#version 310 es\n"
182									  "in highp vec4 a_position;\n"
183									  "in mediump vec4 a_color;\n"
184									  "out mediump vec4 v_color;\n"
185									  "void main()\n"
186									  "{\n"
187									  "	gl_Position = a_position;\n"
188									  "	v_color = a_color;\n"
189									  "}\n";
190	static const char*	s_fragSrc	= "#version 310 es\n"
191									  "#extension GL_KHR_blend_equation_advanced : require\n"
192									  "in mediump vec4 v_color;\n"
193									  "layout(${SUPPORT_QUALIFIER}) out;\n"
194									  "layout(location = 0) out mediump vec4 o_color;\n"
195									  "void main()\n"
196									  "{\n"
197									  "	o_color = v_color;\n"
198									  "}\n";
199
200	map<string, string> args;
201
202	args["SUPPORT_QUALIFIER"] = getBlendLayoutQualifier(equation);
203
204	return glu::ProgramSources()
205		<< glu::VertexSource(s_vertSrc)
206		<< glu::FragmentSource(tcu::StringTemplate(s_fragSrc).specialize(args));
207}
208
209void AdvancedBlendCase::init (void)
210{
211	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
212	const bool				useFbo			= m_rtType != RENDERTARGETTYPE_DEFAULT;
213	const bool				useSRGB			= m_rtType == RENDERTARGETTYPE_SRGB_FBO;
214
215	if (!m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"))
216		throw tcu::NotSupportedError("GL_KHR_blend_equation_advanced is not supported", DE_NULL, __FILE__, __LINE__);
217
218	if (m_coherentBlending && !m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced_coherent"))
219		throw tcu::NotSupportedError("GL_KHR_blend_equation_advanced_coherent is not supported", DE_NULL, __FILE__, __LINE__);
220
221	TCU_CHECK(gl.blendBarrierKHR);
222
223	DE_ASSERT(!m_program);
224	DE_ASSERT(!m_referenceRenderer);
225	DE_ASSERT(!m_refColorBuffer);
226
227	m_program = new glu::ShaderProgram(m_context.getRenderContext(), getBlendProgramSrc(sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode)));
228	m_testCtx.getLog() << *m_program;
229
230	if (!m_program->isOk())
231	{
232		delete m_program;
233		m_program = DE_NULL;
234		TCU_FAIL("Compile failed");
235	}
236
237	m_referenceRenderer	= new ReferenceQuadRenderer;
238	m_refColorBuffer	= new TextureLevel(TextureFormat(useSRGB ? TextureFormat::sRGBA : TextureFormat::RGBA, TextureFormat::UNORM_INT8), m_viewportWidth, m_viewportHeight);
239
240	if (useFbo)
241	{
242		const deUint32	format		= useSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
243		const int		numSamples	= m_rtType == RENDERTARGETTYPE_MSAA_FBO ? 4 : 0;
244
245		m_testCtx.getLog() << TestLog::Message << "Using FBO of size (" << m_renderWidth << ", " << m_renderHeight << ") with format "
246											   << glu::getPixelFormatStr(format) << " and " << numSamples << " samples"
247						   << TestLog::EndMessage;
248
249		gl.genRenderbuffers(1, &m_colorRbo);
250		gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorRbo);
251		gl.renderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, format, m_renderWidth, m_renderHeight);
252		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create color RBO");
253
254		gl.genFramebuffers(1, &m_fbo);
255		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
256		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorRbo);
257		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO");
258
259		TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
260
261		if (numSamples > 0)
262		{
263			// Create resolve FBO
264			gl.genRenderbuffers(1, &m_resolveColorRbo);
265			gl.bindRenderbuffer(GL_RENDERBUFFER, m_resolveColorRbo);
266			gl.renderbufferStorageMultisample(GL_RENDERBUFFER, 0, format, m_renderWidth, m_renderHeight);
267			GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create resolve color RBO");
268
269			gl.genFramebuffers(1, &m_resolveFbo);
270			gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
271			gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_resolveColorRbo);
272			GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO");
273
274			TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
275
276			gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
277		}
278	}
279	else
280		DE_ASSERT(m_rtType == RENDERTARGETTYPE_DEFAULT);
281
282	m_iterNdx = 0;
283}
284
285AdvancedBlendCase::~AdvancedBlendCase (void)
286{
287	AdvancedBlendCase::deinit();
288}
289
290void AdvancedBlendCase::deinit (void)
291{
292	delete m_program;
293	delete m_referenceRenderer;
294	delete m_refColorBuffer;
295
296	m_program			= DE_NULL;
297	m_referenceRenderer	= DE_NULL;
298	m_refColorBuffer	= DE_NULL;
299
300	if (m_colorRbo || m_fbo)
301	{
302		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
303
304		gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
305		gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
306
307		if (m_colorRbo != 0)
308		{
309			gl.deleteRenderbuffers(1, &m_colorRbo);
310			m_colorRbo = 0;
311		}
312
313		if (m_fbo != 0)
314		{
315			gl.deleteFramebuffers(1, &m_fbo);
316			m_fbo = 0;
317		}
318
319		if (m_resolveColorRbo)
320		{
321			gl.deleteRenderbuffers(1, &m_resolveColorRbo);
322			m_resolveColorRbo = 0;
323		}
324
325		if (m_resolveFbo)
326		{
327			gl.deleteRenderbuffers(1, &m_resolveFbo);
328			m_resolveFbo = 0;
329		}
330	}
331}
332
333static tcu::Vec4 randomColor (de::Random* rnd)
334{
335	const float rgbValues[]		= { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f };
336	const float alphaValues[]	= { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f };
337
338	// \note Spec assumes premultiplied inputs.
339	const float a = rnd->choose<float>(DE_ARRAY_BEGIN(alphaValues), DE_ARRAY_END(alphaValues));
340	const float r = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues));
341	const float g = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues));
342	const float b = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues));
343	return tcu::Vec4(r, g, b, a);
344}
345
346static tcu::ConstPixelBufferAccess getLinearAccess (const tcu::ConstPixelBufferAccess& access)
347{
348	if (access.getFormat().order == TextureFormat::sRGBA)
349		return tcu::ConstPixelBufferAccess(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8),
350										   access.getWidth(), access.getHeight(), access.getDepth(),
351										   access.getRowPitch(), access.getSlicePitch(), access.getDataPtr());
352	else
353		return access;
354}
355
356AdvancedBlendCase::IterateResult AdvancedBlendCase::iterate (void)
357{
358	const glu::RenderContext&		renderCtx		= m_context.getRenderContext();
359	const glw::Functions&			gl				= renderCtx.getFunctions();
360	de::Random						rnd				(deStringHash(getName()) ^ deInt32Hash(m_iterNdx));
361	const int						viewportX		= rnd.getInt(0, m_renderWidth - m_viewportWidth);
362	const int						viewportY		= rnd.getInt(0, m_renderHeight - m_viewportHeight);
363	const bool						useFbo			= m_rtType != RENDERTARGETTYPE_DEFAULT;
364	const bool						requiresResolve	= m_rtType == RENDERTARGETTYPE_MSAA_FBO;
365	const int						numQuads		= m_overdrawCount+1;
366	TextureLevel					renderedImg		(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), m_viewportWidth, m_viewportHeight);
367	vector<Vec4>					colors			(numQuads*4);
368
369	for (vector<Vec4>::iterator col = colors.begin(); col != colors.end(); ++col)
370		*col = randomColor(&rnd);
371
372	// Render with GL.
373	{
374		const deUint32		program				= m_program->getProgram();
375		const int			posLoc				= gl.getAttribLocation(program, "a_position");
376		const int			colorLoc			= gl.getAttribLocation(program, "a_color");
377		const glu::Buffer	indexBuffer			(renderCtx);
378		const glu::Buffer	positionBuffer		(renderCtx);
379		const glu::Buffer	colorBuffer			(renderCtx);
380		vector<Vec2>		positions			(numQuads*4);
381		vector<deUint16>	indices				(numQuads*6);
382		const deUint16		singleQuadIndices[]	= { 0, 2, 1, 1, 2, 3 };
383		const Vec2			singleQuadPos[]		=
384		{
385			Vec2(-1.0f, -1.0f),
386			Vec2(-1.0f, +1.0f),
387			Vec2(+1.0f, -1.0f),
388			Vec2(+1.0f, +1.0f),
389		};
390
391		TCU_CHECK(posLoc >= 0 && colorLoc >= 0);
392
393		for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
394		{
395			std::copy(DE_ARRAY_BEGIN(singleQuadPos), DE_ARRAY_END(singleQuadPos), &positions[quadNdx*4]);
396			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(singleQuadIndices); ndx++)
397				indices[quadNdx*6 + ndx] = (deUint16)(quadNdx*4 + singleQuadIndices[ndx]);
398		}
399
400		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
401		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size()*sizeof(indices[0])), &indices[0], GL_STATIC_DRAW);
402
403		gl.bindBuffer(GL_ARRAY_BUFFER, *positionBuffer);
404		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(positions.size()*sizeof(positions[0])), &positions[0], GL_STATIC_DRAW);
405		gl.enableVertexAttribArray(posLoc);
406		gl.vertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL);
407
408		gl.bindBuffer(GL_ARRAY_BUFFER, *colorBuffer);
409		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(colors.size()*sizeof(colors[0])), &colors[0], GL_STATIC_DRAW);
410		gl.enableVertexAttribArray(colorLoc);
411		gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
412		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create buffers");
413
414		gl.useProgram(program);
415		gl.viewport(viewportX, viewportY, m_viewportWidth, m_viewportHeight);
416		gl.blendEquation(m_blendMode);
417		if (m_coherentBlending)
418			gl.enable(GL_BLEND_ADVANCED_COHERENT_KHR);
419
420		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set render state");
421
422		gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
423
424		gl.disable(GL_BLEND);
425		gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL);
426		gl.enable(GL_BLEND);
427
428		if (!m_coherentBlending)
429			gl.blendBarrierKHR();
430
431		if (m_coherentBlending)
432		{
433			gl.drawElements(GL_TRIANGLES, 6*(numQuads-1), GL_UNSIGNED_SHORT, (const void*)(deUintptr)(6*sizeof(deUint16)));
434		}
435		else
436		{
437			for (int quadNdx = 1; quadNdx < numQuads; quadNdx++)
438			{
439				gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void*)(deUintptr)(quadNdx*6*sizeof(deUint16)));
440				gl.blendBarrierKHR();
441			}
442		}
443
444		gl.flush();
445		GLU_EXPECT_NO_ERROR(gl.getError(), "Render failed");
446	}
447
448	// Render reference.
449	{
450		rr::FragmentOperationState		referenceState;
451		const tcu::PixelBufferAccess	colorAccess		= gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess());
452		const tcu::PixelBufferAccess	nullAccess		(TextureFormat(), 0, 0, 0, DE_NULL);
453		IntegerQuad						quad;
454
455		if (!useFbo && m_context.getRenderTarget().getPixelFormat().alphaBits == 0)
456		{
457			// Emulate lack of alpha by clearing to 1 and masking out alpha writes
458			tcu::clear(*m_refColorBuffer, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
459			referenceState.colorMask = tcu::BVec4(true, true, true, false);
460		}
461
462		referenceState.blendEquationAdvaced	= sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode);
463
464		quad.posA = tcu::IVec2(0, 0);
465		quad.posB = tcu::IVec2(m_viewportWidth-1, m_viewportHeight-1);
466
467		for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
468		{
469			referenceState.blendMode = quadNdx == 0 ? rr::BLENDMODE_NONE : rr::BLENDMODE_ADVANCED;
470			std::copy(&colors[4*quadNdx], &colors[4*quadNdx] + 4, &quad.color[0]);
471			m_referenceRenderer->render(colorAccess, nullAccess /* no depth */, nullAccess /* no stencil */, quad, referenceState);
472		}
473	}
474
475	if (requiresResolve)
476	{
477		gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFbo);
478		gl.blitFramebuffer(0, 0, m_renderWidth, m_renderHeight, 0, 0, m_renderWidth, m_renderHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
479		GLU_EXPECT_NO_ERROR(gl.getError(), "Resolve blit failed");
480
481		gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_resolveFbo);
482	}
483
484	glu::readPixels(renderCtx, viewportX, viewportY, renderedImg.getAccess());
485	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels()");
486
487	if (requiresResolve)
488		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
489
490	{
491		const bool	isHSLMode	= m_blendMode == GL_HSL_HUE_KHR			||
492								  m_blendMode == GL_HSL_SATURATION_KHR	||
493								  m_blendMode == GL_HSL_COLOR_KHR		||
494								  m_blendMode == GL_HSL_LUMINOSITY_KHR;
495		bool		comparePass	= false;
496
497		if (isHSLMode)
498		{
499			// Compensate for more demanding HSL code by using fuzzy comparison.
500			const float threshold = 0.002f;
501			comparePass = tcu::fuzzyCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result",
502											getLinearAccess(m_refColorBuffer->getAccess()),
503											renderedImg.getAccess(),
504											threshold, tcu::COMPARE_LOG_RESULT);
505		}
506		else
507		{
508		const UVec4 compareThreshold = (useFbo ? tcu::PixelFormat(8, 8, 8, 8) : m_context.getRenderTarget().getPixelFormat()).getColorThreshold().toIVec().asUint()
509									 * UVec4(5) / UVec4(2) + UVec4(3 * m_overdrawCount);
510
511			comparePass = tcu::bilinearCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result",
512											  getLinearAccess(m_refColorBuffer->getAccess()),
513											  renderedImg.getAccess(),
514											  tcu::RGBA(compareThreshold[0], compareThreshold[1], compareThreshold[2], compareThreshold[3]),
515											  tcu::COMPARE_LOG_RESULT);
516		}
517
518		if (!comparePass)
519		{
520			m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
521			return STOP;
522		}
523	}
524
525	m_iterNdx += 1;
526
527	if (m_iterNdx < m_numIters)
528		return CONTINUE;
529	else
530	{
531		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
532		return STOP;
533	}
534}
535
536} // anonymous
537
538AdvancedBlendTests::AdvancedBlendTests (Context& context)
539	: TestCaseGroup(context, "blend_equation_advanced", "GL_KHR_blend_equation_advanced Tests")
540{
541}
542
543AdvancedBlendTests::~AdvancedBlendTests (void)
544{
545}
546
547void AdvancedBlendTests::init (void)
548{
549	static const struct
550	{
551		deUint32	mode;
552		const char*	name;
553	} s_blendModes[] =
554	{
555		{ GL_MULTIPLY_KHR,			"multiply"			},
556		{ GL_SCREEN_KHR,			"screen"			},
557		{ GL_OVERLAY_KHR,			"overlay"			},
558		{ GL_DARKEN_KHR,			"darken"			},
559		{ GL_LIGHTEN_KHR,			"lighten"			},
560		{ GL_COLORDODGE_KHR,		"colordodge"		},
561		{ GL_COLORBURN_KHR,			"colorburn"			},
562		{ GL_HARDLIGHT_KHR,			"hardlight"			},
563		{ GL_SOFTLIGHT_KHR,			"softlight"			},
564		{ GL_DIFFERENCE_KHR,		"difference"		},
565		{ GL_EXCLUSION_KHR,			"exclusion"			},
566		{ GL_HSL_HUE_KHR,			"hsl_hue"			},
567		{ GL_HSL_SATURATION_KHR,	"hsl_saturation"	},
568		{ GL_HSL_COLOR_KHR,			"hsl_color"			},
569		{ GL_HSL_LUMINOSITY_KHR,	"hsl_luminosity"	}
570	};
571
572	tcu::TestCaseGroup* const	basicGroup			= new tcu::TestCaseGroup(m_testCtx, "basic",			"Single quad only");
573	tcu::TestCaseGroup* const	srgbGroup			= new tcu::TestCaseGroup(m_testCtx, "srgb",				"Advanced blending with sRGB FBO");
574	tcu::TestCaseGroup* const	msaaGroup			= new tcu::TestCaseGroup(m_testCtx, "msaa",				"Advanced blending with MSAA FBO");
575	tcu::TestCaseGroup* const	barrierGroup		= new tcu::TestCaseGroup(m_testCtx, "barrier",			"Multiple overlapping quads with blend barriers");
576	tcu::TestCaseGroup* const	coherentGroup		= new tcu::TestCaseGroup(m_testCtx, "coherent",			"Overlapping quads with coherent blending");
577	tcu::TestCaseGroup* const	coherentMsaaGroup	= new tcu::TestCaseGroup(m_testCtx, "coherent_msaa",	"Overlapping quads with coherent blending with MSAA FBO");
578
579	addChild(basicGroup);
580	addChild(srgbGroup);
581	addChild(msaaGroup);
582	addChild(barrierGroup);
583	addChild(coherentGroup);
584	addChild(coherentMsaaGroup);
585
586	for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(s_blendModes); modeNdx++)
587	{
588		const char* const		name		= s_blendModes[modeNdx].name;
589		const char* const		desc		= "";
590		const deUint32			mode		= s_blendModes[modeNdx].mode;
591
592		basicGroup->addChild		(new AdvancedBlendCase(m_context, name, desc, mode, 1, false,	RENDERTARGETTYPE_DEFAULT));
593		srgbGroup->addChild			(new AdvancedBlendCase(m_context, name, desc, mode, 1, false,	RENDERTARGETTYPE_SRGB_FBO));
594		msaaGroup->addChild			(new AdvancedBlendCase(m_context, name, desc, mode, 1, false,	RENDERTARGETTYPE_MSAA_FBO));
595		barrierGroup->addChild		(new AdvancedBlendCase(m_context, name, desc, mode, 4, false,	RENDERTARGETTYPE_DEFAULT));
596		coherentGroup->addChild		(new AdvancedBlendCase(m_context, name, desc, mode, 4, true,	RENDERTARGETTYPE_DEFAULT));
597		coherentMsaaGroup->addChild	(new AdvancedBlendCase(m_context, name, desc, mode, 4, true,	RENDERTARGETTYPE_MSAA_FBO));
598	}
599}
600
601} // Functional
602} // gles31
603} // deqp
604