Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Typedefs | Functions | Variables
MeshTest.cpp File Reference
#include "include/core/SkBlendMode.h"
#include "include/core/SkBlender.h"
#include "include/core/SkColor.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkData.h"
#include "include/core/SkMesh.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkShader.h"
#include "include/core/SkSpan.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "include/effects/SkRuntimeEffect.h"
#include "src/base/SkZip.h"
#include "src/core/SkMeshPriv.h"
#include "tests/Test.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <limits>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>

Go to the source code of this file.

Typedefs

using Attribute = SkMeshSpecification::Attribute
 
using Varying = SkMeshSpecification::Varying
 

Functions

static const char * attr_type_str (const Attribute::Type type)
 
static const char * var_type_str (const Varying::Type type)
 
static SkString make_description (SkSpan< const Attribute > attributes, size_t stride, SkSpan< const Varying > varyings, const SkString &vs, const SkString &fs)
 
static bool 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)
 
static bool 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)
 
 DEF_TEST (MeshSpec_Valid, reporter)
 
 DEF_TEST (MeshSpec_InvalidSignature, reporter)
 
 DEF_TEST (MeshSpec_Float4Color, reporter)
 
 DEF_TEST (MeshSpec_DisallowsChildEffectInVertex, reporter)
 
 DEF_TEST (MeshSpec_AllowsChildEffectInFragment, reporter)
 
 DEF_TEST (MeshSpec_FindChild, reporter)
 
 DEF_TEST (Mesh_ChildEffectsMatchSpec, reporter)
 
 DEF_TEST (MeshSpec_ValidUniforms, reporter)
 
 DEF_TEST (MeshSpec_InvalidUniforms, reporter)
 
 DEF_TEST (MeshSpec_MissingMain, reporter)
 
 DEF_TEST (MeshSpec_ZeroAttributes, reporter)
 
 DEF_TEST (MeshSpec_ZeroVaryings, reporter)
 
 DEF_TEST (MeshSpec_InvalidStride, reporter)
 
 DEF_TEST (MeshSpec_InvalidOffset, reporter)
 
 DEF_TEST (MeshSpec_TooManyAttributes, reporter)
 
 DEF_TEST (MeshSpec_TooManyVaryings, reporter)
 
 DEF_TEST (MeshSpec_DuplicateAttributeNames, reporter)
 
 DEF_TEST (MeshSpec_DuplicateVaryingNames, reporter)
 
 DEF_TEST (MeshSpec_SneakyExtraAttribute, reporter)
 
 DEF_TEST (MeshSpec_SneakyExtraVarying, reporter)
 
 DEF_TEST (MeshSpec_AllowsFloat2PositionVarying, reporter)
 
 DEF_TEST (MeshSpec_InvalidPositionType, reporter)
 
 DEF_TEST (MeshSpec_EmptyAttributeName, reporter)
 
 DEF_TEST (MeshSpec_EmptyVaryingName, reporter)
 
 DEF_TEST (MeshSpecVaryingPassthrough, reporter)
 
 DEF_TEST (MeshSpecUnusedVaryings, reporter)
 

Variables

static const SkString kValidVS
 
static const SkString kValidFSes []
 
static const Attribute kValidAttrs []
 
static constexpr size_t kValidStride = 4*4
 
static const Varying kValidVaryings []
 
static constexpr const char * kSneakyName = "name; float3 sneaky"
 

Typedef Documentation

◆ Attribute

Definition at line 36 of file MeshTest.cpp.

◆ Varying

Definition at line 37 of file MeshTest.cpp.

Function Documentation

◆ attr_type_str()

static const char * attr_type_str ( const Attribute::Type  type)
static

Definition at line 39 of file MeshTest.cpp.

◆ check_for_failure()

static bool 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 
)
static

Definition at line 94 of file MeshTest.cpp.

100 {
101 auto [spec, error] = SkMeshSpecification::Make(attributes, stride, varyings, vs, fs);
102 if (spec) {
104 "Expected to fail but succeeded:\n%s",
105 make_description(attributes, stride, varyings, vs, fs).c_str());
106 return false;
107 }
108 if (expectedErrorSubstring && !error.contains(expectedErrorSubstring)) {
110 " Expected: %s\n"
111 "Actual error: %s\n",
112 expectedErrorSubstring, error.c_str());
113 return false;
114 }
115 return true;
116}
reporter
static SkString make_description(SkSpan< const Attribute > attributes, size_t stride, SkSpan< const Varying > varyings, const SkString &vs, const SkString &fs)
Definition MeshTest.cpp:64
#define ERRORF(r,...)
Definition Test.h:293
static Result Make(SkSpan< const Attribute > attributes, size_t vertexStride, SkSpan< const Varying > varyings, const SkString &vs, const SkString &fs)
Definition SkMesh.cpp:389
const uint8_t uint32_t uint32_t GError ** error

◆ check_for_success()

static bool 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 
)
static

Definition at line 118 of file MeshTest.cpp.

124 {
125 auto [s, error] = SkMeshSpecification::Make(attributes, stride, varyings, vs, fs);
126 if (s) {
127 REPORTER_ASSERT(reporter, error.isEmpty());
128 if (spec) {
129 *spec = std::move(s);
130 }
131 return true;
132 }
134 "Expected to succeed but failed:\n%sError:\n%s",
135 make_description(attributes, stride, varyings, vs, fs).c_str(),
136 error.c_str());
137 return false;
138}
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
const char * c_str() const
Definition SkString.h:133
struct MyStruct s

