Changeset - r25029:37f02ef4446d
[Not reviewed]
master
0 19 0
Patric Stout - 3 years ago 2021-03-09 13:53:51
truebrain@openttd.org
Add: make modal windows update more smooth

Basically, modal windows had their own thread-locking for what
drawing was possible. This is a bit nonsense now we have a
game-thread. And it makes much more sense to do things like
NewGRFScan and GenerateWorld in the game-thread, and not in a
thread next to the game-thread.

This commit changes that: it removes the threads for NewGRFScan
and GenerateWorld, and just runs the code in the game-thread.
On regular intervals it allows the draw-thread to do a tick,
which gives a much smoother look and feel.

It does slow down NewGRFScan and GenerateWorld ever so slightly
as it spends more time on drawing. But the slowdown is not
measureable on my machines (with 700+ NewGRFs / 4kx4k map and
a Debug build).

Running without a game-thread means NewGRFScan and GenerateWorld
are now blocking.
19 files changed with 89 insertions and 209 deletions:
0 comments (0 inline, 0 general)
src/clear_cmd.cpp
Show inline comments
 
@@ -338,6 +338,7 @@ void GenerateClearTile()
 
				TileIndex tile_new;
 

	
 
				SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
 
				MarkTileDirtyByTile(tile);
 
				do {
 
					if (--j == 0) goto get_out;
 
					tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2));
src/console_cmds.cpp
Show inline comments
 
@@ -1340,7 +1340,7 @@ DEF_CONSOLE_CMD(ConRescanNewGRF)
 
		return true;
 
	}
 

	
 
	ScanNewGRFFiles(nullptr);
 
	RequestNewGRFScan();
 

	
 
	return true;
 
}
src/genworld.cpp
Show inline comments
 
@@ -59,18 +59,10 @@ GenWorldInfo _gw;
 
/** Whether we are generating the map or not. */
 
bool _generating_world;
 

	
 
/**
 
 * Tells if the world generation is done in a thread or not.
 
 * @return the 'threaded' status
 
 */
 
bool IsGenerateWorldThreaded()
 
{
 
	return _gw.threaded && !_gw.quit_thread;
 
}
 
class AbortGenerateWorldSignal { };
 

	
 
/**
 
 * Clean up the 'mess' of generation. That is, show windows again, reset
 
 * thread variables, and delete the progress window.
 
 * Generation is done; show windows again and delete the progress window.
 
 */
 
static void CleanupGeneration()
 
{
 
@@ -78,11 +70,10 @@ static void CleanupGeneration()
 

	
 
	SetMouseCursorBusy(false);
 
	/* Show all vital windows again, because we have hidden them */
 
	if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows();
 
	if (_game_mode != GM_MENU) ShowVitalWindows();
 
	SetModalProgress(false);
 
	_gw.proc     = nullptr;
 
	_gw.abortp   = nullptr;
 
	_gw.threaded = false;
 

	
 
	DeleteWindowByClass(WC_MODAL_PROGRESS);
 
	ShowFirstError();
 
@@ -97,10 +88,8 @@ static void _GenerateWorld()
 
	/* Make sure everything is done via OWNER_NONE. */
 
	Backup<CompanyID> _cur_company(_current_company, OWNER_NONE, FILE_LINE);
 

	
 
	std::unique_lock<std::mutex> lock(_modal_progress_work_mutex, std::defer_lock);
 
	try {
 
		_generating_world = true;
 
		lock.lock();
 
		if (_network_dedicated) DEBUG(net, 1, "Generating map, please wait...");
 
		/* Set the Random() seed to generation_seed so we produce the same map with the same seed */
 
		if (_settings_game.game_creation.generation_seed == GENERATE_NEW_SEED) _settings_game.game_creation.generation_seed = _settings_newgame.game_creation.generation_seed = InteractiveRandom();
 
@@ -136,14 +125,7 @@ static void _GenerateWorld()
 
			/* Only generate towns, tree and industries in newgame mode. */
 
			if (_game_mode != GM_EDITOR) {
 
				if (!GenerateTowns(_settings_game.economy.town_layout)) {
 
					_cur_company.Restore();
 
					HandleGeneratingWorldAbortion();
 
					BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP);
 
					if (_network_dedicated) {
 
						/* Exit the game to prevent a return to main menu.  */
 
						DEBUG(net, 0, "Generating map failed, aborting");
 
						_exit_game = true;
 
					}
 
					return;
 
				}
 
				GenerateIndustries();
 
@@ -200,7 +182,6 @@ static void _GenerateWorld()
 
		IncreaseGeneratingWorldProgress(GWP_GAME_START);
 

	
 
		CleanupGeneration();
 
		lock.unlock();
 

	
 
		ShowNewGRFError();
 

	
 
@@ -212,11 +193,19 @@ static void _GenerateWorld()
 
			seprintf(name, lastof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
 
			SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false);
 
		}
 
	} catch (...) {
 
	} catch (AbortGenerateWorldSignal&) {
 
		CleanupGeneration();
 

	
 
		BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true);
 
		if (_cur_company.IsValid()) _cur_company.Restore();
 
		_generating_world = false;
 
		throw;
 

	
 
		if (_network_dedicated) {
 
			/* Exit the game to prevent a return to main menu.  */
 
			DEBUG(net, 0, "Generating map failed, aborting");
 
			_exit_game = true;
 
		} else {
 
			SwitchToMode(_switch_mode);
 
		}
 
	}
 
}
 

	
 
