consolidated writing fields logic and added more builtins for skslc msl backend
Bug: skia:
Change-Id: I6cad948bc68194322f031926ab9a49186ec2302b
Reviewed-on: https://skia-review.googlesource.com/134502
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Timothy Liang <timliang@google.com>
diff --git a/src/sksl/SkSLMetalCodeGenerator.cpp b/src/sksl/SkSLMetalCodeGenerator.cpp
index af2366e..5a7ccb7 100644
--- a/src/sksl/SkSLMetalCodeGenerator.cpp
+++ b/src/sksl/SkSLMetalCodeGenerator.cpp
@@ -80,14 +80,7 @@
fWrittenStructs.push_back(&type);
this->writeLine("struct " + type.name() + " {");
fIndentation++;
- for (const auto& f : type.fields()) {
- this->writeModifiers(f.fModifiers, false);
- // sizes (which must be static in structs) are part of the type name here
- this->writeType(*f.fType);
- this->write(" ");
- this->writeName(f.fName);
- this->writeLine(";");
- }
+ this->writeFields(type.fields(), type.fOffset);
fIndentation--;
this->write("}");
break;
@@ -317,6 +310,12 @@
case SK_FRAGCOORD_BUILTIN:
this->writeFragCoord();
break;
+ case SK_VERTEXID_BUILTIN:
+ this->write("sk_VertexID");
+ break;
+ case SK_INSTANCEID_BUILTIN:
+ this->write("sk_InstanceID");
+ break;
default:
if (Variable::kGlobal_Storage == ref.fVariable.fStorage) {
if (ref.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) {
@@ -574,6 +573,8 @@
}
if (fProgram.fKind == Program::kFragment_Kind) {
this->write(", float4 _fragCoord [[position]]");
+ } else if (fProgram.fKind == Program::kVertex_Kind) {
+ this->write(", uint sk_VertexID [[vertex_id]], uint sk_InstanceID [[instance_id]]");
}
separator = ", ";
} else {
@@ -707,58 +708,16 @@
if ("sk_PerVertex" == intf.fTypeName) {
return;
}
- MemoryLayout memoryLayout(MemoryLayout::k140_Standard);
- this->write("struct ");
this->writeModifiers(intf.fVariable.fModifiers, true);
+ this->write("struct ");
this->writeLine(intf.fTypeName + " {");
- fIndentation++;
const Type* structType = &intf.fVariable.fType;
fWrittenStructs.push_back(structType);
while (Type::kArray_Kind == structType->kind()) {
structType = &structType->componentType();
}
- int currentOffset = 0;
- for (const auto& field: structType->fields()) {
- int fieldOffset = field.fModifiers.fLayout.fOffset;
- if (fieldOffset != -1) {
- if (currentOffset > fieldOffset) {
- ABORT("Original interface offsets are too close for MoltenVK");
- } else if (currentOffset < fieldOffset) {
- this->write("char pad");
- this->write(to_string(fPaddingCount++));
- this->write("[");
- this->write(to_string(fieldOffset - currentOffset));
- this->writeLine("];");
- currentOffset = fieldOffset;
- }
- }
- const Type* fieldType = field.fType;
- if (fieldType->kind() == Type::kVector_Kind &&
- fieldType->columns() == 3) {
- // Pack all vec3 types so that their size in bytes will match what was expected in the
- // original SkSL code since MSL has vec3 sizes equal to 4 * component type, while SkSL
- // has vec3 equal to 3 * component type.
- this->write(PACKED_PREFIX);
- }
- currentOffset += memoryLayout.size(*fieldType);
- std::vector<int> sizes;
- while (fieldType->kind() == Type::kArray_Kind) {
- sizes.push_back(fieldType->columns());
- fieldType = &fieldType->componentType();
- }
- this->writeType(*fieldType);
- this->write(" ");
- this->writeName(field.fName);
- for (int s : sizes) {
- if (s <= 0) {
- this->write("[]");
- } else {
- this->write("[" + to_string(s) + "]");
- }
- }
- this->writeLine(";");
- fInterfaceBlockMap[&field] = &intf;
- }
+ fIndentation++;
+ writeFields(structType->fields(), structType->fOffset, &intf);
if (fProgram.fKind == Program::kFragment_Kind) {
this->writeLine("float u_skRTHeight;");
}
@@ -781,6 +740,64 @@
this->writeLine(";");
}
+void MetalCodeGenerator::writeFields(const std::vector<Type::Field>& fields, int parentOffset,
+ const InterfaceBlock* parentIntf) {
+ MemoryLayout memoryLayout(MemoryLayout::k140_Standard);
+ int currentOffset = 0;
+ for (const auto& field: fields) {
+ int fieldOffset = field.fModifiers.fLayout.fOffset;
+ const Type* fieldType = field.fType;
+ if (fieldOffset != -1) {
+ if (currentOffset > fieldOffset) {
+ fErrors.error(parentOffset,
+ "offset of field '" + field.fName + "' must be at least " +
+ to_string((int) currentOffset));
+ } else if (currentOffset < fieldOffset) {
+ this->write("char pad");
+ this->write(to_string(fPaddingCount++));
+ this->write("[");
+ this->write(to_string(fieldOffset - currentOffset));
+ this->writeLine("];");
+ currentOffset = fieldOffset;
+ }
+ int alignment = memoryLayout.alignment(*fieldType);
+ if (fieldOffset % alignment) {
+ fErrors.error(parentOffset,
+ "offset of field '" + field.fName + "' must be a multiple of " +
+ to_string((int) alignment));
+ }
+ }
+ if (fieldType->kind() == Type::kVector_Kind &&
+ fieldType->columns() == 3) {
+ // Pack all vec3 types so that their size in bytes will match what was expected in the
+ // original SkSL code since MSL has vec3 sizes equal to 4 * component type, while SkSL
+ // has vec3 equal to 3 * component type.
+ this->write(PACKED_PREFIX);
+ }
+ currentOffset += memoryLayout.size(*fieldType);
+ std::vector<int> sizes;
+ while (fieldType->kind() == Type::kArray_Kind) {
+ sizes.push_back(fieldType->columns());
+ fieldType = &fieldType->componentType();
+ }
+ this->writeModifiers(field.fModifiers, false);
+ this->writeType(*fieldType);
+ this->write(" ");
+ this->writeName(field.fName);
+ for (int s : sizes) {
+ if (s <= 0) {
+ this->write("[]");
+ } else {
+ this->write("[" + to_string(s) + "]");
+ }
+ }
+ this->writeLine(";");
+ if (parentIntf) {
+ fInterfaceBlockMap[&field] = parentIntf;
+ }
+ }
+}
+
void MetalCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
this->writeExpression(value, kTopLevel_Precedence);
}
diff --git a/src/sksl/SkSLMetalCodeGenerator.h b/src/sksl/SkSLMetalCodeGenerator.h
index d5a8ca1..49a5bd6 100644
--- a/src/sksl/SkSLMetalCodeGenerator.h
+++ b/src/sksl/SkSLMetalCodeGenerator.h
@@ -80,7 +80,7 @@
MetalCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
OutputStream* out)
: INHERITED(program, errors, out)
- , fReservedWords({"atan2", "rsqrt", "dfdx", "dfdy"})
+ , fReservedWords({"atan2", "rsqrt", "dfdx", "dfdy", "vertex", "fragment"})
, fLineEnding("\n")
, fContext(*context) {
this->setupIntrinsics();
@@ -136,6 +136,9 @@
void writeInterfaceBlocks();
+ void writeFields(const std::vector<Type::Field>& fields, int parentOffset,
+ const InterfaceBlock* parentIntf = nullptr);
+
int size(const Type* type, bool isPacked) const;
int alignment(const Type* type, bool isPacked) const;