mirror of
https://github.com/luanti-org/luanti.git
synced 2025-10-21 20:05:45 +02:00
Increase flexibility of ShaderSource
This commit is contained in:
@@ -401,8 +401,10 @@ public:
|
|||||||
created_nosky.clear();
|
created_nosky.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual IShaderUniformSetter* create()
|
virtual IShaderUniformSetter* create(const std::string &name)
|
||||||
{
|
{
|
||||||
|
if (str_starts_with(name, "shadow/"))
|
||||||
|
return nullptr;
|
||||||
auto *scs = new GameGlobalShaderUniformSetter(m_sky, m_client);
|
auto *scs = new GameGlobalShaderUniformSetter(m_sky, m_client);
|
||||||
if (!m_sky)
|
if (!m_sky)
|
||||||
created_nosky.push_back(scs);
|
created_nosky.push_back(scs);
|
||||||
|
@@ -101,7 +101,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
IShaderUniformSetter *FogShaderUniformSetterFactory::create()
|
IShaderUniformSetter *FogShaderUniformSetterFactory::create(const std::string &name)
|
||||||
{
|
{
|
||||||
return new FogShaderUniformSetter();
|
return new FogShaderUniformSetter();
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,7 @@ class FogShaderUniformSetterFactory : public IShaderUniformSetterFactory
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FogShaderUniformSetterFactory() {};
|
FogShaderUniformSetterFactory() {};
|
||||||
virtual IShaderUniformSetter *create();
|
virtual IShaderUniformSetter *create(const std::string &name);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Rendering engine class */
|
/* Rendering engine class */
|
||||||
|
@@ -160,28 +160,44 @@ private:
|
|||||||
class ShaderCallback : public video::IShaderConstantSetCallBack
|
class ShaderCallback : public video::IShaderConstantSetCallBack
|
||||||
{
|
{
|
||||||
std::vector<std::unique_ptr<IShaderUniformSetter>> m_setters;
|
std::vector<std::unique_ptr<IShaderUniformSetter>> m_setters;
|
||||||
|
irr_ptr<IShaderUniformSetterRC> m_extra_setter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename Factories>
|
template <typename Factories>
|
||||||
ShaderCallback(const Factories &factories)
|
ShaderCallback(const std::string &name, const Factories &factories)
|
||||||
{
|
{
|
||||||
for (auto &&factory : factories) {
|
for (auto &&factory : factories) {
|
||||||
auto *setter = factory->create();
|
auto *setter = factory->create(name);
|
||||||
if (setter)
|
if (setter) {
|
||||||
|
// since we use unique_ptr, the object may not be refcounted
|
||||||
|
assert(dynamic_cast<IReferenceCounted*>(setter) == nullptr);
|
||||||
m_setters.emplace_back(setter);
|
m_setters.emplace_back(setter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ShaderCallback() = default;
|
||||||
|
|
||||||
|
void setExtraSetter(IShaderUniformSetterRC *setter)
|
||||||
|
{
|
||||||
|
assert(!m_extra_setter);
|
||||||
|
m_extra_setter.grab(setter);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
|
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
|
||||||
{
|
{
|
||||||
for (auto &&setter : m_setters)
|
for (auto &&setter : m_setters)
|
||||||
setter->onSetUniforms(services);
|
setter->onSetUniforms(services);
|
||||||
|
if (m_extra_setter)
|
||||||
|
m_extra_setter->onSetUniforms(services);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnSetMaterial(const video::SMaterial& material) override
|
virtual void OnSetMaterial(const video::SMaterial& material) override
|
||||||
{
|
{
|
||||||
for (auto &&setter : m_setters)
|
for (auto &&setter : m_setters)
|
||||||
setter->onSetMaterial(material);
|
setter->onSetMaterial(material);
|
||||||
|
if (m_extra_setter)
|
||||||
|
m_extra_setter->onSetMaterial(material);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -328,7 +344,7 @@ public:
|
|||||||
class MainShaderUniformSetterFactory : public IShaderUniformSetterFactory
|
class MainShaderUniformSetterFactory : public IShaderUniformSetterFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual IShaderUniformSetter* create()
|
virtual IShaderUniformSetter* create(const std::string &name)
|
||||||
{ return new MainShaderUniformSetter(); }
|
{ return new MainShaderUniformSetter(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -350,7 +366,7 @@ public:
|
|||||||
The id 0 points to a null shader. Its material is EMT_SOLID.
|
The id 0 points to a null shader. Its material is EMT_SOLID.
|
||||||
*/
|
*/
|
||||||
u32 getShaderIdDirect(const std::string &name, const ShaderConstants &input_const,
|
u32 getShaderIdDirect(const std::string &name, const ShaderConstants &input_const,
|
||||||
video::E_MATERIAL_TYPE base_mat);
|
video::E_MATERIAL_TYPE base_mat, IShaderUniformSetterRC *setter_cb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If shader specified by the name pointed by the id doesn't
|
If shader specified by the name pointed by the id doesn't
|
||||||
@@ -361,7 +377,8 @@ public:
|
|||||||
for processing.
|
for processing.
|
||||||
*/
|
*/
|
||||||
u32 getShader(const std::string &name, const ShaderConstants &input_const,
|
u32 getShader(const std::string &name, const ShaderConstants &input_const,
|
||||||
video::E_MATERIAL_TYPE base_mat) override;
|
video::E_MATERIAL_TYPE base_mat,
|
||||||
|
IShaderUniformSetterRC *setter_cb = nullptr) override;
|
||||||
|
|
||||||
const ShaderInfo &getShaderInfo(u32 id) override;
|
const ShaderInfo &getShaderInfo(u32 id) override;
|
||||||
|
|
||||||
@@ -414,9 +431,8 @@ private:
|
|||||||
// Global uniform setter factories
|
// Global uniform setter factories
|
||||||
std::vector<std::unique_ptr<IShaderUniformSetterFactory>> m_uniform_factories;
|
std::vector<std::unique_ptr<IShaderUniformSetterFactory>> m_uniform_factories;
|
||||||
|
|
||||||
// Generate shader given the shader name.
|
// Generate shader for given input parameters.
|
||||||
ShaderInfo generateShader(const std::string &name,
|
void generateShader(ShaderInfo &info);
|
||||||
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat);
|
|
||||||
|
|
||||||
/// @brief outputs a constant to an ostream
|
/// @brief outputs a constant to an ostream
|
||||||
inline void putConstant(std::ostream &os, const ShaderConstants::mapped_type &it)
|
inline void putConstant(std::ostream &os, const ShaderConstants::mapped_type &it)
|
||||||
@@ -465,14 +481,15 @@ ShaderSource::~ShaderSource()
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 ShaderSource::getShader(const std::string &name,
|
u32 ShaderSource::getShader(const std::string &name,
|
||||||
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat)
|
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat,
|
||||||
|
IShaderUniformSetterRC *setter_cb)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Get shader
|
Get shader
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (std::this_thread::get_id() == m_main_thread) {
|
if (std::this_thread::get_id() == m_main_thread) {
|
||||||
return getShaderIdDirect(name, input_const, base_mat);
|
return getShaderIdDirect(name, input_const, base_mat, setter_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
errorstream << "ShaderSource::getShader(): getting from "
|
errorstream << "ShaderSource::getShader(): getting from "
|
||||||
@@ -510,7 +527,8 @@ u32 ShaderSource::getShader(const std::string &name,
|
|||||||
This method generates all the shaders
|
This method generates all the shaders
|
||||||
*/
|
*/
|
||||||
u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
||||||
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat)
|
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat,
|
||||||
|
IShaderUniformSetterRC *setter_cb)
|
||||||
{
|
{
|
||||||
// Empty name means shader 0
|
// Empty name means shader 0
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
@@ -522,23 +540,23 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
|||||||
for (u32 i = 0; i < m_shaderinfo_cache.size(); i++) {
|
for (u32 i = 0; i < m_shaderinfo_cache.size(); i++) {
|
||||||
auto &info = m_shaderinfo_cache[i];
|
auto &info = m_shaderinfo_cache[i];
|
||||||
if (info.name == name && info.base_material == base_mat &&
|
if (info.name == name && info.base_material == base_mat &&
|
||||||
info.input_constants == input_const)
|
info.input_constants == input_const && info.setter_cb == setter_cb)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Calling only allowed from main thread
|
||||||
Calling only allowed from main thread
|
sanity_check(std::this_thread::get_id() == m_main_thread);
|
||||||
*/
|
|
||||||
if (std::this_thread::get_id() != m_main_thread) {
|
|
||||||
errorstream<<"ShaderSource::getShaderIdDirect() "
|
|
||||||
"called not from main thread"<<std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderInfo info = generateShader(name, input_const, base_mat);
|
ShaderInfo info;
|
||||||
|
info.name = name;
|
||||||
|
info.input_constants = input_const;
|
||||||
|
info.base_material = base_mat;
|
||||||
|
info.setter_cb.grab(setter_cb);
|
||||||
|
|
||||||
|
generateShader(info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Add shader to caches (add dummy shaders too)
|
Add shader to caches
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MutexAutoLock lock(m_shaderinfo_cache_mutex);
|
MutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||||
@@ -597,29 +615,28 @@ void ShaderSource::rebuildShaders()
|
|||||||
|
|
||||||
// Recreate shaders
|
// Recreate shaders
|
||||||
for (ShaderInfo &i : m_shaderinfo_cache) {
|
for (ShaderInfo &i : m_shaderinfo_cache) {
|
||||||
ShaderInfo *info = &i;
|
if (!i.name.empty()) {
|
||||||
if (!info->name.empty()) {
|
generateShader(i);
|
||||||
*info = generateShader(info->name, info->input_constants, info->base_material);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ShaderInfo ShaderSource::generateShader(const std::string &name,
|
void ShaderSource::generateShader(ShaderInfo &shaderinfo)
|
||||||
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat)
|
|
||||||
{
|
{
|
||||||
ShaderInfo shaderinfo;
|
const auto &name = shaderinfo.name;
|
||||||
shaderinfo.name = name;
|
const auto &input_const = shaderinfo.input_constants;
|
||||||
shaderinfo.input_constants = input_const;
|
|
||||||
// fixed pipeline materials don't make sense here
|
// fixed pipeline materials don't make sense here
|
||||||
assert(base_mat != video::EMT_TRANSPARENT_VERTEX_ALPHA && base_mat != video::EMT_ONETEXTURE_BLEND);
|
assert(shaderinfo.base_material != video::EMT_TRANSPARENT_VERTEX_ALPHA &&
|
||||||
shaderinfo.base_material = base_mat;
|
shaderinfo.base_material != video::EMT_ONETEXTURE_BLEND);
|
||||||
shaderinfo.material = shaderinfo.base_material;
|
|
||||||
|
|
||||||
auto *driver = RenderingEngine::get_video_driver();
|
auto *driver = RenderingEngine::get_video_driver();
|
||||||
// The null driver doesn't support shaders (duh), but we can pretend it does.
|
// The null driver doesn't support shaders (duh), but we can pretend it does.
|
||||||
if (driver->getDriverType() == video::EDT_NULL)
|
if (driver->getDriverType() == video::EDT_NULL) {
|
||||||
return shaderinfo;
|
shaderinfo.material = shaderinfo.base_material;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto *gpu = driver->getGPUProgrammingServices();
|
auto *gpu = driver->getGPUProgrammingServices();
|
||||||
if (!driver->queryFeature(video::EVDF_ARB_GLSL) || !gpu) {
|
if (!driver->queryFeature(video::EVDF_ARB_GLSL) || !gpu) {
|
||||||
@@ -746,7 +763,9 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
|||||||
geometry_shader_ptr = geometry_shader.c_str();
|
geometry_shader_ptr = geometry_shader.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cb = make_irr<ShaderCallback>(m_uniform_factories);
|
auto cb = make_irr<ShaderCallback>(name, m_uniform_factories);
|
||||||
|
cb->setExtraSetter(shaderinfo.setter_cb.get());
|
||||||
|
|
||||||
infostream << "Compiling high level shaders for " << log_name << std::endl;
|
infostream << "Compiling high level shaders for " << log_name << std::endl;
|
||||||
s32 shadermat = gpu->addHighLevelShaderMaterial(
|
s32 shadermat = gpu->addHighLevelShaderMaterial(
|
||||||
vertex_shader.c_str(), fragment_shader.c_str(), geometry_shader_ptr,
|
vertex_shader.c_str(), fragment_shader.c_str(), geometry_shader_ptr,
|
||||||
@@ -765,7 +784,6 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
|||||||
|
|
||||||
// Apply the newly created material type
|
// Apply the newly created material type
|
||||||
shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
|
shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
|
||||||
return shaderinfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "irrlichttypes_bloated.h"
|
#include "irrlichttypes_bloated.h"
|
||||||
#include <IMaterialRendererServices.h>
|
#include <IMaterialRendererServices.h>
|
||||||
|
#include "irr_ptr.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
@@ -51,26 +52,41 @@ public:
|
|||||||
Abstraction for updating uniforms used by shaders
|
Abstraction for updating uniforms used by shaders
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace video {
|
|
||||||
class IMaterialRendererServices;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class IShaderUniformSetter {
|
class IShaderUniformSetter {
|
||||||
public:
|
public:
|
||||||
virtual ~IShaderUniformSetter() = default;
|
virtual ~IShaderUniformSetter() = default;
|
||||||
|
/**
|
||||||
|
* Called when uniforms need to be updated
|
||||||
|
* @param services interface for setting uniforms
|
||||||
|
*/
|
||||||
virtual void onSetUniforms(video::IMaterialRendererServices *services) = 0;
|
virtual void onSetUniforms(video::IMaterialRendererServices *services) = 0;
|
||||||
virtual void onSetMaterial(const video::SMaterial& material)
|
virtual void onSetMaterial(const video::SMaterial& material)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IShaderUniformSetterRC : public IShaderUniformSetter, public IReferenceCounted
|
||||||
|
{
|
||||||
|
// Reference counted variant for special use-cases
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class IShaderUniformSetterFactory {
|
class IShaderUniformSetterFactory {
|
||||||
public:
|
public:
|
||||||
virtual ~IShaderUniformSetterFactory() = default;
|
virtual ~IShaderUniformSetterFactory() = default;
|
||||||
virtual IShaderUniformSetter* create() = 0;
|
/**
|
||||||
|
* Called to create an uniform setter for a specific shader
|
||||||
|
* @param name name of the shader
|
||||||
|
* @return new uniform setter (or nullptr). caller takes ownership.
|
||||||
|
*/
|
||||||
|
virtual IShaderUniformSetter *create(const std::string &name) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Helpers to set uniforms only when changed.
|
||||||
|
|
||||||
|
Be warned that when using this you can't attach a IShaderUniformSetter to
|
||||||
|
multiple different shaders. But you probably don't want to anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename T, std::size_t count, bool cache>
|
template <typename T, std::size_t count, bool cache>
|
||||||
class CachedShaderSetting {
|
class CachedShaderSetting {
|
||||||
@@ -217,6 +233,8 @@ struct ShaderInfo {
|
|||||||
video::E_MATERIAL_TYPE material = video::EMT_SOLID;
|
video::E_MATERIAL_TYPE material = video::EMT_SOLID;
|
||||||
// Input constants
|
// Input constants
|
||||||
ShaderConstants input_constants;
|
ShaderConstants input_constants;
|
||||||
|
// Extra uniform callback
|
||||||
|
irr_ptr<IShaderUniformSetterRC> setter_cb;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IShaderSource {
|
class IShaderSource {
|
||||||
@@ -239,11 +257,13 @@ public:
|
|||||||
* @param name name of the shader (directory on disk)
|
* @param name name of the shader (directory on disk)
|
||||||
* @param input_const primary key constants for this shader
|
* @param input_const primary key constants for this shader
|
||||||
* @param base_mat base material to use
|
* @param base_mat base material to use
|
||||||
|
* @param setter_cb additional uniform setter to use
|
||||||
* @return shader ID
|
* @return shader ID
|
||||||
* @note `base_material` only controls alpha behavior
|
* @note `base_material` only controls alpha behavior
|
||||||
*/
|
*/
|
||||||
virtual u32 getShader(const std::string &name,
|
virtual u32 getShader(const std::string &name,
|
||||||
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat) = 0;
|
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat,
|
||||||
|
IShaderUniformSetterRC *setter_cb = nullptr) = 0;
|
||||||
|
|
||||||
/// @brief Helper: Generates or gets a shader suitable for nodes and entities
|
/// @brief Helper: Generates or gets a shader suitable for nodes and entities
|
||||||
u32 getShader(const std::string &name,
|
u32 getShader(const std::string &name,
|
||||||
|
@@ -42,7 +42,7 @@ public:
|
|||||||
class ShadowUniformSetterFactory : public IShaderUniformSetterFactory
|
class ShadowUniformSetterFactory : public IShaderUniformSetterFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual IShaderUniformSetter *create() {
|
virtual IShaderUniformSetter *create(const std::string &name) {
|
||||||
return new ShadowUniformSetter();
|
return new ShadowUniformSetter();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user