mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
win32/vulkan: a borderless fullscreen toggle keeps its window and its drivers
Toggling fullscreen restarted everything. The log of one F press on Windows with Vulkan: the video thread stopped and started, the device and the shader chain rebuilt, the audio driver closed and reopened its pin, the input and joypad drivers freed and started, the controller detected and configured again, and the window destroyed and created. For exclusive fullscreen the window has to go, since the display mode changes under it. For borderless fullscreen - Windowed Fullscreen, the default - the only thing that differs between the two states is the window's style, position and size. win32_window_set_fullscreen() changes those on the window that is there: the style, the menu bar (which belongs to the windowed state), and a position and size worked out the way a new window's are. Going windowed, the window returns to where it stood before it went fullscreen, to the saved position if positions are saved, or to the middle of its monitor if it has never been windowed. The video driver hears of it as it hears of any resize, through WM_SIZE, and rebuilds its swapchain for the new size. Exclusive fullscreen is refused and left to the restart. It runs through the path that already exists for changing the video mode: the toggle calls video_driver_set_video_mode(), the threaded video wrapper carries that to the thread that owns the window, and the Windows Vulkan context, finding a window already up, restyles it instead of creating another. A context says it can do this with GFX_CTX_FLAGS_FULLSCREEN_IN_PLACE; the toggle uses it when Windowed Fullscreen is on and the context has the flag, and restarts the drivers as before otherwise. Only the Windows Vulkan context has it so far. The size a window is asked for was worked out inside video_driver_init_internal(); that is video_driver_window_size() now, so the toggle asks for the size a restart would have. samples/gfx/win32_window_proc drives it on a real window under Wine: twenty toggles on one window, which must stay the same window, wear the right style, be the monitor's size when fullscreen and the asked size when windowed, and raise a resize each time; and exclusive fullscreen must be refused. The stand-in video state gets a core geometry for this - without one the window code limits a window to a width too small to hold it - and the recorded trace of the old window procedures is unchanged by that. Compiled for Windows with mingw (win32_common.c, the Vulkan context and driver, video_driver.c, retroarch.c). Not run on Windows, and the Wine test has no GPU in it: what the Vulkan driver does when its window changes size under it this way is the same code as a resize by hand, but has not been seen with this.
This commit is contained in:
1 parent
8aacd31c22
commit
35f2d183dc
11 files changed
+384
-110
No files matched your search
@@ -2138,6 +2138,104 @@ bool win32_set_video_mode(void *data,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Takes the window that is already there between windowed and
|
||||
* borderless fullscreen: its style, position and size change, and it
|
||||
* stays the same window.
|
||||
*
|
||||
* A fullscreen toggle used to mean a full driver restart - window,
|
||||
* video device, shaders, audio, input drivers, controllers detected
|
||||
* again - because the only way to a window of the other kind was to
|
||||
* destroy this one and create another. For a borderless fullscreen
|
||||
* window nothing but the window differs. The size it ends up with
|
||||
* reaches the video driver as any resize does, through WM_SIZE.
|
||||
*
|
||||
* Not for exclusive fullscreen, which changes the display mode: that
|
||||
* answers false and is left to the restart.
|
||||
*
|
||||
* Has to run on the thread that owns the window; a video driver's
|
||||
* set_video_mode does. */
|
||||
bool win32_window_set_fullscreen(unsigned dims, bool fullscreen)
|
||||
{
|
||||
DWORD style;
|
||||
RECT mon_rect;
|
||||
RECT rect;
|
||||
MONITORINFOEX current_mon;
|
||||
int x, y;
|
||||
unsigned width = VIDEO_SCALE_W(dims);
|
||||
unsigned height = VIDEO_SCALE_H(dims);
|
||||
unsigned mon_id = 0;
|
||||
HMONITOR hm_to_use = NULL;
|
||||
HWND hwnd = main_window.hwnd;
|
||||
settings_t *settings = config_get_ptr();
|
||||
win32_common_state_t *g_win32 = (win32_common_state_t*)&win32_st;
|
||||
/* where the window stood before it last went fullscreen */
|
||||
static RECT windowed_rect;
|
||||
static HWND windowed_rect_of;
|
||||
|
||||
if (!hwnd || !settings->bools.video_windowed_fullscreen)
|
||||
return false;
|
||||
|
||||
/* fullscreen on the monitor the window is on, as a restart has it */
|
||||
win32_monitor_last = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
win32_monitor_info(¤t_mon, &hm_to_use, &mon_id);
|
||||
mon_rect = current_mon.rcMonitor;
|
||||
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = 0;
|
||||
rect.bottom = 0;
|
||||
|
||||
if (fullscreen && !(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_POPUP))
|
||||
{
|
||||
GetWindowRect(hwnd, &windowed_rect);
|
||||
windowed_rect_of = hwnd;
|
||||
}
|
||||
|
||||
win32_set_style(¤t_mon, &hm_to_use, &width, &height,
|
||||
fullscreen, true, &rect, &mon_rect, &style);
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
/* the menu bar belongs to the windowed state */
|
||||
HMENU menu = GetMenu(hwnd);
|
||||
if (menu)
|
||||
{
|
||||
SetMenu(hwnd, NULL);
|
||||
DestroyMenu(menu);
|
||||
}
|
||||
x = mon_rect.left;
|
||||
y = mon_rect.top;
|
||||
}
|
||||
else if (g_win32->pos_set)
|
||||
{
|
||||
x = VIDEO_POS_X(g_win32->pos);
|
||||
y = VIDEO_POS_Y(g_win32->pos);
|
||||
}
|
||||
else if (windowed_rect_of == hwnd)
|
||||
{
|
||||
x = windowed_rect.left;
|
||||
y = windowed_rect.top;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* never windowed yet: the middle of its monitor */
|
||||
x = mon_rect.left + ((mon_rect.right - mon_rect.left) - (int)width) / 2;
|
||||
y = mon_rect.top + ((mon_rect.bottom - mon_rect.top) - (int)height) / 2;
|
||||
if (x < mon_rect.left)
|
||||
x = mon_rect.left;
|
||||
if (y < mon_rect.top)
|
||||
y = mon_rect.top;
|
||||
}
|
||||
|
||||
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_VISIBLE);
|
||||
SetWindowPos(hwnd, HWND_TOP, x, y, width, height,
|
||||
SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
|
||||
|
||||
win32_set_window(&width, &height, fullscreen, true, &rect);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool win32_get_client_rect(RECT* rect)
|
||||
|
||||
@@ -105,6 +105,11 @@ bool win32_set_video_mode(void *data,
|
||||
unsigned dims,
|
||||
bool fullscreen);
|
||||
|
||||
/* Takes the existing window between windowed and borderless fullscreen
|
||||
* without destroying it. False if there is no window, or fullscreen is
|
||||
* the exclusive kind. Call on the thread that owns the window. */
|
||||
bool win32_window_set_fullscreen(unsigned dims, bool fullscreen);
|
||||
|
||||
bool win32_suspend_screensaver(void *data, bool enable);
|
||||
|
||||
void win32_show_cursor(void *data, bool state);
|
||||
|
||||
@@ -7035,9 +7035,15 @@ static void vulkan_set_video_mode(void *data,
|
||||
bool fullscreen)
|
||||
{
|
||||
vk_t *vk = (vk_t*)data;
|
||||
if (vk->ctx_driver->set_video_mode)
|
||||
vk->ctx_driver->set_video_mode(vk->ctx_data,
|
||||
dims, fullscreen);
|
||||
if ( vk->ctx_driver->set_video_mode
|
||||
&& vk->ctx_driver->set_video_mode(vk->ctx_data,
|
||||
dims, fullscreen))
|
||||
{
|
||||
if (fullscreen)
|
||||
vk->flags |= VK_FLAG_FULLSCREEN;
|
||||
else
|
||||
vk->flags &= ~VK_FLAG_FULLSCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
static void vulkan_set_viewport(void *data, unsigned dims,
|
||||
|
||||
@@ -218,6 +218,21 @@ static bool gfx_ctx_w_vk_set_video_mode(void *data,
|
||||
unsigned dims,
|
||||
bool fullscreen)
|
||||
{
|
||||
/* With a window already up this is a fullscreen toggle on it: the
|
||||
* window is restyled where it stands, and the swapchain follows
|
||||
* when the resize reaches check_window, as for any resize. Where
|
||||
* that is refused - exclusive fullscreen - this goes on as it
|
||||
* always has. */
|
||||
if ( win32_get_window()
|
||||
&& win32_window_set_fullscreen(dims, fullscreen))
|
||||
{
|
||||
if (fullscreen)
|
||||
win32_vk.flags |= VK_DATA_FLAG_FULLSCREEN;
|
||||
else
|
||||
win32_vk.flags &= ~VK_DATA_FLAG_FULLSCREEN;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fullscreen)
|
||||
win32_vk.flags |= VK_DATA_FLAG_FULLSCREEN;
|
||||
else
|
||||
@@ -294,6 +309,8 @@ static uint32_t gfx_ctx_w_vk_get_flags(void *data)
|
||||
&win32_vk.context.supports_adaptive_vsync))
|
||||
BIT32_SET(flags, GFX_CTX_FLAGS_ADAPTIVE_VSYNC);
|
||||
|
||||
BIT32_SET(flags, GFX_CTX_FLAGS_FULLSCREEN_IN_PLACE);
|
||||
|
||||
#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
|
||||
BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG);
|
||||
#endif
|
||||
|
||||
+5
-1
@@ -371,7 +371,11 @@ enum display_flags
|
||||
/* Set by a context driver whose default framebuffer is 10-bit
|
||||
* Rec.2020 PQ (HDR10, e.g. a KMS scanout with HDR metadata): the
|
||||
* video driver encodes its frame to PQ instead of scRGB. */
|
||||
GFX_CTX_FLAGS_HDR10_FRAMEBUFFER
|
||||
GFX_CTX_FLAGS_HDR10_FRAMEBUFFER,
|
||||
/* The window can go between windowed and borderless fullscreen where
|
||||
* it stands, through set_video_mode, with the driver seeing only a
|
||||
* resize: a fullscreen toggle need not restart the drivers. */
|
||||
GFX_CTX_FLAGS_FULLSCREEN_IN_PLACE
|
||||
};
|
||||
|
||||
enum shader_uniform_type
|
||||
|
||||
+134
-103
@@ -5747,111 +5747,21 @@ const char* video_driver_get_gpu_api_version_string(void)
|
||||
return video_st->gpu_api_version_string;
|
||||
}
|
||||
|
||||
bool video_driver_init_internal(bool *video_is_threaded, bool verbosity_enabled)
|
||||
/* The size the video driver asks its window for: the configured
|
||||
* fullscreen size, or for a window the saved or custom size, else the
|
||||
* core's geometry times the window scale, kept within the largest
|
||||
* window allowed. Used when the driver starts and when a fullscreen
|
||||
* toggle changes the window it already has. */
|
||||
static void video_driver_window_size(settings_t *settings,
|
||||
video_driver_state_t *video_st, bool fullscreen,
|
||||
unsigned *out_width, unsigned *out_height)
|
||||
{
|
||||
video_info_t video;
|
||||
unsigned max_dim, scale, width, height;
|
||||
video_viewport_settings_t *custom_vp = NULL;
|
||||
input_driver_t *tmp = NULL;
|
||||
static uint16_t dummy_pixels[32] = {0};
|
||||
runloop_state_t *runloop_st = runloop_state_get_ptr();
|
||||
settings_t *settings = config_get_ptr();
|
||||
struct retro_game_geometry *geom = &video_st->av_info.geometry;
|
||||
unsigned int rotation = retroarch_get_rotation();
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
|
||||
input_driver_state_t *input_st = input_state_get_ptr();
|
||||
video_driver_state_t *video_st = &video_driver_st;
|
||||
struct retro_game_geometry *geom = &video_st->av_info.geometry;
|
||||
const enum retro_pixel_format
|
||||
video_driver_pix_fmt = video_st->pix_fmt;
|
||||
unsigned int rotation = retroarch_get_rotation();
|
||||
#ifdef HAVE_VIDEO_FILTER
|
||||
const char *path_softfilter_plugin = settings->paths.path_softfilter_plugin;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VIDEO_FILTER
|
||||
/* Bound before any driver or wrapper exists: under threaded video
|
||||
* the OSD fonts live on the video thread, and the font driver
|
||||
* reaches ra-video state through this capture, not the getter. */
|
||||
font_driver_bind_video_state(video_state_get_ptr());
|
||||
|
||||
/* Init video filter only when game is running */
|
||||
if (( runloop_st->current_core.flags & RETRO_CORE_FLAG_GAME_LOADED)
|
||||
&& (path_softfilter_plugin && *path_softfilter_plugin))
|
||||
video_driver_init_filter(video_driver_pix_fmt, settings);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(FRAME_CACHE_HAZARDS)
|
||||
/* Lazily allocate the cached-frame tuple lock on first video
|
||||
* driver init. Kept across video driver reinits (HDR toggle,
|
||||
* fullscreen change) and for the rest of the process: the cache is
|
||||
* still invalidated from retroarch_deinit_drivers() after the video
|
||||
* driver itself is gone, so there is no point at which freeing
|
||||
* this would be safe. */
|
||||
if (!cached_frame_lock)
|
||||
cached_frame_lock = slock_new();
|
||||
#endif
|
||||
|
||||
max_dim = MAX(geom->max_width, geom->max_height);
|
||||
scale = next_pow2(max_dim) / RARCH_SCALE_BASE;
|
||||
scale = MAX(scale, 1);
|
||||
|
||||
#ifdef HAVE_VIDEO_FILTER
|
||||
if (video_st->state_filter)
|
||||
scale = video_st->state_scale;
|
||||
#endif
|
||||
|
||||
strlcpy(aspectratio_lut[ASPECT_RATIO_CONFIG].name,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_CONFIG),
|
||||
sizeof(aspectratio_lut[ASPECT_RATIO_CONFIG].name));
|
||||
strlcpy(aspectratio_lut[ASPECT_RATIO_CORE].name,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_CORE_PROVIDED),
|
||||
sizeof(aspectratio_lut[ASPECT_RATIO_CORE].name));
|
||||
strlcpy(aspectratio_lut[ASPECT_RATIO_CUSTOM].name,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_CUSTOM),
|
||||
sizeof(aspectratio_lut[ASPECT_RATIO_CUSTOM].name));
|
||||
strlcpy(aspectratio_lut[ASPECT_RATIO_FULL].name,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_FULL),
|
||||
sizeof(aspectratio_lut[ASPECT_RATIO_FULL].name));
|
||||
|
||||
/* Update core-dependent aspect ratio values. */
|
||||
video_driver_set_viewport_square_pixel(geom, rotation);
|
||||
video_driver_set_viewport_core();
|
||||
video_driver_set_viewport_config(geom,
|
||||
settings->floats.video_aspect_ratio,
|
||||
settings->bools.video_aspect_ratio_auto);
|
||||
|
||||
/* Update CUSTOM viewport. */
|
||||
custom_vp = &settings->video_vp_custom;
|
||||
|
||||
if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
|
||||
{
|
||||
float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value;
|
||||
aspectratio_lut[ASPECT_RATIO_CUSTOM].value =
|
||||
(custom_vp->dims
|
||||
&& VIDEO_SCALE_W(custom_vp->dims)
|
||||
&& VIDEO_SCALE_H(custom_vp->dims))
|
||||
? (float)VIDEO_SCALE_W(custom_vp->dims)
|
||||
/ VIDEO_SCALE_H(custom_vp->dims) : default_aspect;
|
||||
}
|
||||
|
||||
{
|
||||
/* Guard against aspect ratio index possibly being out of bounds */
|
||||
unsigned new_aspect_idx = settings->uints.video_aspect_ratio_idx;
|
||||
if (new_aspect_idx > ASPECT_RATIO_END)
|
||||
new_aspect_idx = settings->uints.video_aspect_ratio_idx = 0;
|
||||
video_driver_aspect_ratio_put(&video_st->aspect_ratio_bits,
|
||||
aspectratio_lut[new_aspect_idx].value);
|
||||
}
|
||||
|
||||
/* Seed the viewport-parameter snapshot before the driver's init
|
||||
* runs: drivers call video_driver_update_viewport() from inside
|
||||
* init. This must come after the aspect ratio above is stored -
|
||||
* published any earlier, the snapshot carries the previous (on a
|
||||
* cold start, zero) aspect, and init-time viewports come out
|
||||
* 0 pixels wide until the first frame republishes. */
|
||||
video_driver_publish_vp_params();
|
||||
|
||||
if ( settings->bools.video_fullscreen
|
||||
|| ((uint32_t)retro_atomic_load_relaxed_int(&video_st->flags) & VIDEO_FLAG_FORCE_FULLSCREEN))
|
||||
if (fullscreen)
|
||||
{
|
||||
width = settings->uints.video_fullscreen_x;
|
||||
height = settings->uints.video_fullscreen_y;
|
||||
@@ -5988,6 +5898,127 @@ bool video_driver_init_internal(bool *video_is_threaded, bool verbosity_enabled)
|
||||
}
|
||||
}
|
||||
|
||||
*out_width = width;
|
||||
*out_height = height;
|
||||
}
|
||||
|
||||
unsigned video_driver_window_dims(bool fullscreen)
|
||||
{
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
video_driver_window_size(config_get_ptr(), &video_driver_st,
|
||||
fullscreen, &width, &height);
|
||||
return VIDEO_SCALE_PACK(width, height);
|
||||
}
|
||||
|
||||
bool video_driver_init_internal(bool *video_is_threaded, bool verbosity_enabled)
|
||||
{
|
||||
video_info_t video;
|
||||
unsigned max_dim, scale, width, height;
|
||||
video_viewport_settings_t *custom_vp = NULL;
|
||||
input_driver_t *tmp = NULL;
|
||||
static uint16_t dummy_pixels[32] = {0};
|
||||
runloop_state_t *runloop_st = runloop_state_get_ptr();
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
input_driver_state_t *input_st = input_state_get_ptr();
|
||||
video_driver_state_t *video_st = &video_driver_st;
|
||||
struct retro_game_geometry *geom = &video_st->av_info.geometry;
|
||||
const enum retro_pixel_format
|
||||
video_driver_pix_fmt = video_st->pix_fmt;
|
||||
unsigned int rotation = retroarch_get_rotation();
|
||||
#ifdef HAVE_VIDEO_FILTER
|
||||
const char *path_softfilter_plugin = settings->paths.path_softfilter_plugin;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VIDEO_FILTER
|
||||
/* Bound before any driver or wrapper exists: under threaded video
|
||||
* the OSD fonts live on the video thread, and the font driver
|
||||
* reaches ra-video state through this capture, not the getter. */
|
||||
font_driver_bind_video_state(video_state_get_ptr());
|
||||
|
||||
/* Init video filter only when game is running */
|
||||
if (( runloop_st->current_core.flags & RETRO_CORE_FLAG_GAME_LOADED)
|
||||
&& (path_softfilter_plugin && *path_softfilter_plugin))
|
||||
video_driver_init_filter(video_driver_pix_fmt, settings);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(FRAME_CACHE_HAZARDS)
|
||||
/* Lazily allocate the cached-frame tuple lock on first video
|
||||
* driver init. Kept across video driver reinits (HDR toggle,
|
||||
* fullscreen change) and for the rest of the process: the cache is
|
||||
* still invalidated from retroarch_deinit_drivers() after the video
|
||||
* driver itself is gone, so there is no point at which freeing
|
||||
* this would be safe. */
|
||||
if (!cached_frame_lock)
|
||||
cached_frame_lock = slock_new();
|
||||
#endif
|
||||
|
||||
max_dim = MAX(geom->max_width, geom->max_height);
|
||||
scale = next_pow2(max_dim) / RARCH_SCALE_BASE;
|
||||
scale = MAX(scale, 1);
|
||||
|
||||
#ifdef HAVE_VIDEO_FILTER
|
||||
if (video_st->state_filter)
|
||||
scale = video_st->state_scale;
|
||||
#endif
|
||||
|
||||
strlcpy(aspectratio_lut[ASPECT_RATIO_CONFIG].name,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_CONFIG),
|
||||
sizeof(aspectratio_lut[ASPECT_RATIO_CONFIG].name));
|
||||
strlcpy(aspectratio_lut[ASPECT_RATIO_CORE].name,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_CORE_PROVIDED),
|
||||
sizeof(aspectratio_lut[ASPECT_RATIO_CORE].name));
|
||||
strlcpy(aspectratio_lut[ASPECT_RATIO_CUSTOM].name,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_CUSTOM),
|
||||
sizeof(aspectratio_lut[ASPECT_RATIO_CUSTOM].name));
|
||||
strlcpy(aspectratio_lut[ASPECT_RATIO_FULL].name,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_FULL),
|
||||
sizeof(aspectratio_lut[ASPECT_RATIO_FULL].name));
|
||||
|
||||
/* Update core-dependent aspect ratio values. */
|
||||
video_driver_set_viewport_square_pixel(geom, rotation);
|
||||
video_driver_set_viewport_core();
|
||||
video_driver_set_viewport_config(geom,
|
||||
settings->floats.video_aspect_ratio,
|
||||
settings->bools.video_aspect_ratio_auto);
|
||||
|
||||
/* Update CUSTOM viewport. */
|
||||
custom_vp = &settings->video_vp_custom;
|
||||
|
||||
if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
|
||||
{
|
||||
float default_aspect = aspectratio_lut[ASPECT_RATIO_CORE].value;
|
||||
aspectratio_lut[ASPECT_RATIO_CUSTOM].value =
|
||||
(custom_vp->dims
|
||||
&& VIDEO_SCALE_W(custom_vp->dims)
|
||||
&& VIDEO_SCALE_H(custom_vp->dims))
|
||||
? (float)VIDEO_SCALE_W(custom_vp->dims)
|
||||
/ VIDEO_SCALE_H(custom_vp->dims) : default_aspect;
|
||||
}
|
||||
|
||||
{
|
||||
/* Guard against aspect ratio index possibly being out of bounds */
|
||||
unsigned new_aspect_idx = settings->uints.video_aspect_ratio_idx;
|
||||
if (new_aspect_idx > ASPECT_RATIO_END)
|
||||
new_aspect_idx = settings->uints.video_aspect_ratio_idx = 0;
|
||||
video_driver_aspect_ratio_put(&video_st->aspect_ratio_bits,
|
||||
aspectratio_lut[new_aspect_idx].value);
|
||||
}
|
||||
|
||||
/* Seed the viewport-parameter snapshot before the driver's init
|
||||
* runs: drivers call video_driver_update_viewport() from inside
|
||||
* init. This must come after the aspect ratio above is stored -
|
||||
* published any earlier, the snapshot carries the previous (on a
|
||||
* cold start, zero) aspect, and init-time viewports come out
|
||||
* 0 pixels wide until the first frame republishes. */
|
||||
video_driver_publish_vp_params();
|
||||
|
||||
video_driver_window_size(settings, video_st,
|
||||
settings->bools.video_fullscreen
|
||||
|| ((uint32_t)retro_atomic_load_relaxed_int(&video_st->flags) & VIDEO_FLAG_FORCE_FULLSCREEN),
|
||||
&width, &height);
|
||||
|
||||
if (width && height)
|
||||
RARCH_LOG("[Video] Set video size to: %ux%u.\n", width, height);
|
||||
else
|
||||
|
||||
@@ -1681,6 +1681,11 @@ void video_driver_shader_deferred_tick(void);
|
||||
|
||||
bool video_driver_set_rotation(unsigned rotation);
|
||||
|
||||
/* The size, packed with VIDEO_SCALE_PACK, the video driver would ask
|
||||
* its window for in the given state; what a fullscreen toggle on the
|
||||
* existing window resizes it to. */
|
||||
unsigned video_driver_window_dims(bool fullscreen);
|
||||
|
||||
bool video_driver_set_video_mode(unsigned dims, bool fullscreen);
|
||||
|
||||
/* Appends printf-formatted text at @len to a statistics buffer of
|
||||
|
||||
+16
-3
@@ -5699,9 +5699,22 @@ bool command_event(enum event_command cmd, void *data)
|
||||
if (ra_is_forced_fs)
|
||||
video_driver_modify_disp_flags(0, VIDEO_FLAG_FORCE_FULLSCREEN);
|
||||
|
||||
/* If we go fullscreen we drop all drivers and
|
||||
* reinitialize to be safe. */
|
||||
command_event(CMD_EVENT_REINIT, NULL);
|
||||
/* Where the window can change state in place - borderless
|
||||
* fullscreen on a context that says so - that is all a
|
||||
* toggle is: the window is restyled and the video driver
|
||||
* sees a resize. Device, shaders, audio and input drivers
|
||||
* stay as they are.
|
||||
*
|
||||
* Otherwise (exclusive fullscreen, which changes the
|
||||
* display mode, or a context without the means) all
|
||||
* drivers are dropped and reinitialised, as before. */
|
||||
if ( !settings->bools.video_windowed_fullscreen
|
||||
|| !video_driver_test_all_flags(
|
||||
GFX_CTX_FLAGS_FULLSCREEN_IN_PLACE)
|
||||
|| !video_driver_set_video_mode(
|
||||
video_driver_window_dims(new_fullscreen_state),
|
||||
new_fullscreen_state))
|
||||
command_event(CMD_EVENT_REINIT, NULL);
|
||||
if (video_fullscreen)
|
||||
{
|
||||
if ( video_st->poke
|
||||
|
||||
@@ -2693,3 +2693,7 @@
|
||||
== 20 fullscreen toggles
|
||||
windows made 20, inited 20, gone again 20
|
||||
window objects left behind: no
|
||||
== 20 fullscreen toggles on one window
|
||||
same window 20, right style 20, right size 20, resize seen 20
|
||||
exclusive fullscreen left to a restart: yes
|
||||
destroyed: window gone
|
||||
@@ -190,6 +190,10 @@ ui_companion_driver_t ui_companion_win32;
|
||||
|
||||
void stubs_init(void)
|
||||
{
|
||||
/* a core's geometry: the window limits its size to twenty times
|
||||
* it, and with none the limit is too small to hold a window */
|
||||
stub_video_st.av_info.geometry.base_width = 320;
|
||||
stub_video_st.av_info.geometry.base_height = 240;
|
||||
stub_application.process_events = stub_process_events;
|
||||
ui_companion_win32.application = &stub_application;
|
||||
ui_companion_win32.window = &stub_window;
|
||||
|
||||
@@ -289,6 +289,93 @@ int main(int argc, char **argv)
|
||||
(objects_last > objects_first) ? "yes" : "no");
|
||||
}
|
||||
|
||||
#ifndef W32T_OLD
|
||||
/* The same toggles on one window: win32_window_set_fullscreen()
|
||||
* takes the window between windowed and borderless fullscreen where
|
||||
* it stands. It has to stay the same window, wear the right style,
|
||||
* end up the right size, and tell the video driver through a
|
||||
* resize. (The twelve old procedures had no such thing: these lines
|
||||
* of the expected trace are this function's own.) */
|
||||
{
|
||||
WNDCLASSEX wndclass;
|
||||
HWND hwnd;
|
||||
MONITORINFO mon;
|
||||
int cycle, same = 0, styled = 0, sized = 0, resized = 0;
|
||||
const int cycles = 20;
|
||||
bool refused;
|
||||
|
||||
strlcpy(settings->arrays.input_driver, "raw",
|
||||
sizeof(settings->arrays.input_driver));
|
||||
settings->bools.video_fullscreen = false;
|
||||
trace_on = false;
|
||||
|
||||
win32_window_reset();
|
||||
win32_monitor_init();
|
||||
memset(&wndclass, 0, sizeof(wndclass));
|
||||
wndclass.lpfnWndProc = proc_for(FAM_VK, IN_WINRAW);
|
||||
if ( win32_window_init(&wndclass, true, NULL)
|
||||
&& win32_set_video_mode(NULL, VIDEO_SCALE_PACK(640, 480), false))
|
||||
{
|
||||
hwnd = win32_get_window();
|
||||
pump();
|
||||
|
||||
memset(&mon, 0, sizeof(mon));
|
||||
mon.cbSize = sizeof(mon);
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mon);
|
||||
|
||||
for (cycle = 0; cycle < cycles; cycle++)
|
||||
{
|
||||
RECT client;
|
||||
bool fullscreen = !(cycle & 1);
|
||||
bool popup;
|
||||
|
||||
win32_window_reset();
|
||||
settings->bools.video_fullscreen = fullscreen;
|
||||
if (!win32_window_set_fullscreen(VIDEO_SCALE_PACK(640, 480), fullscreen))
|
||||
break;
|
||||
pump();
|
||||
|
||||
if (win32_get_window() == hwnd && IsWindow(hwnd))
|
||||
same++;
|
||||
popup = (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_POPUP) != 0;
|
||||
if (popup == fullscreen && IsWindowVisible(hwnd))
|
||||
styled++;
|
||||
GetClientRect(hwnd, &client);
|
||||
if (fullscreen
|
||||
? ( client.right == mon.rcMonitor.right - mon.rcMonitor.left
|
||||
&& client.bottom == mon.rcMonitor.bottom - mon.rcMonitor.top)
|
||||
: (client.right == 640 && client.bottom == 480))
|
||||
sized++;
|
||||
if (win32_get_flags() & WIN32_CMN_FLAG_RESIZED)
|
||||
resized++;
|
||||
}
|
||||
|
||||
/* exclusive fullscreen changes the display mode: not done in
|
||||
* place, left to the driver restart */
|
||||
settings->bools.video_windowed_fullscreen = false;
|
||||
refused = !win32_window_set_fullscreen(VIDEO_SCALE_PACK(640, 480), true);
|
||||
settings->bools.video_windowed_fullscreen = true;
|
||||
|
||||
win32_monitor_from_window();
|
||||
win32_destroy_window();
|
||||
pump();
|
||||
|
||||
trace_on = true;
|
||||
trace("== %d fullscreen toggles on one window\n", cycles);
|
||||
trace(" same window %d, right style %d, right size %d, resize seen %d\n",
|
||||
same, styled, sized, resized);
|
||||
trace(" exclusive fullscreen left to a restart: %s\n",
|
||||
refused ? "yes" : "no");
|
||||
trace(" destroyed: window %s\n", IsWindow(hwnd) ? "still there" : "gone");
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_on = true;
|
||||
trace("== fullscreen toggles on one window: no window\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
out = fopen(argc > 1 ? argv[1] : "trace.txt", "wb");
|
||||
if (!out)
|
||||
return 2;
|
||||
|
||||
Reference in new issue
Block a user