Shader: Remove struct and functions that aren't required

This commit is contained in:
Jérôme Leclercq
2022-03-12 15:43:25 +01:00
parent d29876f448
commit 33554cf5a0
2 changed files with 287 additions and 3 deletions

View File

@@ -225,6 +225,19 @@ namespace Nz::ShaderAst
if (!clone->rootNode) if (!clone->rootNode)
return {}; return {};
// Remove unused statements of imported modules
for (std::size_t moduleId = 0; moduleId < clone->importedModules.size(); ++moduleId)
{
auto& moduleData = m_context->modules[moduleId];
auto& importedModule = clone->importedModules[moduleId];
if (moduleData.dependenciesVisitor)
{
moduleData.dependenciesVisitor->Resolve();
importedModule.module = EliminateUnusedPass(*importedModule.module, moduleData.dependenciesVisitor->GetUsage());
}
}
return clone; return clone;
} }

View File

@@ -12,11 +12,27 @@ TEST_CASE("Modules", "[Shader]")
{ {
WHEN("using a simple module") WHEN("using a simple module")
{ {
// UUID are required here to have a stable output
std::string_view importedSource = R"( std::string_view importedSource = R"(
[nzsl_version("1.0")] [nzsl_version("1.0")]
[uuid("ad3aed6e-0619-4a26-b5ce-abc2ec0836c4")] [uuid("ad3aed6e-0619-4a26-b5ce-abc2ec0836c4")]
module; module;
[layout(std140)]
struct Data
{
value: f32
}
[export]
[layout(std140)]
struct Block
{
data: Data
}
struct Unused {}
[export] [export]
struct InputData struct InputData
{ {
@@ -36,11 +52,16 @@ module;
import SimpleModule; import SimpleModule;
external
{
[binding(0)] block: uniform[Block]
}
[entry(frag)] [entry(frag)]
fn main(input: InputData) -> OutputData fn main(input: InputData) -> OutputData
{ {
let output: OutputData; let output: OutputData;
output.value = input.value; output.value = block.data.value * input.value;
return output; return output;
} }
)"; )";
@@ -56,6 +77,16 @@ fn main(input: InputData) -> OutputData
REQUIRE_NOTHROW(shaderModule = Nz::ShaderAst::Sanitize(*shaderModule, sanitizeOpt)); REQUIRE_NOTHROW(shaderModule = Nz::ShaderAst::Sanitize(*shaderModule, sanitizeOpt));
ExpectGLSL(*shaderModule, R"( ExpectGLSL(*shaderModule, R"(
struct Data__181c45e9
{
float value;
};
struct Block__181c45e9
{
Data__181c45e9 data;
};
struct InputData__181c45e9 struct InputData__181c45e9
{ {
float value; float value;
@@ -66,6 +97,12 @@ struct OutputData__181c45e9
float value; float value;
}; };
layout(std140) uniform _NzBinding_block
{
Data__181c45e9 data;
} block;
/**************** Inputs ****************/ /**************** Inputs ****************/
in float _NzIn_value; in float _NzIn_value;
@@ -78,7 +115,7 @@ void main()
input_.value = _NzIn_value; input_.value = _NzIn_value;
OutputData__181c45e9 output_; OutputData__181c45e9 output_;
output_.value = input_.value; output_.value = block.data.value * input_.value;
_NzOut_value = output_.value; _NzOut_value = output_.value;
return; return;
@@ -93,6 +130,18 @@ module;
[uuid("ad3aed6e-0619-4a26-b5ce-abc2ec0836c4")] [uuid("ad3aed6e-0619-4a26-b5ce-abc2ec0836c4")]
module __181c45e9 module __181c45e9
{ {
[layout(std140)]
struct Data
{
value: f32
}
[layout(std140)]
struct Block
{
data: Data
}
struct InputData struct InputData
{ {
value: f32 value: f32
@@ -104,15 +153,22 @@ module __181c45e9
} }
} }
alias Block = __181c45e9.Block;
alias InputData = __181c45e9.InputData; alias InputData = __181c45e9.InputData;
alias OutputData = __181c45e9.OutputData; alias OutputData = __181c45e9.OutputData;
external
{
[set(0), binding(0)] block: uniform[__181c45e9.Block]
}
[entry(frag)] [entry(frag)]
fn main(input: InputData) -> OutputData fn main(input: InputData) -> OutputData
{ {
let output: OutputData; let output: OutputData;
output.value = input.value; output.value = block.data.value * input.value;
return output; return output;
} }
)"); )");
@@ -125,6 +181,221 @@ OpVariable
OpAccessChain OpAccessChain
OpLoad OpLoad
OpAccessChain OpAccessChain
OpLoad
OpFMul
OpAccessChain
OpStore
OpLoad
OpReturn
OpFunctionEnd)");
}
WHEN("Using nested modules")
{
// UUID are required here to have a stable output
std::string_view dataModule = R"(
[nzsl_version("1.0")]
[uuid("ad3aed6e-0619-4a26-b5ce-abc2ec0836c4")]
module;
fn dummy() {}
[export]
[layout(std140)]
struct Data
{
value: f32
}
)";
std::string_view blockModule = R"(
[nzsl_version("1.0")]
[uuid("7a548506-89e6-4944-897f-4f695a8bca01")]
module;
import Modules/Data;
[export]
[layout(std140)]
struct Block
{
data: Data
}
struct Unused {}
)";
std::string_view inputOutputModule = R"(
[nzsl_version("1.0")]
[uuid("e66c6e98-fc37-4390-a7e1-c81508ff8e49")]
module;
[export]
struct InputData
{
value: f32
}
[export]
struct OutputData
{
value: f32
}
)";
std::string_view shaderSource = R"(
[nzsl_version("1.0")]
module;
import Modules/Block;
import Modules/InputOutput;
external
{
[binding(0)] block: uniform[Block]
}
[entry(frag)]
fn main(input: InputData) -> OutputData
{
let output: OutputData;
output.value = block.data.value * input.value;
return output;
}
)";
Nz::ShaderAst::ModulePtr shaderModule = Nz::ShaderLang::Parse(shaderSource);
auto directoryModuleResolver = std::make_shared<Nz::DirectoryModuleResolver>();
directoryModuleResolver->RegisterModuleFile("Modules/Data", dataModule.data(), dataModule.size());
directoryModuleResolver->RegisterModuleFile("Modules/Block", blockModule.data(), blockModule.size());
directoryModuleResolver->RegisterModuleFile("Modules/InputOutput", inputOutputModule.data(), inputOutputModule.size());
Nz::ShaderAst::SanitizeVisitor::Options sanitizeOpt;
sanitizeOpt.moduleResolver = directoryModuleResolver;
REQUIRE_NOTHROW(shaderModule = Nz::ShaderAst::Sanitize(*shaderModule, sanitizeOpt));
ExpectGLSL(*shaderModule, R"(
struct Data__181c45e9
{
float value;
};
struct Block__e528265d
{
Data__181c45e9 data;
};
struct InputData__26cce136
{
float value;
};
struct OutputData__26cce136
{
float value;
};
layout(std140) uniform _NzBinding_block
{
Data__181c45e9 data;
} block;
/**************** Inputs ****************/
in float _NzIn_value;
/*************** Outputs ***************/
out float _NzOut_value;
void main()
{
InputData__26cce136 input_;
input_.value = _NzIn_value;
OutputData__26cce136 output_;
output_.value = block.data.value * input_.value;
_NzOut_value = output_.value;
return;
}
)");
ExpectNZSL(*shaderModule, R"(
[nzsl_version("1.0")]
module;
[nzsl_version("1.0")]
[uuid("ad3aed6e-0619-4a26-b5ce-abc2ec0836c4")]
module __181c45e9
{
[layout(std140)]
struct Data
{
value: f32
}
}
[nzsl_version("1.0")]
[uuid("7a548506-89e6-4944-897f-4f695a8bca01")]
module __e528265d
{
alias Data = __181c45e9.Data;
[layout(std140)]
struct Block
{
data: Data
}
}
[nzsl_version("1.0")]
[uuid("e66c6e98-fc37-4390-a7e1-c81508ff8e49")]
module __26cce136
{
struct InputData
{
value: f32
}
struct OutputData
{
value: f32
}
}
alias Block = __e528265d.Block;
alias InputData = __26cce136.InputData;
alias OutputData = __26cce136.OutputData;
external
{
[set(0), binding(0)] block: uniform[__e528265d.Block]
}
[entry(frag)]
fn main(input: InputData) -> OutputData
{
let output: OutputData;
output.value = block.data.value * input.value;
return output;
}
)");
ExpectSPIRV(*shaderModule, R"(
OpFunction
OpLabel
OpVariable
OpVariable
OpAccessChain
OpLoad
OpAccessChain
OpLoad
OpFMul
OpAccessChain
OpStore OpStore
OpLoad OpLoad
OpReturn OpReturn