◆ DEF_TEST() [1/26]

DEF_TEST ( Mesh_ChildEffectsMatchSpec  ,
reporter   
)

Definition at line 349 of file MeshTest.cpp.

353 {
354 auto test = [&](const char* prefix,
356 const char* expectedError = nullptr) {
357 SkString fsWithChild{prefix};
358 fsWithChild.append(kValidFSes[0]);
359
365 kValidVS,
366 fsWithChild,
367 &meshSpec)) {
368 return;
369 }
370
371 constexpr float kVertexCount = 4;
372 sk_sp<SkMesh::VertexBuffer> vertexBuffer =
376 vertexBuffer,
378 /*vertexOffset=*/0,
379 /*uniforms=*/nullptr,
380 children,
382
383 if (expectedError) {
384 REPORTER_ASSERT(reporter, !result.mesh.isValid());
386 result.error.contains(expectedError),
387 "Expected: '%s'\n"
388 " Actual: '%s'\n", expectedError, result.error.c_str());
389 } else {
390 REPORTER_ASSERT(reporter, result.mesh.isValid());
392 result.error.isEmpty(),
393 "Expected: no errors\n"
394 " Actual: '%s'\n", result.error.c_str());
395 }
396 };
397
398 SkRuntimeEffect::ChildPtr childShader[] = {SkShaders::Color(SK_ColorBLACK)};
401 SkRuntimeEffect::ChildPtr childNull[1] = {};
402
403 // These are expected to report a count mismatch.
404 test("uniform shader myshader;", {},
405 "The mesh specification declares 1 child effects, but the mesh supplies 0.");
406 test("", childShader,
407 "The mesh specification declares 0 child effects, but the mesh supplies 1.");
408
409 // These are expected to report a type mismatch.
410 test("uniform shader myshader;", childFilter,
411 "Child effect 'myshader' was specified as a shader, but passed as a color filter.");
412 test("uniform shader myshader;", childBlender,
413 "Child effect 'myshader' was specified as a shader, but passed as a blender.");
414 test("uniform colorFilter myfilter;", childShader,
415 "Child effect 'myfilter' was specified as a color filter, but passed as a shader.");
416 test("uniform colorFilter myfilter;", childBlender,
417 "Child effect 'myfilter' was specified as a color filter, but passed as a blender.");
418 test("uniform blender myblender;", childShader,
419 "Child effect 'myblender' was specified as a blender, but passed as a shader.");
420 test("uniform blender myblender;", childFilter,
421 "Child effect 'myblender' was specified as a blender, but passed as a color filter.");
422
423 // Null children are supported.
424 test("uniform shader myshader;", childNull);
425 test("uniform shader myfilter;", childNull);
426 test("uniform shader myblender;", childNull);
427
428 // Properly-typed child effects are supported.
429 test("uniform shader myshader;", childShader);
#define test(name)
static const size_t kVertexCount
static const Attribute kValidAttrs[]
Definition MeshTest.cpp:159
static const SkString kValidFSes[]
Definition MeshTest.cpp:148
static bool 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)
Definition MeshTest.cpp:118
static const SkString kValidVS
Definition MeshTest.cpp:141
static const Varying kValidVaryings[]
Definition MeshTest.cpp:163
static constexpr size_t kValidStride
Definition MeshTest.cpp:162
@ kSrcOver
r = s + (1-sa)*d
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
static sk_sp< SkBlender > Mode(SkBlendMode mode)
static sk_sp< SkColorFilter > LinearToSRGBGamma()
static Result Make(sk_sp< SkMeshSpecification >, Mode, sk_sp< VertexBuffer >, size_t vertexCount, size_t vertexOffset, sk_sp< const SkData > uniforms, SkSpan< ChildPtr > children, const SkRect &bounds)
Definition SkMesh.cpp:694
GAsyncResult * result
SK_API sk_sp< SkMesh::VertexBuffer > MakeVertexBuffer(const void *, size_t size)
Definition SkMesh.cpp:905
static constexpr SkRect MakeEmpty()
Definition SkRect.h:595

◆ DEF_TEST() [2/26]

DEF_TEST ( MeshSpec_AllowsChildEffectInFragment  ,
reporter   
)

Definition at line 304 of file MeshTest.cpp.

308 {
309 static constexpr const char* kChildEffects[] {
310 "uniform shader myshader;",
311 "uniform colorFilter mycolorfilter; uniform shader myshader;",
312 "uniform shader myshader; uniform blender myblender; uniform colorFilter mycolorfilter;"
313 };
314
315 for (const auto& global : kChildEffects) {
316 SkString fsWithChild{global};
317 fsWithChild.append(kValidFSes[0]);
318
323 kValidVS,
324 fsWithChild)) {
void append(const char text[])
Definition SkString.h:203

◆ DEF_TEST() [3/26]

DEF_TEST ( MeshSpec_AllowsFloat2PositionVarying  ,
reporter   
)

Definition at line 921 of file MeshTest.cpp.

925 {
926 // Position varying can be explicit if it is float2
927 static const Varying kVaryings[] {
928 {Varying::Type::kFloat2, SkString{"position"}},
929 };

◆ DEF_TEST() [4/26]

DEF_TEST ( MeshSpec_DisallowsChildEffectInVertex  ,
reporter   
)

Definition at line 268 of file MeshTest.cpp.

272 {
273 static constexpr const char* kChildEffects[] {
274 "uniform shader myshader;",
275 "uniform colorFilter mycolorfilter;",
276 "uniform blender myblender;"
277 };
278
279 for (const auto& global : kChildEffects) {
280 SkString vsWithChild{global};
281 vsWithChild.append(kValidVS);
282
283 SkString fsWithChild{global};
284 fsWithChild.append(kValidFSes[0]);
285
290 vsWithChild,
291 kValidFSes[0],
292 "effects are not permitted in mesh vertex shaders")) {
293 return;
294 }
295
300 vsWithChild,
301 fsWithChild,
302 "effects are not permitted in mesh vertex shaders")) {
static bool 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)
Definition MeshTest.cpp:94

