mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Fix superflous shader setting updates (#4800)
This improves rendering performance by ~40%
This commit is contained in:
parent
c6ca7a81cc
commit
4bf4154cad
3 changed files with 250 additions and 128 deletions
129
src/shader.cpp
129
src/shader.cpp
|
@ -167,29 +167,27 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
ShaderCallback: Sets constants that can be used in shaders
|
||||
*/
|
||||
|
||||
class IShaderConstantSetterRegistry
|
||||
{
|
||||
public:
|
||||
virtual ~IShaderConstantSetterRegistry(){};
|
||||
virtual void onSetConstants(video::IMaterialRendererServices *services,
|
||||
bool is_highlevel, const std::string &name) = 0;
|
||||
};
|
||||
|
||||
class ShaderCallback : public video::IShaderConstantSetCallBack
|
||||
{
|
||||
IShaderConstantSetterRegistry *m_scsr;
|
||||
std::string m_name;
|
||||
std::vector<IShaderConstantSetter*> m_setters;
|
||||
|
||||
public:
|
||||
ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
|
||||
m_scsr(scsr),
|
||||
m_name(name)
|
||||
{}
|
||||
~ShaderCallback() {}
|
||||
ShaderCallback(const std::vector<IShaderConstantSetterFactory*> &factories)
|
||||
{
|
||||
for (u32 i = 0; i < factories.size(); ++i)
|
||||
m_setters.push_back(factories[i]->create());
|
||||
}
|
||||
|
||||
~ShaderCallback()
|
||||
{
|
||||
for (u32 i = 0; i < m_setters.size(); ++i)
|
||||
delete m_setters[i];
|
||||
}
|
||||
|
||||
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
|
||||
{
|
||||
|
@ -198,18 +196,25 @@ public:
|
|||
|
||||
bool is_highlevel = userData;
|
||||
|
||||
m_scsr->onSetConstants(services, is_highlevel, m_name);
|
||||
for (u32 i = 0; i < m_setters.size(); ++i)
|
||||
m_setters[i]->onSetConstants(services, is_highlevel);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
MainShaderConstantSetter: Set basic constants required for almost everything
|
||||
*/
|
||||
|
||||
class MainShaderConstantSetter : public IShaderConstantSetter
|
||||
{
|
||||
CachedVertexShaderSetting<float, 16> m_world_view_proj;
|
||||
CachedVertexShaderSetting<float, 16> m_world;
|
||||
|
||||
public:
|
||||
MainShaderConstantSetter(IrrlichtDevice *device)
|
||||
MainShaderConstantSetter() :
|
||||
m_world_view_proj("mWorldViewProj"),
|
||||
m_world("mWorld")
|
||||
{}
|
||||
~MainShaderConstantSetter() {}
|
||||
|
||||
|
@ -219,31 +224,40 @@ public:
|
|||
video::IVideoDriver *driver = services->getVideoDriver();
|
||||
sanity_check(driver);
|
||||
|
||||
// set clip matrix
|
||||
// Set clip matrix
|
||||
core::matrix4 worldViewProj;
|
||||
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
|
||||
worldViewProj *= driver->getTransform(video::ETS_VIEW);
|
||||
worldViewProj *= driver->getTransform(video::ETS_WORLD);
|
||||
if(is_highlevel)
|
||||
services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
|
||||
if (is_highlevel)
|
||||
m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
|
||||
else
|
||||
services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
|
||||
services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
|
||||
|
||||
// set world matrix
|
||||
// Set world matrix
|
||||
core::matrix4 world = driver->getTransform(video::ETS_WORLD);
|
||||
if(is_highlevel)
|
||||
services->setVertexShaderConstant("mWorld", world.pointer(), 16);
|
||||
if (is_highlevel)
|
||||
m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
|
||||
else
|
||||
services->setVertexShaderConstant(world.pointer(), 8, 4);
|
||||
services->setVertexShaderConstant(world.pointer(), 4, 4);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
|
||||
{
|
||||
public:
|
||||
virtual IShaderConstantSetter* create()
|
||||
{ return new MainShaderConstantSetter(); }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
ShaderSource
|
||||
*/
|
||||
|
||||
class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
|
||||
class ShaderSource : public IWritableShaderSource
|
||||
{
|
||||
public:
|
||||
ShaderSource(IrrlichtDevice *device);
|
||||
|
@ -286,22 +300,17 @@ public:
|
|||
// Shall be called from the main thread.
|
||||
void rebuildShaders();
|
||||
|
||||
void addGlobalConstantSetter(IShaderConstantSetter *setter)
|
||||
void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
|
||||
{
|
||||
m_global_setters.push_back(setter);
|
||||
m_setter_factories.push_back(setter);
|
||||
}
|
||||
|
||||
void onSetConstants(video::IMaterialRendererServices *services,
|
||||
bool is_highlevel, const std::string &name);
|
||||
|
||||
private:
|
||||
|
||||
// The id of the thread that is allowed to use irrlicht directly
|
||||
threadid_t m_main_thread;
|
||||
// The irrlicht device
|
||||
IrrlichtDevice *m_device;
|
||||
// The set-constants callback
|
||||
ShaderCallback *m_shader_callback;
|
||||
|
||||
// Cache of source shaders
|
||||
// This should be only accessed from the main thread
|
||||
|
@ -316,9 +325,11 @@ private:
|
|||
// Queued shader fetches (to be processed by the main thread)
|
||||
RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
|
||||
|
||||
// Global constant setters
|
||||
// TODO: Delete these in the destructor
|
||||
std::vector<IShaderConstantSetter*> m_global_setters;
|
||||
// Global constant setter factories
|
||||
std::vector<IShaderConstantSetterFactory *> m_setter_factories;
|
||||
|
||||
// Shader callbacks
|
||||
std::vector<ShaderCallback *> m_callbacks;
|
||||
};
|
||||
|
||||
IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
|
||||
|
@ -331,8 +342,8 @@ IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
|
|||
*/
|
||||
ShaderInfo generate_shader(std::string name,
|
||||
u8 material_type, u8 drawtype,
|
||||
IrrlichtDevice *device,
|
||||
video::IShaderConstantSetCallBack *callback,
|
||||
IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
|
||||
const std::vector<IShaderConstantSetterFactory*> &setter_factories,
|
||||
SourceShaderCache *sourcecache);
|
||||
|
||||
/*
|
||||
|
@ -348,28 +359,24 @@ ShaderSource::ShaderSource(IrrlichtDevice *device):
|
|||
{
|
||||
assert(m_device); // Pre-condition
|
||||
|
||||
m_shader_callback = new ShaderCallback(this, "default");
|
||||
|
||||
m_main_thread = thr_get_current_thread_id();
|
||||
|
||||
// Add a dummy ShaderInfo as the first index, named ""
|
||||
m_shaderinfo_cache.push_back(ShaderInfo());
|
||||
|
||||
// Add main global constant setter
|
||||
addGlobalConstantSetter(new MainShaderConstantSetter(device));
|
||||
addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
|
||||
}
|
||||
|
||||
ShaderSource::~ShaderSource()
|
||||
{
|
||||
for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
|
||||
iter != m_global_setters.end(); ++iter) {
|
||||
for (std::vector<ShaderCallback *>::iterator iter = m_callbacks.begin();
|
||||
iter != m_callbacks.end(); ++iter) {
|
||||
delete *iter;
|
||||
}
|
||||
m_global_setters.clear();
|
||||
|
||||
if (m_shader_callback) {
|
||||
m_shader_callback->drop();
|
||||
m_shader_callback = NULL;
|
||||
for (std::vector<IShaderConstantSetterFactory *>::iterator iter = m_setter_factories.begin();
|
||||
iter != m_setter_factories.end(); ++iter) {
|
||||
delete *iter;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,8 +452,8 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
|||
return 0;
|
||||
}
|
||||
|
||||
ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
|
||||
m_shader_callback, &m_sourcecache);
|
||||
ShaderInfo info = generate_shader(name, material_type, drawtype,
|
||||
m_device, m_callbacks, m_setter_factories, &m_sourcecache);
|
||||
|
||||
/*
|
||||
Add shader to caches (add dummy shaders too)
|
||||
|
@ -511,22 +518,16 @@ void ShaderSource::rebuildShaders()
|
|||
ShaderInfo *info = &m_shaderinfo_cache[i];
|
||||
if(info->name != ""){
|
||||
*info = generate_shader(info->name, info->material_type,
|
||||
info->drawtype, m_device, m_shader_callback, &m_sourcecache);
|
||||
info->drawtype, m_device, m_callbacks,
|
||||
m_setter_factories, &m_sourcecache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
|
||||
bool is_highlevel, const std::string &name)
|
||||
{
|
||||
for(u32 i=0; i<m_global_setters.size(); i++){
|
||||
IShaderConstantSetter *setter = m_global_setters[i];
|
||||
setter->onSetConstants(services, is_highlevel);
|
||||
}
|
||||
}
|
||||
|
||||
ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
|
||||
IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
|
||||
IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
|
||||
const std::vector<IShaderConstantSetterFactory*> &setter_factories,
|
||||
SourceShaderCache *sourcecache)
|
||||
{
|
||||
ShaderInfo shaderinfo;
|
||||
|
@ -766,6 +767,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
|
|||
geometry_program = shaders_header + geometry_program;
|
||||
geometry_program_ptr = geometry_program.c_str();
|
||||
}
|
||||
ShaderCallback *cb = new ShaderCallback(setter_factories);
|
||||
s32 shadermat = -1;
|
||||
if(is_highlevel){
|
||||
infostream<<"Compiling high level shaders for "<<name<<std::endl;
|
||||
|
@ -782,7 +784,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
|
|||
scene::EPT_TRIANGLES, // Geometry shader input
|
||||
scene::EPT_TRIANGLE_STRIP, // Geometry shader output
|
||||
0, // Support maximum number of vertices
|
||||
callback, // Set-constant callback
|
||||
cb, // Set-constant callback
|
||||
shaderinfo.base_material, // Base material
|
||||
1 // Userdata passed to callback
|
||||
);
|
||||
|
@ -794,6 +796,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
|
|||
dumpShaderProgram(warningstream, "Vertex", vertex_program);
|
||||
dumpShaderProgram(warningstream, "Pixel", pixel_program);
|
||||
dumpShaderProgram(warningstream, "Geometry", geometry_program);
|
||||
delete cb;
|
||||
return shaderinfo;
|
||||
}
|
||||
}
|
||||
|
@ -802,7 +805,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
|
|||
shadermat = gpu->addShaderMaterial(
|
||||
vertex_program_ptr, // Vertex shader program
|
||||
pixel_program_ptr, // Pixel shader program
|
||||
callback, // Set-constant callback
|
||||
cb, // Set-constant callback
|
||||
shaderinfo.base_material, // Base material
|
||||
0 // Userdata passed to callback
|
||||
);
|
||||
|
@ -814,9 +817,11 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
|
|||
<<std::endl;
|
||||
dumpShaderProgram(warningstream, "Vertex", vertex_program);
|
||||
dumpShaderProgram(warningstream,"Pixel", pixel_program);
|
||||
delete cb;
|
||||
return shaderinfo;
|
||||
}
|
||||
}
|
||||
callbacks.push_back(cb);
|
||||
|
||||
// HACK, TODO: investigate this better
|
||||
// Grab the material renderer once more so minetest doesn't crash on exit
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue