Merge pull request #118 from mihaip/upstream-hidpi

Enable HiDPI mode for SDL and ensure that we use nearest-neighbor scaling
This commit is contained in:
dingusdev
2024-11-09 16:59:15 -07:00
committed by GitHub
3 changed files with 41 additions and 7 deletions

View File

@@ -35,6 +35,12 @@ public:
uint32_t window_id; 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 { enum : uint32_t {
MOUSE_EVENT_MOTION = 1 << 0, MOUSE_EVENT_MOTION = 1 << 0,
MOUSE_EVENT_BUTTON = 1 << 1, MOUSE_EVENT_BUTTON = 1 << 1,

View File

@@ -54,14 +54,24 @@ void EventManager::poll_events()
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: { case SDL_KEYUP: {
// Internal shortcuts to trigger mouse grab, intentionally not // Internal shortcuts, intentionally not sent to the host.
// sent to the host. // Control-G: mouse grab
if (event.key.keysym.sym == SDLK_g && SDL_GetModState() & KMOD_LCTRL) { if (event.key.keysym.sym == SDLK_g && SDL_GetModState() & KMOD_LCTRL) {
if (event.type == SDL_KEYUP) { if (event.type == SDL_KEYUP) {
toggle_mouse_grab(event.key); toggle_mouse_grab(event.key);
} }
return; 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); int key_code = get_sdl_event_key_code(event.key);
if (key_code != -1) { if (key_code != -1) {
KeyboardEvent ke; KeyboardEvent ke;

View File

@@ -29,12 +29,15 @@ public:
uint32_t disp_wnd_id = 0; uint32_t disp_wnd_id = 0;
SDL_Window* display_wnd = 0; SDL_Window* display_wnd = 0;
SDL_Renderer* renderer = 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* disp_texture = 0;
SDL_Texture* cursor_texture = 0; SDL_Texture* cursor_texture = 0;
SDL_Rect cursor_rect; // destination rectangle for cursor drawing SDL_Rect cursor_rect; // destination rectangle for cursor drawing
}; };
Display::Display(): impl(std::make_unique<Impl>()) { Display::Display(): impl(std::make_unique<Impl>()) {
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
} }
Display::~Display() { Display::~Display() {
@@ -61,7 +64,7 @@ bool Display::configure(int width, int height) {
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width, height, width, height,
SDL_WINDOW_OPENGL SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI
); );
impl->disp_wnd_id = SDL_GetWindowID(impl->display_wnd); impl->disp_wnd_id = SDL_GetWindowID(impl->display_wnd);
@@ -72,6 +75,11 @@ bool Display::configure(int width, int height) {
if (impl->renderer == NULL) if (impl->renderer == NULL)
ABORT_F("Display: SDL_CreateRenderer failed with %s", SDL_GetError()); 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; is_initialization = true;
} else { // resize display window } else { // resize display window
SDL_SetWindowSize(impl->display_wnd, width, height); SDL_SetWindowSize(impl->display_wnd, width, height);
@@ -100,6 +108,16 @@ void Display::handle_events(const WindowEvent& wnd_event) {
if (wnd_event.sub_type == SDL_WINDOWEVENT_EXPOSED && if (wnd_event.sub_type == SDL_WINDOWEVENT_EXPOSED &&
wnd_event.window_id == impl->disp_wnd_id) wnd_event.window_id == impl->disp_wnd_id)
SDL_RenderPresent(impl->renderer); 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() { void Display::blank() {
@@ -133,8 +151,8 @@ void Display::update(std::function<void(uint8_t *dst_buf, int dst_pitch)> conver
// draw HW cursor if enabled // draw HW cursor if enabled
if (draw_hw_cursor) { if (draw_hw_cursor) {
impl->cursor_rect.x = cursor_x; impl->cursor_rect.x = cursor_x * impl->renderer_scale_x;
impl->cursor_rect.y = cursor_y; impl->cursor_rect.y = cursor_y * impl->renderer_scale_y;
SDL_RenderCopy(impl->renderer, impl->cursor_texture, NULL, &impl->cursor_rect); SDL_RenderCopy(impl->renderer, impl->cursor_texture, NULL, &impl->cursor_rect);
} }
@@ -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.x = 0;
impl->cursor_rect.y = 0; impl->cursor_rect.y = 0;
impl->cursor_rect.w = cursor_width; impl->cursor_rect.w = cursor_width * impl->renderer_scale_x;
impl->cursor_rect.h = cursor_height; impl->cursor_rect.h = cursor_height * impl->renderer_scale_y;
} }