◆ DEF_TEST() [5/26]

DEF_TEST ( MeshSpec_DuplicateAttributeNames  ,
reporter   
)

Definition at line 869 of file MeshTest.cpp.

873 {
874 static const Attribute kAttributes[] {
877 };
879 kAttributes,
880 24,

◆ DEF_TEST() [6/26]

DEF_TEST ( MeshSpec_DuplicateVaryingNames  ,
reporter   
)

Definition at line 882 of file MeshTest.cpp.

◆ DEF_TEST() [7/26]

DEF_TEST ( MeshSpec_EmptyAttributeName  ,
reporter   
)

Definition at line 947 of file MeshTest.cpp.

951 {
952 static const Attribute kAttributes[] {
954 };
956 kAttributes,
957 16,

◆ DEF_TEST() [8/26]

DEF_TEST ( MeshSpec_EmptyVaryingName  ,
reporter   
)

Definition at line 959 of file MeshTest.cpp.

963 {
964 static const Varying kVaryings[] {
966 };

◆ DEF_TEST() [9/26]

DEF_TEST ( MeshSpec_FindChild  ,
reporter   
)

Definition at line 326 of file MeshTest.cpp.

330 {
331 SkString fsWithChild{"uniform shader myshader;"
332 "uniform blender myblender;"
333 "uniform colorFilter mycolorfilter;"};
334 fsWithChild.append(kValidFSes[0]);
335
341 kValidVS,
342 fsWithChild,
343 &meshSpec)) {
344 return;
345 }
346
347 REPORTER_ASSERT(reporter, meshSpec->findChild("myshader")->index == 0);

◆ DEF_TEST() [10/26]

DEF_TEST ( MeshSpec_Float4Color  ,
reporter   
)

Definition at line 256 of file MeshTest.cpp.

256 {
257 static const SkString kFloat4FS {
258 R"(
259 float2 main(const Varyings varyings, out float4 color) {
260 color = float4(.2); return float2(10);
261 }
262 )"
263 };

◆ DEF_TEST() [11/26]

DEF_TEST ( MeshSpec_InvalidOffset  ,
reporter   
)

Definition at line 796 of file MeshTest.cpp.

800 {
801 { // offset isn't aligned
802 static const Attribute kAttributes[] {
804 };
806 kAttributes,
807 32,
809 kValidVS,
810 kValidFSes[0])) {
811 return;
812 }
813 }
814 { // straddles stride boundary
815 static const Attribute kAttributes[] {
818 };
820 kAttributes,
821 20,
823 kValidVS,
824 kValidFSes[0])) {
825 return;
826 }
827 }
828 { // straddles stride boundary with attempt to overflow
829 static const Attribute kAttributes[] {
830 {Attribute::Type::kFloat, std::numeric_limits<size_t>::max() - 3, SkString{"var"}},
831 };
833 kAttributes,
834 4,
836 kValidVS,
837 kValidFSes[0])) {

◆ DEF_TEST() [12/26]

DEF_TEST ( MeshSpec_InvalidPositionType  ,
reporter   
)

Definition at line 934 of file MeshTest.cpp.

938 {
939 // Position varying can be explicit but it must be float2
940 static const Varying kVaryings[] {
941 {Varying::Type::kFloat4, SkString{"position"}},
942 };

◆ DEF_TEST() [13/26]

DEF_TEST ( MeshSpec_InvalidSignature  ,
reporter   
)

Definition at line 180 of file MeshTest.cpp.

180 {
181 static constexpr const char* kVSBody = "{ return float2(10); }";
182
183 static constexpr const char* kInvalidVSSigs[] {
184 "float3 main(const Attributes attrs)", // bad return
185 "Varyings main(Attributes attrs)", // non-const Attributes
186 "Varyings main(out Attributes attrs)", // out Varyings
187 "Varyings main()", // no Attributes
188 "Varyings main(const Varyings v, float2)" // extra arg
189 };
190
191 static constexpr const char* kNoColorFSBody = "{ return float2(10); }";
192
193 static constexpr const char* kInvalidNoColorFSSigs[] {
194 "half2 main(const Varyings v)", // bad return
195 "float2 main(const Attributes v)", // wrong param type
196 "float2 main(inout Varyings attrs)", // inout Varyings
197 "float2 main(Varyings v)", // non-const Varyings
198 "float2 main()", // no args
199 "float2 main(const Varyings, float)" // extra arg
200 };
201
202 static constexpr const char* kColorFSBody = "{ color = half4(.2); return float2(10); }";
203
204 static constexpr const char* kInvalidColorFSSigs[] {
205 "half2 main(const Varyings v, out half4 color)", // bad return
206 "float2 main(const Attributes v, out half4 color)", // wrong first param type
207 "float2 main(const Varyings v, out half3 color)", // wrong second param type
208 "float2 main(out Varyings v, out half4 color)", // out Varyings
209 "float2 main(const Varyings v, half4 color)", // in color
210 "float2 main(const Varyings v, out half4 color, float)" // extra arg
211 };
212
213 for (const char* vsSig : kInvalidVSSigs) {
214 SkString invalidVS;
215 invalidVS.appendf("%s %s", vsSig, kVSBody);
216 for (const auto& validFS : kValidFSes) {
221 invalidVS,
222 validFS)) {
223 return;
224 }
225 }
226 }
227
228 for (const char* noColorFSSig : kInvalidNoColorFSSigs) {
229 SkString invalidFS;
230 invalidFS.appendf("%s %s", noColorFSSig, kNoColorFSBody);
235 kValidVS,
236 invalidFS)) {
237 return;
238 }
239 }
240
241 for (const char* colorFSSig : kInvalidColorFSSigs) {
242 SkString invalidFS;
243 invalidFS.appendf("%s %s", colorFSSig, kColorFSBody);
248 kValidVS,
249 invalidFS)) {
250 return;
251 }
252 }
253}
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:550

