Accept texture failures
When the scrcpy window is minimized on Windows with D3D9, texture creation and update fail. In that case, do not terminate scrcpy. Instead, store the pending size or frame to update, to attempt again during the next update or rendering. Fixes #3947 <https://github.com/Genymobile/scrcpy/issues/3947>
This commit is contained in:
parent
7d33798b40
commit
6298ef095f
3 changed files with 147 additions and 21 deletions
|
@ -62,11 +62,17 @@ sc_display_init(struct sc_display *display, SDL_Window *window, bool mipmaps) {
|
||||||
LOGD("Trilinear filtering disabled (not an OpenGL renderer");
|
LOGD("Trilinear filtering disabled (not an OpenGL renderer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display->pending.flags = 0;
|
||||||
|
display->pending.frame = NULL;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_display_destroy(struct sc_display *display) {
|
sc_display_destroy(struct sc_display *display) {
|
||||||
|
if (display->pending.frame) {
|
||||||
|
av_frame_free(&display->pending.frame);
|
||||||
|
}
|
||||||
#ifdef SC_DISPLAY_FORCE_OPENGL_CORE_PROFILE
|
#ifdef SC_DISPLAY_FORCE_OPENGL_CORE_PROFILE
|
||||||
SDL_GL_DeleteContext(display->gl_context);
|
SDL_GL_DeleteContext(display->gl_context);
|
||||||
#endif
|
#endif
|
||||||
|
@ -84,7 +90,7 @@ sc_display_create_texture(struct sc_display *display,
|
||||||
SDL_TEXTUREACCESS_STREAMING,
|
SDL_TEXTUREACCESS_STREAMING,
|
||||||
size.width, size.height);
|
size.width, size.height);
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
LOGE("Could not create texture: %s", SDL_GetError());
|
LOGD("Could not create texture: %s", SDL_GetError());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,8 +110,66 @@ sc_display_create_texture(struct sc_display *display,
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static inline void
|
||||||
sc_display_set_texture_size(struct sc_display *display, struct sc_size size) {
|
sc_display_set_pending_size(struct sc_display *display, struct sc_size size) {
|
||||||
|
assert(!display->texture);
|
||||||
|
display->pending.size = size;
|
||||||
|
display->pending.flags |= SC_DISPLAY_PENDING_FLAG_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sc_display_set_pending_frame(struct sc_display *display, const AVFrame *frame) {
|
||||||
|
if (!display->pending.frame) {
|
||||||
|
display->pending.frame = av_frame_alloc();
|
||||||
|
if (!display->pending.frame) {
|
||||||
|
LOG_OOM();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int r = av_frame_ref(display->pending.frame, frame);
|
||||||
|
if (r) {
|
||||||
|
LOGE("Could not ref frame: %d", r);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
display->pending.flags |= SC_DISPLAY_PENDING_FLAG_FRAME;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sc_display_apply_pending(struct sc_display *display) {
|
||||||
|
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_SIZE) {
|
||||||
|
assert(!display->texture);
|
||||||
|
display->texture =
|
||||||
|
sc_display_create_texture(display, display->pending.size);
|
||||||
|
if (!display->texture) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
display->pending.flags &= ~SC_DISPLAY_PENDING_FLAG_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_FRAME) {
|
||||||
|
assert(display->pending.frame);
|
||||||
|
bool ok = sc_display_update_texture(display, display->pending.frame);
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_frame_unref(display->pending.frame);
|
||||||
|
display->pending.flags &= ~SC_DISPLAY_PENDING_FLAG_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sc_display_set_texture_size_internal(struct sc_display *display,
|
||||||
|
struct sc_size size) {
|
||||||
|
assert(size.width && size.height);
|
||||||
|
|
||||||
if (display->texture) {
|
if (display->texture) {
|
||||||
SDL_DestroyTexture(display->texture);
|
SDL_DestroyTexture(display->texture);
|
||||||
}
|
}
|
||||||
|
@ -119,14 +183,27 @@ sc_display_set_texture_size(struct sc_display *display, struct sc_size size) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
enum sc_display_result
|
||||||
sc_display_update_texture(struct sc_display *display, const AVFrame *frame) {
|
sc_display_set_texture_size(struct sc_display *display, struct sc_size size) {
|
||||||
|
bool ok = sc_display_set_texture_size_internal(display, size);
|
||||||
|
if (!ok) {
|
||||||
|
sc_display_set_pending_size(display, size);
|
||||||
|
return SC_DISPLAY_RESULT_PENDING;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return SC_DISPLAY_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sc_display_update_texture_internal(struct sc_display *display,
|
||||||
|
const AVFrame *frame) {
|
||||||
int ret = SDL_UpdateYUVTexture(display->texture, NULL,
|
int ret = SDL_UpdateYUVTexture(display->texture, NULL,
|
||||||
frame->data[0], frame->linesize[0],
|
frame->data[0], frame->linesize[0],
|
||||||
frame->data[1], frame->linesize[1],
|
frame->data[1], frame->linesize[1],
|
||||||
frame->data[2], frame->linesize[2]);
|
frame->data[2], frame->linesize[2]);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
LOGE("Could not update texture: %s", SDL_GetError());
|
LOGD("Could not update texture: %s", SDL_GetError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,11 +216,34 @@ sc_display_update_texture(struct sc_display *display, const AVFrame *frame) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
enum sc_display_result
|
||||||
|
sc_display_update_texture(struct sc_display *display, const AVFrame *frame) {
|
||||||
|
bool ok = sc_display_update_texture_internal(display, frame);
|
||||||
|
if (!ok) {
|
||||||
|
ok = sc_display_set_pending_frame(display, frame);
|
||||||
|
if (!ok) {
|
||||||
|
LOGE("Could not set pending frame");
|
||||||
|
return SC_DISPLAY_RESULT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SC_DISPLAY_RESULT_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SC_DISPLAY_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum sc_display_result
|
||||||
sc_display_render(struct sc_display *display, const SDL_Rect *geometry,
|
sc_display_render(struct sc_display *display, const SDL_Rect *geometry,
|
||||||
unsigned rotation) {
|
unsigned rotation) {
|
||||||
SDL_RenderClear(display->renderer);
|
SDL_RenderClear(display->renderer);
|
||||||
|
|
||||||
|
if (display->pending.flags) {
|
||||||
|
bool ok = sc_display_apply_pending(display);
|
||||||
|
if (!ok) {
|
||||||
|
return SC_DISPLAY_RESULT_PENDING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SDL_Renderer *renderer = display->renderer;
|
SDL_Renderer *renderer = display->renderer;
|
||||||
SDL_Texture *texture = display->texture;
|
SDL_Texture *texture = display->texture;
|
||||||
|
|
||||||
|
@ -151,7 +251,7 @@ sc_display_render(struct sc_display *display, const SDL_Rect *geometry,
|
||||||
int ret = SDL_RenderCopy(renderer, texture, NULL, geometry);
|
int ret = SDL_RenderCopy(renderer, texture, NULL, geometry);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
LOGE("Could not render texture: %s", SDL_GetError());
|
LOGE("Could not render texture: %s", SDL_GetError());
|
||||||
return false;
|
return SC_DISPLAY_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// rotation in RenderCopyEx() is clockwise, while screen->rotation is
|
// rotation in RenderCopyEx() is clockwise, while screen->rotation is
|
||||||
|
@ -176,10 +276,10 @@ sc_display_render(struct sc_display *display, const SDL_Rect *geometry,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
LOGE("Could not render texture: %s", SDL_GetError());
|
LOGE("Could not render texture: %s", SDL_GetError());
|
||||||
return false;
|
return SC_DISPLAY_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_RenderPresent(display->renderer);
|
SDL_RenderPresent(display->renderer);
|
||||||
return true;
|
return SC_DISPLAY_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,20 @@ struct sc_display {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool mipmaps;
|
bool mipmaps;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
#define SC_DISPLAY_PENDING_FLAG_SIZE 1
|
||||||
|
#define SC_DISPLAY_PENDING_FLAG_FRAME 2
|
||||||
|
int8_t flags;
|
||||||
|
struct sc_size size;
|
||||||
|
AVFrame *frame;
|
||||||
|
} pending;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum sc_display_result {
|
||||||
|
SC_DISPLAY_RESULT_OK,
|
||||||
|
SC_DISPLAY_RESULT_PENDING,
|
||||||
|
SC_DISPLAY_RESULT_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -32,13 +46,13 @@ sc_display_init(struct sc_display *display, SDL_Window *window, bool mipmaps);
|
||||||
void
|
void
|
||||||
sc_display_destroy(struct sc_display *display);
|
sc_display_destroy(struct sc_display *display);
|
||||||
|
|
||||||
bool
|
enum sc_display_result
|
||||||
sc_display_set_texture_size(struct sc_display *display, struct sc_size size);
|
sc_display_set_texture_size(struct sc_display *display, struct sc_size size);
|
||||||
|
|
||||||
bool
|
enum sc_display_result
|
||||||
sc_display_update_texture(struct sc_display *display, const AVFrame *frame);
|
sc_display_update_texture(struct sc_display *display, const AVFrame *frame);
|
||||||
|
|
||||||
bool
|
enum sc_display_result
|
||||||
sc_display_render(struct sc_display *display, const SDL_Rect *geometry,
|
sc_display_render(struct sc_display *display, const SDL_Rect *geometry,
|
||||||
unsigned rotation);
|
unsigned rotation);
|
||||||
|
|
||||||
|
|
|
@ -249,9 +249,9 @@ sc_screen_render(struct sc_screen *screen, bool update_content_rect) {
|
||||||
sc_screen_update_content_rect(screen);
|
sc_screen_update_content_rect(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = sc_display_render(&screen->display, &screen->rect,
|
enum sc_display_result res =
|
||||||
screen->rotation);
|
sc_display_render(&screen->display, &screen->rect, screen->rotation);
|
||||||
(void) ok; // error already logged
|
(void) res; // any error already logged
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__WINDOWS__)
|
#if defined(__APPLE__) || defined(__WINDOWS__)
|
||||||
|
@ -583,15 +583,17 @@ sc_screen_init_size(struct sc_screen *screen) {
|
||||||
get_rotated_size(screen->frame_size, screen->rotation);
|
get_rotated_size(screen->frame_size, screen->rotation);
|
||||||
screen->content_size = content_size;
|
screen->content_size = content_size;
|
||||||
|
|
||||||
return sc_display_set_texture_size(&screen->display, screen->frame_size);
|
enum sc_display_result res =
|
||||||
|
sc_display_set_texture_size(&screen->display, screen->frame_size);
|
||||||
|
return res != SC_DISPLAY_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// recreate the texture and resize the window if the frame size has changed
|
// recreate the texture and resize the window if the frame size has changed
|
||||||
static bool
|
static enum sc_display_result
|
||||||
prepare_for_frame(struct sc_screen *screen, struct sc_size new_frame_size) {
|
prepare_for_frame(struct sc_screen *screen, struct sc_size new_frame_size) {
|
||||||
if (screen->frame_size.width == new_frame_size.width
|
if (screen->frame_size.width == new_frame_size.width
|
||||||
&& screen->frame_size.height == new_frame_size.height) {
|
&& screen->frame_size.height == new_frame_size.height) {
|
||||||
return true;
|
return SC_DISPLAY_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// frame dimension changed
|
// frame dimension changed
|
||||||
|
@ -615,13 +617,23 @@ sc_screen_update_frame(struct sc_screen *screen) {
|
||||||
sc_fps_counter_add_rendered_frame(&screen->fps_counter);
|
sc_fps_counter_add_rendered_frame(&screen->fps_counter);
|
||||||
|
|
||||||
struct sc_size new_frame_size = {frame->width, frame->height};
|
struct sc_size new_frame_size = {frame->width, frame->height};
|
||||||
if (!prepare_for_frame(screen, new_frame_size)) {
|
enum sc_display_result res = prepare_for_frame(screen, new_frame_size);
|
||||||
|
if (res == SC_DISPLAY_RESULT_ERROR) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (res == SC_DISPLAY_RESULT_PENDING) {
|
||||||
|
// Not an error, but do not continue
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sc_display_update_texture(&screen->display, frame)) {
|
res = sc_display_update_texture(&screen->display, frame);
|
||||||
|
if (res == SC_DISPLAY_RESULT_ERROR) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (res == SC_DISPLAY_RESULT_PENDING) {
|
||||||
|
// Not an error, but do not continue
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!screen->has_frame) {
|
if (!screen->has_frame) {
|
||||||
screen->has_frame = true;
|
screen->has_frame = true;
|
||||||
|
|
Loading…
Reference in a new issue