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