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