Compare commits

...

3 Commits

Author SHA1 Message Date
Romain Vimont
2e425e6605 Fix HiDPI issues on secondary screen
Reset the renderer and texture on display scaling change.

FIXME problem with texture (see FIXME in code)

Co-authored-by: Louis Kruger <louisk@gmail.com>
2020-04-24 23:50:42 +02:00
Romain Vimont
f3b7712ea2 Add a mechanism to report errors on event handling
This paves the way to workaround HiDPI issues, which may recreate the
renderer and texture (which may fail) on window event.
2020-04-24 23:35:42 +02:00
Romain Vimont
04a31ef7b9 Remove HIDPI_SUPPORT compilation flag
We never need to build without HiDPI support.
2020-04-24 23:02:58 +02:00
5 changed files with 103 additions and 11 deletions

View File

@ -116,9 +116,6 @@ conf.set('DEFAULT_LOCK_VIDEO_ORIENTATION', '-1') # -1: unlocked
# overridden by option --bit-rate # overridden by option --bit-rate
conf.set('DEFAULT_BIT_RATE', '8000000') # 8Mbps conf.set('DEFAULT_BIT_RATE', '8000000') # 8Mbps
# enable High DPI support
conf.set('HIDPI_SUPPORT', get_option('hidpi_support'))
# disable console on Windows # disable console on Windows
conf.set('WINDOWS_NOCONSOLE', get_option('windows_noconsole')) conf.set('WINDOWS_NOCONSOLE', get_option('windows_noconsole'))

View File

