[graphite] Add SkPaintParamsKey::BlockReader class
This class hides a lot of the finicky details of block handling and provides a structured means of accessing an SkPaintParamsKey's data payload. In a following CL this will be used to expose the SkPaintParamsKey's data to the snippet glue code. Bug: skia:12701 Change-Id: I6554940429c7c6e048cfd37533951c61cf255408 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/516337 Reviewed-by: Michael Ludwig <michaelludwig@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
0c43db950c
commit
6509844d91
@ -196,62 +196,13 @@ bool SkPaintParamsKey::operator==(const SkPaintParamsKey& that) const {
|
||||
!memcmp(fData.data(), that.fData.data(), fData.size());
|
||||
}
|
||||
|
||||
SkPaintParamsKey::BlockReader SkPaintParamsKey::reader(const SkShaderCodeDictionary* dict,
|
||||
int headerOffset) const {
|
||||
return BlockReader(dict, fData, headerOffset);
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
|
||||
namespace {
|
||||
|
||||
void output_indent(int indent) {
|
||||
for (int i = 0; i < indent; ++i) {
|
||||
SkDebugf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
int dump_block(const SkShaderCodeDictionary* dict,
|
||||
const SkPaintParamsKey& key,
|
||||
int headerOffset,
|
||||
int indent) {
|
||||
uint8_t id = key.byte(headerOffset);
|
||||
uint8_t blockSize = key.byte(headerOffset+1);
|
||||
SkASSERT(blockSize >= 2 && headerOffset+blockSize <= key.sizeInBytes());
|
||||
|
||||
auto entry = dict->getEntry(id);
|
||||
if (!entry) {
|
||||
output_indent(indent);
|
||||
SkDebugf("unknown block! (%dB)\n", blockSize);
|
||||
}
|
||||
|
||||
output_indent(indent);
|
||||
SkDebugf("%s block (%dB)\n", entry->fStaticFunctionName, blockSize);
|
||||
|
||||
int curOffset = headerOffset + SkPaintParamsKey::kBlockHeaderSizeInBytes;
|
||||
|
||||
for (int i = 0; i < entry->fNumChildren; ++i) {
|
||||
output_indent(indent);
|
||||
// TODO: it would be nice if the names of the children were also stored (i.e., "src"/"dst")
|
||||
SkDebugf("child %d:\n", i);
|
||||
|
||||
int childSize = dump_block(dict, key, curOffset, indent+1);
|
||||
curOffset += childSize;
|
||||
}
|
||||
|
||||
for (auto e : entry->fDataPayloadExpectations) {
|
||||
output_indent(indent);
|
||||
SkDebugf("%s[%d]: ", e.fName, e.fCount);
|
||||
// TODO: add some sort of templatized reader object for this
|
||||
SkASSERT(e.fType == SkPaintParamsKey::DataPayloadType::kByte);
|
||||
for (uint32_t i = 0; i < e.fCount; ++i) {
|
||||
output_indent(indent);
|
||||
SkDebugf("%d,", key.byte(curOffset));
|
||||
++curOffset;
|
||||
}
|
||||
SkDebugf("\n");
|
||||
}
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// This just iterates over the top-level blocks calling block-specific dump methods.
|
||||
void SkPaintParamsKey::dump(const SkShaderCodeDictionary* dict) const {
|
||||
SkDebugf("--------------------------------------\n");
|
||||
@ -259,45 +210,39 @@ void SkPaintParamsKey::dump(const SkShaderCodeDictionary* dict) const {
|
||||
|
||||
int curHeaderOffset = 0;
|
||||
while (curHeaderOffset < this->sizeInBytes()) {
|
||||
int blockSize = dump_block(dict, *this, curHeaderOffset, 0);
|
||||
curHeaderOffset += blockSize;
|
||||
BlockReader reader = this->reader(dict, curHeaderOffset);
|
||||
reader.dump(dict, /* indent */ 0);
|
||||
curHeaderOffset += reader.blockSize();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // SK_DEBUG
|
||||
|
||||
int SkPaintParamsKey::AddBlockToShaderInfo(SkShaderCodeDictionary* dict,
|
||||
const SkPaintParamsKey& key,
|
||||
int headerOffset,
|
||||
SkShaderInfo* result) {
|
||||
auto [codeSnippetID, blockSize] = key.readCodeSnippetID(headerOffset);
|
||||
void SkPaintParamsKey::AddBlockToShaderInfo(SkShaderCodeDictionary* dict,
|
||||
const SkPaintParamsKey::BlockReader& reader,
|
||||
SkShaderInfo* result) {
|
||||
|
||||
auto entry = dict->getEntry(codeSnippetID);
|
||||
|
||||
result->add(*entry);
|
||||
result->add(*reader.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);
|
||||
for (int i = 0; i < reader.numChildren(); ++i) {
|
||||
SkPaintParamsKey::BlockReader childReader = reader.child(dict, i);
|
||||
|
||||
int childBlockSize = AddBlockToShaderInfo(dict, key, childOffset, result);
|
||||
childOffset += childBlockSize;
|
||||
AddBlockToShaderInfo(dict, childReader, result);
|
||||
}
|
||||
|
||||
if (codeSnippetID != SkBuiltInCodeSnippetID::kDepthStencilOnlyDraw) {
|
||||
if (reader.codeSnippetId() != SkBuiltInCodeSnippetID::kDepthStencilOnlyDraw) {
|
||||
result->setWritesColor();
|
||||
}
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
void SkPaintParamsKey::toShaderInfo(SkShaderCodeDictionary* dict, SkShaderInfo* result) const {
|
||||
|
||||
int curHeaderOffset = 0;
|
||||
while (curHeaderOffset < this->sizeInBytes()) {
|
||||
int blockSize = AddBlockToShaderInfo(dict, *this, curHeaderOffset, result);
|
||||
curHeaderOffset += blockSize;
|
||||
SkPaintParamsKey::BlockReader reader = this->reader(dict, curHeaderOffset);
|
||||
AddBlockToShaderInfo(dict, reader, result);
|
||||
curHeaderOffset += reader.blockSize();
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,3 +253,125 @@ bool SkPaintParamsKey::isErrorKey() const {
|
||||
fData[1] == SkPaintParamsKey::kBlockHeaderSizeInBytes;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
void output_indent(int indent) {
|
||||
for (int i = 0; i < indent; ++i) {
|
||||
SkDebugf(" ");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::pair<SkBuiltInCodeSnippetID, uint8_t> read_header(SkSpan<const uint8_t> parentSpan,
|
||||
int headerOffset) {
|
||||
SkASSERT(headerOffset + SkPaintParamsKey::kBlockHeaderSizeInBytes <=
|
||||
SkTo<int>(parentSpan.size()));
|
||||
|
||||
SkBuiltInCodeSnippetID id = static_cast<SkBuiltInCodeSnippetID>(parentSpan[headerOffset]);
|
||||
uint8_t blockSize = parentSpan[headerOffset+SkPaintParamsKey::kBlockSizeOffsetInBytes];
|
||||
SkASSERT(blockSize >= SkPaintParamsKey::kBlockHeaderSizeInBytes);
|
||||
SkASSERT(headerOffset + blockSize <= static_cast<int>(parentSpan.size()));
|
||||
|
||||
return { id, blockSize };
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SkPaintParamsKey::BlockReader::BlockReader(const SkShaderCodeDictionary* dict,
|
||||
SkSpan<const uint8_t> parentSpan,
|
||||
int offsetInParent) {
|
||||
auto [codeSnippetID, blockSize] = read_header(parentSpan, offsetInParent);
|
||||
|
||||
fBlock = parentSpan.subspan(offsetInParent, blockSize);
|
||||
fEntry = dict->getEntry(codeSnippetID);
|
||||
SkASSERT(fEntry);
|
||||
}
|
||||
|
||||
int SkPaintParamsKey::BlockReader::numChildren() const { return fEntry->fNumChildren; }
|
||||
|
||||
SkPaintParamsKey::BlockReader SkPaintParamsKey::BlockReader::child(
|
||||
const SkShaderCodeDictionary* dict,
|
||||
int childIndex) const {
|
||||
SkASSERT(childIndex < fEntry->fNumChildren);
|
||||
|
||||
int childOffset = kBlockHeaderSizeInBytes;
|
||||
for (int i = 0; i < childIndex; ++i) {
|
||||
auto [_, childBlockSize] = read_header(fBlock, childOffset);
|
||||
childOffset += childBlockSize;
|
||||
}
|
||||
|
||||
return BlockReader(dict, fBlock, childOffset);
|
||||
}
|
||||
|
||||
SkSpan<const uint8_t> SkPaintParamsKey::BlockReader::dataPayload() const {
|
||||
int payloadOffset = kBlockHeaderSizeInBytes;
|
||||
for (int i = 0; i < fEntry->fNumChildren; ++i) {
|
||||
auto [_, childBlockSize] = read_header(fBlock, payloadOffset);
|
||||
payloadOffset += childBlockSize;
|
||||
}
|
||||
|
||||
int payloadSize = this->blockSize() - payloadOffset;
|
||||
return fBlock.subspan(payloadOffset, payloadSize);
|
||||
}
|
||||
|
||||
SkSpan<const uint8_t> SkPaintParamsKey::BlockReader::bytes(int fieldIndex) const {
|
||||
SkASSERT(fEntry->fDataPayloadExpectations[fieldIndex].fType == DataPayloadType::kByte);
|
||||
|
||||
int byteOffsetInPayload = 0;
|
||||
for (int i = 0; i < fieldIndex; ++i) {
|
||||
SkASSERT(fEntry->fDataPayloadExpectations[i].fType == DataPayloadType::kByte);
|
||||
byteOffsetInPayload += fEntry->fDataPayloadExpectations[i].fCount;
|
||||
}
|
||||
|
||||
SkSpan<const uint8_t> dataPayload = this->dataPayload();
|
||||
return dataPayload.subspan(byteOffsetInPayload,
|
||||
fEntry->fDataPayloadExpectations[fieldIndex].fCount);
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
|
||||
int SkPaintParamsKey::BlockReader::numDataPayloadFields() const {
|
||||
return fEntry->fDataPayloadExpectations.size();
|
||||
}
|
||||
|
||||
void SkPaintParamsKey::BlockReader::dump(const SkShaderCodeDictionary* dict, int indent) const {
|
||||
uint8_t id = static_cast<uint8_t>(this->codeSnippetId());
|
||||
uint8_t blockSize = this->blockSize();
|
||||
|
||||
auto entry = dict->getEntry(id);
|
||||
if (!entry) {
|
||||
output_indent(indent);
|
||||
SkDebugf("unknown block! (%dB)\n", blockSize);
|
||||
}
|
||||
|
||||
output_indent(indent);
|
||||
SkDebugf("%s block (%dB)\n", entry->fStaticFunctionName, blockSize);
|
||||
|
||||
for (int i = 0; i < this->numChildren(); ++i) {
|
||||
output_indent(indent);
|
||||
// TODO: it would be nice if the names of the children were also stored (i.e., "src"/"dst")
|
||||
SkDebugf("child %d:\n", i);
|
||||
|
||||
SkPaintParamsKey::BlockReader childReader = this->child(dict, i);
|
||||
childReader.dump(dict, indent+1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int) fEntry->fDataPayloadExpectations.size(); ++i) {
|
||||
output_indent(indent);
|
||||
SkDebugf("%s[%d]: ",
|
||||
fEntry->fDataPayloadExpectations[i].fName,
|
||||
fEntry->fDataPayloadExpectations[i].fCount);
|
||||
SkSpan<const uint8_t> bytes = this->bytes(i);
|
||||
for (uint8_t b : bytes) {
|
||||
SkDebugf("%d,", b);
|
||||
}
|
||||
|
||||
SkDebugf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SK_DEBUG
|
||||
|
@ -22,10 +22,10 @@ enum class SkBackend : uint8_t {
|
||||
kGraphite,
|
||||
kSkVM
|
||||
};
|
||||
struct SkDataPayloadInfo;
|
||||
class SkPaintParamsKeyBuilder;
|
||||
class SkShaderCodeDictionary;
|
||||
class SkShaderInfo;
|
||||
struct SkShaderSnippet;
|
||||
|
||||
// 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
|
||||
@ -56,15 +56,50 @@ public:
|
||||
|
||||
~SkPaintParamsKey();
|
||||
|
||||
std::pair<SkBuiltInCodeSnippetID, uint8_t> readCodeSnippetID(int headerOffset) const {
|
||||
SkASSERT(headerOffset <= this->sizeInBytes() - kBlockHeaderSizeInBytes);
|
||||
class BlockReader {
|
||||
public:
|
||||
uint8_t blockSize() const {
|
||||
SkASSERT(fBlock[kBlockSizeOffsetInBytes] == fBlock.size());
|
||||
return SkTo<uint8_t>(fBlock.size());
|
||||
}
|
||||
|
||||
SkBuiltInCodeSnippetID id = static_cast<SkBuiltInCodeSnippetID>(fData[headerOffset]);
|
||||
uint8_t blockSize = fData[headerOffset+1];
|
||||
SkASSERT(headerOffset + blockSize <= this->sizeInBytes());
|
||||
int numChildren() const;
|
||||
|
||||
return { id, blockSize };
|
||||
}
|
||||
// Return the childIndex-th child's BlockReader
|
||||
BlockReader child(const SkShaderCodeDictionary*, int childIndex) const;
|
||||
|
||||
// Retrieve the fieldIndex-th field in the data payload as a span of bytes. The type
|
||||
// being read (bytes in this case) is checked against the data payload's structure.
|
||||
SkSpan<const uint8_t> bytes(int fieldIndex) const;
|
||||
// TODO: add more types (as needed) and their corresponding access methods
|
||||
|
||||
const SkShaderSnippet* entry() const { return fEntry; }
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
int numDataPayloadFields() const;
|
||||
void dump(const SkShaderCodeDictionary*, int indent) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class SkPaintParamsKey; // for ctor
|
||||
|
||||
BlockReader(const SkShaderCodeDictionary*,
|
||||
SkSpan<const uint8_t> parentSpan,
|
||||
int offsetInParent);
|
||||
|
||||
SkBuiltInCodeSnippetID codeSnippetId() const {
|
||||
return static_cast<SkBuiltInCodeSnippetID>(fBlock[0]);
|
||||
}
|
||||
|
||||
// The data payload appears after any children and occupies the remainder of the
|
||||
// block's space.
|
||||
SkSpan<const uint8_t> dataPayload() const;
|
||||
|
||||
SkSpan<const uint8_t> fBlock;
|
||||
const SkShaderSnippet* fEntry;
|
||||
};
|
||||
|
||||
BlockReader reader(const SkShaderCodeDictionary*, int headerOffset) const;
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
uint8_t byte(int offset) const {
|
||||
@ -99,10 +134,9 @@ private:
|
||||
// is in the dictionary). In this case the dictionary will own the memory backing the span.
|
||||
SkPaintParamsKey(SkSpan<const uint8_t> rawData);
|
||||
|
||||
static int AddBlockToShaderInfo(SkShaderCodeDictionary*,
|
||||
const SkPaintParamsKey&,
|
||||
int headerOffset,
|
||||
SkShaderInfo*);
|
||||
static void AddBlockToShaderInfo(SkShaderCodeDictionary*,
|
||||
const SkPaintParamsKey::BlockReader&,
|
||||
SkShaderInfo*);
|
||||
|
||||
// The memory referenced in 'fData' is always owned by someone else.
|
||||
// If 'fOriginatingBuilder' is null, the dictionary's SkArena owns the memory and no explicit
|
||||
|
Loading…
Reference in New Issue
Block a user