Skip to content

Commit 4bf4154

Browse files
ShadowNinjaZeno-
authored andcommittedNov 22, 2016
Fix superflous shader setting updates (#4800)
This improves rendering performance by ~40%
1 parent c6ca7a8 commit 4bf4154

File tree

3 files changed

+249
-127
lines changed

3 files changed

+249
-127
lines changed
 

‎src/game.cpp

+128-56
Original file line numberDiff line numberDiff line change
@@ -888,40 +888,73 @@ class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
888888
}
889889
};
890890

891+
892+
// before 1.8 there isn't a "integer interface", only float
893+
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
894+
typedef f32 SamplerLayer_t;
895+
#else
896+
typedef s32 SamplerLayer_t;
897+
#endif
898+
899+
891900
class GameGlobalShaderConstantSetter : public IShaderConstantSetter
892901
{
893902
Sky *m_sky;
894903
bool *m_force_fog_off;
895904
f32 *m_fog_range;
905+
bool m_fog_enabled;
906+
CachedPixelShaderSetting<float, 4> m_sky_bg_color;
907+
CachedPixelShaderSetting<float> m_fog_distance;
908+
CachedVertexShaderSetting<float> m_animation_timer_vertex;
909+
CachedPixelShaderSetting<float> m_animation_timer_pixel;
910+
CachedPixelShaderSetting<float> m_day_night_ratio;
911+
CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
912+
CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
913+
CachedPixelShaderSetting<float, 3> m_minimap_yaw;
914+
CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
915+
CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
916+
CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags;
896917
Client *m_client;
897-
bool m_fogEnabled;
898918

899919
public:
900920
void onSettingsChange(const std::string &name)
901921
{
902922
if (name == "enable_fog")
903-
m_fogEnabled = g_settings->getBool("enable_fog");
923+
m_fog_enabled = g_settings->getBool("enable_fog");
904924
}
905925

906-
static void SettingsCallback(const std::string &name, void *userdata)
926+
static void settingsCallback(const std::string &name, void *userdata)
907927
{
908928
reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
909929
}
910930

931+
void setSky(Sky *sky) { m_sky = sky; }
932+
911933
GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
912934
f32 *fog_range, Client *client) :
913935
m_sky(sky),
914936
m_force_fog_off(force_fog_off),
915937
m_fog_range(fog_range),
938+
m_sky_bg_color("skyBgColor"),
939+
m_fog_distance("fogDistance"),
940+
m_animation_timer_vertex("animationTimer"),
941+
m_animation_timer_pixel("animationTimer"),
942+
m_day_night_ratio("dayNightRatio"),
943+
m_eye_position_pixel("eyePosition"),
944+
m_eye_position_vertex("eyePosition"),
945+
m_minimap_yaw("yawVec"),
946+
m_base_texture("baseTexture"),
947+
m_normal_texture("normalTexture"),
948+
m_texture_flags("textureFlags"),
916949
m_client(client)
917950
{
918-
g_settings->registerChangedCallback("enable_fog", SettingsCallback, this);
919-
m_fogEnabled = g_settings->getBool("enable_fog");
951+
g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
952+
m_fog_enabled = g_settings->getBool("enable_fog");
920953
}
921954

922955
~GameGlobalShaderConstantSetter()
923956
{
924-
g_settings->deregisterChangedCallback("enable_fog", SettingsCallback, this);
957+
g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
925958
}
926959

927960
virtual void onSetConstants(video::IMaterialRendererServices *services,
@@ -939,54 +972,92 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
939972
bgcolorf.b,
940973
bgcolorf.a,
941974
};
942-
services->setPixelShaderConstant("skyBgColor", bgcolorfa, 4);
975+
m_sky_bg_color.set(bgcolorfa, services);
943976

944977
// Fog distance
945978
float fog_distance = 10000 * BS;
946979

947-
if (m_fogEnabled && !*m_force_fog_off)
980+
if (m_fog_enabled && !*m_force_fog_off)
948981
fog_distance = *m_fog_range;
949982

950-
services->setPixelShaderConstant("fogDistance", &fog_distance, 1);
983+
m_fog_distance.set(&fog_distance, services);
951984

952-
// Day-night ratio
953-
u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
954-
float daynight_ratio_f = (float)daynight_ratio / 1000.0;
955-
services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1);
985+
float daynight_ratio = (float)m_client->getEnv().getDayNightRatio() / 1000.f;
986+
m_day_night_ratio.set(&daynight_ratio, services);
956987

