Changeset - r25363:aeaaaf1c6dce
[Not reviewed]
master
0 3 0
Michael Lutz - 3 years ago 2021-05-01 17:39:03
michi@icosahedron.de
Codechange: Generalise the delayed blitter change to a generic video driver command queue.
3 files changed with 55 insertions and 34 deletions:
0 comments (0 inline, 0 general)
src/gfxinit.cpp
Show inline comments
 
@@ -244,6 +244,28 @@ static void LoadSpriteTables()
 
}
 

	
 

	
 
static void RealChangeBlitter(const char *repl_blitter)
 
{
 
	const char *cur_blitter = BlitterFactory::GetCurrentBlitter()->GetName();
 
	if (strcmp(cur_blitter, repl_blitter) == 0) return;
 

	
 
	DEBUG(driver, 1, "Switching blitter from '%s' to '%s'... ", cur_blitter, repl_blitter);
 
	Blitter *new_blitter = BlitterFactory::SelectBlitter(repl_blitter);
 
	if (new_blitter == nullptr) NOT_REACHED();
 
	DEBUG(driver, 1, "Successfully switched to %s.", repl_blitter);
 

	
 
	if (!VideoDriver::GetInstance()->AfterBlitterChange()) {
 
		/* Failed to switch blitter, let's hope we can return to the old one. */
 
		if (BlitterFactory::SelectBlitter(cur_blitter) == nullptr || !VideoDriver::GetInstance()->AfterBlitterChange()) usererror("Failed to reinitialize video driver. Specify a fixed blitter in the config");
 
	}
 

	
 
	/* Clear caches that might have sprites for another blitter. */
 
	VideoDriver::GetInstance()->ClearSystemSprites();
 
	ClearFontCache();
 
	GfxClearSpriteCache();
 
	ReInitAllWindows(false);
 
}
 

	
 
/**
 
 * Check blitter needed by NewGRF config and switch if needed.
 
 * @return False when nothing changed, true otherwise.
 
@@ -309,7 +331,7 @@ static bool SwitchNewGRFBlitter()
 
		if (BlitterFactory::GetBlitterFactory(repl_blitter) == nullptr) continue;
 

	
 
		/* Inform the video driver we want to switch blitter as soon as possible. */
 
		VideoDriver::GetInstance()->ChangeBlitter(repl_blitter);
 
		VideoDriver::GetInstance()->QueueOnMainThread(std::bind(&RealChangeBlitter, repl_blitter));
 
		break;
 
	}
 

	
src/video/video_driver.cpp
Show inline comments
 
@@ -97,27 +97,6 @@ void VideoDriver::StopGameThread()
 
	this->game_thread.join();
 
}
 

	
 
void VideoDriver::RealChangeBlitter(const char *repl_blitter)
 
{
 
	const char *cur_blitter = BlitterFactory::GetCurrentBlitter()->GetName();
 

	
 
	DEBUG(driver, 1, "Switching blitter from '%s' to '%s'... ", cur_blitter, repl_blitter);
 
	Blitter *new_blitter = BlitterFactory::SelectBlitter(repl_blitter);
 
	if (new_blitter == nullptr) NOT_REACHED();
 
	DEBUG(driver, 1, "Successfully switched to %s.", repl_blitter);
 

	
 
	if (!this->AfterBlitterChange()) {
 
		/* Failed to switch blitter, let's hope we can return to the old one. */
 
		if (BlitterFactory::SelectBlitter(cur_blitter) == nullptr || !this->AfterBlitterChange()) usererror("Failed to reinitialize video driver. Specify a fixed blitter in the config");
 
	}
 

	
 
	/* Clear caches that might have sprites for another blitter. */
 
	this->ClearSystemSprites();
 
	ClearFontCache();
 
	GfxClearSpriteCache();
 
	ReInitAllWindows(false);
 
}
 

	
 
void VideoDriver::Tick()
 
{
 
	if (!this->is_game_threaded && std::chrono::steady_clock::now() >= this->next_game_tick) {
 
@@ -159,10 +138,7 @@ void VideoDriver::Tick()
 

	
 
			this->LockVideoBuffer();
 

	
 
			if (this->change_blitter != nullptr) {
 
				this->RealChangeBlitter(this->change_blitter);
 
				this->change_blitter = nullptr;
 
			}
 
			this->DrainCommandQueue();
 

	
 
			while (this->PollEvent()) {}
 
			::InputLoop();
src/video/video_driver.hpp
Show inline comments
 
@@ -22,6 +22,7 @@
 
#include <mutex>
 
#include <thread>
 
#include <vector>
 
#include <functional>
 

	
 
extern std::string _ini_videodriver;
 
extern std::vector<Dimension> _resolutions;
 
@@ -36,7 +37,7 @@ class VideoDriver : public Driver {
 
	const uint DEFAULT_WINDOW_HEIGHT = 480u; ///< Default window height.
 

	
 
public:
 
	VideoDriver() : fast_forward_key_pressed(false), fast_forward_via_key(false), is_game_threaded(true), change_blitter(nullptr) {}
 
	VideoDriver() : fast_forward_key_pressed(false), fast_forward_via_key(false), is_game_threaded(true) {}
 

	
 
	/**
 
	 * Mark a particular area dirty.
 
@@ -178,12 +179,16 @@ public:
 
	}
 

	
 
	/**
 
	 * Queue a request to change the blitter. This is not executed immediately,
 
	 * but instead on the next draw-tick.
 
	 * Queue a function to be called on the main thread with game state
 
	 * lock held and video buffer locked. Queued functions will be
 
	 * executed on the next draw tick.
 
	 * @param func Function to call.
 
	 */
 
	void ChangeBlitter(const char *new_blitter)
 
	void QueueOnMainThread(std::function<void()> &&func)
 
	{
 
		this->change_blitter = new_blitter;
 
		std::lock_guard<std::mutex> lock(this->cmd_queue_mutex);
 

	
 
		this->cmd_queue.emplace_back(std::forward<std::function<void()>>(func));
 
	}
 

	
 
	void GameLoopPause();
 
@@ -328,11 +333,29 @@ protected:
 
	static void GameThreadThunk(VideoDriver *drv);
 

	
 
private:
 
	std::mutex cmd_queue_mutex;
 
	std::vector<std::function<void()>> cmd_queue;
 

	
 
	/** Execute all queued commands. */
 
	void DrainCommandQueue()
 
	{
 
		std::vector<std::function<void()>> cmds{};
 

	
 
		{
 
			/* Exchange queue with an empty one to limit the time we
 
			 * hold the mutex. This also ensures that queued functions can
 
			 * add new functions to the queue without everything blocking. */
 
			std::lock_guard<std::mutex> lock(this->cmd_queue_mutex);
 
			cmds.swap(this->cmd_queue);
 
		}
 

	
 
		for (auto &f : cmds) {
 
			f();
 
		}
 
	}
 

	
 
	void GameLoop();
 
	void GameThread();
 
	void RealChangeBlitter(const char *repl_blitter);
 

	
 
	const char *change_blitter; ///< Request to change the blitter. nullptr if no pending request.
 
};
 

	
 
#endif /* VIDEO_VIDEO_DRIVER_HPP */
0 comments (0 inline, 0 general)