Changeset - r24744:6381326705ae
[Not reviewed]
master
0 1 0
Patric Stout - 4 years ago 2021-02-11 10:19:05
truebrain@openttd.org
Codechange: [SDL2] Don't use globals if we can do with locals
1 file changed with 4 insertions and 6 deletions:
0 comments (0 inline, 0 general)
src/video/sdl2_v.cpp
Show inline comments
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file sdl2_v.cpp Implementation of the SDL2 video driver. */
 

	
 
#include "../stdafx.h"
 
#include "../openttd.h"
 
#include "../gfx_func.h"
 
#include "../rev.h"
 
#include "../blitter/factory.hpp"
 
#include "../network/network.h"
 
#include "../thread.h"
 
#include "../progress.h"
 
#include "../core/random_func.hpp"
 
#include "../core/math_func.hpp"
 
#include "../fileio_func.h"
 
#include "../framerate_type.h"
 
#include "../window_func.h"
 
#include "sdl2_v.h"
 
#include <SDL.h>
 
#include <mutex>
 
#include <condition_variable>
 
#ifdef __EMSCRIPTEN__
 
#	include <emscripten.h>
 
#	include <emscripten/html5.h>
 
#endif
 

	
 
#include "../safeguards.h"
 

	
 
static FVideoDriver_SDL iFVideoDriver_SDL;
 

	
 
static SDL_Window *_sdl_window;
 
static SDL_Surface *_sdl_surface;
 
static SDL_Surface *_sdl_rgb_surface;
 
static SDL_Surface *_sdl_real_surface;
 

	
 
/** Whether the drawing is/may be done in a separate thread. */
 
static bool _draw_threaded;
 
/** Mutex to keep the access to the shared memory controlled. */
 
static std::recursive_mutex *_draw_mutex = nullptr;
 
/** Signal to draw the next frame. */
 
static std::condition_variable_any *_draw_signal = nullptr;
 
/** Should we keep continue drawing? */
 
static volatile bool _draw_continue;
 
static Palette _local_palette;
 
static SDL_Palette *_sdl_palette;
 

	
 
#ifdef __EMSCRIPTEN__
 
/** Whether we just had a window-enter event. */
 
static bool _cursor_new_in_window = false;
 
#endif
 

	
 
#define MAX_DIRTY_RECTS 100
 
static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS];
 
static int _num_dirty_rects;
 

	
 
/* Size of window */
 
static int _window_size_w;
 
static int _window_size_h;
 

	
 
void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height)
 
{
 
	if (_num_dirty_rects < MAX_DIRTY_RECTS) {
 
		_dirty_rects[_num_dirty_rects].x = left;
 
		_dirty_rects[_num_dirty_rects].y = top;
 
		_dirty_rects[_num_dirty_rects].w = width;
 
		_dirty_rects[_num_dirty_rects].h = height;
 
	}
 
	_num_dirty_rects++;
 
}
 

	
 
static void UpdatePalette()
 
{
 
	SDL_Color pal[256];
 

	
 
	for (int i = 0; i != _local_palette.count_dirty; i++) {
 
		pal[i].r = _local_palette.palette[_local_palette.first_dirty + i].r;
 
		pal[i].g = _local_palette.palette[_local_palette.first_dirty + i].g;
 
		pal[i].b = _local_palette.palette[_local_palette.first_dirty + i].b;
 
		pal[i].a = 0;
 
	}
 

	
 
	SDL_SetPaletteColors(_sdl_palette, pal, _local_palette.first_dirty, _local_palette.count_dirty);
 
	SDL_SetSurfacePalette(_sdl_surface, _sdl_palette);
 
}
 

	
 
static void MakePalette()
 
