From 0d997665e6ddda100889822447e29d1d2bac0b6a Mon Sep 17 00:00:00 2001 From: Ethan Nicholas Date: Mon, 8 Apr 2019 09:46:01 -0400 Subject: [PATCH] Revert "Reland "Revert "Reland "GPU support for SkMixers"""" This reverts commit 1263889f3a3ea44db959f043254f4ee9e4014ac9. Bug: skia: Change-Id: I647cb228e4a8169f12f4afadaf1db06843e4e5fd Reviewed-on: https://skia-review.googlesource.com/c/skia/+/206391 Reviewed-by: Mike Reed Commit-Queue: Ethan Nicholas --- gm/runtimecolorfilter.cpp | 8 +- src/core/SkMixer.cpp | 108 +++++++++++++++++--- src/core/SkMixerBase.h | 10 +- src/gpu/effects/GrSkSLFP.cpp | 47 ++++++--- src/gpu/effects/GrSkSLFP.h | 19 ++-- src/shaders/SkMixerShader.cpp | 13 +-- src/sksl/SkSLCFGGenerator.cpp | 8 +- src/sksl/SkSLCompiler.cpp | 11 ++ src/sksl/SkSLIRGenerator.cpp | 72 ++++++++----- src/sksl/SkSLPipelineStageCodeGenerator.cpp | 22 +++- src/sksl/SkSLPipelineStageCodeGenerator.h | 1 + src/sksl/SkSLSPIRVCodeGenerator.cpp | 26 +++-- src/sksl/ir/SkSLProgram.h | 3 +- src/sksl/sksl_mixer.inc | 8 ++ 14 files changed, 252 insertions(+), 104 deletions(-) create mode 100644 src/sksl/sksl_mixer.inc diff --git a/gm/runtimecolorfilter.cpp b/gm/runtimecolorfilter.cpp index 89252b6cc6..70b7ee950b 100644 --- a/gm/runtimecolorfilter.cpp +++ b/gm/runtimecolorfilter.cpp @@ -34,7 +34,9 @@ DEF_SIMPLE_GPU_GM(runtimecolorfilter, context, rtc, canvas, 768, 256) { float b = 0.75; sk_sp data = SkData::MakeWithCopy(&b, sizeof(b)); - auto cf1 = SkRuntimeColorFilterFactory(SkString(SKSL_TEST_SRC), runtimeCpuFunc).make(data); + static SkRuntimeColorFilterFactory fact = SkRuntimeColorFilterFactory(SkString(SKSL_TEST_SRC), + runtimeCpuFunc); + auto cf1 = fact.make(data); SkPaint p; p.setColorFilter(cf1); canvas->drawImage(img, 256, 0, &p); @@ -57,7 +59,9 @@ DEF_SIMPLE_GM(runtimecolorfilter_interpreted, canvas, 768, 256) { float b = 0.75; sk_sp data = SkData::MakeWithCopy(&b, sizeof(b)); - auto cf1 = SkRuntimeColorFilterFactory(SkString(SKSL_TEST_SRC), nullptr).make(data); + static SkRuntimeColorFilterFactory fact = SkRuntimeColorFilterFactory(SkString(SKSL_TEST_SRC), + nullptr); + auto cf1 = fact.make(data); SkPaint p; p.setColorFilter(cf1); canvas->drawImage(img, 256, 0, &p); diff --git a/src/core/SkMixer.cpp b/src/core/SkMixer.cpp index 72c5a75b41..c148822173 100644 --- a/src/core/SkMixer.cpp +++ b/src/core/SkMixer.cpp @@ -8,13 +8,36 @@ #include "SkBlendModePriv.h" #include "SkEffectPriv.h" #include "SkMixerBase.h" +#include "SkMixerShader.h" #include "SkReadBuffer.h" #include "SkRasterPipeline.h" #include "SkWriteBuffer.h" #if SK_SUPPORT_GPU +#include "GrRecordingContext.h" #include "effects/GrConstColorProcessor.h" +#include "effects/GrSkSLFP.h" #include "effects/GrXfermodeFragmentProcessor.h" + +static std::unique_ptr sksl_mixer_fp( + const GrFPArgs& args, + int index, + const char* sksl, + sk_sp inputs, + std::unique_ptr fp1, + std::unique_ptr fp2, + std::unique_ptr fp3 = nullptr) { + std::unique_ptr result = GrSkSLFP::Make(args.fContext, index, "Runtime Mixer", sksl, + inputs ? inputs->data() : nullptr, + inputs ? inputs->size() : 0, + SkSL::Program::kMixer_Kind); + result->addChild(std::move(fp1)); + result->addChild(std::move(fp2)); + if (fp3) { + result->addChild(std::move(fp3)); + } + return std::move(result); +} #endif /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -37,9 +60,9 @@ public: #if SK_SUPPORT_GPU std::unique_ptr - asFragmentProcessor(GrRecordingContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const override { - // return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), std::move(fpA), fMode); - return nullptr; + asFragmentProcessor(const GrFPArgs& args, const sk_sp shader1, + const sk_sp shader2) const override { + return GrConstColorProcessor::Make(fPM, GrConstColorProcessor::InputMode::kIgnore); } #endif }; @@ -82,9 +105,9 @@ public: #if SK_SUPPORT_GPU std::unique_ptr - asFragmentProcessor(GrRecordingContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const override { - // return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), std::move(fpA), fMode); - return nullptr; + asFragmentProcessor(const GrFPArgs& args, const sk_sp shader1, + const sk_sp shader2) const override { + return as_MB(fProxy)->asFragmentProcessor(args, shader2, shader1); } #endif }; @@ -114,9 +137,18 @@ public: #if SK_SUPPORT_GPU std::unique_ptr - asFragmentProcessor(GrRecordingContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const override { - // return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), std::move(fpA), fMode); - return nullptr; + asFragmentProcessor(const GrFPArgs& args, const sk_sp shader1, + const sk_sp shader2) const override { + std::unique_ptr fp1 = as_SB(shader1)->asFragmentProcessor(args); + if (!fp1) { + return nullptr; + } + std::unique_ptr fp2 = as_SB(shader2)->asFragmentProcessor(args); + if (!fp2) { + return nullptr; + } + return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fp2), std::move(fp1), + fMode); } #endif }; @@ -151,9 +183,26 @@ public: #if SK_SUPPORT_GPU std::unique_ptr - asFragmentProcessor(GrRecordingContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const override { - // return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), std::move(fpA), fMode); - return nullptr; + asFragmentProcessor(const GrFPArgs& args, const sk_sp shader1, + const sk_sp shader2) const override { + std::unique_ptr fp1 = as_SB(shader1)->asFragmentProcessor(args); + if (!fp1) { + return nullptr; + } + std::unique_ptr fp2 = as_SB(shader2)->asFragmentProcessor(args); + if (!fp2) { + return nullptr; + } + static int index = GrSkSLFP::NewIndex(); + return sksl_mixer_fp(args, + index, + "in uniform float weight;" + "void main(half4 input1, half4 input2) {" + " sk_OutColor = mix(input1, input2, half(weight));" + "}", + SkData::MakeWithCopy(&fWeight, sizeof(fWeight)), + std::move(fp1), + std::move(fp2)); } #endif }; @@ -206,8 +255,31 @@ public: #if SK_SUPPORT_GPU std::unique_ptr - asFragmentProcessor(GrRecordingContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const override { - return nullptr; + asFragmentProcessor(const GrFPArgs& args, const sk_sp shader1, + const sk_sp shader2) const override { + std::unique_ptr fp1 = as_SB(shader1)->asFragmentProcessor(args); + if (!fp1) { + return nullptr; + } + std::unique_ptr fp2 = as_SB(shader2)->asFragmentProcessor(args); + if (!fp2) { + return nullptr; + } + std::unique_ptr fp3 = as_SB(fShader)->asFragmentProcessor(args); + if (!fp3) { + return nullptr; + } + static int index = GrSkSLFP::NewIndex(); + return sksl_mixer_fp(args, + index, + "in fragmentProcessor lerpControl;" + "void main(half4 input1, half4 input2) {" + " sk_OutColor = mix(input1, input2, process(lerpControl).r);" + "}", + nullptr, + std::move(fp1), + std::move(fp2), + std::move(fp3)); } #endif }; @@ -276,9 +348,11 @@ public: #if SK_SUPPORT_GPU std::unique_ptr - asFragmentProcessor(GrRecordingContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const override { - // return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), std::move(fpA), fMode); - return nullptr; + asFragmentProcessor(const GrFPArgs& args, const sk_sp shader1, + const sk_sp shader2) const override { + return SkShader_Mixer(sk_sp(new SkShader_Mixer(shader1, shader2, fM0)), + sk_sp(new SkShader_Mixer(shader1, shader2, fM1)), + fCombine).asFragmentProcessor(args); } #endif }; diff --git a/src/core/SkMixerBase.h b/src/core/SkMixerBase.h index 31b17b8596..bfa5283108 100644 --- a/src/core/SkMixerBase.h +++ b/src/core/SkMixerBase.h @@ -5,13 +5,14 @@ * found in the LICENSE file. */ -#ifndef SkMixerPriv_DEFINED -#define SkMixerPriv_DEFINED +#ifndef SkMixerBase_DEFINED +#define SkMixerBase_DEFINED #include "SkMixer.h" #include "SkColorData.h" class GrColorSpaceInfo; +struct GrFPArgs; class GrFragmentProcessor; class GrRecordingContext; struct SkStageRec; @@ -31,8 +32,9 @@ public: * * A null return indicates that the color filter isn't implemented for the GPU backend. */ - virtual std::unique_ptr asFragmentProcessor( - GrRecordingContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const = 0; + virtual std::unique_ptr + asFragmentProcessor(const GrFPArgs& args, const sk_sp shader1, + const sk_sp shader2) const = 0; #endif static void RegisterFlattenables(); diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp index a9cc5104f9..1c7673e6ff 100644 --- a/src/gpu/effects/GrSkSLFP.cpp +++ b/src/gpu/effects/GrSkSLFP.cpp @@ -16,13 +16,13 @@ #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLProgramBuilder.h" -GrSkSLFPFactory::GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl) - : fName(name) { +GrSkSLFPFactory::GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl, + SkSL::Program::Kind kind) + : fKind(kind) + , fName(name) { SkSL::Program::Settings settings; settings.fCaps = shaderCaps; - fBaseProgram = fCompiler.convertProgram(SkSL::Program::kPipelineStage_Kind, - SkSL::String(sksl), - settings); + fBaseProgram = fCompiler.convertProgram(fKind, SkSL::String(sksl), settings); if (fCompiler.errorCount()) { SkDebugf("%s\n", fCompiler.errorText().c_str()); } @@ -83,7 +83,11 @@ const SkSL::Program* GrSkSLFPFactory::getSpecialization(const SkSL::String& key, } std::unique_ptr specialized = fCompiler.specialize(*fBaseProgram, inputMap); - SkAssertResult(fCompiler.optimize(*specialized)); + bool optimized = fCompiler.optimize(*specialized); + if (!optimized) { + SkDebugf("%s\n", fCompiler.errorText().c_str()); + SkASSERT(false); + } const SkSL::Program* result = specialized.get(); fSpecializations.insert(std::make_pair(key, std::move(specialized))); return result; @@ -269,34 +273,38 @@ public: std::unique_ptr GrSkSLFP::Make(GrContext_Base* context, int index, const char* name, const char* sksl, const void* inputs, - size_t inputSize) { + size_t inputSize, SkSL::Program::Kind kind) { return std::unique_ptr(new GrSkSLFP(context->priv().fpFactoryCache(), context->priv().caps()->shaderCaps(), - index, name, sksl, SkString(), inputs, - inputSize)); + kind, index, name, sksl, SkString(), + inputs, inputSize)); } std::unique_ptr GrSkSLFP::Make(GrContext_Base* context, int index, const char* name, - SkString sksl, const void* inputs, size_t inputSize) { + SkString sksl, const void* inputs, size_t inputSize, + SkSL::Program::Kind kind) { return std::unique_ptr(new GrSkSLFP(context->priv().fpFactoryCache(), context->priv().caps()->shaderCaps(), - index, name, nullptr, std::move(sksl), inputs, - inputSize)); + kind, index, name, nullptr, std::move(sksl), + inputs, inputSize)); } GrSkSLFP::GrSkSLFP(sk_sp factoryCache, const GrShaderCaps* shaderCaps, - int index, const char* name, const char* sksl, SkString skslString, - const void* inputs, size_t inputSize) + SkSL::Program::Kind kind, int index, const char* name, const char* sksl, + SkString skslString, const void* inputs, size_t inputSize) : INHERITED(kGrSkSLFP_ClassID, kNone_OptimizationFlags) , fFactoryCache(factoryCache) , fShaderCaps(sk_ref_sp(shaderCaps)) + , fKind(kind) , fIndex(index) , fName(name) , fSkSLString(skslString) , fSkSL(sksl ? sksl : fSkSLString.c_str()) , fInputs(new int8_t[inputSize]) , fInputSize(inputSize) { - memcpy(fInputs.get(), inputs, inputSize); + if (fInputSize) { + memcpy(fInputs.get(), inputs, inputSize); + } } GrSkSLFP::GrSkSLFP(const GrSkSLFP& other) @@ -304,13 +312,16 @@ GrSkSLFP::GrSkSLFP(const GrSkSLFP& other) , fFactoryCache(other.fFactoryCache) , fShaderCaps(other.fShaderCaps) , fFactory(other.fFactory) + , fKind(other.fKind) , fIndex(other.fIndex) , fName(other.fName) , fSkSLString(other.fSkSLString) , fSkSL(other.fSkSL) , fInputs(new int8_t[other.fInputSize]) , fInputSize(other.fInputSize) { - memcpy(fInputs.get(), other.fInputs.get(), fInputSize); + if (fInputSize) { + memcpy(fInputs.get(), other.fInputs.get(), fInputSize); + } } const char* GrSkSLFP::name() const { @@ -321,7 +332,8 @@ void GrSkSLFP::createFactory() const { if (!fFactory) { fFactory = fFactoryCache->get(fIndex); if (!fFactory) { - fFactory = sk_sp(new GrSkSLFPFactory(fName, fShaderCaps.get(), fSkSL)); + fFactory = sk_sp(new GrSkSLFPFactory(fName, fShaderCaps.get(), fSkSL, + fKind)); fFactoryCache->set(fIndex, fFactory); } } @@ -346,6 +358,7 @@ GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const { void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { this->createFactory(); + b->add32(fIndex); size_t offset = 0; char* inputs = (char*) fInputs.get(); const SkSL::Context& context = fFactory->fCompiler.context(); diff --git a/src/gpu/effects/GrSkSLFP.h b/src/gpu/effects/GrSkSLFP.h index 83a7537ff5..fb7369fc78 100644 --- a/src/gpu/effects/GrSkSLFP.h +++ b/src/gpu/effects/GrSkSLFP.h @@ -73,7 +73,8 @@ public: const char* name, const char* sksl, const void* inputs, - size_t inputSize); + size_t inputSize, + SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind); static std::unique_ptr Make( GrContext_Base* context, @@ -81,7 +82,8 @@ public: const char* name, SkString sksl, const void* inputs, - size_t inputSize); + size_t inputSize, + SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind); const char* name() const override; @@ -90,9 +92,9 @@ public: std::unique_ptr clone() const override; private: - GrSkSLFP(sk_sp factoryCache, const GrShaderCaps* shaderCaps, int fIndex, - const char* name, const char* sksl, SkString skslString, const void* inputs, - size_t inputSize); + GrSkSLFP(sk_sp factoryCache, const GrShaderCaps* shaderCaps, + SkSL::Program::Kind kind, int fIndex, const char* name, const char* sksl, + SkString skslString, const void* inputs, size_t inputSize); GrSkSLFP(const GrSkSLFP& other); @@ -110,6 +112,8 @@ private: mutable sk_sp fFactory; + SkSL::Program::Kind fKind; + int fIndex; const char* fName; @@ -152,11 +156,14 @@ public: * the produced shaders to differ), so it is important to reuse the same factory instance for * the same shader in order to avoid repeatedly re-parsing the SkSL. */ - GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl); + GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl, + SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind); const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs, size_t inputSize); + SkSL::Program::Kind fKind; + const char* fName; SkSL::Compiler fCompiler; diff --git a/src/shaders/SkMixerShader.cpp b/src/shaders/SkMixerShader.cpp index c34a07e5d8..e10325d013 100644 --- a/src/shaders/SkMixerShader.cpp +++ b/src/shaders/SkMixerShader.cpp @@ -73,17 +73,6 @@ bool SkShader_Mixer::onAppendStages(const SkStageRec& rec) const { std::unique_ptr SkShader_Mixer::asFragmentProcessor(const GrFPArgs& args) const { - std::unique_ptr fpA(as_SB(fShader0)->asFragmentProcessor(args)); - if (!fpA) { - return nullptr; - } - std::unique_ptr fpB(as_SB(fShader1)->asFragmentProcessor(args)); - if (!fpB) { - return nullptr; - } - - // TODO: need to make a mixer-processor... - return nullptr; - //return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), std::move(fpA), fMode); + return as_MB(fMixer)->asFragmentProcessor(args, fShader0, fShader1); } #endif diff --git a/src/sksl/SkSLCFGGenerator.cpp b/src/sksl/SkSLCFGGenerator.cpp index 9d6fb06607..d86892e01d 100644 --- a/src/sksl/SkSLCFGGenerator.cpp +++ b/src/sksl/SkSLCFGGenerator.cpp @@ -451,6 +451,10 @@ void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr* e) { } } +static bool is_true(Expression& expr) { + return expr.fKind == Expression::kBoolLiteral_Kind && ((BoolLiteral&) expr).fValue; +} + void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr* s) { switch ((*s)->fKind) { case Statement::kBlock_Kind: @@ -536,7 +540,9 @@ void CFGGenerator::addStatement(CFG& cfg, std::unique_ptr* s) { fLoopExits.push(loopExit); this->addExpression(cfg, &w.fTest, true); BlockId test = cfg.fCurrent; - cfg.addExit(test, loopExit); + if (!is_true(*w.fTest)) { + cfg.addExit(test, loopExit); + } cfg.newBlock(); this->addStatement(cfg, &w.fStatement); cfg.addExit(cfg.fCurrent, loopStart); diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp index 4b9709ad6c..9d4238f439 100644 --- a/src/sksl/SkSLCompiler.cpp +++ b/src/sksl/SkSLCompiler.cpp @@ -61,6 +61,10 @@ static const char* SKSL_PIPELINE_STAGE_INCLUDE = #include "sksl_pipeline.inc" ; +static const char* SKSL_MIXER_INCLUDE = +#include "sksl_mixer.inc" +; + namespace SkSL { Compiler::Compiler(Flags flags) @@ -1268,6 +1272,13 @@ std::unique_ptr Compiler::convertProgram(Program::Kind kind, String tex strlen(SKSL_PIPELINE_STAGE_INCLUDE), *fTypes, &elements); fIRGenerator->fSymbolTable->markAllFunctionsBuiltin(); break; + case Program::kMixer_Kind: + inherited = nullptr; + fIRGenerator->start(&settings, nullptr); + fIRGenerator->convertProgram(kind, SKSL_MIXER_INCLUDE, strlen(SKSL_MIXER_INCLUDE), + *fTypes, &elements); + fIRGenerator->fSymbolTable->markAllFunctionsBuiltin(); + break; } for (auto& element : elements) { if (element->fKind == ProgramElement::kEnum_Kind) { diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp index 4baa90ed6f..696b4a111f 100644 --- a/src/sksl/SkSLIRGenerator.cpp +++ b/src/sksl/SkSLIRGenerator.cpp @@ -673,6 +673,10 @@ std::unique_ptr IRGenerator::getNormalizeSkPositionCode() { return std::unique_ptr(new ExpressionStatement(std::move(result))); } +// returns true if the modifiers are (explicitly or implicitly) nothing but 'in' +static bool is_in(const Modifiers& modifiers) { + return (modifiers.fFlags & ~Modifiers::kIn_Flag) == 0; +} void IRGenerator::convertFunction(const ASTFunction& f) { const Type* returnType = this->convertType(*f.fReturnType); @@ -700,33 +704,51 @@ void IRGenerator::convertFunction(const ASTFunction& f) { } if (f.fName == "main") { - if (fKind == Program::kPipelineStage_Kind) { - bool valid; - switch (parameters.size()) { - case 3: - valid = parameters[0]->fType == *fContext.fInt_Type && - parameters[0]->fModifiers.fFlags == 0 && - parameters[1]->fType == *fContext.fInt_Type && - parameters[1]->fModifiers.fFlags == 0 && - parameters[2]->fType == *fContext.fHalf4_Type && - parameters[2]->fModifiers.fFlags == (Modifiers::kIn_Flag | - Modifiers::kOut_Flag); - break; - case 1: - valid = parameters[0]->fType == *fContext.fHalf4_Type && - parameters[0]->fModifiers.fFlags == (Modifiers::kIn_Flag | - Modifiers::kOut_Flag); - break; - default: - valid = false; + switch (fKind) { + case Program::kPipelineStage_Kind: { + bool valid; + switch (parameters.size()) { + case 3: + valid = parameters[0]->fType == *fContext.fInt_Type && + parameters[0]->fModifiers.fFlags == 0 && + parameters[1]->fType == *fContext.fInt_Type && + parameters[1]->fModifiers.fFlags == 0 && + parameters[2]->fType == *fContext.fHalf4_Type && + parameters[2]->fModifiers.fFlags == (Modifiers::kIn_Flag | + Modifiers::kOut_Flag); + break; + case 1: + valid = parameters[0]->fType == *fContext.fHalf4_Type && + parameters[0]->fModifiers.fFlags == (Modifiers::kIn_Flag | + Modifiers::kOut_Flag); + break; + default: + valid = false; + } + if (!valid) { + fErrors.error(f.fOffset, "pipeline stage 'main' must be declared main(int, " + "int, inout half4) or main(inout half4)"); + return; + } + break; } - if (!valid) { - fErrors.error(f.fOffset, "pipeline stage 'main' must be declared main(int, " - "int, inout half4) or main(inout half4)"); - return; + case Program::kMixer_Kind: { + if (*returnType != *fContext.fVoid_Type || + parameters.size() != 2 || + parameters[0]->fType != *fContext.fHalf4_Type || + !is_in(parameters[0]->fModifiers) || + parameters[1]->fType != *fContext.fHalf4_Type || + !is_in(parameters[1]->fModifiers)) { + fErrors.error(f.fOffset, "mixer stage 'main' must be declared void main(" + "half4, half4)"); + return; + } + break; } - } else if (parameters.size()) { - fErrors.error(f.fOffset, "shader 'main' must have zero parameters"); + default: + if (parameters.size()) { + fErrors.error(f.fOffset, "shader 'main' must have zero parameters"); + } } } diff --git a/src/sksl/SkSLPipelineStageCodeGenerator.cpp b/src/sksl/SkSLPipelineStageCodeGenerator.cpp index 5121b6738b..5e36535546 100644 --- a/src/sksl/SkSLPipelineStageCodeGenerator.cpp +++ b/src/sksl/SkSLPipelineStageCodeGenerator.cpp @@ -59,7 +59,7 @@ String PipelineStageCodeGenerator::getTypeName(const Type& type) { } void PipelineStageCodeGenerator::writeBinaryExpression(const BinaryExpression& b, - Precedence parentPrecedence) { + Precedence parentPrecedence) { if (b.fOperator == Token::PERCENT) { // need to use "%%" instead of "%" b/c the code will be inside of a printf Precedence precedence = GetBinaryPrecedence(b.fOperator); @@ -147,8 +147,7 @@ void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& found = true; break; } - if (var.fModifiers.fFlags & (Modifiers::kIn_Flag | - Modifiers::kUniform_Flag)) { + if (var.fModifiers.fFlags & Modifiers::kUniform_Flag) { ++index; } } @@ -157,8 +156,20 @@ void PipelineStageCodeGenerator::writeVariableReference(const VariableReference& SkASSERT(found); fFormatArgs->push_back(Compiler::FormatArg(Compiler::FormatArg::Kind::kUniform, index)); - } - else { + } else if (fProgramKind == Program::kMixer_Kind && + ref.fVariable.fStorage == Variable::kParameter_Storage && + fCurrentFunction->fName == "main") { + this->write("%s"); + for (size_t i = 0; i < fCurrentFunction->fParameters.size(); ++i) { + if (fCurrentFunction->fParameters[i] == &ref.fVariable) { + fFormatArgs->push_back(Compiler::FormatArg( + Compiler::FormatArg::Kind::kChildProcessor, + i)); + return; + } + } + SkASSERT(false); + } else { this->write(ref.fVariable.fName); } } @@ -179,6 +190,7 @@ void PipelineStageCodeGenerator::writeSwitchStatement(const SwitchStatement& s) } void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) { + fCurrentFunction = &f.fDeclaration; if (f.fDeclaration.fName == "main") { fFunctionHeader = ""; OutputStream* oldOut = fOut; diff --git a/src/sksl/SkSLPipelineStageCodeGenerator.h b/src/sksl/SkSLPipelineStageCodeGenerator.h index 9de7a4ab14..7357b30c9c 100644 --- a/src/sksl/SkSLPipelineStageCodeGenerator.h +++ b/src/sksl/SkSLPipelineStageCodeGenerator.h @@ -58,6 +58,7 @@ private: String fExtraEmitCodeCode; std::set fWrittenTransformedCoords; std::vector* fFormatArgs; + const FunctionDeclaration* fCurrentFunction; typedef GLSLCodeGenerator INHERITED; }; diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp index e05327adb8..c68859424e 100644 --- a/src/sksl/SkSLSPIRVCodeGenerator.cpp +++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp @@ -2954,23 +2954,16 @@ void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& } void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) { - // We believe the while loop code below will work, but Skia doesn't actually use them and - // adequately testing this code in the absence of Skia exercising it isn't straightforward. For - // the time being, we just fail with an error due to the lack of testing. If you encounter this - // message, simply remove the error call below to see whether our while loop support actually - // works. - fErrors.error(w.fOffset, "internal error: while loop support has been disabled in SPIR-V, " - "see SkSLSPIRVCodeGenerator.cpp for details"); - SpvId header = this->nextId(); SpvId start = this->nextId(); SpvId body = this->nextId(); - fContinueTarget.push(start); + SpvId continueTarget = this->nextId(); + fContinueTarget.push(continueTarget); SpvId end = this->nextId(); fBreakTarget.push(end); this->writeInstruction(SpvOpBranch, header, out); this->writeLabel(header, out); - this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out); + this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out); this->writeInstruction(SpvOpBranch, start, out); this->writeLabel(start, out); SpvId test = this->writeExpression(*w.fTest, out); @@ -2978,8 +2971,10 @@ void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStre this->writeLabel(body, out); this->writeStatement(*w.fStatement, out); if (fCurrentBlock) { - this->writeInstruction(SpvOpBranch, start, out); + this->writeInstruction(SpvOpBranch, continueTarget, out); } + this->writeLabel(continueTarget, out); + this->writeInstruction(SpvOpBranch, header, out); this->writeLabel(end, out); fBreakTarget.pop(); fContinueTarget.pop(); @@ -2997,12 +2992,13 @@ void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& ou SpvId header = this->nextId(); SpvId start = this->nextId(); SpvId next = this->nextId(); - fContinueTarget.push(next); + SpvId continueTarget = this->nextId(); + fContinueTarget.push(continueTarget); SpvId end = this->nextId(); fBreakTarget.push(end); this->writeInstruction(SpvOpBranch, header, out); this->writeLabel(header, out); - this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out); + this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out); this->writeInstruction(SpvOpBranch, start, out); this->writeLabel(start, out); this->writeStatement(*d.fStatement, out); @@ -3011,7 +3007,9 @@ void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& ou } this->writeLabel(next, out); SpvId test = this->writeExpression(*d.fTest, out); - this->writeInstruction(SpvOpBranchConditional, test, start, end, out); + this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out); + this->writeLabel(continueTarget, out); + this->writeInstruction(SpvOpBranch, header, out); this->writeLabel(end, out); fBreakTarget.pop(); fContinueTarget.pop(); diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h index a3c40934fe..887145503f 100644 --- a/src/sksl/ir/SkSLProgram.h +++ b/src/sksl/ir/SkSLProgram.h @@ -213,7 +213,8 @@ struct Program { kVertex_Kind, kGeometry_Kind, kFragmentProcessor_Kind, - kPipelineStage_Kind + kPipelineStage_Kind, + kMixer_Kind }; Program(Kind kind, diff --git a/src/sksl/sksl_mixer.inc b/src/sksl/sksl_mixer.inc new file mode 100644 index 0000000000..88143d41b2 --- /dev/null +++ b/src/sksl/sksl_mixer.inc @@ -0,0 +1,8 @@ +STRINGIFY( +in fragmentProcessor _child1; +in fragmentProcessor _child2; + +layout(builtin=10004) out half4 sk_OutColor; + +half4 process(fragmentProcessor fp); +)