◆ DEF_TEST() [14/26]

DEF_TEST ( MeshSpec_InvalidStride  ,
reporter   
)

Definition at line 764 of file MeshTest.cpp.

768 {
769 // Zero stride
772 0,
774 kValidVS,
775 kValidFSes[0])) {
776 return;
777 }
778
779 // Unaligned
782 kValidStride + 1,
784 kValidVS,
785 kValidFSes[0])) {
786 return;
787 }
788
789 // Too large
792 1 << 20,
794 kValidVS,

◆ DEF_TEST() [15/26]

DEF_TEST ( MeshSpec_InvalidUniforms  ,
reporter   
)

Definition at line 661 of file MeshTest.cpp.

665 {
666 // We assume general uniform declarations are broadly tested generically in SkSL. Here we are
667 // concerned with agreement between VS and FS declarations, which is a unique aspect of
668 // SkMeshSpecification.
669
670 // Each test case is a fs and vs uniform declaration with the same name but some other
671 // difference that should make them incompatible.
672 static std::tuple<const char*, const char*> kTestCases[]{
673 // different types
674 {"uniform float x;", "uniform int x;"},
675 // array vs non-array
676 {"uniform float2x2 m[1];", "uniform float2x2 m;"},
677 // array count mismatch
678 {"uniform int3 i[1];", "uniform int3 i[2];"},
679 // layout difference
680 {"layout(color) uniform float4 color;", "uniform float4 color;"},
681 };
682
683 for (bool reverse : {false, true}) {
684 for (auto [u1, u2] : kTestCases) {
685 if (reverse) {
686 using std::swap;
687 swap(u1, u2);
688 }
689 SkString vs = kValidVS;
690 vs.prepend(u1);
691
692 SkString fs = kValidFSes[0];
693 fs.prepend(u2);
694
695 auto attrs = SkSpan(kValidAttrs);
696 auto varys = SkSpan(kValidVaryings);
697 if (!check_for_failure(reporter, attrs, kValidStride, varys, vs, fs)) {
698 return;
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition SkRefCnt.h:341
void prepend(const char text[])
Definition SkString.h:215

◆ DEF_TEST() [16/26]

DEF_TEST ( MeshSpec_MissingMain  ,
reporter   
)

Definition at line 700 of file MeshTest.cpp.

704 {
705 static const SkString kHelper{"float2 swiz(float2 x) { return z.yx; }"};
706
707 // Empty VS
712 SkString{},
713 kValidFSes[0])) {
714 return;
715 }
716
717 // VS with helper function but no main
722 kHelper,
723 kValidFSes[0])) {
724 return;
725 }
726
727 // Empty FS
732 kValidVS,
733 SkString{})) {
734 return;
735 }
736
737 // VS with helper function but no main
742 kValidVS,

◆ DEF_TEST() [17/26]

DEF_TEST ( MeshSpec_SneakyExtraAttribute  ,
reporter   
)

Definition at line 897 of file MeshTest.cpp.

