re-land of added sk_FragCoord support to skslc
authorEthan Nicholas <ethannicholas@google.com>
Mon, 12 Dec 2016 20:33:30 +0000 (15:33 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Tue, 13 Dec 2016 14:28:53 +0000 (14:28 +0000)
BUG=skia:

Change-Id: Ifac1aa39839058787ad1794200c3dbb93c147a69
Reviewed-on: https://skia-review.googlesource.com/5850
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>

33 files changed:
bench/GLBench.cpp
fuzz/fuzz.cpp
src/gpu/gl/GrGLGpu.cpp
src/gpu/gl/builders/GrGLProgramBuilder.cpp
src/gpu/gl/builders/GrGLProgramBuilder.h
src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
src/gpu/gl/builders/GrGLShaderStringBuilder.h
src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
src/gpu/glsl/GrGLSLProgramBuilder.cpp
src/gpu/glsl/GrGLSLProgramBuilder.h
src/gpu/vk/GrVkCopyManager.cpp
src/gpu/vk/GrVkGpu.cpp
src/gpu/vk/GrVkGpu.h
src/gpu/vk/GrVkPipelineStateBuilder.cpp
src/gpu/vk/GrVkPipelineStateBuilder.h
src/gpu/vk/GrVkUtil.cpp
src/gpu/vk/GrVkUtil.h
src/sksl/SkSLCodeGenerator.h
src/sksl/SkSLCompiler.cpp
src/sksl/SkSLCompiler.h
src/sksl/SkSLErrorReporter.h
src/sksl/SkSLGLSLCodeGenerator.cpp
src/sksl/SkSLGLSLCodeGenerator.h
src/sksl/SkSLIRGenerator.cpp
src/sksl/SkSLIRGenerator.h
src/sksl/SkSLMain.cpp
src/sksl/SkSLSPIRVCodeGenerator.cpp
src/sksl/SkSLSPIRVCodeGenerator.h
src/sksl/SkSLUtil.h
src/sksl/ir/SkSLProgram.h
src/sksl/sksl_frag.include
tests/SkSLErrorTest.cpp
tests/SkSLGLSLTest.cpp

index 38205e2..0fcd56f 100644 (file)
@@ -68,14 +68,15 @@ void GLBench::onDraw(int loops, SkCanvas* canvas) {
 GrGLuint GLBench::CompileShader(const GrGLContext* context, const char* sksl, GrGLenum type) {
     const GrGLInterface* gl = context->interface();
     SkString glsl;
-    bool result = context->compiler()->toGLSL(type == GR_GL_VERTEX_SHADER 
-                                                                    ? SkSL::Program::kVertex_Kind
+    SkSL::Program::Settings settings;
+    settings.fCaps = context->caps()->shaderCaps();
+    std::unique_ptr<SkSL::Program> program = context->compiler()->convertProgram(
+                                        type == GR_GL_VERTEX_SHADER ? SkSL::Program::kVertex_Kind
                                                                     : SkSL::Program::kFragment_Kind,
-                                              SkString(sksl),
-                                              *context->caps()->shaderCaps(),
-                                              &glsl);
-    if (!result) {
-        SkDebugf("SkSL compilation failed:\n%s\n%s\n", sksl, 
+                                        SkString(sksl),
+                                        settings);
+    if (!program || !context->compiler()->toGLSL(*program, &glsl)) {
+        SkDebugf("SkSL compilation failed:\n%s\n%s\n", sksl,
                  context->compiler()->errorText().c_str());
     }
     GrGLuint shader;
index 047bcd8..f8f02a3 100644 (file)
@@ -444,10 +444,13 @@ int fuzz_color_deserialize(sk_sp<SkData> bytes) {
 int fuzz_sksl2glsl(sk_sp<SkData> bytes) {
     SkSL::Compiler compiler;
     SkString output;
-    bool result = compiler.toGLSL(SkSL::Program::kFragment_Kind,
-        SkString((const char*)bytes->data()), *SkSL::ShaderCapsFactory::Default(), &output);
-
-    if (!result) {
+    SkSL::Program::Settings settings;
+    sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
+    settings.fCaps = caps.get();
+    std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
+                                                              SkString((const char*) bytes->data()),
+                                                              settings);
+    if (!program || !compiler.toGLSL(*program, &output)) {
         SkDebugf("[terminated] Couldn't compile input.\n");
         return 1;
     }
index 20609af..bbbcf4c 100644 (file)
@@ -27,6 +27,7 @@
 #include "SkMipMap.h"
 #include "SkPixmap.h"
 #include "SkStrokeRec.h"
+#include "SkSLCompiler.h"
 #include "SkTemplates.h"
 #include "SkTypes.h"
 #include "../private/GrGLSL.h"
@@ -399,13 +400,20 @@ bool GrGLGpu::createPLSSetupProgram() {
 
     str = vshaderTxt.c_str();
     length = SkToInt(vshaderTxt.size());
+    SkSL::Program::Settings settings;
+    settings.fCaps = shaderCaps;
+    SkSL::Program::Inputs inputs;
     GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram,
-                                                  GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats);
+                                                  GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats,
+                                                  settings, &inputs);
+    SkASSERT(inputs.isEmpty());
 
     str = fshaderTxt.c_str();
     length = SkToInt(fshaderTxt.size());
     GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram,
-                                                  GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats);
+                                                  GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats,
+                                                  settings, &inputs);
+    SkASSERT(inputs.isEmpty());
 
     GL_CALL(LinkProgram(fPLSSetupProgram.fProgram));
 
@@ -3855,15 +3863,20 @@ bool GrGLGpu::createCopyProgram(GrTexture* srcTex) {
 
     str = vshaderTxt.c_str();
     length = SkToInt(vshaderTxt.size());
+    SkSL::Program::Settings settings;
+    settings.fCaps = shaderCaps;
+    SkSL::Program::Inputs inputs;
     GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram,
                                                   GR_GL_VERTEX_SHADER, &str, &length, 1,
-                                                  &fStats);
+                                                  &fStats, settings, &inputs);
+    SkASSERT(inputs.isEmpty());
 
     str = fshaderTxt.c_str();
     length = SkToInt(fshaderTxt.size());
     GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[progIdx].fProgram,
                                                   GR_GL_FRAGMENT_SHADER, &str, &length, 1,
-                                                  &fStats);
+                                                  &fStats, settings, &inputs);
+    SkASSERT(inputs.isEmpty());
 
     GL_CALL(LinkProgram(fCopyPrograms[progIdx].fProgram));
 
@@ -4008,15 +4021,20 @@ bool GrGLGpu::createMipmapProgram(int progIdx) {
 
     str = vshaderTxt.c_str();
     length = SkToInt(vshaderTxt.size());
+    SkSL::Program::Settings settings;
+    settings.fCaps = shaderCaps;
+    SkSL::Program::Inputs inputs;
     GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram,
                                                   GR_GL_VERTEX_SHADER, &str, &length, 1,
-                                                  &fStats);
+                                                  &fStats, settings, &inputs);
+    SkASSERT(inputs.isEmpty());
 
     str = fshaderTxt.c_str();
     length = SkToInt(fshaderTxt.size());
     GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fMipmapPrograms[progIdx].fProgram,
                                                   GR_GL_FRAGMENT_SHADER, &str, &length, 1,
-                                                  &fStats);
+                                                  &fStats, settings, &inputs);
+    SkASSERT(inputs.isEmpty());
 
     GL_CALL(LinkProgram(fMipmapPrograms[progIdx].fProgram));
 
@@ -4097,15 +4115,20 @@ bool GrGLGpu::createWireRectProgram() {
 
     str = vshaderTxt.c_str();
     length = SkToInt(vshaderTxt.size());
+    SkSL::Program::Settings settings;
+    settings.fCaps = this->caps()->shaderCaps();
+    SkSL::Program::Inputs inputs;
     GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fWireRectProgram.fProgram,
                                                   GR_GL_VERTEX_SHADER, &str, &length, 1,
-                                                  &fStats);
+                                                  &fStats, settings, &inputs);
+    SkASSERT(inputs.isEmpty());
 
     str = fshaderTxt.c_str();
     length = SkToInt(fshaderTxt.size());
     GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fWireRectProgram.fProgram,
                                                   GR_GL_FRAGMENT_SHADER, &str, &length, 1,
-                                                  &fStats);
+                                                  &fStats, settings, &inputs);
+    SkASSERT(inputs.isEmpty());
 
     GL_CALL(LinkProgram(fWireRectProgram.fProgram));
 
index cc29022..045593f 100644 (file)
@@ -69,7 +69,9 @@ const GrCaps* GrGLProgramBuilder::caps() const {
 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
                                                  GrGLuint programId,
                                                  GrGLenum type,
-                                                 SkTDArray<GrGLuint>* shaderIds) {
+                                                 SkTDArray<GrGLuint>* shaderIds,
+                                                 const SkSL::Program::Settings& settings,
+                                                 SkSL::Program::Inputs* outInputs) {
     GrGLGpu* gpu = this->gpu();
     GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
                                                    programId,
@@ -77,7 +79,9 @@ bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
                                                    shader.fCompilerStrings.begin(),
                                                    shader.fCompilerStringLengths.begin(),
                                                    shader.fCompilerStrings.count(),
-                                                   gpu->stats());
+                                                   gpu->stats(),
+                                                   settings,
+                                                   outInputs);
 
     if (!shaderId) {
         return false;
@@ -100,8 +104,13 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
     this->finalizeShaders();
 
     // compile shaders and bind attributes / uniforms
+    SkSL::Program::Settings settings;
+    settings.fCaps = this->gpu()->glCaps().shaderCaps();
+    settings.fFlipY = this->pipeline().getRenderTarget()->origin() != kTopLeft_GrSurfaceOrigin;
+    SkSL::Program::Inputs inputs;
     SkTDArray<GrGLuint> shadersToDelete;
-    if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete)) {
+    if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete,
+                                       settings, &inputs)) {
         this->cleanupProgram(programID, shadersToDelete);
         return nullptr;
     }
