1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.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 Blend tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es2fBlendTests.hpp"
25 #include "glsFragmentOpUtil.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "gluStrUtil.hpp"
28 #include "tcuSurface.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "deRandom.hpp"
34 #include "rrFragmentOperations.hpp"
35 #include "sglrReferenceUtils.hpp"
36 
37 #include "glw.h"
38 
39 #include <string>
40 #include <vector>
41 
42 namespace deqp
43 {
44 
45 using gls::FragmentOpUtil::Quad;
46 using gls::FragmentOpUtil::IntegerQuad;
47 using gls::FragmentOpUtil::QuadRenderer;
48 using gls::FragmentOpUtil::ReferenceQuadRenderer;
49 using glu::getBlendEquationName;
50 using glu::getBlendFactorName;
51 using tcu::Vec4;
52 using tcu::UVec4;
53 using tcu::TestLog;
54 using tcu::Surface;
55 using tcu::TextureFormat;
56 using tcu::TextureLevel;
57 using std::string;
58 using std::vector;
59 
60 namespace gles2
61 {
62 namespace Functional
63 {
64 
65 static const int MAX_VIEWPORT_WIDTH		= 64;
66 static const int MAX_VIEWPORT_HEIGHT	= 64;
67 
68 struct BlendParams
69 {
70 	GLenum	equationRGB;
71 	GLenum	srcFuncRGB;
72 	GLenum	dstFuncRGB;
73 	GLenum	equationAlpha;
74 	GLenum	srcFuncAlpha;
75 	GLenum	dstFuncAlpha;
76 	Vec4	blendColor;
77 
BlendParamsdeqp::gles2::Functional::BlendParams78 	BlendParams (GLenum		equationRGB_,
79 				 GLenum		srcFuncRGB_,
80 				 GLenum		dstFuncRGB_,
81 				 GLenum		equationAlpha_,
82 				 GLenum		srcFuncAlpha_,
83 				 GLenum		dstFuncAlpha_,
84 				 Vec4		blendColor_)
85 	: equationRGB	(equationRGB_)
86 	, srcFuncRGB	(srcFuncRGB_)
87 	, dstFuncRGB	(dstFuncRGB_)
88 	, equationAlpha	(equationAlpha_)
89 	, srcFuncAlpha	(srcFuncAlpha_)
90 	, dstFuncAlpha	(dstFuncAlpha_)
91 	, blendColor	(blendColor_)
92 	{
93 	}
94 };
95 
96 class BlendCase : public TestCase
97 {
98 public:
99 							BlendCase	(Context&						context,
100 										 const char*					name,
101 										 const char*					desc,
102 										 const vector<BlendParams>&		paramSets);
103 
104 							~BlendCase	(void);
105 
106 	void					init		(void);
107 	void					deinit		(void);
108 
109 	IterateResult			iterate		(void);
110 
111 private:
112 							BlendCase	(const BlendCase& other);
113 	BlendCase&				operator=	(const BlendCase& other);
114 
115 	vector<BlendParams>		m_paramSets;
116 	int						m_curParamSetNdx;
117 
118 	QuadRenderer*			m_renderer;
119 	ReferenceQuadRenderer*	m_referenceRenderer;
120 	TextureLevel*			m_refColorBuffer;
121 	Quad					m_firstQuad;
122 	Quad					m_secondQuad;
123 	IntegerQuad				m_firstQuadInt;
124 	IntegerQuad				m_secondQuadInt;
125 
126 	int						m_viewportW;
127 	int						m_viewportH;
128 };
129 
BlendCase(Context & context,const char * name,const char * desc,const vector<BlendParams> & paramSets)130 BlendCase::BlendCase (Context&						context,
131 					  const char*					name,
132 					  const char*					desc,
133 					  const vector<BlendParams>&	paramSets)
134 	: TestCase				(context, name, desc)
135 	, m_paramSets			(paramSets)
136 	, m_curParamSetNdx		(0)
137 	, m_renderer			(DE_NULL)
138 	, m_referenceRenderer	(DE_NULL)
139 	, m_refColorBuffer		(DE_NULL)
140 	, m_viewportW			(0)
141 	, m_viewportH			(0)
142 {
143 	DE_ASSERT(!m_paramSets.empty());
144 	for (int i = 0; i < (int)m_paramSets.size(); i++)
145 		DE_ASSERT(m_paramSets[i].dstFuncRGB != GL_SRC_ALPHA_SATURATE && m_paramSets[i].dstFuncAlpha != GL_SRC_ALPHA_SATURATE);
146 }
147 
init(void)148 void BlendCase::init (void)
149 {
150 	bool useRGB = m_context.getRenderTarget().getPixelFormat().alphaBits == 0;
151 
152 	static const Vec4 baseGradientColors[4] =
153 	{
154 		Vec4(0.0f, 0.5f, 1.0f, 0.5f),
155 		Vec4(0.5f, 0.0f, 0.5f, 1.0f),
156 		Vec4(0.5f, 1.0f, 0.5f, 0.0f),
157 		Vec4(1.0f, 0.5f, 0.0f, 0.5f)
158 	};
159 
160 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(m_firstQuad.color) == DE_LENGTH_OF_ARRAY(m_firstQuadInt.color));
161 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_firstQuad.color); i++)
162 	{
163 		m_firstQuad.color[i]		= (baseGradientColors[i] - 0.5f) * 0.2f + 0.5f;
164 		m_firstQuadInt.color[i]		= m_firstQuad.color[i];
165 
166 		m_secondQuad.color[i]		= (Vec4(1.0f) - baseGradientColors[i] - 0.5f) * 1.0f + 0.5f;
167 		m_secondQuadInt.color[i]	= m_secondQuad.color[i];
168 	}
169 
170 	m_viewportW = de::min<int>(m_context.getRenderTarget().getWidth(),	MAX_VIEWPORT_WIDTH);
171 	m_viewportH = de::min<int>(m_context.getRenderTarget().getHeight(),	MAX_VIEWPORT_HEIGHT);
172 
173 	m_firstQuadInt.posA		= tcu::IVec2(0,					0);
174 	m_secondQuadInt.posA	= tcu::IVec2(0,					0);
175 	m_firstQuadInt.posB		= tcu::IVec2(m_viewportW-1,		m_viewportH-1);
176 	m_secondQuadInt.posB	= tcu::IVec2(m_viewportW-1,		m_viewportH-1);
177 
178 	DE_ASSERT(!m_renderer);
179 	DE_ASSERT(!m_referenceRenderer);
180 	DE_ASSERT(!m_refColorBuffer);
181 
182 	m_renderer				= new QuadRenderer(m_context.getRenderContext(), glu::GLSL_VERSION_100_ES);
183 	m_referenceRenderer		= new ReferenceQuadRenderer;
184 	m_refColorBuffer		= new TextureLevel(TextureFormat(useRGB ? TextureFormat::RGB : TextureFormat::RGBA, TextureFormat::UNORM_INT8),
185 											   m_viewportW, m_viewportH);
186 
187 	m_curParamSetNdx = 0;
188 }
189 
~BlendCase(void)190 BlendCase::~BlendCase (void)
191 {
192 	delete m_renderer;
193 	delete m_referenceRenderer;
194 	delete m_refColorBuffer;
195 }
196 
deinit(void)197 void BlendCase::deinit (void)
198 {
199 	delete m_renderer;
200 	delete m_referenceRenderer;
201 	delete m_refColorBuffer;
202 
203 	m_renderer			= DE_NULL;
204 	m_referenceRenderer	= DE_NULL;
205 	m_refColorBuffer	= DE_NULL;
206 }
207 
iterate(void)208 BlendCase::IterateResult BlendCase::iterate (void)
209 {
210 	de::Random						rnd				(deStringHash(getName()) ^ deInt32Hash(m_curParamSetNdx));
211 	int								viewportX		= rnd.getInt(0, m_context.getRenderTarget().getWidth() - m_viewportW);
212 	int								viewportY		= rnd.getInt(0, m_context.getRenderTarget().getHeight() - m_viewportH);
213 	tcu::Surface					renderedImg		(m_viewportW, m_viewportH);
214 	tcu::Surface					referenceImg	(m_viewportH, m_viewportH);
215 	TestLog&						log				(m_testCtx.getLog());
216 	const BlendParams&				paramSet		= m_paramSets[m_curParamSetNdx];
217 	rr::FragmentOperationState		referenceState;
218 
219 	// Log the blend parameters.
220 
221 	log << TestLog::Message << "RGB equation = " << getBlendEquationName(paramSet.equationRGB) << TestLog::EndMessage;
222 	log << TestLog::Message << "RGB src func = " << getBlendFactorName(paramSet.srcFuncRGB) << TestLog::EndMessage;
223 	log << TestLog::Message << "RGB dst func = " << getBlendFactorName(paramSet.dstFuncRGB) << TestLog::EndMessage;
224 	log << TestLog::Message << "Alpha equation = " << getBlendEquationName(paramSet.equationAlpha) << TestLog::EndMessage;
225 	log << TestLog::Message << "Alpha src func = " << getBlendFactorName(paramSet.srcFuncAlpha) << TestLog::EndMessage;
226 	log << TestLog::Message << "Alpha dst func = " << getBlendFactorName(paramSet.dstFuncAlpha) << TestLog::EndMessage;
227 	log << TestLog::Message << "Blend color = (" << paramSet.blendColor.x() << ", " << paramSet.blendColor.y() << ", " << paramSet.blendColor.z() << ", " << paramSet.blendColor.w() << ")" << TestLog::EndMessage;
228 
229 	// Set GL state.
230 
231 	GLU_CHECK_CALL(glBlendEquationSeparate(paramSet.equationRGB, paramSet.equationAlpha));
232 	GLU_CHECK_CALL(glBlendFuncSeparate(paramSet.srcFuncRGB, paramSet.dstFuncRGB, paramSet.srcFuncAlpha, paramSet.dstFuncAlpha));
233 	GLU_CHECK_CALL(glBlendColor(paramSet.blendColor.x(), paramSet.blendColor.y(), paramSet.blendColor.z(), paramSet.blendColor.w()));
234 
235 	// Set reference state.
236 
237 	referenceState.blendRGBState.equation	= sglr::rr_util::mapGLBlendEquation(paramSet.equationRGB);
238 	referenceState.blendRGBState.srcFunc	= sglr::rr_util::mapGLBlendFunc(paramSet.srcFuncRGB);
239 	referenceState.blendRGBState.dstFunc	= sglr::rr_util::mapGLBlendFunc(paramSet.dstFuncRGB);
240 	referenceState.blendAState.equation		= sglr::rr_util::mapGLBlendEquation(paramSet.equationAlpha);
241 	referenceState.blendAState.srcFunc		= sglr::rr_util::mapGLBlendFunc(paramSet.srcFuncAlpha);
242 	referenceState.blendAState.dstFunc		= sglr::rr_util::mapGLBlendFunc(paramSet.dstFuncAlpha);
243 	referenceState.blendColor				= paramSet.blendColor;
244 
245 	// Render with GL.
246 
247 	glDisable(GL_BLEND);
248 	glViewport(viewportX, viewportY, m_viewportW, m_viewportH);
249 	m_renderer->render(m_firstQuad);
250 	glEnable(GL_BLEND);
251 	m_renderer->render(m_secondQuad);
252 	glFlush();
253 
254 	// Render reference.
255 
256 	const tcu::PixelBufferAccess nullAccess = tcu::PixelBufferAccess();
257 
258 	referenceState.blendMode = rr::BLENDMODE_NONE;
259 	m_referenceRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()), nullAccess /* no depth */, nullAccess /* no stencil */, m_firstQuadInt, referenceState);
260 	referenceState.blendMode = rr::BLENDMODE_STANDARD;
261 	m_referenceRenderer->render(gls::FragmentOpUtil::getMultisampleAccess(m_refColorBuffer->getAccess()), nullAccess /* no depth */, nullAccess /* no stencil */, m_secondQuadInt, referenceState);
262 
263 	// Expand reference color buffer to RGBA8
264 	copy(referenceImg.getAccess(), m_refColorBuffer->getAccess());
265 
266 	// Read GL image.
267 
268 	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedImg.getAccess());
269 
270 	// Compare images.
271 
272 	UVec4 compareThreshold = m_context.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().asUint()
273 							 * UVec4(5) / UVec4(2) + UVec4(3); // \note Non-scientific ad hoc formula. Need big threshold when few color bits; blending brings extra inaccuracy.
274 
275 	bool comparePass = tcu::intThresholdCompare(m_testCtx.getLog(), "CompareResult", "Image Comparison Result", referenceImg.getAccess(), renderedImg.getAccess(), compareThreshold, tcu::COMPARE_LOG_RESULT);
276 
277 	// Fail now if images don't match.
278 
279 	if (!comparePass)
280 	{
281 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Image compare failed");
282 		return STOP;
283 	}
284 
285 	// Continue if param sets still remain in m_paramSets; otherwise stop.
286 
287 	m_curParamSetNdx++;
288 
289 	if (m_curParamSetNdx < (int)m_paramSets.size())
290 		return CONTINUE;
291 	else
292 	{
293 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
294 		return STOP;
295 	}
296 }
297 
BlendTests(Context & context)298 BlendTests::BlendTests (Context& context)
299 	: TestCaseGroup(context, "blend", "Blend tests")
300 {
301 }
302 
~BlendTests(void)303 BlendTests::~BlendTests (void)
304 {
305 }
306 
init(void)307 void BlendTests::init (void)
308 {
309 	struct EnumGL
310 	{
311 		GLenum			glValue;
312 		const char*		nameStr;
313 	};
314 
315 	static const EnumGL blendEquations[] =
316 	{
317 		{ GL_FUNC_ADD,					"add"					},
318 		{ GL_FUNC_SUBTRACT,				"subtract"				},
319 		{ GL_FUNC_REVERSE_SUBTRACT,		"reverse_subtract"		}
320 	};
321 
322 	static const EnumGL blendFunctions[] =
323 	{
324 		{ GL_ZERO,							"zero"						},
325 		{ GL_ONE,							"one"						},
326 		{ GL_SRC_COLOR,						"src_color"					},
327 		{ GL_ONE_MINUS_SRC_COLOR,			"one_minus_src_color"		},
328 		{ GL_DST_COLOR,						"dst_color"					},
329 		{ GL_ONE_MINUS_DST_COLOR,			"one_minus_dst_color"		},
330 		{ GL_SRC_ALPHA,						"src_alpha"					},
331 		{ GL_ONE_MINUS_SRC_ALPHA,			"one_minus_src_alpha"		},
332 		{ GL_DST_ALPHA,						"dst_alpha"					},
333 		{ GL_ONE_MINUS_DST_ALPHA,			"one_minus_dst_alpha"		},
334 		{ GL_CONSTANT_COLOR,				"constant_color"			},
335 		{ GL_ONE_MINUS_CONSTANT_COLOR,		"one_minus_constant_color"	},
336 		{ GL_CONSTANT_ALPHA,				"constant_alpha"			},
337 		{ GL_ONE_MINUS_CONSTANT_ALPHA,		"one_minus_constant_alpha"	},
338 		{ GL_SRC_ALPHA_SATURATE,			"src_alpha_saturate"		}
339 	};
340 
341 	const Vec4 defaultBlendColor(0.2f, 0.4f, 0.6f, 0.8f);
342 
343 	// Test all blend equation, src blend function, dst blend function combinations. RGB and alpha modes are the same.
344 
345 	{
346 		TestCaseGroup* group = new TestCaseGroup(m_context, "equation_src_func_dst_func", "Combinations of Blend Equations and Functions");
347 		addChild(group);
348 
349 		for (int equationNdx = 0;	equationNdx < DE_LENGTH_OF_ARRAY(blendEquations);	equationNdx++)
350 		for (int srcFuncNdx = 0;	srcFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions);	srcFuncNdx++)
351 		for (int dstFuncNdx = 0;	dstFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions);	dstFuncNdx++)
352 		{
353 			const EnumGL& eq	= blendEquations[equationNdx];
354 			const EnumGL& src	= blendFunctions[srcFuncNdx];
355 			const EnumGL& dst	= blendFunctions[dstFuncNdx];
356 
357 			if (dst.glValue == GL_SRC_ALPHA_SATURATE) // SRC_ALPHA_SATURATE is only valid for src func.
358 				continue;
359 
360 			string name			= string("") + eq.nameStr + "_" + src.nameStr + "_" + dst.nameStr;
361 			string description	= string("") +
362 								  "Equations "		+ getBlendEquationName(eq.glValue) +
363 								  ", src funcs "	+ getBlendFactorName(src.glValue) +
364 								  ", dst funcs "	+ getBlendFactorName(dst.glValue);
365 
366 			vector<BlendParams> paramSets;
367 			paramSets.push_back(BlendParams(eq.glValue, src.glValue, dst.glValue, eq.glValue, src.glValue, dst.glValue, defaultBlendColor));
368 
369 			group->addChild(new BlendCase(m_context, name.c_str(), description.c_str(), paramSets));
370 		}
371 	}
372 
373 	// Test all RGB src, alpha src and RGB dst, alpha dst combinations. Equations are ADD.
374 	// \note For all RGB src, alpha src combinations, also test a couple of different RGBA dst functions, and vice versa.
375 
376 	{
377 		TestCaseGroup* mainGroup = new TestCaseGroup(m_context, "rgb_func_alpha_func", "Combinations of RGB and Alpha Functions");
378 		addChild(mainGroup);
379 		TestCaseGroup* srcGroup = new TestCaseGroup(m_context, "src", "Source functions");
380 		TestCaseGroup* dstGroup = new TestCaseGroup(m_context, "dst", "Destination functions");
381 		mainGroup->addChild(srcGroup);
382 		mainGroup->addChild(dstGroup);
383 
384 		for (int isDstI = 0;		isDstI <= 1;										isDstI++)
385 		for (int rgbFuncNdx = 0;	rgbFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions);	rgbFuncNdx++)
386 		for (int alphaFuncNdx = 0;	alphaFuncNdx < DE_LENGTH_OF_ARRAY(blendFunctions);	alphaFuncNdx++)
387 		{
388 			bool			isSrc			= isDstI == 0;
389 			TestCaseGroup*	curGroup		= isSrc ? srcGroup : dstGroup;
390 			const EnumGL&	funcRGB			= blendFunctions[rgbFuncNdx];
391 			const EnumGL&	funcAlpha		= blendFunctions[alphaFuncNdx];
392 			const char*		dstOrSrcStr		= isSrc ? "src" : "dst";
393 
394 			if (!isSrc && (funcRGB.glValue == GL_SRC_ALPHA_SATURATE || funcAlpha.glValue == GL_SRC_ALPHA_SATURATE)) // SRC_ALPHA_SATURATE is only valid for src func.
395 				continue;
396 
397 			string name			= string("") + funcRGB.nameStr + "_" + funcAlpha.nameStr;
398 			string description	= string("") +
399 								  "RGB "		+ dstOrSrcStr + " func " + getBlendFactorName(funcRGB.glValue) +
400 								  ", alpha "	+ dstOrSrcStr + " func " + getBlendFactorName(funcAlpha.glValue);
401 
402 			// First, make param sets as if this was a src case.
403 
404 			vector<BlendParams> paramSets;
405 			paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_ONE,			GL_FUNC_ADD, funcAlpha.glValue, GL_ONE,			defaultBlendColor));
406 			paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_ZERO,			GL_FUNC_ADD, funcAlpha.glValue, GL_ZERO,		defaultBlendColor));
407 			paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_SRC_COLOR,		GL_FUNC_ADD, funcAlpha.glValue, GL_SRC_COLOR,	defaultBlendColor));
408 			paramSets.push_back(BlendParams(GL_FUNC_ADD, funcRGB.glValue, GL_DST_COLOR,		GL_FUNC_ADD, funcAlpha.glValue, GL_DST_COLOR,	defaultBlendColor));
409 
410 			// Swap src and dst params if this is a dst case.
411 
412 			if (!isSrc)
413 			{
414 				for (int i = 0; i < (int)paramSets.size(); i++)
415 				{
416 					std::swap(paramSets[i].srcFuncRGB,		paramSets[i].dstFuncRGB);
417 					std::swap(paramSets[i].srcFuncAlpha,	paramSets[i].dstFuncAlpha);
418 				}
419 			}
420 
421 			curGroup->addChild(new BlendCase(m_context, name.c_str(), description.c_str(), paramSets));
422 		}
423 	}
424 
425 	// Test all RGB and alpha equation combinations. Src and dst funcs are ONE for both.
426 
427 	{
428 		TestCaseGroup* group = new TestCaseGroup(m_context, "rgb_equation_alpha_equation", "Combinations of RGB and Alpha Equation Combinations");
429 		addChild(group);
430 
431 		for (int equationRGBNdx = 0;	equationRGBNdx < DE_LENGTH_OF_ARRAY(blendEquations);	equationRGBNdx++)
432 		for (int equationAlphaNdx = 0;	equationAlphaNdx < DE_LENGTH_OF_ARRAY(blendEquations);	equationAlphaNdx++)
433 		{
434 			const EnumGL& eqRGB			= blendEquations[equationRGBNdx];
435 			const EnumGL& eqAlpha		= blendEquations[equationAlphaNdx];
436 
437 			string name			= string("") + eqRGB.nameStr + "_" + eqAlpha.nameStr;
438 			string description	= string("") +
439 								  "RGB equation "		+ getBlendEquationName(eqRGB.glValue) +
440 								  ", alpha equation "	+ getBlendEquationName(eqAlpha.glValue);
441 
442 			vector<BlendParams> paramSets;
443 			paramSets.push_back(BlendParams(eqRGB.glValue, GL_ONE, GL_ONE, eqAlpha.glValue, GL_ONE, GL_ONE, defaultBlendColor));
444 
445 			group->addChild(new BlendCase(m_context, name.c_str(), description.c_str(), paramSets));
446 		}
447 	}
448 }
449 
450 } // Functional
451 } // gles2
452 } // deqp
453