Flutter Engine
The Flutter Engine
Namespaces | Macros | Typedefs | Functions
SkMesh.cpp File Reference
#include "include/core/SkMesh.h"
#include "include/core/SkAlphaType.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkData.h"
#include "include/private/SkSLSampleUsage.h"
#include "include/private/base/SkAlign.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkTArray.h"
#include "include/private/base/SkTo.h"
#include "src/base/SkSafeMath.h"
#include "src/core/SkChecksum.h"
#include "src/core/SkMeshPriv.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/sksl/SkSLAnalysis.h"
#include "src/sksl/SkSLBuiltinTypes.h"
#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLContext.h"
#include "src/sksl/SkSLProgramKind.h"
#include "src/sksl/SkSLProgramSettings.h"
#include "src/sksl/analysis/SkSLProgramVisitor.h"
#include "src/sksl/ir/SkSLExpression.h"
#include "src/sksl/ir/SkSLFieldAccess.h"
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
#include "src/sksl/ir/SkSLFunctionDefinition.h"
#include "src/sksl/ir/SkSLModifierFlags.h"
#include "src/sksl/ir/SkSLProgram.h"
#include "src/sksl/ir/SkSLProgramElement.h"
#include "src/sksl/ir/SkSLReturnStatement.h"
#include "src/sksl/ir/SkSLStatement.h"
#include "src/sksl/ir/SkSLStructDefinition.h"
#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
#include "src/sksl/ir/SkSLVariable.h"
#include "src/sksl/ir/SkSLVariableReference.h"
#include <algorithm>
#include <locale>
#include <optional>
#include <string>
#include <tuple>
#include <utility>

Go to the source code of this file.

Namespaces

namespace  SkMeshes
 

Macros

#define RETURN_FAILURE(...)   return Result{nullptr, SkStringPrintf(__VA_ARGS__)}
 
#define RETURN_ERROR(...)   return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))
 
#define RETURN_SUCCESS   return std::make_tuple(true, SkString{})
 
#define FAIL_MESH_VALIDATE(...)   return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))
 

Typedefs

using Attribute = SkMeshSpecification::Attribute
 
using Varying = SkMeshSpecification::Varying
 
using IndexBuffer = SkMesh::IndexBuffer
 
using VertexBuffer = SkMesh::VertexBuffer
 
using Uniform = SkMeshSpecification::Uniform
 
using Child = SkMeshSpecification::Child
 
using ColorType = SkMeshSpecificationPriv::ColorType
 

Functions

static std::vector< Uniform >::iterator find_uniform (std::vector< Uniform > &uniforms, std::string_view name)
 
static std::tuple< bool, SkStringgather_uniforms_and_check_for_main (const SkSL::Program &program, std::vector< Uniform > *uniforms, std::vector< Child > *children, SkMeshSpecification::Uniform::Flags stage, size_t *offset)
 
ColorType get_fs_color_type (const SkSL::Program &fsProgram)
 
static bool check_name (const SkString &name)
 
static size_t attribute_type_size (Attribute::Type type)
 
static const char * attribute_type_string (Attribute::Type type)
 
static const char * varying_type_string (Varying::Type type)
 
std::tuple< bool, SkStringcheck_vertex_offsets_and_stride (SkSpan< const Attribute > attributes, size_t stride)
 
int check_for_passthrough_local_coords_and_dead_varyings (const SkSL::Program &fsProgram, uint32_t *deadVaryingMask)
 
static size_t min_vcount_for_mode (SkMesh::Mode mode)
 
static bool check_update (const void *data, size_t offset, size_t size, size_t bufferSize)
 
SK_API sk_sp< SkMesh::IndexBufferSkMeshes::MakeIndexBuffer (const void *data, size_t size)
 
SK_API sk_sp< SkMesh::IndexBufferSkMeshes::CopyIndexBuffer (const sk_sp< SkMesh::IndexBuffer > &)
 
SK_API sk_sp< SkMesh::VertexBufferSkMeshes::MakeVertexBuffer (const void *, size_t size)
 
