[graphite] Use CombinationBuilder to create SkPaintParamsKeys directly

Bug: skia:12701
Change-Id: I53bbabb2aba44e3bfc215df81dae1ae59d149263
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/544319
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2022-06-16 12:31:08 -04:00 committed by SkCQ
parent a444743005
commit 47a67a7f4f
7 changed files with 166 additions and 127 deletions

View File

@ -2167,7 +2167,7 @@ Result GraphiteSink::draw(const Src& src,
return result;
}
// For now we cast and call directly into Surface. Once we have a been idea of
// For now we cast and call directly into Surface. Once we have a better idea of
// what the public API for synchronous graphite readPixels we can update this call to use
// that instead.
SkPixmap pm;

View File

@ -19,6 +19,7 @@
class SkArenaAllocWithReset;
class SkCombinationBuilder;
class SkKeyContext;
class SkOption;
class SkPaintParamsKeyBuilder;
class SkShaderCodeDictionary;
@ -155,6 +156,9 @@ private:
return this->numShaderCombinations() * this->numBlendModeCombinations();
}
// 'desiredCombination' must be less than numCombinations
void createKey(const SkKeyContext&, int desiredCombination, SkPaintParamsKeyBuilder*);
#ifdef SK_DEBUG
void dump() const;
int epoch() const { return fEpoch; }

View File

