1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkTypes.h" 9 #include "Test.h" 10 11 #include "GrClip.h" 12 #include "GrContext.h" 13 #include "GrContextPriv.h" 14 #include "GrGpuResource.h" 15 #include "GrMemoryPool.h" 16 #include "GrProxyProvider.h" 17 #include "GrRenderTargetContext.h" 18 #include "GrRenderTargetContextPriv.h" 19 #include "GrResourceProvider.h" 20 #include "glsl/GrGLSLFragmentProcessor.h" 21 #include "glsl/GrGLSLFragmentShaderBuilder.h" 22 #include "ops/GrFillRectOp.h" 23 #include "ops/GrMeshDrawOp.h" 24 #include "TestUtils.h" 25 26 #include <atomic> 27 #include <random> 28 29 namespace { 30 class TestOp : public GrMeshDrawOp { 31 public: 32 DEFINE_OP_CLASS_ID 33 static std::unique_ptr<GrDrawOp> Make(GrContext* context, 34 std::unique_ptr<GrFragmentProcessor> fp) { 35 GrOpMemoryPool* pool = context->priv().opMemoryPool(); 36 37 return pool->allocate<TestOp>(std::move(fp)); 38 } 39 40 const char* name() const override { return "TestOp"; } 41 42 void visitProxies(const VisitProxyFunc& func, VisitorType) const override { 43 fProcessors.visitProxies(func); 44 } 45 46 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } 47 48 GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip, 49 GrFSAAType fsaaType, GrClampType clampType) override { 50 static constexpr GrProcessorAnalysisColor kUnknownColor; 51 SkPMColor4f overrideColor; 52 return fProcessors.finalize( 53 kUnknownColor, GrProcessorAnalysisCoverage::kNone, clip, 54 &GrUserStencilSettings::kUnused, fsaaType, caps, clampType, &overrideColor); 55 } 56 57 private: 58 friend class ::GrOpMemoryPool; // for ctor 59 60 TestOp(std::unique_ptr<GrFragmentProcessor> fp) 61 : INHERITED(ClassID()), fProcessors(std::move(fp)) { 62 this->setBounds(SkRect::MakeWH(100, 100), HasAABloat::kNo, IsZeroArea::kNo); 63 } 64 65 void onPrepareDraws(Target* target) override { return; } 66 void onExecute(GrOpFlushState*, const SkRect&) override { return; } 67 68 GrProcessorSet fProcessors; 69 70 typedef GrMeshDrawOp INHERITED; 71 }; 72 73 /** 74 * FP used to test ref/IO counts on owned GrGpuResources. Can also be a parent FP to test counts 75 * of resources owned by child FPs. 76 */ 77 class TestFP : public GrFragmentProcessor { 78 public: 79 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child) { 80 return std::unique_ptr<GrFragmentProcessor>(new TestFP(std::move(child))); 81 } 82 static std::unique_ptr<GrFragmentProcessor> Make(const SkTArray<sk_sp<GrTextureProxy>>& proxies, 83 const SkTArray<sk_sp<GrGpuBuffer>>& buffers) { 84 return std::unique_ptr<GrFragmentProcessor>(new TestFP(proxies, buffers)); 85 } 86 87 const char* name() const override { return "test"; } 88 89 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { 90 static std::atomic<int32_t> nextKey{0}; 91 b->add32(nextKey++); 92 } 93 94 std::unique_ptr<GrFragmentProcessor> clone() const override { 95 return std::unique_ptr<GrFragmentProcessor>(new TestFP(*this)); 96 } 97 98 private: 99 TestFP(const SkTArray<sk_sp<GrTextureProxy>>& proxies, 100 const SkTArray<sk_sp<GrGpuBuffer>>& buffers) 101 : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags), fSamplers(4) { 102 for (const auto& proxy : proxies) { 103 fSamplers.emplace_back(proxy); 104 } 105 this->setTextureSamplerCnt(fSamplers.count()); 106 } 107 108 TestFP(std::unique_ptr<GrFragmentProcessor> child) 109 : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags), fSamplers(4) { 110 this->registerChildProcessor(std::move(child)); 111 } 112 113 explicit TestFP(const TestFP& that) 114 : INHERITED(kTestFP_ClassID, that.optimizationFlags()), fSamplers(4) { 115 for (int i = 0; i < that.fSamplers.count(); ++i) { 116 fSamplers.emplace_back(that.fSamplers[i]); 117 } 118 for (int i = 0; i < that.numChildProcessors(); ++i) { 119 this->registerChildProcessor(that.childProcessor(i).clone()); 120 } 121 this->setTextureSamplerCnt(fSamplers.count()); 122 } 123 124 virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { 125 class TestGLSLFP : public GrGLSLFragmentProcessor { 126 public: 127 TestGLSLFP() {} 128 void emitCode(EmitArgs& args) override { 129 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 130 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor); 131 } 132 133 private: 134 }; 135 return new TestGLSLFP(); 136 } 137 138 bool onIsEqual(const GrFragmentProcessor&) const override { return false; } 139 const TextureSampler& onTextureSampler(int i) const override { return fSamplers[i]; } 140 141 GrTAllocator<TextureSampler> fSamplers; 142 typedef GrFragmentProcessor INHERITED; 143 }; 144 } 145 146 template <typename T> 147 inline void testingOnly_getIORefCnts(const T* resource, int* refCnt, int* readCnt, int* writeCnt) { 148 *refCnt = resource->fRefCnt; 149 *readCnt = resource->fPendingReads; 150 *writeCnt = resource->fPendingWrites; 151 } 152 153 void testingOnly_getIORefCnts(GrTextureProxy* proxy, int* refCnt, int* readCnt, int* writeCnt) { 154 *refCnt = proxy->getBackingRefCnt_TestOnly(); 155 *readCnt = proxy->getPendingReadCnt_TestOnly(); 156 *writeCnt = proxy->getPendingWriteCnt_TestOnly(); 157 } 158 159 DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) { 160 GrContext* context = ctxInfo.grContext(); 161 GrProxyProvider* proxyProvider = context->priv().proxyProvider(); 162 163 GrSurfaceDesc desc; 164 desc.fWidth = 10; 165 desc.fHeight = 10; 166 desc.fConfig = kRGBA_8888_GrPixelConfig; 167 168 const GrBackendFormat format = 169 context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); 170 171 for (bool makeClone : {false, true}) { 172 for (int parentCnt = 0; parentCnt < 2; parentCnt++) { 173 sk_sp<GrRenderTargetContext> renderTargetContext( 174 context->priv().makeDeferredRenderTargetContext( 175 format, SkBackingFit::kApprox, 1, 1, 176 kRGBA_8888_GrPixelConfig, nullptr)); 177 { 178 sk_sp<GrTextureProxy> proxy1 = proxyProvider->createProxy( 179 format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact, 180 SkBudgeted::kYes); 181 sk_sp<GrTextureProxy> proxy2 = proxyProvider->createProxy( 182 format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact, 183 SkBudgeted::kYes); 184 sk_sp<GrTextureProxy> proxy3 = proxyProvider->createProxy( 185 format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact, 186 SkBudgeted::kYes); 187 sk_sp<GrTextureProxy> proxy4 = proxyProvider->createProxy( 188 format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact, 189 SkBudgeted::kYes); 190 { 191 SkTArray<sk_sp<GrTextureProxy>> proxies; 192 SkTArray<sk_sp<GrGpuBuffer>> buffers; 193 proxies.push_back(proxy1); 194 auto fp = TestFP::Make(std::move(proxies), std::move(buffers)); 195 for (int i = 0; i < parentCnt; ++i) { 196 fp = TestFP::Make(std::move(fp)); 197 } 198 std::unique_ptr<GrFragmentProcessor> clone; 199 if (makeClone) { 200 clone = fp->clone(); 201 } 202 std::unique_ptr<GrDrawOp> op(TestOp::Make(context, std::move(fp))); 203 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op)); 204 if (clone) { 205 op = TestOp::Make(context, std::move(clone)); 206 renderTargetContext->priv().testingOnly_addDrawOp(std::move(op)); 207 } 208 } 209 int refCnt, readCnt, writeCnt; 210 211 testingOnly_getIORefCnts(proxy1.get(), &refCnt, &readCnt, &writeCnt); 212 // IO counts should be double if there is a clone of the FP. 213 int ioRefMul = makeClone ? 2 : 1; 214 REPORTER_ASSERT(reporter, -1 == refCnt); 215 REPORTER_ASSERT(reporter, ioRefMul * 1 == readCnt); 216 REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt); 217 218 context->flush(); 219 220 testingOnly_getIORefCnts(proxy1.get(), &refCnt, &readCnt, &writeCnt); 221 REPORTER_ASSERT(reporter, 1 == refCnt); 222 REPORTER_ASSERT(reporter, ioRefMul * 0 == readCnt); 223 REPORTER_ASSERT(reporter, ioRefMul * 0 == writeCnt); 224 225 } 226 } 227 } 228 } 229 230 // This test uses the random GrFragmentProcessor test factory, which relies on static initializers. 231 #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 232 233 #include "SkCommandLineFlags.h" 234 DEFINE_bool(randomProcessorTest, false, "Use non-deterministic seed for random processor tests?"); 235 DEFINE_uint32(processorSeed, 0, "Use specific seed for processor tests. Overridden by " \ 236 "--randomProcessorTest."); 237 238 #if GR_TEST_UTILS 239 240 static GrColor input_texel_color(int i, int j, SkScalar delta) { 241 // Delta must be less than 0.5 to prevent over/underflow issues with the input color 242 SkASSERT(delta <= 0.5); 243 244 SkColor color = SkColorSetARGB((uint8_t)(i & 0xFF), 245 (uint8_t)(j & 0xFF), 246 (uint8_t)((i + j) & 0xFF), 247 (uint8_t)((2 * j - i) & 0xFF)); 248 SkColor4f color4f = SkColor4f::FromColor(color); 249 for (int i = 0; i < 4; i++) { 250 if (color4f[i] > 0.5) { 251 color4f[i] -= delta; 252 } else { 253 color4f[i] += delta; 254 } 255 } 256 return color4f.premul().toBytes_RGBA(); 257 } 258 259 void test_draw_op(GrContext* context, 260 GrRenderTargetContext* rtc, 261 std::unique_ptr<GrFragmentProcessor> fp, 262 sk_sp<GrTextureProxy> inputDataProxy) { 263 GrPaint paint; 264 paint.addColorTextureProcessor(std::move(inputDataProxy), SkMatrix::I()); 265 paint.addColorFragmentProcessor(std::move(fp)); 266 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 267 268 auto op = GrFillRectOp::Make(context, std::move(paint), GrAAType::kNone, SkMatrix::I(), 269 SkRect::MakeWH(rtc->width(), rtc->height())); 270 rtc->addDrawOp(GrNoClip(), std::move(op)); 271 } 272 273 // This assumes that the output buffer will be the same size as inputDataProxy 274 void render_fp(GrContext* context, GrRenderTargetContext* rtc, GrFragmentProcessor* fp, 275 sk_sp<GrTextureProxy> inputDataProxy, GrColor* buffer) { 276 int width = inputDataProxy->width(); 277 int height = inputDataProxy->height(); 278 279 // test_draw_op needs to take ownership of an FP, so give it a clone that it can own 280 test_draw_op(context, rtc, fp->clone(), inputDataProxy); 281 memset(buffer, 0x0, sizeof(GrColor) * width * height); 282 rtc->readPixels(SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, 283 kPremul_SkAlphaType), 284 buffer, 0, 0, 0); 285 } 286 287 /** Initializes the two test texture proxies that are available to the FP test factories. */ 288 bool init_test_textures(GrProxyProvider* proxyProvider, SkRandom* random, 289 sk_sp<GrTextureProxy> proxies[2]) { 290 static const int kTestTextureSize = 256; 291 292 { 293 // Put premul data into the RGBA texture that the test FPs can optionally use. 294 std::unique_ptr<GrColor[]> rgbaData(new GrColor[kTestTextureSize * kTestTextureSize]); 295 for (int y = 0; y < kTestTextureSize; ++y) { 296 for (int x = 0; x < kTestTextureSize; ++x) { 297 rgbaData[kTestTextureSize * y + x] = input_texel_color( 298 random->nextULessThan(256), random->nextULessThan(256), 0.0f); 299 } 300 } 301 302 SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize, 303 kRGBA_8888_SkColorType, kPremul_SkAlphaType); 304 SkPixmap pixmap(ii, rgbaData.get(), ii.minRowBytes()); 305 sk_sp<SkImage> img = SkImage::MakeRasterCopy(pixmap); 306 proxies[0] = proxyProvider->createTextureProxy(img, kNone_GrSurfaceFlags, 1, 307 SkBudgeted::kYes, SkBackingFit::kExact); 308 } 309 310 { 311 // Put random values into the alpha texture that the test FPs can optionally use. 312 std::unique_ptr<uint8_t[]> alphaData(new uint8_t[kTestTextureSize * kTestTextureSize]); 313 for (int y = 0; y < kTestTextureSize; ++y) { 314 for (int x = 0; x < kTestTextureSize; ++x) { 315 alphaData[kTestTextureSize * y + x] = random->nextULessThan(256); 316 } 317 } 318 319 SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize, 320 kAlpha_8_SkColorType, kPremul_SkAlphaType); 321 SkPixmap pixmap(ii, alphaData.get(), ii.minRowBytes()); 322 sk_sp<SkImage> img = SkImage::MakeRasterCopy(pixmap); 323 proxies[1] = proxyProvider->createTextureProxy(img, kNone_GrSurfaceFlags, 1, 324 SkBudgeted::kYes, SkBackingFit::kExact); 325 } 326 327 return proxies[0] && proxies[1]; 328 } 329 330 // Creates a texture of premul colors used as the output of the fragment processor that precedes 331 // the fragment processor under test. Color values are those provided by input_texel_color(). 332 sk_sp<GrTextureProxy> make_input_texture(GrProxyProvider* proxyProvider, int width, int height, 333 SkScalar delta) { 334 std::unique_ptr<GrColor[]> data(new GrColor[width * height]); 335 for (int y = 0; y < width; ++y) { 336 for (int x = 0; x < height; ++x) { 337 data.get()[width * y + x] = input_texel_color(x, y, delta); 338 } 339 } 340 341 SkImageInfo ii = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType); 342 SkPixmap pixmap(ii, data.get(), ii.minRowBytes()); 343 sk_sp<SkImage> img = SkImage::MakeRasterCopy(pixmap); 344 return proxyProvider->createTextureProxy(img, kNone_GrSurfaceFlags, 1, 345 SkBudgeted::kYes, SkBackingFit::kExact); 346 } 347 348 bool log_surface_context(sk_sp<GrSurfaceContext> src, SkString* dst) { 349 SkImageInfo ii = SkImageInfo::Make(src->width(), src->height(), kRGBA_8888_SkColorType, 350 kPremul_SkAlphaType); 351 SkBitmap bm; 352 SkAssertResult(bm.tryAllocPixels(ii)); 353 SkAssertResult(src->readPixels(ii, bm.getPixels(), bm.rowBytes(), 0, 0)); 354 355 return bitmap_to_base64_data_uri(bm, dst); 356 } 357 358 bool log_surface_proxy(GrContext* context, sk_sp<GrSurfaceProxy> src, SkString* dst) { 359 sk_sp<GrSurfaceContext> sContext(context->priv().makeWrappedSurfaceContext(src)); 360 return log_surface_context(sContext, dst); 361 } 362 363 bool fuzzy_color_equals(const SkPMColor4f& c1, const SkPMColor4f& c2) { 364 // With the loss of precision of rendering into 32-bit color, then estimating the FP's output 365 // from that, it is not uncommon for a valid output to differ from estimate by up to 0.01 366 // (really 1/128 ~ .0078, but frequently floating point issues make that tolerance a little 367 // too unforgiving). 368 static constexpr SkScalar kTolerance = 0.01f; 369 for (int i = 0; i < 4; i++) { 370 if (!SkScalarNearlyEqual(c1[i], c2[i], kTolerance)) { 371 return false; 372 } 373 } 374 return true; 375 } 376 377 int modulation_index(int channelIndex, bool alphaModulation) { 378 return alphaModulation ? 3 : channelIndex; 379 } 380 381 // Given three input colors (color preceding the FP being tested), and the output of the FP, this 382 // ensures that the out1 = fp * in1.a, out2 = fp * in2.a, and out3 = fp * in3.a, where fp is the 383 // pre-modulated color that should not be changing across frames (FP's state doesn't change). 384 // 385 // When alphaModulation is false, this tests the very similar conditions that out1 = fp * in1, 386 // etc. using per-channel modulation instead of modulation by just the input alpha channel. 387 // - This estimates the pre-modulated fp color from one of the input/output pairs and confirms the 388 // conditions hold for the other two pairs. 389 bool legal_modulation(const GrColor& in1, const GrColor& in2, const GrColor& in3, 390 const GrColor& out1, const GrColor& out2, const GrColor& out3, 391 bool alphaModulation) { 392 // Convert to floating point, which is the number space the FP operates in (more or less) 393 SkPMColor4f in1f = SkPMColor4f::FromBytes_RGBA(in1); 394 SkPMColor4f in2f = SkPMColor4f::FromBytes_RGBA(in2); 395 SkPMColor4f in3f = SkPMColor4f::FromBytes_RGBA(in3); 396 SkPMColor4f out1f = SkPMColor4f::FromBytes_RGBA(out1); 397 SkPMColor4f out2f = SkPMColor4f::FromBytes_RGBA(out2); 398 SkPMColor4f out3f = SkPMColor4f::FromBytes_RGBA(out3); 399 400 // Reconstruct the output of the FP before the shader modulated its color with the input value. 401 // When the original input is very small, it may cause the final output color to round 402 // to 0, in which case we estimate the pre-modulated color using one of the stepped frames that 403 // will then have a guaranteed larger channel value (since the offset will be added to it). 404 SkPMColor4f fpPreModulation; 405 for (int i = 0; i < 4; i++) { 406 int modulationIndex = modulation_index(i, alphaModulation); 407 if (in1f[modulationIndex] < 0.2f) { 408 // Use the stepped frame 409 fpPreModulation[i] = out2f[i] / in2f[modulationIndex]; 410 } else { 411 fpPreModulation[i] = out1f[i] / in1f[modulationIndex]; 412 } 413 } 414 415 // With reconstructed pre-modulated FP output, derive the expected value of fp * input for each 416 // of the transformed input colors. 417 SkPMColor4f expected1 = alphaModulation ? (fpPreModulation * in1f.fA) 418 : (fpPreModulation * in1f); 419 SkPMColor4f expected2 = alphaModulation ? (fpPreModulation * in2f.fA) 420 : (fpPreModulation * in2f); 421 SkPMColor4f expected3 = alphaModulation ? (fpPreModulation * in3f.fA) 422 : (fpPreModulation * in3f); 423 424 return fuzzy_color_equals(out1f, expected1) && 425 fuzzy_color_equals(out2f, expected2) && 426 fuzzy_color_equals(out3f, expected3); 427 } 428 429 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) { 430 GrContext* context = ctxInfo.grContext(); 431 GrProxyProvider* proxyProvider = context->priv().proxyProvider(); 432 auto resourceProvider = context->priv().resourceProvider(); 433 using FPFactory = GrFragmentProcessorTestFactory; 434 435 uint32_t seed = FLAGS_processorSeed; 436 if (FLAGS_randomProcessorTest) { 437 std::random_device rd; 438 seed = rd(); 439 } 440 // If a non-deterministic bot fails this test, check the output to see what seed it used, then 441 // use --processorSeed <seed> (without --randomProcessorTest) to reproduce. 442 SkRandom random(seed); 443 444 const GrBackendFormat format = 445 context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); 446 447 // Make the destination context for the test. 448 static constexpr int kRenderSize = 256; 449 sk_sp<GrRenderTargetContext> rtc = context->priv().makeDeferredRenderTargetContext( 450 format, SkBackingFit::kExact, kRenderSize, kRenderSize, kRGBA_8888_GrPixelConfig, 451 nullptr); 452 453 sk_sp<GrTextureProxy> proxies[2]; 454 if (!init_test_textures(proxyProvider, &random, proxies)) { 455 ERRORF(reporter, "Could not create test textures"); 456 return; 457 } 458 GrProcessorTestData testData(&random, context, rtc.get(), proxies); 459 460 // Coverage optimization uses three frames with a linearly transformed input texture. The first 461 // frame has no offset, second frames add .2 and .4, which should then be present as a fixed 462 // difference between the frame outputs if the FP is properly following the modulation 463 // requirements of the coverage optimization. 464 static constexpr SkScalar kInputDelta = 0.2f; 465 auto inputTexture1 = make_input_texture(proxyProvider, kRenderSize, kRenderSize, 0.0f); 466 auto inputTexture2 = make_input_texture(proxyProvider, kRenderSize, kRenderSize, kInputDelta); 467 auto inputTexture3 = make_input_texture(proxyProvider, kRenderSize, kRenderSize, 2*kInputDelta); 468 469 // Encoded images are very verbose and this tests many potential images, so only export the 470 // first failure (subsequent failures have a reasonable chance of being related). 471 bool loggedFirstFailure = false; 472 bool loggedFirstWarning = false; 473 474 // Storage for the three frames required for coverage compatibility optimization. Each frame 475 // uses the correspondingly numbered inputTextureX. 476 std::unique_ptr<GrColor[]> readData1(new GrColor[kRenderSize * kRenderSize]); 477 std::unique_ptr<GrColor[]> readData2(new GrColor[kRenderSize * kRenderSize]); 478 std::unique_ptr<GrColor[]> readData3(new GrColor[kRenderSize * kRenderSize]); 479 480 // Because processor factories configure themselves in random ways, this is not exhaustive. 481 for (int i = 0; i < FPFactory::Count(); ++i) { 482 int timesToInvokeFactory = 5; 483 // Increase the number of attempts if the FP has child FPs since optimizations likely depend 484 // on child optimizations being present. 485 std::unique_ptr<GrFragmentProcessor> fp = FPFactory::MakeIdx(i, &testData); 486 for (int j = 0; j < fp->numChildProcessors(); ++j) { 487 // This value made a reasonable trade off between time and coverage when this test was 488 // written. 489 timesToInvokeFactory *= FPFactory::Count() / 2; 490 } 491 #if defined(__MSVC_RUNTIME_CHECKS) 492 // This test is infuriatingly slow with MSVC runtime checks enabled 493 timesToInvokeFactory = 1; 494 #endif 495 for (int j = 0; j < timesToInvokeFactory; ++j) { 496 fp = FPFactory::MakeIdx(i, &testData); 497 if (!fp->instantiate(resourceProvider)) { 498 continue; 499 } 500 501 if (!fp->hasConstantOutputForConstantInput() && !fp->preservesOpaqueInput() && 502 !fp->compatibleWithCoverageAsAlpha()) { 503 continue; 504 } 505 506 if (fp->compatibleWithCoverageAsAlpha()) { 507 // 2nd and 3rd frames are only used when checking coverage optimization 508 render_fp(context, rtc.get(), fp.get(), inputTexture2, readData2.get()); 509 render_fp(context, rtc.get(), fp.get(), inputTexture3, readData3.get()); 510 } 511 // Draw base frame last so that rtc holds the original FP behavior if we need to 512 // dump the image to the log. 513 render_fp(context, rtc.get(), fp.get(), inputTexture1, readData1.get()); 514 515 if (0) { // Useful to see what FPs are being tested. 516 SkString children; 517 for (int c = 0; c < fp->numChildProcessors(); ++c) { 518 if (!c) { 519 children.append("("); 520 } 521 children.append(fp->childProcessor(c).name()); 522 children.append(c == fp->numChildProcessors() - 1 ? ")" : ", "); 523 } 524 SkDebugf("%s %s\n", fp->name(), children.c_str()); 525 } 526 527 // This test has a history of being flaky on a number of devices. If an FP is logically 528 // violating the optimizations, it's reasonable to expect it to violate requirements on 529 // a large number of pixels in the image. Sporadic pixel violations are more indicative 530 // of device errors and represents a separate problem. 531 #if defined(SK_BUILD_FOR_SKQP) 532 static constexpr int kMaxAcceptableFailedPixels = 0; // Strict when running as SKQP 533 #else 534 static constexpr int kMaxAcceptableFailedPixels = 2 * kRenderSize; // ~0.7% of the image 535 #endif 536 537 int failedPixelCount = 0; 538 // Collect first optimization failure message, to be output later as a warning or an 539 // error depending on whether the rendering "passed" or failed. 540 SkString coverageMessage; 541 SkString opaqueMessage; 542 SkString constMessage; 543 for (int y = 0; y < kRenderSize; ++y) { 544 for (int x = 0; x < kRenderSize; ++x) { 545 bool passing = true; 546 GrColor input = input_texel_color(x, y, 0.0f); 547 GrColor output = readData1.get()[y * kRenderSize + x]; 548 549 if (fp->compatibleWithCoverageAsAlpha()) { 550 GrColor i2 = input_texel_color(x, y, kInputDelta); 551 GrColor i3 = input_texel_color(x, y, 2 * kInputDelta); 552 553 GrColor o2 = readData2.get()[y * kRenderSize + x]; 554 GrColor o3 = readData3.get()[y * kRenderSize + x]; 555 556 // A compatible processor is allowed to modulate either the input color or 557 // just the input alpha. 558 bool legalAlphaModulation = legal_modulation(input, i2, i3, output, o2, o3, 559 /* alpha */ true); 560 bool legalColorModulation = legal_modulation(input, i2, i3, output, o2, o3, 561 /* alpha */ false); 562 563 if (!legalColorModulation && !legalAlphaModulation) { 564 passing = false; 565 566 if (coverageMessage.isEmpty()) { 567 coverageMessage.printf("\"Modulating\" processor %s did not match " 568 "alpha-modulation nor color-modulation rules. " 569 "Input: 0x%08x, Output: 0x%08x, pixel (%d, %d).", 570 fp->name(), input, output, x, y); 571 } 572 } 573 } 574 575 SkPMColor4f input4f = SkPMColor4f::FromBytes_RGBA(input); 576 SkPMColor4f output4f = SkPMColor4f::FromBytes_RGBA(output); 577 SkPMColor4f expected4f; 578 if (fp->hasConstantOutputForConstantInput(input4f, &expected4f)) { 579 float rDiff = fabsf(output4f.fR - expected4f.fR); 580 float gDiff = fabsf(output4f.fG - expected4f.fG); 581 float bDiff = fabsf(output4f.fB - expected4f.fB); 582 float aDiff = fabsf(output4f.fA - expected4f.fA); 583 static constexpr float kTol = 4 / 255.f; 584 if (rDiff > kTol || gDiff > kTol || bDiff > kTol || aDiff > kTol) { 585 if (constMessage.isEmpty()) { 586 passing = false; 587 588 constMessage.printf("Processor %s claimed output for const input " 589 "doesn't match actual output. Error: %f, Tolerance: %f, " 590 "input: (%f, %f, %f, %f), actual: (%f, %f, %f, %f), " 591 "expected(%f, %f, %f, %f)", fp->name(), 592 SkTMax(rDiff, SkTMax(gDiff, SkTMax(bDiff, aDiff))), kTol, 593 input4f.fR, input4f.fG, input4f.fB, input4f.fA, 594 output4f.fR, output4f.fG, output4f.fB, output4f.fA, 595 expected4f.fR, expected4f.fG, expected4f.fB, expected4f.fA); 596 } 597 } 598 } 599 if (input4f.isOpaque() && fp->preservesOpaqueInput() && !output4f.isOpaque()) { 600 passing = false; 601 602 if (opaqueMessage.isEmpty()) { 603 opaqueMessage.printf("Processor %s claimed opaqueness is preserved but " 604 "it is not. Input: 0x%08x, Output: 0x%08x.", 605 fp->name(), input, output); 606 } 607 } 608 609 if (!passing) { 610 // Regardless of how many optimizations the pixel violates, count it as a 611 // single bad pixel. 612 failedPixelCount++; 613 } 614 } 615 } 616 617 // Finished analyzing the entire image, see if the number of pixel failures meets the 618 // threshold for an FP violating the optimization requirements. 619 if (failedPixelCount > kMaxAcceptableFailedPixels) { 620 ERRORF(reporter, "Processor violated %d of %d pixels, seed: 0x%08x, processor: %s" 621 ", first failing pixel details are below:", 622 failedPixelCount, kRenderSize * kRenderSize, seed, 623 fp->dumpInfo().c_str()); 624 625 // Print first failing pixel's details. 626 if (!coverageMessage.isEmpty()) { 627 ERRORF(reporter, coverageMessage.c_str()); 628 } 629 if (!constMessage.isEmpty()) { 630 ERRORF(reporter, constMessage.c_str()); 631 } 632 if (!opaqueMessage.isEmpty()) { 633 ERRORF(reporter, opaqueMessage.c_str()); 634 } 635 636 if (!loggedFirstFailure) { 637 // Print with ERRORF to make sure the encoded image is output 638 SkString input; 639 log_surface_proxy(context, inputTexture1, &input); 640 SkString output; 641 log_surface_context(rtc, &output); 642 ERRORF(reporter, "Input image: %s\n\n" 643 "===========================================================\n\n" 644 "Output image: %s\n", input.c_str(), output.c_str()); 645 loggedFirstFailure = true; 646 } 647 } else if(failedPixelCount > 0) { 648 // Don't trigger an error, but don't just hide the failures either. 649 INFOF(reporter, "Processor violated %d of %d pixels (below error threshold), seed: " 650 "0x%08x, processor: %s", failedPixelCount, kRenderSize * kRenderSize, 651 seed, fp->dumpInfo().c_str()); 652 if (!coverageMessage.isEmpty()) { 653 INFOF(reporter, coverageMessage.c_str()); 654 } 655 if (!constMessage.isEmpty()) { 656 INFOF(reporter, constMessage.c_str()); 657 } 658 if (!opaqueMessage.isEmpty()) { 659 INFOF(reporter, opaqueMessage.c_str()); 660 } 661 if (!loggedFirstWarning) { 662 SkString input; 663 log_surface_proxy(context, inputTexture1, &input); 664 SkString output; 665 log_surface_context(rtc, &output); 666 INFOF(reporter, "Input image: %s\n\n" 667 "===========================================================\n\n" 668 "Output image: %s\n", input.c_str(), output.c_str()); 669 loggedFirstWarning = true; 670 } 671 } 672 } 673 } 674 } 675 676 // Tests that fragment processors returned by GrFragmentProcessor::clone() are equivalent to their 677 // progenitors. 678 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorCloneTest, reporter, ctxInfo) { 679 GrContext* context = ctxInfo.grContext(); 680 GrProxyProvider* proxyProvider = context->priv().proxyProvider(); 681 auto resourceProvider = context->priv().resourceProvider(); 682 683 SkRandom random; 684 685 const GrBackendFormat format = 686 context->priv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); 687 688 // Make the destination context for the test. 689 static constexpr int kRenderSize = 1024; 690 sk_sp<GrRenderTargetContext> rtc = context->priv().makeDeferredRenderTargetContext( 691 format, SkBackingFit::kExact, kRenderSize, kRenderSize, kRGBA_8888_GrPixelConfig, 692 nullptr); 693 694 sk_sp<GrTextureProxy> proxies[2]; 695 if (!init_test_textures(proxyProvider, &random, proxies)) { 696 ERRORF(reporter, "Could not create test textures"); 697 return; 698 } 699 GrProcessorTestData testData(&random, context, rtc.get(), proxies); 700 701 auto inputTexture = make_input_texture(proxyProvider, kRenderSize, kRenderSize, 0.0f); 702 std::unique_ptr<GrColor[]> readData1(new GrColor[kRenderSize * kRenderSize]); 703 std::unique_ptr<GrColor[]> readData2(new GrColor[kRenderSize * kRenderSize]); 704 auto readInfo = SkImageInfo::Make(kRenderSize, kRenderSize, kRGBA_8888_SkColorType, 705 kPremul_SkAlphaType); 706 707 // Because processor factories configure themselves in random ways, this is not exhaustive. 708 for (int i = 0; i < GrFragmentProcessorTestFactory::Count(); ++i) { 709 static constexpr int kTimesToInvokeFactory = 10; 710 for (int j = 0; j < kTimesToInvokeFactory; ++j) { 711 auto fp = GrFragmentProcessorTestFactory::MakeIdx(i, &testData); 712 auto clone = fp->clone(); 713 if (!clone) { 714 ERRORF(reporter, "Clone of processor %s failed.", fp->name()); 715 continue; 716 } 717 const char* name = fp->name(); 718 if (!fp->instantiate(resourceProvider) || !clone->instantiate(resourceProvider)) { 719 continue; 720 } 721 REPORTER_ASSERT(reporter, !strcmp(fp->name(), clone->name())); 722 REPORTER_ASSERT(reporter, fp->compatibleWithCoverageAsAlpha() == 723 clone->compatibleWithCoverageAsAlpha()); 724 REPORTER_ASSERT(reporter, fp->isEqual(*clone)); 725 REPORTER_ASSERT(reporter, fp->preservesOpaqueInput() == clone->preservesOpaqueInput()); 726 REPORTER_ASSERT(reporter, fp->hasConstantOutputForConstantInput() == 727 clone->hasConstantOutputForConstantInput()); 728 REPORTER_ASSERT(reporter, fp->numChildProcessors() == clone->numChildProcessors()); 729 REPORTER_ASSERT(reporter, fp->usesLocalCoords() == clone->usesLocalCoords()); 730 // Draw with original and read back the results. 731 render_fp(context, rtc.get(), fp.get(), inputTexture, readData1.get()); 732 733 // Draw with clone and read back the results. 734 render_fp(context, rtc.get(), clone.get(), inputTexture, readData2.get()); 735 736 // Check that the results are the same. 737 bool passing = true; 738 for (int y = 0; y < kRenderSize && passing; ++y) { 739 for (int x = 0; x < kRenderSize && passing; ++x) { 740 int idx = y * kRenderSize + x; 741 if (readData1[idx] != readData2[idx]) { 742 ERRORF(reporter, 743 "Processor %s made clone produced different output. " 744 "Input color: 0x%08x, Original Output Color: 0x%08x, " 745 "Clone Output Color: 0x%08x..", 746 name, input_texel_color(x, y, 0.0f), readData1[idx], readData2[idx]); 747 passing = false; 748 } 749 } 750 } 751 } 752 } 753 } 754 755 #endif // GR_TEST_UTILS 756 #endif // SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 757