SK_API sk_sp< SkMesh::VertexBufferSkMeshes::CopyVertexBuffer (const sk_sp< SkMesh::VertexBuffer > &)
 

Macro Definition Documentation

◆ FAIL_MESH_VALIDATE

#define FAIL_MESH_VALIDATE (   ...)    return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))

◆ RETURN_ERROR

#define RETURN_ERROR (   ...)    return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))

Definition at line 62 of file SkMesh.cpp.

◆ RETURN_FAILURE

#define RETURN_FAILURE (   ...)    return Result{nullptr, SkStringPrintf(__VA_ARGS__)}

Definition at line 60 of file SkMesh.cpp.

◆ RETURN_SUCCESS

#define RETURN_SUCCESS   return std::make_tuple(true, SkString{})

Definition at line 64 of file SkMesh.cpp.

Typedef Documentation

◆ Attribute

Definition at line 54 of file SkMesh.cpp.

◆ Child

Definition at line 67 of file SkMesh.cpp.

◆ ColorType

using ColorType = SkMeshSpecificationPriv::ColorType

Definition at line 137 of file SkMesh.cpp.

◆ IndexBuffer

Definition at line 57 of file SkMesh.cpp.

◆ Uniform

Definition at line 66 of file SkMesh.cpp.

◆ Varying

Definition at line 55 of file SkMesh.cpp.

◆ VertexBuffer

Definition at line 58 of file SkMesh.cpp.

Function Documentation

◆ attribute_type_size()

static size_t attribute_type_size ( Attribute::Type  type)
static

Definition at line 175 of file SkMesh.cpp.

◆ attribute_type_string()

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

Definition at line 186 of file SkMesh.cpp.

186 {
187 switch (type) {
188 case Attribute::Type::kFloat: return "float";
189 case Attribute::Type::kFloat2: return "float2";
190 case Attribute::Type::kFloat3: return "float3";
191 case Attribute::Type::kFloat4: return "float4";
192 case Attribute::Type::kUByte4_unorm: return "half4";
193 }
195}

◆ check_for_passthrough_local_coords_and_dead_varyings()

int check_for_passthrough_local_coords_and_dead_varyings ( const SkSL::Program fsProgram,
uint32_t *  deadVaryingMask 
)

Definition at line 254 of file SkMesh.cpp.

