[graphite] Add first version of Blend Shader support

This CL adds children to the SkPaintParamsKey and ShaderInfo objects and then uses them to implement the blend shader glue code.

Bug: skia:12701
Change-Id: I6750fe375b20a5c1cda315336bfcb3feda8cab28
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/505297
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2022-02-15 11:29:08 -05:00 committed by SkCQ
parent c13cd6479d
commit ee910053ec
5 changed files with 155 additions and 14 deletions

View File

@ -547,7 +547,7 @@ void AddToKey(SkShaderCodeDictionary* dict,
if (backend == SkBackend::kGraphite) {
int headerOffset = key->beginBlock(SkBuiltInCodeSnippetID::kBlendShader);
add_blendmode_to_key(key, blendData.fBM);
// Child blocks always go right after the parent block's header
int start = key->sizeInBytes();
as_SB(blendData.fDst)->addToKey(dict, backend, key, uniformBlock);
int firstShaderSize = key->sizeInBytes() - start;
@ -556,6 +556,8 @@ void AddToKey(SkShaderCodeDictionary* dict,
as_SB(blendData.fSrc)->addToKey(dict, backend, key, uniformBlock);
int secondShaderSize = key->sizeInBytes() - start;
add_blendmode_to_key(key, blendData.fBM);
key->endBlock(headerOffset, SkBuiltInCodeSnippetID::kBlendShader);
int expectedBlockSize = 1 + firstShaderSize + secondShaderSize;
@ -581,18 +583,19 @@ void Dump(const SkPaintParamsKey& key, int headerOffset) {
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);
runningOffset += secondBlockSize;
uint8_t data = key.byte(runningOffset);
SkBlendMode bm = to_blendmode(data);
SkDebugf("BlendMode: %s\n", SkBlendMode_Name(bm));
runningOffset += 1; // 1 byte for blendmode
int calculatedBlockSize = SkPaintParamsKey::kBlockHeaderSizeInBytes +
firstBlockSize + secondBlockSize + 1;

View File

@ -84,6 +84,16 @@ int SkPaintParamsKey::AddBlockToShaderInfo(SkShaderCodeDictionary* dict,
result->add(*entry);
// The child blocks appear right after the parent block's header in the key and go
// right after the parent's SnippetEntry in the shader info
int childOffset = headerOffset + kBlockHeaderSizeInBytes;
for (int i = 0; i < entry->fNumChildren; ++i) {
SkASSERT(childOffset < headerOffset + blockSize);
int childBlockSize = AddBlockToShaderInfo(dict, key, childOffset, result);
childOffset += childBlockSize;
}
if (codeSnippetID != SkBuiltInCodeSnippetID::kDepthStencilOnlyDraw) {
result->setWritesColor();
}

View File

@ -23,8 +23,12 @@ class SkShaderInfo;
// This class is a compact representation of the shader needed to implement a given
// PaintParams. Its structure is a series of blocks where each block has a
// header that consists of 2-bytes - a 1-byte code-snippet ID and a 1-byte number-of-bytes-in-the-
// block field. The rest of the data in the block is dependent on the individual code snippet.
// header that consists of 2-bytes:
// a 1-byte code-snippet ID
// a 1-byte number-of-bytes-in-the-block field (incl. the space for the header)
// The rest of the data in the block is dependent on the individual code snippet.
// If a given block has child blocks, they appear in the key right after their
// parent block's header.
class SkPaintParamsKey {
public:
static const int kBlockHeaderSizeInBytes = 2;

View File

@ -36,7 +36,12 @@ std::string GetMtlUniforms(int bufferID,
//
// half4 outColor%d;
// {
// /* emitted snippet sksl assigns to outColor%d */
// half4 child-outColor%d; // for each child
// {
// /* emitted snippet sksl assigns to child-outColor%d */
// }
//
// /* emitted snippet sksl assigns to outColor%d - taking a vector of child var names */
// }
// Where the %d is filled in with 'entryIndex'.
std::string SkShaderInfo::emitGlueCodeForEntry(int* entryIndex,
@ -52,7 +57,17 @@ std::string SkShaderInfo::emitGlueCodeForEntry(int* entryIndex,
add_indent(result, indent);
*result += "{\n";
*result += (entry.fGlueCodeGenerator)(scopeOutputVar, curEntryIndex, entry, indent+1);
// Although the children appear after the parent in the shader info they are emitted
// before the parent
std::vector<std::string> childNames;
for (int j = 0; j < entry.fNumChildren; ++j) {
*entryIndex += 1;
std::string childOutputVar = this->emitGlueCodeForEntry(entryIndex, result, indent+1);
childNames.push_back(childOutputVar);
}
*result += (entry.fGlueCodeGenerator)(scopeOutputVar, curEntryIndex,
entry, childNames, indent+1);
add_indent(result, indent);
*result += "}\n";
@ -160,7 +175,10 @@ namespace {
std::string GenerateDefaultGlueCode(const std::string& resultName,
int entryIndex,
const SkShaderInfo::SnippetEntry& entry,
const std::vector<std::string>& childNames,
int indent) {
SkASSERT(childNames.empty());
std::string result;
add_indent(&result, indent);
@ -246,6 +264,99 @@ static const char* kImageShaderSkSL =
" return half4(c, c, c, 1.0);\n"
"}\n";
//--------------------------------------------------------------------------------------------------
static constexpr int kNumBlendShaderUniforms = 0;
static constexpr int kNumBlendShaderChildren = 2;
// Note: we're counting on the compiler to inline this code and trim it down to just the used
// branch(es).
static const char* kBlendShaderName = "blend_shader";
static const char* kBlendShaderSkSL =
"const int kClear = 0;\n"
"const int kSrc = 1;\n"
"const int kDst = 2;\n"
"const int kSrcOver = 3;\n"
"const int kDstOver = 4;\n"
"const int kSrcIn = 5;\n"
"const int kDstIn = 6;\n"
"const int kSrcOut = 7;\n"
"const int kDstOut = 8;\n"
"const int kSrcATop = 9;\n"
"const int kDstATop = 10;\n"
"const int kXor = 11;\n"
"const int kPlus = 12;\n"
"const int kModulate = 13;\n"
"const int kScreen = 14;\n"
"const int kOverlay = 15;\n"
"const int kDarken = 16;\n"
"const int kLighten = 17;\n"
"const int kColorDodge = 18;\n"
"const int kColorBurn = 19;\n"
"const int kHardLight = 20;\n"
"const int kSoftLight = 21;\n"
"const int kDifference = 22;\n"
"const int kExclusion = 23;\n"
"const int kMultiply = 24;\n"
"const int kHue = 25;\n"
"const int kSaturation = 26;\n"
"const int kColor = 27;\n"
"const int kLuminosity = 28;\n"
"\n"
"half4 blend(int mode, half4 src, half4 dst) {\n"
" switch (mode) {\n"
" case kClear: { return blend_clear(src, dst); }\n"
" case kSrc: { return blend_src(src, dst); }\n"
" case kDst: { return blend_dst(src, dst); }\n"
" case kSrcOver: { return blend_src_over(src, dst); }\n"
" case kDstOver: { return blend_dst_over(src, dst); }\n"
" case kSrcIn: { return blend_src_in(src, dst); }\n"
" case kDstIn: { return blend_dst_in(src, dst); }\n"
" case kSrcOut: { return blend_src_out(src, dst); }\n"
" case kDstOut: { return blend_dst_out(src, dst); }\n"
" case kSrcATop: { return blend_src_atop(src, dst); }\n"
" case kDstATop: { return blend_dst_atop(src, dst); }\n"
" case kXor: { return blend_xor(src, dst); }\n"
" case kPlus: { return blend_plus(src, dst); }\n"
" case kModulate: { return blend_modulate(src, dst); }\n"
" case kScreen: { return blend_screen(src, dst); }\n"
" case kOverlay: { return blend_overlay(src, dst); }\n"
" case kDarken: { return blend_darken(src, dst); }\n"
" case kLighten: { return blend_lighten(src, dst); }\n"
" case kColorDodge: { return blend_color_dodge(src, dst); }\n"
" case kColorBurn: { return blend_color_burn(src, dst); }\n"
" case kHardLight: { return blend_hard_light(src, dst); }\n"
" case kSoftLight: { return blend_soft_light(src, dst); }\n"
" case kDifference: { return blend_difference(src, dst); }\n"
" case kExclusion: { return blend_exclusion(src, dst); }\n"
" case kMultiply: { return blend_multiply(src, dst); }\n"
" case kHue: { return blend_hue(src, dst); }\n"
" case kSaturation: { return blend_saturation(src, dst); }\n"
" case kColor: { return blend_color(src, dst); }\n"
" case kLuminosity: { return blend_luminosity(src, dst); }\n"
" default: return half4(0); // Avoids 'blend can exit without returning a value' error\n"
" }\n"
"}\n";
std::string GenerateBlendShaderGlueCode(const std::string& resultName,
int entryIndex,
const SkShaderInfo::SnippetEntry& entry,
const std::vector<std::string>& childNames,
int indent) {
SkASSERT(childNames.size() == kNumBlendShaderChildren);
std::string result;
add_indent(&result, indent);
// TODO: actually feed in the blend mode either through a uniform or, somehow, from the
// SkPaintParamsKey
SkSL::String::appendf(&result, "%s = blend(kModulate, %s, %s);\n",
resultName.c_str(),
childNames[1].c_str(),
childNames[0].c_str());
return result;
}
//--------------------------------------------------------------------------------------------------
static constexpr int kNumErrorUniforms = 0;
static const char* kErrorName = "error";
@ -256,6 +367,8 @@ static const char* kErrorSkSL =
} // anonymous namespace
static constexpr int kNoChildren = 0;
SkShaderCodeDictionary::SkShaderCodeDictionary() {
// The 0th index is reserved as invalid
fEntryVector.push_back(nullptr);
@ -264,45 +377,54 @@ SkShaderCodeDictionary::SkShaderCodeDictionary() {
{ nullptr, kNumErrorUniforms },
kErrorName, kErrorSkSL,
GenerateDefaultGlueCode,
kNoChildren
};
fCodeSnippets[(int) SkBuiltInCodeSnippetID::kSolidColorShader] = {
SkMakeSpan(kSolidShaderUniforms, kNumSolidShaderUniforms),
kSolidShaderName, kSolidShaderSkSL,
GenerateDefaultGlueCode,
kNoChildren
};
fCodeSnippets[(int) SkBuiltInCodeSnippetID::kLinearGradientShader] = {
SkMakeSpan(kGradientUniforms, kNumGradientUniforms),
kLinearGradient4Name, kLinearGradient4SkSL,
GenerateDefaultGlueCode,
kNoChildren
};
fCodeSnippets[(int) SkBuiltInCodeSnippetID::kRadialGradientShader] = {
SkMakeSpan(kGradientUniforms, kNumGradientUniforms),
kLinearGradient4Name, kLinearGradient4SkSL,
GenerateDefaultGlueCode,
kNoChildren
};
fCodeSnippets[(int) SkBuiltInCodeSnippetID::kSweepGradientShader] = {
SkMakeSpan(kGradientUniforms, kNumGradientUniforms),
kLinearGradient4Name, kLinearGradient4SkSL,
GenerateDefaultGlueCode,
kNoChildren
};
fCodeSnippets[(int) SkBuiltInCodeSnippetID::kConicalGradientShader] = {
SkMakeSpan(kGradientUniforms, kNumGradientUniforms),
kLinearGradient4Name, kLinearGradient4SkSL,
GenerateDefaultGlueCode,
kNoChildren
};
fCodeSnippets[(int) SkBuiltInCodeSnippetID::kImageShader] = {
{ nullptr, kNumImageShaderUniforms },
kImageShaderName, kImageShaderSkSL,
GenerateDefaultGlueCode,
kNoChildren
};
fCodeSnippets[(int) SkBuiltInCodeSnippetID::kBlendShader] = {
{ nullptr, kNumErrorUniforms },
kErrorName, kErrorSkSL,
GenerateDefaultGlueCode,
{ nullptr, kNumBlendShaderUniforms },
kBlendShaderName, kBlendShaderSkSL,
GenerateBlendShaderGlueCode,
kNumBlendShaderChildren
};
fCodeSnippets[(int) SkBuiltInCodeSnippetID::kSimpleBlendMode] = {
{ nullptr, kNumErrorUniforms },
kErrorName, kErrorSkSL,
GenerateDefaultGlueCode,
kNoChildren
};
}

View File

@ -24,6 +24,7 @@ public:
using GenerateGlueCodeForEntry = std::string (*)(const std::string& resultName,
int entryIndex, // for uniform name mangling
const SnippetEntry&,
const std::vector<std::string>& childNames,
int indent);
struct SnippetEntry {
@ -31,6 +32,7 @@ public:
const char* fStaticFunctionName;
const char* fStaticSkSL;
GenerateGlueCodeForEntry fGlueCodeGenerator;
int fNumChildren;
};
void add(const SnippetEntry& entry) {