From 67c91353e01f6f2c0cc80c17eeddbad6def7cb01 Mon Sep 17 00:00:00 2001
From: Eric Wasylishen <[EMAIL REDACTED]>
Date: Wed, 11 Jan 2023 19:45:01 -0700
Subject: [PATCH] Handle DPI scaling in SDL_GetWindowSurface
Fixes DPI awareness of testdrawchessboard (previously, the surface was
being created in points instead of pixels, resulting in the demo app
only drawing in a corner of the screen on High-DPI displays)
*_CreateWindowFramebuffer()/*_UpdateWindowFramebuffer(): are updated
to use SDL_GetWindowSizeInPixels instead of SDL_GetWindowSize() or
window->w/window->h.
Most of the _CreateWindowFramebuffer backends are untested except
for Windows.
Fixes #7047
---
include/SDL3/SDL_video.h | 2 +-
src/render/software/SDL_render_sw.c | 2 +-
src/video/SDL_video.c | 23 +++++++++----
src/video/dummy/SDL_nullframebuffer.c | 2 +-
.../emscripten/SDL_emscriptenframebuffer.c | 2 +-
src/video/n3ds/SDL_n3dsframebuffer.c | 2 +-
src/video/ngage/SDL_ngageframebuffer.cpp | 2 +-
.../offscreen/SDL_offscreenframebuffer.c | 2 +-
src/video/riscos/SDL_riscosframebuffer.c | 11 ++++---
src/video/windows/SDL_windowsframebuffer.c | 11 ++++---
src/video/x11/SDL_x11framebuffer.c | 33 +++++++++++--------
11 files changed, 57 insertions(+), 35 deletions(-)
diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h
index 07a978c6946f..f9f6ef1a1fb4 100644
--- a/include/SDL3/SDL_video.h
+++ b/include/SDL3/SDL_video.h
@@ -1261,7 +1261,7 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurface(SDL_Window * window);
*
* \param window the window to update
* \param rects an array of SDL_Rect structures representing areas of the
- * surface to copy
+ * surface to copy, in pixels
* \param numrects the number of rectangles
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c
index 814fdd947b73..4c4b0391a173 100644
--- a/src/render/software/SDL_render_sw.c
+++ b/src/render/software/SDL_render_sw.c
@@ -90,7 +90,7 @@ static int SW_GetOutputSize(SDL_Renderer *renderer, int *w, int *h)
}
if (renderer->window) {
- SDL_GetWindowSize(renderer->window, w, h);
+ SDL_GetWindowSizeInPixels(renderer->window, w, h);
return 0;
}
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 6d9644eca025..569c845fb43d 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -203,6 +203,9 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U
SDL_RendererInfo info;
SDL_WindowTextureData *data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
int i;
+ int w, h;
+
+ SDL_GetWindowSizeInPixels(window, &w, &h);
if (data == NULL) {
SDL_Renderer *renderer = NULL;
@@ -280,7 +283,7 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U
data->texture = SDL_CreateTexture(data->renderer, *format,
SDL_TEXTUREACCESS_STREAMING,
- window->w, window->h);
+ w, h);
if (!data->texture) {
/* codechecker_false_positive [Malloc] Static analyzer doesn't realize allocated `data` is saved to SDL_WINDOWTEXTUREDATA and not leaked here. */
return -1; /* NOLINT(clang-analyzer-unix.Malloc) */
@@ -288,11 +291,11 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U
/* Create framebuffer data */
data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format);
- data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3);
+ data->pitch = (((w * data->bytes_per_pixel) + 3) & ~3);
{
/* Make static analysis happy about potential SDL_malloc(0) calls. */
- const size_t allocsize = (size_t)window->h * data->pitch;
+ const size_t allocsize = (size_t)h * data->pitch;
data->pixels = SDL_malloc((allocsize > 0) ? allocsize : 1);
if (!data->pixels) {
return SDL_OutOfMemory();
@@ -316,6 +319,9 @@ static int SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window *window,
SDL_WindowTextureData *data;
SDL_Rect rect;
void *src;
+ int w, h;
+
+ SDL_GetWindowSizeInPixels(window, &w, &h);
data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA);
if (data == NULL || !data->texture) {
@@ -323,7 +329,7 @@ static int SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window *window,
}
/* Update a single rect that contains subrects for best DMA performance */
- if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) {
+ if (SDL_GetSpanEnclosingRect(w, h, numrects, rects, &rect)) {
src = (void *)((Uint8 *)data->pixels +
rect.y * data->pitch +
rect.x * data->bytes_per_pixel);
@@ -2569,6 +2575,9 @@ static SDL_Surface *SDL_CreateWindowFramebuffer(SDL_Window *window)
void *pixels = NULL;
int pitch = 0;
SDL_bool created_framebuffer = SDL_FALSE;
+ int w, h;
+
+ SDL_GetWindowSizeInPixels(window, &w, &h);
/* This will switch the video backend from using a software surface to
using a GPU texture through the 2D render API, if we think this would
@@ -2643,7 +2652,7 @@ static SDL_Surface *SDL_CreateWindowFramebuffer(SDL_Window *window)
return window->surface;
}
- return SDL_CreateSurfaceFrom(pixels, window->w, window->h, pitch, format);
+ return SDL_CreateSurfaceFrom(pixels, w, h, pitch, format);
}
SDL_Surface *SDL_GetWindowSurface(SDL_Window *window)
@@ -2673,8 +2682,8 @@ int SDL_UpdateWindowSurface(SDL_Window *window)
full_rect.x = 0;
full_rect.y = 0;
- full_rect.w = window->w;
- full_rect.h = window->h;
+ SDL_GetWindowSizeInPixels(window, &full_rect.w, &full_rect.h);
+
return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1);
}
diff --git a/src/video/dummy/SDL_nullframebuffer.c b/src/video/dummy/SDL_nullframebuffer.c
index 74b67d18ec5a..96a2cad6e5ec 100644
--- a/src/video/dummy/SDL_nullframebuffer.c
+++ b/src/video/dummy/SDL_nullframebuffer.c
@@ -37,7 +37,7 @@ int SDL_DUMMY_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format,
SDL_DUMMY_DestroyWindowFramebuffer(_this, window);
/* Create a new one */
- SDL_GetWindowSize(window, &w, &h);
+ SDL_GetWindowSizeInPixels(window, &w, &h);
surface = SDL_CreateSurface(w, h, surface_format);
if (surface == NULL) {
return -1;
diff --git a/src/video/emscripten/SDL_emscriptenframebuffer.c b/src/video/emscripten/SDL_emscriptenframebuffer.c
index 848c9d10cf04..5c0f663f773e 100644
--- a/src/video/emscripten/SDL_emscriptenframebuffer.c
+++ b/src/video/emscripten/SDL_emscriptenframebuffer.c
@@ -39,7 +39,7 @@ int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format
SDL_DestroySurface(surface);
/* Create a new one */
- SDL_GetWindowSize(window, &w, &h);
+ SDL_GetWindowSizeInPixels(window, &w, &h);
surface = SDL_CreateSurface(w, h, surface_format);
if (surface == NULL) {
diff --git a/src/video/n3ds/SDL_n3dsframebuffer.c b/src/video/n3ds/SDL_n3dsframebuffer.c
index 89bb7bc46583..2bdad707775e 100644
--- a/src/video/n3ds/SDL_n3dsframebuffer.c
+++ b/src/video/n3ds/SDL_n3dsframebuffer.c
@@ -69,7 +69,7 @@ SDL_FORCE_INLINE SDL_Surface *
CreateNewWindowFramebuffer(SDL_Window *window)
{
int w, h;
- SDL_GetWindowSize(window, &w, &h);
+ SDL_GetWindowSizeInPixels(window, &w, &h);
return SDL_CreateSurface(w, h, FRAMEBUFFER_FORMAT);
}
diff --git a/src/video/ngage/SDL_ngageframebuffer.cpp b/src/video/ngage/SDL_ngageframebuffer.cpp
index 23289725a4d1..0d98ea82e984 100644
--- a/src/video/ngage/SDL_ngageframebuffer.cpp
+++ b/src/video/ngage/SDL_ngageframebuffer.cpp
@@ -55,7 +55,7 @@ int SDL_NGAGE_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format,
SDL_NGAGE_DestroyWindowFramebuffer(_this, window);
/* Create a new one */
- SDL_GetWindowSize(window, &w, &h);
+ SDL_GetWindowSizeInPixels(window, &w, &h);
surface = SDL_CreateSurface(w, h, surface_format);
if (surface == NULL) {
return -1;
diff --git a/src/video/offscreen/SDL_offscreenframebuffer.c b/src/video/offscreen/SDL_offscreenframebuffer.c
index d7fac9d00a1c..5eff510fdbb8 100644
--- a/src/video/offscreen/SDL_offscreenframebuffer.c
+++ b/src/video/offscreen/SDL_offscreenframebuffer.c
@@ -37,7 +37,7 @@ int SDL_OFFSCREEN_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *for
SDL_OFFSCREEN_DestroyWindowFramebuffer(_this, window);
/* Create a new one */
- SDL_GetWindowSize(window, &w, &h);
+ SDL_GetWindowSizeInPixels(window, &w, &h);
surface = SDL_CreateSurface(w, h, surface_format);
if (surface == NULL) {
return -1;
diff --git a/src/video/riscos/SDL_riscosframebuffer.c b/src/video/riscos/SDL_riscosframebuffer.c
index 917134e57f6a..1620f4dbb7c5 100644
--- a/src/video/riscos/SDL_riscosframebuffer.c
+++ b/src/video/riscos/SDL_riscosframebuffer.c
@@ -39,6 +39,9 @@ int RISCOS_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, vo
_kernel_swi_regs regs;
SDL_DisplayMode mode;
int size;
+ int w, h;
+
+ SDL_GetWindowSizeInPixels(window, &w, &h);
/* Free the old framebuffer surface */
RISCOS_DestroyWindowFramebuffer(_this, window);
@@ -54,10 +57,10 @@ int RISCOS_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, vo
}
/* Calculate pitch */
- *pitch = (((window->w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
+ *pitch = (((w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
/* Allocate the sprite area */
- size = sizeof(sprite_area) + sizeof(sprite_header) + ((*pitch) * window->h);
+ size = sizeof(sprite_area) + sizeof(sprite_header) + ((*pitch) * h);
driverdata->fb_area = SDL_malloc(size);
if (!driverdata->fb_area) {
return SDL_OutOfMemory();
@@ -73,8 +76,8 @@ int RISCOS_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, vo
regs.r[1] = (int)driverdata->fb_area;
regs.r[2] = (int)sprite_name;
regs.r[3] = 0;
- regs.r[4] = window->w;
- regs.r[5] = window->h;
+ regs.r[4] = w;
+ regs.r[5] = h;
regs.r[6] = sprite_mode;
error = _kernel_swi(OS_SpriteOp, ®s, ®s);
if (error != NULL) {
diff --git a/src/video/windows/SDL_windowsframebuffer.c b/src/video/windows/SDL_windowsframebuffer.c
index 9c49fca8852f..925d2c640fdb 100644
--- a/src/video/windows/SDL_windowsframebuffer.c
+++ b/src/video/windows/SDL_windowsframebuffer.c
@@ -31,6 +31,9 @@ int WIN_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void
size_t size;
LPBITMAPINFO info;
HBITMAP hbm;
+ int w, h;
+
+ SDL_GetWindowSizeInPixels(window, &w, &h);
/* Free the old framebuffer surface */
if (data->mdc) {
@@ -78,10 +81,10 @@ int WIN_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void
}
/* Fill in the size information */
- *pitch = (((window->w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
- info->bmiHeader.biWidth = window->w;
- info->bmiHeader.biHeight = -window->h; /* negative for topdown bitmap */
- info->bmiHeader.biSizeImage = (DWORD)window->h * (*pitch);
+ *pitch = (((w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
+ info->bmiHeader.biWidth = w;
+ info->bmiHeader.biHeight = -h; /* negative for topdown bitmap */
+ info->bmiHeader.biSizeImage = (DWORD)h * (*pitch);
data->mdc = CreateCompatibleDC(data->hdc);
data->hbm = CreateDIBSection(data->hdc, info, DIB_RGB_COLORS, pixels, NULL, 0);
diff --git a/src/video/x11/SDL_x11framebuffer.c b/src/video/x11/SDL_x11framebuffer.c
index b2ef7345eb11..466ded8493dc 100644
--- a/src/video/x11/SDL_x11framebuffer.c
+++ b/src/video/x11/SDL_x11framebuffer.c
@@ -55,6 +55,9 @@ int X11_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format,
Display *display = data->videodata->display;
XGCValues gcv;
XVisualInfo vinfo;
+ int w, h;
+
+ SDL_GetWindowSizeInPixels(window, &w, &h);
/* Free the old framebuffer surface */
X11_DestroyWindowFramebuffer(_this, window);
@@ -77,14 +80,14 @@ int X11_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format,
}
/* Calculate pitch */
- *pitch = (((window->w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
+ *pitch = (((w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
/* Create the actual image */
#ifndef NO_SHARED_MEMORY
if (have_mitshm(display)) {
XShmSegmentInfo *shminfo = &data->shminfo;
- shminfo->shmid = shmget(IPC_PRIVATE, (size_t)window->h * (*pitch), IPC_CREAT | 0777);
+ shminfo->shmid = shmget(IPC_PRIVATE, (size_t)h * (*pitch), IPC_CREAT | 0777);
if (shminfo->shmid >= 0) {
shminfo->shmaddr = (char *)shmat(shminfo->shmid, 0, 0);
shminfo->readOnly = False;
@@ -108,7 +111,7 @@ int X11_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format,
data->ximage = X11_XShmCreateImage(display, data->visual,
vinfo.depth, ZPixmap,
shminfo->shmaddr, shminfo,
- window->w, window->h);
+ w, h);
if (!data->ximage) {
X11_XShmDetach(display, shminfo);
X11_XSync(display, False);
@@ -124,14 +127,14 @@ int X11_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format,
}
#endif /* not NO_SHARED_MEMORY */
- *pixels = SDL_malloc((size_t)window->h * (*pitch));
+ *pixels = SDL_malloc((size_t)h * (*pitch));
if (*pixels == NULL) {
return SDL_OutOfMemory();
}
data->ximage = X11_XCreateImage(display, data->visual,
vinfo.depth, ZPixmap, 0, (char *)(*pixels),
- window->w, window->h, 32, 0);
+ w, h, 32, 0);
if (!data->ximage) {
SDL_free(*pixels);
return SDL_SetError("Couldn't create XImage");
@@ -147,6 +150,10 @@ int X11_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects
Display *display = data->videodata->display;
int i;
int x, y, w, h;
+ int window_w, window_h;
+
+ SDL_GetWindowSizeInPixels(window, &window_w, &window_h);
+
#ifndef NO_SHARED_MEMORY
if (data->use_mitshm) {
for (i = 0; i < numrects; ++i) {
@@ -167,11 +174,11 @@ int X11_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects
y += h;
h += rects[i].y;
}
- if (x + w > window->w) {
- w = window->w - x;
+ if (x + w > window_w) {
+ w = window_w - x;
}
- if (y + h > window->h) {
- h = window->h - y;
+ if (y + h > window_h) {
+ h = window_h - y;
}
X11_XShmPutImage(display, data->xwindow, data->gc, data->ximage,
@@ -198,11 +205,11 @@ int X11_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects
y += h;
h += rects[i].y;
}
- if (x + w > window->w) {
- w = window->w - x;
+ if (x + w > window_w) {
+ w = window_w - x;
}
- if (y + h > window->h) {
- h = window->h - y;
+ if (y + h > window_h) {
+ h = window_h - y;
}
X11_XPutImage(display, data->xwindow, data->gc, data->ximage,