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:
parent
ab0795c4dd
commit
ee84fe1e64
@ -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) {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user