255 {
256 SkASSERT(deadVaryingMask);
257
258 using namespace SkSL;
259 static constexpr int kFailed = -2;
260
261 class Visitor final : public SkSL::ProgramVisitor {
262 public:
263 Visitor(const Context& context) : fContext(context) {}
264
265 void visit(const Program& program) { ProgramVisitor::visit(program); }
266
267 int passthroughFieldIndex() const { return fPassthroughFieldIndex; }
268
269 uint32_t fieldUseMask() const { return fFieldUseMask; }
270
271 protected:
272 bool visitProgramElement(const ProgramElement& p) override {
273 if (p.is<StructDefinition>()) {
274 const auto& def = p.as<StructDefinition>();
275 if (def.type().name() == "Varyings") {
276 fVaryingsType = &def.type();
277 }
278 // No reason to keep looking at this type definition.
279 return false;
280 }
281 if (p.is<FunctionDefinition>() && p.as<FunctionDefinition>().declaration().isMain()) {
282 SkASSERT(!fVaryings);
283 fVaryings = p.as<FunctionDefinition>().declaration().parameters()[0];
284
285 SkASSERT(fVaryingsType && fVaryingsType->matches(fVaryings->type()));
286
287 fInMain = true;
289 fInMain = false;
290 return result;
291 }
293 }
294
295 bool visitStatement(const Statement& s) override {
296 if (!fInMain) {
298 }
299 // We should only get here if are in main and therefore found the varyings parameter.
300 SkASSERT(fVaryings);
301 SkASSERT(fVaryingsType);
302
303 if (fPassthroughFieldIndex == kFailed) {
304 // We've already determined there are return statements that aren't passthrough
305 // or return different fields.
307 }
308 if (!s.is<ReturnStatement>()) {
310 }
311
312 // We just detect simple cases like "return varyings.foo;"
313 const auto& rs = s.as<ReturnStatement>();
314 SkASSERT(rs.expression());
315 if (!rs.expression()->is<FieldAccess>()) {
316 this->passthroughFailed();
318 }
319 const auto& fa = rs.expression()->as<FieldAccess>();
320 if (!fa.base()->is<VariableReference>()) {
321 this->passthroughFailed();
323 }
324 const auto& baseRef = fa.base()->as<VariableReference>();
325 if (baseRef.variable() != fVaryings) {
326 this->passthroughFailed();
328 }
329 if (fPassthroughFieldIndex >= 0) {
330 // We already found an OK return statement. Check if this one returns the same
331 // field.
332 if (fa.fieldIndex() != fPassthroughFieldIndex) {
333 this->passthroughFailed();
335 }
336 // We don't call our base class here because we don't want to hit visitExpression
337 // and mark the returned field as used.
338 return false;
339 }
340 const Field& field = fVaryings->type().fields()[fa.fieldIndex()];
341 if (!field.fType->matches(*fContext.fTypes.fFloat2)) {
342 this->passthroughFailed();
344 }
345 fPassthroughFieldIndex = fa.fieldIndex();
346 // We don't call our base class here because we don't want to hit visitExpression and
347 // mark the returned field as used.
348 return false;
349 }
350
351 bool visitExpression(const Expression& e) override {
352 // Anything before the Varyings struct is defined doesn't matter.
353 if (!fVaryingsType) {
354 return false;
355 }
356 if (!e.is<FieldAccess>()) {
358 }
359 const auto& fa = e.as<FieldAccess>();
360 if (!fa.base()->type().matches(*fVaryingsType)) {
362 }
363 fFieldUseMask |= 1 << fa.fieldIndex();
364 return false;
365 }
366
367 private:
368 void passthroughFailed() {
369 if (fPassthroughFieldIndex >= 0) {
370 fFieldUseMask |= 1 << fPassthroughFieldIndex;
371 }
372 fPassthroughFieldIndex = kFailed;
373 }
374
375 const Context& fContext;
376 const Type* fVaryingsType = nullptr;
377 const Variable* fVaryings = nullptr;
378 int fPassthroughFieldIndex = -1;
379 bool fInMain = false;
380 uint32_t fFieldUseMask = 0;
381 };
382
383 Visitor v(*fsProgram.fContext);
384 v.visit(fsProgram);
385 *deadVaryingMask = ~v.fieldUseMask();
386 return v.passthroughFieldIndex();
387}
#define SkASSERT(cond)
Definition: SkAssert.h:116
const Context & fContext
bool visit(const Program &program)
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
Definition: SkSLType.h:269
struct MyStruct s
GAsyncResult * result
Visitor(Ts...) -> Visitor< Ts... >
const Type * fType
Definition: SkSLType.h:88
std::shared_ptr< Context > fContext
Definition: SkSLProgram.h:154

◆ check_name()

static bool check_name ( const SkString name)
static

Definition at line 163 of file SkMesh.cpp.

163 {
164 if (name.isEmpty()) {
165 return false;
166 }
167 for (size_t i = 0; i < name.size(); ++i) {
168 if (name[i] != '_' && !std::isalnum(name[i], std::locale::classic())) {
169 return false;
170 }
171 }
172 return true;
173}
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32

◆ check_update()

static bool check_update ( const void *  data,
size_t  offset,
size_t  size,
size_t  bufferSize 
)
inlinestatic

Definition at line 864 of file SkMesh.cpp.

864 {
865 SkSafeMath sm;
866 return data &&
867 size &&
869 SkIsAlign4(size) &&
870 sm.add(offset, size) <= bufferSize &&
871 sm.ok();
872}
static constexpr bool SkIsAlign4(T x)
Definition: SkAlign.h:20
size_t add(size_t x, size_t y)
Definition: SkSafeMath.h:33
bool ok() const
Definition: SkSafeMath.h:26
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SeparatedVector2 offset
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63

