From adc787cbaa0671fad73d715c5031f82875420bb8 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Mon, 27 Jan 2025 05:13:16 +0300 Subject: [PATCH 1/9] Engine: support choosing DisplayIndex in the DisplayMode --- Engine/gfx/ali3dogl.cpp | 6 ++++- Engine/gfx/ali3dsw.cpp | 34 +++++++++++++++++++++--- Engine/gfx/ali3dsw.h | 2 ++ Engine/gfx/gfxdefines.h | 7 +++-- Engine/main/config.cpp | 1 + Engine/main/engine.cpp | 5 ++-- Engine/main/graphics_mode.cpp | 13 +++++---- Engine/main/graphics_mode.h | 11 ++++---- Engine/platform/base/sys_main.cpp | 13 ++++++--- Engine/platform/base/sys_main.h | 2 +- Engine/platform/windows/gfx/ali3dd3d.cpp | 24 ++++++++++++----- Engine/platform/windows/gfx/ali3dd3d.h | 1 + 12 files changed, 87 insertions(+), 32 deletions(-) diff --git a/Engine/gfx/ali3dogl.cpp b/Engine/gfx/ali3dogl.cpp index dfb7b8a70f6..5a77a67458c 100644 --- a/Engine/gfx/ali3dogl.cpp +++ b/Engine/gfx/ali3dogl.cpp @@ -245,6 +245,9 @@ bool OGLGraphicsDriver::InitGlScreen(const DisplayMode &mode) } else { +#if (AGS_PLATFORM_DESKTOP) + sys_window_fit_in_display(mode.DisplayIndex); +#endif sys_window_set_style(mode.Mode, Size(mode.Width, mode.Height)); } @@ -302,7 +305,7 @@ bool OGLGraphicsDriver::CreateWindowAndGlContext(const DisplayMode &mode) if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0) SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Error occured setting attribute SDL_GL_DOUBLEBUFFER: %s", SDL_GetError()); - SDL_Window *sdl_window = sys_window_create("", mode.Width, mode.Height, mode.Mode, SDL_WINDOW_OPENGL); + SDL_Window *sdl_window = sys_window_create("", mode.DisplayIndex, mode.Width, mode.Height, mode.Mode, SDL_WINDOW_OPENGL); if (!sdl_window) { Debug::Printf(kDbgMsg_Error, "Error opening window for OpenGL: %s", SDL_GetError()); @@ -760,6 +763,7 @@ bool OGLGraphicsDriver::SetDisplayMode(const DisplayMode &mode) // On certain platforms OpenGL renderer ignores requested screen sizes // and uses values imposed by the operating system (device). DisplayMode final_mode = mode; + final_mode.DisplayIndex = sys_get_window_display_index(); final_mode.Width = device_screen_physical_width; final_mode.Height = device_screen_physical_height; OnModeSet(final_mode); diff --git a/Engine/gfx/ali3dsw.cpp b/Engine/gfx/ali3dsw.cpp index 1574fe5f260..615a7b30c6b 100644 --- a/Engine/gfx/ali3dsw.cpp +++ b/Engine/gfx/ali3dsw.cpp @@ -13,6 +13,7 @@ //============================================================================= #include "gfx/ali3dsw.h" #include +#include #include #include "ac/sys_events.h" #include "gfx/ali3dexception.h" @@ -20,7 +21,8 @@ #include "gfx/gfx_util.h" #include "platform/base/agsplatformdriver.h" #include "platform/base/sys_main.h" -#include "ac/timer.h" +#include "util/string_compat.h" + namespace AGS { @@ -130,7 +132,7 @@ bool SDLRendererGraphicsDriver::SetDisplayMode(const DisplayMode &mode) SDL_Window *window = sys_get_window(); if (!window) { - window = sys_window_create("", mode.Width, mode.Height, mode.Mode); + window = sys_window_create("", mode.DisplayIndex, mode.Width, mode.Height, mode.Mode); _hasGamma = SDL_GetWindowGammaRamp(window, _defaultGammaRed, _defaultGammaGreen, _defaultGammaBlue) == 0; @@ -154,12 +156,34 @@ bool SDLRendererGraphicsDriver::SetDisplayMode(const DisplayMode &mode) if (!_capsVsync) Debug::Printf(kDbgMsg_Warn, "WARNING: Vertical sync is not supported. Setting will be kept at driver default."); } + + // Record if SDL have created a DirectX renderer - we use this info for some checks + const std::array directx_renderers = { { "direct3d", "direct3d11", "direct3d12" } }; + for (const char *name : directx_renderers) + { + if (ags_stricmp(rinfo.name, name) == 0) + { + _isDirectX = true; + break; + } + } } else { Debug::Printf("SDLRenderer: failed to query renderer info: %s", SDL_GetError()); } } else { +#if (AGS_PLATFORM_DESKTOP) + // This is a bit of a hack, but certain drivers do not support changing + // display in exclusive fullscreen mode, and here we find out if it's the case. + // NOTE: we may in theory support this, but we'd have to release and recreate + // ALL the resources, including all textures currently in memory. + if (_isDirectX && mode.IsRealFullscreen() && + (_fullscreenDisplay > 0) && (sys_get_window_display_index() != _fullscreenDisplay)) + { + sys_window_fit_in_display(_fullscreenDisplay); + } +#endif // AGS_PLATFORM_DESKTOP sys_window_set_style(mode.Mode, Size(mode.Width, mode.Height)); } @@ -168,7 +192,11 @@ bool SDLRendererGraphicsDriver::SetDisplayMode(const DisplayMode &mode) #endif OnInit(); - OnModeSet(mode); + DisplayMode set_mode = mode; + set_mode.DisplayIndex = sys_get_window_display_index(); + if ((_fullscreenDisplay < 0) || set_mode.IsRealFullscreen()) + _fullscreenDisplay = set_mode.DisplayIndex; + OnModeSet(set_mode); return true; } diff --git a/Engine/gfx/ali3dsw.h b/Engine/gfx/ali3dsw.h index 09f3f921738..224891d1e71 100644 --- a/Engine/gfx/ali3dsw.h +++ b/Engine/gfx/ali3dsw.h @@ -240,6 +240,8 @@ class SDLRendererGraphicsDriver : public GraphicsDriverBase SDL_Renderer *_renderer = nullptr; SDL_Texture *_screenTex = nullptr; + bool _isDirectX = false; // records if created DirectX based renderer + int _fullscreenDisplay = -1; // a display where exclusive fullscreen was created // BITMAP struct for wrapping screen texture locked pixels, so that we may use blit() BITMAP *_fakeTexBitmap = nullptr; unsigned char *_lastTexPixels = nullptr; diff --git a/Engine/gfx/gfxdefines.h b/Engine/gfx/gfxdefines.h index e11ccb762d2..d7d970721dd 100644 --- a/Engine/gfx/gfxdefines.h +++ b/Engine/gfx/gfxdefines.h @@ -50,7 +50,8 @@ enum WindowMode struct DisplayMode : public GraphicResolution { WindowMode Mode = kWnd_Windowed; - int32_t RefreshRate = 0; + int DisplayIndex = 0; // which display to use (0 - default) + int RefreshRate = 0; bool Vsync = false; // Tells if this is logically a normal windowed mode @@ -59,9 +60,11 @@ struct DisplayMode : public GraphicResolution inline bool IsRealFullscreen() const { return Mode == kWnd_Fullscreen; } DisplayMode() = default; - DisplayMode(const GraphicResolution &res, WindowMode mode = kWnd_Windowed, int32_t refresh = 0, bool vsync = false) + DisplayMode(const GraphicResolution &res, WindowMode mode = kWnd_Windowed, + int display_index = 0, int32_t refresh = 0, bool vsync = false) : GraphicResolution(res) , Mode(mode) + , DisplayIndex(display_index) , RefreshRate(refresh) , Vsync(vsync) {} diff --git a/Engine/main/config.cpp b/Engine/main/config.cpp index 035b2153c6f..253d6582451 100644 --- a/Engine/main/config.cpp +++ b/Engine/main/config.cpp @@ -362,6 +362,7 @@ void load_common_config(const ConfigTree &cfg, GameConfig &setup, const Size &de // Graphics mode and options setup.Display.DriverID = CfgReadString(cfg, "graphics", "driver", setup.Display.DriverID); + setup.Display.DisplayIndex = CfgReadInt(cfg, "graphics", "display", 0); setup.Display.Windowed = CfgReadBoolInt(cfg, "graphics", "windowed", setup.Display.Windowed); setup.Display.FsSetup = parse_window_mode(CfgReadString(cfg, "graphics", "fullscreen", "default"), false, diff --git a/Engine/main/engine.cpp b/Engine/main/engine.cpp index e9a1c578357..a51ab3e4ea3 100644 --- a/Engine/main/engine.cpp +++ b/Engine/main/engine.cpp @@ -1376,7 +1376,8 @@ bool engine_try_switch_windowed_gfxmode() // *and* if the window is on the same display where it's been last time, // then use old params, otherwise - get default setup for the new mode. bool res; - if (last_opposite_mode.IsValid() && (setting.DisplayIndex == sys_get_window_display_index())) + const int use_display_index = sys_get_window_display_index(); + if (last_opposite_mode.IsValid() && (setting.Dm.DisplayIndex == use_display_index)) { res = graphics_mode_set_dm(last_opposite_mode); } @@ -1385,7 +1386,7 @@ bool engine_try_switch_windowed_gfxmode() WindowSetup ws = windowed ? usetup.Display.WinSetup : usetup.Display.FsSetup; frame = windowed ? usetup.Display.WinGameFrame : usetup.Display.FsGameFrame; res = graphics_mode_set_dm_any(game.GetGameRes(), ws, old_dm.ColorDepth, - frame, DisplaySetupEx(usetup.Display.RefreshRate, usetup.Display.VSync)); + frame, DisplaySetupEx(use_display_index, usetup.Display.RefreshRate, usetup.Display.VSync)); } // Apply corresponding frame render method diff --git a/Engine/main/graphics_mode.cpp b/Engine/main/graphics_mode.cpp index 8fd1c02be34..b2598c9d5bc 100644 --- a/Engine/main/graphics_mode.cpp +++ b/Engine/main/graphics_mode.cpp @@ -292,7 +292,7 @@ static bool try_init_mode_using_setup(const GraphicResolution &game_res, const W // We determine the requested size of the screen using setup options const Size screen_size = precalc_screen_size(game_res, ws, frame); DisplayMode dm(GraphicResolution(screen_size.Width, screen_size.Height, col_depth), - ws.Mode, params.RefreshRate, params.VSync); + ws.Mode, params.DisplayIndex, params.RefreshRate, params.VSync); if (!try_init_compatible_mode(dm)) return false; @@ -354,14 +354,14 @@ bool create_gfx_driver_and_init_mode_any(const String &gfx_driver_id, bool windowed = setup.Windowed; WindowSetup ws = windowed ? setup.WinSetup : setup.FsSetup; FrameScaleDef frame = windowed ? setup.WinGameFrame : setup.FsGameFrame; - bool result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, DisplaySetupEx(setup.RefreshRate, setup.VSync)); + bool result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, DisplaySetupEx(setup.DisplayIndex, setup.RefreshRate, setup.VSync)); // Try windowed mode if fullscreen failed, and vice versa if (!result && editor_debugging_initialized == 0) { windowed = !windowed; ws = windowed ? setup.WinSetup : setup.FsSetup; frame = windowed ? setup.WinGameFrame : setup.FsGameFrame; - result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, DisplaySetupEx(setup.RefreshRate, setup.VSync)); + result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, DisplaySetupEx(setup.DisplayIndex, setup.RefreshRate, setup.VSync)); } return result; } @@ -379,7 +379,7 @@ static bool simple_create_gfx_driver_and_init_mode(const String &gfx_driver_id, const FrameScaleDef frame = setup.Windowed ? setup.WinGameFrame : setup.FsGameFrame; DisplayMode dm(GraphicResolution(game_res.Width, game_res.Height, col_depth), - ws.Mode, setup.RefreshRate, setup.VSync); + ws.Mode, setup.DisplayIndex, setup.RefreshRate, setup.VSync); if (!graphics_mode_set_dm(dm)) { return false; } if (!graphics_mode_set_native_res(dm)) { return false; } @@ -495,7 +495,7 @@ bool graphics_mode_set_dm_any(const Size &game_size, const WindowSetup &ws, // We determine the requested size of the screen using setup options const Size screen_size = precalc_screen_size(game_size, ws, frame); DisplayMode dm(GraphicResolution(screen_size.Width, screen_size.Height, color_depth.Bits), - ws.Mode, params.RefreshRate, params.VSync); + ws.Mode, params.DisplayIndex, params.RefreshRate, params.VSync); return try_init_compatible_mode(dm); } @@ -517,12 +517,11 @@ bool graphics_mode_set_dm(const DisplayMode &dm) DisplayMode rdm = gfxDriver->GetDisplayMode(); ActiveDisplaySetting &setting = rdm.IsWindowed() ? SavedWindowedSetting : SavedFullscreenSetting; setting.Dm = rdm; - setting.DisplayIndex = sys_get_window_display_index(); Debug::Printf(kDbgMsg_Info, "Graphics driver set: %s", gfxDriver->GetDriverName()); Debug::Printf(kDbgMsg_Info, "Graphics mode set: %d x %d (%d-bit) %s, on display %d", rdm.Width, rdm.Height, rdm.ColorDepth, rdm.IsWindowed() ? "windowed" : (rdm.IsRealFullscreen() ? "fullscreen" : "fullscreen desktop"), - setting.DisplayIndex); + setting.Dm.DisplayIndex); Debug::Printf(kDbgMsg_Info, "Graphics mode set: refresh rate (optional): %d, vsync: %d", rdm.RefreshRate, rdm.Vsync); uint64_t tex_mem = gfxDriver->GetAvailableTextureMemory(); if (tex_mem > 0u) diff --git a/Engine/main/graphics_mode.h b/Engine/main/graphics_mode.h index bca27f67162..fc43a679d22 100644 --- a/Engine/main/graphics_mode.h +++ b/Engine/main/graphics_mode.h @@ -92,11 +92,12 @@ struct WindowSetup // Additional parameters for the display mode setup struct DisplaySetupEx { - int RefreshRate = 0; // gfx mode refresh rate - bool VSync = false; // vertical sync + int DisplayIndex = 0; // which display to use (0 - default) + int RefreshRate = 0; // gfx mode refresh rate + bool VSync = false; // vertical sync - DisplaySetupEx(int rate, bool vsync) - : RefreshRate(rate), VSync(vsync) {} + DisplaySetupEx(int display_index, int rate, bool vsync) + : DisplayIndex(display_index), RefreshRate(rate), VSync(vsync) {} }; // Full graphics configuration, contains graphics driver selection, @@ -115,6 +116,7 @@ struct DisplayModeSetup FrameScaleDef WinGameFrame = // how the game frame should be scaled/positioned in windowed mode kFrame_Undefined; + int DisplayIndex = 0; // which display to use (0 - default) bool Windowed = false; // initial mode int RefreshRate = 0; // gfx mode refresh rate bool VSync = false; // vertical sync @@ -138,7 +140,6 @@ struct ActiveDisplaySetting { DisplayMode Dm; FrameScaleDef Frame = kFrame_Undefined; - int DisplayIndex = -1; }; // Initializes any possible gfx mode, using user config as a recommendation; diff --git a/Engine/platform/base/sys_main.cpp b/Engine/platform/base/sys_main.cpp index 85e2cd5e02e..fcf88e7358c 100644 --- a/Engine/platform/base/sys_main.cpp +++ b/Engine/platform/base/sys_main.cpp @@ -181,7 +181,7 @@ void sys_audio_shutdown() // TODO: support multiple windows? in case we need some for diag purposes etc static SDL_Window *window = nullptr; -SDL_Window *sys_window_create(const char *window_title, int w, int h, WindowMode mode, int ex_flags) { +SDL_Window *sys_window_create(const char *window_title, int display_index, int w, int h, WindowMode mode, int ex_flags) { if (window) { sys_window_destroy(); } @@ -200,11 +200,16 @@ SDL_Window *sys_window_create(const char *window_title, int w, int h, WindowMode #endif #if (AGS_PLATFORM_OS_IOS) flags |= SDL_WINDOW_ALLOW_HIGHDPI; +#endif +#if !(AGS_PLATFORM_DESKTOP) + // Force displays setting to default on non-desktop platforms + assert(display_index == DEFAULT_DISPLAY_INDEX); + display_index = DEFAULT_DISPLAY_INDEX; #endif window = SDL_CreateWindow( window_title, - SDL_WINDOWPOS_CENTERED_DISPLAY(DEFAULT_DISPLAY_INDEX), - SDL_WINDOWPOS_CENTERED_DISPLAY(DEFAULT_DISPLAY_INDEX), + SDL_WINDOWPOS_CENTERED_DISPLAY(display_index), + SDL_WINDOWPOS_CENTERED_DISPLAY(display_index), w, h, flags @@ -216,7 +221,7 @@ SDL_Window *sys_window_create(const char *window_title, int w, int h, WindowMode // may be known only after the window is displayed, which means that // this may have to be called with a short delay (but how to know when?) if (mode == kWnd_Windowed) - sys_window_center(); + sys_window_center(display_index); #endif return window; } diff --git a/Engine/platform/base/sys_main.h b/Engine/platform/base/sys_main.h index 090e24aeaf3..5363f102635 100644 --- a/Engine/platform/base/sys_main.h +++ b/Engine/platform/base/sys_main.h @@ -59,7 +59,7 @@ void sys_audio_shutdown(); // struct SDL_Window; // Create a new single game window. -SDL_Window *sys_window_create(const char *window_title, int w, int h, AGS::Engine::WindowMode mode, int ex_flags = 0); +SDL_Window *sys_window_create(const char *window_title, int display_index, int w, int h, AGS::Engine::WindowMode mode, int ex_flags = 0); // Returns current game window, if one exists, or null. SDL_Window *sys_get_window(); // Changes the window style for the given mode (fullscreen / windowed). diff --git a/Engine/platform/windows/gfx/ali3dd3d.cpp b/Engine/platform/windows/gfx/ali3dd3d.cpp index 4c7c8128d19..d58978578ab 100644 --- a/Engine/platform/windows/gfx/ali3dd3d.cpp +++ b/Engine/platform/windows/gfx/ali3dd3d.cpp @@ -471,18 +471,23 @@ bool D3DGraphicsDriver::CreateDisplayMode(const DisplayMode &mode) return false; SDL_Window *window = sys_get_window(); + int use_display = mode.DisplayIndex; if (!window) { - sys_window_create("", mode.Width, mode.Height, mode.Mode); + sys_window_create("", mode.DisplayIndex, mode.Width, mode.Height, mode.Mode); } else { #if (AGS_PLATFORM_DESKTOP) - // Move window to the default display, this is where we create exclusive fullscreen - if (mode.IsRealFullscreen()) + // If user requested an exclusive fullscreen, move window to where we created it first, + // because DirectX does not normally support switching displays in exclusive mode. + // NOTE: we may in theory support this, but we'd have to release and recreate + // ALL the resources, including all textures currently in memory. + if (mode.IsRealFullscreen() && + (_fullscreenDisplay > 0) && (sys_get_window_display_index() != _fullscreenDisplay)) { - if (sys_get_window_display_index() != 0) - sys_window_fit_in_display(0); + use_display = _fullscreenDisplay; + sys_window_fit_in_display(_fullscreenDisplay); } #endif } @@ -523,7 +528,8 @@ bool D3DGraphicsDriver::CreateDisplayMode(const DisplayMode &mode) } else { - hr = direct3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, + const UINT use_adapter = SDL_Direct3D9GetAdapterIndex(use_display); + hr = direct3d->CreateDevice(use_adapter, D3DDEVTYPE_HAL, hwnd, D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, // multithreaded required for AVI player &d3dpp, direct3ddevice.Acquire()); } @@ -699,7 +705,11 @@ bool D3DGraphicsDriver::SetDisplayMode(const DisplayMode &mode) return false; OnInit(); - OnModeSet(mode); + DisplayMode set_mode = mode; + set_mode.DisplayIndex = sys_get_window_display_index(); + OnModeSet(set_mode); + if ((_fullscreenDisplay < 0) || set_mode.IsRealFullscreen()) + _fullscreenDisplay = set_mode.DisplayIndex; InitializeD3DState(); CreateVirtualScreen(); return true; diff --git a/Engine/platform/windows/gfx/ali3dd3d.h b/Engine/platform/windows/gfx/ali3dd3d.h index 00a7c08958b..b8e9fe9ca82 100644 --- a/Engine/platform/windows/gfx/ali3dd3d.h +++ b/Engine/platform/windows/gfx/ali3dd3d.h @@ -300,6 +300,7 @@ class D3DGraphicsDriver : public VideoMemoryGraphicsDriver CUSTOMVERTEX defaultVertices[4]; String previousError; D3DPixelShaderPtr pixelShader; + int _fullscreenDisplay = -1; // a display where exclusive fullscreen was created bool _smoothScaling; bool _legacyPixelShader; float _pixelRenderXOffset; From eeea4a60aae84f1795fb9155c36c7a9dfbe7407b Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Mon, 27 Jan 2025 07:38:24 +0300 Subject: [PATCH 2/9] Engine: use display index where necessary instead of current/default --- Engine/gfx/ali3dogl.cpp | 6 +- Engine/gfx/ali3dogl.h | 2 +- Engine/gfx/ali3dsw.cpp | 6 +- Engine/gfx/ali3dsw.h | 2 +- Engine/gfx/graphicsdriver.h | 2 +- Engine/main/config.cpp | 25 ++++----- Engine/main/config.h | 9 ++- Engine/main/engine.cpp | 4 +- Engine/main/engine_setup.cpp | 2 +- Engine/main/graphics_mode.cpp | 55 +++++++++++-------- Engine/main/graphics_mode.h | 3 + Engine/platform/base/agsplatformdriver.cpp | 4 +- Engine/platform/base/agsplatformdriver.h | 2 +- Engine/platform/base/sys_main.cpp | 20 ++++--- Engine/platform/base/sys_main.h | 8 ++- Engine/platform/windows/acplwin.cpp | 6 +- Engine/platform/windows/gfx/ali3dd3d.cpp | 24 ++++++-- Engine/platform/windows/gfx/ali3dd3d.h | 16 +++--- .../windows/setup/basicpagedialog.cpp | 14 ++--- .../platform/windows/setup/basicpagedialog.h | 5 +- Engine/platform/windows/setup/winsetup.cpp | 13 ++--- 21 files changed, 125 insertions(+), 103 deletions(-) diff --git a/Engine/gfx/ali3dogl.cpp b/Engine/gfx/ali3dogl.cpp index 5a77a67458c..f30a6a543d4 100644 --- a/Engine/gfx/ali3dogl.cpp +++ b/Engine/gfx/ali3dogl.cpp @@ -809,14 +809,14 @@ int OGLGraphicsDriver::GetDisplayDepthForNativeDepth(int /*native_color_depth*/) return 32; } -IGfxModeList *OGLGraphicsDriver::GetSupportedModeList(int color_depth) +IGfxModeList *OGLGraphicsDriver::GetSupportedModeList(int display_index, int color_depth) { std::vector modes {}; - sys_get_desktop_modes(modes, color_depth); + sys_get_desktop_modes(display_index, modes, color_depth); if ((modes.size() == 0) && color_depth == 32) { // Pretend that 24-bit are 32-bit - sys_get_desktop_modes(modes, 24); + sys_get_desktop_modes(display_index, modes, 24); for (auto &m : modes) { m.ColorDepth = 32; } } return new OGLDisplayModeList(modes); diff --git a/Engine/gfx/ali3dogl.h b/Engine/gfx/ali3dogl.h index fd3aeb74764..ad916cfc029 100644 --- a/Engine/gfx/ali3dogl.h +++ b/Engine/gfx/ali3dogl.h @@ -235,7 +235,7 @@ class OGLGraphicsDriver : public VideoMemoryGraphicsDriver bool SetNativeResolution(const GraphicResolution &native_res) override; bool SetRenderFrame(const Rect &dst_rect) override; int GetDisplayDepthForNativeDepth(int native_color_depth) const override; - IGfxModeList *GetSupportedModeList(int color_depth) override; + IGfxModeList *GetSupportedModeList(int display_index, int color_depth) override; bool IsModeSupported(const DisplayMode &mode) override; PGfxFilter GetGraphicsFilter() const override; void UnInit(); diff --git a/Engine/gfx/ali3dsw.cpp b/Engine/gfx/ali3dsw.cpp index 615a7b30c6b..364d97f86cc 100644 --- a/Engine/gfx/ali3dsw.cpp +++ b/Engine/gfx/ali3dsw.cpp @@ -81,14 +81,14 @@ int SDLRendererGraphicsDriver::GetDisplayDepthForNativeDepth(int /*native_color_ return 32; } -IGfxModeList *SDLRendererGraphicsDriver::GetSupportedModeList(int color_depth) +IGfxModeList *SDLRendererGraphicsDriver::GetSupportedModeList(int display_index, int color_depth) { std::vector modes; - sys_get_desktop_modes(modes, color_depth); + sys_get_desktop_modes(display_index, modes, color_depth); if ((modes.size() == 0) && color_depth == 32) { // Pretend that 24-bit are 32-bit - sys_get_desktop_modes(modes, 24); + sys_get_desktop_modes(display_index, modes, 24); for (auto &m : modes) { m.ColorDepth = 32; } } return new SDLRendererGfxModeList(modes); diff --git a/Engine/gfx/ali3dsw.h b/Engine/gfx/ali3dsw.h index 224891d1e71..da503ce5182 100644 --- a/Engine/gfx/ali3dsw.h +++ b/Engine/gfx/ali3dsw.h @@ -165,7 +165,7 @@ class SDLRendererGraphicsDriver : public GraphicsDriverBase bool SetRenderFrame(const Rect &dst_rect) override; bool IsModeSupported(const DisplayMode &mode) override; int GetDisplayDepthForNativeDepth(int native_color_depth) const override; - IGfxModeList *GetSupportedModeList(int color_depth) override; + IGfxModeList *GetSupportedModeList(int display_index, int color_depth) override; PGfxFilter GetGraphicsFilter() const override; void UnInit(); // Clears the screen rectangle. The coordinates are expected in the **native game resolution**. diff --git a/Engine/gfx/graphicsdriver.h b/Engine/gfx/graphicsdriver.h index 0cd93d04fa3..c8f640a6cda 100644 --- a/Engine/gfx/graphicsdriver.h +++ b/Engine/gfx/graphicsdriver.h @@ -120,7 +120,7 @@ class IGraphicsDriver virtual bool IsRenderFrameValid() const = 0; // Report which color depth options are best suited for the given native color depth virtual int GetDisplayDepthForNativeDepth(int native_color_depth) const = 0; - virtual IGfxModeList *GetSupportedModeList(int color_depth) = 0; + virtual IGfxModeList *GetSupportedModeList(int display_index, int color_depth) = 0; virtual bool IsModeSupported(const DisplayMode &mode) = 0; virtual DisplayMode GetDisplayMode() const = 0; virtual PGfxFilter GetGraphicsFilter() const = 0; diff --git a/Engine/main/config.cpp b/Engine/main/config.cpp index 253d6582451..451d11bb3cd 100644 --- a/Engine/main/config.cpp +++ b/Engine/main/config.cpp @@ -45,8 +45,7 @@ extern SpriteCache spriteset; const String DefaultConfigFileName = "acsetup.cfg"; -WindowSetup parse_window_mode(const String &option, bool as_windowed, - const Size &game_res, const Size &desktop_res, const WindowSetup &def_value) +WindowSetup parse_window_mode(const String &option, bool as_windowed, const WindowSetup &def_value) { // "full_window" option means pseudo fullscreen ("borderless fullscreen window") if (!as_windowed && (option.CompareNoCase("full_window") == 0)) @@ -57,10 +56,10 @@ WindowSetup parse_window_mode(const String &option, bool as_windowed, // Note that for "desktop" we return "default" for windowed, this will result // in refering to the desktop size but resizing in accordance to the scaling style if (option.CompareNoCase("desktop") == 0) - return as_windowed ? WindowSetup(exp_wmode) : WindowSetup(kWndSizeHint_Desktop, desktop_res, exp_wmode); + return as_windowed ? WindowSetup(exp_wmode) : WindowSetup(kWndSizeHint_Desktop, Size(), exp_wmode); // "Native" means using game resolution as a window size if (option.CompareNoCase("native") == 0) - return WindowSetup(kWndSizeHint_GameNative, game_res, exp_wmode); + return WindowSetup(kWndSizeHint_GameNative, Size(), exp_wmode); // Try parse an explicit resolution type or game scale factor -- size_t at = option.FindChar('x'); if (at == 0) @@ -164,7 +163,7 @@ void parse_asset_dirs(const String &option, std::vectorReadConfiguration(cfg); } -void load_common_config(const ConfigTree &cfg, GameConfig &setup, const Size &desktop_res) +void load_common_config(const ConfigTree &cfg, GameConfig &setup) { // Legacy settings have to be translated into new options; // they must be read first, to let newer options override them, if ones are present @@ -366,10 +365,10 @@ void load_common_config(const ConfigTree &cfg, GameConfig &setup, const Size &de setup.Display.Windowed = CfgReadBoolInt(cfg, "graphics", "windowed", setup.Display.Windowed); setup.Display.FsSetup = parse_window_mode(CfgReadString(cfg, "graphics", "fullscreen", "default"), false, - game.GetGameRes(), desktop_res, setup.Display.FsSetup); + setup.Display.FsSetup); setup.Display.WinSetup = parse_window_mode(CfgReadString(cfg, "graphics", "window", "default"), true, - game.GetGameRes(), desktop_res, setup.Display.WinSetup); + setup.Display.WinSetup); setup.Display.Filter.ID = CfgReadString(cfg, "graphics", "filter", "StdScale"); setup.Display.FsGameFrame = @@ -432,9 +431,7 @@ void load_common_config(const ConfigTree &cfg, GameConfig &setup, const Size &de void apply_config(const ConfigTree &cfg, GameSetup &setup) { - const Size &desktop_res = get_desktop_size(); - - load_common_config(cfg, setup, desktop_res); + load_common_config(cfg, setup); // // Additional config applied by the engine @@ -480,15 +477,15 @@ void post_config(GameSetup &setup) } } -void save_common_config(const GameConfig &setup, ConfigTree &cfg, const Size &game_res, const Size &desktop_res) +void save_common_config(const GameConfig &setup, ConfigTree &cfg) { CfgWriteString(cfg, "misc", "user_data_dir", setup.UserSaveDir); CfgWriteString(cfg, "misc", "shared_data_dir", setup.AppDataDir); CfgWriteString(cfg, "graphics", "driver", setup.Display.DriverID); CfgWriteString(cfg, "graphics", "filter", setup.Display.Filter.ID); - CfgWriteString(cfg, "graphics", "fullscreen", make_window_mode_option(setup.Display.FsSetup, game_res, desktop_res)); - CfgWriteString(cfg, "graphics", "window", make_window_mode_option(setup.Display.WinSetup, game_res, desktop_res)); + CfgWriteString(cfg, "graphics", "fullscreen", make_window_mode_option(setup.Display.FsSetup)); + CfgWriteString(cfg, "graphics", "window", make_window_mode_option(setup.Display.WinSetup)); CfgWriteString(cfg, "graphics", "game_scale_fs", make_scaling_option(setup.Display.FsGameFrame)); CfgWriteString(cfg, "graphics", "game_scale_win", make_scaling_option(setup.Display.WinGameFrame)); CfgWriteInt(cfg, "graphics", "windowed", setup.Display.Windowed ? 1 : 0); diff --git a/Engine/main/config.h b/Engine/main/config.h index bc16d57d575..fd51c8fb593 100644 --- a/Engine/main/config.h +++ b/Engine/main/config.h @@ -42,19 +42,18 @@ void apply_config(const ConfigTree &cfg, GameSetup &setup); void post_config(GameSetup &setup); // Load common configuration from the config tree into GameConfig struct -void load_common_config(const ConfigTree &cfg, GameConfig &setup, const Size &desktop_res); +void load_common_config(const ConfigTree &cfg, GameConfig &setup); // Saves common configuration from GameConfig struct to the config tree -void save_common_config(const GameConfig &setup, ConfigTree &cfg, const Size &game_res, const Size &desktop_res); +void save_common_config(const GameConfig &setup, ConfigTree &cfg); // Saves minimal runtime config using current engine state void save_runtime_config_file(); -WindowSetup parse_window_mode(const String &option, bool as_windowed, - const Size &game_res, const Size &desktop_res, const WindowSetup &def_value = WindowSetup()); +WindowSetup parse_window_mode(const String &option, bool as_windowed, const WindowSetup &def_value = WindowSetup()); FrameScaleDef parse_scaling_option(const String &option, FrameScaleDef def_value = kFrame_Undefined); SkipSpeechStyle parse_speechskip_style(const String &option, SkipSpeechStyle def_value = kSkipSpeechNone); void parse_asset_dirs(const String &option, std::vector> &opt_dirs); -String make_window_mode_option(const WindowSetup &ws, const Size &game_res, const Size &desktop_res); +String make_window_mode_option(const WindowSetup &ws); String make_scaling_option(FrameScaleDef scale_def); String make_speechskip_option(SkipSpeechStyle style); uint32_t convert_scaling_to_fp(int scale_factor); diff --git a/Engine/main/engine.cpp b/Engine/main/engine.cpp index a51ab3e4ea3..7bd6e684cb6 100644 --- a/Engine/main/engine.cpp +++ b/Engine/main/engine.cpp @@ -1340,7 +1340,7 @@ bool engine_try_set_gfxmode_any(const DisplayModeSetup &setup) sys_renderer_set_output(usetup.SoftwareRenderDriver); - const Size init_desktop = get_desktop_size(); + const Size init_desktop = get_desktop_size(setup.DisplayIndex); bool res = graphics_mode_init_any(GraphicResolution(game.GetGameRes(), game.color_depth * 8), setup, ColorDepthOption(game.GetColorDepth())); @@ -1363,7 +1363,7 @@ bool engine_try_switch_windowed_gfxmode() // Release engine resources that depend on display mode engine_pre_gfxmode_release(); - Size init_desktop = get_desktop_size(); + Size init_desktop = get_desktop_size(old_dm.DisplayIndex); bool windowed = !old_dm.IsWindowed(); ActiveDisplaySetting setting = graphics_mode_get_last_setting(windowed); DisplayMode last_opposite_mode = setting.Dm; diff --git a/Engine/main/engine_setup.cpp b/Engine/main/engine_setup.cpp index 10dafc3cd75..216bd041241 100644 --- a/Engine/main/engine_setup.cpp +++ b/Engine/main/engine_setup.cpp @@ -119,7 +119,7 @@ void engine_post_gfxmode_mouse_setup(const Size &init_desktop) if (usetup.MouseSpeedDef == kMouseSpeed_CurrentDisplay) { Size cur_desktop; - if (sys_get_desktop_resolution(cur_desktop.Width, cur_desktop.Height) == 0) + if (sys_get_desktop_resolution(cur_desktop.Width, cur_desktop.Height)) Mouse::SetSpeedUnit(std::max((float)cur_desktop.Width / (float)init_desktop.Width, (float)cur_desktop.Height / (float)init_desktop.Height)); } diff --git a/Engine/main/graphics_mode.cpp b/Engine/main/graphics_mode.cpp index b2598c9d5bc..7b9b1765fe0 100644 --- a/Engine/main/graphics_mode.cpp +++ b/Engine/main/graphics_mode.cpp @@ -61,18 +61,23 @@ PlaneScaling GameScaling; -Size get_desktop_size() +Size get_desktop_size(int display_index) { Size sz; - sys_get_desktop_resolution(sz.Width, sz.Height); + sys_get_desktop_resolution(display_index, sz.Width, sz.Height); return sz; } -Size get_max_display_size(bool windowed) +Size get_desktop_size() { - Size device_size = get_desktop_size(); + return get_desktop_size(sys_get_window_display_index()); +} + +Size get_max_display_size(int display_index, bool windowed) +{ + Size device_size = get_desktop_size(display_index); if (windowed) - device_size = platform->ValidateWindowSize(device_size, false); + device_size = platform->ValidateWindowSize(display_index, device_size, false); return device_size; } @@ -213,24 +218,27 @@ Size get_game_frame_from_screen_size(const Size &game_size, const Size screen_si } } -static Size precalc_screen_size(const Size &game_size, const WindowSetup &ws, const FrameScaleDef frame) +static Size precalc_screen_size(const Size &game_size, int display_index, const WindowSetup &ws, const FrameScaleDef frame) { const bool windowed = ws.Mode == kWnd_Windowed; - // Set requested screen (window) size, depending on screen definition option - if (!ws.Size.IsNull()) + if (ws.SizeHint == kWndSizeHint_GameNative) + { + return game_size; + } + else if (!ws.Size.IsNull()) { // Use explicit resolution from user config return ws.Size; } else if (ws.Scale > 0) { - return get_game_frame_from_screen_size(game_size, get_max_display_size(windowed), frame, ws.Scale); + return get_game_frame_from_screen_size(game_size, get_max_display_size(display_index, windowed), frame, ws.Scale); } // If nothing is set, then for the fullscreen mode set as big as current device/desktop size; // for the windowed mode assume maximal size inside desktop using given frame scaling if (windowed) - return get_game_frame_from_screen_size(game_size, get_max_display_size(windowed), frame); - return get_max_display_size(false); + return get_game_frame_from_screen_size(game_size, get_max_display_size(display_index, windowed), frame); + return get_max_display_size(display_index, false); } // Find closest possible compatible display mode and initialize it @@ -239,13 +247,13 @@ bool try_init_compatible_mode(const DisplayMode &dm) const Size &screen_size = Size(dm.Width, dm.Height); // Find nearest compatible mode and init that Debug::Printf("Attempt to find nearest supported resolution for screen size %d x %d (%d-bit) %s, on display %d", - dm.Width, dm.Height, dm.ColorDepth, dm.IsWindowed() ? "windowed" : "fullscreen", sys_get_window_display_index()); - const Size device_size = get_max_display_size(dm.IsWindowed()); + dm.Width, dm.Height, dm.ColorDepth, dm.IsWindowed() ? "windowed" : "fullscreen", dm.DisplayIndex); + const Size device_size = get_max_display_size(dm.DisplayIndex, dm.IsWindowed()); if (dm.IsWindowed()) Debug::Printf("Maximal allowed window size: %d x %d", device_size.Width, device_size.Height); DisplayMode dm_compat = dm; - std::unique_ptr modes(gfxDriver->GetSupportedModeList(dm.ColorDepth)); + std::unique_ptr modes(gfxDriver->GetSupportedModeList(dm.DisplayIndex, dm.ColorDepth)); // Windowed mode if (dm.IsWindowed()) @@ -290,7 +298,7 @@ static bool try_init_mode_using_setup(const GraphicResolution &game_res, const W const DisplaySetupEx ¶ms) { // We determine the requested size of the screen using setup options - const Size screen_size = precalc_screen_size(game_res, ws, frame); + const Size screen_size = precalc_screen_size(game_res, params.DisplayIndex, ws, frame); DisplayMode dm(GraphicResolution(screen_size.Width, screen_size.Height, col_depth), ws.Mode, params.DisplayIndex, params.RefreshRate, params.VSync); if (!try_init_compatible_mode(dm)) @@ -306,12 +314,12 @@ static bool try_init_mode_using_setup(const GraphicResolution &game_res, const W return true; } -void log_out_driver_modes(const int color_depth) +void log_out_driver_modes(const int display_index, const int color_depth) { - IGfxModeList *modes = gfxDriver->GetSupportedModeList(color_depth); + IGfxModeList *modes = gfxDriver->GetSupportedModeList(display_index, color_depth); if (!modes) { - Debug::Printf(kDbgMsg_Error, "Couldn't get a list of supported resolutions for color depth = %d", color_depth); + Debug::Printf(kDbgMsg_Error, "Couldn't get a list of supported resolutions for display %d, color depth = %d", display_index, color_depth); return; } const int mode_count = modes->GetModeCount(); @@ -326,7 +334,7 @@ void log_out_driver_modes(const int color_depth) } delete modes; - String out_str = String::FromFormat("Supported gfx modes (%d-bit): ", color_depth); + String out_str = String::FromFormat("Supported gfx modes for display %d (%d-bit): ", display_index, color_depth); if (!mode_str.IsEmpty()) { out_str.Append("\n\t"); @@ -349,7 +357,7 @@ bool create_gfx_driver_and_init_mode_any(const String &gfx_driver_id, const int use_col_depth = color_depth.Forced ? color_depth.Bits : gfxDriver->GetDisplayDepthForNativeDepth(color_depth.Bits); // Log out supported driver modes - log_out_driver_modes(use_col_depth); + log_out_driver_modes(setup.DisplayIndex, use_col_depth); bool windowed = setup.Windowed; WindowSetup ws = windowed ? setup.WinSetup : setup.FsSetup; @@ -374,6 +382,7 @@ static bool simple_create_gfx_driver_and_init_mode(const String &gfx_driver_id, { if (!graphics_mode_create_renderer(gfx_driver_id)) { return false; } + // FIXME: use precalc_screen_size() here for Desktop systems, don't hardcode to using game_res const int col_depth = gfxDriver->GetDisplayDepthForNativeDepth(color_depth.Bits); const WindowSetup ws = setup.Windowed ? setup.WinSetup : setup.FsSetup; const FrameScaleDef frame = setup.Windowed ? setup.WinGameFrame : setup.FsGameFrame; @@ -417,7 +426,7 @@ bool graphics_mode_init_any(const GraphicResolution &game_res, const DisplayMode { // Log out display information Size device_size; - if (sys_get_desktop_resolution(device_size.Width, device_size.Height) == 0) + if (sys_get_desktop_resolution(setup.DisplayIndex, device_size.Width, device_size.Height)) Debug::Printf("Device display resolution: %d x %d", device_size.Width, device_size.Height); else Debug::Printf(kDbgMsg_Error, "Unable to obtain device resolution"); @@ -493,7 +502,7 @@ bool graphics_mode_set_dm_any(const Size &game_size, const WindowSetup &ws, const FrameScaleDef frame, const DisplaySetupEx ¶ms) { // We determine the requested size of the screen using setup options - const Size screen_size = precalc_screen_size(game_size, ws, frame); + const Size screen_size = precalc_screen_size(game_size, params.DisplayIndex, ws, frame); DisplayMode dm(GraphicResolution(screen_size.Width, screen_size.Height, color_depth.Bits), ws.Mode, params.DisplayIndex, params.RefreshRate, params.VSync); return try_init_compatible_mode(dm); @@ -502,7 +511,7 @@ bool graphics_mode_set_dm_any(const Size &game_size, const WindowSetup &ws, bool graphics_mode_set_dm(const DisplayMode &dm) { Debug::Printf("Attempt to switch gfx mode to %d x %d (%d-bit) %s, on display %d", - dm.Width, dm.Height, dm.ColorDepth, dm.IsWindowed() ? "windowed" : "fullscreen", sys_get_window_display_index()); + dm.Width, dm.Height, dm.ColorDepth, dm.IsWindowed() ? "windowed" : "fullscreen", dm.DisplayIndex); // Tell Allegro new default bitmap color depth (must be done before set_gfx_mode) // TODO: this is also done inside ALSoftwareGraphicsDriver implementation; can remove one? diff --git a/Engine/main/graphics_mode.h b/Engine/main/graphics_mode.h index fc43a679d22..3d1606d1bf4 100644 --- a/Engine/main/graphics_mode.h +++ b/Engine/main/graphics_mode.h @@ -27,6 +27,9 @@ using AGS::Engine::GraphicResolution; using AGS::Engine::DisplayMode; using AGS::Engine::WindowMode; +// Gets desktop size for the given display +Size get_desktop_size(int display_index); +// Gets desktop size for the displays that hosts game window Size get_desktop_size(); namespace AGS { namespace Engine { class IGfxModeList; }} diff --git a/Engine/platform/base/agsplatformdriver.cpp b/Engine/platform/base/agsplatformdriver.cpp index 75a6ac3d59b..804d7aac528 100644 --- a/Engine/platform/base/agsplatformdriver.cpp +++ b/Engine/platform/base/agsplatformdriver.cpp @@ -55,7 +55,7 @@ void AGSPlatformDriver::AttachToParentConsole() { } void AGSPlatformDriver::PauseApplication() { } void AGSPlatformDriver::ResumeApplication() { } -Size AGSPlatformDriver::ValidateWindowSize(const Size &sz, bool borderless) const +Size AGSPlatformDriver::ValidateWindowSize(int display_index, const Size &sz, bool borderless) const { // TODO: Ideally we should also test for the minimal / maximal // allowed size of the window in current system here; @@ -64,7 +64,7 @@ Size AGSPlatformDriver::ValidateWindowSize(const Size &sz, bool borderless) cons // without creating a window first. But this potentially may be // acquired, at least on some platforms (e.g. Windows). SDL_Rect rc; - SDL_GetDisplayUsableBounds(sys_get_window_display_index(), &rc); + SDL_GetDisplayUsableBounds(display_index, &rc); return Size::Clamp(sz, Size(1, 1), Size(rc.w, rc.h)); } diff --git a/Engine/platform/base/agsplatformdriver.h b/Engine/platform/base/agsplatformdriver.h index e79250ba390..5c9c774bea5 100644 --- a/Engine/platform/base/agsplatformdriver.h +++ b/Engine/platform/base/agsplatformdriver.h @@ -108,7 +108,7 @@ class AGSPlatformDriver // Called when the application is being resumed. virtual void ResumeApplication(); // Adjust window's * client size * to ensure it is in the supported limits - virtual Size ValidateWindowSize(const Size &sz, bool borderless) const; + virtual Size ValidateWindowSize(int display_index, const Size &sz, bool borderless) const; // Either set window icon using system API directly, or create a SDL_Surface // for the SDL backend to set an icon instead. virtual SDL_Surface *CreateWindowIcon() { return nullptr; } diff --git a/Engine/platform/base/sys_main.cpp b/Engine/platform/base/sys_main.cpp index fcf88e7358c..1de858375d3 100644 --- a/Engine/platform/base/sys_main.cpp +++ b/Engine/platform/base/sys_main.cpp @@ -85,24 +85,27 @@ int sys_get_window_display_index() { #endif } -int sys_get_desktop_resolution(int &width, int &height) { +bool sys_get_desktop_resolution(int &width, int &height) { + return sys_get_desktop_resolution(sys_get_window_display_index(), width, height); +} + +bool sys_get_desktop_resolution(int display_index, int &width, int &height) { SDL_Rect r; - if (SDL_GetDisplayBounds(sys_get_window_display_index(), &r) != 0) { + if (SDL_GetDisplayBounds(display_index, &r) != 0) { Debug::Printf(kDbgMsg_Error, "SDL_GetDisplayBounds failed: %s", SDL_GetError()); - return -1; + return false; } width = r.w; height = r.h; - return 0; + return true; } -void sys_get_desktop_modes(std::vector &dms, int color_depth) { +void sys_get_desktop_modes(int display_index, std::vector &dms, int color_depth) { SDL_DisplayMode mode; - const int display_id = sys_get_window_display_index(); - const int count = SDL_GetNumDisplayModes(display_id); + const int count = SDL_GetNumDisplayModes(display_index); dms.clear(); for (int i = 0; i < count; ++i) { - if (SDL_GetDisplayMode(display_id, i, &mode) != 0) { + if (SDL_GetDisplayMode(display_index, i, &mode) != 0) { Debug::Printf(kDbgMsg_Error, "SDL_GetDisplayMode failed: %s", SDL_GetError()); continue; } @@ -111,6 +114,7 @@ void sys_get_desktop_modes(std::vector &dms, int color continue; } AGS::Engine::DisplayMode dm; + dm.DisplayIndex = display_index; dm.Width = mode.w; dm.Height = mode.h; dm.ColorDepth = bitsdepth; diff --git a/Engine/platform/base/sys_main.h b/Engine/platform/base/sys_main.h index 5363f102635..5fdca01cde2 100644 --- a/Engine/platform/base/sys_main.h +++ b/Engine/platform/base/sys_main.h @@ -40,10 +40,12 @@ void sys_set_background_mode(bool on); // Queries the display index on which the window is currently positioned. // Returns default display index in case window does not exist yet, or on any error. int sys_get_window_display_index(); -// Queries current desktop resolution. -int sys_get_desktop_resolution(int &width, int &height); +// Queries current desktop resolution from the display that hosts game window. +bool sys_get_desktop_resolution(int &width, int &height); +// Queries current desktop resolution from the requested display. +bool sys_get_desktop_resolution(int display_index, int &width, int &height); // Queries supported desktop modes. -void sys_get_desktop_modes(std::vector &dms, int color_depth = 0); +void sys_get_desktop_modes(int display_index, std::vector &dms, int color_depth = 0); // Sets output driver for the backend's renderer // TODO: consider make part of the SDLRendererGraphicsDriver later void sys_renderer_set_output(const String &name); diff --git a/Engine/platform/windows/acplwin.cpp b/Engine/platform/windows/acplwin.cpp index 94cb1f1bedb..4cfe8ebddba 100644 --- a/Engine/platform/windows/acplwin.cpp +++ b/Engine/platform/windows/acplwin.cpp @@ -78,7 +78,7 @@ struct AGSWin32 : AGSPlatformDriver { void DisplayMessageBox(const char *text) override; void PauseApplication() override; void ResumeApplication() override; - Size ValidateWindowSize(const Size &sz, bool borderless) const override; + Size ValidateWindowSize(int display_index, const Size &sz, bool borderless) const override; SDL_Surface *CreateWindowIcon() override; // Returns command line argument in a UTF-8 format @@ -408,7 +408,7 @@ void AGSWin32::ShutdownCDPlayer() { cd_exit(); } -Size AGSWin32::ValidateWindowSize(const Size &sz, bool borderless) const +Size AGSWin32::ValidateWindowSize(int display_index, const Size &sz, bool borderless) const { // Limit the window's client size by the two metrics: // * system's window size limit, @@ -419,7 +419,7 @@ Size AGSWin32::ValidateWindowSize(const Size &sz, bool borderless) const // This is the size of the available workspace on user's desktop // NOTE: using SDL here, because WinAPI monitor enumeration may have different order // (SDL deals with this by registering monitors in its own list, but we'd like to avoid a hassle) - SDL_GetDisplayUsableBounds(sys_get_window_display_index(), &bounds_rc); + SDL_GetDisplayUsableBounds(display_index, &bounds_rc); // This is the maximal size that OS can reliably resize the window to (including any frame) const Size max_win(GetSystemMetrics(SM_CXMAXTRACK), GetSystemMetrics(SM_CYMAXTRACK)); // This is the size of window's non-client area (frame, caption, etc) diff --git a/Engine/platform/windows/gfx/ali3dd3d.cpp b/Engine/platform/windows/gfx/ali3dd3d.cpp index d58978578ab..b3d5e167c66 100644 --- a/Engine/platform/windows/gfx/ali3dd3d.cpp +++ b/Engine/platform/windows/gfx/ali3dd3d.cpp @@ -84,13 +84,23 @@ void D3DBitmap::ReleaseTextureData() static D3DFORMAT color_depth_to_d3d_format(int color_depth, bool wantAlpha); static int d3d_format_to_color_depth(D3DFORMAT format, bool secondary); +D3DGfxModeList::D3DGfxModeList(const D3DPtr &direct3d, int display_index, D3DFORMAT d3dformat) + : _direct3d(direct3d) + , _displayIndex(display_index) + , _pixelFormat(d3dformat) +{ + _adapterIndex = SDL_Direct3D9GetAdapterIndex(display_index); + _modeCount = _direct3d->GetAdapterModeCount(_adapterIndex, _pixelFormat); +} + bool D3DGfxModeList::GetMode(int index, DisplayMode &mode) const { if (_direct3d && index >= 0 && index < _modeCount) { D3DDISPLAYMODE d3d_mode; - if (SUCCEEDED(_direct3d->EnumAdapterModes(D3DADAPTER_DEFAULT, _pixelFormat, index, &d3d_mode))) + if (SUCCEEDED(_direct3d->EnumAdapterModes(_adapterIndex, _pixelFormat, index, &d3d_mode))) { + mode.DisplayIndex = _displayIndex; mode.Width = d3d_mode.Width; mode.Height = d3d_mode.Height; mode.ColorDepth = d3d_format_to_color_depth(d3d_mode.Format, false); @@ -215,6 +225,7 @@ bool D3DGraphicsDriver::FirstTimeInit() { HRESULT hr; + direct3ddevice->GetCreationParameters(&direct3dcreateparams); direct3ddevice->GetDeviceCaps(&direct3ddevicecaps); // the PixelShader.fx uses ps_1_4 @@ -385,10 +396,11 @@ bool D3DGraphicsDriver::IsModeSupported(const DisplayMode &mode) D3DFORMAT pixelFormat = color_depth_to_d3d_format(mode.ColorDepth, false); D3DDISPLAYMODE d3d_mode; - int mode_count = direct3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, pixelFormat); + const UINT use_adapter = SDL_Direct3D9GetAdapterIndex(mode.DisplayIndex); + int mode_count = direct3d->GetAdapterModeCount(use_adapter, pixelFormat); for (int i = 0; i < mode_count; i++) { - if (FAILED(direct3d->EnumAdapterModes(D3DADAPTER_DEFAULT, pixelFormat, i, &d3d_mode))) + if (FAILED(direct3d->EnumAdapterModes(use_adapter, pixelFormat, i, &d3d_mode))) { SDL_SetError("IDirect3D9::EnumAdapterModes failed"); return false; @@ -854,9 +866,9 @@ int D3DGraphicsDriver::GetDisplayDepthForNativeDepth(int /*native_color_depth*/) return 32; } -IGfxModeList *D3DGraphicsDriver::GetSupportedModeList(int color_depth) +IGfxModeList *D3DGraphicsDriver::GetSupportedModeList(int display_index, int color_depth) { - return new D3DGfxModeList(direct3d, color_depth_to_d3d_format(color_depth, false)); + return new D3DGfxModeList(direct3d, display_index, color_depth_to_d3d_format(color_depth, false)); } PGfxFilter D3DGraphicsDriver::GetGraphicsFilter() const @@ -1742,7 +1754,7 @@ void D3DGraphicsDriver::AdjustSizeToNearestSupportedByCard(int *width, int *heig bool D3DGraphicsDriver::IsTextureFormatOk( D3DFORMAT TextureFormat, D3DFORMAT AdapterFormat ) { - HRESULT hr = direct3d->CheckDeviceFormat( D3DADAPTER_DEFAULT, + HRESULT hr = direct3d->CheckDeviceFormat(direct3dcreateparams.AdapterOrdinal, D3DDEVTYPE_HAL, AdapterFormat, 0, diff --git a/Engine/platform/windows/gfx/ali3dd3d.h b/Engine/platform/windows/gfx/ali3dd3d.h index b8e9fe9ca82..b04109eb9e4 100644 --- a/Engine/platform/windows/gfx/ali3dd3d.h +++ b/Engine/platform/windows/gfx/ali3dd3d.h @@ -159,12 +159,7 @@ class D3DBitmap : public BaseDDB class D3DGfxModeList : public IGfxModeList { public: - D3DGfxModeList(const D3DPtr &direct3d, D3DFORMAT d3dformat) - : _direct3d(direct3d) - , _pixelFormat(d3dformat) - { - _modeCount = _direct3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, _pixelFormat); - } + D3DGfxModeList(const D3DPtr &direct3d, int display_index, D3DFORMAT d3dformat); ~D3DGfxModeList() = default; int GetModeCount() const override @@ -176,6 +171,8 @@ class D3DGfxModeList : public IGfxModeList private: D3DPtr _direct3d; + int _displayIndex = 0; + UINT _adapterIndex = 0u; D3DFORMAT _pixelFormat; int _modeCount = 0; }; @@ -226,7 +223,7 @@ class D3DGraphicsDriver : public VideoMemoryGraphicsDriver bool SetNativeResolution(const GraphicResolution &native_res) override; bool SetRenderFrame(const Rect &dst_rect) override; int GetDisplayDepthForNativeDepth(int native_color_depth) const override; - IGfxModeList *GetSupportedModeList(int color_depth) override; + IGfxModeList *GetSupportedModeList(int display_index, int color_depth) override; bool IsModeSupported(const DisplayMode &mode) override; PGfxFilter GetGraphicsFilter() const override; // Clears the screen rectangle. The coordinates are expected in the **native game resolution**. @@ -290,9 +287,10 @@ class D3DGraphicsDriver : public VideoMemoryGraphicsDriver D3DPtr direct3d; D3DPRESENT_PARAMETERS d3dpp; D3DDevicePtr direct3ddevice; + D3DDEVICE_CREATION_PARAMETERS direct3dcreateparams; + D3DCAPS9 direct3ddevicecaps; D3DGAMMARAMP defaultgammaramp; D3DGAMMARAMP currentgammaramp; - D3DCAPS9 direct3ddevicecaps; // Default vertex buffer, for textures that don't have one D3DVertexBufferPtr vertexbuffer; // Texture for rendering in native resolution @@ -377,7 +375,7 @@ class D3DGraphicsDriver : public VideoMemoryGraphicsDriver void AdjustSizeToNearestSupportedByCard(int *width, int *height); void UpdateTextureRegion(D3DTextureTile *tile, const Bitmap *bitmap, bool has_alpha, bool opaque); void CreateVirtualScreen(); - bool IsTextureFormatOk( D3DFORMAT TextureFormat, D3DFORMAT AdapterFormat ); + bool IsTextureFormatOk(D3DFORMAT TextureFormat, D3DFORMAT AdapterFormat); // Backup all draw lists in the temp storage void BackupDrawLists(); diff --git a/Engine/platform/windows/setup/basicpagedialog.cpp b/Engine/platform/windows/setup/basicpagedialog.cpp index c21f6a3457f..bcfca0e01a5 100644 --- a/Engine/platform/windows/setup/basicpagedialog.cpp +++ b/Engine/platform/windows/setup/basicpagedialog.cpp @@ -87,14 +87,14 @@ void WinConfig::LoadMeta(const ConfigTree &cfg) DefaultLanguageName = CfgReadString(cfg, "language", "default_translation_name", DefaultLanguageName); } -void WinConfig::LoadCommon(const ConfigTree &cfg, const Size &desktop_res) +void WinConfig::LoadCommon(const ConfigTree &cfg) { - load_common_config(cfg, *this, desktop_res); + load_common_config(cfg, *this); } -void WinConfig::Save(ConfigTree &cfg, const Size &desktop_res) const +void WinConfig::Save(ConfigTree &cfg) const { - save_common_config(*this, cfg, GameResolution, desktop_res); + save_common_config(*this, cfg); } //============================================================================= @@ -115,8 +115,8 @@ INT_PTR BasicPageDialog::OnInitDialog() _hGfxFilterList = GetDlgItem(_hwnd, IDC_GFXFILTER); _hLanguageList = GetDlgItem(_hwnd, IDC_LANGUAGE); - _desktopSize = get_desktop_size(); - _maxWindowSize = AGSPlatformDriver::GetDriver()->ValidateWindowSize(_desktopSize, false); + _desktopSize = get_desktop_size(_displayIndex); + _maxWindowSize = AGSPlatformDriver::GetDriver()->ValidateWindowSize(_displayIndex, _desktopSize, false); // Resolution controls if (_winCfg.GameResolution.IsNull()) @@ -440,7 +440,7 @@ void BasicPageDialog::InitDriverDescFromFactory(const String &id) drv_desc->UseColorDepth = gfx_driver->GetDisplayDepthForNativeDepth(_winCfg.GameColourDepth ? _winCfg.GameColourDepth : 32); - IGfxModeList *gfxm_list = gfx_driver->GetSupportedModeList(drv_desc->UseColorDepth); + IGfxModeList *gfxm_list = gfx_driver->GetSupportedModeList(_displayIndex, drv_desc->UseColorDepth); VDispModes &modes = drv_desc->GfxModeList.Modes; if (gfxm_list) { diff --git a/Engine/platform/windows/setup/basicpagedialog.h b/Engine/platform/windows/setup/basicpagedialog.h index 20792a4b280..d1c6acc2c7e 100644 --- a/Engine/platform/windows/setup/basicpagedialog.h +++ b/Engine/platform/windows/setup/basicpagedialog.h @@ -57,8 +57,8 @@ struct WinConfig : public GameConfig WinConfig(); void SetDefaults(); void LoadMeta(const ConfigTree &cfg); - void LoadCommon(const ConfigTree &cfg, const Size &desktop_res); - void Save(ConfigTree &cfg, const Size &desktop_res) const; + void LoadCommon(const ConfigTree &cfg); + void Save(ConfigTree &cfg) const; }; //============================================================================= @@ -166,6 +166,7 @@ class BasicPageDialog : public WinSetupPageDialog PDriverDesc _drvDesc; GfxFilterInfo _gfxFilterInfo; // Resolution limits + int _displayIndex = 0; Size _desktopSize; Size _maxWindowSize; diff --git a/Engine/platform/windows/setup/winsetup.cpp b/Engine/platform/windows/setup/winsetup.cpp index a6072926cf6..d3e7220d5e3 100644 --- a/Engine/platform/windows/setup/winsetup.cpp +++ b/Engine/platform/windows/setup/winsetup.cpp @@ -74,7 +74,6 @@ class WinSetupDialog : public WinDialog const ConfigTree &_cfgIn; const ConfigTree &_defCfgIn; // game defaults, not including player's setup ConfigTree &_cfgOut; - Size _desktopSize; // Dialog controls HWND _hTabber = NULL; @@ -114,13 +113,11 @@ SetupReturnValue WinSetupDialog::ShowModal(const ConfigTree &cfg_in, const Confi INT_PTR WinSetupDialog::OnInitDialog() { - _hVersionText = GetDlgItem(_hwnd, IDC_VERSION); - _hTabber = GetDlgItem(_hwnd, IDC_TABPANEL); - - _desktopSize = get_desktop_size(); + _hVersionText = GetDlgItem(_hwnd, IDC_VERSION); + _hTabber = GetDlgItem(_hwnd, IDC_TABPANEL); _winCfg.LoadMeta(_defCfgIn); - _winCfg.LoadCommon(_cfgIn, _desktopSize); + _winCfg.LoadCommon(_cfgIn); // Resolution controls if (_winCfg.GameResolution.IsNull() && @@ -197,7 +194,7 @@ void WinSetupDialog::OnResetToDefaults() return; _winCfg.SetDefaults(); - _winCfg.LoadCommon(_defCfgIn, _desktopSize); + _winCfg.LoadCommon(_defCfgIn); for (auto &p : _pages) p->ResetSetup(_defCfgIn); } @@ -208,7 +205,7 @@ void WinSetupDialog::SaveSetup() for (auto &p : _pages) p->SaveSetup(); - _winCfg.Save(_cfgOut, _desktopSize); + _winCfg.Save(_cfgOut); } //============================================================================= From 4cff2e3fbafd99454a048cad829ecc36d7358958 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Mon, 27 Jan 2025 12:45:19 +0300 Subject: [PATCH 3/9] WinSetup: add "Start on display" list for selecting display index --- Engine/main/config.cpp | 1 + .../windows/setup/advancedpagedialog.cpp | 14 +++++--- .../windows/setup/basicpagedialog.cpp | 29 +++++++++++++++++ .../platform/windows/setup/basicpagedialog.h | 3 ++ Engine/resource/resource.h | 1 + Engine/resource/version.rc | 32 ++++++++++--------- 6 files changed, 61 insertions(+), 19 deletions(-) diff --git a/Engine/main/config.cpp b/Engine/main/config.cpp index 451d11bb3cd..982b700a836 100644 --- a/Engine/main/config.cpp +++ b/Engine/main/config.cpp @@ -483,6 +483,7 @@ void save_common_config(const GameConfig &setup, ConfigTree &cfg) CfgWriteString(cfg, "misc", "shared_data_dir", setup.AppDataDir); CfgWriteString(cfg, "graphics", "driver", setup.Display.DriverID); + CfgWriteInt(cfg, "graphics", "display", setup.Display.DisplayIndex); CfgWriteString(cfg, "graphics", "filter", setup.Display.Filter.ID); CfgWriteString(cfg, "graphics", "fullscreen", make_window_mode_option(setup.Display.FsSetup)); CfgWriteString(cfg, "graphics", "window", make_window_mode_option(setup.Display.WinSetup)); diff --git a/Engine/platform/windows/setup/advancedpagedialog.cpp b/Engine/platform/windows/setup/advancedpagedialog.cpp index 2185c487837..0683b109159 100644 --- a/Engine/platform/windows/setup/advancedpagedialog.cpp +++ b/Engine/platform/windows/setup/advancedpagedialog.cpp @@ -38,20 +38,18 @@ namespace Engine INT_PTR AdvancedPageDialog::OnInitDialog() { - _hAudioDriverList = GetDlgItem(_hwnd, IDC_DIGISOUND); _hSpriteCacheList = GetDlgItem(_hwnd, IDC_SPRITECACHE); _hTextureCacheList = GetDlgItem(_hwnd, IDC_TEXTURECACHE); - _hSoundCacheList = GetDlgItem(_hwnd, IDC_SOUNDCACHE); _hVSync = GetDlgItem(_hwnd, IDC_VSYNC); _hRenderAtScreenRes = GetDlgItem(_hwnd, IDC_RENDERATSCREENRES); _hAntialiasSprites = GetDlgItem(_hwnd, IDC_ANTIALIAS); + _hAudioDriverList = GetDlgItem(_hwnd, IDC_DIGISOUND); + _hSoundCacheList = GetDlgItem(_hwnd, IDC_SOUNDCACHE); _hUseVoicePack = GetDlgItem(_hwnd, IDC_VOICEPACK); _hMouseLock = GetDlgItem(_hwnd, IDC_MOUSE_AUTOLOCK); _hMouseSpeed = GetDlgItem(_hwnd, IDC_MOUSESPEED); _hMouseSpeedText = GetDlgItem(_hwnd, IDC_MOUSESPEED_TEXT); - SetSliderRange(_hMouseSpeed, MouseSpeedMin, MouseSpeedMax); - // Init sprite cache and texture cache lists // 32-bit programs have accessible RAM limit of 2-3 GB (may be less in practice), // and engine will need RAM for other things too, keep that in mind @@ -60,8 +58,10 @@ INT_PTR AdvancedPageDialog::OnInitDialog() { "256 MB", 256}, { "384 MB", 384}, { "512 MB", 512 }, { "640 MB", 640 }, { "768 MB", 768 }, { "896 MB", 896 }, { "1 GB", 1024 }, }}; + ResetContent(_hSpriteCacheList); for (const auto &val : spr_cache_vals) AddString(_hSpriteCacheList, val.first, val.second); + ResetContent(_hTextureCacheList); for (const auto &val : spr_cache_vals) AddString(_hTextureCacheList, val.first, val.second); #if AGS_PLATFORM_64BIT @@ -78,6 +78,7 @@ INT_PTR AdvancedPageDialog::OnInitDialog() const std::array, 5> sound_cache_vals = { { { "Off", 0 }, { "16 MB", 16 }, { "32 MB", 32 }, { "64 MB", 64 }, { "128 MB", 128 } }}; + ResetContent(_hSoundCacheList); for (const auto &val : sound_cache_vals) AddString(_hSoundCacheList, val.first, val.second); @@ -85,6 +86,8 @@ INT_PTR AdvancedPageDialog::OnInitDialog() if (!File::IsFile("speech.vox")) EnableWindow(_hUseVoicePack, FALSE); + SetSliderRange(_hMouseSpeed, MouseSpeedMin, MouseSpeedMax); + if (CfgReadBoolInt(_cfgIn, "disabled", "speechvox")) EnableWindow(_hUseVoicePack, FALSE); if (CfgReadBoolInt(_cfgIn, "disabled", "antialias")) @@ -136,6 +139,7 @@ void AdvancedPageDialog::FillAudioDriverList() for (const auto &names : drv_names) _drvAudioList.push_back(std::make_pair(names.first, names.second)); // Fill driver data into UI list + ResetContent(_hAudioDriverList); for (const auto &desc : _drvAudioList) AddString(_hAudioDriverList, STR(desc.second), (DWORD_PTR)desc.first.GetCStr()); } @@ -352,6 +356,8 @@ INT_PTR AccessibilityPageDialog::OnInitDialog() const std::array, 4> skip_vals = { { { "Game Default", kSkipSpeechNone }, { "Player Input", kSkipSpeech_AnyInput }, { "Auto (by time)", kSkipSpeechTime }, { "Any", kSkipSpeech_AnyInputOrTime } }}; + ResetContent(_hSpeechSkipStyle); + ResetContent(_hTextSkipStyle); for (const auto &val : skip_vals) { AddString(_hSpeechSkipStyle, val.first, val.second); diff --git a/Engine/platform/windows/setup/basicpagedialog.cpp b/Engine/platform/windows/setup/basicpagedialog.cpp index bcfca0e01a5..3717f2ca740 100644 --- a/Engine/platform/windows/setup/basicpagedialog.cpp +++ b/Engine/platform/windows/setup/basicpagedialog.cpp @@ -106,6 +106,7 @@ void WinConfig::Save(ConfigTree &cfg) const INT_PTR BasicPageDialog::OnInitDialog() { _hGameResolutionText = GetDlgItem(_hwnd, IDC_RESOLUTION); + _hDisplayList = GetDlgItem(_hwnd, IDC_DISPLAYINDEX); _hWindowed = GetDlgItem(_hwnd, IDC_WINDOWED); _hGfxDriverList = GetDlgItem(_hwnd, IDC_GFXDRIVER); _hGfxModeList = GetDlgItem(_hwnd, IDC_GFXMODE); @@ -115,6 +116,7 @@ INT_PTR BasicPageDialog::OnInitDialog() _hGfxFilterList = GetDlgItem(_hwnd, IDC_GFXFILTER); _hLanguageList = GetDlgItem(_hwnd, IDC_LANGUAGE); + _displayIndex = _winCfg.Display.DisplayIndex; _desktopSize = get_desktop_size(_displayIndex); _maxWindowSize = AGSPlatformDriver::GetDriver()->ValidateWindowSize(_displayIndex, _desktopSize, false); @@ -125,6 +127,7 @@ INT_PTR BasicPageDialog::OnInitDialog() SetText(_hGameResolutionText, STR(String::FromFormat("Native game resolution: %d x %d x %d", _winCfg.GameResolution.Width, _winCfg.GameResolution.Height, _winCfg.GameColourDepth))); + FillDisplayList(); FillGfxDriverList(); FillScalingList(_hFsScalingList, false); FillScalingList(_hWinScalingList, true); @@ -165,6 +168,7 @@ INT_PTR BasicPageDialog::OnListSelection(WORD id) { switch (id) { + case IDC_DISPLAYINDEX: OnDisplayUpdate(); break; case IDC_GFXDRIVER: OnGfxDriverUpdate(); break; case IDC_GFXFILTER: OnGfxFilterUpdate(); break; case IDC_GFXMODE: OnGfxModeUpdate(); break; @@ -176,6 +180,12 @@ INT_PTR BasicPageDialog::OnListSelection(WORD id) return TRUE; } +void BasicPageDialog::OnDisplayUpdate() +{ + _displayIndex = GetCurSel(_hDisplayList); + FillGfxModeList(); +} + void BasicPageDialog::OnGfxDriverUpdate() { _winCfg.Display.DriverID = (LPCSTR)GetCurItemData(_hGfxDriverList); @@ -279,6 +289,23 @@ bool BasicPageDialog::GfxModes::GetMode(int index, DisplayMode &mode) const return false; } +void BasicPageDialog::FillDisplayList() +{ + ResetContent(_hDisplayList); + int display_count = SDL_GetNumVideoDisplays(); + for (int i = 0; i < display_count; ++i) + { + const char *disp_name = SDL_GetDisplayName(i); + String item_name = String::FromFormat("%d : %s", i + 1, disp_name ? disp_name : "(unknown)"); + AddString(_hDisplayList, STR(item_name)); + } + + if (display_count <= 1) + { + EnableWindow(_hDisplayList, FALSE); + } +} + void BasicPageDialog::AddScalingString(HWND hlist, int scaling_factor) { String s; @@ -516,6 +543,7 @@ void BasicPageDialog::SelectNearestGfxMode(const WindowSetup &ws) void BasicPageDialog::ResetSetup(const ConfigTree & /*cfg_from*/) { SetCurSelToItemDataStr(_hGfxDriverList, _winCfg.Display.DriverID.GetCStr(), 0); + SetCurSel(_hDisplayList, _winCfg.Display.DisplayIndex); SetCheck(_hFullscreenDesktop, _winCfg.Display.FsSetup.Mode == kWnd_FullDesktop); EnableWindow(_hGfxModeList, _winCfg.Display.FsSetup.Mode == kWnd_Fullscreen); OnGfxDriverUpdate(); @@ -529,6 +557,7 @@ void BasicPageDialog::SaveSetup() if (!_isInit) return; // was not init, don't apply settings + _winCfg.Display.DisplayIndex = GetCurSel(_hDisplayList); if (GetCurSel(_hLanguageList) == 0) _winCfg.Translation.Empty(); else diff --git a/Engine/platform/windows/setup/basicpagedialog.h b/Engine/platform/windows/setup/basicpagedialog.h index d1c6acc2c7e..0aa6c9f8e34 100644 --- a/Engine/platform/windows/setup/basicpagedialog.h +++ b/Engine/platform/windows/setup/basicpagedialog.h @@ -117,6 +117,7 @@ class BasicPageDialog : public WinSetupPageDialog }; // Event handlers + void OnDisplayUpdate(); void OnGfxDriverUpdate(); void OnGfxFilterUpdate(); void OnGfxModeUpdate(); @@ -149,6 +150,7 @@ class BasicPageDialog : public WinSetupPageDialog // Operations void AddScalingString(HWND hlist, int scaling_factor); + void FillDisplayList(); void FillGfxDriverList(); void FillGfxFilterList(); void FillGfxModeList(); @@ -172,6 +174,7 @@ class BasicPageDialog : public WinSetupPageDialog // Dialog controls HWND _hGameResolutionText = NULL; + HWND _hDisplayList = NULL; HWND _hWindowed = NULL; HWND _hGfxDriverList = NULL; HWND _hGfxModeList = NULL; diff --git a/Engine/resource/resource.h b/Engine/resource/resource.h index 42e28e7f57b..ca57187a1e7 100644 --- a/Engine/resource/resource.h +++ b/Engine/resource/resource.h @@ -17,6 +17,7 @@ #define IDC_LANGUAGE 1009 #define IDC_SPRITECACHE 1010 #define IDC_RENDERATSCREENRES 1011 +#define IDC_DISPLAYINDEX 1012 #define IDC_FULLSCREENDESKTOP 1013 #define IDC_TEXTURECACHE 1014 #define IDC_SPRITECACHE3 1015 diff --git a/Engine/resource/version.rc b/Engine/resource/version.rc index 6ce436c3ba8..cba1ee6d210 100644 --- a/Engine/resource/version.rc +++ b/Engine/resource/version.rc @@ -127,28 +127,30 @@ BEGIN PUSHBUTTON "Reset To Defaults",IDRESETTODEFAULTS,229,282,80,14 END -IDD_PAGE_BASIC DIALOGEX 0, 0, 270, 198 +IDD_PAGE_BASIC DIALOGEX 0, 0, 270, 231 STYLE DS_SETFONT | WS_CHILD FONT 8, "Tahoma", 400, 0, 0xCC BEGIN - GROUPBOX "Graphics settings",IDC_GFXOPTIONS,7,7,247,148 + GROUPBOX "Graphics settings",IDC_GFXOPTIONS,7,7,247,178 CONTROL "Game resolution: XXXX x XXXX",IDC_RESOLUTION,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,15,19,161,10 CONTROL "Driver:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,34,35,10 COMBOBOX IDC_GFXDRIVER,50,32,136,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "&Start in a windowed mode",IDC_WINDOWED,"Button",BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER | WS_TABSTOP,14,49,172,9 - CONTROL "Fullscreen mode:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,66,55,8 - COMBOBOX IDC_GFXMODE,75,64,166,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Display:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,51,35,10 + COMBOBOX IDC_DISPLAYINDEX,50,49,136,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "&Start in a windowed mode",IDC_WINDOWED,"Button",BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER | WS_TABSTOP,14,71,172,9 + CONTROL "Fullscreen mode:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,88,55,8 + COMBOBOX IDC_GFXMODE,75,86,166,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Fullscreen as borderless window",IDC_FULLSCREENDESKTOP, - "Button",BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER | WS_TABSTOP,14,83,172,9 - CONTROL "Fullscreen scale:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,102,56,10 - COMBOBOX IDC_FSSCALING,75,100,166,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Windowed scale:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,119,54,10 - COMBOBOX IDC_WINDOWSCALING,75,117,166,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Scaling method:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,136,56,10 - COMBOBOX IDC_GFXFILTER,75,134,166,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Gameplay settings",IDC_STATIC,7,158,247,33 - CONTROL "Game language:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,15,172,56,10 - COMBOBOX IDC_LANGUAGE,71,170,170,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + "Button",BS_AUTOCHECKBOX | BS_LEFT | BS_VCENTER | WS_TABSTOP,14,105,172,9 + CONTROL "Fullscreen scale:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,124,56,10 + COMBOBOX IDC_FSSCALING,75,122,166,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Windowed scale:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,141,54,10 + COMBOBOX IDC_WINDOWSCALING,75,139,166,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Scaling method:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,14,158,56,10 + COMBOBOX IDC_GFXFILTER,75,156,166,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Gameplay settings",IDC_STATIC,7,191,247,33 + CONTROL "Game language:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,15,205,56,10 + COMBOBOX IDC_LANGUAGE,71,203,170,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END IDD_PAGE_ADVANCED DIALOGEX 0, 0, 278, 233 From 6694f69c7d1305477ed99c5d8b7c14638ba3eef3 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Tue, 28 Jan 2025 11:28:31 +0300 Subject: [PATCH 4/9] Engine: bring window to front when displayed mode is initialized This apparently fixes an issue when the window is created on secondary monitor, which already has application windows on. --- Engine/gfx/ali3dogl.cpp | 1 + Engine/gfx/ali3dsw.cpp | 1 + Engine/platform/base/sys_main.cpp | 5 +++++ Engine/platform/base/sys_main.h | 2 ++ Engine/platform/windows/gfx/ali3dd3d.cpp | 1 + 5 files changed, 10 insertions(+) diff --git a/Engine/gfx/ali3dogl.cpp b/Engine/gfx/ali3dogl.cpp index f30a6a543d4..ace4a04c7cf 100644 --- a/Engine/gfx/ali3dogl.cpp +++ b/Engine/gfx/ali3dogl.cpp @@ -249,6 +249,7 @@ bool OGLGraphicsDriver::InitGlScreen(const DisplayMode &mode) sys_window_fit_in_display(mode.DisplayIndex); #endif sys_window_set_style(mode.Mode, Size(mode.Width, mode.Height)); + sys_window_bring_to_front(); } SDL_GL_GetDrawableSize(_sdlWindow, &device_screen_physical_width, &device_screen_physical_height); diff --git a/Engine/gfx/ali3dsw.cpp b/Engine/gfx/ali3dsw.cpp index 364d97f86cc..68e860a0a0f 100644 --- a/Engine/gfx/ali3dsw.cpp +++ b/Engine/gfx/ali3dsw.cpp @@ -185,6 +185,7 @@ bool SDLRendererGraphicsDriver::SetDisplayMode(const DisplayMode &mode) } #endif // AGS_PLATFORM_DESKTOP sys_window_set_style(mode.Mode, Size(mode.Width, mode.Height)); + sys_window_bring_to_front(); } #if AGS_PLATFORM_MOBILE diff --git a/Engine/platform/base/sys_main.cpp b/Engine/platform/base/sys_main.cpp index 1de858375d3..ca9879f4c69 100644 --- a/Engine/platform/base/sys_main.cpp +++ b/Engine/platform/base/sys_main.cpp @@ -261,6 +261,11 @@ void sys_window_set_style(WindowMode mode, Size size) { } } +void sys_window_bring_to_front() { + if (!window) return; + SDL_RaiseWindow(window); +} + void sys_window_show_cursor(bool on) { SDL_ShowCursor(on ? SDL_ENABLE : SDL_DISABLE); } diff --git a/Engine/platform/base/sys_main.h b/Engine/platform/base/sys_main.h index 5fdca01cde2..49f01ec9134 100644 --- a/Engine/platform/base/sys_main.h +++ b/Engine/platform/base/sys_main.h @@ -66,6 +66,8 @@ SDL_Window *sys_window_create(const char *window_title, int display_index, int w SDL_Window *sys_get_window(); // Changes the window style for the given mode (fullscreen / windowed). void sys_window_set_style(AGS::Engine::WindowMode mode, Size size = Size()); +// Brings the game window to front +void sys_window_bring_to_front(); // Set new window size; optionally center new window on screen bool sys_window_set_size(int w, int h, bool center); // Centers the window on screen, optionally choose the display to position on diff --git a/Engine/platform/windows/gfx/ali3dd3d.cpp b/Engine/platform/windows/gfx/ali3dd3d.cpp index b3d5e167c66..31c6d22a640 100644 --- a/Engine/platform/windows/gfx/ali3dd3d.cpp +++ b/Engine/platform/windows/gfx/ali3dd3d.cpp @@ -566,6 +566,7 @@ bool D3DGraphicsDriver::CreateDisplayMode(const DisplayMode &mode) if (!mode.IsRealFullscreen()) { sys_window_set_style(mode.Mode, Size(mode.Width, mode.Height)); + sys_window_bring_to_front(); } } return true; From 36fa735030b73adebcc7c2c0a2202d1f1afd4f80 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Tue, 28 Jan 2025 12:57:58 +0300 Subject: [PATCH 5/9] Engine: store display index 1-based in config, 0 means "default" --- Engine/gfx/gfxdefines.h | 2 +- Engine/main/config.cpp | 7 +++++-- Engine/main/engine.cpp | 2 +- Engine/main/graphics_mode.cpp | 8 ++++---- Engine/main/graphics_mode.h | 11 ++++++----- Engine/platform/windows/setup/basicpagedialog.cpp | 15 ++++++++++++--- Engine/platform/windows/setup/basicpagedialog.h | 1 + 7 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Engine/gfx/gfxdefines.h b/Engine/gfx/gfxdefines.h index d7d970721dd..60e4aae5855 100644 --- a/Engine/gfx/gfxdefines.h +++ b/Engine/gfx/gfxdefines.h @@ -50,7 +50,7 @@ enum WindowMode struct DisplayMode : public GraphicResolution { WindowMode Mode = kWnd_Windowed; - int DisplayIndex = 0; // which display to use (0 - default) + int DisplayIndex = 0; // 0-based display index int RefreshRate = 0; bool Vsync = false; diff --git a/Engine/main/config.cpp b/Engine/main/config.cpp index 982b700a836..48e8a1fb1ed 100644 --- a/Engine/main/config.cpp +++ b/Engine/main/config.cpp @@ -361,7 +361,9 @@ void load_common_config(const ConfigTree &cfg, GameConfig &setup) // Graphics mode and options setup.Display.DriverID = CfgReadString(cfg, "graphics", "driver", setup.Display.DriverID); - setup.Display.DisplayIndex = CfgReadInt(cfg, "graphics", "display", 0); + const int user_display_index = CfgReadInt(cfg, "graphics", "display", 0); + setup.Display.UseDefaultDisplay = user_display_index <= 0; + setup.Display.DisplayIndex = user_display_index <= 0 ? 0 : user_display_index - 1; setup.Display.Windowed = CfgReadBoolInt(cfg, "graphics", "windowed", setup.Display.Windowed); setup.Display.FsSetup = parse_window_mode(CfgReadString(cfg, "graphics", "fullscreen", "default"), false, @@ -483,7 +485,8 @@ void save_common_config(const GameConfig &setup, ConfigTree &cfg) CfgWriteString(cfg, "misc", "shared_data_dir", setup.AppDataDir); CfgWriteString(cfg, "graphics", "driver", setup.Display.DriverID); - CfgWriteInt(cfg, "graphics", "display", setup.Display.DisplayIndex); + CfgWriteInt(cfg, "graphics", "display", (setup.Display.UseDefaultDisplay) ? + 0 : setup.Display.DisplayIndex + 1); CfgWriteString(cfg, "graphics", "filter", setup.Display.Filter.ID); CfgWriteString(cfg, "graphics", "fullscreen", make_window_mode_option(setup.Display.FsSetup)); CfgWriteString(cfg, "graphics", "window", make_window_mode_option(setup.Display.WinSetup)); diff --git a/Engine/main/engine.cpp b/Engine/main/engine.cpp index 7bd6e684cb6..d6a0c659154 100644 --- a/Engine/main/engine.cpp +++ b/Engine/main/engine.cpp @@ -1386,7 +1386,7 @@ bool engine_try_switch_windowed_gfxmode() WindowSetup ws = windowed ? usetup.Display.WinSetup : usetup.Display.FsSetup; frame = windowed ? usetup.Display.WinGameFrame : usetup.Display.FsGameFrame; res = graphics_mode_set_dm_any(game.GetGameRes(), ws, old_dm.ColorDepth, - frame, DisplaySetupEx(use_display_index, usetup.Display.RefreshRate, usetup.Display.VSync)); + frame, DisplayParamsEx(use_display_index, usetup.Display.RefreshRate, usetup.Display.VSync)); } // Apply corresponding frame render method diff --git a/Engine/main/graphics_mode.cpp b/Engine/main/graphics_mode.cpp index 7b9b1765fe0..45c6cfa4ac2 100644 --- a/Engine/main/graphics_mode.cpp +++ b/Engine/main/graphics_mode.cpp @@ -295,7 +295,7 @@ bool try_init_compatible_mode(const DisplayMode &dm) static bool try_init_mode_using_setup(const GraphicResolution &game_res, const WindowSetup &ws, const int col_depth, const FrameScaleDef frame, const GfxFilterSetup &filter, - const DisplaySetupEx ¶ms) + const DisplayParamsEx ¶ms) { // We determine the requested size of the screen using setup options const Size screen_size = precalc_screen_size(game_res, params.DisplayIndex, ws, frame); @@ -362,14 +362,14 @@ bool create_gfx_driver_and_init_mode_any(const String &gfx_driver_id, bool windowed = setup.Windowed; WindowSetup ws = windowed ? setup.WinSetup : setup.FsSetup; FrameScaleDef frame = windowed ? setup.WinGameFrame : setup.FsGameFrame; - bool result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, DisplaySetupEx(setup.DisplayIndex, setup.RefreshRate, setup.VSync)); + bool result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, DisplayParamsEx(setup.DisplayIndex, setup.RefreshRate, setup.VSync)); // Try windowed mode if fullscreen failed, and vice versa if (!result && editor_debugging_initialized == 0) { windowed = !windowed; ws = windowed ? setup.WinSetup : setup.FsSetup; frame = windowed ? setup.WinGameFrame : setup.FsGameFrame; - result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, DisplaySetupEx(setup.DisplayIndex, setup.RefreshRate, setup.VSync)); + result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, DisplayParamsEx(setup.DisplayIndex, setup.RefreshRate, setup.VSync)); } return result; } @@ -499,7 +499,7 @@ bool graphics_mode_create_renderer(const String &driver_id) bool graphics_mode_set_dm_any(const Size &game_size, const WindowSetup &ws, const ColorDepthOption &color_depth, - const FrameScaleDef frame, const DisplaySetupEx ¶ms) + const FrameScaleDef frame, const DisplayParamsEx ¶ms) { // We determine the requested size of the screen using setup options const Size screen_size = precalc_screen_size(game_size, params.DisplayIndex, ws, frame); diff --git a/Engine/main/graphics_mode.h b/Engine/main/graphics_mode.h index 3d1606d1bf4..e3e1badfeb9 100644 --- a/Engine/main/graphics_mode.h +++ b/Engine/main/graphics_mode.h @@ -93,13 +93,13 @@ struct WindowSetup }; // Additional parameters for the display mode setup -struct DisplaySetupEx +struct DisplayParamsEx { - int DisplayIndex = 0; // which display to use (0 - default) + int DisplayIndex = 0; // 0-based display index int RefreshRate = 0; // gfx mode refresh rate bool VSync = false; // vertical sync - DisplaySetupEx(int display_index, int rate, bool vsync) + DisplayParamsEx(int display_index, int rate, bool vsync) : DisplayIndex(display_index), RefreshRate(rate), VSync(vsync) {} }; @@ -119,7 +119,8 @@ struct DisplayModeSetup FrameScaleDef WinGameFrame = // how the game frame should be scaled/positioned in windowed mode kFrame_Undefined; - int DisplayIndex = 0; // which display to use (0 - default) + bool UseDefaultDisplay = true; // used when writing config back + int DisplayIndex = 0; // 0-based display index bool Windowed = false; // initial mode int RefreshRate = 0; // gfx mode refresh rate bool VSync = false; // vertical sync @@ -155,7 +156,7 @@ bool graphics_mode_create_renderer(const String &driver_id); // Try to find and initialize compatible display mode as close to given setup as possible bool graphics_mode_set_dm_any(const Size &game_size, const WindowSetup &ws, const ColorDepthOption &color_depth, - const FrameScaleDef frame, const DisplaySetupEx ¶ms); + const FrameScaleDef frame, const DisplayParamsEx ¶ms); // Set the display mode with given parameters bool graphics_mode_set_dm(const AGS::Engine::DisplayMode &dm); // Set the native image size diff --git a/Engine/platform/windows/setup/basicpagedialog.cpp b/Engine/platform/windows/setup/basicpagedialog.cpp index 3717f2ca740..a3bb9ce5db7 100644 --- a/Engine/platform/windows/setup/basicpagedialog.cpp +++ b/Engine/platform/windows/setup/basicpagedialog.cpp @@ -182,7 +182,7 @@ INT_PTR BasicPageDialog::OnListSelection(WORD id) void BasicPageDialog::OnDisplayUpdate() { - _displayIndex = GetCurSel(_hDisplayList); + _displayIndex = GetRealDisplayIndex(); FillGfxModeList(); } @@ -292,6 +292,7 @@ bool BasicPageDialog::GfxModes::GetMode(int index, DisplayMode &mode) const void BasicPageDialog::FillDisplayList() { ResetContent(_hDisplayList); + AddString(_hDisplayList, "Default"); int display_count = SDL_GetNumVideoDisplays(); for (int i = 0; i < display_count; ++i) { @@ -430,6 +431,12 @@ void BasicPageDialog::FillScalingList(HWND hlist, bool windowed) } } +int BasicPageDialog::GetRealDisplayIndex() +{ + const int user_display_sel = GetCurSel(_hDisplayList); + return user_display_sel == 0 ? 0 : user_display_sel - 1; +} + void BasicPageDialog::SetScalingSelection() { SetCurSelToItemData(_hFsScalingList, _winCfg.Display.FsGameFrame, NULL, 0); @@ -543,7 +550,7 @@ void BasicPageDialog::SelectNearestGfxMode(const WindowSetup &ws) void BasicPageDialog::ResetSetup(const ConfigTree & /*cfg_from*/) { SetCurSelToItemDataStr(_hGfxDriverList, _winCfg.Display.DriverID.GetCStr(), 0); - SetCurSel(_hDisplayList, _winCfg.Display.DisplayIndex); + SetCurSel(_hDisplayList, _winCfg.Display.UseDefaultDisplay ? 0 : _winCfg.Display.DisplayIndex + 1); SetCheck(_hFullscreenDesktop, _winCfg.Display.FsSetup.Mode == kWnd_FullDesktop); EnableWindow(_hGfxModeList, _winCfg.Display.FsSetup.Mode == kWnd_Fullscreen); OnGfxDriverUpdate(); @@ -557,7 +564,9 @@ void BasicPageDialog::SaveSetup() if (!_isInit) return; // was not init, don't apply settings - _winCfg.Display.DisplayIndex = GetCurSel(_hDisplayList); + const int user_display_index = GetCurSel(_hDisplayList); + _winCfg.Display.UseDefaultDisplay = user_display_index == 0; + _winCfg.Display.DisplayIndex = user_display_index == 0 ? 0 : user_display_index - 1; if (GetCurSel(_hLanguageList) == 0) _winCfg.Translation.Empty(); else diff --git a/Engine/platform/windows/setup/basicpagedialog.h b/Engine/platform/windows/setup/basicpagedialog.h index 0aa6c9f8e34..cbe0f50454b 100644 --- a/Engine/platform/windows/setup/basicpagedialog.h +++ b/Engine/platform/windows/setup/basicpagedialog.h @@ -156,6 +156,7 @@ class BasicPageDialog : public WinSetupPageDialog void FillGfxModeList(); void FillLanguageList(); void FillScalingList(HWND hlist, bool windowed); + int GetRealDisplayIndex(); void SetScalingSelection(); void InitDriverDescFromFactory(const String &id); void SelectNearestGfxMode(const WindowSetup &ws); From 1e7915a2e87b9cb3a4509aa9baed0ea86d81fccc Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Tue, 28 Jan 2025 11:42:37 +0300 Subject: [PATCH 6/9] Engine: implemented "--display X" command line argument This is a 1-based display index, where 0 would mean "use defaults". --- Engine/main/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Engine/main/main.cpp b/Engine/main/main.cpp index cd063048fb5..8875af3221b 100644 --- a/Engine/main/main.cpp +++ b/Engine/main/main.cpp @@ -115,6 +115,7 @@ void main_print_help() { #if AGS_PLATFORM_OS_WINDOWS " --console-attach Write output to the parent process's console\n" #endif + " --display 1-based index of system display to start the game on.\n" " --fps Display fps counter\n" " --fullscreen Force display mode to fullscreen\n" " --gfxdriver Request graphics driver. Available options:\n" @@ -318,6 +319,8 @@ static int main_process_cmdline(ConfigTree &cfg, int argc, char *argv[]) } } } + else if ((ags_stricmp(arg, "--display") == 0) && (argc > ee + 1)) + cfg["graphics"]["display"] = argv[++ee]; else if ((ags_stricmp(arg, "--translation") == 0) && (argc > ee + 1)) cfg["language"]["translation"] = argv[++ee]; else if (ags_stricmp(arg, "--no-translation") == 0) From 298db1475551872430e107bb30dc8439da7e6f0c Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Tue, 28 Jan 2025 13:05:53 +0300 Subject: [PATCH 7/9] OPTIONS.md: added "display" config option and cmd arg --- OPTIONS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OPTIONS.md b/OPTIONS.md index 17594bbe28a..40f4a4b789b 100644 --- a/OPTIONS.md +++ b/OPTIONS.md @@ -27,6 +27,7 @@ Locations of two latter files differ between running platforms: * Software - software renderer. * software_driver = \[string\] - *optional* id of the SDL2 driver to use for the final output in software mode, leave empty for default. IDs are provided by SDL2, not all of these will work on any system: * direct3d, opengl, opengles, opengles2, metal, software. + * display = \[number\] - *1-based* index of system display to start the game on; 0 means "use defaults". * fullscreen = \[string\] - a fullscreen mode definition, which may be one of the following: * WxH - explicit window size (e.g. `1280x720`); * xS - integer game scaling factor (e.g. `x4`); @@ -157,6 +158,7 @@ Following OPTIONS are supported when running from command line: * --clear-cache-on-room-change - clears sprite cache on every room change. * --conf \ - specify explicit config file to read on startup. * --console-attach - write output to the parent process's console (Windows only). +* --display \ - *1-based* index of system display to start the game on; 0 means "use defaults". * --fps - display fps counter. * --fullscreen - run in fullscreen mode. * --gfxdriver \ - use specified graphics driver: From b35939dbb9ff5ac07584733d3814c99ed4234817 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Tue, 28 Jan 2025 22:28:50 +0300 Subject: [PATCH 8/9] WinSetup: properly update list of graphic modes after changing display --- .../windows/setup/basicpagedialog.cpp | 50 ++++++++++++++++--- .../platform/windows/setup/basicpagedialog.h | 9 ++++ Engine/platform/windows/setup/windialog.cpp | 2 + Engine/platform/windows/setup/windialog.h | 1 + 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/Engine/platform/windows/setup/basicpagedialog.cpp b/Engine/platform/windows/setup/basicpagedialog.cpp index a3bb9ce5db7..bc65f71599f 100644 --- a/Engine/platform/windows/setup/basicpagedialog.cpp +++ b/Engine/platform/windows/setup/basicpagedialog.cpp @@ -152,6 +152,12 @@ INT_PTR BasicPageDialog::OnInitDialog() return FALSE; // notify WinAPI that we set focus ourselves } +INT_PTR BasicPageDialog::OnDestroyDialog() +{ + ReleaseDrivers(); + return FALSE; +} + INT_PTR BasicPageDialog::OnCommand(WORD id) { switch (id) @@ -183,6 +189,10 @@ INT_PTR BasicPageDialog::OnListSelection(WORD id) void BasicPageDialog::OnDisplayUpdate() { _displayIndex = GetRealDisplayIndex(); + _desktopSize = get_desktop_size(_displayIndex); + _maxWindowSize = AGSPlatformDriver::GetDriver()->ValidateWindowSize(_displayIndex, _desktopSize, false); + + UpdateDriverModesFromFactory(); FillGfxModeList(); } @@ -469,13 +479,38 @@ void BasicPageDialog::InitDriverDescFromFactory(const String &id) } PDriverDesc drv_desc(new DriverDesc()); + drv_desc->Factory = gfx_factory; + drv_desc->Driver = gfx_driver; drv_desc->Id = gfx_driver->GetDriverID(); drv_desc->UserName = gfx_driver->GetDriverName(); drv_desc->UseColorDepth = gfx_driver->GetDisplayDepthForNativeDepth(_winCfg.GameColourDepth ? _winCfg.GameColourDepth : 32); + UpdateDriverModes(drv_desc.get()); + + drv_desc->FilterList.resize(gfx_factory->GetFilterCount()); + for (size_t i = 0; i < drv_desc->FilterList.size(); ++i) + { + drv_desc->FilterList[i] = *gfx_factory->GetFilterInfo(i); + } + + _drvDescMap[drv_desc->Id] = drv_desc; +} + +void BasicPageDialog::UpdateDriverModesFromFactory() +{ + for (auto &drv_desc : _drvDescMap) + { + UpdateDriverModes(drv_desc.second.get()); + } +} + +void BasicPageDialog::UpdateDriverModes(DriverDesc *drv_desc) +{ + IGraphicsDriver *gfx_driver = drv_desc->Driver; IGfxModeList *gfxm_list = gfx_driver->GetSupportedModeList(_displayIndex, drv_desc->UseColorDepth); VDispModes &modes = drv_desc->GfxModeList.Modes; + modes.clear(); if (gfxm_list) { std::set unique_sizes; // trying to hide modes which only have different refresh rates @@ -497,15 +532,14 @@ void BasicPageDialog::InitDriverDescFromFactory(const String &id) modes.push_back(DisplayMode(GraphicResolution(_desktopSize.Width, _desktopSize.Height, drv_desc->UseColorDepth))); modes.push_back(DisplayMode(GraphicResolution(_winCfg.GameResolution.Width, _winCfg.GameResolution.Height, drv_desc->UseColorDepth))); } +} - drv_desc->FilterList.resize(gfx_factory->GetFilterCount()); - for (size_t i = 0; i < drv_desc->FilterList.size(); ++i) - { - drv_desc->FilterList[i] = *gfx_factory->GetFilterInfo(i); - } - - gfx_factory->Shutdown(); - _drvDescMap[drv_desc->Id] = drv_desc; +void BasicPageDialog::ReleaseDrivers() +{ + _drvDesc = nullptr; + for (auto &drv_desc : _drvDescMap) + drv_desc.second->Factory->Shutdown(); + _drvDescMap = {}; } void BasicPageDialog::SelectNearestGfxMode(const WindowSetup &ws) diff --git a/Engine/platform/windows/setup/basicpagedialog.h b/Engine/platform/windows/setup/basicpagedialog.h index cbe0f50454b..c17ebba3e4b 100644 --- a/Engine/platform/windows/setup/basicpagedialog.h +++ b/Engine/platform/windows/setup/basicpagedialog.h @@ -37,6 +37,9 @@ namespace Engine using namespace AGS::Common; +class IGfxDriverFactory; +class IGraphicsDriver; + //============================================================================= // // WinConfig struct, keeps all configurable data. @@ -105,6 +108,7 @@ class BasicPageDialog : public WinSetupPageDialog // Event handlers INT_PTR OnInitDialog() override; + INT_PTR OnDestroyDialog() override; INT_PTR OnCommand(WORD id) override; INT_PTR OnListSelection(WORD id) override; @@ -141,6 +145,8 @@ class BasicPageDialog : public WinSetupPageDialog typedef std::vector VFilters; struct DriverDesc { + IGfxDriverFactory *Factory = nullptr; + IGraphicsDriver *Driver = nullptr; String Id; // internal id String UserName; // human-friendly driver name GfxModes GfxModeList; // list of supported modes @@ -159,6 +165,9 @@ class BasicPageDialog : public WinSetupPageDialog int GetRealDisplayIndex(); void SetScalingSelection(); void InitDriverDescFromFactory(const String &id); + void UpdateDriverModesFromFactory(); + void UpdateDriverModes(DriverDesc *desc); + void ReleaseDrivers(); void SelectNearestGfxMode(const WindowSetup &ws); // Dialog properties diff --git a/Engine/platform/windows/setup/windialog.cpp b/Engine/platform/windows/setup/windialog.cpp index b54f510f3d3..23d9876bdeb 100644 --- a/Engine/platform/windows/setup/windialog.cpp +++ b/Engine/platform/windows/setup/windialog.cpp @@ -106,6 +106,8 @@ INT_PTR WinDialog::OnDialogEvent(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/) { case WM_INITDIALOG: return OnInitDialog(); + case WM_DESTROY: + return OnDestroyDialog(); case WM_COMMAND: if (HIWORD(wParam) == CBN_SELCHANGE) return OnListSelection(LOWORD(wParam)); diff --git a/Engine/platform/windows/setup/windialog.h b/Engine/platform/windows/setup/windialog.h index 23241a86f83..374122348e4 100644 --- a/Engine/platform/windows/setup/windialog.h +++ b/Engine/platform/windows/setup/windialog.h @@ -56,6 +56,7 @@ class WinDialog // Event handlers virtual INT_PTR OnDialogEvent(UINT uMsg, WPARAM wParam, LPARAM lParam); virtual INT_PTR OnInitDialog() { return FALSE; /* do nothing */ } + virtual INT_PTR OnDestroyDialog() { return FALSE; /* do nothing */ } virtual INT_PTR OnCommand(WORD id) { return FALSE; /* do nothing */ } virtual INT_PTR OnListSelection(WORD id) { return FALSE; /* do nothing */ } From 55361748f8262dbedcbff56a967f643d180fe4f1 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Wed, 29 Jan 2025 00:46:50 +0300 Subject: [PATCH 9/9] Engine: define AGS_SUPPORT_MULTIDISPLAY flag for displays-related code --- Common/core/platform.h | 1 + Engine/gfx/ali3dogl.cpp | 2 +- Engine/gfx/ali3dsw.cpp | 4 ++-- Engine/platform/base/sys_main.cpp | 14 +++++++------- Engine/platform/windows/gfx/ali3dd3d.cpp | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Common/core/platform.h b/Common/core/platform.h index f890f7b1be3..eeafd2758e8 100644 --- a/Common/core/platform.h +++ b/Common/core/platform.h @@ -165,6 +165,7 @@ AGS_PLATFORM_OS_MACOS) #define AGS_PLATFORM_MOBILE ((AGS_PLATFORM_OS_ANDROID) || (AGS_PLATFORM_OS_IOS)) +#define AGS_SUPPORT_MULTIDISPLAY (AGS_PLATFORM_DESKTOP) #define AGS_HAS_DIRECT3D (AGS_PLATFORM_OS_WINDOWS) #define AGS_HAS_OPENGL (AGS_PLATFORM_OS_WINDOWS || \ AGS_PLATFORM_OS_ANDROID || \ diff --git a/Engine/gfx/ali3dogl.cpp b/Engine/gfx/ali3dogl.cpp index ace4a04c7cf..51d93e4b799 100644 --- a/Engine/gfx/ali3dogl.cpp +++ b/Engine/gfx/ali3dogl.cpp @@ -245,7 +245,7 @@ bool OGLGraphicsDriver::InitGlScreen(const DisplayMode &mode) } else { -#if (AGS_PLATFORM_DESKTOP) +#if (AGS_SUPPORT_MULTIDISPLAY) sys_window_fit_in_display(mode.DisplayIndex); #endif sys_window_set_style(mode.Mode, Size(mode.Width, mode.Height)); diff --git a/Engine/gfx/ali3dsw.cpp b/Engine/gfx/ali3dsw.cpp index 68e860a0a0f..1d48984412a 100644 --- a/Engine/gfx/ali3dsw.cpp +++ b/Engine/gfx/ali3dsw.cpp @@ -173,7 +173,7 @@ bool SDLRendererGraphicsDriver::SetDisplayMode(const DisplayMode &mode) } else { -#if (AGS_PLATFORM_DESKTOP) +#if (AGS_SUPPORT_MULTIDISPLAY) // This is a bit of a hack, but certain drivers do not support changing // display in exclusive fullscreen mode, and here we find out if it's the case. // NOTE: we may in theory support this, but we'd have to release and recreate @@ -183,7 +183,7 @@ bool SDLRendererGraphicsDriver::SetDisplayMode(const DisplayMode &mode) { sys_window_fit_in_display(_fullscreenDisplay); } -#endif // AGS_PLATFORM_DESKTOP +#endif // AGS_SUPPORT_MULTIDISPLAY sys_window_set_style(mode.Mode, Size(mode.Width, mode.Height)); sys_window_bring_to_front(); } diff --git a/Engine/platform/base/sys_main.cpp b/Engine/platform/base/sys_main.cpp index ca9879f4c69..47329ddf2b0 100644 --- a/Engine/platform/base/sys_main.cpp +++ b/Engine/platform/base/sys_main.cpp @@ -74,7 +74,7 @@ void sys_set_background_mode(bool /*on*/) { const int DEFAULT_DISPLAY_INDEX = 0; int sys_get_window_display_index() { -#if (AGS_PLATFORM_DESKTOP) +#if (AGS_SUPPORT_MULTIDISPLAY) int index = -1; SDL_Window *window = sys_get_window(); if (window) @@ -205,7 +205,7 @@ SDL_Window *sys_window_create(const char *window_title, int display_index, int w #if (AGS_PLATFORM_OS_IOS) flags |= SDL_WINDOW_ALLOW_HIGHDPI; #endif -#if !(AGS_PLATFORM_DESKTOP) +#if !(AGS_SUPPORT_MULTIDISPLAY) // Force displays setting to default on non-desktop platforms assert(display_index == DEFAULT_DISPLAY_INDEX); display_index = DEFAULT_DISPLAY_INDEX; @@ -218,7 +218,7 @@ SDL_Window *sys_window_create(const char *window_title, int display_index, int w h, flags ); -#if (AGS_PLATFORM_DESKTOP) +#if (AGS_SUPPORT_MULTIDISPLAY) // CHECKME: this is done because SDL2 has some bug(s) during // centering. See: https://github.com/libsdl-org/SDL/issues/6875 // TODO: SDL2 docs mentioned that on some systems the window border size @@ -318,7 +318,7 @@ bool sys_window_set_size(int w, int h, bool center) { void sys_window_center(int display_index) { if (!window) return; -#if (AGS_PLATFORM_DESKTOP) +#if (AGS_SUPPORT_MULTIDISPLAY) if (display_index < 0) display_index = SDL_GetWindowDisplayIndex(window); // CHECKME: @@ -338,7 +338,7 @@ void sys_window_center(int display_index) { int x = bounds.x + bx1 + (bounds.w - (w + bx1 + bx2)) / 2; int y = bounds.y + by1 + (bounds.h - (h + by1 + by2)) / 2; SDL_SetWindowPosition(window, x, y); -#else // !AGS_PLATFORM_DESKTOP +#else // !AGS_SUPPORT_MULTIDISPLAY SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); #endif } @@ -346,7 +346,7 @@ void sys_window_center(int display_index) { void sys_window_fit_in_display(int display_index) { if (!window) return; -#if (AGS_PLATFORM_DESKTOP) +#if (AGS_SUPPORT_MULTIDISPLAY) SDL_Rect bounds; if (SDL_GetDisplayUsableBounds(display_index, &bounds) != 0) return; @@ -356,7 +356,7 @@ void sys_window_fit_in_display(int display_index) { SDL_SetWindowSize(window, std::min(bounds.w, w), std::min(bounds.h, h)); } sys_window_center(display_index); -#else // !AGS_PLATFORM_DESKTOP +#else // !AGS_SUPPORT_MULTIDISPLAY // Dummy implementation for the time being SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); #endif diff --git a/Engine/platform/windows/gfx/ali3dd3d.cpp b/Engine/platform/windows/gfx/ali3dd3d.cpp index 31c6d22a640..52762f5b9ab 100644 --- a/Engine/platform/windows/gfx/ali3dd3d.cpp +++ b/Engine/platform/windows/gfx/ali3dd3d.cpp @@ -490,7 +490,7 @@ bool D3DGraphicsDriver::CreateDisplayMode(const DisplayMode &mode) } else { -#if (AGS_PLATFORM_DESKTOP) +#if (AGS_SUPPORT_MULTIDISPLAY) // If user requested an exclusive fullscreen, move window to where we created it first, // because DirectX does not normally support switching displays in exclusive mode. // NOTE: we may in theory support this, but we'd have to release and recreate