@@ -117,16 +126,22 @@ GrGLProgram* GrGLProgramBuilder::finalize() {
     }
 
     if (primProc.willUseGeoShader() &&
-        !this->compileAndAttachShaders(fGS, programID, GR_GL_GEOMETRY_SHADER, &shadersToDelete)) {
+        !this->compileAndAttachShaders(fGS, programID, GR_GL_GEOMETRY_SHADER, &shadersToDelete,
+                                       settings, &inputs)) {
         this->cleanupProgram(programID, shadersToDelete);
         return nullptr;
     }
 
-    if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete)) {
+    if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete,
+                                       settings, &inputs)) {
         this->cleanupProgram(programID, shadersToDelete);
         return nullptr;
     }
 
+    if (inputs.fRTHeight) {
+        this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
+    }
+
     this->bindProgramResourceLocations(programID);
 
     GL_CALL(LinkProgram(programID));
index a88f278..84d6d91 100644 (file)
@@ -14,6 +14,7 @@
 #include "gl/GrGLVaryingHandler.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
+#include "ir/SkSLProgram.h"
 
 class GrFragmentProcessor;
 class GrGLContextInfo;
@@ -46,7 +47,9 @@ private:
     bool compileAndAttachShaders(GrGLSLShaderBuilder& shader,
                                  GrGLuint programId,
                                  GrGLenum type,
-                                 SkTDArray<GrGLuint>* shaderIds);
+                                 SkTDArray<GrGLuint>* shaderIds,
+                                 const SkSL::Program::Settings& settings,
+                                 SkSL::Program::Inputs* outInputs);
     GrGLProgram* finalize();
     void bindProgramResourceLocations(GrGLuint programID);
     bool checkLinkStatus(GrGLuint programID);
index bd4921b..df44edd 100644 (file)
@@ -44,7 +44,9 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
                                     const char** strings,
                                     int* lengths,
                                     int count,
-                                    GrGpu::Stats* stats) {
+                                    GrGpu::Stats* stats,
+                                    const SkSL::Program::Settings& settings,
+                                    SkSL::Program::Inputs* outInputs) {
     const GrGLInterface* gli = glCtx.interface();
 
     GrGLuint shaderId;
@@ -65,21 +67,20 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
     SkString glsl;
     if (type == GR_GL_VERTEX_SHADER || type == GR_GL_FRAGMENT_SHADER) {
         SkSL::Compiler& compiler = *glCtx.compiler();
-        SkDEBUGCODE(bool result = )compiler.toGLSL(type == GR_GL_VERTEX_SHADER 
-                                                                    ? SkSL::Program::kVertex_Kind
+        std::unique_ptr<SkSL::Program> program;
+        program = compiler.convertProgram(
+                                        type == GR_GL_VERTEX_SHADER ? SkSL::Program::kVertex_Kind
                                                                     : SkSL::Program::kFragment_Kind,
-                                                   sksl,
-                                                   *glCtx.caps()->shaderCaps(),
-                                                   &glsl);
-#ifdef SK_DEBUG
-        if (!result) {
+                                        sksl,
+                                        settings);
+        if (!program || !compiler.toGLSL(*program, &glsl)) {
             SkDebugf("SKSL compilation error\n----------------------\n");
             SkDebugf("SKSL:\n");
             dump_string(sksl);
             SkDebugf("\nErrors:\n%s\n", compiler.errorText().c_str());
             SkDEBUGFAIL("SKSL compilation failed!\n");
         }
-#endif
+        *outInputs = program->fInputs;
     } else {
         // TODO: geometry shader support in sksl.
         SkASSERT(type == GR_GL_GEOMETRY_SHADER);
index 71fce6a..242fe61 100644 (file)
@@ -20,6 +20,8 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
                                     const char** strings,
                                     int* lengths,
                                     int count,
-                                    GrGpu::Stats*);
+                                    GrGpu::Stats*,
+                                    const SkSL::Program::Settings& settings,
+                                    SkSL::Program::Inputs* inputs);
 
 #endif
index 8355f1d..7ef7348 100644 (file)
@@ -132,49 +132,7 @@ SkString GrGLSLFragmentShaderBuilder::ensureCoords2D(const GrShaderVar& coords)
 
 const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
     SkDEBUGCODE(fUsedProcessorFeatures |= GrProcessor::kFragmentPosition_RequiredFeature;)
-
-    const GrShaderCaps* shaderCaps = fProgramBuilder->shaderCaps();
-    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
-    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
-    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
-    if (kTopLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) {
-        fSetupFragPosition = true;
-        return "gl_FragCoord";
-    } else if (const char* extension = shaderCaps->fragCoordConventionsExtensionString()) {
-        if (!fSetupFragPosition) {
-            if (shaderCaps->generation() < k150_GrGLSLGeneration) {
-                this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
-                                 extension);
-            }
-            fInputs.push_back().set(kVec4f_GrSLType,
-                                    "gl_FragCoord",
-                                    GrShaderVar::kIn_TypeModifier,
-                                    kDefault_GrSLPrecision,
-                                    "origin_upper_left");
-            fSetupFragPosition = true;
-        }
-        return "gl_FragCoord";
-    } else {
-        static const char* kTempName = "tmpXYFragCoord";
-        static const char* kCoordName = "fragCoordYDown";
-        if (!fSetupFragPosition) {
-            const char* rtHeightName;
-
-            fProgramBuilder->addRTHeightUniform("RTHeight", &rtHeightName);
-
-            // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
-            // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
-            // depending on the surrounding code, accessing .xy with a uniform involved can
-            // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
-            // (and only accessing .xy) seems to "fix" things.
-            this->codePrependf("\thighp vec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n", kCoordName,
-                               kTempName, rtHeightName, kTempName);
-            this->codePrependf("highp vec2 %s = gl_FragCoord.xy;", kTempName);
-            fSetupFragPosition = true;
-        }
-        SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
-        return kCoordName;
-    }
+    return "sk_FragCoord";
 }
 
 const char* GrGLSLFragmentShaderBuilder::distanceVectorName() const {
index 590439d..1182996 100644 (file)
@@ -470,13 +470,13 @@ void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision,
                                                outName);
 }
 
-void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** outName) {
+void GrGLSLProgramBuilder::addRTHeightUniform(const char* name) {
         SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
         GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
         fUniformHandles.fRTHeightUni =
             uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag,
                                                     kFloat_GrSLType, kDefault_GrSLPrecision,
-                                                    name, false, 0, outName);
+                                                    name, false, 0, nullptr);
 }
 
 void GrGLSLProgramBuilder::cleanupFragmentProcessors() {
index fdb6e11..bfd9f7a 100644 (file)
@@ -72,7 +72,7 @@ public:
 
     // Used to add a uniform for the RenderTarget height (used for frag position) without mangling
     // the name of the uniform inside of a stage.
-    void addRTHeightUniform(const char* name, const char** outName);
+    void addRTHeightUniform(const char* name);
 
     // Generates a name for a variable. The generated string will be name prefixed by the prefix
     // char (unless the prefix is '\0'). It also will mangle the name to be stage-specific unless
index 78194fc..7b2c734 100644 (file)
@@ -65,19 +65,21 @@ bool GrVkCopyManager::createCopyProgram(GrVkGpu* gpu) {
         "}"
     );
 
-    if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(),
-                                 VK_SHADER_STAGE_VERTEX_BIT,
-                                 &fVertShaderModule, &fShaderStageInfo[0])) {
+    SkSL::Program::Settings settings;
+    SkSL::Program::Inputs inputs;
+    if (!GrCompileVkShaderModule(gpu, vertShaderText.c_str(), VK_SHADER_STAGE_VERTEX_BIT,
+                                 &fVertShaderModule, &fShaderStageInfo[0], settings, &inputs)) {
         this->destroyResources(gpu);
         return false;
     }
+    SkASSERT(inputs.isEmpty());
 
-    if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(),
-                                 VK_SHADER_STAGE_FRAGMENT_BIT,
-                                 &fFragShaderModule, &fShaderStageInfo[1])) {
+    if (!GrCompileVkShaderModule(gpu, fragShaderText.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT,
+                                 &fFragShaderModule, &fShaderStageInfo[1], settings, &inputs)) {
         this->destroyResources(gpu);
         return false;
     }
+    SkASSERT(inputs.isEmpty());
 
     VkDescriptorSetLayout dsLayout[2];
 
index a742c4b..f31c743 100644 (file)
@@ -36,9 +36,7 @@
 #include "vk/GrVkInterface.h"
 #include "vk/GrVkTypes.h"
 
-#if USE_SKSL
 #include "SkSLCompiler.h"
-#endif
 
 #define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X)
 #define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X)
@@ -119,11 +117,7 @@ GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
     }
 #endif
 
-#if USE_SKSL
     fCompiler = new SkSL::Compiler();
-#else
-    fCompiler = shaderc_compiler_initialize();
-#endif
 
     fVkCaps.reset(new GrVkCaps(options, this->vkInterface(), backendCtx->fPhysicalDevice,
                                backendCtx->fFeatures, backendCtx->fExtensions));
