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