added global variable and multi-texture support to metal sksl backend

Bug: skia:
Change-Id: If676774ec0a30c5b536ccffbff2220d180b7fa59
Reviewed-on: https://skia-review.googlesource.com/129187
Commit-Queue: Timothy Liang <timliang@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
Timothy Liang 2018-05-18 14:38:19 -04:00 committed by Skia Commit-Bot
parent ab0795c4dd
commit ee84fe1e64
2 changed files with 114 additions and 24 deletions

View File

@ -17,7 +17,7 @@
namespace SkSL {
void MetalCodeGenerator::setupIntrinsics(){
void MetalCodeGenerator::setupIntrinsics() {
#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
k ## x ## _SpecialIntrinsic)
@ -25,6 +25,10 @@ void MetalCodeGenerator::setupIntrinsics(){
fIntrinsicMap[String("texture")] = SPECIAL(Texture);
}
MetalCodeGenerator::TextureId MetalCodeGenerator::nextTextureId() {
return fCurrentTextureId++;
}
void MetalCodeGenerator::write(const char* s) {
if (!s[0]) {
return;
@ -86,6 +90,9 @@ void MetalCodeGenerator::writeType(const Type& type) {
this->writeType(type.componentType());
this->write(to_string(type.columns()));
break;
case Type::kSampler_Kind:
this->write("texture2d<half> "); //FIXME - support other texture types;
break;
default:
this->write(type.name());
}
@ -186,6 +193,11 @@ void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
this->write("_uniforms");
separator = ", ";
}
if (this->requirements(c.fFunction) & kGlobals_Requirement) {
this->write(separator);
this->write("_globals");
separator = ", ";
}
for (size_t i = 0; i < c.fArguments.size(); ++i) {
const Expression& arg = *c.fArguments[i];
this->write(separator);
@ -201,9 +213,15 @@ void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIntrinsic kind) {
switch (kind) {
case kTexture_SpecialIntrinsic:
this->write("_colorMap.sample($colorSampler, ");
this->writeExpression(*c.fArguments[0], kSequence_Precedence);
this->write(".sample(_globals->colorSampler, ");
this->writeExpression(*c.fArguments[1], kSequence_Precedence);
this->write(".xy)"); // FIXME - dimension checking
if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
this->write(".xy)"); // FIXME - add projection functionality
} else {
ASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
this->write(")");
}
break;
default:
ABORT("unsupported special intrinsic kind");
@ -254,12 +272,11 @@ void MetalCodeGenerator::writeVariableReference(const VariableReference& ref) {
if (ref.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) {
this->write("_in.");
} else if (ref.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag) {
this->write("_out.");
this->write("_out->");
} else if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) {
this->write("_uniforms.");
} else {
fErrors.error(ref.fVariable.fOffset, "Metal backend does not support global "
"variables");
this->write("_globals->");
}
}
this->write(ref.fVariable.fName);
@ -283,7 +300,7 @@ void MetalCodeGenerator::writeFieldAccess(const FieldAccess& f) {
this->write("gl_ClipDistance");
break;
case SK_POSITION_BUILTIN:
this->write("_out.position");
this->write("_out->position");
break;
default:
this->write(f.fBase->fType.fields()[f.fFieldIndex].fName);
@ -437,7 +454,6 @@ void MetalCodeGenerator::writeSetting(const Setting& s) {
}
void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
bool needColorSampler = false;
const char* separator = "";
if ("main" == f.fDeclaration.fName) {
switch (fProgram.fKind) {
@ -461,12 +477,15 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
if (!decls.fVars.size()) {
continue;
}
for(const auto& stmt: decls.fVars){
for (const auto& stmt: decls.fVars) {
VarDeclaration& var = (VarDeclaration&) *stmt;
if(var.fVar->fType == *fContext.fSampler2D_Type){
needColorSampler = true;
this->write(", texture2d<half> _colorMap [[texture(TextureIndexColor)]]");
} // FIXME may require textureindexcolor field, hardcoded for now
if (var.fVar->fType.kind() == Type::kSampler_Kind) {
this->write(", texture2d<half> "); // FIXME - support other texture types
this->write(var.fVar->fName);
this->write("[[texture(");
this->write(to_string(fTextureMap[var.fVar->fName]));
this->write(")]]");
}
}
}
}
@ -480,7 +499,7 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
}
if (this->requirements(f.fDeclaration) & kOutputs_Requirement) {
this->write(separator);
this->write("thread Outputs& _out");
this->write("thread Outputs* _out");
separator = ", ";
}
if (this->requirements(f.fDeclaration) & kUniforms_Requirement) {
@ -488,6 +507,11 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
this->write("Uniforms _uniforms");
separator = ", ";
}
if (this->requirements(f.fDeclaration) & kGlobals_Requirement) {
this->write(separator);
this->write("thread Globals* _globals");
separator = ", ";
}
}
for (const auto& param : f.fDeclaration.fParameters) {
this->write(separator);
@ -517,9 +541,27 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
ASSERT(!fProgram.fSettings.fFragColorIsInOut);
if ("main" == f.fDeclaration.fName) {
if (needColorSampler) {
this->writeLine(" constexpr sampler "
"$colorSampler(mip_filter::linear, mag_filter::linear, min_filter::linear);");
if (fNeedsGlobalStructInit) {
this->writeLine(" Globals globalStruct;");
this->writeLine(" thread Globals* _globals = &globalStruct;");
for (const auto var: fInitNonConstGlobalVars) {
this->write(" _globals->");
this->write(var->fVar->fName);
this->write(" = ");
this->writeVarInitializer(*var->fVar, *var->fValue);
this->writeLine(";");
}
}
if (!fTextureMap.empty()) {
this->writeLine(" _globals->colorSampler = sampler(mip_filter::linear, "
"mag_filter::linear, min_filter::linear);"); // FIXME - support other samplers
for (const auto& texture: fTextureMap) {
this->write(" _globals->");
this->write(texture.first);
this->write(" = ");
this->write(texture.first);
this->write(";\n");
}
}
switch (fProgram.fKind) {
case Program::kFragment_Kind:
@ -564,7 +606,7 @@ void MetalCodeGenerator::writeModifiers(const Modifiers& modifiers,
this->write("thread ");
}
if (modifiers.fFlags & Modifiers::kConst_Flag) {
this->write("const ");
this->write("constant ");
}
}
@ -609,14 +651,9 @@ void MetalCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool
bool wroteType = false;
for (const auto& stmt : decl.fVars) {
VarDeclaration& var = (VarDeclaration&) *stmt;
if (var.fVar->fModifiers.fFlags & (Modifiers::kIn_Flag | Modifiers::kOut_Flag |
Modifiers::kUniform_Flag)) {
ASSERT(global);
if (global && !(var.fVar->fModifiers.fFlags & Modifiers::kConst_Flag)) {
continue;
}
if (var.fVar->fType == *fContext.fSampler2D_Type){
continue; // FIXME - temporarily ignoring global sampler2Ds
}
if (wroteType) {
this->write(", ");
} else {
@ -892,6 +929,46 @@ void MetalCodeGenerator::writeOutputStruct() {
} this->write("};\n");
}
void MetalCodeGenerator::writeGlobalStruct() {
bool wroteStructDecl = false;
for (const auto& e : fProgram) {
if (ProgramElement::kVar_Kind == e.fKind) {
VarDeclarations& decls = (VarDeclarations&) e;
if (!decls.fVars.size()) {
continue;
}
const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
if (!first.fModifiers.fFlags && -1 == first.fModifiers.fLayout.fBuiltin) {
if (!wroteStructDecl) {
this->write("struct Globals {\n");
wroteStructDecl = true;
}
fNeedsGlobalStructInit = true;
this->write(" ");
this->writeType(first.fType);
this->write(" ");
for (const auto& stmt : decls.fVars) {
VarDeclaration& var = (VarDeclaration&) *stmt;
if (var.fVar->fType.kind() == Type::kSampler_Kind) {
fTextureMap[var.fVar->fName] = this->nextTextureId();
}
this->write(var.fVar->fName);
if (var.fValue) {
fInitNonConstGlobalVars.push_back(&var);
}
}
this->write(";\n");
}
}
}
if (!fTextureMap.empty()) {
this->writeLine(" sampler colorSampler;");
}
if (wroteStructDecl) {
this->write("};\n");
}
}
void MetalCodeGenerator::writeProgramElement(const ProgramElement& e) {
switch (e.fKind) {
case ProgramElement::kExtension_Kind:
@ -977,6 +1054,8 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expressi
result = kOutputs_Requirement;
} else if (v.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) {
result = kUniforms_Requirement;
} else {
result = kGlobals_Requirement;
}
}
return result;
@ -1072,6 +1151,7 @@ bool MetalCodeGenerator::generateCode() {
if (Program::kVertex_Kind == fProgram.fKind) {
this->writeOutputStruct();
}
this->writeGlobalStruct();
StringStream body;
fOut = &body;
for (const auto& e : fProgram) {

View File

@ -85,10 +85,12 @@ public:
protected:
typedef int Requirements;
typedef unsigned int TextureId;
static constexpr Requirements kNo_Requirements = 0;
static constexpr Requirements kInputs_Requirement = 1 << 0;
static constexpr Requirements kOutputs_Requirement = 1 << 1;
static constexpr Requirements kUniforms_Requirement = 1 << 2;
static constexpr Requirements kGlobals_Requirement = 1 << 3;
enum IntrinsicKind {
kSpecial_IntrinsicKind
@ -100,6 +102,8 @@ protected:
void setupIntrinsics();
TextureId nextTextureId();
void write(const char* s);
void writeLine();
@ -118,6 +122,8 @@ protected:
void writeOutputStruct();
void writeGlobalStruct();
void writePrecisionModifier();
void writeType(const Type& type);
@ -210,6 +216,10 @@ protected:
typedef std::tuple<IntrinsicKind, int32_t, int32_t, int32_t, int32_t> Intrinsic;
std::unordered_map<String, Intrinsic> fIntrinsicMap;
std::vector<const VarDeclaration*> fInitNonConstGlobalVars;
TextureId fCurrentTextureId = 0;
std::unordered_map<String, TextureId> fTextureMap;
bool fNeedsGlobalStructInit = false;
const char* fLineEnding;
const Context& fContext;
StringStream fHeader;