@@ -193,11 +187,7 @@ GrVkGpu::~GrVkGpu() {
 
     VK_CALL(DestroyCommandPool(fDevice, fCmdPool, nullptr));
 
-#if USE_SKSL
     delete fCompiler;
-#else
-    shaderc_compiler_release(fCompiler);
-#endif
 
 #ifdef SK_ENABLE_VK_LAYERS
     if (fCallback) {
index 0e5f228..5dddb93 100644 (file)
@@ -8,8 +8,6 @@
 #ifndef GrVkGpu_DEFINED
 #define GrVkGpu_DEFINED
 
-#define USE_SKSL 1
-
 #include "GrGpu.h"
 #include "GrGpuFactory.h"
 #include "vk/GrVkBackendContext.h"
 #include "GrVkResourceProvider.h"
 #include "GrVkVertexBuffer.h"
 #include "GrVkUtil.h"
-
-#if USE_SKSL
-namespace SkSL {
-    class Compiler;
-}
-#else
-#include "shaderc/shaderc.h"
-#endif
-
 #include "vk/GrVkDefines.h"
 
 class GrPipeline;
@@ -43,6 +32,10 @@ class GrVkSecondaryCommandBuffer;
 class GrVkTexture;
 struct GrVkInterface;
 
+namespace SkSL {
+    class Compiler;
+}
+
 class GrVkGpu : public GrGpu {
 public:
     static GrGpu* Create(GrBackendContext backendContext, const GrContextOptions& options,
@@ -120,15 +113,9 @@ public:
                                bool byRegion,
                                VkImageMemoryBarrier* barrier) const;
 
-#if USE_SKSL
     SkSL::Compiler* shaderCompiler() const {
         return fCompiler;
     }
-#else
-    shaderc_compiler_t shadercCompiler() const {
-        return fCompiler;
-    }
-#endif
 
     void onResolveRenderTarget(GrRenderTarget* target) override;
 
@@ -272,13 +259,9 @@ private:
     VkDebugReportCallbackEXT               fCallback;
 #endif
 
-#if USE_SKSL
+    // compiler used for compiling sksl into spirv. We only want to create the compiler once since
+    // there is significant overhead to the first compile of any compiler.
     SkSL::Compiler* fCompiler;
-#else
-    // Shaderc compiler used for compiling glsl in spirv. We only want to create the compiler once
-    // since there is significant overhead to the first compile of any compiler.
-    shaderc_compiler_t fCompiler;
-#endif
 
     typedef GrGpu INHERITED;
 };
index 49f5cf8..4125938 100644 (file)
@@ -58,11 +58,11 @@ void GrVkPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outpu
     outputColor.addLayoutQualifier("location = 0, index = 1");
 }
 
-bool GrVkPipelineStateBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
-                                                    VkShaderStageFlagBits stage,
+bool GrVkPipelineStateBuilder::createVkShaderModule(VkShaderStageFlagBits stage,
                                                     const GrGLSLShaderBuilder& builder,
                                                     VkShaderModule* shaderModule,
-                                                    VkPipelineShaderStageCreateInfo* stageInfo) {
+                                                    VkPipelineShaderStageCreateInfo* stageInfo,
+                                                    const SkSL::Program::Settings& settings) {
     SkString shaderString;
     for (int i = 0; i < builder.fCompilerStrings.count(); ++i) {
         if (builder.fCompilerStrings[i]) {
@@ -70,7 +70,17 @@ bool GrVkPipelineStateBuilder::CreateVkShaderModule(const GrVkGpu* gpu,
             shaderString.append("\n");
         }
     }
-    return GrCompileVkShaderModule(gpu, shaderString.c_str(), stage, shaderModule, stageInfo);
+
+    SkSL::Program::Inputs inputs;
+    bool result = GrCompileVkShaderModule(fGpu, shaderString.c_str(), stage, shaderModule,
+                                          stageInfo, settings, &inputs);
+    if (!result) {
+        return false;
+    }
+    if (inputs.fRTHeight) {
+        this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
+    }
+    return result;
 }
 
 GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& stencil,
@@ -117,20 +127,22 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrStencilSettings& s
     this->finalizeShaders();
 
     VkPipelineShaderStageCreateInfo shaderStageInfo[2];
-    SkAssertResult(CreateVkShaderModule(fGpu,
-                                        VK_SHADER_STAGE_VERTEX_BIT,
-                                        fVS,
-                                        &vertShaderModule,
-                                        &shaderStageInfo[0]));
+    SkSL::Program::Settings settings;
+    settings.fFlipY = this->pipeline().getRenderTarget()->origin() != kTopLeft_GrSurfaceOrigin;
+    SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
+                                              fVS,
+                                              &vertShaderModule,
+                                              &shaderStageInfo[0],
+                                              settings));
 
     // TODO: geometry shader support.
     SkASSERT(!this->primitiveProcessor().willUseGeoShader());
 
-    SkAssertResult(CreateVkShaderModule(fGpu,
-                                        VK_SHADER_STAGE_FRAGMENT_BIT,
-                                        fFS,
-                                        &fragShaderModule,
-                                        &shaderStageInfo[1]));
+    SkAssertResult(this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
+                                              fFS,
+                                              &fragShaderModule,
+                                              &shaderStageInfo[1],
+                                              settings));
 
     GrVkPipeline* pipeline = resourceProvider.createPipeline(fPipeline,
                                                              stencil,
index c36f9ac..cf4a983 100644 (file)
@@ -14,6 +14,7 @@
 #include "GrVkPipelineState.h"
 #include "GrVkUniformHandler.h"
 #include "GrVkVaryingHandler.h"
+#include "SkSLCompiler.h"
 
 #include "vk/GrVkDefines.h"
 
@@ -55,11 +56,11 @@ private:
                                 const GrVkRenderPass& renderPass,
                                 const GrVkPipelineState::Desc&);
 
-    static bool CreateVkShaderModule(const GrVkGpu* gpu,
-                                     VkShaderStageFlagBits stage,
-                                     const GrGLSLShaderBuilder& builder,
-                                     VkShaderModule* shaderModule,
-                                     VkPipelineShaderStageCreateInfo* stageInfo);
+    bool createVkShaderModule(VkShaderStageFlagBits stage,
+                              const GrGLSLShaderBuilder& builder,
+                              VkShaderModule* shaderModule,
+                              VkPipelineShaderStageCreateInfo* stageInfo,
+                              const SkSL::Program::Settings& settings);
 
     GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; }
     const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; }
index 4446dfe..3071fc8 100644 (file)
@@ -8,9 +8,7 @@
 #include "GrVkUtil.h"
 
 #include "vk/GrVkGpu.h"
-#if USE_SKSL
 #include "SkSLCompiler.h"
-#endif
 
 bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) {
     VkFormat dontCare;
@@ -262,7 +260,6 @@ bool GrSampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits* vkSam
     }
 }
 
-#if USE_SKSL
 SkSL::Program::Kind vk_shader_stage_to_skiasl_kind(VkShaderStageFlagBits stage) {
     if (VK_SHADER_STAGE_VERTEX_BIT == stage) {
         return SkSL::Program::kVertex_Kind;
@@ -270,85 +267,49 @@ SkSL::Program::Kind vk_shader_stage_to_skiasl_kind(VkShaderStageFlagBits stage)
     SkASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == stage);
     return SkSL::Program::kFragment_Kind;
 }
-#else
-shaderc_shader_kind vk_shader_stage_to_shaderc_kind(VkShaderStageFlagBits stage) {
-    if (VK_SHADER_STAGE_VERTEX_BIT == stage) {
-        return shaderc_glsl_vertex_shader;
+
+VkShaderStageFlagBits skiasl_kind_to_vk_shader_stage(SkSL::Program::Kind kind) {
+    if (SkSL::Program::kVertex_Kind == kind) {
+        return VK_SHADER_STAGE_VERTEX_BIT;
     }
-    SkASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == stage);
-    return shaderc_glsl_fragment_shader;
+    SkASSERT(SkSL::Program::kFragment_Kind == kind);
+    return VK_SHADER_STAGE_FRAGMENT_BIT;
 }
-#endif
 
 bool GrCompileVkShaderModule(const GrVkGpu* gpu,
                              const char* shaderString,
                              VkShaderStageFlagBits stage,
                              VkShaderModule* shaderModule,
-                             VkPipelineShaderStageCreateInfo* stageInfo) {
+                             VkPipelineShaderStageCreateInfo* stageInfo,
+                             const SkSL::Program::Settings& settings,
+                             SkSL::Program::Inputs* outInputs) {
+    std::unique_ptr<SkSL::Program> program = gpu->shaderCompiler()->convertProgram(
+                                                              vk_shader_stage_to_skiasl_kind(stage),
+                                                              SkString(shaderString),
+                                                              settings);
+    if (!program) {
+        SkDebugf("SkSL error:\n%s\n", gpu->shaderCompiler()->errorText().c_str());
+        SkASSERT(false);
+    }
+    *outInputs = program->fInputs;
+    SkString code;
+    if (!gpu->shaderCompiler()->toSPIRV(*program, &code)) {
+        SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str());
+        return false;
+    }
+
     VkShaderModuleCreateInfo moduleCreateInfo;
     memset(&moduleCreateInfo, 0, sizeof(VkShaderModuleCreateInfo));
     moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
     moduleCreateInfo.pNext = nullptr;
     moduleCreateInfo.flags = 0;
-
-#if USE_SKSL
-    SkString code;
-#else
-    shaderc_compilation_result_t result = nullptr;
-#endif
-
-    if (gpu->vkCaps().canUseGLSLForShaderModule()) {
-        moduleCreateInfo.codeSize = strlen(shaderString);
-        moduleCreateInfo.pCode = (const uint32_t*)shaderString;
-    } else {
-
-#if USE_SKSL
-        bool result = gpu->shaderCompiler()->toSPIRV(vk_shader_stage_to_skiasl_kind(stage),
-                                                     SkString(shaderString),
-                                                     &code);
-        if (!result) {
-            SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str());
-            return false;
-        }
-        moduleCreateInfo.codeSize = code.size();
-        moduleCreateInfo.pCode = (const uint32_t*)code.c_str();
-#else
-        shaderc_compiler_t compiler = gpu->shadercCompiler();
-
-        shaderc_compile_options_t options = shaderc_compile_options_initialize();
-
-        shaderc_shader_kind shadercStage = vk_shader_stage_to_shaderc_kind(stage);
-        result = shaderc_compile_into_spv(compiler,
-                                          shaderString,
-                                          strlen(shaderString),
-                                          shadercStage,
-                                          "shader",
-                                          "main",
-                                          options);
-        shaderc_compile_options_release(options);
-#ifdef SK_DEBUG
-        if (shaderc_result_get_num_errors(result)) {
-            SkDebugf("%s\n", shaderString);
-            SkDebugf("%s\n", shaderc_result_get_error_message(result));
-            return false;
-        }
-#endif // SK_DEBUG
-
-        moduleCreateInfo.codeSize = shaderc_result_get_length(result);
-        moduleCreateInfo.pCode = (const uint32_t*)shaderc_result_get_bytes(result);
-#endif // USE_SKSL
-    }
+    moduleCreateInfo.codeSize = code.size();
+    moduleCreateInfo.pCode = (const uint32_t*)code.c_str();
 
     VkResult err = GR_VK_CALL(gpu->vkInterface(), CreateShaderModule(gpu->device(),
                                                                      &moduleCreateInfo,
                                                                      nullptr,
                                                                      shaderModule));
