aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gpu/gl/GrGLContext.cpp12
-rw-r--r--src/gpu/gl/GrGLContext.h17
-rw-r--r--src/gpu/gl/GrGLGpu.cpp44
-rw-r--r--src/gpu/gl/builders/GrGLShaderStringBuilder.cpp95
-rw-r--r--src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp2
-rw-r--r--src/gpu/glsl/GrGLSLShaderVar.h10
-rw-r--r--src/sksl/README34
-rw-r--r--src/sksl/SkSLCompiler.h2
-rw-r--r--src/sksl/SkSLGLSLCodeGenerator.cpp147
-rw-r--r--src/sksl/SkSLGLSLCodeGenerator.h15
-rw-r--r--src/sksl/SkSLIRGenerator.cpp16
-rw-r--r--src/sksl/SkSLParser.cpp10
-rw-r--r--src/sksl/SkSLUtil.cpp35
-rw-r--r--src/sksl/SkSLUtil.h14
-rw-r--r--src/sksl/sksl_frag.include2
15 files changed, 373 insertions, 82 deletions
diff --git a/src/gpu/gl/GrGLContext.cpp b/src/gpu/gl/GrGLContext.cpp
index 9e70b472c5..93f14cfc67 100644
--- a/src/gpu/gl/GrGLContext.cpp
+++ b/src/gpu/gl/GrGLContext.cpp
@@ -7,6 +7,7 @@
#include "GrGLContext.h"
#include "GrGLGLSL.h"
+#include "SkSLCompiler.h"
////////////////////////////////////////////////////////////////////////////////
@@ -63,6 +64,17 @@ GrGLContext* GrGLContext::Create(const GrGLInterface* interface, const GrContext
return new GrGLContext(args);
}
+GrGLContext::~GrGLContext() {
+ delete fCompiler;
+}
+
+SkSL::Compiler* GrGLContext::compiler() {
+ if (!fCompiler) {
+ fCompiler = new SkSL::Compiler();
+ }
+ return fCompiler;
+}
+
GrGLContextInfo::GrGLContextInfo(const ConstructorArgs& args) {
fInterface.reset(SkRef(args.fInterface));
fGLVersion = args.fGLVersion;
diff --git a/src/gpu/gl/GrGLContext.h b/src/gpu/gl/GrGLContext.h
index 6016f6859a..8a56535887 100644
--- a/src/gpu/gl/GrGLContext.h
+++ b/src/gpu/gl/GrGLContext.h
@@ -15,6 +15,9 @@
#include "GrGLUtil.h"
struct GrContextOptions;
+namespace SkSL {
+ class Compiler;
+}
/**
* Encapsulates information about an OpenGL context including the OpenGL
@@ -39,6 +42,8 @@ public:
const GrGLExtensions& extensions() const { return fInterface->fExtensions; }
+ virtual ~GrGLContextInfo() {}
+
protected:
struct ConstructorArgs {
const GrGLInterface* fInterface;
@@ -64,7 +69,7 @@ protected:
};
/**
- * Extension of GrGLContextInfo that also provides access to GrGLInterface.
+ * Extension of GrGLContextInfo that also provides access to GrGLInterface and SkSL::Compiler.
*/
class GrGLContext : public GrGLContextInfo {
public:
@@ -76,8 +81,16 @@ public:
const GrGLInterface* interface() const { return fInterface; }
+ SkSL::Compiler* compiler();
+
+ ~GrGLContext() override;
+
private:
- GrGLContext(const ConstructorArgs& args) : INHERITED(args) {}
+ GrGLContext(const ConstructorArgs& args)
+ : INHERITED(args)
+ , fCompiler(nullptr) {}
+
+ SkSL::Compiler* fCompiler;
typedef GrGLContextInfo INHERITED;
};
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index e002d5101b..e37f8430fb 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -3775,20 +3775,11 @@ bool GrGLGpu::createCopyProgram(int progIdx) {
fshaderTxt.append(";");
uTexture.appendDecl(glslCaps, &fshaderTxt);
fshaderTxt.append(";");
- const char* fsOutName;
- if (glslCaps->mustDeclareFragmentShaderOutput()) {
- oFragColor.appendDecl(glslCaps, &fshaderTxt);
- fshaderTxt.append(";");
- fsOutName = oFragColor.c_str();
- } else {
- fsOutName = "gl_FragColor";
- }
fshaderTxt.appendf(
"// Copy Program FS\n"
"void main() {"
- " %s = %s(u_texture, v_texCoord);"
+ " sk_FragColor = %s(u_texture, v_texCoord);"
"}",
- fsOutName,
GrGLSLTexture2DFunctionName(kVec2f_GrSLType, kSamplerTypes[progIdx], this->glslGeneration())
);
@@ -3921,14 +3912,6 @@ bool GrGLGpu::createMipmapProgram(int progIdx) {
}
uTexture.appendDecl(glslCaps, &fshaderTxt);
fshaderTxt.append(";");
- const char* fsOutName;
- if (glslCaps->mustDeclareFragmentShaderOutput()) {
- oFragColor.appendDecl(glslCaps, &fshaderTxt);
- fshaderTxt.append(";");
- fsOutName = oFragColor.c_str();
- } else {
- fsOutName = "gl_FragColor";
- }
const char* sampleFunction = GrGLSLTexture2DFunctionName(kVec2f_GrSLType,
kTexture2DSampler_GrSLType,
this->glslGeneration());
@@ -3939,19 +3922,19 @@ bool GrGLGpu::createMipmapProgram(int progIdx) {
if (oddWidth && oddHeight) {
fshaderTxt.appendf(
- " %s = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1) + "
- " %s(u_texture, v_texCoord2) + %s(u_texture, v_texCoord3)) * 0.25;",
- fsOutName, sampleFunction, sampleFunction, sampleFunction, sampleFunction
+ " sk_FragColor = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1) + "
+ " %s(u_texture, v_texCoord2) + %s(u_texture, v_texCoord3)) * 0.25;",
+ sampleFunction, sampleFunction, sampleFunction, sampleFunction
);
} else if (oddWidth || oddHeight) {
fshaderTxt.appendf(
- " %s = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1)) * 0.5;",
- fsOutName, sampleFunction, sampleFunction
+ " sk_FragColor = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1)) * 0.5;",
+ sampleFunction, sampleFunction
);
} else {
fshaderTxt.appendf(
- " %s = %s(u_texture, v_texCoord0);",
- fsOutName, sampleFunction
+ " sk_FragColor = %s(u_texture, v_texCoord0);",
+ sampleFunction
);
}
@@ -4038,20 +4021,11 @@ bool GrGLGpu::createWireRectProgram() {
&fshaderTxt);
uColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
fshaderTxt.append(";");
- const char* fsOutName;
- if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) {
- oFragColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
- fshaderTxt.append(";");
- fsOutName = oFragColor.c_str();
- } else {
- fsOutName = "gl_FragColor";
- }
fshaderTxt.appendf(
"// Write Rect Program FS\n"
"void main() {"
- " %s = %s;"
+ " sk_FragColor = %s;"
"}",
- fsOutName,
uColor.c_str()
);
diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
index d2e49a5cfb..0282fbb8a9 100644
--- a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
@@ -9,6 +9,8 @@
#include "gl/GrGLGpu.h"
#include "gl/GrGLSLPrettyPrint.h"
#include "SkTraceEvent.h"
+#include "SkSLCompiler.h"
+#include "ir/SkSLProgram.h"
#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
@@ -18,6 +20,74 @@ static const bool c_PrintShaders{false};
static void print_shader_source(const char** strings, int* lengths, int count);
+static SkSL::GLCaps skslcaps_for_context(const GrGLContext& context) {
+ GrGLStandard standard = context.standard();
+ const GrGLCaps* caps = context.caps();
+ const GrGLSLCaps* glslCaps = caps->glslCaps();
+ SkSL::GLCaps result;
+ switch (standard) {
+ case kGL_GrGLStandard:
+ result.fStandard = SkSL::GLCaps::kGL_Standard;
+ break;
+ case kGLES_GrGLStandard:
+ result.fStandard = SkSL::GLCaps::kGLES_Standard;
+ break;
+ default:
+ SkASSERT(false);
+ result.fStandard = SkSL::GLCaps::kGL_Standard;
+ }
+
+ switch (glslCaps->generation()) {
+ case k110_GrGLSLGeneration:
+ if (kGLES_GrGLStandard == standard) {
+ // ES2's shader language is based on GLSL 1.20 but is version 1.00 of the ES
+ // language
+ result.fVersion = 100;
+ } else {
+ SkASSERT(kGL_GrGLStandard == standard);
+ result.fVersion = 110;
+ }
+ break;
+ case k130_GrGLSLGeneration:
+ SkASSERT(kGL_GrGLStandard == standard);
+ result.fVersion = 130;
+ break;
+ case k140_GrGLSLGeneration:
+ SkASSERT(kGL_GrGLStandard == standard);
+ result.fVersion = 140;
+ break;
+ case k150_GrGLSLGeneration:
+ SkASSERT(kGL_GrGLStandard == standard);
+ result.fVersion = 150;
+ break;
+ case k330_GrGLSLGeneration:
+ if (kGLES_GrGLStandard == standard) {
+ result.fVersion = 300;
+ } else {
+ SkASSERT(kGL_GrGLStandard == standard);
+ result.fVersion = 330;
+ }
+ break;
+ case k400_GrGLSLGeneration:
+ SkASSERT(kGL_GrGLStandard == standard);
+ result.fVersion = 400;
+ break;
+ case k310es_GrGLSLGeneration:
+ SkASSERT(kGLES_GrGLStandard == standard);
+ result.fVersion = 310;
+ break;
+ case k320es_GrGLSLGeneration:
+ SkASSERT(kGLES_GrGLStandard == standard);
+ result.fVersion = 320;
+ break;
+ }
+ result.fIsCoreProfile = caps->isCoreProfile();
+ result.fUsesPrecisionModifiers = glslCaps->usesPrecisionModifiers();
+ result.fMustDeclareFragmentShaderOutput = glslCaps->mustDeclareFragmentShaderOutput();
+ result.fCanUseMinAndAbsTogether = glslCaps->canUseMinAndAbsTogether();
+ return result;
+}
+
GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
GrGLuint programId,
GrGLenum type,
@@ -33,15 +103,32 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
return 0;
}
+ std::string sksl;
#ifdef SK_DEBUG
SkString prettySource = GrGLSLPrettyPrint::PrettyPrintGLSL(strings, lengths, count, false);
- const GrGLchar* sourceStr = prettySource.c_str();
- GrGLint sourceLength = static_cast<GrGLint>(prettySource.size());
- GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength));
+ sksl = std::string(prettySource.c_str());
#else
- GR_GL_CALL(gli, ShaderSource(shaderId, count, strings, lengths));
+ for (int i = 0; i < count; i++) {
+ sksl.append(strings[i], lengths[i]);
+ }
#endif
+ std::string glsl;
+ // creating Compiler is expensive, and we are single-threaded anyway, so just reuse a static one
+ static SkSL::Compiler compiler;
+ SkSL::GLCaps caps = skslcaps_for_context(glCtx);
+ SkASSERT(type == GR_GL_VERTEX_SHADER || type == GR_GL_FRAGMENT_SHADER);
+ SkDEBUGCODE(bool result = )compiler.toGLSL(type == GR_GL_VERTEX_SHADER
+ ? SkSL::Program::kVertex_Kind
+ : SkSL::Program::kFragment_Kind,
+ std::string(sksl.c_str()),
+ caps,
+ &glsl);
+ SkASSERTF(result, "SkSL errors:\n%s", compiler.errorText().c_str());
+ const char* glslChars = glsl.c_str();
+ GrGLint glslLength = (GrGLint) glsl.length();
+ GR_GL_CALL(gli, ShaderSource(shaderId, 1, &glslChars, &glslLength));
+
// If tracing is enabled in chrome then we pretty print
bool traceShader;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), &traceShader);
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index 7763f86e42..f1c655c58c 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -321,7 +321,7 @@ void GrGLSLFragmentShaderBuilder::enableSecondaryOutput() {
}
const char* GrGLSLFragmentShaderBuilder::getPrimaryColorOutputName() const {
- return fHasCustomColorOutput ? DeclaredColorOutputName() : "gl_FragColor";
+ return fHasCustomColorOutput ? DeclaredColorOutputName() : "sk_FragColor";
}
void GrGLSLFragmentBuilder::declAppendf(const char* fmt, ...) {
diff --git a/src/gpu/glsl/GrGLSLShaderVar.h b/src/gpu/glsl/GrGLSLShaderVar.h
index 9d162ecaa4..35ac4bcb84 100644
--- a/src/gpu/glsl/GrGLSLShaderVar.h
+++ b/src/gpu/glsl/GrGLSLShaderVar.h
@@ -213,24 +213,20 @@ public:
private:
static const char* TypeModifierString(const GrGLSLCaps* glslCaps, TypeModifier t) {
- GrGLSLGeneration gen = glslCaps->generation();
switch (t) {
case kNone_TypeModifier:
return "";
+ case kAttribute_TypeModifier: // fall through
+ case kVaryingIn_TypeModifier: // fall through
case kIn_TypeModifier:
return "in";
case kInOut_TypeModifier:
return "inout";
+ case kVaryingOut_TypeModifier: // fall through
case kOut_TypeModifier:
return "out";
case kUniform_TypeModifier:
return "uniform";
- case kAttribute_TypeModifier:
- return k110_GrGLSLGeneration == gen ? "attribute" : "in";
- case kVaryingIn_TypeModifier:
- return k110_GrGLSLGeneration == gen ? "varying" : "in";
- case kVaryingOut_TypeModifier:
- return k110_GrGLSLGeneration == gen ? "varying" : "out";
default:
SkFAIL("Unknown shader variable type modifier.");
return ""; // suppress warning
diff --git a/src/sksl/README b/src/sksl/README
new file mode 100644
index 0000000000..da426923e3
--- /dev/null
+++ b/src/sksl/README
@@ -0,0 +1,34 @@
+Overview
+========
+
+SkSL ("Skia Shading Language") is a variant of GLSL which is used as Skia's
+internal shading language. SkSL is, at its heart, a single standardized version
+of GLSL which avoids all of the various version and dialect differences found
+in GLSL "in the wild", but it does bring a few of its own changes to the table.
+
+Skia uses the SkSL compiler to convert SkSL code to GLSL, GLSL ES, or SPIR-V
+before handing it over to the graphics driver.
+
+Differences from GLSL
+=====================
+
+SkSL is based on GLSL 4.5. For the most part, write SkSL exactly as you would
+desktop GLSL, and the SkSL compiler will take care of version and dialect
+differences (for instance, you always use "in" and "out", and skslc will handle
+translating them to "varying" and "attribute" as appropriate). Be aware of the
+following differences between SkSL and GLSL:
+
+* no #version or "precision" statement is required, and they will be ignored if
+ present
+* the output color is sk_FragColor (do not declare it)
+* lowp, mediump, and highp are always permitted (but will only be respected if
+ you run on a GLES device)
+* you do not need to include ".0" to make a number a float (meaning that
+ "vec2(x, y) * 4" is perfectly legal in SkSL, unlike GLSL where it would have
+ to be expressed "vec2(x, y) * 4.0". There is no performance penalty for this,
+ as the number is converted to a float at compile time)
+* some built-in functions and one or two rarely-used language features are not
+ yet supported (sorry!)
+
+SkSL is still under development, and is expected to diverge further from GLSL
+over time.
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index 9cd1eac3f9..3f76aec3a0 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -24,6 +24,8 @@ class IRGenerator;
* file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to
* produce a Program (a tree of IRNodes), then feeds the Program into a CodeGenerator to produce
* compiled output.
+ *
+ * See the README for information about SkSL.
*/
class Compiler : public ErrorReporter {
public:
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index da0bcb903c..f989decdee 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -16,6 +16,8 @@
#include "ir/SkSLIndexExpression.h"
#include "ir/SkSLVariableReference.h"
+#define SK_FRAGCOLOR_BUILTIN 10001
+
namespace SkSL {
void GLSLCodeGenerator::write(const char* s) {
@@ -66,7 +68,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 +126,40 @@ 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 (abs(x) > (tmpVar = y) ? tmpVar : abs(x)) to avoid a Tegra3 compiler
+// bug.
+void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
+ ASSERT(!fCaps.fCanUseMinAndAbsTogether);
+ std::string varName = "minAbsHackVar" + to_string(fVarCount++);
+ this->fFunctionHeader += " " + otherExpr.fType.name() + " " + varName + ";\n";
+ this->write("(");
+ this->writeExpression(absExpr, kTopLevel_Precedence);
+ this->write(" > (" + varName + " = ");
+ this->writeExpression(otherExpr, kRelational_Precedence);
+ this->write(") ? " + varName + " : ");
+ this->writeExpression(absExpr, kTernary_Precedence);
+ this->write(")");
+}
+
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])) {
+ 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 +182,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) {
@@ -284,28 +327,89 @@ void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
for (const auto& param : f.fDeclaration.fParameters) {
this->write(separator);
separator = ", ";
- this->writeModifiers(param->fModifiers);
+ this->writeModifiers(param->fModifiers, false);
this->writeType(param->fType);
this->write(" " + param->fName);
}
- 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) {
+ bool modifier = false;
+ if (modifiers.fFlags & Modifiers::kLowp_Flag) {
+ this->write("lowp ");
+ modifier = true;
+ }
+ if (modifiers.fFlags & Modifiers::kHighp_Flag) {
+ this->write("highp ");
+ modifier = true;
+ }
+ if (!modifier) {
+ this->write("mediump ");
+ }
+ }
}
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 +417,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) {
@@ -349,7 +453,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,9 +548,12 @@ 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) {
this->write(" es");
+ } else if (fCaps.fIsCoreProfile) {
+ this->write(" core");
}
this->writeLine();
for (const auto& e : program.fElements) {
@@ -456,10 +563,16 @@ void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out)
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->writeLine("out vec4 sk_FragColor;");
+ }
}
break;
}
diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h
index 3534affccc..63fab05e08 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.h
+++ b/src/sksl/SkSLGLSLCodeGenerator.h
@@ -50,6 +50,11 @@ struct GLCaps {
kGL_Standard,
kGLES_Standard
} fStandard;
+ bool fIsCoreProfile;
+ bool fUsesPrecisionModifiers;
+ bool fMustDeclareFragmentShaderOutput;
+ // The Tegra3 compiler will sometimes never return if we have min(abs(x), y)
+ bool fCanUseMinAndAbsTogether;
};
/**
@@ -81,6 +86,7 @@ public:
GLSLCodeGenerator(const Context* context, GLCaps caps)
: fContext(*context)
, fCaps(caps)
+ , fVarCount(0)
, fIndentation(0)
, fAtLineStart(true) {}
@@ -111,11 +117,11 @@ private:
void writeLayout(const Layout& layout);
- void writeModifiers(const Modifiers& modifiers);
+ void writeModifiers(const Modifiers& modifiers, bool globalContext);
void writeGlobalVars(const VarDeclaration& vs);
- void writeVarDeclarations(const VarDeclarations& decl);
+ void writeVarDeclarations(const VarDeclarations& decl, bool global);
void writeVariableReference(const VariableReference& ref);
@@ -123,6 +129,8 @@ private:
void writeIntrinsicCall(const FunctionCall& c);
+ void writeMinAbsHack(Expression& absExpr, Expression& otherExpr);
+
void writeFunctionCall(const FunctionCall& c);
void writeConstructor(const Constructor& c);
@@ -164,6 +172,9 @@ private:
const Context& fContext;
const GLCaps fCaps;
std::ostream* fOut;
+ std::string fFunctionHeader;
+ Program::Kind fProgramKind;
+ int fVarCount;
int fIndentation;
bool fAtLineStart;
// Keeps track of which struct types we have written. Given that we are unlikely to ever write
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index c30cac17d7..5e136a4d2f 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -419,8 +419,9 @@ std::unique_ptr<FunctionDefinition> IRGenerator::convertFunction(const ASTFuncti
for (size_t i = 0; i < parameters.size(); i++) {
if (parameters[i]->fModifiers != other->fParameters[i]->fModifiers) {
fErrors.error(f.fPosition, "modifiers on parameter " +
- to_string(i + 1) + " differ between " +
- "declaration and definition");
+ to_string((uint64_t) i + 1) +
+ " differ between declaration and "
+ "definition");
return nullptr;
}
}
@@ -616,8 +617,9 @@ std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr
ASSERT(ctor);
return this->call(Position(), std::move(ctor), std::move(args));
}
- ABORT("cannot coerce %s to %s", expr->fType.description().c_str(),
- type.description().c_str());
+ std::vector<std::unique_ptr<Expression>> args;
+ args.push_back(std::move(expr));
+ return std::unique_ptr<Expression>(new Constructor(Position(), type, std::move(args)));
}
static bool is_matrix_multiply(const Type& left, const Type& right) {
@@ -832,12 +834,12 @@ std::unique_ptr<Expression> IRGenerator::call(Position position,
std::vector<std::unique_ptr<Expression>> arguments) {
if (function.fParameters.size() != arguments.size()) {
std::string msg = "call to '" + function.fName + "' expected " +
- to_string(function.fParameters.size()) +
+ to_string((uint64_t) function.fParameters.size()) +
" argument";
if (function.fParameters.size() != 1) {
msg += "s";
}
- msg += ", but found " + to_string(arguments.size());
+ msg += ", but found " + to_string((uint64_t) arguments.size());
fErrors.error(position, msg);
return nullptr;
}
@@ -938,7 +940,7 @@ std::unique_ptr<Expression> IRGenerator::convertConstructor(
if (args.size() != 1) {
fErrors.error(position, "invalid arguments to '" + type.description() +
"' constructor, (expected exactly 1 argument, but found " +
- to_string(args.size()) + ")");
+ to_string((uint64_t) args.size()) + ")");
}
if (args[0]->fType == *fContext.fBool_Type) {
std::unique_ptr<IntLiteral> zero(new IntLiteral(fContext, position, 0));
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp
index b240e4501e..f9e7498ee5 100644
--- a/src/sksl/SkSLParser.cpp
+++ b/src/sksl/SkSLParser.cpp
@@ -185,7 +185,8 @@ void Parser::precision() {
this->expect(Token::SEMICOLON, "';'");
}
-/* DIRECTIVE(#version) INT_LITERAL | DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
+/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
+ DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
std::unique_ptr<ASTDeclaration> Parser::directive() {
Token start;
if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
@@ -193,7 +194,12 @@ std::unique_ptr<ASTDeclaration> Parser::directive() {
}
if (start.fText == "#version") {
this->expect(Token::INT_LITERAL, "a version number");
- // ignored for now
+ Token next = this->peek();
+ if (next.fText == "es" || next.fText == "compatibility") {
+ this->nextToken();
+ }
+ // version is ignored for now; it will eventually become an error when we stop pretending
+ // to be GLSL
return nullptr;
} else if (start.fText == "#extension") {
Token name;
diff --git a/src/sksl/SkSLUtil.cpp b/src/sksl/SkSLUtil.cpp
index 327bffe4f1..aefad69367 100644
--- a/src/sksl/SkSLUtil.cpp
+++ b/src/sksl/SkSLUtil.cpp
@@ -9,6 +9,41 @@
namespace SkSL {
+std::string to_string(double value) {
+ std::stringstream buffer;
+ buffer << std::setprecision(std::numeric_limits<double>::digits10) << value;
+ std::string result = buffer.str();
+ if (result.find_last_of(".") == std::string::npos &&
+ result.find_last_of("e") == std::string::npos) {
+ result += ".0";
+ }
+ return result;
+}
+
+std::string to_string(int32_t value) {
+ std::stringstream buffer;
+ buffer << value;
+ return buffer.str();
+}
+
+std::string to_string(uint32_t value) {
+ std::stringstream buffer;
+ buffer << value;
+ return buffer.str();
+}
+
+std::string to_string(int64_t value) {
+ std::stringstream buffer;
+ buffer << value;
+ return buffer.str();
+}
+
+std::string to_string(uint64_t value) {
+ std::stringstream buffer;
+ buffer << value;
+ return buffer.str();
+}
+
int stoi(std::string s) {
return atoi(s.c_str());
}
diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h
index 33611cde02..efffaaec01 100644
--- a/src/sksl/SkSLUtil.h
+++ b/src/sksl/SkSLUtil.h
@@ -19,11 +19,15 @@ namespace SkSL {
// our own definitions of certain std:: functions, because they are not always present on Android
-template <typename T> std::string to_string(T value) {
- std::stringstream buffer;
- buffer << std::setprecision(std::numeric_limits<T>::digits10) << value;
- return buffer.str();
-}
+std::string to_string(double value);
+
+std::string to_string(int32_t value);
+
+std::string to_string(uint32_t value);
+
+std::string to_string(int64_t value);
+
+std::string to_string(uint64_t value);
#if _MSC_VER
#define NORETURN __declspec(noreturn)
diff --git a/src/sksl/sksl_frag.include b/src/sksl/sksl_frag.include
index b4047fe091..d6c438910f 100644
--- a/src/sksl/sksl_frag.include
+++ b/src/sksl/sksl_frag.include
@@ -4,4 +4,6 @@ STRINGIFY(
layout(builtin=15) in vec4 gl_FragCoord;
+layout(builtin=10001) vec4 sk_FragColor;
+
) \ No newline at end of file