901 {
902 static const Attribute kAttributes[] {
904 };
906 kAttributes,
907 16,
static constexpr const char * kSneakyName
Definition MeshTest.cpp:895

◆ DEF_TEST() [18/26]

DEF_TEST ( MeshSpec_SneakyExtraVarying  ,
reporter   
)

Definition at line 909 of file MeshTest.cpp.

913 {
914 static const Varying kVaryings[] {
916 };

◆ DEF_TEST() [19/26]

DEF_TEST ( MeshSpec_TooManyAttributes  ,
reporter   
)

Definition at line 839 of file MeshTest.cpp.

843 {
844 static constexpr size_t kN = 500;
845 std::vector<Attribute> attrs;
846 attrs.reserve(kN);
847 for (size_t i = 0; i < kN; ++i) {
848 attrs.push_back({Attribute::Type::kFloat4, 0, SkStringPrintf("attr%zu", i)});
849 }
851 attrs,
852 4*4,
SK_API SkString static SkString SkStringPrintf()
Definition SkString.h:287

◆ DEF_TEST() [20/26]

DEF_TEST ( MeshSpec_TooManyVaryings  ,
reporter   
)

Definition at line 854 of file MeshTest.cpp.

858 {
859 static constexpr size_t kN = 500;
860 std::vector<Varying> varyings;
861 varyings.reserve(kN);
862 for (size_t i = 0; i < kN; ++i) {
863 varyings.push_back({Varying::Type::kFloat4, SkStringPrintf("varying%zu", i)});
864 }

◆ DEF_TEST() [21/26]

DEF_TEST ( MeshSpec_Valid  ,
reporter   
)

Definition at line 167 of file MeshTest.cpp.

167 {
168 for (const auto& validFS : kValidFSes) {
173 kValidVS,
174 validFS)) {
175 return;
176 }
177 }
178}

◆ DEF_TEST() [22/26]

DEF_TEST ( MeshSpec_ValidUniforms  ,
reporter   
)

Definition at line 431 of file MeshTest.cpp.

435 {
437 using Type = Uniform::Type;
438 using Flags = Uniform::Flags;
439
440 constexpr Flags kVS = Uniform::kVertex_Flag;
441 constexpr Flags kFS = Uniform::kFragment_Flag;
443 constexpr Flags kHalfP = Uniform::kHalfPrecision_Flag;
444
445 auto make_uni = [](Type type,
446 std::string_view name,
447 size_t offset,
448 uint32_t flags,
449 int count = 0) {
450 if (count) {
452 } else {
454 return Uniform{name, offset, type, 1, flags};
455 }
456 };
457
458 // Each test case is a set of VS and FS uniform declarations followed and the expected output
459 // of SkMeshSpecification::uniforms().
460 struct {
461 const std::vector<const char*> vsUniformDecls;
462 const std::vector<const char*> fsUniformDecls;
463 const std::vector<SkMeshSpecification::Uniform> expectations;
464 } static kTestCases[] {
465 // A single VS uniform.
466 {
467 {
468 "uniform float x;"
469 },
470 {},
471 {
472 make_uni(Type::kFloat, "x", 0, kVS)
473 }
474 },
475
476 // A single FS uniform.
477 {
478 {},
479 {
480 "uniform float2 v;"
481 },
482 {
483 make_uni(Type::kFloat2, "v", 0, kFS)
484 }
485 },
486
487 // A single uniform in both that uses color layout.
488 {
489 {
490 "layout(color) uniform float4 color;",
491 },
492 {
493 "layout(color) uniform float4 color;",
494 },
495 {
496 make_uni(Type::kFloat4, "color", 0, kVS|kFS|kColor)
497 }
498 },
499
500 // A shared uniform after an unshared vertex uniform
501 {
502 {
503 "layout(color) uniform float4 color;",
504 " uniform float x[5];",
505 },
506 {
507 "uniform float x[5];",
508 },
509 {
510 make_uni(Type::kFloat4, "color", 0, kVS|kColor, 0),
511 make_uni(Type::kFloat , "x" , 16, kVS|kFS , 5)
512 }
513 },
514
515 // A shared uniform before an unshared vertex uniform
516 {
517 {
518 "uniform half x[2];",
519 "uniform int y;",
520 },
521 {
522 "uniform half x[2];",
523 },
524 {
525 make_uni(Type::kFloat, "x", 0, kVS|kFS|kHalfP, 2),
526 make_uni(Type::kInt, "y", 8, kVS , 0)
527 }
528 },
529
530 // A shared uniform after an unshared fragment uniform
531 {
532 {
533 "uniform float3x3 m;",
534 },
535 {
536 "uniform int2 i2;",
537 "uniform float3x3 m;",
538 },
539 {
540 make_uni(Type::kFloat3x3, "m" , 0, kVS|kFS),
541 make_uni(Type::kInt2 , "i2", 36, kFS )
542 }
543 },
544
545 // A shared uniform before an unshared fragment uniform
546 {
547 {
548 "uniform half4x4 m[4];",
549 },
550 {
551 "uniform half4x4 m[4];",
552 "uniform int3 i3[1];",
553 },
554 {
555 make_uni(Type::kFloat4x4, "m", 0, kVS|kFS|kHalfP, 4),
556 make_uni(Type::kInt3, "i3", 256, kFS , 1)
557 }
558 },
559
560 // Complex case with 2 shared uniforms that are declared in the opposite order.
561 {
562 {
563 "uniform float x;"
564 "uniform half4x4 m[4];", // shared
565 "uniform int2 i2[2];"
566 "uniform float3 v[8];" // shared
567 "uniform int3 i3;"
568 },
569 {
570 "uniform float y;"
571 "uniform float3 v[8];" // shared
572 "uniform int4 i4[2];"
573 "uniform half4x4 m[4];", // shared
574 "uniform int i;"
575 },
576 {
577 make_uni(Type::kFloat, "x" , 0, kVS , 0),
578 make_uni(Type::kFloat4x4, "m" , 4, kVS|kFS|kHalfP, 4),
579 make_uni(Type::kInt2, "i2", 260, kVS , 2),
580 make_uni(Type::kFloat3, "v" , 276, kVS|kFS , 8),
581 make_uni(Type::kInt3, "i3", 372, kVS , 0),
582 make_uni(Type::kFloat, "y" , 384, kFS , 0),
583 make_uni(Type::kInt4, "i4", 388, kFS , 2),
584 make_uni(Type::kInt, "i" , 420, kFS , 0),
585 }
586 },
587 };
588
589 for (const auto& c : kTestCases) {
590 SkString vs = kValidVS;
591 SkString unis;
592 for (const auto u : c.vsUniformDecls) {
593 unis.append(u);
594 }
595 vs.prepend(unis);
596
597 SkString fs = kValidFSes[0];
598 unis = {};
599 for (const auto u : c.fsUniformDecls) {
600 unis.append(u);
601 }
602 fs.prepend(unis);
603
604 auto attrs = SkSpan(kValidAttrs);
605 auto varys = SkSpan(kValidVaryings);
607 if (!check_for_success(reporter, attrs, kValidStride, varys, vs, fs, &spec)) {
608 return;
609 }
610 SkString desc = make_description(attrs, kValidStride, varys, vs, fs);
611 SkSpan<const Uniform> uniforms = spec->uniforms();
612 if (uniforms.size() != c.expectations.size()) {
614 "Expected %zu uniforms but actually %zu:\n%s",
615 c.expectations.size(),
616 uniforms.size(),
617 desc.c_str());
618 return;
619 }
620 for (const auto& [actual, expected] : SkMakeZip(uniforms, c.expectations)) {
621 std::string name = std::string(actual.name);
622 if (name != expected.name) {
624 "Actual uniform name (%s) does not match expected name (%.*s)",
625 name.c_str(),
626 (int)expected.name.size(), expected.name.data());
627 return;
628 }
629 if (actual.type != expected.type) {
631 "Uniform %s: Actual type (%d) does not match expected type (%d)",
632 name.c_str(),
633 static_cast<int>(actual.type),
634 static_cast<int>(expected.type));
635 return;
636 }
637 if (actual.count != expected.count) {
639 "Uniform %s: Actual count (%d) does not match expected count (%d)",
640 name.c_str(),
641 actual.count,
642 expected.count);
643 return;
644 }
645 if (actual.flags != expected.flags) {
647 "Uniform %s: Actual flags (0x%04x) do not match expected flags (0x%04x)",
648 name.c_str(),
649 actual.flags,
650 expected.flags);
651 return;
652 }
653 if (actual.offset != expected.offset) {
655 "Uniform %s: Actual offset (%zu) does not match expected offset (%zu)",
656 name.c_str(),
657 actual.offset,
658 expected.offset);
659 return;
static constexpr SkColor kColor
int count
#define SkASSERT(cond)
Definition SkAssert.h:116
constexpr auto SkMakeZip(Ts &&... ts)
Definition SkZip.h:212
SkRuntimeEffect::Uniform Uniform
Definition SkMesh.h:106
constexpr size_t size() const
Definition SkSpan_impl.h:95
FlutterSemanticsFlag flags
const char * name
Definition fuchsia.cc:50
Point offset