{
 
	if (_sdl_palette == nullptr) {
 
		_sdl_palette = SDL_AllocPalette(256);
 
		if (_sdl_palette == nullptr) usererror("SDL2: Couldn't allocate palette: %s", SDL_GetError());
 
	}
 

	
 
	_cur_palette.first_dirty = 0;
 
	_cur_palette.count_dirty = 256;
 
	_local_palette = _cur_palette;
 
	UpdatePalette();
 

	
 
	if (_sdl_surface != _sdl_real_surface) {
 
		/* When using a shadow surface, also set our palette on the real screen. This lets SDL
 
		 * allocate as many colors (or approximations) as
 
		 * possible, instead of using only the default SDL
 
		 * palette. This allows us to get more colors exactly
 
		 * right and might allow using better approximations for
 
		 * other colors.
 
		 *
 
		 * Note that colors allocations are tried in-order, so
 
		 * this favors colors further up into the palette. Also
 
		 * note that if two colors from the same animation
 
		 * sequence are approximated using the same color, that
 
		 * animation will stop working.
 
		 *
 
		 * Since changing the system palette causes the colours
 
		 * to change right away, and allocations might
 
		 * drastically change, we can't use this for animation,
 
		 * since that could cause weird coloring between the
 
		 * palette change and the blitting below, so we only set
 
		 * the real palette during initialisation.
 
		 */
 
		SDL_SetSurfacePalette(_sdl_real_surface, _sdl_palette);
 
	}
 
}
 

	
 
void VideoDriver_SDL::CheckPaletteAnim()
 
{
 
	if (_cur_palette.count_dirty == 0) return;
 

	
 
	_local_palette = _cur_palette;
 
	this->MakeDirty(0, 0, _screen.width, _screen.height);
 
}
 

	
 
static void Paint()
 
{
 
	PerformanceMeasurer framerate(PFE_VIDEO);
 

	
 
	if (_num_dirty_rects == 0) return;
 

	
 
	if (_cur_palette.count_dirty != 0) {
 
		Blitter *blitter = BlitterFactory::GetCurrentBlitter();
 

	
 
		switch (blitter->UsePaletteAnimation()) {
 
			case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND:
 
				UpdatePalette();
 
				break;
 

	
 
			case Blitter::PALETTE_ANIMATION_BLITTER:
 
				blitter->PaletteAnimate(_local_palette);
 
				break;
 

	
 
			case Blitter::PALETTE_ANIMATION_NONE:
 
				break;
 

	
 
			default:
 
				NOT_REACHED();
 
		}
 
		_cur_palette.count_dirty = 0;
 
@@ -836,147 +832,149 @@ void VideoDriver_SDL::LoopOnce()
 
		/* Oh, we didn't have threads, then just draw unthreaded */
 
		Paint();
 
	}
 
}
 

	
 
void VideoDriver_SDL::MainLoop()
 
{
 
	cur_ticks = SDL_GetTicks();
 
	last_cur_ticks = cur_ticks;
 
	next_tick = cur_ticks + MILLISECONDS_PER_TICK;
 

	
 
	this->CheckPaletteAnim();
 

	
 
	if (_draw_threaded) {
 
		/* Initialise the mutex first, because that's the thing we *need*
 
		 * directly in the newly created thread. */
 
		_draw_mutex = new std::recursive_mutex();
 
		if (_draw_mutex == nullptr) {
 
			_draw_threaded = false;
 
		} else {
 
			draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
 
			_draw_signal = new std::condition_variable_any();
 
			_draw_continue = true;
 

	
 
			_draw_threaded = StartNewThread(&draw_thread, "ottd:draw-sdl", &PaintThread);
 

	
 
			/* Free the mutex if we won't be able to use it. */
 
			if (!_draw_threaded) {
 
				draw_lock.unlock();
 
				draw_lock.release();
 
				delete _draw_mutex;
 
				delete _draw_signal;
 
				_draw_mutex = nullptr;
 
				_draw_signal = nullptr;
 
			} else {
 
				/* Wait till the draw mutex has started itself. */
 
				_draw_signal->wait(*_draw_mutex);
 
			}
 
		}
 
	}
 

	
 
	DEBUG(driver, 1, "SDL2: using %sthreads", _draw_threaded ? "" : "no ");
 

	
 
#ifdef __EMSCRIPTEN__
 
	/* Run the main loop event-driven, based on RequestAnimationFrame. */
 
	emscripten_set_main_loop_arg(&this->EmscriptenLoop, this, 0, 1);
 
#else
 
	while (!_exit_game) {
 
		LoopOnce();
 
	}
 

	
 
	MainLoopCleanup();
 
#endif
 
}
 

	
 