@@ -241,23 +230,6 @@ void GenerateWorldSetAbortCallback(GWAbo
 
}
 

	
 
/**
 
 * This will wait for the thread to finish up his work. It will not continue
 
 * till the work is done.
 
 */
 
void WaitTillGeneratedWorld()
 
{
 
	if (!_gw.thread.joinable()) return;
 

	
 
	_modal_progress_work_mutex.unlock();
 
	_modal_progress_paint_mutex.unlock();
 
	_gw.quit_thread = true;
 
	_gw.thread.join();
 
	_gw.threaded = false;
 
	_modal_progress_work_mutex.lock();
 
	_modal_progress_paint_mutex.lock();
 
}
 

	
 
/**
 
 * Initializes the abortion process
 
 */
 
void AbortGeneratingWorld()
 
@@ -284,11 +256,7 @@ void HandleGeneratingWorldAbortion()
 

	
 
	if (_gw.abortp != nullptr) _gw.abortp();
 

	
 
	CleanupGeneration();
 

	
 
	if (_gw.thread.joinable() && _gw.thread.get_id() == std::this_thread::get_id()) throw OTTDThreadExitSignal();
 

	
 
	SwitchToMode(_switch_mode);
 
	throw AbortGenerateWorldSignal();
 
}
 

	
 
/**
 
@@ -308,8 +276,6 @@ void GenerateWorld(GenWorldMode mode, ui
 
	_gw.abort  = false;
 
	_gw.abortp = nullptr;
 
	_gw.lc     = _local_company;
 
	_gw.quit_thread   = false;
 
	_gw.threaded      = true;
 

	
 
	/* This disables some commands and stuff */
 
	SetLocalCompany(COMPANY_SPECTATOR);
 
@@ -328,28 +294,16 @@ void GenerateWorld(GenWorldMode mode, ui
 
	SetupColoursAndInitialWindow();
 
	SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
 

	
 
	if (_gw.thread.joinable()) _gw.thread.join();
 

	
 
	if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !StartNewThread(&_gw.thread, "ottd:genworld", &_GenerateWorld)) {
 
		DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode");
 
		_gw.threaded = false;
 
		_modal_progress_work_mutex.unlock();
 
		_GenerateWorld();
 
		_modal_progress_work_mutex.lock();
 
		return;
 
	}
 

	
 
	UnshowCriticalError();
 
	/* Remove any open window */
 
	DeleteAllNonVitalWindows();
 
	/* Hide vital windows, because we don't allow to use them */
 
	HideVitalWindows();
 

	
 
	/* Don't show the dialog if we don't have a thread */
 
	ShowGenerateWorldProgress();
 

	
 
	/* Centre the view on the map */
 
	if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) {
 
		ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2), true);
 
	}
 

	
 
	_GenerateWorld();
 
}
src/genworld.h
Show inline comments
 
@@ -52,15 +52,12 @@ typedef void GWAbortProc(); ///< Called 
 
/** Properties of current genworld process */
 
struct GenWorldInfo {
 
	bool abort;            ///< Whether to abort the thread ASAP
 
	bool quit_thread;      ///< Do we want to quit the active thread
 
	bool threaded;         ///< Whether we run _GenerateWorld threaded
 
	GenWorldMode mode;     ///< What mode are we making a world in
 
