xref: /aosp_15_r20/external/skia/tests/MeshTest.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 "include/core/SkBlendMode.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlender.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorFilter.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMesh.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSpan.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkZip.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMeshPriv.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
26*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
27*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
28*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
29*c8dee2aaSAndroid Build Coastguard Worker #include <limits>
30*c8dee2aaSAndroid Build Coastguard Worker #include <string>
31*c8dee2aaSAndroid Build Coastguard Worker #include <string_view>
32*c8dee2aaSAndroid Build Coastguard Worker #include <tuple>
33*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
34*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker using Attribute = SkMeshSpecification::Attribute;
37*c8dee2aaSAndroid Build Coastguard Worker using Varying   = SkMeshSpecification::Varying;
38*c8dee2aaSAndroid Build Coastguard Worker 
attr_type_str(const Attribute::Type type)39*c8dee2aaSAndroid Build Coastguard Worker static const char* attr_type_str(const Attribute::Type type) {
40*c8dee2aaSAndroid Build Coastguard Worker     switch (type) {
41*c8dee2aaSAndroid Build Coastguard Worker         case Attribute::Type::kFloat:        return "float";
42*c8dee2aaSAndroid Build Coastguard Worker         case Attribute::Type::kFloat2:       return "float2";
43*c8dee2aaSAndroid Build Coastguard Worker         case Attribute::Type::kFloat3:       return "float3";
44*c8dee2aaSAndroid Build Coastguard Worker         case Attribute::Type::kFloat4:       return "float4";
45*c8dee2aaSAndroid Build Coastguard Worker         case Attribute::Type::kUByte4_unorm: return "ubyte4_unorm";
46*c8dee2aaSAndroid Build Coastguard Worker     }
47*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
48*c8dee2aaSAndroid Build Coastguard Worker }
49*c8dee2aaSAndroid Build Coastguard Worker 
var_type_str(const Varying::Type type)50*c8dee2aaSAndroid Build Coastguard Worker static const char* var_type_str(const Varying::Type type) {
51*c8dee2aaSAndroid Build Coastguard Worker     switch (type) {
52*c8dee2aaSAndroid Build Coastguard Worker         case Varying::Type::kFloat:  return "float";
53*c8dee2aaSAndroid Build Coastguard Worker         case Varying::Type::kFloat2: return "float2";
54*c8dee2aaSAndroid Build Coastguard Worker         case Varying::Type::kFloat3: return "float3";
55*c8dee2aaSAndroid Build Coastguard Worker         case Varying::Type::kFloat4: return "float4";
56*c8dee2aaSAndroid Build Coastguard Worker         case Varying::Type::kHalf:   return "half";
57*c8dee2aaSAndroid Build Coastguard Worker         case Varying::Type::kHalf2:  return "half2";
58*c8dee2aaSAndroid Build Coastguard Worker         case Varying::Type::kHalf3:  return "half3";
59*c8dee2aaSAndroid Build Coastguard Worker         case Varying::Type::kHalf4:  return "half4";
60*c8dee2aaSAndroid Build Coastguard Worker     }
61*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker 
make_description(SkSpan<const Attribute> attributes,size_t stride,SkSpan<const Varying> varyings,const SkString & vs,const SkString & fs)64*c8dee2aaSAndroid Build Coastguard Worker static SkString make_description(SkSpan<const Attribute> attributes,
65*c8dee2aaSAndroid Build Coastguard Worker                                  size_t                  stride,
66*c8dee2aaSAndroid Build Coastguard Worker                                  SkSpan<const Varying>   varyings,
67*c8dee2aaSAndroid Build Coastguard Worker                                  const SkString&         vs,
68*c8dee2aaSAndroid Build Coastguard Worker                                  const SkString&         fs) {
69*c8dee2aaSAndroid Build Coastguard Worker     static constexpr size_t kMax = 10;
70*c8dee2aaSAndroid Build Coastguard Worker     SkString result;
71*c8dee2aaSAndroid Build Coastguard Worker     result.appendf("Attributes (count=%zu, stride=%zu):\n", attributes.size(), stride);
72*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::min(kMax, attributes.size()); ++i) {
73*c8dee2aaSAndroid Build Coastguard Worker         const auto& a = attributes[i];
74*c8dee2aaSAndroid Build Coastguard Worker         result.appendf(" {%-10s, %3zu, \"%s\"}\n", attr_type_str(a.type), a.offset, a.name.c_str());
75*c8dee2aaSAndroid Build Coastguard Worker     }
76*c8dee2aaSAndroid Build Coastguard Worker     if (kMax < attributes.size()) {
77*c8dee2aaSAndroid Build Coastguard Worker         result.append(" ...\n");
78*c8dee2aaSAndroid Build Coastguard Worker     }
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker     result.appendf("Varyings (count=%zu):\n", varyings.size());
81*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < std::min(kMax, varyings.size()); ++i) {
82*c8dee2aaSAndroid Build Coastguard Worker         const auto& v = varyings[i];
83*c8dee2aaSAndroid Build Coastguard Worker         result.appendf(" {%5s, \"%s\"}\n", var_type_str(v.type), v.name.c_str());
84*c8dee2aaSAndroid Build Coastguard Worker     }
85*c8dee2aaSAndroid Build Coastguard Worker     if (kMax < varyings.size()) {
86*c8dee2aaSAndroid Build Coastguard Worker         result.append(" ...\n");
87*c8dee2aaSAndroid Build Coastguard Worker     }
88*c8dee2aaSAndroid Build Coastguard Worker 
89*c8dee2aaSAndroid Build Coastguard Worker     result.appendf("\n--VS--\n%s\n------\n", vs.c_str());
90*c8dee2aaSAndroid Build Coastguard Worker     result.appendf("\n--FS--\n%s\n------\n", fs.c_str());
91*c8dee2aaSAndroid Build Coastguard Worker     return result;
92*c8dee2aaSAndroid Build Coastguard Worker }
93*c8dee2aaSAndroid Build Coastguard Worker 
check_for_failure(skiatest::Reporter * reporter,SkSpan<const Attribute> attributes,size_t stride,SkSpan<const Varying> varyings,const SkString & vs,const SkString & fs,const char * expectedErrorSubstring=nullptr)94*c8dee2aaSAndroid Build Coastguard Worker static bool check_for_failure(skiatest::Reporter*     reporter,
95*c8dee2aaSAndroid Build Coastguard Worker                               SkSpan<const Attribute> attributes,
96*c8dee2aaSAndroid Build Coastguard Worker                               size_t                  stride,
97*c8dee2aaSAndroid Build Coastguard Worker                               SkSpan<const Varying>   varyings,
98*c8dee2aaSAndroid Build Coastguard Worker                               const SkString&         vs,
99*c8dee2aaSAndroid Build Coastguard Worker                               const SkString&         fs,
100*c8dee2aaSAndroid Build Coastguard Worker                               const char*             expectedErrorSubstring = nullptr) {
101*c8dee2aaSAndroid Build Coastguard Worker     auto [spec, error] = SkMeshSpecification::Make(attributes, stride, varyings, vs, fs);
102*c8dee2aaSAndroid Build Coastguard Worker     if (spec) {
103*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter,
104*c8dee2aaSAndroid Build Coastguard Worker                "Expected to fail but succeeded:\n%s",
105*c8dee2aaSAndroid Build Coastguard Worker                make_description(attributes, stride, varyings, vs, fs).c_str());
106*c8dee2aaSAndroid Build Coastguard Worker         return false;
107*c8dee2aaSAndroid Build Coastguard Worker     }
108*c8dee2aaSAndroid Build Coastguard Worker     if (expectedErrorSubstring && !error.contains(expectedErrorSubstring)) {
109*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter,
110*c8dee2aaSAndroid Build Coastguard Worker                "    Expected: %s\n"
111*c8dee2aaSAndroid Build Coastguard Worker                "Actual error: %s\n",
112*c8dee2aaSAndroid Build Coastguard Worker                expectedErrorSubstring, error.c_str());
113*c8dee2aaSAndroid Build Coastguard Worker         return false;
114*c8dee2aaSAndroid Build Coastguard Worker     }
115*c8dee2aaSAndroid Build Coastguard Worker     return true;
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker 
check_for_success(skiatest::Reporter * reporter,SkSpan<const Attribute> attributes,size_t stride,SkSpan<const Varying> varyings,const SkString & vs,const SkString & fs,sk_sp<SkMeshSpecification> * spec=nullptr)118*c8dee2aaSAndroid Build Coastguard Worker static bool check_for_success(skiatest::Reporter*         reporter,
119*c8dee2aaSAndroid Build Coastguard Worker                               SkSpan<const Attribute>     attributes,
120*c8dee2aaSAndroid Build Coastguard Worker                               size_t                      stride,
121*c8dee2aaSAndroid Build Coastguard Worker                               SkSpan<const Varying>       varyings,
122*c8dee2aaSAndroid Build Coastguard Worker                               const SkString&             vs,
123*c8dee2aaSAndroid Build Coastguard Worker                               const SkString&             fs,
124*c8dee2aaSAndroid Build Coastguard Worker                               sk_sp<SkMeshSpecification>* spec = nullptr) {
125*c8dee2aaSAndroid Build Coastguard Worker     auto [s, error] = SkMeshSpecification::Make(attributes, stride, varyings, vs, fs);
126*c8dee2aaSAndroid Build Coastguard Worker     if (s) {
127*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, error.isEmpty());
128*c8dee2aaSAndroid Build Coastguard Worker         if (spec) {
129*c8dee2aaSAndroid Build Coastguard Worker             *spec = std::move(s);
130*c8dee2aaSAndroid Build Coastguard Worker         }
131*c8dee2aaSAndroid Build Coastguard Worker         return true;
132*c8dee2aaSAndroid Build Coastguard Worker     }
133*c8dee2aaSAndroid Build Coastguard Worker     ERRORF(reporter,
134*c8dee2aaSAndroid Build Coastguard Worker            "Expected to succeed but failed:\n%sError:\n%s",
135*c8dee2aaSAndroid Build Coastguard Worker            make_description(attributes, stride, varyings, vs, fs).c_str(),
136*c8dee2aaSAndroid Build Coastguard Worker            error.c_str());
137*c8dee2aaSAndroid Build Coastguard Worker     return false;
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker // Simple valid strings to make specifications
141*c8dee2aaSAndroid Build Coastguard Worker static const SkString kValidVS {R"(
142*c8dee2aaSAndroid Build Coastguard Worker Varyings main(const Attributes attrs) {
143*c8dee2aaSAndroid Build Coastguard Worker     Varyings v;
144*c8dee2aaSAndroid Build Coastguard Worker     return v;
145*c8dee2aaSAndroid Build Coastguard Worker })"};
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker // There are multiple valid VS signatures.
148*c8dee2aaSAndroid Build Coastguard Worker static const SkString kValidFSes[]{
149*c8dee2aaSAndroid Build Coastguard Worker         SkString{"float2 main(const Varyings varyings) { return float2(10); }"},
150*c8dee2aaSAndroid Build Coastguard Worker         SkString{R"(
151*c8dee2aaSAndroid Build Coastguard Worker             float2 main(const Varyings varyings, out half4 color) {
152*c8dee2aaSAndroid Build Coastguard Worker                 color = half4(.2);
153*c8dee2aaSAndroid Build Coastguard Worker                 return float2(10);
154*c8dee2aaSAndroid Build Coastguard Worker             }
155*c8dee2aaSAndroid Build Coastguard Worker         )"},
156*c8dee2aaSAndroid Build Coastguard Worker };
157*c8dee2aaSAndroid Build Coastguard Worker 
158*c8dee2aaSAndroid Build Coastguard Worker // Simple valid attributes, stride, and varyings to make specifications
159*c8dee2aaSAndroid Build Coastguard Worker static const Attribute kValidAttrs[] = {
160*c8dee2aaSAndroid Build Coastguard Worker         {Attribute::Type::kFloat4, 0, SkString{"pos"}},
161*c8dee2aaSAndroid Build Coastguard Worker };
162*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t kValidStride = 4*4;
163*c8dee2aaSAndroid Build Coastguard Worker static const Varying kValidVaryings[] = {
164*c8dee2aaSAndroid Build Coastguard Worker         {Varying::Type::kFloat2, SkString{"uv"}},
165*c8dee2aaSAndroid Build Coastguard Worker };
166*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_Valid,reporter)167*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_Valid, reporter) {
168*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& validFS : kValidFSes) {
169*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_success(reporter,
170*c8dee2aaSAndroid Build Coastguard Worker                                kValidAttrs,
171*c8dee2aaSAndroid Build Coastguard Worker                                kValidStride,
172*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
173*c8dee2aaSAndroid Build Coastguard Worker                                kValidVS,
174*c8dee2aaSAndroid Build Coastguard Worker                                validFS)) {
175*c8dee2aaSAndroid Build Coastguard Worker             return;
176*c8dee2aaSAndroid Build Coastguard Worker         }
177*c8dee2aaSAndroid Build Coastguard Worker     }
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_InvalidSignature,reporter)180*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_InvalidSignature, reporter) {
181*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* kVSBody = "{ return float2(10); }";
182*c8dee2aaSAndroid Build Coastguard Worker 
183*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* kInvalidVSSigs[] {
184*c8dee2aaSAndroid Build Coastguard Worker             "float3   main(const Attributes attrs)",   // bad return
185*c8dee2aaSAndroid Build Coastguard Worker             "Varyings main(Attributes attrs)",         // non-const Attributes
186*c8dee2aaSAndroid Build Coastguard Worker             "Varyings main(out Attributes attrs)",     // out Varyings
187*c8dee2aaSAndroid Build Coastguard Worker             "Varyings main()",                         // no Attributes
188*c8dee2aaSAndroid Build Coastguard Worker             "Varyings main(const Varyings v, float2)"  // extra arg
189*c8dee2aaSAndroid Build Coastguard Worker     };
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* kNoColorFSBody = "{ return float2(10); }";
192*c8dee2aaSAndroid Build Coastguard Worker 
193*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* kInvalidNoColorFSSigs[] {
194*c8dee2aaSAndroid Build Coastguard Worker             "half2  main(const Varyings v)",      // bad return
195*c8dee2aaSAndroid Build Coastguard Worker             "float2 main(const Attributes v)",    // wrong param type
196*c8dee2aaSAndroid Build Coastguard Worker             "float2 main(inout Varyings attrs)",  // inout Varyings
197*c8dee2aaSAndroid Build Coastguard Worker             "float2 main(Varyings v)",            // non-const Varyings
198*c8dee2aaSAndroid Build Coastguard Worker             "float2 main()",                      // no args
199*c8dee2aaSAndroid Build Coastguard Worker             "float2 main(const Varyings, float)"  // extra arg
200*c8dee2aaSAndroid Build Coastguard Worker     };
201*c8dee2aaSAndroid Build Coastguard Worker 
202*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* kColorFSBody = "{ color = half4(.2); return float2(10); }";
203*c8dee2aaSAndroid Build Coastguard Worker 
204*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* kInvalidColorFSSigs[] {
205*c8dee2aaSAndroid Build Coastguard Worker             "half2  main(const Varyings v, out half4 color)",        // bad return
206*c8dee2aaSAndroid Build Coastguard Worker             "float2 main(const Attributes v, out half4 color)",      // wrong first param type
207*c8dee2aaSAndroid Build Coastguard Worker             "float2 main(const Varyings v, out half3 color)",        // wrong second param type
208*c8dee2aaSAndroid Build Coastguard Worker             "float2 main(out   Varyings v, out half4 color)",        // out Varyings
209*c8dee2aaSAndroid Build Coastguard Worker             "float2 main(const Varyings v, half4 color)",            // in color
210*c8dee2aaSAndroid Build Coastguard Worker             "float2 main(const Varyings v, out half4 color, float)"  // extra arg
211*c8dee2aaSAndroid Build Coastguard Worker     };
212*c8dee2aaSAndroid Build Coastguard Worker 
213*c8dee2aaSAndroid Build Coastguard Worker     for (const char* vsSig : kInvalidVSSigs) {
214*c8dee2aaSAndroid Build Coastguard Worker         SkString invalidVS;
215*c8dee2aaSAndroid Build Coastguard Worker         invalidVS.appendf("%s %s", vsSig, kVSBody);
216*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& validFS : kValidFSes) {
217*c8dee2aaSAndroid Build Coastguard Worker             if (!check_for_failure(reporter,
218*c8dee2aaSAndroid Build Coastguard Worker                                    kValidAttrs,
219*c8dee2aaSAndroid Build Coastguard Worker                                    kValidStride,
220*c8dee2aaSAndroid Build Coastguard Worker                                    kValidVaryings,
221*c8dee2aaSAndroid Build Coastguard Worker                                    invalidVS,
222*c8dee2aaSAndroid Build Coastguard Worker                                    validFS)) {
223*c8dee2aaSAndroid Build Coastguard Worker                 return;
224*c8dee2aaSAndroid Build Coastguard Worker             }
225*c8dee2aaSAndroid Build Coastguard Worker         }
226*c8dee2aaSAndroid Build Coastguard Worker     }
227*c8dee2aaSAndroid Build Coastguard Worker 
228*c8dee2aaSAndroid Build Coastguard Worker     for (const char* noColorFSSig : kInvalidNoColorFSSigs) {
229*c8dee2aaSAndroid Build Coastguard Worker         SkString invalidFS;
230*c8dee2aaSAndroid Build Coastguard Worker         invalidFS.appendf("%s %s", noColorFSSig, kNoColorFSBody);
231*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_failure(reporter,
232*c8dee2aaSAndroid Build Coastguard Worker                                kValidAttrs,
233*c8dee2aaSAndroid Build Coastguard Worker                                kValidStride,
234*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
235*c8dee2aaSAndroid Build Coastguard Worker                                kValidVS,
236*c8dee2aaSAndroid Build Coastguard Worker                                invalidFS)) {
237*c8dee2aaSAndroid Build Coastguard Worker             return;
238*c8dee2aaSAndroid Build Coastguard Worker         }
239*c8dee2aaSAndroid Build Coastguard Worker     }
240*c8dee2aaSAndroid Build Coastguard Worker 
241*c8dee2aaSAndroid Build Coastguard Worker     for (const char* colorFSSig : kInvalidColorFSSigs) {
242*c8dee2aaSAndroid Build Coastguard Worker         SkString invalidFS;
243*c8dee2aaSAndroid Build Coastguard Worker         invalidFS.appendf("%s %s", colorFSSig, kColorFSBody);
244*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_failure(reporter,
245*c8dee2aaSAndroid Build Coastguard Worker                                kValidAttrs,
246*c8dee2aaSAndroid Build Coastguard Worker                                kValidStride,
247*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
248*c8dee2aaSAndroid Build Coastguard Worker                                kValidVS,
249*c8dee2aaSAndroid Build Coastguard Worker                                invalidFS)) {
250*c8dee2aaSAndroid Build Coastguard Worker             return;
251*c8dee2aaSAndroid Build Coastguard Worker         }
252*c8dee2aaSAndroid Build Coastguard Worker     }
253*c8dee2aaSAndroid Build Coastguard Worker }
254*c8dee2aaSAndroid Build Coastguard Worker 
255*c8dee2aaSAndroid Build Coastguard Worker // We allow the optional out color from the FS to either be float4 or half4
DEF_TEST(MeshSpec_Float4Color,reporter)256*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_Float4Color, reporter) {
257*c8dee2aaSAndroid Build Coastguard Worker     static const SkString kFloat4FS {
258*c8dee2aaSAndroid Build Coastguard Worker         R"(
259*c8dee2aaSAndroid Build Coastguard Worker             float2 main(const Varyings varyings, out float4 color) {
260*c8dee2aaSAndroid Build Coastguard Worker                 color = float4(.2); return float2(10);
261*c8dee2aaSAndroid Build Coastguard Worker             }
262*c8dee2aaSAndroid Build Coastguard Worker         )"
263*c8dee2aaSAndroid Build Coastguard Worker     };
264*c8dee2aaSAndroid Build Coastguard Worker     check_for_success(reporter,
265*c8dee2aaSAndroid Build Coastguard Worker                       kValidAttrs,
266*c8dee2aaSAndroid Build Coastguard Worker                       kValidStride,
267*c8dee2aaSAndroid Build Coastguard Worker                       kValidVaryings,
268*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
269*c8dee2aaSAndroid Build Coastguard Worker                       kFloat4FS);
270*c8dee2aaSAndroid Build Coastguard Worker }
271*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_DisallowsChildEffectInVertex,reporter)272*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_DisallowsChildEffectInVertex, reporter) {
273*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* kChildEffects[] {
274*c8dee2aaSAndroid Build Coastguard Worker         "uniform shader myshader;",
275*c8dee2aaSAndroid Build Coastguard Worker         "uniform colorFilter mycolorfilter;",
276*c8dee2aaSAndroid Build Coastguard Worker         "uniform blender myblender;"
277*c8dee2aaSAndroid Build Coastguard Worker     };
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& global : kChildEffects) {
280*c8dee2aaSAndroid Build Coastguard Worker         SkString vsWithChild{global};
281*c8dee2aaSAndroid Build Coastguard Worker         vsWithChild.append(kValidVS);
282*c8dee2aaSAndroid Build Coastguard Worker 
283*c8dee2aaSAndroid Build Coastguard Worker         SkString fsWithChild{global};
284*c8dee2aaSAndroid Build Coastguard Worker         fsWithChild.append(kValidFSes[0]);
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_failure(reporter,
287*c8dee2aaSAndroid Build Coastguard Worker                                kValidAttrs,
288*c8dee2aaSAndroid Build Coastguard Worker                                kValidStride,
289*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
290*c8dee2aaSAndroid Build Coastguard Worker                                vsWithChild,
291*c8dee2aaSAndroid Build Coastguard Worker                                kValidFSes[0],
292*c8dee2aaSAndroid Build Coastguard Worker                                "effects are not permitted in mesh vertex shaders")) {
293*c8dee2aaSAndroid Build Coastguard Worker             return;
294*c8dee2aaSAndroid Build Coastguard Worker         }
295*c8dee2aaSAndroid Build Coastguard Worker 
296*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_failure(reporter,
297*c8dee2aaSAndroid Build Coastguard Worker                                kValidAttrs,
298*c8dee2aaSAndroid Build Coastguard Worker                                kValidStride,
299*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
300*c8dee2aaSAndroid Build Coastguard Worker                                vsWithChild,
301*c8dee2aaSAndroid Build Coastguard Worker                                fsWithChild,
302*c8dee2aaSAndroid Build Coastguard Worker                                "effects are not permitted in mesh vertex shaders")) {
303*c8dee2aaSAndroid Build Coastguard Worker             return;
304*c8dee2aaSAndroid Build Coastguard Worker         }
305*c8dee2aaSAndroid Build Coastguard Worker     }
306*c8dee2aaSAndroid Build Coastguard Worker }
307*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_AllowsChildEffectInFragment,reporter)308*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_AllowsChildEffectInFragment, reporter) {
309*c8dee2aaSAndroid Build Coastguard Worker     static constexpr const char* kChildEffects[] {
310*c8dee2aaSAndroid Build Coastguard Worker         "uniform shader myshader;",
311*c8dee2aaSAndroid Build Coastguard Worker         "uniform colorFilter mycolorfilter; uniform shader myshader;",
312*c8dee2aaSAndroid Build Coastguard Worker         "uniform shader myshader; uniform blender myblender; uniform colorFilter mycolorfilter;"
313*c8dee2aaSAndroid Build Coastguard Worker     };
314*c8dee2aaSAndroid Build Coastguard Worker 
315*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& global : kChildEffects) {
316*c8dee2aaSAndroid Build Coastguard Worker         SkString fsWithChild{global};
317*c8dee2aaSAndroid Build Coastguard Worker         fsWithChild.append(kValidFSes[0]);
318*c8dee2aaSAndroid Build Coastguard Worker 
319*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_success(reporter,
320*c8dee2aaSAndroid Build Coastguard Worker                                kValidAttrs,
321*c8dee2aaSAndroid Build Coastguard Worker                                kValidStride,
322*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
323*c8dee2aaSAndroid Build Coastguard Worker                                kValidVS,
324*c8dee2aaSAndroid Build Coastguard Worker                                fsWithChild)) {
325*c8dee2aaSAndroid Build Coastguard Worker             return;
326*c8dee2aaSAndroid Build Coastguard Worker         }
327*c8dee2aaSAndroid Build Coastguard Worker     }
328*c8dee2aaSAndroid Build Coastguard Worker }
329*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_FindChild,reporter)330*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_FindChild, reporter) {
331*c8dee2aaSAndroid Build Coastguard Worker     SkString fsWithChild{"uniform shader myshader;"
332*c8dee2aaSAndroid Build Coastguard Worker                          "uniform blender myblender;"
333*c8dee2aaSAndroid Build Coastguard Worker                          "uniform colorFilter mycolorfilter;"};
334*c8dee2aaSAndroid Build Coastguard Worker     fsWithChild.append(kValidFSes[0]);
335*c8dee2aaSAndroid Build Coastguard Worker 
336*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkMeshSpecification> meshSpec;
337*c8dee2aaSAndroid Build Coastguard Worker     if (!check_for_success(reporter,
338*c8dee2aaSAndroid Build Coastguard Worker                            kValidAttrs,
339*c8dee2aaSAndroid Build Coastguard Worker                            kValidStride,
340*c8dee2aaSAndroid Build Coastguard Worker                            kValidVaryings,
341*c8dee2aaSAndroid Build Coastguard Worker                            kValidVS,
342*c8dee2aaSAndroid Build Coastguard Worker                            fsWithChild,
343*c8dee2aaSAndroid Build Coastguard Worker                            &meshSpec)) {
344*c8dee2aaSAndroid Build Coastguard Worker         return;
345*c8dee2aaSAndroid Build Coastguard Worker     }
346*c8dee2aaSAndroid Build Coastguard Worker 
347*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, meshSpec->findChild("myshader")->index == 0);
348*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, meshSpec->findChild("myblender")->index == 1);
349*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, meshSpec->findChild("mycolorfilter")->index == 2);
350*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !meshSpec->findChild("missing"));
351*c8dee2aaSAndroid Build Coastguard Worker }
352*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(Mesh_ChildEffectsMatchSpec,reporter)353*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(Mesh_ChildEffectsMatchSpec, reporter) {
354*c8dee2aaSAndroid Build Coastguard Worker     auto test = [&](const char* prefix,
355*c8dee2aaSAndroid Build Coastguard Worker                     SkSpan<SkRuntimeEffect::ChildPtr> children,
356*c8dee2aaSAndroid Build Coastguard Worker                     const char* expectedError = nullptr) {
357*c8dee2aaSAndroid Build Coastguard Worker         SkString fsWithChild{prefix};
358*c8dee2aaSAndroid Build Coastguard Worker         fsWithChild.append(kValidFSes[0]);
359*c8dee2aaSAndroid Build Coastguard Worker 
360*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkMeshSpecification> meshSpec;
361*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_success(reporter,
362*c8dee2aaSAndroid Build Coastguard Worker                                kValidAttrs,
363*c8dee2aaSAndroid Build Coastguard Worker                                kValidStride,
364*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
365*c8dee2aaSAndroid Build Coastguard Worker                                kValidVS,
366*c8dee2aaSAndroid Build Coastguard Worker                                fsWithChild,
367*c8dee2aaSAndroid Build Coastguard Worker                                &meshSpec)) {
368*c8dee2aaSAndroid Build Coastguard Worker             return;
369*c8dee2aaSAndroid Build Coastguard Worker         }
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker         constexpr float kVertexCount = 4;
372*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkMesh::VertexBuffer> vertexBuffer =
373*c8dee2aaSAndroid Build Coastguard Worker                 SkMeshes::MakeVertexBuffer(nullptr, kValidStride * kVertexCount);
374*c8dee2aaSAndroid Build Coastguard Worker         SkMesh::Result result = SkMesh::Make(meshSpec,
375*c8dee2aaSAndroid Build Coastguard Worker                                              SkMesh::Mode::kTriangleStrip,
376*c8dee2aaSAndroid Build Coastguard Worker                                              vertexBuffer,
377*c8dee2aaSAndroid Build Coastguard Worker                                              kVertexCount,
378*c8dee2aaSAndroid Build Coastguard Worker                                              /*vertexOffset=*/0,
379*c8dee2aaSAndroid Build Coastguard Worker                                              /*uniforms=*/nullptr,
380*c8dee2aaSAndroid Build Coastguard Worker                                              children,
381*c8dee2aaSAndroid Build Coastguard Worker                                              SkRect::MakeEmpty());
382*c8dee2aaSAndroid Build Coastguard Worker 
383*c8dee2aaSAndroid Build Coastguard Worker         if (expectedError) {
384*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !result.mesh.isValid());
385*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter,
386*c8dee2aaSAndroid Build Coastguard Worker                             result.error.contains(expectedError),
387*c8dee2aaSAndroid Build Coastguard Worker                             "Expected: '%s'\n"
388*c8dee2aaSAndroid Build Coastguard Worker                             "  Actual: '%s'\n", expectedError, result.error.c_str());
389*c8dee2aaSAndroid Build Coastguard Worker         } else {
390*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, result.mesh.isValid());
391*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter,
392*c8dee2aaSAndroid Build Coastguard Worker                             result.error.isEmpty(),
393*c8dee2aaSAndroid Build Coastguard Worker                             "Expected: no errors\n"
394*c8dee2aaSAndroid Build Coastguard Worker                             "  Actual: '%s'\n", result.error.c_str());
395*c8dee2aaSAndroid Build Coastguard Worker         }
396*c8dee2aaSAndroid Build Coastguard Worker     };
397*c8dee2aaSAndroid Build Coastguard Worker 
398*c8dee2aaSAndroid Build Coastguard Worker     SkRuntimeEffect::ChildPtr childShader[]  = {SkShaders::Color(SK_ColorBLACK)};
399*c8dee2aaSAndroid Build Coastguard Worker     SkRuntimeEffect::ChildPtr childFilter[]  = {SkColorFilters::LinearToSRGBGamma()};
400*c8dee2aaSAndroid Build Coastguard Worker     SkRuntimeEffect::ChildPtr childBlender[] = {SkBlender::Mode(SkBlendMode::kSrcOver)};
401*c8dee2aaSAndroid Build Coastguard Worker     SkRuntimeEffect::ChildPtr childNull[1]   = {};
402*c8dee2aaSAndroid Build Coastguard Worker 
403*c8dee2aaSAndroid Build Coastguard Worker     // These are expected to report a count mismatch.
404*c8dee2aaSAndroid Build Coastguard Worker     test("uniform shader myshader;", {},
405*c8dee2aaSAndroid Build Coastguard Worker          "The mesh specification declares 1 child effects, but the mesh supplies 0.");
406*c8dee2aaSAndroid Build Coastguard Worker     test("", childShader,
407*c8dee2aaSAndroid Build Coastguard Worker          "The mesh specification declares 0 child effects, but the mesh supplies 1.");
408*c8dee2aaSAndroid Build Coastguard Worker 
409*c8dee2aaSAndroid Build Coastguard Worker     // These are expected to report a type mismatch.
410*c8dee2aaSAndroid Build Coastguard Worker     test("uniform shader myshader;", childFilter,
411*c8dee2aaSAndroid Build Coastguard Worker          "Child effect 'myshader' was specified as a shader, but passed as a color filter.");
412*c8dee2aaSAndroid Build Coastguard Worker     test("uniform shader myshader;", childBlender,
413*c8dee2aaSAndroid Build Coastguard Worker          "Child effect 'myshader' was specified as a shader, but passed as a blender.");
414*c8dee2aaSAndroid Build Coastguard Worker     test("uniform colorFilter myfilter;", childShader,
415*c8dee2aaSAndroid Build Coastguard Worker          "Child effect 'myfilter' was specified as a color filter, but passed as a shader.");
416*c8dee2aaSAndroid Build Coastguard Worker     test("uniform colorFilter myfilter;", childBlender,
417*c8dee2aaSAndroid Build Coastguard Worker          "Child effect 'myfilter' was specified as a color filter, but passed as a blender.");
418*c8dee2aaSAndroid Build Coastguard Worker     test("uniform blender myblender;", childShader,
419*c8dee2aaSAndroid Build Coastguard Worker          "Child effect 'myblender' was specified as a blender, but passed as a shader.");
420*c8dee2aaSAndroid Build Coastguard Worker     test("uniform blender myblender;", childFilter,
421*c8dee2aaSAndroid Build Coastguard Worker          "Child effect 'myblender' was specified as a blender, but passed as a color filter.");
422*c8dee2aaSAndroid Build Coastguard Worker 
423*c8dee2aaSAndroid Build Coastguard Worker     // Null children are supported.
424*c8dee2aaSAndroid Build Coastguard Worker     test("uniform shader myshader;", childNull);
425*c8dee2aaSAndroid Build Coastguard Worker     test("uniform shader myfilter;", childNull);
426*c8dee2aaSAndroid Build Coastguard Worker     test("uniform shader myblender;", childNull);
427*c8dee2aaSAndroid Build Coastguard Worker 
428*c8dee2aaSAndroid Build Coastguard Worker     // Properly-typed child effects are supported.
429*c8dee2aaSAndroid Build Coastguard Worker     test("uniform shader myshader;", childShader);
430*c8dee2aaSAndroid Build Coastguard Worker     test("uniform colorFilter myfilter;", childFilter);
431*c8dee2aaSAndroid Build Coastguard Worker     test("uniform blender myblender;", childBlender);
432*c8dee2aaSAndroid Build Coastguard Worker 
433*c8dee2aaSAndroid Build Coastguard Worker }
434*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_ValidUniforms,reporter)435*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_ValidUniforms, reporter) {
436*c8dee2aaSAndroid Build Coastguard Worker     using Uniform = SkMeshSpecification::Uniform;
437*c8dee2aaSAndroid Build Coastguard Worker     using Type    = Uniform::Type;
438*c8dee2aaSAndroid Build Coastguard Worker     using Flags   = Uniform::Flags;
439*c8dee2aaSAndroid Build Coastguard Worker 
440*c8dee2aaSAndroid Build Coastguard Worker     constexpr Flags kVS    = Uniform::kVertex_Flag;
441*c8dee2aaSAndroid Build Coastguard Worker     constexpr Flags kFS    = Uniform::kFragment_Flag;
442*c8dee2aaSAndroid Build Coastguard Worker     constexpr Flags kColor = Uniform::kColor_Flag;
443*c8dee2aaSAndroid Build Coastguard Worker     constexpr Flags kHalfP = Uniform::kHalfPrecision_Flag;
444*c8dee2aaSAndroid Build Coastguard Worker 
445*c8dee2aaSAndroid Build Coastguard Worker     auto make_uni = [](Type type,
446*c8dee2aaSAndroid Build Coastguard Worker                        std::string_view name,
447*c8dee2aaSAndroid Build Coastguard Worker                        size_t offset,
448*c8dee2aaSAndroid Build Coastguard Worker                        uint32_t flags,
449*c8dee2aaSAndroid Build Coastguard Worker                        int count = 0) {
450*c8dee2aaSAndroid Build Coastguard Worker         if (count) {
451*c8dee2aaSAndroid Build Coastguard Worker             return Uniform{name, offset, type, count, flags | Uniform::kArray_Flag};
452*c8dee2aaSAndroid Build Coastguard Worker         } else {
453*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!(flags & Uniform::kArray_Flag));
454*c8dee2aaSAndroid Build Coastguard Worker             return Uniform{name, offset, type, 1, flags};
455*c8dee2aaSAndroid Build Coastguard Worker         }
456*c8dee2aaSAndroid Build Coastguard Worker     };
457*c8dee2aaSAndroid Build Coastguard Worker 
458*c8dee2aaSAndroid Build Coastguard Worker     // Each test case is a set of VS and FS uniform declarations followed and the expected output
459*c8dee2aaSAndroid Build Coastguard Worker     // of SkMeshSpecification::uniforms().
460*c8dee2aaSAndroid Build Coastguard Worker     struct {
461*c8dee2aaSAndroid Build Coastguard Worker         const std::vector<const char*>                  vsUniformDecls;
462*c8dee2aaSAndroid Build Coastguard Worker         const std::vector<const char*>                  fsUniformDecls;
463*c8dee2aaSAndroid Build Coastguard Worker         const std::vector<SkMeshSpecification::Uniform> expectations;
464*c8dee2aaSAndroid Build Coastguard Worker     } static kTestCases[] {
465*c8dee2aaSAndroid Build Coastguard Worker             // A single VS uniform.
466*c8dee2aaSAndroid Build Coastguard Worker             {
467*c8dee2aaSAndroid Build Coastguard Worker                     {
468*c8dee2aaSAndroid Build Coastguard Worker                             "uniform float x;"
469*c8dee2aaSAndroid Build Coastguard Worker                     },
470*c8dee2aaSAndroid Build Coastguard Worker                     {},
471*c8dee2aaSAndroid Build Coastguard Worker                     {
472*c8dee2aaSAndroid Build Coastguard Worker                             make_uni(Type::kFloat, "x", 0, kVS)
473*c8dee2aaSAndroid Build Coastguard Worker                     }
474*c8dee2aaSAndroid Build Coastguard Worker             },
475*c8dee2aaSAndroid Build Coastguard Worker 
476*c8dee2aaSAndroid Build Coastguard Worker             // A single FS uniform.
477*c8dee2aaSAndroid Build Coastguard Worker             {
478*c8dee2aaSAndroid Build Coastguard Worker                     {},
479*c8dee2aaSAndroid Build Coastguard Worker                     {
480*c8dee2aaSAndroid Build Coastguard Worker                             "uniform float2 v;"
481*c8dee2aaSAndroid Build Coastguard Worker                     },
482*c8dee2aaSAndroid Build Coastguard Worker                     {
483*c8dee2aaSAndroid Build Coastguard Worker                             make_uni(Type::kFloat2, "v", 0, kFS)
484*c8dee2aaSAndroid Build Coastguard Worker                     }
485*c8dee2aaSAndroid Build Coastguard Worker             },
486*c8dee2aaSAndroid Build Coastguard Worker 
487*c8dee2aaSAndroid Build Coastguard Worker             // A single uniform in both that uses color layout.
488*c8dee2aaSAndroid Build Coastguard Worker             {
489*c8dee2aaSAndroid Build Coastguard Worker                     {
490*c8dee2aaSAndroid Build Coastguard Worker                             "layout(color) uniform float4 color;",
491*c8dee2aaSAndroid Build Coastguard Worker                     },
492*c8dee2aaSAndroid Build Coastguard Worker                     {
493*c8dee2aaSAndroid Build Coastguard Worker                             "layout(color) uniform float4 color;",
494*c8dee2aaSAndroid Build Coastguard Worker                     },
495*c8dee2aaSAndroid Build Coastguard Worker                     {
496*c8dee2aaSAndroid Build Coastguard Worker                             make_uni(Type::kFloat4, "color", 0, kVS|kFS|kColor)
497*c8dee2aaSAndroid Build Coastguard Worker                     }
498*c8dee2aaSAndroid Build Coastguard Worker             },
499*c8dee2aaSAndroid Build Coastguard Worker 
500*c8dee2aaSAndroid Build Coastguard Worker             // A shared uniform after an unshared vertex uniform
501*c8dee2aaSAndroid Build Coastguard Worker             {
502*c8dee2aaSAndroid Build Coastguard Worker                     {
503*c8dee2aaSAndroid Build Coastguard Worker                             "layout(color) uniform float4 color;",
504*c8dee2aaSAndroid Build Coastguard Worker                             "              uniform float x[5];",
505*c8dee2aaSAndroid Build Coastguard Worker                     },
506*c8dee2aaSAndroid Build Coastguard Worker                     {
507*c8dee2aaSAndroid Build Coastguard Worker                             "uniform float x[5];",
508*c8dee2aaSAndroid Build Coastguard Worker                     },
509*c8dee2aaSAndroid Build Coastguard Worker                     {
510*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kFloat4, "color",  0, kVS|kColor, 0),
511*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kFloat , "x"    , 16, kVS|kFS   , 5)
512*c8dee2aaSAndroid Build Coastguard Worker                     }
513*c8dee2aaSAndroid Build Coastguard Worker             },
514*c8dee2aaSAndroid Build Coastguard Worker 
515*c8dee2aaSAndroid Build Coastguard Worker             // A shared uniform before an unshared vertex uniform
516*c8dee2aaSAndroid Build Coastguard Worker             {
517*c8dee2aaSAndroid Build Coastguard Worker                     {
518*c8dee2aaSAndroid Build Coastguard Worker                         "uniform half x[2];",
519*c8dee2aaSAndroid Build Coastguard Worker                         "uniform int  y;",
520*c8dee2aaSAndroid Build Coastguard Worker                     },
521*c8dee2aaSAndroid Build Coastguard Worker                     {
522*c8dee2aaSAndroid Build Coastguard Worker                         "uniform half x[2];",
523*c8dee2aaSAndroid Build Coastguard Worker                     },
524*c8dee2aaSAndroid Build Coastguard Worker                     {
525*c8dee2aaSAndroid Build Coastguard Worker                         make_uni(Type::kFloat, "x",  0, kVS|kFS|kHalfP, 2),
526*c8dee2aaSAndroid Build Coastguard Worker                         make_uni(Type::kInt,   "y",  8, kVS           , 0)
527*c8dee2aaSAndroid Build Coastguard Worker                     }
528*c8dee2aaSAndroid Build Coastguard Worker             },
529*c8dee2aaSAndroid Build Coastguard Worker 
530*c8dee2aaSAndroid Build Coastguard Worker             // A shared uniform after an unshared fragment uniform
531*c8dee2aaSAndroid Build Coastguard Worker             {
532*c8dee2aaSAndroid Build Coastguard Worker                     {
533*c8dee2aaSAndroid Build Coastguard Worker                             "uniform float3x3 m;",
534*c8dee2aaSAndroid Build Coastguard Worker                     },
535*c8dee2aaSAndroid Build Coastguard Worker                     {
536*c8dee2aaSAndroid Build Coastguard Worker                              "uniform int2     i2;",
537*c8dee2aaSAndroid Build Coastguard Worker                              "uniform float3x3 m;",
538*c8dee2aaSAndroid Build Coastguard Worker                     },
539*c8dee2aaSAndroid Build Coastguard Worker                     {
540*c8dee2aaSAndroid Build Coastguard Worker                             make_uni(Type::kFloat3x3, "m" ,  0, kVS|kFS),
541*c8dee2aaSAndroid Build Coastguard Worker                             make_uni(Type::kInt2    , "i2", 36, kFS    )
542*c8dee2aaSAndroid Build Coastguard Worker                     }
543*c8dee2aaSAndroid Build Coastguard Worker             },
544*c8dee2aaSAndroid Build Coastguard Worker 
545*c8dee2aaSAndroid Build Coastguard Worker             // A shared uniform before an unshared fragment uniform
546*c8dee2aaSAndroid Build Coastguard Worker             {
547*c8dee2aaSAndroid Build Coastguard Worker                     {
548*c8dee2aaSAndroid Build Coastguard Worker                             "uniform half4x4 m[4];",
549*c8dee2aaSAndroid Build Coastguard Worker                     },
550*c8dee2aaSAndroid Build Coastguard Worker                     {
551*c8dee2aaSAndroid Build Coastguard Worker                             "uniform half4x4  m[4];",
552*c8dee2aaSAndroid Build Coastguard Worker                             "uniform int3    i3[1];",
553*c8dee2aaSAndroid Build Coastguard Worker                     },
554*c8dee2aaSAndroid Build Coastguard Worker                     {
555*c8dee2aaSAndroid Build Coastguard Worker                             make_uni(Type::kFloat4x4, "m",    0, kVS|kFS|kHalfP, 4),
556*c8dee2aaSAndroid Build Coastguard Worker                             make_uni(Type::kInt3,     "i3", 256, kFS           , 1)
557*c8dee2aaSAndroid Build Coastguard Worker                     }
558*c8dee2aaSAndroid Build Coastguard Worker             },
559*c8dee2aaSAndroid Build Coastguard Worker 
560*c8dee2aaSAndroid Build Coastguard Worker             // Complex case with 2 shared uniforms that are declared in the opposite order.
561*c8dee2aaSAndroid Build Coastguard Worker             {
562*c8dee2aaSAndroid Build Coastguard Worker                     {
563*c8dee2aaSAndroid Build Coastguard Worker                              "uniform float   x;"
564*c8dee2aaSAndroid Build Coastguard Worker                              "uniform half4x4 m[4];",  // shared
565*c8dee2aaSAndroid Build Coastguard Worker                              "uniform int2    i2[2];"
566*c8dee2aaSAndroid Build Coastguard Worker                              "uniform float3  v[8];"   // shared
567*c8dee2aaSAndroid Build Coastguard Worker                              "uniform int3    i3;"
568*c8dee2aaSAndroid Build Coastguard Worker                     },
569*c8dee2aaSAndroid Build Coastguard Worker                     {
570*c8dee2aaSAndroid Build Coastguard Worker                              "uniform float   y;"
571*c8dee2aaSAndroid Build Coastguard Worker                              "uniform float3  v[8];"   // shared
572*c8dee2aaSAndroid Build Coastguard Worker                              "uniform int4    i4[2];"
573*c8dee2aaSAndroid Build Coastguard Worker                              "uniform half4x4 m[4];",  // shared
574*c8dee2aaSAndroid Build Coastguard Worker                              "uniform int     i;"
575*c8dee2aaSAndroid Build Coastguard Worker                     },
576*c8dee2aaSAndroid Build Coastguard Worker                     {
577*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kFloat,    "x" ,   0, kVS           , 0),
578*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kFloat4x4, "m" ,   4, kVS|kFS|kHalfP, 4),
579*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kInt2,     "i2", 260, kVS           , 2),
580*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kFloat3,   "v" , 276, kVS|kFS       , 8),
581*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kInt3,     "i3", 372, kVS           , 0),
582*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kFloat,    "y" , 384, kFS           , 0),
583*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kInt4,     "i4", 388, kFS           , 2),
584*c8dee2aaSAndroid Build Coastguard Worker                              make_uni(Type::kInt,      "i" , 420, kFS           , 0),
585*c8dee2aaSAndroid Build Coastguard Worker                     }
586*c8dee2aaSAndroid Build Coastguard Worker             },
587*c8dee2aaSAndroid Build Coastguard Worker     };
588*c8dee2aaSAndroid Build Coastguard Worker 
589*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& c : kTestCases) {
590*c8dee2aaSAndroid Build Coastguard Worker         SkString vs = kValidVS;
591*c8dee2aaSAndroid Build Coastguard Worker         SkString unis;
592*c8dee2aaSAndroid Build Coastguard Worker         for (const auto u : c.vsUniformDecls) {
593*c8dee2aaSAndroid Build Coastguard Worker             unis.append(u);
594*c8dee2aaSAndroid Build Coastguard Worker         }
595*c8dee2aaSAndroid Build Coastguard Worker         vs.prepend(unis);
596*c8dee2aaSAndroid Build Coastguard Worker 
597*c8dee2aaSAndroid Build Coastguard Worker         SkString fs = kValidFSes[0];
598*c8dee2aaSAndroid Build Coastguard Worker         unis = {};
599*c8dee2aaSAndroid Build Coastguard Worker         for (const auto u : c.fsUniformDecls) {
600*c8dee2aaSAndroid Build Coastguard Worker             unis.append(u);
601*c8dee2aaSAndroid Build Coastguard Worker         }
602*c8dee2aaSAndroid Build Coastguard Worker         fs.prepend(unis);
603*c8dee2aaSAndroid Build Coastguard Worker 
604*c8dee2aaSAndroid Build Coastguard Worker         auto attrs = SkSpan(kValidAttrs);
605*c8dee2aaSAndroid Build Coastguard Worker         auto varys = SkSpan(kValidVaryings);
606*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkMeshSpecification> spec;
607*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_success(reporter, attrs, kValidStride, varys, vs, fs, &spec)) {
608*c8dee2aaSAndroid Build Coastguard Worker             return;
609*c8dee2aaSAndroid Build Coastguard Worker         }
610*c8dee2aaSAndroid Build Coastguard Worker         SkString desc = make_description(attrs, kValidStride, varys, vs, fs);
611*c8dee2aaSAndroid Build Coastguard Worker         SkSpan<const Uniform> uniforms = spec->uniforms();
612*c8dee2aaSAndroid Build Coastguard Worker         if (uniforms.size() != c.expectations.size()) {
613*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(reporter,
614*c8dee2aaSAndroid Build Coastguard Worker                    "Expected %zu uniforms but actually %zu:\n%s",
615*c8dee2aaSAndroid Build Coastguard Worker                    c.expectations.size(),
616*c8dee2aaSAndroid Build Coastguard Worker                    uniforms.size(),
617*c8dee2aaSAndroid Build Coastguard Worker                    desc.c_str());
618*c8dee2aaSAndroid Build Coastguard Worker             return;
619*c8dee2aaSAndroid Build Coastguard Worker         }
620*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& [actual, expected] : SkMakeZip(uniforms, c.expectations)) {
621*c8dee2aaSAndroid Build Coastguard Worker             std::string name = std::string(actual.name);
622*c8dee2aaSAndroid Build Coastguard Worker             if (name != expected.name) {
623*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(reporter,
624*c8dee2aaSAndroid Build Coastguard Worker                        "Actual uniform name (%s) does not match expected name (%.*s)",
625*c8dee2aaSAndroid Build Coastguard Worker                        name.c_str(),
626*c8dee2aaSAndroid Build Coastguard Worker                        (int)expected.name.size(), expected.name.data());
627*c8dee2aaSAndroid Build Coastguard Worker                 return;
628*c8dee2aaSAndroid Build Coastguard Worker             }
629*c8dee2aaSAndroid Build Coastguard Worker             if (actual.type != expected.type) {
630*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(reporter,
631*c8dee2aaSAndroid Build Coastguard Worker                        "Uniform %s: Actual type (%d) does not match expected type (%d)",
632*c8dee2aaSAndroid Build Coastguard Worker                        name.c_str(),
633*c8dee2aaSAndroid Build Coastguard Worker                        static_cast<int>(actual.type),
634*c8dee2aaSAndroid Build Coastguard Worker                        static_cast<int>(expected.type));
635*c8dee2aaSAndroid Build Coastguard Worker                 return;
636*c8dee2aaSAndroid Build Coastguard Worker             }
637*c8dee2aaSAndroid Build Coastguard Worker             if (actual.count != expected.count) {
638*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(reporter,
639*c8dee2aaSAndroid Build Coastguard Worker                        "Uniform %s: Actual count (%d) does not match expected count (%d)",
640*c8dee2aaSAndroid Build Coastguard Worker                        name.c_str(),
641*c8dee2aaSAndroid Build Coastguard Worker                        actual.count,
642*c8dee2aaSAndroid Build Coastguard Worker                        expected.count);
643*c8dee2aaSAndroid Build Coastguard Worker                 return;
644*c8dee2aaSAndroid Build Coastguard Worker             }
645*c8dee2aaSAndroid Build Coastguard Worker             if (actual.flags != expected.flags) {
646*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(reporter,
647*c8dee2aaSAndroid Build Coastguard Worker                        "Uniform %s: Actual flags (0x%04x) do not match expected flags (0x%04x)",
648*c8dee2aaSAndroid Build Coastguard Worker                        name.c_str(),
649*c8dee2aaSAndroid Build Coastguard Worker                        actual.flags,
650*c8dee2aaSAndroid Build Coastguard Worker                        expected.flags);
651*c8dee2aaSAndroid Build Coastguard Worker                 return;
652*c8dee2aaSAndroid Build Coastguard Worker             }
653*c8dee2aaSAndroid Build Coastguard Worker             if (actual.offset != expected.offset) {
654*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(reporter,
655*c8dee2aaSAndroid Build Coastguard Worker                        "Uniform %s: Actual offset (%zu) does not match expected offset (%zu)",
656*c8dee2aaSAndroid Build Coastguard Worker                        name.c_str(),
657*c8dee2aaSAndroid Build Coastguard Worker                        actual.offset,
658*c8dee2aaSAndroid Build Coastguard Worker                        expected.offset);
659*c8dee2aaSAndroid Build Coastguard Worker                 return;
660*c8dee2aaSAndroid Build Coastguard Worker             }
661*c8dee2aaSAndroid Build Coastguard Worker         }
662*c8dee2aaSAndroid Build Coastguard Worker     }
663*c8dee2aaSAndroid Build Coastguard Worker }
664*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_InvalidUniforms,reporter)665*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_InvalidUniforms, reporter) {
666*c8dee2aaSAndroid Build Coastguard Worker     // We assume general uniform declarations are broadly tested generically in SkSL. Here we are
667*c8dee2aaSAndroid Build Coastguard Worker     // concerned with agreement between VS and FS declarations, which is a unique aspect of
668*c8dee2aaSAndroid Build Coastguard Worker     // SkMeshSpecification.
669*c8dee2aaSAndroid Build Coastguard Worker 
670*c8dee2aaSAndroid Build Coastguard Worker     // Each test case is a fs and vs uniform declaration with the same name but some other
671*c8dee2aaSAndroid Build Coastguard Worker     // difference that should make them incompatible.
672*c8dee2aaSAndroid Build Coastguard Worker     static std::tuple<const char*, const char*> kTestCases[]{
673*c8dee2aaSAndroid Build Coastguard Worker             // different types
674*c8dee2aaSAndroid Build Coastguard Worker             {"uniform float x;", "uniform int x;"},
675*c8dee2aaSAndroid Build Coastguard Worker             // array vs non-array
676*c8dee2aaSAndroid Build Coastguard Worker             {"uniform float2x2 m[1];", "uniform float2x2 m;"},
677*c8dee2aaSAndroid Build Coastguard Worker             // array count mismatch
678*c8dee2aaSAndroid Build Coastguard Worker             {"uniform int3 i[1];", "uniform int3 i[2];"},
679*c8dee2aaSAndroid Build Coastguard Worker             // layout difference
680*c8dee2aaSAndroid Build Coastguard Worker             {"layout(color) uniform float4 color;", "uniform float4 color;"},
681*c8dee2aaSAndroid Build Coastguard Worker     };
682*c8dee2aaSAndroid Build Coastguard Worker 
683*c8dee2aaSAndroid Build Coastguard Worker     for (bool reverse : {false, true}) {
684*c8dee2aaSAndroid Build Coastguard Worker         for (auto [u1, u2] : kTestCases) {
685*c8dee2aaSAndroid Build Coastguard Worker             if (reverse) {
686*c8dee2aaSAndroid Build Coastguard Worker                 using std::swap;
687*c8dee2aaSAndroid Build Coastguard Worker                 swap(u1, u2);
688*c8dee2aaSAndroid Build Coastguard Worker             }
689*c8dee2aaSAndroid Build Coastguard Worker             SkString vs = kValidVS;
690*c8dee2aaSAndroid Build Coastguard Worker             vs.prepend(u1);
691*c8dee2aaSAndroid Build Coastguard Worker 
692*c8dee2aaSAndroid Build Coastguard Worker             SkString fs = kValidFSes[0];
693*c8dee2aaSAndroid Build Coastguard Worker             fs.prepend(u2);
694*c8dee2aaSAndroid Build Coastguard Worker 
695*c8dee2aaSAndroid Build Coastguard Worker             auto attrs = SkSpan(kValidAttrs);
696*c8dee2aaSAndroid Build Coastguard Worker             auto varys = SkSpan(kValidVaryings);
697*c8dee2aaSAndroid Build Coastguard Worker             if (!check_for_failure(reporter, attrs, kValidStride, varys, vs, fs)) {
698*c8dee2aaSAndroid Build Coastguard Worker                 return;
699*c8dee2aaSAndroid Build Coastguard Worker             }
700*c8dee2aaSAndroid Build Coastguard Worker         }
701*c8dee2aaSAndroid Build Coastguard Worker     }
702*c8dee2aaSAndroid Build Coastguard Worker }
703*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_MissingMain,reporter)704*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_MissingMain, reporter) {
705*c8dee2aaSAndroid Build Coastguard Worker     static const SkString kHelper{"float2 swiz(float2 x) { return z.yx; }"};
706*c8dee2aaSAndroid Build Coastguard Worker 
707*c8dee2aaSAndroid Build Coastguard Worker     // Empty VS
708*c8dee2aaSAndroid Build Coastguard Worker     if (!check_for_failure(reporter,
709*c8dee2aaSAndroid Build Coastguard Worker                            kValidAttrs,
710*c8dee2aaSAndroid Build Coastguard Worker                            kValidStride,
711*c8dee2aaSAndroid Build Coastguard Worker                            kValidVaryings,
712*c8dee2aaSAndroid Build Coastguard Worker                            SkString{},
713*c8dee2aaSAndroid Build Coastguard Worker                            kValidFSes[0])) {
714*c8dee2aaSAndroid Build Coastguard Worker         return;
715*c8dee2aaSAndroid Build Coastguard Worker     }
716*c8dee2aaSAndroid Build Coastguard Worker 
717*c8dee2aaSAndroid Build Coastguard Worker     // VS with helper function but no main
718*c8dee2aaSAndroid Build Coastguard Worker     if (!check_for_failure(reporter,
719*c8dee2aaSAndroid Build Coastguard Worker                            kValidAttrs,
720*c8dee2aaSAndroid Build Coastguard Worker                            kValidStride,
721*c8dee2aaSAndroid Build Coastguard Worker                            kValidVaryings,
722*c8dee2aaSAndroid Build Coastguard Worker                            kHelper,
723*c8dee2aaSAndroid Build Coastguard Worker                            kValidFSes[0])) {
724*c8dee2aaSAndroid Build Coastguard Worker         return;
725*c8dee2aaSAndroid Build Coastguard Worker     }
726*c8dee2aaSAndroid Build Coastguard Worker 
727*c8dee2aaSAndroid Build Coastguard Worker     // Empty FS
728*c8dee2aaSAndroid Build Coastguard Worker     if (!check_for_failure(reporter,
729*c8dee2aaSAndroid Build Coastguard Worker                            kValidAttrs,
730*c8dee2aaSAndroid Build Coastguard Worker                            kValidStride,
731*c8dee2aaSAndroid Build Coastguard Worker                            kValidVaryings,
732*c8dee2aaSAndroid Build Coastguard Worker                            kValidVS,
733*c8dee2aaSAndroid Build Coastguard Worker                            SkString{})) {
734*c8dee2aaSAndroid Build Coastguard Worker         return;
735*c8dee2aaSAndroid Build Coastguard Worker     }
736*c8dee2aaSAndroid Build Coastguard Worker 
737*c8dee2aaSAndroid Build Coastguard Worker     // VS with helper function but no main
738*c8dee2aaSAndroid Build Coastguard Worker     if (!check_for_failure(reporter,
739*c8dee2aaSAndroid Build Coastguard Worker                            kValidAttrs,
740*c8dee2aaSAndroid Build Coastguard Worker                            kValidStride,
741*c8dee2aaSAndroid Build Coastguard Worker                            kValidVaryings,
742*c8dee2aaSAndroid Build Coastguard Worker                            kValidVS,
743*c8dee2aaSAndroid Build Coastguard Worker                            kHelper)) {
744*c8dee2aaSAndroid Build Coastguard Worker         return;
745*c8dee2aaSAndroid Build Coastguard Worker     }
746*c8dee2aaSAndroid Build Coastguard Worker }
747*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_ZeroAttributes,reporter)748*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_ZeroAttributes, reporter) {
749*c8dee2aaSAndroid Build Coastguard Worker     // We require at least one attribute
750*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
751*c8dee2aaSAndroid Build Coastguard Worker                       SkSpan<Attribute>(),
752*c8dee2aaSAndroid Build Coastguard Worker                       kValidStride,
753*c8dee2aaSAndroid Build Coastguard Worker                       kValidVaryings,
754*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
755*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
756*c8dee2aaSAndroid Build Coastguard Worker }
757*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_ZeroVaryings,reporter)758*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_ZeroVaryings, reporter) {
759*c8dee2aaSAndroid Build Coastguard Worker     // Varyings are not required.
760*c8dee2aaSAndroid Build Coastguard Worker     check_for_success(reporter,
761*c8dee2aaSAndroid Build Coastguard Worker                       kValidAttrs,
762*c8dee2aaSAndroid Build Coastguard Worker                       kValidStride,
763*c8dee2aaSAndroid Build Coastguard Worker                       SkSpan<Varying>(),
764*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
765*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
766*c8dee2aaSAndroid Build Coastguard Worker }
767*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_InvalidStride,reporter)768*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_InvalidStride, reporter) {
769*c8dee2aaSAndroid Build Coastguard Worker     // Zero stride
770*c8dee2aaSAndroid Build Coastguard Worker     if (!check_for_failure(reporter,
771*c8dee2aaSAndroid Build Coastguard Worker                            kValidAttrs,
772*c8dee2aaSAndroid Build Coastguard Worker                            0,
773*c8dee2aaSAndroid Build Coastguard Worker                            kValidVaryings,
774*c8dee2aaSAndroid Build Coastguard Worker                            kValidVS,
775*c8dee2aaSAndroid Build Coastguard Worker                            kValidFSes[0])) {
776*c8dee2aaSAndroid Build Coastguard Worker         return;
777*c8dee2aaSAndroid Build Coastguard Worker     }
778*c8dee2aaSAndroid Build Coastguard Worker 
779*c8dee2aaSAndroid Build Coastguard Worker     // Unaligned
780*c8dee2aaSAndroid Build Coastguard Worker     if (!check_for_failure(reporter,
781*c8dee2aaSAndroid Build Coastguard Worker                            kValidAttrs,
782*c8dee2aaSAndroid Build Coastguard Worker                            kValidStride + 1,
783*c8dee2aaSAndroid Build Coastguard Worker                            kValidVaryings,
784*c8dee2aaSAndroid Build Coastguard Worker                            kValidVS,
785*c8dee2aaSAndroid Build Coastguard Worker                            kValidFSes[0])) {
786*c8dee2aaSAndroid Build Coastguard Worker         return;
787*c8dee2aaSAndroid Build Coastguard Worker     }
788*c8dee2aaSAndroid Build Coastguard Worker 
789*c8dee2aaSAndroid Build Coastguard Worker     // Too large
790*c8dee2aaSAndroid Build Coastguard Worker     if (!check_for_failure(reporter,
791*c8dee2aaSAndroid Build Coastguard Worker                            kValidAttrs,
792*c8dee2aaSAndroid Build Coastguard Worker                            1 << 20,
793*c8dee2aaSAndroid Build Coastguard Worker                            kValidVaryings,
794*c8dee2aaSAndroid Build Coastguard Worker                            kValidVS,
795*c8dee2aaSAndroid Build Coastguard Worker                            kValidFSes[0])) {
796*c8dee2aaSAndroid Build Coastguard Worker         return;
797*c8dee2aaSAndroid Build Coastguard Worker     }
798*c8dee2aaSAndroid Build Coastguard Worker }
799*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_InvalidOffset,reporter)800*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_InvalidOffset, reporter) {
801*c8dee2aaSAndroid Build Coastguard Worker     {  // offset isn't aligned
802*c8dee2aaSAndroid Build Coastguard Worker         static const Attribute kAttributes[] {
803*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat4,  1, SkString{"var"}},
804*c8dee2aaSAndroid Build Coastguard Worker         };
805*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_failure(reporter,
806*c8dee2aaSAndroid Build Coastguard Worker                                kAttributes,
807*c8dee2aaSAndroid Build Coastguard Worker                                32,
808*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
809*c8dee2aaSAndroid Build Coastguard Worker                                kValidVS,
810*c8dee2aaSAndroid Build Coastguard Worker                                kValidFSes[0])) {
811*c8dee2aaSAndroid Build Coastguard Worker             return;
812*c8dee2aaSAndroid Build Coastguard Worker         }
813*c8dee2aaSAndroid Build Coastguard Worker     }
814*c8dee2aaSAndroid Build Coastguard Worker     {  // straddles stride boundary
815*c8dee2aaSAndroid Build Coastguard Worker         static const Attribute kAttributes[] {
816*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat4,   0, SkString{"var"}},
817*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat2,  16, SkString{"var"}},
818*c8dee2aaSAndroid Build Coastguard Worker         };
819*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_failure(reporter,
820*c8dee2aaSAndroid Build Coastguard Worker                                kAttributes,
821*c8dee2aaSAndroid Build Coastguard Worker                                20,
822*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
823*c8dee2aaSAndroid Build Coastguard Worker                                kValidVS,
824*c8dee2aaSAndroid Build Coastguard Worker                                kValidFSes[0])) {
825*c8dee2aaSAndroid Build Coastguard Worker             return;
826*c8dee2aaSAndroid Build Coastguard Worker         }
827*c8dee2aaSAndroid Build Coastguard Worker     }
828*c8dee2aaSAndroid Build Coastguard Worker     {  // straddles stride boundary with attempt to overflow
829*c8dee2aaSAndroid Build Coastguard Worker         static const Attribute kAttributes[] {
830*c8dee2aaSAndroid Build Coastguard Worker                 {Attribute::Type::kFloat, std::numeric_limits<size_t>::max() - 3, SkString{"var"}},
831*c8dee2aaSAndroid Build Coastguard Worker         };
832*c8dee2aaSAndroid Build Coastguard Worker         if (!check_for_failure(reporter,
833*c8dee2aaSAndroid Build Coastguard Worker                                kAttributes,
834*c8dee2aaSAndroid Build Coastguard Worker                                4,
835*c8dee2aaSAndroid Build Coastguard Worker                                kValidVaryings,
836*c8dee2aaSAndroid Build Coastguard Worker                                kValidVS,
837*c8dee2aaSAndroid Build Coastguard Worker                                kValidFSes[0])) {
838*c8dee2aaSAndroid Build Coastguard Worker             return;
839*c8dee2aaSAndroid Build Coastguard Worker         }
840*c8dee2aaSAndroid Build Coastguard Worker     }
841*c8dee2aaSAndroid Build Coastguard Worker }
842*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_TooManyAttributes,reporter)843*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_TooManyAttributes, reporter) {
844*c8dee2aaSAndroid Build Coastguard Worker     static constexpr size_t kN = 500;
845*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Attribute> attrs;
846*c8dee2aaSAndroid Build Coastguard Worker     attrs.reserve(kN);
847*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < kN; ++i) {
848*c8dee2aaSAndroid Build Coastguard Worker         attrs.push_back({Attribute::Type::kFloat4, 0, SkStringPrintf("attr%zu", i)});
849*c8dee2aaSAndroid Build Coastguard Worker     }
850*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
851*c8dee2aaSAndroid Build Coastguard Worker                       attrs,
852*c8dee2aaSAndroid Build Coastguard Worker                       4*4,
853*c8dee2aaSAndroid Build Coastguard Worker                       kValidVaryings,
854*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
855*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
856*c8dee2aaSAndroid Build Coastguard Worker }
857*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_TooManyVaryings,reporter)858*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_TooManyVaryings, reporter) {
859*c8dee2aaSAndroid Build Coastguard Worker     static constexpr size_t kN = 500;
860*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Varying> varyings;
861*c8dee2aaSAndroid Build Coastguard Worker     varyings.reserve(kN);
862*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < kN; ++i) {
863*c8dee2aaSAndroid Build Coastguard Worker         varyings.push_back({Varying::Type::kFloat4, SkStringPrintf("varying%zu", i)});
864*c8dee2aaSAndroid Build Coastguard Worker     }
865*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
866*c8dee2aaSAndroid Build Coastguard Worker                       kValidAttrs,
867*c8dee2aaSAndroid Build Coastguard Worker                       kValidStride,
868*c8dee2aaSAndroid Build Coastguard Worker                       SkSpan(varyings),
869*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
870*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
871*c8dee2aaSAndroid Build Coastguard Worker }
872*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_DuplicateAttributeNames,reporter)873*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_DuplicateAttributeNames, reporter) {
874*c8dee2aaSAndroid Build Coastguard Worker     static const Attribute kAttributes[] {
875*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kFloat4,  0, SkString{"var"}},
876*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kFloat2, 16, SkString{"var"}}
877*c8dee2aaSAndroid Build Coastguard Worker     };
878*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
879*c8dee2aaSAndroid Build Coastguard Worker                       kAttributes,
880*c8dee2aaSAndroid Build Coastguard Worker                       24,
881*c8dee2aaSAndroid Build Coastguard Worker                       kValidVaryings,
882*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
883*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
884*c8dee2aaSAndroid Build Coastguard Worker }
885*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_DuplicateVaryingNames,reporter)886*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_DuplicateVaryingNames, reporter) {
887*c8dee2aaSAndroid Build Coastguard Worker     static const Varying kVaryings[] {
888*c8dee2aaSAndroid Build Coastguard Worker         {Varying::Type::kFloat4, SkString{"var"}},
889*c8dee2aaSAndroid Build Coastguard Worker         {Varying::Type::kFloat3, SkString{"var"}}
890*c8dee2aaSAndroid Build Coastguard Worker     };
891*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
892*c8dee2aaSAndroid Build Coastguard Worker                       kValidAttrs,
893*c8dee2aaSAndroid Build Coastguard Worker                       kValidStride,
894*c8dee2aaSAndroid Build Coastguard Worker                       kVaryings,
895*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
896*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
897*c8dee2aaSAndroid Build Coastguard Worker }
898*c8dee2aaSAndroid Build Coastguard Worker 
899*c8dee2aaSAndroid Build Coastguard Worker static constexpr const char* kSneakyName = "name; float3 sneaky";
900*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_SneakyExtraAttribute,reporter)901*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_SneakyExtraAttribute, reporter) {
902*c8dee2aaSAndroid Build Coastguard Worker     static const Attribute kAttributes[] {
903*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kFloat4, 0, SkString{kSneakyName}},
904*c8dee2aaSAndroid Build Coastguard Worker     };
905*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
906*c8dee2aaSAndroid Build Coastguard Worker                       kAttributes,
907*c8dee2aaSAndroid Build Coastguard Worker                       16,
908*c8dee2aaSAndroid Build Coastguard Worker                       kValidVaryings,
909*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
910*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
911*c8dee2aaSAndroid Build Coastguard Worker }
912*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_SneakyExtraVarying,reporter)913*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_SneakyExtraVarying, reporter) {
914*c8dee2aaSAndroid Build Coastguard Worker     static const Varying kVaryings[] {
915*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kFloat4, SkString{kSneakyName}},
916*c8dee2aaSAndroid Build Coastguard Worker     };
917*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
918*c8dee2aaSAndroid Build Coastguard Worker                       kValidAttrs,
919*c8dee2aaSAndroid Build Coastguard Worker                       kValidStride,
920*c8dee2aaSAndroid Build Coastguard Worker                       kVaryings,
921*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
922*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
923*c8dee2aaSAndroid Build Coastguard Worker }
924*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_AllowsFloat2PositionVarying,reporter)925*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_AllowsFloat2PositionVarying, reporter) {
926*c8dee2aaSAndroid Build Coastguard Worker     // Position varying can be explicit if it is float2
927*c8dee2aaSAndroid Build Coastguard Worker     static const Varying kVaryings[] {
928*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kFloat2, SkString{"position"}},
929*c8dee2aaSAndroid Build Coastguard Worker     };
930*c8dee2aaSAndroid Build Coastguard Worker     check_for_success(reporter,
931*c8dee2aaSAndroid Build Coastguard Worker                       kValidAttrs,
932*c8dee2aaSAndroid Build Coastguard Worker                       kValidStride,
933*c8dee2aaSAndroid Build Coastguard Worker                       kVaryings,
934*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
935*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
936*c8dee2aaSAndroid Build Coastguard Worker }
937*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_InvalidPositionType,reporter)938*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_InvalidPositionType, reporter) {
939*c8dee2aaSAndroid Build Coastguard Worker     // Position varying can be explicit but it must be float2
940*c8dee2aaSAndroid Build Coastguard Worker     static const Varying kVaryings[] {
941*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kFloat4, SkString{"position"}},
942*c8dee2aaSAndroid Build Coastguard Worker     };
943*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
944*c8dee2aaSAndroid Build Coastguard Worker                       kValidAttrs,
945*c8dee2aaSAndroid Build Coastguard Worker                       kValidStride,
946*c8dee2aaSAndroid Build Coastguard Worker                       kVaryings,
947*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
948*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
949*c8dee2aaSAndroid Build Coastguard Worker }
950*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_EmptyAttributeName,reporter)951*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_EmptyAttributeName, reporter) {
952*c8dee2aaSAndroid Build Coastguard Worker     static const Attribute kAttributes[] {
953*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kFloat4, 0, SkString{}},
954*c8dee2aaSAndroid Build Coastguard Worker     };
955*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
956*c8dee2aaSAndroid Build Coastguard Worker                       kAttributes,
957*c8dee2aaSAndroid Build Coastguard Worker                       16,
958*c8dee2aaSAndroid Build Coastguard Worker                       kValidVaryings,
959*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
960*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
961*c8dee2aaSAndroid Build Coastguard Worker }
962*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpec_EmptyVaryingName,reporter)963*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpec_EmptyVaryingName, reporter) {
964*c8dee2aaSAndroid Build Coastguard Worker     static const Varying kVaryings[] {
965*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kFloat4, SkString{}},
966*c8dee2aaSAndroid Build Coastguard Worker     };
967*c8dee2aaSAndroid Build Coastguard Worker     check_for_failure(reporter,
968*c8dee2aaSAndroid Build Coastguard Worker                       kValidAttrs,
969*c8dee2aaSAndroid Build Coastguard Worker                       kValidStride,
970*c8dee2aaSAndroid Build Coastguard Worker                       kVaryings,
971*c8dee2aaSAndroid Build Coastguard Worker                       kValidVS,
972*c8dee2aaSAndroid Build Coastguard Worker                       kValidFSes[0]);
973*c8dee2aaSAndroid Build Coastguard Worker }
974*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpecVaryingPassthrough,reporter)975*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpecVaryingPassthrough, reporter) {
976*c8dee2aaSAndroid Build Coastguard Worker     static const Attribute kAttributes[]{
977*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kFloat2,        0, SkString{"position"}},
978*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kFloat2,        8, SkString{"uv"}      },
979*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kUByte4_unorm, 16, SkString{"color"}   },
980*c8dee2aaSAndroid Build Coastguard Worker     };
981*c8dee2aaSAndroid Build Coastguard Worker     static const Varying kVaryings[]{
982*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kFloat2, SkString{"position"}},
983*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kFloat2, SkString{"uv"}      },
984*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kHalf4,  SkString{"color"}   },
985*c8dee2aaSAndroid Build Coastguard Worker     };
986*c8dee2aaSAndroid Build Coastguard Worker 
987*c8dee2aaSAndroid Build Coastguard Worker     static constexpr char kVS[] = R"(
988*c8dee2aaSAndroid Build Coastguard Worker             Varyings main(const Attributes a) {
989*c8dee2aaSAndroid Build Coastguard Worker                 Varyings v;
990*c8dee2aaSAndroid Build Coastguard Worker                 v.uv       = a.uv;
991*c8dee2aaSAndroid Build Coastguard Worker                 v.position = a.position;
992*c8dee2aaSAndroid Build Coastguard Worker                 v.color    = a.color;
993*c8dee2aaSAndroid Build Coastguard Worker                 return v;
994*c8dee2aaSAndroid Build Coastguard Worker             }
995*c8dee2aaSAndroid Build Coastguard Worker     )";
996*c8dee2aaSAndroid Build Coastguard Worker     auto check = [&] (const char* fs, const char* passthroughAttr) {
997*c8dee2aaSAndroid Build Coastguard Worker         auto [spec, error] = SkMeshSpecification::Make(kAttributes,
998*c8dee2aaSAndroid Build Coastguard Worker                                                        /*vertexStride=*/24,
999*c8dee2aaSAndroid Build Coastguard Worker                                                        kVaryings,
1000*c8dee2aaSAndroid Build Coastguard Worker                                                        SkString(kVS),
1001*c8dee2aaSAndroid Build Coastguard Worker                                                        SkString(fs));
1002*c8dee2aaSAndroid Build Coastguard Worker         if (!spec) {
1003*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(reporter, "%s\n%s", fs, error.c_str());
1004*c8dee2aaSAndroid Build Coastguard Worker             return;
1005*c8dee2aaSAndroid Build Coastguard Worker         }
1006*c8dee2aaSAndroid Build Coastguard Worker         int idx = SkMeshSpecificationPriv::PassthroughLocalCoordsVaryingIndex(*spec);
1007*c8dee2aaSAndroid Build Coastguard Worker         const SkString& actualAttr = idx >= 0 ? spec->attributes()[idx].name : SkString("<none>");
1008*c8dee2aaSAndroid Build Coastguard Worker         if (!passthroughAttr) {
1009*c8dee2aaSAndroid Build Coastguard Worker             if (idx >= 0) {
1010*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(reporter, "Expected no passthrough coords attribute, found %s.\n%s",
1011*c8dee2aaSAndroid Build Coastguard Worker                        actualAttr.c_str(),
1012*c8dee2aaSAndroid Build Coastguard Worker                        fs);
1013*c8dee2aaSAndroid Build Coastguard Worker             }
1014*c8dee2aaSAndroid Build Coastguard Worker         } else if (!actualAttr.equals(passthroughAttr)) {
1015*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(reporter, "Expected %s as passthrough coords attribute, found %s.\n%s",
1016*c8dee2aaSAndroid Build Coastguard Worker                    passthroughAttr,
1017*c8dee2aaSAndroid Build Coastguard Worker                    actualAttr.c_str(),
1018*c8dee2aaSAndroid Build Coastguard Worker                    fs);
1019*c8dee2aaSAndroid Build Coastguard Worker         }
1020*c8dee2aaSAndroid Build Coastguard Worker     };
1021*c8dee2aaSAndroid Build Coastguard Worker 
1022*c8dee2aaSAndroid Build Coastguard Worker     // Simple
1023*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v) {
1024*c8dee2aaSAndroid Build Coastguard Worker                   return v.uv;
1025*c8dee2aaSAndroid Build Coastguard Worker               })",
1026*c8dee2aaSAndroid Build Coastguard Worker           "uv");
1027*c8dee2aaSAndroid Build Coastguard Worker 
1028*c8dee2aaSAndroid Build Coastguard Worker     // Simple, using position
1029*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v) {
1030*c8dee2aaSAndroid Build Coastguard Worker                   return v.position;
1031*c8dee2aaSAndroid Build Coastguard Worker               })",
1032*c8dee2aaSAndroid Build Coastguard Worker           "position");
1033*c8dee2aaSAndroid Build Coastguard Worker 
1034*c8dee2aaSAndroid Build Coastguard Worker     // Simple, with output color
1035*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v, out half4 color) {
1036*c8dee2aaSAndroid Build Coastguard Worker                   color = v.color;
1037*c8dee2aaSAndroid Build Coastguard Worker                   return v.uv;
1038*c8dee2aaSAndroid Build Coastguard Worker               })",
1039*c8dee2aaSAndroid Build Coastguard Worker           "uv");
1040*c8dee2aaSAndroid Build Coastguard Worker 
1041*c8dee2aaSAndroid Build Coastguard Worker     // Three returns, all the same.
1042*c8dee2aaSAndroid Build Coastguard Worker     check(R"(uniform int selector;
1043*c8dee2aaSAndroid Build Coastguard Worker 
1044*c8dee2aaSAndroid Build Coastguard Worker              float2 main(const Varyings v, out half4 color) {
1045*c8dee2aaSAndroid Build Coastguard Worker                   if (selector == 0) {
1046*c8dee2aaSAndroid Build Coastguard Worker                       color = half4(1, 0, 0, 1);
1047*c8dee2aaSAndroid Build Coastguard Worker                       return v.position;
1048*c8dee2aaSAndroid Build Coastguard Worker                   }
1049*c8dee2aaSAndroid Build Coastguard Worker                   if (selector == 1) {
1050*c8dee2aaSAndroid Build Coastguard Worker                       color = half4(1, 1, 0, 1);
1051*c8dee2aaSAndroid Build Coastguard Worker                       return v.position;
1052*c8dee2aaSAndroid Build Coastguard Worker                   }
1053*c8dee2aaSAndroid Build Coastguard Worker                   color = half4(1, 0, 1, 1);
1054*c8dee2aaSAndroid Build Coastguard Worker                   return v.position;
1055*c8dee2aaSAndroid Build Coastguard Worker              })",
1056*c8dee2aaSAndroid Build Coastguard Worker           "position");
1057*c8dee2aaSAndroid Build Coastguard Worker 
1058*c8dee2aaSAndroid Build Coastguard Worker     // Three returns, one not like the others
1059*c8dee2aaSAndroid Build Coastguard Worker     check(R"(uniform int selector;
1060*c8dee2aaSAndroid Build Coastguard Worker 
1061*c8dee2aaSAndroid Build Coastguard Worker              float2 main(const Varyings v, out half4 color) {
1062*c8dee2aaSAndroid Build Coastguard Worker                   if (selector == 0) {
1063*c8dee2aaSAndroid Build Coastguard Worker                       color = color.bgra;
1064*c8dee2aaSAndroid Build Coastguard Worker                       return v.position;
1065*c8dee2aaSAndroid Build Coastguard Worker                   }
1066*c8dee2aaSAndroid Build Coastguard Worker                   if (selector == 1) {
1067*c8dee2aaSAndroid Build Coastguard Worker                       color = half4(1);
1068*c8dee2aaSAndroid Build Coastguard Worker                       return v.uv;
1069*c8dee2aaSAndroid Build Coastguard Worker                   }
1070*c8dee2aaSAndroid Build Coastguard Worker                   color = color;
1071*c8dee2aaSAndroid Build Coastguard Worker                   return v.position;
1072*c8dee2aaSAndroid Build Coastguard Worker              })",
1073*c8dee2aaSAndroid Build Coastguard Worker           nullptr);
1074*c8dee2aaSAndroid Build Coastguard Worker 
1075*c8dee2aaSAndroid Build Coastguard Worker     // Swizzles aren't handled (yet?).
1076*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v) {
1077*c8dee2aaSAndroid Build Coastguard Worker                   return v.uv.yx;
1078*c8dee2aaSAndroid Build Coastguard Worker               })",
1079*c8dee2aaSAndroid Build Coastguard Worker           nullptr);
1080*c8dee2aaSAndroid Build Coastguard Worker 
1081*c8dee2aaSAndroid Build Coastguard Worker     // Return from non-main fools us?
1082*c8dee2aaSAndroid Build Coastguard Worker     check(R"(noinline half4 get_color(const Varyings v) { return v.color; }
1083*c8dee2aaSAndroid Build Coastguard Worker 
1084*c8dee2aaSAndroid Build Coastguard Worker              float2 main(const Varyings v, out half4 color) {
1085*c8dee2aaSAndroid Build Coastguard Worker                   color = get_color(v);
1086*c8dee2aaSAndroid Build Coastguard Worker                   return v.position;
1087*c8dee2aaSAndroid Build Coastguard Worker               })",
1088*c8dee2aaSAndroid Build Coastguard Worker           "position");
1089*c8dee2aaSAndroid Build Coastguard Worker }
1090*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MeshSpecUnusedVaryings,reporter)1091*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MeshSpecUnusedVaryings, reporter) {
1092*c8dee2aaSAndroid Build Coastguard Worker     static const Attribute kAttributes[]{
1093*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kFloat2,        0, SkString{"position"}},
1094*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kFloat2,        8, SkString{"uv"}      },
1095*c8dee2aaSAndroid Build Coastguard Worker             {Attribute::Type::kUByte4_unorm, 16, SkString{"color"}   },
1096*c8dee2aaSAndroid Build Coastguard Worker     };
1097*c8dee2aaSAndroid Build Coastguard Worker     static const Varying kVaryings[]{
1098*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kFloat2, SkString{"position"}},
1099*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kFloat2, SkString{"uv"}      },
1100*c8dee2aaSAndroid Build Coastguard Worker             {Varying::Type::kHalf4,  SkString{"color"}   },
1101*c8dee2aaSAndroid Build Coastguard Worker     };
1102*c8dee2aaSAndroid Build Coastguard Worker 
1103*c8dee2aaSAndroid Build Coastguard Worker     static constexpr char kVS[] = R"(
1104*c8dee2aaSAndroid Build Coastguard Worker             Varyings main(const Attributes a) {
1105*c8dee2aaSAndroid Build Coastguard Worker                 Varyings v;
1106*c8dee2aaSAndroid Build Coastguard Worker                 v.uv       = a.uv;
1107*c8dee2aaSAndroid Build Coastguard Worker                 v.position = a.position;
1108*c8dee2aaSAndroid Build Coastguard Worker                 v.color    = a.color;
1109*c8dee2aaSAndroid Build Coastguard Worker                 return v;
1110*c8dee2aaSAndroid Build Coastguard Worker             }
1111*c8dee2aaSAndroid Build Coastguard Worker     )";
1112*c8dee2aaSAndroid Build Coastguard Worker 
1113*c8dee2aaSAndroid Build Coastguard Worker     auto check = [&](const char* fs, bool positionDead, bool uvDead, bool colorDead) {
1114*c8dee2aaSAndroid Build Coastguard Worker         static_assert(std::size(kVaryings) == 3);
1115*c8dee2aaSAndroid Build Coastguard Worker         auto [spec, error] = SkMeshSpecification::Make(kAttributes,
1116*c8dee2aaSAndroid Build Coastguard Worker                                                        /*vertexStride=*/24,
1117*c8dee2aaSAndroid Build Coastguard Worker                                                        kVaryings,
1118*c8dee2aaSAndroid Build Coastguard Worker                                                        SkString(kVS),
1119*c8dee2aaSAndroid Build Coastguard Worker                                                        SkString(fs));
1120*c8dee2aaSAndroid Build Coastguard Worker         if (!spec) {
1121*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(reporter, "%s\n%s", fs, error.c_str());
1122*c8dee2aaSAndroid Build Coastguard Worker             return;
1123*c8dee2aaSAndroid Build Coastguard Worker         }
1124*c8dee2aaSAndroid Build Coastguard Worker         bool positionActuallyDead = SkMeshSpecificationPriv::VaryingIsDead(*spec, 0);
1125*c8dee2aaSAndroid Build Coastguard Worker         bool uvActuallyDead       = SkMeshSpecificationPriv::VaryingIsDead(*spec, 1);
1126*c8dee2aaSAndroid Build Coastguard Worker         bool colorActuallyDead    = SkMeshSpecificationPriv::VaryingIsDead(*spec, 2);
1127*c8dee2aaSAndroid Build Coastguard Worker         auto str = [](bool dead) { return dead ? "dead" : "not dead"; };
1128*c8dee2aaSAndroid Build Coastguard Worker         if (positionActuallyDead != positionDead) {
1129*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(reporter,
1130*c8dee2aaSAndroid Build Coastguard Worker                    "Expected position to be detected %s but it is detected %s.\n%s",
1131*c8dee2aaSAndroid Build Coastguard Worker                    str(positionDead),
1132*c8dee2aaSAndroid Build Coastguard Worker                    str(positionActuallyDead),
1133*c8dee2aaSAndroid Build Coastguard Worker                    fs);
1134*c8dee2aaSAndroid Build Coastguard Worker         }
1135*c8dee2aaSAndroid Build Coastguard Worker         if (uvActuallyDead != uvDead) {
1136*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(reporter,
1137*c8dee2aaSAndroid Build Coastguard Worker                    "Expected uv to be detected %s but it is detected %s.\n%s",
1138*c8dee2aaSAndroid Build Coastguard Worker                    str(uvDead),
1139*c8dee2aaSAndroid Build Coastguard Worker                    str(uvActuallyDead),
1140*c8dee2aaSAndroid Build Coastguard Worker                    fs);
1141*c8dee2aaSAndroid Build Coastguard Worker         }
1142*c8dee2aaSAndroid Build Coastguard Worker         if (colorActuallyDead != colorDead) {
1143*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(reporter,
1144*c8dee2aaSAndroid Build Coastguard Worker                    "Expected color to be detected %s but it is detected %s.\n%s",
1145*c8dee2aaSAndroid Build Coastguard Worker                    str(colorDead),
1146*c8dee2aaSAndroid Build Coastguard Worker                    str(colorActuallyDead),
1147*c8dee2aaSAndroid Build Coastguard Worker                    fs);
1148*c8dee2aaSAndroid Build Coastguard Worker         }
1149*c8dee2aaSAndroid Build Coastguard Worker     };
1150*c8dee2aaSAndroid Build Coastguard Worker 
1151*c8dee2aaSAndroid Build Coastguard Worker     // Simple
1152*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v) {
1153*c8dee2aaSAndroid Build Coastguard Worker                  return v.uv;
1154*c8dee2aaSAndroid Build Coastguard Worker              })",
1155*c8dee2aaSAndroid Build Coastguard Worker           true,
1156*c8dee2aaSAndroid Build Coastguard Worker           true,
1157*c8dee2aaSAndroid Build Coastguard Worker           true);
1158*c8dee2aaSAndroid Build Coastguard Worker 
1159*c8dee2aaSAndroid Build Coastguard Worker     // Simple, using position
1160*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v) {
1161*c8dee2aaSAndroid Build Coastguard Worker                  return v.position;
1162*c8dee2aaSAndroid Build Coastguard Worker              })",
1163*c8dee2aaSAndroid Build Coastguard Worker           true,
1164*c8dee2aaSAndroid Build Coastguard Worker           true,
1165*c8dee2aaSAndroid Build Coastguard Worker           true);
1166*c8dee2aaSAndroid Build Coastguard Worker 
1167*c8dee2aaSAndroid Build Coastguard Worker     // Two returns that are both passthrough of the same varying
1168*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v, out half4 color) {
1169*c8dee2aaSAndroid Build Coastguard Worker                  if (v.color.r > 0.5) {
1170*c8dee2aaSAndroid Build Coastguard Worker                      color = v.color;
1171*c8dee2aaSAndroid Build Coastguard Worker                      return v.uv;
1172*c8dee2aaSAndroid Build Coastguard Worker                  } else {
1173*c8dee2aaSAndroid Build Coastguard Worker                      color = 2*color;
1174*c8dee2aaSAndroid Build Coastguard Worker                      return v.uv;
1175*c8dee2aaSAndroid Build Coastguard Worker                  }
1176*c8dee2aaSAndroid Build Coastguard Worker              })",
1177*c8dee2aaSAndroid Build Coastguard Worker           true,
1178*c8dee2aaSAndroid Build Coastguard Worker           true,
1179*c8dee2aaSAndroid Build Coastguard Worker           false);
1180*c8dee2aaSAndroid Build Coastguard Worker 
1181*c8dee2aaSAndroid Build Coastguard Worker     // Two returns that are both passthrough of the different varyings and unused other varying
1182*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v, out half4 color) {
1183*c8dee2aaSAndroid Build Coastguard Worker                  if (v.position.x > 10) {
1184*c8dee2aaSAndroid Build Coastguard Worker                      color = half4(0);
1185*c8dee2aaSAndroid Build Coastguard Worker                      return v.uv;
1186*c8dee2aaSAndroid Build Coastguard Worker                  } else {
1187*c8dee2aaSAndroid Build Coastguard Worker                      color = half4(1);
1188*c8dee2aaSAndroid Build Coastguard Worker                      return v.position;
1189*c8dee2aaSAndroid Build Coastguard Worker                  }
1190*c8dee2aaSAndroid Build Coastguard Worker              })",
1191*c8dee2aaSAndroid Build Coastguard Worker           false,
1192*c8dee2aaSAndroid Build Coastguard Worker           false,
1193*c8dee2aaSAndroid Build Coastguard Worker           true);
1194*c8dee2aaSAndroid Build Coastguard Worker 
1195*c8dee2aaSAndroid Build Coastguard Worker     // Passthrough but we also use the varying elsewhere
1196*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v, out half4 color) {
1197*c8dee2aaSAndroid Build Coastguard Worker                  color = half4(v.uv.x, 0, 0, 1);
1198*c8dee2aaSAndroid Build Coastguard Worker                  return v.uv;
1199*c8dee2aaSAndroid Build Coastguard Worker              })",
1200*c8dee2aaSAndroid Build Coastguard Worker           true,
1201*c8dee2aaSAndroid Build Coastguard Worker           false,
1202*c8dee2aaSAndroid Build Coastguard Worker           true);
1203*c8dee2aaSAndroid Build Coastguard Worker 
1204*c8dee2aaSAndroid Build Coastguard Worker     // Use two varyings is a return statement
1205*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v) {
1206*c8dee2aaSAndroid Build Coastguard Worker                   return v.uv + v.position;
1207*c8dee2aaSAndroid Build Coastguard Worker               })",
1208*c8dee2aaSAndroid Build Coastguard Worker           false,
1209*c8dee2aaSAndroid Build Coastguard Worker           false,
1210*c8dee2aaSAndroid Build Coastguard Worker           true);
1211*c8dee2aaSAndroid Build Coastguard Worker 
1212*c8dee2aaSAndroid Build Coastguard Worker     // Slightly more complicated varying use.
1213*c8dee2aaSAndroid Build Coastguard Worker     check(R"(noinline vec2 get_pos(const Varyings v) { return v.position; }
1214*c8dee2aaSAndroid Build Coastguard Worker 
1215*c8dee2aaSAndroid Build Coastguard Worker              noinline half4 identity(half4 c) { return c; }
1216*c8dee2aaSAndroid Build Coastguard Worker 
1217*c8dee2aaSAndroid Build Coastguard Worker              float2 main(const Varyings v, out half4 color) {
1218*c8dee2aaSAndroid Build Coastguard Worker                  color = identity(v.color);
1219*c8dee2aaSAndroid Build Coastguard Worker                  return v.uv + get_pos(v);
1220*c8dee2aaSAndroid Build Coastguard Worker              })",
1221*c8dee2aaSAndroid Build Coastguard Worker           false,
1222*c8dee2aaSAndroid Build Coastguard Worker           false,
1223*c8dee2aaSAndroid Build Coastguard Worker           false);
1224*c8dee2aaSAndroid Build Coastguard Worker 
1225*c8dee2aaSAndroid Build Coastguard Worker     // Go through assignment to another Varyings.
1226*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v) {
1227*c8dee2aaSAndroid Build Coastguard Worker                  Varyings otherVaryings;
1228*c8dee2aaSAndroid Build Coastguard Worker                  otherVaryings = v;
1229*c8dee2aaSAndroid Build Coastguard Worker                  return otherVaryings.uv;
1230*c8dee2aaSAndroid Build Coastguard Worker              })",
1231*c8dee2aaSAndroid Build Coastguard Worker           true,
1232*c8dee2aaSAndroid Build Coastguard Worker           false,
1233*c8dee2aaSAndroid Build Coastguard Worker           true);
1234*c8dee2aaSAndroid Build Coastguard Worker 
1235*c8dee2aaSAndroid Build Coastguard Worker     // We're not very smart. We just look for any use of the field in any Varyings value and don't
1236*c8dee2aaSAndroid Build Coastguard Worker     // do any data flow analysis.
1237*c8dee2aaSAndroid Build Coastguard Worker     check(R"(float2 main(const Varyings v) {
1238*c8dee2aaSAndroid Build Coastguard Worker                  Varyings otherVaryings;
1239*c8dee2aaSAndroid Build Coastguard Worker                  otherVaryings.uv       = half2(5);
1240*c8dee2aaSAndroid Build Coastguard Worker                  otherVaryings.position = half2(10);
1241*c8dee2aaSAndroid Build Coastguard Worker                  return otherVaryings.position;
1242*c8dee2aaSAndroid Build Coastguard Worker              })",
1243*c8dee2aaSAndroid Build Coastguard Worker           false,
1244*c8dee2aaSAndroid Build Coastguard Worker           false,
1245*c8dee2aaSAndroid Build Coastguard Worker           true);
1246*c8dee2aaSAndroid Build Coastguard Worker }
1247