-
-    if (!gpu->vkCaps().canUseGLSLForShaderModule()) {
-#if !USE_SKSL
-        shaderc_result_release(result);
-#endif
-    }
     if (err) {
         return false;
     }
@@ -357,7 +318,7 @@ bool GrCompileVkShaderModule(const GrVkGpu* gpu,
     stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
     stageInfo->pNext = nullptr;
     stageInfo->flags = 0;
-    stageInfo->stage = stage;
+    stageInfo->stage = skiasl_kind_to_vk_shader_stage(program->fKind);
     stageInfo->module = *shaderModule;
     stageInfo->pName = "main";
     stageInfo->pSpecializationInfo = nullptr;
index fae3c20..ba07bca 100644 (file)
@@ -12,6 +12,7 @@
 #include "GrTypes.h"
 #include "vk/GrVkDefines.h"
 #include "vk/GrVkInterface.h"
+#include "ir/SkSLProgram.h"
 
 class GrVkGpu;
 
@@ -48,6 +49,8 @@ bool GrCompileVkShaderModule(const GrVkGpu* gpu,
                              const char* shaderString,
                              VkShaderStageFlagBits stage,
                              VkShaderModule* shaderModule,
-                             VkPipelineShaderStageCreateInfo* stageInfo);
+                             VkPipelineShaderStageCreateInfo* stageInfo,
+                             const SkSL::Program::Settings& settings,
+                             SkSL::Program::Inputs* outInputs);
 
 #endif
index ed93778..111e73a 100644 (file)
@@ -18,9 +18,20 @@ namespace SkSL {
  */
 class CodeGenerator {
 public:
+    CodeGenerator(const Program* program, ErrorReporter* errors, SkWStream* out)
+    : fProgram(*program)
+    , fErrors(*errors)
+    , fOut(out) {}
+
     virtual ~CodeGenerator() {}
 
-    virtual void generateCode(const Program& program, ErrorReporter& errors, SkWStream& out) = 0;
+    virtual bool generateCode() = 0;
+
+protected:
+
+    const Program& fProgram;
+    ErrorReporter& fErrors;
+    SkWStream* fOut;
 };
 
 } // namespace
index 1be0ba9..9faf836 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "ast/SkSLASTPrecision.h"
 #include "SkSLCFGGenerator.h"
+#include "SkSLGLSLCodeGenerator.h"
 #include "SkSLIRGenerator.h"
 #include "SkSLParser.h"
 #include "SkSLSPIRVCodeGenerator.h"
@@ -392,10 +393,10 @@ void Compiler::internalConvertProgram(SkString text,
 }
 
 std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, SkString text,