	CompanyID lc;          ///< The local_company before generating
 
	uint size_x;           ///< X-size of the map
 
	uint size_y;           ///< Y-size of the map
 
	GWDoneProc *proc;      ///< Proc that is called when done (can be nullptr)
 
	GWAbortProc *abortp;   ///< Proc that is called when aborting (can be nullptr)
 
	std::thread thread;    ///< The thread we are in (joinable if a thread was created)
 
};
 

	
 
/** Current stage of world generation process */
 
@@ -81,10 +78,8 @@ enum GenWorldProgress {
 
};
 

	
 
/* genworld.cpp */
 
bool IsGenerateWorldThreaded();
 
void GenerateWorldSetCallback(GWDoneProc *proc);
 
void GenerateWorldSetAbortCallback(GWAbortProc *proc);
 
void WaitTillGeneratedWorld();
 
void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_settings = true);
 
void AbortGeneratingWorld();
 
bool IsGeneratingWorldAborted();
src/genworld_gui.cpp
Show inline comments
 
@@ -29,6 +29,7 @@
 
#include "error.h"
 
#include "newgrf_townname.h"
 
#include "townname_type.h"
 
#include "video/video_driver.hpp"
 

	
 
#include "widgets/genworld_widget.h"
 

	
 
@@ -1312,10 +1313,10 @@ static void _SetGeneratingWorldProgress(
 
	static_assert(lengthof(percent_table) == GWP_CLASS_COUNT + 1);
 
	assert(cls < GWP_CLASS_COUNT);
 

	
 
	/* Do not run this function if we aren't in a thread */
 
	if (!IsGenerateWorldThreaded() && !_network_dedicated) return;
 

	
 
	if (IsGeneratingWorldAborted()) HandleGeneratingWorldAbortion();
 
	if (IsGeneratingWorldAborted()) {
 
		HandleGeneratingWorldAbortion();
 
		return;
 
	}
 

	
 
	if (total == 0) {
 
		assert(_gws.cls == _generation_class_table[cls]);
 
@@ -1328,10 +1329,6 @@ static void _SetGeneratingWorldProgress(
 
		_gws.percent = percent_table[cls];
 
	}
 

	
 
	/* Don't update the screen too often. So update it once in every once in a while... */
 
	if (!_network_dedicated && std::chrono::steady_clock::now() < _gws.next_update) return;
 
	_gws.next_update = std::chrono::steady_clock::now() + std::chrono::milliseconds(MODAL_PROGRESS_REDRAW_TIMEOUT);
 

	
 
	/* Percentage is about the number of completed tasks, so 'current - 1' */
 
	_gws.percent = percent_table[cls] + (percent_table[cls + 1] - percent_table[cls]) * (_gws.current == 0 ? 0 : _gws.current - 1) / _gws.total;
 

	
 
@@ -1350,21 +1347,12 @@ static void _SetGeneratingWorldProgress(
 
		DEBUG(net, 1, "Map generation percentage complete: %d", _gws.percent);
 
		last_percent = _gws.percent;
 

	
 
		/* Don't continue as dedicated never has a thread running */
 
		return;
 
	}
 

	
 
	SetWindowDirty(WC_MODAL_PROGRESS, 0);
 
	MarkWholeScreenDirty();
 

	
 
	/* Release the rights to the map generator, and acquire the rights to the
 
	 * paint thread. The 'other' thread already has the paint thread rights so
 
	 * this ensures us that we are waiting until the paint thread is done
 
	 * before we reacquire the mapgen rights */
 
	_modal_progress_work_mutex.unlock();
 
	_modal_progress_paint_mutex.lock();
 
	_modal_progress_work_mutex.lock();
 
	_modal_progress_paint_mutex.unlock();
 
	VideoDriver::GetInstance()->GameLoopPause();
 
}
 

	
 
/**
src/gfx.cpp
Show inline comments
 
@@ -1470,26 +1470,6 @@ void DrawDirtyBlocks()
 
	int x;
 
	int y;
 

	
 
	if (HasModalProgress()) {
 
		/* We are generating the world, so release our rights to the map and
 
		 * painting while we are waiting a bit. */
 
		_modal_progress_paint_mutex.unlock();
 
		_modal_progress_work_mutex.unlock();
 

	
 
		/* Wait a while and hope the modal gives us a bit of time to draw the GUI. */
 
		if (!IsFirstModalProgressLoop()) CSleep(MODAL_PROGRESS_REDRAW_TIMEOUT);
 

	
 
		/* Modal progress thread may need blitter access while we are waiting for it. */
 
		_modal_progress_paint_mutex.lock();
 
		_modal_progress_work_mutex.lock();
 

	
 
		/* When we ended with the modal progress, do not draw the blocks.
 
		 * Simply let the next run do so, otherwise we would be loading
 
		 * the new state (and possibly change the blitter) when we hold
 
		 * the drawing lock, which we must not do. */
 
		if (_switch_mode != SM_NONE && !HasModalProgress()) return;
 
	}
 

	
 
	y = 0;
 
	do {
 
		x = 0;
src/landscape.cpp
Show inline comments
 
@@ -1062,6 +1062,7 @@ static bool MakeLake(TileIndex tile, voi
 
		TileIndex t2 = tile + TileOffsByDiagDir(d);
 
		if (IsWaterTile(t2)) {
 
			MakeRiver(tile, Random());
 
			MarkTileDirtyByTile(tile);
 
			/* Remove desert directly around the river tile. */
 
			TileIndex t = tile;
 
			CircularTileSearch(&t, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
 
@@ -1135,6 +1136,7 @@ static void River_FoundEndNode(AyStar *a
 
		TileIndex tile = path->node.tile;
 
		if (!IsWaterTile(tile)) {
 
			MakeRiver(tile, Random());
 
			MarkTileDirtyByTile(tile);
 
			/* Remove desert directly around the river tile. */
 
			CircularTileSearch(&tile, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
 
		}
 
@@ -1247,6 +1249,7 @@ static bool FlowRiver(TileIndex spring, 
 
				DistanceManhattan(spring, lakeCenter) > _settings_game.game_creation.min_river_length) {
 
			end = lakeCenter;
 
			MakeRiver(lakeCenter, Random());
 
			MarkTileDirtyByTile(lakeCenter);
 
			/* Remove desert directly around the river tile. */
 
			CircularTileSearch(&lakeCenter, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
 
			lakeCenter = end;
 
@@ -1368,8 +1371,11 @@ void GenerateLandscape(byte mode)
 
	/* Do not call IncreaseGeneratingWorldProgress() before FixSlopes(),
 
	 * it allows screen redraw. Drawing of broken slopes crashes the game */
 
	FixSlopes();
 
	MarkWholeScreenDirty();
 
	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
 

	
 
	ConvertGroundTilesIntoWaterTiles();
 
	MarkWholeScreenDirty();
 
	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
 

	
 
	if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
src/network/network_content_gui.cpp
Show inline comments
 
@@ -15,6 +15,7 @@
 
#include "../ai/ai.hpp"
 
#include "../game/game.hpp"
 
#include "../base_media_base.h"
 
#include "../openttd.h"
 
#include "../sortlist_type.h"
 
#include "../stringfilter_type.h"
 
#include "../querystring_gui.h"
 
@@ -236,7 +237,7 @@ public:
 
					break;
 

	
 
				case CONTENT_TYPE_NEWGRF:
 
					ScanNewGRFFiles(nullptr);
 
					RequestNewGRFScan();
 
					break;
 

	
 
				case CONTENT_TYPE_SCENARIO:
src/newgrf_config.cpp
Show inline comments
 
@@ -635,20 +635,12 @@ bool GRFFileScanner::AddFile(const std::
 
	}
 

	
 
	this->num_scanned++;
 
	if (std::chrono::steady_clock::now() >= this->next_update) {
 
		this->next_update = std::chrono::steady_clock::now() + std::chrono::milliseconds(MODAL_PROGRESS_REDRAW_TIMEOUT);
 

	
 
		_modal_progress_work_mutex.unlock();
 
		_modal_progress_paint_mutex.lock();
 

	
 
		const char *name = nullptr;
 
		if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name);
 
		if (name == nullptr) name = c->filename;
 
		UpdateNewGRFScanStatus(this->num_scanned, name);
 

	
 
		_modal_progress_work_mutex.lock();
 
		_modal_progress_paint_mutex.unlock();
 
	}
 
	const char *name = nullptr;
 
	if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name);
 
	if (name == nullptr) name = c->filename;
 
	UpdateNewGRFScanStatus(this->num_scanned, name);
 
	VideoDriver::GetInstance()->GameLoopPause();
 

	
 
	if (!added) {
 
		/* File couldn't be opened, or is either not a NewGRF or is a
 
@@ -676,8 +668,6 @@ static bool GRFSorter(GRFConfig * const 
 
 */
 
void DoScanNewGRFFiles(NewGRFScanCallback *callback)
 
{
 
	std::unique_lock<std::mutex> lock_work(_modal_progress_work_mutex);
 

	
 
	ClearGRFConfigList(&_all_grfs);
 
	TarScanner::DoScan(TarScanner::NEWGRF);
 

	
 
@@ -709,9 +699,6 @@ void DoScanNewGRFFiles(NewGRFScanCallbac
 
		NetworkAfterNewGRFScan();
 
	}
 

	
 
	lock_work.unlock();
 
	std::lock_guard<std::mutex> lock_paint(_modal_progress_paint_mutex);
 

	
 
	/* Yes... these are the NewGRF windows */
 
	InvalidateWindowClassesData(WC_SAVELOAD, 0, true);
 
	InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE, GOID_NEWGRF_RESCANNED, true);
 
@@ -733,15 +720,7 @@ void ScanNewGRFFiles(NewGRFScanCallback 
 
	/* Only then can we really start, especially by marking the whole screen dirty. Get those other windows hidden!. */
 
	MarkWholeScreenDirty();
 

	
 
	if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !StartNewThread(nullptr, "ottd:newgrf-scan", &DoScanNewGRFFiles, (NewGRFScanCallback *)callback)) { // Without the seemingly superfluous cast, strange compiler errors ensue.
 
		_modal_progress_work_mutex.unlock();
 
		_modal_progress_paint_mutex.unlock();
 
		DoScanNewGRFFiles(callback);
 
		_modal_progress_paint_mutex.lock();
 
		_modal_progress_work_mutex.lock();
 
	} else {
 
		UpdateNewGRFScanStatus(0, nullptr);
 
	}
 
	DoScanNewGRFFiles(callback);
 
}
 

	
 
/**
src/newgrf_gui.cpp
Show inline comments
 
@@ -1127,7 +1127,7 @@ struct NewGRFWindow : public Window, New
 

	
 
			case WID_NS_RESCAN_FILES:
 
			case WID_NS_RESCAN_FILES2:
 
				ScanNewGRFFiles(this);
 
				RequestNewGRFScan(this);
 
				break;
 
		}
 
	}
src/openttd.cpp
Show inline comments
 
@@ -91,6 +91,8 @@ extern void ShowOSErrorBox(const char *b
 
extern std::string _config_file;
 

	
 
bool _save_config = false;
 
bool _request_newgrf_scan = false;
 
NewGRFScanCallback *_request_newgrf_scan_callback = nullptr;
 

	
 
/**
 
 * Error handling for fatal user errors.
 
@@ -345,7 +347,6 @@ static void LoadIntroGame(bool load_newg
 
	/* Load the default opening screen savegame */
 
	if (SaveOrLoad("opntitle.dat", SLO_LOAD, DFT_GAME_FILE, BASESET_DIR) != SL_OK) {
 
		GenerateWorld(GWM_EMPTY, 64, 64); // if failed loading, make empty world.
 
		WaitTillGeneratedWorld();
 
		SetLocalCompany(COMPANY_SPECTATOR);
 
	} else {
 
		SetLocalCompany(COMPANY_FIRST);
 
@@ -559,9 +560,6 @@ int openttd_main(int argc, char *argv[])
 
	extern bool _dedicated_forks;
 
	_dedicated_forks = false;
 

	
 
	std::unique_lock<std::mutex> modal_work_lock(_modal_progress_work_mutex, std::defer_lock);
 
	std::unique_lock<std::mutex> modal_paint_lock(_modal_progress_paint_mutex, std::defer_lock);
 

	
 
	_game_mode = GM_MENU;
 
	_switch_mode = SM_MENU;
 

	
 
@@ -828,30 +826,17 @@ int openttd_main(int argc, char *argv[])
 
	if (musicdriver.empty() && !_ini_musicdriver.empty()) musicdriver = _ini_musicdriver;
 
	DriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC);
 

	
 
	/* Take our initial lock on whatever we might want to do! */
 
	try {
 
		modal_work_lock.lock();
 
		modal_paint_lock.lock();
 
	} catch (const std::system_error&) {
 
		/* If there is some error we assume that threads aren't usable on the system we run. */
 
		extern bool _use_threaded_modal_progress; // From progress.cpp
 
		_use_threaded_modal_progress = false;
 
	}
 

	
 
	GenerateWorld(GWM_EMPTY, 64, 64); // Make the viewport initialization happy
 
	WaitTillGeneratedWorld();
 

	
 
	LoadIntroGame(false);
 

	
 
	CheckForMissingGlyphs();
 

	
 
	/* ScanNewGRFFiles now has control over the scanner. */
 
	ScanNewGRFFiles(scanner.release());
 
	RequestNewGRFScan(scanner.release());
 

	
 
	VideoDriver::GetInstance()->MainLoop();
 

	
 
	WaitTillSaved();
 
	WaitTillGeneratedWorld(); // Make sure any generate world threads have been joined.
 

	
 
	/* only save config if we have to */
 
	if (_save_config) {
 
@@ -1460,6 +1445,19 @@ static void DoAutosave()
 
	}
 
}
 

	
 
/**
 
 * Request a new NewGRF scan. This will be executed on the next game-tick.
 
 * This is mostly needed to ensure NewGRF scans (which are blocking) are
 
 * done in the game-thread, and not in the draw-thread (which most often
 
 * triggers this request).
 
 * @param callback Optional callback to call when NewGRF scan is completed.
 
 */
 
void RequestNewGRFScan(NewGRFScanCallback *callback)
 
{
 
	_request_newgrf_scan = true;
 
	_request_newgrf_scan_callback = callback;
 
}
 

	
 
void GameLoop()
 
{
 
	if (_game_mode == GM_BOOTSTRAP) {
 
@@ -1468,6 +1466,12 @@ void GameLoop()
 
		return;
 
	}
 

	
 
	if (_request_newgrf_scan) {
 
		ScanNewGRFFiles(_request_newgrf_scan_callback);
 
		_request_newgrf_scan = false;
 
		_request_newgrf_scan_callback = nullptr;
 
	}
 

	
 
	ProcessAsyncSaveFinish();
 

	
 
	/* autosave game? */
src/openttd.h
Show inline comments
 
@@ -81,4 +81,6 @@ void HandleExitGameRequest();
 

	
 
void SwitchToMode(SwitchMode new_mode);
 

	
 
void RequestNewGRFScan(struct NewGRFScanCallback *callback = nullptr);
 

	
 
#endif /* OPENTTD_H */
src/progress.cpp
Show inline comments
 
@@ -14,33 +14,12 @@
 

	
 
/** Are we in a modal progress or not? */
 
bool _in_modal_progress = false;
 
bool _first_in_modal_loop = false;
 
/** Threading usable for modal progress? */
 
bool _use_threaded_modal_progress = true;
 
/** Rights for the performing work. */
 
std::mutex _modal_progress_work_mutex;
 
/** Rights for the painting. */
 
std::mutex _modal_progress_paint_mutex;
 

	
 
/**
 
 * Set the modal progress state.
 
 * @note Makes IsFirstModalProgressLoop return true for the next call.
 
 * @param state The new state; are we modal or not?
 
 */
 
void SetModalProgress(bool state)
 
{
 
	_in_modal_progress = state;
 
	_first_in_modal_loop = true;
 
}
 

	
 
/**
 
 * Check whether this is the first modal progress loop.
 
 * @note Set by SetModalProgress, unset by calling this method.
 
 * @return True if this is the first loop.
 
 */
 
bool IsFirstModalProgressLoop()
 
{
 
	bool ret = _first_in_modal_loop;
 
	_first_in_modal_loop = false;
 
	return ret;
 
}
src/progress.h
Show inline comments
 
@@ -10,10 +10,6 @@
 
#ifndef PROGRESS_H
 
#define PROGRESS_H
 

	
 
#include <mutex>
 

	
 
static const uint MODAL_PROGRESS_REDRAW_TIMEOUT = 200; ///< Timeout between redraws
 

	
 
/**
 
 * Check if we are currently in a modal progress state.
 
 * @return Are we in the modal state?
 
@@ -24,20 +20,6 @@ static inline bool HasModalProgress()
 
	return _in_modal_progress;
 
}
 

	
 
/**
 
 * Check if we can use a thread for modal progress.
 
 * @return Threading usable?
 
 */
 
static inline bool UseThreadedModelProgress()
 
{
 
	extern bool _use_threaded_modal_progress;
 
	return _use_threaded_modal_progress;
 
}
 

	
 
bool IsFirstModalProgressLoop();
 
void SetModalProgress(bool state);
 

	
 
extern std::mutex _modal_progress_work_mutex;
 
extern std::mutex _modal_progress_paint_mutex;
 

	
 
#endif /* PROGRESS_H */
src/thread.h
Show inline comments
 
@@ -14,10 +14,6 @@
 
#include <system_error>
 
#include <thread>
 

	
 
/** Signal used for signalling we knowingly want to end the thread. */
 
class OTTDThreadExitSignal { };
 

	
 

	
 
/**
 
 * Sleep on the current thread for a defined time.
 
 * @param milliseconds Time to sleep for in milliseconds.
 
@@ -54,7 +50,6 @@ inline bool StartNewThread(std::thread *
 
				try {
 
					/* Call user function with the given arguments. */
 
					F(A...);
 
				} catch (OTTDThreadExitSignal&) {
 
				} catch (...) {
 
					NOT_REACHED();
 
				}
src/tree_cmd.cpp
Show inline comments
 
@@ -164,6 +164,7 @@ static void PlaceTree(TileIndex tile, ui
 

	
 
	if (tree != TREE_INVALID) {
 
		PlantTreesOnTile(tile, tree, GB(r, 22, 2), std::min<byte>(GB(r, 16, 3), 6));
 
		MarkTileDirtyByTile(tile);
 

	
 
		/* Rerandomize ground, if neither snow nor shore */
 
		TreeGround ground = GetTreeGround(tile);
src/video/dedicated_v.cpp
Show inline comments
 
@@ -251,19 +251,16 @@ void VideoDriver_Dedicated::MainLoop()
 
	/* If SwitchMode is SM_LOAD_GAME, it means that the user used the '-g' options */
 
	if (_switch_mode != SM_LOAD_GAME) {
 
		StartNewGameWithoutGUI(GENERATE_NEW_SEED);
 
		SwitchToMode(_switch_mode);
 
		_switch_mode = SM_NONE;
 
	} else {
 
		_switch_mode = SM_NONE;
 
		/* First we need to test if the savegame can be loaded, else we will end up playing the
 
		 *  intro game... */
 
		if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_NORMAL, BASE_DIR)) {
 
		if (SaveOrLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, BASE_DIR) == SL_ERROR) {
 
			/* Loading failed, pop out.. */
 
			DEBUG(net, 0, "Loading requested map failed, aborting");
 
			_networking = false;
 
			return;
 
		} else {
 
			/* We can load this game, so go ahead */
 
			SwitchToMode(SM_LOAD_GAME);
 
			_switch_mode = SM_LOAD_GAME;
 
		}
 
	}
 

	
 
@@ -271,11 +268,6 @@ void VideoDriver_Dedicated::MainLoop()
 

	
 
	/* Done loading, start game! */
 

	
 
	if (!_networking) {
 
		DEBUG(net, 0, "Dedicated server could not be started, aborting");
 
		return;
 
	}
 

	
 
	while (!_exit_game) {
 
		if (!_dedicated_forks) DedicatedHandleKeyInput();
 

	
src/video/video_driver.cpp
Show inline comments
 
@@ -56,6 +56,25 @@ void VideoDriver::GameThread()
 
	}
 
}
 

	
 
/**
 
 * Pause the game-loop for a bit, releasing the game-state lock. This allows,
 
 * if the draw-tick requested this, the drawing to happen.
 
 */
 
void VideoDriver::GameLoopPause()
 
{
 
	/* If we are not called from the game-thread, ignore this request. */
 
	if (std::this_thread::get_id() != this->game_thread.get_id()) return;
 

	
 
	this->game_state_mutex.unlock();
 

	
 
	{
 
		/* See GameThread() for more details on this lock. */
 
		std::lock_guard<std::mutex> lock(this->game_thread_wait_mutex);
 
	}
 

	
 
	this->game_state_mutex.lock();
 
}
 

	
 
/* static */ void VideoDriver::GameThreadThunk(VideoDriver *drv)
 
{
 
	drv->GameThread();
src/video/video_driver.hpp
Show inline comments
 
@@ -179,6 +179,8 @@ public:
 
		this->change_blitter = new_blitter;
 
	}
 

	
 
	void GameLoopPause();
 

	
 
	/**
 
	 * Get the currently active instance of the video driver.
 
	 */
0 comments (0 inline, 0 general)