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