Skip to content
This repository has been archived by the owner on Jul 7, 2024. It is now read-only.

Windows highdpi2 #1

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f38fbef
rebased windows-highdpi patch as of Nov 11, 2019 (b59d2dc from https:…
ericwa May 20, 2021
a793757
add IsValidDpiAwarenessContext function pointer
ericwa May 29, 2021
7b2b762
print display usable bounds
ericwa Jun 7, 2021
c64abd5
Revert "print display usable bounds"
ericwa Jun 8, 2021
e4cd6e1
add missing include
ericwa Jun 14, 2021
e47e541
highdpi: remove system_xdpi/system_ydpi
ericwa Jun 22, 2021
2f007a6
hidpi: remove EnableNonClientDpiScaling call
ericwa Jun 22, 2021
4eb585a
highdpi: remove support for separate xdpi/ydpi
ericwa Jun 22, 2021
15d0a24
highdpi: make WIN_GetGlobalMouseState dpi aware
ericwa Jun 22, 2021
592a6c7
highdpi: support WIN_WarpMouseGlobal
ericwa Jun 22, 2021
2632ff6
highdpi: revert WIN_GetDisplayBounds/WIN_GetDisplayUsableBounds
ericwa Jun 22, 2021
d759e21
highdpi: fix up last commit
ericwa Jun 22, 2021
3aaedf0
highdpi: fix WIN_GetDisplayBounds/WIN_GetDisplayUsableBounds
ericwa Jun 22, 2021
b8642ee
highdpi: clean up WM_GETMINMAXINFO
ericwa Jun 22, 2021
72ad1bc
highdpi: replace WIN_ScreenRectToSDL with WIN_ScreenPointToSDL
ericwa Jun 22, 2021
00cc462
highdpi: remove <PMV2 workaround
ericwa Jun 23, 2021
66a67a5
highdpi: avoid WIN_AdjustWindowRect in WM_GETDPISCALEDSIZE
ericwa Jun 23, 2021
0b91d8e
highdpi: warning fixes
ericwa Jun 23, 2021
2f569ce
highdpi: revert some changes in windowswindow.c
ericwa Jun 23, 2021
5c340e9
highdpi: split awareness hint into 2
ericwa Jun 23, 2021
011a7c6
highdpi: fix last commit
ericwa Jun 23, 2021
b67512d
highdpi: remove unused code
ericwa Jun 24, 2021
dbcccad
highdpi: fix declaration
ericwa Jun 24, 2021
d8989a8
highdpi: experiment with removing WIN_ScreenRectFromSDL
ericwa Jun 25, 2021
3a0fa2c
highdpi: add logging
ericwa Jun 25, 2021
8e34396
highdpi: fix SDL_GetPointDisplayIndex test
ericwa Jun 26, 2021
1591972
highdpi: fix last commit
ericwa Jun 26, 2021
918b02b
highdpi: fix typo
ericwa Jun 26, 2021
787c19b
highdpi: misc cleanup
ericwa Jun 30, 2021
b4bf1f1
highdpi: use SetThreadDpiAwarenessContext
ericwa Jul 1, 2021
a6b619d
highdpi: fullscreen wip
ericwa Jul 2, 2021
4ee1565
fix SDL_WINDOW_FULLSCREEN_DESKTOP giving window size in pixels
ericwa Nov 7, 2021
80e41de
enable HIGHDPI_DEBUG
ericwa Nov 7, 2021
d5979c0
highdpi: GetDrawableSize stuff
ericwa Nov 9, 2021
4b6f42f
highdpi: fix testgl2 issue caused by using SetThreadDpiAwarenessContext
ericwa Nov 21, 2021
18007f0
highdpi: also support DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
ericwa Nov 21, 2021
f308ad5
highdpi: fix exiting exclusive fullscreen on highdpi monitor causing …
ericwa Nov 22, 2021
fc53a9a
highdpi: fix vulkan drawable size
ericwa Nov 22, 2021
4c95411
highdpi: port mouse_rect functionaliy
ericwa Nov 22, 2021
381863e
highdpi: extra logging
ericwa Nov 22, 2021
c31ce1a
highdpi: wip: debugging exiting from fullscreen on macbook
ericwa Nov 22, 2021
b298013
highdpi: work around for exiting fullscreen with dx9 renderer giving …
ericwa Nov 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions include/SDL_hints.h
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,26 @@ extern "C" {
*/
#define SDL_HINT_RENDER_DIRECT3D11_DEBUG "SDL_RENDER_DIRECT3D11_DEBUG"

/**
* \brief If set to 1, then allow high-DPI on all windows.
*
* If high-DPI is allowed, the framebuffer size (which can be queried by calling SDL_GL_GetDrawableSize,
* and returns a size in pixels) is decoupled from the SDL window size. SDL window sizes are in
* points, which are translated to pixels by multiplying by the scale factor of the monitor that
* the window is on.
*
* If high-DPI is not enabled with this hint, the framebuffer size will be equal to the window size
* returned by SDL_GetWindowSize, but the OS will scale up the framebuffer if the window is on a
* high-DPI monitor.
*
* An SDL_WINDOWEVENT_RESIZED event will be sent to the application when the framebuffer size changes,
* which could happen in response to the window moving to a monitor with a different scale factor
* (either from the user moving it, or SDL_SetWindowPosition), or the monitor's scale factor changing.
*
* High-DPI support is currently implemented on macOS and Windows.
*/
#define SDL_HINT_VIDEO_ALLOW_HIGHDPI "SDL_VIDEO_ALLOW_HIGHDPI"

/**
* \brief A variable controlling whether the Direct3D device is initialized for thread-safe operations.
*
Expand Down
3 changes: 2 additions & 1 deletion include/SDL_video.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ typedef enum
SDL_WINDOW_FOREIGN = 0x00000800, /**< window not created by SDL */
SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, /**< window should be created in high-DPI mode if supported.
On macOS NSHighResolutionCapable must be set true in the
application's Info.plist for this to have any effect. */
application's Info.plist for this to have any effect.
(deprecated, use SDL_HINT_VIDEO_ALLOW_HIGHDPI) */
SDL_WINDOW_MOUSE_CAPTURE = 0x00004000, /**< window has mouse captured (unrelated to MOUSE_GRABBED) */
SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000, /**< window should always be above others */
SDL_WINDOW_SKIP_TASKBAR = 0x00010000, /**< window should not be added to the taskbar */
Expand Down
14 changes: 11 additions & 3 deletions src/render/direct3d/SDL_render_d3d.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,7 @@ D3D_ActivateRenderer(SDL_Renderer * renderer)
SDL_Window *window = renderer->window;
int w, h;
Uint32 window_flags = SDL_GetWindowFlags(window);

SDL_GetWindowSize(window, &w, &h);
WIN_GetDrawableSize(window, &w, &h);
data->pparams.BackBufferWidth = w;
data->pparams.BackBufferHeight = h;
if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
Expand Down Expand Up @@ -344,9 +343,17 @@ D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)

if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
data->updateSize = SDL_TRUE;
D3D_ActivateRenderer(renderer);
}
}

