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 "glsStateQueryUtil.hpp"
     28 #include "gluPixelTransfer.hpp"
     29 #include "gluObjectWrapper.hpp"
     30 #include "gluContextInfo.hpp"
     31 #include "gluShaderProgram.hpp"
     32 #include "gluCallLogWrapper.hpp"
     33 #include "gluStrUtil.hpp"
     34 #include "tcuPixelFormat.hpp"
     35 #include "tcuTexture.hpp"
     36 #include "tcuTextureUtil.hpp"
     37 #include "tcuImageCompare.hpp"
     38 #include "tcuRenderTarget.hpp"
     39 #include "tcuTestLog.hpp"
     40 #include "tcuStringTemplate.hpp"
     41 #include "deRandom.hpp"
     42 #include "deStringUtil.hpp"
     43 #include "rrFragmentOperations.hpp"
     44 #include "sglrReferenceUtils.hpp"
     45 #include "glwEnums.hpp"
     46 #include "glwFunctions.hpp"
     47 
     48 #include <string>
     49 #include <vector>
     50 
     51 namespace deqp
     52 {
     53 
     54 using gls::FragmentOpUtil::IntegerQuad;
     55 using gls::FragmentOpUtil::ReferenceQuadRenderer;
     56 using tcu::TextureLevel;
     57 using tcu::Vec2;
     58 using tcu::Vec4;
     59 using tcu::UVec4;
     60 using tcu::TestLog;
     61 using tcu::TextureFormat;
     62 using std::string;
     63 using std::vector;
     64 using std::map;
     65 
     66 namespace gles31
     67 {
     68 namespace Functional
     69 {
     70 
     71 namespace
     72 {
     73 
     74 enum
     75 {
     76 	MAX_VIEWPORT_WIDTH		= 128,
     77 	MAX_VIEWPORT_HEIGHT		= 128
     78 };
     79 
     80 enum RenderTargetType
     81 {
     82 	RENDERTARGETTYPE_DEFAULT	= 0,	//!< Default framebuffer
     83 	RENDERTARGETTYPE_SRGB_FBO,
     84 	RENDERTARGETTYPE_MSAA_FBO,
     85 
     86 	RENDERTARGETTYPE_LAST
     87 };
     88 
     89 static const char* getEquationName (glw::GLenum equation)
     90 {
     91 	switch (equation)
     92 	{
     93 		case GL_MULTIPLY:		return "multiply";
     94 		case GL_SCREEN:			return "screen";
     95 		case GL_OVERLAY:		return "overlay";
     96 		case GL_DARKEN:			return "darken";
     97 		case GL_LIGHTEN:		return "lighten";
     98 		case GL_COLORDODGE:		return "colordodge";
     99 		case GL_COLORBURN:		return "colorburn";
    100 		case GL_HARDLIGHT:		return "hardlight";
    101 		case GL_SOFTLIGHT:		return "softlight";
    102 		case GL_DIFFERENCE:		return "difference";
    103 		case GL_EXCLUSION:		return "exclusion";
    104 		case GL_HSL_HUE:		return "hsl_hue";
    105 		case GL_HSL_SATURATION:	return "hsl_saturation";
    106 		case GL_HSL_COLOR:		return "hsl_color";
    107 		case GL_HSL_LUMINOSITY:	return "hsl_luminosity";
    108 		default:
    109 			DE_ASSERT(false);
    110 			return DE_NULL;
    111 	}
    112 }
    113 
    114 class AdvancedBlendCase : public TestCase
    115 {
    116 public:
    117 							AdvancedBlendCase	(Context& context, const char* name, const char* desc, deUint32 mode, int overdrawCount, bool coherent, RenderTargetType rtType);
    118 
    119 							~AdvancedBlendCase	(void);
    120 
    121 	void					init				(void);
    122 	void					deinit				(void);
    123 
    124 	IterateResult			iterate		(void);
    125 
    126 private:
    127 							AdvancedBlendCase	(const AdvancedBlendCase&);
    128 	AdvancedBlendCase&		operator=			(const AdvancedBlendCase&);
    129 
    130 	const deUint32			m_blendMode;
    131 	const int				m_overdrawCount;
    132 	const bool				m_coherentBlending;
    133 	const RenderTargetType	m_rtType;
    134 	const int				m_numIters;
    135 
    136 	bool					m_coherentExtensionSupported;
    137 
    138 	deUint32				m_colorRbo;
    139 	deUint32				m_fbo;
    140 
    141 	deUint32				m_resolveColorRbo;
    142 	deUint32				m_resolveFbo;
    143 
    144 	glu::ShaderProgram*		m_program;
    145 
    146 	ReferenceQuadRenderer*	m_referenceRenderer;
    147 	TextureLevel*			m_refColorBuffer;
    148 
    149 	const int				m_renderWidth;
    150 	const int				m_renderHeight;
    151 	const int				m_viewportWidth;
    152 	const int				m_viewportHeight;
    153 
    154 	int						m_iterNdx;
    155 };
    156 
    157 AdvancedBlendCase::AdvancedBlendCase (Context&			context,
    158 									  const char*		name,
    159 									  const char*		desc,
    160 									  deUint32			mode,
    161 									  int				overdrawCount,
    162 									  bool				coherent,
    163 									  RenderTargetType	rtType)
    164 	: TestCase				(context, name, desc)
    165 	, m_blendMode			(mode)
    166 	, m_overdrawCount		(overdrawCount)
    167 	, m_coherentBlending	(coherent)
    168 	, m_rtType				(rtType)
    169 	, m_numIters			(5)
    170 	, m_colorRbo			(0)
    171 	, m_fbo					(0)
    172 	, m_resolveColorRbo		(0)
    173 	, m_resolveFbo			(0)
    174 	, m_program				(DE_NULL)
    175 	, m_referenceRenderer	(DE_NULL)
    176 	, m_refColorBuffer		(DE_NULL)
    177 	, m_renderWidth			(rtType != RENDERTARGETTYPE_DEFAULT ? 2*MAX_VIEWPORT_WIDTH	: m_context.getRenderTarget().getWidth())
    178 	, m_renderHeight		(rtType != RENDERTARGETTYPE_DEFAULT ? 2*MAX_VIEWPORT_HEIGHT	: m_context.getRenderTarget().getHeight())
    179 	, m_viewportWidth		(de::min<int>(m_renderWidth,	MAX_VIEWPORT_WIDTH))
    180 	, m_viewportHeight		(de::min<int>(m_renderHeight,	MAX_VIEWPORT_HEIGHT))
    181 	, m_iterNdx				(0)
    182 {
    183 }
    184 
    185 const char* getBlendLayoutQualifier (rr::BlendEquationAdvanced equation)
    186 {
    187 	static const char* s_qualifiers[] =
    188 	{
    189 		"blend_support_multiply",
    190 		"blend_support_screen",
    191 		"blend_support_overlay",
    192 		"blend_support_darken",
    193 		"blend_support_lighten",
    194 		"blend_support_colordodge",
    195 		"blend_support_colorburn",
    196 		"blend_support_hardlight",
    197 		"blend_support_softlight",
    198 		"blend_support_difference",
    199 		"blend_support_exclusion",
    200 		"blend_support_hsl_hue",
    201 		"blend_support_hsl_saturation",
    202 		"blend_support_hsl_color",
    203 		"blend_support_hsl_luminosity",
    204 	};
    205 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qualifiers) == rr::BLENDEQUATION_ADVANCED_LAST);
    206 	DE_ASSERT(de::inBounds<int>(equation, 0, rr::BLENDEQUATION_ADVANCED_LAST));
    207 	return s_qualifiers[equation];
    208 }
    209 
    210 glu::ProgramSources getBlendProgramSrc (rr::BlendEquationAdvanced equation, glu::RenderContext& renderContext)
    211 {
    212 	const bool supportsES32 = glu::contextSupports(renderContext.getType(), glu::ApiType::es(3, 2));
    213 
    214 	static const char*	s_vertSrc	= "${GLSL_VERSION_DECL}\n"
    215 									  "in highp vec4 a_position;\n"
    216 									  "in mediump vec4 a_color;\n"
    217 									  "out mediump vec4 v_color;\n"
    218 									  "void main()\n"
    219 									  "{\n"
    220 									  "	gl_Position = a_position;\n"
    221 									  "	v_color = a_color;\n"
    222 									  "}\n";
    223 	static const char*	s_fragSrc	= "${GLSL_VERSION_DECL}\n"
    224 									  "${EXTENSION}"
    225 									  "in mediump vec4 v_color;\n"
    226 									  "layout(${SUPPORT_QUALIFIER}) out;\n"
    227 									  "layout(location = 0) out mediump vec4 o_color;\n"
    228 									  "void main()\n"
    229 									  "{\n"
    230 									  "	o_color = v_color;\n"
    231 									  "}\n";
    232 
    233 	map<string, string> args;
    234 	args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
    235 	args["EXTENSION"] = supportsES32 ? "\n" : "#extension GL_KHR_blend_equation_advanced : require\n";
    236 	args["SUPPORT_QUALIFIER"] = getBlendLayoutQualifier(equation);
    237 
    238 	return glu::ProgramSources()
    239 		<< glu::VertexSource(tcu::StringTemplate(s_vertSrc).specialize(args))
    240 		<< glu::FragmentSource(tcu::StringTemplate(s_fragSrc).specialize(args));
    241 }
    242 
    243 void AdvancedBlendCase::init (void)
    244 {
    245 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
    246 	const bool				useFbo			= m_rtType != RENDERTARGETTYPE_DEFAULT;
    247 	const bool				useSRGB			= m_rtType == RENDERTARGETTYPE_SRGB_FBO;
    248 
    249 	m_coherentExtensionSupported = m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced_coherent");
    250 
    251 	if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
    252 		if (!m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"))
    253 			TCU_THROW(NotSupportedError, "GL_KHR_blend_equation_advanced is not supported");
    254 
    255 	if (m_coherentBlending && !m_coherentExtensionSupported)
    256 		TCU_THROW(NotSupportedError, "GL_KHR_blend_equation_advanced_coherent is not supported");
    257 
    258 	TCU_CHECK(gl.blendBarrier);
    259 
    260 	DE_ASSERT(!m_program);
    261 	DE_ASSERT(!m_referenceRenderer);
    262 	DE_ASSERT(!m_refColorBuffer);
    263 
    264 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), getBlendProgramSrc(sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode), m_context.getRenderContext()));
    265 	m_testCtx.getLog() << *m_program;
    266 
    267 	if (!m_program->isOk())
    268 	{
    269 		delete m_program;
    270 		m_program = DE_NULL;
    271 		TCU_FAIL("Compile failed");
    272 	}
    273 
    274 	m_referenceRenderer	= new ReferenceQuadRenderer;
    275 	m_refColorBuffer	= new TextureLevel(TextureFormat(useSRGB ? TextureFormat::sRGBA : TextureFormat::RGBA, TextureFormat::UNORM_INT8), m_viewportWidth, m_viewportHeight);
    276 
    277 	if (useFbo)
    278 	{
    279 		const deUint32	format		= useSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
    280 		const int		numSamples	= m_rtType == RENDERTARGETTYPE_MSAA_FBO ? 4 : 0;
    281 
    282 		m_testCtx.getLog() << TestLog::Message << "Using FBO of size (" << m_renderWidth << ", " << m_renderHeight << ") with format "
    283 											   << glu::getTextureFormatStr(format) << " and " << numSamples << " samples"
    284 						   << TestLog::EndMessage;
    285 
    286 		gl.genRenderbuffers(1, &m_colorRbo);
    287 		gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorRbo);
    288 		gl.renderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, format, m_renderWidth, m_renderHeight);
    289 		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create color RBO");
    290 
    291 		gl.genFramebuffers(1, &m_fbo);
    292 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    293 		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorRbo);
    294 		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO");
    295 
    296 		TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    297 
    298 		if (numSamples > 0)
    299 		{
    300 			// Create resolve FBO
    301 			gl.genRenderbuffers(1, &m_resolveColorRbo);
    302 			gl.bindRenderbuffer(GL_RENDERBUFFER, m_resolveColorRbo);
    303 			gl.renderbufferStorageMultisample(GL_RENDERBUFFER, 0, format, m_renderWidth, m_renderHeight);
    304 			GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create resolve color RBO");
    305 
    306 			gl.genFramebuffers(1, &m_resolveFbo);
    307 			gl.bindFramebuffer(GL_FRAMEBUFFER, m_resolveFbo);
    308 			gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_resolveColorRbo);
    309 			GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create FBO");
    310 
    311 			TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
    312 
    313 			gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    314 		}
    315 	}
    316 	else
    317 		DE_ASSERT(m_rtType == RENDERTARGETTYPE_DEFAULT);
    318 
    319 	m_iterNdx = 0;
    320 }
    321 
    322 AdvancedBlendCase::~AdvancedBlendCase (void)
    323 {
    324 	AdvancedBlendCase::deinit();
    325 }
    326 
    327 void AdvancedBlendCase::deinit (void)
    328 {
    329 	delete m_program;
    330 	delete m_referenceRenderer;
    331 	delete m_refColorBuffer;
    332 
    333 	m_program			= DE_NULL;
    334 	m_referenceRenderer	= DE_NULL;
    335 	m_refColorBuffer	= DE_NULL;
    336 
    337 	if (m_colorRbo || m_fbo)
    338 	{
    339 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    340 
    341 		gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
    342 		gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
    343 
    344 		if (m_colorRbo != 0)
    345 		{
    346 			gl.deleteRenderbuffers(1, &m_colorRbo);
    347 			m_colorRbo = 0;
    348 		}
    349 
    350 		if (m_fbo != 0)
    351 		{
    352 			gl.deleteFramebuffers(1, &m_fbo);
    353 			m_fbo = 0;
    354 		}
    355 
    356 		if (m_resolveColorRbo)
    357 		{
    358 			gl.deleteRenderbuffers(1, &m_resolveColorRbo);
    359 			m_resolveColorRbo = 0;
    360 		}
    361 
    362 		if (m_resolveFbo)
    363 		{
    364 			gl.deleteRenderbuffers(1, &m_resolveFbo);
    365 			m_resolveFbo = 0;
    366 		}
    367 	}
    368 }
    369 
    370 static tcu::Vec4 randomColor (de::Random* rnd)
    371 {
    372 	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 };
    373 	const float alphaValues[]	= { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f };
    374 
    375 	// \note Spec assumes premultiplied inputs.
    376 	const float a = rnd->choose<float>(DE_ARRAY_BEGIN(alphaValues), DE_ARRAY_END(alphaValues));
    377 	const float r = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues));
    378 	const float g = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues));
    379 	const float b = a * rnd->choose<float>(DE_ARRAY_BEGIN(rgbValues), DE_ARRAY_END(rgbValues));
    380 	return tcu::Vec4(r, g, b, a);
    381 }
    382 
    383 static tcu::ConstPixelBufferAccess getLinearAccess (const tcu::ConstPixelBufferAccess& access)
    384 {
    385 	if (access.getFormat().order == TextureFormat::sRGBA)
    386 		return tcu::ConstPixelBufferAccess(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8),
    387 										   access.getWidth(), access.getHeight(), access.getDepth(),
    388 										   access.getRowPitch(), access.getSlicePitch(), access.getDataPtr());
    389 	else
    390 		return access;
    391 }
    392 
    393 AdvancedBlendCase::IterateResult AdvancedBlendCase::iterate (void)
    394 {
    395 	const glu::RenderContext&		renderCtx		= m_context.getRenderContext();
    396 	const glw::Functions&			gl				= renderCtx.getFunctions();
    397 	de::Random						rnd				(deStringHash(getName()) ^ deInt32Hash(m_iterNdx));
    398 	const int						viewportX		= rnd.getInt(0, m_renderWidth - m_viewportWidth);
    399 	const int						viewportY		= rnd.getInt(0, m_renderHeight - m_viewportHeight);
    400 	const bool						useFbo			= m_rtType != RENDERTARGETTYPE_DEFAULT;
    401 	const bool						requiresResolve	= m_rtType == RENDERTARGETTYPE_MSAA_FBO;
    402 	const int						numQuads		= m_overdrawCount+1;
    403 	TextureLevel					renderedImg		(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), m_viewportWidth, m_viewportHeight);
    404 	vector<Vec4>					colors			(numQuads*4);
    405 
    406 	for (vector<Vec4>::iterator col = colors.begin(); col != colors.end(); ++col)
    407 		*col = randomColor(&rnd);
    408 
    409 	// Render with GL.
    410 	{
    411 		const deUint32		program				= m_program->getProgram();
    412 		const int			posLoc				= gl.getAttribLocation(program, "a_position");
    413 		const int			colorLoc			= gl.getAttribLocation(program, "a_color");
    414 		const glu::Buffer	indexBuffer			(renderCtx);
    415 		const glu::Buffer	positionBuffer		(renderCtx);
    416 		const glu::Buffer	colorBuffer			(renderCtx);
    417 		vector<Vec2>		positions			(numQuads*4);
    418 		vector<deUint16>	indices				(numQuads*6);
    419 		const deUint16		singleQuadIndices[]	= { 0, 2, 1, 1, 2, 3 };
    420 		const Vec2			singleQuadPos[]		=
    421 		{
    422 			Vec2(-1.0f, -1.0f),
    423 			Vec2(-1.0f, +1.0f),
    424 			Vec2(+1.0f, -1.0f),
    425 			Vec2(+1.0f, +1.0f),
    426 		};
    427 
    428 		TCU_CHECK(posLoc >= 0 && colorLoc >= 0);
    429 
    430 		for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
    431 		{
    432 			std::copy(DE_ARRAY_BEGIN(singleQuadPos), DE_ARRAY_END(singleQuadPos), &positions[quadNdx*4]);
    433 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(singleQuadIndices); ndx++)
    434 				indices[quadNdx*6 + ndx] = (deUint16)(quadNdx*4 + singleQuadIndices[ndx]);
    435 		}
    436 
    437 		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, *indexBuffer);
    438 		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (glw::GLsizeiptr)(indices.size()*sizeof(indices[0])), &indices[0], GL_STATIC_DRAW);
    439 
    440 		gl.bindBuffer(GL_ARRAY_BUFFER, *positionBuffer);
    441 		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(positions.size()*sizeof(positions[0])), &positions[0], GL_STATIC_DRAW);
    442 		gl.enableVertexAttribArray(posLoc);
    443 		gl.vertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    444 
    445 		gl.bindBuffer(GL_ARRAY_BUFFER, *colorBuffer);
    446 		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(colors.size()*sizeof(colors[0])), &colors[0], GL_STATIC_DRAW);
    447 		gl.enableVertexAttribArray(colorLoc);
    448 		gl.vertexAttribPointer(colorLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    449 		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create buffers");
    450 
    451 		gl.useProgram(program);
    452 		gl.viewport(viewportX, viewportY, m_viewportWidth, m_viewportHeight);
    453 		gl.blendEquation(m_blendMode);
    454 
    455 		// \note coherent extension enables GL_BLEND_ADVANCED_COHERENT_KHR by default
    456 		if (m_coherentBlending)
    457 			gl.enable(GL_BLEND_ADVANCED_COHERENT_KHR);
    458 		else if (m_coherentExtensionSupported)
    459 			gl.disable(GL_BLEND_ADVANCED_COHERENT_KHR);
    460 
    461 		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set render state");
    462 
    463 		gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    464 
    465 		gl.disable(GL_BLEND);
    466 		gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL);
    467 		gl.enable(GL_BLEND);
    468 
    469 		if (!m_coherentBlending)
    470 			gl.blendBarrier();
    471 
    472 		if (m_coherentBlending)
    473 		{
    474 			gl.drawElements(GL_TRIANGLES, 6*(numQuads-1), GL_UNSIGNED_SHORT, (const void*)(deUintptr)(6*sizeof(deUint16)));
    475 		}
    476 		else
    477 		{
    478 			for (int quadNdx = 1; quadNdx < numQuads; quadNdx++)
    479 			{
    480 				gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void*)(deUintptr)(quadNdx*6*sizeof(deUint16)));
    481 				gl.blendBarrier();
    482 			}
    483 		}
    484 
    485 		gl.flush();
    486 		GLU_EXPECT_NO_ERROR(gl.getError(), "Render failed");
    487 	}
    488 
    489 	// Render reference.
    490 	{
    491 		rr::FragmentOperationState		referenceState;
    492 		const tcu::PixelBufferAccess	colorAccess		= gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess());
    493 		const tcu::PixelBufferAccess	nullAccess		= tcu::PixelBufferAccess();
    494 		IntegerQuad						quad;
    495 
    496 		if (!useFbo && m_context.getRenderTarget().getPixelFormat().alphaBits == 0)
    497 		{
    498 			// Emulate lack of alpha by clearing to 1 and masking out alpha writes
    499 			tcu::clear(*m_refColorBuffer, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
    500 			referenceState.colorMask = tcu::BVec4(true, true, true, false);
    501 		}
    502 
    503 		referenceState.blendEquationAdvaced	= sglr::rr_util::mapGLBlendEquationAdvanced(m_blendMode);
    504 
    505 		quad.posA = tcu::IVec2(0, 0);
    506 		quad.posB = tcu::IVec2(m_viewportWidth-1, m_viewportHeight-1);
    507 
    508 		for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
    509 		{
    510 			referenceState.blendMode = quadNdx == 0 ? rr::BLENDMODE_NONE : rr::BLENDMODE_ADVANCED;
    511 			std::copy(&colors[4*quadNdx], &colors[4*quadNdx] + 4, &quad.color[0]);
    512 			m_referenceRenderer->render(colorAccess, nullAccess /* no depth */, nullAccess /* no stencil */, quad, referenceState);
    513 		}
    514 	}
    515 
    516 	if (requiresResolve)
    517 	{
    518 		gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_resolveFbo);
    519 		gl.blitFramebuffer(0, 0, m_renderWidth, m_renderHeight, 0, 0, m_renderWidth, m_renderHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    520 		GLU_EXPECT_NO_ERROR(gl.getError(), "Resolve blit failed");
    521 
    522 		gl.bindFramebuffer(GL_READ_FRAMEBUFFER, m_resolveFbo);
    523 	}
    524 
    525 	glu::readPixels(renderCtx, viewportX, viewportY, renderedImg.getAccess());
    526 	GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels()");
    527 
    528 	if (requiresResolve)
    529 		gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    530 
    531 	{
    532 		const bool	isHSLMode	= m_blendMode == GL_HSL_HUE			||
    533 								  m_blendMode == GL_HSL_SATURATION	||
    534 								  m_blendMode == GL_HSL_COLOR		||
    535 								  m_blendMode == GL_HSL_LUMINOSITY;
    536 		bool		comparePass	= false;
    537 
    538 		if (isHSLMode)
    539 		{
    540 			// Compensate for more demanding HSL code by using fuzzy comparison.
    541 			const float threshold = 0.002f;
    542 			comparePass = tcu::fuzzyCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result",
    543 											getLinearAccess(m_refColorBuffer->getAccess()),
    544 											renderedImg.getAccess(),
    545 											threshold, tcu::COMPARE_LOG_RESULT);
    546 		}
    547 		else
    548 		{
    549 			const UVec4 compareThreshold = (useFbo ? tcu::PixelFormat(8, 8, 8, 8) : m_context.getRenderTarget().getPixelFormat()).getColorThreshold().toIVec().asUint()
    550 									 * UVec4(5) / UVec4(2) + UVec4(3 * m_overdrawCount);
    551 
    552 			comparePass = tcu::bilinearCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result",
    553 											  getLinearAccess(m_refColorBuffer->getAccess()),
    554 											  renderedImg.getAccess(),
    555 											  tcu::RGBA(compareThreshold[0], compareThreshold[1], compareThreshold[2], compareThreshold[3]),
    556 											  tcu::COMPARE_LOG_RESULT);
    557 		}
    558 
    559 		if (!comparePass)
    560 		{
    561 			m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    562 			return STOP;
    563 		}
    564 	}
    565 
    566 	m_iterNdx += 1;
    567 
    568 	if (m_iterNdx < m_numIters)
    569 		return CONTINUE;
    570 	else
    571 	{
    572 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    573 		return STOP;
    574 	}
    575 }
    576 
    577 class BlendAdvancedCoherentStateCase : public TestCase
    578 {
    579 public:
    580 											BlendAdvancedCoherentStateCase	(Context&						context,
    581 																			 const char*					name,
    582 																			 const char*					description,
    583 																			 gls::StateQueryUtil::QueryType	type);
    584 private:
    585 	IterateResult							iterate							(void);
    586 
    587 	const gls::StateQueryUtil::QueryType	m_type;
    588 };
    589 
    590 BlendAdvancedCoherentStateCase::BlendAdvancedCoherentStateCase	(Context&						context,
    591 																 const char*					name,
    592 																 const char*					description,
    593 																 gls::StateQueryUtil::QueryType	type)
    594 	: TestCase	(context, name, description)
    595 	, m_type	(type)
    596 {
    597 }
    598 
    599 BlendAdvancedCoherentStateCase::IterateResult BlendAdvancedCoherentStateCase::iterate (void)
    600 {
    601 	TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced_coherent"), "GL_KHR_blend_equation_advanced_coherent is not supported");
    602 
    603 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    604 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
    605 
    606 	gl.enableLogging(true);
    607 
    608 	// check inital value
    609 	{
    610 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "Initial", "Initial");
    611 		gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, true, m_type);
    612 	}
    613 
    614 	// check toggle
    615 	{
    616 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "Toggle", "Toggle");
    617 		gl.glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
    618 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "glDisable");
    619 
    620 		gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, false, m_type);
    621 
    622 		gl.glEnable(GL_BLEND_ADVANCED_COHERENT_KHR);
    623 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "glEnable");
    624 
    625 		gls::StateQueryUtil::verifyStateBoolean(result, gl, GL_BLEND_ADVANCED_COHERENT_KHR, true, m_type);
    626 	}
    627 
    628 	result.setTestContextResult(m_testCtx);
    629 	return STOP;
    630 }
    631 
    632 class BlendEquationStateCase : public TestCase
    633 {
    634 public:
    635 											BlendEquationStateCase	(Context&						context,
    636 																	 const char*					name,
    637 																	 const char*					description,
    638 																	 const glw::GLenum*				equations,
    639 																	 int							numEquations,
    640 																	 gls::StateQueryUtil::QueryType	type);
    641 private:
    642 	IterateResult							iterate					(void);
    643 
    644 	const gls::StateQueryUtil::QueryType	m_type;
    645 	const glw::GLenum*						m_equations;
    646 	const int								m_numEquations;
    647 };
    648 
    649 BlendEquationStateCase::BlendEquationStateCase	(Context&						context,
    650 												 const char*					name,
    651 												 const char*					description,
    652 												 const glw::GLenum*				equations,
    653 												 int							numEquations,
    654 												 gls::StateQueryUtil::QueryType	type)
    655 	: TestCase			(context, name, description)
    656 	, m_type			(type)
    657 	, m_equations		(equations)
    658 	, m_numEquations	(numEquations)
    659 {
    660 }
    661 
    662 BlendEquationStateCase::IterateResult BlendEquationStateCase::iterate (void)
    663 {
    664 	if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
    665 		TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"), "GL_KHR_blend_equation_advanced is not supported");
    666 
    667 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    668 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
    669 
    670 	gl.enableLogging(true);
    671 
    672 	for (int ndx = 0; ndx < m_numEquations; ++ndx)
    673 	{
    674 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "Type", "Test " + de::toString(glu::getBlendEquationStr(m_equations[ndx])));
    675 
    676 		gl.glBlendEquation(m_equations[ndx]);
    677 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "glBlendEquation");
    678 
    679 		gls::StateQueryUtil::verifyStateInteger(result, gl, GL_BLEND_EQUATION, m_equations[ndx], m_type);
    680 	}
    681 
    682 	result.setTestContextResult(m_testCtx);
    683 	return STOP;
    684 }
    685 
    686 class BlendEquationIndexedStateCase : public TestCase
    687 {
    688 public:
    689 											BlendEquationIndexedStateCase	(Context&						context,
    690 																			 const char*					name,
    691 																			 const char*					description,
    692 																			 const glw::GLenum*				equations,
    693 																			 int							numEquations,
    694 																			 gls::StateQueryUtil::QueryType	type);
    695 private:
    696 	IterateResult							iterate							(void);
    697 
    698 	const gls::StateQueryUtil::QueryType	m_type;
    699 	const glw::GLenum*						m_equations;
    700 	const int								m_numEquations;
    701 };
    702 
    703 BlendEquationIndexedStateCase::BlendEquationIndexedStateCase	(Context&						context,
    704 																 const char*					name,
    705 																 const char*					description,
    706 																 const glw::GLenum*				equations,
    707 																 int							numEquations,
    708 																 gls::StateQueryUtil::QueryType	type)
    709 	: TestCase			(context, name, description)
    710 	, m_type			(type)
    711 	, m_equations		(equations)
    712 	, m_numEquations	(numEquations)
    713 {
    714 }
    715 
    716 BlendEquationIndexedStateCase::IterateResult BlendEquationIndexedStateCase::iterate (void)
    717 {
    718 	if (!glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
    719 	{
    720 		TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_KHR_blend_equation_advanced"), "GL_KHR_blend_equation_advanced is not supported");
    721 		TCU_CHECK_AND_THROW(NotSupportedError, m_context.getContextInfo().isExtensionSupported("GL_EXT_draw_buffers_indexed"), "GL_EXT_draw_buffers_indexed is not supported");
    722 	}
    723 
    724 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    725 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
    726 
    727 	gl.enableLogging(true);
    728 
    729 	for (int ndx = 0; ndx < m_numEquations; ++ndx)
    730 	{
    731 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "Type", "Test " + de::toString(glu::getBlendEquationStr(m_equations[ndx])));
    732 
    733 		gl.glBlendEquationi(2, m_equations[ndx]);
    734 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "glBlendEquationi");
    735 
    736 		gls::StateQueryUtil::verifyStateIndexedInteger(result, gl, GL_BLEND_EQUATION, 2, m_equations[ndx], m_type);
    737 	}
    738 
    739 	result.setTestContextResult(m_testCtx);
    740 	return STOP;
    741 }
    742 
    743 } // anonymous
    744 
    745 AdvancedBlendTests::AdvancedBlendTests (Context& context)
    746 	: TestCaseGroup(context, "blend_equation_advanced", "GL_blend_equation_advanced Tests")
    747 {
    748 }
    749 
    750 AdvancedBlendTests::~AdvancedBlendTests (void)
    751 {
    752 }
    753 
    754 void AdvancedBlendTests::init (void)
    755 {
    756 	static const glw::GLenum s_blendEquations[] =
    757 	{
    758 		GL_MULTIPLY,
    759 		GL_SCREEN,
    760 		GL_OVERLAY,
    761 		GL_DARKEN,
    762 		GL_LIGHTEN,
    763 		GL_COLORDODGE,
    764 		GL_COLORBURN,
    765 		GL_HARDLIGHT,
    766 		GL_SOFTLIGHT,
    767 		GL_DIFFERENCE,
    768 		GL_EXCLUSION,
    769 		GL_HSL_HUE,
    770 		GL_HSL_SATURATION,
    771 		GL_HSL_COLOR,
    772 		GL_HSL_LUMINOSITY,
    773 	};
    774 
    775 	tcu::TestCaseGroup* const	stateQueryGroup		= new tcu::TestCaseGroup(m_testCtx, "state_query",		"State query tests");
    776 	tcu::TestCaseGroup* const	basicGroup			= new tcu::TestCaseGroup(m_testCtx, "basic",			"Single quad only");
    777 	tcu::TestCaseGroup* const	srgbGroup			= new tcu::TestCaseGroup(m_testCtx, "srgb",				"Advanced blending with sRGB FBO");
    778 	tcu::TestCaseGroup* const	msaaGroup			= new tcu::TestCaseGroup(m_testCtx, "msaa",				"Advanced blending with MSAA FBO");
    779 	tcu::TestCaseGroup* const	barrierGroup		= new tcu::TestCaseGroup(m_testCtx, "barrier",			"Multiple overlapping quads with blend barriers");
    780 	tcu::TestCaseGroup* const	coherentGroup		= new tcu::TestCaseGroup(m_testCtx, "coherent",			"Overlapping quads with coherent blending");
    781 	tcu::TestCaseGroup* const	coherentMsaaGroup	= new tcu::TestCaseGroup(m_testCtx, "coherent_msaa",	"Overlapping quads with coherent blending with MSAA FBO");
    782 
    783 	addChild(stateQueryGroup);
    784 	addChild(basicGroup);
    785 	addChild(srgbGroup);
    786 	addChild(msaaGroup);
    787 	addChild(barrierGroup);
    788 	addChild(coherentGroup);
    789 	addChild(coherentMsaaGroup);
    790 
    791 	// .state_query
    792 	{
    793 		using namespace gls::StateQueryUtil;
    794 
    795 		stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getboolean",	"Test BLEND_ADVANCED_COHERENT_KHR", QUERY_BOOLEAN));
    796 		stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_isenabled",	"Test BLEND_ADVANCED_COHERENT_KHR", QUERY_ISENABLED));
    797 		stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getinteger",	"Test BLEND_ADVANCED_COHERENT_KHR", QUERY_INTEGER));
    798 		stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getinteger64",	"Test BLEND_ADVANCED_COHERENT_KHR", QUERY_INTEGER64));
    799 		stateQueryGroup->addChild(new BlendAdvancedCoherentStateCase(m_context, "blend_advanced_coherent_getfloat",		"Test BLEND_ADVANCED_COHERENT_KHR", QUERY_FLOAT));
    800 
    801 		stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getboolean",	"Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_BOOLEAN));
    802 		stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getinteger",	"Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INTEGER));
    803 		stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getinteger64",	"Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INTEGER64));
    804 		stateQueryGroup->addChild(new BlendEquationStateCase(m_context, "blend_equation_getfloat",		"Test BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_FLOAT));
    805 
    806 		stateQueryGroup->addChild(new BlendEquationIndexedStateCase(m_context, "blend_equation_getbooleani_v",		"Test per-attchment BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INDEXED_BOOLEAN));
    807 		stateQueryGroup->addChild(new BlendEquationIndexedStateCase(m_context, "blend_equation_getintegeri_v",		"Test per-attchment BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INDEXED_INTEGER));
    808 		stateQueryGroup->addChild(new BlendEquationIndexedStateCase(m_context, "blend_equation_getinteger64i_v",	"Test per-attchment BLEND_EQUATION", s_blendEquations, DE_LENGTH_OF_ARRAY(s_blendEquations), QUERY_INDEXED_INTEGER64));
    809 	}
    810 
    811 	// others
    812 	for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(s_blendEquations); modeNdx++)
    813 	{
    814 		const char* const		name		= getEquationName(s_blendEquations[modeNdx]);
    815 		const char* const		desc		= "";
    816 		const deUint32			mode		= s_blendEquations[modeNdx];
    817 
    818 		basicGroup->addChild		(new AdvancedBlendCase(m_context, name, desc, mode, 1, false,	RENDERTARGETTYPE_DEFAULT));
    819 		srgbGroup->addChild			(new AdvancedBlendCase(m_context, name, desc, mode, 1, false,	RENDERTARGETTYPE_SRGB_FBO));
    820 		msaaGroup->addChild			(new AdvancedBlendCase(m_context, name, desc, mode, 1, false,	RENDERTARGETTYPE_MSAA_FBO));
    821 		barrierGroup->addChild		(new AdvancedBlendCase(m_context, name, desc, mode, 4, false,	RENDERTARGETTYPE_DEFAULT));
    822 		coherentGroup->addChild		(new AdvancedBlendCase(m_context, name, desc, mode, 4, true,	RENDERTARGETTYPE_DEFAULT));
    823 		coherentMsaaGroup->addChild	(new AdvancedBlendCase(m_context, name, desc, mode, 4, true,	RENDERTARGETTYPE_MSAA_FBO));
    824 	}
    825 }
    826 
    827 } // Functional
    828 } // gles31
    829 } // deqp
    830