Improved whole-program dehydration and rehydration

This adds a Dehydrator.write(Program) to mirror the Rehydrator's
program() method and simplifies the API.

Change-Id: I1b6d6b722d0ce8e6a292132522f806e43d49ce85
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/502704
Reviewed-by: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
Ethan Nicholas 2022-02-03 16:03:17 -05:00 committed by SkCQ
parent 47045c9e06
commit 744116876e
10 changed files with 4855 additions and 4813 deletions

View File

@ -603,6 +603,34 @@ void Dehydrator::write(const std::vector<std::unique_ptr<ProgramElement>>& eleme
this->writeCommand(Rehydrator::kElementsComplete_Command);
}
void Dehydrator::write(const Program& program) {
this->writeCommand(Rehydrator::kProgram_Command);
// Collect the symbol tables so we can write out the count
std::vector<SymbolTable*> symbolTables;
SymbolTable* symbols = program.fSymbols.get();
while (symbols) {
symbolTables.push_back(symbols);
symbols = symbols->fParent.get();
}
this->writeU8(symbolTables.size());
// Write the symbol tables from the root down
for (int i = symbolTables.size() - 1; i >= 0; --i) {
this->write(*symbolTables[i]);
}
// Write the elements
this->write(program.fOwnedElements);
// Write the inputs
struct KnownSkSLProgramInputs { bool useRTFlipUniform; };
// Since it would be easy to forget to update this code in the face of Inputs changes and any
// resulting bugs could be very subtle, assert that the struct hasn't changed:
static_assert(sizeof(SkSL::Program::Inputs) == sizeof(KnownSkSLProgramInputs));
this->writeU8(program.fInputs.fUseFlipRTUniform);
}
void Dehydrator::finish(OutputStream& out) {
out.write16(Rehydrator::kVersion);
std::string stringBuffer = fStringBuffer.str();

View File

@ -23,6 +23,7 @@ namespace SkSL {
class AnyConstructor;
class Expression;
struct Program;
class ProgramElement;
class Statement;
class Symbol;
@ -45,6 +46,8 @@ public:
SkASSERT(fSymbolMap.size() == 1);
}
void write(const Program& program);
void write(const SymbolTable& symbols);
void write(const std::vector<std::unique_ptr<ProgramElement>>& elements);

View File

@ -15,6 +15,7 @@
#include "include/private/SkSLStatement.h"
#include "src/sksl/SkSLAnalysis.h"
#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLThreadContext.h"
#include "src/sksl/ir/SkSLBinaryExpression.h"
#include "src/sksl/ir/SkSLBreakStatement.h"
#include "src/sksl/ir/SkSLConstructor.h"
@ -89,8 +90,7 @@ Rehydrator::Rehydrator(const Compiler& compiler, const uint8_t* src, size_t leng
SkASSERT(fSymbolTable);
SkASSERT(fSymbolTable->isBuiltin());
fIP = src;
uint16_t version = this->readU16();
(void)version;
[[maybe_unused]] uint16_t version = this->readU16();
SkASSERTF(version == kVersion, "Dehydrated file is an unsupported version (current version is "
"%d, found version %d)", kVersion, version);
fStringStart = fIP;
@ -98,6 +98,13 @@ Rehydrator::Rehydrator(const Compiler& compiler, const uint8_t* src, size_t leng
fIP += this->readU16();
}
#ifdef SK_DEBUG
Rehydrator::~Rehydrator() {
// ensure that we have read the expected number of bytes
SkASSERT(fIP == fEnd);
}
#endif
Layout Rehydrator::layout() {
switch (this->readU8()) {
case kBuiltinLayout_Command: {
@ -259,16 +266,16 @@ const Type* Rehydrator::type() {
return (const Type*) result;
}
std::unique_ptr<Program> Rehydrator::program(int symbolTableCount,
std::unique_ptr<std::string> source,
std::unique_ptr<ProgramConfig> config,
std::vector<const ProgramElement*> sharedElements,
std::unique_ptr<ModifiersPool> modifiers,
std::unique_ptr<Pool> pool,
Program::Inputs inputs) {
std::unique_ptr<Program> Rehydrator::program(
const std::vector<const ProgramElement*>* sharedElements) {
[[maybe_unused]] uint8_t command = this->readU8();
SkASSERT(command == kProgram_Command);
uint8_t symbolTableCount = this->readU8();
ProgramConfig* oldConfig = fContext->fConfig;
ModifiersPool* oldModifiersPool = fContext->fModifiersPool;
auto config = std::make_unique<ProgramConfig>();
fContext->fConfig = config.get();
auto modifiers = std::make_unique<ModifiersPool>();
fContext->fModifiersPool = modifiers.get();
for (int i = 0; i < symbolTableCount; ++i) {
this->symbolTable();
@ -276,9 +283,13 @@ std::unique_ptr<Program> Rehydrator::program(int symbolTableCount,
std::vector<std::unique_ptr<ProgramElement>> elements = this->elements();
fContext->fConfig = oldConfig;
fContext->fModifiersPool = oldModifiersPool;
return std::make_unique<Program>(std::move(source), std::move(config), fContext,
std::move(elements), std::move(sharedElements), std::move(modifiers), fSymbolTable,
std::move(pool), inputs);
if (!sharedElements) {
sharedElements = &ThreadContext::SharedElements();
}
Program::Inputs inputs;
inputs.fUseFlipRTUniform = this->readU8();
return std::make_unique<Program>(nullptr, std::move(config), fContext, std::move(elements),
*sharedElements, std::move(modifiers), fSymbolTable, /*pool=*/nullptr, inputs);
}
std::vector<std::unique_ptr<ProgramElement>> Rehydrator::elements() {

View File

@ -34,7 +34,7 @@ class Type;
*/
class Rehydrator {
public:
static constexpr uint16_t kVersion = 5;
static constexpr uint16_t kVersion = 6;
enum Command {
// uint16 id, Type componentType, uint8 count
@ -110,6 +110,9 @@ public:
kPostfix_Command,
// uint8 op, Expression operand
kPrefix_Command,
// uint8_t symbolTableCount, SymbolTable[] symbolTables, Elements elements,
// bool useFlipRTUniform
kProgram_Command,
// Expression value
kReturn_Command,
// String name, Expression value
@ -149,20 +152,20 @@ public:
Rehydrator(const Compiler& compiler, const uint8_t* src, size_t length,
std::shared_ptr<SymbolTable> base = nullptr);
#ifdef SK_DEBUG
~Rehydrator();
#endif
// Reads a symbol table and makes it current (inheriting from the previous current table)
std::shared_ptr<SymbolTable> symbolTable();
// Reads a collection of program elements and returns it
std::vector<std::unique_ptr<ProgramElement>> elements();
// Reads an entire program
std::unique_ptr<Program> program(int symbolTableCount,
std::unique_ptr<std::string> source,
std::unique_ptr<ProgramConfig> config,
std::vector<const ProgramElement*> sharedElements,
std::unique_ptr<ModifiersPool> modifiers,
std::unique_ptr<Pool> pool,
Program::Inputs inputs);
// Reads an entire program. If the sharedElements are not provided, they will be pulled from the
// current ThreadContext.
std::unique_ptr<Program> program(
const std::vector<const ProgramElement*>* sharedElements = nullptr);
private:
// If this ID appears in a symbol table, it means the corresponding symbol isn't actually

View File

@ -1,4 +1,4 @@
static uint8_t SKSL_INCLUDE_sksl_frag[] = {5,0,96,0,
static uint8_t SKSL_INCLUDE_sksl_frag[] = {6,0,96,0,
12,115,107,95,70,114,97,103,67,111,111,114,100,
6,102,108,111,97,116,52,
12,115,107,95,67,108,111,99,107,119,105,115,101,
@ -7,52 +7,52 @@ static uint8_t SKSL_INCLUDE_sksl_frag[] = {5,0,96,0,
5,104,97,108,102,52,
16,115,107,95,76,97,115,116,70,114,97,103,67,111,108,111,114,
21,115,107,95,83,101,99,111,110,100,97,114,121,70,114,97,103,67,111,108,111,114,
49,1,5,0,
53,1,0,
50,1,5,0,
54,1,0,
37,
36,0,2,0,0,255,255,255,255,255,255,255,15,0,255,16,2,0,
50,2,0,15,0,0,
53,3,0,
51,2,0,15,0,0,
54,3,0,
37,
36,0,2,0,0,255,255,255,255,255,255,255,17,0,255,16,22,0,
50,4,0,35,0,0,
53,5,0,
51,4,0,35,0,0,
54,5,0,
37,
36,144,2,0,0,0,255,255,255,255,0,255,17,39,255,32,40,0,
50,6,0,53,0,0,
53,7,0,
51,6,0,53,0,0,
54,7,0,
37,
36,0,2,0,0,255,255,255,255,255,255,255,24,39,255,0,59,0,
48,6,0,0,
53,8,0,
49,6,0,0,
54,8,0,
37,
36,0,2,0,0,255,255,255,255,255,255,255,28,39,255,32,76,0,
48,6,0,0,5,0,
49,6,0,0,5,0,
1,0,
2,0,
0,0,
3,0,
4,0,
20,
55,
54,1,0,
48,2,0,0,
57,
55,
54,3,0,
48,4,0,0,
57,
55,
54,5,0,
48,6,0,0,
57,
55,
54,7,0,
48,6,0,0,
57,
55,
54,8,0,
48,6,0,0,
57,
56,
55,1,0,
49,2,0,0,
58,
56,
55,3,0,
49,4,0,0,
58,
56,
55,5,0,
49,6,0,0,
58,
56,
55,7,0,
49,6,0,0,
58,
56,
55,8,0,
49,6,0,0,
58,
21,};
static constexpr size_t SKSL_INCLUDE_sksl_frag_LENGTH = sizeof(SKSL_INCLUDE_sksl_frag);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,16 @@
static uint8_t SKSL_INCLUDE_sksl_rt_shader[] = {5,0,20,0,
static uint8_t SKSL_INCLUDE_sksl_rt_shader[] = {6,0,20,0,
12,115,107,95,70,114,97,103,67,111,111,114,100,
6,102,108,111,97,116,52,
49,1,1,0,
53,1,0,
50,1,1,0,
54,1,0,
37,
36,0,2,0,0,255,255,255,255,255,255,255,15,0,255,0,2,0,
50,2,0,15,0,0,1,0,
51,2,0,15,0,0,1,0,
0,0,
20,
55,
54,1,0,
48,2,0,0,
57,
56,
55,1,0,
49,2,0,0,
58,
21,};
static constexpr size_t SKSL_INCLUDE_sksl_rt_shader_LENGTH = sizeof(SKSL_INCLUDE_sksl_rt_shader);

View File

@ -1,4 +1,4 @@
static uint8_t SKSL_INCLUDE_sksl_vert[] = {5,0,82,0,
static uint8_t SKSL_INCLUDE_sksl_vert[] = {6,0,82,0,
12,115,107,95,80,101,114,86,101,114,116,101,120,
11,115,107,95,80,111,115,105,116,105,111,110,
6,102,108,111,97,116,52,
@ -8,42 +8,42 @@ static uint8_t SKSL_INCLUDE_sksl_vert[] = {5,0,82,0,
3,105,110,116,
13,115,107,95,73,110,115,116,97,110,99,101,73,68,
0,
49,1,6,0,
45,1,0,2,0,2,
50,1,6,0,
46,1,0,2,0,2,
37,
36,0,2,0,0,255,255,255,255,255,255,255,0,0,255,0,15,0,
50,2,0,27,0,
51,2,0,27,0,
37,
36,0,2,0,0,255,255,255,255,255,255,255,1,0,255,0,34,0,
50,3,0,47,0,1,
53,4,0,
51,3,0,47,0,1,
54,4,0,
37,
16,32,2,0,
48,1,0,0,
49,1,0,0,
23,4,0,0,
23,4,0,1,
53,5,0,
54,5,0,
37,
36,0,2,0,0,255,255,255,255,255,255,255,42,0,255,16,53,0,
50,6,0,65,0,0,
53,7,0,
51,6,0,65,0,0,
54,7,0,
37,
36,0,2,0,0,255,255,255,255,255,255,255,43,0,255,16,69,0,
48,6,0,0,4,0,
49,6,0,0,4,0,
5,0,
3,0,
2,0,
4,0,
20,
34,
48,4,0,2,0,83,0,0,
55,
54,5,0,
48,6,0,0,
57,
55,
54,7,0,
48,6,0,0,
57,
49,4,0,2,0,83,0,0,
56,
55,5,0,
49,6,0,0,
58,
56,
55,7,0,
49,6,0,0,
58,
21,};
static constexpr size_t SKSL_INCLUDE_sksl_vert_LENGTH = sizeof(SKSL_INCLUDE_sksl_vert);

View File

@ -240,16 +240,13 @@ static void test_rehydrate(skiatest::Reporter* r, const char* testFile) {
return;
}
SkSL::Dehydrator dehydrator;
int symbolTableCount = write_symbol_tables(dehydrator, *program->fSymbols);
dehydrator.write(program->fOwnedElements);
dehydrator.write(*program);
SkSL::StringStream stream;
dehydrator.finish(stream);
SkSL::Rehydrator rehydrator(compiler, (const uint8_t*) stream.str().data(),
stream.str().length());
std::unique_ptr<SkSL::Program> rehydrated = rehydrator.program(symbolTableCount,
/*source=*/nullptr, std::make_unique<SkSL::ProgramConfig>(), program->fSharedElements,
std::make_unique<SkSL::ModifiersPool>(), /*pool=*/nullptr, program->fInputs);
std::unique_ptr<SkSL::Program> rehydrated = rehydrator.program(&program->fSharedElements);
REPORTER_ASSERT(r, rehydrated->description() == program->description(),
"Mismatch between original and dehydrated/rehydrated:\n-- Original:\n%s\n"
"-- Rehydrated:\n%s", program->description().c_str(),