xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fSampleShadingTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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