Skip to content
Permalink
Browse files

Fix superflous shader setting updates (#4800)

This improves rendering performance by ~40%
  • Loading branch information
ShadowNinja authored and Zeno- committed Nov 22, 2016
1 parent c6ca7a8 commit 4bf4154cad127560ffe831e7b2cd1a0b960d0f03
Showing with 249 additions and 127 deletions.
  1. +128 −56 src/game.cpp
  2. +67 −62 src/shader.cpp
  3. +54 −9 src/shader.h
@@ -888,40 +888,73 @@ class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
}
};


// before 1.8 there isn't a "integer interface", only float
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
typedef f32 SamplerLayer_t;
#else
typedef s32 SamplerLayer_t;
#endif


class GameGlobalShaderConstantSetter : public IShaderConstantSetter
{
Sky *m_sky;
bool *m_force_fog_off;
f32 *m_fog_range;
bool m_fog_enabled;
CachedPixelShaderSetting<float, 4> m_sky_bg_color;
CachedPixelShaderSetting<float> m_fog_distance;
CachedVertexShaderSetting<float> m_animation_timer_vertex;
CachedPixelShaderSetting<float> m_animation_timer_pixel;
CachedPixelShaderSetting<float> m_day_night_ratio;
CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
CachedPixelShaderSetting<float, 3> m_minimap_yaw;
CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags;
Client *m_client;
bool m_fogEnabled;

public:
void onSettingsChange(const std::string &name)
{
if (name == "enable_fog")
m_fogEnabled = g_settings->getBool("enable_fog");
m_fog_enabled = g_settings->getBool("enable_fog");
}

static void SettingsCallback(const std::string &name, void *userdata)
static void settingsCallback(const std::string &name, void *userdata)
{
reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
}

void setSky(Sky *sky) { m_sky = sky; }

GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
f32 *fog_range, Client *client) :
m_sky(sky),
m_force_fog_off(force_fog_off),
m_fog_range(fog_range),
m_sky_bg_color("skyBgColor"),
m_fog_distance("fogDistance"),
m_animation_timer_vertex("animationTimer"),
m_animation_timer_pixel("animationTimer"),
m_day_night_ratio("dayNightRatio"),
m_eye_position_pixel("eyePosition"),
m_eye_position_vertex("eyePosition"),
m_minimap_yaw("yawVec"),
m_base_texture("baseTexture"),
m_normal_texture("normalTexture"),
m_texture_flags("textureFlags"),
m_client(client)
{
g_settings->registerChangedCallback("enable_fog", SettingsCallback, this);
m_fogEnabled = g_settings->getBool("enable_fog");
g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
m_fog_enabled = g_settings->getBool("enable_fog");
}

~GameGlobalShaderConstantSetter()
{
g_settings->deregisterChangedCallback("enable_fog", SettingsCallback, this);
g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
}

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

// Fog distance
float fog_distance = 10000 * BS;

if (m_fogEnabled && !*m_force_fog_off)
if (m_fog_enabled && !*m_force_fog_off)
fog_distance = *m_fog_range;

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

// Day-night ratio
u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
float daynight_ratio_f = (float)daynight_ratio / 1000.0;
services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1);
float daynight_ratio = (float)m_client->getEnv().getDayNightRatio() / 1000.f;
m_day_night_ratio.set(&daynight_ratio, services);

u32 animation_timer = porting::getTimeMs() % 100000;
float animation_timer_f = (float)animation_timer / 100000.0;
services->setPixelShaderConstant("animationTimer", &animation_timer_f, 1);
services->setVertexShaderConstant("animationTimer", &animation_timer_f, 1);
float animation_timer_f = (float)animation_timer / 100000.f;
m_animation_timer_vertex.set(&animation_timer_f, services);
m_animation_timer_pixel.set(&animation_timer_f, services);

LocalPlayer *player = m_client->getEnv().getLocalPlayer();
v3f eye_position = player->getEyePosition();
services->setPixelShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3);
services->setVertexShaderConstant("eyePosition", (irr::f32 *)&eye_position, 3);

v3f minimap_yaw_vec = m_client->getMapper()->getYawVec();
services->setPixelShaderConstant("yawVec", (irr::f32 *)&minimap_yaw_vec, 3);
float eye_position_array[3];
v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
eye_position_array[0] = epos.X;
eye_position_array[1] = epos.Y;
eye_position_array[2] = epos.Z;
#else
epos.getAs3Values(eye_position_array);
#endif
m_eye_position_pixel.set(eye_position_array, services);
m_eye_position_vertex.set(eye_position_array, services);

