diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index defcb751ba..cb4cfb36d9 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -144,8 +144,15 @@ 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 + 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: screen_render(&screen); break; } diff --git a/app/src/screen.c b/app/src/screen.c index e34bcf46b0..8ec4fc9e35 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -46,6 +46,12 @@ 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 + if (!screen_test_correct_hidpi_ratio(screen)) { + LOGW("Reinitializing renderer due to incorrect hidpi ratio"); + screen_init_renderer_and_texture(screen); + } +#endif } } @@ -134,6 +140,50 @@ 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; + } + +#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()); + 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 +212,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,15 +222,21 @@ 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 screen_init_renderer_and_texture(screen); +} - return true; +#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) { @@ -300,8 +341,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 +353,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 +361,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..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,20 @@ 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 +screen_init_renderer_and_texture(struct screen *screen); + // show the window void screen_show_window(struct screen *screen);