Add shader optimization level toggles to Viewer.
This lets us see at a glance what each optimization pass contributes to
our final compiled SkSL output.
Change-Id: I52c56c92c408eee34045c5e6f60298cf9548ff5d
Bug: skia:11319
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/381257
Commit-Queue: John Stiles <johnstiles@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 8adad8e..fae1562 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -72,7 +72,10 @@
namespace SkSL {
-// TODO(skia:11319): Set to `false` to disable control-flow analysis unilaterally.
+// Set these flags to `false` to disable optimization passes unilaterally.
+// These flags allow tools like Viewer or Nanobench to override the compiler's ProgramSettings.
+bool gSkSLOptimizer = true;
+bool gSkSLInliner = true;
bool gSkSLControlFlowAnalysis = true;
using RefKind = VariableReference::RefKind;
@@ -710,8 +713,7 @@
case Expression::Kind::kVariableReference: {
const VariableReference& ref = expr->as<VariableReference>();
const Variable* var = ref.variable();
- if (gSkSLControlFlowAnalysis &&
- fContext->fConfig->fSettings.fDeadCodeElimination &&
+ if (fContext->fConfig->fSettings.fDeadCodeElimination &&
ref.refKind() != VariableReference::RefKind::kWrite &&
ref.refKind() != VariableReference::RefKind::kPointer &&
var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
@@ -1321,7 +1323,7 @@
CFG cfg = CFGGenerator().getCFG(f);
this->computeDataFlow(&cfg);
- if (gSkSLControlFlowAnalysis && fContext->fConfig->fSettings.fDeadCodeElimination) {
+ if (fContext->fConfig->fSettings.fDeadCodeElimination) {
// Check for unreachable code.
for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
const BasicBlock& block = cfg.fBlocks[i];
@@ -1360,7 +1362,7 @@
}
BasicBlock& b = cfg.fBlocks[blockId];
- if (gSkSLControlFlowAnalysis && fContext->fConfig->fSettings.fDeadCodeElimination) {
+ if (fContext->fConfig->fSettings.fDeadCodeElimination) {
if (blockId > 0 && !b.fIsReachable) {
// Block was reachable before optimization, but has since become unreachable. In
// addition to being dead code, it's broken - since control flow can't reach it,
@@ -1425,6 +1427,16 @@
auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
AutoProgramConfig autoConfig(fContext, config.get());
+ // Honor our global optimization-disable flags.
+ config->fSettings.fOptimize &= gSkSLOptimizer;
+ config->fSettings.fControlFlowAnalysis &= gSkSLControlFlowAnalysis;
+ config->fSettings.fInlineThreshold *= (int)gSkSLInliner;
+
+ // Disable optimization settings that depend on a parent setting which has been disabled.
+ config->fSettings.fControlFlowAnalysis &= config->fSettings.fOptimize;
+ config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
+ config->fSettings.fDeadCodeElimination &= config->fSettings.fControlFlowAnalysis;
+
fErrorText = "";
fErrorCount = 0;
fInliner.reset(fIRGenerator->fModifiers.get());
@@ -1455,7 +1467,7 @@
bool success = false;
if (fErrorCount) {
// Do not return programs that failed to compile.
- } else if (settings.fOptimize && !this->optimize(*program)) {
+ } else if (!this->optimize(*program)) {
// Do not return programs that failed to optimize.
} else {
// We have a successful program!
@@ -1536,7 +1548,7 @@
bool madeChanges = false;
// Scan and optimize based on the control-flow graph for each function.
- if (gSkSLControlFlowAnalysis && config.fSettings.fControlFlowAnalysis) {
+ if (config.fSettings.fControlFlowAnalysis) {
for (const auto& element : module.fElements) {
if (element->is<FunctionDefinition>()) {
madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
@@ -1555,6 +1567,11 @@
}
bool Compiler::optimize(Program& program) {
+ // The optimizer only needs to run when it is enabled.
+ if (!program.fConfig->fSettings.fOptimize) {
+ return true;
+ }
+
SkASSERT(!fErrorCount);
ProgramUsage* usage = program.fUsage.get();
@@ -1562,7 +1579,7 @@
bool madeChanges = false;
// Scan and optimize based on the control-flow graph for each function.
- if (gSkSLControlFlowAnalysis && program.fConfig->fSettings.fControlFlowAnalysis) {
+ if (program.fConfig->fSettings.fControlFlowAnalysis) {
for (const auto& element : program.ownedElements()) {
if (element->is<FunctionDefinition>()) {
madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);