[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 <michaelludwig@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2022-01-20 16:04:03 -05:00 committed by SkCQ
parent 6edd5d9e19
commit 7e8fdf4706
10 changed files with 268 additions and 0 deletions

View File

@ -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",

View File

@ -32,6 +32,9 @@ enum class CodeSnippetID : uint8_t {
kSweepGradientShader,
kConicalGradientShader,
kImageShader,
kBlendShader, // aka ComposeShader
// BlendMode code snippets
kSimpleBlendMode,

View File

@ -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<uint8_t>(imgData.fTileModes[0]) << kXTileModeShift) |
(static_cast<uint8_t>(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 {

View File

@ -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);

View File

@ -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;

View File

@ -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<GrFragmentProcessor> 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 });
}

View File

@ -28,6 +28,10 @@ public:
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
#endif
void addToKey(SkShaderCodeDictionary*,
SkBackend,
SkPaintParamsKey*) const override;
protected:
SkShader_Blend(SkReadBuffer&);
void flatten(SkWriteBuffer&) const override;

View File

@ -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<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
#endif
void SkImageShader::addToKey(SkShaderCodeDictionary* dict,
SkBackend backend,
SkPaintParamsKey* key) const {
ImageShaderBlock::AddToKey(backend, key, { fTileModeX, fTileModeY });
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "src/core/SkImagePriv.h"

View File

@ -44,6 +44,10 @@ public:
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
#endif
void addToKey(SkShaderCodeDictionary*,
SkBackend,
SkPaintParamsKey*) const override;
static SkM44 CubicResamplerMatrix(float B, float C);
private:

View File

@ -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<SkShader> 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<SkShader> 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<SkShader> make_blend_shader(sk_sp<SkShader> shaderA,
sk_sp<SkShader> 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);
}
}