// Uniform sampler layers
// before 1.8 there isn't a "integer interface", only float
float minimap_yaw_array[3];
v3f minimap_yaw = m_client->getMapper()->getYawVec();
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
f32 layer0 = 0;
f32 layer1 = 1;
f32 layer2 = 2;
services->setPixelShaderConstant("baseTexture" , (irr::f32 *)&layer0, 1);
services->setPixelShaderConstant("normalTexture" , (irr::f32 *)&layer1, 1);
services->setPixelShaderConstant("textureFlags" , (irr::f32 *)&layer2, 1);
minimap_yaw_array[0] = minimap_yaw.X;
minimap_yaw_array[1] = minimap_yaw.Y;
minimap_yaw_array[2] = minimap_yaw.Z;
#else
s32 layer0 = 0;
s32 layer1 = 1;
s32 layer2 = 2;
services->setPixelShaderConstant("baseTexture" , (irr::s32 *)&layer0, 1);
services->setPixelShaderConstant("normalTexture" , (irr::s32 *)&layer1, 1);
services->setPixelShaderConstant("textureFlags" , (irr::s32 *)&layer2, 1);
minimap_yaw.getAs3Values(minimap_yaw_array);
#endif
m_minimap_yaw.set(minimap_yaw_array, services);

SamplerLayer_t base_tex = 0,
normal_tex = 1,
flags_tex = 2;
m_base_texture.set(&base_tex, services);
m_normal_texture.set(&normal_tex, services);
m_texture_flags.set(&flags_tex, services);
}
};


class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
{
Sky *m_sky;
bool *m_force_fog_off;
f32 *m_fog_range;
Client *m_client;
std::vector<GameGlobalShaderConstantSetter *> created_nosky;
public:
GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
f32 *fog_range, Client *client) :
m_sky(NULL),
m_force_fog_off(force_fog_off),
m_fog_range(fog_range),
m_client(client)
{}

void setSky(Sky *sky) {
m_sky = sky;
for (size_t i = 0; i < created_nosky.size(); ++i) {
created_nosky[i]->setSky(m_sky);
}
created_nosky.clear();
}

virtual IShaderConstantSetter* create()
{
GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter(
m_sky, m_force_fog_off, m_fog_range, m_client);
if (!m_sky)
created_nosky.push_back(scs);
return scs;
}
};


bool nodePlacementPrediction(Client &client,
const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos)
{
@@ -1695,6 +1766,9 @@ class Game {
Hud *hud;
Mapper *mapper;

GameRunData runData;
VolatileRunFlags flags;

/* 'cache'
This class does take ownership/responsibily for cleaning up etc of any of
these items (e.g. device)
@@ -1886,6 +1960,18 @@ bool Game::startup(bool *kill,

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

memset(&runData, 0, sizeof(runData));
runData.time_from_last_punch = 10.0;
runData.profiler_max_page = 3;
runData.update_wielded_item_trigger = true;

memset(&flags, 0, sizeof(flags));
flags.show_chat = true;
flags.show_hud = true;
flags.show_debug = g_settings->getBool("show_debug");
flags.invert_mouse = g_settings->getBool("invert_mouse");
flags.first_loop_after_window_activation = true;

if (!init(map_dir, address, port, gamespec))
return false;

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

runData.time_from_last_punch = 10.0;
runData.profiler_max_page = 3;
runData.update_wielded_item_trigger = true;

flags.show_chat = true;
flags.show_hud = true;
flags.show_minimap = g_settings->getBool("enable_minimap");
flags.show_debug = g_settings->getBool("show_debug");
flags.invert_mouse = g_settings->getBool("invert_mouse");
flags.first_loop_after_window_activation = true;

/* Clear the profiler */
Profiler::GraphValues dummyvalues;
g_profiler->graphGet(dummyvalues);

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

shader_src->addGlobalConstantSetter(new GameGlobalShaderConstantSetter(
sky,
&flags.force_fog_off,
&runData.fog_range,
client));

set_light_table(g_settings->getFloat("display_gamma"));

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

GameGlobalShaderConstantSetterFactory *scsf = new GameGlobalShaderConstantSetterFactory(
&flags.force_fog_off, &runData.fog_range, client);
shader_src->addShaderConstantSetterFactory(scsf);

// Update cached textures, meshes and materials
client->afterContentReceived(device);

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

local_inventory = new Inventory(itemdef_manager);

0 comments on commit 4bf4154

Please sign in to comment.