Home | History | Annotate | Download | only in functional
      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 
    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 
    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 
    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 
    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 
    285 AdvancedBlendCase::~AdvancedBlendCase (void)
    286 {
    287 	AdvancedBlendCase::deinit();
    288 }
    289 
    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 
    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 
    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 
    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 
    538 AdvancedBlendTests::AdvancedBlendTests (Context& context)
    539 	: TestCaseGroup(context, "blend_equation_advanced", "GL_KHR_blend_equation_advanced Tests")
    540 {
    541 }
    542 
    543 AdvancedBlendTests::~AdvancedBlendTests (void)
    544 {
    545 }
    546 
    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