Officially added the concept of window pixel density

The SDL_WINDOW_ALLOW_HIGHDPI flag has been renamed SDL_WINDOW_HIGH_PIXEL_DENSITY, and added the function SDL_GetWindowPixelDensity()
This commit is contained in:
Sam Lantinga 2023-05-17 16:39:15 -07:00
parent e708674416
commit cc94f600fd
19 changed files with 59 additions and 70 deletions

View File

@ -1,18 +1,8 @@
SDL 3.0 has new support for high DPI displays
Displays now have a content display scale.
Displays now have a content display scale, which is the expected scale for content based on the DPI settings of the display. For example, a 4K display might have a 2.0 (200%) display scale, which means that the user expects UI elements to be twice as big on this display, to aid in readability. You can query the display content scale using `SDL_GetDisplayContentScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
The display scale is the expected scale for content based on the DPI settings of the display. For example, a 4K display might have a 2.0 (200%) display scale, which means that the user expects UI elements to be twice as big on this display, to aid in readability.
The window size is now distinct from the window pixel size, and the ratio between the two is the window pixel density. If the window is created with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, SDL will try to match the native pixel density for the display, otherwise it will try to have the pixel size match the window size. You can query the window pixel density using `SDL_GetWindowPixelDensity()`. You can query the window pixel size using `SDL_GetWindowSizeInPixels()`, and when this changes you get an `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event. You are guaranteed to get a `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event when a window is created and resized, and you can use this event to create and resize your graphics context for the window.
The window size is now distinct from the window pixel size.
The window also has a display scale, which is the content display scale relative to the window pixel size.
For example, a 3840x2160 window displayed at 200% on Windows, and a 1920x1080 window on a 2x display on macOS will both have a pixel size of 3840x2160 and a display scale of 2.0.
You can query the window size using SDL_GetWindowSize(), and when this changes you get an SDL_EVENT_WINDOW_RESIZED event.
You can query the window pixel size using SDL_GetWindowSizeInPixels(), and when this changes you get an SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED event. You are guaranteed to get a SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED event when a window is created and resized, and you can use this event to create and resize your graphics context for the window.
You can query the window display scale using SDL_GetWindowDisplayScale(), and when this changes you get an SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED event.
The window has a display scale, which is the scale from the pixel resolution to the desired content size, e.g. the combination of the pixel density and the content scale. For example, a 3840x2160 window displayed at 200% on Windows, and a 1920x1080 window with the high density flag on a 2x display on macOS will both have a pixel size of 3840x2160 and a display scale of 2.0. You can query the window display scale using `SDL_GetWindowDisplayScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.

View File

@ -1085,7 +1085,7 @@ The SDL_WINDOWPOS_UNDEFINED_DISPLAY() and SDL_WINDOWPOS_CENTERED_DISPLAY() macro
The SDL_WINDOW_SHOWN flag has been removed. Windows are shown by default and can be created hidden by using the SDL_WINDOW_HIDDEN flag.
The SDL_WINDOW_ALLOW_HIGHDPI flag has been replaced by the SDL_HINT_VIDEO_ENABLE_HIGH_PIXEL_DENSITY hint, which is enabled by default.
The SDL_WINDOW_ALLOW_HIGHDPI flag has been renamed SDL_WINDOW_HIGH_PIXEL_DENSITY.
SDL_DisplayMode now includes the pixel density which can be greater than 1.0 for display modes that have a higher pixel size than the mode size. You should use SDL_GetWindowSizeInPixels() to get the actual pixel size of the window back buffer.

View File

