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 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 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 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 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 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 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 183 MinSampleShadingValueClampingCase::MinSampleShadingValueClampingCase (Context& ctx, const char* name, const char* desc) 184 : TestCase(ctx, name, desc) 185 { 186 } 187 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 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 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 269 SampleShadingRenderingCase::~SampleShadingRenderingCase (void) 270 { 271 deinit(); 272 } 273 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 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 333 void SampleShadingRenderingCase::preDraw (void) 334 { 335 setShadingValue(m_iteration); 336 } 337 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 346 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 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 405 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 437 SampleShadingTests::SampleShadingTests (Context& context) 438 : TestCaseGroup(context, "sample_shading", "Test sample shading") 439 { 440 } 441 442 SampleShadingTests::~SampleShadingTests (void) 443 { 444 } 445 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