• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "tests/Test.h"
9 
10 #include "include/gpu/GrContext.h"
11 #include "include/gpu/GrGpuResource.h"
12 #include "src/gpu/GrClip.h"
13 #include "src/gpu/GrContextPriv.h"
14 #include "src/gpu/GrMemoryPool.h"
15 #include "src/gpu/GrProxyProvider.h"
16 #include "src/gpu/GrRenderTargetContext.h"
17 #include "src/gpu/GrRenderTargetContextPriv.h"
18 #include "src/gpu/GrResourceProvider.h"
19 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
20 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
21 #include "src/gpu/ops/GrFillRectOp.h"
22 #include "src/gpu/ops/GrMeshDrawOp.h"
23 #include "tests/TestUtils.h"
24 #include <atomic>
25 #include <random>
26 
27 namespace {
28 class TestOp : public GrMeshDrawOp {
29 public:
30     DEFINE_OP_CLASS_ID
Make(GrContext * context,std::unique_ptr<GrFragmentProcessor> fp)31     static std::unique_ptr<GrDrawOp> Make(GrContext* context,
32                                           std::unique_ptr<GrFragmentProcessor> fp) {
33         GrOpMemoryPool* pool = context->priv().opMemoryPool();
34 
35         return pool->allocate<TestOp>(std::move(fp));
36     }
37 
name() const38     const char* name() const override { return "TestOp"; }
39 
visitProxies(const VisitProxyFunc & func) const40     void visitProxies(const VisitProxyFunc& func) const override {
41         fProcessors.visitProxies(func);
42     }
43 
fixedFunctionFlags() const44     FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
45 
finalize(const GrCaps & caps,const GrAppliedClip * clip,bool hasMixedSampledCoverage,GrClampType clampType)46     GrProcessorSet::Analysis finalize(
47             const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
48             GrClampType clampType) override {
49         static constexpr GrProcessorAnalysisColor kUnknownColor;
50         SkPMColor4f overrideColor;
51         return fProcessors.finalize(
52                 kUnknownColor, GrProcessorAnalysisCoverage::kNone, clip,
53                 &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps, clampType,
54                 &overrideColor);
55     }
56 
57 private:
58     friend class ::GrOpMemoryPool; // for ctor
59 
TestOp(std::unique_ptr<GrFragmentProcessor> fp)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 
onPrepareDraws(Target * target)65     void onPrepareDraws(Target* target) override { return; }
onExecute(GrOpFlushState *,const SkRect &)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 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:
Make(std::unique_ptr<GrFragmentProcessor> child)79     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child) {
80         return std::unique_ptr<GrFragmentProcessor>(new TestFP(std::move(child)));
81     }
Make(const SkTArray<sk_sp<GrTextureProxy>> & proxies,const SkTArray<sk_sp<GrGpuBuffer>> & buffers)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 
name() const87     const char* name() const override { return "test"; }
88 
onGetGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder * b) const89     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
90         static std::atomic<int32_t> nextKey{0};
91         b->add32(nextKey++);
92     }
93 
clone() const94     std::unique_ptr<GrFragmentProcessor> clone() const override {
95         return std::unique_ptr<GrFragmentProcessor>(new TestFP(*this));
96     }
97 
98 private:
TestFP(const SkTArray<sk_sp<GrTextureProxy>> & proxies,const SkTArray<sk_sp<GrGpuBuffer>> & buffers)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 
TestFP(std::unique_ptr<GrFragmentProcessor> child)108     TestFP(std::unique_ptr<GrFragmentProcessor> child)
109             : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags), fSamplers(4) {
110         this->registerChildProcessor(std::move(child));
111     }
112 
TestFP(const TestFP & that)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 
onCreateGLSLInstance() const124     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 
onIsEqual(const GrFragmentProcessor &) const138     bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
onTextureSampler(int i) const139     const TextureSampler& onTextureSampler(int i) const override { return fSamplers[i]; }
140 
141     GrTAllocator<TextureSampler> fSamplers;
142     typedef GrFragmentProcessor INHERITED;
143 };
144 }
145 
check_refs(skiatest::Reporter * reporter,GrTextureProxy * proxy,int32_t expectedProxyRefs,int32_t expectedBackingRefs)146 static void check_refs(skiatest::Reporter* reporter,
147                        GrTextureProxy* proxy,
148                        int32_t expectedProxyRefs,
149                        int32_t expectedBackingRefs) {
150     int32_t actualProxyRefs = proxy->priv().getProxyRefCnt();
151     int32_t actualBackingRefs = proxy->testingOnly_getBackingRefCnt();
152 
153     SkASSERT(actualProxyRefs == expectedProxyRefs);
154     SkASSERT(actualBackingRefs == expectedBackingRefs);
155 
156     REPORTER_ASSERT(reporter, actualProxyRefs == expectedProxyRefs);
157     REPORTER_ASSERT(reporter, actualBackingRefs == expectedBackingRefs);
158 }
159 
DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest,reporter,ctxInfo)160 DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) {
161     GrContext* context = ctxInfo.grContext();
162     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
163 
164     GrSurfaceDesc desc;
165     desc.fWidth = 10;
166     desc.fHeight = 10;
167     desc.fConfig = kRGBA_8888_GrPixelConfig;
168 
169     const GrBackendFormat format =
170         context->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
171                                                         GrRenderable::kNo);
172 
173     for (bool makeClone : {false, true}) {
174         for (int parentCnt = 0; parentCnt < 2; parentCnt++) {
175             sk_sp<GrRenderTargetContext> renderTargetContext(
176                     context->priv().makeDeferredRenderTargetContext(
177                             SkBackingFit::kApprox, 1, 1, GrColorType::kRGBA_8888, nullptr));
178             {
179                 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(
180                         format, desc, GrRenderable::kNo, 1, kTopLeft_GrSurfaceOrigin,
181                         SkBackingFit::kExact, SkBudgeted::kYes, GrProtected::kNo);
182 
183                 {
184                     SkTArray<sk_sp<GrTextureProxy>> proxies;
185                     SkTArray<sk_sp<GrGpuBuffer>> buffers;
186                     proxies.push_back(proxy);
187                     auto fp = TestFP::Make(std::move(proxies), std::move(buffers));
188                     for (int i = 0; i < parentCnt; ++i) {
189                         fp = TestFP::Make(std::move(fp));
190                     }
191                     std::unique_ptr<GrFragmentProcessor> clone;
192                     if (makeClone) {
193                         clone = fp->clone();
194                     }
195                     std::unique_ptr<GrDrawOp> op(TestOp::Make(context, std::move(fp)));
196                     renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
197                     if (clone) {
198                         op = TestOp::Make(context, std::move(clone));
199                         renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
200                     }
201                 }
202 
203                 // If the fp is cloned the number of refs should increase by one (for the clone)
204                 int expectedProxyRefs = makeClone ? 3 : 2;
205 
206                 check_refs(reporter, proxy.get(), expectedProxyRefs, -1);
207 
208                 context->flush();
209 
210                 check_refs(reporter, proxy.get(), 1, 1); // just one from the 'proxy' sk_sp
211             }
212         }
213     }
214 }
215 
216 #include "tools/flags/CommandLineFlags.h"
217 static DEFINE_bool(randomProcessorTest, false,
218                    "Use non-deterministic seed for random processor tests?");
219 static DEFINE_int(processorSeed, 0,
220                   "Use specific seed for processor tests. Overridden by --randomProcessorTest.");
221 
222 #if GR_TEST_UTILS
223 
input_texel_color(int i,int j,SkScalar delta)224 static GrColor input_texel_color(int i, int j, SkScalar delta) {
225     // Delta must be less than 0.5 to prevent over/underflow issues with the input color
226     SkASSERT(delta <= 0.5);
227 
228     SkColor color = SkColorSetARGB((uint8_t)(i & 0xFF),
229                                    (uint8_t)(j & 0xFF),
230                                    (uint8_t)((i + j) & 0xFF),
231                                    (uint8_t)((2 * j - i) & 0xFF));
232     SkColor4f color4f = SkColor4f::FromColor(color);
233     for (int i = 0; i < 4; i++) {
234         if (color4f[i] > 0.5) {
235             color4f[i] -= delta;
236         } else {
237             color4f[i] += delta;
238         }
239     }
240     return color4f.premul().toBytes_RGBA();
241 }
242 
test_draw_op(GrContext * context,GrRenderTargetContext * rtc,std::unique_ptr<GrFragmentProcessor> fp,sk_sp<GrTextureProxy> inputDataProxy)243 void test_draw_op(GrContext* context,
244                   GrRenderTargetContext* rtc,
245                   std::unique_ptr<GrFragmentProcessor> fp,
246                   sk_sp<GrTextureProxy> inputDataProxy) {
247     GrPaint paint;
248     paint.addColorTextureProcessor(std::move(inputDataProxy), SkMatrix::I());
249     paint.addColorFragmentProcessor(std::move(fp));
250     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
251 
252     auto op = GrFillRectOp::MakeNonAARect(context, std::move(paint), SkMatrix::I(),
253                                           SkRect::MakeWH(rtc->width(), rtc->height()));
254     rtc->addDrawOp(GrNoClip(), std::move(op));
255 }
256 
257 // This assumes that the output buffer will be the same size as inputDataProxy
render_fp(GrContext * context,GrRenderTargetContext * rtc,GrFragmentProcessor * fp,sk_sp<GrTextureProxy> inputDataProxy,GrColor * buffer)258 void render_fp(GrContext* context, GrRenderTargetContext* rtc, GrFragmentProcessor* fp,
259                sk_sp<GrTextureProxy> inputDataProxy, GrColor* buffer) {
260     int width = inputDataProxy->width();
261     int height = inputDataProxy->height();
262 
263     // test_draw_op needs to take ownership of an FP, so give it a clone that it can own
264     test_draw_op(context, rtc, fp->clone(), inputDataProxy);
265     memset(buffer, 0x0, sizeof(GrColor) * width * height);
266     rtc->readPixels(SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
267                     buffer, 0, {0, 0});
268 }
269 
270 /** Initializes the two test texture proxies that are available to the FP test factories. */
init_test_textures(GrResourceProvider * resourceProvider,GrProxyProvider * proxyProvider,SkRandom * random,sk_sp<GrTextureProxy> proxies[2])271 bool init_test_textures(GrResourceProvider* resourceProvider,
272                         GrProxyProvider* proxyProvider,
273                         SkRandom* random,
274                         sk_sp<GrTextureProxy> proxies[2]) {
275     static const int kTestTextureSize = 256;
276 
277     {
278         // Put premul data into the RGBA texture that the test FPs can optionally use.
279         std::unique_ptr<GrColor[]> rgbaData(new GrColor[kTestTextureSize * kTestTextureSize]);
280         for (int y = 0; y < kTestTextureSize; ++y) {
281             for (int x = 0; x < kTestTextureSize; ++x) {
282                 rgbaData[kTestTextureSize * y + x] = input_texel_color(
283                         random->nextULessThan(256), random->nextULessThan(256), 0.0f);
284             }
285         }
286 
287         SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize,
288                                            kRGBA_8888_SkColorType, kPremul_SkAlphaType);
289         SkPixmap pixmap(ii, rgbaData.get(), ii.minRowBytes());
290         sk_sp<SkImage> img = SkImage::MakeRasterCopy(pixmap);
291         proxies[0] =
292                 proxyProvider->createTextureProxy(img, 1, SkBudgeted::kYes, SkBackingFit::kExact);
293         proxies[0]->instantiate(resourceProvider);
294     }
295 
296     {
297         // Put random values into the alpha texture that the test FPs can optionally use.
298         std::unique_ptr<uint8_t[]> alphaData(new uint8_t[kTestTextureSize * kTestTextureSize]);
299         for (int y = 0; y < kTestTextureSize; ++y) {
300             for (int x = 0; x < kTestTextureSize; ++x) {
301                 alphaData[kTestTextureSize * y + x] = random->nextULessThan(256);
302             }
303         }
304 
305         SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize,
306                                            kAlpha_8_SkColorType, kPremul_SkAlphaType);
307         SkPixmap pixmap(ii, alphaData.get(), ii.minRowBytes());
308         sk_sp<SkImage> img = SkImage::MakeRasterCopy(pixmap);
309         proxies[1] =
310                 proxyProvider->createTextureProxy(img, 1, SkBudgeted::kYes, SkBackingFit::kExact);
311         proxies[1]->instantiate(resourceProvider);
312     }
313 
314     return proxies[0] && proxies[1];
315 }
316 
317 // Creates a texture of premul colors used as the output of the fragment processor that precedes
318 // the fragment processor under test. Color values are those provided by input_texel_color().
make_input_texture(GrProxyProvider * proxyProvider,int width,int height,SkScalar delta)319 sk_sp<GrTextureProxy> make_input_texture(GrProxyProvider* proxyProvider, int width, int height,
320                                          SkScalar delta) {
321     std::unique_ptr<GrColor[]> data(new GrColor[width * height]);
322     for (int y = 0; y < width; ++y) {
323         for (int x = 0; x < height; ++x) {
324             data.get()[width * y + x] = input_texel_color(x, y, delta);
325         }
326     }
327 
328     SkImageInfo ii = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
329     SkPixmap pixmap(ii, data.get(), ii.minRowBytes());
330     sk_sp<SkImage> img = SkImage::MakeRasterCopy(pixmap);
331     return proxyProvider->createTextureProxy(img, 1, SkBudgeted::kYes, SkBackingFit::kExact);
332 }
333 
334 // We tag logged  data as unpremul to avoid conversion when encoding as  PNG. The input texture
335 // actually contains unpremul data. Also, even though we made the result data by rendering into
336 // a "unpremul" GrRenderTargetContext, our input texture is unpremul and outside of the random
337 // effect configuration, we didn't do anything to ensure the output is actually premul. We just
338 // don't currently allow kUnpremul GrRenderTargetContexts.
339 static constexpr auto kLogAlphaType = kUnpremul_SkAlphaType;
340 
log_pixels(GrColor * pixels,int widthHeight,SkString * dst)341 bool log_pixels(GrColor* pixels, int widthHeight, SkString* dst) {
342     auto info = SkImageInfo::Make(widthHeight, widthHeight, kRGBA_8888_SkColorType, kLogAlphaType);
343     SkBitmap bmp;
344     bmp.installPixels(info, pixels, widthHeight * sizeof(GrColor));
345     return bitmap_to_base64_data_uri(bmp, dst);
346 }
347 
log_texture_proxy(GrContext * context,sk_sp<GrTextureProxy> src,SkString * dst)348 bool log_texture_proxy(GrContext* context, sk_sp<GrTextureProxy> src, SkString* dst) {
349     sk_sp<GrSurfaceContext> sContext(
350             context->priv().makeWrappedSurfaceContext(src, GrColorType::kRGBA_8888, kLogAlphaType));
351     SkImageInfo ii =
352             SkImageInfo::Make(src->width(), src->height(), kRGBA_8888_SkColorType, kLogAlphaType);
353     SkBitmap bm;
354     SkAssertResult(bm.tryAllocPixels(ii));
355     SkAssertResult(sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), {0, 0}));
356     return bitmap_to_base64_data_uri(bm, dst);
357 }
358 
fuzzy_color_equals(const SkPMColor4f & c1,const SkPMColor4f & c2)359 bool fuzzy_color_equals(const SkPMColor4f& c1, const SkPMColor4f& c2) {
360     // With the loss of precision of rendering into 32-bit color, then estimating the FP's output
361     // from that, it is not uncommon for a valid output to differ from estimate by up to 0.01
362     // (really 1/128 ~ .0078, but frequently floating point issues make that tolerance a little
363     // too unforgiving).
364     static constexpr SkScalar kTolerance = 0.01f;
365     for (int i = 0; i < 4; i++) {
366         if (!SkScalarNearlyEqual(c1[i], c2[i], kTolerance)) {
367             return false;
368         }
369     }
370     return true;
371 }
372 
modulation_index(int channelIndex,bool alphaModulation)373 int modulation_index(int channelIndex, bool alphaModulation) {
374     return alphaModulation ? 3 : channelIndex;
375 }
376 
377 // Given three input colors (color preceding the FP being tested), and the output of the FP, this
378 // ensures that the out1 = fp * in1.a, out2 = fp * in2.a, and out3 = fp * in3.a, where fp is the
379 // pre-modulated color that should not be changing across frames (FP's state doesn't change).
380 //
381 // When alphaModulation is false, this tests the very similar conditions that out1 = fp * in1,
382 // etc. using per-channel modulation instead of modulation by just the input alpha channel.
383 // - This estimates the pre-modulated fp color from one of the input/output pairs and confirms the
384 //   conditions hold for the other two pairs.
legal_modulation(const GrColor & in1,const GrColor & in2,const GrColor & in3,const GrColor & out1,const GrColor & out2,const GrColor & out3,bool alphaModulation)385 bool legal_modulation(const GrColor& in1, const GrColor& in2, const GrColor& in3,
386                       const GrColor& out1, const GrColor& out2, const GrColor& out3,
387                       bool alphaModulation) {
388     // Convert to floating point, which is the number space the FP operates in (more or less)
389     SkPMColor4f in1f = SkPMColor4f::FromBytes_RGBA(in1);
390     SkPMColor4f in2f = SkPMColor4f::FromBytes_RGBA(in2);
391     SkPMColor4f in3f = SkPMColor4f::FromBytes_RGBA(in3);
392     SkPMColor4f out1f = SkPMColor4f::FromBytes_RGBA(out1);
393     SkPMColor4f out2f = SkPMColor4f::FromBytes_RGBA(out2);
394     SkPMColor4f out3f = SkPMColor4f::FromBytes_RGBA(out3);
395 
396     // Reconstruct the output of the FP before the shader modulated its color with the input value.
397     // When the original input is very small, it may cause the final output color to round
398     // to 0, in which case we estimate the pre-modulated color using one of the stepped frames that
399     // will then have a guaranteed larger channel value (since the offset will be added to it).
400     SkPMColor4f fpPreModulation;
401     for (int i = 0; i < 4; i++) {
402         int modulationIndex = modulation_index(i, alphaModulation);
403         if (in1f[modulationIndex] < 0.2f) {
404             // Use the stepped frame
405             fpPreModulation[i] = out2f[i] / in2f[modulationIndex];
406         } else {
407             fpPreModulation[i] = out1f[i] / in1f[modulationIndex];
408         }
409     }
410 
411     // With reconstructed pre-modulated FP output, derive the expected value of fp * input for each
412     // of the transformed input colors.
413     SkPMColor4f expected1 = alphaModulation ? (fpPreModulation * in1f.fA)
414                                             : (fpPreModulation * in1f);
415     SkPMColor4f expected2 = alphaModulation ? (fpPreModulation * in2f.fA)
416                                             : (fpPreModulation * in2f);
417     SkPMColor4f expected3 = alphaModulation ? (fpPreModulation * in3f.fA)
418                                             : (fpPreModulation * in3f);
419 
420     return fuzzy_color_equals(out1f, expected1) &&
421            fuzzy_color_equals(out2f, expected2) &&
422            fuzzy_color_equals(out3f, expected3);
423 }
424 
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest,reporter,ctxInfo)425 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) {
426     GrContext* context = ctxInfo.grContext();
427     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
428     auto resourceProvider = context->priv().resourceProvider();
429     using FPFactory = GrFragmentProcessorTestFactory;
430 
431     uint32_t seed = FLAGS_processorSeed;
432     if (FLAGS_randomProcessorTest) {
433         std::random_device rd;
434         seed = rd();
435     }
436     // If a non-deterministic bot fails this test, check the output to see what seed it used, then
437     // use --processorSeed <seed> (without --randomProcessorTest) to reproduce.
438     SkRandom random(seed);
439 
440     // Make the destination context for the test.
441     static constexpr int kRenderSize = 256;
442     sk_sp<GrRenderTargetContext> rtc = context->priv().makeDeferredRenderTargetContext(
443             SkBackingFit::kExact, kRenderSize, kRenderSize, GrColorType::kRGBA_8888, nullptr);
444 
445     sk_sp<GrTextureProxy> proxies[2];
446     if (!init_test_textures(resourceProvider, proxyProvider, &random, proxies)) {
447         ERRORF(reporter, "Could not create test textures");
448         return;
449     }
450     GrProcessorTestData testData(&random, context, rtc.get(), proxies);
451 
452     // Coverage optimization uses three frames with a linearly transformed input texture.  The first
453     // frame has no offset, second frames add .2 and .4, which should then be present as a fixed
454     // difference between the frame outputs if the FP is properly following the modulation
455     // requirements of the coverage optimization.
456     static constexpr SkScalar kInputDelta = 0.2f;
457     auto inputTexture1 = make_input_texture(proxyProvider, kRenderSize, kRenderSize, 0.0f);
458     auto inputTexture2 = make_input_texture(proxyProvider, kRenderSize, kRenderSize, kInputDelta);
459     auto inputTexture3 = make_input_texture(proxyProvider, kRenderSize, kRenderSize, 2*kInputDelta);
460 
461     // Encoded images are very verbose and this tests many potential images, so only export the
462     // first failure (subsequent failures have a reasonable chance of being related).
463     bool loggedFirstFailure = false;
464     bool loggedFirstWarning = false;
465 
466     // Storage for the three frames required for coverage compatibility optimization. Each frame
467     // uses the correspondingly numbered inputTextureX.
468     std::unique_ptr<GrColor[]> readData1(new GrColor[kRenderSize * kRenderSize]);
469     std::unique_ptr<GrColor[]> readData2(new GrColor[kRenderSize * kRenderSize]);
470     std::unique_ptr<GrColor[]> readData3(new GrColor[kRenderSize * kRenderSize]);
471 
472     // Because processor factories configure themselves in random ways, this is not exhaustive.
473     for (int i = 0; i < FPFactory::Count(); ++i) {
474         int timesToInvokeFactory = 5;
475         // Increase the number of attempts if the FP has child FPs since optimizations likely depend
476         // on child optimizations being present.
477         std::unique_ptr<GrFragmentProcessor> fp = FPFactory::MakeIdx(i, &testData);
478         for (int j = 0; j < fp->numChildProcessors(); ++j) {
479             // This value made a reasonable trade off between time and coverage when this test was
480             // written.
481             timesToInvokeFactory *= FPFactory::Count() / 2;
482         }
483 #if defined(__MSVC_RUNTIME_CHECKS)
484         // This test is infuriatingly slow with MSVC runtime checks enabled
485         timesToInvokeFactory = 1;
486 #endif
487         for (int j = 0; j < timesToInvokeFactory; ++j) {
488             fp = FPFactory::MakeIdx(i, &testData);
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_texture_proxy(context, inputTexture1, &input);
629                     SkString output;
630                     log_pixels(readData1.get(), kRenderSize, &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_texture_proxy(context, inputTexture1, &input);
653                     SkString output;
654                     log_pixels(readData1.get(), kRenderSize, &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.
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorCloneTest,reporter,ctxInfo)667 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorCloneTest, reporter, ctxInfo) {
668     GrContext* context = ctxInfo.grContext();
669     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
670     auto resourceProvider = context->priv().resourceProvider();
671 
672     SkRandom random;
673 
674     // Make the destination context for the test.
675     static constexpr int kRenderSize = 1024;
676     sk_sp<GrRenderTargetContext> rtc = context->priv().makeDeferredRenderTargetContext(
677             SkBackingFit::kExact, kRenderSize, kRenderSize, GrColorType::kRGBA_8888, nullptr);
678 
679     sk_sp<GrTextureProxy> proxies[2];
680     if (!init_test_textures(resourceProvider, proxyProvider, &random, proxies)) {
681         ERRORF(reporter, "Could not create test textures");
682         return;
683     }
684     GrProcessorTestData testData(&random, context, rtc.get(), proxies);
685 
686     auto inputTexture = make_input_texture(proxyProvider, kRenderSize, kRenderSize, 0.0f);
687     std::unique_ptr<GrColor[]> readData1(new GrColor[kRenderSize * kRenderSize]);
688     std::unique_ptr<GrColor[]> readData2(new GrColor[kRenderSize * kRenderSize]);
689     // On failure we write out images, but just write the first failing set as the print is very
690     // large.
691     bool loggedFirstFailure = false;
692 
693     // This test has a history of being flaky on a number of devices. If an FP clone is logically
694     // wrong, it's reasonable to expect it produce a large number of pixel differences in the image
695     // Sporadic pixel violations are more indicative device errors and represents a separate
696     // problem.
697 #if defined(SK_BUILD_FOR_SKQP)
698     static constexpr int kMaxAcceptableFailedPixels = 0;  // Strict when running as SKQP
699 #else
700     static constexpr int kMaxAcceptableFailedPixels = 2 * kRenderSize;  // ~0.7% of the image
701 #endif
702 
703     // Because processor factories configure themselves in random ways, this is not exhaustive.
704     for (int i = 0; i < GrFragmentProcessorTestFactory::Count(); ++i) {
705         static constexpr int kTimesToInvokeFactory = 10;
706         for (int j = 0; j < kTimesToInvokeFactory; ++j) {
707             auto fp = GrFragmentProcessorTestFactory::MakeIdx(i, &testData);
708             auto clone = fp->clone();
709             if (!clone) {
710                 ERRORF(reporter, "Clone of processor %s failed.", fp->name());
711                 continue;
712             }
713             const char* name = fp->name();
714             REPORTER_ASSERT(reporter, !strcmp(fp->name(), clone->name()));
715             REPORTER_ASSERT(reporter, fp->compatibleWithCoverageAsAlpha() ==
716                                       clone->compatibleWithCoverageAsAlpha());
717             REPORTER_ASSERT(reporter, fp->isEqual(*clone));
718             REPORTER_ASSERT(reporter, fp->preservesOpaqueInput() == clone->preservesOpaqueInput());
719             REPORTER_ASSERT(reporter, fp->hasConstantOutputForConstantInput() ==
720                                       clone->hasConstantOutputForConstantInput());
721             REPORTER_ASSERT(reporter, fp->numChildProcessors() == clone->numChildProcessors());
722             REPORTER_ASSERT(reporter, fp->usesLocalCoords() == clone->usesLocalCoords());
723             // Draw with original and read back the results.
724             render_fp(context, rtc.get(), fp.get(), inputTexture, readData1.get());
725 
726             // Draw with clone and read back the results.
727             render_fp(context, rtc.get(), clone.get(), inputTexture, readData2.get());
728 
729             // Check that the results are the same.
730             bool passing = true;
731             int failedPixelCount = 0;
732             int firstWrongX = 0;
733             int firstWrongY = 0;
734             for (int y = 0; y < kRenderSize && passing; ++y) {
735                 for (int x = 0; x < kRenderSize && passing; ++x) {
736                     int idx = y * kRenderSize + x;
737                     if (readData1[idx] != readData2[idx]) {
738                         if (!failedPixelCount) {
739                             firstWrongX = x;
740                             firstWrongY = y;
741                         }
742                         ++failedPixelCount;
743                     }
744                     if (failedPixelCount > kMaxAcceptableFailedPixels) {
745                         passing = false;
746                         idx = firstWrongY * kRenderSize + firstWrongX;
747                         ERRORF(reporter,
748                                "Processor %s made clone produced different output at (%d, %d). "
749                                "Input color: 0x%08x, Original Output Color: 0x%08x, "
750                                "Clone Output Color: 0x%08x.",
751                                name, firstWrongX, firstWrongY, input_texel_color(x, y, 0.0f),
752                                readData1[idx], readData2[idx]);
753                         if (!loggedFirstFailure) {
754                             // Write the images out as data urls for inspection.
755                             // We mark the data as unpremul to avoid conversion when encoding as
756                             // PNG. Also, even though we made the data by rendering into
757                             // a "unpremul" GrRenderTargetContext, our input texture is unpremul and
758                             // outside of the random effect configuration, we didn't do anything to
759                             // ensure the output is actually premul.
760                             auto info = SkImageInfo::Make(kRenderSize, kRenderSize,
761                                                           kRGBA_8888_SkColorType,
762                                                           kUnpremul_SkAlphaType);
763                             SkString input, orig, clone;
764                             if (log_texture_proxy(context, inputTexture, &input) &&
765                                 log_pixels(readData1.get(), kRenderSize, &orig) &&
766                                 log_pixels(readData2.get(), kRenderSize, &clone)) {
767                                 ERRORF(reporter,
768                                        "\nInput image:\n%s\n\n"
769                                        "==========================================================="
770                                        "\n\n"
771                                        "Orig output image:\n%s\n"
772                                        "==========================================================="
773                                        "\n\n"
774                                        "Clone output image:\n%s\n",
775                                        input.c_str(), orig.c_str(), clone.c_str());
776                                 loggedFirstFailure = true;
777                             }
778                         }
779                     }
780                 }
781             }
782         }
783     }
784 }
785 
786 #endif  // GR_TEST_UTILS
787