Skip to content

Commit

Permalink
SDL_DisplayMode now represents physical pixels and has added a displa…
Browse files Browse the repository at this point in the history
…y scaling factor

Work in progress on libsdl-org#7134
  • Loading branch information
slouken committed Jan 25, 2023
1 parent 6240252 commit 321768f
Show file tree
Hide file tree
Showing 21 changed files with 109 additions and 91 deletions.
10 changes: 6 additions & 4 deletions include/SDL3/SDL_video.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ typedef Uint32 SDL_WindowID;
typedef struct
{
Uint32 format; /**< pixel format */
int w; /**< width, in screen coordinates */
int h; /**< height, in screen coordinates */
int w; /**< width in pixels */
int h; /**< height in pixels */
float display_scale; /**< scale converting screen coordinates to pixels (e.g. a 3840x2160 mode with 1.5 scale would have a screen size of 2560x1440) */
float refresh_rate; /**< refresh rate (or zero for unspecified) */
void *driverdata; /**< driver-specific data, initialize to 0 */
} SDL_DisplayMode;
Expand Down Expand Up @@ -322,7 +323,7 @@ extern DECLSPEC int SDLCALL SDL_GetNumVideoDisplays(void);
extern DECLSPEC const char *SDLCALL SDL_GetDisplayName(int displayIndex);

