Merge branch 'master' into jgrpp
This commit is contained in:
@@ -236,6 +236,16 @@ bool VideoDriver_Allegro::ClaimMousePointer()
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<int> VideoDriver_Allegro::GetListOfMonitorRefreshRates()
|
||||
{
|
||||
std::vector<int> rates = {};
|
||||
|
||||
int refresh_rate = get_refresh_rate();
|
||||
if (refresh_rate != 0) rates.push_back(refresh_rate);
|
||||
|
||||
return rates;
|
||||
}
|
||||
|
||||
struct AllegroVkMapping {
|
||||
uint16 vk_from;
|
||||
byte vk_count;
|
||||
@@ -412,7 +422,7 @@ bool VideoDriver_Allegro::PollEvent()
|
||||
*/
|
||||
int _allegro_instance_count = 0;
|
||||
|
||||
const char *VideoDriver_Allegro::Start(const StringList &parm)
|
||||
const char *VideoDriver_Allegro::Start(const StringList ¶m)
|
||||
{
|
||||
if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, nullptr)) {
|
||||
DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error);
|
||||
@@ -440,6 +450,8 @@ const char *VideoDriver_Allegro::Start(const StringList &parm)
|
||||
MarkWholeScreenDirty();
|
||||
set_close_button_callback(HandleExitGameRequest);
|
||||
|
||||
this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -477,14 +489,16 @@ void VideoDriver_Allegro::InputLoop()
|
||||
|
||||
void VideoDriver_Allegro::MainLoop()
|
||||
{
|
||||
for (;;) {
|
||||
if (_exit_game) return;
|
||||
this->StartGameThread();
|
||||
|
||||
if (this->Tick()) {
|
||||
this->Paint();
|
||||
}
|
||||
for (;;) {
|
||||
if (_exit_game) break;
|
||||
|
||||
this->Tick();
|
||||
this->SleepTillNextTick();
|
||||
}
|
||||
|
||||
this->StopGameThread();
|
||||
}
|
||||
|
||||
bool VideoDriver_Allegro::ChangeResolution(int w, int h)
|
||||
|
||||
@@ -31,6 +31,8 @@ public:
|
||||
|
||||
bool ClaimMousePointer() override;
|
||||
|
||||
std::vector<int> GetListOfMonitorRefreshRates() override;
|
||||
|
||||
const char *GetName() const override { return "allegro"; }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -33,6 +33,8 @@ public:
|
||||
|
||||
void ClearSystemSprites() override;
|
||||
|
||||
void PopulateSystemSprites() override;
|
||||
|
||||
bool HasAnimBuffer() override { return true; }
|
||||
uint8 *GetAnimBuffer() override { return this->anim_buffer; }
|
||||
|
||||
@@ -54,6 +56,9 @@ class FVideoDriver_CocoaOpenGL : public DriverFactoryBase {
|
||||
public:
|
||||
FVideoDriver_CocoaOpenGL() : DriverFactoryBase(Driver::DT_VIDEO, 9, "cocoa-opengl", "Cocoa OpenGL Video Driver") {}
|
||||
Driver *CreateInstance() const override { return new VideoDriver_CocoaOpenGL(); }
|
||||
|
||||
protected:
|
||||
bool UsesHardwareAcceleration() const override { return true; }
|
||||
};
|
||||
|
||||
#endif /* VIDEO_COCOA_OGL_H */
|
||||
|
||||
@@ -214,6 +214,8 @@ const char *VideoDriver_CocoaOpenGL::Start(const StringList ¶m)
|
||||
this->UpdateVideoModes();
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
@@ -227,6 +229,11 @@ void VideoDriver_CocoaOpenGL::Stop()
|
||||
CGLReleaseContext(this->gl_context);
|
||||
}
|
||||
|
||||
void VideoDriver_CocoaOpenGL::PopulateSystemSprites()
|
||||
{
|
||||
OpenGLBackend::Get()->PopulateCursorCache();
|
||||
}
|
||||
|
||||
void VideoDriver_CocoaOpenGL::ClearSystemSprites()
|
||||
{
|
||||
CGLSetCurrentContext(this->gl_context);
|
||||
@@ -265,7 +272,7 @@ void VideoDriver_CocoaOpenGL::AllocateBackingStore(bool force)
|
||||
CGLSetCurrentContext(this->gl_context);
|
||||
NSRect frame = [ this->cocoaview getRealRect:[ this->cocoaview frame ] ];
|
||||
OpenGLBackend::Get()->Resize(frame.size.width, frame.size.height, force);
|
||||
_screen.dst_ptr = this->GetVideoPointer();
|
||||
if (this->buffer_locked) _screen.dst_ptr = this->GetVideoPointer();
|
||||
this->dirty_rect = {};
|
||||
|
||||
/* Redraw screen */
|
||||
|
||||
@@ -47,6 +47,8 @@ public:
|
||||
|
||||
void EditBoxLostFocus() override;
|
||||
|
||||
std::vector<int> GetListOfMonitorRefreshRates() override;
|
||||
|
||||
/* --- The following methods should be private, but can't be due to Obj-C limitations. --- */
|
||||
|
||||
void MainLoopReal();
|
||||
@@ -122,7 +124,7 @@ protected:
|
||||
|
||||
class FVideoDriver_CocoaQuartz : public DriverFactoryBase {
|
||||
public:
|
||||
FVideoDriver_CocoaQuartz() : DriverFactoryBase(Driver::DT_VIDEO, 10, "cocoa", "Cocoa Video Driver") {}
|
||||
FVideoDriver_CocoaQuartz() : DriverFactoryBase(Driver::DT_VIDEO, 8, "cocoa", "Cocoa Video Driver") {}
|
||||
Driver *CreateInstance() const override { return new VideoDriver_CocoaQuartz(); }
|
||||
};
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#import <sys/param.h> /* for MAXPATHLEN */
|
||||
#import <sys/time.h> /* gettimeofday */
|
||||
#include <array>
|
||||
|
||||
/**
|
||||
* Important notice regarding all modifications!!!!!!!
|
||||
@@ -201,6 +202,7 @@ bool VideoDriver_Cocoa::ToggleFullscreen(bool full_screen)
|
||||
[ NSMenu setMenuBarVisible:!full_screen ];
|
||||
|
||||
this->UpdateVideoModes();
|
||||
this->InvalidateGameOptionsWindow();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -213,7 +215,7 @@ bool VideoDriver_Cocoa::ToggleFullscreen(bool full_screen)
|
||||
*/
|
||||
bool VideoDriver_Cocoa::AfterBlitterChange()
|
||||
{
|
||||
this->ChangeResolution(_cur_resolution.width, _cur_resolution.height);
|
||||
this->AllocateBackingStore(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -224,7 +226,31 @@ void VideoDriver_Cocoa::EditBoxLostFocus()
|
||||
{
|
||||
[ [ this->cocoaview inputContext ] discardMarkedText ];
|
||||
/* Clear any marked string from the current edit box. */
|
||||
HandleTextInput(NULL, true);
|
||||
HandleTextInput(nullptr, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get refresh rates of all connected monitors.
|
||||
*/
|
||||
std::vector<int> VideoDriver_Cocoa::GetListOfMonitorRefreshRates()
|
||||
{
|
||||
std::vector<int> rates{};
|
||||
|
||||
if (MacOSVersionIsAtLeast(10, 6, 0)) {
|
||||
std::array<CGDirectDisplayID, 16> displays;
|
||||
|
||||
uint32_t count = 0;
|
||||
CGGetActiveDisplayList(displays.size(), displays.data(), &count);
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
|
||||
int rate = (int)CGDisplayModeGetRefreshRate(mode);
|
||||
if (rate > 0) rates.push_back(rate);
|
||||
CGDisplayModeRelease(mode);
|
||||
}
|
||||
}
|
||||
|
||||
return rates;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -436,6 +462,8 @@ void VideoDriver_Cocoa::InputLoop()
|
||||
/** Main game loop. */
|
||||
void VideoDriver_Cocoa::MainLoopReal()
|
||||
{
|
||||
this->StartGameThread();
|
||||
|
||||
for (;;) {
|
||||
@autoreleasepool {
|
||||
if (_exit_game) {
|
||||
@@ -444,12 +472,12 @@ void VideoDriver_Cocoa::MainLoopReal()
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->Tick()) {
|
||||
this->Paint();
|
||||
}
|
||||
this->Tick();
|
||||
this->SleepTillNextTick();
|
||||
}
|
||||
}
|
||||
|
||||
this->StopGameThread();
|
||||
}
|
||||
|
||||
|
||||
@@ -561,6 +589,8 @@ const char *VideoDriver_CocoaQuartz::Start(const StringList ¶m)
|
||||
this->GameSizeChanged();
|
||||
this->UpdateVideoModes();
|
||||
|
||||
this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
@@ -700,9 +700,9 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
|
||||
if (!EditBoxInGlobalFocus() || IsInsideMM(pressed_key & ~WKC_SPECIAL_KEYS, WKC_F1, WKC_PAUSE + 1)) {
|
||||
HandleKeypress(pressed_key, unicode);
|
||||
}
|
||||
DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), down, mapping: %x", keycode, unicode, pressed_key);
|
||||
DEBUG(driver, 3, "cocoa_v: QZ_KeyEvent: %x (%x), down, mapping: %x", keycode, unicode, pressed_key);
|
||||
} else {
|
||||
DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), up", keycode, unicode);
|
||||
DEBUG(driver, 3, "cocoa_v: QZ_KeyEvent: %x (%x), up", keycode, unicode);
|
||||
}
|
||||
|
||||
return interpret_keys;
|
||||
|
||||
@@ -251,28 +251,22 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Done loading, start game! */
|
||||
this->is_game_threaded = false;
|
||||
|
||||
if (!_networking) {
|
||||
DEBUG(net, 0, "Dedicated server could not be started, aborting");
|
||||
return;
|
||||
}
|
||||
/* Done loading, start game! */
|
||||
|
||||
while (!_exit_game) {
|
||||
if (!_dedicated_forks) DedicatedHandleKeyInput();
|
||||
|
||||
@@ -50,17 +50,17 @@ void VideoDriver_Null::MainLoop()
|
||||
{
|
||||
if (this->until_exit) {
|
||||
while (!_exit_game) {
|
||||
GameLoop();
|
||||
GameLoopPaletteAnimations();
|
||||
InputLoop();
|
||||
UpdateWindows();
|
||||
::GameLoop();
|
||||
::GameLoopPaletteAnimations();
|
||||
::InputLoop();
|
||||
::UpdateWindows();
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < this->ticks; i++) {
|
||||
GameLoop();
|
||||
GameLoopPaletteAnimations();
|
||||
InputLoop();
|
||||
UpdateWindows();
|
||||
::GameLoop();
|
||||
::GameLoopPaletteAnimations();
|
||||
::InputLoop();
|
||||
::UpdateWindows();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1036,7 +1036,36 @@ void OpenGLBackend::DrawMouseCursor()
|
||||
_cur_dpi = &_screen;
|
||||
for (uint i = 0; i < _cursor.sprite_count; ++i) {
|
||||
SpriteID sprite = _cursor.sprite_seq[i].sprite;
|
||||
const Sprite *spr = GetSprite(sprite, ST_NORMAL);
|
||||
|
||||
/* Sprites are cached by PopulateCursorCache(). */
|
||||
if (this->cursor_cache.Contains(sprite)) {
|
||||
const Sprite *spr = GetSprite(sprite, ST_NORMAL);
|
||||
|
||||
this->RenderOglSprite((OpenGLSprite *)this->cursor_cache.Get(sprite)->data, _cursor.sprite_seq[i].pal,
|
||||
_cursor.pos.x + _cursor.sprite_pos[i].x + UnScaleByZoom(spr->x_offs, ZOOM_LVL_GUI),
|
||||
_cursor.pos.y + _cursor.sprite_pos[i].y + UnScaleByZoom(spr->y_offs, ZOOM_LVL_GUI),
|
||||
ZOOM_LVL_GUI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLBackend::PopulateCursorCache()
|
||||
{
|
||||
if (this->clear_cursor_cache) {
|
||||
/* We have a pending cursor cache clear to do first. */
|
||||
this->clear_cursor_cache = false;
|
||||
this->last_sprite_pal = (PaletteID)-1;
|
||||
|
||||
Sprite *sp;
|
||||
while ((sp = this->cursor_cache.Pop()) != nullptr) {
|
||||
OpenGLSprite *sprite = (OpenGLSprite *)sp->data;
|
||||
sprite->~OpenGLSprite();
|
||||
free(sp);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _cursor.sprite_count; ++i) {
|
||||
SpriteID sprite = _cursor.sprite_seq[i].sprite;
|
||||
|
||||
if (!this->cursor_cache.Contains(sprite)) {
|
||||
Sprite *old = this->cursor_cache.Insert(sprite, (Sprite *)GetRawSprite(sprite, ST_NORMAL, &SimpleSpriteAlloc, this));
|
||||
@@ -1046,11 +1075,6 @@ void OpenGLBackend::DrawMouseCursor()
|
||||
free(old);
|
||||
}
|
||||
}
|
||||
|
||||
this->RenderOglSprite((OpenGLSprite *)this->cursor_cache.Get(sprite)->data, _cursor.sprite_seq[i].pal,
|
||||
_cursor.pos.x + _cursor.sprite_pos[i].x + UnScaleByZoom(spr->x_offs, ZOOM_LVL_GUI),
|
||||
_cursor.pos.y + _cursor.sprite_pos[i].y + UnScaleByZoom(spr->y_offs, ZOOM_LVL_GUI),
|
||||
ZOOM_LVL_GUI);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1059,14 +1083,11 @@ void OpenGLBackend::DrawMouseCursor()
|
||||
*/
|
||||
void OpenGLBackend::ClearCursorCache()
|
||||
{
|
||||
this->last_sprite_pal = (PaletteID)-1;
|
||||
|
||||
Sprite *sp;
|
||||
while ((sp = this->cursor_cache.Pop()) != nullptr) {
|
||||
OpenGLSprite *sprite = (OpenGLSprite *)sp->data;
|
||||
sprite->~OpenGLSprite();
|
||||
free(sp);
|
||||
}
|
||||
/* If the game loop is threaded, this function might be called
|
||||
* from the game thread. As we can call OpenGL functions only
|
||||
* on the main thread, just set a flag that is handled the next
|
||||
* time we prepare the cursor cache for drawing. */
|
||||
this->clear_cursor_cache = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,6 +63,7 @@ private:
|
||||
|
||||
LRUCache<SpriteID, Sprite> cursor_cache; ///< Cache of encoded cursor sprites.
|
||||
PaletteID last_sprite_pal = (PaletteID)-1; ///< Last uploaded remap palette.
|
||||
bool clear_cursor_cache = false; ///< A clear of the cursor cache is pending.
|
||||
|
||||
OpenGLBackend();
|
||||
~OpenGLBackend();
|
||||
@@ -88,6 +89,7 @@ public:
|
||||
void Paint();
|
||||
|
||||
void DrawMouseCursor();
|
||||
void PopulateCursorCache();
|
||||
void ClearCursorCache();
|
||||
|
||||
void *GetVideoBuffer();
|
||||
|
||||
@@ -111,13 +111,7 @@ void VideoDriver_SDL_Default::Paint()
|
||||
break;
|
||||
|
||||
case Blitter::PALETTE_ANIMATION_BLITTER: {
|
||||
bool need_buf = _screen.dst_ptr == nullptr;
|
||||
if (need_buf) _screen.dst_ptr = this->GetVideoPointer();
|
||||
blitter->PaletteAnimate(this->local_palette);
|
||||
if (need_buf) {
|
||||
this->ReleaseVideoPointer();
|
||||
_screen.dst_ptr = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -140,22 +134,6 @@ void VideoDriver_SDL_Default::Paint()
|
||||
this->dirty_rect = {};
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_Default::PaintThread()
|
||||
{
|
||||
/* First tell the main thread we're started */
|
||||
std::unique_lock<std::recursive_mutex> lock(*this->draw_mutex);
|
||||
this->draw_signal->notify_one();
|
||||
|
||||
/* Now wait for the first thing to draw! */
|
||||
this->draw_signal->wait(*this->draw_mutex);
|
||||
|
||||
while (this->draw_continue) {
|
||||
/* Then just draw and wait till we stop */
|
||||
this->Paint();
|
||||
this->draw_signal->wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
bool VideoDriver_SDL_Default::AllocateBackingStore(int w, int h, bool force)
|
||||
{
|
||||
int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
|
||||
|
||||
@@ -21,7 +21,6 @@ protected:
|
||||
bool AllocateBackingStore(int w, int h, bool force = false) override;
|
||||
void *GetVideoPointer() override;
|
||||
void Paint() override;
|
||||
void PaintThread() override;
|
||||
|
||||
void ReleaseVideoPointer() override {}
|
||||
|
||||
|
||||
@@ -75,7 +75,6 @@ const char *VideoDriver_SDL_OpenGL::Start(const StringList ¶m)
|
||||
this->ClientSizeChanged(w, h, true);
|
||||
|
||||
SDL_GL_SetSwapInterval(GetDriverParamBool(param, "vsync") ? 1 : 0);
|
||||
this->draw_threaded = false;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -115,6 +114,11 @@ const char *VideoDriver_SDL_OpenGL::AllocateContext()
|
||||
return OpenGLBackend::Create(&GetOGLProcAddressCallback);
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_OpenGL::PopulateSystemSprites()
|
||||
{
|
||||
OpenGLBackend::Get()->PopulateCursorCache();
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_OpenGL::ClearSystemSprites()
|
||||
{
|
||||
OpenGLBackend::Get()->ClearCursorCache();
|
||||
|
||||
@@ -24,6 +24,8 @@ public:
|
||||
|
||||
void ClearSystemSprites() override;
|
||||
|
||||
void PopulateSystemSprites() override;
|
||||
|
||||
bool HasAnimBuffer() override { return true; }
|
||||
uint8 *GetAnimBuffer() override { return this->anim_buffer; }
|
||||
|
||||
@@ -36,8 +38,6 @@ protected:
|
||||
void Paint() override;
|
||||
bool CreateMainWindow(uint w, uint h, uint flags) override;
|
||||
|
||||
void PaintThread() override {}
|
||||
|
||||
private:
|
||||
void *gl_context; ///< OpenGL context.
|
||||
uint8 *anim_buffer; ///< Animation buffer from OpenGL back-end.
|
||||
@@ -51,4 +51,7 @@ class FVideoDriver_SDL_OpenGL : public DriverFactoryBase {
|
||||
public:
|
||||
FVideoDriver_SDL_OpenGL() : DriverFactoryBase(Driver::DT_VIDEO, 8, "sdl-opengl", "SDL OpenGL Video Driver") {}
|
||||
/* virtual */ Driver *CreateInstance() const override { return new VideoDriver_SDL_OpenGL(); }
|
||||
|
||||
protected:
|
||||
bool UsesHardwareAcceleration() const override { return true; }
|
||||
};
|
||||
|
||||
@@ -24,10 +24,6 @@
|
||||
#include "sdl2_v.h"
|
||||
#include <SDL.h>
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#if defined(__MINGW32__)
|
||||
#include "../3rdparty/mingw-std-threads/mingw.mutex.h"
|
||||
#endif
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <emscripten.h>
|
||||
# include <emscripten/html5.h>
|
||||
@@ -264,11 +260,6 @@ void VideoDriver_SDL_Base::CheckPaletteAnim()
|
||||
this->MakeDirty(0, 0, _screen.width, _screen.height);
|
||||
}
|
||||
|
||||
/* static */ void VideoDriver_SDL_Base::PaintThreadThunk(VideoDriver_SDL_Base *drv)
|
||||
{
|
||||
drv->PaintThread();
|
||||
}
|
||||
|
||||
static const Dimension default_resolutions[] = {
|
||||
{ 640, 480 },
|
||||
{ 800, 600 },
|
||||
@@ -516,6 +507,17 @@ void VideoDriver_SDL_Base::EditBoxLostFocus()
|
||||
HandleTextInput(nullptr, true);
|
||||
}
|
||||
|
||||
std::vector<int> VideoDriver_SDL_Base::GetListOfMonitorRefreshRates()
|
||||
{
|
||||
std::vector<int> rates = {};
|
||||
for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) {
|
||||
SDL_DisplayMode mode = {};
|
||||
if (SDL_GetDisplayMode(i, 0, &mode) != 0) continue;
|
||||
if (mode.refresh_rate != 0) rates.push_back(mode.refresh_rate);
|
||||
}
|
||||
return rates;
|
||||
}
|
||||
|
||||
struct SDLVkMapping {
|
||||
SDL_Keycode vk_from;
|
||||
byte vk_count;
|
||||
@@ -873,14 +875,14 @@ const char *VideoDriver_SDL_Base::Initialize()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *VideoDriver_SDL_Base::Start(const StringList &parm)
|
||||
const char *VideoDriver_SDL_Base::Start(const StringList ¶m)
|
||||
{
|
||||
if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) return "Only real blitters supported";
|
||||
|
||||
const char *error = this->Initialize();
|
||||
if (error != nullptr) return error;
|
||||
|
||||
this->startup_display = FindStartupDisplay(GetDriverParamInt(parm, "display", -1));
|
||||
this->startup_display = FindStartupDisplay(GetDriverParamInt(param, "display", -1));
|
||||
|
||||
if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height, false)) {
|
||||
return SDL_GetError();
|
||||
@@ -891,25 +893,17 @@ const char *VideoDriver_SDL_Base::Start(const StringList &parm)
|
||||
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
this->draw_threaded = !GetDriverParamBool(parm, "no_threads") && !GetDriverParamBool(parm, "no_thread");
|
||||
/* Wayland SDL video driver uses EGL to render the game. SDL created the
|
||||
* EGL context from the main-thread, and with EGL you are not allowed to
|
||||
* draw in another thread than the context was created. The function of
|
||||
* draw_threaded is to do exactly this: draw in another thread than the
|
||||
* window was created, and as such, this fails on Wayland SDL video
|
||||
* driver. So, we disable threading by default if Wayland SDL video
|
||||
* driver is detected.
|
||||
*/
|
||||
if (strcmp(dname, "wayland") == 0) {
|
||||
this->draw_threaded = false;
|
||||
}
|
||||
|
||||
SDL_StopTextInput();
|
||||
this->edit_box_focused = false;
|
||||
|
||||
#if defined(WITH_FCITX)
|
||||
if (_fcitx_mode) SDL_EventState(SDL_SYSWMEVENT, 1);
|
||||
#endif
|
||||
#ifdef __EMSCRIPTEN__
|
||||
this->is_game_threaded = false;
|
||||
#else
|
||||
this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -966,18 +960,17 @@ void VideoDriver_SDL_Base::LoopOnce()
|
||||
* After that, Emscripten just halts, and the HTML shows a nice
|
||||
* "bye, see you next time" message. */
|
||||
emscripten_cancel_main_loop();
|
||||
MainLoopCleanup();
|
||||
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
|
||||
return;
|
||||
}
|
||||
|
||||
if (VideoDriver::Tick()) {
|
||||
if (this->draw_mutex != nullptr && !HasModalProgress()) {
|
||||
this->draw_signal->notify_one();
|
||||
} else {
|
||||
this->Paint();
|
||||
}
|
||||
}
|
||||
this->Tick();
|
||||
|
||||
/* Emscripten is running an event-based mainloop; there is already some
|
||||
* downtime between each iteration, so no need to sleep. */
|
||||
@@ -988,89 +981,27 @@ void VideoDriver_SDL_Base::LoopOnce()
|
||||
|
||||
void VideoDriver_SDL_Base::MainLoop()
|
||||
{
|
||||
if (this->draw_threaded) {
|
||||
/* Initialise the mutex first, because that's the thing we *need*
|
||||
* directly in the newly created thread. */
|
||||
this->draw_mutex = new std::recursive_mutex();
|
||||
if (this->draw_mutex == nullptr) {
|
||||
this->draw_threaded = false;
|
||||
} else {
|
||||
draw_lock = std::unique_lock<std::recursive_mutex>(*this->draw_mutex);
|
||||
this->draw_signal = new std::condition_variable_any();
|
||||
this->draw_continue = true;
|
||||
|
||||
this->draw_threaded = StartNewThread(&draw_thread, "ottd:draw-sdl", &VideoDriver_SDL_Base::PaintThreadThunk, this);
|
||||
|
||||
/* Free the mutex if we won't be able to use it. */
|
||||
if (!this->draw_threaded) {
|
||||
draw_lock.unlock();
|
||||
draw_lock.release();
|
||||
delete this->draw_mutex;
|
||||
delete this->draw_signal;
|
||||
this->draw_mutex = nullptr;
|
||||
this->draw_signal = nullptr;
|
||||
} else {
|
||||
/* Wait till the draw mutex has started itself. */
|
||||
this->draw_signal->wait(*this->draw_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(driver, 1, "SDL2: using %sthreads", this->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
|
||||
this->StartGameThread();
|
||||
|
||||
while (!_exit_game) {
|
||||
LoopOnce();
|
||||
}
|
||||
|
||||
MainLoopCleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_Base::MainLoopCleanup()
|
||||
{
|
||||
if (this->draw_mutex != nullptr) {
|
||||
this->draw_continue = false;
|
||||
/* Sending signal if there is no thread blocked
|
||||
* is very valid and results in noop */
|
||||
this->draw_signal->notify_one();
|
||||
if (draw_lock.owns_lock()) draw_lock.unlock();
|
||||
draw_lock.release();
|
||||
draw_thread.join();
|
||||
|
||||
delete this->draw_mutex;
|
||||
delete this->draw_signal;
|
||||
|
||||
this->draw_mutex = nullptr;
|
||||
this->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());
|
||||
this->StopGameThread();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VideoDriver_SDL_Base::ChangeResolution(int w, int h)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock;
|
||||
if (this->draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*this->draw_mutex);
|
||||
|
||||
return CreateMainSurface(w, h, true);
|
||||
}
|
||||
|
||||
bool VideoDriver_SDL_Base::ToggleFullscreen(bool fullscreen)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock;
|
||||
if (this->draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*this->draw_mutex);
|
||||
|
||||
int w, h;
|
||||
|
||||
/* Remember current window size */
|
||||
@@ -1096,6 +1027,7 @@ bool VideoDriver_SDL_Base::ToggleFullscreen(bool fullscreen)
|
||||
DEBUG(driver, 0, "SDL_SetWindowFullscreen() failed: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
this->InvalidateGameOptionsWindow();
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
@@ -1107,16 +1039,6 @@ bool VideoDriver_SDL_Base::AfterBlitterChange()
|
||||
return CreateMainSurface(w, h, false);
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_Base::AcquireBlitterLock()
|
||||
{
|
||||
if (this->draw_mutex != nullptr) this->draw_mutex->lock();
|
||||
}
|
||||
|
||||
void VideoDriver_SDL_Base::ReleaseBlitterLock()
|
||||
{
|
||||
if (this->draw_mutex != nullptr) this->draw_mutex->unlock();
|
||||
}
|
||||
|
||||
Dimension VideoDriver_SDL_Base::GetScreenSize() const
|
||||
{
|
||||
SDL_DisplayMode mode;
|
||||
@@ -1130,8 +1052,6 @@ bool VideoDriver_SDL_Base::LockVideoBuffer()
|
||||
if (this->buffer_locked) return false;
|
||||
this->buffer_locked = true;
|
||||
|
||||
if (this->draw_threaded) this->draw_lock.lock();
|
||||
|
||||
_screen.dst_ptr = this->GetVideoPointer();
|
||||
assert(_screen.dst_ptr != nullptr);
|
||||
|
||||
@@ -1146,6 +1066,5 @@ void VideoDriver_SDL_Base::UnlockVideoBuffer()
|
||||
_screen.dst_ptr = nullptr;
|
||||
}
|
||||
|
||||
if (this->draw_threaded) this->draw_lock.unlock();
|
||||
this->buffer_locked = false;
|
||||
}
|
||||
|
||||
@@ -36,25 +36,19 @@ public:
|
||||
|
||||
bool AfterBlitterChange() override;
|
||||
|
||||
void AcquireBlitterLock() override;
|
||||
|
||||
void ReleaseBlitterLock() override;
|
||||
|
||||
bool ClaimMousePointer() override;
|
||||
|
||||
void EditBoxGainedFocus() override;
|
||||
|
||||
void EditBoxLostFocus() override;
|
||||
|
||||
std::vector<int> GetListOfMonitorRefreshRates() override;
|
||||
|
||||
const char *GetName() const override { return "sdl"; }
|
||||
|
||||
protected:
|
||||
struct SDL_Window *sdl_window; ///< Main SDL window.
|
||||
Palette local_palette; ///< Copy of _cur_palette.
|
||||
bool draw_threaded; ///< Whether the drawing is/may be done in a separate thread.
|
||||
std::recursive_mutex *draw_mutex = nullptr; ///< Mutex to keep the access to the shared memory controlled.
|
||||
std::condition_variable_any *draw_signal = nullptr; ///< Signal to draw the next frame.
|
||||
volatile bool draw_continue; ///< Should we keep continue drawing?
|
||||
bool buffer_locked; ///< Video buffer was locked by the main thread.
|
||||
Rect dirty_rect; ///< Rectangle encompassing the dirty area of the video buffer.
|
||||
|
||||
@@ -94,10 +88,6 @@ private:
|
||||
bool edit_box_focused;
|
||||
|
||||
int startup_display;
|
||||
std::thread draw_thread;
|
||||
std::unique_lock<std::recursive_mutex> draw_lock;
|
||||
|
||||
static void PaintThreadThunk(VideoDriver_SDL_Base *drv);
|
||||
};
|
||||
|
||||
#endif /* VIDEO_SDL_H */
|
||||
|
||||
@@ -23,12 +23,6 @@
|
||||
#include "../window_func.h"
|
||||
#include "sdl_v.h"
|
||||
#include <SDL.h>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#if defined(__MINGW32__)
|
||||
#include "../3rdparty/mingw-std-threads/mingw.mutex.h"
|
||||
#include "../3rdparty/mingw-std-threads/mingw.condition_variable.h"
|
||||
#endif
|
||||
#include <algorithm>
|
||||
|
||||
#include "../safeguards.h"
|
||||
@@ -39,14 +33,6 @@ static SDL_Surface *_sdl_surface;
|
||||
static SDL_Surface *_sdl_realscreen;
|
||||
static bool _all_modes;
|
||||
|
||||
/** 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;
|
||||
|
||||
#define MAX_DIRTY_RECTS 100
|
||||
@@ -179,27 +165,6 @@ void VideoDriver_SDL::Paint()
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDriver_SDL::PaintThread()
|
||||
{
|
||||
/* First tell the main thread we're started */
|
||||
std::unique_lock<std::recursive_mutex> lock(*_draw_mutex);
|
||||
_draw_signal->notify_one();
|
||||
|
||||
/* Now wait for the first thing to draw! */
|
||||
_draw_signal->wait(*_draw_mutex);
|
||||
|
||||
while (_draw_continue) {
|
||||
/* Then just draw and wait till we stop */
|
||||
this->Paint();
|
||||
_draw_signal->wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void VideoDriver_SDL::PaintThreadThunk(VideoDriver_SDL *drv)
|
||||
{
|
||||
drv->PaintThread();
|
||||
}
|
||||
|
||||
static const Dimension _default_resolutions[] = {
|
||||
{ 640, 480},
|
||||
{ 800, 600},
|
||||
@@ -607,10 +572,10 @@ bool VideoDriver_SDL::PollEvent()
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *VideoDriver_SDL::Start(const StringList &parm)
|
||||
const char *VideoDriver_SDL::Start(const StringList ¶m)
|
||||
{
|
||||
char buf[30];
|
||||
_use_hwpalette = GetDriverParamInt(parm, "hw_palette", 2);
|
||||
_use_hwpalette = GetDriverParamInt(param, "hw_palette", 2);
|
||||
|
||||
/* Just on the offchance the audio subsystem started before the video system,
|
||||
* check whether any part of SDL has been initialised before getting here.
|
||||
@@ -636,7 +601,7 @@ const char *VideoDriver_SDL::Start(const StringList &parm)
|
||||
MarkWholeScreenDirty();
|
||||
SetupKeyboard();
|
||||
|
||||
_draw_threaded = !GetDriverParamBool(parm, "no_threads") && !GetDriverParamBool(parm, "no_thread");
|
||||
this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -688,80 +653,25 @@ void VideoDriver_SDL::InputLoop()
|
||||
|
||||
void VideoDriver_SDL::MainLoop()
|
||||
{
|
||||
std::thread draw_thread;
|
||||
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 {
|
||||
this->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", &VideoDriver_SDL::PaintThreadThunk, this);
|
||||
|
||||
/* Free the mutex if we won't be able to use it. */
|
||||
if (!_draw_threaded) {
|
||||
this->draw_lock.unlock();
|
||||
this->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, "SDL: using %sthreads", _draw_threaded ? "" : "no ");
|
||||
this->StartGameThread();
|
||||
|
||||
for (;;) {
|
||||
if (_exit_game) break;
|
||||
|
||||
if (this->Tick()) {
|
||||
if (_draw_mutex != nullptr && !HasModalProgress()) {
|
||||
_draw_signal->notify_one();
|
||||
} else {
|
||||
this->Paint();
|
||||
}
|
||||
}
|
||||
this->Tick();
|
||||
this->SleepTillNextTick();
|
||||
}
|
||||
|
||||
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 (this->draw_lock.owns_lock()) this->draw_lock.unlock();
|
||||
this->draw_lock.release();
|
||||
draw_thread.join();
|
||||
|
||||
delete _draw_mutex;
|
||||
delete _draw_signal;
|
||||
|
||||
_draw_mutex = nullptr;
|
||||
_draw_signal = nullptr;
|
||||
}
|
||||
this->StopGameThread();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
_fullscreen = fullscreen;
|
||||
GetVideoModes(); // get the list of available video modes
|
||||
bool ret = !_resolutions.empty() && CreateMainSurface(_cur_resolution.width, _cur_resolution.height);
|
||||
@@ -771,6 +681,7 @@ bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen)
|
||||
_fullscreen ^= true;
|
||||
}
|
||||
|
||||
this->InvalidateGameOptionsWindow();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -779,25 +690,4 @@ bool VideoDriver_SDL::AfterBlitterChange()
|
||||
return CreateMainSurface(_screen.width, _screen.height);
|
||||
}
|
||||
|
||||
void VideoDriver_SDL::AcquireBlitterLock()
|
||||
{
|
||||
if (_draw_mutex != nullptr) _draw_mutex->lock();
|
||||
}
|
||||
|
||||
void VideoDriver_SDL::ReleaseBlitterLock()
|
||||
{
|
||||
if (_draw_mutex != nullptr) _draw_mutex->unlock();
|
||||
}
|
||||
|
||||
bool VideoDriver_SDL::LockVideoBuffer()
|
||||
{
|
||||
if (_draw_threaded) this->draw_lock.lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoDriver_SDL::UnlockVideoBuffer()
|
||||
{
|
||||
if (_draw_threaded) this->draw_lock.unlock();
|
||||
}
|
||||
|
||||
#endif /* WITH_SDL */
|
||||
|
||||
@@ -29,30 +29,19 @@ public:
|
||||
|
||||
bool AfterBlitterChange() override;
|
||||
|
||||
void AcquireBlitterLock() override;
|
||||
|
||||
void ReleaseBlitterLock() override;
|
||||
|
||||
bool ClaimMousePointer() override;
|
||||
|
||||
const char *GetName() const override { return "sdl"; }
|
||||
|
||||
protected:
|
||||
void InputLoop() override;
|
||||
bool LockVideoBuffer() override;
|
||||
void UnlockVideoBuffer() override;
|
||||
void Paint() override;
|
||||
void PaintThread() override;
|
||||
void CheckPaletteAnim() override;
|
||||
bool PollEvent() override;
|
||||
|
||||
private:
|
||||
std::unique_lock<std::recursive_mutex> draw_lock;
|
||||
|
||||
bool CreateMainSurface(uint w, uint h);
|
||||
void SetupKeyboard();
|
||||
|
||||
static void PaintThreadThunk(VideoDriver_SDL *drv);
|
||||
};
|
||||
|
||||
/** Factory for the SDL video driver. */
|
||||
|
||||
@@ -8,50 +8,142 @@
|
||||
/** @file video_driver.cpp Common code between video driver implementations. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../debug.h"
|
||||
#include "../core/random_func.hpp"
|
||||
#include "../network/network.h"
|
||||
#include "../blitter/factory.hpp"
|
||||
#include "../debug.h"
|
||||
#include "../fontcache.h"
|
||||
#include "../gfx_func.h"
|
||||
#include "../gfxinit.h"
|
||||
#include "../progress.h"
|
||||
#include "../thread.h"
|
||||
#include "../window_func.h"
|
||||
#include "video_driver.hpp"
|
||||
|
||||
bool VideoDriver::Tick()
|
||||
bool _video_hw_accel; ///< Whether to consider hardware accelerated video drivers.
|
||||
|
||||
void VideoDriver::GameLoop()
|
||||
{
|
||||
auto cur_ticks = std::chrono::steady_clock::now();
|
||||
this->next_game_tick += this->GetGameInterval();
|
||||
|
||||
if (cur_ticks >= this->next_game_tick) {
|
||||
this->next_game_tick += this->GetGameInterval();
|
||||
/* Avoid next_game_tick getting behind more and more if it cannot keep up. */
|
||||
if (this->next_game_tick < cur_ticks - ALLOWED_DRIFT * this->GetGameInterval()) this->next_game_tick = cur_ticks;
|
||||
/* Avoid next_game_tick getting behind more and more if it cannot keep up. */
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (this->next_game_tick < now - ALLOWED_DRIFT * this->GetGameInterval()) this->next_game_tick = now;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(this->game_state_mutex);
|
||||
|
||||
/* The game loop is the part that can run asynchronously.
|
||||
* The rest except sleeping can't. */
|
||||
this->UnlockVideoBuffer();
|
||||
::GameLoop();
|
||||
this->LockVideoBuffer();
|
||||
|
||||
// TODO: lock
|
||||
::GameLoopPaletteAnimations();
|
||||
// TODO: unlock
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDriver::GameThread()
|
||||
{
|
||||
while (!_exit_game) {
|
||||
this->GameLoop();
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (this->next_game_tick > now) {
|
||||
std::this_thread::sleep_for(this->next_game_tick - now);
|
||||
} else {
|
||||
/* Ensure we yield this thread if drawings wants to take a lock on
|
||||
* the game state. This is mainly because most OSes have an
|
||||
* optimization that if you unlock/lock a mutex in the same thread
|
||||
* quickly, it will never context switch even if there is another
|
||||
* thread waiting to take the lock on the same mutex. */
|
||||
std::lock_guard<std::mutex> lock(this->game_thread_wait_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
void VideoDriver::StartGameThread()
|
||||
{
|
||||
if (this->is_game_threaded) {
|
||||
this->is_game_threaded = StartNewThread(&this->game_thread, "ottd:game", &VideoDriver::GameThreadThunk, this);
|
||||
}
|
||||
|
||||
DEBUG(driver, 1, "using %sthread for game-loop", this->is_game_threaded ? "" : "no ");
|
||||
}
|
||||
|
||||
void VideoDriver::StopGameThread()
|
||||
{
|
||||
if (!this->is_game_threaded) return;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void VideoDriver::Tick()
|
||||
{
|
||||
if (!this->is_game_threaded && std::chrono::steady_clock::now() >= this->next_game_tick) {
|
||||
this->GameLoop();
|
||||
|
||||
/* For things like dedicated server, don't run a separate draw-tick. */
|
||||
if (!this->HasGUI()) {
|
||||
::InputLoop();
|
||||
UpdateWindows();
|
||||
::UpdateWindows();
|
||||
this->next_draw_tick = this->next_game_tick;
|
||||
}
|
||||
}
|
||||
|
||||
/* Prevent drawing when switching mode, as windows can be removed when they should still appear. */
|
||||
if (this->HasGUI() && cur_ticks >= this->next_draw_tick && (_switch_mode == SM_NONE || _game_mode == GM_BOOTSTRAP || HasModalProgress())) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (this->HasGUI() && now >= this->next_draw_tick) {
|
||||
this->next_draw_tick += this->GetDrawInterval();
|
||||
/* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
|
||||
if (this->next_draw_tick < cur_ticks - ALLOWED_DRIFT * this->GetDrawInterval()) this->next_draw_tick = cur_ticks;
|
||||
if (this->next_draw_tick < now - ALLOWED_DRIFT * this->GetDrawInterval()) this->next_draw_tick = now;
|
||||
|
||||
/* Keep the interactive randomizer a bit more random by requesting
|
||||
* new values when-ever we can. */
|
||||
InteractiveRandom();
|
||||
|
||||
while (this->PollEvent()) {}
|
||||
this->InputLoop();
|
||||
|
||||
/* Check if the fast-forward button is still pressed. */
|
||||
@@ -63,25 +155,51 @@ bool VideoDriver::Tick()
|
||||
this->fast_forward_via_key = false;
|
||||
}
|
||||
|
||||
::InputLoop();
|
||||
UpdateWindows();
|
||||
{
|
||||
/* Tell the game-thread to stop so we can have a go. */
|
||||
std::lock_guard<std::mutex> lock_wait(this->game_thread_wait_mutex);
|
||||
std::lock_guard<std::mutex> lock_state(this->game_state_mutex);
|
||||
|
||||
this->LockVideoBuffer();
|
||||
|
||||
if (this->change_blitter != nullptr) {
|
||||
this->RealChangeBlitter(this->change_blitter);
|
||||
this->change_blitter = nullptr;
|
||||
}
|
||||
|
||||
while (this->PollEvent()) {}
|
||||
::InputLoop();
|
||||
|
||||
/* Prevent drawing when switching mode, as windows can be removed when they should still appear. */
|
||||
if (_game_mode == GM_BOOTSTRAP || _switch_mode == SM_NONE || HasModalProgress()) {
|
||||
::UpdateWindows();
|
||||
}
|
||||
|
||||
this->PopulateSystemSprites();
|
||||
}
|
||||
|
||||
this->CheckPaletteAnim();
|
||||
this->Paint();
|
||||
|
||||
return true;
|
||||
this->UnlockVideoBuffer();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void VideoDriver::SleepTillNextTick()
|
||||
{
|
||||
/* See how much time there is till we have to process the next event, and try to hit that as close as possible. */
|
||||
auto next_tick = std::min(this->next_draw_tick, this->next_game_tick);
|
||||
auto next_tick = this->next_draw_tick;
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
|
||||
if (!this->is_game_threaded) {
|
||||
next_tick = min(next_tick, this->next_game_tick);
|
||||
}
|
||||
|
||||
if (next_tick > now) {
|
||||
this->UnlockVideoBuffer();
|
||||
std::this_thread::sleep_for(next_tick - now);
|
||||
this->LockVideoBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDriver::InvalidateGameOptionsWindow()
|
||||
{
|
||||
InvalidateWindowClassesData(WC_GAME_OPTIONS, 3);
|
||||
}
|
||||
|
||||
@@ -16,13 +16,18 @@
|
||||
#include "../gfx_func.h"
|
||||
#include "../settings_type.h"
|
||||
#include "../zoom_type.h"
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
extern std::string _ini_videodriver;
|
||||
extern std::vector<Dimension> _resolutions;
|
||||
extern Dimension _cur_resolution;
|
||||
extern bool _rightclick_emulate;
|
||||
extern bool _video_hw_accel;
|
||||
|
||||
/** The base of all video drivers. */
|
||||
class VideoDriver : public Driver {
|
||||
@@ -30,6 +35,8 @@ class VideoDriver : public Driver {
|
||||
const uint DEFAULT_WINDOW_HEIGHT = 480u; ///< Default window height.
|
||||
|
||||
public:
|
||||
VideoDriver() : is_game_threaded(true), change_blitter(nullptr) {}
|
||||
|
||||
/**
|
||||
* Mark a particular area dirty.
|
||||
* @param left The left most line of the dirty area.
|
||||
@@ -61,7 +68,6 @@ public:
|
||||
|
||||
/**
|
||||
* Callback invoked after the blitter was changed.
|
||||
* This may only be called between AcquireBlitterLock and ReleaseBlitterLock.
|
||||
* @return True if no error.
|
||||
*/
|
||||
virtual bool AfterBlitterChange()
|
||||
@@ -69,18 +75,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire any lock(s) required to be held when changing blitters.
|
||||
* These lock(s) may not be acquired recursively.
|
||||
*/
|
||||
virtual void AcquireBlitterLock() { }
|
||||
|
||||
/**
|
||||
* Release any lock(s) required to be held when changing blitters.
|
||||
* These lock(s) may not be acquired recursively.
|
||||
*/
|
||||
virtual void ReleaseBlitterLock() { }
|
||||
|
||||
virtual bool ClaimMousePointer()
|
||||
{
|
||||
return true;
|
||||
@@ -95,6 +89,11 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate all sprites in cache.
|
||||
*/
|
||||
virtual void PopulateSystemSprites() {}
|
||||
|
||||
/**
|
||||
* Clear all cached sprites.
|
||||
*/
|
||||
@@ -150,6 +149,15 @@ public:
|
||||
*/
|
||||
virtual void EditBoxGainedFocus() {}
|
||||
|
||||
/**
|
||||
* Get a list of refresh rates of each available monitor.
|
||||
* @return A vector of the refresh rates of all available monitors.
|
||||
*/
|
||||
virtual std::vector<int> GetListOfMonitorRefreshRates()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a suggested default GUI zoom taking screen DPI into account.
|
||||
*/
|
||||
@@ -162,6 +170,17 @@ public:
|
||||
return ZOOM_LVL_OUT_4X;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a request to change the blitter. This is not executed immediately,
|
||||
* but instead on the next draw-tick.
|
||||
*/
|
||||
void ChangeBlitter(const char *new_blitter)
|
||||
{
|
||||
this->change_blitter = new_blitter;
|
||||
}
|
||||
|
||||
void GameLoopPause();
|
||||
|
||||
/**
|
||||
* Get the currently active instance of the video driver.
|
||||
*/
|
||||
@@ -240,11 +259,6 @@ protected:
|
||||
*/
|
||||
virtual void Paint() {}
|
||||
|
||||
/**
|
||||
* Thread function for threaded drawing.
|
||||
*/
|
||||
virtual void PaintThread() {}
|
||||
|
||||
/**
|
||||
* Process any pending palette animation.
|
||||
*/
|
||||
@@ -257,16 +271,29 @@ protected:
|
||||
virtual bool PollEvent() { return false; };
|
||||
|
||||
/**
|
||||
* Run the game for a single tick, processing boththe game-tick and draw-tick.
|
||||
* @returns True if the driver should redraw the screen.
|
||||
* Start the loop for game-tick.
|
||||
*/
|
||||
bool Tick();
|
||||
void StartGameThread();
|
||||
|
||||
/**
|
||||
* Stop the loop for the game-tick. This can still tick at most one time before truly shutting down.
|
||||
*/
|
||||
void StopGameThread();
|
||||
|
||||
/**
|
||||
* Give the video-driver a tick.
|
||||
* It will process any potential game-tick and/or draw-tick, and/or any
|
||||
* other video-driver related event.
|
||||
*/
|
||||
void Tick();
|
||||
|
||||
/**
|
||||
* Sleep till the next tick is about to happen.
|
||||
*/
|
||||
void SleepTillNextTick();
|
||||
|
||||
void InvalidateGameOptionsWindow();
|
||||
|
||||
std::chrono::steady_clock::duration GetGameInterval()
|
||||
{
|
||||
/* If we are paused, run on normal speed. */
|
||||
@@ -287,6 +314,20 @@ protected:
|
||||
|
||||
bool fast_forward_key_pressed; ///< The fast-forward key is being pressed.
|
||||
bool fast_forward_via_key; ///< The fast-forward was enabled by key press.
|
||||
|
||||
bool is_game_threaded;
|
||||
std::thread game_thread;
|
||||
std::mutex game_state_mutex;
|
||||
std::mutex game_thread_wait_mutex;
|
||||
|
||||
static void GameThreadThunk(VideoDriver *drv);
|
||||
|
||||
private:
|
||||
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 */
|
||||
|
||||
@@ -129,9 +129,10 @@ uint8 VideoDriver_Win32Base::GetFullscreenBpp()
|
||||
/**
|
||||
* Instantiate a new window.
|
||||
* @param full_screen Whether to make a full screen window or not.
|
||||
* @param resize Whether to change window size.
|
||||
* @return True if the window could be created.
|
||||
*/
|
||||
bool VideoDriver_Win32Base::MakeWindow(bool full_screen)
|
||||
bool VideoDriver_Win32Base::MakeWindow(bool full_screen, bool resize)
|
||||
{
|
||||
/* full_screen is whether the new window should be fullscreen,
|
||||
* _wnd.fullscreen is whether the current window is. */
|
||||
@@ -173,7 +174,7 @@ bool VideoDriver_Win32Base::MakeWindow(bool full_screen)
|
||||
}
|
||||
|
||||
if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
|
||||
this->MakeWindow(false); // don't care about the result
|
||||
this->MakeWindow(false, resize); // don't care about the result
|
||||
return false; // the request failed
|
||||
}
|
||||
} else if (this->fullscreen) {
|
||||
@@ -206,7 +207,7 @@ bool VideoDriver_Win32Base::MakeWindow(bool full_screen)
|
||||
h = r.bottom - r.top;
|
||||
|
||||
if (this->main_wnd != nullptr) {
|
||||
if (!_window_maximize) SetWindowPos(this->main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
|
||||
if (!_window_maximize && resize) SetWindowPos(this->main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
|
||||
} else {
|
||||
int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
|
||||
int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
|
||||
@@ -226,11 +227,6 @@ bool VideoDriver_Win32Base::MakeWindow(bool full_screen)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ void VideoDriver_Win32Base::PaintThreadThunk(VideoDriver_Win32Base *drv)
|
||||
{
|
||||
drv->PaintThread();
|
||||
}
|
||||
|
||||
/** Forward key presses to the window system. */
|
||||
static LRESULT HandleCharMsg(uint keycode, WChar charcode)
|
||||
{
|
||||
@@ -871,70 +867,16 @@ bool VideoDriver_Win32Base::PollEvent()
|
||||
|
||||
void VideoDriver_Win32Base::MainLoop()
|
||||
{
|
||||
std::thread draw_thread;
|
||||
|
||||
if (this->draw_threaded) {
|
||||
/* Initialise the mutex first, because that's the thing we *need*
|
||||
* directly in the newly created thread. */
|
||||
try {
|
||||
this->draw_signal = new std::condition_variable_any();
|
||||
this->draw_mutex = new std::recursive_mutex();
|
||||
} catch (...) {
|
||||
this->draw_threaded = false;
|
||||
}
|
||||
|
||||
if (this->draw_threaded) {
|
||||
this->draw_lock = std::unique_lock<std::recursive_mutex>(*this->draw_mutex);
|
||||
|
||||
this->draw_continue = true;
|
||||
this->draw_threaded = StartNewThread(&draw_thread, "ottd:draw-win32", &VideoDriver_Win32Base::PaintThreadThunk, this);
|
||||
|
||||
/* Free the mutex if we won't be able to use it. */
|
||||
if (!this->draw_threaded) {
|
||||
this->draw_lock.unlock();
|
||||
this->draw_lock.release();
|
||||
delete this->draw_mutex;
|
||||
delete this->draw_signal;
|
||||
this->draw_mutex = nullptr;
|
||||
this->draw_signal = nullptr;
|
||||
} else {
|
||||
DEBUG(driver, 1, "Threaded drawing enabled");
|
||||
/* Wait till the draw thread has started itself. */
|
||||
this->draw_signal->wait(*this->draw_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
this->StartGameThread();
|
||||
|
||||
for (;;) {
|
||||
if (_exit_game) break;
|
||||
|
||||
/* Flush GDI buffer to ensure we don't conflict with the drawing thread. */
|
||||
GdiFlush();
|
||||
|
||||
if (this->Tick()) {
|
||||
if (this->draw_mutex != nullptr && !HasModalProgress()) {
|
||||
this->draw_signal->notify_one();
|
||||
} else {
|
||||
this->Paint();
|
||||
}
|
||||
}
|
||||
this->Tick();
|
||||
this->SleepTillNextTick();
|
||||
}
|
||||
|
||||
if (this->draw_threaded) {
|
||||
this->draw_continue = false;
|
||||
/* Sending signal if there is no thread blocked
|
||||
* is very valid and results in noop */
|
||||
this->draw_signal->notify_all();
|
||||
if (this->draw_lock.owns_lock()) this->draw_lock.unlock();
|
||||
this->draw_lock.release();
|
||||
draw_thread.join();
|
||||
|
||||
delete this->draw_mutex;
|
||||
delete this->draw_signal;
|
||||
|
||||
this->draw_mutex = nullptr;
|
||||
}
|
||||
this->StopGameThread();
|
||||
}
|
||||
|
||||
void VideoDriver_Win32Base::ClientSizeChanged(int w, int h, bool force)
|
||||
@@ -954,9 +896,6 @@ void VideoDriver_Win32Base::ClientSizeChanged(int w, int h, bool force)
|
||||
|
||||
bool VideoDriver_Win32Base::ChangeResolution(int w, int h)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock;
|
||||
if (this->draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*this->draw_mutex);
|
||||
|
||||
if (_window_maximize) ShowWindow(this->main_wnd, SW_SHOWNORMAL);
|
||||
|
||||
this->width = this->width_org = w;
|
||||
@@ -967,32 +906,40 @@ bool VideoDriver_Win32Base::ChangeResolution(int w, int h)
|
||||
|
||||
bool VideoDriver_Win32Base::ToggleFullscreen(bool full_screen)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock;
|
||||
if (this->draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*this->draw_mutex);
|
||||
bool res = this->MakeWindow(full_screen);
|
||||
|
||||
return this->MakeWindow(full_screen);
|
||||
}
|
||||
|
||||
void VideoDriver_Win32Base::AcquireBlitterLock()
|
||||
{
|
||||
if (this->draw_mutex != nullptr) this->draw_mutex->lock();
|
||||
}
|
||||
|
||||
void VideoDriver_Win32Base::ReleaseBlitterLock()
|
||||
{
|
||||
if (this->draw_mutex != nullptr) this->draw_mutex->unlock();
|
||||
this->InvalidateGameOptionsWindow();
|
||||
return res;
|
||||
}
|
||||
|
||||
void VideoDriver_Win32Base::EditBoxLostFocus()
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock;
|
||||
if (this->draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*this->draw_mutex);
|
||||
|
||||
CancelIMEComposition(this->main_wnd);
|
||||
SetCompositionPos(this->main_wnd);
|
||||
SetCandidatePos(this->main_wnd);
|
||||
}
|
||||
|
||||
std::vector<int> VideoDriver_Win32Base::GetListOfMonitorRefreshRates()
|
||||
{
|
||||
std::vector<int> rates = {};
|
||||
EnumDisplayMonitors(nullptr, nullptr, [](HMONITOR hMonitor, HDC hDC, LPRECT rc, LPARAM data) -> BOOL {
|
||||
auto &list = *reinterpret_cast<std::vector<int>*>(data);
|
||||
|
||||
MONITORINFOEX monitorInfo = {};
|
||||
monitorInfo.cbSize = sizeof(MONITORINFOEX);
|
||||
GetMonitorInfo(hMonitor, &monitorInfo);
|
||||
|
||||
DEVMODE devMode = {};
|
||||
devMode.dmSize = sizeof(DEVMODE);
|
||||
devMode.dmDriverExtra = 0;
|
||||
EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &devMode);
|
||||
|
||||
if (devMode.dmDisplayFrequency != 0) list.push_back(devMode.dmDisplayFrequency);
|
||||
return true;
|
||||
}, reinterpret_cast<LPARAM>(&rates));
|
||||
return rates;
|
||||
}
|
||||
|
||||
Dimension VideoDriver_Win32Base::GetScreenSize() const
|
||||
{
|
||||
return { static_cast<uint>(GetSystemMetrics(SM_CXSCREEN)), static_cast<uint>(GetSystemMetrics(SM_CYSCREEN)) };
|
||||
@@ -1043,8 +990,6 @@ bool VideoDriver_Win32Base::LockVideoBuffer()
|
||||
if (this->buffer_locked) return false;
|
||||
this->buffer_locked = true;
|
||||
|
||||
if (this->draw_threaded) this->draw_lock.lock();
|
||||
|
||||
_screen.dst_ptr = this->GetVideoPointer();
|
||||
assert(_screen.dst_ptr != nullptr);
|
||||
|
||||
@@ -1060,7 +1005,6 @@ void VideoDriver_Win32Base::UnlockVideoBuffer()
|
||||
_screen.dst_ptr = nullptr;
|
||||
}
|
||||
|
||||
if (this->draw_threaded) this->draw_lock.unlock();
|
||||
this->buffer_locked = false;
|
||||
}
|
||||
|
||||
@@ -1079,7 +1023,7 @@ const char *VideoDriver_Win32GDI::Start(const StringList ¶m)
|
||||
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
this->draw_threaded = !GetDriverParam(param, "no_threads") && !GetDriverParam(param, "no_thread") && std::thread::hardware_concurrency() > 1;
|
||||
this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1130,7 +1074,7 @@ bool VideoDriver_Win32GDI::AllocateBackingStore(int w, int h, bool force)
|
||||
bool VideoDriver_Win32GDI::AfterBlitterChange()
|
||||
{
|
||||
assert(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 0);
|
||||
return this->AllocateBackingStore(_screen.width, _screen.height, true) && this->MakeWindow(_fullscreen);
|
||||
return this->AllocateBackingStore(_screen.width, _screen.height, true) && this->MakeWindow(_fullscreen, false);
|
||||
}
|
||||
|
||||
void VideoDriver_Win32GDI::MakePalette()
|
||||
@@ -1201,13 +1145,7 @@ void VideoDriver_Win32GDI::Paint()
|
||||
break;
|
||||
|
||||
case Blitter::PALETTE_ANIMATION_BLITTER: {
|
||||
bool need_buf = _screen.dst_ptr == nullptr;
|
||||
if (need_buf) _screen.dst_ptr = this->GetVideoPointer();
|
||||
blitter->PaletteAnimate(_local_palette);
|
||||
if (need_buf) {
|
||||
this->ReleaseVideoPointer();
|
||||
_screen.dst_ptr = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1230,26 +1168,6 @@ void VideoDriver_Win32GDI::Paint()
|
||||
this->dirty_rect = {};
|
||||
}
|
||||
|
||||
void VideoDriver_Win32GDI::PaintThread()
|
||||
{
|
||||
/* First tell the main thread we're started */
|
||||
std::unique_lock<std::recursive_mutex> lock(*this->draw_mutex);
|
||||
this->draw_signal->notify_one();
|
||||
|
||||
/* Now wait for the first thing to draw! */
|
||||
this->draw_signal->wait(*this->draw_mutex);
|
||||
|
||||
while (this->draw_continue) {
|
||||
this->Paint();
|
||||
|
||||
/* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */
|
||||
GdiFlush();
|
||||
|
||||
this->draw_signal->wait(*this->draw_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
/* Keep this function here..
|
||||
* It allows you to redraw the screen from within the MSVC debugger */
|
||||
@@ -1395,9 +1313,10 @@ const char *VideoDriver_Win32OpenGL::Start(const StringList ¶m)
|
||||
|
||||
this->ClientSizeChanged(this->width, this->height, true);
|
||||
|
||||
this->draw_threaded = false;
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1478,6 +1397,11 @@ bool VideoDriver_Win32OpenGL::AfterBlitterChange()
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoDriver_Win32OpenGL::PopulateSystemSprites()
|
||||
{
|
||||
OpenGLBackend::Get()->PopulateCursorCache();
|
||||
}
|
||||
|
||||
void VideoDriver_Win32OpenGL::ClearSystemSprites()
|
||||
{
|
||||
OpenGLBackend::Get()->ClearCursorCache();
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
/** Base class for Windows video drivers. */
|
||||
class VideoDriver_Win32Base : public VideoDriver {
|
||||
public:
|
||||
VideoDriver_Win32Base() : main_wnd(nullptr), fullscreen(false), draw_mutex(nullptr), draw_signal(nullptr) {}
|
||||
VideoDriver_Win32Base() : main_wnd(nullptr), fullscreen(false) {}
|
||||
|
||||
void Stop() override;
|
||||
|
||||
@@ -33,14 +33,12 @@ public:
|
||||
|
||||
bool ToggleFullscreen(bool fullscreen) override;
|
||||
|
||||
void AcquireBlitterLock() override;
|
||||
|
||||
void ReleaseBlitterLock() override;
|
||||
|
||||
bool ClaimMousePointer() override;
|
||||
|
||||
void EditBoxLostFocus() override;
|
||||
|
||||
std::vector<int> GetListOfMonitorRefreshRates() override;
|
||||
|
||||
protected:
|
||||
HWND main_wnd; ///< Handle to system window.
|
||||
bool fullscreen; ///< Whether to use (true) fullscreen mode.
|
||||
@@ -51,12 +49,7 @@ protected:
|
||||
int width_org = 0; ///< Original monitor resolution width, before we changed it.
|
||||
int height_org = 0; ///< Original monitor resolution height, before we changed it.
|
||||
|
||||
bool draw_threaded; ///< Whether the drawing is/may be done in a separate thread.
|
||||
bool buffer_locked; ///< Video buffer was locked by the main thread.
|
||||
volatile bool draw_continue; ///< Should we keep continue drawing?
|
||||
|
||||
std::recursive_mutex *draw_mutex; ///< Mutex to keep the access to the shared memory controlled.
|
||||
std::condition_variable_any *draw_signal; ///< Signal to draw the next frame.
|
||||
bool buffer_locked; ///< Video buffer was locked by the main thread.
|
||||
|
||||
Dimension GetScreenSize() const override;
|
||||
float GetDPIScale() override;
|
||||
@@ -67,7 +60,7 @@ protected:
|
||||
bool PollEvent() override;
|
||||
|
||||
void Initialize();
|
||||
bool MakeWindow(bool full_screen);
|
||||
bool MakeWindow(bool full_screen, bool resize = true);
|
||||
void ClientSizeChanged(int w, int h, bool force = false);
|
||||
|
||||
/** Get screen depth to use for fullscreen mode. */
|
||||
@@ -82,10 +75,6 @@ protected:
|
||||
virtual void PaletteChanged(HWND hWnd) = 0;
|
||||
|
||||
private:
|
||||
std::unique_lock<std::recursive_mutex> draw_lock;
|
||||
|
||||
static void PaintThreadThunk(VideoDriver_Win32Base *drv);
|
||||
|
||||
friend LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
};
|
||||
/** The GDI video driver for windows. */
|
||||
@@ -108,7 +97,6 @@ protected:
|
||||
|
||||
void Paint() override;
|
||||
void *GetVideoPointer() override { return this->buffer_bits; }
|
||||
void PaintThread() override;
|
||||
|
||||
bool AllocateBackingStore(int w, int h, bool force = false) override;
|
||||
void PaletteChanged(HWND hWnd) override;
|
||||
@@ -147,6 +135,8 @@ public:
|
||||
|
||||
bool UseSystemCursor() override { return true; }
|
||||
|
||||
void PopulateSystemSprites() override;
|
||||
|
||||
void ClearSystemSprites() override;
|
||||
|
||||
bool HasAnimBuffer() override { return true; }
|
||||
@@ -163,7 +153,6 @@ protected:
|
||||
uint8 GetFullscreenBpp() override { return 32; } // OpenGL is always 32 bpp.
|
||||
|
||||
void Paint() override;
|
||||
void PaintThread() override {}
|
||||
|
||||
bool AllocateBackingStore(int w, int h, bool force = false) override;
|
||||
void *GetVideoPointer() override;
|
||||
@@ -179,6 +168,9 @@ class FVideoDriver_Win32OpenGL : public DriverFactoryBase {
|
||||
public:
|
||||
FVideoDriver_Win32OpenGL() : DriverFactoryBase(Driver::DT_VIDEO, 10, "win32-opengl", "Win32 OpenGL Video Driver") {}
|
||||
/* virtual */ Driver *CreateInstance() const override { return new VideoDriver_Win32OpenGL(); }
|
||||
|
||||
protected:
|
||||
bool UsesHardwareAcceleration() const override { return true; }
|
||||
};
|
||||
|
||||
#endif /* WITH_OPENGL */
|
||||
|
||||
Reference in New Issue
Block a user