Skip to content

Enable HiDPI mode for SDL and ensure that we use nearest-neighbor scaling #118

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions core/hostevents.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ class WindowEvent {
uint32_t window_id;
};

enum : uint16_t {
// Standard SDL window event types are uint8_t's, we add our own custom
// events after that.
WINDOW_SCALE_QUALITY_TOGGLE = 1 << 8,
};

enum : uint32_t {
MOUSE_EVENT_MOTION = 1 << 0,
MOUSE_EVENT_BUTTON = 1 << 1,
Expand Down
14 changes: 12 additions & 2 deletions core/hostevents_sdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,24 @@ void EventManager::poll_events()

case SDL_KEYDOWN:
case SDL_KEYUP: {
// Internal shortcuts to trigger mouse grab, intentionally not
// sent to the host.
// Internal shortcuts, intentionally not sent to the host.
// Control-G: mouse grab
if (event.key.keysym.sym == SDLK_g && SDL_GetModState() & KMOD_LCTRL) {
if (event.type == SDL_KEYUP) {
toggle_mouse_grab(event.key);
}
return;
}
// Control-S: scale quality
if (event.key.keysym.sym == SDLK_s && SDL_GetModState() & KMOD_LCTRL) {
if (event.type == SDL_KEYUP) {
WindowEvent we;
we.sub_type = WINDOW_SCALE_QUALITY_TOGGLE;
we.window_id = event.window.windowID;
this->_window_signal.emit(we);
}
return;
}
int key_code = get_sdl_event_key_code(event.key);
if (key_code != -1) {
KeyboardEvent ke;
Expand Down
28 changes: 23 additions & 5 deletions devices/video/display_sdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ class Display::Impl {
uint32_t disp_wnd_id = 0;
SDL_Window* display_wnd = 0;
SDL_Renderer* renderer = 0;
double renderer_scale_x; // scaling factor from guest OS to host OS
double renderer_scale_y;
SDL_Texture* disp_texture = 0;
SDL_Texture* cursor_texture = 0;
SDL_Rect cursor_rect; // destination rectangle for cursor drawing
};

Display::Display(): impl(std::make_unique<Impl>()) {
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
}

Display::~Display() {
Expand All @@ -61,7 +64,7 @@ bool Display::configure(int width, int height) {
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width, height,
SDL_WINDOW_OPENGL
SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI
);

impl->disp_wnd_id = SDL_GetWindowID(impl->display_wnd);
Expand All @@ -72,6 +75,11 @@ bool Display::configure(int width, int height) {
if (impl->renderer == NULL)
ABORT_F("Display: SDL_CreateRenderer failed with %s", SDL_GetError());

int drawable_width, drawable_height;
SDL_GetRendererOutputSize(impl->renderer, &drawable_width, &drawable_height);
impl->renderer_scale_x = static_cast<double>(drawable_width) / width;
impl->renderer_scale_y = static_cast<float>(drawable_height) / height;

is_initialization = true;
} else { // resize display window
SDL_SetWindowSize(impl->display_wnd, width, height);
Expand Down Expand Up @@ -100,6 +108,16 @@ void Display::handle_events(const WindowEvent& wnd_event) {
if (wnd_event.sub_type == SDL_WINDOWEVENT_EXPOSED &&
wnd_event.window_id == impl->disp_wnd_id)
SDL_RenderPresent(impl->renderer);
if (wnd_event.sub_type == WINDOW_SCALE_QUALITY_TOGGLE &&
wnd_event.window_id == impl->disp_wnd_id) {
auto current_quality = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
auto new_quality = current_quality == NULL || strcmp(current_quality, "nearest") == 0 ? "best" : "nearest";
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, new_quality);
// We need the window/texture to be recreated to pick up the hint change.
int width, height;
SDL_GetWindowSize(impl->display_wnd, &width, &height);
this->configure(width, height);
}
}

void Display::blank() {
Expand Down Expand Up @@ -133,8 +151,8 @@ void Display::update(std::function<void(uint8_t *dst_buf, int dst_pitch)> conver

// draw HW cursor if enabled
if (draw_hw_cursor) {
impl->cursor_rect.x = cursor_x;
impl->cursor_rect.y = cursor_y;
impl->cursor_rect.x = cursor_x * impl->renderer_scale_x;
impl->cursor_rect.y = cursor_y * impl->renderer_scale_y;
SDL_RenderCopy(impl->renderer, impl->cursor_texture, NULL, &impl->cursor_rect);
}

Expand Down Expand Up @@ -170,6 +188,6 @@ void Display::setup_hw_cursor(std::function<void(uint8_t *dst_buf, int dst_pitch

impl->cursor_rect.x = 0;
impl->cursor_rect.y = 0;
impl->cursor_rect.w = cursor_width;
impl->cursor_rect.h = cursor_height;
impl->cursor_rect.w = cursor_width * impl->renderer_scale_x;
impl->cursor_rect.h = cursor_height * impl->renderer_scale_y;
}
Loading