Remove Ganesh code from SkBlenderBase and SkBlendModeBlender
This copies SkRuntimeEffect::make_effect_fp into GrFragmentProcessors
and that copy should be removed when other parts of SkRuntimeEffect
are decoupled from Ganesh.
In order to move SkRuntimeBlender into its own header, I hoisted some
classes and functions to SkRuntimeEffectPriv. I also enforced IWYU
on SkRuntimeEffect.cpp and the newly added SkRuntimeBlender.cpp
Change-Id: I9da04a64ac4d31949532f7fc3f8010b1b58c94f3
Bug: skia:14317
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/701520
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Kevin Lubick <kjlubick@google.com>
diff --git a/gn/core.gni b/gn/core.gni
index 3c32537..5635497 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -502,6 +502,8 @@
"$_src/core/SkRegion_path.cpp",
"$_src/core/SkResourceCache.cpp",
"$_src/core/SkResourceCache.h",
+ "$_src/core/SkRuntimeBlender.cpp",
+ "$_src/core/SkRuntimeBlender.h",
"$_src/core/SkRuntimeEffect.cpp",
"$_src/core/SkRuntimeEffectPriv.h",
"$_src/core/SkSLTypeShared.cpp",
diff --git a/include/core/SkBlender.h b/include/core/SkBlender.h
index 7acba87..741c461 100644
--- a/include/core/SkBlender.h
+++ b/include/core/SkBlender.h
@@ -26,8 +26,6 @@
private:
SkBlender() = default;
friend class SkBlenderBase;
-
- using INHERITED = SkFlattenable;
};
#endif
diff --git a/include/effects/SkRuntimeEffect.h b/include/effects/SkRuntimeEffect.h
index 4d3450e..41918ed 100644
--- a/include/effects/SkRuntimeEffect.h
+++ b/include/effects/SkRuntimeEffect.h
@@ -8,11 +8,12 @@
#ifndef SkRuntimeEffect_DEFINED
#define SkRuntimeEffect_DEFINED
-#include "include/core/SkBlender.h"
-#include "include/core/SkColorFilter.h"
+#include "include/core/SkBlender.h" // IWYU pragma: keep
+#include "include/core/SkColorFilter.h" // IWYU pragma: keep
#include "include/core/SkData.h"
-#include "include/core/SkImageInfo.h"
+#include "include/core/SkFlattenable.h"
#include "include/core/SkMatrix.h"
+#include "include/core/SkRefCnt.h"
#include "include/core/SkShader.h"
#include "include/core/SkSpan.h"
#include "include/core/SkString.h"
@@ -20,34 +21,38 @@
#include "include/private/SkSLSampleUsage.h"
#include "include/private/base/SkOnce.h"
#include "include/private/base/SkTemplates.h"
+#include "include/private/base/SkTo.h"
+#include "include/private/base/SkTypeTraits.h"
-#include <string>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
#include <optional>
+#include <string>
+#include <string_view>
+#include <utility>
#include <vector>
#ifdef SK_ENABLE_SKSL
+#include "include/sksl/SkSLDebugTrace.h"
#include "include/sksl/SkSLVersion.h"
class GrRecordingContext;
class SkFilterColorProgram;
class SkImage;
-class SkRuntimeImageFilter;
+struct SkIPoint;
+struct SkImageInfo;
namespace SkSL {
-class DebugTrace;
class DebugTracePriv;
-class ErrorReporter;
class FunctionDefinition;
struct Program;
enum class ProgramKind : int8_t;
struct ProgramSettings;
} // namespace SkSL
-namespace skvm {
-class Program;
-}
-
namespace SkSL::RP {
class Program;
}
diff --git a/public.bzl b/public.bzl
index 5aff944..b9112ca 100644
--- a/public.bzl
+++ b/public.bzl
@@ -622,6 +622,8 @@
"src/core/SkRegion_path.cpp",
"src/core/SkResourceCache.cpp",
"src/core/SkResourceCache.h",
+ "src/core/SkRuntimeBlender.cpp",
+ "src/core/SkRuntimeBlender.h",
"src/core/SkRuntimeEffect.cpp",
"src/core/SkRuntimeEffectPriv.h",
"src/core/SkSLTypeShared.cpp",
diff --git a/src/BUILD.bazel b/src/BUILD.bazel
index 8934c33..4ead2a0 100644
--- a/src/BUILD.bazel
+++ b/src/BUILD.bazel
@@ -162,6 +162,7 @@
"src/core/SkDrawProcs.h",
"src/core/SkMatrixPriv.h",
"src/core/SkPathPriv.h",
+ "src/core/SkRuntimeEffectPriv.h",
"src/encode/SkICCPriv.h",
"src/encode/SkImageEncoderFns.h",
"src/encode/SkImageEncoderPriv.h",
diff --git a/src/core/BUILD.bazel b/src/core/BUILD.bazel
index 30667fb..7b99be0 100644
--- a/src/core/BUILD.bazel
+++ b/src/core/BUILD.bazel
@@ -368,6 +368,8 @@
"SkFilterColorProgram.cpp",
"SkFilterColorProgram.h",
"SkRuntimeEffect.cpp",
+ "SkRuntimeBlender.cpp",
+ "SkRuntimeBlender.h",
"SkSLTypeShared.cpp",
"SkSLTypeShared.h",
]
diff --git a/src/core/SkBlendModeBlender.cpp b/src/core/SkBlendModeBlender.cpp
index bb561cc..cd290b4 100644
--- a/src/core/SkBlendModeBlender.cpp
+++ b/src/core/SkBlendModeBlender.cpp
@@ -17,19 +17,11 @@
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
-#if defined(SK_GANESH)
-#include "src/gpu/ganesh/GrFragmentProcessor.h"
-#include "src/gpu/ganesh/effects/GrBlendFragmentProcessor.h"
-struct GrFPArgs;
-#endif
-
#if defined(SK_GRAPHITE)
#include "src/gpu/graphite/KeyHelpers.h"
#include "src/gpu/graphite/PaintParamsKey.h"
#endif
-#include <utility>
-
sk_sp<SkBlender> SkBlender::Mode(SkBlendMode mode) {
#define RETURN_SINGLETON_BLENDER(m) \
case m: { \
@@ -103,15 +95,6 @@
buffer.writeInt((int)fMode);
}
-#if defined(SK_GANESH)
-std::unique_ptr<GrFragmentProcessor> SkBlendModeBlender::asFragmentProcessor(
- std::unique_ptr<GrFragmentProcessor> srcFP,
- std::unique_ptr<GrFragmentProcessor> dstFP,
- const GrFPArgs& fpArgs) const {
- return GrBlendFragmentProcessor::Make(std::move(srcFP), std::move(dstFP), fMode);
-}
-#endif
-
bool SkBlendModeBlender::onAppendStages(const SkStageRec& rec) const {
SkBlendMode_AppendStages(fMode, rec.fPipeline);
return true;
diff --git a/src/core/SkBlendModeBlender.h b/src/core/SkBlendModeBlender.h
index 5a64da6..0c4c07d 100644
--- a/src/core/SkBlendModeBlender.h
+++ b/src/core/SkBlendModeBlender.h
@@ -11,20 +11,20 @@
#include "include/core/SkFlattenable.h"
#include "src/core/SkBlenderBase.h"
-#include <memory>
#include <optional>
-class GrFragmentProcessor;
class SkReadBuffer;
class SkWriteBuffer;
enum class SkBlendMode;
-struct GrFPArgs;
struct SkStageRec;
class SkBlendModeBlender : public SkBlenderBase {
public:
SkBlendModeBlender(SkBlendMode mode) : fMode(mode) {}
+ BlenderType type() const override { return BlenderType::kBlendMode; }
+ SkBlendMode mode() const { return fMode; }
+
SK_FLATTENABLE_HOOKS(SkBlendModeBlender)
private:
@@ -32,13 +32,6 @@
std::optional<SkBlendMode> asBlendMode() const final { return fMode; }
-#if defined(SK_GANESH)
- std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
- std::unique_ptr<GrFragmentProcessor> srcFP,
- std::unique_ptr<GrFragmentProcessor> dstFP,
- const GrFPArgs& fpArgs) const override;
-#endif
-
#if defined(SK_GRAPHITE)
void addToKey(const skgpu::graphite::KeyContext&,
skgpu::graphite::PaintParamsKeyBuilder*,
diff --git a/src/core/SkBlenderBase.h b/src/core/SkBlenderBase.h
index 76e7582..05844c9 100644
--- a/src/core/SkBlenderBase.h
+++ b/src/core/SkBlenderBase.h
@@ -28,6 +28,10 @@
class PipelineDataGatherer;
}
+#define SK_ALL_BLENDERS(M) \
+ M(BlendMode) \
+ M(Runtime)
+
/**
* Encapsulates a blend function, including non-public APIs.
* Blends combine a source color (the result of our paint) and destination color (from the canvas)
@@ -58,17 +62,6 @@
}
#endif
-#if defined(SK_GANESH)
- /**
- * Returns a GrFragmentProcessor that implements this blend for the GPU backend.
- * The GrFragmentProcessor expects premultiplied inputs and returns a premultiplied output.
- */
- virtual std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
- std::unique_ptr<GrFragmentProcessor> srcFP,
- std::unique_ptr<GrFragmentProcessor> dstFP,
- const GrFPArgs& fpArgs) const = 0;
-#endif
-
virtual SkRuntimeEffect* asRuntimeEffect() const { return nullptr; }
#if defined(SK_GRAPHITE)
@@ -78,7 +71,15 @@
#endif
static SkFlattenable::Type GetFlattenableType() { return kSkBlender_Type; }
- Type getFlattenableType() const override { return GetFlattenableType(); }
+ SkFlattenable::Type getFlattenableType() const override { return GetFlattenableType(); }
+
+ enum class BlenderType {
+ #define M(type) k ## type,
+ SK_ALL_BLENDERS(M)
+ #undef M
+ };
+
+ virtual BlenderType type() const = 0;
private:
#if defined(SK_ENABLE_SKVM)
@@ -86,8 +87,6 @@
const SkColorInfo& colorInfo, skvm::Uniforms* uniforms,
SkArenaAlloc* alloc) const = 0;
#endif
-
- using INHERITED = SkFlattenable;
};
inline SkBlenderBase* as_BB(SkBlender* blend) {
diff --git a/src/core/SkRuntimeBlender.cpp b/src/core/SkRuntimeBlender.cpp
new file mode 100644
index 0000000..e2a3912
--- /dev/null
+++ b/src/core/SkRuntimeBlender.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "src/core/SkRuntimeBlender.h"
+
+#include "include/core/SkCapabilities.h"
+#include "include/core/SkData.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkString.h"
+#include "include/effects/SkRuntimeEffect.h"
+#include "include/private/SkSLSampleUsage.h"
+#include "include/private/base/SkTArray.h"
+#include "src/core/SkEffectPriv.h"
+#include "src/core/SkReadBuffer.h"
+#include "src/core/SkRuntimeEffectPriv.h"
+#include "src/core/SkWriteBuffer.h"
+#include "src/shaders/SkShaderBase.h"
+#include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
+
+#if defined(SK_GRAPHITE)
+#include "src/gpu/graphite/KeyContext.h"
+#include "src/gpu/graphite/KeyHelpers.h"
+#include "src/gpu/graphite/PaintParamsKey.h"
+#endif
+
+#include <string>
+
+using namespace skia_private;
+
+#if defined(SK_BUILD_FOR_DEBUGGER)
+ #define SK_LENIENT_SKSL_DESERIALIZATION 1
+#else
+ #define SK_LENIENT_SKSL_DESERIALIZATION 0
+#endif
+
+sk_sp<SkFlattenable> SkRuntimeBlender::CreateProc(SkReadBuffer& buffer) {
+ if (!buffer.validate(buffer.allowSkSL())) {
+ return nullptr;
+ }
+
+ SkString sksl;
+ buffer.readString(&sksl);
+ sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
+
+ auto effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForBlender, std::move(sksl));
+#if !SK_LENIENT_SKSL_DESERIALIZATION
+ if (!buffer.validate(effect != nullptr)) {
+ return nullptr;
+ }
+#endif
+
+ STArray<4, SkRuntimeEffect::ChildPtr> children;
+ if (!SkRuntimeEffectPriv::ReadChildEffects(buffer, effect.get(), &children)) {
+ return nullptr;
+ }
+
+#if SK_LENIENT_SKSL_DESERIALIZATION
+ if (!effect) {
+ SkDebugf("Serialized SkSL failed to compile. Ignoring/dropping SkSL blender.\n");
+ return nullptr;
+ }
+#endif
+
+ return effect->makeBlender(std::move(uniforms), SkSpan(children));
+}
+
+bool SkRuntimeBlender::onAppendStages(const SkStageRec& rec) const {
+#ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
+ if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
+ // SkRP has support for many parts of #version 300 already, but for now, we restrict its
+ // usage in runtime effects to just #version 100.
+ return false;
+ }
+ if (const SkSL::RP::Program* program = fEffect->getRPProgram(/*debugTrace=*/nullptr)) {
+ SkSpan<const float> uniforms = SkRuntimeEffectPriv::UniformsAsSpan(
+ fEffect->uniforms(),
+ fUniforms,
+ /*alwaysCopyIntoAlloc=*/false,
+ rec.fDstCS,
+ rec.fAlloc);
+ SkShaderBase::MatrixRec matrix(SkMatrix::I());
+ matrix.markCTMApplied();
+ RuntimeEffectRPCallbacks callbacks(rec, matrix, fChildren, fEffect->fSampleUsages);
+ bool success = program->appendStages(rec.fPipeline, rec.fAlloc, &callbacks, uniforms);
+ return success;
+ }
+#endif
+ return false;
+}
+
+void SkRuntimeBlender::flatten(SkWriteBuffer& buffer) const {
+ buffer.writeString(fEffect->source().c_str());
+ buffer.writeDataAsByteArray(fUniforms.get());
+ SkRuntimeEffectPriv::WriteChildEffects(buffer, fChildren);
+}
+
+#ifdef SK_ENABLE_SKVM
+skvm::Color SkRuntimeBlender::onProgram(skvm::Builder* p, skvm::Color src, skvm::Color dst,
+ const SkColorInfo& colorInfo, skvm::Uniforms* uniforms,
+ SkArenaAlloc* alloc) const {
+ if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
+ return {};
+ }
+
+ sk_sp<const SkData> inputs = SkRuntimeEffectPriv::TransformUniforms(fEffect->uniforms(),
+ fUniforms,
+ colorInfo.colorSpace());
+ SkASSERT(inputs);
+
+ SkShaderBase::MatrixRec mRec(SkMatrix::I());
+ mRec.markTotalMatrixInvalid();
+ RuntimeEffectVMCallbacks callbacks(p, uniforms, alloc, fChildren, mRec, src, colorInfo);
+ std::vector<skvm::Val> uniform = SkRuntimeEffectPriv::MakeSkVMUniforms(p,
+ uniforms,
+ fEffect->uniformSize(),
+ *inputs);
+
+ // Emit the blend function as an SkVM program.
+ skvm::Coord zeroCoord = {p->splat(0.0f), p->splat(0.0f)};
+ return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p,/*debugTrace=*/nullptr,
+ SkSpan(uniform), /*device=*/zeroCoord, /*local=*/zeroCoord,
+ src, dst, &callbacks);
+}
+#endif
+
+#if defined(SK_GRAPHITE)
+void SkRuntimeBlender::addToKey(const skgpu::graphite::KeyContext& keyContext,
+ skgpu::graphite::PaintParamsKeyBuilder* builder,
+ skgpu::graphite::PipelineDataGatherer* gatherer) const {
+ using namespace skgpu::graphite;
+
+ sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
+ fEffect->uniforms(),
+ fUniforms,
+ keyContext.dstColorInfo().colorSpace());
+ SkASSERT(uniforms);
+
+ RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
+ { fEffect, std::move(uniforms) });
+
+ SkRuntimeEffectPriv::AddChildrenToKey(fChildren, fEffect->children(), keyContext, builder,
+ gatherer);
+
+ builder->endBlock();
+}
+#endif
diff --git a/src/core/SkRuntimeBlender.h b/src/core/SkRuntimeBlender.h
new file mode 100644
index 0000000..b060437
--- /dev/null
+++ b/src/core/SkRuntimeBlender.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkRuntimeBlender_DEFINED
+#define SkRuntimeBlender_DEFINED
+
+#include "include/core/SkData.h"
+#include "include/core/SkFlattenable.h"
+#include "include/core/SkRefCnt.h"
+#include "include/effects/SkRuntimeEffect.h"
+#include "include/private/base/SkSpan_impl.h"
+#include "src/core/SkBlenderBase.h"
+
+#include <utility>
+#include <vector>
+
+class SkReadBuffer;
+class SkWriteBuffer;
+struct SkStageRec;
+
+class SkRuntimeBlender : public SkBlenderBase {
+public:
+ SkRuntimeBlender(sk_sp<SkRuntimeEffect> effect,
+ sk_sp<const SkData> uniforms,
+ SkSpan<SkRuntimeEffect::ChildPtr> children)
+ : fEffect(std::move(effect))
+ , fUniforms(std::move(uniforms))
+ , fChildren(children.begin(), children.end()) {}
+
+ SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
+
+ BlenderType type() const override { return BlenderType::kRuntime; }
+
+ bool onAppendStages(const SkStageRec& rec) const override;
+
+#ifdef SK_ENABLE_SKVM
+ skvm::Color onProgram(skvm::Builder* p, skvm::Color src, skvm::Color dst,
+ const SkColorInfo& colorInfo, skvm::Uniforms* uniforms,
+ SkArenaAlloc* alloc) const override;
+#endif
+
+#if defined(SK_GRAPHITE)
+ void addToKey(const skgpu::graphite::KeyContext& keyContext,
+ skgpu::graphite::PaintParamsKeyBuilder* builder,
+ skgpu::graphite::PipelineDataGatherer* gatherer) const override;
+#endif
+
+ void flatten(SkWriteBuffer& buffer) const override;
+
+ SK_FLATTENABLE_HOOKS(SkRuntimeBlender)
+
+ sk_sp<SkRuntimeEffect> effect() const { return fEffect; }
+ sk_sp<const SkData> uniforms() const { return fUniforms; }
+ std::vector<SkRuntimeEffect::ChildPtr> children() const { return fChildren; }
+private:
+ sk_sp<SkRuntimeEffect> fEffect;
+ sk_sp<const SkData> fUniforms;
+ std::vector<SkRuntimeEffect::ChildPtr> fChildren;
+};
+
+#endif
diff --git a/src/core/SkRuntimeEffect.cpp b/src/core/SkRuntimeEffect.cpp
index 0655dd8..a2d3946 100644
--- a/src/core/SkRuntimeEffect.cpp
+++ b/src/core/SkRuntimeEffect.cpp
@@ -7,55 +7,82 @@
#include "include/effects/SkRuntimeEffect.h"
+#include "include/core/SkAlphaType.h"
+#include "include/core/SkBlendMode.h"
+#include "include/core/SkBlender.h"
+#include "include/core/SkCanvas.h"
#include "include/core/SkCapabilities.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkData.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkImageInfo.h"
+#include "include/core/SkPaint.h"
#include "include/core/SkSurface.h"
+#include "include/private/SkColorData.h"
+#include "include/private/base/SkAlign.h"
+#include "include/private/base/SkDebug.h"
#include "include/private/base/SkMutex.h"
#include "include/private/base/SkOnce.h"
+#include "include/private/base/SkTArray.h"
+#include "src/base/SkArenaAlloc.h"
#include "src/base/SkNoDestructor.h"
-#include "src/base/SkUtils.h"
+#include "src/base/SkTLazy.h"
#include "src/core/SkBlenderBase.h"
-#include "src/core/SkCanvasPriv.h"
#include "src/core/SkChecksum.h"
#include "src/core/SkColorFilterBase.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkColorSpaceXformSteps.h"
+#include "src/core/SkEffectPriv.h"
#include "src/core/SkFilterColorProgram.h"
#include "src/core/SkLRUCache.h"
-#include "src/core/SkMatrixProvider.h"
+#include "src/core/SkPicturePriv.h"
#include "src/core/SkRasterPipeline.h"
+#include "src/core/SkRasterPipelineOpList.h"
#include "src/core/SkReadBuffer.h"
+#include "src/core/SkRuntimeBlender.h"
#include "src/core/SkRuntimeEffectPriv.h"
-#include "src/core/SkVM.h"
+#include "src/core/SkStreamPriv.h"
#include "src/core/SkWriteBuffer.h"
#include "src/shaders/SkLocalMatrixShader.h"
+#include "src/shaders/SkShaderBase.h"
#include "src/sksl/SkSLAnalysis.h"
#include "src/sksl/SkSLBuiltinTypes.h"
#include "src/sksl/SkSLCompiler.h"
+#include "src/sksl/SkSLContext.h"
+#include "src/sksl/SkSLProgramKind.h"
#include "src/sksl/SkSLProgramSettings.h"
#include "src/sksl/SkSLUtil.h"
#include "src/sksl/analysis/SkSLProgramUsage.h"
#include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
-#include "src/sksl/codegen/SkSLVMCodeGenerator.h"
-#include "src/sksl/ir/SkSLFunctionDefinition.h"
+#include "src/sksl/ir/SkSLFunctionDeclaration.h"
+#include "src/sksl/ir/SkSLLayout.h"
+#include "src/sksl/ir/SkSLModifiers.h"
#include "src/sksl/ir/SkSLProgram.h"
+#include "src/sksl/ir/SkSLProgramElement.h"
+#include "src/sksl/ir/SkSLStatement.h"
+#include "src/sksl/ir/SkSLType.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
+#include "src/sksl/ir/SkSLVariable.h"
#include "src/sksl/tracing/SkSLDebugTracePriv.h"
+#include <algorithm>
+#include <tuple>
+
+class SkColorSpace;
+class SkSurfaceProps;
+struct SkIPoint;
+
#if defined(SK_GANESH)
+#include "include/gpu/GpuTypes.h"
#include "include/gpu/GrRecordingContext.h"
+#include "include/gpu/GrTypes.h"
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
-#include "src/gpu/SkBackingFit.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrColorInfo.h"
#include "src/gpu/ganesh/GrFPArgs.h"
-#include "src/gpu/ganesh/GrImageInfo.h"
+#include "src/gpu/ganesh/GrFragmentProcessor.h"
+#include "src/gpu/ganesh/GrFragmentProcessors.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
-#include "src/gpu/ganesh/SurfaceFillContext.h"
-#include "src/gpu/ganesh/effects/GrMatrixEffect.h"
-#include "src/gpu/ganesh/effects/GrSkSLFP.h"
-#include "src/gpu/ganesh/image/SkImage_Ganesh.h"
#endif
#if defined(SK_GRAPHITE)
@@ -66,13 +93,11 @@
// Set `skia_enable_sksl_in_raster_pipeline = true` in your GN args to use Raster Pipeline SkSL.
#ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
-#include "src/core/SkStreamPriv.h"
#include "src/sksl/codegen/SkSLRasterPipelineCodeGenerator.h"
+
constexpr bool kRPEnableLiveTrace = false;
#endif
-#include <algorithm>
-
using namespace skia_private;
#if defined(SK_BUILD_FOR_DEBUGGER)
@@ -237,7 +262,7 @@
return fRPProgram.get();
}
-[[maybe_unused]] static SkSpan<const float> uniforms_as_span(
+SkSpan<const float> SkRuntimeEffectPriv::UniformsAsSpan(
SkSpan<const SkRuntimeEffect::Uniform> uniforms,
sk_sp<const SkData> originalData,
bool alwaysCopyIntoAlloc,
@@ -262,87 +287,73 @@
}
#ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
-class RuntimeEffectRPCallbacks : public SkSL::RP::Callbacks {
-public:
- RuntimeEffectRPCallbacks(const SkStageRec& s,
- const SkShaderBase::MatrixRec& m,
- SkSpan<const SkRuntimeEffect::ChildPtr> c,
- SkSpan<const SkSL::SampleUsage> u)
- : fStage(s), fMatrix(m), fChildren(c), fSampleUsages(u) {}
+bool RuntimeEffectRPCallbacks::appendShader(int index) {
+ if (SkShader* shader = fChildren[index].shader()) {
+ if (fSampleUsages[index].isPassThrough()) {
+ // Given a passthrough sample, the total-matrix is still as valid as before.
+ return as_SB(shader)->appendStages(fStage, fMatrix);
+ }
+ // For a non-passthrough sample, we need to explicitly mark the total-matrix as invalid.
+ SkShaderBase::MatrixRec nonPassthroughMatrix = fMatrix;
+ nonPassthroughMatrix.markTotalMatrixInvalid();
+ return as_SB(shader)->appendStages(fStage, nonPassthroughMatrix);
+ }
+ // Return the paint color when a null child shader is evaluated.
+ fStage.fPipeline->append_constant_color(fStage.fAlloc, fStage.fPaintColor);
+ return true;
+}
+bool RuntimeEffectRPCallbacks::appendColorFilter(int index) {
+ if (SkColorFilter* colorFilter = fChildren[index].colorFilter()) {
+ return as_CFB(colorFilter)->appendStages(fStage, /*shaderIsOpaque=*/false);
+ }
+ // Return the original color as-is when a null child color filter is evaluated.
+ return true;
+}
+bool RuntimeEffectRPCallbacks::appendBlender(int index) {
+ if (SkBlender* blender = fChildren[index].blender()) {
+ return as_BB(blender)->appendStages(fStage);
+ }
+ // Return a source-over blend when a null blender is evaluated.
+ fStage.fPipeline->append(SkRasterPipelineOp::srcover);
+ return true;
+}
- bool appendShader(int index) override {
- if (SkShader* shader = fChildren[index].shader()) {
- if (fSampleUsages[index].isPassThrough()) {
- // Given a passthrough sample, the total-matrix is still as valid as before.
- return as_SB(shader)->appendStages(fStage, fMatrix);
- }
- // For a non-passthrough sample, we need to explicitly mark the total-matrix as invalid.
- SkShaderBase::MatrixRec nonPassthroughMatrix = fMatrix;
- nonPassthroughMatrix.markTotalMatrixInvalid();
- return as_SB(shader)->appendStages(fStage, nonPassthroughMatrix);
- }
- // Return the paint color when a null child shader is evaluated.
- fStage.fPipeline->append_constant_color(fStage.fAlloc, fStage.fPaintColor);
- return true;
- }
- bool appendColorFilter(int index) override {
- if (SkColorFilter* colorFilter = fChildren[index].colorFilter()) {
- return as_CFB(colorFilter)->appendStages(fStage, /*shaderIsOpaque=*/false);
- }
- // Return the original color as-is when a null child color filter is evaluated.
- return true;
- }
- bool appendBlender(int index) override {
- if (SkBlender* blender = fChildren[index].blender()) {
- return as_BB(blender)->appendStages(fStage);
- }
- // Return a source-over blend when a null blender is evaluated.
- fStage.fPipeline->append(SkRasterPipelineOp::srcover);
- return true;
- }
-
- // TODO: If an effect calls these intrinsics more than once, we could cache and re-use the steps
- // object(s), rather than re-creating them in the arena repeatedly.
- void toLinearSrgb(const void* color) override {
- if (fStage.fDstCS) {
- SkColorSpaceXformSteps xform{fStage.fDstCS, kUnpremul_SkAlphaType,
- sk_srgb_linear_singleton(), kUnpremul_SkAlphaType};
- if (xform.flags.mask()) {
- // We have a non-identity colorspace transform; apply it.
- this->applyColorSpaceXform(xform, color);
- }
+// TODO: If an effect calls these intrinsics more than once, we could cache and re-use the steps
+// object(s), rather than re-creating them in the arena repeatedly.
+void RuntimeEffectRPCallbacks::toLinearSrgb(const void* color) {
+ if (fStage.fDstCS) {
+ SkColorSpaceXformSteps xform{fStage.fDstCS, kUnpremul_SkAlphaType,
+ sk_srgb_linear_singleton(), kUnpremul_SkAlphaType};
+ if (xform.flags.mask()) {
+ // We have a non-identity colorspace transform; apply it.
+ this->applyColorSpaceXform(xform, color);
}
}
+}
- void fromLinearSrgb(const void* color) override {
- if (fStage.fDstCS) {
- SkColorSpaceXformSteps xform{sk_srgb_linear_singleton(), kUnpremul_SkAlphaType,
- fStage.fDstCS, kUnpremul_SkAlphaType};
- if (xform.flags.mask()) {
- // We have a non-identity colorspace transform; apply it.
- this->applyColorSpaceXform(xform, color);
- }
+void RuntimeEffectRPCallbacks::fromLinearSrgb(const void* color) {
+ if (fStage.fDstCS) {
+ SkColorSpaceXformSteps xform{sk_srgb_linear_singleton(), kUnpremul_SkAlphaType,
+ fStage.fDstCS, kUnpremul_SkAlphaType};
+ if (xform.flags.mask()) {
+ // We have a non-identity colorspace transform; apply it.
+ this->applyColorSpaceXform(xform, color);
}
}
+}
-private:
- void applyColorSpaceXform(const SkColorSpaceXformSteps& tempXform, const void* color) {
- // Copy the transform steps into our alloc.
- SkColorSpaceXformSteps* xform = fStage.fAlloc->make<SkColorSpaceXformSteps>(tempXform);
+void RuntimeEffectRPCallbacks::applyColorSpaceXform(const SkColorSpaceXformSteps& tempXform,
+ const void* color) {
+ // Copy the transform steps into our alloc.
+ SkColorSpaceXformSteps* xform = fStage.fAlloc->make<SkColorSpaceXformSteps>(tempXform);
- // Put the color into src.rgba (and temporarily stash the execution mask there instead).
- fStage.fPipeline->append(SkRasterPipelineOp::exchange_src, color);
- // Add the color space transform to our raster pipeline.
- xform->apply(fStage.fPipeline);
- // Restore the execution mask, and move the color back into program data.
- fStage.fPipeline->append(SkRasterPipelineOp::exchange_src, color);
- }
-
- const SkStageRec& fStage;
- const SkShaderBase::MatrixRec& fMatrix;
- SkSpan<const SkRuntimeEffect::ChildPtr> fChildren;
- SkSpan<const SkSL::SampleUsage> fSampleUsages;
-};
+ // Put the color into src.rgba (and temporarily stash the execution mask there instead).
+ fStage.fPipeline->append(SkRasterPipelineOp::exchange_src, color);
+ // Add the color space transform to our raster pipeline.
+ xform->apply(fStage.fPipeline);
+ // Restore the execution mask, and move the color back into program data.
+ fStage.fPipeline->append(SkRasterPipelineOp::exchange_src, color);
+}
#endif // SK_ENABLE_SKSL_IN_RASTER_PIPELINE
bool SkRuntimeEffectPriv::CanDraw(const SkCapabilities* caps, const SkSL::Program* program) {
@@ -413,9 +424,9 @@
* children() of `effect`. If it's nullptr, this is skipped, allowing deserialization of children,
* even when the effect could not be constructed (ie, due to malformed SkSL).
*/
-static bool read_child_effects(SkReadBuffer& buffer,
- const SkRuntimeEffect* effect,
- TArray<SkRuntimeEffect::ChildPtr>* children) {
+bool SkRuntimeEffectPriv::ReadChildEffects(SkReadBuffer& buffer,
+ const SkRuntimeEffect* effect,
+ TArray<SkRuntimeEffect::ChildPtr>* children) {
size_t childCount = buffer.read32();
if (effect && !buffer.validate(childCount == effect->children().size())) {
return false;
@@ -448,19 +459,20 @@
return buffer.isValid();
}
-static void write_child_effects(SkWriteBuffer& buffer,
- const std::vector<SkRuntimeEffect::ChildPtr>& children) {
+void SkRuntimeEffectPriv::WriteChildEffects(
+ SkWriteBuffer& buffer, const std::vector<SkRuntimeEffect::ChildPtr>& children) {
buffer.write32(children.size());
for (const auto& child : children) {
buffer.writeFlattenable(child.flattenable());
}
}
+
#ifdef SK_ENABLE_SKVM
-static std::vector<skvm::Val> make_skvm_uniforms(skvm::Builder* p,
- skvm::Uniforms* uniforms,
- size_t inputSize,
- const SkData& inputs) {
+std::vector<skvm::Val> SkRuntimeEffectPriv::MakeSkVMUniforms(skvm::Builder* p,
+ skvm::Uniforms* uniforms,
+ size_t inputSize,
+ const SkData& inputs) {
SkASSERTF(!(inputSize & 3), "inputSize was %zu, expected a multiple of 4", inputSize);
const int32_t* data = reinterpret_cast<const int32_t*>(inputs.data());
@@ -797,11 +809,11 @@
};
static_assert(sizeof(Options) == sizeof(KnownOptions));
fHash = SkChecksum::Hash32(&options.forceUnoptimized,
- sizeof(options.forceUnoptimized), fHash);
+ sizeof(options.forceUnoptimized), fHash);
fHash = SkChecksum::Hash32(&options.allowPrivateAccess,
- sizeof(options.allowPrivateAccess), fHash);
+ sizeof(options.allowPrivateAccess), fHash);
fHash = SkChecksum::Hash32(&options.maxVersionAllowed,
- sizeof(options.maxVersionAllowed), fHash);
+ sizeof(options.maxVersionAllowed), fHash);
fFilterColorProgram = SkFilterColorProgram::Make(this);
}
@@ -837,70 +849,12 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
-#if defined(SK_GANESH)
-static GrFPResult make_effect_fp(sk_sp<SkRuntimeEffect> effect,
- const char* name,
- sk_sp<const SkData> uniforms,
- std::unique_ptr<GrFragmentProcessor> inputFP,
- std::unique_ptr<GrFragmentProcessor> destColorFP,
- SkSpan<const SkRuntimeEffect::ChildPtr> children,
- const GrFPArgs& childArgs) {
- STArray<8, std::unique_ptr<GrFragmentProcessor>> childFPs;
- for (const auto& child : children) {
- std::optional<ChildType> type = child.type();
- if (type == ChildType::kShader) {
- // Convert a SkShader into a child FP.
- SkShaderBase::MatrixRec mRec(SkMatrix::I());
- mRec.markTotalMatrixInvalid();
- auto childFP = as_SB(child.shader())->asFragmentProcessor(childArgs, mRec);
- if (!childFP) {
- return GrFPFailure(std::move(inputFP));
- }
- childFPs.push_back(std::move(childFP));
- } else if (type == ChildType::kColorFilter) {
- // Convert a SkColorFilter into a child FP.
- auto [success, childFP] = as_CFB(child.colorFilter())
- ->asFragmentProcessor(/*inputFP=*/nullptr,
- childArgs.fContext,
- *childArgs.fDstColorInfo,
- childArgs.fSurfaceProps);
- if (!success) {
- return GrFPFailure(std::move(inputFP));
- }
- childFPs.push_back(std::move(childFP));
- } else if (type == ChildType::kBlender) {
- // Convert a SkBlender into a child FP.
- auto childFP = as_BB(child.blender())->asFragmentProcessor(
- /*srcFP=*/nullptr,
- GrFragmentProcessor::DestColor(),
- childArgs);
- if (!childFP) {
- return GrFPFailure(std::move(inputFP));
- }
- childFPs.push_back(std::move(childFP));
- } else {
- // We have a null child effect.
- childFPs.push_back(nullptr);
- }
- }
- auto fp = GrSkSLFP::MakeWithData(std::move(effect),
- name,
- childArgs.fDstColorInfo->refColorSpace(),
- std::move(inputFP),
- std::move(destColorFP),
- std::move(uniforms),
- SkSpan(childFPs));
- SkASSERT(fp);
- return GrFPSuccess(std::move(fp));
-}
-#endif
-
#if defined(SK_GRAPHITE)
-static void add_children_to_key(SkSpan<const SkRuntimeEffect::ChildPtr> children,
- SkSpan<const SkRuntimeEffect::Child> childInfo,
- const skgpu::graphite::KeyContext& keyContext,
- skgpu::graphite::PaintParamsKeyBuilder* builder,
- skgpu::graphite::PipelineDataGatherer* gatherer) {
+void SkRuntimeEffectPriv::AddChildrenToKey(SkSpan<const SkRuntimeEffect::ChildPtr> children,
+ SkSpan<const SkRuntimeEffect::Child> childInfo,
+ const skgpu::graphite::KeyContext& keyContext,
+ skgpu::graphite::PaintParamsKeyBuilder* builder,
+ skgpu::graphite::PipelineDataGatherer* gatherer) {
using namespace skgpu::graphite;
SkASSERT(children.size() == childInfo.size());
@@ -937,85 +891,61 @@
#endif
#if defined(SK_ENABLE_SKVM)
-class RuntimeEffectVMCallbacks : public SkSL::SkVMCallbacks {
-public:
- RuntimeEffectVMCallbacks(skvm::Builder* builder,
- skvm::Uniforms* uniforms,
- SkArenaAlloc* alloc,
- const std::vector<SkRuntimeEffect::ChildPtr>& children,
- const SkShaderBase::MatrixRec& mRec,
- skvm::Color inColor,
- const SkColorInfo& colorInfo)
- : fBuilder(builder)
- , fUniforms(uniforms)
- , fAlloc(alloc)
- , fChildren(children)
- , fMRec(mRec)
- , fInColor(inColor)
- , fColorInfo(colorInfo) {}
- skvm::Color sampleShader(int ix, skvm::Coord coord) override {
- // We haven't tracked device coords and the runtime effect could have arbitrarily
- // manipulated the passed coords. We should be in a state where any pending matrix was
- // already applied before the runtime effect's code could have manipulated the coords
- // and the total matrix from child shader to device space is flagged as unknown.
- SkASSERT(!fMRec.hasPendingMatrix());
- SkASSERT(!fMRec.totalMatrixIsValid());
- if (SkShader* shader = fChildren[ix].shader()) {
- return as_SB(shader)->program(fBuilder,
- coord,
- coord,
- fInColor,
- fMRec,
- fColorInfo,
- fUniforms,
- fAlloc);
- }
- return fInColor;
+skvm::Color RuntimeEffectVMCallbacks::sampleShader(int ix, skvm::Coord coord) {
+ // We haven't tracked device coords and the runtime effect could have arbitrarily
+ // manipulated the passed coords. We should be in a state where any pending matrix was
+ // already applied before the runtime effect's code could have manipulated the coords
+ // and the total matrix from child shader to device space is flagged as unknown.
+ SkASSERT(!fMRec.hasPendingMatrix());
+ SkASSERT(!fMRec.totalMatrixIsValid());
+ if (SkShader* shader = fChildren[ix].shader()) {
+ return as_SB(shader)->program(fBuilder,
+ coord,
+ coord,
+ fInColor,
+ fMRec,
+ fColorInfo,
+ fUniforms,
+ fAlloc);
}
+ return fInColor;
+}
- skvm::Color sampleColorFilter(int ix, skvm::Color color) override {
- if (SkColorFilter* colorFilter = fChildren[ix].colorFilter()) {
- return as_CFB(colorFilter)->program(fBuilder, color, fColorInfo, fUniforms, fAlloc);
- }
+skvm::Color RuntimeEffectVMCallbacks::sampleColorFilter(int ix, skvm::Color color) {
+ if (SkColorFilter* colorFilter = fChildren[ix].colorFilter()) {
+ return as_CFB(colorFilter)->program(fBuilder, color, fColorInfo, fUniforms, fAlloc);
+ }
+ return color;
+}
+
+skvm::Color RuntimeEffectVMCallbacks::sampleBlender(int ix, skvm::Color src, skvm::Color dst) {
+ if (SkBlender* blender = fChildren[ix].blender()) {
+ return as_BB(blender)->program(fBuilder, src, dst, fColorInfo, fUniforms, fAlloc);
+ }
+ return blend(SkBlendMode::kSrcOver, src, dst);
+}
+
+skvm::Color RuntimeEffectVMCallbacks::toLinearSrgb(skvm::Color color) {
+ if (!fColorInfo.colorSpace()) {
+ // These intrinsics do nothing when color management is disabled
return color;
}
+ return SkColorSpaceXformSteps{fColorInfo.colorSpace(), kUnpremul_SkAlphaType,
+ sk_srgb_linear_singleton(), kUnpremul_SkAlphaType}
+ .program(fBuilder, fUniforms, color);
+}
- skvm::Color sampleBlender(int ix, skvm::Color src, skvm::Color dst) override {
- if (SkBlender* blender = fChildren[ix].blender()) {
- return as_BB(blender)->program(fBuilder, src, dst, fColorInfo, fUniforms, fAlloc);
- }
- return blend(SkBlendMode::kSrcOver, src, dst);
+skvm::Color RuntimeEffectVMCallbacks::fromLinearSrgb(skvm::Color color) {
+ if (!fColorInfo.colorSpace()) {
+ // These intrinsics do nothing when color management is disabled
+ return color;
}
+ return SkColorSpaceXformSteps{sk_srgb_linear_singleton(), kUnpremul_SkAlphaType,
+ fColorInfo.colorSpace(), kUnpremul_SkAlphaType}
+ .program(fBuilder, fUniforms, color);
+}
- skvm::Color toLinearSrgb(skvm::Color color) override {
- if (!fColorInfo.colorSpace()) {
- // These intrinsics do nothing when color management is disabled
- return color;
- }
- return SkColorSpaceXformSteps{fColorInfo.colorSpace(), kUnpremul_SkAlphaType,
- sk_srgb_linear_singleton(), kUnpremul_SkAlphaType}
- .program(fBuilder, fUniforms, color);
- }
-
- skvm::Color fromLinearSrgb(skvm::Color color) override {
- if (!fColorInfo.colorSpace()) {
- // These intrinsics do nothing when color management is disabled
- return color;
- }
- return SkColorSpaceXformSteps{sk_srgb_linear_singleton(), kUnpremul_SkAlphaType,
- fColorInfo.colorSpace(), kUnpremul_SkAlphaType}
- .program(fBuilder, fUniforms, color);
- }
-
- skvm::Builder* fBuilder;
- skvm::Uniforms* fUniforms;
- SkArenaAlloc* fAlloc;
- const std::vector<SkRuntimeEffect::ChildPtr>& fChildren;
- const SkShaderBase::MatrixRec& fMRec;
- const skvm::Color fInColor;
- const SkColorInfo& fColorInfo;
-};
#endif // defined(SK_ENABLE_SKVM)
class SkRuntimeColorFilter : public SkColorFilterBase {
@@ -1039,13 +969,13 @@
SkASSERT(uniforms);
GrFPArgs childArgs(context, &colorInfo, props);
- return make_effect_fp(fEffect,
- "runtime_color_filter",
- std::move(uniforms),
- std::move(inputFP),
- /*destColorFP=*/nullptr,
- SkSpan(fChildren),
- childArgs);
+ return GrFragmentProcessors::make_effect_fp(fEffect,
+ "runtime_color_filter",
+ std::move(uniforms),
+ std::move(inputFP),
+ /*destColorFP=*/nullptr,
+ SkSpan(fChildren),
+ childArgs);
}
#endif
@@ -1064,7 +994,8 @@
RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
{ fEffect, std::move(uniforms) });
- add_children_to_key(fChildren, fEffect->children(), keyContext, builder, gatherer);
+ SkRuntimeEffectPriv::AddChildrenToKey(fChildren, fEffect->children(), keyContext, builder,
+ gatherer);
builder->endBlock();
}
@@ -1078,11 +1009,12 @@
return false;
}
if (const SkSL::RP::Program* program = fEffect->getRPProgram(/*debugTrace=*/nullptr)) {
- SkSpan<const float> uniforms = uniforms_as_span(fEffect->uniforms(),
- fUniforms,
- /*alwaysCopyIntoAlloc=*/false,
- rec.fDstCS,
- rec.fAlloc);
+ SkSpan<const float> uniforms = SkRuntimeEffectPriv::UniformsAsSpan(
+ fEffect->uniforms(),
+ fUniforms,
+ /*alwaysCopyIntoAlloc=*/false,
+ rec.fDstCS,
+ rec.fAlloc);
SkShaderBase::MatrixRec matrix(SkMatrix::I());
matrix.markCTMApplied();
RuntimeEffectRPCallbacks callbacks(rec, matrix, fChildren, fEffect->fSampleUsages);
@@ -1109,8 +1041,8 @@
SkShaderBase::MatrixRec mRec(SkMatrix::I());
mRec.markTotalMatrixInvalid();
RuntimeEffectVMCallbacks callbacks(p, uniforms, alloc, fChildren, mRec, c, colorInfo);
- std::vector<skvm::Val> uniform = make_skvm_uniforms(p, uniforms, fEffect->uniformSize(),
- *inputs);
+ std::vector<skvm::Val> uniform = SkRuntimeEffectPriv::MakeSkVMUniforms(
+ p, uniforms, fEffect->uniformSize(), *inputs);
// There should be no way for the color filter to use device coords, but we need to supply
// something. (Uninitialized values can trigger asserts in skvm::Builder).
@@ -1164,7 +1096,7 @@
void flatten(SkWriteBuffer& buffer) const override {
buffer.writeString(fEffect->source().c_str());
buffer.writeDataAsByteArray(fUniforms.get());
- write_child_effects(buffer, fChildren);
+ SkRuntimeEffectPriv::WriteChildEffects(buffer, fChildren);
}
SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
@@ -1194,7 +1126,7 @@
#endif
STArray<4, SkRuntimeEffect::ChildPtr> children;
- if (!read_child_effects(buffer, effect.get(), &children)) {
+ if (!SkRuntimeEffectPriv::ReadChildEffects(buffer, effect.get(), &children)) {
return nullptr;
}
@@ -1258,13 +1190,13 @@
bool success;
std::unique_ptr<GrFragmentProcessor> fp;
- std::tie(success, fp) = make_effect_fp(fEffect,
- "runtime_shader",
- std::move(uniforms),
- /*inputFP=*/nullptr,
- /*destColorFP=*/nullptr,
- SkSpan(fChildren),
- args);
+ std::tie(success, fp) = GrFragmentProcessors::make_effect_fp(fEffect,
+ "runtime_shader",
+ std::move(uniforms),
+ /*inputFP=*/nullptr,
+ /*destColorFP=*/nullptr,
+ SkSpan(fChildren),
+ args);
if (!success) {
return nullptr;
}
@@ -1292,7 +1224,8 @@
RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
{ fEffect, std::move(uniforms) });
- add_children_to_key(fChildren, fEffect->children(), keyContext, builder, gatherer);
+ SkRuntimeEffectPriv::AddChildrenToKey(fChildren, fEffect->children(), keyContext, builder,
+ gatherer);
builder->endBlock();
}
@@ -1310,12 +1243,12 @@
if (!newMRec.has_value()) {
return false;
}
- SkSpan<const float> uniforms =
- uniforms_as_span(fEffect->uniforms(),
- this->uniformData(rec.fDstCS),
- /*alwaysCopyIntoAlloc=*/fUniformData == nullptr,
- rec.fDstCS,
- rec.fAlloc);
+ SkSpan<const float> uniforms = SkRuntimeEffectPriv::UniformsAsSpan(
+ fEffect->uniforms(),
+ this->uniformData(rec.fDstCS),
+ /*alwaysCopyIntoAlloc=*/fUniformData == nullptr,
+ rec.fDstCS,
+ rec.fAlloc);
RuntimeEffectRPCallbacks callbacks(rec, *newMRec, fChildren, fEffect->fSampleUsages);
bool success = program->appendStages(rec.fPipeline, rec.fAlloc, &callbacks, uniforms);
return success;
@@ -1359,8 +1292,8 @@
*newMRec,
paint,
colorInfo);
- std::vector<skvm::Val> uniform = make_skvm_uniforms(p, uniforms, fEffect->uniformSize(),
- *inputs);
+ std::vector<skvm::Val> uniform = SkRuntimeEffectPriv::MakeSkVMUniforms(
+ p, uniforms, fEffect->uniformSize(), *inputs);
return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p, fDebugTrace.get(),
SkSpan(uniform), device, local, paint, paint, &callbacks);
@@ -1370,7 +1303,7 @@
void flatten(SkWriteBuffer& buffer) const override {
buffer.writeString(fEffect->source().c_str());
buffer.writeDataAsByteArray(this->uniformData(nullptr).get());
- write_child_effects(buffer, fChildren);
+ SkRuntimeEffectPriv::WriteChildEffects(buffer, fChildren);
}
SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
@@ -1426,7 +1359,7 @@
#endif
STArray<4, SkRuntimeEffect::ChildPtr> children;
- if (!read_child_effects(buffer, effect.get(), &children)) {
+ if (!SkRuntimeEffectPriv::ReadChildEffects(buffer, effect.get(), &children)) {
return nullptr;
}
@@ -1449,165 +1382,6 @@
return effect->makeShader(std::move(uniforms), SkSpan(children), localM.getMaybeNull());
}
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class SkRuntimeBlender : public SkBlenderBase {
-public:
- SkRuntimeBlender(sk_sp<SkRuntimeEffect> effect,
- sk_sp<const SkData> uniforms,
- SkSpan<SkRuntimeEffect::ChildPtr> children)
- : fEffect(std::move(effect))
- , fUniforms(std::move(uniforms))
- , fChildren(children.begin(), children.end()) {}
-
- SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
-
- bool onAppendStages(const SkStageRec& rec) const override {
-#ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
- if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
- // SkRP has support for many parts of #version 300 already, but for now, we restrict its
- // usage in runtime effects to just #version 100.
- return false;
- }
- if (const SkSL::RP::Program* program = fEffect->getRPProgram(/*debugTrace=*/nullptr)) {
- SkSpan<const float> uniforms = uniforms_as_span(fEffect->uniforms(),
- fUniforms,
- /*alwaysCopyIntoAlloc=*/false,
- rec.fDstCS,
- rec.fAlloc);
- SkShaderBase::MatrixRec matrix(SkMatrix::I());
- matrix.markCTMApplied();
- RuntimeEffectRPCallbacks callbacks(rec, matrix, fChildren, fEffect->fSampleUsages);
- bool success = program->appendStages(rec.fPipeline, rec.fAlloc, &callbacks, uniforms);
- return success;
- }
-#endif
- return false;
- }
-
-#ifdef SK_ENABLE_SKVM
- skvm::Color onProgram(skvm::Builder* p, skvm::Color src, skvm::Color dst,
- const SkColorInfo& colorInfo, skvm::Uniforms* uniforms,
- SkArenaAlloc* alloc) const override {
- if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
- return {};
- }
-
- sk_sp<const SkData> inputs = SkRuntimeEffectPriv::TransformUniforms(fEffect->uniforms(),
- fUniforms,
- colorInfo.colorSpace());
- SkASSERT(inputs);
-
- SkShaderBase::MatrixRec mRec(SkMatrix::I());
- mRec.markTotalMatrixInvalid();
- RuntimeEffectVMCallbacks callbacks(p, uniforms, alloc, fChildren, mRec, src, colorInfo);
- std::vector<skvm::Val> uniform = make_skvm_uniforms(p, uniforms, fEffect->uniformSize(),
- *inputs);
-
- // Emit the blend function as an SkVM program.
- skvm::Coord zeroCoord = {p->splat(0.0f), p->splat(0.0f)};
- return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p,/*debugTrace=*/nullptr,
- SkSpan(uniform), /*device=*/zeroCoord, /*local=*/zeroCoord,
- src, dst, &callbacks);
- }
-#endif
-
-#if defined(SK_GANESH)
- std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
- std::unique_ptr<GrFragmentProcessor> srcFP,
- std::unique_ptr<GrFragmentProcessor> dstFP,
- const GrFPArgs& args) const override {
- if (!SkRuntimeEffectPriv::CanDraw(args.fContext->priv().caps(), fEffect.get())) {
- return nullptr;
- }
-
- sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
- fEffect->uniforms(),
- fUniforms,
- args.fDstColorInfo->colorSpace());
- SkASSERT(uniforms);
- auto [success, fp] = make_effect_fp(fEffect,
- "runtime_blender",
- std::move(uniforms),
- std::move(srcFP),
- std::move(dstFP),
- SkSpan(fChildren),
- args);
-
- return success ? std::move(fp) : nullptr;
- }
-#endif
-
-#if defined(SK_GRAPHITE)
- void addToKey(const skgpu::graphite::KeyContext& keyContext,
- skgpu::graphite::PaintParamsKeyBuilder* builder,
- skgpu::graphite::PipelineDataGatherer* gatherer) const override {
- using namespace skgpu::graphite;
-
- sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
- fEffect->uniforms(),
- fUniforms,
- keyContext.dstColorInfo().colorSpace());
- SkASSERT(uniforms);
-
- RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
- { fEffect, std::move(uniforms) });
-
- add_children_to_key(fChildren, fEffect->children(), keyContext, builder, gatherer);
-
- builder->endBlock();
- }
-#endif
-
- void flatten(SkWriteBuffer& buffer) const override {
- buffer.writeString(fEffect->source().c_str());
- buffer.writeDataAsByteArray(fUniforms.get());
- write_child_effects(buffer, fChildren);
- }
-
- SK_FLATTENABLE_HOOKS(SkRuntimeBlender)
-
-private:
- using INHERITED = SkBlenderBase;
-
- sk_sp<SkRuntimeEffect> fEffect;
- sk_sp<const SkData> fUniforms;
- std::vector<SkRuntimeEffect::ChildPtr> fChildren;
-};
-
-sk_sp<SkFlattenable> SkRuntimeBlender::CreateProc(SkReadBuffer& buffer) {
- if (!buffer.validate(buffer.allowSkSL())) {
- return nullptr;
- }
-
- SkString sksl;
- buffer.readString(&sksl);
- sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
-
- auto effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForBlender, std::move(sksl));
-#if !SK_LENIENT_SKSL_DESERIALIZATION
- if (!buffer.validate(effect != nullptr)) {
- return nullptr;
- }
-#endif
-
- STArray<4, SkRuntimeEffect::ChildPtr> children;
- if (!read_child_effects(buffer, effect.get(), &children)) {
- return nullptr;
- }
-
-#if SK_LENIENT_SKSL_DESERIALIZATION
- if (!effect) {
- SkDebugf("Serialized SkSL failed to compile. Ignoring/dropping SkSL blender.\n");
- return nullptr;
- }
-#endif
-
- return effect->makeBlender(std::move(uniforms), SkSpan(children));
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
sk_sp<SkShader> SkRuntimeEffectPriv::MakeDeferredShader(const SkRuntimeEffect* effect,
UniformsCallback uniformsCallback,
SkSpan<SkRuntimeEffect::ChildPtr> children,
diff --git a/src/core/SkRuntimeEffectPriv.h b/src/core/SkRuntimeEffectPriv.h
index d077eb2..47d3c4f 100644
--- a/src/core/SkRuntimeEffectPriv.h
+++ b/src/core/SkRuntimeEffectPriv.h
@@ -8,13 +8,40 @@
#ifndef SkRuntimeEffectPriv_DEFINED
#define SkRuntimeEffectPriv_DEFINED
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkString.h"
#include "include/effects/SkRuntimeEffect.h"
-#include "include/private/SkColorData.h"
-#include "src/core/SkVM.h"
+#include "include/private/SkSLSampleUsage.h"
+#include "include/private/base/SkAssert.h"
+#include "include/private/base/SkSpan_impl.h"
+#include "include/private/base/SkTArray.h"
+#include "src/shaders/SkShaderBase.h"
+#include <cstddef>
+#include <cstdint>
#include <functional>
+#include <memory>
+#include <vector>
#ifdef SK_ENABLE_SKSL
+#include "include/sksl/SkSLVersion.h"
+
+#ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
+#include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
+#endif
+
+#ifdef SK_ENABLE_SKVM
+#include "src/sksl/codegen/SkSLVMCodeGenerator.h"
+#endif
+
+class SkArenaAlloc;
+class SkColorSpace;
+class SkData;
+class SkMatrix;
+class SkReadBuffer;
+class SkShader;
+class SkWriteBuffer;
+struct SkStageRec;
namespace SkSL {
class Context;
@@ -87,9 +114,36 @@
static sk_sp<const SkData> TransformUniforms(SkSpan<const SkRuntimeEffect::Uniform> uniforms,
sk_sp<const SkData> originalData,
const SkColorSpace* dstCS);
+ static SkSpan<const float> UniformsAsSpan(
+ SkSpan<const SkRuntimeEffect::Uniform> uniforms,
+ sk_sp<const SkData> originalData,
+ bool alwaysCopyIntoAlloc,
+ const SkColorSpace* destColorSpace,
+ SkArenaAlloc* alloc);
static bool CanDraw(const SkCapabilities*, const SkSL::Program*);
static bool CanDraw(const SkCapabilities*, const SkRuntimeEffect*);
+
+ static bool ReadChildEffects(SkReadBuffer& buffer,
+ const SkRuntimeEffect* effect,
+ skia_private::TArray<SkRuntimeEffect::ChildPtr>* children);
+ static void WriteChildEffects(SkWriteBuffer &buffer,
+ const std::vector<SkRuntimeEffect::ChildPtr> &children);
+
+#ifdef SK_ENABLE_SKVM
+ static std::vector<skvm::Val> MakeSkVMUniforms(skvm::Builder*,
+ skvm::Uniforms*,
+ size_t inputSize,
+ const SkData& inputs);
+#endif
+
+#if defined(SK_GRAPHITE)
+static void AddChildrenToKey(SkSpan<const SkRuntimeEffect::ChildPtr> children,
+ SkSpan<const SkRuntimeEffect::Child> childInfo,
+ const skgpu::graphite::KeyContext& keyContext,
+ skgpu::graphite::PaintParamsKeyBuilder* builder,
+ skgpu::graphite::PipelineDataGatherer* gatherer);
+#endif
};
// These internal APIs for creating runtime effects vary from the public API in two ways:
@@ -132,6 +186,73 @@
return result.effect.release();
}
+#ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
+class RuntimeEffectRPCallbacks : public SkSL::RP::Callbacks {
+public:
+ RuntimeEffectRPCallbacks(const SkStageRec& s,
+ const SkShaderBase::MatrixRec& m,
+ SkSpan<const SkRuntimeEffect::ChildPtr> c,
+ SkSpan<const SkSL::SampleUsage> u)
+ : fStage(s), fMatrix(m), fChildren(c), fSampleUsages(u) {}
+
+ bool appendShader(int index) override;
+ bool appendColorFilter(int index) override;
+ bool appendBlender(int index) override;
+
+ // TODO: If an effect calls these intrinsics more than once, we could cache and re-use the steps
+ // object(s), rather than re-creating them in the arena repeatedly.
+ void toLinearSrgb(const void* color) override;
+
+ void fromLinearSrgb(const void* color) override;
+
+private:
+ void applyColorSpaceXform(const SkColorSpaceXformSteps& tempXform, const void* color);
+
+ const SkStageRec& fStage;
+ const SkShaderBase::MatrixRec& fMatrix;
+ SkSpan<const SkRuntimeEffect::ChildPtr> fChildren;
+ SkSpan<const SkSL::SampleUsage> fSampleUsages;
+};
+#endif // SK_ENABLE_SKSL_IN_RASTER_PIPELINE
+
+#if defined(SK_ENABLE_SKVM)
+class RuntimeEffectVMCallbacks : public SkSL::SkVMCallbacks {
+public:
+ RuntimeEffectVMCallbacks(skvm::Builder* builder,
+ skvm::Uniforms* uniforms,
+ SkArenaAlloc* alloc,
+ const std::vector<SkRuntimeEffect::ChildPtr>& children,
+ const SkShaderBase::MatrixRec& mRec,
+ skvm::Color inColor,
+ const SkColorInfo& colorInfo)
+ : fBuilder(builder)
+ , fUniforms(uniforms)
+ , fAlloc(alloc)
+ , fChildren(children)
+ , fMRec(mRec)
+ , fInColor(inColor)
+ , fColorInfo(colorInfo) {}
+
+ skvm::Color sampleShader(int ix, skvm::Coord coord) override;
+
+ skvm::Color sampleColorFilter(int ix, skvm::Color color) override;
+
+ skvm::Color sampleBlender(int ix, skvm::Color src, skvm::Color dst) override;
+
+ skvm::Color toLinearSrgb(skvm::Color color) override;
+
+ skvm::Color fromLinearSrgb(skvm::Color color) override;
+
+ skvm::Builder* fBuilder;
+ skvm::Uniforms* fUniforms;
+ SkArenaAlloc* fAlloc;
+ const std::vector<SkRuntimeEffect::ChildPtr>& fChildren;
+ const SkShaderBase::MatrixRec& fMRec;
+ const skvm::Color fInColor;
+ const SkColorInfo& fColorInfo;
+};
+#endif // defined(SK_ENABLE_SKVM)
+
#endif // SK_ENABLE_SKSL
#endif // SkRuntimeEffectPriv_DEFINED
diff --git a/src/effects/imagefilters/SkBlendImageFilter.cpp b/src/effects/imagefilters/SkBlendImageFilter.cpp
index 23080e2..d904cf0 100644
--- a/src/effects/imagefilters/SkBlendImageFilter.cpp
+++ b/src/effects/imagefilters/SkBlendImageFilter.cpp
@@ -42,12 +42,14 @@
#include "src/gpu/ganesh/GrColorSpaceXform.h"
#include "src/gpu/ganesh/GrFPArgs.h"
#include "src/gpu/ganesh/GrFragmentProcessor.h"
+#include "src/gpu/ganesh/GrFragmentProcessors.h"
#include "src/gpu/ganesh/GrImageInfo.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
#include "src/gpu/ganesh/GrSamplerState.h"
#include "src/gpu/ganesh/GrSurfaceProxyView.h"
#include "src/gpu/ganesh/SurfaceFillContext.h"
#include "src/gpu/ganesh/effects/GrTextureEffect.h"
+
#endif
namespace {
@@ -329,7 +331,7 @@
SkSurfaceProps props{}; // default OK; blend-image filters don't render text
GrFPArgs args(rContext, &info.colorInfo(), props);
- fp = as_BB(fBlender)->asFragmentProcessor(std::move(fgFP), std::move(fp), args);
+ fp = GrFragmentProcessors::Make(as_BB(fBlender), std::move(fgFP), std::move(fp), args);
}
auto sfc = rContext->priv().makeSFC(
diff --git a/src/gpu/ganesh/GrFragmentProcessors.cpp b/src/gpu/ganesh/GrFragmentProcessors.cpp
index 6bfc76a..6be7343 100644
--- a/src/gpu/ganesh/GrFragmentProcessors.cpp
+++ b/src/gpu/ganesh/GrFragmentProcessors.cpp
@@ -7,15 +7,46 @@
#include "src/gpu/ganesh/GrFragmentProcessors.h"
+#include "include/core/SkColorSpace.h" // IWYU pragma: keep
+#include "include/core/SkData.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkRefCnt.h"
+#include "include/effects/SkRuntimeEffect.h"
+#include "include/gpu/GrRecordingContext.h"
+#include "include/private/base/SkAssert.h"
+#include "include/private/base/SkTArray.h"
+#include "src/core/SkBlendModeBlender.h"
+#include "src/core/SkBlenderBase.h"
+#include "src/core/SkColorFilterBase.h"
#include "src/core/SkMaskFilterBase.h"
+#include "src/core/SkRuntimeBlender.h"
+#include "src/core/SkRuntimeEffectPriv.h"
#include "src/effects/SkShaderMaskFilterImpl.h"
+#include "src/gpu/ganesh/GrCaps.h"
+#include "src/gpu/ganesh/GrColorInfo.h"
+#include "src/gpu/ganesh/GrFPArgs.h"
#include "src/gpu/ganesh/GrFragmentProcessor.h"
+#include "src/gpu/ganesh/GrRecordingContextPriv.h"
+#include "src/gpu/ganesh/effects/GrBlendFragmentProcessor.h"
+#include "src/gpu/ganesh/effects/GrSkSLFP.h"
#include "src/shaders/SkShaderBase.h"
#include <memory>
+#include <optional>
#include <utility>
+#include <vector>
namespace GrFragmentProcessors {
+static std::unique_ptr<GrFragmentProcessor>
+ make_fp_from_shader_mask_filter(const SkMaskFilterBase* maskfilter,
+ const GrFPArgs& args,
+ const SkMatrix& ctm) {
+ SkASSERT(maskfilter);
+ auto shaderMF = static_cast<const SkShaderMaskFilterImpl*>(maskfilter);
+ auto fp = as_SB(shaderMF->shader())->asFragmentProcessor(args, SkShaderBase::MatrixRec(ctm));
+ return GrFragmentProcessor::MulInputByChildAlpha(std::move(fp));
+}
+
std::unique_ptr<GrFragmentProcessor> Make(const SkMaskFilter* maskfilter,
const GrFPArgs& args,
const SkMatrix& ctm) {
@@ -23,12 +54,130 @@
return nullptr;
}
auto mfb = as_MFB(maskfilter);
- if (mfb->type() != SkMaskFilterBase::Type::kShader) {
+ switch (mfb->type()) {
+ case SkMaskFilterBase::Type::kShader:
+ return make_fp_from_shader_mask_filter(mfb, args, ctm);
+ case SkMaskFilterBase::Type::kBlur:
+ case SkMaskFilterBase::Type::kEmboss:
+ case SkMaskFilterBase::Type::kSDF:
+ case SkMaskFilterBase::Type::kTable:
+ return nullptr;
+ }
+ SkUNREACHABLE;
+}
+
+using ChildType = SkRuntimeEffect::ChildType;
+
+GrFPResult make_effect_fp(sk_sp<SkRuntimeEffect> effect,
+ const char* name,
+ sk_sp<const SkData> uniforms,
+ std::unique_ptr<GrFragmentProcessor> inputFP,
+ std::unique_ptr<GrFragmentProcessor> destColorFP,
+ SkSpan<const SkRuntimeEffect::ChildPtr> children,
+ const GrFPArgs& childArgs) {
+ skia_private::STArray<8, std::unique_ptr<GrFragmentProcessor>> childFPs;
+ for (const auto& child : children) {
+ std::optional<ChildType> type = child.type();
+ if (type == ChildType::kShader) {
+ // Convert a SkShader into a child FP.
+ SkShaderBase::MatrixRec mRec(SkMatrix::I());
+ mRec.markTotalMatrixInvalid();
+ auto childFP = as_SB(child.shader())->asFragmentProcessor(childArgs, mRec);
+ if (!childFP) {
+ return GrFPFailure(std::move(inputFP));
+ }
+ childFPs.push_back(std::move(childFP));
+ } else if (type == ChildType::kColorFilter) {
+ // Convert a SkColorFilter into a child FP.
+ auto [success, childFP] = as_CFB(child.colorFilter())
+ ->asFragmentProcessor(/*inputFP=*/nullptr,
+ childArgs.fContext,
+ *childArgs.fDstColorInfo,
+ childArgs.fSurfaceProps);
+ if (!success) {
+ return GrFPFailure(std::move(inputFP));
+ }
+ childFPs.push_back(std::move(childFP));
+ } else if (type == ChildType::kBlender) {
+ // Convert a SkBlender into a child FP.
+ auto childFP = GrFragmentProcessors::Make(as_BB(child.blender()),
+ /*srcFP=*/nullptr,
+ GrFragmentProcessor::DestColor(),
+ childArgs);
+ if (!childFP) {
+ return GrFPFailure(std::move(inputFP));
+ }
+ childFPs.push_back(std::move(childFP));
+ } else {
+ // We have a null child effect.
+ childFPs.push_back(nullptr);
+ }
+ }
+ auto fp = GrSkSLFP::MakeWithData(std::move(effect),
+ name,
+ childArgs.fDstColorInfo->refColorSpace(),
+ std::move(inputFP),
+ std::move(destColorFP),
+ std::move(uniforms),
+ SkSpan(childFPs));
+ SkASSERT(fp);
+ return GrFPSuccess(std::move(fp));
+}
+
+static std::unique_ptr<GrFragmentProcessor> make_blender_fp(
+ const SkRuntimeBlender* rtb,
+ std::unique_ptr<GrFragmentProcessor> srcFP,
+ std::unique_ptr<GrFragmentProcessor> dstFP,
+ const GrFPArgs& fpArgs) {
+ SkASSERT(rtb);
+ if (!SkRuntimeEffectPriv::CanDraw(fpArgs.fContext->priv().caps(), rtb->effect().get())) {
return nullptr;
}
- auto shaderMF = static_cast<const SkShaderMaskFilterImpl*>(maskfilter);
- auto fp = as_SB(shaderMF->shader())->asFragmentProcessor(args, SkShaderBase::MatrixRec(ctm));
- return GrFragmentProcessor::MulInputByChildAlpha(std::move(fp));
+
+ sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
+ rtb->effect()->uniforms(),
+ rtb->uniforms(),
+ fpArgs.fDstColorInfo->colorSpace());
+ SkASSERT(uniforms);
+ auto children = rtb->children();
+ auto [success, fp] = make_effect_fp(rtb->effect(),
+ "runtime_blender",
+ std::move(uniforms),
+ std::move(srcFP),
+ std::move(dstFP),
+ SkSpan(children),
+ fpArgs);
+
+ return success ? std::move(fp) : nullptr;
+}
+
+static std::unique_ptr<GrFragmentProcessor> make_blender_fp(
+ const SkBlendModeBlender* blender,
+ std::unique_ptr<GrFragmentProcessor> srcFP,
+ std::unique_ptr<GrFragmentProcessor> dstFP,
+ const GrFPArgs& fpArgs) {
+ SkASSERT(blender);
+ return GrBlendFragmentProcessor::Make(std::move(srcFP), std::move(dstFP), blender->mode());
+}
+
+std::unique_ptr<GrFragmentProcessor> Make(const SkBlenderBase* blender,
+ std::unique_ptr<GrFragmentProcessor> srcFP,
+ std::unique_ptr<GrFragmentProcessor> dstFP,
+ const GrFPArgs& fpArgs) {
+ if (!blender) {
+ return nullptr;
+ }
+ switch (blender->type()) {
+#define M(type) \
+ case SkBlenderBase::BlenderType::k##type: \
+ return make_blender_fp(static_cast<const Sk##type##Blender*>(blender), \
+ std::move(srcFP), \
+ std::move(dstFP), \
+ fpArgs);
+ SK_ALL_BLENDERS(M)
+#undef M
+ }
+ SkUNREACHABLE;
}
bool IsSupported(const SkMaskFilter* maskfilter) {
@@ -36,9 +185,15 @@
return false;
}
auto mfb = as_MFB(maskfilter);
- if (mfb->type() != SkMaskFilterBase::Type::kShader) {
- return false;
+ switch (mfb->type()) {
+ case SkMaskFilterBase::Type::kShader:
+ return true;
+ case SkMaskFilterBase::Type::kBlur:
+ case SkMaskFilterBase::Type::kEmboss:
+ case SkMaskFilterBase::Type::kSDF:
+ case SkMaskFilterBase::Type::kTable:
+ return false;
}
- return true;
+ SkUNREACHABLE;
}
} // namespace GrFragmentProcessors
diff --git a/src/gpu/ganesh/GrFragmentProcessors.h b/src/gpu/ganesh/GrFragmentProcessors.h
index 11125b6..0dbc37b 100644
--- a/src/gpu/ganesh/GrFragmentProcessors.h
+++ b/src/gpu/ganesh/GrFragmentProcessors.h
@@ -8,19 +8,46 @@
#ifndef GrFragmentProcessors_DEFINED
#define GrFragmentProcessors_DEFINED
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkSpan.h"
+#include "include/effects/SkRuntimeEffect.h"
+
+#include <tuple>
#include <memory>
class GrFragmentProcessor;
+class SkBlenderBase;
+class SkData;
class SkMaskFilter;
-struct GrFPArgs;
class SkMatrix;
+struct GrFPArgs;
+
+using GrFPResult = std::tuple<bool, std::unique_ptr<GrFragmentProcessor>>;
namespace GrFragmentProcessors {
std::unique_ptr<GrFragmentProcessor> Make(const SkMaskFilter*,
const GrFPArgs&,
const SkMatrix& ctm);
+/**
+ * Returns a GrFragmentProcessor that implements this blend for the Ganesh GPU backend.
+ * The GrFragmentProcessor expects premultiplied inputs and returns a premultiplied output.
+ */
+std::unique_ptr<GrFragmentProcessor> Make(const SkBlenderBase*,
+ std::unique_ptr<GrFragmentProcessor> srcFP,
+ std::unique_ptr<GrFragmentProcessor> dstFP,
+ const GrFPArgs& fpArgs);
+
bool IsSupported(const SkMaskFilter*);
+
+// TODO(kjlubick, brianosman) remove this after all related effects have been migrated
+GrFPResult make_effect_fp(sk_sp<SkRuntimeEffect> effect,
+ const char* name,
+ sk_sp<const SkData> uniforms,
+ std::unique_ptr<GrFragmentProcessor> inputFP,
+ std::unique_ptr<GrFragmentProcessor> destColorFP,
+ SkSpan<const SkRuntimeEffect::ChildPtr> children,
+ const GrFPArgs& childArgs);
}
#endif
diff --git a/src/gpu/ganesh/SkGr.cpp b/src/gpu/ganesh/SkGr.cpp
index b3697af..3199e1b 100644
--- a/src/gpu/ganesh/SkGr.cpp
+++ b/src/gpu/ganesh/SkGr.cpp
@@ -397,9 +397,10 @@
SkPMColor4f shaderInput = origColor.makeOpaque().premul();
paintFP = GrFragmentProcessor::OverrideInput(std::move(paintFP), shaderInput);
- paintFP = as_BB(primColorBlender)->asFragmentProcessor(std::move(paintFP),
- /*dstFP=*/nullptr,
- fpArgs);
+ paintFP = GrFragmentProcessors::Make(as_BB(primColorBlender),
+ /*srcFP=*/std::move(paintFP),
+ /*dstFP=*/nullptr,
+ fpArgs);
if (!paintFP) {
return false;
}
@@ -442,9 +443,10 @@
grPaint->setColor4f(SK_PMColor4fWHITE); // won't be used.
if (blender_requires_shader(primColorBlender)) {
paintFP = GrFragmentProcessor::MakeColor(origColor.makeOpaque().premul());
- paintFP = as_BB(primColorBlender)->asFragmentProcessor(std::move(paintFP),
- /*dstFP=*/nullptr,
- fpArgs);
+ paintFP = GrFragmentProcessors::Make(as_BB(primColorBlender),
+ /*srcFP=*/std::move(paintFP),
+ /*dstFP=*/nullptr,
+ fpArgs);
if (!paintFP) {
return false;
}
@@ -512,10 +514,10 @@
} else {
// Apply a custom blend against the surface color, and force the XP to kSrc so that the
// computed result is applied directly to the canvas while still honoring the alpha.
- paintFP = as_BB(skPaint.getBlender())->asFragmentProcessor(
- std::move(paintFP),
- GrFragmentProcessor::SurfaceColor(),
- fpArgs);
+ paintFP = GrFragmentProcessors::Make(as_BB(skPaint.getBlender()),
+ std::move(paintFP),
+ GrFragmentProcessor::SurfaceColor(),
+ fpArgs);
if (!paintFP) {
return false;
}
diff --git a/toolchain/linux_trampolines/clang_trampoline_linux.sh b/toolchain/linux_trampolines/clang_trampoline_linux.sh
index cef4942..2207d9c 100755
--- a/toolchain/linux_trampolines/clang_trampoline_linux.sh
+++ b/toolchain/linux_trampolines/clang_trampoline_linux.sh
@@ -88,6 +88,7 @@
"src/core/SkReadPixelsRec.cpp"
"src/core/SkRecorder.cpp"
"src/core/SkRect.cpp"
+ "src/core/SkRuntime"
"src/core/SkScalar.cpp"
"src/core/SkStream.cpp"
"src/core/SkString.cpp"