@ -1638,17 +1638,6 @@ extern "C" {
*/
#define SDL_HINT_VIDEO_EXTERNAL_CONTEXT "SDL_VIDEO_EXTERNAL_CONTEXT"
/**
* \brief A variable controlling whether to use high pixel density display modes
*
* The variable can be set to the following values:
* "0" - Disable high pixel density display modes
* "1" - Enable high pixel density display modes
*
* The default value is "1". This hint must be set before display modes are queried and windows are created.
*/
#define SDL_HINT_VIDEO_ENABLE_HIGH_PIXEL_DENSITY "SDL_VIDEO_ENABLE_HIGH_PIXEL_DENSITY"
/**
* \brief A variable that dictates policy for fullscreen Spaces on macOS.
*

View File

@ -141,7 +141,7 @@ typedef enum
SDL_WINDOW_MOUSE_FOCUS = 0x00000400, /**< window has mouse focus */
/* 0x00001000 was SDL_WINDOW_FULLSCREEN_DESKTOP in SDL2, please reserve this bit for sdl2-compat. */
SDL_WINDOW_FOREIGN = 0x00000800, /**< window not created by SDL */
/* 0x00002000 was SDL_WINDOW_ALLOW_HIGHDPI in SDL2, please reserve this bit for sdl2-compat. */
SDL_WINDOW_HIGH_PIXEL_DENSITY = 0x00002000, /**< window uses high pixel density back buffer if possible */
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 */
@ -557,6 +557,21 @@ extern DECLSPEC SDL_DisplayID SDLCALL SDL_GetDisplayForRect(const SDL_Rect *rect
*/
extern DECLSPEC SDL_DisplayID SDLCALL SDL_GetDisplayForWindow(SDL_Window *window);
/**
* Get the pixel density of a window.
*
* This is a ratio of pixel size to window size. For example, if the window is 1920x1080 and it has a high density back buffer of 3840x2160 pixels, it would have a pixel density of 2.0.
*
* \param window the window to query
* \returns the pixel density or 0.0f on failure; call SDL_GetError() for
* more information.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_GetWindowDisplayScale
*/
extern DECLSPEC float SDLCALL SDL_GetWindowPixelDensity(SDL_Window *window);
/**
* Get the content display scale relative to a window's pixel size.
*

View File

@ -857,6 +857,7 @@ SDL3_0.0.0 {
SDL_GetPath;
SDL_GetDisplayContentScale;
SDL_GetWindowDisplayScale;
SDL_GetWindowPixelDensity;
# extra symbols go here (don't modify this line)
local: *;
};

View File

@ -883,3 +883,4 @@
#define SDL_GetPath SDL_GetPath_REAL
#define SDL_GetDisplayContentScale SDL_GetDisplayContentScale_REAL
#define SDL_GetWindowDisplayScale SDL_GetWindowDisplayScale_REAL
#define SDL_GetWindowPixelDensity SDL_GetWindowPixelDensity_REAL

View File

@ -928,3 +928,4 @@ SDL_DYNAPI_PROC(void,SDL_DestroyRWLock,(SDL_RWLock *a),(a),)
SDL_DYNAPI_PROC(char*,SDL_GetPath,(SDL_Folder a),(a),return)
SDL_DYNAPI_PROC(float,SDL_GetDisplayContentScale,(SDL_DisplayID a),(a),return)
SDL_DYNAPI_PROC(float,SDL_GetWindowDisplayScale,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(float,SDL_GetWindowPixelDensity,(SDL_Window *a),(a),return)

View File

@ -35,7 +35,7 @@ static const char *video_usage[] = {
"[--fullscreen | --fullscreen-desktop | --windows N]", "[--title title]",
"[--icon icon.bmp]", "[--center | --position X,Y]", "[--geometry WxH]",
"[--min-geometry WxH]", "[--max-geometry WxH]", "[--logical WxH]",
"[--disable-high-pixel-density]", "[--auto-scale-content]",
"[--high-pixel-density]", "[--auto-scale-content]",
"[--logical-presentation disabled|match|stretch|letterbox|overscan|integer_scale]",
"[--logical-scale-quality nearest|linear|best]",
"[--scale N]", "[--depth N]", "[--refresh R]", "[--vsync]", "[--noframe]",
@ -429,9 +429,8 @@ int SDLTest_CommonArg(SDLTest_CommonState *state, int index)
state->logical_h = SDL_atoi(h);
return 2;
}
if (SDL_strcasecmp(argv[index], "--disable-high-pixel-density") == 0) {
/* Note that on some platforms it's not possible to disable high density modes */
SDL_SetHint(SDL_HINT_VIDEO_ENABLE_HIGH_PIXEL_DENSITY, "0");
if (SDL_strcasecmp(argv[index], "--high-pixel-density") == 0) {
state->window_flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
return 1;
}
if (SDL_strcasecmp(argv[index], "--auto-scale-content") == 0) {

View File

@ -537,7 +537,4 @@ extern SDL_bool SDL_ShouldAllowTopmost(void);
extern void SDL_ToggleDragAndDropSupport(void);
/* This has been moved out of the public API, but is still available for now */
#define SDL_WINDOW_ALLOW_HIGHDPI 0x00002000
#endif /* SDL_sysvideo_h_ */

View File

@ -1381,6 +1381,20 @@ static void SDL_CheckWindowDisplayChanged(SDL_Window *window)
}
}
float SDL_GetWindowPixelDensity(SDL_Window *window)
{
int window_w, window_h, pixel_w, pixel_h;
float pixel_density = 1.0f;
CHECK_WINDOW_MAGIC(window, 0.0f);
if (SDL_GetWindowSize(window, &window_w, &window_h) == 0 &&
SDL_GetWindowSizeInPixels(window, &pixel_w, &pixel_h) == 0) {
pixel_density = (float)pixel_w / window_w;
}
return pixel_density;
}
float SDL_GetWindowDisplayScale(SDL_Window *window)
{
CHECK_WINDOW_MAGIC(window, 0.0f);
@ -1390,16 +1404,10 @@ float SDL_GetWindowDisplayScale(SDL_Window *window)
static void SDL_CheckWindowDisplayScaleChanged(SDL_Window *window)
{
int window_w, window_h, pixel_w, pixel_h;
float pixel_density = 1.0f;
float pixel_density = SDL_GetWindowPixelDensity(window);
float content_scale = SDL_GetDisplayContentScale(SDL_GetDisplayForWindowPosition(window));
float display_scale;
if (SDL_GetWindowSize(window, &window_w, &window_h) == 0 &&
SDL_GetWindowSizeInPixels(window, &pixel_w, &pixel_h) == 0) {
pixel_density = (float)pixel_w / window_w;
}
display_scale = (pixel_density * content_scale);
if (display_scale != window->display_scale) {
window->display_scale = display_scale;
@ -1686,7 +1694,7 @@ Uint32 SDL_GetWindowPixelFormat(SDL_Window *window)
}
#define CREATE_FLAGS \
(SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL | SDL_WINDOW_TRANSPARENT)
(SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL | SDL_WINDOW_TRANSPARENT)
static SDL_INLINE SDL_bool IsAcceptingDragAndDrop(void)
{
@ -1879,10 +1887,6 @@ static SDL_Window *SDL_CreateWindowInternal(const char *title, int x, int y, int
}
}
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_ENABLE_HIGH_PIXEL_DENSITY, SDL_TRUE)) {
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
}
window = (SDL_Window *)SDL_calloc(1, sizeof(*window));
if (window == NULL) {
SDL_OutOfMemory();

View File

@ -138,7 +138,7 @@ Cocoa_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window)
@autoreleasepool {
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata;
NSView *view = data.nswindow.contentView;
BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
BOOL highDPI = (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) != 0;
BOOL opaque = (window->flags & SDL_WINDOW_TRANSPARENT) == 0;
Uint32 windowID = SDL_GetWindowID(window);
SDL_cocoametalview *newview;

View File

@ -174,13 +174,6 @@ static SDL_bool GetDisplayMode(SDL_VideoDevice *_this, CGDisplayModeRef vidmode,
pixelW = CGDisplayModeGetPixelWidth(vidmode);
pixelH = CGDisplayModeGetPixelHeight(vidmode);
if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_ENABLE_HIGH_PIXEL_DENSITY, SDL_TRUE)) {
if (width != pixelW) {
/* We don't want high pixel density modes */
return SDL_FALSE;
}
}
if (modelist != NULL) {
CFIndex modescount = CFArrayGetCount(modelist);
int i;

View File

@ -1870,7 +1870,7 @@ int Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
#endif
/* Note: as of the macOS 10.15 SDK, this defaults to YES instead of NO when
* the NSHighResolutionCapable boolean is set in Info.plist. */
highdpi = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
highdpi = (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) ? YES : NO;
[contentView setWantsBestResolutionOpenGLSurface:highdpi];
#ifdef __clang__
#pragma clang diagnostic pop
@ -1881,12 +1881,11 @@ int Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
if ((window->flags & SDL_WINDOW_OPENGL) &&
_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
[contentView setWantsLayer:TRUE];
if (!(window->flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
contentView.layer.contentsScale = 1;
if ((window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) &&
[nswindow.screen respondsToSelector:@selector(backingScaleFactor)]) {
contentView.layer.contentsScale = nswindow.screen.backingScaleFactor;
} else {
if ([nswindow.screen respondsToSelector:@selector(backingScaleFactor)]) {
contentView.layer.contentsScale = nswindow.screen.backingScaleFactor;
}
contentView.layer.contentsScale = 1;
}
}
#endif /* SDL_VIDEO_OPENGL_EGL */
@ -1950,7 +1949,7 @@ int Cocoa_CreateWindowFrom(SDL_VideoDevice *_this, SDL_Window *window, const voi
#endif
/* Note: as of the macOS 10.15 SDK, this defaults to YES instead of NO when
* the NSHighResolutionCapable boolean is set in Info.plist. */
highdpi = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
highdpi = (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) ? YES : NO;
[nsview setWantsBestResolutionOpenGLSurface:highdpi];
#ifdef __clang__
#pragma clang diagnostic pop
@ -2091,7 +2090,7 @@ void Cocoa_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int
NSView *contentView = windata.sdlContentView;
NSRect viewport = [contentView bounds];
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
/* This gives us the correct viewport for a Retina-enabled view. */
viewport = [contentView convertRectToBacking:viewport];
}

View File

@ -861,7 +861,7 @@ static EM_BOOL Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *u
SDL_bool force = SDL_FALSE;
/* update pixel ratio */
if (window_data->window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
if (window_data->window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
if (window_data->pixel_ratio != emscripten_get_device_pixel_ratio()) {
window_data->pixel_ratio = emscripten_get_device_pixel_ratio();
force = SDL_TRUE;

View File

@ -191,7 +191,7 @@ static int Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
wdata->canvas_id = SDL_strdup(selector);
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
} else {
wdata->pixel_ratio = 1.0f;
@ -245,7 +245,7 @@ static void Emscripten_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
if (window->driverdata) {
data = window->driverdata;
/* update pixel ratio */
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
data->pixel_ratio = emscripten_get_device_pixel_ratio();
}
emscripten_set_canvas_element_size(data->canvas_id, window->w * data->pixel_ratio, window->h * data->pixel_ratio);
@ -300,7 +300,7 @@ static void Emscripten_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *w
if (!is_fullscreen_desktop) {
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE;
} else if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
} else if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
} else {
strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF;

View File

@ -82,7 +82,7 @@ UIKit_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window)
CGFloat scale = 1.0;
SDL_uikitmetalview *metalview;
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
/* Set the scale to the natural scale factor of the screen - then
* the backing dimensions of the Metal view will match the pixel
* dimensions of the screen rather than the dimensions in points

View File

@ -140,7 +140,7 @@ SDL_GLContext UIKit_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
sharegroup = currContext.sharegroup;
}
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
/* Set the scale to the natural scale factor of the screen - the
* backing dimensions of the OpenGL view will match the pixel
* dimensions of the screen rather than the dimensions in points. */

View File

@ -349,7 +349,7 @@ void UIKit_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int
CGSize size = view.bounds.size;
CGFloat scale = 1.0;
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
scale = windata.uiwindow.screen.nativeScale;
}

View File

@ -1006,7 +1006,7 @@ static void Wayland_HandlePreferredScaleChanged(SDL_WindowData *window_data, flo
{
const float old_factor = window_data->windowed_scale_factor;
if (!(window_data->sdlwindow->flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
if (!(window_data->sdlwindow->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY)) {
/* Scale will always be 1, just ignore this */
return;
}
@ -2036,7 +2036,7 @@ int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
data->windowed_scale_factor = 1.0f;
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
int i;
for (i = 0; i < _this->num_displays; i++) {
float scale = _this->displays[i].driverdata->scale_factor;