From 71903997254fae5c2aea09da631d9ccabd3722d8 Mon Sep 17 00:00:00 2001 From: Brian Osman Date: Tue, 12 May 2020 13:40:01 -0400 Subject: [PATCH] SkRuntimeEffect: Support late bound uniforms in raster Supports marked matrices and srgb_unpremul colors Change-Id: Icabd329758ac0a12ee323d73724d68c7927106c3 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/289242 Commit-Queue: Brian Osman Reviewed-by: Mike Klein --- src/core/SkColorSpaceXformSteps.cpp | 4 +- src/core/SkColorSpaceXformSteps.h | 4 +- src/core/SkRasterPipeline.h | 11 ++-- src/core/SkRuntimeEffect.cpp | 79 ++++++++++++++++++----------- src/opts/SkRasterPipeline_opts.h | 5 +- 5 files changed, 64 insertions(+), 39 deletions(-) diff --git a/src/core/SkColorSpaceXformSteps.cpp b/src/core/SkColorSpaceXformSteps.cpp index 9523065acc..133d661f4d 100644 --- a/src/core/SkColorSpaceXformSteps.cpp +++ b/src/core/SkColorSpaceXformSteps.cpp @@ -13,8 +13,8 @@ // See skia.org/user/color (== site/user/color.md). -SkColorSpaceXformSteps::SkColorSpaceXformSteps(SkColorSpace* src, SkAlphaType srcAT, - SkColorSpace* dst, SkAlphaType dstAT) { +SkColorSpaceXformSteps::SkColorSpaceXformSteps(const SkColorSpace* src, SkAlphaType srcAT, + const SkColorSpace* dst, SkAlphaType dstAT) { // Opaque outputs are treated as the same alpha type as the source input. // TODO: we'd really like to have a good way of explaining why we think this is useful. if (dstAT == kOpaque_SkAlphaType) { diff --git a/src/core/SkColorSpaceXformSteps.h b/src/core/SkColorSpaceXformSteps.h index c3db584c8d..7d15259e30 100644 --- a/src/core/SkColorSpaceXformSteps.h +++ b/src/core/SkColorSpaceXformSteps.h @@ -33,8 +33,8 @@ struct SkColorSpaceXformSteps { } }; - SkColorSpaceXformSteps(SkColorSpace* src, SkAlphaType srcAT, - SkColorSpace* dst, SkAlphaType dstAT); + SkColorSpaceXformSteps(const SkColorSpace* src, SkAlphaType srcAT, + const SkColorSpace* dst, SkAlphaType dstAT); template SkColorSpaceXformSteps(const S& src, const D& dst) diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h index cf6ac4779f..316e884629 100644 --- a/src/core/SkRasterPipeline.h +++ b/src/core/SkRasterPipeline.h @@ -11,6 +11,7 @@ #include "include/core/SkColor.h" #include "include/core/SkImageInfo.h" #include "include/core/SkMatrix.h" +#include "include/core/SkRefCnt.h" #include "include/core/SkTileMode.h" #include "include/core/SkTypes.h" #include "include/private/SkNx.h" @@ -19,6 +20,8 @@ #include #include // TODO: unused +class SkData; + /** * SkRasterPipeline provides a cheap way to chain together a pixel processing pipeline. * @@ -169,10 +172,10 @@ struct SkRasterPipeline_InterpreterCtx { const SkSL::ByteCode* byteCode; const SkSL::ByteCodeFunction* fn; - SkColor4f paintColor; - const void* inputs; - int ninputs; - bool shaderConvention; // if false, we're a colorfilter + SkColor4f paintColor; + sk_sp inputs; + int ninputs; + bool shaderConvention; // if false, we're a colorfilter }; struct SkRasterPipeline_GradientCtx { diff --git a/src/core/SkRuntimeEffect.cpp b/src/core/SkRuntimeEffect.cpp index a447405074..ac5652bec4 100644 --- a/src/core/SkRuntimeEffect.cpp +++ b/src/core/SkRuntimeEffect.cpp @@ -11,6 +11,8 @@ #include "include/private/SkChecksum.h" #include "include/private/SkMutex.h" #include "src/core/SkCanvasPriv.h" +#include "src/core/SkColorSpacePriv.h" +#include "src/core/SkColorSpaceXformSteps.h" #include "src/core/SkMatrixProvider.h" #include "src/core/SkRasterPipeline.h" #include "src/core/SkReadBuffer.h" @@ -685,7 +687,7 @@ public: bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override { auto ctx = rec.fAlloc->make(); // don't need to set ctx->paintColor - ctx->inputs = fInputs->data(); + ctx->inputs = fInputs; ctx->ninputs = fEffect->uniformSize() / 4; ctx->shaderConvention = false; @@ -792,31 +794,27 @@ public: bool isOpaque() const override { return fIsOpaque; } -#if SK_SUPPORT_GPU - std::unique_ptr asFragmentProcessor(const GrFPArgs& args) const override { - SkMatrix matrix; - if (!this->totalLocalMatrix(args.fPreLocalMatrix)->invert(&matrix)) { - return nullptr; - } - // If any of our uniforms are late-bound (eg, layout(marker)), we need to clone the blob - sk_sp inputs = fInputs; - auto copyOnWrite = [&]() { - if (inputs == fInputs) { - inputs = SkData::MakeWithCopy(fInputs->data(), fInputs->size()); - } - }; - + sk_sp getUniforms(const SkMatrixProvider& matrixProvider, + const SkColorSpace* dstCS) const { using Flags = SkRuntimeEffect::Variable::Flags; using Type = SkRuntimeEffect::Variable::Type; + SkColorSpaceXformSteps steps(sk_srgb_singleton(), kUnpremul_SkAlphaType, + dstCS, kUnpremul_SkAlphaType); + + sk_sp inputs = nullptr; + auto writableData = [&]() { + if (!inputs) { + inputs = SkData::MakeWithCopy(fInputs->data(), fInputs->size()); + } + return inputs->writable_data(); + }; + for (const auto& v : fEffect->inputs()) { if (v.fFlags & Flags::kMarker_Flag) { - copyOnWrite(); - SkASSERT(v.fType == Type::kFloat4x4); - SkM44* localToMarker = SkTAddOffset(inputs->writable_data(), v.fOffset); - if (!args.fMatrixProvider.getLocalToMarker(v.fMarker, localToMarker)) { + SkM44* localToMarker = SkTAddOffset(writableData(), v.fOffset); + if (!matrixProvider.getLocalToMarker(v.fMarker, localToMarker)) { // We couldn't provide a matrix that was requested by the SkSL - SkDebugf("Failed to get marked matrix %u\n", v.fMarker); return nullptr; } if (v.fFlags & Flags::kMarkerNormals_Flag) { @@ -831,11 +829,8 @@ public: } } else if (v.fFlags & Flags::kSRGBUnpremul_Flag) { SkASSERT(v.fType == Type::kFloat3 || v.fType == Type::kFloat4); - if (auto xform = args.fDstColorInfo->colorSpaceXformFromSRGB()) { - copyOnWrite(); - - const SkColorSpaceXformSteps& steps(xform->steps()); - float* color = SkTAddOffset(inputs->writable_data(), v.fOffset); + if (steps.flags.mask()) { + float* color = SkTAddOffset(writableData(), v.fOffset); if (v.fType == Type::kFloat4) { // RGBA, easy case for (int i = 0; i < v.fCount; ++i) { @@ -858,6 +853,21 @@ public: } } } + return inputs ? inputs : fInputs; + } + +#if SK_SUPPORT_GPU + std::unique_ptr asFragmentProcessor(const GrFPArgs& args) const override { + SkMatrix matrix; + if (!this->totalLocalMatrix(args.fPreLocalMatrix)->invert(&matrix)) { + return nullptr; + } + + sk_sp inputs = + this->getUniforms(args.fMatrixProvider, args.fDstColorInfo->colorSpace()); + if (!inputs) { + return nullptr; + } auto fp = GrSkSLFP::Make(args.fContext, fEffect, "runtime_shader", std::move(inputs)); for (const auto& child : fChildren) { @@ -894,7 +904,6 @@ public: } bool onAppendStages(const SkStageRec& rec) const override { - // TODO: Populate dynamic uniforms! SkMatrix inverse; if (!this->computeTotalInverse(rec.fMatrixProvider.localToDevice(), rec.fLocalM, &inverse)) { @@ -903,7 +912,10 @@ public: auto ctx = rec.fAlloc->make(); ctx->paintColor = rec.fPaint.getColor4f(); - ctx->inputs = fInputs->data(); + ctx->inputs = this->getUniforms(rec.fMatrixProvider, rec.fDstCS); + if (!ctx->inputs) { + return false; + } ctx->ninputs = fEffect->uniformSize() / 4; ctx->shaderConvention = true; @@ -920,7 +932,7 @@ public: skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, const SkMatrix& ctm, const SkMatrix* localM, - SkFilterQuality, const SkColorInfo& /*dst*/, + SkFilterQuality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc*) const override { const SkSL::ByteCode* bc = this->byteCode(); if (!bc) { @@ -932,10 +944,19 @@ public: return {}; } + // TODO: Eventually, plumb SkMatrixProvider here (instead of just ctm). For now, we will + // simply fail if our effect requires any marked matrices (SkSimpleMatrixProvider always + // returns false in getLocalToMarker). + SkSimpleMatrixProvider matrixProvider(SkMatrix::I()); + sk_sp inputs = this->getUniforms(matrixProvider, dst.colorSpace()); + if (!inputs) { + return {}; + } + std::vector uniform; for (int i = 0; i < (int)fEffect->uniformSize() / 4; i++) { float f; - memcpy(&f, (const char*)fInputs->data() + 4*i, 4); + memcpy(&f, (const char*)inputs->data() + 4*i, 4); uniform.push_back(p->uniformF(uniforms->pushF(f))); } diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h index c2acf62f18..7e9558efc7 100644 --- a/src/opts/SkRasterPipeline_opts.h +++ b/src/opts/SkRasterPipeline_opts.h @@ -8,6 +8,7 @@ #ifndef SkRasterPipeline_opts_DEFINED #define SkRasterPipeline_opts_DEFINED +#include "include/core/SkData.h" #include "include/core/SkTypes.h" #include "src/core/SkUtils.h" // unaligned_{load,store} #include "src/sksl/SkSLByteCode.h" @@ -2737,8 +2738,8 @@ STAGE(interpreter, SkRasterPipeline_InterpreterCtx* c) { sk_unaligned_store(aa, a); } - SkAssertResult(c->byteCode->runStriped(c->fn, tail ? tail : N, in_args, in_count, - nullptr, 0, (const float*)c->inputs, c->ninputs)); + SkAssertResult(c->byteCode->runStriped(c->fn, tail ? tail : N, in_args, in_count, nullptr, 0, + (const float*)c->inputs->data(), c->ninputs)); r = sk_unaligned_load(rr); g = sk_unaligned_load(gg);