mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 01:05:48 +01:00 
			
		
		
		
	Fix superflous shader setting updates (#4800)
This improves rendering performance by ~40%
This commit is contained in:
		
							
								
								
									
										186
									
								
								src/game.cpp
									
									
									
									
									
								
							
							
						
						
									
										186
									
								
								src/game.cpp
									
									
									
									
									
								
							@@ -888,40 +888,73 @@ public:
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 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 @@ public:
 | 
			
		||||
			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);
 | 
			
		||||
 | 
			
		||||
		// Uniform sampler layers
 | 
			
		||||
		// before 1.8 there isn't a "integer interface", only float
 | 
			
		||||
		float eye_position_array[3];
 | 
			
		||||
		v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
 | 
			
		||||
#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);
 | 
			
		||||
		eye_position_array[0] = epos.X;
 | 
			
		||||
		eye_position_array[1] = epos.Y;
 | 
			
		||||
		eye_position_array[2] = epos.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);
 | 
			
		||||
		epos.getAs3Values(eye_position_array);
 | 
			
		||||
#endif
 | 
			
		||||
		m_eye_position_pixel.set(eye_position_array, services);
 | 
			
		||||
		m_eye_position_vertex.set(eye_position_array, services);
 | 
			
		||||
 | 
			
		||||
		float minimap_yaw_array[3];
 | 
			
		||||
		v3f minimap_yaw = m_client->getMapper()->getYawVec();
 | 
			
		||||
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
 | 
			
		||||
		minimap_yaw_array[0] = minimap_yaw.X;
 | 
			
		||||
		minimap_yaw_array[1] = minimap_yaw.Y;
 | 
			
		||||
		minimap_yaw_array[2] = minimap_yaw.Z;
 | 
			
		||||
#else
 | 
			
		||||
		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 @@ private:
 | 
			
		||||
	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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										63
									
								
								src/shader.h
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								src/shader.h
									
									
									
									
									
								
							@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#ifndef SHADER_HEADER
 | 
			
		||||
#define SHADER_HEADER
 | 
			
		||||
 | 
			
		||||
#include <IMaterialRendererServices.h>
 | 
			
		||||
#include "irrlichttypes_extrabloated.h"
 | 
			
		||||
#include "threads.h"
 | 
			
		||||
#include <string>
 | 
			
		||||
@@ -43,8 +44,7 @@ class IGameDef;
 | 
			
		||||
std::string getShaderPath(const std::string &name_of_shader,
 | 
			
		||||
		const std::string &filename);
 | 
			
		||||
 | 
			
		||||
struct ShaderInfo
 | 
			
		||||
{
 | 
			
		||||
struct ShaderInfo {
 | 
			
		||||
	std::string name;
 | 
			
		||||
	video::E_MATERIAL_TYPE base_material;
 | 
			
		||||
	video::E_MATERIAL_TYPE material;
 | 
			
		||||
@@ -66,20 +66,66 @@ namespace irr { namespace video {
 | 
			
		||||
	class IMaterialRendererServices;
 | 
			
		||||
} }
 | 
			
		||||
 | 
			
		||||
class IShaderConstantSetter
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class IShaderConstantSetter {
 | 
			
		||||
public:
 | 
			
		||||
	virtual ~IShaderConstantSetter(){};
 | 
			
		||||
	virtual void onSetConstants(video::IMaterialRendererServices *services,
 | 
			
		||||
			bool is_highlevel) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IShaderConstantSetterFactory {
 | 
			
		||||
public:
 | 
			
		||||
	virtual ~IShaderConstantSetterFactory() {};
 | 
			
		||||
	virtual IShaderConstantSetter* create() = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T, std::size_t count=1>
 | 
			
		||||
class CachedShaderSetting {
 | 
			
		||||
	const char *m_name;
 | 
			
		||||
	T m_sent[count];
 | 
			
		||||
	bool has_been_set;
 | 
			
		||||
	bool is_pixel;
 | 
			
		||||
protected:
 | 
			
		||||
	CachedShaderSetting(const char *name, bool is_pixel) :
 | 
			
		||||
		m_name(name), has_been_set(false), is_pixel(is_pixel)
 | 
			
		||||
	{}
 | 
			
		||||
public:
 | 
			
		||||
	void set(const T value[count], video::IMaterialRendererServices *services)
 | 
			
		||||
	{
 | 
			
		||||
		if (has_been_set && std::equal(m_sent, m_sent + count, value))
 | 
			
		||||
			return;
 | 
			
		||||
		if (is_pixel)
 | 
			
		||||
			services->setPixelShaderConstant(m_name, value, count);
 | 
			
		||||
		else
 | 
			
		||||
			services->setVertexShaderConstant(m_name, value, count);
 | 
			
		||||
		std::copy(value, value + count, m_sent);
 | 
			
		||||
		has_been_set = true;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, std::size_t count = 1>
 | 
			
		||||
class CachedPixelShaderSetting : public CachedShaderSetting<T, count> {
 | 
			
		||||
public:
 | 
			
		||||
	CachedPixelShaderSetting(const char *name) :
 | 
			
		||||
		CachedShaderSetting<T, count>(name, true){}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, std::size_t count = 1>
 | 
			
		||||
class CachedVertexShaderSetting : public CachedShaderSetting<T, count> {
 | 
			
		||||
public:
 | 
			
		||||
	CachedVertexShaderSetting(const char *name) :
 | 
			
		||||
		CachedShaderSetting<T, count>(name, false){}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	ShaderSource creates and caches shaders.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
class IShaderSource
 | 
			
		||||
{
 | 
			
		||||
class IShaderSource {
 | 
			
		||||
public:
 | 
			
		||||
	IShaderSource(){}
 | 
			
		||||
	virtual ~IShaderSource(){}
 | 
			
		||||
@@ -90,8 +136,7 @@ public:
 | 
			
		||||
		const u8 material_type, const u8 drawtype){return 0;}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class IWritableShaderSource : public IShaderSource
 | 
			
		||||
{
 | 
			
		||||
class IWritableShaderSource : public IShaderSource {
 | 
			
		||||
public:
 | 
			
		||||
	IWritableShaderSource(){}
 | 
			
		||||
	virtual ~IWritableShaderSource(){}
 | 
			
		||||
@@ -105,7 +150,7 @@ public:
 | 
			
		||||
	virtual void insertSourceShader(const std::string &name_of_shader,
 | 
			
		||||
		const std::string &filename, const std::string &program)=0;
 | 
			
		||||
	virtual void rebuildShaders()=0;
 | 
			
		||||
	virtual void addGlobalConstantSetter(IShaderConstantSetter *setter)=0;
 | 
			
		||||
	virtual void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
IWritableShaderSource* createShaderSource(IrrlichtDevice *device);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user