◆ check_vertex_offsets_and_stride()

std::tuple< bool, SkString > check_vertex_offsets_and_stride ( SkSpan< const Attribute attributes,
size_t  stride 
)

Definition at line 212 of file SkMesh.cpp.

213 {
214 // Vulkan 1.0 has a minimum maximum attribute count of 2048.
215 static_assert(SkMeshSpecification::kMaxStride <= 2048);
216 // ES 2 has a max of 8.
217 static_assert(SkMeshSpecification::kMaxAttributes <= 8);
218 // Four bytes alignment is required by Metal.
219 static_assert(SkMeshSpecification::kStrideAlignment >= 4);
220 static_assert(SkMeshSpecification::kOffsetAlignment >= 4);
221 // ES2 has a minimum maximum of 8. We may need one for a broken gl_FragCoord workaround and
222 // one for local coords.
223 static_assert(SkMeshSpecification::kMaxVaryings <= 6);
224
225 if (attributes.empty()) {
226 RETURN_ERROR("At least 1 attribute is required.");
227 }
228 if (attributes.size() > SkMeshSpecification::kMaxAttributes) {
229 RETURN_ERROR("A maximum of %zu attributes is allowed.",
231 }
233 if (stride == 0 || stride & (SkMeshSpecification::kStrideAlignment - 1)) {
234 RETURN_ERROR("Vertex stride must be a non-zero multiple of %zu.",
236 }
237 if (stride > SkMeshSpecification::kMaxStride) {
238 RETURN_ERROR("Stride cannot exceed %zu.", SkMeshSpecification::kMaxStride);
239 }
240 for (const auto& a : attributes) {
241 if (a.offset & (SkMeshSpecification::kOffsetAlignment - 1)) {
242 RETURN_ERROR("Attribute offset must be a multiple of %zu.",
244 }
245 // This equivalent to vertexAttributeAccessBeyondStride==VK_FALSE in
246 // VK_KHR_portability_subset. First check is to avoid overflow in second check.
247 if (a.offset >= stride || a.offset + attribute_type_size(a.type) > stride) {
248 RETURN_ERROR("Attribute offset plus size cannot exceed stride.");
249 }
250 }
252}
constexpr bool SkIsPow2(T value)
Definition: SkMath.h:51
static size_t attribute_type_size(Attribute::Type type)
Definition: SkMesh.cpp:175
#define RETURN_SUCCESS
Definition: SkMesh.cpp:64
#define RETURN_ERROR(...)
Definition: SkMesh.cpp:62
static constexpr size_t kStrideAlignment
Definition: SkMesh.h:70
static constexpr size_t kMaxVaryings
Definition: SkMesh.h:72
static constexpr size_t kMaxAttributes
Definition: SkMesh.h:69
static constexpr size_t kOffsetAlignment
Definition: SkMesh.h:71
static constexpr size_t kMaxStride
Definition: SkMesh.h:68
constexpr bool empty() const
Definition: SkSpan_impl.h:96
constexpr size_t size() const
Definition: SkSpan_impl.h:95
struct MyStruct a[10]

◆ find_uniform()

static std::vector< Uniform >::iterator find_uniform ( std::vector< Uniform > &  uniforms,
std::string_view  name 
)
static

Definition at line 69 of file SkMesh.cpp.

70 {
71 return std::find_if(uniforms.begin(), uniforms.end(),
72 [name](const SkMeshSpecification::Uniform& u) { return u.name == name; });
73}

◆ gather_uniforms_and_check_for_main()

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

Definition at line 76 of file SkMesh.cpp.

80 {
81 bool foundMain = false;
82 for (const SkSL::ProgramElement* elem : program.elements()) {
83 if (elem->is<SkSL::FunctionDefinition>()) {
85 const SkSL::FunctionDeclaration& decl = defn.declaration();
86 if (decl.isMain()) {
87 foundMain = true;
88 }
89 } else if (elem->is<SkSL::GlobalVarDeclaration>()) {
91 const SkSL::VarDeclaration& varDecl = global.declaration()->as<SkSL::VarDeclaration>();
92 const SkSL::Variable& var = *varDecl.var();
93 if (var.modifierFlags().isUniform()) {
94 if (var.type().isEffectChild()) {
95 // This is a child effect; add it to our list of children.
96 children->push_back(SkRuntimeEffectPriv::VarAsChild(var, children->size()));
97 } else {
98 // This is a uniform variable; make sure it exists in our list of uniforms, and
99 // ensure that the type and layout matches between VS and FS.
100 auto iter = find_uniform(*uniforms, var.name());
101 const auto& context = *program.fContext;
102 if (iter == uniforms->end()) {
103 uniforms->push_back(SkRuntimeEffectPriv::VarAsUniform(var, context,
104 offset));
105 uniforms->back().flags |= stage;
106 } else {
107 // Check that the two declarations are equivalent
108 size_t ignoredOffset = 0;
109 auto uniform = SkRuntimeEffectPriv::VarAsUniform(var, context,
110 &ignoredOffset);
111 if (uniform.isArray() != iter->isArray() ||
112 uniform.type != iter->type ||
113 uniform.count != iter->count) {
114 return {false,
115 SkStringPrintf("Uniform %.*s declared with different types"
116 " in vertex and fragment shaders.",
117 (int)var.name().size(), var.name().data())};
118 }
119 if (uniform.isColor() != iter->isColor()) {
120 return {false,
121 SkStringPrintf("Uniform %.*s declared with different color"
122 " layout in vertex and fragment shaders.",
123 (int)var.name().size(), var.name().data())};
124 }
125 (*iter).flags |= stage;
126 }
127 }
128 }
129 }
130 }
131 if (!foundMain) {
132 return {false, SkString("No main function found.")};
133 }
134 return {true, {}};
135}
static std::vector< Uniform >::iterator find_uniform(std::vector< Uniform > &uniforms, std::string_view name)
Definition: SkMesh.cpp:69
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
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()
const T & as() const
Definition: SkSLIRNode.h:133
ElementsCollection elements() const
Definition: SkSLProgram.h:140

◆ get_fs_color_type()

ColorType get_fs_color_type ( const SkSL::Program fsProgram)

Definition at line 139 of file SkMesh.cpp.

139 {
140 for (const SkSL::ProgramElement* elem : fsProgram.elements()) {
141 if (elem->is<SkSL::FunctionDefinition>()) {
143 const SkSL::FunctionDeclaration& decl = defn.declaration();
144 if (decl.isMain()) {
145 SkASSERT(decl.parameters().size() == 1 || decl.parameters().size() == 2);
146 if (decl.parameters().size() == 1) {
147 return ColorType::kNone;
148 }
149 const SkSL::Type& paramType = decl.parameters()[1]->type();
150 SkASSERT(paramType.matches(*fsProgram.fContext->fTypes.fHalf4) ||
151 paramType.matches(*fsProgram.fContext->fTypes.fFloat4));
152 return paramType.matches(*fsProgram.fContext->fTypes.fHalf4) ? ColorType::kHalf4
153 : ColorType::kFloat4;
154 }
155 }
156 }
158}
const Type & type() const
Definition: SkSLSymbol.h:42
@ kNone
Definition: layer.h:53

◆ min_vcount_for_mode()

static size_t min_vcount_for_mode ( SkMesh::Mode  mode)
static

Definition at line 759 of file SkMesh.cpp.

759 {
760 switch (mode) {
761 case SkMesh::Mode::kTriangles: return 3;
762 case SkMesh::Mode::kTriangleStrip: return 3;
763 }
765}
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228

◆ varying_type_string()

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

Definition at line 197 of file SkMesh.cpp.