957988
u32 animation_timer = porting::getTimeMs() % 100000;
958-
float animation_timer_f = (float)animation_timer / 100000.0;
959-
services->setPixelShaderConstant("animationTimer", &animation_timer_f, 1);
960-
services->setVertexShaderConstant("animationTimer", &animation_timer_f, 1);
989+
float animation_timer_f = (float)animation_timer / 100000.f;
990+
m_animation_timer_vertex.set(&animation_timer_f, services);
991+
m_animation_timer_pixel.set(&animation_timer_f, services);
961992

962-
LocalPlayer *player = m_client->getEnv().getLocalPlayer();
963-
v3f eye_position = player->getEyePosition();
964-
services->setPixelShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3);
965-
services->setVertexShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3);
966-
967-
v3f minimap_yaw_vec = m_client->getMapper()->getYawVec();
968-
services->setPixelShaderConstant("yawVec", (irr::f32 *)&minimap_yaw_vec, 3);
993+
float eye_position_array[3];
994+
v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
995+
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
996+
eye_position_array[0] = epos.X;
997+
eye_position_array[1] = epos.Y;
998+
eye_position_array[2] = epos.Z;
999+
#else
1000+
epos.getAs3Values(eye_position_array);
1001+
#endif
1002+
m_eye_position_pixel.set(eye_position_array, services);
1003+
m_eye_position_vertex.set(eye_position_array, services);
9691004

970-
// Uniform sampler layers
971-
// before 1.8 there isn't a "integer interface", only float
1005+
float minimap_yaw_array[3];
1006+
v3f minimap_yaw = m_client->getMapper()->getYawVec();
9721007
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
973-
f32 layer0 = 0;
974-
f32 layer1 = 1;
975-
f32 layer2 = 2;
976-
services->setPixelShaderConstant("baseTexture" , (irr::f32 *)&layer0, 1);
977-
services->setPixelShaderConstant("normalTexture" , (irr::f32 *)&layer1, 1);
978-
services->setPixelShaderConstant("textureFlags" , (irr::f32 *)&layer2, 1);
1008+
minimap_yaw_array[0] = minimap_yaw.X;
1009+
minimap_yaw_array[1] = minimap_yaw.Y;
1010+
minimap_yaw_array[2] = minimap_yaw.Z;
9791011
#else
980-
s32 layer0 = 0;
981-
s32 layer1 = 1;
982-
s32 layer2 = 2;
983-
services->setPixelShaderConstant("baseTexture" , (irr::s32 *)&layer0, 1);
984-
services->setPixelShaderConstant("normalTexture" , (irr::s32 *)&layer1, 1);
985-
services->setPixelShaderConstant("textureFlags" , (irr::s32 *)&layer2, 1);
1012+
minimap_yaw.getAs3Values(minimap_yaw_array);
9861013
#endif
1014+
m_minimap_yaw.set(minimap_yaw_array, services);
1015+
1016+
SamplerLayer_t base_tex = 0,
1017+
normal_tex = 1,
1018+
flags_tex = 2;
1019+
m_base_texture.set(&base_tex, services);
1020+
m_normal_texture.set(&normal_tex, services);
1021+
m_texture_flags.set(&flags_tex, services);
9871022
}
9881023
};
9891024

