xref: /aosp_15_r20/external/skia/gm/mesh.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 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/SkBlender.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMesh.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkMeshGanesh.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCanvasPriv.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "tools/DecodeUtils.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "tools/timer/TimeUtils.h"
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker class MeshGM : public skiagm::GM {
34*c8dee2aaSAndroid Build Coastguard Worker public:
MeshGM()35*c8dee2aaSAndroid Build Coastguard Worker     MeshGM() {}
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker protected:
38*c8dee2aaSAndroid Build Coastguard Worker     using Attribute = SkMeshSpecification::Attribute;
39*c8dee2aaSAndroid Build Coastguard Worker     using Varying   = SkMeshSpecification::Varying;
40*c8dee2aaSAndroid Build Coastguard Worker 
getISize()41*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {435, 1180}; }
42*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()43*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
44*c8dee2aaSAndroid Build Coastguard Worker         {
45*c8dee2aaSAndroid Build Coastguard Worker             static const Attribute kAttributes[]{
46*c8dee2aaSAndroid Build Coastguard Worker                     {Attribute::Type::kFloat4,       8, SkString{"xuyv"}},
47*c8dee2aaSAndroid Build Coastguard Worker                     {Attribute::Type::kUByte4_unorm, 4, SkString{"brag"}},
48*c8dee2aaSAndroid Build Coastguard Worker             };
49*c8dee2aaSAndroid Build Coastguard Worker             static const Varying kVaryings[]{
50*c8dee2aaSAndroid Build Coastguard Worker                     {Varying::Type::kHalf4,  SkString{"color"}},
51*c8dee2aaSAndroid Build Coastguard Worker                     {Varying::Type::kFloat2, SkString{"uv"}   },
52*c8dee2aaSAndroid Build Coastguard Worker             };
53*c8dee2aaSAndroid Build Coastguard Worker             static constexpr char kVS[] = R"(
54*c8dee2aaSAndroid Build Coastguard Worker                     half4 unswizzle_color(half4 color) { return color.garb; }
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker                     Varyings main(const in Attributes attributes) {
57*c8dee2aaSAndroid Build Coastguard Worker                         Varyings varyings;
58*c8dee2aaSAndroid Build Coastguard Worker                         varyings.color    = unswizzle_color(attributes.brag);
59*c8dee2aaSAndroid Build Coastguard Worker                         varyings.uv       = attributes.xuyv.yw;
60*c8dee2aaSAndroid Build Coastguard Worker                         varyings.position = attributes.xuyv.xz;
61*c8dee2aaSAndroid Build Coastguard Worker                         return varyings;
62*c8dee2aaSAndroid Build Coastguard Worker                     }
63*c8dee2aaSAndroid Build Coastguard Worker             )";
64*c8dee2aaSAndroid Build Coastguard Worker             static constexpr char kFS[] = R"(
65*c8dee2aaSAndroid Build Coastguard Worker                     uniform colorFilter filter;
66*c8dee2aaSAndroid Build Coastguard Worker 
67*c8dee2aaSAndroid Build Coastguard Worker                     float2 main(const in Varyings varyings, out float4 color) {
68*c8dee2aaSAndroid Build Coastguard Worker                         color = filter.eval(varyings.color);
69*c8dee2aaSAndroid Build Coastguard Worker                         return varyings.uv;
70*c8dee2aaSAndroid Build Coastguard Worker                     }
71*c8dee2aaSAndroid Build Coastguard Worker             )";
72*c8dee2aaSAndroid Build Coastguard Worker             auto [spec, error] = SkMeshSpecification::Make(kAttributes,
73*c8dee2aaSAndroid Build Coastguard Worker                                                            sizeof(ColorVertex),
74*c8dee2aaSAndroid Build Coastguard Worker                                                            kVaryings,
75*c8dee2aaSAndroid Build Coastguard Worker                                                            SkString(kVS),
76*c8dee2aaSAndroid Build Coastguard Worker                                                            SkString(kFS));
77*c8dee2aaSAndroid Build Coastguard Worker             if (!spec) {
78*c8dee2aaSAndroid Build Coastguard Worker                 SkDebugf("%s\n", error.c_str());
79*c8dee2aaSAndroid Build Coastguard Worker             }
80*c8dee2aaSAndroid Build Coastguard Worker             fSpecWithColor = std::move(spec);
81*c8dee2aaSAndroid Build Coastguard Worker         }
82*c8dee2aaSAndroid Build Coastguard Worker         {
83*c8dee2aaSAndroid Build Coastguard Worker             static const Attribute kAttributes[]{
84*c8dee2aaSAndroid Build Coastguard Worker                     {Attribute::Type::kFloat4, 0, SkString{"xuyv"}},
85*c8dee2aaSAndroid Build Coastguard Worker             };
86*c8dee2aaSAndroid Build Coastguard Worker             static const Varying kVaryings[]{
87*c8dee2aaSAndroid Build Coastguard Worker                     {Varying::Type::kFloat2, SkString{"vux2"}},
88*c8dee2aaSAndroid Build Coastguard Worker             };
89*c8dee2aaSAndroid Build Coastguard Worker             static constexpr char kVS[] = R"(
90*c8dee2aaSAndroid Build Coastguard Worker                     Varyings main(const in Attributes a) {
91*c8dee2aaSAndroid Build Coastguard Worker                         Varyings v;
92*c8dee2aaSAndroid Build Coastguard Worker                         v.vux2     = 2*a.xuyv.wy;
93*c8dee2aaSAndroid Build Coastguard Worker                         v.position = a.xuyv.xz;
94*c8dee2aaSAndroid Build Coastguard Worker                         return v;
95*c8dee2aaSAndroid Build Coastguard Worker                     }
96*c8dee2aaSAndroid Build Coastguard Worker             )";
97*c8dee2aaSAndroid Build Coastguard Worker             static constexpr char kFS[] = R"(
98*c8dee2aaSAndroid Build Coastguard Worker                     float2 helper(in float2 vux2) { return vux2.yx/2; }
99*c8dee2aaSAndroid Build Coastguard Worker                     float2 main(const in Varyings varyings) {
100*c8dee2aaSAndroid Build Coastguard Worker                         return helper(varyings.vux2);
101*c8dee2aaSAndroid Build Coastguard Worker                     }
102*c8dee2aaSAndroid Build Coastguard Worker             )";
103*c8dee2aaSAndroid Build Coastguard Worker             auto [spec, error] = SkMeshSpecification::Make(kAttributes,
104*c8dee2aaSAndroid Build Coastguard Worker                                                            sizeof(NoColorVertex),
105*c8dee2aaSAndroid Build Coastguard Worker                                                            kVaryings,
106*c8dee2aaSAndroid Build Coastguard Worker                                                            SkString(kVS),
107*c8dee2aaSAndroid Build Coastguard Worker                                                            SkString(kFS));
108*c8dee2aaSAndroid Build Coastguard Worker             if (!spec) {
109*c8dee2aaSAndroid Build Coastguard Worker                 SkDebugf("%s\n", error.c_str());
110*c8dee2aaSAndroid Build Coastguard Worker             }
111*c8dee2aaSAndroid Build Coastguard Worker             fSpecWithNoColor = std::move(spec);
112*c8dee2aaSAndroid Build Coastguard Worker         }
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkColor kColors[] = {SK_ColorTRANSPARENT, SK_ColorWHITE};
115*c8dee2aaSAndroid Build Coastguard Worker         fShader = SkGradientShader::MakeRadial({10, 10},
116*c8dee2aaSAndroid Build Coastguard Worker                                                3,
117*c8dee2aaSAndroid Build Coastguard Worker                                                kColors,
118*c8dee2aaSAndroid Build Coastguard Worker                                                nullptr,
119*c8dee2aaSAndroid Build Coastguard Worker                                                2,
120*c8dee2aaSAndroid Build Coastguard Worker                                                SkTileMode::kMirror);
121*c8dee2aaSAndroid Build Coastguard Worker     }
122*c8dee2aaSAndroid Build Coastguard Worker 
onGpuSetup(SkCanvas * canvas,SkString * string,GraphiteTestContext *)123*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onGpuSetup(SkCanvas* canvas, SkString* string, GraphiteTestContext*) override {
124*c8dee2aaSAndroid Build Coastguard Worker         auto dc = GrAsDirectContext(canvas->recordingContext());
125*c8dee2aaSAndroid Build Coastguard Worker         this->ensureBuffers();
126*c8dee2aaSAndroid Build Coastguard Worker         if (!dc || dc->abandoned()) {
127*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kOk;
128*c8dee2aaSAndroid Build Coastguard Worker         }
129*c8dee2aaSAndroid Build Coastguard Worker 
130*c8dee2aaSAndroid Build Coastguard Worker         fColorVB        = SkMeshes::CopyVertexBuffer(dc, fColorVB);
131*c8dee2aaSAndroid Build Coastguard Worker         fColorIndexedVB = SkMeshes::CopyVertexBuffer(dc, fColorIndexedVB);
132*c8dee2aaSAndroid Build Coastguard Worker         fIB[1]          = SkMeshes::CopyIndexBuffer (dc, fIB[0]);
133*c8dee2aaSAndroid Build Coastguard Worker         if (!fColorVB || !fColorIndexedVB || !fIB[1]) {
134*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kFail;
135*c8dee2aaSAndroid Build Coastguard Worker         }
136*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker 
onGpuTeardown()139*c8dee2aaSAndroid Build Coastguard Worker     void onGpuTeardown() override {
140*c8dee2aaSAndroid Build Coastguard Worker         // Destroy the GPU buffers and recreate on CPU
141*c8dee2aaSAndroid Build Coastguard Worker         fColorVB        = nullptr;
142*c8dee2aaSAndroid Build Coastguard Worker         fColorIndexedVB = nullptr;
143*c8dee2aaSAndroid Build Coastguard Worker         fIB[1]          = nullptr;
144*c8dee2aaSAndroid Build Coastguard Worker         this->ensureBuffers();
145*c8dee2aaSAndroid Build Coastguard Worker     }
146*c8dee2aaSAndroid Build Coastguard Worker 
getName() const147*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("custommesh"); }
148*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString *)149*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString*) override {
150*c8dee2aaSAndroid Build Coastguard Worker         SkRuntimeEffect::ChildPtr nullChild[1] = {};
151*c8dee2aaSAndroid Build Coastguard Worker         int i = 0;
152*c8dee2aaSAndroid Build Coastguard Worker         for (const sk_sp<SkBlender>& blender : {SkBlender::Mode(SkBlendMode::kDst),
153*c8dee2aaSAndroid Build Coastguard Worker                                                 SkBlender::Mode(SkBlendMode::kSrc),
154*c8dee2aaSAndroid Build Coastguard Worker                                                 SkBlender::Mode(SkBlendMode::kSaturation)}) {
155*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
156*c8dee2aaSAndroid Build Coastguard Worker             for (uint8_t alpha  : {0xFF , 0x40})
157*c8dee2aaSAndroid Build Coastguard Worker             for (bool    colors : {false, true})
158*c8dee2aaSAndroid Build Coastguard Worker             for (bool    shader : {false, true}) {
159*c8dee2aaSAndroid Build Coastguard Worker                 SkMesh::Result result;
160*c8dee2aaSAndroid Build Coastguard Worker                 // Rather than pile onto the combinatorics we draw every other test case indexed.
161*c8dee2aaSAndroid Build Coastguard Worker                 if ((i & 1) == 0) {
162*c8dee2aaSAndroid Build Coastguard Worker                     if (colors) {
163*c8dee2aaSAndroid Build Coastguard Worker                         result = SkMesh::Make(fSpecWithColor,
164*c8dee2aaSAndroid Build Coastguard Worker                                             SkMesh::Mode::kTriangleStrip,
165*c8dee2aaSAndroid Build Coastguard Worker                                             fColorVB,
166*c8dee2aaSAndroid Build Coastguard Worker                                             /*vertexCount=*/4,
167*c8dee2aaSAndroid Build Coastguard Worker                                             /*vertexOffset=*/0,
168*c8dee2aaSAndroid Build Coastguard Worker                                             /*uniforms=*/nullptr,
169*c8dee2aaSAndroid Build Coastguard Worker                                             /*children=*/nullChild,
170*c8dee2aaSAndroid Build Coastguard Worker                                             kRect);
171*c8dee2aaSAndroid Build Coastguard Worker                     } else {
172*c8dee2aaSAndroid Build Coastguard Worker                         result = SkMesh::Make(fSpecWithNoColor,
173*c8dee2aaSAndroid Build Coastguard Worker                                             SkMesh::Mode::kTriangleStrip,
174*c8dee2aaSAndroid Build Coastguard Worker                                             fNoColorVB,
175*c8dee2aaSAndroid Build Coastguard Worker                                             /*vertexCount=*/4,
176*c8dee2aaSAndroid Build Coastguard Worker                                             kNoColorOffset,
177*c8dee2aaSAndroid Build Coastguard Worker                                             /*uniforms=*/nullptr,
178*c8dee2aaSAndroid Build Coastguard Worker                                             /*children=*/{},
179*c8dee2aaSAndroid Build Coastguard Worker                                             kRect);
180*c8dee2aaSAndroid Build Coastguard Worker                     }
181*c8dee2aaSAndroid Build Coastguard Worker                 } else {
182*c8dee2aaSAndroid Build Coastguard Worker                     // Alternate between CPU and GPU-backend index buffers.
183*c8dee2aaSAndroid Build Coastguard Worker                     auto ib = (i % 4 == 0) ? fIB[0] : fIB[1];
184*c8dee2aaSAndroid Build Coastguard Worker                     if (colors) {
185*c8dee2aaSAndroid Build Coastguard Worker                         result = SkMesh::MakeIndexed(fSpecWithColor,
186*c8dee2aaSAndroid Build Coastguard Worker                                                      SkMesh::Mode::kTriangles,
187*c8dee2aaSAndroid Build Coastguard Worker                                                      fColorIndexedVB,
188*c8dee2aaSAndroid Build Coastguard Worker                                                      /*vertexCount=*/6,
189*c8dee2aaSAndroid Build Coastguard Worker                                                      kColorIndexedOffset,
190*c8dee2aaSAndroid Build Coastguard Worker                                                      std::move(ib),
191*c8dee2aaSAndroid Build Coastguard Worker                                                      /*indexCount=*/6,
192*c8dee2aaSAndroid Build Coastguard Worker                                                      kIndexOffset,
193*c8dee2aaSAndroid Build Coastguard Worker                                                      /*uniforms=*/nullptr,
194*c8dee2aaSAndroid Build Coastguard Worker                                                      /*children=*/nullChild,
195*c8dee2aaSAndroid Build Coastguard Worker                                                      kRect);
196*c8dee2aaSAndroid Build Coastguard Worker                     } else {
197*c8dee2aaSAndroid Build Coastguard Worker                         result = SkMesh::MakeIndexed(fSpecWithNoColor,
198*c8dee2aaSAndroid Build Coastguard Worker                                                      SkMesh::Mode::kTriangles,
199*c8dee2aaSAndroid Build Coastguard Worker                                                      fNoColorIndexedVB,
200*c8dee2aaSAndroid Build Coastguard Worker                                                      /*vertexCount=*/6,
201*c8dee2aaSAndroid Build Coastguard Worker                                                      /*vertexOffset=*/0,
202*c8dee2aaSAndroid Build Coastguard Worker                                                      std::move(ib),
203*c8dee2aaSAndroid Build Coastguard Worker                                                      /*indexCount=*/6,
204*c8dee2aaSAndroid Build Coastguard Worker                                                      kIndexOffset,
205*c8dee2aaSAndroid Build Coastguard Worker                                                      /*uniforms=*/nullptr,
206*c8dee2aaSAndroid Build Coastguard Worker                                                      /*children=*/{},
207*c8dee2aaSAndroid Build Coastguard Worker                                                      kRect);
208*c8dee2aaSAndroid Build Coastguard Worker                     }
209*c8dee2aaSAndroid Build Coastguard Worker                 }
210*c8dee2aaSAndroid Build Coastguard Worker                 if (!result.mesh.isValid()) {
211*c8dee2aaSAndroid Build Coastguard Worker                     SkDebugf("Mesh creation failed: %s\n", result.error.c_str());
212*c8dee2aaSAndroid Build Coastguard Worker                     return DrawResult::kFail;
213*c8dee2aaSAndroid Build Coastguard Worker                 }
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker                 SkPaint paint;
216*c8dee2aaSAndroid Build Coastguard Worker                 paint.setColor(SK_ColorGREEN);
217*c8dee2aaSAndroid Build Coastguard Worker                 paint.setShader(shader ? fShader : nullptr);
218*c8dee2aaSAndroid Build Coastguard Worker                 paint.setAlpha(alpha);
219*c8dee2aaSAndroid Build Coastguard Worker 
220*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawMesh(result.mesh, blender, paint);
221*c8dee2aaSAndroid Build Coastguard Worker 
222*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(0, 150);
223*c8dee2aaSAndroid Build Coastguard Worker                 ++i;
224*c8dee2aaSAndroid Build Coastguard Worker             }
225*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
226*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(150, 0);
227*c8dee2aaSAndroid Build Coastguard Worker         }
228*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
229*c8dee2aaSAndroid Build Coastguard Worker     }
230*c8dee2aaSAndroid Build Coastguard Worker 
231*c8dee2aaSAndroid Build Coastguard Worker private:
ensureBuffers()232*c8dee2aaSAndroid Build Coastguard Worker     void ensureBuffers() {
233*c8dee2aaSAndroid Build Coastguard Worker         if (!fColorVB) {
234*c8dee2aaSAndroid Build Coastguard Worker             fColorVB = SkMeshes::MakeVertexBuffer(kColorQuad, sizeof(kColorQuad));
235*c8dee2aaSAndroid Build Coastguard Worker         }
236*c8dee2aaSAndroid Build Coastguard Worker 
237*c8dee2aaSAndroid Build Coastguard Worker         if (!fNoColorVB) {
238*c8dee2aaSAndroid Build Coastguard Worker             // Make this one such that the data is offset into the buffer.
239*c8dee2aaSAndroid Build Coastguard Worker             auto data = SkData::MakeUninitialized(sizeof(kNoColorQuad) + kNoColorOffset);
240*c8dee2aaSAndroid Build Coastguard Worker             std::memcpy(SkTAddOffset<void>(data->writable_data(), kNoColorOffset),
241*c8dee2aaSAndroid Build Coastguard Worker                         kNoColorQuad,
242*c8dee2aaSAndroid Build Coastguard Worker                         sizeof(kNoColorQuad));
243*c8dee2aaSAndroid Build Coastguard Worker             fNoColorVB = SkMeshes::MakeVertexBuffer(data->data(), data->size());
244*c8dee2aaSAndroid Build Coastguard Worker         }
245*c8dee2aaSAndroid Build Coastguard Worker 
246*c8dee2aaSAndroid Build Coastguard Worker         if (!fColorIndexedVB) {
247*c8dee2aaSAndroid Build Coastguard Worker             // This buffer also has an offset.
248*c8dee2aaSAndroid Build Coastguard Worker             auto data = SkData::MakeUninitialized(sizeof(kColorIndexedQuad) + kColorIndexedOffset);
249*c8dee2aaSAndroid Build Coastguard Worker             std::memcpy(SkTAddOffset<void>(data->writable_data(), kColorIndexedOffset),
250*c8dee2aaSAndroid Build Coastguard Worker                         kColorIndexedQuad,
251*c8dee2aaSAndroid Build Coastguard Worker                         sizeof(kColorIndexedQuad));
252*c8dee2aaSAndroid Build Coastguard Worker             fColorIndexedVB = SkMeshes::MakeVertexBuffer(data->data(), data->size());
253*c8dee2aaSAndroid Build Coastguard Worker         }
254*c8dee2aaSAndroid Build Coastguard Worker 
255*c8dee2aaSAndroid Build Coastguard Worker         if (!fNoColorIndexedVB) {
256*c8dee2aaSAndroid Build Coastguard Worker             fNoColorIndexedVB =
257*c8dee2aaSAndroid Build Coastguard Worker                     SkMeshes::MakeVertexBuffer(kNoColorIndexedQuad, sizeof(kNoColorIndexedQuad));
258*c8dee2aaSAndroid Build Coastguard Worker         }
259*c8dee2aaSAndroid Build Coastguard Worker 
260*c8dee2aaSAndroid Build Coastguard Worker         if (!fIB[0]) {
261*c8dee2aaSAndroid Build Coastguard Worker             // The index buffer has an offset.
262*c8dee2aaSAndroid Build Coastguard Worker             auto data = SkData::MakeUninitialized(sizeof(kIndices) + kIndexOffset);
263*c8dee2aaSAndroid Build Coastguard Worker             std::memcpy(SkTAddOffset<void>(data->writable_data(), kIndexOffset),
264*c8dee2aaSAndroid Build Coastguard Worker                         kIndices,
265*c8dee2aaSAndroid Build Coastguard Worker                         sizeof(kIndices));
266*c8dee2aaSAndroid Build Coastguard Worker             fIB[0] = SkMeshes::MakeIndexBuffer(data->data(), data->size());
267*c8dee2aaSAndroid Build Coastguard Worker         }
268*c8dee2aaSAndroid Build Coastguard Worker 
269*c8dee2aaSAndroid Build Coastguard Worker         if (!fIB[1]) {
270*c8dee2aaSAndroid Build Coastguard Worker             // On CPU we always use the same CPU-backed index buffer.
271*c8dee2aaSAndroid Build Coastguard Worker             fIB[1] = fIB[0];
272*c8dee2aaSAndroid Build Coastguard Worker         }
273*c8dee2aaSAndroid Build Coastguard Worker     }
274*c8dee2aaSAndroid Build Coastguard Worker 
275*c8dee2aaSAndroid Build Coastguard Worker     struct ColorVertex {
276*c8dee2aaSAndroid Build Coastguard Worker         uint32_t pad;
277*c8dee2aaSAndroid Build Coastguard Worker         uint32_t brag;
278*c8dee2aaSAndroid Build Coastguard Worker         float    xuyv[4];
279*c8dee2aaSAndroid Build Coastguard Worker     };
280*c8dee2aaSAndroid Build Coastguard Worker 
281*c8dee2aaSAndroid Build Coastguard Worker     struct NoColorVertex {
282*c8dee2aaSAndroid Build Coastguard Worker         float xuyv[4];
283*c8dee2aaSAndroid Build Coastguard Worker     };
284*c8dee2aaSAndroid Build Coastguard Worker 
285*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kRect = SkRect::MakeLTRB(20, 20, 120, 120);
286*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kUV   = SkRect::MakeLTRB( 0,  0,  20,  20);
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker     static constexpr ColorVertex kColorQuad[] {
289*c8dee2aaSAndroid Build Coastguard Worker             {0, 0x00FFFF00, {kRect.left(),  kUV.left(),  kRect.top(),    kUV.top()   }},
290*c8dee2aaSAndroid Build Coastguard Worker             {0, 0x00FFFFFF, {kRect.right(), kUV.right(), kRect.top(),    kUV.top()   }},
291*c8dee2aaSAndroid Build Coastguard Worker             {0, 0xFFFF00FF, {kRect.left(),  kUV.left(),  kRect.bottom(), kUV.bottom()}},
292*c8dee2aaSAndroid Build Coastguard Worker             {0, 0xFFFFFF00, {kRect.right(), kUV.right(), kRect.bottom(), kUV.bottom()}},
293*c8dee2aaSAndroid Build Coastguard Worker     };
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker     static constexpr NoColorVertex kNoColorQuad[]{
296*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left(),  kUV.left(),  kRect.top(),    kUV.top()   }},
297*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kUV.right(), kRect.top(),    kUV.top()   }},
298*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left(),  kUV.left(),  kRect.bottom(), kUV.bottom()}},
299*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kUV.right(), kRect.bottom(), kUV.bottom()}},
300*c8dee2aaSAndroid Build Coastguard Worker     };
301*c8dee2aaSAndroid Build Coastguard Worker 
302*c8dee2aaSAndroid Build Coastguard Worker     // The indexed quads draw the same as the non-indexed. They just have unused vertices that the
303*c8dee2aaSAndroid Build Coastguard Worker     // index buffer skips over draw with triangles instead of a triangle strip.
304*c8dee2aaSAndroid Build Coastguard Worker     static constexpr ColorVertex kColorIndexedQuad[] {
305*c8dee2aaSAndroid Build Coastguard Worker             {0, 0x00FFFF00, {kRect.left(),  kUV.left(),  kRect.top(),    kUV.top()   }},
306*c8dee2aaSAndroid Build Coastguard Worker             {0, 0x00000000, {        100.f,        0.f,        100.f,    5.f         }}, // unused
307*c8dee2aaSAndroid Build Coastguard Worker             {0, 0x00FFFFFF, {kRect.right(), kUV.right(), kRect.top(),    kUV.top()   }},
308*c8dee2aaSAndroid Build Coastguard Worker             {0, 0x00000000, {        200.f,        10.f,        200.f,   10.f        }}, // unused
309*c8dee2aaSAndroid Build Coastguard Worker             {0, 0xFFFF00FF, {kRect.left(),  kUV.left(),  kRect.bottom(), kUV.bottom()}},
310*c8dee2aaSAndroid Build Coastguard Worker             {0, 0xFFFFFF00, {kRect.right(), kUV.right(), kRect.bottom(), kUV.bottom()}},
311*c8dee2aaSAndroid Build Coastguard Worker     };
312*c8dee2aaSAndroid Build Coastguard Worker 
313*c8dee2aaSAndroid Build Coastguard Worker     static constexpr NoColorVertex kNoColorIndexedQuad[]{
314*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left(),  kUV.left(),  kRect.top(),    kUV.top()   }},
315*c8dee2aaSAndroid Build Coastguard Worker             {{        100.f,        0.f,        100.f,    5.f         }}, // unused
316*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kUV.right(), kRect.top(),    kUV.top()   }},
317*c8dee2aaSAndroid Build Coastguard Worker             {{        200.f,        10.f,        200.f,   10.f        }}, // unused
318*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left(),  kUV.left(),  kRect.bottom(), kUV.bottom()}},
319*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kUV.right(), kRect.bottom(), kUV.bottom()}},
320*c8dee2aaSAndroid Build Coastguard Worker     };
321*c8dee2aaSAndroid Build Coastguard Worker 
322*c8dee2aaSAndroid Build Coastguard Worker     static constexpr uint16_t kIndices[]{0, 2, 4, 2, 5, 4};
323*c8dee2aaSAndroid Build Coastguard Worker 
324*c8dee2aaSAndroid Build Coastguard Worker     // For some buffers we add an offset to ensure we're exercising drawing from mid-buffer.
325*c8dee2aaSAndroid Build Coastguard Worker     static constexpr size_t kNoColorOffset      = sizeof(NoColorVertex);
326*c8dee2aaSAndroid Build Coastguard Worker     static constexpr size_t kColorIndexedOffset = 2*sizeof(ColorVertex);
327*c8dee2aaSAndroid Build Coastguard Worker     static constexpr size_t kIndexOffset        = 6;
328*c8dee2aaSAndroid Build Coastguard Worker 
329*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader;
330*c8dee2aaSAndroid Build Coastguard Worker 
331*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMeshSpecification> fSpecWithColor;
332*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMeshSpecification> fSpecWithNoColor;
333*c8dee2aaSAndroid Build Coastguard Worker 
334*c8dee2aaSAndroid Build Coastguard Worker     // On GPU the first IB is a CPU buffer and the second is a GPU buffer.
335*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::IndexBuffer> fIB[2];
336*c8dee2aaSAndroid Build Coastguard Worker 
337*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::VertexBuffer> fColorVB;
338*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::VertexBuffer> fNoColorVB;
339*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::VertexBuffer> fColorIndexedVB;
340*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::VertexBuffer> fNoColorIndexedVB;
341*c8dee2aaSAndroid Build Coastguard Worker };
342*c8dee2aaSAndroid Build Coastguard Worker 
343*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MeshGM;)
344*c8dee2aaSAndroid Build Coastguard Worker 
345*c8dee2aaSAndroid Build Coastguard Worker class MeshColorSpaceGM : public skiagm::GM {
346*c8dee2aaSAndroid Build Coastguard Worker public:
MeshColorSpaceGM()347*c8dee2aaSAndroid Build Coastguard Worker     MeshColorSpaceGM() {}
348*c8dee2aaSAndroid Build Coastguard Worker 
349*c8dee2aaSAndroid Build Coastguard Worker protected:
350*c8dee2aaSAndroid Build Coastguard Worker     using Attribute = SkMeshSpecification::Attribute;
351*c8dee2aaSAndroid Build Coastguard Worker     using Varying   = SkMeshSpecification::Varying;
352*c8dee2aaSAndroid Build Coastguard Worker 
getISize()353*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {468, 258}; }
354*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()355*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
356*c8dee2aaSAndroid Build Coastguard Worker         static const Attribute kAttributes[]{
357*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat2, 0, SkString{"pos"}  },
358*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat4, 8, SkString{"color"}},
359*c8dee2aaSAndroid Build Coastguard Worker         };
360*c8dee2aaSAndroid Build Coastguard Worker         static const Varying kVaryings[]{
361*c8dee2aaSAndroid Build Coastguard Worker                 {Varying::Type::kHalf4,  SkString{"color"}},
362*c8dee2aaSAndroid Build Coastguard Worker         };
363*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kPremulVS[] = R"(
364*c8dee2aaSAndroid Build Coastguard Worker                 Varyings main(const in Attributes attributes) {
365*c8dee2aaSAndroid Build Coastguard Worker                     Varyings varyings;
366*c8dee2aaSAndroid Build Coastguard Worker                     varyings.color = half4(attributes.color.a*attributes.color.rgb,
367*c8dee2aaSAndroid Build Coastguard Worker                                            attributes.color.a);
368*c8dee2aaSAndroid Build Coastguard Worker                     varyings.position = attributes.pos;
369*c8dee2aaSAndroid Build Coastguard Worker                     return varyings;
370*c8dee2aaSAndroid Build Coastguard Worker                 }
371*c8dee2aaSAndroid Build Coastguard Worker         )";
372*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kUnpremulVS[] = R"(
373*c8dee2aaSAndroid Build Coastguard Worker                 Varyings main(const in Attributes attributes) {
374*c8dee2aaSAndroid Build Coastguard Worker                     Varyings varyings;
375*c8dee2aaSAndroid Build Coastguard Worker                     varyings.color    = attributes.color;
376*c8dee2aaSAndroid Build Coastguard Worker                     varyings.position = attributes.pos;
377*c8dee2aaSAndroid Build Coastguard Worker                     return varyings;
378*c8dee2aaSAndroid Build Coastguard Worker                 }
379*c8dee2aaSAndroid Build Coastguard Worker         )";
380*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kFS[] = R"(
381*c8dee2aaSAndroid Build Coastguard Worker                 float2 main(in const Varyings varyings, out half4 color) {
382*c8dee2aaSAndroid Build Coastguard Worker                     color = varyings.color;
383*c8dee2aaSAndroid Build Coastguard Worker                     return varyings.position;
384*c8dee2aaSAndroid Build Coastguard Worker                 }
385*c8dee2aaSAndroid Build Coastguard Worker         )";
386*c8dee2aaSAndroid Build Coastguard Worker         for (bool unpremul : {false, true}) {
387*c8dee2aaSAndroid Build Coastguard Worker             auto at = unpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
388*c8dee2aaSAndroid Build Coastguard Worker             auto vs = unpremul ? kUnpremulVS : kPremulVS;
389*c8dee2aaSAndroid Build Coastguard Worker             for (bool spin : {false, true}) {
390*c8dee2aaSAndroid Build Coastguard Worker                 auto cs = SkColorSpace::MakeSRGB();
391*c8dee2aaSAndroid Build Coastguard Worker                 if (spin) {
392*c8dee2aaSAndroid Build Coastguard Worker                     cs = cs->makeColorSpin();
393*c8dee2aaSAndroid Build Coastguard Worker                 }
394*c8dee2aaSAndroid Build Coastguard Worker 
395*c8dee2aaSAndroid Build Coastguard Worker                 auto [spec, error] = SkMeshSpecification::Make(
396*c8dee2aaSAndroid Build Coastguard Worker                         kAttributes,
397*c8dee2aaSAndroid Build Coastguard Worker                         sizeof(Vertex),
398*c8dee2aaSAndroid Build Coastguard Worker                         kVaryings,
399*c8dee2aaSAndroid Build Coastguard Worker                         SkString(vs),
400*c8dee2aaSAndroid Build Coastguard Worker                         SkString(kFS),
401*c8dee2aaSAndroid Build Coastguard Worker                         std::move(cs),
402*c8dee2aaSAndroid Build Coastguard Worker                         at);
403*c8dee2aaSAndroid Build Coastguard Worker                 if (!spec) {
404*c8dee2aaSAndroid Build Coastguard Worker                     SkDebugf("%s\n", error.c_str());
405*c8dee2aaSAndroid Build Coastguard Worker                 }
406*c8dee2aaSAndroid Build Coastguard Worker                 fSpecs[SpecIndex(unpremul, spin)] = std::move(spec);
407*c8dee2aaSAndroid Build Coastguard Worker             }
408*c8dee2aaSAndroid Build Coastguard Worker         }
409*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts[]    = {{kRect.fLeft, 0}, {kRect.centerX(), 0}};
410*c8dee2aaSAndroid Build Coastguard Worker         SkColor colors[] = {SK_ColorWHITE,    SK_ColorTRANSPARENT};
411*c8dee2aaSAndroid Build Coastguard Worker         fShader = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kMirror);
412*c8dee2aaSAndroid Build Coastguard Worker 
413*c8dee2aaSAndroid Build Coastguard Worker         fVB = SkMeshes::MakeVertexBuffer(kQuad, sizeof(kQuad));
414*c8dee2aaSAndroid Build Coastguard Worker     }
415*c8dee2aaSAndroid Build Coastguard Worker 
getName() const416*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("custommesh_cs"); }
417*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * error)418*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* error) override {
419*c8dee2aaSAndroid Build Coastguard Worker         // Force an intermediate surface if the canvas is in "legacy" mode
420*c8dee2aaSAndroid Build Coastguard Worker         SkCanvas* c = canvas;
421*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkSurface> surface;
422*c8dee2aaSAndroid Build Coastguard Worker         if (!c->imageInfo().colorSpace()) {
423*c8dee2aaSAndroid Build Coastguard Worker             SkImageInfo info = canvas->imageInfo().makeColorSpace(SkColorSpace::MakeSRGB());
424*c8dee2aaSAndroid Build Coastguard Worker             surface = canvas->makeSurface(info);
425*c8dee2aaSAndroid Build Coastguard Worker             if (!surface) {
426*c8dee2aaSAndroid Build Coastguard Worker                 // This GM won't work on configs that use a recording canvas.
427*c8dee2aaSAndroid Build Coastguard Worker                 return DrawResult::kSkip;
428*c8dee2aaSAndroid Build Coastguard Worker             }
429*c8dee2aaSAndroid Build Coastguard Worker             c = surface->getCanvas();
430*c8dee2aaSAndroid Build Coastguard Worker             c->clear(SK_ColorWHITE);
431*c8dee2aaSAndroid Build Coastguard Worker         }
432*c8dee2aaSAndroid Build Coastguard Worker         for (bool useShader : {false, true})
433*c8dee2aaSAndroid Build Coastguard Worker         for (bool unpremul  : {false, true}) {
434*c8dee2aaSAndroid Build Coastguard Worker             c->save();
435*c8dee2aaSAndroid Build Coastguard Worker             for (bool spin : {false, true}) {
436*c8dee2aaSAndroid Build Coastguard Worker                 auto result = SkMesh::Make(fSpecs[SpecIndex(unpremul, spin)],
437*c8dee2aaSAndroid Build Coastguard Worker                                            SkMesh::Mode::kTriangleStrip,
438*c8dee2aaSAndroid Build Coastguard Worker                                            fVB,
439*c8dee2aaSAndroid Build Coastguard Worker                                            /*vertexCount=*/4,
440*c8dee2aaSAndroid Build Coastguard Worker                                            /*vertexOffset=*/0,
441*c8dee2aaSAndroid Build Coastguard Worker                                            /*uniforms=*/nullptr,
442*c8dee2aaSAndroid Build Coastguard Worker                                            /*children=*/{},
443*c8dee2aaSAndroid Build Coastguard Worker                                            kRect);
444*c8dee2aaSAndroid Build Coastguard Worker                 if (!result.mesh.isValid()) {
445*c8dee2aaSAndroid Build Coastguard Worker                     SkDebugf("Mesh creation failed: %s\n", result.error.c_str());
446*c8dee2aaSAndroid Build Coastguard Worker                     return DrawResult::kFail;
447*c8dee2aaSAndroid Build Coastguard Worker                 }
448*c8dee2aaSAndroid Build Coastguard Worker 
449*c8dee2aaSAndroid Build Coastguard Worker                 SkPaint paint;
450*c8dee2aaSAndroid Build Coastguard Worker                 paint.setShader(useShader ? fShader : nullptr);
451*c8dee2aaSAndroid Build Coastguard Worker                 SkBlendMode mode = useShader ? SkBlendMode::kModulate : SkBlendMode::kDst;
452*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawMesh(result.mesh, SkBlender::Mode(mode), paint);
453*c8dee2aaSAndroid Build Coastguard Worker 
454*c8dee2aaSAndroid Build Coastguard Worker                 c->translate(0, kRect.height() + 10);
455*c8dee2aaSAndroid Build Coastguard Worker             }
456*c8dee2aaSAndroid Build Coastguard Worker             c->restore();
457*c8dee2aaSAndroid Build Coastguard Worker             c->translate(kRect.width() + 10, 0);
458*c8dee2aaSAndroid Build Coastguard Worker             c->save();
459*c8dee2aaSAndroid Build Coastguard Worker         }
460*c8dee2aaSAndroid Build Coastguard Worker         if (surface) {
461*c8dee2aaSAndroid Build Coastguard Worker             surface->draw(canvas, 0, 0);
462*c8dee2aaSAndroid Build Coastguard Worker         }
463*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
464*c8dee2aaSAndroid Build Coastguard Worker     }
465*c8dee2aaSAndroid Build Coastguard Worker 
466*c8dee2aaSAndroid Build Coastguard Worker private:
467*c8dee2aaSAndroid Build Coastguard Worker     struct Vertex {
468*c8dee2aaSAndroid Build Coastguard Worker         SkPoint   pos;
469*c8dee2aaSAndroid Build Coastguard Worker         SkColor4f color;
470*c8dee2aaSAndroid Build Coastguard Worker     };
471*c8dee2aaSAndroid Build Coastguard Worker 
SpecIndex(bool spin,bool unpremul)472*c8dee2aaSAndroid Build Coastguard Worker     static int SpecIndex(bool spin, bool unpremul) {
473*c8dee2aaSAndroid Build Coastguard Worker         return static_cast<int>(spin) + 2*static_cast<int>(unpremul);
474*c8dee2aaSAndroid Build Coastguard Worker     }
475*c8dee2aaSAndroid Build Coastguard Worker 
476*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kRect = SkRect::MakeLTRB(20, 20, 120, 120);
477*c8dee2aaSAndroid Build Coastguard Worker 
478*c8dee2aaSAndroid Build Coastguard Worker     static constexpr Vertex kQuad[] {
479*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left() , kRect.top()   }, {1, 0, 0, 1}},
480*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kRect.top()   }, {0, 1, 0, 0}},
481*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left() , kRect.bottom()}, {1, 1, 0, 0}},
482*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kRect.bottom()}, {0, 0, 1, 1}},
483*c8dee2aaSAndroid Build Coastguard Worker     };
484*c8dee2aaSAndroid Build Coastguard Worker 
485*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::VertexBuffer> fVB;
486*c8dee2aaSAndroid Build Coastguard Worker 
487*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMeshSpecification> fSpecs[4];
488*c8dee2aaSAndroid Build Coastguard Worker 
489*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader;
490*c8dee2aaSAndroid Build Coastguard Worker };
491*c8dee2aaSAndroid Build Coastguard Worker 
492*c8dee2aaSAndroid Build Coastguard Worker // helpers for cases when ctx could be nullptr
make_vertex_buffer(GrDirectContext * ctx,const void * data,size_t size)493*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkMesh::VertexBuffer> make_vertex_buffer(GrDirectContext* ctx,
494*c8dee2aaSAndroid Build Coastguard Worker                                                       const void* data,
495*c8dee2aaSAndroid Build Coastguard Worker                                                       size_t size) {
496*c8dee2aaSAndroid Build Coastguard Worker     if (ctx) {
497*c8dee2aaSAndroid Build Coastguard Worker         return SkMeshes::MakeVertexBuffer(ctx, data, size);
498*c8dee2aaSAndroid Build Coastguard Worker     }
499*c8dee2aaSAndroid Build Coastguard Worker     return SkMeshes::MakeVertexBuffer(data, size);
500*c8dee2aaSAndroid Build Coastguard Worker }
501*c8dee2aaSAndroid Build Coastguard Worker 
make_index_buffer(GrDirectContext * ctx,const void * data,size_t size)502*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkMesh::IndexBuffer> make_index_buffer(GrDirectContext* ctx,
503*c8dee2aaSAndroid Build Coastguard Worker                                                     const void* data,
504*c8dee2aaSAndroid Build Coastguard Worker                                                     size_t size) {
505*c8dee2aaSAndroid Build Coastguard Worker     if (ctx) {
506*c8dee2aaSAndroid Build Coastguard Worker         return SkMeshes::MakeIndexBuffer(ctx, data, size);
507*c8dee2aaSAndroid Build Coastguard Worker     }
508*c8dee2aaSAndroid Build Coastguard Worker     return SkMeshes::MakeIndexBuffer(data, size);
509*c8dee2aaSAndroid Build Coastguard Worker }
510*c8dee2aaSAndroid Build Coastguard Worker 
511*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MeshColorSpaceGM;)
512*c8dee2aaSAndroid Build Coastguard Worker 
513*c8dee2aaSAndroid Build Coastguard Worker class MeshUniformsGM : public skiagm::GM {
514*c8dee2aaSAndroid Build Coastguard Worker public:
MeshUniformsGM()515*c8dee2aaSAndroid Build Coastguard Worker     MeshUniformsGM() { this->onAnimate(0); }
516*c8dee2aaSAndroid Build Coastguard Worker 
517*c8dee2aaSAndroid Build Coastguard Worker protected:
518*c8dee2aaSAndroid Build Coastguard Worker     using Attribute = SkMeshSpecification::Attribute;
519*c8dee2aaSAndroid Build Coastguard Worker     using Varying   = SkMeshSpecification::Varying;
520*c8dee2aaSAndroid Build Coastguard Worker 
getISize()521*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {140, 250}; }
522*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()523*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
524*c8dee2aaSAndroid Build Coastguard Worker         static const Attribute kAttributes[]{
525*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat2, 0, SkString{"pos"}  },
526*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat2, 8, SkString{"coords"}},
527*c8dee2aaSAndroid Build Coastguard Worker         };
528*c8dee2aaSAndroid Build Coastguard Worker         static const Varying kVaryings[]{
529*c8dee2aaSAndroid Build Coastguard Worker                 {Varying::Type::kFloat2, SkString{"coords"}},
530*c8dee2aaSAndroid Build Coastguard Worker         };
531*c8dee2aaSAndroid Build Coastguard Worker         // To exercise shared VS/FS uniforms we have a matrix that is applied twice, once in each
532*c8dee2aaSAndroid Build Coastguard Worker         // stage.
533*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kVS[] = R"(
534*c8dee2aaSAndroid Build Coastguard Worker                 uniform float t[2];
535*c8dee2aaSAndroid Build Coastguard Worker                 uniform half3x3 m;
536*c8dee2aaSAndroid Build Coastguard Worker                 Varyings main(in const Attributes attributes) {
537*c8dee2aaSAndroid Build Coastguard Worker                     Varyings varyings;
538*c8dee2aaSAndroid Build Coastguard Worker                     varyings.coords   = (m*float3(attributes.coords + float2(t[0], t[1]), 1)).xy;
539*c8dee2aaSAndroid Build Coastguard Worker                     varyings.position = attributes.pos;
540*c8dee2aaSAndroid Build Coastguard Worker                     return varyings;
541*c8dee2aaSAndroid Build Coastguard Worker                 }
542*c8dee2aaSAndroid Build Coastguard Worker         )";
543*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kFS[] = R"(
544*c8dee2aaSAndroid Build Coastguard Worker                 uniform half3x3 m;
545*c8dee2aaSAndroid Build Coastguard Worker                 layout(color) uniform half4 color;
546*c8dee2aaSAndroid Build Coastguard Worker                 float2 main(const Varyings varyings, out half4 c) {
547*c8dee2aaSAndroid Build Coastguard Worker                     c = color;
548*c8dee2aaSAndroid Build Coastguard Worker                     return (m*float3(varyings.coords, 1)).xy;
549*c8dee2aaSAndroid Build Coastguard Worker                 }
550*c8dee2aaSAndroid Build Coastguard Worker         )";
551*c8dee2aaSAndroid Build Coastguard Worker         auto [spec, error] =
552*c8dee2aaSAndroid Build Coastguard Worker                 SkMeshSpecification::Make(kAttributes,
553*c8dee2aaSAndroid Build Coastguard Worker                                           sizeof(Vertex),
554*c8dee2aaSAndroid Build Coastguard Worker                                           kVaryings,
555*c8dee2aaSAndroid Build Coastguard Worker                                           SkString(kVS),
556*c8dee2aaSAndroid Build Coastguard Worker                                           SkString(kFS),
557*c8dee2aaSAndroid Build Coastguard Worker                                           SkColorSpace::MakeSRGB(),
558*c8dee2aaSAndroid Build Coastguard Worker                                           kPremul_SkAlphaType);
559*c8dee2aaSAndroid Build Coastguard Worker         if (!spec) {
560*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("%s\n", error.c_str());
561*c8dee2aaSAndroid Build Coastguard Worker         }
562*c8dee2aaSAndroid Build Coastguard Worker         fSpec = std::move(spec);
563*c8dee2aaSAndroid Build Coastguard Worker 
564*c8dee2aaSAndroid Build Coastguard Worker         SkColor colors[] = {SK_ColorWHITE, SK_ColorBLACK};
565*c8dee2aaSAndroid Build Coastguard Worker         fShader = SkGradientShader::MakeRadial(kGradCenter,
566*c8dee2aaSAndroid Build Coastguard Worker                                                .4f,
567*c8dee2aaSAndroid Build Coastguard Worker                                                colors,
568*c8dee2aaSAndroid Build Coastguard Worker                                                nullptr,
569*c8dee2aaSAndroid Build Coastguard Worker                                                2,
570*c8dee2aaSAndroid Build Coastguard Worker                                                SkTileMode::kMirror);
571*c8dee2aaSAndroid Build Coastguard Worker 
572*c8dee2aaSAndroid Build Coastguard Worker         fVB = SkMeshes::MakeVertexBuffer(kQuad, sizeof(kQuad));
573*c8dee2aaSAndroid Build Coastguard Worker     }
574*c8dee2aaSAndroid Build Coastguard Worker 
getName() const575*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("custommesh_uniforms"); }
576*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * error)577*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* error) override {
578*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrices[] {
579*c8dee2aaSAndroid Build Coastguard Worker                 SkMatrix::MakeAll(-1,  0, 0, // self inverse so no effect.
580*c8dee2aaSAndroid Build Coastguard Worker                                    0, -1, 0,
581*c8dee2aaSAndroid Build Coastguard Worker                                    0,  0, 1),
582*c8dee2aaSAndroid Build Coastguard Worker                 SkMatrix::RotateDeg(fDegrees/2.f, {0.5f, 0.5f}),
583*c8dee2aaSAndroid Build Coastguard Worker         };
584*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& m : matrices) {
585*c8dee2aaSAndroid Build Coastguard Worker             auto unis = SkData::MakeUninitialized(fSpec->uniformSize());
586*c8dee2aaSAndroid Build Coastguard Worker 
587*c8dee2aaSAndroid Build Coastguard Worker             SkPoint trans = -kCoordTrans;
588*c8dee2aaSAndroid Build Coastguard Worker             static_assert(sizeof(SkPoint) == 2*sizeof(float));
589*c8dee2aaSAndroid Build Coastguard Worker 
590*c8dee2aaSAndroid Build Coastguard Worker             const SkMeshSpecification::Uniform* u = fSpec->findUniform("t");
591*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(u);
592*c8dee2aaSAndroid Build Coastguard Worker             std::memcpy(SkTAddOffset<void>(unis->writable_data(), u->offset),
593*c8dee2aaSAndroid Build Coastguard Worker                         (void*)&trans,
594*c8dee2aaSAndroid Build Coastguard Worker                         2*sizeof(float));
595*c8dee2aaSAndroid Build Coastguard Worker 
596*c8dee2aaSAndroid Build Coastguard Worker             u = fSpec->findUniform("m");
597*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(u);
598*c8dee2aaSAndroid Build Coastguard Worker             for (size_t offset = u->offset, col = 0; col < 3; ++col) {
599*c8dee2aaSAndroid Build Coastguard Worker                 for (size_t row = 0; row < 3; ++row, offset += sizeof(float)) {
600*c8dee2aaSAndroid Build Coastguard Worker                     *SkTAddOffset<float>(unis->writable_data(), offset) = m.rc(row, col);
601*c8dee2aaSAndroid Build Coastguard Worker                 }
602*c8dee2aaSAndroid Build Coastguard Worker             }
603*c8dee2aaSAndroid Build Coastguard Worker 
604*c8dee2aaSAndroid Build Coastguard Worker             u = fSpec->findUniform("color");
605*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(u);
606*c8dee2aaSAndroid Build Coastguard Worker             std::memcpy(SkTAddOffset<void>(unis->writable_data(), u->offset),
607*c8dee2aaSAndroid Build Coastguard Worker                         fColor.vec(),
608*c8dee2aaSAndroid Build Coastguard Worker                         4*sizeof(float));
609*c8dee2aaSAndroid Build Coastguard Worker 
610*c8dee2aaSAndroid Build Coastguard Worker             auto result = SkMesh::Make(fSpec,
611*c8dee2aaSAndroid Build Coastguard Worker                                        SkMesh::Mode::kTriangleStrip,
612*c8dee2aaSAndroid Build Coastguard Worker                                        fVB,
613*c8dee2aaSAndroid Build Coastguard Worker                                        /*vertexCount=*/4,
614*c8dee2aaSAndroid Build Coastguard Worker                                        /*vertexOffset=*/0,
615*c8dee2aaSAndroid Build Coastguard Worker                                        /*uniforms=*/std::move(unis),
616*c8dee2aaSAndroid Build Coastguard Worker                                        /*children=*/{},
617*c8dee2aaSAndroid Build Coastguard Worker                                        kRect);
618*c8dee2aaSAndroid Build Coastguard Worker 
619*c8dee2aaSAndroid Build Coastguard Worker             if (!result.mesh.isValid()) {
620*c8dee2aaSAndroid Build Coastguard Worker                 SkDebugf("Mesh creation failed: %s\n", result.error.c_str());
621*c8dee2aaSAndroid Build Coastguard Worker                 return DrawResult::kFail;
622*c8dee2aaSAndroid Build Coastguard Worker             }
623*c8dee2aaSAndroid Build Coastguard Worker 
624*c8dee2aaSAndroid Build Coastguard Worker             SkPaint paint;
625*c8dee2aaSAndroid Build Coastguard Worker             paint.setShader(fShader);
626*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawMesh(result.mesh, SkBlender::Mode(SkBlendMode::kModulate), paint);
627*c8dee2aaSAndroid Build Coastguard Worker 
628*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(0, kRect.height() + 10);
629*c8dee2aaSAndroid Build Coastguard Worker         }
630*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
631*c8dee2aaSAndroid Build Coastguard Worker     }
632*c8dee2aaSAndroid Build Coastguard Worker 
onAnimate(double nanos)633*c8dee2aaSAndroid Build Coastguard Worker     bool onAnimate(double nanos) override {
634*c8dee2aaSAndroid Build Coastguard Worker         fDegrees = TimeUtils::NanosToSeconds(nanos) * 360.f/10.f + 45.f;
635*c8dee2aaSAndroid Build Coastguard Worker         // prime number periods, like locusts.
636*c8dee2aaSAndroid Build Coastguard Worker         fColor.fR = TimeUtils::SineWave(nanos, 13.f, 0.f, 0.f, 1.f);
637*c8dee2aaSAndroid Build Coastguard Worker         fColor.fG = TimeUtils::SineWave(nanos, 23.f, 5.f, 0.f, 1.f);
638*c8dee2aaSAndroid Build Coastguard Worker         fColor.fB = TimeUtils::SineWave(nanos, 11.f, 0.f, 0.f, 1.f);
639*c8dee2aaSAndroid Build Coastguard Worker         fColor.fA = 1.f;
640*c8dee2aaSAndroid Build Coastguard Worker         return true;
641*c8dee2aaSAndroid Build Coastguard Worker     }
642*c8dee2aaSAndroid Build Coastguard Worker 
643*c8dee2aaSAndroid Build Coastguard Worker private:
644*c8dee2aaSAndroid Build Coastguard Worker     struct Vertex {
645*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pos;
646*c8dee2aaSAndroid Build Coastguard Worker         SkPoint tex;
647*c8dee2aaSAndroid Build Coastguard Worker     };
648*c8dee2aaSAndroid Build Coastguard Worker 
649*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kRect = SkRect::MakeLTRB(20, 20, 120, 120);
650*c8dee2aaSAndroid Build Coastguard Worker 
651*c8dee2aaSAndroid Build Coastguard Worker     // Our logical tex coords are [0..1] but we insert an arbitrary translation that gets undone
652*c8dee2aaSAndroid Build Coastguard Worker     // with a uniform.
653*c8dee2aaSAndroid Build Coastguard Worker     static constexpr SkPoint kCoordTrans = {75, -37};
654*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto    kCoordRect  = SkRect::MakeXYWH(kCoordTrans.x(), kCoordTrans.y(), 1, 1);
655*c8dee2aaSAndroid Build Coastguard Worker 
656*c8dee2aaSAndroid Build Coastguard Worker     static constexpr SkPoint kGradCenter = {0.3f, 0.2f};
657*c8dee2aaSAndroid Build Coastguard Worker 
658*c8dee2aaSAndroid Build Coastguard Worker     static constexpr Vertex kQuad[] {
659*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left() , kRect.top()   }, {kCoordRect.left() , kCoordRect.top()}   },
660*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kRect.top()   }, {kCoordRect.right(), kCoordRect.top()}   },
661*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left() , kRect.bottom()}, {kCoordRect.left() , kCoordRect.bottom()}},
662*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kRect.bottom()}, {kCoordRect.right(), kCoordRect.bottom()}},
663*c8dee2aaSAndroid Build Coastguard Worker     };
664*c8dee2aaSAndroid Build Coastguard Worker 
665*c8dee2aaSAndroid Build Coastguard Worker     float fDegrees;
666*c8dee2aaSAndroid Build Coastguard Worker 
667*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f fColor;
668*c8dee2aaSAndroid Build Coastguard Worker 
669*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::VertexBuffer> fVB;
670*c8dee2aaSAndroid Build Coastguard Worker 
671*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMeshSpecification> fSpec;
672*c8dee2aaSAndroid Build Coastguard Worker 
673*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader;
674*c8dee2aaSAndroid Build Coastguard Worker };
675*c8dee2aaSAndroid Build Coastguard Worker 
676*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MeshUniformsGM())
677*c8dee2aaSAndroid Build Coastguard Worker 
678*c8dee2aaSAndroid Build Coastguard Worker class MeshUpdateGM : public skiagm::GM {
679*c8dee2aaSAndroid Build Coastguard Worker public:
680*c8dee2aaSAndroid Build Coastguard Worker     MeshUpdateGM() = default;
681*c8dee2aaSAndroid Build Coastguard Worker 
682*c8dee2aaSAndroid Build Coastguard Worker protected:
683*c8dee2aaSAndroid Build Coastguard Worker     using Attribute = SkMeshSpecification::Attribute;
684*c8dee2aaSAndroid Build Coastguard Worker     using Varying = SkMeshSpecification::Varying;
685*c8dee2aaSAndroid Build Coastguard Worker 
getISize()686*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {270, 490}; }
687*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()688*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
689*c8dee2aaSAndroid Build Coastguard Worker         static const Attribute kAttributes[]{
690*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat2, 0, SkString{"pos"}},
691*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat2, 8, SkString{"coords"}},
692*c8dee2aaSAndroid Build Coastguard Worker         };
693*c8dee2aaSAndroid Build Coastguard Worker         static const Varying kVaryings[]{
694*c8dee2aaSAndroid Build Coastguard Worker                 {Varying::Type::kFloat2, SkString{"coords"}},
695*c8dee2aaSAndroid Build Coastguard Worker         };
696*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kVS[] = R"(
697*c8dee2aaSAndroid Build Coastguard Worker                 Varyings main(const in Attributes attributes) {
698*c8dee2aaSAndroid Build Coastguard Worker                     Varyings varyings;
699*c8dee2aaSAndroid Build Coastguard Worker                     varyings.coords   = attributes.coords;
700*c8dee2aaSAndroid Build Coastguard Worker                     varyings.position = attributes.pos;
701*c8dee2aaSAndroid Build Coastguard Worker                     return varyings;
702*c8dee2aaSAndroid Build Coastguard Worker                 }
703*c8dee2aaSAndroid Build Coastguard Worker         )";
704*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kFS[] = R"(
705*c8dee2aaSAndroid Build Coastguard Worker                 float2 main(const Varyings varyings) { return varyings.coords; }
706*c8dee2aaSAndroid Build Coastguard Worker         )";
707*c8dee2aaSAndroid Build Coastguard Worker         auto [spec, error] = SkMeshSpecification::Make(kAttributes,
708*c8dee2aaSAndroid Build Coastguard Worker                                                        sizeof(Vertex),
709*c8dee2aaSAndroid Build Coastguard Worker                                                        kVaryings,
710*c8dee2aaSAndroid Build Coastguard Worker                                                        SkString(kVS),
711*c8dee2aaSAndroid Build Coastguard Worker                                                        SkString(kFS),
712*c8dee2aaSAndroid Build Coastguard Worker                                                        SkColorSpace::MakeSRGB(),
713*c8dee2aaSAndroid Build Coastguard Worker                                                        kPremul_SkAlphaType);
714*c8dee2aaSAndroid Build Coastguard Worker         if (!spec) {
715*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("%s\n", error.c_str());
716*c8dee2aaSAndroid Build Coastguard Worker         }
717*c8dee2aaSAndroid Build Coastguard Worker         fSpec = std::move(spec);
718*c8dee2aaSAndroid Build Coastguard Worker 
719*c8dee2aaSAndroid Build Coastguard Worker         uint32_t colors[] = {SK_ColorYELLOW, SK_ColorMAGENTA, SK_ColorCYAN, SK_ColorWHITE};
720*c8dee2aaSAndroid Build Coastguard Worker         SkPixmap pixmap(SkImageInfo::Make({2, 2}, kBGRA_8888_SkColorType, kPremul_SkAlphaType),
721*c8dee2aaSAndroid Build Coastguard Worker                         colors,
722*c8dee2aaSAndroid Build Coastguard Worker                         /*rowBytes=*/8);
723*c8dee2aaSAndroid Build Coastguard Worker         fShader = SkImages::RasterFromPixmapCopy(pixmap)->makeShader(
724*c8dee2aaSAndroid Build Coastguard Worker                 SkTileMode::kClamp, SkTileMode::kClamp, SkFilterMode::kLinear);
725*c8dee2aaSAndroid Build Coastguard Worker     }
726*c8dee2aaSAndroid Build Coastguard Worker 
getName() const727*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("mesh_updates"); }
728*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * error)729*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* error) override {
730*c8dee2aaSAndroid Build Coastguard Worker         canvas->clear(SK_ColorBLACK);
731*c8dee2aaSAndroid Build Coastguard Worker 
732*c8dee2aaSAndroid Build Coastguard Worker         GrRecordingContext* rc = canvas->recordingContext();
733*c8dee2aaSAndroid Build Coastguard Worker         GrDirectContext* dc = GrAsDirectContext(rc);
734*c8dee2aaSAndroid Build Coastguard Worker         if (rc && !dc) {
735*c8dee2aaSAndroid Build Coastguard Worker             // On GPU this relies on using the DC to update the GPU backed vertex/index buffers.
736*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
737*c8dee2aaSAndroid Build Coastguard Worker         }
738*c8dee2aaSAndroid Build Coastguard Worker 
739*c8dee2aaSAndroid Build Coastguard Worker         if (dc && dc->abandoned()) {
740*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
741*c8dee2aaSAndroid Build Coastguard Worker         }
742*c8dee2aaSAndroid Build Coastguard Worker 
743*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
744*c8dee2aaSAndroid Build Coastguard Worker         paint.setShader(fShader);
745*c8dee2aaSAndroid Build Coastguard Worker 
746*c8dee2aaSAndroid Build Coastguard Worker         SkRect r = SkRect::MakeXYWH(10.f, 10.f, 50.f, 50.f);
747*c8dee2aaSAndroid Build Coastguard Worker 
748*c8dee2aaSAndroid Build Coastguard Worker         // We test updating CPU and GPU buffers.
749*c8dee2aaSAndroid Build Coastguard Worker         for (bool gpuBuffer : {false, true}) {
750*c8dee2aaSAndroid Build Coastguard Worker             auto ctx = gpuBuffer ? dc : nullptr;
751*c8dee2aaSAndroid Build Coastguard Worker 
752*c8dee2aaSAndroid Build Coastguard Worker             // How many rects worth of storage is in the vertex buffer?
753*c8dee2aaSAndroid Build Coastguard Worker             static constexpr int kVBRects = 2;
754*c8dee2aaSAndroid Build Coastguard Worker 
755*c8dee2aaSAndroid Build Coastguard Worker             // How many times do we update the vertex buffer? Wraps to start of buffer if
756*c8dee2aaSAndroid Build Coastguard Worker             // > kVBRects.
757*c8dee2aaSAndroid Build Coastguard Worker             static constexpr int kUpdatesRects = 3;
758*c8dee2aaSAndroid Build Coastguard Worker 
759*c8dee2aaSAndroid Build Coastguard Worker             auto vb = make_vertex_buffer(ctx, /*data=*/nullptr, kVBRects * 6 * sizeof(Vertex));
760*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(vb);
761*c8dee2aaSAndroid Build Coastguard Worker 
762*c8dee2aaSAndroid Build Coastguard Worker             SkRect bounds;
763*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < kUpdatesRects; ++i) {
764*c8dee2aaSAndroid Build Coastguard Worker                 auto p = r.makeOffset(100.f*i, 0.f);
765*c8dee2aaSAndroid Build Coastguard Worker                 if (i) {
766*c8dee2aaSAndroid Build Coastguard Worker                     bounds.join(p);
767*c8dee2aaSAndroid Build Coastguard Worker                 } else {
768*c8dee2aaSAndroid Build Coastguard Worker                     bounds = p;
769*c8dee2aaSAndroid Build Coastguard Worker                 }
770*c8dee2aaSAndroid Build Coastguard Worker 
771*c8dee2aaSAndroid Build Coastguard Worker                 SkPoint t[4];
772*c8dee2aaSAndroid Build Coastguard Worker                 SkRect::MakeWH(2.f, 2.f).toQuad(t);
773*c8dee2aaSAndroid Build Coastguard Worker                 SkMatrix::RotateDeg(90.f*i, {1.f, 1.f}).mapPoints(t, std::size(t));
774*c8dee2aaSAndroid Build Coastguard Worker 
775*c8dee2aaSAndroid Build Coastguard Worker                 Vertex vertices[6];
776*c8dee2aaSAndroid Build Coastguard Worker                 vertices[0] = {{p.left(), p.top()}, t[0]};
777*c8dee2aaSAndroid Build Coastguard Worker                 vertices[1] = {{p.left(), p.bottom()}, t[3]};
778*c8dee2aaSAndroid Build Coastguard Worker                 vertices[2] = {{p.right(), p.top()}, t[1]};
779*c8dee2aaSAndroid Build Coastguard Worker                 vertices[3] = vertices[2];
780*c8dee2aaSAndroid Build Coastguard Worker                 vertices[4] = vertices[1];
781*c8dee2aaSAndroid Build Coastguard Worker                 vertices[5] = {{p.right(), p.bottom()}, t[2]};
782*c8dee2aaSAndroid Build Coastguard Worker 
783*c8dee2aaSAndroid Build Coastguard Worker                 size_t offset = 6*(i % kVBRects)*sizeof(Vertex);
784*c8dee2aaSAndroid Build Coastguard Worker                 SkAssertResult(vb->update(ctx, vertices, offset, 6*sizeof(Vertex)));
785*c8dee2aaSAndroid Build Coastguard Worker                 // Make there aren't accidentally deferred reads of the client data.
786*c8dee2aaSAndroid Build Coastguard Worker                 std::memset(vertices, 0, sizeof(vertices));
787*c8dee2aaSAndroid Build Coastguard Worker 
788*c8dee2aaSAndroid Build Coastguard Worker                 int rectCount = std::min(i + 1, kVBRects);
789*c8dee2aaSAndroid Build Coastguard Worker                 auto result = SkMesh::Make(fSpec,
790*c8dee2aaSAndroid Build Coastguard Worker                                            SkMesh::Mode::kTriangles,
791*c8dee2aaSAndroid Build Coastguard Worker                                            vb,
792*c8dee2aaSAndroid Build Coastguard Worker                                            /*vertexCount=*/6 * rectCount,
793*c8dee2aaSAndroid Build Coastguard Worker                                            /*vertexOffset=*/0,
794*c8dee2aaSAndroid Build Coastguard Worker                                            /*uniforms=*/nullptr,
795*c8dee2aaSAndroid Build Coastguard Worker                                            /*children=*/{},
796*c8dee2aaSAndroid Build Coastguard Worker                                            bounds);
797*c8dee2aaSAndroid Build Coastguard Worker 
798*c8dee2aaSAndroid Build Coastguard Worker                 if (!result.mesh.isValid()) {
799*c8dee2aaSAndroid Build Coastguard Worker                     SkDebugf("Mesh creation failed: %s\n", result.error.c_str());
800*c8dee2aaSAndroid Build Coastguard Worker                     return DrawResult::kFail;
801*c8dee2aaSAndroid Build Coastguard Worker                 }
802*c8dee2aaSAndroid Build Coastguard Worker 
803*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawMesh(result.mesh, SkBlender::Mode(SkBlendMode::kDst), paint);
804*c8dee2aaSAndroid Build Coastguard Worker 
805*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(0, r.height() + 10);
806*c8dee2aaSAndroid Build Coastguard Worker             }
807*c8dee2aaSAndroid Build Coastguard Worker 
808*c8dee2aaSAndroid Build Coastguard Worker             // Now test updating an IB.
809*c8dee2aaSAndroid Build Coastguard Worker 
810*c8dee2aaSAndroid Build Coastguard Worker             // How many rects worth of storage is in the index buffer?
811*c8dee2aaSAndroid Build Coastguard Worker             static constexpr int kIBRects = 2;
812*c8dee2aaSAndroid Build Coastguard Worker 
813*c8dee2aaSAndroid Build Coastguard Worker             // How many times do we update the index buffer? Wraps to start of buffer if > kIBRects.
814*c8dee2aaSAndroid Build Coastguard Worker             static constexpr int kNumIBUpdates = 3;
815*c8dee2aaSAndroid Build Coastguard Worker 
816*c8dee2aaSAndroid Build Coastguard Worker             // Make the vertex buffer large enough to hold all the rects and populate.
817*c8dee2aaSAndroid Build Coastguard Worker             vb = make_vertex_buffer(ctx, /*data=*/nullptr, kNumIBUpdates * 4 * sizeof(Vertex));
818*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(vb);
819*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < kNumIBUpdates; ++i) {
820*c8dee2aaSAndroid Build Coastguard Worker                 SkPoint p[4];
821*c8dee2aaSAndroid Build Coastguard Worker                 auto rect = r.makeOffset(100*i, 0);
822*c8dee2aaSAndroid Build Coastguard Worker                 rect.toQuad(p);
823*c8dee2aaSAndroid Build Coastguard Worker                 if (i) {
824*c8dee2aaSAndroid Build Coastguard Worker                     bounds.join(rect);
825*c8dee2aaSAndroid Build Coastguard Worker                 } else {
826*c8dee2aaSAndroid Build Coastguard Worker                     bounds = rect;
827*c8dee2aaSAndroid Build Coastguard Worker                 }
828*c8dee2aaSAndroid Build Coastguard Worker 
829*c8dee2aaSAndroid Build Coastguard Worker                 SkPoint t[4];
830*c8dee2aaSAndroid Build Coastguard Worker                 SkRect::MakeWH(2.f, 2.f).toQuad(t);
831*c8dee2aaSAndroid Build Coastguard Worker                 SkMatrix::RotateDeg(90.f*i, {1.f, 1.f}).mapPoints(t, std::size(t));
832*c8dee2aaSAndroid Build Coastguard Worker                 Vertex vertices[4]{{p[0], t[0]}, {p[1], t[1]}, {p[2], t[2]}, {p[3], t[3]}};
833*c8dee2aaSAndroid Build Coastguard Worker                 SkAssertResult(
834*c8dee2aaSAndroid Build Coastguard Worker                         vb->update(ctx, vertices, i*4*sizeof(Vertex), 4*sizeof(Vertex)));
835*c8dee2aaSAndroid Build Coastguard Worker             }
836*c8dee2aaSAndroid Build Coastguard Worker 
837*c8dee2aaSAndroid Build Coastguard Worker             auto ib = make_index_buffer(
838*c8dee2aaSAndroid Build Coastguard Worker                     ctx, /*data=*/nullptr, kIBRects * 6 * sizeof(uint16_t));
839*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(ib);
840*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < kNumIBUpdates; ++i) {
841*c8dee2aaSAndroid Build Coastguard Worker                 uint16_t indices[6] = {SkToU16(0 + 4*i),
842*c8dee2aaSAndroid Build Coastguard Worker                                        SkToU16(3 + 4*i),
843*c8dee2aaSAndroid Build Coastguard Worker                                        SkToU16(1 + 4*i),
844*c8dee2aaSAndroid Build Coastguard Worker                                        SkToU16(1 + 4*i),
845*c8dee2aaSAndroid Build Coastguard Worker                                        SkToU16(3 + 4*i),
846*c8dee2aaSAndroid Build Coastguard Worker                                        SkToU16(2 + 4*i)};
847*c8dee2aaSAndroid Build Coastguard Worker                 size_t offset = 6*(i % kIBRects)*sizeof(uint16_t);
848*c8dee2aaSAndroid Build Coastguard Worker                 SkAssertResult(ib->update(ctx, indices, offset, 6*sizeof(uint16_t)));
849*c8dee2aaSAndroid Build Coastguard Worker                 std::memset(indices, 0, 6*sizeof(uint16_t));
850*c8dee2aaSAndroid Build Coastguard Worker 
851*c8dee2aaSAndroid Build Coastguard Worker                 auto result = SkMesh::MakeIndexed(fSpec,
852*c8dee2aaSAndroid Build Coastguard Worker                                                   SkMesh::Mode::kTriangles,
853*c8dee2aaSAndroid Build Coastguard Worker                                                   vb,
854*c8dee2aaSAndroid Build Coastguard Worker                                                   /*vertexCount=*/4 * kNumIBUpdates,
855*c8dee2aaSAndroid Build Coastguard Worker                                                   /*vertexOffset=*/0,
856*c8dee2aaSAndroid Build Coastguard Worker                                                   ib,
857*c8dee2aaSAndroid Build Coastguard Worker                                                   /*indexCount=*/6,
858*c8dee2aaSAndroid Build Coastguard Worker                                                   /*indexOffset=*/offset,
859*c8dee2aaSAndroid Build Coastguard Worker                                                   /*uniforms=*/nullptr,
860*c8dee2aaSAndroid Build Coastguard Worker                                                   /*children=*/{},
861*c8dee2aaSAndroid Build Coastguard Worker                                                   bounds);
862*c8dee2aaSAndroid Build Coastguard Worker 
863*c8dee2aaSAndroid Build Coastguard Worker                 if (!result.mesh.isValid()) {
864*c8dee2aaSAndroid Build Coastguard Worker                     SkDebugf("Mesh creation failed: %s\n", result.error.c_str());
865*c8dee2aaSAndroid Build Coastguard Worker                     return DrawResult::kFail;
866*c8dee2aaSAndroid Build Coastguard Worker                 }
867*c8dee2aaSAndroid Build Coastguard Worker 
868*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawMesh(result.mesh, SkBlender::Mode(SkBlendMode::kDst), paint);
869*c8dee2aaSAndroid Build Coastguard Worker             }
870*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(0, r.height() + 10);
871*c8dee2aaSAndroid Build Coastguard Worker         }
872*c8dee2aaSAndroid Build Coastguard Worker 
873*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
874*c8dee2aaSAndroid Build Coastguard Worker     }
875*c8dee2aaSAndroid Build Coastguard Worker 
876*c8dee2aaSAndroid Build Coastguard Worker private:
877*c8dee2aaSAndroid Build Coastguard Worker     struct Vertex {
878*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pos;
879*c8dee2aaSAndroid Build Coastguard Worker         SkPoint tex;
880*c8dee2aaSAndroid Build Coastguard Worker     };
881*c8dee2aaSAndroid Build Coastguard Worker 
882*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMeshSpecification> fSpec;
883*c8dee2aaSAndroid Build Coastguard Worker 
884*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader;
885*c8dee2aaSAndroid Build Coastguard Worker };
886*c8dee2aaSAndroid Build Coastguard Worker 
887*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MeshUpdateGM())
888*c8dee2aaSAndroid Build Coastguard Worker 
889*c8dee2aaSAndroid Build Coastguard Worker class MeshZeroInitGM : public skiagm::GM {
890*c8dee2aaSAndroid Build Coastguard Worker public:
891*c8dee2aaSAndroid Build Coastguard Worker     MeshZeroInitGM() = default;
892*c8dee2aaSAndroid Build Coastguard Worker 
893*c8dee2aaSAndroid Build Coastguard Worker protected:
894*c8dee2aaSAndroid Build Coastguard Worker     using Attribute = SkMeshSpecification::Attribute;
895*c8dee2aaSAndroid Build Coastguard Worker     using Varying   = SkMeshSpecification::Varying;
896*c8dee2aaSAndroid Build Coastguard Worker 
getISize()897*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {90, 30}; }
898*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()899*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
900*c8dee2aaSAndroid Build Coastguard Worker         static const Attribute kAttributes1[]{
901*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kUByte4_unorm, 0, SkString{"color"}},
902*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat2,       4, SkString{"pos"  }},
903*c8dee2aaSAndroid Build Coastguard Worker         };
904*c8dee2aaSAndroid Build Coastguard Worker         static const Attribute kAttributes2[]{
905*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat2,       0, SkString{"pos"  }},
906*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kUByte4_unorm, 8, SkString{"color"}},
907*c8dee2aaSAndroid Build Coastguard Worker         };
908*c8dee2aaSAndroid Build Coastguard Worker         static const Varying kVaryings[]{{Varying::Type::kHalf4, SkString{"color"}}};
909*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kVS[] = R"(
910*c8dee2aaSAndroid Build Coastguard Worker                 Varyings main(const in Attributes attributes) {
911*c8dee2aaSAndroid Build Coastguard Worker                     Varyings varyings;
912*c8dee2aaSAndroid Build Coastguard Worker                     varyings.color    = attributes.color;
913*c8dee2aaSAndroid Build Coastguard Worker                     varyings.position = attributes.pos;
914*c8dee2aaSAndroid Build Coastguard Worker                     return varyings;
915*c8dee2aaSAndroid Build Coastguard Worker                 }
916*c8dee2aaSAndroid Build Coastguard Worker         )";
917*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kFS[] = R"(
918*c8dee2aaSAndroid Build Coastguard Worker                 float2 main(const Varyings varyings, out half4 color) {
919*c8dee2aaSAndroid Build Coastguard Worker                     color = varyings.color;
920*c8dee2aaSAndroid Build Coastguard Worker                     return varyings.position;
921*c8dee2aaSAndroid Build Coastguard Worker                 }
922*c8dee2aaSAndroid Build Coastguard Worker         )";
923*c8dee2aaSAndroid Build Coastguard Worker         auto result = SkMeshSpecification::Make(kAttributes1,
924*c8dee2aaSAndroid Build Coastguard Worker                                                 /*vertexStride==*/12,
925*c8dee2aaSAndroid Build Coastguard Worker                                                 kVaryings,
926*c8dee2aaSAndroid Build Coastguard Worker                                                 SkString(kVS),
927*c8dee2aaSAndroid Build Coastguard Worker                                                 SkString(kFS),
928*c8dee2aaSAndroid Build Coastguard Worker                                                 SkColorSpace::MakeSRGB(),
929*c8dee2aaSAndroid Build Coastguard Worker                                                 kPremul_SkAlphaType);
930*c8dee2aaSAndroid Build Coastguard Worker         if (!result.specification) {
931*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("%s\n", result.error.c_str());
932*c8dee2aaSAndroid Build Coastguard Worker         }
933*c8dee2aaSAndroid Build Coastguard Worker         fSpec[0] = std::move(result.specification);
934*c8dee2aaSAndroid Build Coastguard Worker 
935*c8dee2aaSAndroid Build Coastguard Worker         result = SkMeshSpecification::Make(kAttributes1,
936*c8dee2aaSAndroid Build Coastguard Worker                                            /*vertexStride=*/12,
937*c8dee2aaSAndroid Build Coastguard Worker                                            kVaryings,
938*c8dee2aaSAndroid Build Coastguard Worker                                            SkString(kVS),
939*c8dee2aaSAndroid Build Coastguard Worker                                            SkString(kFS),
940*c8dee2aaSAndroid Build Coastguard Worker                                            SkColorSpace::MakeSRGB(),
941*c8dee2aaSAndroid Build Coastguard Worker                                            kPremul_SkAlphaType);
942*c8dee2aaSAndroid Build Coastguard Worker         if (!result.specification) {
943*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("%s\n", result.error.c_str());
944*c8dee2aaSAndroid Build Coastguard Worker         }
945*c8dee2aaSAndroid Build Coastguard Worker         fSpec[1] = std::move(result.specification);
946*c8dee2aaSAndroid Build Coastguard Worker     }
947*c8dee2aaSAndroid Build Coastguard Worker 
getName() const948*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("mesh_zero_init"); }
949*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * error)950*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* error) override {
951*c8dee2aaSAndroid Build Coastguard Worker         GrRecordingContext* rc = canvas->recordingContext();
952*c8dee2aaSAndroid Build Coastguard Worker         GrDirectContext* dc = GrAsDirectContext(rc);
953*c8dee2aaSAndroid Build Coastguard Worker         if (rc && !dc) {
954*c8dee2aaSAndroid Build Coastguard Worker             // On GPU this relies on using the DC to update the GPU backed vertex/index buffers.
955*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
956*c8dee2aaSAndroid Build Coastguard Worker         }
957*c8dee2aaSAndroid Build Coastguard Worker 
958*c8dee2aaSAndroid Build Coastguard Worker         if (dc && dc->abandoned()) {
959*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
960*c8dee2aaSAndroid Build Coastguard Worker         }
961*c8dee2aaSAndroid Build Coastguard Worker 
962*c8dee2aaSAndroid Build Coastguard Worker         static constexpr SkPoint kTri[]{{10, 10}, {20, 10}, {10, 20}};
963*c8dee2aaSAndroid Build Coastguard Worker         // The zero will come from the uninit part of the buffer.
964*c8dee2aaSAndroid Build Coastguard Worker         static constexpr uint16_t kTiIndices[]{1, 2};
965*c8dee2aaSAndroid Build Coastguard Worker 
966*c8dee2aaSAndroid Build Coastguard Worker         // We test updating CPU and GPU buffers.
967*c8dee2aaSAndroid Build Coastguard Worker         for (bool gpuBuffer : {false, true}) {
968*c8dee2aaSAndroid Build Coastguard Worker             auto ctx = gpuBuffer ? dc : nullptr;
969*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < 2; ++i) {
970*c8dee2aaSAndroid Build Coastguard Worker                 const auto& spec = fSpec[i];
971*c8dee2aaSAndroid Build Coastguard Worker 
972*c8dee2aaSAndroid Build Coastguard Worker                 size_t posOffset = spec->findAttribute("pos")->offset;
973*c8dee2aaSAndroid Build Coastguard Worker                 auto vb = make_vertex_buffer(ctx, nullptr, spec->stride() * std::size(kTri));
974*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(vb);
975*c8dee2aaSAndroid Build Coastguard Worker                 for (size_t j = 0; j < std::size(kTri); ++j) {
976*c8dee2aaSAndroid Build Coastguard Worker                     SkAssertResult(vb->update(ctx,
977*c8dee2aaSAndroid Build Coastguard Worker                                               &kTri[j],
978*c8dee2aaSAndroid Build Coastguard Worker                                               spec->stride()*j + posOffset,
979*c8dee2aaSAndroid Build Coastguard Worker                                               sizeof(kTri[j])));
980*c8dee2aaSAndroid Build Coastguard Worker                 }
981*c8dee2aaSAndroid Build Coastguard Worker 
982*c8dee2aaSAndroid Build Coastguard Worker                 // The first time we make the indices be 0,1,2 using the zero'ed buffer for the
983*c8dee2aaSAndroid Build Coastguard Worker                 // first. However, because uploads must be 4 byte aligned it's actually 0,0,1,2.
984*c8dee2aaSAndroid Build Coastguard Worker                 // The second time we upload 1,2 to beginning of the buffer to form 1,2,0.
985*c8dee2aaSAndroid Build Coastguard Worker                 size_t indexUploadOffset = i == 0 ? 4 : 0;
986*c8dee2aaSAndroid Build Coastguard Worker                 size_t indexMeshOffset   = i == 0 ? 2 : 0;
987*c8dee2aaSAndroid Build Coastguard Worker 
988*c8dee2aaSAndroid Build Coastguard Worker                 auto ib = make_index_buffer(ctx, nullptr, sizeof(uint16_t) * 4);
989*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(ib);
990*c8dee2aaSAndroid Build Coastguard Worker                 SkAssertResult(ib->update(ctx, kTiIndices, indexUploadOffset, sizeof(kTiIndices)));
991*c8dee2aaSAndroid Build Coastguard Worker 
992*c8dee2aaSAndroid Build Coastguard Worker                 SkRect bounds;
993*c8dee2aaSAndroid Build Coastguard Worker                 bounds.setBounds(kTri, std::size(kTri));
994*c8dee2aaSAndroid Build Coastguard Worker                 auto result = SkMesh::MakeIndexed(spec,
995*c8dee2aaSAndroid Build Coastguard Worker                                                   SkMesh::Mode::kTriangles,
996*c8dee2aaSAndroid Build Coastguard Worker                                                   std::move(vb),
997*c8dee2aaSAndroid Build Coastguard Worker                                                   /*vertexCount=*/std::size(kTri),
998*c8dee2aaSAndroid Build Coastguard Worker                                                   /*vertexOffset=*/0,
999*c8dee2aaSAndroid Build Coastguard Worker                                                   std::move(ib),
1000*c8dee2aaSAndroid Build Coastguard Worker                                                   /*indexCount=*/std::size(kTiIndices) + 1,
1001*c8dee2aaSAndroid Build Coastguard Worker                                                   indexMeshOffset,
1002*c8dee2aaSAndroid Build Coastguard Worker                                                   /*uniforms=*/nullptr,
1003*c8dee2aaSAndroid Build Coastguard Worker                                                   /*children=*/{},
1004*c8dee2aaSAndroid Build Coastguard Worker                                                   bounds);
1005*c8dee2aaSAndroid Build Coastguard Worker                 if (!result.mesh.isValid()) {
1006*c8dee2aaSAndroid Build Coastguard Worker                     SkDebugf("Mesh creation failed: %s\n", result.error.c_str());
1007*c8dee2aaSAndroid Build Coastguard Worker                     return DrawResult::kFail;
1008*c8dee2aaSAndroid Build Coastguard Worker                 }
1009*c8dee2aaSAndroid Build Coastguard Worker 
1010*c8dee2aaSAndroid Build Coastguard Worker                 SkPaint paint;
1011*c8dee2aaSAndroid Build Coastguard Worker                 // The color will be transparent black. Set the blender to kDstOver so when combined
1012*c8dee2aaSAndroid Build Coastguard Worker                 // with the paint's opaque black we get opaque black.
1013*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawMesh(result.mesh, SkBlender::Mode(SkBlendMode::kDstOver), paint);
1014*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(bounds.width() + 10, 0);
1015*c8dee2aaSAndroid Build Coastguard Worker                 if (ctx) {
1016*c8dee2aaSAndroid Build Coastguard Worker                     // Free up the buffers for recycling in the cache. This helps test that
1017*c8dee2aaSAndroid Build Coastguard Worker                     // a recycled buffer gets zero'ed.
1018*c8dee2aaSAndroid Build Coastguard Worker                     result.mesh = {};
1019*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(!ib);  // NOLINT - bugprone-use-after-move. We're asserting it's moved.
1020*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(!vb);  // NOLINT
1021*c8dee2aaSAndroid Build Coastguard Worker                     ctx->flushAndSubmit(GrSyncCpu::kYes);
1022*c8dee2aaSAndroid Build Coastguard Worker                 }
1023*c8dee2aaSAndroid Build Coastguard Worker             }
1024*c8dee2aaSAndroid Build Coastguard Worker         }
1025*c8dee2aaSAndroid Build Coastguard Worker 
1026*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
1027*c8dee2aaSAndroid Build Coastguard Worker     }
1028*c8dee2aaSAndroid Build Coastguard Worker 
1029*c8dee2aaSAndroid Build Coastguard Worker private:
1030*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMeshSpecification> fSpec[2];
1031*c8dee2aaSAndroid Build Coastguard Worker };
1032*c8dee2aaSAndroid Build Coastguard Worker 
1033*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MeshZeroInitGM())
1034*c8dee2aaSAndroid Build Coastguard Worker 
1035*c8dee2aaSAndroid Build Coastguard Worker // We have a special GM for testing SkMesh through SkPicture because all of SkPicture GM testing
1036*c8dee2aaSAndroid Build Coastguard Worker // uses the CPU backend and SkMesh only works on GPU.
1037*c8dee2aaSAndroid Build Coastguard Worker class PictureMesh : public skiagm::GM {
1038*c8dee2aaSAndroid Build Coastguard Worker public:
1039*c8dee2aaSAndroid Build Coastguard Worker     PictureMesh() = default;
1040*c8dee2aaSAndroid Build Coastguard Worker 
1041*c8dee2aaSAndroid Build Coastguard Worker protected:
1042*c8dee2aaSAndroid Build Coastguard Worker     using Attribute = SkMeshSpecification::Attribute;
1043*c8dee2aaSAndroid Build Coastguard Worker     using Varying   = SkMeshSpecification::Varying;
1044*c8dee2aaSAndroid Build Coastguard Worker 
getISize()1045*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {390, 90}; }
1046*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()1047*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
1048*c8dee2aaSAndroid Build Coastguard Worker         static const Attribute kAttributes[]{
1049*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat2, 0, SkString{"pos"}},
1050*c8dee2aaSAndroid Build Coastguard Worker         };
1051*c8dee2aaSAndroid Build Coastguard Worker         static const Varying kVaryings[]{
1052*c8dee2aaSAndroid Build Coastguard Worker                 {Varying::Type::kFloat2, SkString{"coords"}},
1053*c8dee2aaSAndroid Build Coastguard Worker         };
1054*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kVS[] = R"(
1055*c8dee2aaSAndroid Build Coastguard Worker                 Varyings main(in const Attributes attributes) {
1056*c8dee2aaSAndroid Build Coastguard Worker                     Varyings varyings;
1057*c8dee2aaSAndroid Build Coastguard Worker                     varyings.position = attributes.pos;
1058*c8dee2aaSAndroid Build Coastguard Worker                     return varyings;
1059*c8dee2aaSAndroid Build Coastguard Worker                 }
1060*c8dee2aaSAndroid Build Coastguard Worker         )";
1061*c8dee2aaSAndroid Build Coastguard Worker         static const SkString kFS = SkStringPrintf(R"(
1062*c8dee2aaSAndroid Build Coastguard Worker                 uniform float2 offset;
1063*c8dee2aaSAndroid Build Coastguard Worker                 float2 main(const Varyings varyings, out float4 color) {
1064*c8dee2aaSAndroid Build Coastguard Worker                     float2 tl = float2(%f, %f);
1065*c8dee2aaSAndroid Build Coastguard Worker                     float2 wh = float2(%f, %f);
1066*c8dee2aaSAndroid Build Coastguard Worker                     float2 c = tl + wh/2;
1067*c8dee2aaSAndroid Build Coastguard Worker                     float  r = length(wh)/4;
1068*c8dee2aaSAndroid Build Coastguard Worker                     color.rba = float3(1);
1069*c8dee2aaSAndroid Build Coastguard Worker                     color.g = min(1, length(varyings.position - c + offset) / r);
1070*c8dee2aaSAndroid Build Coastguard Worker                     return varyings.position;
1071*c8dee2aaSAndroid Build Coastguard Worker                 }
1072*c8dee2aaSAndroid Build Coastguard Worker         )", kRect.x(), kRect.y(), kRect.width(), kRect.height());
1073*c8dee2aaSAndroid Build Coastguard Worker         auto [spec, error] =
1074*c8dee2aaSAndroid Build Coastguard Worker                 SkMeshSpecification::Make(kAttributes,
1075*c8dee2aaSAndroid Build Coastguard Worker                                           sizeof(Vertex),
1076*c8dee2aaSAndroid Build Coastguard Worker                                           kVaryings,
1077*c8dee2aaSAndroid Build Coastguard Worker                                           SkString(kVS),
1078*c8dee2aaSAndroid Build Coastguard Worker                                           kFS,
1079*c8dee2aaSAndroid Build Coastguard Worker                                           SkColorSpace::MakeSRGB()->makeColorSpin(),
1080*c8dee2aaSAndroid Build Coastguard Worker                                           kPremul_SkAlphaType);
1081*c8dee2aaSAndroid Build Coastguard Worker         if (!spec) {
1082*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("%s\n", error.c_str());
1083*c8dee2aaSAndroid Build Coastguard Worker         }
1084*c8dee2aaSAndroid Build Coastguard Worker         fSpec = std::move(spec);
1085*c8dee2aaSAndroid Build Coastguard Worker 
1086*c8dee2aaSAndroid Build Coastguard Worker         fVB = SkMeshes::MakeVertexBuffer(kQuad, sizeof(kQuad));
1087*c8dee2aaSAndroid Build Coastguard Worker         fIB = SkMeshes::MakeIndexBuffer(kIndices, sizeof(kIndices));
1088*c8dee2aaSAndroid Build Coastguard Worker 
1089*c8dee2aaSAndroid Build Coastguard Worker         SkRandom random;
1090*c8dee2aaSAndroid Build Coastguard Worker         SkColor4f colors[6];
1091*c8dee2aaSAndroid Build Coastguard Worker         for (size_t i = 0; i < std::size(colors) - 1; ++i) {
1092*c8dee2aaSAndroid Build Coastguard Worker             colors[i] = {random.nextF(), random.nextF(), random.nextF(), 1.f};
1093*c8dee2aaSAndroid Build Coastguard Worker         }
1094*c8dee2aaSAndroid Build Coastguard Worker         colors[std::size(colors) - 1] = colors[0];
1095*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
1096*c8dee2aaSAndroid Build Coastguard Worker         SkGradientShader::Interpolation interpolation;
1097*c8dee2aaSAndroid Build Coastguard Worker         interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kHSL;
1098*c8dee2aaSAndroid Build Coastguard Worker         fShader = SkGradientShader::MakeSweep(kRect.centerX(), kRect.centerY(),
1099*c8dee2aaSAndroid Build Coastguard Worker                                               colors,
1100*c8dee2aaSAndroid Build Coastguard Worker                                               SkColorSpace::MakeSRGB(),
1101*c8dee2aaSAndroid Build Coastguard Worker                                               nullptr,
1102*c8dee2aaSAndroid Build Coastguard Worker                                               std::size(colors),
1103*c8dee2aaSAndroid Build Coastguard Worker                                               SkTileMode::kRepeat,
1104*c8dee2aaSAndroid Build Coastguard Worker                                               0,
1105*c8dee2aaSAndroid Build Coastguard Worker                                               360.f,
1106*c8dee2aaSAndroid Build Coastguard Worker                                               interpolation,
1107*c8dee2aaSAndroid Build Coastguard Worker                                               /*localMatrix=*/nullptr);
1108*c8dee2aaSAndroid Build Coastguard Worker     }
1109*c8dee2aaSAndroid Build Coastguard Worker 
getName() const1110*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("picture_mesh"); }
1111*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * error)1112*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* error) override {
1113*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
1114*c8dee2aaSAndroid Build Coastguard Worker         paint.setShader(fShader);
1115*c8dee2aaSAndroid Build Coastguard Worker 
1116*c8dee2aaSAndroid Build Coastguard Worker         auto dc = GrAsDirectContext(canvas->recordingContext());
1117*c8dee2aaSAndroid Build Coastguard Worker         for (bool picture : {false, true}) {
1118*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
1119*c8dee2aaSAndroid Build Coastguard Worker             for (bool gpu : {false, true}) {
1120*c8dee2aaSAndroid Build Coastguard Worker                 auto vb = gpu ? SkMeshes::CopyVertexBuffer(dc, fVB) : fVB;
1121*c8dee2aaSAndroid Build Coastguard Worker                 auto ib = gpu ? SkMeshes::CopyIndexBuffer (dc, fIB) : fIB;
1122*c8dee2aaSAndroid Build Coastguard Worker 
1123*c8dee2aaSAndroid Build Coastguard Worker                 float offset[2] = {8, 8};
1124*c8dee2aaSAndroid Build Coastguard Worker                 for (size_t i = 0; i < 4; ++i) {
1125*c8dee2aaSAndroid Build Coastguard Worker                     auto uniforms = SkData::MakeWithCopy(&offset, sizeof(offset));
1126*c8dee2aaSAndroid Build Coastguard Worker                     SkMesh::Result r;
1127*c8dee2aaSAndroid Build Coastguard Worker                     switch (i) {
1128*c8dee2aaSAndroid Build Coastguard Worker                         case 0:
1129*c8dee2aaSAndroid Build Coastguard Worker                             r = SkMesh::Make(fSpec,
1130*c8dee2aaSAndroid Build Coastguard Worker                                              SkMesh::Mode::kTriangles,
1131*c8dee2aaSAndroid Build Coastguard Worker                                              fVB,
1132*c8dee2aaSAndroid Build Coastguard Worker                                              6,
1133*c8dee2aaSAndroid Build Coastguard Worker                                              1 * sizeof(Vertex),
1134*c8dee2aaSAndroid Build Coastguard Worker                                              std::move(uniforms),
1135*c8dee2aaSAndroid Build Coastguard Worker                                              /*children=*/{},
1136*c8dee2aaSAndroid Build Coastguard Worker                                              kRect);
1137*c8dee2aaSAndroid Build Coastguard Worker                             break;
1138*c8dee2aaSAndroid Build Coastguard Worker                         case 1:
1139*c8dee2aaSAndroid Build Coastguard Worker                             r = SkMesh::Make(fSpec,
1140*c8dee2aaSAndroid Build Coastguard Worker                                              SkMesh::Mode::kTriangleStrip,
1141*c8dee2aaSAndroid Build Coastguard Worker                                              fVB,
1142*c8dee2aaSAndroid Build Coastguard Worker                                              4,
1143*c8dee2aaSAndroid Build Coastguard Worker                                              1 * sizeof(Vertex),
1144*c8dee2aaSAndroid Build Coastguard Worker                                              std::move(uniforms),
1145*c8dee2aaSAndroid Build Coastguard Worker                                              /*children=*/{},
1146*c8dee2aaSAndroid Build Coastguard Worker                                              kRect);
1147*c8dee2aaSAndroid Build Coastguard Worker                             break;
1148*c8dee2aaSAndroid Build Coastguard Worker                         case 2:
1149*c8dee2aaSAndroid Build Coastguard Worker                             r = SkMesh::MakeIndexed(fSpec,
1150*c8dee2aaSAndroid Build Coastguard Worker                                                     SkMesh::Mode::kTriangles,
1151*c8dee2aaSAndroid Build Coastguard Worker                                                     fVB,
1152*c8dee2aaSAndroid Build Coastguard Worker                                                     std::size(kQuad),
1153*c8dee2aaSAndroid Build Coastguard Worker                                                     0,
1154*c8dee2aaSAndroid Build Coastguard Worker                                                     fIB,
1155*c8dee2aaSAndroid Build Coastguard Worker                                                     6,
1156*c8dee2aaSAndroid Build Coastguard Worker                                                     2 * (sizeof(uint16_t)),
1157*c8dee2aaSAndroid Build Coastguard Worker                                                     std::move(uniforms),
1158*c8dee2aaSAndroid Build Coastguard Worker                                                     /*children=*/{},
1159*c8dee2aaSAndroid Build Coastguard Worker                                                     kRect);
1160*c8dee2aaSAndroid Build Coastguard Worker                             break;
1161*c8dee2aaSAndroid Build Coastguard Worker                         case 3:
1162*c8dee2aaSAndroid Build Coastguard Worker                             r = SkMesh::MakeIndexed(fSpec,
1163*c8dee2aaSAndroid Build Coastguard Worker                                                     SkMesh::Mode::kTriangleStrip,
1164*c8dee2aaSAndroid Build Coastguard Worker                                                     fVB,
1165*c8dee2aaSAndroid Build Coastguard Worker                                                     std::size(kQuad),
1166*c8dee2aaSAndroid Build Coastguard Worker                                                     0,
1167*c8dee2aaSAndroid Build Coastguard Worker                                                     fIB,
1168*c8dee2aaSAndroid Build Coastguard Worker                                                     6,
1169*c8dee2aaSAndroid Build Coastguard Worker                                                     2 * sizeof(uint16_t),
1170*c8dee2aaSAndroid Build Coastguard Worker                                                     std::move(uniforms),
1171*c8dee2aaSAndroid Build Coastguard Worker                                                     /*children=*/{},
1172*c8dee2aaSAndroid Build Coastguard Worker                                                     kRect);
1173*c8dee2aaSAndroid Build Coastguard Worker                             break;
1174*c8dee2aaSAndroid Build Coastguard Worker                     }
1175*c8dee2aaSAndroid Build Coastguard Worker 
1176*c8dee2aaSAndroid Build Coastguard Worker                     if (!r.mesh.isValid()) {
1177*c8dee2aaSAndroid Build Coastguard Worker                         *error = r.error;
1178*c8dee2aaSAndroid Build Coastguard Worker                         return DrawResult::kFail;
1179*c8dee2aaSAndroid Build Coastguard Worker                     }
1180*c8dee2aaSAndroid Build Coastguard Worker 
1181*c8dee2aaSAndroid Build Coastguard Worker                     auto draw = [&](SkCanvas* c) {
1182*c8dee2aaSAndroid Build Coastguard Worker                         c->drawMesh(r.mesh, SkBlender::Mode(SkBlendMode::kDifference), paint);
1183*c8dee2aaSAndroid Build Coastguard Worker                     };
1184*c8dee2aaSAndroid Build Coastguard Worker                     if (picture) {
1185*c8dee2aaSAndroid Build Coastguard Worker                         SkPictureRecorder recorder;
1186*c8dee2aaSAndroid Build Coastguard Worker                         draw(recorder.beginRecording(SkRect::Make(this->getISize()),
1187*c8dee2aaSAndroid Build Coastguard Worker                                                      /*bbhFactory=*/nullptr));
1188*c8dee2aaSAndroid Build Coastguard Worker                         canvas->drawPicture(recorder.finishRecordingAsPicture());
1189*c8dee2aaSAndroid Build Coastguard Worker                     } else {
1190*c8dee2aaSAndroid Build Coastguard Worker                         draw(canvas);
1191*c8dee2aaSAndroid Build Coastguard Worker                     }
1192*c8dee2aaSAndroid Build Coastguard Worker                     offset[i%2] *= -1;
1193*c8dee2aaSAndroid Build Coastguard Worker                     canvas->translate(kRect.width() + 10, 0);
1194*c8dee2aaSAndroid Build Coastguard Worker                 }
1195*c8dee2aaSAndroid Build Coastguard Worker             }
1196*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
1197*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(0, kRect.height() + 10);
1198*c8dee2aaSAndroid Build Coastguard Worker         }
1199*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
1200*c8dee2aaSAndroid Build Coastguard Worker     }
1201*c8dee2aaSAndroid Build Coastguard Worker 
1202*c8dee2aaSAndroid Build Coastguard Worker private:
1203*c8dee2aaSAndroid Build Coastguard Worker     struct Vertex {
1204*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pos;
1205*c8dee2aaSAndroid Build Coastguard Worker     };
1206*c8dee2aaSAndroid Build Coastguard Worker 
1207*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kRect = SkRect::MakeWH(40, 40);
1208*c8dee2aaSAndroid Build Coastguard Worker 
1209*c8dee2aaSAndroid Build Coastguard Worker     static constexpr Vertex kQuad[] {
1210*c8dee2aaSAndroid Build Coastguard Worker             {1000, 1000},  // skip
1211*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left() , kRect.top()   }},
1212*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kRect.top()   }},
1213*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left() , kRect.bottom()}},
1214*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kRect.bottom()}},
1215*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.left() , kRect.bottom()}},
1216*c8dee2aaSAndroid Build Coastguard Worker             {{kRect.right(), kRect.top()   }},
1217*c8dee2aaSAndroid Build Coastguard Worker     };
1218*c8dee2aaSAndroid Build Coastguard Worker 
1219*c8dee2aaSAndroid Build Coastguard Worker     static constexpr uint16_t kIndices[] = {1000, 2000, 1, 2, 3, 4, 5, 6};
1220*c8dee2aaSAndroid Build Coastguard Worker 
1221*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::VertexBuffer> fVB;
1222*c8dee2aaSAndroid Build Coastguard Worker 
1223*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::IndexBuffer> fIB;
1224*c8dee2aaSAndroid Build Coastguard Worker 
1225*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMeshSpecification> fSpec;
1226*c8dee2aaSAndroid Build Coastguard Worker 
1227*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader;
1228*c8dee2aaSAndroid Build Coastguard Worker };
1229*c8dee2aaSAndroid Build Coastguard Worker 
1230*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new PictureMesh())
1231*c8dee2aaSAndroid Build Coastguard Worker 
1232*c8dee2aaSAndroid Build Coastguard Worker class MeshWithShadersGM : public skiagm::GM {
1233*c8dee2aaSAndroid Build Coastguard Worker public:
1234*c8dee2aaSAndroid Build Coastguard Worker     enum class Type {
1235*c8dee2aaSAndroid Build Coastguard Worker         kMeshWithImage,
1236*c8dee2aaSAndroid Build Coastguard Worker         kMeshWithPaintColor,
1237*c8dee2aaSAndroid Build Coastguard Worker         kMeshWithPaintImage,
1238*c8dee2aaSAndroid Build Coastguard Worker         kMeshWithEffects,
1239*c8dee2aaSAndroid Build Coastguard Worker     };
1240*c8dee2aaSAndroid Build Coastguard Worker 
MeshWithShadersGM(Type type)1241*c8dee2aaSAndroid Build Coastguard Worker     MeshWithShadersGM(Type type) : fType(type) {
1242*c8dee2aaSAndroid Build Coastguard Worker         // Create a grid of evenly spaced points for our mesh
1243*c8dee2aaSAndroid Build Coastguard Worker         this->onAnimate(0.0);
1244*c8dee2aaSAndroid Build Coastguard Worker 
1245*c8dee2aaSAndroid Build Coastguard Worker         // Create an index buffer of triangles over our point mesh.
1246*c8dee2aaSAndroid Build Coastguard Worker         for (int y = 0; y < kMeshSize - 1; ++y) {
1247*c8dee2aaSAndroid Build Coastguard Worker             for (int x = 0; x < kMeshSize - 1; ++x) {
1248*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(((y + 1) * kMeshSize + x + 1) < fVerts.size());
1249*c8dee2aaSAndroid Build Coastguard Worker 
1250*c8dee2aaSAndroid Build Coastguard Worker                 uint16_t TL =  y      * kMeshSize + x;
1251*c8dee2aaSAndroid Build Coastguard Worker                 uint16_t TR =  y      * kMeshSize + x + 1;
1252*c8dee2aaSAndroid Build Coastguard Worker                 uint16_t BL = (y + 1) * kMeshSize + x;
1253*c8dee2aaSAndroid Build Coastguard Worker                 uint16_t BR = (y + 1) * kMeshSize + x + 1;
1254*c8dee2aaSAndroid Build Coastguard Worker 
1255*c8dee2aaSAndroid Build Coastguard Worker                 fIndices.push_back(TL);
1256*c8dee2aaSAndroid Build Coastguard Worker                 fIndices.push_back(TR);
1257*c8dee2aaSAndroid Build Coastguard Worker                 fIndices.push_back(BL);
1258*c8dee2aaSAndroid Build Coastguard Worker 
1259*c8dee2aaSAndroid Build Coastguard Worker                 fIndices.push_back(BR);
1260*c8dee2aaSAndroid Build Coastguard Worker                 fIndices.push_back(BL);
1261*c8dee2aaSAndroid Build Coastguard Worker                 fIndices.push_back(TR);
1262*c8dee2aaSAndroid Build Coastguard Worker             }
1263*c8dee2aaSAndroid Build Coastguard Worker         }
1264*c8dee2aaSAndroid Build Coastguard Worker     }
1265*c8dee2aaSAndroid Build Coastguard Worker 
1266*c8dee2aaSAndroid Build Coastguard Worker protected:
1267*c8dee2aaSAndroid Build Coastguard Worker     using Attribute = SkMeshSpecification::Attribute;
1268*c8dee2aaSAndroid Build Coastguard Worker     using Varying   = SkMeshSpecification::Varying;
1269*c8dee2aaSAndroid Build Coastguard Worker 
getISize()1270*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {320, 320}; }
1271*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()1272*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
1273*c8dee2aaSAndroid Build Coastguard Worker         {
1274*c8dee2aaSAndroid Build Coastguard Worker             static const Attribute kAttributes[] = {
1275*c8dee2aaSAndroid Build Coastguard Worker                     {Attribute::Type::kFloat2, 0, SkString{"position"}},
1276*c8dee2aaSAndroid Build Coastguard Worker                     {Attribute::Type::kFloat2, 8, SkString{"uv"}},
1277*c8dee2aaSAndroid Build Coastguard Worker             };
1278*c8dee2aaSAndroid Build Coastguard Worker             static const Varying kVaryings[] = {
1279*c8dee2aaSAndroid Build Coastguard Worker                     {Varying::Type::kFloat2, SkString{"uv"}},
1280*c8dee2aaSAndroid Build Coastguard Worker             };
1281*c8dee2aaSAndroid Build Coastguard Worker             static constexpr char kVS[] = R"(
1282*c8dee2aaSAndroid Build Coastguard Worker                     Varyings main(const in Attributes attributes) {
1283*c8dee2aaSAndroid Build Coastguard Worker                         Varyings varyings;
1284*c8dee2aaSAndroid Build Coastguard Worker                         varyings.uv       = attributes.uv;
1285*c8dee2aaSAndroid Build Coastguard Worker                         varyings.position = attributes.position;
1286*c8dee2aaSAndroid Build Coastguard Worker                         return varyings;
1287*c8dee2aaSAndroid Build Coastguard Worker                     }
1288*c8dee2aaSAndroid Build Coastguard Worker             )";
1289*c8dee2aaSAndroid Build Coastguard Worker             static constexpr char kFS[] = R"(
1290*c8dee2aaSAndroid Build Coastguard Worker                     uniform shader myShader1;
1291*c8dee2aaSAndroid Build Coastguard Worker                     uniform shader myShader2;
1292*c8dee2aaSAndroid Build Coastguard Worker                     uniform colorFilter myColorFilter;
1293*c8dee2aaSAndroid Build Coastguard Worker                     uniform blender myBlend;
1294*c8dee2aaSAndroid Build Coastguard Worker 
1295*c8dee2aaSAndroid Build Coastguard Worker                     float2 main(const in Varyings varyings, out half4 color) {
1296*c8dee2aaSAndroid Build Coastguard Worker                         half4 color1 = myShader1.eval(varyings.uv);
1297*c8dee2aaSAndroid Build Coastguard Worker                         half4 color2 = myShader2.eval(varyings.uv);
1298*c8dee2aaSAndroid Build Coastguard Worker 
1299*c8dee2aaSAndroid Build Coastguard Worker                         // Apply a inverse color filter to the first image.
1300*c8dee2aaSAndroid Build Coastguard Worker                         color1 = myColorFilter.eval(color1);
1301*c8dee2aaSAndroid Build Coastguard Worker 
1302*c8dee2aaSAndroid Build Coastguard Worker                         // Fade in the second image horizontally, leveraging the UVs.
1303*c8dee2aaSAndroid Build Coastguard Worker                         color2 *= varyings.uv.x / 128.0;
1304*c8dee2aaSAndroid Build Coastguard Worker 
1305*c8dee2aaSAndroid Build Coastguard Worker                         // Combine the two images by using a blender (set to dst-over).
1306*c8dee2aaSAndroid Build Coastguard Worker                         color = myBlend.eval(color1, color2);
1307*c8dee2aaSAndroid Build Coastguard Worker 
1308*c8dee2aaSAndroid Build Coastguard Worker                         return varyings.uv;
1309*c8dee2aaSAndroid Build Coastguard Worker                     }
1310*c8dee2aaSAndroid Build Coastguard Worker             )";
1311*c8dee2aaSAndroid Build Coastguard Worker             auto [spec, error] = SkMeshSpecification::Make(kAttributes,
1312*c8dee2aaSAndroid Build Coastguard Worker                                                            sizeof(Vertex),
1313*c8dee2aaSAndroid Build Coastguard Worker                                                            kVaryings,
1314*c8dee2aaSAndroid Build Coastguard Worker                                                            SkString(kVS),
1315*c8dee2aaSAndroid Build Coastguard Worker                                                            SkString(kFS));
1316*c8dee2aaSAndroid Build Coastguard Worker             if (!spec) {
1317*c8dee2aaSAndroid Build Coastguard Worker                 SkDebugf("%s\n", error.c_str());
1318*c8dee2aaSAndroid Build Coastguard Worker             }
1319*c8dee2aaSAndroid Build Coastguard Worker             fSpec = std::move(spec);
1320*c8dee2aaSAndroid Build Coastguard Worker         }
1321*c8dee2aaSAndroid Build Coastguard Worker 
1322*c8dee2aaSAndroid Build Coastguard Worker 
1323*c8dee2aaSAndroid Build Coastguard Worker         switch (fType) {
1324*c8dee2aaSAndroid Build Coastguard Worker             case Type::kMeshWithImage: {
1325*c8dee2aaSAndroid Build Coastguard Worker                 fShader1 = ToolUtils::GetResourceAsImage("images/mandrill_128.png")
1326*c8dee2aaSAndroid Build Coastguard Worker                                    ->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
1327*c8dee2aaSAndroid Build Coastguard Worker                 fShader2 = nullptr;
1328*c8dee2aaSAndroid Build Coastguard Worker                 fColorFilter = nullptr;
1329*c8dee2aaSAndroid Build Coastguard Worker                 fBlender = nullptr;
1330*c8dee2aaSAndroid Build Coastguard Worker                 fPaintShader = nullptr;
1331*c8dee2aaSAndroid Build Coastguard Worker                 break;
1332*c8dee2aaSAndroid Build Coastguard Worker             }
1333*c8dee2aaSAndroid Build Coastguard Worker             case Type::kMeshWithEffects: {
1334*c8dee2aaSAndroid Build Coastguard Worker                 uint8_t inverseTable[256];
1335*c8dee2aaSAndroid Build Coastguard Worker                 for (int index = 0; index < 256; ++index) {
1336*c8dee2aaSAndroid Build Coastguard Worker                     inverseTable[index] = 255 - index;
1337*c8dee2aaSAndroid Build Coastguard Worker                 }
1338*c8dee2aaSAndroid Build Coastguard Worker 
1339*c8dee2aaSAndroid Build Coastguard Worker                 fShader1 = ToolUtils::GetResourceAsImage("images/mandrill_128.png")
1340*c8dee2aaSAndroid Build Coastguard Worker                                    ->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
1341*c8dee2aaSAndroid Build Coastguard Worker                 fShader2 = ToolUtils::GetResourceAsImage("images/color_wheel.png")
1342*c8dee2aaSAndroid Build Coastguard Worker                                    ->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
1343*c8dee2aaSAndroid Build Coastguard Worker                 fColorFilter = SkColorFilters::TableARGB(/*tableA=*/nullptr,
1344*c8dee2aaSAndroid Build Coastguard Worker                                                          inverseTable,
1345*c8dee2aaSAndroid Build Coastguard Worker                                                          inverseTable,
1346*c8dee2aaSAndroid Build Coastguard Worker                                                          inverseTable);
1347*c8dee2aaSAndroid Build Coastguard Worker                 fBlender = SkBlender::Mode(SkBlendMode::kDstOver);
1348*c8dee2aaSAndroid Build Coastguard Worker                 fPaintShader = nullptr;
1349*c8dee2aaSAndroid Build Coastguard Worker                 break;
1350*c8dee2aaSAndroid Build Coastguard Worker             }
1351*c8dee2aaSAndroid Build Coastguard Worker             case Type::kMeshWithPaintColor: {
1352*c8dee2aaSAndroid Build Coastguard Worker                 fShader1 = nullptr;
1353*c8dee2aaSAndroid Build Coastguard Worker                 fShader2 = ToolUtils::GetResourceAsImage("images/mandrill_128.png")
1354*c8dee2aaSAndroid Build Coastguard Worker                                    ->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
1355*c8dee2aaSAndroid Build Coastguard Worker                 fColorFilter = nullptr;
1356*c8dee2aaSAndroid Build Coastguard Worker                 fBlender = SkBlender::Mode(SkBlendMode::kDst);
1357*c8dee2aaSAndroid Build Coastguard Worker                 fPaintShader = SkShaders::Color(SK_ColorGREEN);
1358*c8dee2aaSAndroid Build Coastguard Worker                 break;
1359*c8dee2aaSAndroid Build Coastguard Worker             }
1360*c8dee2aaSAndroid Build Coastguard Worker             case Type::kMeshWithPaintImage: {
1361*c8dee2aaSAndroid Build Coastguard Worker                 fShader1 = ToolUtils::GetResourceAsImage("images/color_wheel.png")
1362*c8dee2aaSAndroid Build Coastguard Worker                                    ->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
1363*c8dee2aaSAndroid Build Coastguard Worker                 fShader2 = nullptr;
1364*c8dee2aaSAndroid Build Coastguard Worker                 fColorFilter = nullptr;
1365*c8dee2aaSAndroid Build Coastguard Worker                 fBlender = nullptr;
1366*c8dee2aaSAndroid Build Coastguard Worker                 fPaintShader = ToolUtils::GetResourceAsImage("images/mandrill_128.png")
1367*c8dee2aaSAndroid Build Coastguard Worker                                        ->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
1368*c8dee2aaSAndroid Build Coastguard Worker                 break;
1369*c8dee2aaSAndroid Build Coastguard Worker             }
1370*c8dee2aaSAndroid Build Coastguard Worker             default:
1371*c8dee2aaSAndroid Build Coastguard Worker                 SkUNREACHABLE;
1372*c8dee2aaSAndroid Build Coastguard Worker         }
1373*c8dee2aaSAndroid Build Coastguard Worker     }
1374*c8dee2aaSAndroid Build Coastguard Worker 
onGpuSetup(SkCanvas * canvas,SkString * string,GraphiteTestContext *)1375*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onGpuSetup(SkCanvas* canvas, SkString* string, GraphiteTestContext*) override {
1376*c8dee2aaSAndroid Build Coastguard Worker         auto dc = GrAsDirectContext(canvas->recordingContext());
1377*c8dee2aaSAndroid Build Coastguard Worker         this->ensureBuffers();
1378*c8dee2aaSAndroid Build Coastguard Worker         if (!dc || dc->abandoned()) {
1379*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kOk;
1380*c8dee2aaSAndroid Build Coastguard Worker         }
1381*c8dee2aaSAndroid Build Coastguard Worker 
1382*c8dee2aaSAndroid Build Coastguard Worker         fVB = SkMeshes::CopyVertexBuffer(dc, fVB);
1383*c8dee2aaSAndroid Build Coastguard Worker         fIB = SkMeshes::CopyIndexBuffer (dc, fIB);
1384*c8dee2aaSAndroid Build Coastguard Worker         return (!fVB || !fIB) ? DrawResult::kFail
1385*c8dee2aaSAndroid Build Coastguard Worker                               : DrawResult::kOk;
1386*c8dee2aaSAndroid Build Coastguard Worker     }
1387*c8dee2aaSAndroid Build Coastguard Worker 
onGpuTeardown()1388*c8dee2aaSAndroid Build Coastguard Worker     void onGpuTeardown() override {
1389*c8dee2aaSAndroid Build Coastguard Worker         // Destroy the GPU buffers and recreate on CPU
1390*c8dee2aaSAndroid Build Coastguard Worker         fVB = nullptr;
1391*c8dee2aaSAndroid Build Coastguard Worker         fIB = nullptr;
1392*c8dee2aaSAndroid Build Coastguard Worker         this->ensureBuffers();
1393*c8dee2aaSAndroid Build Coastguard Worker     }
1394*c8dee2aaSAndroid Build Coastguard Worker 
getName() const1395*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override {
1396*c8dee2aaSAndroid Build Coastguard Worker         switch (fType) {
1397*c8dee2aaSAndroid Build Coastguard Worker             case Type::kMeshWithImage:      return SkString("mesh_with_image");
1398*c8dee2aaSAndroid Build Coastguard Worker             case Type::kMeshWithEffects:    return SkString("mesh_with_effects");
1399*c8dee2aaSAndroid Build Coastguard Worker             case Type::kMeshWithPaintColor: return SkString("mesh_with_paint_color");
1400*c8dee2aaSAndroid Build Coastguard Worker             case Type::kMeshWithPaintImage: return SkString("mesh_with_paint_image");
1401*c8dee2aaSAndroid Build Coastguard Worker             default: SkUNREACHABLE;
1402*c8dee2aaSAndroid Build Coastguard Worker         }
1403*c8dee2aaSAndroid Build Coastguard Worker     }
1404*c8dee2aaSAndroid Build Coastguard Worker 
onAnimate(double nanos)1405*c8dee2aaSAndroid Build Coastguard Worker     bool onAnimate(double nanos) override {
1406*c8dee2aaSAndroid Build Coastguard Worker         // `periodic` goes from zero to 2π every four seconds, then wraps around.
1407*c8dee2aaSAndroid Build Coastguard Worker         double periodic = nanos / 4'000'000'000.;
1408*c8dee2aaSAndroid Build Coastguard Worker         periodic -= std::floor(periodic);
1409*c8dee2aaSAndroid Build Coastguard Worker         periodic *= 2 * SK_DoublePI;
1410*c8dee2aaSAndroid Build Coastguard Worker 
1411*c8dee2aaSAndroid Build Coastguard Worker         double xOff[kMeshSize], yOff[kMeshSize];
1412*c8dee2aaSAndroid Build Coastguard Worker         for (int index = 0; index < kMeshSize; ++index) {
1413*c8dee2aaSAndroid Build Coastguard Worker             xOff[index] = std::sin(periodic) * kRippleSize;
1414*c8dee2aaSAndroid Build Coastguard Worker             yOff[index] = std::sin(periodic + 10.0) * kRippleSize;
1415*c8dee2aaSAndroid Build Coastguard Worker             periodic += 0.8;
1416*c8dee2aaSAndroid Build Coastguard Worker         }
1417*c8dee2aaSAndroid Build Coastguard Worker 
1418*c8dee2aaSAndroid Build Coastguard Worker         fVerts.clear();
1419*c8dee2aaSAndroid Build Coastguard Worker         for (int y = 0; y < kMeshSize; ++y) {
1420*c8dee2aaSAndroid Build Coastguard Worker             float yf = (float)y / (kMeshSize - 1);  // yf = 0 .. 1
1421*c8dee2aaSAndroid Build Coastguard Worker             for (int x = 0; x < kMeshSize; ++x) {
1422*c8dee2aaSAndroid Build Coastguard Worker                 float xf = (float)x / (kMeshSize - 1);  // xf = 0 .. 1
1423*c8dee2aaSAndroid Build Coastguard Worker 
1424*c8dee2aaSAndroid Build Coastguard Worker                 Vertex* vert = &fVerts.push_back();
1425*c8dee2aaSAndroid Build Coastguard Worker                 vert->pos[0] = kRect.left() + xf * kRect.width()  + xOff[y];
1426*c8dee2aaSAndroid Build Coastguard Worker                 vert->pos[1] = kRect.top()  + yf * kRect.height() + yOff[x];
1427*c8dee2aaSAndroid Build Coastguard Worker                 vert->uv[0]  = kUV.left()   + xf * kUV.width();
1428*c8dee2aaSAndroid Build Coastguard Worker                 vert->uv[1]  = kUV.top()    + yf * kUV.height();
1429*c8dee2aaSAndroid Build Coastguard Worker             }
1430*c8dee2aaSAndroid Build Coastguard Worker         }
1431*c8dee2aaSAndroid Build Coastguard Worker 
1432*c8dee2aaSAndroid Build Coastguard Worker         return true;
1433*c8dee2aaSAndroid Build Coastguard Worker     }
1434*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString *)1435*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString*) override {
1436*c8dee2aaSAndroid Build Coastguard Worker         SkRuntimeEffect::ChildPtr child[4] = {fShader1, fShader2, fColorFilter, fBlender};
1437*c8dee2aaSAndroid Build Coastguard Worker 
1438*c8dee2aaSAndroid Build Coastguard Worker         GrRecordingContext* rc = canvas->recordingContext();
1439*c8dee2aaSAndroid Build Coastguard Worker         GrDirectContext* dc = GrAsDirectContext(rc);
1440*c8dee2aaSAndroid Build Coastguard Worker         fVB->update(dc, fVerts.data(), /*offset=*/0, fVerts.size_bytes());
1441*c8dee2aaSAndroid Build Coastguard Worker 
1442*c8dee2aaSAndroid Build Coastguard Worker         SkMesh::Result result = SkMesh::MakeIndexed(fSpec,
1443*c8dee2aaSAndroid Build Coastguard Worker                                                     SkMesh::Mode::kTriangles,
1444*c8dee2aaSAndroid Build Coastguard Worker                                                     fVB,
1445*c8dee2aaSAndroid Build Coastguard Worker                                                     fVerts.size(),
1446*c8dee2aaSAndroid Build Coastguard Worker                                                     /*vertexOffset=*/0,
1447*c8dee2aaSAndroid Build Coastguard Worker                                                     fIB,
1448*c8dee2aaSAndroid Build Coastguard Worker                                                     fIndices.size(),
1449*c8dee2aaSAndroid Build Coastguard Worker                                                     /*indexOffset=*/0,
1450*c8dee2aaSAndroid Build Coastguard Worker                                                     /*uniforms=*/nullptr,
1451*c8dee2aaSAndroid Build Coastguard Worker                                                     /*children=*/child,
1452*c8dee2aaSAndroid Build Coastguard Worker                                                     kRect.makeOutset(kRippleSize, kRippleSize));
1453*c8dee2aaSAndroid Build Coastguard Worker         if (!result.mesh.isValid()) {
1454*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("Mesh creation failed: %s\n", result.error.c_str());
1455*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kFail;
1456*c8dee2aaSAndroid Build Coastguard Worker         }
1457*c8dee2aaSAndroid Build Coastguard Worker 
1458*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
1459*c8dee2aaSAndroid Build Coastguard Worker         paint.setShader(fPaintShader);
1460*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawMesh(result.mesh, SkBlender::Mode(SkBlendMode::kDstOver), paint);
1461*c8dee2aaSAndroid Build Coastguard Worker 
1462*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
1463*c8dee2aaSAndroid Build Coastguard Worker     }
1464*c8dee2aaSAndroid Build Coastguard Worker 
1465*c8dee2aaSAndroid Build Coastguard Worker private:
ensureBuffers()1466*c8dee2aaSAndroid Build Coastguard Worker     void ensureBuffers() {
1467*c8dee2aaSAndroid Build Coastguard Worker         if (!fVB) {
1468*c8dee2aaSAndroid Build Coastguard Worker             fVB = SkMeshes::MakeVertexBuffer(fVerts.data(), fVerts.size_bytes());
1469*c8dee2aaSAndroid Build Coastguard Worker         }
1470*c8dee2aaSAndroid Build Coastguard Worker         if (!fIB) {
1471*c8dee2aaSAndroid Build Coastguard Worker             fIB = SkMeshes::MakeIndexBuffer(fIndices.data(), fIndices.size_bytes());
1472*c8dee2aaSAndroid Build Coastguard Worker         }
1473*c8dee2aaSAndroid Build Coastguard Worker     }
1474*c8dee2aaSAndroid Build Coastguard Worker 
1475*c8dee2aaSAndroid Build Coastguard Worker     struct Vertex {
1476*c8dee2aaSAndroid Build Coastguard Worker         float pos[2];
1477*c8dee2aaSAndroid Build Coastguard Worker         float uv[2];
1478*c8dee2aaSAndroid Build Coastguard Worker     };
1479*c8dee2aaSAndroid Build Coastguard Worker 
1480*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kRect = SkRect::MakeLTRB(20, 20, 300, 300);
1481*c8dee2aaSAndroid Build Coastguard Worker     static constexpr auto kUV   = SkRect::MakeLTRB( 0,  0, 128, 128);
1482*c8dee2aaSAndroid Build Coastguard Worker     static constexpr int kMeshSize = 16;
1483*c8dee2aaSAndroid Build Coastguard Worker     static constexpr float kRippleSize = 6.0f;
1484*c8dee2aaSAndroid Build Coastguard Worker 
1485*c8dee2aaSAndroid Build Coastguard Worker     Type fType;
1486*c8dee2aaSAndroid Build Coastguard Worker 
1487*c8dee2aaSAndroid Build Coastguard Worker     TArray<Vertex>   fVerts;
1488*c8dee2aaSAndroid Build Coastguard Worker     TArray<uint16_t> fIndices;
1489*c8dee2aaSAndroid Build Coastguard Worker 
1490*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader1, fShader2, fPaintShader;
1491*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkColorFilter> fColorFilter;
1492*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkBlender> fBlender;
1493*c8dee2aaSAndroid Build Coastguard Worker 
1494*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMeshSpecification> fSpec;
1495*c8dee2aaSAndroid Build Coastguard Worker 
1496*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::VertexBuffer> fVB;
1497*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::IndexBuffer> fIB;
1498*c8dee2aaSAndroid Build Coastguard Worker };
1499*c8dee2aaSAndroid Build Coastguard Worker 
1500*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MeshWithShadersGM(MeshWithShadersGM::Type::kMeshWithImage))
DEF_GM(return new MeshWithShadersGM (MeshWithShadersGM::Type::kMeshWithPaintColor))1501*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MeshWithShadersGM(MeshWithShadersGM::Type::kMeshWithPaintColor))
1502*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MeshWithShadersGM(MeshWithShadersGM::Type::kMeshWithPaintImage))
1503*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new MeshWithShadersGM(MeshWithShadersGM::Type::kMeshWithEffects))
1504*c8dee2aaSAndroid Build Coastguard Worker 
1505*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM_CAN_FAIL(custommesh_cs_uniforms, canvas, errorMsg, 200, 900) {
1506*c8dee2aaSAndroid Build Coastguard Worker     if (!canvas->recordingContext() && !canvas->recorder()) {
1507*c8dee2aaSAndroid Build Coastguard Worker         *errorMsg = GM::kErrorMsg_DrawSkippedGpuOnly;
1508*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kSkip;
1509*c8dee2aaSAndroid Build Coastguard Worker     }
1510*c8dee2aaSAndroid Build Coastguard Worker 
1511*c8dee2aaSAndroid Build Coastguard Worker     // Shared data
1512*c8dee2aaSAndroid Build Coastguard Worker     static constexpr SkRect kRect = SkRect::MakeLTRB(20, 20, 80, 80);
1513*c8dee2aaSAndroid Build Coastguard Worker     static constexpr SkPoint kQuad[]{
1514*c8dee2aaSAndroid Build Coastguard Worker             {kRect.left(), kRect.top()},
1515*c8dee2aaSAndroid Build Coastguard Worker             {kRect.right(), kRect.top()},
1516*c8dee2aaSAndroid Build Coastguard Worker             {kRect.left(), kRect.bottom()},
1517*c8dee2aaSAndroid Build Coastguard Worker             {kRect.right(), kRect.bottom()},
1518*c8dee2aaSAndroid Build Coastguard Worker     };
1519*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMesh::VertexBuffer> vb = SkMeshes::MakeVertexBuffer(kQuad, sizeof(kQuad));
1520*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> unis = SkData::MakeWithCopy(&SkColors::kRed, sizeof(SkColor4f));
1521*c8dee2aaSAndroid Build Coastguard Worker 
1522*c8dee2aaSAndroid Build Coastguard Worker     // Surface helper
1523*c8dee2aaSAndroid Build Coastguard Worker     auto makeSurface = [=](sk_sp<SkColorSpace> cs) {
1524*c8dee2aaSAndroid Build Coastguard Worker         SkImageInfo ii = SkImageInfo::MakeN32Premul(200, 100, cs);
1525*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkSurface> surface = canvas->makeSurface(ii);
1526*c8dee2aaSAndroid Build Coastguard Worker         return surface ? surface : SkSurfaces::Raster(ii);
1527*c8dee2aaSAndroid Build Coastguard Worker     };
1528*c8dee2aaSAndroid Build Coastguard Worker 
1529*c8dee2aaSAndroid Build Coastguard Worker     // Mesh helper
1530*c8dee2aaSAndroid Build Coastguard Worker     enum class Managed : bool { kNo, kYes };
1531*c8dee2aaSAndroid Build Coastguard Worker     auto makeMesh = [&](Managed managed, sk_sp<SkColorSpace> workingCS) {
1532*c8dee2aaSAndroid Build Coastguard Worker         static const SkMeshSpecification::Attribute kAttributes[]{
1533*c8dee2aaSAndroid Build Coastguard Worker                 {SkMeshSpecification::Attribute::Type::kFloat2, 0, SkString{"pos"}},
1534*c8dee2aaSAndroid Build Coastguard Worker         };
1535*c8dee2aaSAndroid Build Coastguard Worker 
1536*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kVS[] = R"(
1537*c8dee2aaSAndroid Build Coastguard Worker             Varyings main(in const Attributes attributes) {
1538*c8dee2aaSAndroid Build Coastguard Worker                 Varyings varyings;
1539*c8dee2aaSAndroid Build Coastguard Worker                 varyings.position = attributes.pos;
1540*c8dee2aaSAndroid Build Coastguard Worker                 return varyings;
1541*c8dee2aaSAndroid Build Coastguard Worker             }
1542*c8dee2aaSAndroid Build Coastguard Worker         )";
1543*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kManagedFS[] = R"(
1544*c8dee2aaSAndroid Build Coastguard Worker             layout(color) uniform half4 color;
1545*c8dee2aaSAndroid Build Coastguard Worker             float2 main(const Varyings varyings, out half4 c) {
1546*c8dee2aaSAndroid Build Coastguard Worker                 c = color;
1547*c8dee2aaSAndroid Build Coastguard Worker                 return varyings.position;
1548*c8dee2aaSAndroid Build Coastguard Worker             }
1549*c8dee2aaSAndroid Build Coastguard Worker         )";
1550*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kRawFS[] = R"(
1551*c8dee2aaSAndroid Build Coastguard Worker             uniform half4 color;
1552*c8dee2aaSAndroid Build Coastguard Worker             float2 main(const Varyings varyings, out half4 c) {
1553*c8dee2aaSAndroid Build Coastguard Worker                 c = color;
1554*c8dee2aaSAndroid Build Coastguard Worker                 return varyings.position;
1555*c8dee2aaSAndroid Build Coastguard Worker             }
1556*c8dee2aaSAndroid Build Coastguard Worker         )";
1557*c8dee2aaSAndroid Build Coastguard Worker 
1558*c8dee2aaSAndroid Build Coastguard Worker         auto [spec, error] = SkMeshSpecification::Make(
1559*c8dee2aaSAndroid Build Coastguard Worker                 kAttributes,
1560*c8dee2aaSAndroid Build Coastguard Worker                 sizeof(SkPoint),
1561*c8dee2aaSAndroid Build Coastguard Worker                 /*varyings=*/{},
1562*c8dee2aaSAndroid Build Coastguard Worker                 SkString(kVS),
1563*c8dee2aaSAndroid Build Coastguard Worker                 SkString(managed == Managed::kYes ? kManagedFS : kRawFS),
1564*c8dee2aaSAndroid Build Coastguard Worker                 std::move(workingCS),
1565*c8dee2aaSAndroid Build Coastguard Worker                 kPremul_SkAlphaType);
1566*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(spec);
1567*c8dee2aaSAndroid Build Coastguard Worker 
1568*c8dee2aaSAndroid Build Coastguard Worker         SkMesh::Result result = SkMesh::Make(std::move(spec),
1569*c8dee2aaSAndroid Build Coastguard Worker                                              SkMesh::Mode::kTriangleStrip,
1570*c8dee2aaSAndroid Build Coastguard Worker                                              vb,
1571*c8dee2aaSAndroid Build Coastguard Worker                                              /*vertexCount=*/4,
1572*c8dee2aaSAndroid Build Coastguard Worker                                              /*vertexOffset=*/0,
1573*c8dee2aaSAndroid Build Coastguard Worker                                              /*uniforms=*/unis,
1574*c8dee2aaSAndroid Build Coastguard Worker                                              /*children=*/{},
1575*c8dee2aaSAndroid Build Coastguard Worker                                              kRect);
1576*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(result.mesh.isValid());
1577*c8dee2aaSAndroid Build Coastguard Worker         return result.mesh;
1578*c8dee2aaSAndroid Build Coastguard Worker     };
1579*c8dee2aaSAndroid Build Coastguard Worker 
1580*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkColorSpace> null = nullptr,
1581*c8dee2aaSAndroid Build Coastguard Worker                         srgb = SkColorSpace::MakeSRGB(),
1582*c8dee2aaSAndroid Build Coastguard Worker                         spin = SkColorSpace::MakeSRGB()->makeColorSpin(),
1583*c8dee2aaSAndroid Build Coastguard Worker                         wide = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2,
1584*c8dee2aaSAndroid Build Coastguard Worker                                                      SkNamedGamut::kRec2020);
1585*c8dee2aaSAndroid Build Coastguard Worker 
1586*c8dee2aaSAndroid Build Coastguard Worker     struct Config {
1587*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkColorSpace> fMeshCS;
1588*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkColorSpace> fSurfaceCS;
1589*c8dee2aaSAndroid Build Coastguard Worker         Managed fManaged;
1590*c8dee2aaSAndroid Build Coastguard Worker         SkColor fExpectedColor = SK_ColorRED;
1591*c8dee2aaSAndroid Build Coastguard Worker     };
1592*c8dee2aaSAndroid Build Coastguard Worker     static const Config kConfigs[] = {
1593*c8dee2aaSAndroid Build Coastguard Worker             // Uniforms should remain in sRGB mode, then get converted to destination after mesh FS
1594*c8dee2aaSAndroid Build Coastguard Worker             // Before b/316594914 was fixed, these would get double-converted:
1595*c8dee2aaSAndroid Build Coastguard Worker             {srgb, null, Managed::kYes},
1596*c8dee2aaSAndroid Build Coastguard Worker             {srgb, srgb, Managed::kYes},
1597*c8dee2aaSAndroid Build Coastguard Worker             {srgb, spin, Managed::kYes},
1598*c8dee2aaSAndroid Build Coastguard Worker             {srgb, wide, Managed::kYes},
1599*c8dee2aaSAndroid Build Coastguard Worker 
1600*c8dee2aaSAndroid Build Coastguard Worker             // Uniforms should be converted to working space (spun), then converted to destination
1601*c8dee2aaSAndroid Build Coastguard Worker             {spin, srgb, Managed::kYes},
1602*c8dee2aaSAndroid Build Coastguard Worker             {spin, spin, Managed::kYes},
1603*c8dee2aaSAndroid Build Coastguard Worker             {spin, wide, Managed::kYes},
1604*c8dee2aaSAndroid Build Coastguard Worker 
1605*c8dee2aaSAndroid Build Coastguard Worker             // Non-managed uniforms serve as a control group. The red uniforms are not converted to
1606*c8dee2aaSAndroid Build Coastguard Worker             // the working space. The mesh FS returns "red" {1, 0, 0, 1}, but that's actually green,
1607*c8dee2aaSAndroid Build Coastguard Worker             // because the working space of the mesh is `spin`. That output is converted to dest,
1608*c8dee2aaSAndroid Build Coastguard Worker             // rendering as green. Therefore, we manually change the control color's box to green.
1609*c8dee2aaSAndroid Build Coastguard Worker             {spin, srgb, Managed::kNo, SK_ColorGREEN},
1610*c8dee2aaSAndroid Build Coastguard Worker             {spin, wide, Managed::kNo, SK_ColorGREEN},
1611*c8dee2aaSAndroid Build Coastguard Worker     };
1612*c8dee2aaSAndroid Build Coastguard Worker 
1613*c8dee2aaSAndroid Build Coastguard Worker     for (const Config& config : kConfigs) {
1614*c8dee2aaSAndroid Build Coastguard Worker         SkMesh mesh = makeMesh(config.fManaged, config.fMeshCS);
1615*c8dee2aaSAndroid Build Coastguard Worker 
1616*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkSurface> offscreen = makeSurface(config.fSurfaceCS);
1617*c8dee2aaSAndroid Build Coastguard Worker         SkCanvas* offscreenCanvas = offscreen->getCanvas();
1618*c8dee2aaSAndroid Build Coastguard Worker 
1619*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
1620*c8dee2aaSAndroid Build Coastguard Worker         offscreenCanvas->drawMesh(mesh, SkBlender::Mode(SkBlendMode::kDst), paint);
1621*c8dee2aaSAndroid Build Coastguard Worker         offscreenCanvas->translate(100, 0);
1622*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(config.fExpectedColor);
1623*c8dee2aaSAndroid Build Coastguard Worker         offscreenCanvas->drawRect(kRect, paint);
1624*c8dee2aaSAndroid Build Coastguard Worker 
1625*c8dee2aaSAndroid Build Coastguard Worker         offscreen->draw(canvas, 0, 0);
1626*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(0, 100);
1627*c8dee2aaSAndroid Build Coastguard Worker     }
1628*c8dee2aaSAndroid Build Coastguard Worker 
1629*c8dee2aaSAndroid Build Coastguard Worker     return DrawResult::kOk;
1630*c8dee2aaSAndroid Build Coastguard Worker }
1631*c8dee2aaSAndroid Build Coastguard Worker 
1632*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skiagm
1633