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