1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "tests/Test.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
11cb93a386Sopenharmony_ci#include "src/gpu/GrClip.h"
12cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrFragmentProcessor.h"
14cb93a386Sopenharmony_ci#include "src/gpu/GrGpuResource.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrImageInfo.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h"
19cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h"
20cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h"
21cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
22cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h"
23cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h"
24cb93a386Sopenharmony_ci#include "tests/TestUtils.h"
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci#include <atomic>
27cb93a386Sopenharmony_ci#include <random>
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_cinamespace {
30cb93a386Sopenharmony_ciclass TestOp : public GrMeshDrawOp {
31cb93a386Sopenharmony_cipublic:
32cb93a386Sopenharmony_ci    DEFINE_OP_CLASS_ID
33cb93a386Sopenharmony_ci    static GrOp::Owner Make(GrRecordingContext* rContext,
34cb93a386Sopenharmony_ci                            std::unique_ptr<GrFragmentProcessor> fp) {
35cb93a386Sopenharmony_ci        return GrOp::Make<TestOp>(rContext, std::move(fp));
36cb93a386Sopenharmony_ci    }
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci    const char* name() const override { return "TestOp"; }
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci    void visitProxies(const GrVisitProxyFunc& func) const override {
41cb93a386Sopenharmony_ci        fProcessors.visitProxies(func);
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_ci    FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci    GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
47cb93a386Sopenharmony_ci                                      GrClampType clampType) override {
48cb93a386Sopenharmony_ci        static constexpr GrProcessorAnalysisColor kUnknownColor;
49cb93a386Sopenharmony_ci        SkPMColor4f overrideColor;
50cb93a386Sopenharmony_ci        return fProcessors.finalize(
51cb93a386Sopenharmony_ci                kUnknownColor, GrProcessorAnalysisCoverage::kNone, clip,
52cb93a386Sopenharmony_ci                &GrUserStencilSettings::kUnused, caps, clampType, &overrideColor);
53cb93a386Sopenharmony_ci    }
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ciprivate:
56cb93a386Sopenharmony_ci    friend class ::GrOp; // for ctor
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    TestOp(std::unique_ptr<GrFragmentProcessor> fp)
59cb93a386Sopenharmony_ci            : INHERITED(ClassID()), fProcessors(std::move(fp)) {
60cb93a386Sopenharmony_ci        this->setBounds(SkRect::MakeWH(100, 100), HasAABloat::kNo, IsHairline::kNo);
61cb93a386Sopenharmony_ci    }
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    GrProgramInfo* programInfo() override { return nullptr; }
64cb93a386Sopenharmony_ci    void onCreateProgramInfo(const GrCaps*,
65cb93a386Sopenharmony_ci                             SkArenaAlloc*,
66cb93a386Sopenharmony_ci                             const GrSurfaceProxyView& writeView,
67cb93a386Sopenharmony_ci                             bool usesMSAASurface,
68cb93a386Sopenharmony_ci                             GrAppliedClip&&,
69cb93a386Sopenharmony_ci                             const GrDstProxyView&,
70cb93a386Sopenharmony_ci                             GrXferBarrierFlags renderPassXferBarriers,
71cb93a386Sopenharmony_ci                             GrLoadOp colorLoadOp) override {}
72cb93a386Sopenharmony_ci    void onPrePrepareDraws(GrRecordingContext*,
73cb93a386Sopenharmony_ci                           const GrSurfaceProxyView& writeView,
74cb93a386Sopenharmony_ci                           GrAppliedClip*,
75cb93a386Sopenharmony_ci                           const GrDstProxyView&,
76cb93a386Sopenharmony_ci                           GrXferBarrierFlags renderPassXferBarriers,
77cb93a386Sopenharmony_ci                           GrLoadOp colorLoadOp) override {}
78cb93a386Sopenharmony_ci    void onPrepareDraws(GrMeshDrawTarget*) override { return; }
79cb93a386Sopenharmony_ci    void onExecute(GrOpFlushState*, const SkRect&) override { return; }
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ci    GrProcessorSet fProcessors;
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci    using INHERITED = GrMeshDrawOp;
84cb93a386Sopenharmony_ci};
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci/**
87cb93a386Sopenharmony_ci * FP used to test ref counts on owned GrGpuResources. Can also be a parent FP to test counts
88cb93a386Sopenharmony_ci * of resources owned by child FPs.
89cb93a386Sopenharmony_ci */
90cb93a386Sopenharmony_ciclass TestFP : public GrFragmentProcessor {
91cb93a386Sopenharmony_cipublic:
92cb93a386Sopenharmony_ci    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child) {
93cb93a386Sopenharmony_ci        return std::unique_ptr<GrFragmentProcessor>(new TestFP(std::move(child)));
94cb93a386Sopenharmony_ci    }
95cb93a386Sopenharmony_ci    static std::unique_ptr<GrFragmentProcessor> Make(const SkTArray<GrSurfaceProxyView>& views) {
96cb93a386Sopenharmony_ci        return std::unique_ptr<GrFragmentProcessor>(new TestFP(views));
97cb93a386Sopenharmony_ci    }
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    const char* name() const override { return "test"; }
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci    void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
102cb93a386Sopenharmony_ci        static std::atomic<int32_t> nextKey{0};
103cb93a386Sopenharmony_ci        b->add32(nextKey++);
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    std::unique_ptr<GrFragmentProcessor> clone() const override {
107cb93a386Sopenharmony_ci        return std::unique_ptr<GrFragmentProcessor>(new TestFP(*this));
108cb93a386Sopenharmony_ci    }
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ciprivate:
111cb93a386Sopenharmony_ci    TestFP(const SkTArray<GrSurfaceProxyView>& views)
112cb93a386Sopenharmony_ci            : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags) {
113cb93a386Sopenharmony_ci        for (const GrSurfaceProxyView& view : views) {
114cb93a386Sopenharmony_ci            this->registerChild(GrTextureEffect::Make(view, kUnknown_SkAlphaType));
115cb93a386Sopenharmony_ci        }
116cb93a386Sopenharmony_ci    }
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci    TestFP(std::unique_ptr<GrFragmentProcessor> child)
119cb93a386Sopenharmony_ci            : INHERITED(kTestFP_ClassID, kNone_OptimizationFlags) {
120cb93a386Sopenharmony_ci        this->registerChild(std::move(child));
121cb93a386Sopenharmony_ci    }
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci    explicit TestFP(const TestFP& that) : INHERITED(that) {}
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci    std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
126cb93a386Sopenharmony_ci        class Impl : public ProgramImpl {
127cb93a386Sopenharmony_ci        public:
128cb93a386Sopenharmony_ci            void emitCode(EmitArgs& args) override {
129cb93a386Sopenharmony_ci                args.fFragBuilder->codeAppendf("return half4(1);");
130cb93a386Sopenharmony_ci            }
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci        private:
133cb93a386Sopenharmony_ci        };
134cb93a386Sopenharmony_ci        return std::make_unique<Impl>();
135cb93a386Sopenharmony_ci    }
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci    bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci    using INHERITED = GrFragmentProcessor;
140cb93a386Sopenharmony_ci};
141cb93a386Sopenharmony_ci}  // namespace
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) {
144cb93a386Sopenharmony_ci    auto dContext = ctxInfo.directContext();
145cb93a386Sopenharmony_ci    GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci    static constexpr SkISize kDims = {10, 10};
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_ci    const GrBackendFormat format =
150cb93a386Sopenharmony_ci        dContext->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
151cb93a386Sopenharmony_ci                                                         GrRenderable::kNo);
152cb93a386Sopenharmony_ci    GrSwizzle swizzle = dContext->priv().caps()->getReadSwizzle(format, GrColorType::kRGBA_8888);
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ci    for (bool makeClone : {false, true}) {
155cb93a386Sopenharmony_ci        for (int parentCnt = 0; parentCnt < 2; parentCnt++) {
156cb93a386Sopenharmony_ci            auto sdc = skgpu::v1::SurfaceDrawContext::Make(
157cb93a386Sopenharmony_ci                    dContext, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox, {1, 1},
158cb93a386Sopenharmony_ci                    SkSurfaceProps());
159cb93a386Sopenharmony_ci            {
160cb93a386Sopenharmony_ci                sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(
161cb93a386Sopenharmony_ci                        format, kDims, GrRenderable::kNo, 1, GrMipmapped::kNo, SkBackingFit::kExact,
162cb93a386Sopenharmony_ci                        SkBudgeted::kYes, GrProtected::kNo);
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci                {
165cb93a386Sopenharmony_ci                    SkTArray<GrSurfaceProxyView> views;
166cb93a386Sopenharmony_ci                    views.push_back({proxy, kTopLeft_GrSurfaceOrigin, swizzle});
167cb93a386Sopenharmony_ci                    auto fp = TestFP::Make(std::move(views));
168cb93a386Sopenharmony_ci                    for (int i = 0; i < parentCnt; ++i) {
169cb93a386Sopenharmony_ci                        fp = TestFP::Make(std::move(fp));
170cb93a386Sopenharmony_ci                    }
171cb93a386Sopenharmony_ci                    std::unique_ptr<GrFragmentProcessor> clone;
172cb93a386Sopenharmony_ci                    if (makeClone) {
173cb93a386Sopenharmony_ci                        clone = fp->clone();
174cb93a386Sopenharmony_ci                    }
175cb93a386Sopenharmony_ci                    GrOp::Owner op = TestOp::Make(dContext, std::move(fp));
176cb93a386Sopenharmony_ci                    sdc->addDrawOp(std::move(op));
177cb93a386Sopenharmony_ci                    if (clone) {
178cb93a386Sopenharmony_ci                        op = TestOp::Make(dContext, std::move(clone));
179cb93a386Sopenharmony_ci                        sdc->addDrawOp(std::move(op));
180cb93a386Sopenharmony_ci                    }
181cb93a386Sopenharmony_ci                }
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_ci                // If the fp is cloned the number of refs should increase by one (for the clone)
184cb93a386Sopenharmony_ci                int expectedProxyRefs = makeClone ? 3 : 2;
185cb93a386Sopenharmony_ci
186cb93a386Sopenharmony_ci                CheckSingleThreadedProxyRefs(reporter, proxy.get(), expectedProxyRefs, -1);
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci                dContext->flushAndSubmit();
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci                // just one from the 'proxy' sk_sp
191cb93a386Sopenharmony_ci                CheckSingleThreadedProxyRefs(reporter, proxy.get(), 1, 1);
192cb93a386Sopenharmony_ci            }
193cb93a386Sopenharmony_ci        }
194cb93a386Sopenharmony_ci    }
195cb93a386Sopenharmony_ci}
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ci#include "tools/flags/CommandLineFlags.h"
198cb93a386Sopenharmony_cistatic DEFINE_bool(randomProcessorTest, false,
199cb93a386Sopenharmony_ci                   "Use non-deterministic seed for random processor tests?");
200cb93a386Sopenharmony_cistatic DEFINE_int(processorSeed, 0,
201cb93a386Sopenharmony_ci                  "Use specific seed for processor tests. Overridden by --randomProcessorTest.");
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_ci#if GR_TEST_UTILS
204cb93a386Sopenharmony_ci
205cb93a386Sopenharmony_cistatic GrColor input_texel_color(int x, int y, SkScalar delta) {
206cb93a386Sopenharmony_ci    // Delta must be less than 0.5 to prevent over/underflow issues with the input color
207cb93a386Sopenharmony_ci    SkASSERT(delta <= 0.5);
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_ci    SkColor color = SkColorSetARGB((uint8_t)(x & 0xFF),
210cb93a386Sopenharmony_ci                                   (uint8_t)(y & 0xFF),
211cb93a386Sopenharmony_ci                                   (uint8_t)((x + y) & 0xFF),
212cb93a386Sopenharmony_ci                                   (uint8_t)((2 * y - x) & 0xFF));
213cb93a386Sopenharmony_ci    SkColor4f color4f = SkColor4f::FromColor(color);
214cb93a386Sopenharmony_ci    // We only apply delta to the r,g, and b channels. This is because we're using this
215cb93a386Sopenharmony_ci    // to test the canTweakAlphaForCoverage() optimization. A processor is allowed
216cb93a386Sopenharmony_ci    // to use the input color's alpha in its calculation and report this optimization.
217cb93a386Sopenharmony_ci    for (int i = 0; i < 3; i++) {
218cb93a386Sopenharmony_ci        if (color4f[i] > 0.5) {
219cb93a386Sopenharmony_ci            color4f[i] -= delta;
220cb93a386Sopenharmony_ci        } else {
221cb93a386Sopenharmony_ci            color4f[i] += delta;
222cb93a386Sopenharmony_ci        }
223cb93a386Sopenharmony_ci    }
224cb93a386Sopenharmony_ci    return color4f.premul().toBytes_RGBA();
225cb93a386Sopenharmony_ci}
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci// The output buffer must be the same size as the render-target context.
228cb93a386Sopenharmony_cistatic void render_fp(GrDirectContext* dContext,
229cb93a386Sopenharmony_ci                      skgpu::v1::SurfaceDrawContext* sdc,
230cb93a386Sopenharmony_ci                      std::unique_ptr<GrFragmentProcessor> fp,
231cb93a386Sopenharmony_ci                      GrColor* outBuffer) {
232cb93a386Sopenharmony_ci    sdc->fillWithFP(std::move(fp));
233cb93a386Sopenharmony_ci    std::fill_n(outBuffer, sdc->width() * sdc->height(), 0);
234cb93a386Sopenharmony_ci    auto ii = SkImageInfo::Make(sdc->dimensions(), kRGBA_8888_SkColorType, kPremul_SkAlphaType);
235cb93a386Sopenharmony_ci    GrPixmap resultPM(ii, outBuffer, sdc->width()*sizeof(uint32_t));
236cb93a386Sopenharmony_ci    sdc->readPixels(dContext, resultPM, {0, 0});
237cb93a386Sopenharmony_ci}
238cb93a386Sopenharmony_ci
239cb93a386Sopenharmony_ci// This class is responsible for reproducibly generating a random fragment processor.
240cb93a386Sopenharmony_ci// An identical randomly-designed FP can be generated as many times as needed.
241cb93a386Sopenharmony_ciclass TestFPGenerator {
242cb93a386Sopenharmony_ci    public:
243cb93a386Sopenharmony_ci        TestFPGenerator() = delete;
244cb93a386Sopenharmony_ci        TestFPGenerator(GrDirectContext* context, GrResourceProvider* resourceProvider)
245cb93a386Sopenharmony_ci                : fContext(context)
246cb93a386Sopenharmony_ci                , fResourceProvider(resourceProvider)
247cb93a386Sopenharmony_ci                , fInitialSeed(synthesizeInitialSeed())
248cb93a386Sopenharmony_ci                , fRandomSeed(fInitialSeed) {}
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_ci        uint32_t initialSeed() { return fInitialSeed; }
251cb93a386Sopenharmony_ci
252cb93a386Sopenharmony_ci        bool init() {
253cb93a386Sopenharmony_ci            // Initializes the two test texture proxies that are available to the FP test factories.
254cb93a386Sopenharmony_ci            SkRandom random{fRandomSeed};
255cb93a386Sopenharmony_ci            static constexpr int kTestTextureSize = 256;
256cb93a386Sopenharmony_ci
257cb93a386Sopenharmony_ci            {
258cb93a386Sopenharmony_ci                // Put premul data into the RGBA texture that the test FPs can optionally use.
259cb93a386Sopenharmony_ci                GrColor* rgbaData = new GrColor[kTestTextureSize * kTestTextureSize];
260cb93a386Sopenharmony_ci                for (int y = 0; y < kTestTextureSize; ++y) {
261cb93a386Sopenharmony_ci                    for (int x = 0; x < kTestTextureSize; ++x) {
262cb93a386Sopenharmony_ci                        rgbaData[kTestTextureSize * y + x] = input_texel_color(
263cb93a386Sopenharmony_ci                                random.nextULessThan(256), random.nextULessThan(256), 0.0f);
264cb93a386Sopenharmony_ci                    }
265cb93a386Sopenharmony_ci                }
266cb93a386Sopenharmony_ci
267cb93a386Sopenharmony_ci                SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize,
268cb93a386Sopenharmony_ci                                                   kRGBA_8888_SkColorType, kPremul_SkAlphaType);
269cb93a386Sopenharmony_ci                SkBitmap bitmap;
270cb93a386Sopenharmony_ci                bitmap.installPixels(
271cb93a386Sopenharmony_ci                        ii, rgbaData, ii.minRowBytes(),
272cb93a386Sopenharmony_ci                        [](void* addr, void* context) { delete[](GrColor*) addr; }, nullptr);
273cb93a386Sopenharmony_ci                bitmap.setImmutable();
274cb93a386Sopenharmony_ci                auto view = std::get<0>(GrMakeUncachedBitmapProxyView(fContext, bitmap));
275cb93a386Sopenharmony_ci                if (!view || !view.proxy()->instantiate(fResourceProvider)) {
276cb93a386Sopenharmony_ci                    SkDebugf("Unable to instantiate RGBA8888 test texture.");
277cb93a386Sopenharmony_ci                    return false;
278cb93a386Sopenharmony_ci                }
279cb93a386Sopenharmony_ci                fTestViews[0] = GrProcessorTestData::ViewInfo{view, GrColorType::kRGBA_8888,
280cb93a386Sopenharmony_ci                                                              kPremul_SkAlphaType};
281cb93a386Sopenharmony_ci            }
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_ci            {
284cb93a386Sopenharmony_ci                // Put random values into the alpha texture that the test FPs can optionally use.
285cb93a386Sopenharmony_ci                uint8_t* alphaData = new uint8_t[kTestTextureSize * kTestTextureSize];
286cb93a386Sopenharmony_ci                for (int y = 0; y < kTestTextureSize; ++y) {
287cb93a386Sopenharmony_ci                    for (int x = 0; x < kTestTextureSize; ++x) {
288cb93a386Sopenharmony_ci                        alphaData[kTestTextureSize * y + x] = random.nextULessThan(256);
289cb93a386Sopenharmony_ci                    }
290cb93a386Sopenharmony_ci                }
291cb93a386Sopenharmony_ci
292cb93a386Sopenharmony_ci                SkImageInfo ii = SkImageInfo::Make(kTestTextureSize, kTestTextureSize,
293cb93a386Sopenharmony_ci                                                   kAlpha_8_SkColorType, kPremul_SkAlphaType);
294cb93a386Sopenharmony_ci                SkBitmap bitmap;
295cb93a386Sopenharmony_ci                bitmap.installPixels(
296cb93a386Sopenharmony_ci                        ii, alphaData, ii.minRowBytes(),
297cb93a386Sopenharmony_ci                        [](void* addr, void* context) { delete[](uint8_t*) addr; }, nullptr);
298cb93a386Sopenharmony_ci                bitmap.setImmutable();
299cb93a386Sopenharmony_ci                auto view = std::get<0>(GrMakeUncachedBitmapProxyView(fContext, bitmap));
300cb93a386Sopenharmony_ci                if (!view || !view.proxy()->instantiate(fResourceProvider)) {
301cb93a386Sopenharmony_ci                    SkDebugf("Unable to instantiate A8 test texture.");
302cb93a386Sopenharmony_ci                    return false;
303cb93a386Sopenharmony_ci                }
304cb93a386Sopenharmony_ci                fTestViews[1] = GrProcessorTestData::ViewInfo{view, GrColorType::kAlpha_8,
305cb93a386Sopenharmony_ci                                                              kPremul_SkAlphaType};
306cb93a386Sopenharmony_ci            }
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci            return true;
309cb93a386Sopenharmony_ci        }
310cb93a386Sopenharmony_ci
311cb93a386Sopenharmony_ci        void reroll() {
312cb93a386Sopenharmony_ci            // Feed our current random seed into SkRandom to generate a new seed.
313cb93a386Sopenharmony_ci            SkRandom random{fRandomSeed};
314cb93a386Sopenharmony_ci            fRandomSeed = random.nextU();
315cb93a386Sopenharmony_ci        }
316cb93a386Sopenharmony_ci
317cb93a386Sopenharmony_ci        std::unique_ptr<GrFragmentProcessor> make(int type, int randomTreeDepth,
318cb93a386Sopenharmony_ci                                                  std::unique_ptr<GrFragmentProcessor> inputFP) {
319cb93a386Sopenharmony_ci            // This will generate the exact same randomized FP (of each requested type) each time
320cb93a386Sopenharmony_ci            // it's called. Call `reroll` to get a different FP.
321cb93a386Sopenharmony_ci            SkRandom random{fRandomSeed};
322cb93a386Sopenharmony_ci            GrProcessorTestData testData{&random, fContext, randomTreeDepth,
323cb93a386Sopenharmony_ci                                         SK_ARRAY_COUNT(fTestViews), fTestViews,
324cb93a386Sopenharmony_ci                                         std::move(inputFP)};
325cb93a386Sopenharmony_ci            return GrFragmentProcessorTestFactory::MakeIdx(type, &testData);
326cb93a386Sopenharmony_ci        }
327cb93a386Sopenharmony_ci
328cb93a386Sopenharmony_ci        std::unique_ptr<GrFragmentProcessor> make(int type, int randomTreeDepth,
329cb93a386Sopenharmony_ci                                                  GrSurfaceProxyView view,
330cb93a386Sopenharmony_ci                                                  SkAlphaType alpha = kPremul_SkAlphaType) {
331cb93a386Sopenharmony_ci            return make(type, randomTreeDepth, GrTextureEffect::Make(view, alpha));
332cb93a386Sopenharmony_ci        }
333cb93a386Sopenharmony_ci
334cb93a386Sopenharmony_ci    private:
335cb93a386Sopenharmony_ci        static uint32_t synthesizeInitialSeed() {
336cb93a386Sopenharmony_ci            if (FLAGS_randomProcessorTest) {
337cb93a386Sopenharmony_ci                std::random_device rd;
338cb93a386Sopenharmony_ci                return rd();
339cb93a386Sopenharmony_ci            } else {
340cb93a386Sopenharmony_ci                return FLAGS_processorSeed;
341cb93a386Sopenharmony_ci            }
342cb93a386Sopenharmony_ci        }
343cb93a386Sopenharmony_ci
344cb93a386Sopenharmony_ci        GrDirectContext* fContext;              // owned by caller
345cb93a386Sopenharmony_ci        GrResourceProvider* fResourceProvider;  // owned by caller
346cb93a386Sopenharmony_ci        const uint32_t fInitialSeed;
347cb93a386Sopenharmony_ci        uint32_t fRandomSeed;
348cb93a386Sopenharmony_ci        GrProcessorTestData::ViewInfo fTestViews[2];
349cb93a386Sopenharmony_ci};
350cb93a386Sopenharmony_ci
351cb93a386Sopenharmony_ci// Creates an array of color values from input_texel_color(), to be used as an input texture.
352cb93a386Sopenharmony_cistatic std::vector<GrColor> make_input_pixels(int width, int height, SkScalar delta) {
353cb93a386Sopenharmony_ci    std::vector<GrColor> pixel(width * height);
354cb93a386Sopenharmony_ci    for (int y = 0; y < width; ++y) {
355cb93a386Sopenharmony_ci        for (int x = 0; x < height; ++x) {
356cb93a386Sopenharmony_ci            pixel[width * y + x] = input_texel_color(x, y, delta);
357cb93a386Sopenharmony_ci        }
358cb93a386Sopenharmony_ci    }
359cb93a386Sopenharmony_ci
360cb93a386Sopenharmony_ci    return pixel;
361cb93a386Sopenharmony_ci}
362cb93a386Sopenharmony_ci
363cb93a386Sopenharmony_ci// Creates a texture of premul colors used as the output of the fragment processor that precedes
364cb93a386Sopenharmony_ci// the fragment processor under test. An array of W*H colors are passed in as the texture data.
365cb93a386Sopenharmony_cistatic GrSurfaceProxyView make_input_texture(GrRecordingContext* context,
366cb93a386Sopenharmony_ci                                      int width, int height, GrColor* pixel) {
367cb93a386Sopenharmony_ci    SkImageInfo ii = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
368cb93a386Sopenharmony_ci    SkBitmap bitmap;
369cb93a386Sopenharmony_ci    bitmap.installPixels(ii, pixel, ii.minRowBytes());
370cb93a386Sopenharmony_ci    bitmap.setImmutable();
371cb93a386Sopenharmony_ci    return std::get<0>(GrMakeUncachedBitmapProxyView(context, bitmap));
372cb93a386Sopenharmony_ci}
373cb93a386Sopenharmony_ci
374cb93a386Sopenharmony_ci// We tag logged data as unpremul to avoid conversion when encoding as PNG. The input texture
375cb93a386Sopenharmony_ci// actually contains unpremul data. Also, even though we made the result data by rendering into
376cb93a386Sopenharmony_ci// a "unpremul" SurfaceDrawContext, our input texture is unpremul and outside of the random
377cb93a386Sopenharmony_ci// effect configuration, we didn't do anything to ensure the output is actually premul. We just
378cb93a386Sopenharmony_ci// don't currently allow kUnpremul GrSurfaceDrawContexts.
379cb93a386Sopenharmony_cistatic constexpr auto kLogAlphaType = kUnpremul_SkAlphaType;
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_cistatic bool log_pixels(GrColor* pixels, int widthHeight, SkString* dst) {
382cb93a386Sopenharmony_ci    SkImageInfo info =
383cb93a386Sopenharmony_ci            SkImageInfo::Make(widthHeight, widthHeight, kRGBA_8888_SkColorType, kLogAlphaType);
384cb93a386Sopenharmony_ci    SkBitmap bmp;
385cb93a386Sopenharmony_ci    bmp.installPixels(info, pixels, widthHeight * sizeof(GrColor));
386cb93a386Sopenharmony_ci    return BipmapToBase64DataURI(bmp, dst);
387cb93a386Sopenharmony_ci}
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_cistatic bool log_texture_view(GrDirectContext* dContext, GrSurfaceProxyView src, SkString* dst) {
390cb93a386Sopenharmony_ci    SkImageInfo ii = SkImageInfo::Make(src.proxy()->dimensions(), kRGBA_8888_SkColorType,
391cb93a386Sopenharmony_ci                                       kLogAlphaType);
392cb93a386Sopenharmony_ci
393cb93a386Sopenharmony_ci    auto sContext = dContext->priv().makeSC(std::move(src), ii.colorInfo());
394cb93a386Sopenharmony_ci    SkBitmap bm;
395cb93a386Sopenharmony_ci    SkAssertResult(bm.tryAllocPixels(ii));
396cb93a386Sopenharmony_ci    SkAssertResult(sContext->readPixels(dContext, bm.pixmap(), {0, 0}));
397cb93a386Sopenharmony_ci    return BipmapToBase64DataURI(bm, dst);
398cb93a386Sopenharmony_ci}
399cb93a386Sopenharmony_ci
400cb93a386Sopenharmony_cistatic bool fuzzy_color_equals(const SkPMColor4f& c1, const SkPMColor4f& c2) {
401cb93a386Sopenharmony_ci    // With the loss of precision of rendering into 32-bit color, then estimating the FP's output
402cb93a386Sopenharmony_ci    // from that, it is not uncommon for a valid output to differ from estimate by up to 0.01
403cb93a386Sopenharmony_ci    // (really 1/128 ~ .0078, but frequently floating point issues make that tolerance a little
404cb93a386Sopenharmony_ci    // too unforgiving).
405cb93a386Sopenharmony_ci    static constexpr SkScalar kTolerance = 0.01f;
406cb93a386Sopenharmony_ci    for (int i = 0; i < 4; i++) {
407cb93a386Sopenharmony_ci        if (!SkScalarNearlyEqual(c1[i], c2[i], kTolerance)) {
408cb93a386Sopenharmony_ci            return false;
409cb93a386Sopenharmony_ci        }
410cb93a386Sopenharmony_ci    }
411cb93a386Sopenharmony_ci    return true;
412cb93a386Sopenharmony_ci}
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ci// Given three input colors (color preceding the FP being tested) provided to the FP at the same
415cb93a386Sopenharmony_ci// local coord and the three corresponding FP outputs, this ensures that either:
416cb93a386Sopenharmony_ci//   out[0] = fp * in[0].a, out[1] = fp * in[1].a, and out[2] = fp * in[2].a
417cb93a386Sopenharmony_ci// where fp is the pre-modulated color that should not be changing across frames (FP's state doesn't
418cb93a386Sopenharmony_ci// change), OR:
419cb93a386Sopenharmony_ci//   out[0] = fp * in[0], out[1] = fp * in[1], and out[2] = fp * in[2]
420cb93a386Sopenharmony_ci// (per-channel modulation instead of modulation by just the alpha channel)
421cb93a386Sopenharmony_ci// It does this by estimating the pre-modulated fp color from one of the input/output pairs and
422cb93a386Sopenharmony_ci// confirms the conditions hold for the other two pairs.
423cb93a386Sopenharmony_ci// It is required that the three input colors have the same alpha as fp is allowed to be a function
424cb93a386Sopenharmony_ci// of the input alpha (but not r, g, or b).
425cb93a386Sopenharmony_cistatic bool legal_modulation(const GrColor inGr[3], const GrColor outGr[3]) {
426cb93a386Sopenharmony_ci    // Convert to floating point, which is the number space the FP operates in (more or less)
427cb93a386Sopenharmony_ci    SkPMColor4f inf[3], outf[3];
428cb93a386Sopenharmony_ci    for (int i = 0; i < 3; ++i) {
429cb93a386Sopenharmony_ci        inf[i]  = SkPMColor4f::FromBytes_RGBA(inGr[i]);
430cb93a386Sopenharmony_ci        outf[i] = SkPMColor4f::FromBytes_RGBA(outGr[i]);
431cb93a386Sopenharmony_ci    }
432cb93a386Sopenharmony_ci    // This test is only valid if all the input alphas are the same.
433cb93a386Sopenharmony_ci    SkASSERT(inf[0].fA == inf[1].fA && inf[1].fA == inf[2].fA);
434cb93a386Sopenharmony_ci
435cb93a386Sopenharmony_ci    // Reconstruct the output of the FP before the shader modulated its color with the input value.
436cb93a386Sopenharmony_ci    // When the original input is very small, it may cause the final output color to round
437cb93a386Sopenharmony_ci    // to 0, in which case we estimate the pre-modulated color using one of the stepped frames that
438cb93a386Sopenharmony_ci    // will then have a guaranteed larger channel value (since the offset will be added to it).
439cb93a386Sopenharmony_ci    SkPMColor4f fpPreColorModulation = {0,0,0,0};
440cb93a386Sopenharmony_ci    SkPMColor4f fpPreAlphaModulation = {0,0,0,0};
441cb93a386Sopenharmony_ci    for (int i = 0; i < 4; i++) {
442cb93a386Sopenharmony_ci        // Use the most stepped up frame
443cb93a386Sopenharmony_ci        int maxInIdx = inf[0][i] > inf[1][i] ? 0 : 1;
444cb93a386Sopenharmony_ci        maxInIdx = inf[maxInIdx][i] > inf[2][i] ? maxInIdx : 2;
445cb93a386Sopenharmony_ci        const SkPMColor4f& in = inf[maxInIdx];
446cb93a386Sopenharmony_ci        const SkPMColor4f& out = outf[maxInIdx];
447cb93a386Sopenharmony_ci        if (in[i] > 0) {
448cb93a386Sopenharmony_ci            fpPreColorModulation[i] = out[i] / in[i];
449cb93a386Sopenharmony_ci        }
450cb93a386Sopenharmony_ci        if (in[3] > 0) {
451cb93a386Sopenharmony_ci            fpPreAlphaModulation[i] = out[i] / in[3];
452cb93a386Sopenharmony_ci        }
453cb93a386Sopenharmony_ci    }
454cb93a386Sopenharmony_ci
455cb93a386Sopenharmony_ci    // With reconstructed pre-modulated FP output, derive the expected value of fp * input for each
456cb93a386Sopenharmony_ci    // of the transformed input colors.
457cb93a386Sopenharmony_ci    SkPMColor4f expectedForAlphaModulation[3];
458cb93a386Sopenharmony_ci    SkPMColor4f expectedForColorModulation[3];
459cb93a386Sopenharmony_ci    for (int i = 0; i < 3; ++i) {
460cb93a386Sopenharmony_ci        expectedForAlphaModulation[i] = fpPreAlphaModulation * inf[i].fA;
461cb93a386Sopenharmony_ci        expectedForColorModulation[i] = fpPreColorModulation * inf[i];
462cb93a386Sopenharmony_ci        // If the input alpha is 0 then the other channels should also be zero
463cb93a386Sopenharmony_ci        // since the color is assumed to be premul. Modulating zeros by anything
464cb93a386Sopenharmony_ci        // should produce zeros.
465cb93a386Sopenharmony_ci        if (inf[i].fA == 0) {
466cb93a386Sopenharmony_ci            SkASSERT(inf[i].fR == 0 && inf[i].fG == 0 && inf[i].fB == 0);
467cb93a386Sopenharmony_ci            expectedForColorModulation[i] = expectedForAlphaModulation[i] = {0, 0, 0, 0};
468cb93a386Sopenharmony_ci        }
469cb93a386Sopenharmony_ci    }
470cb93a386Sopenharmony_ci
471cb93a386Sopenharmony_ci    bool isLegalColorModulation = fuzzy_color_equals(outf[0], expectedForColorModulation[0]) &&
472cb93a386Sopenharmony_ci                                  fuzzy_color_equals(outf[1], expectedForColorModulation[1]) &&
473cb93a386Sopenharmony_ci                                  fuzzy_color_equals(outf[2], expectedForColorModulation[2]);
474cb93a386Sopenharmony_ci
475cb93a386Sopenharmony_ci    bool isLegalAlphaModulation = fuzzy_color_equals(outf[0], expectedForAlphaModulation[0]) &&
476cb93a386Sopenharmony_ci                                  fuzzy_color_equals(outf[1], expectedForAlphaModulation[1]) &&
477cb93a386Sopenharmony_ci                                  fuzzy_color_equals(outf[2], expectedForAlphaModulation[2]);
478cb93a386Sopenharmony_ci
479cb93a386Sopenharmony_ci    // This can be enabled to print the values that caused this check to fail.
480cb93a386Sopenharmony_ci    if (0 && !isLegalColorModulation && !isLegalAlphaModulation) {
481cb93a386Sopenharmony_ci        SkDebugf("Color modulation test\n\timplied mod color: (%.03f, %.03f, %.03f, %.03f)\n",
482cb93a386Sopenharmony_ci                 fpPreColorModulation[0],
483cb93a386Sopenharmony_ci                 fpPreColorModulation[1],
484cb93a386Sopenharmony_ci                 fpPreColorModulation[2],
485cb93a386Sopenharmony_ci                 fpPreColorModulation[3]);
486cb93a386Sopenharmony_ci        for (int i = 0; i < 3; ++i) {
487cb93a386Sopenharmony_ci            SkDebugf("\t(%.03f, %.03f, %.03f, %.03f) -> "
488cb93a386Sopenharmony_ci                     "(%.03f, %.03f, %.03f, %.03f) | "
489cb93a386Sopenharmony_ci                     "(%.03f, %.03f, %.03f, %.03f), ok: %d\n",
490cb93a386Sopenharmony_ci                     inf[i].fR, inf[i].fG, inf[i].fB, inf[i].fA,
491cb93a386Sopenharmony_ci                     outf[i].fR, outf[i].fG, outf[i].fB, outf[i].fA,
492cb93a386Sopenharmony_ci                     expectedForColorModulation[i].fR, expectedForColorModulation[i].fG,
493cb93a386Sopenharmony_ci                     expectedForColorModulation[i].fB, expectedForColorModulation[i].fA,
494cb93a386Sopenharmony_ci                     fuzzy_color_equals(outf[i], expectedForColorModulation[i]));
495cb93a386Sopenharmony_ci        }
496cb93a386Sopenharmony_ci        SkDebugf("Alpha modulation test\n\timplied mod color: (%.03f, %.03f, %.03f, %.03f)\n",
497cb93a386Sopenharmony_ci                 fpPreAlphaModulation[0],
498cb93a386Sopenharmony_ci                 fpPreAlphaModulation[1],
499cb93a386Sopenharmony_ci                 fpPreAlphaModulation[2],
500cb93a386Sopenharmony_ci                 fpPreAlphaModulation[3]);
501cb93a386Sopenharmony_ci        for (int i = 0; i < 3; ++i) {
502cb93a386Sopenharmony_ci            SkDebugf("\t(%.03f, %.03f, %.03f, %.03f) -> "
503cb93a386Sopenharmony_ci                     "(%.03f, %.03f, %.03f, %.03f) | "
504cb93a386Sopenharmony_ci                     "(%.03f, %.03f, %.03f, %.03f), ok: %d\n",
505cb93a386Sopenharmony_ci                     inf[i].fR, inf[i].fG, inf[i].fB, inf[i].fA,
506cb93a386Sopenharmony_ci                     outf[i].fR, outf[i].fG, outf[i].fB, outf[i].fA,
507cb93a386Sopenharmony_ci                     expectedForAlphaModulation[i].fR, expectedForAlphaModulation[i].fG,
508cb93a386Sopenharmony_ci                     expectedForAlphaModulation[i].fB, expectedForAlphaModulation[i].fA,
509cb93a386Sopenharmony_ci                     fuzzy_color_equals(outf[i], expectedForAlphaModulation[i]));
510cb93a386Sopenharmony_ci        }
511cb93a386Sopenharmony_ci    }
512cb93a386Sopenharmony_ci    return isLegalColorModulation || isLegalAlphaModulation;
513cb93a386Sopenharmony_ci}
514cb93a386Sopenharmony_ci
515cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) {
516cb93a386Sopenharmony_ci    GrDirectContext* context = ctxInfo.directContext();
517cb93a386Sopenharmony_ci    GrResourceProvider* resourceProvider = context->priv().resourceProvider();
518cb93a386Sopenharmony_ci    using FPFactory = GrFragmentProcessorTestFactory;
519cb93a386Sopenharmony_ci
520cb93a386Sopenharmony_ci    TestFPGenerator fpGenerator{context, resourceProvider};
521cb93a386Sopenharmony_ci    if (!fpGenerator.init()) {
522cb93a386Sopenharmony_ci        ERRORF(reporter, "Could not initialize TestFPGenerator");
523cb93a386Sopenharmony_ci        return;
524cb93a386Sopenharmony_ci    }
525cb93a386Sopenharmony_ci
526cb93a386Sopenharmony_ci    // Make the destination context for the test.
527cb93a386Sopenharmony_ci    static constexpr int kRenderSize = 256;
528cb93a386Sopenharmony_ci    auto sdc = skgpu::v1::SurfaceDrawContext::Make(
529cb93a386Sopenharmony_ci            context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact,
530cb93a386Sopenharmony_ci            {kRenderSize, kRenderSize}, SkSurfaceProps());
531cb93a386Sopenharmony_ci
532cb93a386Sopenharmony_ci    // Coverage optimization uses three frames with a linearly transformed input texture.  The first
533cb93a386Sopenharmony_ci    // frame has no offset, second frames add .2 and .4, which should then be present as a fixed
534cb93a386Sopenharmony_ci    // difference between the frame outputs if the FP is properly following the modulation
535cb93a386Sopenharmony_ci    // requirements of the coverage optimization.
536cb93a386Sopenharmony_ci    static constexpr SkScalar kInputDelta = 0.2f;
537cb93a386Sopenharmony_ci    std::vector<GrColor> inputPixels1 = make_input_pixels(kRenderSize, kRenderSize, 0.0f);
538cb93a386Sopenharmony_ci    std::vector<GrColor> inputPixels2 =
539cb93a386Sopenharmony_ci            make_input_pixels(kRenderSize, kRenderSize, 1 * kInputDelta);
540cb93a386Sopenharmony_ci    std::vector<GrColor> inputPixels3 =
541cb93a386Sopenharmony_ci            make_input_pixels(kRenderSize, kRenderSize, 2 * kInputDelta);
542cb93a386Sopenharmony_ci    GrSurfaceProxyView inputTexture1 =
543cb93a386Sopenharmony_ci            make_input_texture(context, kRenderSize, kRenderSize, inputPixels1.data());
544cb93a386Sopenharmony_ci    GrSurfaceProxyView inputTexture2 =
545cb93a386Sopenharmony_ci            make_input_texture(context, kRenderSize, kRenderSize, inputPixels2.data());
546cb93a386Sopenharmony_ci    GrSurfaceProxyView inputTexture3 =
547cb93a386Sopenharmony_ci            make_input_texture(context, kRenderSize, kRenderSize, inputPixels3.data());
548cb93a386Sopenharmony_ci
549cb93a386Sopenharmony_ci    // Encoded images are very verbose and this tests many potential images, so only export the
550cb93a386Sopenharmony_ci    // first failure (subsequent failures have a reasonable chance of being related).
551cb93a386Sopenharmony_ci    bool loggedFirstFailure = false;
552cb93a386Sopenharmony_ci    bool loggedFirstWarning = false;
553cb93a386Sopenharmony_ci
554cb93a386Sopenharmony_ci    // Storage for the three frames required for coverage compatibility optimization testing.
555cb93a386Sopenharmony_ci    // Each frame uses the correspondingly numbered inputTextureX.
556cb93a386Sopenharmony_ci    std::vector<GrColor> readData1(kRenderSize * kRenderSize);
557cb93a386Sopenharmony_ci    std::vector<GrColor> readData2(kRenderSize * kRenderSize);
558cb93a386Sopenharmony_ci    std::vector<GrColor> readData3(kRenderSize * kRenderSize);
559cb93a386Sopenharmony_ci
560cb93a386Sopenharmony_ci    // Because processor factories configure themselves in random ways, this is not exhaustive.
561cb93a386Sopenharmony_ci    for (int i = 0; i < FPFactory::Count(); ++i) {
562cb93a386Sopenharmony_ci        int optimizedForOpaqueInput = 0;
563cb93a386Sopenharmony_ci        int optimizedForCoverageAsAlpha = 0;
564cb93a386Sopenharmony_ci        int optimizedForConstantOutputForInput = 0;
565cb93a386Sopenharmony_ci
566cb93a386Sopenharmony_ci#ifdef __MSVC_RUNTIME_CHECKS
567cb93a386Sopenharmony_ci        // This test is infuriatingly slow with MSVC runtime checks enabled
568cb93a386Sopenharmony_ci        static constexpr int kMinimumTrials = 1;
569cb93a386Sopenharmony_ci        static constexpr int kMaximumTrials = 1;
570cb93a386Sopenharmony_ci        static constexpr int kExpectedSuccesses = 1;
571cb93a386Sopenharmony_ci#else
572cb93a386Sopenharmony_ci        // We start by testing each fragment-processor 100 times, watching the optimization bits
573cb93a386Sopenharmony_ci        // that appear. If we see an optimization bit appear in those first 100 trials, we keep
574cb93a386Sopenharmony_ci        // running tests until we see at least five successful trials that have this optimization
575cb93a386Sopenharmony_ci        // bit enabled. If we never see a particular optimization bit after 100 trials, we assume
576cb93a386Sopenharmony_ci        // that this FP doesn't support that optimization at all.
577cb93a386Sopenharmony_ci        static constexpr int kMinimumTrials = 100;
578cb93a386Sopenharmony_ci        static constexpr int kMaximumTrials = 2000;
579cb93a386Sopenharmony_ci        static constexpr int kExpectedSuccesses = 5;
580cb93a386Sopenharmony_ci#endif
581cb93a386Sopenharmony_ci
582cb93a386Sopenharmony_ci        for (int trial = 0;; ++trial) {
583cb93a386Sopenharmony_ci            // Create a randomly-configured FP.
584cb93a386Sopenharmony_ci            fpGenerator.reroll();
585cb93a386Sopenharmony_ci            std::unique_ptr<GrFragmentProcessor> fp =
586cb93a386Sopenharmony_ci                    fpGenerator.make(i, /*randomTreeDepth=*/1, inputTexture1);
587cb93a386Sopenharmony_ci
588cb93a386Sopenharmony_ci            // If we have iterated enough times and seen a sufficient number of successes on each
589cb93a386Sopenharmony_ci            // optimization bit that can be returned, stop running trials.
590cb93a386Sopenharmony_ci            if (trial >= kMinimumTrials) {
591cb93a386Sopenharmony_ci                bool moreTrialsNeeded = (optimizedForOpaqueInput > 0 &&
592cb93a386Sopenharmony_ci                                         optimizedForOpaqueInput < kExpectedSuccesses) ||
593cb93a386Sopenharmony_ci                                        (optimizedForCoverageAsAlpha > 0 &&
594cb93a386Sopenharmony_ci                                         optimizedForCoverageAsAlpha < kExpectedSuccesses) ||
595cb93a386Sopenharmony_ci                                        (optimizedForConstantOutputForInput > 0 &&
596cb93a386Sopenharmony_ci                                         optimizedForConstantOutputForInput < kExpectedSuccesses);
597cb93a386Sopenharmony_ci                if (!moreTrialsNeeded) break;
598cb93a386Sopenharmony_ci
599cb93a386Sopenharmony_ci                if (trial >= kMaximumTrials) {
600cb93a386Sopenharmony_ci                    SkDebugf("Abandoning ProcessorOptimizationValidationTest after %d trials. "
601cb93a386Sopenharmony_ci                             "Seed: 0x%08x, processor:\n%s",
602cb93a386Sopenharmony_ci                             kMaximumTrials, fpGenerator.initialSeed(), fp->dumpTreeInfo().c_str());
603cb93a386Sopenharmony_ci                    break;
604cb93a386Sopenharmony_ci                }
605cb93a386Sopenharmony_ci            }
606cb93a386Sopenharmony_ci
607cb93a386Sopenharmony_ci            // Skip further testing if this trial has no optimization bits enabled.
608cb93a386Sopenharmony_ci            if (!fp->hasConstantOutputForConstantInput() && !fp->preservesOpaqueInput() &&
609cb93a386Sopenharmony_ci                !fp->compatibleWithCoverageAsAlpha()) {
610cb93a386Sopenharmony_ci                continue;
611cb93a386Sopenharmony_ci            }
612cb93a386Sopenharmony_ci
613cb93a386Sopenharmony_ci            // We can make identical copies of the test FP in order to test coverage-as-alpha.
614cb93a386Sopenharmony_ci            if (fp->compatibleWithCoverageAsAlpha()) {
615cb93a386Sopenharmony_ci                // Create and render two identical versions of this FP, but using different input
616cb93a386Sopenharmony_ci                // textures, to check coverage optimization. We don't need to do this step for
617cb93a386Sopenharmony_ci                // constant-output or preserving-opacity tests.
618cb93a386Sopenharmony_ci                render_fp(context, sdc.get(),
619cb93a386Sopenharmony_ci                          fpGenerator.make(i, /*randomTreeDepth=*/1, inputTexture2),
620cb93a386Sopenharmony_ci                          readData2.data());
621cb93a386Sopenharmony_ci                render_fp(context, sdc.get(),
622cb93a386Sopenharmony_ci                          fpGenerator.make(i, /*randomTreeDepth=*/1, inputTexture3),
623cb93a386Sopenharmony_ci                          readData3.data());
624cb93a386Sopenharmony_ci                ++optimizedForCoverageAsAlpha;
625cb93a386Sopenharmony_ci            }
626cb93a386Sopenharmony_ci
627cb93a386Sopenharmony_ci            if (fp->hasConstantOutputForConstantInput()) {
628cb93a386Sopenharmony_ci                ++optimizedForConstantOutputForInput;
629cb93a386Sopenharmony_ci            }
630cb93a386Sopenharmony_ci
631cb93a386Sopenharmony_ci            if (fp->preservesOpaqueInput()) {
632cb93a386Sopenharmony_ci                ++optimizedForOpaqueInput;
633cb93a386Sopenharmony_ci            }
634cb93a386Sopenharmony_ci
635cb93a386Sopenharmony_ci            // Draw base frame last so that rtc holds the original FP behavior if we need to dump
636cb93a386Sopenharmony_ci            // the image to the log.
637cb93a386Sopenharmony_ci            render_fp(context, sdc.get(), fpGenerator.make(i, /*randomTreeDepth=*/1, inputTexture1),
638cb93a386Sopenharmony_ci                      readData1.data());
639cb93a386Sopenharmony_ci
640cb93a386Sopenharmony_ci            // This test has a history of being flaky on a number of devices. If an FP is logically
641cb93a386Sopenharmony_ci            // violating the optimizations, it's reasonable to expect it to violate requirements on
642cb93a386Sopenharmony_ci            // a large number of pixels in the image. Sporadic pixel violations are more indicative
643cb93a386Sopenharmony_ci            // of device errors and represents a separate problem.
644cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_SKQP)
645cb93a386Sopenharmony_ci            static constexpr int kMaxAcceptableFailedPixels = 0; // Strict when running as SKQP
646cb93a386Sopenharmony_ci#else
647cb93a386Sopenharmony_ci            static constexpr int kMaxAcceptableFailedPixels = 2 * kRenderSize; // ~0.7% of the image
648cb93a386Sopenharmony_ci#endif
649cb93a386Sopenharmony_ci
650cb93a386Sopenharmony_ci            // Collect first optimization failure message, to be output later as a warning or an
651cb93a386Sopenharmony_ci            // error depending on whether the rendering "passed" or failed.
652cb93a386Sopenharmony_ci            int failedPixelCount = 0;
653cb93a386Sopenharmony_ci            SkString coverageMessage;
654cb93a386Sopenharmony_ci            SkString opaqueMessage;
655cb93a386Sopenharmony_ci            SkString constMessage;
656cb93a386Sopenharmony_ci            for (int y = 0; y < kRenderSize; ++y) {
657cb93a386Sopenharmony_ci                for (int x = 0; x < kRenderSize; ++x) {
658cb93a386Sopenharmony_ci                    bool passing = true;
659cb93a386Sopenharmony_ci                    GrColor input = inputPixels1[y * kRenderSize + x];
660cb93a386Sopenharmony_ci                    GrColor output = readData1[y * kRenderSize + x];
661cb93a386Sopenharmony_ci
662cb93a386Sopenharmony_ci                    if (fp->compatibleWithCoverageAsAlpha()) {
663cb93a386Sopenharmony_ci                        GrColor ins[3];
664cb93a386Sopenharmony_ci                        ins[0] = input;
665cb93a386Sopenharmony_ci                        ins[1] = inputPixels2[y * kRenderSize + x];
666cb93a386Sopenharmony_ci                        ins[2] = inputPixels3[y * kRenderSize + x];
667cb93a386Sopenharmony_ci
668cb93a386Sopenharmony_ci                        GrColor outs[3];
669cb93a386Sopenharmony_ci                        outs[0] = output;
670cb93a386Sopenharmony_ci                        outs[1] = readData2[y * kRenderSize + x];
671cb93a386Sopenharmony_ci                        outs[2] = readData3[y * kRenderSize + x];
672cb93a386Sopenharmony_ci
673cb93a386Sopenharmony_ci                        if (!legal_modulation(ins, outs)) {
674cb93a386Sopenharmony_ci                            passing = false;
675cb93a386Sopenharmony_ci                            if (coverageMessage.isEmpty()) {
676cb93a386Sopenharmony_ci                                coverageMessage.printf(
677cb93a386Sopenharmony_ci                                        "\"Modulating\" processor did not match alpha-modulation "
678cb93a386Sopenharmony_ci                                        "nor color-modulation rules.\n"
679cb93a386Sopenharmony_ci                                        "Input: 0x%08x, Output: 0x%08x, pixel (%d, %d).",
680cb93a386Sopenharmony_ci                                        input, output, x, y);
681cb93a386Sopenharmony_ci                            }
682cb93a386Sopenharmony_ci                        }
683cb93a386Sopenharmony_ci                    }
684cb93a386Sopenharmony_ci
685cb93a386Sopenharmony_ci                    SkPMColor4f input4f = SkPMColor4f::FromBytes_RGBA(input);
686cb93a386Sopenharmony_ci                    SkPMColor4f output4f = SkPMColor4f::FromBytes_RGBA(output);
687cb93a386Sopenharmony_ci                    SkPMColor4f expected4f;
688cb93a386Sopenharmony_ci                    if (fp->hasConstantOutputForConstantInput(input4f, &expected4f)) {
689cb93a386Sopenharmony_ci                        float rDiff = fabsf(output4f.fR - expected4f.fR);
690cb93a386Sopenharmony_ci                        float gDiff = fabsf(output4f.fG - expected4f.fG);
691cb93a386Sopenharmony_ci                        float bDiff = fabsf(output4f.fB - expected4f.fB);
692cb93a386Sopenharmony_ci                        float aDiff = fabsf(output4f.fA - expected4f.fA);
693cb93a386Sopenharmony_ci                        static constexpr float kTol = 4 / 255.f;
694cb93a386Sopenharmony_ci                        if (rDiff > kTol || gDiff > kTol || bDiff > kTol || aDiff > kTol) {
695cb93a386Sopenharmony_ci                            if (constMessage.isEmpty()) {
696cb93a386Sopenharmony_ci                                passing = false;
697cb93a386Sopenharmony_ci
698cb93a386Sopenharmony_ci                                constMessage.printf(
699cb93a386Sopenharmony_ci                                        "Processor claimed output for const input doesn't match "
700cb93a386Sopenharmony_ci                                        "actual output.\n"
701cb93a386Sopenharmony_ci                                        "Error: %f, Tolerance: %f, input: (%f, %f, %f, %f), "
702cb93a386Sopenharmony_ci                                        "actual: (%f, %f, %f, %f), expected(%f, %f, %f, %f).",
703cb93a386Sopenharmony_ci                                        std::max(rDiff, std::max(gDiff, std::max(bDiff, aDiff))),
704cb93a386Sopenharmony_ci                                        kTol, input4f.fR, input4f.fG, input4f.fB, input4f.fA,
705cb93a386Sopenharmony_ci                                        output4f.fR, output4f.fG, output4f.fB, output4f.fA,
706cb93a386Sopenharmony_ci                                        expected4f.fR, expected4f.fG, expected4f.fB, expected4f.fA);
707cb93a386Sopenharmony_ci                            }
708cb93a386Sopenharmony_ci                        }
709cb93a386Sopenharmony_ci                    }
710cb93a386Sopenharmony_ci                    if (input4f.isOpaque() && fp->preservesOpaqueInput() && !output4f.isOpaque()) {
711cb93a386Sopenharmony_ci                        passing = false;
712cb93a386Sopenharmony_ci
713cb93a386Sopenharmony_ci                        if (opaqueMessage.isEmpty()) {
714cb93a386Sopenharmony_ci                            opaqueMessage.printf(
715cb93a386Sopenharmony_ci                                    "Processor claimed opaqueness is preserved but "
716cb93a386Sopenharmony_ci                                    "it is not. Input: 0x%08x, Output: 0x%08x.",
717cb93a386Sopenharmony_ci                                    input, output);
718cb93a386Sopenharmony_ci                        }
719cb93a386Sopenharmony_ci                    }
720cb93a386Sopenharmony_ci
721cb93a386Sopenharmony_ci                    if (!passing) {
722cb93a386Sopenharmony_ci                        // Regardless of how many optimizations the pixel violates, count it as a
723cb93a386Sopenharmony_ci                        // single bad pixel.
724cb93a386Sopenharmony_ci                        failedPixelCount++;
725cb93a386Sopenharmony_ci                    }
726cb93a386Sopenharmony_ci                }
727cb93a386Sopenharmony_ci            }
728cb93a386Sopenharmony_ci
729cb93a386Sopenharmony_ci            // Finished analyzing the entire image, see if the number of pixel failures meets the
730cb93a386Sopenharmony_ci            // threshold for an FP violating the optimization requirements.
731cb93a386Sopenharmony_ci            if (failedPixelCount > kMaxAcceptableFailedPixels) {
732cb93a386Sopenharmony_ci                ERRORF(reporter,
733cb93a386Sopenharmony_ci                       "Processor violated %d of %d pixels, seed: 0x%08x.\n"
734cb93a386Sopenharmony_ci                       "Processor:\n%s\nFirst failing pixel details are below:",
735cb93a386Sopenharmony_ci                       failedPixelCount, kRenderSize * kRenderSize, fpGenerator.initialSeed(),
736cb93a386Sopenharmony_ci                       fp->dumpTreeInfo().c_str());
737cb93a386Sopenharmony_ci
738cb93a386Sopenharmony_ci                // Print first failing pixel's details.
739cb93a386Sopenharmony_ci                if (!coverageMessage.isEmpty()) {
740cb93a386Sopenharmony_ci                    ERRORF(reporter, coverageMessage.c_str());
741cb93a386Sopenharmony_ci                }
742cb93a386Sopenharmony_ci                if (!constMessage.isEmpty()) {
743cb93a386Sopenharmony_ci                    ERRORF(reporter, constMessage.c_str());
744cb93a386Sopenharmony_ci                }
745cb93a386Sopenharmony_ci                if (!opaqueMessage.isEmpty()) {
746cb93a386Sopenharmony_ci                    ERRORF(reporter, opaqueMessage.c_str());
747cb93a386Sopenharmony_ci                }
748cb93a386Sopenharmony_ci
749cb93a386Sopenharmony_ci                if (!loggedFirstFailure) {
750cb93a386Sopenharmony_ci                    // Print with ERRORF to make sure the encoded image is output
751cb93a386Sopenharmony_ci                    SkString input;
752cb93a386Sopenharmony_ci                    log_texture_view(context, inputTexture1, &input);
753cb93a386Sopenharmony_ci                    SkString output;
754cb93a386Sopenharmony_ci                    log_pixels(readData1.data(), kRenderSize, &output);
755cb93a386Sopenharmony_ci                    ERRORF(reporter, "Input image: %s\n\n"
756cb93a386Sopenharmony_ci                           "===========================================================\n\n"
757cb93a386Sopenharmony_ci                           "Output image: %s\n", input.c_str(), output.c_str());
758cb93a386Sopenharmony_ci                    loggedFirstFailure = true;
759cb93a386Sopenharmony_ci                }
760cb93a386Sopenharmony_ci            } else if (failedPixelCount > 0) {
761cb93a386Sopenharmony_ci                // Don't trigger an error, but don't just hide the failures either.
762cb93a386Sopenharmony_ci                INFOF(reporter, "Processor violated %d of %d pixels (below error threshold), seed: "
763cb93a386Sopenharmony_ci                      "0x%08x, processor: %s", failedPixelCount, kRenderSize * kRenderSize,
764cb93a386Sopenharmony_ci                      fpGenerator.initialSeed(), fp->dumpInfo().c_str());
765cb93a386Sopenharmony_ci                if (!coverageMessage.isEmpty()) {
766cb93a386Sopenharmony_ci                    INFOF(reporter, "%s", coverageMessage.c_str());
767cb93a386Sopenharmony_ci                }
768cb93a386Sopenharmony_ci                if (!constMessage.isEmpty()) {
769cb93a386Sopenharmony_ci                    INFOF(reporter, "%s", constMessage.c_str());
770cb93a386Sopenharmony_ci                }
771cb93a386Sopenharmony_ci                if (!opaqueMessage.isEmpty()) {
772cb93a386Sopenharmony_ci                    INFOF(reporter, "%s", opaqueMessage.c_str());
773cb93a386Sopenharmony_ci                }
774cb93a386Sopenharmony_ci                if (!loggedFirstWarning) {
775cb93a386Sopenharmony_ci                    SkString input;
776cb93a386Sopenharmony_ci                    log_texture_view(context, inputTexture1, &input);
777cb93a386Sopenharmony_ci                    SkString output;
778cb93a386Sopenharmony_ci                    log_pixels(readData1.data(), kRenderSize, &output);
779cb93a386Sopenharmony_ci                    INFOF(reporter, "Input image: %s\n\n"
780cb93a386Sopenharmony_ci                          "===========================================================\n\n"
781cb93a386Sopenharmony_ci                          "Output image: %s\n", input.c_str(), output.c_str());
782cb93a386Sopenharmony_ci                    loggedFirstWarning = true;
783cb93a386Sopenharmony_ci                }
784cb93a386Sopenharmony_ci            }
785cb93a386Sopenharmony_ci        }
786cb93a386Sopenharmony_ci    }
787cb93a386Sopenharmony_ci}
788cb93a386Sopenharmony_ci
789cb93a386Sopenharmony_cistatic void assert_processor_equality(skiatest::Reporter* reporter,
790cb93a386Sopenharmony_ci                                      const GrFragmentProcessor& fp,
791cb93a386Sopenharmony_ci                                      const GrFragmentProcessor& clone) {
792cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, !strcmp(fp.name(), clone.name()),
793cb93a386Sopenharmony_ci                              "\n%s", fp.dumpTreeInfo().c_str());
794cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fp.compatibleWithCoverageAsAlpha() ==
795cb93a386Sopenharmony_ci                              clone.compatibleWithCoverageAsAlpha(),
796cb93a386Sopenharmony_ci                              "\n%s", fp.dumpTreeInfo().c_str());
797cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fp.isEqual(clone),
798cb93a386Sopenharmony_ci                              "\n%s", fp.dumpTreeInfo().c_str());
799cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fp.preservesOpaqueInput() == clone.preservesOpaqueInput(),
800cb93a386Sopenharmony_ci                              "\n%s", fp.dumpTreeInfo().c_str());
801cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fp.hasConstantOutputForConstantInput() ==
802cb93a386Sopenharmony_ci                              clone.hasConstantOutputForConstantInput(),
803cb93a386Sopenharmony_ci                              "\n%s", fp.dumpTreeInfo().c_str());
804cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fp.numChildProcessors() == clone.numChildProcessors(),
805cb93a386Sopenharmony_ci                              "\n%s", fp.dumpTreeInfo().c_str());
806cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fp.sampleUsage() == clone.sampleUsage(),
807cb93a386Sopenharmony_ci                              "\n%s", fp.dumpTreeInfo().c_str());
808cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, fp.usesSampleCoords() == clone.usesSampleCoords(),
809cb93a386Sopenharmony_ci                              "\n%s", fp.dumpTreeInfo().c_str());
810cb93a386Sopenharmony_ci}
811cb93a386Sopenharmony_ci
812cb93a386Sopenharmony_cistatic bool verify_identical_render(skiatest::Reporter* reporter, int renderSize,
813cb93a386Sopenharmony_ci                                    const char* processorType,
814cb93a386Sopenharmony_ci                                    const GrColor readData1[], const GrColor readData2[]) {
815cb93a386Sopenharmony_ci    // The ProcessorClone test has a history of being flaky on a number of devices. If an FP clone
816cb93a386Sopenharmony_ci    // is logically wrong, it's reasonable to expect it produce a large number of pixel differences
817cb93a386Sopenharmony_ci    // in the image. Sporadic pixel violations are more indicative device errors and represents a
818cb93a386Sopenharmony_ci    // separate problem.
819cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_SKQP)
820cb93a386Sopenharmony_ci    const int maxAcceptableFailedPixels = 0;  // Strict when running as SKQP
821cb93a386Sopenharmony_ci#else
822cb93a386Sopenharmony_ci    const int maxAcceptableFailedPixels = 2 * renderSize;  // ~0.002% of the pixels (size 1024*1024)
823cb93a386Sopenharmony_ci#endif
824cb93a386Sopenharmony_ci
825cb93a386Sopenharmony_ci    int failedPixelCount = 0;
826cb93a386Sopenharmony_ci    int firstWrongX = 0;
827cb93a386Sopenharmony_ci    int firstWrongY = 0;
828cb93a386Sopenharmony_ci    int idx = 0;
829cb93a386Sopenharmony_ci    for (int y = 0; y < renderSize; ++y) {
830cb93a386Sopenharmony_ci        for (int x = 0; x < renderSize; ++x, ++idx) {
831cb93a386Sopenharmony_ci            if (readData1[idx] != readData2[idx]) {
832cb93a386Sopenharmony_ci                if (!failedPixelCount) {
833cb93a386Sopenharmony_ci                    firstWrongX = x;
834cb93a386Sopenharmony_ci                    firstWrongY = y;
835cb93a386Sopenharmony_ci                }
836cb93a386Sopenharmony_ci                ++failedPixelCount;
837cb93a386Sopenharmony_ci            }
838cb93a386Sopenharmony_ci            if (failedPixelCount > maxAcceptableFailedPixels) {
839cb93a386Sopenharmony_ci                idx = firstWrongY * renderSize + firstWrongX;
840cb93a386Sopenharmony_ci                ERRORF(reporter,
841cb93a386Sopenharmony_ci                       "%s produced different output at (%d, %d). "
842cb93a386Sopenharmony_ci                       "Input color: 0x%08x, Original Output Color: 0x%08x, "
843cb93a386Sopenharmony_ci                       "Clone Output Color: 0x%08x.",
844cb93a386Sopenharmony_ci                       processorType, firstWrongX, firstWrongY, input_texel_color(x, y, 0.0f),
845cb93a386Sopenharmony_ci                       readData1[idx], readData2[idx]);
846cb93a386Sopenharmony_ci
847cb93a386Sopenharmony_ci                return false;
848cb93a386Sopenharmony_ci            }
849cb93a386Sopenharmony_ci        }
850cb93a386Sopenharmony_ci    }
851cb93a386Sopenharmony_ci
852cb93a386Sopenharmony_ci    return true;
853cb93a386Sopenharmony_ci}
854cb93a386Sopenharmony_ci
855cb93a386Sopenharmony_cistatic void log_clone_failure(skiatest::Reporter* reporter, int renderSize,
856cb93a386Sopenharmony_ci                              GrDirectContext* context, const GrSurfaceProxyView& inputTexture,
857cb93a386Sopenharmony_ci                              GrColor pixelsFP[], GrColor pixelsClone[], GrColor pixelsRegen[]) {
858cb93a386Sopenharmony_ci    // Write the images out as data URLs for inspection.
859cb93a386Sopenharmony_ci    SkString inputURL, origURL, cloneURL, regenURL;
860cb93a386Sopenharmony_ci    if (log_texture_view(context, inputTexture, &inputURL) &&
861cb93a386Sopenharmony_ci        log_pixels(pixelsFP, renderSize, &origURL) &&
862cb93a386Sopenharmony_ci        log_pixels(pixelsClone, renderSize, &cloneURL) &&
863cb93a386Sopenharmony_ci        log_pixels(pixelsRegen, renderSize, &regenURL)) {
864cb93a386Sopenharmony_ci        ERRORF(reporter,
865cb93a386Sopenharmony_ci               "\nInput image:\n%s\n\n"
866cb93a386Sopenharmony_ci               "==========================================================="
867cb93a386Sopenharmony_ci               "\n\n"
868cb93a386Sopenharmony_ci               "Orig output image:\n%s\n"
869cb93a386Sopenharmony_ci               "==========================================================="
870cb93a386Sopenharmony_ci               "\n\n"
871cb93a386Sopenharmony_ci               "Clone output image:\n%s\n"
872cb93a386Sopenharmony_ci               "==========================================================="
873cb93a386Sopenharmony_ci               "\n\n"
874cb93a386Sopenharmony_ci               "Regen output image:\n%s\n",
875cb93a386Sopenharmony_ci               inputURL.c_str(), origURL.c_str(), cloneURL.c_str(), regenURL.c_str());
876cb93a386Sopenharmony_ci    }
877cb93a386Sopenharmony_ci}
878cb93a386Sopenharmony_ci
879cb93a386Sopenharmony_ci// Tests that a fragment processor returned by GrFragmentProcessor::clone() is equivalent to its
880cb93a386Sopenharmony_ci// progenitor.
881cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorCloneTest, reporter, ctxInfo) {
882cb93a386Sopenharmony_ci    GrDirectContext* context = ctxInfo.directContext();
883cb93a386Sopenharmony_ci    GrResourceProvider* resourceProvider = context->priv().resourceProvider();
884cb93a386Sopenharmony_ci
885cb93a386Sopenharmony_ci    TestFPGenerator fpGenerator{context, resourceProvider};
886cb93a386Sopenharmony_ci    if (!fpGenerator.init()) {
887cb93a386Sopenharmony_ci        ERRORF(reporter, "Could not initialize TestFPGenerator");
888cb93a386Sopenharmony_ci        return;
889cb93a386Sopenharmony_ci    }
890cb93a386Sopenharmony_ci
891cb93a386Sopenharmony_ci    // Make the destination context for the test.
892cb93a386Sopenharmony_ci    static constexpr int kRenderSize = 1024;
893cb93a386Sopenharmony_ci    auto sdc = skgpu::v1::SurfaceDrawContext::Make(
894cb93a386Sopenharmony_ci            context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kExact,
895cb93a386Sopenharmony_ci            {kRenderSize, kRenderSize}, SkSurfaceProps());
896cb93a386Sopenharmony_ci
897cb93a386Sopenharmony_ci    std::vector<GrColor> inputPixels = make_input_pixels(kRenderSize, kRenderSize, 0.0f);
898cb93a386Sopenharmony_ci    GrSurfaceProxyView inputTexture =
899cb93a386Sopenharmony_ci            make_input_texture(context, kRenderSize, kRenderSize, inputPixels.data());
900cb93a386Sopenharmony_ci
901cb93a386Sopenharmony_ci    // On failure we write out images, but just write the first failing set as the print is very
902cb93a386Sopenharmony_ci    // large.
903cb93a386Sopenharmony_ci    bool loggedFirstFailure = false;
904cb93a386Sopenharmony_ci
905cb93a386Sopenharmony_ci    // Storage for the original frame's readback and the readback of its clone.
906cb93a386Sopenharmony_ci    std::vector<GrColor> readDataFP(kRenderSize * kRenderSize);
907cb93a386Sopenharmony_ci    std::vector<GrColor> readDataClone(kRenderSize * kRenderSize);
908cb93a386Sopenharmony_ci    std::vector<GrColor> readDataRegen(kRenderSize * kRenderSize);
909cb93a386Sopenharmony_ci
910cb93a386Sopenharmony_ci    // Because processor factories configure themselves in random ways, this is not exhaustive.
911cb93a386Sopenharmony_ci    for (int i = 0; i < GrFragmentProcessorTestFactory::Count(); ++i) {
912cb93a386Sopenharmony_ci        static constexpr int kTimesToInvokeFactory = 10;
913cb93a386Sopenharmony_ci        for (int j = 0; j < kTimesToInvokeFactory; ++j) {
914cb93a386Sopenharmony_ci            fpGenerator.reroll();
915cb93a386Sopenharmony_ci            std::unique_ptr<GrFragmentProcessor> fp =
916cb93a386Sopenharmony_ci                    fpGenerator.make(i, /*randomTreeDepth=*/1, /*inputFP=*/nullptr);
917cb93a386Sopenharmony_ci            std::unique_ptr<GrFragmentProcessor> regen =
918cb93a386Sopenharmony_ci                    fpGenerator.make(i, /*randomTreeDepth=*/1, /*inputFP=*/nullptr);
919cb93a386Sopenharmony_ci            std::unique_ptr<GrFragmentProcessor> clone = fp->clone();
920cb93a386Sopenharmony_ci            if (!clone) {
921cb93a386Sopenharmony_ci                ERRORF(reporter, "Clone of processor %s failed.", fp->dumpTreeInfo().c_str());
922cb93a386Sopenharmony_ci                continue;
923cb93a386Sopenharmony_ci            }
924cb93a386Sopenharmony_ci            assert_processor_equality(reporter, *fp, *clone);
925cb93a386Sopenharmony_ci
926cb93a386Sopenharmony_ci            // Draw with original and read back the results.
927cb93a386Sopenharmony_ci            render_fp(context, sdc.get(), std::move(fp), readDataFP.data());
928cb93a386Sopenharmony_ci
929cb93a386Sopenharmony_ci            // Draw with clone and read back the results.
930cb93a386Sopenharmony_ci            render_fp(context, sdc.get(), std::move(clone), readDataClone.data());
931cb93a386Sopenharmony_ci
932cb93a386Sopenharmony_ci            // Check that the results are the same.
933cb93a386Sopenharmony_ci            if (!verify_identical_render(reporter, kRenderSize, "Processor clone",
934cb93a386Sopenharmony_ci                                         readDataFP.data(), readDataClone.data())) {
935cb93a386Sopenharmony_ci                // Dump a description from the regenerated processor (since the original FP has
936cb93a386Sopenharmony_ci                // already been consumed).
937cb93a386Sopenharmony_ci                ERRORF(reporter, "FP hierarchy:\n%s", regen->dumpTreeInfo().c_str());
938cb93a386Sopenharmony_ci
939cb93a386Sopenharmony_ci                // Render and readback output from the regenerated FP. If this also mismatches, the
940cb93a386Sopenharmony_ci                // FP itself doesn't generate consistent output. This could happen if:
941cb93a386Sopenharmony_ci                // - the FP's TestCreate() does not always generate the same FP from a given seed
942cb93a386Sopenharmony_ci                // - the FP's Make() does not always generate the same FP when given the same inputs
943cb93a386Sopenharmony_ci                // - the FP itself generates inconsistent pixels (shader UB?)
944cb93a386Sopenharmony_ci                // - the driver has a bug
945cb93a386Sopenharmony_ci                render_fp(context, sdc.get(), std::move(regen), readDataRegen.data());
946cb93a386Sopenharmony_ci
947cb93a386Sopenharmony_ci                if (!verify_identical_render(reporter, kRenderSize, "Regenerated processor",
948cb93a386Sopenharmony_ci                                             readDataFP.data(), readDataRegen.data())) {
949cb93a386Sopenharmony_ci                    ERRORF(reporter, "Output from regen did not match original!\n");
950cb93a386Sopenharmony_ci                } else {
951cb93a386Sopenharmony_ci                    ERRORF(reporter, "Regenerated processor output matches original results.\n");
952cb93a386Sopenharmony_ci                }
953cb93a386Sopenharmony_ci
954cb93a386Sopenharmony_ci                // If this is the first time we've encountered a cloning failure, log the generated
955cb93a386Sopenharmony_ci                // images to the reporter as data URLs.
956cb93a386Sopenharmony_ci                if (!loggedFirstFailure) {
957cb93a386Sopenharmony_ci                    log_clone_failure(reporter, kRenderSize, context, inputTexture,
958cb93a386Sopenharmony_ci                                      readDataFP.data(), readDataClone.data(),
959cb93a386Sopenharmony_ci                                      readDataRegen.data());
960cb93a386Sopenharmony_ci                    loggedFirstFailure = true;
961cb93a386Sopenharmony_ci                }
962cb93a386Sopenharmony_ci            }
963cb93a386Sopenharmony_ci        }
964cb93a386Sopenharmony_ci    }
965cb93a386Sopenharmony_ci}
966cb93a386Sopenharmony_ci
967cb93a386Sopenharmony_ci#endif  // GR_TEST_UTILS
968