• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
47 namespace deqp
48 {
49 
50 using gls::FragmentOpUtil::IntegerQuad;
51 using gls::FragmentOpUtil::ReferenceQuadRenderer;
52 using tcu::TextureLevel;
53 using tcu::Vec2;
54 using tcu::Vec4;
55 using tcu::UVec4;
56 using tcu::TestLog;
57 using tcu::TextureFormat;
58 using std::string;
59 using std::vector;
60 using std::map;
61 
62 namespace gles31
63 {
64 namespace Functional
65 {
66 
67 namespace
68 {
69 
70 enum
71 {
72 	MAX_VIEWPORT_WIDTH		= 128,
73 	MAX_VIEWPORT_HEIGHT		= 128
74 };
75 
76 enum RenderTargetType
77 {
78 	RENDERTARGETTYPE_DEFAULT	= 0,	//!< Default framebuffer
79 	RENDERTARGETTYPE_SRGB_FBO,
80 	RENDERTARGETTYPE_MSAA_FBO,
81 
82 	RENDERTARGETTYPE_LAST
83 };
84 
85 class AdvancedBlendCase : public TestCase
86 {
87 public:
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 
97 private:
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 
AdvancedBlendCase(Context & context,const char * name,const char * desc,deUint32 mode,int overdrawCount,bool coherent,RenderTargetType rtType)126 AdvancedBlendCase::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 
getBlendLayoutQualifier(rr::BlendEquationAdvanced equation)154 const 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 
getBlendProgramSrc(rr::BlendEquationAdvanced equation)179 glu::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 
init(void)209 void 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 
~AdvancedBlendCase(void)285 AdvancedBlendCase::~AdvancedBlendCase (void)
286 {
287 	AdvancedBlendCase::deinit();
288 }
289 
deinit(void)290 void 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 
randomColor(de::Random * rnd)333 static 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 
getLinearAccess(const tcu::ConstPixelBufferAccess & access)346 static 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 
iterate(void)356 AdvancedBlendCase::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 
AdvancedBlendTests(Context & context)538 AdvancedBlendTests::AdvancedBlendTests (Context& context)
539 	: TestCaseGroup(context, "blend_equation_advanced", "GL_KHR_blend_equation_advanced Tests")
540 {
541 }
542 
~AdvancedBlendTests(void)543 AdvancedBlendTests::~AdvancedBlendTests (void)
544 {
545 }
546 
init(void)547 void 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