@ -97,6 +97,8 @@ public:
int numCombinations() const;
void addToKey(const SkKeyContext&, int desiredCombination, SkPaintParamsKeyBuilder*);
#ifdef SK_DEBUG
void dump(int indent) const;
#endif
@ -155,6 +157,39 @@ public:
return this->numIntrinsicCombinations() * this->numChildCombinations();
}
void addToKey(const SkKeyContext& keyContext,
int desiredCombination,
SkPaintParamsKeyBuilder* keyBuilder) {
SkASSERT(desiredCombination < this->numCombinations());
int intrinsicCombination = desiredCombination / this->numChildCombinations();
int childCombination = desiredCombination % this->numChildCombinations();
this->beginBlock(keyContext, intrinsicCombination, keyBuilder);
if (fNumSlots) {
int numCombinationsSeen = 0;
for (int slotIndex = 0; slotIndex < fNumSlots; ++slotIndex) {
SkSlot* slot = this->getSlot(slotIndex);
numCombinationsSeen += slot->numCombinations();
int numCombosLeft = this->numChildCombinations() / numCombinationsSeen;
int slotCombination;
if (slotIndex+1 < fNumSlots) {
slotCombination = childCombination / (numCombosLeft ? numCombosLeft : 1);
childCombination %= numCombosLeft;
} else {
slotCombination = childCombination;
}
slot->addToKey(keyContext, slotCombination, keyBuilder);
}
}
keyBuilder->endBlock();
}
#ifdef SK_DEBUG
void dump(int indent = 0) const {
SkDebugf("%s", type_to_str(fType));
@ -211,6 +246,21 @@ int SkOption::SkSlot::numCombinations() const {
return numCombinations;
}
void SkOption::SkSlot::addToKey(const SkKeyContext& keyContext,
int desiredCombination,
SkPaintParamsKeyBuilder* keyBuilder) {
SkASSERT(desiredCombination < this->numCombinations());
for (SkOption* option = fHead; option; option = option->fNext) {
if (desiredCombination < option->numCombinations()) {
option->addToKey(keyContext, desiredCombination, keyBuilder);
return;
}
desiredCombination -= option->numCombinations();
}
}
#ifdef SK_DEBUG
void SkOption::SkSlot::dump(int indent) const {
SkDebugf("{ %d } ", this->numCombinations());
@ -657,6 +707,40 @@ void SkCombinationBuilder::dump() const {
}
#endif
void SkCombinationBuilder::createKey(const SkKeyContext& keyContext,
int desiredCombination,
SkPaintParamsKeyBuilder* keyBuilder) {
SkDEBUGCODE(keyBuilder->checkReset();)
SkASSERT(desiredCombination < this->numCombinations());
int numBlendModeCombos = this->numBlendModeCombinations();
int desiredShaderCombination = desiredCombination / numBlendModeCombos;
int desiredBlendCombination = desiredCombination % numBlendModeCombos;
for (SkOption* shaderOption : fShaderOptions) {
if (desiredShaderCombination < shaderOption->numCombinations()) {
shaderOption->addToKey(keyContext, desiredShaderCombination, keyBuilder);
break;
}
desiredShaderCombination -= shaderOption->numCombinations();
}
if (desiredBlendCombination < SkPopCount(fBlendModes)) {
int ith_set_bit = SkNthSet(fBlendModes, desiredBlendCombination);
SkASSERT(ith_set_bit < kSkBlendModeCount);
SkBlendMode bm = (SkBlendMode) ith_set_bit;
BlendModeBlock::BeginBlock(keyContext, keyBuilder, /*gatherer=*/nullptr, bm); // bm is used!
keyBuilder->endBlock();
} else {
// TODO: need to handle fBlenders here
}
}
void SkCombinationBuilder::buildCombinations(
SkShaderCodeDictionary* dict,
const std::function<void(SkUniquePaintParamsID)>& func) {
@ -673,23 +757,12 @@ void SkCombinationBuilder::buildCombinations(
this->addOption(SkShaderType::kSolidColor);
}
for (int i = 0; i < kSkBlendModeCount; ++i) {
if (!(fBlendModes & (0x1 << i))) {
continue;
}
int numCombos = this->numCombinations();
for (int i = 0; i < numCombos; ++i) {
this->createKey(keyContext, i, &builder);
SkBlendMode bm = (SkBlendMode) i;
auto entry = dict->findOrCreate(&builder);
// TODO: actually iterate over the SkOption's combinations and have each option add
// itself to the key.
for (SkOption* shaderOption : fShaderOptions) {
// TODO: expand CreateKey to take either an SkBlendMode or an SkBlendID
SkUniquePaintParamsID uniqueID = CreateKey(keyContext, &builder,
shaderOption->type(), bm);
func(uniqueID);
}
func(entry->uniqueID());
}
// TODO: need to loop over fBlenders here
}

View File

@ -641,106 +641,3 @@ const SkRuntimeEffect* TestingOnly_GetCommonRuntimeEffect() {
)");
return effect;
}
//--------------------------------------------------------------------------------------------------
// TODO: we need to feed the number of stops in the gradients into this method from the
// combination code
SkUniquePaintParamsID CreateKey(const SkKeyContext& keyContext,
SkPaintParamsKeyBuilder* builder,
SkShaderType s,
SkBlendMode bm) {
SkDEBUGCODE(builder->checkReset());
// TODO: split out the portion of the block data that is always required from the portion
// that is only required to gather uniforms. Right now we're passing in a lot of unused
// data and it is unclear what is actually used.
switch (s) {
case SkShaderType::kSolidColor:
SolidColorShaderBlock::BeginBlock(keyContext, builder, nullptr,
/* unused */ kErrorColor);
builder->endBlock();
break;
case SkShaderType::kLinearGradient:
GradientShaderBlocks::BeginBlock(keyContext, builder, nullptr,
// only the type and numStops are used
{ SkShader::kLinear_GradientType, 0 });
builder->endBlock();
break;
case SkShaderType::kRadialGradient:
GradientShaderBlocks::BeginBlock(keyContext, builder, nullptr,
// only the type and numStops are used
{ SkShader::kRadial_GradientType, 0 });
builder->endBlock();
break;
case SkShaderType::kSweepGradient:
GradientShaderBlocks::BeginBlock(keyContext, builder, nullptr,
// only the type and numStops are used
{ SkShader::kSweep_GradientType, 0 });
builder->endBlock();
break;
case SkShaderType::kConicalGradient:
GradientShaderBlocks::BeginBlock(keyContext, builder, nullptr,
// only the type and numStops are used
{ SkShader::kConical_GradientType, 0 });
builder->endBlock();
break;
case SkShaderType::kLocalMatrix:
LocalMatrixShaderBlock::BeginBlock(keyContext, builder, nullptr,
// matrix is unused
{ SkMatrix::I() });
{
// proxy shader
SolidColorShaderBlock::BeginBlock(keyContext, builder, nullptr,
/* unused */ kErrorColor);
builder->endBlock();
}
builder->endBlock();
break;
case SkShaderType::kImage:
ImageShaderBlock::BeginBlock(keyContext, builder, nullptr,
// none of the ImageData is used
{ SkSamplingOptions(),
SkTileMode::kClamp, SkTileMode::kClamp,
SkRect::MakeEmpty(), SkMatrix::I() });
builder->endBlock();
break;
case SkShaderType::kBlendShader:
BlendShaderBlock::BeginBlock(keyContext, builder, nullptr,
{ SkBlendMode::kSrc });
{
// dst
SolidColorShaderBlock::BeginBlock(keyContext, builder, nullptr,
/* unused */ kErrorColor);
builder->endBlock();
// src
SolidColorShaderBlock::BeginBlock(keyContext, builder, nullptr,
/* unused */ kErrorColor);
builder->endBlock();
}
builder->endBlock();
break;
case SkShaderType::kRuntimeShader:
{
const SkRuntimeEffect* effect = TestingOnly_GetCommonRuntimeEffect();
RuntimeShaderBlock::BeginBlock(
keyContext, builder, nullptr,
{sk_ref_sp(effect), SkMatrix::I(), /*uniforms=*/nullptr});
builder->endBlock();
}
break;
}
BlendModeBlock::BeginBlock(keyContext, builder, /* pipelineData*/ nullptr, bm); // 'bm' is used
builder->endBlock();
auto dict = keyContext.dict();
auto entry = dict->findOrCreate(builder);
return entry->uniqueID();
}

View File

@ -195,12 +195,6 @@ struct RuntimeShaderBlock {
const ShaderData&);
};
// Bridge between the combinations system and the SkPaintParamsKey
const SkRuntimeEffect* TestingOnly_GetCommonRuntimeEffect();
SkUniquePaintParamsID CreateKey(const SkKeyContext&,
SkPaintParamsKeyBuilder*,
SkShaderType,
SkBlendMode);
#endif // SkKeyHelpers_DEFINED

View File

@ -9,12 +9,25 @@
#define CombinationBuilderTestAccess_DEFINED
#include "include/core/SkCombinationBuilder.h"
#include "include/private/SkUniquePaintParamsID.h"
class CombinationBuilderTestAccess {
public:
static int NumCombinations(SkCombinationBuilder* builder) {
return builder->numCombinations();
}
static std::vector<SkUniquePaintParamsID> BuildCombinations(SkShaderCodeDictionary* dict,
SkCombinationBuilder* builder) {
std::vector<SkUniquePaintParamsID> uniqueIDs;
builder->buildCombinations(dict,
[&](SkUniquePaintParamsID uniqueID) {
uniqueIDs.push_back(uniqueID);
});
return uniqueIDs;
}
#ifdef SK_DEBUG
static int Epoch(const SkCombinationBuilder& builder) {
return builder.epoch();

View File

@ -28,6 +28,7 @@
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/ResourceProvider.h"
#include "src/shaders/SkImageShader.h"
#include "tests/graphite/CombinationBuilderTestAccess.h"
using namespace skgpu::graphite;
@ -106,6 +107,57 @@ std::tuple<SkPaint, int> create_paint(Recorder* recorder,
return { p, numTextures };
}
SkUniquePaintParamsID create_key(Context* context,
SkPaintParamsKeyBuilder* keyBuilder,
SkShaderType shaderType,
SkTileMode tileMode,
SkBlendMode blendMode) {
SkShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
SkCombinationBuilder combinationBuilder(context);
switch (shaderType) {
case SkShaderType::kSolidColor:
combinationBuilder.addOption(shaderType);
break;
case SkShaderType::kLinearGradient: [[fallthrough]];
case SkShaderType::kRadialGradient: [[fallthrough]];
case SkShaderType::kSweepGradient: [[fallthrough]];
case SkShaderType::kConicalGradient:
combinationBuilder.addOption(shaderType, 2, 2);
break;
case SkShaderType::kLocalMatrix: {
SkCombinationOption option = combinationBuilder.addOption(shaderType);
option.addChildOption(0, SkShaderType::kSolidColor);
} break;
case SkShaderType::kImage: {
SkTileModePair tilingOptions[] = { { tileMode, tileMode } };
combinationBuilder.addOption(shaderType, tilingOptions);
} break;
case SkShaderType::kBlendShader: {
SkCombinationOption option = combinationBuilder.addOption(shaderType);
option.addChildOption(0, SkShaderType::kSolidColor);
option.addChildOption(1, SkShaderType::kSolidColor);
} break;
case SkShaderType::kRuntimeShader: {
combinationBuilder.addOption(shaderType);
// TODO: this needs to be connected to the runtime effect from
// TestingOnly_GetCommonRuntimeEffect. Unfortunately, right now, we only have a
// way of adding runtime blenders to the combination system. For now, we skip this
// case below
} break;
}
combinationBuilder.addOption(blendMode);
std::vector<SkUniquePaintParamsID> uniqueIDs = CombinationBuilderTestAccess::BuildCombinations(
dict, &combinationBuilder);
SkASSERT(uniqueIDs.size() == 1);
return uniqueIDs[0];
}
} // anonymous namespace
// This is intended to be a smoke test for the agreement between the two ways of creating a
@ -148,6 +200,12 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(PaintParamsKeyTest, reporter, context) {
}
}
// TODO: re-enable this combination when we can add runtime shaders to the combination
// system.
if (s == SkShaderType::kRuntimeShader) {
continue;
}
// TODO: test out a runtime SkBlender here
for (auto bm : { SkBlendMode::kSrc, SkBlendMode::kSrcOver }) {
auto [ p, expectedNumTextures ] = create_paint(recorder.get(), s, tm, bm);
@ -155,7 +213,7 @@ DEF_GRAPHITE_TEST_FOR_CONTEXTS(PaintParamsKeyTest, reporter, context) {
auto [ uniqueID1, uIndex, tIndex] = ExtractPaintData(recorder.get(), &gatherer,
&builder, {}, PaintParams(p));
SkUniquePaintParamsID uniqueID2 = CreateKey(keyContext, &builder, s, bm);
SkUniquePaintParamsID uniqueID2 = create_key(context, &builder, s, tm, bm);
// ExtractPaintData and CreateKey agree
REPORTER_ASSERT(reporter, uniqueID1 == uniqueID2);