From ce33f10677630e34187b661a02161378d8304d68 Mon Sep 17 00:00:00 2001 From: Ethan Nicholas Date: Fri, 9 Dec 2016 17:22:59 -0500 Subject: [PATCH] added sk_FragCoord support to skslc BUG=skia: Change-Id: If78a4d08121699f87659f0d2e35f3edbf1867401 Reviewed-on: https://skia-review.googlesource.com/5408 Reviewed-by: Greg Daniel Commit-Queue: Ethan Nicholas --- bench/GLBench.cpp | 15 +-- fuzz/fuzz.cpp | 11 ++- src/gpu/gl/GrGLGpu.cpp | 39 ++++++-- src/gpu/gl/builders/GrGLProgramBuilder.cpp | 25 ++++- src/gpu/gl/builders/GrGLProgramBuilder.h | 5 +- src/gpu/gl/builders/GrGLShaderStringBuilder.cpp | 19 ++-- src/gpu/gl/builders/GrGLShaderStringBuilder.h | 4 +- src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp | 44 +-------- src/gpu/glsl/GrGLSLProgramBuilder.cpp | 4 +- src/gpu/glsl/GrGLSLProgramBuilder.h | 2 +- src/gpu/vk/GrVkCopyManager.cpp | 14 +-- src/gpu/vk/GrVkGpu.cpp | 10 -- src/gpu/vk/GrVkGpu.h | 29 ++---- src/gpu/vk/GrVkPipelineStateBuilder.cpp | 40 +++++--- src/gpu/vk/GrVkPipelineStateBuilder.h | 11 ++- src/gpu/vk/GrVkUtil.cpp | 93 ++++++------------- src/gpu/vk/GrVkUtil.h | 5 +- src/sksl/SkSLCodeGenerator.h | 13 ++- src/sksl/SkSLCompiler.cpp | 108 +++++++++------------- src/sksl/SkSLCompiler.h | 30 +++--- src/sksl/SkSLErrorReporter.h | 2 + src/sksl/SkSLGLSLCodeGenerator.cpp | 118 ++++++++++++++++-------- src/sksl/SkSLGLSLCodeGenerator.h | 27 +++--- src/sksl/SkSLIRGenerator.cpp | 44 +++++++-- src/sksl/SkSLIRGenerator.h | 12 ++- src/sksl/SkSLMain.cpp | 9 +- src/sksl/SkSLSPIRVCodeGenerator.cpp | 105 ++++++++++++++++----- src/sksl/SkSLSPIRVCodeGenerator.h | 28 ++++-- src/sksl/SkSLUtil.h | 15 +++ src/sksl/ir/SkSLProgram.h | 43 +++++++-- src/sksl/sksl_frag.include | 2 +- tests/SkSLErrorTest.cpp | 21 ++++- tests/SkSLGLSLTest.cpp | 88 ++++++++++++++++-- 33 files changed, 637 insertions(+), 398 deletions(-) diff --git a/bench/GLBench.cpp b/bench/GLBench.cpp index 38205e2..0fcd56f 100644 --- a/bench/GLBench.cpp +++ b/bench/GLBench.cpp @@ -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 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; diff --git a/fuzz/fuzz.cpp b/fuzz/fuzz.cpp index 047bcd8..f8f02a3 100644 --- a/fuzz/fuzz.cpp +++ b/fuzz/fuzz.cpp @@ -444,10 +444,13 @@ int fuzz_color_deserialize(sk_sp bytes) { int fuzz_sksl2glsl(sk_sp 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 caps = SkSL::ShaderCapsFactory::Default(); + settings.fCaps = caps.get(); + std::unique_ptr 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; } diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 20609af..bbbcf4c 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -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)); diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index cc29022..045593f 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -69,7 +69,9 @@ const GrCaps* GrGLProgramBuilder::caps() const { bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader, GrGLuint programId, GrGLenum type, - SkTDArray* shaderIds) { + SkTDArray* 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 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)); diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h index a88f278..84d6d91 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.h +++ b/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -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* shaderIds); + SkTDArray* shaderIds, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs); GrGLProgram* finalize(); void bindProgramResourceLocations(GrGLuint programID); bool checkLinkStatus(GrGLuint programID); diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp index bd4921b..df44edd 100644 --- a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp +++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp @@ -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 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); diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.h b/src/gpu/gl/builders/GrGLShaderStringBuilder.h index 71fce6a..242fe61 100644 --- a/src/gpu/gl/builders/GrGLShaderStringBuilder.h +++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.h @@ -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 diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp index 8355f1d..7ef7348 100644 --- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp +++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp @@ -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 { diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp index 590439d..1182996 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -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() { diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h index fdb6e11..bfd9f7a 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.h +++ b/src/gpu/glsl/GrGLSLProgramBuilder.h @@ -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 diff --git a/src/gpu/vk/GrVkCopyManager.cpp b/src/gpu/vk/GrVkCopyManager.cpp index 78194fc..7b2c734 100644 --- a/src/gpu/vk/GrVkCopyManager.cpp +++ b/src/gpu/vk/GrVkCopyManager.cpp @@ -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]; diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index a742c4b..f31c743 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -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) { diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index 0e5f228..5dddb93 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -8,8 +8,6 @@ #ifndef GrVkGpu_DEFINED #define GrVkGpu_DEFINED -#define USE_SKSL 1 - #include "GrGpu.h" #include "GrGpuFactory.h" #include "vk/GrVkBackendContext.h" @@ -20,15 +18,6 @@ #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; }; diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/src/gpu/vk/GrVkPipelineStateBuilder.cpp index 49f5cf8..4125938 100644 --- a/src/gpu/vk/GrVkPipelineStateBuilder.cpp +++ b/src/gpu/vk/GrVkPipelineStateBuilder.cpp @@ -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, diff --git a/src/gpu/vk/GrVkPipelineStateBuilder.h b/src/gpu/vk/GrVkPipelineStateBuilder.h index c36f9ac..cf4a983 100644 --- a/src/gpu/vk/GrVkPipelineStateBuilder.h +++ b/src/gpu/vk/GrVkPipelineStateBuilder.h @@ -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; } diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp index 4446dfe..3071fc8 100644 --- a/src/gpu/vk/GrVkUtil.cpp +++ b/src/gpu/vk/GrVkUtil.cpp @@ -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 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; diff --git a/src/gpu/vk/GrVkUtil.h b/src/gpu/vk/GrVkUtil.h index fae3c20..ba07bca 100644 --- a/src/gpu/vk/GrVkUtil.h +++ b/src/gpu/vk/GrVkUtil.h @@ -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 diff --git a/src/sksl/SkSLCodeGenerator.h b/src/sksl/SkSLCodeGenerator.h index ed93778..111e73a 100644 --- a/src/sksl/SkSLCodeGenerator.h +++ b/src/sksl/SkSLCodeGenerator.h @@ -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 diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp index 1be0ba9..9faf836 100644 --- a/src/sksl/SkSLCompiler.cpp +++ b/src/sksl/SkSLCompiler.cpp @@ -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 Compiler::convertProgram(Program::Kind kind, SkString text, - std::unordered_map caps) { + const Program::Settings& settings) { fErrorText = ""; fErrorCount = 0; - fIRGenerator->start(&caps); + fIRGenerator->start(&settings); std::vector> elements; Modifiers::Flag ignored; switch (kind) { @@ -409,47 +410,46 @@ std::unique_ptr Compiler::convertProgram(Program::Kind kind, SkString t fIRGenerator->fSymbolTable->markAllFunctionsBuiltin(); Modifiers::Flag defaultPrecision; this->internalConvertProgram(text, &defaultPrecision, &elements); - auto result = std::unique_ptr(new Program(kind, defaultPrecision, std::move(elements), - fIRGenerator->fSymbolTable)); + auto result = std::unique_ptr(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 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 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 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* 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 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 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 diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h index 114f8ef..0f893f7 100644 --- a/src/sksl/SkSLCompiler.h +++ b/src/sksl/SkSLCompiler.h @@ -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 convertProgram(Program::Kind kind, SkString text, - std::unordered_map caps); + std::unique_ptr 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* definitions); - - void addDefinitions(const BasicBlock::Node& node, + + void addDefinitions(const BasicBlock::Node& node, std::unordered_map* definitions); void scanCFG(CFG* cfg, BlockId block, std::set* workList); diff --git a/src/sksl/SkSLErrorReporter.h b/src/sksl/SkSLErrorReporter.h index 585a97c..85d386d 100644 --- a/src/sksl/SkSLErrorReporter.h +++ b/src/sksl/SkSLErrorReporter.h @@ -24,6 +24,8 @@ public: } virtual void error(Position position, SkString msg) = 0; + + virtual int errorCount() = 0; }; } // namespace diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp index 5b74724..caf6ec8 100644 --- a/src/sksl/SkSLGLSLCodeGenerator.cpp +++ b/src/sksl/SkSLGLSLCodeGenerator.cpp @@ -11,14 +11,13 @@ #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,56 @@ 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) { + fSetupFragPosition = true; + this->write("gl_FragCoord"); + } else if (const char* extension = + fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) { + if (!fSetupFragPosition) { + 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"); + fSetupFragPosition = true; } + this->write("gl_FragCoord"); } else { - this->write(ref.fVariable.fName); + if (!fSetupFragPosition) { + // 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. + fHeader.writeText("uniform float " SKSL_RTHEIGHT_NAME ";\n" + "highp vec2 _sktmpCoord = gl_FragCoord.xy;\n" + "highp vec4 sk_FragCoord = vec4(_sktmpCoord.x, " SKSL_RTHEIGHT_NAME + " - _sktmpCoord.y, 1.0, 1.0);\n"); + fSetupFragPosition = 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 +526,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 +547,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 +598,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 +714,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 +745,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 +758,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 +785,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; } } diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h index ffc5a4d..bb7d8b1 100644 --- a/src/sksl/SkSLGLSLCodeGenerator.h +++ b/src/sksl/SkSLGLSLCodeGenerator.h @@ -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 #include -#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,22 @@ 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 fWrittenStructs; // true if we have run into usages of dFdx / dFdy bool fFoundDerivatives = false; bool fFoundImageDecl = false; + bool fSetupFragPosition = false; + + typedef CodeGenerator INHERITED; }; } diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp index 023f191..0698817 100644 --- a/src/sksl/SkSLIRGenerator.cpp +++ b/src/sksl/SkSLIRGenerator.cpp @@ -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 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* caps) { - this->fCapsMap = caps; +static void fill_caps(const GrShaderCaps& caps, std::unordered_map* 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 IRGenerator::convertExtension(const ASTExtension& extension) { @@ -600,6 +626,11 @@ std::unique_ptr 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(new VariableReference(identifier.fPosition, *var)); } @@ -1336,9 +1367,8 @@ std::unique_ptr IRGenerator::convertSwizzle(std::unique_ptr 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; } diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h index ade6150..13b20fb 100644 --- a/src/sksl/SkSLIRGenerator.h +++ b/src/sksl/SkSLIRGenerator.h @@ -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 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. can be resolved. + * Prepare to compile a program. Resets state, pushes a new symbol table, and installs the + * settings. */ - void start(std::unordered_map* 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* fCapsMap; + const Program::Settings* fSettings; + std::unordered_map fCapsMap; std::shared_ptr fSymbolTable; int fLoopLevel; ErrorReporter& fErrors; diff --git a/src/sksl/SkSLMain.cpp b/src/sksl/SkSLMain.cpp index 381fcf0..f493b05 100644 --- a/src/sksl/SkSLMain.cpp +++ b/src/sksl/SkSLMain.cpp @@ -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 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 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 program = compiler.convertProgram(kind, text, settings); + if (!program || !compiler.toGLSL(*program, out)) { printf("%s", compiler.errorText().c_str()); exit(3); } diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp index b2857f4..63fe020 100644 --- a/src/sksl/SkSLSPIRVCodeGenerator.cpp +++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp @@ -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::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 st(new SymbolTable(fErrors)); + ASSERT(fRTHeightFieldIndex == (SpvId) -1); + std::vector 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 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(); } } diff --git a/src/sksl/SkSLSPIRVCodeGenerator.h b/src/sksl/SkSLSPIRVCodeGenerator.h index 5567ec5..96ff187 100644 --- a/src/sksl/SkSLSPIRVCodeGenerator.h +++ b/src/sksl/SkSLSPIRVCodeGenerator.h @@ -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 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 fUIntConstants; std::unordered_map fFloatConstants; std::unordered_map fDoubleConstants; + bool fSetupFragPosition; // label of the current block, or 0 if we are not in a block SpvId fCurrentBlock; std::stack fBreakTarget; std::stack fContinueTarget; + SpvId fRTHeightStructId = (SpvId) -1; + SpvId fRTHeightFieldIndex = (SpvId) -1; friend class PointerLValue; friend class SwizzleLValue; + + typedef CodeGenerator INHERITED; }; } diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h index 95b2529..678241d 100644 --- a/src/sksl/SkSLUtil.h +++ b/src/sksl/SkSLUtil.h @@ -72,6 +72,21 @@ public: return result; } + static sk_sp FragCoordsOld() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 110"; + result->fGLSLGeneration = GrGLSLGeneration::k110_GrGLSLGeneration; + result->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions"; + return result; + } + + static sk_sp FragCoordsNew() { + sk_sp result = sk_make_sp(GrContextOptions()); + result->fVersionDeclString = "#version 400"; + result->fFragCoordConventionsExtensionString = "GL_ARB_fragment_coord_conventions"; + return result; + } + static sk_sp VariousCaps() { sk_sp result = sk_make_sp(GrContextOptions()); result->fVersionDeclString = "#version 400"; diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h index 8393341..ac49d6d 100644 --- a/src/sksl/ir/SkSLProgram.h +++ b/src/sksl/ir/SkSLProgram.h @@ -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 #include +#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> elements, - std::shared_ptr symbols) - : fKind(kind) + Context* context, + std::vector> elements, + std::shared_ptr 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> fElements; std::shared_ptr fSymbols; + Inputs fInputs; }; } // namespace diff --git a/src/sksl/sksl_frag.include b/src/sksl/sksl_frag.include index 62f06e8..2184986 100644 --- a/src/sksl/sksl_frag.include +++ b/src/sksl/sksl_frag.include @@ -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 diff --git a/tests/SkSLErrorTest.cpp b/tests/SkSLErrorTest.cpp index c653072..e872977 100644 --- a/tests/SkSLErrorTest.cpp +++ b/tests/SkSLErrorTest.cpp @@ -14,21 +14,34 @@ 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 caps = SkSL::ShaderCapsFactory::Default(); + settings.fCaps = caps.get(); + std::unique_ptr 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 caps = SkSL::ShaderCapsFactory::Default(); + settings.fCaps = caps.get(); + std::unique_ptr 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) { diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp index ceb7cb7..37d9a27 100644 --- a/tests/SkSLGLSLTest.cpp +++ b/tests/SkSLGLSLTest.cpp @@ -11,25 +11,37 @@ #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 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 = ∩︀ + 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 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" + "highp vec2 _sktmpCoord = gl_FragCoord.xy;\n" + "highp vec4 sk_FragCoord = vec4(_sktmpCoord.x, u_skRTHeight - _sktmpCoord.y, 1.0, 1.0);\n" + "out vec4 sk_FragColor;\n" + "void main() {\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 -- 2.7.4