1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2019 Google LLC.
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 "gm/gm.h"
9cb93a386Sopenharmony_ci#include "include/core/SkFont.h"
10cb93a386Sopenharmony_ci#include "include/effects/SkRuntimeEffect.h"
11cb93a386Sopenharmony_ci#include "src/core/SkCanvasPriv.h"
12cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrPaint.h"
14cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h"
15cb93a386Sopenharmony_ci#include "src/gpu/effects/GrMatrixEffect.h"
16cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h"
17cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
18cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h"
19cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_cinamespace {
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ci// Samples child with a uniform matrix (functionally identical to GrMatrixEffect)
24cb93a386Sopenharmony_ci// Scales along Y
25cb93a386Sopenharmony_ciclass UniformMatrixEffect : public GrFragmentProcessor {
26cb93a386Sopenharmony_cipublic:
27cb93a386Sopenharmony_ci    inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 4;
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci    UniformMatrixEffect(std::unique_ptr<GrFragmentProcessor> child)
30cb93a386Sopenharmony_ci            : GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) {
31cb93a386Sopenharmony_ci        this->registerChild(std::move(child),
32cb93a386Sopenharmony_ci                            SkSL::SampleUsage::UniformMatrix(/*hasPerspective=*/false));
33cb93a386Sopenharmony_ci    }
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci    const char* name() const override { return "UniformMatrixEffect"; }
36cb93a386Sopenharmony_ci    void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
37cb93a386Sopenharmony_ci    bool onIsEqual(const GrFragmentProcessor& that) const override { return this == &that; }
38cb93a386Sopenharmony_ci    std::unique_ptr<GrFragmentProcessor> clone() const override { return nullptr; }
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci    std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
41cb93a386Sopenharmony_ci        class Impl : public ProgramImpl {
42cb93a386Sopenharmony_ci        public:
43cb93a386Sopenharmony_ci            void emitCode(EmitArgs& args) override {
44cb93a386Sopenharmony_ci                fMatrixVar =
45cb93a386Sopenharmony_ci                        args.fUniformHandler->addUniform(&args.fFp,
46cb93a386Sopenharmony_ci                                                         kFragment_GrShaderFlag,
47cb93a386Sopenharmony_ci                                                         kFloat3x3_GrSLType,
48cb93a386Sopenharmony_ci                                                         SkSL::SampleUsage::MatrixUniformName());
49cb93a386Sopenharmony_ci                SkString sample = this->invokeChildWithMatrix(0, args);
50cb93a386Sopenharmony_ci                args.fFragBuilder->codeAppendf("return %s;\n", sample.c_str());
51cb93a386Sopenharmony_ci            }
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ci        private:
54cb93a386Sopenharmony_ci            void onSetData(const GrGLSLProgramDataManager& pdman,
55cb93a386Sopenharmony_ci                           const GrFragmentProcessor& proc) override {
56cb93a386Sopenharmony_ci                pdman.setSkMatrix(fMatrixVar, SkMatrix::Scale(1, 0.5f));
57cb93a386Sopenharmony_ci            }
58cb93a386Sopenharmony_ci            UniformHandle fMatrixVar;
59cb93a386Sopenharmony_ci        };
60cb93a386Sopenharmony_ci        return std::make_unique<Impl>();
61cb93a386Sopenharmony_ci    }
62cb93a386Sopenharmony_ci};
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ci// Samples child with explicit coords
65cb93a386Sopenharmony_ci// Translates along Y
66cb93a386Sopenharmony_ciclass ExplicitCoordEffect : public GrFragmentProcessor {
67cb93a386Sopenharmony_cipublic:
68cb93a386Sopenharmony_ci    inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 6;
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci    ExplicitCoordEffect(std::unique_ptr<GrFragmentProcessor> child)
71cb93a386Sopenharmony_ci            : GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) {
72cb93a386Sopenharmony_ci        this->registerChild(std::move(child), SkSL::SampleUsage::Explicit());
73cb93a386Sopenharmony_ci        this->setUsesSampleCoordsDirectly();
74cb93a386Sopenharmony_ci    }
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci    const char* name() const override { return "ExplicitCoordEffect"; }
77cb93a386Sopenharmony_ci    void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
78cb93a386Sopenharmony_ci    bool onIsEqual(const GrFragmentProcessor& that) const override { return this == &that; }
79cb93a386Sopenharmony_ci    std::unique_ptr<GrFragmentProcessor> clone() const override { return nullptr; }
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ci    std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
82cb93a386Sopenharmony_ci        class Impl : public ProgramImpl {
83cb93a386Sopenharmony_ci        public:
84cb93a386Sopenharmony_ci            void emitCode(EmitArgs& args) override {
85cb93a386Sopenharmony_ci                args.fFragBuilder->codeAppendf("float2 coord = %s + float2(0, 8);",
86cb93a386Sopenharmony_ci                                               args.fSampleCoord);
87cb93a386Sopenharmony_ci                SkString sample = this->invokeChild(0, args, "coord");
88cb93a386Sopenharmony_ci                args.fFragBuilder->codeAppendf("return %s;\n", sample.c_str());
89cb93a386Sopenharmony_ci            }
90cb93a386Sopenharmony_ci        };
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ci        return std::make_unique<Impl>();
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci};
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci// Generates test pattern
97cb93a386Sopenharmony_ciclass TestPatternEffect : public GrFragmentProcessor {
98cb93a386Sopenharmony_cipublic:
99cb93a386Sopenharmony_ci    inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 7;
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci    TestPatternEffect() : GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) {
102cb93a386Sopenharmony_ci        this->setUsesSampleCoordsDirectly();
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci    const char* name() const override { return "TestPatternEffect"; }
106cb93a386Sopenharmony_ci    void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
107cb93a386Sopenharmony_ci    bool onIsEqual(const GrFragmentProcessor& that) const override { return this == &that; }
108cb93a386Sopenharmony_ci    std::unique_ptr<GrFragmentProcessor> clone() const override { return nullptr; }
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci    std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
111cb93a386Sopenharmony_ci        class Impl : public ProgramImpl {
112cb93a386Sopenharmony_ci        public:
113cb93a386Sopenharmony_ci            void emitCode(EmitArgs& args) override {
114cb93a386Sopenharmony_ci                auto fb = args.fFragBuilder;
115cb93a386Sopenharmony_ci                fb->codeAppendf("float2 coord = %s / 64.0;", args.fSampleCoord);
116cb93a386Sopenharmony_ci                fb->codeAppendf("coord = floor(coord * 4) / 3;");
117cb93a386Sopenharmony_ci                fb->codeAppendf("return half2(coord).rg01;\n");
118cb93a386Sopenharmony_ci            }
119cb93a386Sopenharmony_ci        };
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci        return std::make_unique<Impl>();
122cb93a386Sopenharmony_ci    }
123cb93a386Sopenharmony_ci};
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ciSkBitmap make_test_bitmap() {
126cb93a386Sopenharmony_ci    SkBitmap bitmap;
127cb93a386Sopenharmony_ci    bitmap.allocN32Pixels(64, 64);
128cb93a386Sopenharmony_ci    SkCanvas canvas(bitmap);
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci    SkFont font(ToolUtils::create_portable_typeface());
131cb93a386Sopenharmony_ci    const char* alpha = "ABCDEFGHIJKLMNOP";
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ci    for (int i = 0; i < 16; ++i) {
134cb93a386Sopenharmony_ci        int tx = i % 4,
135cb93a386Sopenharmony_ci            ty = i / 4;
136cb93a386Sopenharmony_ci        int x = tx * 16,
137cb93a386Sopenharmony_ci            y = ty * 16;
138cb93a386Sopenharmony_ci        SkPaint paint;
139cb93a386Sopenharmony_ci        paint.setColor4f({ tx / 3.0f, ty / 3.0f, 0.0f, 1.0f });
140cb93a386Sopenharmony_ci        canvas.drawRect(SkRect::MakeXYWH(x, y, 16, 16), paint);
141cb93a386Sopenharmony_ci        paint.setColor4f({ (3-tx) / 3.0f, (3-ty)/3.0f, 1.0f, 1.0f });
142cb93a386Sopenharmony_ci        canvas.drawSimpleText(alpha + i, 1, SkTextEncoding::kUTF8, x + 3, y + 13, font, paint);
143cb93a386Sopenharmony_ci    }
144cb93a386Sopenharmony_ci
145cb93a386Sopenharmony_ci    return bitmap;
146cb93a386Sopenharmony_ci}
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_cienum EffectType {
149cb93a386Sopenharmony_ci    kUniform,
150cb93a386Sopenharmony_ci    kExplicit,
151cb93a386Sopenharmony_ci    kDevice,
152cb93a386Sopenharmony_ci};
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_cistatic std::unique_ptr<GrFragmentProcessor> wrap(std::unique_ptr<GrFragmentProcessor> fp,
155cb93a386Sopenharmony_ci                                                 EffectType effectType,
156cb93a386Sopenharmony_ci                                                 int drawX, int drawY) {
157cb93a386Sopenharmony_ci    switch (effectType) {
158cb93a386Sopenharmony_ci        case kUniform:
159cb93a386Sopenharmony_ci            return std::make_unique<UniformMatrixEffect>(std::move(fp));
160cb93a386Sopenharmony_ci        case kExplicit:
161cb93a386Sopenharmony_ci            return std::make_unique<ExplicitCoordEffect>(std::move(fp));
162cb93a386Sopenharmony_ci        case kDevice:
163cb93a386Sopenharmony_ci            // Subtract out upper-left corner of draw so that device is effectively identity.
164cb93a386Sopenharmony_ci            fp = GrMatrixEffect::Make(SkMatrix::Translate(-drawX, -drawY), std::move(fp));
165cb93a386Sopenharmony_ci            return GrFragmentProcessor::DeviceSpace(std::move(fp));
166cb93a386Sopenharmony_ci    }
167cb93a386Sopenharmony_ci    SkUNREACHABLE;
168cb93a386Sopenharmony_ci}
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci} // namespace
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_cinamespace skiagm {
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(fp_sample_chaining, rContext, canvas, errorMsg, 232, 306) {
175cb93a386Sopenharmony_ci    auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
176cb93a386Sopenharmony_ci    if (!sdc) {
177cb93a386Sopenharmony_ci        *errorMsg = GM::kErrorMsg_DrawSkippedGpuOnly;
178cb93a386Sopenharmony_ci        return DrawResult::kSkip;
179cb93a386Sopenharmony_ci    }
180cb93a386Sopenharmony_ci
181cb93a386Sopenharmony_ci    SkBitmap bmp = make_test_bitmap();
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_ci    int x = 10, y = 10;
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci    auto nextCol = [&] { x += (64 + 10); };
186cb93a386Sopenharmony_ci    auto nextRow = [&] { x = 10; y += (64 + 10); };
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci    auto draw = [&](std::initializer_list<EffectType> effects) {
189cb93a386Sopenharmony_ci        // Enable TestPatternEffect to get a fully procedural inner effect. It's not quite as nice
190cb93a386Sopenharmony_ci        // visually (no text labels in each box), but it avoids the extra GrMatrixEffect.
191cb93a386Sopenharmony_ci        // Switching it on actually triggers *more* shader compilation failures.
192cb93a386Sopenharmony_ci#if 0
193cb93a386Sopenharmony_ci        auto fp = std::unique_ptr<GrFragmentProcessor>(new TestPatternEffect());
194cb93a386Sopenharmony_ci#else
195cb93a386Sopenharmony_ci        auto view = std::get<0>(GrMakeCachedBitmapProxyView(rContext, bmp, GrMipmapped::kNo));
196cb93a386Sopenharmony_ci        auto fp = GrTextureEffect::Make(std::move(view), bmp.alphaType());
197cb93a386Sopenharmony_ci#endif
198cb93a386Sopenharmony_ci        for (EffectType effectType : effects) {
199cb93a386Sopenharmony_ci            fp = wrap(std::move(fp), effectType, x, y);
200cb93a386Sopenharmony_ci        }
201cb93a386Sopenharmony_ci        GrPaint paint;
202cb93a386Sopenharmony_ci        paint.setColorFragmentProcessor(std::move(fp));
203cb93a386Sopenharmony_ci        sdc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::Translate(x, y),
204cb93a386Sopenharmony_ci                      SkRect::MakeIWH(64, 64));
205cb93a386Sopenharmony_ci        nextCol();
206cb93a386Sopenharmony_ci    };
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci    // Reminder, in every case, the chain is more complicated than it seems, because the
209cb93a386Sopenharmony_ci    // GrTextureEffect is wrapped in a GrMatrixEffect, which is subject to the same bugs that
210cb93a386Sopenharmony_ci    // we're testing (particularly the bug about owner/base in UniformMatrixEffect).
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci    // First row: no transform, then each one independently applied
213cb93a386Sopenharmony_ci    draw({});             // Identity (4 rows and columns)
214cb93a386Sopenharmony_ci    draw({ kUniform  });  // Scale Y axis by 2x (2 visible rows)
215cb93a386Sopenharmony_ci    draw({ kExplicit });  // Translate up by 8px
216cb93a386Sopenharmony_ci    nextRow();
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci    // Second row: transform duplicated
219cb93a386Sopenharmony_ci    draw({ kUniform,  kUniform  });  // Scale Y axis by 4x (1 visible row)
220cb93a386Sopenharmony_ci    draw({ kExplicit, kExplicit });  // Translate up by 16px
221cb93a386Sopenharmony_ci    nextRow();
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_ci    // Third row: Remember, these are applied inside out:
224cb93a386Sopenharmony_ci    draw({ kUniform,  kExplicit }); // Scale Y by 2x and translate up by 8px
225cb93a386Sopenharmony_ci    draw({ kExplicit, kUniform });  // Scale Y by 2x and translate up by 16px
226cb93a386Sopenharmony_ci    nextRow();
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci    // Fourth row: device space.
229cb93a386Sopenharmony_ci    draw({ kDevice, kUniform });                     // Same as identity (uniform applied *before*
230cb93a386Sopenharmony_ci                                                     // device so ignored).
231cb93a386Sopenharmony_ci    draw({ kExplicit, kUniform, kDevice });          // Scale Y by 2x and translate up by 16px
232cb93a386Sopenharmony_ci    draw({ kDevice, kExplicit, kUniform, kDevice }); // Identity, again.
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci    return DrawResult::kOk;
235cb93a386Sopenharmony_ci}
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci} // namespace skiagm
238