[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:
parent
c13cd6479d
commit
ee910053ec
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user