static int
D3D_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
{
WIN_GetDrawableSize(renderer->window, w, h);
return 0;
}

static D3DBLEND GetBlendFunc(SDL_BlendFactor factor)
{
switch (factor) {
Expand Down Expand Up @@ -1571,6 +1578,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
}

renderer->WindowEvent = D3D_WindowEvent;
renderer->GetOutputSize = D3D_GetOutputSize;
renderer->SupportsBlendMode = D3D_SupportsBlendMode;
renderer->CreateTexture = D3D_CreateTexture;
renderer->UpdateTexture = D3D_UpdateTexture;
Expand Down Expand Up @@ -1600,7 +1608,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
SDL_GetWindowWMInfo(window, &windowinfo);

window_flags = SDL_GetWindowFlags(window);
SDL_GetWindowSize(window, &w, &h);
WIN_GetDrawableSize(window, &w, &h);
SDL_GetWindowDisplayMode(window, &fullscreen_mode);

SDL_zero(pparams);
Expand Down
11 changes: 10 additions & 1 deletion src/render/direct3d11/SDL_render_d3d11.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#define COBJMACROS
#include "../../core/windows/SDL_windows.h"
#include "../../video/windows/SDL_windowswindow.h"
#include "SDL_hints.h"
#include "SDL_loadso.h"
#include "SDL_syswm.h"
Expand Down Expand Up @@ -910,7 +911,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
/* The width and height of the swap chain must be based on the display's
* non-rotated size.
*/
SDL_GetWindowSize(renderer->window, &w, &h);
WIN_GetDrawableSize(renderer->window, &w, &h);
data->rotation = D3D11_GetCurrentRotation();
/* SDL_Log("%s: windowSize={%d,%d}, orientation=%d\n", __FUNCTION__, w, h, (int)data->rotation); */
if (D3D11_IsDisplayRotated90Degrees(data->rotation)) {
Expand Down Expand Up @@ -1041,6 +1042,13 @@ D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
}
}

static int
D3D11_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
{
WIN_GetDrawableSize(renderer->window, w, h);
return 0;
}

