diff --git a/app/src/screen.c b/app/src/screen.c index 974935d5..3c452317 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -309,6 +309,11 @@ screen_init_rendering(struct screen *screen, const char *window_title, screen->windowed_window_size = window_size; + struct scale_ratio *rw = &screen->scale.w; + struct scale_ratio *rh = &screen->scale.h; + SDL_GetWindowSize(screen->window, &rw->window, &rh->window); + SDL_GL_GetDrawableSize(screen->window, &rw->drawable, &rh->drawable); + return true; } @@ -518,11 +523,74 @@ screen_resize_to_pixel_perfect(struct screen *screen) { content_size.height); } +bool +screen_fix_hidpi(struct screen *screen) { + // If the scale ratio has changed, recreate the renderer to fix HiDPI issues + // + + int ww, wh, dw, dh; + SDL_GetWindowSize(screen->window, &ww, &wh); + SDL_GL_GetDrawableSize(screen->window, &dw, &dh); + + struct scale_ratio *rw = &screen->scale.w; + struct scale_ratio *rh = &screen->scale.h; + + if (ww * rw->drawable == dw * rw->window && + wh * rh->drawable == dh * rh->window) { + // same ratio, both horizontally and vertically, nothing to do + return true; + } + + // update the current scale + rw->window = ww; + rh->window = wh; + rw->drawable = dw; + rh->drawable = dh; + + if (screen->texture) { + SDL_DestroyTexture(screen->texture); + } + if (screen->renderer) { + SDL_DestroyRenderer(screen->renderer); + } + + screen->renderer = SDL_CreateRenderer(screen->window, -1, + SDL_RENDERER_ACCELERATED); + if (!screen->renderer) { + LOGC("Could not create renderer: %s", SDL_GetError()); + return false; + } + + struct size content_size = screen->content_size; + if (SDL_RenderSetLogicalSize(screen->renderer, content_size.width, + content_size.height)) { + LOGE("Could not set renderer logical size: %s", SDL_GetError()); + SDL_DestroyRenderer(screen->renderer); + return false; + } + + // FIXME this is wrong, we must update the last frame to the new texture, + // but we don't have it anymore! + screen->texture = create_texture(screen); + if (!screen->texture) { + LOGC("Could not create texture: %s", SDL_GetError()); + SDL_DestroyRenderer(screen->renderer); + return false; + } + + LOGD("Renderer and texture reset"); + return true; +} + bool screen_handle_window_event(struct screen *screen, const SDL_WindowEvent *event) { switch (event->event) { case SDL_WINDOWEVENT_EXPOSED: + if (!screen_fix_hidpi(screen)) { + // unrecoverable + return false; + } screen_render(screen); break; case SDL_WINDOWEVENT_SIZE_CHANGED: diff --git a/app/src/screen.h b/app/src/screen.h index c52b7cb8..31f407bb 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -13,6 +13,11 @@ struct video_buffer; +struct scale_ratio { + int window; + int drawable; +}; + struct screen { SDL_Window *window; SDL_Renderer *renderer; @@ -33,6 +38,11 @@ struct screen { bool maximized; bool no_window; bool mipmaps; + + struct { + struct scale_ratio w; + struct scale_ratio h; + } scale; }; #define SCREEN_INITIALIZER { \ @@ -63,6 +73,16 @@ struct screen { .maximized = false, \ .no_window = false, \ .mipmaps = false, \ + .scale = { \ + .w = { \ + .window = 0, \ + .drawable = 0, \ + }, \ + .h = { \ + .window = 0, \ + .drawable = 0, \ + }, \ + } \ } // initialize default values