◆ DEF_TEST() [23/26]

DEF_TEST ( MeshSpec_ZeroAttributes  ,
reporter   
)

Definition at line 744 of file MeshTest.cpp.

748 {
749 // We require at least one attribute

◆ DEF_TEST() [24/26]

DEF_TEST ( MeshSpec_ZeroVaryings  ,
reporter   
)

Definition at line 754 of file MeshTest.cpp.

758 {
759 // Varyings are not required.

◆ DEF_TEST() [25/26]

DEF_TEST ( MeshSpecUnusedVaryings  ,
reporter   
)

Definition at line 1087 of file MeshTest.cpp.

1091 {
1092 static const Attribute kAttributes[]{
1093 {Attribute::Type::kFloat2, 0, SkString{"position"}},
1096 };
1097 static const Varying kVaryings[]{
1098 {Varying::Type::kFloat2, SkString{"position"}},
1100 {Varying::Type::kHalf4, SkString{"color"} },
1101 };
1102
1103 static constexpr char kVS[] = R"(
1104 Varyings main(const Attributes a) {
1105 Varyings v;
1106 v.uv = a.uv;
1107 v.position = a.position;
1108 v.color = a.color;
1109 return v;
1110 }
1111 )";
1112
1113 auto check = [&](const char* fs, bool positionDead, bool uvDead, bool colorDead) {
1114 static_assert(std::size(kVaryings) == 3);
1115 auto [spec, error] = SkMeshSpecification::Make(kAttributes,
1116 /*vertexStride=*/24,
1117 kVaryings,
1118 SkString(kVS),
1119 SkString(fs));
1120 if (!spec) {
1121 ERRORF(reporter, "%s\n%s", fs, error.c_str());
1122 return;
1123 }
1124 bool positionActuallyDead = SkMeshSpecificationPriv::VaryingIsDead(*spec, 0);
1125 bool uvActuallyDead = SkMeshSpecificationPriv::VaryingIsDead(*spec, 1);
1126 bool colorActuallyDead = SkMeshSpecificationPriv::VaryingIsDead(*spec, 2);
1127 auto str = [](bool dead) { return dead ? "dead" : "not dead"; };
1128 if (positionActuallyDead != positionDead) {
1130 "Expected position to be detected %s but it is detected %s.\n%s",
1131 str(positionDead),
1132 str(positionActuallyDead),
1133 fs);
1134 }
1135 if (uvActuallyDead != uvDead) {
1137 "Expected uv to be detected %s but it is detected %s.\n%s",
1138 str(uvDead),
1139 str(uvActuallyDead),
1140 fs);
1141 }
1142 if (colorActuallyDead != colorDead) {
1144 "Expected color to be detected %s but it is detected %s.\n%s",
1145 str(colorDead),
1146 str(colorActuallyDead),
1147 fs);
1148 }
1149 };
1150
1151 // Simple
1152 check(R"(float2 main(const Varyings v) {
1153 return v.uv;
1154 })",
1155 true,
1156 true,
1157 true);
1158
1159 // Simple, using position
1160 check(R"(float2 main(const Varyings v) {
1161 return v.position;
1162 })",
1163 true,
1164 true,
1165 true);
1166
1167 // Two returns that are both passthrough of the same varying
1168 check(R"(float2 main(const Varyings v, out half4 color) {
1169 if (v.color.r > 0.5) {
1170 color = v.color;
1171 return v.uv;
1172 } else {
1173 color = 2*color;
1174 return v.uv;
1175 }
1176 })",
1177 true,
1178 true,
1179 false);
1180
1181 // Two returns that are both passthrough of the different varyings and unused other varying
1182 check(R"(float2 main(const Varyings v, out half4 color) {
1183 if (v.position.x > 10) {
1184 color = half4(0);
1185 return v.uv;
1186 } else {
1187 color = half4(1);
1188 return v.position;
1189 }
1190 })",
1191 false,
1192 false,
1193 true);
1194
1195 // Passthrough but we also use the varying elsewhere
1196 check(R"(float2 main(const Varyings v, out half4 color) {
1197 color = half4(v.uv.x, 0, 0, 1);
1198 return v.uv;
1199 })",
1200 true,
1201 false,
1202 true);
1203
1204 // Use two varyings is a return statement
1205 check(R"(float2 main(const Varyings v) {
1206 return v.uv + v.position;
1207 })",
1208 false,
1209 false,
1210 true);
1211
1212 // Slightly more complicated varying use.
1213 check(R"(noinline vec2 get_pos(const Varyings v) { return v.position; }
1214
1215 noinline half4 identity(half4 c) { return c; }
1216
1217 float2 main(const Varyings v, out half4 color) {
1218 color = identity(v.color);
1219 return v.uv + get_pos(v);
1220 })",
1221 false,
1222 false,
1223 false);
1224
1225 // Go through assignment to another Varyings.
1226 check(R"(float2 main(const Varyings v) {
1227 Varyings otherVaryings;
1228 otherVaryings = v;
1229 return otherVaryings.uv;
1230 })",
1231 true,
1232 false,
1233 true);
1234
1235 // We're not very smart. We just look for any use of the field in any Varyings value and don't
1236 // do any data flow analysis.
1237 check(R"(float2 main(const Varyings v) {
1238 Varyings otherVaryings;
1239 otherVaryings.uv = half2(5);
1240 otherVaryings.position = half2(10);
1241 return otherVaryings.position;
1242 })",
#define check(reporter, ref, unref, make, kill)
static bool VaryingIsDead(const SkMeshSpecification &spec, int v)
Definition SkMeshPriv.h:75

