• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 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 Sample shading tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fSampleShadingTests.hpp"
25 #include "es31fMultisampleShaderRenderCase.hpp"
26 #include "tcuRenderTarget.hpp"
27 #include "tcuSurface.hpp"
28 #include "glsStateQueryUtil.hpp"
29 #include "gluCallLogWrapper.hpp"
30 #include "gluContextInfo.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "gluRenderContext.hpp"
33 #include "gluPixelTransfer.hpp"
34 #include "glwFunctions.hpp"
35 #include "glwEnums.hpp"
36 #include "deStringUtil.hpp"
37 #include "deRandom.hpp"
38 
39 #include <map>
40 
41 namespace deqp
42 {
43 namespace gles31
44 {
45 namespace Functional
46 {
47 namespace
48 {
49 
checkSupport(Context & ctx)50 static bool checkSupport(Context& ctx)
51 {
52 	auto contextType = ctx.getRenderContext().getType();
53 	return contextSupports(contextType, glu::ApiType::es(3, 2)) ||
54 		   contextSupports(contextType, glu::ApiType::core(4, 5)) ||
55 		   ctx.getContextInfo().isExtensionSupported("GL_OES_sample_shading");
56 }
57 
58 using namespace gls::StateQueryUtil;
59 
60 class SampleShadingStateCase : public TestCase
61 {
62 public:
63 						SampleShadingStateCase	(Context& ctx, const char* name, const char* desc, QueryType);
64 
65 	void				init					(void);
66 	IterateResult		iterate					(void);
67 
68 private:
69 	const QueryType		m_verifier;
70 };
71 
SampleShadingStateCase(Context & ctx,const char * name,const char * desc,QueryType type)72 SampleShadingStateCase::SampleShadingStateCase (Context& ctx, const char* name, const char* desc, QueryType type)
73 	: TestCase		(ctx, name, desc)
74 	, m_verifier	(type)
75 {
76 }
77 
init(void)78 void SampleShadingStateCase::init (void)
79 {
80 	if (!checkSupport(m_context))
81 		throw tcu::NotSupportedError("Test requires GL_OES_sample_shading extension or a context version 3.2 or higher.");
82 }
83 
iterate(void)84 SampleShadingStateCase::IterateResult SampleShadingStateCase::iterate (void)
85 {
86 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
87 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
88 	gl.enableLogging(true);
89 
90 	// initial
91 	{
92 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying initial value" << tcu::TestLog::EndMessage;
93 		verifyStateBoolean(result, gl, GL_SAMPLE_SHADING, false, m_verifier);
94 	}
95 
96 	// true and false too
97 	{
98 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying random values" << tcu::TestLog::EndMessage;
99 
100 		gl.glEnable(GL_SAMPLE_SHADING);
101 		verifyStateBoolean(result, gl, GL_SAMPLE_SHADING, true, m_verifier);
102 
103 		gl.glDisable(GL_SAMPLE_SHADING);
104 		verifyStateBoolean(result, gl, GL_SAMPLE_SHADING, false, m_verifier);
105 	}
106 
107 	result.setTestContextResult(m_testCtx);
108 	return STOP;
109 }
110 
111 class MinSampleShadingValueCase : public TestCase
112 {
113 public:
114 						MinSampleShadingValueCase	(Context& ctx, const char* name, const char* desc, QueryType);
115 
116 	void				init						(void);
117 	IterateResult		iterate						(void);
118 
119 private:
120 	const QueryType		m_verifier;
121 };
122 
MinSampleShadingValueCase(Context & ctx,const char * name,const char * desc,QueryType type)123 MinSampleShadingValueCase::MinSampleShadingValueCase (Context& ctx, const char* name, const char* desc, QueryType type)
124 	: TestCase		(ctx, name, desc)
125 	, m_verifier	(type)
126 {
127 }
128 
init(void)129 void MinSampleShadingValueCase::init (void)
130 {
131 	if (!checkSupport(m_context))
132 		throw tcu::NotSupportedError("Test requires GL_OES_sample_shading extension or a context version 3.2 or higher.");
133 }
134 
iterate(void)135 MinSampleShadingValueCase::IterateResult MinSampleShadingValueCase::iterate (void)
136 {
137 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
138 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
139 
140 	gl.enableLogging(true);
141 
142 	// initial
143 	{
144 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying initial value" << tcu::TestLog::EndMessage;
145 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 0.0, m_verifier);
146 	}
147 
148 	// special values
149 	{
150 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying special values" << tcu::TestLog::EndMessage;
151 
152 		gl.glMinSampleShading(0.0f);
153 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 0.0, m_verifier);
154 
155 		gl.glMinSampleShading(1.0f);
156 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 1.0, m_verifier);
157 
158 		gl.glMinSampleShading(0.5f);
159 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 0.5, m_verifier);
160 	}
161 
162 	// random values
163 	{
164 		const int	numRandomTests	= 10;
165 		de::Random	rnd				(0xde123);
166 
167 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying random values" << tcu::TestLog::EndMessage;
168 
169 		for (int randNdx = 0; randNdx < numRandomTests; ++randNdx)
170 		{
171 			const float value = rnd.getFloat();
172 
173 			gl.glMinSampleShading(value);
174 			verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, value, m_verifier);
175 		}
176 	}
177 
178 	result.setTestContextResult(m_testCtx);
179 	return STOP;
180 }
181 
182 class MinSampleShadingValueClampingCase : public TestCase
183 {
184 public:
185 						MinSampleShadingValueClampingCase	(Context& ctx, const char* name, const char* desc);
186 
187 	void				init								(void);
188 	IterateResult		iterate								(void);
189 };
190 
MinSampleShadingValueClampingCase(Context & ctx,const char * name,const char * desc)191 MinSampleShadingValueClampingCase::MinSampleShadingValueClampingCase (Context& ctx, const char* name, const char* desc)
192 	: TestCase(ctx, name, desc)
193 {
194 }
195 
init(void)196 void MinSampleShadingValueClampingCase::init (void)
197 {
198 	if (!checkSupport(m_context))
199 		throw tcu::NotSupportedError("Test requires GL_OES_sample_shading extension or a context version 3.2 or higher.");
200 }
201 
iterate(void)202 MinSampleShadingValueClampingCase::IterateResult MinSampleShadingValueClampingCase::iterate (void)
203 {
204 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
205 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
206 	gl.enableLogging(true);
207 
208 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
209 
210 	// special values
211 	{
212 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying clamped values. Value is clamped when specified." << tcu::TestLog::EndMessage;
213 
214 		gl.glMinSampleShading(-0.5f);
215 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 0.0, QUERY_FLOAT);
216 
217 		gl.glMinSampleShading(-1.0f);
218 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 0.0, QUERY_FLOAT);
219 
220 		gl.glMinSampleShading(-1.5f);
221 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 0.0, QUERY_FLOAT);
222 
223 		gl.glMinSampleShading(1.5f);
224 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 1.0, QUERY_FLOAT);
225 
226 		gl.glMinSampleShading(2.0f);
227 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 1.0, QUERY_FLOAT);
228 
229 		gl.glMinSampleShading(2.5f);
230 		verifyStateFloat(result, gl, GL_MIN_SAMPLE_SHADING_VALUE, 1.0, QUERY_FLOAT);
231 	}
232 
233 	result.setTestContextResult(m_testCtx);
234 	return STOP;
235 }
236 
237 class SampleShadingRenderingCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
238 {
239 public:
240 	enum TestType
241 	{
242 		TEST_DISCARD = 0,
243 		TEST_COLOR,
244 
245 		TEST_LAST
246 	};
247 						SampleShadingRenderingCase	(Context& ctx, const char* name, const char* desc, RenderTarget target, int numSamples, TestType type);
248 						~SampleShadingRenderingCase	(void);
249 
250 	void				init						(void);
251 private:
252 	void				setShadingValue				(int sampleCount);
253 
254 	void				preDraw						(void);
255 	void				postDraw					(void);
256 	std::string			getIterationDescription		(int iteration) const;
257 
258 	bool				verifyImage					(const tcu::Surface& resultImage);
259 
260 	std::string			genFragmentSource			(int numSamples) const;
261 
262 	enum
263 	{
264 		RENDER_SIZE = 128
265 	};
266 
267 	const TestType		m_type;
268 };
269 
SampleShadingRenderingCase(Context & ctx,const char * name,const char * desc,RenderTarget target,int numSamples,TestType type)270 SampleShadingRenderingCase::SampleShadingRenderingCase (Context& ctx, const char* name, const char* desc, RenderTarget target, int numSamples, TestType type)
271 	: MultisampleShaderRenderUtil::MultisampleRenderCase	(ctx, name, desc, numSamples, target, RENDER_SIZE)
272 	, m_type												(type)
273 {
274 	DE_ASSERT(type < TEST_LAST);
275 }
276 
~SampleShadingRenderingCase(void)277 SampleShadingRenderingCase::~SampleShadingRenderingCase (void)
278 {
279 	deinit();
280 }
281 
init(void)282 void SampleShadingRenderingCase::init (void)
283 {
284 	// requirements
285 	if (!checkSupport(m_context))
286 		throw tcu::NotSupportedError("Test requires GL_OES_sample_shading extension or a context version 3.2 or higher.");
287 	if (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1)
288 		throw tcu::NotSupportedError("Multisampled default framebuffer required");
289 
290 	// test purpose and expectations
291 	m_testCtx.getLog()
292 		<< tcu::TestLog::Message
293 		<< "Verifying that a varying is given at least N different values for different samples within a single pixel.\n"
294 		<< "	Render high-frequency function, map result to black/white. Modify N with glMinSampleShading().\n"
295 		<< "	=> Resulting image should contain N+1 shades of gray.\n"
296 		<< tcu::TestLog::EndMessage;
297 
298 	// setup resources
299 
300 	MultisampleShaderRenderUtil::MultisampleRenderCase::init();
301 
302 	// set iterations
303 
304 	m_numIterations = m_numTargetSamples + 1;
305 }
306 
setShadingValue(int sampleCount)307 void SampleShadingRenderingCase::setShadingValue (int sampleCount)
308 {
309 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
310 
311 	if (sampleCount == 0)
312 	{
313 		gl.disable(GL_SAMPLE_SHADING);
314 		gl.minSampleShading(1.0f);
315 		GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
316 	}
317 	else
318 	{
319 		// Minimum number of samples is max(ceil(<mss> * <samples>),1). Decrease mss with epsilon to prevent
320 		// ceiling to a too large sample count.
321 		const float epsilon	= 0.25f / (float)m_numTargetSamples;
322 		const float ratio	= ((float)sampleCount / (float)m_numTargetSamples) - epsilon;
323 
324 		gl.enable(GL_SAMPLE_SHADING);
325 		gl.minSampleShading(ratio);
326 		GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
327 
328 		m_testCtx.getLog()
329 			<< tcu::TestLog::Message
330 			<< "Setting MIN_SAMPLE_SHADING_VALUE = " << ratio << "\n"
331 			<< "Requested sample count: shadingValue * numSamples = " << ratio << " * " << m_numTargetSamples << " = " << (ratio * (float)m_numTargetSamples) << "\n"
332 			<< "Minimum sample count: ceil(shadingValue * numSamples) = ceil(" << (ratio * (float)m_numTargetSamples) << ") = " << sampleCount
333 			<< tcu::TestLog::EndMessage;
334 
335 		// can't fail with reasonable values of numSamples
336 		DE_ASSERT(deFloatCeil(ratio * (float)m_numTargetSamples) == float(sampleCount));
337 	}
338 }
339 
preDraw(void)340 void SampleShadingRenderingCase::preDraw (void)
341 {
342 	setShadingValue(m_iteration);
343 }
344 
postDraw(void)345 void SampleShadingRenderingCase::postDraw (void)
346 {
347 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
348 
349 	gl.disable(GL_SAMPLE_SHADING);
350 	gl.minSampleShading(1.0f);
351 }
352 
getIterationDescription(int iteration) const353 std::string	SampleShadingRenderingCase::getIterationDescription (int iteration) const
354 {
355 	if (iteration == 0)
356 		return "Disabled SAMPLE_SHADING";
357 	else
358 		return "Samples per pixel: " + de::toString(iteration);
359 }
360 
verifyImage(const tcu::Surface & resultImage)361 bool SampleShadingRenderingCase::verifyImage (const tcu::Surface& resultImage)
362 {
363 	const int				numShadesRequired	= (m_iteration == 0) ? (2) : (m_iteration + 1);
364 	const int				rareThreshold		= 100;
365 	int						rareCount			= 0;
366 	std::map<deUint32, int>	shadeFrequency;
367 
368 	// we should now have n+1 different shades of white, n = num samples
369 
370 	m_testCtx.getLog()
371 		<< tcu::TestLog::Image("ResultImage", "Result Image", resultImage.getAccess())
372 		<< tcu::TestLog::Message
373 		<< "Verifying image has (at least) " << numShadesRequired << " different shades.\n"
374 		<< "Excluding pixels with no full coverage (pixels on the shared edge of the triangle pair)."
375 		<< tcu::TestLog::EndMessage;
376 
377 	for (int y = 0; y < RENDER_SIZE; ++y)
378 	for (int x = 0; x < RENDER_SIZE; ++x)
379 	{
380 		const tcu::RGBA	color	= resultImage.getPixel(x, y);
381 		const deUint32	packed	= ((deUint32)color.getRed()) + ((deUint32)color.getGreen() << 8) + ((deUint32)color.getGreen() << 16);
382 
383 		// on the triangle edge, skip
384 		if (x == y)
385 			continue;
386 
387 		if (shadeFrequency.find(packed) == shadeFrequency.end())
388 			shadeFrequency[packed] = 1;
389 		else
390 			shadeFrequency[packed] = shadeFrequency[packed] + 1;
391 	}
392 
393 	for (std::map<deUint32, int>::const_iterator it = shadeFrequency.begin(); it != shadeFrequency.end(); ++it)
394 		if (it->second < rareThreshold)
395 			rareCount++;
396 
397 	m_testCtx.getLog()
398 		<< tcu::TestLog::Message
399 		<< "Found " << (int)shadeFrequency.size() << " different shades.\n"
400 		<< "\tRare (less than " << rareThreshold << " pixels): " << rareCount << "\n"
401 		<< "\tCommon: " << (int)shadeFrequency.size() - rareCount << "\n"
402 		<< tcu::TestLog::EndMessage;
403 
404 	if ((int)shadeFrequency.size() < numShadesRequired)
405 	{
406 		m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage;
407 		return false;
408 	}
409 	return true;
410 }
411 
genFragmentSource(int numSamples) const412 std::string SampleShadingRenderingCase::genFragmentSource (int numSamples) const
413 {
414 	DE_UNREF(numSamples);
415 
416         const bool supportsES32orGL45 =
417 		glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
418 		glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
419 
420 	const glu::GLSLVersion	version	= supportsES32orGL45 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
421 	std::ostringstream		buf;
422 
423 	buf <<	glu::getGLSLVersionDeclaration(version) << "\n"
424 			"in highp vec4 v_position;\n"
425 			"layout(location = 0) out mediump vec4 fragColor;\n"
426 			"void main (void)\n"
427 			"{\n"
428 			"	highp float field = dot(v_position.xy, v_position.xy) + dot(21.0 * v_position.xx, sin(3.1 * v_position.xy));\n"
429 			"	fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
430 			"\n"
431 			"	if (fract(field) > 0.5)\n";
432 
433 	if (m_type == TEST_DISCARD)
434 		buf <<	"		discard;\n";
435 	else if (m_type == TEST_COLOR)
436 		buf <<	"		fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n";
437 	else
438 		DE_ASSERT(false);
439 
440 	buf <<	"}";
441 
442 	return buf.str();
443 }
444 
445 } // anonymous
446 
SampleShadingTests(Context & context)447 SampleShadingTests::SampleShadingTests (Context& context)
448 	: TestCaseGroup(context, "sample_shading", "Test sample shading")
449 {
450 }
451 
~SampleShadingTests(void)452 SampleShadingTests::~SampleShadingTests (void)
453 {
454 }
455 
init(void)456 void SampleShadingTests::init (void)
457 {
458 	tcu::TestCaseGroup* const stateQueryGroup = new tcu::TestCaseGroup(m_testCtx, "state_query", "State query tests.");
459 	tcu::TestCaseGroup* const minSamplesGroup = new tcu::TestCaseGroup(m_testCtx, "min_sample_shading", "Min sample shading tests.");
460 
461 	addChild(stateQueryGroup);
462 	addChild(minSamplesGroup);
463 
464 	// .state query
465 	{
466 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_is_enabled",				"test SAMPLE_SHADING",						QUERY_ISENABLED));
467 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_get_boolean",				"test SAMPLE_SHADING",						QUERY_BOOLEAN));
468 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_get_integer",				"test SAMPLE_SHADING",						QUERY_INTEGER));
469 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_get_float",					"test SAMPLE_SHADING",						QUERY_FLOAT));
470 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_get_integer64",				"test SAMPLE_SHADING",						QUERY_INTEGER64));
471 		stateQueryGroup->addChild(new MinSampleShadingValueCase			(m_context, "min_sample_shading_value_get_boolean",		"test MIN_SAMPLE_SHADING_VALUE",			QUERY_BOOLEAN));
472 		stateQueryGroup->addChild(new MinSampleShadingValueCase			(m_context, "min_sample_shading_value_get_integer",		"test MIN_SAMPLE_SHADING_VALUE",			QUERY_INTEGER));
473 		stateQueryGroup->addChild(new MinSampleShadingValueCase			(m_context, "min_sample_shading_value_get_float",		"test MIN_SAMPLE_SHADING_VALUE",			QUERY_FLOAT));
474 		stateQueryGroup->addChild(new MinSampleShadingValueCase			(m_context, "min_sample_shading_value_get_integer64",	"test MIN_SAMPLE_SHADING_VALUE",			QUERY_INTEGER64));
475 		stateQueryGroup->addChild(new MinSampleShadingValueClampingCase	(m_context, "min_sample_shading_value_clamping",		"test MIN_SAMPLE_SHADING_VALUE clamping"));
476 	}
477 
478 	// .min_sample_count
479 	{
480 		static const struct Target
481 		{
482 			SampleShadingRenderingCase::RenderTarget	target;
483 			int											numSamples;
484 			const char*									name;
485 		} targets[] =
486 		{
487 			{ SampleShadingRenderingCase::TARGET_DEFAULT,			0,	"default_framebuffer"					},
488 			{ SampleShadingRenderingCase::TARGET_TEXTURE,			2,	"multisample_texture_samples_2"			},
489 			{ SampleShadingRenderingCase::TARGET_TEXTURE,			4,	"multisample_texture_samples_4"			},
490 			{ SampleShadingRenderingCase::TARGET_TEXTURE,			8,	"multisample_texture_samples_8"			},
491 			{ SampleShadingRenderingCase::TARGET_TEXTURE,			16,	"multisample_texture_samples_16"		},
492 			{ SampleShadingRenderingCase::TARGET_RENDERBUFFER,		2,	"multisample_renderbuffer_samples_2"	},
493 			{ SampleShadingRenderingCase::TARGET_RENDERBUFFER,		4,	"multisample_renderbuffer_samples_4"	},
494 			{ SampleShadingRenderingCase::TARGET_RENDERBUFFER,		8,	"multisample_renderbuffer_samples_8"	},
495 			{ SampleShadingRenderingCase::TARGET_RENDERBUFFER,		16,	"multisample_renderbuffer_samples_16"	},
496 		};
497 
498 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(targets); ++ndx)
499 		{
500 			minSamplesGroup->addChild(new SampleShadingRenderingCase(m_context, (std::string(targets[ndx].name) + "_color").c_str(),	"Test multiple samples per pixel with color",	targets[ndx].target, targets[ndx].numSamples, SampleShadingRenderingCase::TEST_COLOR));
501 			minSamplesGroup->addChild(new SampleShadingRenderingCase(m_context, (std::string(targets[ndx].name) + "_discard").c_str(),	"Test multiple samples per pixel with",			targets[ndx].target, targets[ndx].numSamples, SampleShadingRenderingCase::TEST_DISCARD));
502 		}
503 	}
504 }
505 
506 } // Functional
507 } // gles31
508 } // deqp
509