static SDL_bool
D3D11_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
{
Expand Down Expand Up @@ -2353,6 +2361,7 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
data->identity = MatrixIdentity();

renderer->WindowEvent = D3D11_WindowEvent;
renderer->GetOutputSize = D3D11_GetOutputSize;
renderer->SupportsBlendMode = D3D11_SupportsBlendMode;
renderer->CreateTexture = D3D11_CreateTexture;
renderer->UpdateTexture = D3D11_UpdateTexture;
Expand Down
2 changes: 1 addition & 1 deletion src/test/SDL_test_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ SDLTest_CommonArg(SDLTest_CommonState * state, int index)
return 1;
}
if (SDL_strcasecmp(argv[index], "--allow-highdpi") == 0) {
state->window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_HIGHDPI, "1");
return 1;
}
if (SDL_strcasecmp(argv[index], "--windows") == 0) {
Expand Down
5 changes: 5 additions & 0 deletions src/video/SDL_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,11 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
}
}

/* This hint adds SDL_WINDOW_ALLOW_HIGHDPI to all windows. */
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_ALLOW_HIGHDPI, SDL_FALSE)) {
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
}

if (flags & SDL_WINDOW_VULKAN) {
if (!_this->Vulkan_CreateSurface) {
SDL_SetError("Vulkan support is either not configured in SDL "
Expand Down
167 changes: 164 additions & 3 deletions src/video/windows/SDL_windowsevents.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "../../events/SDL_touch_c.h"
#include "../../events/scancodes_windows.h"
#include "SDL_hints.h"
#include "SDL_log.h"

/* Dropfile support */
#include <shellapi.h>
Expand All @@ -51,6 +52,8 @@
#include "wmmsg.h"
#endif

#define HIGHDPI_DEBUG

/* Masks for processing the windows KEYDOWN and KEYUP messages */
#define REPEATED_KEYMASK (1<<30)
#define EXTENDED_KEYMASK (1<<24)
Expand Down Expand Up @@ -85,6 +88,12 @@
#ifndef WM_UNICHAR
#define WM_UNICHAR 0x0109
#endif
#ifndef WM_DPICHANGED
#define WM_DPICHANGED 0x02E0
#endif
#ifndef WM_GETDPISCALEDSIZE
#define WM_GETDPISCALEDSIZE 0x02E4
#endif

#ifndef IS_HIGH_SURROGATE
#define IS_HIGH_SURROGATE(x) (((x) >= 0xd800) && ((x) <= 0xdbff))
Expand Down Expand Up @@ -733,7 +742,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
/* Only generate mouse events for real mouse */
if (GetMouseMessageSource() != SDL_MOUSE_EVENT_SOURCE_TOUCH &&
lParam != data->last_pointer_update) {
SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);

WIN_ClientPointToSDL(data->window, &x, &y);

SDL_SendMouseMotion(data->window, 0, 0, x, y);
}
}
}
Expand Down Expand Up @@ -1052,6 +1066,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);

/* Convert w, h, min_w, min_h, max_w, max_h to unscaled.
We can treat them as a point in the client area. */
WIN_ClientPointFromSDL(data->window, &w, &h);
WIN_ClientPointFromSDL(data->window, &min_w, &min_h);
WIN_ClientPointFromSDL(data->window, &max_w, &max_h);

/* Store in min_w and min_h difference between current size and minimal
size so we don't need to call AdjustWindowRectEx twice */
min_w -= w;
Expand All @@ -1077,7 +1097,11 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
size.bottom = h;
size.right = w;

AdjustWindowRectEx(&size, style, menu, 0);
if (data->videodata->highdpi_enabled && data->videodata->AdjustWindowRectExForDpi) {
data->videodata->AdjustWindowRectExForDpi(&size, style, menu, 0, data->scaling_dpi);
} else {
AdjustWindowRectEx(&size, style, menu, 0);
}
w = size.right - size.left;
h = size.bottom - size.top;
}
Expand Down Expand Up @@ -1141,12 +1165,25 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

x = rect.left;
y = rect.top;
WIN_ScreenPointToSDL(&x, &y);

SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);

/* NOTE: important to convert w/h from SDL (points) to Windows (pixels) using
WIN_ClientPointToSDL, which uses the window's actual
DPI value. */
w = rect.right - rect.left;
h = rect.bottom - rect.top;
WIN_ClientPointToSDL(data->window, &w, &h);

SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w, h);

#ifdef HIGHDPI_DEBUG
SDL_Log("WM_WINDOWPOSCHANGED: Windows client rect (pixels): (%d, %d) (%d x %d)\tSDL client rect (points): (%d, %d) (%d x %d) cached dpi %d, windows reported dpi %d",
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
x, y, w, h, data->scaling_dpi, data->videodata->GetDpiForWindow ? data->videodata->GetDpiForWindow(data->hwnd) : 0);
#endif

/* Forces a WM_PAINT event */
InvalidateRect(hwnd, NULL, FALSE);

