[graphite] Add matrix convolution ImageFilter to Precompilation system
Bug: b/259548724
Change-Id: Ib1ef773836e5ab320ddfe3b1f5adab3753fabb49
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/859396
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/graphite/FactoryFunctions.cpp b/src/gpu/graphite/FactoryFunctions.cpp
index 50853ac..91760bc 100644
--- a/src/gpu/graphite/FactoryFunctions.cpp
+++ b/src/gpu/graphite/FactoryFunctions.cpp
@@ -507,6 +507,13 @@
return PrecompileShaders::LocalMatrix({ sk_make_sp<PrecompileImageShader>(flags) });
}
+sk_sp<PrecompileShader> PrecompileShadersPriv::RawImage(
+ SkEnumBitMask<PrecompileImageShaderFlags> flags) {
+ return PrecompileShaders::LocalMatrix(
+ { sk_make_sp<PrecompileImageShader>(flags |
+ PrecompileImageShaderFlags::kExcludeAlpha) });
+}
+
//--------------------------------------------------------------------------------------------------
class PrecompileYUVImageShader : public PrecompileShader {
public:
@@ -947,6 +954,81 @@
}
//--------------------------------------------------------------------------------------------------
+class PrecompileMatrixConvolutionShader : public PrecompileShader {
+public:
+ PrecompileMatrixConvolutionShader(sk_sp<PrecompileShader> wrapped)
+ : fWrapped(std::move(wrapped)) {
+ fNumWrappedCombos = fWrapped->numCombinations();
+
+ // When the matrix convolution ImageFilter uses a texture we know it will only ever
+ // be SkFilterMode::kNearest and SkTileMode::kClamp.
+ // TODO: add a PrecompileImageShaderFlags to further limit the raw image shader
+ // combinations. Right now we're getting two combinations for the raw shader
+ // (sk_image_shader and sk_hw_image_shader).
+ fRawImageShader =
+ PrecompileShadersPriv::RawImage(PrecompileImageShaderFlags::kExcludeCubic);
+ fNumRawImageShaderCombos = fRawImageShader->numCombinations();
+ }
+
+private:
+ int numIntrinsicCombinations() const override {
+ // The uniform version only has one option but the two texture-based versions will
+ // have as many combinations as the raw image shader.
+ return 1 + 2 * fNumRawImageShaderCombos;
+ }
+
+ int numChildCombinations() const override { return fNumWrappedCombos; }
+
+ void addToKey(const KeyContext& keyContext,
+ PaintParamsKeyBuilder* builder,
+ PipelineDataGatherer* gatherer,
+ int desiredCombination) const override {
+
+ int desiredTextureCombination = 0;
+
+ const int desiredWrappedCombination = desiredCombination % fNumWrappedCombos;
+ int remainingCombinations = desiredCombination / fNumWrappedCombos;
+
+ SkKnownRuntimeEffects::StableKey stableKey = SkKnownRuntimeEffects::StableKey::kInvalid;
+ if (remainingCombinations == 0) {
+ stableKey = SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms;
+ } else {
+ static constexpr SkKnownRuntimeEffects::StableKey kTextureBasedStableKeys[] = {
+ SkKnownRuntimeEffects::StableKey::kMatrixConvTexSm,
+ SkKnownRuntimeEffects::StableKey::kMatrixConvTexLg,
+ };
+
+ --remainingCombinations;
+ stableKey = kTextureBasedStableKeys[remainingCombinations % 2];
+ desiredTextureCombination = remainingCombinations / 2;
+ SkASSERT(desiredTextureCombination < fNumRawImageShaderCombos);
+ }
+
+ const SkRuntimeEffect* fEffect = GetKnownRuntimeEffect(stableKey);
+
+ KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
+
+ RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer, { sk_ref_sp(fEffect) });
+ fWrapped->priv().addToKey(childContext, builder, gatherer, desiredWrappedCombination);
+ if (stableKey != SkKnownRuntimeEffects::StableKey::kMatrixConvUniforms) {
+ fRawImageShader->priv().addToKey(childContext, builder, gatherer,
+ desiredTextureCombination);
+ }
+ builder->endBlock();
+ }
+
+ sk_sp<PrecompileShader> fWrapped;
+ int fNumWrappedCombos;
+ sk_sp<PrecompileShader> fRawImageShader;
+ int fNumRawImageShaderCombos;
+};
+
+sk_sp<PrecompileShader> PrecompileShadersPriv::MatrixConvolution(
+ sk_sp<skgpu::graphite::PrecompileShader> wrapped) {
+ return sk_make_sp<PrecompileMatrixConvolutionShader>(std::move(wrapped));
+}
+
+//--------------------------------------------------------------------------------------------------
class PrecompileMorphologyShader : public PrecompileShader {
public:
PrecompileMorphologyShader(sk_sp<PrecompileShader> wrapped,
diff --git a/src/gpu/graphite/FactoryFunctionsPriv.h b/src/gpu/graphite/FactoryFunctionsPriv.h
index 9a13f9a..a040d46 100644
--- a/src/gpu/graphite/FactoryFunctionsPriv.h
+++ b/src/gpu/graphite/FactoryFunctionsPriv.h
@@ -31,6 +31,8 @@
sk_sp<PrecompileShader> Lighting(sk_sp<PrecompileShader> wrapped);
+ sk_sp<PrecompileShader> MatrixConvolution(sk_sp<PrecompileShader> wrapped);
+
sk_sp<PrecompileShader> LinearMorphology(sk_sp<PrecompileShader> wrapped);
sk_sp<PrecompileShader> SparseMorphology(sk_sp<PrecompileShader> wrapped);
@@ -42,6 +44,8 @@
sk_sp<PrecompileShader> Image(SkEnumBitMask<PrecompileImageShaderFlags>);
+ sk_sp<PrecompileShader> RawImage(SkEnumBitMask<PrecompileImageShaderFlags>);
+
// This factory variant should be used when the existence or non-existence of the local matrix
// is known. If 'withLM' is true only the LMShader-wrapped shader will be created while, when
// 'withLM' is false, no LMShader will wrap the base shader.
diff --git a/src/gpu/graphite/Precompile.cpp b/src/gpu/graphite/Precompile.cpp
index c375046..f8cf814 100644
--- a/src/gpu/graphite/Precompile.cpp
+++ b/src/gpu/graphite/Precompile.cpp
@@ -507,6 +507,28 @@
processCombination);
}
+void create_matrix_convolution_imagefilter_pipelines(
+ const KeyContext& keyContext,
+ PipelineDataGatherer* gatherer,
+ const PaintOptions::ProcessCombination& processCombination) {
+
+ PaintOptions matrixConv;
+
+ // For matrix convolution imagefilters we know we don't have alpha-only textures and don't
+ // need cubic filtering.
+ sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
+ PrecompileImageShaderFlags::kExcludeAlpha | PrecompileImageShaderFlags::kExcludeCubic);
+
+ matrixConv.setShaders({ PrecompileShadersPriv::MatrixConvolution(imageShader) });
+
+ matrixConv.priv().buildCombinations(keyContext,
+ gatherer,
+ DrawTypeFlags::kSimpleShape,
+ /* withPrimitiveBlender= */ false,
+ Coverage::kSingleChannel,
+ processCombination);
+}
+
void create_morphology_imagefilter_pipelines(
const KeyContext& keyContext,
PipelineDataGatherer* gatherer,
@@ -581,6 +603,10 @@
if (fImageFilterOptions & PrecompileImageFilters::kLighting) {
create_lighting_imagefilter_pipelines(keyContext, gatherer, processCombination);
}
+ if (fImageFilterOptions & PrecompileImageFilters::kMatrixConvolution) {
+ create_matrix_convolution_imagefilter_pipelines(keyContext, gatherer,
+ processCombination);
+ }
if (fImageFilterOptions & PrecompileImageFilters::kMorphology) {
create_morphology_imagefilter_pipelines(keyContext, gatherer, processCombination);
}
diff --git a/src/gpu/graphite/Precompile.h b/src/gpu/graphite/Precompile.h
index 8e34ef5..ae3b2e0 100644
--- a/src/gpu/graphite/Precompile.h
+++ b/src/gpu/graphite/Precompile.h
@@ -157,11 +157,12 @@
};
enum class PrecompileImageFilters : uint32_t {
- kNone = 0x0,
- kBlur = 0x1,
- kDisplacement = 0x2,
- kLighting = 0x4,
- kMorphology = 0x8,
+ kNone = 0x00,
+ kBlur = 0x01,
+ kDisplacement = 0x02,
+ kLighting = 0x04,
+ kMatrixConvolution = 0x08,
+ kMorphology = 0x10,
};
SK_MAKE_BITMASK_OPS(PrecompileImageFilters)
diff --git a/tests/graphite/PaintParamsKeyTest.cpp b/tests/graphite/PaintParamsKeyTest.cpp
index 0da04b7..d9f8ee8 100644
--- a/tests/graphite/PaintParamsKeyTest.cpp
+++ b/tests/graphite/PaintParamsKeyTest.cpp
@@ -248,6 +248,7 @@
M(Blur) \
M(Displacement) \
M(Lighting) \
+ M(MatrixConvolution) \
M(Morphology)
enum class ImageFilterType {
@@ -1227,6 +1228,38 @@
SkUNREACHABLE;
}
+sk_sp<SkImageFilter> matrix_convolution_imagefilter(
+ SkRandom* rand,
+ SkEnumBitMask<PrecompileImageFilters>* imageFilterMask) {
+
+ int kernelSize = 1;
+
+ int option = rand->nextULessThan(3);
+ switch (option) {
+ case 0: kernelSize = 3; break;
+ case 1: kernelSize = 7; break;
+ case 2: kernelSize = 11; break;
+ }
+
+ int center = (kernelSize * kernelSize - 1) / 2;
+ std::vector<float> kernel(kernelSize * kernelSize, SkIntToScalar(1));
+ kernel[center] = 2.0f - kernelSize * kernelSize;
+
+ sk_sp<SkImageFilter> matrixConvIF;
+ matrixConvIF = SkImageFilters::MatrixConvolution({ kernelSize, kernelSize },
+ /* kernel= */ kernel.data(),
+ /* gain= */ 0.3f,
+ /* bias= */ 100.0f,
+ /* kernelOffset= */ { 1, 1 },
+ SkTileMode::kMirror,
+ /* convolveAlpha= */ false,
+ /* input= */ nullptr);
+ SkASSERT(matrixConvIF);
+ *imageFilterMask |= PrecompileImageFilters::kMatrixConvolution;
+
+ return matrixConvIF;
+}
+
sk_sp<SkImageFilter> morphology_imagefilter(
SkRandom* rand,
SkEnumBitMask<PrecompileImageFilters>* imageFilterMask) {
@@ -1265,6 +1298,9 @@
case ImageFilterType::kLighting:
imgFilter = lighting_imagefilter(rand, &imageFilterMask);
break;
+ case ImageFilterType::kMatrixConvolution:
+ imgFilter = matrix_convolution_imagefilter(rand, &imageFilterMask);
+ break;
case ImageFilterType::kMorphology:
imgFilter = morphology_imagefilter(rand, &imageFilterMask);
break;
@@ -1669,6 +1705,7 @@
ImageFilterType::kBlur,
ImageFilterType::kDisplacement,
ImageFilterType::kLighting,
+ ImageFilterType::kMatrixConvolution,
ImageFilterType::kMorphology,
#endif
};