Shader: Add module resolver + use modules for engine shaders
This commit is contained in:
@@ -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 })
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[nzsl_version("1.0")]
|
||||
module;
|
||||
|
||||
[export]
|
||||
[layout(std140)]
|
||||
struct InstanceData
|
||||
{
|
||||
worldMatrix: mat4[f32],
|
||||
invWorldMatrix: mat4[f32]
|
||||
}
|
||||
@@ -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]
|
||||
}
|
||||
@@ -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],
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
57
src/Nazara/Shader/DirectoryModuleResolver.cpp
Normal file
57
src/Nazara/Shader/DirectoryModuleResolver.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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*/)
|
||||
|
||||
11
src/Nazara/Shader/ShaderModuleResolver.cpp
Normal file
11
src/Nazara/Shader/ShaderModuleResolver.cpp
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user