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
51namespace deqp
52{
53
54using gls::FragmentOpUtil::IntegerQuad;
55using gls::FragmentOpUtil::ReferenceQuadRenderer;
56using tcu::TextureLevel;
57using tcu::Vec2;
58using tcu::Vec4;
59using tcu::UVec4;
60using tcu::TestLog;
61using tcu::TextureFormat;
62using std::string;
63using std::vector;
64using std::map;
65
66namespace gles31
67{
68namespace Functional
69{
70
71namespace
72{
73
74enum
75{
76	MAX_VIEWPORT_WIDTH		= 128,
77	MAX_VIEWPORT_HEIGHT		= 128
78};
79
80enum RenderTargetType
81{
82	RENDERTARGETTYPE_DEFAULT	= 0,	//!< Default framebuffer
83	RENDERTARGETTYPE_SRGB_FBO,
84	RENDERTARGETTYPE_MSAA_FBO,
85
86	RENDERTARGETTYPE_LAST
87};
88
89static 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
114class AdvancedBlendCase : public TestCase
115{
116public:
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
126private:
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
157AdvancedBlendCase::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
186const 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
211glu::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
244void 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
326AdvancedBlendCase::~AdvancedBlendCase (void)
327{
328	AdvancedBlendCase::deinit();
329}
330
331void 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
377static 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
390static 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
400AdvancedBlendCase::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
594class BlendAdvancedCoherentStateCase : public TestCase
595{
596public:
597											BlendAdvancedCoherentStateCase	(Context&						context,
598																			 const char*					name,
599																			 const char*					description,
600																			 gls::StateQueryUtil::QueryType	type);
601private:
602	IterateResult							iterate							(void);
603
604	const gls::StateQueryUtil::QueryType	m_type;
605};
606
607BlendAdvancedCoherentStateCase::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
616BlendAdvancedCoherentStateCase::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
649class BlendEquationStateCase : public TestCase
650{
651public:
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);
658private:
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
666BlendEquationStateCase::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
679BlendEquationStateCase::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
703class BlendEquationIndexedStateCase : public TestCase
704{
705public:
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);
712private:
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
720BlendEquationIndexedStateCase::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
733BlendEquationIndexedStateCase::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
764AdvancedBlendTests::AdvancedBlendTests (Context& context)
765	: TestCaseGroup(context, "blend_equation_advanced", "GL_blend_equation_advanced Tests")
766{
767}
768
769AdvancedBlendTests::~AdvancedBlendTests (void)
770{
771}
772
773void 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