1025+
1026+
class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
1027+
{
1028+
Sky *m_sky;
1029+
bool *m_force_fog_off;
1030+
f32 *m_fog_range;
1031+
Client *m_client;
1032+
std::vector<GameGlobalShaderConstantSetter *> created_nosky;
1033+
public:
1034+
GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
1035+
f32 *fog_range, Client *client) :
1036+
m_sky(NULL),
1037+
m_force_fog_off(force_fog_off),
1038+
m_fog_range(fog_range),
1039+
m_client(client)
1040+
{}
1041+
1042+
void setSky(Sky *sky) {
1043+
m_sky = sky;
1044+
for (size_t i = 0; i < created_nosky.size(); ++i) {
1045+
created_nosky[i]->setSky(m_sky);
1046+
}
1047+
created_nosky.clear();
1048+
}
1049+
1050+
virtual IShaderConstantSetter* create()
1051+
{
1052+
GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter(
1053+
m_sky, m_force_fog_off, m_fog_range, m_client);
1054+
if (!m_sky)
1055+
created_nosky.push_back(scs);
1056+
return scs;
1057+
}
1058+
};
1059+
1060+
9901061
bool nodePlacementPrediction(Client &client,
9911062
const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos)
9921063
{
@@ -1695,6 +1766,9 @@ class Game {
16951766
Hud *hud;
16961767
Mapper *mapper;
16971768

1769+
GameRunData runData;
1770+
VolatileRunFlags flags;
1771+
16981772
/* 'cache'
16991773
This class does take ownership/responsibily for cleaning up etc of any of
17001774
these items (e.g. device)
@@ -1886,6 +1960,18 @@ bool Game::startup(bool *kill,
18861960

18871961
smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
18881962

1963+
memset(&runData, 0, sizeof(runData));
1964+
runData.time_from_last_punch = 10.0;
1965+
runData.profiler_max_page = 3;
1966+
runData.update_wielded_item_trigger = true;
1967+
1968+
memset(&flags, 0, sizeof(flags));
1969+
flags.show_chat = true;
1970+
flags.show_hud = true;
1971+
flags.show_debug = g_settings->getBool("show_debug");
1972+
flags.invert_mouse = g_settings->getBool("invert_mouse");
1973+
flags.first_loop_after_window_activation = true;
1974+
18891975
if (!init(map_dir, address, port, gamespec))
18901976
return false;
18911977

@@ -1902,34 +1988,15 @@ void Game::run()
19021988
RunStats stats = { 0 };
19031989
CameraOrientation cam_view_target = { 0 };
19041990
CameraOrientation cam_view = { 0 };
1905-
GameRunData runData = { 0 };
19061991
FpsControl draw_times = { 0 };
1907-
VolatileRunFlags flags = { 0 };
19081992
f32 dtime; // in seconds
19091993

1910-
runData.time_from_last_punch = 10.0;
1911-
runData.profiler_max_page = 3;
1912-
runData.update_wielded_item_trigger = true;
1913-
1914-
flags.show_chat = true;
1915-
flags.show_hud = true;
1916-
flags.show_minimap = g_settings->getBool("enable_minimap");
1917-
flags.show_debug = g_settings->getBool("show_debug");
1918-
flags.invert_mouse = g_settings->getBool("invert_mouse");
1919-
flags.first_loop_after_window_activation = true;
1920-
19211994
/* Clear the profiler */
19221995
Profiler::GraphValues dummyvalues;
19231996
g_profiler->graphGet(dummyvalues);
19241997

19251998
draw_times.last_time = device->getTimer()->getTime();
19261999

1927-
shader_src->addGlobalConstantSetter(new GameGlobalShaderConstantSetter(
1928-
sky,
1929-
&flags.force_fog_off,
1930-
&runData.fog_range,
1931-
client));
1932-
19332000
set_light_table(g_settings->getFloat("display_gamma"));
19342001

19352002
#ifdef __ANDROID__
@@ -2169,6 +2236,10 @@ bool Game::createClient(const std::string &playername,
21692236
return false;
21702237
}
21712238

2239+
GameGlobalShaderConstantSetterFactory *scsf = new GameGlobalShaderConstantSetterFactory(
2240+
&flags.force_fog_off, &runData.fog_range, client);
2241+
shader_src->addShaderConstantSetterFactory(scsf);
2242+
21722243
// Update cached textures, meshes and materials
21732244
client->afterContentReceived(device);
21742245

@@ -2193,6 +2264,7 @@ bool Game::createClient(const std::string &playername,
21932264
/* Skybox
21942265
*/
21952266
sky = new Sky(smgr->getRootSceneNode(), smgr, -1, texture_src);
2267+
scsf->setSky(sky);
21962268
skybox = NULL; // This is used/set later on in the main run loop
21972269

21982270
local_inventory = new Inventory(itemdef_manager);

‎src/shader.cpp

+67-62
Original file line numberDiff line numberDiff line change
@@ -167,29 +167,27 @@ class SourceShaderCache
167167
}
168168
};
169169

170+
170171
/*
171172
ShaderCallback: Sets constants that can be used in shaders
172173
*/
173174

174-
class IShaderConstantSetterRegistry
175-
{
176-
public:
177-
virtual ~IShaderConstantSetterRegistry(){};
178-
virtual void onSetConstants(video::IMaterialRendererServices *services,
179-
bool is_highlevel, const std::string &name) = 0;
180-
};
181-
182175
class ShaderCallback : public video::IShaderConstantSetCallBack
183176
{
184-
IShaderConstantSetterRegistry *m_scsr;
185-
std::string m_name;
177+
std::vector<IShaderConstantSetter*> m_setters;
186178

187179
public:
188-
ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
189-
m_scsr(scsr),
190-
m_name(name)
191-
{}
192-
~ShaderCallback() {}
180+
ShaderCallback(const std::vector<IShaderConstantSetterFactory*> &factories)
181+
{
182+
for (u32 i = 0; i < factories.size(); ++i)
183+
m_setters.push_back(factories[i]->create());
184+
}
185+
186+
~ShaderCallback()
187+
{
188+
for (u32 i = 0; i < m_setters.size(); ++i)
189+
delete m_setters[i];
190+
}
193191

194192
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
195193
{
@@ -198,18 +196,25 @@ class ShaderCallback : public video::IShaderConstantSetCallBack
198196

199197
bool is_highlevel = userData;
200198

201-
m_scsr->onSetConstants(services, is_highlevel, m_name);
199+
for (u32 i = 0; i < m_setters.size(); ++i)
200+
m_setters[i]->onSetConstants(services, is_highlevel);
202201
}
203202
};
204203

204+
205205
/*
206206
MainShaderConstantSetter: Set basic constants required for almost everything
207207
*/
208208

209209
class MainShaderConstantSetter : public IShaderConstantSetter
210210
{
211+
CachedVertexShaderSetting<float, 16> m_world_view_proj;
212+
CachedVertexShaderSetting<float, 16> m_world;
213+
211214
public:
212-
MainShaderConstantSetter(IrrlichtDevice *device)
215+
MainShaderConstantSetter() :
216+
m_world_view_proj("mWorldViewProj"),
217+
m_world("mWorld")
213218
{}
214219
~MainShaderConstantSetter() {}
215220

@@ -219,31 +224,40 @@ class MainShaderConstantSetter : public IShaderConstantSetter
219224
video::IVideoDriver *driver = services->getVideoDriver();
220225
sanity_check(driver);
221226

222-
// set clip matrix
227+
// Set clip matrix
223228
core::matrix4 worldViewProj;
224229
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
225230
worldViewProj *= driver->getTransform(video::ETS_VIEW);
226231
worldViewProj *= driver->getTransform(video::ETS_WORLD);
227-
if(is_highlevel)
228-
services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
232+
if (is_highlevel)
233+
m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
229234
else
230-
services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
235+
services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
231236

232-
// set world matrix
237+
// Set world matrix
233238
core::matrix4 world = driver->getTransform(video::ETS_WORLD);
234-
if(is_highlevel)
235-
services->setVertexShaderConstant("mWorld", world.pointer(), 16);
239+
if (is_highlevel)
240+
m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
236241
else
237-
services->setVertexShaderConstant(world.pointer(), 8, 4);
242+
services->setVertexShaderConstant(world.pointer(), 4, 4);
238243

239244
}
240245
};
241246