◆ DEF_TEST() [26/26]

DEF_TEST ( MeshSpecVaryingPassthrough  ,
reporter   
)

Definition at line 971 of file MeshTest.cpp.

975 {
976 static const Attribute kAttributes[]{
977 {Attribute::Type::kFloat2, 0, SkString{"position"}},
980 };
981 static const Varying kVaryings[]{
982 {Varying::Type::kFloat2, SkString{"position"}},
984 {Varying::Type::kHalf4, SkString{"color"} },
985 };
986
987 static constexpr char kVS[] = R"(
988 Varyings main(const Attributes a) {
989 Varyings v;
990 v.uv = a.uv;
991 v.position = a.position;
992 v.color = a.color;
993 return v;
994 }
995 )";
996 auto check = [&] (const char* fs, const char* passthroughAttr) {
997 auto [spec, error] = SkMeshSpecification::Make(kAttributes,
998 /*vertexStride=*/24,
999 kVaryings,
1000 SkString(kVS),
1001 SkString(fs));
1002 if (!spec) {
1003 ERRORF(reporter, "%s\n%s", fs, error.c_str());
1004 return;
1005 }
1007 const SkString& actualAttr = idx >= 0 ? spec->attributes()[idx].name : SkString("<none>");
1008 if (!passthroughAttr) {
1009 if (idx >= 0) {
1010 ERRORF(reporter, "Expected no passthrough coords attribute, found %s.\n%s",
1011 actualAttr.c_str(),
1012 fs);
1013 }
1014 } else if (!actualAttr.equals(passthroughAttr)) {
1015 ERRORF(reporter, "Expected %s as passthrough coords attribute, found %s.\n%s",
1016 passthroughAttr,
1017 actualAttr.c_str(),
1018 fs);
1019 }
1020 };
1021
1022 // Simple
1023 check(R"(float2 main(const Varyings v) {
1024 return v.uv;
1025 })",
1026 "uv");
1027
1028 // Simple, using position
1029 check(R"(float2 main(const Varyings v) {
1030 return v.position;
1031 })",
1032 "position");
1033
1034 // Simple, with output color
1035 check(R"(float2 main(const Varyings v, out half4 color) {
1036 color = v.color;
1037 return v.uv;
1038 })",
1039 "uv");
1040
1041 // Three returns, all the same.
1042 check(R"(uniform int selector;
1043
1044 float2 main(const Varyings v, out half4 color) {
1045 if (selector == 0) {
1046 color = half4(1, 0, 0, 1);
1047 return v.position;
1048 }
1049 if (selector == 1) {
1050 color = half4(1, 1, 0, 1);
1051 return v.position;
1052 }
1053 color = half4(1, 0, 1, 1);
1054 return v.position;
1055 })",
1056 "position");
1057
1058 // Three returns, one not like the others
1059 check(R"(uniform int selector;
1060
1061 float2 main(const Varyings v, out half4 color) {
1062 if (selector == 0) {
1063 color = color.bgra;
1064 return v.position;
1065 }
1066 if (selector == 1) {
1067 color = half4(1);
1068 return v.uv;
1069 }
1070 color = color;
1071 return v.position;
1072 })",
1073 nullptr);
1074
1075 // Swizzles aren't handled (yet?).
1076 check(R"(float2 main(const Varyings v) {
1077 return v.uv.yx;
1078 })",
1079 nullptr);
1080
1081 // Return from non-main fools us?
1082 check(R"(noinline half4 get_color(const Varyings v) { return v.color; }
1083
1084 float2 main(const Varyings v, out half4 color) {
1085 color = get_color(v);
bool equals(const SkString &) const
Definition SkString.cpp:324
static int PassthroughLocalCoordsVaryingIndex(const SkMeshSpecification &spec)
Definition SkMeshPriv.h:65

◆ make_description()

static SkString make_description ( SkSpan< const Attribute attributes,
size_t  stride,
SkSpan< const Varying varyings,
const SkString vs,
const SkString fs 
)
static

Definition at line 64 of file MeshTest.cpp.

68 {
69 static constexpr size_t kMax = 10;
71 result.appendf("Attributes (count=%zu, stride=%zu):\n", attributes.size(), stride);
72 for (size_t i = 0; i < std::min(kMax, attributes.size()); ++i) {
73 const auto& a = attributes[i];
74 result.appendf(" {%-10s, %3zu, \"%s\"}\n", attr_type_str(a.type), a.offset, a.name.c_str());
75 }
76 if (kMax < attributes.size()) {
77 result.append(" ...\n");
78 }
79
80 result.appendf("Varyings (count=%zu):\n", varyings.size());
81 for (size_t i = 0; i < std::min(kMax, varyings.size()); ++i) {
82 const auto& v = varyings[i];
83 result.appendf(" {%5s, \"%s\"}\n", var_type_str(v.type), v.name.c_str());
84 }
85 if (kMax < varyings.size()) {
86 result.append(" ...\n");
87 }
88
89 result.appendf("\n--VS--\n%s\n------\n", vs.c_str());
90 result.appendf("\n--FS--\n%s\n------\n", fs.c_str());
91 return result;
92}
static const char * attr_type_str(const Attribute::Type type)
Definition MeshTest.cpp:39
static const char * var_type_str(const Varying::Type type)
Definition MeshTest.cpp:50
struct MyStruct a[10]

◆ var_type_str()

static const char * var_type_str ( const Varying::Type  type)
static

Definition at line 50 of file MeshTest.cpp.

50 {
51 switch (type) {
52 case Varying::Type::kFloat: return "float";
53 case Varying::Type::kFloat2: return "float2";
54 case Varying::Type::kFloat3: return "float3";
55 case Varying::Type::kFloat4: return "float4";
56 case Varying::Type::kHalf: return "half";
57 case Varying::Type::kHalf2: return "half2";
58 case Varying::Type::kHalf3: return "half3";
59 case Varying::Type::kHalf4: return "half4";
60 }
62}

Variable Documentation

◆ kSneakyName

constexpr const char* kSneakyName = "name; float3 sneaky"
staticconstexpr

Definition at line 895 of file MeshTest.cpp.

◆ kValidAttrs

const Attribute kValidAttrs[]
static
Initial value:
= {
}

Definition at line 159 of file MeshTest.cpp.

159 {
161};

◆ kValidFSes

const SkString kValidFSes[]
static
Initial value:
{
SkString{"float2 main(const Varyings varyings) { return float2(10); }"},
float2 main(const Varyings varyings, out half4 color) {
color = half4(.2);
return float2(10);
}
)"},
}

Definition at line 148 of file MeshTest.cpp.

148 {
149 SkString{"float2 main(const Varyings varyings) { return float2(10); }"},
150 SkString{R"(
151 float2 main(const Varyings varyings, out half4 color) {
152 color = half4(.2);
153 return float2(10);
154 }
155 )"},
156};

◆ kValidStride

constexpr size_t kValidStride = 4*4
staticconstexpr

Definition at line 162 of file MeshTest.cpp.

◆ kValidVaryings

const Varying kValidVaryings[]
static
Initial value:

Definition at line 163 of file MeshTest.cpp.

163 {
165};

◆ kValidVS

const SkString kValidVS
static
Initial value:
{R"(
Varyings main(const Attributes attrs) {
Varyings v;
return v;
})"}

Definition at line 141 of file MeshTest.cpp.

141 {R"(
142Varyings main(const Attributes attrs) {
143 Varyings v;
144 return v;
145})"};