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