Add support for shader hotreloading
This commit is contained in:
@@ -229,8 +229,7 @@ namespace Nz
|
||||
|
||||
std::vector<std::shared_ptr<UberShader>> BasicMaterial::BuildShaders()
|
||||
{
|
||||
ShaderAst::ModulePtr shaderModule = Graphics::Instance()->GetShaderModuleResolver()->Resolve("BasicMaterial");
|
||||
auto shader = std::make_shared<UberShader>(ShaderStageType::Fragment | ShaderStageType::Vertex, std::move(shaderModule));
|
||||
auto shader = std::make_shared<UberShader>(ShaderStageType::Fragment | ShaderStageType::Vertex, "BasicMaterial");
|
||||
|
||||
return { std::move(shader) };
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ namespace Nz
|
||||
{
|
||||
std::vector<std::shared_ptr<UberShader>> DepthMaterial::BuildShaders()
|
||||
{
|
||||
ShaderAst::ModulePtr shaderModule = Graphics::Instance()->GetShaderModuleResolver()->Resolve("DepthMaterial");
|
||||
auto shader = std::make_shared<UberShader>(ShaderStageType::Fragment | ShaderStageType::Vertex, std::move(shaderModule));
|
||||
auto shader = std::make_shared<UberShader>(ShaderStageType::Fragment | ShaderStageType::Vertex, "DepthMaterial");
|
||||
|
||||
return { std::move(shader) };
|
||||
}
|
||||
|
||||
@@ -33,10 +33,17 @@ namespace Nz
|
||||
m_pipelineInfo.settings = m_settings;
|
||||
|
||||
const auto& shaders = m_settings->GetShaders();
|
||||
for (const auto& shader : shaders)
|
||||
|
||||
m_shaders.resize(shaders.size());
|
||||
for (std::size_t i = 0; i < m_shaders.size(); ++i)
|
||||
{
|
||||
auto& shaderData = m_pipelineInfo.shaders.emplace_back();
|
||||
shaderData.uberShader = shader;
|
||||
shaderData.uberShader = shaders[i];
|
||||
|
||||
m_shaders[i].onShaderUpdated.Connect(shaders[i]->OnShaderUpdated, [this](UberShader*)
|
||||
{
|
||||
InvalidatePipeline();
|
||||
});
|
||||
}
|
||||
|
||||
const auto& textureSettings = m_settings->GetTextures();
|
||||
|
||||
@@ -310,8 +310,7 @@ namespace Nz
|
||||
|
||||
std::vector<std::shared_ptr<UberShader>> PhongLightingMaterial::BuildShaders()
|
||||
{
|
||||
ShaderAst::ModulePtr shaderModule = Graphics::Instance()->GetShaderModuleResolver()->Resolve("PhongMaterial");
|
||||
auto shader = std::make_shared<UberShader>(ShaderStageType::Fragment | ShaderStageType::Vertex, std::move(shaderModule));
|
||||
auto shader = std::make_shared<UberShader>(ShaderStageType::Fragment | ShaderStageType::Vertex, "PhongMaterial");
|
||||
|
||||
return { std::move(shader) };
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/UberShader.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Renderer/RenderDevice.hpp>
|
||||
#include <Nazara/Shader/Ast/AstReflect.hpp>
|
||||
@@ -13,13 +14,81 @@
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
UberShader::UberShader(ShaderStageTypeFlags shaderStages, std::string moduleName) :
|
||||
UberShader(shaderStages, *Graphics::Instance()->GetShaderModuleResolver(), std::move(moduleName))
|
||||
{
|
||||
}
|
||||
|
||||
UberShader::UberShader(ShaderStageTypeFlags shaderStages, ShaderModuleResolver& moduleResolver, std::string moduleName) :
|
||||
m_shaderStages(shaderStages)
|
||||
{
|
||||
m_shaderModule = moduleResolver.Resolve(moduleName);
|
||||
NazaraAssert(m_shaderModule, "invalid shader module");
|
||||
|
||||
Validate(*m_shaderModule);
|
||||
|
||||
m_onShaderModuleUpdated.Connect(moduleResolver.OnModuleUpdated, [this, name = std::move(moduleName)](ShaderModuleResolver* resolver, const std::string& updatedModuleName)
|
||||
{
|
||||
if (updatedModuleName != name)
|
||||
return;
|
||||
|
||||
ShaderAst::ModulePtr newShaderModule = resolver->Resolve(name);
|
||||
if (!newShaderModule)
|
||||
{
|
||||
NazaraError("failed to retrieve updated shader module " + name);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// FIXME: Validate is destructive, in case of failure it can invalidate the shader
|
||||
Validate(*newShaderModule);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraError("failed to retrieve updated shader module " + name + ": " + e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
m_shaderModule = std::move(newShaderModule);
|
||||
|
||||
// Clear cache
|
||||
m_combinations.clear();
|
||||
|
||||
OnShaderUpdated(this);
|
||||
});
|
||||
}
|
||||
|
||||
UberShader::UberShader(ShaderStageTypeFlags shaderStages, ShaderAst::ModulePtr shaderModule) :
|
||||
m_shaderModule(std::move(shaderModule)),
|
||||
m_shaderStages(shaderStages)
|
||||
{
|
||||
NazaraAssert(m_shaderStages != 0, "there must be at least one shader stage");
|
||||
NazaraAssert(m_shaderModule, "invalid shader module");
|
||||
|
||||
Validate(*m_shaderModule);
|
||||
}
|
||||
|
||||
const std::shared_ptr<ShaderModule>& UberShader::Get(const Config& config)
|
||||
{
|
||||
auto it = m_combinations.find(config);
|
||||
if (it == m_combinations.end())
|
||||
{
|
||||
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));
|
||||
|
||||
it = m_combinations.emplace(config, std::move(stage)).first;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void UberShader::Validate(ShaderAst::Module& module)
|
||||
{
|
||||
NazaraAssert(m_shaderStages != 0, "there must be at least one shader stage");
|
||||
|
||||
//TODO: Try to partially sanitize shader?
|
||||
|
||||
std::size_t optionCount = 0;
|
||||
@@ -44,26 +113,9 @@ namespace Nz
|
||||
};
|
||||
|
||||
ShaderAst::AstReflect reflect;
|
||||
reflect.Reflect(*m_shaderModule->rootNode, callbacks);
|
||||
reflect.Reflect(*module.rootNode, callbacks);
|
||||
|
||||
if ((m_shaderStages & supportedStageType) != m_shaderStages)
|
||||
throw std::runtime_error("shader doesn't support all required shader stages");
|
||||
}
|
||||
|
||||
const std::shared_ptr<ShaderModule>& UberShader::Get(const Config& config)
|
||||
{
|
||||
auto it = m_combinations.find(config);
|
||||
if (it == m_combinations.end())
|
||||
{
|
||||
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));
|
||||
|
||||
it = m_combinations.emplace(config, std::move(stage)).first;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user