From 4bf4154cad127560ffe831e7b2cd1a0b960d0f03 Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Tue, 22 Nov 2016 09:05:39 -0500 Subject: Fix superflous shader setting updates (#4800) This improves rendering performance by ~40% --- src/shader.cpp | 129 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 67 insertions(+), 62 deletions(-) (limited to 'src/shader.cpp') diff --git a/src/shader.cpp b/src/shader.cpp index b0131c952..170b0354d 100644 --- a/src/shader.cpp +++ b/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 m_setters; public: - ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name): - m_scsr(scsr), - m_name(name) - {} - ~ShaderCallback() {} + ShaderCallback(const std::vector &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 m_world_view_proj; + CachedVertexShaderSetting 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(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(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 m_get_shader_queue; - // Global constant setters - // TODO: Delete these in the destructor - std::vector m_global_setters; + // Global constant setter factories + std::vector m_setter_factories; + + // Shader callbacks + std::vector 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 &callbacks, + const std::vector &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::iterator iter = m_global_setters.begin(); - iter != m_global_setters.end(); ++iter) { + for (std::vector::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::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; ionSetConstants(services, is_highlevel); - } -} ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, - IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback, + IrrlichtDevice *device, std::vector &callbacks, + const std::vector &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 "<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, <