From ee84fe1e6484d8fb7b9b1549d9d68c9dbabe3737 Mon Sep 17 00:00:00 2001 From: Timothy Liang Date: Fri, 18 May 2018 14:38:19 -0400 Subject: 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 Reviewed-by: Ethan Nicholas --- src/sksl/SkSLMetalCodeGenerator.cpp | 128 +++++++++++++++++++++++++++++------- src/sksl/SkSLMetalCodeGenerator.h | 10 +++ 2 files changed, 114 insertions(+), 24 deletions(-) (limited to 'src/sksl') diff --git a/src/sksl/SkSLMetalCodeGenerator.cpp b/src/sksl/SkSLMetalCodeGenerator.cpp index b8fdc1c193..2f801a8d88 100644 --- a/src/sksl/SkSLMetalCodeGenerator.cpp +++ b/src/sksl/SkSLMetalCodeGenerator.cpp @@ -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 "); //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 _colorMap [[texture(TextureIndexColor)]]"); - } // FIXME may require textureindexcolor field, hardcoded for now + if (var.fVar->fType.kind() == Type::kSampler_Kind) { + this->write(", texture2d "); // 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) { diff --git a/src/sksl/SkSLMetalCodeGenerator.h b/src/sksl/SkSLMetalCodeGenerator.h index 6f8933c381..a0a0cae986 100644 --- a/src/sksl/SkSLMetalCodeGenerator.h +++ b/src/sksl/SkSLMetalCodeGenerator.h @@ -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 Intrinsic; std::unordered_map fIntrinsicMap; + std::vector fInitNonConstGlobalVars; + TextureId fCurrentTextureId = 0; + std::unordered_map fTextureMap; + bool fNeedsGlobalStructInit = false; const char* fLineEnding; const Context& fContext; StringStream fHeader; -- cgit v1.2.3