Shader: Add module resolver + use modules for engine shaders

This commit is contained in:
Jérôme Leclercq
2022-03-10 21:00:10 +01:00
parent 98bd04e35a
commit db0c1e6e8c
30 changed files with 737 additions and 106 deletions

View File

@@ -17,6 +17,14 @@ namespace Nz
const UInt8 r_blitShader[] = {
#include <Nazara/Graphics/Resources/Shaders/blit.nzsl.h>
};
const UInt8 r_instanceDataModule[] = {
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/InstanceData.nzsl.h>
};
const UInt8 r_viewerDataModule[] = {
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/ViewerData.nzsl.h>
};
}
/*!
@@ -66,6 +74,7 @@ namespace Nz
BuildDefaultTextures();
BuildFullscreenVertexBuffer();
RegisterShaderModules();
BuildBlitPipeline();
RegisterMaterialPasses();
SelectDepthStencilFormats();
@@ -125,7 +134,10 @@ namespace Nz
if (!m_blitPipelineLayout)
throw std::runtime_error("failed to instantiate fullscreen renderpipeline layout");
auto blitShader = m_renderDevice->InstantiateShaderModule(ShaderStageType::Fragment | ShaderStageType::Vertex, ShaderLanguage::NazaraShader, r_blitShader, sizeof(r_blitShader), {});
ShaderWriter::States states;
states.shaderModuleResolver = m_shaderModuleResolver;
auto blitShader = m_renderDevice->InstantiateShaderModule(ShaderStageType::Fragment | ShaderStageType::Vertex, ShaderLanguage::NazaraShader, r_blitShader, sizeof(r_blitShader), states);
if (!blitShader)
throw std::runtime_error("failed to instantiate blit shader");
@@ -203,6 +215,13 @@ namespace Nz
m_materialPassRegistry.RegisterPass("DepthPass");
}
void Graphics::RegisterShaderModules()
{
m_shaderModuleResolver = std::make_shared<DirectoryModuleResolver>();
m_shaderModuleResolver->RegisterModuleFile("Engine/InstanceData", r_instanceDataModule, sizeof(r_instanceDataModule));
m_shaderModuleResolver->RegisterModuleFile("Engine/ViewerData", r_viewerDataModule, sizeof(r_viewerDataModule));
}
void Graphics::SelectDepthStencilFormats()
{
for (PixelFormat depthStencilCandidate : { PixelFormat::Depth24Stencil8, PixelFormat::Depth32FStencil8, PixelFormat::Depth16Stencil8 })

View File

@@ -0,0 +1,10 @@
[nzsl_version("1.0")]
module;
[export]
[layout(std140)]
struct InstanceData
{
worldMatrix: mat4[f32],
invWorldMatrix: mat4[f32]
}

View File

@@ -0,0 +1,17 @@
[nzsl_version("1.0")]
module;
[export]
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}

View File

@@ -1,6 +1,9 @@
[nzsl_version("1.0")]
module;
import Engine/InstanceData;
import Engine/ViewerData;
option HasDiffuseTexture: bool = false;
option HasAlphaTexture: bool = false;
option AlphaTest: bool = false;
@@ -27,27 +30,6 @@ struct MaterialSettings
DiffuseColor: vec4[f32]
}
[layout(std140)]
struct InstanceData
{
worldMatrix: mat4[f32],
invWorldMatrix: mat4[f32]
}
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[binding(0)] settings: uniform[MaterialSettings],

View File

@@ -1,6 +1,9 @@
[nzsl_version("1.0")]
module;
import Engine/InstanceData;
import Engine/ViewerData;
option HasDiffuseTexture: bool = false;
option HasAlphaTexture: bool = false;
option AlphaTest: bool = false;
@@ -14,27 +17,6 @@ struct BasicSettings
DiffuseColor: vec4[f32]
}
[layout(std140)]
struct InstanceData
{
worldMatrix: mat4[f32],
invWorldMatrix: mat4[f32]
}
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[binding(0)] settings: uniform[BasicSettings],

View File

@@ -1,6 +1,9 @@
[nzsl_version("1.0")]
module;
import Engine/InstanceData;
import Engine/ViewerData;
// Basic material options
option HasDiffuseTexture: bool = false;
option HasAlphaTexture: bool = false;
@@ -47,13 +50,6 @@ struct MaterialSettings
Shininess: f32,
}
[layout(std140)]
struct InstanceData
{
worldMatrix: mat4[f32],
invWorldMatrix: mat4[f32]
}
// TODO: Add enums
const DirectionalLight = 0;
const PointLight = 1;
@@ -78,20 +74,6 @@ struct LightData
lightCount: u32,
}
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[binding(0)] settings: uniform[MaterialSettings],

View File

@@ -57,6 +57,7 @@ namespace Nz
{
ShaderWriter::States states;
states.optionValues = config.optionValues;
states.shaderModuleResolver = Graphics::Instance()->GetShaderModuleResolver();
std::shared_ptr<ShaderModule> stage = Graphics::Instance()->GetRenderDevice()->InstantiateShaderModule(m_shaderStages, *m_shaderModule, std::move(states));

View File

@@ -141,7 +141,12 @@ namespace Nz
{
m_states = states;
m_states.sanitized = true; //< Shader is always sanitized (because of keywords)
ShaderAst::ModulePtr sanitized = GlslWriter::Sanitize(shaderModule, states.optionValues);
ShaderAst::SanitizeVisitor::Options options = GlslWriter::GetSanitizeOptions();
options.optionValues = states.optionValues;
options.moduleResolver = states.shaderModuleResolver;
ShaderAst::ModulePtr sanitized = ShaderAst::Sanitize(shaderModule, options);
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
{

View File

@@ -1398,7 +1398,7 @@ namespace Nz::ShaderAst
StatementPtr SanitizeVisitor::Clone(ImportStatement& node)
{
if (!m_context->options.moduleCallback)
if (!m_context->options.moduleResolver)
return static_unique_pointer_cast<ImportStatement>(AstCloner::Clone(node));
auto ModulePathAsString = [&]() -> std::string
@@ -1419,7 +1419,7 @@ namespace Nz::ShaderAst
return ss.str();
};
ModulePtr targetModule = m_context->options.moduleCallback(node.modulePath);
ModulePtr targetModule = m_context->options.moduleResolver->Resolve(node.modulePath);
if (!targetModule)
throw AstError{ "module " + ModulePathAsString() + " not found" };
@@ -1506,16 +1506,20 @@ namespace Nz::ShaderAst
AstExportVisitor exportVisitor;
exportVisitor.Visit(*m_context->currentModule->importedModules[moduleIndex].module->rootNode, callbacks);
if (aliasStatements.empty() || m_context->options.removeAliases)
if (aliasStatements.empty())
return ShaderBuilder::NoOp();
// Register module and aliases
// Register aliases
for (auto& aliasPtr : aliasStatements)
Validate(*aliasPtr);
if (m_context->options.removeAliases)
return ShaderBuilder::NoOp();
// Generate alias statements
MultiStatementPtr aliasBlock = std::make_unique<MultiStatement>();
for (auto& aliasPtr : aliasStatements)
{
Validate(*aliasPtr);
aliasBlock->statements.push_back(std::move(aliasPtr));
}
return aliasBlock;
}

View File

@@ -0,0 +1,57 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Shader module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Shader/DirectoryModuleResolver.hpp>
#include <Nazara/Shader/ShaderLangParser.hpp>
#include <filesystem>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
ShaderAst::ModulePtr DirectoryModuleResolver::Resolve(const std::vector<std::string>& modulePath)
{
if (modulePath.empty())
return {};
std::string fullPath;
for (const auto& part : modulePath)
{
if (!fullPath.empty())
fullPath += '/';
fullPath += part;
}
if (auto it = m_knownModules.find(fullPath); it != m_knownModules.end())
return it->second;
VirtualDirectory::Entry entry;
if (!m_searchDirectory->GetEntry(fullPath, &entry))
return {};
ShaderAst::ModulePtr shaderModule;
if (std::holds_alternative<VirtualDirectory::DataPointerEntry>(entry))
{
const auto& content = std::get<VirtualDirectory::DataPointerEntry>(entry);
shaderModule = ShaderLang::Parse(std::string_view(reinterpret_cast<const char*>(content.data), content.size));
}
else if (std::holds_alternative<VirtualDirectory::FileContentEntry>(entry))
{
const auto& content = std::get<VirtualDirectory::FileContentEntry>(entry);
shaderModule = ShaderLang::Parse(std::string_view(reinterpret_cast<const char*>(content.data->data()), content.data->size()));
}
else if (std::holds_alternative<VirtualDirectory::PhysicalFileEntry>(entry))
{
const auto& filePath = std::get<VirtualDirectory::PhysicalFileEntry>(entry);
shaderModule = ShaderLang::ParseFromFile(filePath);
}
if (!shaderModule)
return {};
m_knownModules.emplace(fullPath, shaderModule);
return shaderModule;
}
}

View File

@@ -13,7 +13,6 @@
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
#include <Nazara/Shader/Ast/AstUtils.hpp>
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.hpp>
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
#include <optional>
#include <set>
#include <stdexcept>
@@ -173,7 +172,11 @@ namespace Nz
const ShaderAst::Module* targetModule;
if (!states.sanitized)
{
sanitizedModule = Sanitize(module, states.optionValues);
ShaderAst::SanitizeVisitor::Options options = GetSanitizeOptions();
options.optionValues = states.optionValues;
options.moduleResolver = states.shaderModuleResolver;
sanitizedModule = ShaderAst::Sanitize(module, options);
targetModule = sanitizedModule.get();
}
else
@@ -227,11 +230,10 @@ namespace Nz
return s_flipYUniformName;
}
ShaderAst::ModulePtr GlslWriter::Sanitize(const ShaderAst::Module& module, std::unordered_map<UInt32, ShaderAst::ConstantValue> optionValues, std::string* error)
ShaderAst::SanitizeVisitor::Options GlslWriter::GetSanitizeOptions()
{
// Always sanitize for reserved identifiers
ShaderAst::SanitizeVisitor::Options options;
options.optionValues = std::move(optionValues);
options.makeVariableNameUnique = true;
options.reduceLoopsToWhile = true;
options.removeAliases = true;
@@ -246,7 +248,7 @@ namespace Nz
"cross", "dot", "exp", "length", "max", "min", "pow", "texture"
};
return ShaderAst::Sanitize(module, options, error);
return options;
}
void GlslWriter::Append(const ShaderAst::AliasType& /*aliasType*/)

View File

@@ -0,0 +1,11 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Shader module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Shader/ShaderModuleResolver.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
ShaderModuleResolver::~ShaderModuleResolver() = default;
}

View File

@@ -503,10 +503,12 @@ namespace Nz
if (!states.sanitized)
{
ShaderAst::SanitizeVisitor::Options options;
options.moduleResolver = states.shaderModuleResolver;
options.optionValues = states.optionValues;
options.reduceLoopsToWhile = true;
options.removeAliases = true;
options.removeCompoundAssignments = true;
options.removeConstDeclaration = true;
options.removeMatrixCast = true;
options.removeOptionDeclaration = true;
options.splitMultipleBranches = true;