/**
* Get the desktop area represented by a display.
* Get the desktop area represented by a display, in screen coordinates.
*
* The primary display (`displayIndex` zero) is always located at 0,0.
*
Expand All @@ -338,7 +339,7 @@ extern DECLSPEC const char *SDLCALL SDL_GetDisplayName(int displayIndex);
extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect *rect);

/**
* Get the usable desktop area represented by a display.
* Get the usable desktop area represented by a display, in screen coordinates.
*
* The primary display (`displayIndex` zero) is always located at 0,0.
*
Expand Down Expand Up @@ -440,6 +441,7 @@ extern DECLSPEC int SDLCALL SDL_GetNumDisplayModes(int displayIndex);
*
* - width -> largest to smallest
* - height -> largest to smallest
* - display_scale -> smallest to largest
* - bits per pixel -> more colors to fewer colors
* - packed pixel layout -> largest to smallest
* - refresh rate -> highest to lowest
Expand Down
24 changes: 12 additions & 12 deletions src/test/SDL_test_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1124,13 +1124,13 @@ SDLTest_CommonInit(SDLTest_CommonState *state)

SDL_Log("Bounds: %dx%d at %d,%d\n", bounds.w, bounds.h, bounds.x, bounds.y);
SDL_Log("Usable bounds: %dx%d at %d,%d\n", usablebounds.w, usablebounds.h, usablebounds.x, usablebounds.y);
SDL_Log("DPI: %fx%f\n", hdpi, vdpi);
SDL_Log("DPI: %gx%g\n", hdpi, vdpi);

SDL_GetDesktopDisplayMode(i, &mode);
SDL_GetMasksForPixelFormatEnum(mode.format, &bpp, &Rmask, &Gmask,
&Bmask, &Amask);
SDL_Log(" Current mode: %dx%d@%gHz, %d bits-per-pixel (%s)\n",
mode.w, mode.h, mode.refresh_rate, bpp,
SDL_Log(" Current mode: %dx%d@%gHz, %d%% scale, %d bits-per-pixel (%s)\n",
mode.w, mode.h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), bpp,
SDL_GetPixelFormatName(mode.format));
if (Rmask || Gmask || Bmask) {
SDL_Log(" Red Mask = 0x%.8" SDL_PRIx32 "\n", Rmask);
Expand All @@ -1151,8 +1151,8 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
SDL_GetDisplayMode(i, j, &mode);
SDL_GetMasksForPixelFormatEnum(mode.format, &bpp, &Rmask,
&Gmask, &Bmask, &Amask);
SDL_Log(" Mode %d: %dx%d@%gHz, %d bits-per-pixel (%s)\n",
j, mode.w, mode.h, mode.refresh_rate, bpp,
SDL_Log(" Mode %d: %dx%d@%gHz, %d%% scale, %d bits-per-pixel (%s)\n",
j, mode.w, mode.h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), bpp,
SDL_GetPixelFormatName(mode.format));
if (Rmask || Gmask || Bmask) {
SDL_Log(" Red Mask = 0x%.8" SDL_PRIx32 "\n",
Expand Down Expand Up @@ -2245,8 +2245,8 @@ void SDLTest_CommonDrawWindowInfo(SDL_Renderer *renderer, SDL_Window *window, fl
textY += lineHeight;

if (0 == SDL_GetWindowDisplayMode(window, &mode)) {
(void)SDL_snprintf(text, sizeof text, "SDL_GetWindowDisplayMode: %dx%d@%gHz (%s)",
mode.w, mode.h, mode.refresh_rate, SDL_GetPixelFormatName(mode.format));
(void)SDL_snprintf(text, sizeof text, "SDL_GetWindowDisplayMode: %dx%d@%gHz %d%% scale, (%s)",
mode.w, mode.h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), SDL_GetPixelFormatName(mode.format));
SDLTest_DrawString(renderer, 0.0f, textY, text);
textY += lineHeight;
}
Expand Down Expand Up @@ -2275,21 +2275,21 @@ void SDLTest_CommonDrawWindowInfo(SDL_Renderer *renderer, SDL_Window *window, fl
}

if (0 == SDL_GetCurrentDisplayMode(windowDisplayIndex, &mode)) {
(void)SDL_snprintf(text, sizeof text, "SDL_GetCurrentDisplayMode: %dx%d@%gHz (%s)",
mode.w, mode.h, mode.refresh_rate, SDL_GetPixelFormatName(mode.format));
(void)SDL_snprintf(text, sizeof text, "SDL_GetCurrentDisplayMode: %dx%d@%gHz %d%% scale, (%s)",
mode.w, mode.h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), SDL_GetPixelFormatName(mode.format));
SDLTest_DrawString(renderer, 0.0f, textY, text);
textY += lineHeight;
}

if (0 == SDL_GetDesktopDisplayMode(windowDisplayIndex, &mode)) {
(void)SDL_snprintf(text, sizeof text, "SDL_GetDesktopDisplayMode: %dx%d@%gHz (%s)",
mode.w, mode.h, mode.refresh_rate, SDL_GetPixelFormatName(mode.format));
(void)SDL_snprintf(text, sizeof text, "SDL_GetDesktopDisplayMode: %dx%d@%gHz %d%% scale, (%s)",
mode.w, mode.h, mode.refresh_rate, (int)(mode.display_scale * 100.0f), SDL_GetPixelFormatName(mode.format));
SDLTest_DrawString(renderer, 0.0f, textY, text);
textY += lineHeight;
}

if (0 == SDL_GetDisplayPhysicalDPI(windowDisplayIndex, &ddpi, &hdpi, &vdpi)) {
(void)SDL_snprintf(text, sizeof text, "SDL_GetDisplayPhysicalDPI: ddpi: %f, hdpi: %f, vdpi: %f",
(void)SDL_snprintf(text, sizeof text, "SDL_GetDisplayPhysicalDPI: ddpi: %g, hdpi: %g, vdpi: %g",
ddpi, hdpi, vdpi);
SDLTest_DrawString(renderer, 0.0f, textY, text);
textY += lineHeight;
Expand Down
48 changes: 43 additions & 5 deletions src/video/SDL_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,12 +382,16 @@ static int SDLCALL cmpmodes(const void *A, const void *B)
{
const SDL_DisplayMode *a = (const SDL_DisplayMode *)A;
const SDL_DisplayMode *b = (const SDL_DisplayMode *)B;
float a_display_scale = (a->display_scale == 0.0f) ? 1.0f : a->display_scale;
float b_display_scale = (b->display_scale == 0.0f) ? 1.0f : b->display_scale;
if (a == b) {
return 0;
} else if (a->w != b->w) {
return b->w - a->w;
} else if (a->h != b->h) {
return b->h - a->h;
} else if (a_display_scale != b_display_scale) {
return (int)(a_display_scale * 100) - (int)(b_display_scale * 100);
} else if (SDL_BITSPERPIXEL(a->format) != SDL_BITSPERPIXEL(b->format)) {
return SDL_BITSPERPIXEL(b->format) - SDL_BITSPERPIXEL(a->format);
} else if (SDL_PIXELLAYOUT(a->format) != SDL_PIXELLAYOUT(b->format)) {
Expand Down Expand Up @@ -588,6 +592,9 @@ int SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode)
SDL_zero(display);
if (desktop_mode) {
display.desktop_mode = *desktop_mode;
if (display.desktop_mode.display_scale == 0.0f) {
display.desktop_mode.display_scale = 1.0f;
}
}
display.current_mode = display.desktop_mode;

Expand Down Expand Up @@ -617,6 +624,12 @@ int SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event)
displays[index].name = SDL_strdup(name);
}

if (displays[index].desktop_mode.display_scale == 0.0f) {
displays[index].desktop_mode.display_scale = 1.0f;
}
if (displays[index].current_mode.display_scale == 0.0f) {
displays[index].current_mode.display_scale = 1.0f;
}
if (send_event) {
SDL_SendDisplayEvent(&_this->displays[index], SDL_EVENT_DISPLAY_CONNECTED, 0);
}
Expand Down Expand Up @@ -709,8 +722,8 @@ int SDL_GetDisplayBounds(int displayIndex, SDL_Rect *rect)
SDL_GetDisplayBounds(displayIndex - 1, rect);
rect->x += rect->w;
}
rect->w = display->current_mode.w;
rect->h = display->current_mode.h;
rect->w = (int)(display->current_mode.w / display->current_mode.display_scale);
rect->h = (int)(display->current_mode.h / display->current_mode.display_scale);
return 0;
}

Expand Down Expand Up @@ -791,16 +804,17 @@ SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mo

/* Go ahead and add the new mode */
if (nmodes == display->max_display_modes) {
modes =
SDL_realloc(modes,
(display->max_display_modes + 32) * sizeof(*modes));
modes = SDL_realloc(modes, (display->max_display_modes + 32) * sizeof(*modes));
if (modes == NULL) {
return SDL_FALSE;
}
display->display_modes = modes;
display->max_display_modes += 32;
}
modes[nmodes] = *mode;
if (modes[nmodes].display_scale == 0.0f) {
modes[nmodes].display_scale = 1.0f;
}
display->num_display_modes++;