void VideoDriver_SDL::MainLoopCleanup()
 
{
 
	if (_draw_mutex != nullptr) {
 
		_draw_continue = false;
 
		/* Sending signal if there is no thread blocked
 
		 * is very valid and results in noop */
 
		_draw_signal->notify_one();
 
		if (draw_lock.owns_lock()) draw_lock.unlock();
 
		draw_lock.release();
 
		draw_thread.join();
 

	
 
		delete _draw_mutex;
 
		delete _draw_signal;
 

	
 
		_draw_mutex = nullptr;
 
		_draw_signal = nullptr;
 
	}
 

	
 
#ifdef __EMSCRIPTEN__
 
	emscripten_exit_pointerlock();
 
	/* In effect, the game ends here. As emscripten_set_main_loop() caused
 
	 * the stack to be unwound, the code after MainLoop() in
 
	 * openttd_main() is never executed. */
 
	EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
 
	EM_ASM(if (window["openttd_exit"]) openttd_exit());
 
#endif
 
}
 

	
 
bool VideoDriver_SDL::ChangeResolution(int w, int h)
 
{
 
	std::unique_lock<std::recursive_mutex> lock;
 
	if (_draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
 

	
 
	return CreateMainSurface(w, h, true);
 
}
 

	
 
bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen)
 
{
 
	std::unique_lock<std::recursive_mutex> lock;
 
	if (_draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
 

	
 
	int w, h;
 

	
 
	/* Remember current window size */
 
	if (fullscreen) {
 
		SDL_GetWindowSize(_sdl_window, &_window_size_w, &_window_size_h);
 
		SDL_GetWindowSize(_sdl_window, &w, &h);
 

	
 
		/* Find fullscreen window size */
 
		SDL_DisplayMode dm;
 
		if (SDL_GetCurrentDisplayMode(0, &dm) < 0) {
 
			DEBUG(driver, 0, "SDL_GetCurrentDisplayMode() failed: %s", SDL_GetError());
 
		} else {
 
			SDL_SetWindowSize(_sdl_window, dm.w, dm.h);
 
		}
 
	}
 

	
 
	DEBUG(driver, 1, "SDL2: Setting %s", fullscreen ? "fullscreen" : "windowed");
 
	int ret = SDL_SetWindowFullscreen(_sdl_window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
 
	if (ret == 0) {
 
		/* Switching resolution succeeded, set fullscreen value of window. */
 
		_fullscreen = fullscreen;
 
		if (!fullscreen) SDL_SetWindowSize(_sdl_window, _window_size_w, _window_size_h);
 
		if (!fullscreen) SDL_SetWindowSize(_sdl_window, w, h);
 
	} else {
 
		DEBUG(driver, 0, "SDL_SetWindowFullscreen() failed: %s", SDL_GetError());
 
	}
 

	
 
	return ret == 0;
 
}
 

	
 
bool VideoDriver_SDL::AfterBlitterChange()
 
{
 
	assert(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 0);
 
	int w, h;
 
	SDL_GetWindowSize(_sdl_window, &w, &h);
 
	return CreateMainSurface(w, h, false);
 
}
 

	
 
void VideoDriver_SDL::AcquireBlitterLock()
 
{
 
	if (_draw_mutex != nullptr) _draw_mutex->lock();
 
}
 

	
 
void VideoDriver_SDL::ReleaseBlitterLock()
 
{
 
	if (_draw_mutex != nullptr) _draw_mutex->unlock();
 
}
 

	
 
Dimension VideoDriver_SDL::GetScreenSize() const
 
{
 
	SDL_DisplayMode mode;
 
	if (SDL_GetCurrentDisplayMode(this->startup_display, &mode) != 0) return VideoDriver::GetScreenSize();
 

	
 
	return { static_cast<uint>(mode.w), static_cast<uint>(mode.h) };
 
}
0 comments (0 inline, 0 general)