Index: src/sksl/SkSLGLSLCodeGenerator.cpp |
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp |
index da0bcb903cf3508826e8a311f6f98338ba06f0a1..58cf7d3c36360622f9510a3254bcf403b5c43ee4 100644 |
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp |
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp |
@@ -14,8 +14,11 @@ |
#include "ir/SkSLExpressionStatement.h" |
#include "ir/SkSLExtension.h" |
#include "ir/SkSLIndexExpression.h" |
+#include "ir/SkSLModifiersDeclaration.h" |
#include "ir/SkSLVariableReference.h" |
+#define SK_FRAGCOLOR_BUILTIN 10001 |
+ |
namespace SkSL { |
void GLSLCodeGenerator::write(const char* s) { |
@@ -66,7 +69,7 @@ void GLSLCodeGenerator::writeType(const Type& type) { |
this->writeLine("struct " + type.name() + " {"); |
fIndentation++; |
for (const auto& f : type.fields()) { |
- this->writeModifiers(f.fModifiers); |
+ 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 + ";"); |
@@ -124,7 +127,42 @@ void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence paren |
} |
} |
+static bool is_abs(Expression& expr) { |
+ if (expr.fKind != Expression::kFunctionCall_Kind) { |
+ return false; |
+ } |
+ return ((FunctionCall&) expr).fFunction.fName == "abs"; |
+} |
+ |
+// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a |
+// Tegra3 compiler bug. |
+void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) { |
+ ASSERT(!fCaps.fCanUseMinAndAbsTogether); |
+ std::string tmpVar1 = "minAbsHackVar" + to_string(fVarCount++); |
+ std::string tmpVar2 = "minAbsHackVar" + to_string(fVarCount++); |
+ this->fFunctionHeader += " " + absExpr.fType.name() + " " + tmpVar1 + ";\n"; |
+ this->fFunctionHeader += " " + otherExpr.fType.name() + " " + tmpVar2 + ";\n"; |
+ this->write("((" + tmpVar1 + " = "); |
+ this->writeExpression(absExpr, kTopLevel_Precedence); |
+ this->write(") < (" + tmpVar2 + " = "); |
+ this->writeExpression(otherExpr, kAssignment_Precedence); |
+ this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")"); |
+} |
+ |
void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) { |
+ if (!fCaps.fCanUseMinAndAbsTogether && c.fFunction.fName == "min") { |
+ ASSERT(c.fArguments.size() == 2); |
+ if (is_abs(*c.fArguments[0])) { |
+ this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]); |
+ return; |
+ } |
+ if (is_abs(*c.fArguments[1])) { |
+ // note that this violates the GLSL left-to-right evaluation semantics. I doubt it will |
+ // ever end up mattering, but it's worth calling out. |
+ this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]); |
+ return; |
+ } |
+ } |
this->write(c.fFunction.fName + "("); |
const char* separator = ""; |
for (const auto& arg : c.fArguments) { |
@@ -147,7 +185,15 @@ void GLSLCodeGenerator::writeConstructor(const Constructor& c) { |
} |
void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) { |
- this->write(ref.fVariable.fName); |
+ if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN) { |
+ if (fCaps.fMustDeclareFragmentShaderOutput) { |
+ this->write("sk_FragColor"); |
+ } else { |
+ this->write("gl_FragColor"); |
+ } |
+ } else { |
+ this->write(ref.fVariable.fName); |
+ } |
} |
void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) { |
@@ -270,7 +316,11 @@ void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) { |
} |
void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) { |
- this->write(to_string(i.fValue)); |
+ if (i.fType == *fContext.fUInt_Type) { |
+ this->write(to_string(i.fValue & 0xffffffff) + "u"); |
+ } else { |
+ this->write(to_string((int32_t) i.fValue)); |
+ } |
} |
void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) { |
@@ -284,28 +334,99 @@ void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) { |
for (const auto& param : f.fDeclaration.fParameters) { |
this->write(separator); |
separator = ", "; |
- this->writeModifiers(param->fModifiers); |
- this->writeType(param->fType); |
+ this->writeModifiers(param->fModifiers, false); |
+ std::vector<int> sizes; |
+ const Type* type = ¶m->fType; |
+ while (type->kind() == Type::kArray_Kind) { |
+ sizes.push_back(type->columns()); |
+ type = &type->componentType(); |
+ } |
+ this->writeType(*type); |
this->write(" " + param->fName); |
+ for (int s : sizes) { |
+ if (s <= 0) { |
+ this->write("[]"); |
+ } else { |
+ this->write("[" + to_string(s) + "]"); |
+ } |
+ } |
} |
- this->write(") "); |
- this->writeBlock(*f.fBody); |
- this->writeLine(); |
+ this->writeLine(") {"); |
+ |
+ fFunctionHeader = ""; |
+ std::ostream* oldOut = fOut; |
+ std::stringstream buffer; |
+ fOut = &buffer; |
+ fIndentation++; |
+ for (const auto& s : f.fBody->fStatements) { |
+ this->writeStatement(*s); |
+ this->writeLine(); |
+ } |
+ fIndentation--; |
+ this->writeLine("}"); |
+ |
+ fOut = oldOut; |
+ this->write(fFunctionHeader); |
+ this->write(buffer.str()); |
} |
-void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers) { |
- this->write(modifiers.description()); |
+void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers, |
+ bool globalContext) { |
+ if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) { |
+ this->write("noperspective "); |
+ } |
+ if (modifiers.fFlags & Modifiers::kFlat_Flag) { |
+ this->write("flat "); |
+ } |
+ std::string layout = modifiers.fLayout.description(); |
+ if (layout.length()) { |
+ this->write(layout + " "); |
+ } |
+ if ((modifiers.fFlags & Modifiers::kIn_Flag) && |
+ (modifiers.fFlags & Modifiers::kOut_Flag)) { |
+ this->write("inout "); |
+ } else if (modifiers.fFlags & Modifiers::kIn_Flag) { |
+ if (globalContext && fCaps.fVersion < 130) { |
+ this->write(fProgramKind == Program::kVertex_Kind ? "attribute " |
+ : "varying "); |
+ } else { |
+ this->write("in "); |
+ } |
+ } else if (modifiers.fFlags & Modifiers::kOut_Flag) { |
+ if (globalContext && fCaps.fVersion < 130) { |
+ this->write("varying "); |
+ } else { |
+ this->write("out "); |
+ } |
+ } |
+ if (modifiers.fFlags & Modifiers::kUniform_Flag) { |
+ this->write("uniform "); |
+ } |
+ if (modifiers.fFlags & Modifiers::kConst_Flag) { |
+ this->write("const "); |
+ } |
+ if (fCaps.fUsesPrecisionModifiers) { |
+ if (modifiers.fFlags & Modifiers::kLowp_Flag) { |
+ this->write("lowp "); |
+ } |
+ if (modifiers.fFlags & Modifiers::kMediump_Flag) { |
+ this->write("mediump "); |
+ } |
+ if (modifiers.fFlags & Modifiers::kHighp_Flag) { |
+ this->write("highp "); |
+ } |
+ } |
} |
void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { |
if (intf.fVariable.fName == "gl_PerVertex") { |
return; |
} |
- this->writeModifiers(intf.fVariable.fModifiers); |
+ this->writeModifiers(intf.fVariable.fModifiers, true); |
this->writeLine(intf.fVariable.fType.name() + " {"); |
fIndentation++; |
for (const auto& f : intf.fVariable.fType.fields()) { |
- this->writeModifiers(f.fModifiers); |
+ this->writeModifiers(f.fModifiers, false); |
this->writeType(*f.fType); |
this->writeLine(" " + f.fName + ";"); |
} |
@@ -313,9 +434,9 @@ void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { |
this->writeLine("};"); |
} |
-void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl) { |
+void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) { |
ASSERT(decl.fVars.size() > 0); |
- this->writeModifiers(decl.fVars[0].fVar->fModifiers); |
+ this->writeModifiers(decl.fVars[0].fVar->fModifiers, global); |
this->writeType(decl.fBaseType); |
std::string separator = " "; |
for (const auto& var : decl.fVars) { |
@@ -325,7 +446,9 @@ void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl) { |
this->write(var.fVar->fName); |
for (const auto& size : var.fSizes) { |
this->write("["); |
- this->writeExpression(*size, kTopLevel_Precedence); |
+ if (size) { |
+ this->writeExpression(*size, kTopLevel_Precedence); |
+ } |
this->write("]"); |
} |
if (var.fValue) { |
@@ -349,7 +472,7 @@ void GLSLCodeGenerator::writeStatement(const Statement& s) { |
this->writeReturnStatement((ReturnStatement&) s); |
break; |
case Statement::kVarDeclarations_Kind: |
- this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration); |
+ this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false); |
break; |
case Statement::kIf_Kind: |
this->writeIfStatement((IfStatement&) s); |
@@ -444,22 +567,57 @@ void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) { |
void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) { |
ASSERT(fOut == nullptr); |
fOut = &out; |
+ fProgramKind = program.fKind; |
this->write("#version " + to_string(fCaps.fVersion)); |
- if (fCaps.fStandard == GLCaps::kGLES_Standard) { |
+ if (fCaps.fStandard == GLCaps::kGLES_Standard && fCaps.fVersion >= 300) { |
this->write(" es"); |
+ } else if (fCaps.fIsCoreProfile) { |
+ this->write(" core"); |
} |
this->writeLine(); |
for (const auto& e : program.fElements) { |
+ if (e->fKind == ProgramElement::kExtension_Kind) { |
+ this->writeExtension((Extension&) *e); |
+ } |
+ } |
+ if (fCaps.fStandard == GLCaps::kGLES_Standard) { |
+ this->write("precision "); |
+ switch (program.fDefaultPrecision) { |
+ case Modifiers::kLowp_Flag: |
+ this->write("lowp"); |
+ break; |
+ case Modifiers::kMediump_Flag: |
+ this->write("mediump"); |
+ break; |
+ case Modifiers::kHighp_Flag: |
+ this->write("highp"); |
+ break; |
+ default: |
+ ASSERT(false); |
+ this->write("<error>"); |
+ } |
+ this->writeLine(" float;"); |
+ } |
+ for (const auto& e : program.fElements) { |
switch (e->fKind) { |
case ProgramElement::kExtension_Kind: |
- this->writeExtension((Extension&) *e); |
break; |
case ProgramElement::kVar_Kind: { |
VarDeclarations& decl = (VarDeclarations&) *e; |
- if (decl.fVars.size() > 0 && |
- decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin == -1) { |
- this->writeVarDeclarations(decl); |
- this->writeLine(); |
+ if (decl.fVars.size() > 0) { |
+ int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin; |
+ if (builtin == -1) { |
+ // normal var |
+ this->writeVarDeclarations(decl, true); |
+ this->writeLine(); |
+ } else if (builtin == SK_FRAGCOLOR_BUILTIN && |
+ fCaps.fMustDeclareFragmentShaderOutput) { |
+ this->write("out "); |
+ if (fCaps.fUsesPrecisionModifiers) { |
+ this->write("mediump "); |
+ } |
+ this->writeLine("vec4 sk_FragColor;"); |
+ } |
} |
break; |
} |
@@ -469,6 +627,10 @@ void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) |
case ProgramElement::kFunction_Kind: |
this->writeFunction((FunctionDefinition&) *e); |
break; |
+ case ProgramElement::kModifiers_Kind: |
+ this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true); |
+ this->writeLine(";"); |
+ break; |
default: |
printf("%s\n", e->description().c_str()); |
ABORT("unsupported program element"); |