-                                                  std::unordered_map<SkString, CapValue> caps) {
+                                                  const Program::Settings& settings) {
     fErrorText = "";
     fErrorCount = 0;
-    fIRGenerator->start(&caps);
+    fIRGenerator->start(&settings);
     std::vector<std::unique_ptr<ProgramElement>> elements;
     Modifiers::Flag ignored;
     switch (kind) {
@@ -409,47 +410,46 @@ std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, SkString t
     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
     Modifiers::Flag defaultPrecision;
     this->internalConvertProgram(text, &defaultPrecision, &elements);
-    auto result = std::unique_ptr<Program>(new Program(kind, defaultPrecision, std::move(elements),
-                                                       fIRGenerator->fSymbolTable));
+    auto result = std::unique_ptr<Program>(new Program(kind, settings, defaultPrecision, &fContext,
+                                                       std::move(elements),
+                                                       fIRGenerator->fSymbolTable,
+                                                       fIRGenerator->fInputs));
     fIRGenerator->finish();
     this->writeErrorCount();
+    if (fErrorCount) {
+        return nullptr;
+    }
     return result;
 }
 
-void Compiler::error(Position position, SkString msg) {
-    fErrorCount++;
-    fErrorText += "error: " + position.description() + ": " + msg.c_str() + "\n";
-}
 
-SkString Compiler::errorText() {
-    SkString result = fErrorText;
+bool Compiler::toSPIRV(const Program& program, SkWStream& out) {
+    SPIRVCodeGenerator cg(&fContext, &program, this, &out);
+    bool result = cg.generateCode();
+    this->writeErrorCount();
     return result;
 }
 
-void Compiler::writeErrorCount() {
-    if (fErrorCount) {
-        fErrorText += to_string(fErrorCount) + " error";
-        if (fErrorCount > 1) {
-            fErrorText += "s";
-        }
-        fErrorText += "\n";
+bool Compiler::toSPIRV(const Program& program, SkString* out) {
+    SkDynamicMemoryWStream buffer;
+    bool result = this->toSPIRV(program, buffer);
+    if (result) {
+        sk_sp<SkData> data(buffer.detachAsData());
+        *out = SkString((const char*) data->data(), data->size());
     }
+    return result;
 }
 
-bool Compiler::toSPIRV(Program::Kind kind, const SkString& text, SkWStream& out) {
-    std::unordered_map<SkString, CapValue> capsMap;
-    auto program = this->convertProgram(kind, text, capsMap);
-    if (fErrorCount == 0) {
-        SkSL::SPIRVCodeGenerator cg(&fContext);
-        cg.generateCode(*program.get(), *this, out);
-        this->writeErrorCount();
-    }
-    return fErrorCount == 0;
+bool Compiler::toGLSL(const Program& program, SkWStream& out) {
+    GLSLCodeGenerator cg(&fContext, &program, this, &out);
+    bool result = cg.generateCode();
+    this->writeErrorCount();
+    return result;
 }
 
-bool Compiler::toSPIRV(Program::Kind kind, const SkString& text, SkString* out) {
+bool Compiler::toGLSL(const Program& program, SkString* out) {
     SkDynamicMemoryWStream buffer;
-    bool result = this->toSPIRV(kind, text, buffer);
+    bool result = this->toGLSL(program, buffer);
     if (result) {
         sk_sp<SkData> data(buffer.detachAsData());
         *out = SkString((const char*) data->data(), data->size());
@@ -457,49 +457,25 @@ bool Compiler::toSPIRV(Program::Kind kind, const SkString& text, SkString* out)
     return result;
 }
 
-static void fill_caps(const GrShaderCaps& caps, std::unordered_map<SkString, CapValue>* capsMap) {
-#define CAP(name) capsMap->insert(std::make_pair(SkString(#name), CapValue(caps.name())));
-    CAP(fbFetchSupport);
-    CAP(fbFetchNeedsCustomOutput);
-    CAP(bindlessTextureSupport);
-    CAP(dropsTileOnZeroDivide);
-    CAP(flatInterpolationSupport);
-    CAP(noperspectiveInterpolationSupport);
-    CAP(multisampleInterpolationSupport);
-    CAP(sampleVariablesSupport);
-    CAP(sampleMaskOverrideCoverageSupport);
-    CAP(externalTextureSupport);
-    CAP(texelFetchSupport);
-    CAP(imageLoadStoreSupport);
-    CAP(mustEnableAdvBlendEqs);
-    CAP(mustEnableSpecificAdvBlendEqs);
-    CAP(mustDeclareFragmentShaderOutput);
-    CAP(canUseAnyFunctionInShader);
-#undef CAP
+
+void Compiler::error(Position position, SkString msg) {
+    fErrorCount++;
+    fErrorText += "error: " + position.description() + ": " + msg.c_str() + "\n";
 }
 
-bool Compiler::toGLSL(Program::Kind kind, const SkString& text, const GrShaderCaps& caps,
-                      SkWStream& out) {
-    std::unordered_map<SkString, CapValue> capsMap;
-    fill_caps(caps, &capsMap);
-    auto program = this->convertProgram(kind, text, capsMap);
-    if (fErrorCount == 0) {
-        SkSL::GLSLCodeGenerator cg(&fContext, &caps);
-        cg.generateCode(*program.get(), *this, out);
-        this->writeErrorCount();
-    }
-    return fErrorCount == 0;
+SkString Compiler::errorText() {
+    SkString result = fErrorText;
+    return result;
 }
 
-bool Compiler::toGLSL(Program::Kind kind, const SkString& text, const GrShaderCaps& caps,
-                      SkString* out) {
-    SkDynamicMemoryWStream buffer;
-    bool result = this->toGLSL(kind, text, caps, buffer);
-    if (result) {
-        sk_sp<SkData> data(buffer.detachAsData());
-        *out = SkString((const char*) data->data(), data->size());
+void Compiler::writeErrorCount() {
+    if (fErrorCount) {
+        fErrorText += to_string(fErrorCount) + " error";
+        if (fErrorCount > 1) {
+            fErrorText += "s";
+        }
+        fErrorText += "\n";
     }
-    return result;
 }
 
 } // namespace
index 114f8ef..0f893f7 100644 (file)
@@ -16,9 +16,9 @@
 #include "SkSLContext.h"
 #include "SkSLErrorReporter.h"
 #include "SkSLIRGenerator.h"
-#include "SkSLGLSLCodeGenerator.h"
 
 #define SK_FRAGCOLOR_BUILTIN 10001
+#define SK_FRAGCOORD_BUILTIN 15
 
 namespace SkSL {
 
@@ -26,7 +26,7 @@ class IRGenerator;
 
 /**
  * Main compiler entry point. This is a traditional compiler design which first parses the .sksl
- * file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to 
+ * 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.
  *
@@ -38,18 +38,16 @@ public:
 
     ~Compiler();
 
-    std::unique_ptr<Program> convertProgram(Program::Kind kind, SkString text, 
-                                            std::unordered_map<SkString, CapValue> caps);
+    std::unique_ptr<Program> convertProgram(Program::Kind kind, SkString text,
+                                            const Program::Settings& settings);
 
-    bool toSPIRV(Program::Kind kind, const SkString& text, SkWStream& out);
-    
-    bool toSPIRV(Program::Kind kind, const SkString& text, SkString* out);
+    bool toSPIRV(const Program& program, SkWStream& out);
 
-    bool toGLSL(Program::Kind kind, const SkString& text, const GrShaderCaps& caps,
-                SkWStream& out);
-    
-    bool toGLSL(Program::Kind kind, const SkString& text, const GrShaderCaps& caps,
-                SkString* out);
+    bool toSPIRV(const Program& program, SkString* out);
+
+    bool toGLSL(const Program& program, SkWStream& out);
+
+    bool toGLSL(const Program& program, SkString* out);
 
     void error(Position position, SkString msg) override;
 
@@ -57,11 +55,15 @@ public:
 
     void writeErrorCount();
 
+    int errorCount() override {
+        return fErrorCount;
+    }
+
 private:
     void addDefinition(const Expression* lvalue, const Expression* expr,
                        std::unordered_map<const Variable*, const Expression*>* definitions);
-    void addDefinitions(const BasicBlock::Node& node, 
+
+    void addDefinitions(const BasicBlock::Node& node,
                         std::unordered_map<const Variable*, const Expression*>* definitions);
 
     void scanCFG(CFG* cfg, BlockId block, std::set<BlockId>* workList);
index 585a97c..85d386d 100644 (file)
@@ -24,6 +24,8 @@ public:
     }
 
     virtual void error(Position position, SkString msg) = 0;
+
+    virtual int errorCount() = 0;
 };
 
 } // namespace
index 5b74724..dd8c0cf 100644 (file)
 
 #include "GLSL.std.450.h"
 
+#include "SkSLCompiler.h"
 #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) {
@@ -134,10 +133,10 @@ static bool is_abs(Expression& expr) {
     return ((FunctionCall&) expr).fFunction.fName == "abs";
 }
 
-// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a 
+// 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.canUseMinAndAbsTogether());
+    ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
     SkString tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
     SkString tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
     this->fFunctionHeader += "    " + absExpr.fType.name() + " " + tmpVar1 + ";\n";
@@ -150,7 +149,8 @@ void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherEx
 }
 
 void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
-    if (!fCaps.canUseMinAndAbsTogether() && c.fFunction.fName == "min" && c.fFunction.fBuiltin) {
+    if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether() && c.fFunction.fName == "min" &&
+        c.fFunction.fBuiltin) {
         ASSERT(c.fArguments.size() == 2);
         if (is_abs(*c.fArguments[0])) {
             this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
@@ -163,8 +163,9 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
             return;
         }
     }
-    if (fCaps.mustForceNegatedAtanParamToFloat() && c.fFunction.fName == "atan" && 
-        c.fFunction.fBuiltin && c.fArguments.size() == 2 && 
+    if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
+        c.fFunction.fName == "atan" &&
+        c.fFunction.fBuiltin && c.fArguments.size() == 2 &&
         c.fArguments[1]->fKind == Expression::kPrefix_Kind) {
         const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
         if (p.fOperator == Token::MINUS) {
@@ -176,11 +177,11 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
             return;
         }
     }
-    if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") && 
-        c.fFunction.fBuiltin && fCaps.shaderDerivativeExtensionString()) {
-        ASSERT(fCaps.shaderDerivativeSupport());
+    if (!fFoundDerivatives && (c.fFunction.fName == "dFdx" || c.fFunction.fName == "dFdy") &&
+        c.fFunction.fBuiltin && fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
+        ASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
         fHeader.writeText("#extension ");
-        fHeader.writeText(fCaps.shaderDerivativeExtensionString());
+        fHeader.writeText(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
         fHeader.writeText(" : require\n");
         fFoundDerivatives = true;
     }
@@ -235,7 +236,7 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
                 break;
         }
         this->write("texture");
-        if (fCaps.generation() < k130_GrGLSLGeneration) {
+        if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
             this->write(dim);
         }
         if (proj) {
@@ -266,15 +267,67 @@ void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
     this->write(")");
 }
 
-void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
-    if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN) {
-        if (fCaps.mustDeclareFragmentShaderOutput()) {
-            this->write("sk_FragColor");
-        } else {
-            this->write("gl_FragColor");
+void GLSLCodeGenerator::writeFragCoord() {
+    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
+    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
+    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
+    if (!fProgram.fSettings.fFlipY) {
+        this->write("gl_FragCoord");
+    } else if (const char* extension =
+               fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
+        if (!fSetupFragPositionGlobal) {
+            if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
+                fHeader.writeText("#extension ");
+                fHeader.writeText(extension);
+                fHeader.writeText(" : require\n");
+            }
+            fHeader.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
+            fSetupFragPositionGlobal = true;
         }
+        this->write("gl_FragCoord");
     } else {
-        this->write(ref.fVariable.fName);
+        if (!fSetupFragPositionGlobal) {
+            // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
+            // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
+            // depending on the surrounding code, accessing .xy with a uniform involved can
+            // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
+            // (and only accessing .xy) seems to "fix" things.
+            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
+                                                                                       : "";
+            fHeader.writeText("uniform ");
+            fHeader.writeText(precision);
+            fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
+            fSetupFragPositionGlobal = true;
+        }
+        if (!fSetupFragPositionLocal) {
+            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
+                                                                                       : "";
+            fFunctionHeader += precision;
+            fFunctionHeader += "    vec2 _sktmpCoord = gl_FragCoord.xy;\n";
+            fFunctionHeader += precision;
+            fFunctionHeader += "    vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME
+                               " - _sktmpCoord.y, 1.0, 1.0);\n";
+            fSetupFragPositionLocal = true;
+        }
+        this->write("sk_FragCoord");
+    }
+}
+
+
+void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
+    switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
+        case SK_FRAGCOLOR_BUILTIN:
+            if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
+                this->write("sk_FragColor");
+            } else {
+                this->write("gl_FragColor");
+            }
+            break;
+        case SK_FRAGCOORD_BUILTIN:
+            this->writeFragCoord();
+            break;
+        default:
+            this->write(ref.fVariable.fName);
     }
 }
 
@@ -484,14 +537,16 @@ void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
         (modifiers.fFlags & Modifiers::kOut_Flag)) {
         this->write("inout ");
     } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
-        if (globalContext && fCaps.generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
+        if (globalContext &&
+            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
             this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
                                                               : "varying ");
         } else {
             this->write("in ");
         }
     } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
-        if (globalContext && fCaps.generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
+        if (globalContext &&
+            fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
             this->write("varying ");
         } else {
             this->write("out ");
@@ -503,7 +558,7 @@ void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
     if (modifiers.fFlags & Modifiers::kConst_Flag) {
         this->write("const ");
     }
-    if (fCaps.usesPrecisionModifiers()) {
+    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
         if (modifiers.fFlags & Modifiers::kLowp_Flag) {
             this->write("lowp ");
         }
@@ -554,9 +609,9 @@ void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool g
             this->writeExpression(*var.fValue, kTopLevel_Precedence);
         }
         if (!fFoundImageDecl && var.fVar->fType == *fContext.fImage2D_Type) {
-            if (fCaps.imageLoadStoreExtensionString()) {
+            if (fProgram.fSettings.fCaps->imageLoadStoreExtensionString()) {
                 fHeader.writeText("#extension ");
-                fHeader.writeText(fCaps.imageLoadStoreExtensionString());
+                fHeader.writeText(fProgram.fSettings.fCaps->imageLoadStoreExtensionString());
                 fHeader.writeText(" : require\n");
             }
             fFoundImageDecl = true;
@@ -670,23 +725,22 @@ void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
     this->write(";");
 }
 
-void GLSLCodeGenerator::generateCode(const Program& program, ErrorReporter& errors,
-                                     SkWStream& out) {
-    ASSERT(fOut == nullptr);
+bool GLSLCodeGenerator::generateCode() {
+    SkWStream* rawOut = fOut;
     fOut = &fHeader;
-    fProgramKind = program.fKind;
-    this->write(fCaps.versionDeclString());
+    fProgramKind = fProgram.fKind;
+    this->write(fProgram.fSettings.fCaps->versionDeclString());
     this->writeLine();
-    for (const auto& e : program.fElements) {
+    for (const auto& e : fProgram.fElements) {
         if (e->fKind == ProgramElement::kExtension_Kind) {
             this->writeExtension((Extension&) *e);
         }
     }
     SkDynamicMemoryWStream body;
     fOut = &body;
-    if (fCaps.usesPrecisionModifiers()) {
+    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
         this->write("precision ");
-        switch (program.fDefaultPrecision) {
+        switch (fProgram.fDefaultPrecision) {
             case Modifiers::kLowp_Flag:
                 this->write("lowp");
                 break;
@@ -702,7 +756,7 @@ void GLSLCodeGenerator::generateCode(const Program& program, ErrorReporter& erro
         }
         this->writeLine(" float;");
     }
-    for (const auto& e : program.fElements) {
+    for (const auto& e : fProgram.fElements) {
         switch (e->fKind) {
             case ProgramElement::kExtension_Kind:
                 break;
@@ -715,9 +769,9 @@ void GLSLCodeGenerator::generateCode(const Program& program, ErrorReporter& erro
                         this->writeVarDeclarations(decl, true);
                         this->writeLine();
                     } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
-                               fCaps.mustDeclareFragmentShaderOutput()) {
+                               fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
                         this->write("out ");
-                        if (fCaps.usesPrecisionModifiers()) {
+                        if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
                             this->write("mediump ");
                         }
                         this->writeLine("vec4 sk_FragColor;");
@@ -742,8 +796,9 @@ void GLSLCodeGenerator::generateCode(const Program& program, ErrorReporter& erro
     }
     fOut = nullptr;
 
-    write_data(*fHeader.detachAsData(), out);
-    write_data(*body.detachAsData(), out);
+    write_data(*fHeader.detachAsData(), *rawOut);
+    write_data(*body.detachAsData(), *rawOut);
+    return true;
 }
 
 }
index ffc5a4d..0ae2c5c 100644 (file)
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+
 #ifndef SKSL_GLSLCODEGENERATOR
 #define SKSL_GLSLCODEGENERATOR
 
@@ -12,7 +12,6 @@
 #include <tuple>
 #include <unordered_map>
 
-#include "GrShaderCaps.h"
 #include "SkStream.h"
 #include "SkSLCodeGenerator.h"
 #include "ir/SkSLBinaryExpression.h"
@@ -72,11 +71,12 @@ public:
         kTopLevel_Precedence       = 18
     };
 
-    GLSLCodeGenerator(const Context* context, const GrShaderCaps* caps)
-    : fContext(*context)
-    , fCaps(*caps) {}
+    GLSLCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
+                      SkWStream* out)
+    : INHERITED(program, errors, out)
+    , fContext(*context) {}
 
-    void generateCode(const Program& program, ErrorReporter& errors, SkWStream& out) override;
+    virtual bool generateCode() override;
 
 private:
     void write(const char* s);
@@ -104,15 +104,17 @@ private:
     void writeLayout(const Layout& layout);
 
     void writeModifiers(const Modifiers& modifiers, bool globalContext);
-    
+
     void writeGlobalVars(const VarDeclaration& vs);
 
     void writeVarDeclarations(const VarDeclarations& decl, bool global);
 
+    void writeFragCoord();
+
     void writeVariableReference(const VariableReference& ref);
 
     void writeExpression(const Expression& expr, Precedence parentPrecedence);
-    
+
     void writeIntrinsicCall(const FunctionCall& c);
 
     void writeMinAbsHack(Expression& absExpr, Expression& otherExpr);
@@ -156,21 +158,23 @@ private:
     void writeReturnStatement(const ReturnStatement& r);
 
     const Context& fContext;
-    const GrShaderCaps& fCaps;
-    SkWStream* fOut = nullptr;
     SkDynamicMemoryWStream fHeader;
     SkString fFunctionHeader;
     Program::Kind fProgramKind;
     int fVarCount = 0;
     int fIndentation = 0;
     bool fAtLineStart = false;
-    // Keeps track of which struct types we have written. Given that we are unlikely to ever write 
-    // more than one or two structs per shader, a simple linear search will be faster than anything 
+    // Keeps track of which struct types we have written. Given that we are unlikely to ever write
+    // more than one or two structs per shader, a simple linear search will be faster than anything
     // fancier.
     std::vector<const Type*> fWrittenStructs;
     // true if we have run into usages of dFdx / dFdy
     bool fFoundDerivatives = false;
     bool fFoundImageDecl = false;
+    bool fSetupFragPositionGlobal = false;
+    bool fSetupFragPositionLocal = false;
+
+    typedef CodeGenerator INHERITED;
 };
 
 }
index 023f191..0698817 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "limits.h"
 
+#include "SkSLCompiler.h"
 #include "ast/SkSLASTBoolLiteral.h"
 #include "ast/SkSLASTFieldSuffix.h"
 #include "ast/SkSLASTFloatLiteral.h"
@@ -84,7 +85,6 @@ IRGenerator::IRGenerator(const Context* context, std::shared_ptr<SymbolTable> sy
                          ErrorReporter& errorReporter)
 : fContext(*context)
 , fCurrentFunction(nullptr)
-, fCapsMap(nullptr)
 , fSymbolTable(std::move(symbolTable))
 , fLoopLevel(0)
 , fErrors(errorReporter) {}
@@ -97,14 +97,40 @@ void IRGenerator::popSymbolTable() {
     fSymbolTable = fSymbolTable->fParent;
 }
 
-void IRGenerator::start(std::unordered_map<SkString, CapValue>* caps) {
-    this->fCapsMap = caps;
+static void fill_caps(const GrShaderCaps& caps, std::unordered_map<SkString, CapValue>* capsMap) {
+#define CAP(name) capsMap->insert(std::make_pair(SkString(#name), CapValue(caps.name())));
+    CAP(fbFetchSupport);
+    CAP(fbFetchNeedsCustomOutput);
+    CAP(bindlessTextureSupport);
+    CAP(dropsTileOnZeroDivide);
+    CAP(flatInterpolationSupport);
+    CAP(noperspectiveInterpolationSupport);
+    CAP(multisampleInterpolationSupport);
+    CAP(sampleVariablesSupport);
+    CAP(sampleMaskOverrideCoverageSupport);
+    CAP(externalTextureSupport);
+    CAP(texelFetchSupport);
+    CAP(imageLoadStoreSupport);
+    CAP(mustEnableAdvBlendEqs);
+    CAP(mustEnableSpecificAdvBlendEqs);
+    CAP(mustDeclareFragmentShaderOutput);
+    CAP(canUseAnyFunctionInShader);
+#undef CAP
+}
+
+void IRGenerator::start(const Program::Settings* settings) {
+    fSettings = settings;
+    fCapsMap.clear();
+    if (settings->fCaps) {
+        fill_caps(*settings->fCaps, &fCapsMap);
+    }
     this->pushSymbolTable();
+    fInputs.reset();
 }
 
 void IRGenerator::finish() {
     this->popSymbolTable();
-    this->fCapsMap = nullptr;
+    fSettings = nullptr;
 }
 
 std::unique_ptr<Extension> IRGenerator::convertExtension(const ASTExtension& extension) {
@@ -600,6 +626,11 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(const ASTIdentifier&
         case Symbol::kVariable_Kind: {
             const Variable* var = (const Variable*) result;
             this->markReadFrom(*var);
+            if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
+                fSettings->fFlipY &&
+                (!fSettings->fCaps || !fSettings->fCaps->fragCoordConventionsExtensionString())) {
+                fInputs.fRTHeight = true;
+            }
             return std::unique_ptr<VariableReference>(new VariableReference(identifier.fPosition,
                                                                             *var));
         }
@@ -1336,9 +1367,8 @@ std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expressi
 }
 
 std::unique_ptr<Expression> IRGenerator::getCap(Position position, SkString name) {
-    ASSERT(fCapsMap);
-    auto found = fCapsMap->find(name);
-    if (found == fCapsMap->end()) {
+    auto found = fCapsMap.find(name);
+    if (found == fCapsMap.end()) {
         fErrors.error(position, "unknown capability flag '" + name + "'");
         return nullptr;
     }
index ade6150..13b20fb 100644 (file)
@@ -40,6 +40,7 @@
 #include "ir/SkSLInterfaceBlock.h"
 #include "ir/SkSLModifiers.h"
 #include "ir/SkSLModifiersDeclaration.h"
+#include "ir/SkSLProgram.h"
 #include "ir/SkSLSymbolTable.h"
 #include "ir/SkSLStatement.h"
 #include "ir/SkSLType.h"
@@ -87,12 +88,14 @@ public:
     std::unique_ptr<ModifiersDeclaration> convertModifiersDeclaration(
                                                                   const ASTModifiersDeclaration& m);
 
+    Program::Inputs fInputs;
+
 private:
     /**
-     * Prepare to compile a program. Pushes a new symbol table and installs the caps so that
-     * references to sk_Caps.<cap> can be resolved.
+     * Prepare to compile a program. Resets state, pushes a new symbol table, and installs the
+     * settings.
      */
-    void start(std::unordered_map<SkString, CapValue>* caps);
+    void start(const Program::Settings* settings);
 
     /**
      * Performs cleanup after compilation is complete.
@@ -153,7 +156,8 @@ private:
 
     const Context& fContext;
     const FunctionDeclaration* fCurrentFunction;
-    const std::unordered_map<SkString, CapValue>* fCapsMap;
+    const Program::Settings* fSettings;
+    std::unordered_map<SkString, CapValue> fCapsMap;
     std::shared_ptr<SymbolTable> fSymbolTable;
     int fLoopLevel;
     ErrorReporter& fErrors;
index 381fcf0..f493b05 100644 (file)
@@ -37,6 +37,9 @@ int main(int argc, const char** argv) {
         printf("error reading '%s'\n", argv[1]);
         exit(2);
     }
+    SkSL::Program::Settings settings;
+    sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
+    settings.fCaps = caps.get();
     SkString name(argv[2]);
     if (name.endsWith(".spirv")) {
         SkFILEWStream out(argv[2]);
@@ -45,7 +48,8 @@ int main(int argc, const char** argv) {
             printf("error writing '%s'\n", argv[2]);
             exit(4);
         }
-        if (!compiler.toSPIRV(kind, text, out)) {
+        std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
+        if (!program || !compiler.toSPIRV(*program, out)) {
             printf("%s", compiler.errorText().c_str());
             exit(3);
         }
@@ -56,7 +60,8 @@ int main(int argc, const char** argv) {
             printf("error writing '%s'\n", argv[2]);
             exit(4);
         }
-        if (!compiler.toGLSL(kind, text, *SkSL::ShaderCapsFactory::Default(), out)) {
+        std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
+        if (!program || !compiler.toGLSL(*program, out)) {
             printf("%s", compiler.errorText().c_str());
             exit(3);
         }
index b2857f4..63fe020 100644 (file)
@@ -994,14 +994,14 @@ void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memor
         const Layout& fieldLayout = type.fields()[i].fModifiers.fLayout;
         if (fieldLayout.fOffset >= 0) {
             if (fieldLayout.fOffset <= (int) offset) {
-                fErrors->error(type.fPosition,
-                               "offset of field '" + type.fields()[i].fName + "' must be at "
-                               "least " + to_string((int) offset));
+                fErrors.error(type.fPosition,
+                              "offset of field '" + type.fields()[i].fName + "' must be at "
+                              "least " + to_string((int) offset));
             }
             if (fieldLayout.fOffset % alignment) {
-                fErrors->error(type.fPosition,
-                               "offset of field '" + type.fields()[i].fName + "' must be a multiple"
-                               " of " + to_string((int) alignment));
+                fErrors.error(type.fPosition,
+                              "offset of field '" + type.fields()[i].fName + "' must be a multiple"
+                              " of " + to_string((int) alignment));
             }
             offset = fieldLayout.fOffset;
         } else {
@@ -1847,11 +1847,64 @@ std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const
 }
 
 SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, SkWStream& out) {
+    SpvId result = this->nextId();
     auto entry = fVariableMap.find(&ref.fVariable);
     ASSERT(entry != fVariableMap.end());
     SpvId var = entry->second;
-    SpvId result = this->nextId();
     this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
+    if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
+        fProgram.fSettings.fFlipY) {
+        // need to remap to a top-left coordinate system
+        if (fRTHeightStructId == (SpvId) -1) {
+            // height variable hasn't been written yet
+            std::shared_ptr<SymbolTable> st(new SymbolTable(fErrors));
+            ASSERT(fRTHeightFieldIndex == (SpvId) -1);
+            std::vector<Type::Field> fields;
+            fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME),
+                                fContext.fFloat_Type.get());
+            SkString name("sksl_synthetic_uniforms");
+            Type intfStruct(Position(), name, fields);
+            Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false, Layout::Format::kUnspecified,
+                          false);
+            Variable intfVar(Position(), Modifiers(layout, Modifiers::kUniform_Flag), name,
+                             intfStruct, Variable::kGlobal_Storage);
+            InterfaceBlock intf(Position(), intfVar, st);
+            fRTHeightStructId = this->writeInterfaceBlock(intf);
+            fRTHeightFieldIndex = 0;
+        }
+        ASSERT(fRTHeightFieldIndex != (SpvId) -1);
+        // write vec4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0)
+        SpvId xId = this->nextId();
+        this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
+                               result, 0, out);
+        IntLiteral fieldIndex(fContext, Position(), fRTHeightFieldIndex);
+        SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
+        SpvId heightRead = this->nextId();
+        this->writeOpCode(SpvOpAccessChain, 5, out);
+        this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
+        this->writeWord(heightRead, out);
+        this->writeWord(fRTHeightStructId, out);
+        this->writeWord(fieldIndexId, out);
+        SpvId rawYId = this->nextId();
+        this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
+                               result, 1, out);
+        SpvId flippedYId = this->nextId();
+        this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
+                               heightRead, rawYId, out);
+        FloatLiteral zero(fContext, Position(), 0.0);
+        SpvId zeroId = writeFloatLiteral(zero);
+        FloatLiteral one(fContext, Position(), 1.0);
+        SpvId oneId = writeFloatLiteral(one);
+        SpvId flipped = this->nextId();
+        this->writeOpCode(SpvOpCompositeConstruct, 7, out);
+        this->writeWord(this->getType(*fContext.fVec4_Type), out);
+        this->writeWord(flipped, out);
+        this->writeWord(xId, out);
+        this->writeWord(flippedYId, out);
+        this->writeWord(zeroId, out);
+        this->writeWord(oneId, out);
+        return flipped;
+    }
     return result;
 }
 
@@ -2442,12 +2495,22 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
     MemoryLayout layout = intf.fVariable.fModifiers.fLayout.fPushConstant ?
                           MemoryLayout(MemoryLayout::k430_Standard) :
                           fDefaultLayout;
-    SpvId type = this->getType(intf.fVariable.fType, layout);
     SpvId result = this->nextId();
-    this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
+    const Type* type = &intf.fVariable.fType;
+    if (fProgram.fInputs.fRTHeight) {
+        ASSERT(fRTHeightStructId == (SpvId) -1);
+        ASSERT(fRTHeightFieldIndex == (SpvId) -1);
+        std::vector<Type::Field> fields = type->fields();
+        fRTHeightStructId = result;
+        fRTHeightFieldIndex = fields.size();
+        fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
+        type = new Type(type->fPosition, type->name(), fields);
+    }
+    SpvId typeId = this->getType(*type, layout);
+    this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
     SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
     SpvId ptrType = this->nextId();
-    this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, type, fConstantBuffer);
+    this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
     this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
     this->writeLayout(intf.fVariable.fModifiers.fLayout, result);
     fVariableMap[&intf.fVariable] = result;
@@ -2734,6 +2797,7 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, SkWStream& ou
         }
     }
 
+    write_data(*fExtraGlobalsBuffer.detachAsData(), out);
     write_data(*fNameBuffer.detachAsData(), out);
     write_data(*fDecorationBuffer.detachAsData(), out);
     write_data(*fConstantBuffer.detachAsData(), out);
@@ -2741,18 +2805,17 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, SkWStream& ou
     write_data(*body.detachAsData(), out);
 }
 
-void SPIRVCodeGenerator::generateCode(const Program& program, ErrorReporter& errors,
-                                      SkWStream& out) {
-    fErrors = &errors;
-    this->writeWord(SpvMagicNumber, out);
-    this->writeWord(SpvVersion, out);
-    this->writeWord(SKSL_MAGIC, out);
+bool SPIRVCodeGenerator::generateCode() {
+    ASSERT(!fErrors.errorCount());
+    this->writeWord(SpvMagicNumber, *fOut);
+    this->writeWord(SpvVersion, *fOut);
+    this->writeWord(SKSL_MAGIC, *fOut);
     SkDynamicMemoryWStream buffer;
-    this->writeInstructions(program, buffer);
-    this->writeWord(fIdCount, out);
-    this->writeWord(0, out); // reserved, always zero
-    write_data(*buffer.detachAsData(), out);
-    fErrors = nullptr;
+    this->writeInstructions(fProgram, buffer);
+    this->writeWord(fIdCount, *fOut);
+    this->writeWord(0, *fOut); // reserved, always zero
+    write_data(*buffer.detachAsData(), *fOut);
+    return 0 == fErrors.errorCount();
 }
 
 }
index 5567ec5..96ff187 100644 (file)
@@ -62,18 +62,21 @@ public:
         virtual void store(SpvId value, SkWStream& out) = 0;
     };
 
-    SPIRVCodeGenerator(const Context* context)
-    : fContext(*context)
+    SPIRVCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
+                       SkWStream* out)
+    : INHERITED(program, errors, out)
+    , fContext(*context)
     , fDefaultLayout(MemoryLayout::k140_Standard)
     , fCapabilities(1 << SpvCapabilityShader)
     , fIdCount(1)
     , fBoolTrue(0)
     , fBoolFalse(0)
+    , fSetupFragPosition(false)
     , fCurrentBlock(0) {
         this->setupIntrinsics();
     }
 
-    void generateCode(const Program& program, ErrorReporter& errors, SkWStream& out) override;
+    bool generateCode() override;
 
 private:
     enum IntrinsicKind {
@@ -100,7 +103,7 @@ private:
 
     SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass);
 
-    SpvId getPointerType(const Type& type, const MemoryLayout& layout, 
+    SpvId getPointerType(const Type& type, const MemoryLayout& layout,
                          SpvStorageClass_ storageClass);
 
     std::vector<SpvId> getAccessChain(const Expression& expr, SkWStream& out);
@@ -153,11 +156,11 @@ private:
 
     SpvId writeSwizzle(const Swizzle& swizzle, SkWStream& out);
 
-    SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs, 
-                               SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt, 
+    SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs,
+                               SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
                                SpvOp_ ifBool, SkWStream& out);
 
-    SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt, 
+    SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
                                SpvOp_ ifUInt, SkWStream& out);
 
     SpvId writeBinaryExpression(const BinaryExpression& b, SkWStream& out);
@@ -215,7 +218,7 @@ private:
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, SkWStream& out);
 
-    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, 
+    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3,
                           SkWStream& out);
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
@@ -231,12 +234,11 @@ private:
                           int32_t word5, int32_t word6, int32_t word7, SkWStream& out);
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
-                          int32_t word5, int32_t word6, int32_t word7, int32_t word8, 
+                          int32_t word5, int32_t word6, int32_t word7, int32_t word8,
                           SkWStream& out);
 
     const Context& fContext;
     const MemoryLayout fDefaultLayout;
-    ErrorReporter* fErrors;
 
     uint64_t fCapabilities;
     SpvId fIdCount;
@@ -250,6 +252,7 @@ private:
     SkDynamicMemoryWStream fCapabilitiesBuffer;
     SkDynamicMemoryWStream fGlobalInitializersBuffer;
     SkDynamicMemoryWStream fConstantBuffer;
+    SkDynamicMemoryWStream fExtraGlobalsBuffer;
     SkDynamicMemoryWStream fExternalFunctionsBuffer;
     SkDynamicMemoryWStream fVariableBuffer;
     SkDynamicMemoryWStream fNameBuffer;
@@ -261,13 +264,18 @@ private:
     std::unordered_map<uint64_t, SpvId> fUIntConstants;
     std::unordered_map<float, SpvId> fFloatConstants;
     std::unordered_map<double, SpvId> fDoubleConstants;
+    bool fSetupFragPosition;
     // label of the current block, or 0 if we are not in a block
     SpvId fCurrentBlock;
     std::stack<SpvId> fBreakTarget;
     std::stack<SpvId> fContinueTarget;
+    SpvId fRTHeightStructId = (SpvId) -1;
+    SpvId fRTHeightFieldIndex = (SpvId) -1;
 
     friend class PointerLValue;
     friend class SwizzleLValue;
+
+    typedef CodeGenerator INHERITED;
 };
 
 }
index 95b2529..678241d 100644 (file)
@@ -72,6 +72,21 @@ public:
         return result;
     }
 
+    static sk_sp<GrShaderCaps> FragCoordsOld() {
+        sk_sp<GrShaderCaps> result = sk_make_sp<GrShaderCaps>(GrContextOptions());
+        result->fVersionDeclString = "#version 110";
+        result->fGLSLGeneration = GrGLSLGeneration::k110_GrGLSLGeneration;
+        result->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions";
+        return result;
+    }
+
+    static sk_sp<GrShaderCaps> FragCoordsNew() {
+        sk_sp<GrShaderCaps> result = sk_make_sp<GrShaderCaps>(GrContextOptions());
+        result->fVersionDeclString = "#version 400";
+        result->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions";
+        return result;
+    }
+
     static sk_sp<GrShaderCaps> VariousCaps() {
         sk_sp<GrShaderCaps> result = sk_make_sp<GrShaderCaps>(GrContextOptions());
         result->fVersionDeclString = "#version 400";
index 8393341..ac49d6d 100644 (file)
@@ -4,42 +4,73 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+
 #ifndef SKSL_PROGRAM
 #define SKSL_PROGRAM
 
 #include <vector>
 #include <memory>
 
+#include "SkSLContext.h"
 #include "SkSLModifiers.h"
 #include "SkSLProgramElement.h"
 #include "SkSLSymbolTable.h"
 
+// name of the render target height uniform
+#define SKSL_RTHEIGHT_NAME "u_skRTHeight"
+
 namespace SkSL {
 
 /**
  * Represents a fully-digested program, ready for code generation.
  */
 struct Program {
+    struct Settings {
+        const GrShaderCaps* fCaps = nullptr;
+        bool fFlipY = false;
+    };
+
+    struct Inputs {
+        // if true, this program requires the render target height uniform to be defined
+        bool fRTHeight;
+
+        void reset() {
+            fRTHeight = false;
+        }
+
+        bool isEmpty() {
+            return !fRTHeight;
+        }
+    };
+
     enum Kind {
         kFragment_Kind,
         kVertex_Kind
     };
 
-    Program(Kind kind, 
+    Program(Kind kind,
+            Settings settings,
             Modifiers::Flag defaultPrecision,
-            std::vector<std::unique_ptr<ProgramElement>> elements, 
-            std::shared_ptr<SymbolTable> symbols)
-    : fKind(kind) 
+            Context* context,
+            std::vector<std::unique_ptr<ProgramElement>> elements,
+            std::shared_ptr<SymbolTable> symbols,
+            Inputs inputs)
+    : fKind(kind)
+    , fSettings(settings)
     , fDefaultPrecision(defaultPrecision)
+    , fContext(context)
     , fElements(std::move(elements))
-    , fSymbols(symbols) {}
+    , fSymbols(symbols)
+    , fInputs(inputs) {}
 
     Kind fKind;
+    Settings fSettings;
     // FIXME handle different types; currently it assumes this is for floats
     Modifiers::Flag fDefaultPrecision;
+    Context* fContext;
     std::vector<std::unique_ptr<ProgramElement>> fElements;
     std::shared_ptr<SymbolTable> fSymbols;
+    Inputs fInputs;
 };
 
 } // namespace
index 62f06e8..2184986 100644 (file)
@@ -2,7 +2,7 @@ STRINGIFY(
 
 // defines built-in interfaces supported by SkiaSL fragment shaders
 
-layout(builtin=15) in vec4 gl_FragCoord;
+layout(builtin=15) in vec4 sk_FragCoord;
 
 // 9999 is a temporary value that causes us to ignore these declarations beyond
 // adding them to the symbol table. This works fine in GLSL (where they do not
index c653072..e872977 100644 (file)
 static void test_failure(skiatest::Reporter* r, const char* src, const char* error) {
     SkSL::Compiler compiler;
     SkDynamicMemoryWStream out;
-    bool result = compiler.toSPIRV(SkSL::Program::kFragment_Kind, SkString(src), out);
+    SkSL::Program::Settings settings;
+    sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
+    settings.fCaps = caps.get();
+    std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
+                                                                     SkString(src), settings);
+    if (program) {
+        SkString ignored;
+        compiler.toSPIRV(*program, &ignored);
+    }
     SkString skError(error);
     if (compiler.errorText() != skError) {
         SkDebugf("SKSL ERROR:\n    source: %s\n    expected: %s    received: %s", src, error,
                  compiler.errorText().c_str());
     }
-    REPORTER_ASSERT(r, !result);
     REPORTER_ASSERT(r, compiler.errorText() == skError);
 }
 
 static void test_success(skiatest::Reporter* r, const char* src) {
     SkSL::Compiler compiler;
     SkDynamicMemoryWStream out;
-    bool result = compiler.toSPIRV(SkSL::Program::kFragment_Kind, SkString(src), out);
-    REPORTER_ASSERT(r, result);
+    SkSL::Program::Settings settings;
+    sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
+    settings.fCaps = caps.get();
+    std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
+                                                                     SkString(src), settings);
+    REPORTER_ASSERT(r, program);
+    SkString ignored;
+    REPORTER_ASSERT(r, compiler.toSPIRV(*program, &ignored));
 }
 
 DEF_TEST(SkSLUndefinedSymbol, r) {
index ceb7cb7..12ac4d1 100644 (file)
 
 #if SK_SUPPORT_GPU
 
-static void test(skiatest::Reporter* r, const char* src, const GrShaderCaps& caps,
-                 const char* expected) {
+static void test(skiatest::Reporter* r, const char* src, const SkSL::Program::Settings& settings,
+                 const char* expected, SkSL::Program::Inputs* inputs) {
     SkSL::Compiler compiler;
     SkString output;
-    bool result = compiler.toGLSL(SkSL::Program::kFragment_Kind, SkString(src), caps, &output);
-    if (!result) {
+    std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
+                                                                     SkString(src),
+                                                                     settings);
+    if (!program) {
         SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
     }
-    REPORTER_ASSERT(r, result);
-    if (result) {
+    REPORTER_ASSERT(r, program);
+    *inputs = program->fInputs;
+    REPORTER_ASSERT(r, compiler.toGLSL(*program, &output));
+    if (program) {
         SkString skExpected(expected);
         if (output != skExpected) {
-            SkDebugf("GLSL MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src, 
+            SkDebugf("GLSL MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
                      expected, output.c_str());
         }
         REPORTER_ASSERT(r, output == skExpected);
     }
 }
 
+static void test(skiatest::Reporter* r, const char* src, const GrShaderCaps& caps,
+                 const char* expected) {
+    SkSL::Program::Settings settings;
+    settings.fCaps = &caps;
+    SkSL::Program::Inputs inputs;
+    test(r, src, settings, expected, &inputs);
+}
+
 DEF_TEST(SkSLHelloWorld, r) {
     test(r,
          "void main() { sk_FragColor = vec4(0.75); }",
@@ -603,4 +615,66 @@ DEF_TEST(SkSLOffset, r) {
          "    int z;\n"
          "} test;\n");
 }
+
+DEF_TEST(SkSLFragCoord, r) {
+    SkSL::Program::Settings settings;
+    settings.fFlipY = true;
+    sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::FragCoordsOld();
+    settings.fCaps = caps.get();
+    SkSL::Program::Inputs inputs;
+    test(r,
+         "void main() { sk_FragColor.xy = sk_FragCoord.xy; }",
+         settings,
+         "#version 110\n"
+         "#extension GL_ARB_fragment_coord_conventions : require\n"
+         "layout(origin_upper_left) in vec4 gl_FragCoord;\n"
+         "void main() {\n"
+         "    gl_FragColor.xy = gl_FragCoord.xy;\n"
+         "}\n",
+         &inputs);
+    REPORTER_ASSERT(r, !inputs.fRTHeight);
+
+    caps = SkSL::ShaderCapsFactory::FragCoordsNew();
+    settings.fCaps = caps.get();
+    test(r,
+         "void main() { sk_FragColor.xy = sk_FragCoord.xy; }",
+         settings,
+         "#version 400\n"
+         "layout(origin_upper_left) in vec4 gl_FragCoord;\n"
+         "out vec4 sk_FragColor;\n"
+         "void main() {\n"
+         "    sk_FragColor.xy = gl_FragCoord.xy;\n"
+         "}\n",
+         &inputs);
+    REPORTER_ASSERT(r, !inputs.fRTHeight);
+
+    caps = SkSL::ShaderCapsFactory::Default();
+    settings.fCaps = caps.get();
+    test(r,
+         "void main() { sk_FragColor.xy = sk_FragCoord.xy; }",
+         settings,
+         "#version 400\n"
+         "uniform float u_skRTHeight;\n"
+         "out vec4 sk_FragColor;\n"
+         "void main() {\n"
+         "    vec2 _sktmpCoord = gl_FragCoord.xy;\n"
+         "    vec4 sk_FragCoord = vec4(_sktmpCoord.x, u_skRTHeight - _sktmpCoord.y, 1.0, 1.0);\n"
+         "    sk_FragColor.xy = sk_FragCoord.xy;\n"
+         "}\n",
+         &inputs);
+    REPORTER_ASSERT(r, inputs.fRTHeight);
+
+    settings.fFlipY = false;
+    test(r,
+         "void main() { sk_FragColor.xy = sk_FragCoord.xy; }",
+         settings,
+         "#version 400\n"
+         "out vec4 sk_FragColor;\n"
+         "void main() {\n"
+         "    sk_FragColor.xy = gl_FragCoord.xy;\n"
+         "}\n",
+         &inputs);
+    REPORTER_ASSERT(r, !inputs.fRTHeight);
+}
+
 #endif