fixed vec3 size differences and mod calculation of skslc msl backend

Bug: skia:
Change-Id: I5dc6d956463845627a1a2debee5ac8856e5e2e8d
Reviewed-on: https://skia-review.googlesource.com/132500
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Timothy Liang <timliang@google.com>
This commit is contained in:
Timothy Liang 2018-06-07 09:55:33 -04:00 committed by Skia Commit-Bot
parent 229f4d93c1
commit 651286f5d8
2 changed files with 64 additions and 133 deletions

View File

@ -25,6 +25,7 @@ void MetalCodeGenerator::setupIntrinsics() {
#define METAL(x) std::make_pair(kMetal_IntrinsicKind, k ## x ## _MetalIntrinsic)
#define SPECIAL(x) std::make_pair(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic)
fIntrinsicMap[String("texture")] = SPECIAL(Texture);
fIntrinsicMap[String("mod")] = SPECIAL(Mod);
fIntrinsicMap[String("lessThan")] = METAL(LessThan);
fIntrinsicMap[String("lessThanEqual")] = METAL(LessThanEqual);
fIntrinsicMap[String("greaterThan")] = METAL(GreaterThan);
@ -83,7 +84,9 @@ void MetalCodeGenerator::writeType(const Type& type) {
this->writeModifiers(f.fModifiers, false);
// sizes (which must be static in structs) are part of the type name here
this->writeType(*f.fType);
this->writeLine(" " + f.fName + ";");
this->write(" ");
this->writeName(f.fName);
this->writeLine(";");
}
fIndentation--;
this->write("}");
@ -202,14 +205,12 @@ void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
this->write("atan2");
} else if (c.fFunction.fBuiltin && "inversesqrt" == c.fFunction.fName) {
this->write("rsqrt");
} else if (c.fFunction.fBuiltin && "mod" == c.fFunction.fName) {
this->write("fmod");
} else if (c.fFunction.fBuiltin && "dFdx" == c.fFunction.fName) {
this->write("dfdx");
} else if (c.fFunction.fBuiltin && "dFdy" == c.fFunction.fName) {
this->write("dfdy");
} else {
this->write(c.fFunction.fName);
this->writeName(c.fFunction.fName);
}
this->write("(");
const char* separator = "";
@ -260,6 +261,18 @@ void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIn
this->write(")");
}
break;
case kMod_SpecialIntrinsic:
// fmod(x, y) in metal calculates x - y * trunc(x / y) instead of x - y * floor(x / y)
this->write("((");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->write(") - (");
this->writeExpression(*c.fArguments[1], kSequence_Precedence);
this->write(") * floor((");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->write(") / (");
this->writeExpression(*c.fArguments[1], kSequence_Precedence);
this->write(")))");
break;
default:
ABORT("unsupported special intrinsic kind");
}
@ -317,14 +330,7 @@ void MetalCodeGenerator::writeVariableReference(const VariableReference& ref) {
this->write("_globals->");
}
}
// FIXME - probably going to eventually have a map of renamed functions and
// use it to detect conflicts with variable names.
if (ref.fVariable.fName == "dfdx") {
this->write("dFdx");
} else if (ref.fVariable.fName == "dfdy") {
this->write("dFdy");
}
this->write(ref.fVariable.fName);
this->writeName(ref.fVariable.fName);
}
}
@ -357,7 +363,7 @@ void MetalCodeGenerator::writeFieldAccess(const FieldAccess& f) {
this->write(fInterfaceBlockNameMap[fInterfaceBlockMap[field]]);
this->write("->");
}
this->write(field->fName);
this->writeName(field->fName);
}
}
}
@ -536,12 +542,12 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
VarDeclaration& var = (VarDeclaration&) *stmt;
if (var.fVar->fType.kind() == Type::kSampler_Kind) {
this->write(", texture2d<float> "); // FIXME - support other texture types
this->write(var.fVar->fName);
this->writeName(var.fVar->fName);
this->write("[[texture(");
this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
this->write(")]]");
this->write(", sampler ");
this->write(var.fVar->fName);
this->writeName(var.fVar->fName);
this->write(SAMPLER_SUFFIX);
this->write("[[sampler(");
this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
@ -572,7 +578,9 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
separator = ", ";
} else {
this->writeType(f.fDeclaration.fReturnType);
this->write(" " + f.fDeclaration.fName + "(");
this->write(" ");
this->writeName(f.fDeclaration.fName);
this->write("(");
if (this->requirements(f.fDeclaration) & kInputs_Requirement) {
this->write("Inputs _in");
separator = ", ";
@ -607,7 +615,8 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
this->write("*");
}
this->write(" " + param->fName);
this->write(" ");
this->writeName(param->fName);
for (int s : sizes) {
if (s <= 0) {
this->write("[]");
@ -627,29 +636,29 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
for (const auto& intf: fInterfaceBlockNameMap) {
const auto& intfName = intf.second;
this->write(" _globals->");
this->write(intfName);
this->writeName(intfName);
this->write(" = &");
this->write(intfName);
this->writeName(intfName);
this->write(";\n");
}
for (const auto& var: fInitNonConstGlobalVars) {
this->write(" _globals->");
this->write(var->fVar->fName);
this->writeName(var->fVar->fName);
this->write(" = ");
this->writeVarInitializer(*var->fVar, *var->fValue);
this->writeLine(";");
}
for (const auto& texture: fTextures) {
this->write(" _globals->");
this->write(texture->fName);
this->writeName(texture->fName);
this->write(" = ");
this->write(texture->fName);
this->writeName(texture->fName);
this->write(";\n");
this->write(" _globals->");
this->write(texture->fName);
this->writeName(texture->fName);
this->write(SAMPLER_SUFFIX);
this->write(" = ");
this->write(texture->fName);
this->writeName(texture->fName);
this->write(SAMPLER_SUFFIX);
this->write(";\n");
}
@ -698,6 +707,7 @@ void MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
if ("sk_PerVertex" == intf.fTypeName) {
return;
}
MemoryLayout memoryLayout(MemoryLayout::k140_Standard);
this->write("struct ");
this->writeModifiers(intf.fVariable.fModifiers, true);
this->writeLine(intf.fTypeName + " {");
@ -708,7 +718,6 @@ void MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
structType = &structType->componentType();
}
int currentOffset = 0;
// Pack half/float3 types and add char arrays for padding when needed to maintain alignment
for (const auto& field: structType->fields()) {
int fieldOffset = field.fModifiers.fLayout.fOffset;
if (fieldOffset != -1) {
@ -724,19 +733,22 @@ void MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
}
}
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();
}
bool isPacked = false;
if (fieldType->kind() == Type::kVector_Kind && fieldType->columns() == 3 &&
fieldOffset != -1) {
this->write(PACKED_PREFIX);
isPacked = true;
}
this->writeType(*fieldType);
this->write(" " + field.fName);
this->write(" ");
this->writeName(field.fName);
for (int s : sizes) {
if (s <= 0) {
this->write("[]");
@ -746,7 +758,6 @@ void MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
}
this->writeLine(";");
fInterfaceBlockMap[&field] = &intf;
currentOffset += size(fieldType, isPacked);
}
if (fProgram.fKind == Program::kFragment_Kind) {
this->writeLine("float u_skRTHeight;");
@ -770,96 +781,17 @@ void MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
this->writeLine(";");
}
// FIXME - Update SkSLMemoryLayout.h to calculate size and alignment values below for MSL shaders.
// Also, the below currently only handle cases needed for gm's
int MetalCodeGenerator::size(const Type* type, bool isPacked) const {
if (type->kind() == Type::kArray_Kind && type->componentType().kind() == Type::kScalar_Kind) {
return type->columns() * 4;
}
if ((type->kind() == Type::kVector_Kind || type->kind() == Type::kMatrix_Kind) &&
type->componentType() == *fContext.fHalf_Type) {
type = &fContext.fFloat_Type->toCompound(fContext, type->columns(),type->rows());
} else if (type == fContext.fHalf_Type.get()) {
type = fContext.fFloat_Type.get();
}
if (isPacked) {
if (type == fContext.fFloat_Type.get()) {
return 4;
} else if (type == fContext.fFloat2_Type.get()) {
return 8;
} else if (type == fContext.fFloat3_Type.get()) {
return 12;
} else if (type == fContext.fFloat4_Type.get()) {
return 16;
}
} else {
if (type == fContext.fFloat_Type.get()) {
return 4;
} else if (type == fContext.fFloat2_Type.get()) {
return 8;
} else if (type == fContext.fFloat3_Type.get()) {
return 16;
} else if (type == fContext.fFloat4_Type.get()) {
return 16;
} else if (type == fContext.fFloat2x2_Type.get()) {
return 16;
} else if (type == fContext.fFloat2x3_Type.get()) {
return 32;
} else if (type == fContext.fFloat2x4_Type.get()) {
return 32;
} else if (type == fContext.fFloat3x2_Type.get()) {
return 24;
} else if (type == fContext.fFloat3x3_Type.get()) {
return 48;
} else if (type == fContext.fFloat3x4_Type.get()) {
return 48;
} else if (type == fContext.fFloat4x2_Type.get()) {
return 32;
} else if (type == fContext.fFloat4x3_Type.get()) {
return 64;
} else if (type == fContext.fFloat4x4_Type.get()) {
return 64;
}
}
ABORT("Unsupported type for size: %s", String(type->fName).c_str());
}
int MetalCodeGenerator::alignment(const Type* type, bool isPacked) const {
if ((type->kind() == Type::kVector_Kind || type->kind() == Type::kMatrix_Kind) &&
type->componentType() == *fContext.fHalf_Type) {
type = &fContext.fFloat_Type->toCompound(fContext, type->columns(),type->rows());
} else if (type == fContext.fHalf_Type.get()) {
type = fContext.fFloat_Type.get();
}
if (isPacked) {
if (type == fContext.fFloat_Type.get()) {
return 4;
} else if (type == fContext.fFloat2_Type.get()) {
return 4;
} else if (type == fContext.fFloat3_Type.get()) {
return 4;
} else if (type == fContext.fFloat4_Type.get()) {
return 4;
}
} else {
if (type == fContext.fFloat_Type.get()) {
return 4;
} else if (type == fContext.fFloat2_Type.get()) {
return 8;
} else if (type == fContext.fFloat3_Type.get()) {
return 16;
} else if (type == fContext.fFloat4_Type.get()) {
return 16;
}
}
ABORT("Unsupported type for alignment: %s", String(type->fName).c_str());
}
void MetalCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
this->writeExpression(value, kTopLevel_Precedence);
}
void MetalCodeGenerator::writeName(const String& name) {
if (fReservedWords.find(name) != fReservedWords.end()) {
this->write("_"); // adding underscore before name to avoid conflict with reserved words
}
this->write(name);
}
void MetalCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
ASSERT(decl.fVars.size() > 0);
bool wroteType = false;
@ -876,14 +808,7 @@ void MetalCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool
this->write(" ");
wroteType = true;
}
// FIXME - probably going to eventually have a map of all renamed functions and
// use it to detect conflicts with variable names.
if (var.fVar->fName == "dfdx") {
this->write("dFdx");
} else if (var.fVar->fName == "dfdy") {
this->write("dFdy");
}
this->write(var.fVar->fName);
this->writeName(var.fVar->fName);
for (const auto& size : var.fSizes) {
this->write("[");
if (size) {
@ -1083,7 +1008,7 @@ void MetalCodeGenerator::writeUniformStruct() {
this->write(" ");
for (const auto& stmt : decls.fVars) {
VarDeclaration& var = (VarDeclaration&) *stmt;
this->write(var.fVar->fName);
this->writeName(var.fVar->fName);
}
this->write(";\n");
}
@ -1110,7 +1035,7 @@ void MetalCodeGenerator::writeInputStruct() {
this->write(" ");
for (const auto& stmt : decls.fVars) {
VarDeclaration& var = (VarDeclaration&) *stmt;
this->write(var.fVar->fName);
this->writeName(var.fVar->fName);
if (-1 != var.fVar->fModifiers.fLayout.fLocation) {
if (fProgram.fKind == Program::kVertex_Kind) {
this->write(" [[attribute(" +
@ -1149,7 +1074,7 @@ void MetalCodeGenerator::writeOutputStruct() {
this->write(" ");
for (const auto& stmt : decls.fVars) {
VarDeclaration& var = (VarDeclaration&) *stmt;
this->write(var.fVar->fName);
this->writeName(var.fVar->fName);
if (fProgram.fKind == Program::kVertex_Kind) {
this->write(" [[user(locn" +
to_string(var.fVar->fModifiers.fLayout.fLocation) + ")]]");
@ -1199,7 +1124,7 @@ void MetalCodeGenerator::writeGlobalStruct() {
this->write(" constant ");
this->write(intfType->fTypeName);
this->write("* ");
this->write(intfName);
this->writeName(intfName);
this->write(";\n");
}
for (const auto& e : fProgram) {
@ -1221,12 +1146,12 @@ void MetalCodeGenerator::writeGlobalStruct() {
this->write(" ");
for (const auto& stmt : decls.fVars) {
VarDeclaration& var = (VarDeclaration&) *stmt;
this->write(var.fVar->fName);
this->writeName(var.fVar->fName);
if (var.fVar->fType.kind() == Type::kSampler_Kind) {
fTextures.push_back(var.fVar);
this->write(";\n");
this->write(" sampler ");
this->write(var.fVar->fName);
this->writeName(var.fVar->fName);
this->write(SAMPLER_SUFFIX);
}
if (var.fValue) {

View File

@ -13,6 +13,7 @@
#include <unordered_map>
#include "SkSLCodeGenerator.h"
#include "SkSLMemoryLayout.h"
#include "SkSLStringStream.h"
#include "ir/SkSLBinaryExpression.h"
#include "ir/SkSLBoolLiteral.h"
@ -79,6 +80,7 @@ public:
MetalCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
OutputStream* out)
: INHERITED(program, errors, out)
, fReservedWords({"atan2", "rsqrt", "dfdx", "dfdy"})
, fLineEnding("\n")
, fContext(*context) {
this->setupIntrinsics();
@ -102,6 +104,7 @@ protected:
enum SpecialIntrinsic {
kTexture_SpecialIntrinsic,
kMod_SpecialIntrinsic,
};
enum MetalIntrinsic {
@ -161,6 +164,8 @@ protected:
void writeVarInitializer(const Variable& var, const Expression& value);
void writeName(const String& name);
void writeVarDeclarations(const VarDeclarations& decl, bool global);
void writeFragCoord();
@ -231,6 +236,7 @@ protected:
typedef std::pair<IntrinsicKind, int32_t> Intrinsic;
std::unordered_map<String, Intrinsic> fIntrinsicMap;
std::unordered_set<String> fReservedWords;
std::vector<const VarDeclaration*> fInitNonConstGlobalVars;
std::vector<const Variable*> fTextures;
std::unordered_map<const Type::Field*, const InterfaceBlock*> fInterfaceBlockMap;