Expand Down Expand Up @@ -1364,7 +1401,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
if (window->hit_test) {
POINT winpoint = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if (ScreenToClient(hwnd, &winpoint)) {
const SDL_Point point = { (int) winpoint.x, (int) winpoint.y };
int x = (int) winpoint.x;
int y = (int) winpoint.y;
WIN_ClientPointToSDL(data->window, &x, &y);
const SDL_Point point = { x, y };
const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
switch (rc) {
#define POST_HIT_TEST(ret) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return ret; }
Expand All @@ -1385,6 +1425,127 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
}
break;

case WM_GETDPISCALEDSIZE: /* Windows 10 Creators Update+ */
/* GetDpiForWindow and AdjustWindowRectExForDpi will be present, but check anyway. */
if (data->videodata->highdpi_enabled
&& data->videodata->GetDpiForWindow
&& data->videodata->AdjustWindowRectExForDpi) {

/*
Windows expects applications to scale their window rects linearly
when dragging between monitors with different DPI's.
e.g. a 100x100 window dragged to a 200% scaled monitor
becomes 200x200.

For SDL, we instead want the client size to scale linearly.
This is not the same as the window rect scaling linearly,
because Windows doesn't scale the non-client area (titlebar etc.)
linearly. So, we need to handle this message to request custom
scaling.
*/

const int nextDPI = (int)wParam;
const int prevDPI = (int)data->videodata->GetDpiForWindow(hwnd);
SIZE *sizeInOut = (SIZE *)lParam;

int frame_w, frame_h;
int query_client_w_win, query_client_h_win;

#ifdef HIGHDPI_DEBUG
SDL_Log("WM_GETDPISCALEDSIZE: current DPI: %d potential DPI: %d. input size: (%dx%d)", prevDPI, nextDPI, sizeInOut->cx, sizeInOut->cy);
#endif

/* subtract the window frame size that would have been used at prevDPI */
{
DWORD style = GetWindowLong(hwnd, GWL_STYLE);
BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
RECT rect = {0};

if (!(data->window->flags & SDL_WINDOW_BORDERLESS))
data->videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, prevDPI);

frame_w = -rect.left + rect.right;
frame_h = -rect.top + rect.bottom;

query_client_w_win = sizeInOut->cx - frame_w;
query_client_h_win = sizeInOut->cy - frame_h;
}

/* convert to new dpi */
query_client_w_win = MulDiv(query_client_w_win, nextDPI, prevDPI);
query_client_h_win = MulDiv(query_client_h_win, nextDPI, prevDPI);

/* add the window frame size that would be used at nextDPI */
{
DWORD style = GetWindowLong(hwnd, GWL_STYLE);
BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
RECT rect;

rect.left = 0;
rect.top = 0;
rect.right = query_client_w_win;
rect.bottom = query_client_h_win;

if (!(data->window->flags & SDL_WINDOW_BORDERLESS))
data->videodata->AdjustWindowRectExForDpi(&rect, style, menu, 0, nextDPI);

/* This is supposed to control the suggested rect param of WM_DPICHANGED */
sizeInOut->cx = rect.right - rect.left;
sizeInOut->cy = rect.bottom - rect.top;
}

#ifdef HIGHDPI_DEBUG
SDL_Log("WM_GETDPISCALEDSIZE: output size: (%dx%d)", sizeInOut->cx, sizeInOut->cy);
#endif
return TRUE;
}
break;

case WM_DPICHANGED: /* Windows 8.1+ */
if (data->videodata->highdpi_enabled) {
const int newDPI = HIWORD(wParam);
RECT* const suggestedRect = (RECT*)lParam;
int w, h;

#ifdef HIGHDPI_DEBUG
SDL_Log("WM_DPICHANGED: %d to %d\tsuggested rect: (%d, %d), (%dx%d)\n",
data->scaling_dpi, newDPI,
suggestedRect->left, suggestedRect->top, suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top);
#endif

/* update the cached DPI value for this window */
data->scaling_dpi = newDPI;

/*
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 means that
WM_GETDPISCALEDSIZE will have been called, so we can use suggestedRect.
*/
w = suggestedRect->right - suggestedRect->left;
h = suggestedRect->bottom - suggestedRect->top;

#ifdef HIGHDPI_DEBUG
SDL_Log("WM_DPICHANGED: current SDL window size: (%dx%d)\tcalling SetWindowPos: (%d, %d), (%dx%d)\n",
data->window->w, data->window->h,
suggestedRect->left, suggestedRect->top, w, h);
#endif

/* clear the window size, to cause us to send a SDL_WINDOWEVENT_RESIZED event in WM_WINDOWPOSCHANGED */
data->window->w = 0;
data->window->h = 0;

data->expected_resize = SDL_TRUE;
SetWindowPos(hwnd,
NULL,
suggestedRect->left,
suggestedRect->top,
w,
h,
SWP_NOZORDER | SWP_NOACTIVATE);
data->expected_resize = SDL_FALSE;
return 0;
}
break;
}

/* If there's a window proc, assume it's going to handle messages */
Expand Down
Loading