/* Re-sort video modes */
Expand All @@ -813,11 +827,17 @@ SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mo
void SDL_SetCurrentDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
{
SDL_memcpy(&display->current_mode, mode, sizeof(*mode));
if (display->current_mode.display_scale == 0.0f) {
display->current_mode.display_scale = 1.0f;
}
}

void SDL_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
{
SDL_memcpy(&display->desktop_mode, mode, sizeof(*mode));
if (display->desktop_mode.display_scale == 0.0f) {
display->desktop_mode.display_scale = 1.0f;
}
}

static int SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay *display)
Expand Down Expand Up @@ -902,6 +922,7 @@ static SDL_DisplayMode *SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay *di
SDL_DisplayMode *closest)
{
Uint32 target_format;
float target_display_scale;
float target_refresh_rate;
int i;
SDL_DisplayMode *current, *match;
Expand All @@ -918,6 +939,13 @@ static SDL_DisplayMode *SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay *di
target_format = display->desktop_mode.format;
}

/* Default to 1.0 scale */
if (mode->display_scale > 0.0f) {
target_display_scale = mode->display_scale;
} else {
target_display_scale = 1.0f;
}

/* Default to the desktop refresh rate */
if (mode->refresh_rate > 0.0f) {
target_refresh_rate = mode->refresh_rate;
Expand Down Expand Up @@ -962,6 +990,14 @@ static SDL_DisplayMode *SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay *di
/* Sorted highest refresh to lowest */
if (current->refresh_rate >= target_refresh_rate) {
match = current;
continue;
}
}
if (current->display_scale != match->display_scale) {
/* Sorted lowest display scale to highest */
if (current->display_scale <= target_display_scale) {
match = current;
continue;
}
}
}
Expand All @@ -978,6 +1014,8 @@ static SDL_DisplayMode *SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay *di
closest->w = mode->w;
closest->h = mode->h;
}
closest->display_scale = mode->display_scale;

