2020-07-28 18:46:53 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2020 Google LLC
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "src/sksl/SkSLDehydrator.h"
|
|
|
|
|
2020-08-26 23:46:27 +00:00
|
|
|
#include <map>
|
|
|
|
|
2020-07-28 18:46:53 +00:00
|
|
|
#include "src/sksl/SkSLRehydrator.h"
|
|
|
|
#include "src/sksl/ir/SkSLBinaryExpression.h"
|
|
|
|
#include "src/sksl/ir/SkSLBreakStatement.h"
|
|
|
|
#include "src/sksl/ir/SkSLConstructor.h"
|
|
|
|
#include "src/sksl/ir/SkSLContinueStatement.h"
|
|
|
|
#include "src/sksl/ir/SkSLDiscardStatement.h"
|
|
|
|
#include "src/sksl/ir/SkSLDoStatement.h"
|
|
|
|
#include "src/sksl/ir/SkSLEnum.h"
|
|
|
|
#include "src/sksl/ir/SkSLExpressionStatement.h"
|
|
|
|
#include "src/sksl/ir/SkSLField.h"
|
|
|
|
#include "src/sksl/ir/SkSLFieldAccess.h"
|
|
|
|
#include "src/sksl/ir/SkSLForStatement.h"
|
|
|
|
#include "src/sksl/ir/SkSLFunctionCall.h"
|
|
|
|
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
|
|
|
|
#include "src/sksl/ir/SkSLFunctionDefinition.h"
|
|
|
|
#include "src/sksl/ir/SkSLIfStatement.h"
|
|
|
|
#include "src/sksl/ir/SkSLIndexExpression.h"
|
2020-09-09 18:18:53 +00:00
|
|
|
#include "src/sksl/ir/SkSLInlineMarker.h"
|
2020-07-28 18:46:53 +00:00
|
|
|
#include "src/sksl/ir/SkSLIntLiteral.h"
|
|
|
|
#include "src/sksl/ir/SkSLInterfaceBlock.h"
|
|
|
|
#include "src/sksl/ir/SkSLPostfixExpression.h"
|
|
|
|
#include "src/sksl/ir/SkSLPrefixExpression.h"
|
|
|
|
#include "src/sksl/ir/SkSLProgramElement.h"
|
|
|
|
#include "src/sksl/ir/SkSLReturnStatement.h"
|
|
|
|
#include "src/sksl/ir/SkSLSetting.h"
|
|
|
|
#include "src/sksl/ir/SkSLStatement.h"
|
2020-11-25 21:24:55 +00:00
|
|
|
#include "src/sksl/ir/SkSLStructDefinition.h"
|
2020-07-28 18:46:53 +00:00
|
|
|
#include "src/sksl/ir/SkSLSwitchCase.h"
|
|
|
|
#include "src/sksl/ir/SkSLSwitchStatement.h"
|
|
|
|
#include "src/sksl/ir/SkSLSwizzle.h"
|
|
|
|
#include "src/sksl/ir/SkSLSymbol.h"
|
2020-10-06 20:14:37 +00:00
|
|
|
#include "src/sksl/ir/SkSLSymbolAlias.h"
|
2020-07-28 18:46:53 +00:00
|
|
|
#include "src/sksl/ir/SkSLSymbolTable.h"
|
|
|
|
#include "src/sksl/ir/SkSLTernaryExpression.h"
|
|
|
|
#include "src/sksl/ir/SkSLUnresolvedFunction.h"
|
|
|
|
#include "src/sksl/ir/SkSLVarDeclarations.h"
|
|
|
|
#include "src/sksl/ir/SkSLVariable.h"
|
|
|
|
|
|
|
|
#ifdef SKSL_STANDALONE
|
|
|
|
|
|
|
|
namespace SkSL {
|
|
|
|
|
|
|
|
static constexpr int HEADER_SIZE = 2;
|
|
|
|
|
|
|
|
class AutoDehydratorSymbolTable {
|
|
|
|
public:
|
|
|
|
AutoDehydratorSymbolTable(Dehydrator* dehydrator, const std::shared_ptr<SymbolTable>& symbols)
|
|
|
|
: fDehydrator(dehydrator) {
|
|
|
|
dehydrator->fSymbolMap.emplace_back();
|
|
|
|
if (symbols) {
|
|
|
|
dehydrator->write(*symbols);
|
|
|
|
} else {
|
2020-10-08 17:56:46 +00:00
|
|
|
dehydrator->writeCommand(Rehydrator::kVoid_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~AutoDehydratorSymbolTable() {
|
|
|
|
fDehydrator->fSymbolMap.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Dehydrator* fDehydrator;
|
|
|
|
};
|
|
|
|
|
|
|
|
void Dehydrator::write(Layout l) {
|
|
|
|
if (l == Layout()) {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kDefaultLayout_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
} else if (l == Layout::builtin(l.fBuiltin)) {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kBuiltinLayout_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeS16(l.fBuiltin);
|
|
|
|
} else {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kLayout_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
fBody.write32(l.fFlags);
|
|
|
|
this->writeS8(l.fLocation);
|
|
|
|
this->writeS8(l.fOffset);
|
|
|
|
this->writeS8(l.fBinding);
|
|
|
|
this->writeS8(l.fIndex);
|
|
|
|
this->writeS8(l.fSet);
|
|
|
|
this->writeS16(l.fBuiltin);
|
|
|
|
this->writeS8(l.fInputAttachmentIndex);
|
|
|
|
this->writeS8(l.fPrimitive);
|
|
|
|
this->writeS8(l.fMaxVertices);
|
|
|
|
this->writeS8(l.fInvocations);
|
|
|
|
this->write(l.fMarker);
|
|
|
|
this->write(l.fWhen);
|
|
|
|
this->writeS8((int) l.fCType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::write(Modifiers m) {
|
|
|
|
if (m == Modifiers()) {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kDefaultModifiers_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
} else {
|
|
|
|
if (m.fFlags <= 255) {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kModifiers8Bit_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->write(m.fLayout);
|
|
|
|
this->writeU8(m.fFlags);
|
|
|
|
} else {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kModifiers_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->write(m.fLayout);
|
|
|
|
this->writeS32(m.fFlags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::write(StringFragment s) {
|
|
|
|
this->write(String(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::write(String s) {
|
|
|
|
auto found = fStrings.find(s);
|
|
|
|
int offset;
|
|
|
|
if (found == fStrings.end()) {
|
|
|
|
offset = fStringBuffer.str().length() + HEADER_SIZE;
|
|
|
|
fStrings.insert({ s, offset });
|
|
|
|
SkASSERT(s.length() <= 255);
|
2020-10-08 17:56:46 +00:00
|
|
|
fStringBreaks.add(fStringBuffer.bytesWritten());
|
2020-07-28 18:46:53 +00:00
|
|
|
fStringBuffer.write8(s.length());
|
|
|
|
fStringBuffer.writeString(s);
|
|
|
|
} else {
|
|
|
|
offset = found->second;
|
|
|
|
}
|
|
|
|
this->writeU16(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::write(const Symbol& s) {
|
|
|
|
uint16_t id = this->symbolId(&s, false);
|
|
|
|
if (id) {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kSymbolRef_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeU16(id);
|
|
|
|
return;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
switch (s.kind()) {
|
|
|
|
case Symbol::Kind::kFunctionDeclaration: {
|
2020-08-18 14:40:03 +00:00
|
|
|
const FunctionDeclaration& f = s.as<FunctionDeclaration>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kFunctionDeclaration_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeId(&f);
|
2020-10-08 15:45:44 +00:00
|
|
|
this->write(f.modifiers());
|
2020-10-05 15:49:11 +00:00
|
|
|
this->write(f.name());
|
2020-10-08 15:45:44 +00:00
|
|
|
this->writeU8(f.parameters().size());
|
|
|
|
for (const Variable* p : f.parameters()) {
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeU16(this->symbolId(p));
|
|
|
|
}
|
2020-10-08 15:45:44 +00:00
|
|
|
this->write(f.returnType());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-10-06 20:14:37 +00:00
|
|
|
case Symbol::Kind::kSymbolAlias: {
|
|
|
|
const SymbolAlias& alias = s.as<SymbolAlias>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kSymbolAlias_Command);
|
2020-10-06 20:14:37 +00:00
|
|
|
this->writeId(&alias);
|
|
|
|
this->write(alias.name());
|
|
|
|
this->write(*alias.origSymbol());
|
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Symbol::Kind::kUnresolvedFunction: {
|
2020-08-18 14:40:03 +00:00
|
|
|
const UnresolvedFunction& f = s.as<UnresolvedFunction>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kUnresolvedFunction_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeId(&f);
|
2020-10-09 20:51:18 +00:00
|
|
|
this->writeU8(f.functions().size());
|
|
|
|
for (const FunctionDeclaration* funcDecl : f.functions()) {
|
2020-08-25 17:33:02 +00:00
|
|
|
this->write(*funcDecl);
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Symbol::Kind::kType: {
|
2020-08-18 14:40:03 +00:00
|
|
|
const Type& t = s.as<Type>();
|
2020-09-08 14:22:09 +00:00
|
|
|
switch (t.typeKind()) {
|
|
|
|
case Type::TypeKind::kArray:
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kArrayType_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeId(&t);
|
|
|
|
this->write(t.componentType());
|
2020-10-01 21:22:45 +00:00
|
|
|
this->writeS8(t.columns());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case Type::TypeKind::kEnum:
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kEnumType_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeId(&t);
|
2020-10-05 15:49:11 +00:00
|
|
|
this->write(t.name());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case Type::TypeKind::kStruct:
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kStructType_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeId(&t);
|
2020-10-05 15:49:11 +00:00
|
|
|
this->write(t.name());
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeU8(t.fields().size());
|
|
|
|
for (const Type::Field& f : t.fields()) {
|
|
|
|
this->write(f.fModifiers);
|
|
|
|
this->write(f.fName);
|
|
|
|
this->write(*f.fType);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kSystemType_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeId(&t);
|
2020-10-05 15:49:11 +00:00
|
|
|
this->write(t.name());
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Symbol::Kind::kVariable: {
|
2020-08-18 14:40:03 +00:00
|
|
|
const Variable& v = s.as<Variable>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kVariable_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeId(&v);
|
2020-10-07 20:42:04 +00:00
|
|
|
this->write(v.modifiers());
|
2020-10-05 15:49:11 +00:00
|
|
|
this->write(v.name());
|
2020-09-11 16:27:26 +00:00
|
|
|
this->write(v.type());
|
2020-10-09 14:43:45 +00:00
|
|
|
this->writeU8((int8_t) v.storage());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Symbol::Kind::kField: {
|
2020-08-18 14:40:03 +00:00
|
|
|
const Field& f = s.as<Field>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kField_Command);
|
2020-10-05 15:49:11 +00:00
|
|
|
this->writeU16(this->symbolId(&f.owner()));
|
|
|
|
this->writeU8(f.fieldIndex());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Symbol::Kind::kExternal:
|
2020-07-28 18:46:53 +00:00
|
|
|
SkASSERT(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::write(const SymbolTable& symbols) {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kSymbolTable_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeU16(symbols.fOwnedSymbols.size());
|
|
|
|
for (const std::unique_ptr<const Symbol>& s : symbols.fOwnedSymbols) {
|
|
|
|
this->write(*s);
|
|
|
|
}
|
2020-10-09 16:48:04 +00:00
|
|
|
this->writeU16(symbols.fSymbols.count());
|
2020-07-31 17:18:02 +00:00
|
|
|
std::map<StringFragment, const Symbol*> ordered;
|
2020-10-09 16:48:04 +00:00
|
|
|
symbols.foreach([&](StringFragment name, const Symbol* symbol) {
|
|
|
|
ordered.insert({name, symbol});
|
|
|
|
});
|
2020-07-31 17:18:02 +00:00
|
|
|
for (std::pair<StringFragment, const Symbol*> p : ordered) {
|
2020-07-28 18:46:53 +00:00
|
|
|
bool found = false;
|
|
|
|
for (size_t i = 0; i < symbols.fOwnedSymbols.size(); ++i) {
|
|
|
|
if (symbols.fOwnedSymbols[i].get() == p.second) {
|
2020-10-08 17:56:46 +00:00
|
|
|
fCommandBreaks.add(fBody.bytesWritten());
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeU16(i);
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SkASSERT(found);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::write(const Expression* e) {
|
|
|
|
if (e) {
|
2020-09-08 14:22:09 +00:00
|
|
|
switch (e->kind()) {
|
|
|
|
case Expression::Kind::kBinary: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const BinaryExpression& b = e->as<BinaryExpression>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kBinary_Command);
|
2020-10-30 14:29:12 +00:00
|
|
|
this->write(b.left().get());
|
2021-02-16 15:55:27 +00:00
|
|
|
this->writeU8((int) b.getOperator().kind());
|
2020-10-30 14:29:12 +00:00
|
|
|
this->write(b.right().get());
|
2020-09-11 16:27:26 +00:00
|
|
|
this->write(b.type());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kBoolLiteral: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const BoolLiteral& b = e->as<BoolLiteral>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kBoolLiteral_Command);
|
2020-09-28 13:18:15 +00:00
|
|
|
this->writeU8(b.value());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2021-02-16 18:02:57 +00:00
|
|
|
case Expression::Kind::kCodeString:
|
|
|
|
SkDEBUGFAIL("shouldn't be able to receive kCodeString here");
|
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kConstructor: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const Constructor& c = e->as<Constructor>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kConstructor_Command);
|
2020-09-11 16:27:26 +00:00
|
|
|
this->write(c.type());
|
2020-09-29 16:41:35 +00:00
|
|
|
this->writeU8(c.arguments().size());
|
|
|
|
for (const auto& a : c.arguments()) {
|
2020-07-28 18:46:53 +00:00
|
|
|
this->write(a.get());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kExternalFunctionCall:
|
Strip down SkSL::ExternalValues, limit them to functions
Previously ExternalValues were flexible, and could be used as raw values
(with the ability to chain access via dot notation), or they could be
callable. The only non-test use-case has been for functions (in
particles) for a long time. With the push towards SkVM, limiting
ourselves to this interface simplifies things: external functions are
basically custom intrinsics (and with the SkVM backend, they'll just get
access to the builder, and be able to do any math, as well as
loads/stores, etc).
By narrowing the feature set, we can rename everything to reflect that,
and it's overall clearer (the SkSL types now mirror FunctionReference
and FunctionCall directly, particularly in how they're handled by the
CFG and inliner).
Change-Id: Ib5dd34158ff85aae6c297408a92ace5485a08190
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350704
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
2021-01-06 19:27:35 +00:00
|
|
|
case Expression::Kind::kExternalFunctionReference:
|
2020-10-08 17:56:46 +00:00
|
|
|
SkDEBUGFAIL("unimplemented--not expected to be used from within an include file");
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kFieldAccess: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const FieldAccess& f = e->as<FieldAccess>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kFieldAccess_Command);
|
2020-10-09 15:55:40 +00:00
|
|
|
this->write(f.base().get());
|
|
|
|
this->writeU8(f.fieldIndex());
|
|
|
|
this->writeU8((int8_t) f.ownerKind());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kFloatLiteral: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const FloatLiteral& f = e->as<FloatLiteral>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kFloatLiteral_Command);
|
2020-11-18 15:45:52 +00:00
|
|
|
this->write(f.type());
|
2020-07-28 18:46:53 +00:00
|
|
|
FloatIntUnion u;
|
2020-10-01 16:13:17 +00:00
|
|
|
u.fFloat = f.value();
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeS32(u.fInt);
|
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kFunctionCall: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const FunctionCall& f = e->as<FunctionCall>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kFunctionCall_Command);
|
2020-09-11 16:27:26 +00:00
|
|
|
this->write(f.type());
|
2020-10-05 19:51:52 +00:00
|
|
|
this->writeId(&f.function());
|
|
|
|
this->writeU8(f.arguments().size());
|
|
|
|
for (const auto& a : f.arguments()) {
|
2020-07-28 18:46:53 +00:00
|
|
|
this->write(a.get());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kIndex: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const IndexExpression& i = e->as<IndexExpression>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kIndex_Command);
|
2020-10-08 19:35:56 +00:00
|
|
|
this->write(i.base().get());
|
|
|
|
this->write(i.index().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kIntLiteral: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const IntLiteral& i = e->as<IntLiteral>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kIntLiteral_Command);
|
2020-11-18 15:45:52 +00:00
|
|
|
this->write(i.type());
|
2020-09-28 20:27:18 +00:00
|
|
|
this->writeS32(i.value());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kPostfix: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const PostfixExpression& p = e->as<PostfixExpression>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kPostfix_Command);
|
2021-02-16 15:55:27 +00:00
|
|
|
this->writeU8((int) p.getOperator().kind());
|
2020-10-09 14:16:22 +00:00
|
|
|
this->write(p.operand().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kPrefix: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const PrefixExpression& p = e->as<PrefixExpression>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kPrefix_Command);
|
2021-02-16 15:55:27 +00:00
|
|
|
this->writeU8((int) p.getOperator().kind());
|
2020-10-09 14:16:22 +00:00
|
|
|
this->write(p.operand().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kSetting: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const Setting& s = e->as<Setting>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kSetting_Command);
|
2020-10-08 16:10:12 +00:00
|
|
|
this->write(s.name());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kSwizzle: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const Swizzle& s = e->as<Swizzle>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kSwizzle_Command);
|
2020-10-12 20:11:51 +00:00
|
|
|
this->write(s.base().get());
|
|
|
|
this->writeU8(s.components().size());
|
|
|
|
for (int c : s.components()) {
|
2020-07-28 18:46:53 +00:00
|
|
|
this->writeU8(c);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kTernary: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const TernaryExpression& t = e->as<TernaryExpression>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kTernary_Command);
|
2020-10-08 09:48:01 +00:00
|
|
|
this->write(t.test().get());
|
|
|
|
this->write(t.ifTrue().get());
|
|
|
|
this->write(t.ifFalse().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kVariableReference: {
|
2020-08-18 13:24:00 +00:00
|
|
|
const VariableReference& v = e->as<VariableReference>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kVariableReference_Command);
|
2020-10-08 10:46:27 +00:00
|
|
|
this->writeId(v.variable());
|
2020-10-09 14:43:45 +00:00
|
|
|
this->writeU8((int8_t) v.refKind());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Expression::Kind::kFunctionReference:
|
|
|
|
case Expression::Kind::kTypeReference:
|
|
|
|
case Expression::Kind::kDefined:
|
2020-10-08 17:56:46 +00:00
|
|
|
SkDEBUGFAIL("this expression shouldn't appear in finished code");
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kVoid_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::write(const Statement* s) {
|
|
|
|
if (s) {
|
2020-09-08 14:22:09 +00:00
|
|
|
switch (s->kind()) {
|
|
|
|
case Statement::Kind::kBlock: {
|
2020-08-18 13:30:51 +00:00
|
|
|
const Block& b = s->as<Block>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kBlock_Command);
|
2020-09-25 18:31:59 +00:00
|
|
|
AutoDehydratorSymbolTable symbols(this, b.symbolTable());
|
|
|
|
this->writeU8(b.children().size());
|
|
|
|
for (const std::unique_ptr<Statement>& blockStmt : b.children()) {
|
2020-08-25 17:33:02 +00:00
|
|
|
this->write(blockStmt.get());
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
2020-09-25 18:31:59 +00:00
|
|
|
this->writeU8(b.isScope());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kBreak:
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kBreak_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kContinue:
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kContinue_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kDiscard:
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kDiscard_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kDo: {
|
2020-08-18 13:30:51 +00:00
|
|
|
const DoStatement& d = s->as<DoStatement>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kDo_Command);
|
2020-09-28 17:14:19 +00:00
|
|
|
this->write(d.statement().get());
|
|
|
|
this->write(d.test().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kExpression: {
|
2020-08-18 13:30:51 +00:00
|
|
|
const ExpressionStatement& e = s->as<ExpressionStatement>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kExpressionStatement_Command);
|
2020-09-30 13:29:55 +00:00
|
|
|
this->write(e.expression().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kFor: {
|
2020-08-18 13:30:51 +00:00
|
|
|
const ForStatement& f = s->as<ForStatement>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kFor_Command);
|
2020-10-05 18:47:09 +00:00
|
|
|
this->write(f.initializer().get());
|
|
|
|
this->write(f.test().get());
|
|
|
|
this->write(f.next().get());
|
|
|
|
this->write(f.statement().get());
|
2020-10-16 22:38:39 +00:00
|
|
|
this->write(*f.symbols());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kIf: {
|
2020-08-18 13:30:51 +00:00
|
|
|
const IfStatement& i = s->as<IfStatement>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kIf_Command);
|
2020-10-07 20:47:09 +00:00
|
|
|
this->writeU8(i.isStatic());
|
|
|
|
this->write(i.test().get());
|
|
|
|
this->write(i.ifTrue().get());
|
|
|
|
this->write(i.ifFalse().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-09 18:18:53 +00:00
|
|
|
case Statement::Kind::kInlineMarker: {
|
|
|
|
const InlineMarker& i = s->as<InlineMarker>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kInlineMarker_Command);
|
2020-10-09 20:51:18 +00:00
|
|
|
this->writeId(&i.function());
|
2020-09-09 18:18:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kNop:
|
2020-10-08 17:56:46 +00:00
|
|
|
SkDEBUGFAIL("unexpected--nop statement in finished code");
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kReturn: {
|
2020-08-18 13:30:51 +00:00
|
|
|
const ReturnStatement& r = s->as<ReturnStatement>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kReturn_Command);
|
2020-10-08 19:35:56 +00:00
|
|
|
this->write(r.expression().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kSwitch: {
|
2020-08-18 13:30:51 +00:00
|
|
|
const SwitchStatement& ss = s->as<SwitchStatement>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kSwitch_Command);
|
2020-10-22 19:53:41 +00:00
|
|
|
this->writeU8(ss.isStatic());
|
|
|
|
AutoDehydratorSymbolTable symbols(this, ss.symbols());
|
|
|
|
this->write(ss.value().get());
|
2020-10-30 14:29:12 +00:00
|
|
|
this->writeU8(ss.cases().size());
|
|
|
|
for (const std::unique_ptr<SwitchCase>& sc : ss.cases()) {
|
|
|
|
this->write(sc->value().get());
|
|
|
|
this->writeU8(sc->statements().size());
|
|
|
|
for (const std::unique_ptr<Statement>& stmt : sc->statements()) {
|
2020-07-28 18:46:53 +00:00
|
|
|
this->write(stmt.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-09-11 19:53:40 +00:00
|
|
|
case Statement::Kind::kSwitchCase:
|
2020-10-08 17:56:46 +00:00
|
|
|
SkDEBUGFAIL("SwitchCase statements shouldn't appear here");
|
2020-09-11 19:53:40 +00:00
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case Statement::Kind::kVarDeclaration: {
|
2020-08-18 13:30:51 +00:00
|
|
|
const VarDeclaration& v = s->as<VarDeclaration>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kVarDeclaration_Command);
|
2020-10-13 17:49:44 +00:00
|
|
|
this->writeU16(this->symbolId(&v.var()));
|
|
|
|
this->write(v.baseType());
|
2020-12-03 15:41:58 +00:00
|
|
|
this->writeS8(v.arraySize());
|
2020-10-13 17:49:44 +00:00
|
|
|
this->write(v.value().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kVoid_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::write(const ProgramElement& e) {
|
2020-09-08 14:22:09 +00:00
|
|
|
switch (e.kind()) {
|
|
|
|
case ProgramElement::Kind::kEnum: {
|
2020-08-19 21:48:31 +00:00
|
|
|
const Enum& en = e.as<Enum>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kEnum_Command);
|
2020-09-29 21:05:54 +00:00
|
|
|
this->write(en.typeName());
|
|
|
|
AutoDehydratorSymbolTable symbols(this, en.symbols());
|
|
|
|
for (const std::unique_ptr<const Symbol>& s : en.symbols()->fOwnedSymbols) {
|
2020-09-08 14:22:09 +00:00
|
|
|
SkASSERT(s->kind() == Symbol::Kind::kVariable);
|
2020-07-28 18:46:53 +00:00
|
|
|
Variable& v = (Variable&) *s;
|
2020-10-07 20:42:04 +00:00
|
|
|
SkASSERT(v.initialValue());
|
|
|
|
const IntLiteral& i = v.initialValue()->as<IntLiteral>();
|
2020-09-28 20:27:18 +00:00
|
|
|
this->writeS32(i.value());
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case ProgramElement::Kind::kExtension:
|
2020-07-28 18:46:53 +00:00
|
|
|
SkASSERT(false);
|
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case ProgramElement::Kind::kFunction: {
|
2020-08-19 21:48:31 +00:00
|
|
|
const FunctionDefinition& f = e.as<FunctionDefinition>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kFunctionDefinition_Command);
|
2020-10-14 17:33:18 +00:00
|
|
|
this->writeU16(this->symbolId(&f.declaration()));
|
|
|
|
this->write(f.body().get());
|
|
|
|
this->writeU8(f.referencedIntrinsics().size());
|
2020-07-31 17:18:02 +00:00
|
|
|
std::set<uint16_t> ordered;
|
2020-10-14 17:33:18 +00:00
|
|
|
for (const FunctionDeclaration* ref : f.referencedIntrinsics()) {
|
2020-07-31 17:18:02 +00:00
|
|
|
ordered.insert(this->symbolId(ref));
|
|
|
|
}
|
|
|
|
for (uint16_t ref : ordered) {
|
|
|
|
this->writeU16(ref);
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-11-03 17:18:22 +00:00
|
|
|
case ProgramElement::Kind::kFunctionPrototype: {
|
|
|
|
// We don't need to emit function prototypes into the dehydrated data, because we don't
|
|
|
|
// ever need to re-emit the intrinsics files as raw GLSL/Metal. As long as the symbols
|
|
|
|
// exist in the symbol table, we're in good shape.
|
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case ProgramElement::Kind::kInterfaceBlock: {
|
2020-08-19 21:48:31 +00:00
|
|
|
const InterfaceBlock& i = e.as<InterfaceBlock>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kInterfaceBlock_Command);
|
2020-10-15 14:10:08 +00:00
|
|
|
this->write(i.variable());
|
|
|
|
this->write(i.typeName());
|
|
|
|
this->write(i.instanceName());
|
2020-12-03 15:42:26 +00:00
|
|
|
this->writeS8(i.arraySize());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-09-08 14:22:09 +00:00
|
|
|
case ProgramElement::Kind::kModifiers:
|
2020-07-28 18:46:53 +00:00
|
|
|
SkASSERT(false);
|
|
|
|
break;
|
2020-09-08 14:22:09 +00:00
|
|
|
case ProgramElement::Kind::kSection:
|
2020-07-28 18:46:53 +00:00
|
|
|
SkASSERT(false);
|
|
|
|
break;
|
2020-11-25 21:24:55 +00:00
|
|
|
case ProgramElement::Kind::kStructDefinition: {
|
|
|
|
const StructDefinition& structDef = e.as<StructDefinition>();
|
|
|
|
this->writeCommand(Rehydrator::kStructDefinition_Command);
|
|
|
|
this->write(structDef.type());
|
|
|
|
break;
|
|
|
|
}
|
2020-10-06 18:43:32 +00:00
|
|
|
case ProgramElement::Kind::kGlobalVar: {
|
|
|
|
const GlobalVarDeclaration& v = e.as<GlobalVarDeclaration>();
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kVarDeclarations_Command);
|
2020-10-13 17:49:44 +00:00
|
|
|
this->write(v.declaration().get());
|
2020-07-28 18:46:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::write(const std::vector<std::unique_ptr<ProgramElement>>& elements) {
|
2020-10-08 17:56:46 +00:00
|
|
|
this->writeCommand(Rehydrator::kElements_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
for (const auto& e : elements) {
|
|
|
|
this->write(*e);
|
|
|
|
}
|
2020-11-02 18:07:23 +00:00
|
|
|
this->writeCommand(Rehydrator::kElementsComplete_Command);
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Dehydrator::finish(OutputStream& out) {
|
2020-10-08 17:56:46 +00:00
|
|
|
String stringBuffer = fStringBuffer.str();
|
|
|
|
String commandBuffer = fBody.str();
|
|
|
|
|
2020-07-28 18:46:53 +00:00
|
|
|
out.write16(fStringBuffer.str().size());
|
2020-10-08 17:56:46 +00:00
|
|
|
fStringBufferStart = 2;
|
|
|
|
out.writeString(stringBuffer);
|
|
|
|
fCommandStart = fStringBufferStart + stringBuffer.size();
|
|
|
|
out.writeString(commandBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* Dehydrator::prefixAtOffset(size_t byte) {
|
|
|
|
if (byte >= fCommandStart) {
|
|
|
|
return fCommandBreaks.contains(byte - fCommandStart) ? "\n" : "";
|
|
|
|
}
|
|
|
|
if (byte >= fStringBufferStart) {
|
|
|
|
return fStringBreaks.contains(byte - fStringBufferStart) ? "\n" : "";
|
|
|
|
}
|
|
|
|
return "";
|
2020-07-28 18:46:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
#endif
|