Handling High DPI Displays in SDL2
What's the best approach for handling high DPI displays with SDL2?
Handling high DPI (HiDPI) displays in SDL2 is crucial for ensuring your game looks crisp on modern screens. SDL2 provides built-in support for HiDPI, but you need to set it up correctly. Here's a comprehensive approach:
Enable HiDPI Support
First, enable HiDPI support when creating your window:
#include <SDL.h>
#include <iostream>
int main() {
SDL_Init(SDL_INIT_VIDEO);
// Enable HiDPI support
SDL_SetHint(
SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
SDL_Window* window = SDL_CreateWindow(
"HiDPI Game", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, 800, 600,
SDL_WINDOW_ALLOW_HIGHDPI |
SDL_WINDOW_RESIZABLE);
if (!window) {
std::cout << "Failed to create window: " <<
SDL_GetError() << "\n";
return 1;
}
SDL_Renderer* renderer = SDL_CreateRenderer(
window, -1,
SDL_RENDERER_ACCELERATED |
SDL_RENDERER_PRESENTVSYNC);
if (!renderer) {
std::cout << "Failed to create renderer: "
<< SDL_GetError() << "\n";
return 1;
}
// Rest of the code...
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Get the Correct Window Size
The window size reported by SDL might not match the actual pixel size on HiDPI displays. Use SDL_GetRendererOutputSize()
to get the true pixel size:
int windowWidth, windowHeight,
renderWidth, renderHeight;
SDL_GetWindowSize(
window, &windowWidth, &windowHeight);
SDL_GetRendererOutputSize(
renderer, &renderWidth, &renderHeight);
float scaleX = renderWidth
/ static_cast<float>(windowWidth);
float scaleY = renderHeight
/ static_cast<float>(windowHeight);
std::cout << "Window size: " << windowWidth
<< "x" << windowHeight << "\n";
std::cout << "Render size: " << renderWidth
<< "x" << renderHeight << "\n";
std::cout << "Scale factor: " << scaleX
<< "x" << scaleY << "\n";
Scale Your Rendering
Use the scale factor when rendering:
SDL_Rect GetScaledRect(int x, int y, int w,
int h, float scaleX,
float scaleY) {
return SDL_Rect{
static_cast<int>(x * scaleX),
static_cast<int>(y * scaleY),
static_cast<int>(w * scaleX),
static_cast<int>(h * scaleY)};
}
// In your render loop:
SDL_Rect rect = GetScaledRect(
100, 100, 200, 200, scaleX, scaleY);
SDL_RenderFillRect(renderer, &rect);
Handle Input
Mouse input coordinates are already adjusted by SDL2, but you might need to scale other input values:
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
float gameX = mouseX / scaleX;
float gameY = mouseY / scaleY;
Load HiDPI Assets
For the best visual quality, provide high-resolution versions of your assets and scale them down as needed:
SDL_Surface* LoadScaledSurface(
const char* path, float scale) {
SDL_Surface* original = SDL_LoadBMP(path);
if (!original) return nullptr;
int newWidth = static_cast<int>(original->w *
scale);
int newHeight = static_cast<int>(original->h *
scale);
SDL_Surface* scaled =
SDL_CreateRGBSurface(0, newWidth, newHeight,
32, 0, 0, 0, 0);
SDL_BlitScaled(original, nullptr, scaled,
nullptr);
SDL_FreeSurface(original);
return scaled;
}
By following these steps, your SDL2 game will look great on both standard and HiDPI displays, providing a consistent experience across different screen resolutions.
Image Scaling and Aspect Ratios
Learn techniques for scaling images and working with aspect ratios