Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unoptimized/Debug builds with dead code elimination disabled? #122

Open
jakubtomsu opened this issue Apr 11, 2024 · 1 comment
Open

Unoptimized/Debug builds with dead code elimination disabled? #122

jakubtomsu opened this issue Apr 11, 2024 · 1 comment

Comments

@jakubtomsu
Copy link

jakubtomsu commented Apr 11, 2024

Currently the sokol-shdc compiler aggressively eliminates dead code, which is a bit annoying when iterating on shaders. That's because it also removes all of the uniform and texture slots from the generated headers.

I looked into the source but unfortunately couldn't find a way to disable it in the backend. Maybe there is a way to somehow still generate the binding slots correctly even if they compile out..?

@floooh
Copy link
Owner

floooh commented Apr 12, 2024

That's a surprisingly tricky topic because the removal can happen in different stages (starting at the initial GLSL to SPIRV compilation, but even as late as in the actual sokol application - for instance GL driver GLSL compilers are free to remove unused bindings as well).

In the past there was also a situation where unused vertex attributes were dropped by the SPIRVTools optimizer passes, but that had been fixed in this commit:

16492a0

The optionally generated reflection-info functions (only in the C code generation so far) are also a (somewhat awkward) way to deal with the problem, but that's not a great solution for iterating and experimenting.

Long story short, I haven't found a good solution for this. Unfortunately it's not as easy as disabling all optimizations. Unrelated to that I have thought about a command line option to disable the SPIRVTools optimizer passes completely (here:

static void spirv_optimize(slang_t::type_t slang, std::vector<uint32_t>& spirv) {
if (slang == slang_t::WGSL) {
return;
}
spv_target_env target_env;
target_env = SPV_ENV_UNIVERSAL_1_2;
spvtools::Optimizer optimizer(target_env);
optimizer.SetMessageConsumer(
[](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) {
// FIXME
});
optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
/*
optimizer.RegisterPass(spvtools::CreateMergeReturnPass());
optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());
*/
optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());
optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());
optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass());
optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass());
optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass());
optimizer.RegisterPass(spvtools::CreateSimplificationPass());
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(true)); // NOTE: call the "preserveInterface" version of CreateAggressiveDCEPass()
optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(true));
optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
// NOTE: it's the BlockMergePass which moves the init statement of a for-loop
// out of the for-statement, which makes it invalid for WebGL
// optimizer.RegisterPass(spvtools::CreateBlockMergePass());
// NOTE: this is the pass which may create invalid WebGL code
// optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());
optimizer.RegisterPass(spvtools::CreateIfConversionPass());
optimizer.RegisterPass(spvtools::CreateSimplificationPass());
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(true));
optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass());
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(true));
optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());
spvtools::OptimizerOptions spvOptOptions;
spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on
optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
}
), but that alone definitely won't solve the issue that unused binding declarations are removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants