60#define RETURN_FAILURE(...) return Result{nullptr, SkStringPrintf(__VA_ARGS__)}
62#define RETURN_ERROR(...) return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))
64#define RETURN_SUCCESS return std::make_tuple(true, SkString{})
69static std::vector<Uniform>::iterator
find_uniform(std::vector<Uniform>& uniforms,
70 std::string_view
name) {
71 return std::find_if(uniforms.begin(), uniforms.end(),
75static std::tuple<bool, SkString>
77 std::vector<Uniform>* uniforms,
78 std::vector<Child>* children,
81 bool foundMain =
false;
93 if (var.modifierFlags().isUniform()) {
94 if (var.type().isEffectChild()) {
101 const auto& context = *program.
fContext;
102 if (iter == uniforms->end()) {
105 uniforms->back().flags |= stage;
108 size_t ignoredOffset = 0;
111 if (uniform.isArray() != iter->isArray() ||
112 uniform.type != iter->type ||
113 uniform.count != iter->count) {
116 " in vertex and fragment shaders.",
117 (
int)var.name().size(), var.name().data())};
119 if (uniform.isColor() != iter->isColor()) {
122 " layout in vertex and fragment shaders.",
123 (
int)var.name().size(), var.name().data())};
125 (*iter).flags |= stage;
132 return {
false,
SkString(
"No main function found.")};
145 SkASSERT(decl.parameters().size() == 1 || decl.parameters().size() == 2);
146 if (decl.parameters().size() == 1) {
147 return ColorType::kNone;
152 return paramType.
matches(*fsProgram.
fContext->fTypes.fHalf4) ? ColorType::kHalf4
153 : ColorType::kFloat4;
164 if (
name.isEmpty()) {
167 for (
size_t i = 0; i <
name.size(); ++i) {
168 if (
name[i] !=
'_' && !std::isalnum(
name[i], std::locale::classic())) {
211std::tuple<bool, SkString>
225 if (attributes.
empty()) {
234 RETURN_ERROR(
"Vertex stride must be a non-zero multiple of %zu.",
240 for (
const auto&
a : attributes) {
242 RETURN_ERROR(
"Attribute offset must be a multiple of %zu.",
248 RETURN_ERROR(
"Attribute offset plus size cannot exceed stride.");
255 uint32_t* deadVaryingMask) {
258 using namespace SkSL;
259 static constexpr int kFailed = -2;
267 int passthroughFieldIndex()
const {
return fPassthroughFieldIndex; }
269 uint32_t fieldUseMask()
const {
return fFieldUseMask; }
275 if (def.type().name() ==
"Varyings") {
276 fVaryingsType = &def.
type();
285 SkASSERT(fVaryingsType && fVaryingsType->matches(fVaryings->type()));
303 if (fPassthroughFieldIndex == kFailed) {
316 this->passthroughFailed();
319 const auto& fa = rs.expression()->as<
FieldAccess>();
321 this->passthroughFailed();
325 if (baseRef.variable() != fVaryings) {
326 this->passthroughFailed();
329 if (fPassthroughFieldIndex >= 0) {
332 if (fa.fieldIndex() != fPassthroughFieldIndex) {
333 this->passthroughFailed();
340 const Field& field = fVaryings->type().fields()[fa.fieldIndex()];
342 this->passthroughFailed();
345 fPassthroughFieldIndex = fa.fieldIndex();
353 if (!fVaryingsType) {
360 if (!fa.base()->type().matches(*fVaryingsType)) {
363 fFieldUseMask |= 1 << fa.fieldIndex();
368 void passthroughFailed() {
369 if (fPassthroughFieldIndex >= 0) {
370 fFieldUseMask |= 1 << fPassthroughFieldIndex;
372 fPassthroughFieldIndex = kFailed;
376 const Type* fVaryingsType =
nullptr;
377 const Variable* fVaryings =
nullptr;
378 int fPassthroughFieldIndex = -1;
379 bool fInMain =
false;
380 uint32_t fFieldUseMask = 0;
385 *deadVaryingMask = ~v.fieldUseMask();
386 return v.passthroughFieldIndex();
419 SkString attributesStruct(
"struct Attributes {\n");
423 attributesStruct.
append(
"};\n");
425 bool userProvidedPositionVarying =
false;
426 for (
const auto& v : varyings) {
427 if (v.name.equals(
"position")) {
429 return {
nullptr,
SkString(
"Varying \"position\" must have type float2.")};
431 userProvidedPositionVarying =
true;
436 if (!userProvidedPositionVarying) {
442 for (
const auto& v : varyings) {
446 varyings = tempVaryings;
449 SkString varyingStruct(
"struct Varyings {\n");
450 for (
const auto& v : varyings) {
453 varyingStruct.
append(
"};\n");
482 return {
nullptr,
error};
487 RETURN_FAILURE(
"\"%s\" is not a valid attribute name.",
a.name.c_str());
495 for (
const auto& v : varyings) {
497 return {
nullptr,
SkStringPrintf(
"\"%s\" is not a valid varying name.", v.name.c_str())};
513 std::unique_ptr<SkSL::Program> vsProgram =
compiler.convertProgram(
515 std::string(vs.
c_str()),
528 return {
nullptr, std::move(
error)};
532 RETURN_FAILURE(
"Color transform intrinsics are not permitted in custom mesh shaders");
535 std::unique_ptr<SkSL::Program> fsProgram =
compiler.convertProgram(
537 std::string(fs.
c_str()),
551 return {
nullptr, std::move(
error)};
555 RETURN_FAILURE(
"Color transform intrinsics are not permitted in custom mesh shaders");
560 if (ct == ColorType::kNone) {
565 return {
nullptr,
SkString{
"Must provide a color space if FS returns a color."}};
568 return {
nullptr,
SkString{
"Must provide a valid alpha type if FS returns a color."}};
572 uint32_t deadVaryingMask;
573 int passthroughLocalCoordsVaryingIndex =
576 if (passthroughLocalCoordsVaryingIndex >= 0) {
583 passthroughLocalCoordsVaryingIndex,
587 std::move(vsProgram),
588 std::move(fsProgram),
597SkMeshSpecification::SkMeshSpecification(
601 int passthroughLocalCoordsVaryingIndex,
602 uint32_t deadVaryingMask,
603 std::vector<Uniform> uniforms,
604 std::vector<Child> children,
605 std::unique_ptr<const SkSL::Program> vs,
606 std::unique_ptr<const SkSL::Program> fs,
610 : fAttributes(attributes.
begin(), attributes.
end())
611 , fVaryings(varyings.
begin(), varyings.
end())
612 , fUniforms(
std::move(uniforms))
613 , fChildren(
std::move(children))
617 , fPassthroughLocalCoordsVaryingIndex(passthroughLocalCoordsVaryingIndex)
618 , fDeadVaryingMask(deadVaryingMask)
620 , fColorSpace(
std::move(cs))
628 for (
const auto&
a : fAttributes) {
635 uint64_t csHash = fColorSpace ? fColorSpace->
hash() : 0;
638 auto atInt =
static_cast<uint32_t
>(fAlphaType);
643 return fUniforms.empty() ? 0
644 :
SkAlign4(fUniforms.back().offset + fUniforms.back().sizeInBytes());
648 for (
const Uniform& uniform : fUniforms) {
649 if (uniform.name ==
name) {
657 for (
const Child& child : fChildren) {
658 if (child.name ==
name) {
666 for (
const Attribute& attr : fAttributes) {
667 if (
name == attr.name.c_str()) {
675 for (
const Varying& varying : fVaryings) {
676 if (
name == varying.name.c_str()) {
703 mesh.fSpec = std::move(
spec);
705 mesh.fVB = std::move(vb);
706 mesh.fUniforms = std::move(
uniforms);
711 auto [valid, msg] = mesh.validate();
715 return {std::move(mesh), std::move(msg)};
732 return {{},
SkString{
"An index buffer is required."}};
735 mesh.fSpec = std::move(
spec);
737 mesh.fVB = std::move(vb);
740 mesh.fIB = std::move(ib);
741 mesh.fUniforms = std::move(
uniforms);
746 auto [valid, msg] = mesh.validate();
750 return {std::move(mesh), std::move(msg)};
755 SkASSERT(valid == std::get<0>(this->validate()));
767std::tuple<bool, SkString> SkMesh::validate()
const {
768#define FAIL_MESH_VALIDATE(...) return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))
779 "but the mesh supplies %d.",
784 for (
int index = 0; index < fChildren.size(); ++index) {
786 if (fChildren[index].
type().has_value()) {
787 if (meshSpecChild.
type != fChildren[index].type()) {
789 (
int)meshSpecChild.
name.size(), meshSpecChild.
name.data(),
800 size_t vsize = sm.
mul(fSpec->
stride(), fVCount);
801 if (sm.
add(vsize, fVOffset) > vb->size()) {
802 FAIL_MESH_VALIDATE(
"The vertex buffer offset and vertex count reads beyond the end of the"
806 if (fVOffset%fSpec->
stride() != 0) {
807 FAIL_MESH_VALIDATE(
"The vertex offset (%zu) must be a multiple of the vertex stride (%zu).",
813 if (!fUniforms || fUniforms->
size() < uniformSize) {
820 auto modeToStr = [](
Mode m) {
834 size_t isize = sm.
mul(
sizeof(uint16_t), fICount);
835 if (sm.
add(isize, fIOffset) > ib->size()) {
836 FAIL_MESH_VALIDATE(
"The index buffer offset and index count reads beyond the end of the"
858#undef FAIL_MESH_VALIDATE
898 const void* data = ib->peek();
914 const void* data = vb->peek();
static constexpr bool SkIsAlign2(T x)
static constexpr bool SkIsAlign4(T x)
static constexpr T SkAlign4(T x)
@ kUnknown_SkAlphaType
uninitialized
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
static bool ok(int result)
constexpr bool SkIsPow2(T value)
static const char * attribute_type_string(Attribute::Type type)
#define FAIL_MESH_VALIDATE(...)
static size_t min_vcount_for_mode(SkMesh::Mode mode)
std::tuple< bool, SkString > check_vertex_offsets_and_stride(SkSpan< const Attribute > attributes, size_t stride)
static std::tuple< bool, SkString > gather_uniforms_and_check_for_main(const SkSL::Program &program, std::vector< Uniform > *uniforms, std::vector< Child > *children, SkMeshSpecification::Uniform::Flags stage, size_t *offset)
static std::vector< Uniform >::iterator find_uniform(std::vector< Uniform > &uniforms, std::string_view name)
static bool check_update(const void *data, size_t offset, size_t size, size_t bufferSize)
static size_t attribute_type_size(Attribute::Type type)
static bool check_name(const SkString &name)
#define RETURN_FAILURE(...)
int check_for_passthrough_local_coords_and_dead_varyings(const SkSL::Program &fsProgram, uint32_t *deadVaryingMask)
#define RETURN_ERROR(...)
static const char * varying_type_string(Varying::Type type)
ColorType get_fs_color_type(const SkSL::Program &fsProgram)
SK_API SkString static SkString SkStringPrintf()
constexpr size_t SkToSizeT(S x)
static constexpr bool SkToBool(const T &x)
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< Base > Make(const void *data, size_t size)
SkSpan< const Uniform > uniforms() const
static constexpr size_t kStrideAlignment
const Uniform * findUniform(std::string_view name) const
static constexpr size_t kMaxVaryings
SkSpan< const Child > children() const
static constexpr size_t kMaxAttributes
static constexpr size_t kOffsetAlignment
static constexpr size_t kMaxStride
static Result Make(SkSpan< const Attribute > attributes, size_t vertexStride, SkSpan< const Varying > varyings, const SkString &vs, const SkString &fs)
SkSpan< const Attribute > attributes() const
size_t uniformSize() const
const Varying * findVarying(std::string_view name) const
SkRuntimeEffect::Uniform Uniform
SkRuntimeEffect::Child Child
const Attribute * findAttribute(std::string_view name) const
const Child * findChild(std::string_view name) const
bool update(GrDirectContext *, const void *data, size_t offset, size_t size)
virtual size_t size() const =0
virtual bool onUpdate(GrDirectContext *, const void *data, size_t offset, size_t size)=0
bool update(GrDirectContext *, const void *data, size_t offset, size_t size)
SkMesh & operator=(const SkMesh &)
SkSpan< const ChildPtr > children() const
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)
size_t vertexCount() const
size_t vertexOffset() const
size_t indexCount() const
static Result MakeIndexed(sk_sp< SkMeshSpecification >, Mode, sk_sp< VertexBuffer >, size_t vertexCount, size_t vertexOffset, sk_sp< IndexBuffer >, size_t indexCount, size_t indexOffset, sk_sp< const SkData > uniforms, SkSpan< ChildPtr > children, const SkRect &bounds)
size_t indexOffset() const
const SkData * uniforms() const
SkMeshSpecification * spec() const
static const char * ChildTypeToStr(SkRuntimeEffect::ChildType type)
static SkRuntimeEffect::Uniform VarAsUniform(const SkSL::Variable &, const SkSL::Context &, size_t *offset)
static SkRuntimeEffect::Child VarAsChild(const SkSL::Variable &var, int index)
const FunctionDeclaration & declaration() const
std::unique_ptr< Statement > & declaration()
bool visit(const Program &program)
const Type & type() const
const Type & type() const
virtual bool visitStatement(typename T::Statement &statement)
virtual bool visitExpression(typename T::Expression &expression)
virtual bool visitProgramElement(typename T::ProgramElement &programElement)
bool matches(const Type &other) const
size_t add(size_t x, size_t y)
size_t mul(size_t x, size_t y)
constexpr bool empty() const
constexpr size_t size() const
void append(const char text[])
const char * c_str() const
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
static const char * begin(const StringSlice &s)
const uint8_t uint32_t uint32_t GError ** error
uint32_t Hash32(const void *data, size_t bytes, uint32_t seed)
SK_API sk_sp< SkMesh::IndexBuffer > CopyIndexBuffer(const sk_sp< SkMesh::IndexBuffer > &)
SK_API sk_sp< SkMesh::IndexBuffer > MakeIndexBuffer(const void *data, size_t size)
SK_API sk_sp< SkMesh::VertexBuffer > MakeVertexBuffer(const void *, size_t size)
SK_API sk_sp< SkMesh::VertexBuffer > CopyVertexBuffer(const sk_sp< SkMesh::VertexBuffer > &)
bool CallsColorTransformIntrinsics(const Program &program)
SkMeshSpecification::ColorType ColorType
ElementsCollection elements() const
std::shared_ptr< Context > fContext