247+
248+
class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
249+
{
250+
public:
251+
virtual IShaderConstantSetter* create()
252+
{ return new MainShaderConstantSetter(); }
253+
};
254+
255+
242256
/*
243257
ShaderSource
244258
*/
245259

246-
class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
260+
class ShaderSource : public IWritableShaderSource
247261
{
248262
public:
249263
ShaderSource(IrrlichtDevice *device);
@@ -286,22 +300,17 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR
286300
// Shall be called from the main thread.
287301
void rebuildShaders();
288302

289-
void addGlobalConstantSetter(IShaderConstantSetter *setter)
303+
void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
290304
{
291-
m_global_setters.push_back(setter);
305+
m_setter_factories.push_back(setter);
292306
}
293307

294-
void onSetConstants(video::IMaterialRendererServices *services,
295-
bool is_highlevel, const std::string &name);
296-
297308
private:
298309

299310
// The id of the thread that is allowed to use irrlicht directly
300311
threadid_t m_main_thread;
301312
// The irrlicht device
302313
IrrlichtDevice *m_device;
303-
// The set-constants callback
304-
ShaderCallback *m_shader_callback;
305314

306315
// Cache of source shaders
307316
// This should be only accessed from the main thread
@@ -316,9 +325,11 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR
316325
// Queued shader fetches (to be processed by the main thread)
317326
RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
318327

319-
// Global constant setters
320-
// TODO: Delete these in the destructor
321-
std::vector<IShaderConstantSetter*> m_global_setters;
328+
// Global constant setter factories
329+
std::vector<IShaderConstantSetterFactory *> m_setter_factories;
330+
331+
// Shader callbacks
332+
std::vector<ShaderCallback *> m_callbacks;
322333
};
323334

