Stop cloning elements that declare builtin variables

Instead, add them to the shared program element list of any program that
needs them.

Bug: skia:10905
Change-Id: Ieb470af65eb254154d238554eecffdcbbf268cf1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/335867
Reviewed-by: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2020-11-18 14:48:19 -05:00 committed by Skia Commit-Bot
parent ad5ec1ae85
commit 9496fe5bce
2 changed files with 19 additions and 69 deletions

View File

@ -2893,86 +2893,37 @@ bool IRGenerator::setRefKind(Expression& expr, VariableReference::RefKind kind)
return true;
}
void IRGenerator::cloneBuiltinVariables() {
class BuiltinVariableRemapper : public ProgramWriter {
void IRGenerator::findAndDeclareBuiltinVariables() {
class BuiltinVariableScanner : public ProgramVisitor {
public:
BuiltinVariableRemapper(IRGenerator* generator) : fGenerator(generator) {}
BuiltinVariableScanner(IRGenerator* generator) : fGenerator(generator) {}
void cloneVariable(const String& name) {
void addDeclaringElement(const String& name) {
// If this is the *first* time we've seen this builtin, findAndInclude will return
// the corresponding ProgramElement.
if (const ProgramElement* sharedDecl = fGenerator->fIntrinsics->findAndInclude(name)) {
SkASSERT(sharedDecl->is<GlobalVarDeclaration>() ||
sharedDecl->is<InterfaceBlock>());
// 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>()) {
GlobalVarDeclaration& global = clonedDecl->as<GlobalVarDeclaration>();
VarDeclaration& decl = global.declaration()->as<VarDeclaration>();
sharedVar = &decl.var();
initialValue = decl.value().get();
} else {
SkASSERT(clonedDecl->is<InterfaceBlock>());
sharedVar = &clonedDecl->as<InterfaceBlock>().variable();
}
// 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,
// so we're pointing at a Program-owned expression.
const Variable* clonedVar =
fGenerator->fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Variable>(
sharedVar->fOffset, &sharedVar->modifiers(), sharedVar->name(),
&sharedVar->type(), /*builtin=*/false, sharedVar->storage(),
initialValue));
// Go back and update the declaring element to point at the cloned Variable.
if (clonedDecl->is<GlobalVarDeclaration>()) {
GlobalVarDeclaration& global = clonedDecl->as<GlobalVarDeclaration>();
global.declaration()->as<VarDeclaration>().setVar(clonedVar);
} else {
clonedDecl->as<InterfaceBlock>().setVariable(clonedVar);
}
// Remember this new re-mapping...
fRemap.insert({sharedVar, clonedVar});
// Add the declaring element to this Program
fNewElements.push_back(std::move(clonedDecl));
if (const ProgramElement* decl = fGenerator->fIntrinsics->findAndInclude(name)) {
SkASSERT(decl->is<GlobalVarDeclaration>() || decl->is<InterfaceBlock>());
fNewElements.push_back(decl);
}
}
bool visitExpression(Expression& e) override {
// Look for references to builtin variables.
bool visitExpression(const Expression& e) override {
if (e.is<VariableReference>() && e.as<VariableReference>().variable()->isBuiltin()) {
const Variable* sharedVar = e.as<VariableReference>().variable();
this->cloneVariable(sharedVar->name());
// TODO: SkASSERT(found), once all pre-includes are converted?
auto found = fRemap.find(sharedVar);
if (found != fRemap.end()) {
e.as<VariableReference>().setVariable(found->second);
}
this->addDeclaringElement(e.as<VariableReference>().variable()->name());
}
return INHERITED::visitExpression(e);
}
IRGenerator* fGenerator;
std::unordered_map<const Variable*, const Variable*> fRemap;
std::vector<std::unique_ptr<ProgramElement>> fNewElements;
std::vector<const ProgramElement*> fNewElements;
using INHERITED = ProgramWriter;
using INHERITED = ProgramVisitor;
using INHERITED::visitProgramElement;
};
BuiltinVariableRemapper remapper(this);
BuiltinVariableScanner scanner(this);
for (auto& e : *fProgramElements) {
remapper.visitProgramElement(*e);
scanner.visitProgramElement(*e);
}
// Vulkan requires certain builtin variables be present, even if they're unused. At one time,
@ -2980,15 +2931,14 @@ void IRGenerator::cloneBuiltinVariables() {
// that drop or corrupt draws if they're missing.
switch (fKind) {
case Program::kFragment_Kind:
remapper.cloneVariable("sk_Clockwise");
scanner.addDeclaringElement("sk_Clockwise");
break;
default:
break;
}
fProgramElements->insert(fProgramElements->begin(),
std::make_move_iterator(remapper.fNewElements.begin()),
std::make_move_iterator(remapper.fNewElements.end()));
fSharedElements->insert(
fSharedElements->begin(), scanner.fNewElements.begin(), scanner.fNewElements.end());
}
IRGenerator::IRBundle IRGenerator::convertProgram(
@ -3119,9 +3069,9 @@ IRGenerator::IRBundle IRGenerator::convertProgram(
}
}
// Any variables defined in the pre-includes need to be cloned into the Program
// Variables defined in the pre-includes need their declaring elements added to the program
if (!fIsBuiltinCode && fIntrinsics) {
this->cloneBuiltinVariables();
this->findAndDeclareBuiltinVariables();
}
// Do a final pass looking for dangling FunctionReference or TypeReference expressions

View File

@ -228,7 +228,7 @@ private:
bool setRefKind(Expression& expr, VariableReference::RefKind kind);
bool getConstantInt(const Expression& value, int64_t* out);
void copyIntrinsicIfNeeded(const FunctionDeclaration& function);
void cloneBuiltinVariables();
void findAndDeclareBuiltinVariables();
Program::Inputs fInputs;
const Program::Settings* fSettings = nullptr;