if (match->refresh_rate > 0.0f) {
closest->refresh_rate = match->refresh_rate;
} else {
Expand Down
2 changes: 2 additions & 0 deletions src/video/android/SDL_androidvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,11 @@ int Android_VideoInit(_THIS)
videodata->isPausing = SDL_FALSE;
videodata->pauseAudio = SDL_GetHintBoolean(SDL_HINT_ANDROID_BLOCK_ON_PAUSE_PAUSEAUDIO, SDL_TRUE);

SDL_zero(mode);
mode.format = Android_ScreenFormat;
mode.w = Android_DeviceWidth;
mode.h = Android_DeviceHeight;
mode.display_scale = 1.0f; /* FIXME */
mode.refresh_rate = Android_ScreenRate;
mode.driverdata = NULL;

Expand Down
16 changes: 10 additions & 6 deletions src/video/cocoa/SDL_cocoamodes.m
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ static SDL_bool GetDisplayMode(_THIS, CGDisplayModeRef vidmode, SDL_bool vidmode
bool usableForGUI = CGDisplayModeIsUsableForDesktopGUI(vidmode);
int width = (int)CGDisplayModeGetWidth(vidmode);
int height = (int)CGDisplayModeGetHeight(vidmode);
int pixelW = width;
int pixelH = height;
uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode);
float refreshrate = GetDisplayModeRefreshRate(vidmode, link);
Uint32 format = GetDisplayModePixelFormat(vidmode);
Expand All @@ -164,17 +166,17 @@ static SDL_bool GetDisplayMode(_THIS, CGDisplayModeRef vidmode, SDL_bool vidmode
modes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(modes, vidmode);

/* If a list of possible diplay modes is passed in, use it to filter out
/* If a list of possible display modes is passed in, use it to filter out
* modes that have duplicate sizes. We don't just rely on SDL's higher level
* duplicate filtering because this code can choose what properties are
* prefered, and it can add CGDisplayModes to the DisplayModeData's list of
* modes to try (see comment below for why that's necessary).
* CGDisplayModeGetPixelWidth and friends are only available in 10.8+. */
#ifdef MAC_OS_X_VERSION_10_8
if (modelist != NULL && floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_7) {
int pixelW = (int)CGDisplayModeGetPixelWidth(vidmode);
int pixelH = (int)CGDisplayModeGetPixelHeight(vidmode);
pixelW = (int)CGDisplayModeGetPixelWidth(vidmode);
pixelH = (int)CGDisplayModeGetPixelHeight(vidmode);

if (modelist != NULL && floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_7) {
CFIndex modescount = CFArrayGetCount(modelist);
int i;

Expand Down Expand Up @@ -254,15 +256,17 @@ static SDL_bool GetDisplayMode(_THIS, CGDisplayModeRef vidmode, SDL_bool vidmode
}
#endif

SDL_zerop(mode);
data = (SDL_DisplayModeData *)SDL_malloc(sizeof(*data));
if (!data) {
CFRelease(modes);
return SDL_FALSE;
}
data->modes = modes;
mode->format = format;
mode->w = width;
mode->h = height;
mode->w = pixelW;
mode->h = pixelH;
mode->display_scale = (float)pixelW / width;
mode->refresh_rate = refreshrate;
mode->driverdata = data;
return SDL_TRUE;
Expand Down
2 changes: 0 additions & 2 deletions src/video/dummy/SDL_nullvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ int DUMMY_VideoInit(_THIS)
mode.format = SDL_PIXELFORMAT_RGB888;
mode.w = 1024;
mode.h = 768;
mode.refresh_rate = 0.0f;
mode.driverdata = NULL;
if (SDL_AddBasicVideoDisplay(&mode) < 0) {
return -1;
}
Expand Down
3 changes: 1 addition & 2 deletions src/video/emscripten/SDL_emscriptenvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,10 @@ int Emscripten_VideoInit(_THIS)
SDL_DisplayMode mode;

/* Use a fake 32-bpp desktop mode */
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_RGB888;
emscripten_get_screen_size(&mode.w, &mode.h);

mode.refresh_rate = 0.0f;
mode.driverdata = NULL;
if (SDL_AddBasicVideoDisplay(&mode) < 0) {
return -1;
}
Expand Down
1 change: 1 addition & 0 deletions src/video/haiku/SDL_bmodes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ int32 HAIKU_ColorSpaceToSDLPxFormat(uint32 colorspace)

static void _BDisplayModeToSdlDisplayMode(display_mode *bmode,
SDL_DisplayMode *mode) {
SDL_zerop(mode);
mode->w = bmode->virtual_width;
mode->h = bmode->virtual_height;
mode->refresh_rate = get_refresh_rate(*bmode);
Expand Down
1 change: 1 addition & 0 deletions src/video/kmsdrm/SDL_kmsdrmvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,7 @@ void KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
modedata->mode_index = i;
}

SDL_zero(mode);
mode.w = conn->modes[i].hdisplay;
mode.h = conn->modes[i].vdisplay;
mode.refresh_rate = CalculateRefreshRate(&conn->modes[i]);
Expand Down
1 change: 0 additions & 1 deletion src/video/n3ds/SDL_n3dsvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ AddN3DSDisplay(gfxScreen_t screen)
mode.h = GSP_SCREEN_WIDTH;
mode.refresh_rate = 60.0f;
mode.format = FRAMEBUFFER_FORMAT;
mode.driverdata = NULL;

display.name = (screen == GFX_TOP) ? "N3DS top screen" : "N3DS bottom screen";
display.desktop_mode = mode;
Expand Down
3 changes: 1 addition & 2 deletions src/video/ngage/SDL_ngagevideo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,10 @@ int NGAGE_VideoInit(_THIS)
SDL_DisplayMode mode;

/* Use 12-bpp desktop mode */
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_RGB444;
mode.w = 176;
mode.h = 208;
mode.refresh_rate = 0.0f;
mode.driverdata = NULL;
if (SDL_AddBasicVideoDisplay(&mode) < 0) {
return -1;
}
Expand Down
4 changes: 1 addition & 3 deletions src/video/offscreen/SDL_offscreenvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,14 @@ int OFFSCREEN_VideoInit(_THIS)
SDL_DisplayMode mode;

/* Use a fake 32-bpp desktop mode */
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_RGB888;
mode.w = 1024;
mode.h = 768;
mode.refresh_rate = 0.0f;
mode.driverdata = NULL;
if (SDL_AddBasicVideoDisplay(&mode) < 0) {
return -1;
}

SDL_zero(mode);
SDL_AddDisplayMode(&_this->displays[0], &mode);

/* We're done! */
Expand Down
3 changes: 0 additions & 3 deletions src/video/ps2/SDL_ps2video.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,16 @@ static int PS2_VideoInit(_THIS)
SDL_DisplayMode current_mode;

SDL_zero(current_mode);

current_mode.w = 640;
current_mode.h = 480;
current_mode.refresh_rate = 60.0f;

/* 32 bpp for default */
current_mode.format = SDL_PIXELFORMAT_ABGR8888;
current_mode.driverdata = NULL;

SDL_zero(display);
display.desktop_mode = current_mode;
display.current_mode = current_mode;
display.driverdata = NULL;
SDL_AddDisplayMode(&display, &current_mode);

SDL_AddVideoDisplay(&display, SDL_FALSE);
Expand Down
Loading

0 comments on commit 321768f

Please sign in to comment.