324335
IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
@@ -331,8 +342,8 @@ IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
331342
*/
332343
ShaderInfo generate_shader(std::string name,
333344
u8 material_type, u8 drawtype,
334-
IrrlichtDevice *device,
335-
video::IShaderConstantSetCallBack *callback,
345+
IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
346+
const std::vector<IShaderConstantSetterFactory*> &setter_factories,
336347
SourceShaderCache *sourcecache);
337348

338349
/*
@@ -348,28 +359,24 @@ ShaderSource::ShaderSource(IrrlichtDevice *device):
348359
{
349360
assert(m_device); // Pre-condition
350361

351-
m_shader_callback = new ShaderCallback(this, "default");
352-
353362
m_main_thread = thr_get_current_thread_id();
354363

355364
// Add a dummy ShaderInfo as the first index, named ""
356365
m_shaderinfo_cache.push_back(ShaderInfo());
357366

358367
// Add main global constant setter
359-
addGlobalConstantSetter(new MainShaderConstantSetter(device));
368+
addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
360369
}
361370

362371
ShaderSource::~ShaderSource()
363372
{
364-
for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
365-
iter != m_global_setters.end(); ++iter) {
373+
for (std::vector<ShaderCallback *>::iterator iter = m_callbacks.begin();
374+
iter != m_callbacks.end(); ++iter) {
366375
delete *iter;
367376
}
368-
m_global_setters.clear();
369-
370-
if (m_shader_callback) {
371-
m_shader_callback->drop();
372-
m_shader_callback = NULL;
377+
for (std::vector<IShaderConstantSetterFactory *>::iterator iter = m_setter_factories.begin();
378+
iter != m_setter_factories.end(); ++iter) {
379+
delete *iter;
373380
}
374381
}
375382

@@ -445,8 +452,8 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
445452
return 0;
446453
}
447454

448-
ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
449-
m_shader_callback, &m_sourcecache);
455+
ShaderInfo info = generate_shader(name, material_type, drawtype,
456+
m_device, m_callbacks, m_setter_factories, &m_sourcecache);
450457

451458
/*
452459
Add shader to caches (add dummy shaders too)
@@ -511,22 +518,16 @@ void ShaderSource::rebuildShaders()
511518
ShaderInfo *info = &m_shaderinfo_cache[i];
512519
if(info->name != ""){
513520
*info = generate_shader(info->name, info->material_type,
514-
info->drawtype, m_device, m_shader_callback, &m_sourcecache);
521+
info->drawtype, m_device, m_callbacks,
522+
m_setter_factories, &m_sourcecache);
515523
}
516524
}
517525
}
518526

519-
void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
520-
bool is_highlevel, const std::string &name)
521-
{
522-
for(u32 i=0; i<m_global_setters.size(); i++){
523-
IShaderConstantSetter *setter = m_global_setters[i];
524-
setter->onSetConstants(services, is_highlevel);
525-
}
526-
}
527527

528528
ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
529-
IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
529+
IrrlichtDevice *device, std::vector<ShaderCallback *> &callbacks,
530+
const std::vector<IShaderConstantSetterFactory*> &setter_factories,
530531
SourceShaderCache *sourcecache)
531532
{
532533
ShaderInfo shaderinfo;
@@ -766,6 +767,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
766767
geometry_program = shaders_header + geometry_program;
767768
geometry_program_ptr = geometry_program.c_str();
768769
}
770+
ShaderCallback *cb = new ShaderCallback(setter_factories);
769771
s32 shadermat = -1;
770772
if(is_highlevel){
771773
infostream<<"Compiling high level shaders for "<<name<<std::endl;
@@ -782,7 +784,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
782784
scene::EPT_TRIANGLES, // Geometry shader input
783785
scene::EPT_TRIANGLE_STRIP, // Geometry shader output
784786
0, // Support maximum number of vertices
785-
callback, // Set-constant callback
787+
cb, // Set-constant callback
786788
shaderinfo.base_material, // Base material
787789
1 // Userdata passed to callback
788790
);
@@ -794,6 +796,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
794796
dumpShaderProgram(warningstream, "Vertex", vertex_program);
795797
dumpShaderProgram(warningstream, "Pixel", pixel_program);
796798
dumpShaderProgram(warningstream, "Geometry", geometry_program);
799+
delete cb;
797800
return shaderinfo;
798801
}
799802
}
@@ -802,7 +805,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
802805
shadermat = gpu->addShaderMaterial(
803806
vertex_program_ptr, // Vertex shader program
804807
pixel_program_ptr, // Pixel shader program
805-
callback, // Set-constant callback
808+
cb, // Set-constant callback
806809
shaderinfo.base_material, // Base material
807810
0 // Userdata passed to callback
808811
);
@@ -814,9 +817,11 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
814817
<<std::endl;
815818
dumpShaderProgram(warningstream, "Vertex", vertex_program);
816819
dumpShaderProgram(warningstream,"Pixel", pixel_program);
820+
delete cb;
817821
return shaderinfo;
818822
}
819823
}
824+
callbacks.push_back(cb);
820825

821826
// HACK, TODO: investigate this better
822827
// Grab the material renderer once more so minetest doesn't crash on exit

‎src/shader.h

+54-9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2121
#ifndef SHADER_HEADER
2222
#define SHADER_HEADER
2323

24+
#include <IMaterialRendererServices.h>
2425
#include "irrlichttypes_extrabloated.h"
2526
#include "threads.h"
2627
#include <string>
@@ -43,8 +44,7 @@ class IGameDef;
4344
std::string getShaderPath(const std::string &name_of_shader,
4445
const std::string &filename);
4546

46-
struct ShaderInfo
47-
{
47+
struct ShaderInfo {
4848
std::string name;
4949
video::E_MATERIAL_TYPE base_material;
5050
video::E_MATERIAL_TYPE material;
@@ -66,20 +66,66 @@ namespace irr { namespace video {
6666
class IMaterialRendererServices;
6767
} }
6868

69-
class IShaderConstantSetter
70-
{
69+
70+
class IShaderConstantSetter {
7171
public:
7272
virtual ~IShaderConstantSetter(){};
7373
virtual void onSetConstants(video::IMaterialRendererServices *services,
7474
bool is_highlevel) = 0;
7575
};
7676

77+
78+
class IShaderConstantSetterFactory {
79+
public:
80+
virtual ~IShaderConstantSetterFactory() {};
81+
virtual IShaderConstantSetter* create() = 0;
82+
};
83+
84+
85+
template <typename T, std::size_t count=1>
86+
class CachedShaderSetting {
87+
const char *m_name;
88+
T m_sent[count];
89+
bool has_been_set;
90+
bool is_pixel;
91+
protected:
92+
CachedShaderSetting(const char *name, bool is_pixel) :
93+
m_name(name), has_been_set(false), is_pixel(is_pixel)
94+
{}
95+
public:
96+
void set(const T value[count], video::IMaterialRendererServices *services)
97+
{
98+
if (has_been_set && std::equal(m_sent, m_sent + count, value))
99+
return;
100+
if (is_pixel)
101+
services->setPixelShaderConstant(m_name, value, count);
102+
else
103+
services->setVertexShaderConstant(m_name, value, count);
104+
std::copy(value, value + count, m_sent);
105+
has_been_set = true;
106+
}
107+
};
108+
109+
template <typename T, std::size_t count = 1>
110+
class CachedPixelShaderSetting : public CachedShaderSetting<T, count> {
111+
public:
112+
CachedPixelShaderSetting(const char *name) :
113+
CachedShaderSetting<T, count>(name, true){}
114+
};
115+
116+
template <typename T, std::size_t count = 1>
117+
class CachedVertexShaderSetting : public CachedShaderSetting<T, count> {
118+
public:
119+
CachedVertexShaderSetting(const char *name) :
120+
CachedShaderSetting<T, count>(name, false){}
121+
};
122+
123+
77124
/*
78125
ShaderSource creates and caches shaders.
79126
*/
80127

81-
class IShaderSource
82-
{
128+
class IShaderSource {
83129
public:
84130
IShaderSource(){}
85131
virtual ~IShaderSource(){}
@@ -90,8 +136,7 @@ class IShaderSource
90136
const u8 material_type, const u8 drawtype){return 0;}
91137
};
92138

93-
class IWritableShaderSource : public IShaderSource
94-
{
139+
class IWritableShaderSource : public IShaderSource {
95140
public:
96141
IWritableShaderSource(){}
97142
virtual ~IWritableShaderSource(){}
@@ -105,7 +150,7 @@ class IWritableShaderSource : public IShaderSource
105150
virtual void insertSourceShader(const std::string &name_of_shader,
106151
const std::string &filename, const std::string &program)=0;
107152
virtual void rebuildShaders()=0;
108-
virtual void addGlobalConstantSetter(IShaderConstantSetter *setter)=0;
153+
virtual void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) = 0;
109154
};
110155

111156
IWritableShaderSource* createShaderSource(IrrlichtDevice *device);

0 commit comments

Comments
 (0)
Please sign in to comment.