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