From 6b64d92837628eaf9eb6bfe79353f95ae69b9ab1 Mon Sep 17 00:00:00 2001 From: Louis Kruger Date: Mon, 7 Oct 2019 14:37:16 -0400 Subject: [PATCH 1/2] - fix for resizing MacOS windows when both HIDPI and non-HIDPI monitors are connected - some refactoring to make these hacks a little less ugly --- app/src/scrcpy.c | 7 ++++- app/src/screen.c | 72 +++++++++++++++++++++++++++++------------------- app/src/screen.h | 5 ++++ 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index defcb751ba..cbf3a40ed0 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -144,8 +144,13 @@ handle_event(SDL_Event *event, bool control) { break; case SDL_WINDOWEVENT: switch (event->window.event) { - case SDL_WINDOWEVENT_EXPOSED: case SDL_WINDOWEVENT_SIZE_CHANGED: +#ifdef HIDPI_SUPPORT + LOGD("Reinitializing renderer"); + screen_init_renderer_and_texture(&screen); +#endif + // fall-through no break + case SDL_WINDOWEVENT_EXPOSED: screen_render(&screen); break; } diff --git a/app/src/screen.c b/app/src/screen.c index e34bcf46b0..52035a8084 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -46,6 +46,9 @@ set_window_size(struct screen *screen, struct size new_size) { screen->windowed_window_size = new_size; } else { SDL_SetWindowSize(screen->window, new_size.width, new_size.height); +#ifdef HIDPI_SUPPORT + screen_init_renderer_and_texture(screen); +#endif } } @@ -134,6 +137,42 @@ create_texture(SDL_Renderer *renderer, struct size frame_size) { frame_size.width, frame_size.height); } +// This may be called more than once to work around SDL bugs +bool +screen_init_renderer_and_texture(struct screen *screen) { + if (screen->texture != NULL) { + SDL_DestroyTexture(screen->texture); + screen->texture = NULL; + } + if (screen->renderer != NULL) { + SDL_DestroyRenderer(screen->renderer); + screen->renderer = NULL; + } + + screen->renderer = SDL_CreateRenderer(screen->window, -1, + SDL_RENDERER_ACCELERATED); + if (!screen->renderer) { + LOGC("Could not create renderer: %s", SDL_GetError()); + screen_destroy(screen); + return false; + } + + if (SDL_RenderSetLogicalSize(screen->renderer, screen->frame_size.width, + screen->frame_size.height)) { + LOGE("Could not set renderer logical size: %s", SDL_GetError()); + screen_destroy(screen); + return false; + } + + screen->texture = create_texture(screen->renderer, screen->frame_size); + if (!screen->texture) { + LOGC("Could not create texture: %s", SDL_GetError()); + screen_destroy(screen); + return false; + } + return true; +} + bool screen_init_rendering(struct screen *screen, const char *window_title, struct size frame_size, bool always_on_top) { @@ -162,21 +201,6 @@ screen_init_rendering(struct screen *screen, const char *window_title, return false; } - screen->renderer = SDL_CreateRenderer(screen->window, -1, - SDL_RENDERER_ACCELERATED); - if (!screen->renderer) { - LOGC("Could not create renderer: %s", SDL_GetError()); - screen_destroy(screen); - return false; - } - - if (SDL_RenderSetLogicalSize(screen->renderer, frame_size.width, - frame_size.height)) { - LOGE("Could not set renderer logical size: %s", SDL_GetError()); - screen_destroy(screen); - return false; - } - SDL_Surface *icon = read_xpm(icon_xpm); if (icon) { SDL_SetWindowIcon(screen->window, icon); @@ -187,14 +211,7 @@ screen_init_rendering(struct screen *screen, const char *window_title, LOGI("Initial texture: %" PRIu16 "x%" PRIu16, frame_size.width, frame_size.height); - screen->texture = create_texture(screen->renderer, frame_size); - if (!screen->texture) { - LOGC("Could not create texture: %s", SDL_GetError()); - screen_destroy(screen); - return false; - } - - return true; + return screen_init_renderer_and_texture(screen); } void @@ -300,8 +317,7 @@ screen_switch_fullscreen(struct screen *screen) { screen->fullscreen = !screen->fullscreen; if (!screen->fullscreen) { // fullscreen disabled, restore expected windowed window size - SDL_SetWindowSize(screen->window, screen->windowed_window_size.width, - screen->windowed_window_size.height); + set_window_size(screen, screen->windowed_window_size); } LOGD("Switched to %s mode", screen->fullscreen ? "fullscreen" : "windowed"); @@ -313,8 +329,7 @@ screen_resize_to_fit(struct screen *screen) { if (!screen->fullscreen) { struct size optimal_size = get_optimal_window_size(screen, screen->frame_size); - SDL_SetWindowSize(screen->window, optimal_size.width, - optimal_size.height); + set_window_size(screen, optimal_size); LOGD("Resized to optimal size"); } } @@ -322,8 +337,7 @@ screen_resize_to_fit(struct screen *screen) { void screen_resize_to_pixel_perfect(struct screen *screen) { if (!screen->fullscreen) { - SDL_SetWindowSize(screen->window, screen->frame_size.width, - screen->frame_size.height); + set_window_size(screen, screen->frame_size); LOGD("Resized to pixel-perfect"); } } diff --git a/app/src/screen.h b/app/src/screen.h index bc18918967..6f002d13d7 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -48,6 +48,11 @@ bool screen_init_rendering(struct screen *screen, const char *window_title, struct size frame_size, bool always_on_top); +// reinitialize the renderer (only used in some configurations +// if necessary to workaround SDL bugs) +bool +screen_init_renderer_and_texture(struct screen *screen); + // show the window void screen_show_window(struct screen *screen); From f4a7757fd083a0f8050babc4cc501eb13f5f0849 Mon Sep 17 00:00:00 2001 From: Louis Kruger Date: Tue, 15 Oct 2019 16:18:38 -0400 Subject: [PATCH 2/2] test if renderer re-initialization is really necessary --- app/src/scrcpy.c | 6 ++++-- app/src/screen.c | 26 +++++++++++++++++++++++++- app/src/screen.h | 18 ++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index cbf3a40ed0..cb4cfb36d9 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -146,8 +146,10 @@ handle_event(SDL_Event *event, bool control) { switch (event->window.event) { case SDL_WINDOWEVENT_SIZE_CHANGED: #ifdef HIDPI_SUPPORT - LOGD("Reinitializing renderer"); - screen_init_renderer_and_texture(&screen); + if (!screen_test_correct_hidpi_ratio(&screen)) { + LOGW("Reinitializing renderer due to incorrect hidpi ratio"); + screen_init_renderer_and_texture(&screen); + } #endif // fall-through no break case SDL_WINDOWEVENT_EXPOSED: diff --git a/app/src/screen.c b/app/src/screen.c index 52035a8084..8ec4fc9e35 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -47,7 +47,10 @@ set_window_size(struct screen *screen, struct size new_size) { } else { SDL_SetWindowSize(screen->window, new_size.width, new_size.height); #ifdef HIDPI_SUPPORT - screen_init_renderer_and_texture(screen); + if (!screen_test_correct_hidpi_ratio(screen)) { + LOGW("Reinitializing renderer due to incorrect hidpi ratio"); + screen_init_renderer_and_texture(screen); + } #endif } } @@ -164,6 +167,14 @@ screen_init_renderer_and_texture(struct screen *screen) { return false; } +#ifdef HIDPI_SUPPORT + int window_w, window_h, renderer_w, renderer_h; + SDL_GetWindowSize(screen->window, &window_w, &window_h); + SDL_GetRendererOutputSize(screen->renderer, &renderer_w, &renderer_h); + screen->expected_hidpi_w_factor = renderer_w * 1000 / window_w; + screen->expected_hidpi_h_factor = renderer_h * 1000 / window_h; +#endif + screen->texture = create_texture(screen->renderer, screen->frame_size); if (!screen->texture) { LOGC("Could not create texture: %s", SDL_GetError()); @@ -214,6 +225,19 @@ screen_init_rendering(struct screen *screen, const char *window_title, return screen_init_renderer_and_texture(screen); } +#ifdef HIDPI_SUPPORT +bool +screen_test_correct_hidpi_ratio(struct screen *screen) { + int window_w, window_h, renderer_w, renderer_h; + SDL_GetWindowSize(screen->window, &window_w, &window_h); + SDL_GetRendererOutputSize(screen->renderer, &renderer_w, &renderer_h); + int current_hidpi_w_factor = renderer_w * 1000 / window_w; + int current_hidpi_h_factor = renderer_h * 1000 / window_h; + return current_hidpi_w_factor == screen->expected_hidpi_w_factor && + current_hidpi_h_factor == screen->expected_hidpi_h_factor; +} +#endif + void screen_show_window(struct screen *screen) { SDL_ShowWindow(screen->window); diff --git a/app/src/screen.h b/app/src/screen.h index 6f002d13d7..f337903d24 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -20,6 +20,15 @@ struct screen { bool has_frame; bool fullscreen; bool no_window; +#ifdef HIDPI_SUPPORT + // these values store the ratio between renderer pixel size and window size + // in most configurations these ratios would be 1.0 (1000), but on MacOS with + // a Retina/HIDPI monitor connected they are 2.0 (2000) because that's how + // Apple chose to maintain compatibility with legacy apps, by pretending that + // that the screen has half of its real resolution. + int expected_hidpi_w_factor; // multiplied by 1000 to avoid float + int expected_hidpi_h_factor; // multiplied by 1000 to avoid float +#endif }; #define SCREEN_INITIALIZER { \ @@ -48,6 +57,15 @@ bool screen_init_rendering(struct screen *screen, const char *window_title, struct size frame_size, bool always_on_top); +#ifdef HIDPI_SUPPORT +// test if the expected renderer to window ratio is correct +// used to work around SDL bugs +// returns true if correct. +// If it returns false the renderer state needs to be fixed +bool +screen_test_correct_hidpi_ratio(struct screen *screen); +#endif + // reinitialize the renderer (only used in some configurations // if necessary to workaround SDL bugs) bool