Put interface blocks into the intrinsic maps, too

We now support cloning global variables that are "declared" by an
InterfaceBlock, or a GlocalVarDeclaration. At this point, there are no
"inherited" elements - any mutable data that starts out owned by the
pre-includes is cloned.

Follow-up will remove the inherited element list entirely - splitting
this out to make the changes clearer.

Bug: skia:10589
Change-Id: I2a95c73bf53db313e9f3467c681a05dffffeaa3a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/323976
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2020-10-07 17:47:45 -04:00 committed by Skia Commit-Bot
parent 99aa05339d
commit afa18eeb9a
5 changed files with 75 additions and 38 deletions

View File

@ -73,27 +73,30 @@ namespace SkSL {
static void grab_intrinsics(std::vector<std::unique_ptr<ProgramElement>>* src,
IRIntrinsicMap* target) {
for (auto iter = src->begin(); iter != src->end(); ) {
std::unique_ptr<ProgramElement>& element = *iter;
for (std::unique_ptr<ProgramElement>& element : *src) {
switch (element->kind()) {
case ProgramElement::Kind::kFunction: {
FunctionDefinition& f = element->as<FunctionDefinition>();
const FunctionDefinition& f = element->as<FunctionDefinition>();
SkASSERT(f.fDeclaration.fBuiltin);
target->insertOrDie(f.fDeclaration.description(), std::move(element));
iter = src->erase(iter);
break;
}
case ProgramElement::Kind::kEnum: {
Enum& e = element->as<Enum>();
const Enum& e = element->as<Enum>();
SkASSERT(e.isBuiltin());
target->insertOrDie(e.typeName(), std::move(element));
iter = src->erase(iter);
break;
}
case ProgramElement::Kind::kGlobalVar: {
const GlobalVarDeclaration& vd = element->as<GlobalVarDeclaration>();
const Variable* var = vd.fDecl->fVar;
const Variable* var = element->as<GlobalVarDeclaration>().fDecl->fVar;
SkASSERT(var->isBuiltin());
target->insertOrDie(var->name(), std::move(element));
break;
}
case ProgramElement::Kind::kInterfaceBlock: {
const Variable* var = element->as<InterfaceBlock>().fVariable;
SkASSERT(var->isBuiltin());
target->insertOrDie(var->name(), std::move(element));
iter = src->erase(iter);
break;
}
default:
@ -255,12 +258,13 @@ Compiler::Compiler(Flags flags)
fIRGenerator->fIntrinsics = nullptr;
std::vector<std::unique_ptr<ProgramElement>> gpuElements;
std::vector<std::unique_ptr<ProgramElement>> vertElements;
std::vector<std::unique_ptr<ProgramElement>> fragElements;
#if SKSL_STANDALONE
this->processIncludeFile(Program::kFragment_Kind, SKSL_GPU_INCLUDE, fRootSymbolTable,
&gpuElements, &fGpuSymbolTable);
this->processIncludeFile(Program::kVertex_Kind, SKSL_VERT_INCLUDE, fGpuSymbolTable,
&fVertexInclude, &fVertexSymbolTable);
&vertElements, &fVertexSymbolTable);
this->processIncludeFile(Program::kFragment_Kind, SKSL_FRAG_INCLUDE, fGpuSymbolTable,
&fragElements, &fFragmentSymbolTable);
#else
@ -277,7 +281,7 @@ Compiler::Compiler(Flags flags)
fGpuSymbolTable, this, SKSL_INCLUDE_sksl_vert,
SKSL_INCLUDE_sksl_vert_LENGTH);
fVertexSymbolTable = rehydrator.symbolTable();
fVertexInclude = rehydrator.elements();
vertElements = rehydrator.elements();
fModifiers.push_back(fIRGenerator->releaseModifiers());
}
{
@ -295,12 +299,15 @@ Compiler::Compiler(Flags flags)
// actually use calls from inside the intrinsics, we will clone them into the program and they
// will get new call counts.)
reset_call_counts(&gpuElements);
reset_call_counts(&fVertexInclude);
reset_call_counts(&vertElements);
reset_call_counts(&fragElements);
fGPUIntrinsics = std::make_unique<IRIntrinsicMap>(/*parent=*/nullptr);
grab_intrinsics(&gpuElements, fGPUIntrinsics.get());
fVertexIntrinsics = std::make_unique<IRIntrinsicMap>(fGPUIntrinsics.get());
grab_intrinsics(&vertElements, fVertexIntrinsics.get());
fFragmentIntrinsics = std::make_unique<IRIntrinsicMap>(fGPUIntrinsics.get());
grab_intrinsics(&fragElements, fFragmentIntrinsics.get());
}
@ -311,19 +318,22 @@ void Compiler::loadGeometryIntrinsics() {
if (fGeometrySymbolTable) {
return;
}
fGeometryIntrinsics = std::make_unique<IRIntrinsicMap>(fGPUIntrinsics.get());
std::vector<std::unique_ptr<ProgramElement>> geomElements;
#if !SKSL_STANDALONE
{
Rehydrator rehydrator(&fIRGenerator->fContext, fIRGenerator->fModifiers.get(),
fGpuSymbolTable, this, SKSL_INCLUDE_sksl_geom,
SKSL_INCLUDE_sksl_geom_LENGTH);
fGeometrySymbolTable = rehydrator.symbolTable();
fGeometryInclude = rehydrator.elements();
geomElements = rehydrator.elements();
fModifiers.push_back(fIRGenerator->releaseModifiers());
}
#else
this->processIncludeFile(Program::kGeometry_Kind, SKSL_GEOM_INCLUDE, fGpuSymbolTable,
&fGeometryInclude, &fGeometrySymbolTable);
&geomElements, &fGeometrySymbolTable);
#endif
grab_intrinsics(&geomElements, fGeometryIntrinsics.get());
}
void Compiler::loadFPIntrinsics() {
@ -1586,9 +1596,9 @@ std::unique_ptr<Program> Compiler::convertProgram(
std::vector<std::unique_ptr<ProgramElement>> elements;
switch (kind) {
case Program::kVertex_Kind:
inherited = &fVertexInclude;
fIRGenerator->fIntrinsics = fGPUIntrinsics.get();
fIRGenerator->start(&settings, fVertexSymbolTable, inherited);
inherited = nullptr;
fIRGenerator->fIntrinsics = fVertexIntrinsics.get();
fIRGenerator->start(&settings, fVertexSymbolTable, /*inherited=*/nullptr);
break;
case Program::kFragment_Kind:
inherited = nullptr;
@ -1597,9 +1607,9 @@ std::unique_ptr<Program> Compiler::convertProgram(
break;
case Program::kGeometry_Kind:
this->loadGeometryIntrinsics();
inherited = &fGeometryInclude;
fIRGenerator->fIntrinsics = fGPUIntrinsics.get();
fIRGenerator->start(&settings, fGeometrySymbolTable, inherited);
inherited = nullptr;
fIRGenerator->fIntrinsics = fGeometryIntrinsics.get();
fIRGenerator->start(&settings, fGeometrySymbolTable, /*inherited=*/nullptr);
break;
case Program::kFragmentProcessor_Kind:
this->loadFPIntrinsics();

View File

@ -234,17 +234,18 @@ private:
std::shared_ptr<SymbolTable> fGpuSymbolTable;
std::unique_ptr<IRIntrinsicMap> fGPUIntrinsics;
std::shared_ptr<SymbolTable> fInterpreterSymbolTable;
std::unique_ptr<IRIntrinsicMap> fInterpreterIntrinsics;
std::vector<std::unique_ptr<ProgramElement>> fVertexInclude;
std::shared_ptr<SymbolTable> fVertexSymbolTable;
std::unique_ptr<IRIntrinsicMap> fVertexIntrinsics;
std::shared_ptr<SymbolTable> fFragmentSymbolTable;
std::unique_ptr<IRIntrinsicMap> fFragmentIntrinsics;
std::vector<std::unique_ptr<ProgramElement>> fGeometryInclude;
std::shared_ptr<SymbolTable> fGeometrySymbolTable;
std::unique_ptr<IRIntrinsicMap> fGeometryIntrinsics;
std::shared_ptr<SymbolTable> fPipelineSymbolTable;
std::unique_ptr<IRIntrinsicMap> fPipelineIntrinsics;

View File

@ -195,6 +195,12 @@ void IRGenerator::start(const Program::Settings* settings,
}
if (fIntrinsics) {
fIntrinsics->resetAlreadyIncluded();
if (!fSkPerVertex) {
if (const ProgramElement* perVertexDecl = fIntrinsics->find(Compiler::PERVERTEX_NAME)) {
SkASSERT(perVertexDecl->is<InterfaceBlock>());
fSkPerVertex = perVertexDecl->as<InterfaceBlock>().fVariable;
}
}
}
}
@ -842,7 +848,7 @@ std::unique_ptr<Statement> IRGenerator::getNormalizeSkPositionCode() {
#define FIELD(var, idx) std::unique_ptr<Expression>(\
new FieldAccess(REF(var), idx, FieldAccess::kAnonymousInterfaceBlock_OwnerKind))
#define POS std::unique_ptr<Expression>(new FieldAccess(WREF(fSkPerVertex), 0, \
FieldAccess::kAnonymousInterfaceBlock_OwnerKind))
FieldAccess::kAnonymousInterfaceBlock_OwnerKind))
#define ADJUST (fRTAdjustInterfaceBlock ? \
FIELD(fRTAdjustInterfaceBlock, fRTAdjustFieldIndex) : \
REF(fRTAdjust))
@ -2854,14 +2860,22 @@ void IRGenerator::cloneBuiltinVariables() {
void cloneVariable(const String& name) {
// If this is the *first* time we've seen this builtin, findAndInclude will return
// the corresponding ProgramElement.
if (const ProgramElement* sharedDecls =
fGenerator->fIntrinsics->findAndInclude(name)) {
SkASSERT(sharedDecls->is<GlobalVarDeclaration>());
if (const ProgramElement* sharedDecl = fGenerator->fIntrinsics->findAndInclude(name)) {
SkASSERT(sharedDecl->is<GlobalVarDeclaration>() ||
sharedDecl->is<InterfaceBlock>());
// Clone the GlobalVarDeclaration ProgramElement that declares this variable
std::unique_ptr<ProgramElement> clonedDecls = sharedDecls->clone();
VarDeclaration& varDecl = *clonedDecls->as<GlobalVarDeclaration>().fDecl;
const Variable* sharedVar = varDecl.fVar;
// Clone the ProgramElement that declares this variable
std::unique_ptr<ProgramElement> clonedDecl = sharedDecl->clone();
const Variable* sharedVar = nullptr;
const Expression* initialValue = nullptr;
if (clonedDecl->is<GlobalVarDeclaration>()) {
sharedVar = clonedDecl->as<GlobalVarDeclaration>().fDecl->fVar;
initialValue = clonedDecl->as<GlobalVarDeclaration>().fDecl->fValue.get();
} else {
SkASSERT(clonedDecl->is<InterfaceBlock>());
sharedVar = clonedDecl->as<InterfaceBlock>().fVariable;
}
// Now clone the Variable, and add the clone to the Program's symbol table.
// Any initial value expression was cloned as part of the GlobalVarDeclaration,
@ -2870,16 +2884,20 @@ void IRGenerator::cloneBuiltinVariables() {
fGenerator->fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Variable>(
sharedVar->fOffset, sharedVar->modifiersHandle(), sharedVar->name(),
&sharedVar->type(), /*builtin=*/false, sharedVar->storage(),
varDecl.fValue.get()));
initialValue));
// Go back and update the VarDeclaration to point at the cloned Variable.
varDecl.fVar = clonedVar;
// Go back and update the declaring element to point at the cloned Variable.
if (clonedDecl->is<GlobalVarDeclaration>()) {
clonedDecl->as<GlobalVarDeclaration>().fDecl->fVar = clonedVar;
} else {
clonedDecl->as<InterfaceBlock>().fVariable = clonedVar;
}
// Remember this new re-mapping...
fRemap.insert({sharedVar, clonedVar});
// Add the GlobalVarDeclaration to this Program
fNewElements.push_back(std::move(clonedDecls));
// Add the declaring element to this Program
fNewElements.push_back(std::move(clonedDecl));
}
}
@ -2925,8 +2943,8 @@ void IRGenerator::cloneBuiltinVariables() {
}
fProgramElements->insert(fProgramElements->begin(),
std::make_move_iterator(remapper.fNewElements.begin()),
std::make_move_iterator(remapper.fNewElements.end()));
std::make_move_iterator(remapper.fNewElements.begin()),
std::make_move_iterator(remapper.fNewElements.end()));
}
void IRGenerator::convertProgram(Program::Kind kind,

View File

@ -48,6 +48,14 @@ public:
fIntrinsics[key] = Intrinsic{std::move(element), false};
}
const ProgramElement* find(const String& key) {
auto iter = fIntrinsics.find(key);
if (iter == fIntrinsics.end()) {
return fParent ? fParent->find(key) : nullptr;
}
return iter->second.fIntrinsic.get();
}
// Only returns an intrinsic that isn't already marked as included, and then marks it.
const ProgramElement* findAndInclude(const String& key) {
auto iter = fIntrinsics.find(key);

View File

@ -35,7 +35,7 @@ public:
};
Variable(int offset, ModifiersPool::Handle modifiers, StringFragment name, const Type* type,
bool builtin, Storage storage, Expression* initialValue = nullptr)
bool builtin, Storage storage, const Expression* initialValue = nullptr)
: INHERITED(offset, VariableData{name, type, initialValue, modifiers, /*readCount=*/0,
/*writeCount=*/(int16_t) (initialValue ? 1 : 0),
(int8_t) storage, builtin}) {}