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