From 7e8fdf4706802f5c2c187d6d2679f32dd123f909 Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Thu, 20 Jan 2022 16:04:03 -0500 Subject: [PATCH] [graphite] Add ImageShader and BlendShader SkPaintParamKey support Unfortunately, this won't change any behavior until ExtractPaintData is switched over to using PaintParams::toKey Bug: skia:12701 Change-Id: I4f51dbb43983fe2f01947e26814f581a6d9033cd Reviewed-on: https://skia-review.googlesource.com/c/skia/+/496783 Reviewed-by: Michael Ludwig Commit-Queue: Robert Phillips --- gn/tests.gni | 1 + include/private/SkPaintParamsKey.h | 3 + src/core/SkKeyHelpers.cpp | 115 +++++++++++++++++++++++++++++ src/core/SkKeyHelpers.h | 37 ++++++++++ src/core/SkPaintParamsKey.cpp | 3 + src/shaders/SkComposeShader.cpp | 10 +++ src/shaders/SkComposeShader.h | 4 + src/shaders/SkImageShader.cpp | 7 ++ src/shaders/SkImageShader.h | 4 + tests/graphite/ComboTest.cpp | 84 +++++++++++++++++++++ 10 files changed, 268 insertions(+) create mode 100644 tests/graphite/ComboTest.cpp diff --git a/gn/tests.gni b/gn/tests.gni index cc0cfe0e62..825f2c4795 100644 --- a/gn/tests.gni +++ b/gn/tests.gni @@ -334,6 +334,7 @@ metal_tests_sources = [ graphite_tests_sources = [ "$_tests/graphite/BackendTextureTest.cpp", + "$_tests/graphite/ComboTest.cpp", "$_tests/graphite/CommandBufferTest.cpp", "$_tests/graphite/IntersectionTreeTest.cpp", "$_tests/graphite/MaskTest.cpp", diff --git a/include/private/SkPaintParamsKey.h b/include/private/SkPaintParamsKey.h index 44a88f59fe..726da83bd3 100644 --- a/include/private/SkPaintParamsKey.h +++ b/include/private/SkPaintParamsKey.h @@ -32,6 +32,9 @@ enum class CodeSnippetID : uint8_t { kSweepGradientShader, kConicalGradientShader, + kImageShader, + kBlendShader, // aka ComposeShader + // BlendMode code snippets kSimpleBlendMode, diff --git a/src/core/SkKeyHelpers.cpp b/src/core/SkKeyHelpers.cpp index 626cbed9a6..38a28d70c2 100644 --- a/src/core/SkKeyHelpers.cpp +++ b/src/core/SkKeyHelpers.cpp @@ -9,6 +9,7 @@ #include "include/private/SkPaintParamsKey.h" #include "src/core/SkDebugUtils.h" +#include "src/shaders/SkShaderBase.h" namespace { @@ -185,6 +186,120 @@ void Dump(const SkPaintParamsKey& key, int headerOffset) { } // namespace GradientShaderBlocks +//-------------------------------------------------------------------------------------------------- +namespace ImageShaderBlock { + +inline static constexpr int kTileModeBits = 2; + +static const int kXTileModeShift = 0; +static const int kYTileModeShift = kTileModeBits; + +#ifdef SK_DEBUG +static const int kBlockDataSize = 1; + +inline static constexpr int kTileModeMask = 0x3; + +ImageData ExtractFromKey(const SkPaintParamsKey& key, uint32_t headerOffset) { + validate_block_header(key, headerOffset, + CodeSnippetID::kImageShader, kBlockDataSize); + + uint8_t data = key.byte(headerOffset+SkPaintParamsKey::kBlockHeaderSizeInBytes); + + SkTileMode tmX = to_tilemode(((data) >> kXTileModeShift) & kTileModeMask); + SkTileMode tmY = to_tilemode(((data) >> kYTileModeShift) & kTileModeMask); + + return { tmX, tmY }; +} +#endif + +void AddToKey(SkBackend backend, SkPaintParamsKey* key, const ImageData& imgData) { + + if (backend == SkBackend::kGraphite) { + + uint8_t data = (static_cast(imgData.fTileModes[0]) << kXTileModeShift) | + (static_cast(imgData.fTileModes[1]) << kYTileModeShift); + + int headerOffset = key->beginBlock(CodeSnippetID::kImageShader); + + key->addByte(data); + + key->endBlock(headerOffset, CodeSnippetID::kImageShader); + + SkASSERT(imgData == ExtractFromKey(*key, headerOffset)); + } else { + // TODO: add implementation for other backends + SolidColorShaderBlock::AddToKey(backend, key); + } +} + +#ifdef SK_DEBUG +void Dump(const SkPaintParamsKey& key, int headerOffset) { + ImageData imgData = ExtractFromKey(key, headerOffset); + + SkDebugf("kImageShader: tileModes(%s, %s) ", + SkTileModeToStr(imgData.fTileModes[0]), + SkTileModeToStr(imgData.fTileModes[1])); +} +#endif + +} // namespace ImageShaderBlock + +//-------------------------------------------------------------------------------------------------- +namespace BlendShaderBlock { + +void AddToKey(SkBackend backend, SkPaintParamsKey *key, const BlendData& blendData) { + + if (backend == SkBackend::kGraphite) { + int headerOffset = key->beginBlock(CodeSnippetID::kBlendShader); + + add_blendmode_to_key(key, blendData.fBM); + int start = key->sizeInBytes(); + as_SB(blendData.fDst)->addToKey(nullptr, backend, key); + int firstShaderSize = key->sizeInBytes() - start; + + start = key->sizeInBytes(); + as_SB(blendData.fSrc)->addToKey(nullptr, backend, key); + int secondShaderSize = key->sizeInBytes() - start; + + key->endBlock(headerOffset, CodeSnippetID::kBlendShader); + + int expectedBlockSize = SkPaintParamsKey::kBlockHeaderSizeInBytes + + 1 + firstShaderSize + secondShaderSize; + validate_block_header(*key, headerOffset, CodeSnippetID::kBlendShader, expectedBlockSize); + } else { + // TODO: add implementation for other backends + SolidColorShaderBlock::AddToKey(backend, key); + } +} + +#ifdef SK_DEBUG +void Dump(const SkPaintParamsKey& key, int headerOffset) { + auto [id, storedBlockSize] = key.readCodeSnippetID(headerOffset); + SkASSERT(id == CodeSnippetID::kBlendShader); + + int runningOffset = headerOffset + SkPaintParamsKey::kBlockHeaderSizeInBytes; + + uint8_t data = key.byte(runningOffset); + SkBlendMode bm = to_blendmode(data); + + SkDebugf("BlendMode: %s\n", SkBlendMode_Name(bm)); + runningOffset += 1; // 1 byte for blendmode + + SkDebugf("\nDst: "); + int firstBlockSize = SkPaintParamsKey::DumpBlock(key, runningOffset); + runningOffset += firstBlockSize; + + SkDebugf("Src: "); + int secondBlockSize = SkPaintParamsKey::DumpBlock(key, runningOffset); + + int calculatedBlockSize = SkPaintParamsKey::kBlockHeaderSizeInBytes + + firstBlockSize + secondBlockSize + 1; + SkASSERT(calculatedBlockSize == storedBlockSize); +} +#endif + +} // namespace BlendShaderBlock + //-------------------------------------------------------------------------------------------------- namespace BlendModeBlock { diff --git a/src/core/SkKeyHelpers.h b/src/core/SkKeyHelpers.h index 168c237e0b..6a2602a741 100644 --- a/src/core/SkKeyHelpers.h +++ b/src/core/SkKeyHelpers.h @@ -62,6 +62,43 @@ namespace GradientShaderBlocks { } // namespace GradientShaderBlocks +namespace ImageShaderBlock { + + struct ImageData { + bool operator==(const ImageData& rhs) const { + return fTileModes[0] == rhs.fTileModes[0] && + fTileModes[1] == rhs.fTileModes[1]; + } + bool operator!=(const ImageData& rhs) const { return !(*this == rhs); } + + // TODO: add the other image shader parameters that could impact code snippet selection + // (e.g., sampling options, subsetting, etc.) + SkTileMode fTileModes[2]; + }; + + void AddToKey(SkBackend, SkPaintParamsKey*, const ImageData&); +#ifdef SK_DEBUG + void Dump(const SkPaintParamsKey&, int headerOffset); +#endif + +} // namespace ImageShaderBlock + +namespace BlendShaderBlock { + + struct BlendData { + SkShader* fDst; + SkShader* fSrc; + // TODO: add support for blenders + SkBlendMode fBM; + }; + + void AddToKey(SkBackend, SkPaintParamsKey*, const BlendData&); +#ifdef SK_DEBUG + void Dump(const SkPaintParamsKey&, int headerOffset); +#endif + +} // namespace BlendShaderBlock + namespace BlendModeBlock { void AddToKey(SkBackend, SkPaintParamsKey*, SkBlendMode); diff --git a/src/core/SkPaintParamsKey.cpp b/src/core/SkPaintParamsKey.cpp index f549b59a4d..5d9f3cda96 100644 --- a/src/core/SkPaintParamsKey.cpp +++ b/src/core/SkPaintParamsKey.cpp @@ -40,6 +40,9 @@ DumpMethod get_dump_method(CodeSnippetID id) { case CodeSnippetID::kSweepGradientShader: [[fallthrough]]; case CodeSnippetID::kConicalGradientShader: return GradientShaderBlocks::Dump; + case CodeSnippetID::kImageShader: return ImageShaderBlock::Dump; + case CodeSnippetID::kBlendShader: return BlendShaderBlock::Dump; + // BlendMode code snippets case CodeSnippetID::kSimpleBlendMode: return BlendModeBlock::Dump; diff --git a/src/shaders/SkComposeShader.cpp b/src/shaders/SkComposeShader.cpp index 6a01ac9929..b46634e733 100644 --- a/src/shaders/SkComposeShader.cpp +++ b/src/shaders/SkComposeShader.cpp @@ -11,6 +11,7 @@ #include "src/core/SkArenaAlloc.h" #include "src/core/SkBlendModePriv.h" #include "src/core/SkBlenderBase.h" +#include "src/core/SkKeyHelpers.h" #include "src/core/SkRasterPipeline.h" #include "src/core/SkReadBuffer.h" #include "src/core/SkRuntimeEffectPriv.h" @@ -187,3 +188,12 @@ std::unique_ptr SkShader_Blend::asFragmentProcessor( } } #endif + +void SkShader_Blend::addToKey(SkShaderCodeDictionary* dict, + SkBackend backend, + SkPaintParamsKey* key) const { + // TODO: add blender support + SkASSERT(!fBlender); + + BlendShaderBlock::AddToKey(backend, key, { fDst.get(), fSrc.get(), fMode }); +} diff --git a/src/shaders/SkComposeShader.h b/src/shaders/SkComposeShader.h index a95ffe27a1..2db7bc5ab9 100644 --- a/src/shaders/SkComposeShader.h +++ b/src/shaders/SkComposeShader.h @@ -28,6 +28,10 @@ public: std::unique_ptr asFragmentProcessor(const GrFPArgs&) const override; #endif + void addToKey(SkShaderCodeDictionary*, + SkBackend, + SkPaintParamsKey*) const override; + protected: SkShader_Blend(SkReadBuffer&); void flatten(SkWriteBuffer&) const override; diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp index 2437c03479..90481c3e3f 100755 --- a/src/shaders/SkImageShader.cpp +++ b/src/shaders/SkImageShader.cpp @@ -11,6 +11,7 @@ #include "src/core/SkArenaAlloc.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkColorSpaceXformSteps.h" +#include "src/core/SkKeyHelpers.h" #include "src/core/SkMatrixPriv.h" #include "src/core/SkMatrixProvider.h" #include "src/core/SkMipmapAccessor.h" @@ -372,6 +373,12 @@ std::unique_ptr SkImageShader::asFragmentProcessor( #endif +void SkImageShader::addToKey(SkShaderCodeDictionary* dict, + SkBackend backend, + SkPaintParamsKey* key) const { + ImageShaderBlock::AddToKey(backend, key, { fTileModeX, fTileModeY }); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// #include "src/core/SkImagePriv.h" diff --git a/src/shaders/SkImageShader.h b/src/shaders/SkImageShader.h index a9173a8460..16baf5b86c 100644 --- a/src/shaders/SkImageShader.h +++ b/src/shaders/SkImageShader.h @@ -44,6 +44,10 @@ public: std::unique_ptr asFragmentProcessor(const GrFPArgs&) const override; #endif + void addToKey(SkShaderCodeDictionary*, + SkBackend, + SkPaintParamsKey*) const override; + static SkM44 CubicResamplerMatrix(float B, float C); private: diff --git a/tests/graphite/ComboTest.cpp b/tests/graphite/ComboTest.cpp new file mode 100644 index 0000000000..b1da00d1ce --- /dev/null +++ b/tests/graphite/ComboTest.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2022 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkCanvas.h" +#include "include/core/SkSurface.h" +#include "include/effects/SkGradientShader.h" +#include "include/private/SkPaintParamsKey.h" +#include "include/private/SkShaderCodeDictionary.h" +#include "src/core/SkPaintPriv.h" +#include "tests/Test.h" + +namespace { + +sk_sp make_image_shader(int imageWidth, int imageHeight, + SkTileMode xTileMode, SkTileMode yTileMode, + SkColor color) { + auto surface = SkSurface::MakeRasterN32Premul(imageWidth, imageHeight); + SkCanvas *canvas = surface->getCanvas(); + canvas->clear(color); + return surface->makeImageSnapshot()->makeShader(xTileMode, yTileMode, SkSamplingOptions()); +} + +sk_sp make_linear_gradient_shader(SkTileMode tileMode) { + SkPoint pts[2]; + SkColor colors[2] = {SK_ColorRED, SK_ColorBLUE}; + + pts[0].set(0, 0); + pts[1].set(SkIntToScalar(100), 0); + return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, tileMode); +} + +sk_sp make_blend_shader(sk_sp shaderA, + sk_sp shaderB, + SkBlendMode mode) { + return SkShaders::Blend(mode, std::move(shaderA), std::move(shaderB)); +} + +void dump_keys(SkShaderCodeDictionary *dict, const SkPaint &paint) { + auto keys = SkPaintPriv::ToKeys(paint, dict, SkBackend::kGanesh); + + for (auto k: keys) { + // TODO: we need a better way to assess that key creation succeeded + k.dump(); + } +} + +} // anonymous namespace + +DEF_GRAPHITE_TEST(ComboTest, r) { + SkShaderCodeDictionary dict; + + { + SkPaint paint; + paint.setBlendMode(SkBlendMode::kLighten); + dump_keys(&dict, paint); + } + + { + SkPaint paint; + paint.setShader(make_image_shader(16, 16, SkTileMode::kClamp, + SkTileMode::kRepeat, SK_ColorRED)); + dump_keys(&dict, paint); + } + + { + SkPaint paint; + paint.setShader(make_linear_gradient_shader(SkTileMode::kClamp)); + dump_keys(&dict, paint); + } + + { + SkPaint paint; + auto shaderA = make_image_shader(16, 16, SkTileMode::kDecal, + SkTileMode::kRepeat, SK_ColorBLUE); + auto shaderB = make_linear_gradient_shader(SkTileMode::kClamp); + paint.setShader(make_blend_shader(std::move(shaderA), std::move(shaderB), + SkBlendMode::kDstIn)); + dump_keys(&dict, paint); + } +}