@ -128,6 +128,7 @@ enum event_result {
EVENT_RESULT_CONTINUE, EVENT_RESULT_CONTINUE,
EVENT_RESULT_STOPPED_BY_USER, EVENT_RESULT_STOPPED_BY_USER,
EVENT_RESULT_STOPPED_BY_EOS, EVENT_RESULT_STOPPED_BY_EOS,
EVENT_RESULT_STOPPED_BY_ERROR,
}; };
static enum event_result static enum event_result
@ -150,7 +151,9 @@ handle_event(SDL_Event *event, bool control) {
} }
break; break;
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
screen_handle_window_event(&screen, &event->window); if (!screen_handle_window_event(&screen, &event->window)) {
return EVENT_RESULT_STOPPED_BY_ERROR;
}
break; break;
case SDL_TEXTINPUT: case SDL_TEXTINPUT:
if (!control) { if (!control) {
@ -222,6 +225,9 @@ event_loop(bool display, bool control) {
case EVENT_RESULT_STOPPED_BY_EOS: case EVENT_RESULT_STOPPED_BY_EOS:
LOGW("Device disconnected"); LOGW("Device disconnected");
return false; return false;
case EVENT_RESULT_STOPPED_BY_ERROR:
LOGC("Stopping due to unrecoverable error");
return false;
case EVENT_RESULT_CONTINUE: case EVENT_RESULT_CONTINUE:
break; break;
} }

View File

@ -217,10 +217,9 @@ screen_init_rendering(struct screen *screen, const char *window_title,
struct size window_size = struct size window_size =
get_initial_optimal_size(content_size, window_width, window_height); get_initial_optimal_size(content_size, window_width, window_height);
uint32_t window_flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE; uint32_t window_flags = SDL_WINDOW_HIDDEN
#ifdef HIDPI_SUPPORT | SDL_WINDOW_RESIZABLE
window_flags |= SDL_WINDOW_ALLOW_HIGHDPI; | SDL_WINDOW_ALLOW_HIGHDPI;
#endif
if (always_on_top) { if (always_on_top) {
#ifdef SCRCPY_SDL_HAS_WINDOW_ALWAYS_ON_TOP #ifdef SCRCPY_SDL_HAS_WINDOW_ALWAYS_ON_TOP
window_flags |= SDL_WINDOW_ALWAYS_ON_TOP; window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
@ -310,6 +309,11 @@ screen_init_rendering(struct screen *screen, const char *window_title,
screen->windowed_window_size = window_size; 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; return true;
} }
@ -519,11 +523,74 @@ screen_resize_to_pixel_perfect(struct screen *screen) {
content_size.height); content_size.height);
} }
void bool
screen_fix_hidpi(struct screen *screen) {
// If the scale ratio has changed, recreate the renderer to fix HiDPI issues
// <https://github.com/Genymobile/scrcpy/issues/15>
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, screen_handle_window_event(struct screen *screen,
const SDL_WindowEvent *event) { const SDL_WindowEvent *event) {
switch (event->event) { switch (event->event) {
case SDL_WINDOWEVENT_EXPOSED: case SDL_WINDOWEVENT_EXPOSED:
if (!screen_fix_hidpi(screen)) {
// unrecoverable
return false;
}
screen_render(screen); screen_render(screen);
break; break;
case SDL_WINDOWEVENT_SIZE_CHANGED: case SDL_WINDOWEVENT_SIZE_CHANGED:
@ -559,6 +626,8 @@ screen_handle_window_event(struct screen *screen,
apply_windowed_size(screen); apply_windowed_size(screen);
break; break;
} }
return true;
} }
struct point struct point

View File

@ -13,6 +13,11 @@
struct video_buffer; struct video_buffer;
struct scale_ratio {
int window;
int drawable;
};
struct screen { struct screen {
SDL_Window *window; SDL_Window *window;
SDL_Renderer *renderer; SDL_Renderer *renderer;
@ -33,6 +38,11 @@ struct screen {
bool maximized; bool maximized;
bool no_window; bool no_window;
bool mipmaps; bool mipmaps;
struct {
struct scale_ratio w;
struct scale_ratio h;
} scale;
}; };
#define SCREEN_INITIALIZER { \ #define SCREEN_INITIALIZER { \
@ -63,6 +73,16 @@ struct screen {
.maximized = false, \ .maximized = false, \
.no_window = false, \ .no_window = false, \
.mipmaps = false, \ .mipmaps = false, \
.scale = { \
.w = { \
.window = 0, \
.drawable = 0, \
}, \
.h = { \
.window = 0, \
.drawable = 0, \
}, \
} \
} }
// initialize default values // initialize default values
@ -111,7 +131,8 @@ void
screen_set_rotation(struct screen *screen, unsigned rotation); screen_set_rotation(struct screen *screen, unsigned rotation);
// react to window events // react to window events
void // return true on success, false on unrecoverable error
bool
screen_handle_window_event(struct screen *screen, const SDL_WindowEvent *event); screen_handle_window_event(struct screen *screen, const SDL_WindowEvent *event);
// convert point from window coordinates to frame coordinates // convert point from window coordinates to frame coordinates

View File

@ -4,6 +4,5 @@ option('crossbuild_windows', type: 'boolean', value: false, description: 'Build
option('windows_noconsole', type: 'boolean', value: false, description: 'Disable console on Windows (pass -mwindows flag)') option('windows_noconsole', type: 'boolean', value: false, description: 'Disable console on Windows (pass -mwindows flag)')
option('prebuilt_server', type: 'string', description: 'Path of the prebuilt server') option('prebuilt_server', type: 'string', description: 'Path of the prebuilt server')
option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable') option('portable', type: 'boolean', value: false, description: 'Use scrcpy-server from the same directory as the scrcpy executable')
option('hidpi_support', type: 'boolean', value: true, description: 'Enable High DPI support')
option('server_debugger', type: 'boolean', value: false, description: 'Run a server debugger and wait for a client to be attached') option('server_debugger', type: 'boolean', value: false, description: 'Run a server debugger and wait for a client to be attached')
option('server_debugger_method', type: 'combo', choices: ['old', 'new'], value: 'new', description: 'Select the debugger method (Android < 9: "old", Android >= 9: "new")') option('server_debugger_method', type: 'combo', choices: ['old', 'new'], value: 'new', description: 'Select the debugger method (Android < 9: "old", Android >= 9: "new")')