diff --git a/video/out/cocoa_common.h b/video/out/cocoa_common.h index 0912fbb5c8..9adae029c7 100644 --- a/video/out/cocoa_common.h +++ b/video/out/cocoa_common.h @@ -30,14 +30,10 @@ void vo_cocoa_uninit(struct vo *vo); int vo_cocoa_config_window(struct vo *vo, uint32_t flags); void vo_cocoa_set_current_context(struct vo *vo, bool current); -bool vo_cocoa_start_frame(struct vo *vo); void vo_cocoa_swap_buffers(struct vo *vo); int vo_cocoa_check_events(struct vo *vo); int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg); -void vo_cocoa_register_resize_callback(struct vo *vo, - void (*cb)(struct vo *vo, int w, int h)); - void vo_cocoa_create_nsgl_ctx(struct vo *vo, void *ctx); void vo_cocoa_release_nsgl_ctx(struct vo *vo); diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m index 7a0e6429de..686a064eb9 100644 --- a/video/out/cocoa_common.m +++ b/video/out/cocoa_common.m @@ -35,6 +35,7 @@ #include "config.h" +#include "osdep/timer.h" #include "osdep/macosx_application.h" #include "osdep/macosx_application_objc.h" @@ -88,7 +89,13 @@ struct vo_cocoa_state { NSData *icc_fs_profile; id fs_icc_changed_ns_observer; - void (*resize_redraw)(struct vo *vo, int w, int h); + pthread_mutex_t resize_lock; + pthread_cond_t resize_wakeup; + + // Protected by the resize_lock + bool vo_ready; // the VO is in a state in which it can + // render frames + int frame_w, frame_h; // dimensions of the frame rendered }; static void with_cocoa_lock(struct vo_cocoa_state *s, void(^block)(void)) @@ -248,6 +255,8 @@ int vo_cocoa_init(struct vo *vo) .embedded = vo->opts->WinID >= 0, }; mpthread_mutex_init_recursive(&s->mutex); + pthread_mutex_init(&s->resize_lock, NULL); + pthread_cond_init(&s->resize_wakeup, NULL); vo->cocoa = s; cocoa_init_light_sensor(vo); return 1; @@ -273,17 +282,15 @@ static int vo_cocoa_set_cursor_visibility(struct vo *vo, bool *visible) return VO_TRUE; } -void vo_cocoa_register_resize_callback(struct vo *vo, - void (*cb)(struct vo *vo, int w, int h)) -{ - struct vo_cocoa_state *s = vo->cocoa; - s->resize_redraw = cb; -} - void vo_cocoa_uninit(struct vo *vo) { struct vo_cocoa_state *s = vo->cocoa; + pthread_mutex_lock(&s->resize_lock); + s->vo_ready = false; + pthread_cond_signal(&s->resize_wakeup); + pthread_mutex_unlock(&s->resize_lock); + with_cocoa_lock_on_main_thread_sync(vo, ^{ enable_power_management(s); cocoa_uninit_light_sensor(s); @@ -580,6 +587,10 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t flags) vo_set_level(vo, vo->opts->ontop); } + pthread_mutex_lock(&s->resize_lock); + s->vo_ready = true; + pthread_mutex_unlock(&s->resize_lock); + // trigger a resize -> don't set vo->dwidth and vo->dheight directly // since this block is executed asynchronously to the video // reconfiguration code. @@ -610,20 +621,22 @@ static void vo_cocoa_resize_redraw(struct vo *vo, int width, int height) { struct vo_cocoa_state *s = vo->cocoa; - if (!s->gl_ctx) - return; + struct timespec e = mp_time_us_to_timespec(mp_add_timeout(mp_time_us(), 0.1)); - if (!s->resize_redraw) - return; + pthread_mutex_lock(&s->resize_lock); - vo_cocoa_set_current_context(vo, true); + // Make sure at least one frame will be drawn + s->frame_w = s->frame_h = 0; - [s->gl_ctx update]; - s->resize_redraw(vo, width, height); - s->skip_swap_buffer = true; + s->pending_events |= VO_EVENT_RESIZE | VO_EVENT_EXPOSE; + vo_wakeup(vo); - [s->gl_ctx flushBuffer]; - vo_cocoa_set_current_context(vo, false); + while (s->frame_w != width && s->frame_h != height && s->vo_ready) { + if (pthread_cond_timedwait(&s->resize_wakeup, &s->resize_lock, &e)) + break; + } + + pthread_mutex_unlock(&s->resize_lock); } static void draw_changes_after_next_frame(struct vo *vo) @@ -635,24 +648,21 @@ static void draw_changes_after_next_frame(struct vo *vo) } } -bool vo_cocoa_start_frame(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - - s->skip_swap_buffer = false; - return true; -} - void vo_cocoa_swap_buffers(struct vo *vo) { struct vo_cocoa_state *s = vo->cocoa; - if (s->skip_swap_buffer && !s->waiting_frame) { - s->skip_swap_buffer = false; - s->pending_events |= VO_EVENT_EXPOSE; - } else { - [s->gl_ctx flushBuffer]; - } + // Don't swap a frame with wrong size + if (s->pending_events & VO_EVENT_RESIZE) + return; + + [s->gl_ctx flushBuffer]; + + pthread_mutex_lock(&s->resize_lock); + s->frame_w = vo->dwidth; + s->frame_h = vo->dheight; + pthread_cond_signal(&s->resize_wakeup); + pthread_mutex_unlock(&s->resize_lock); if (s->waiting_frame) { s->waiting_frame = false; diff --git a/video/out/gl_cocoa.c b/video/out/gl_cocoa.c index 1ff9c668ed..66c363f79a 100644 --- a/video/out/gl_cocoa.c +++ b/video/out/gl_cocoa.c @@ -153,11 +153,6 @@ static void releaseGlContext_cocoa(MPGLContext *ctx) CGLReleaseContext(p->ctx); } -static bool start_frame_cocoa(MPGLContext *ctx) -{ - return vo_cocoa_start_frame(ctx->vo); -} - static void swapGlBuffers_cocoa(MPGLContext *ctx) { vo_cocoa_swap_buffers(ctx->vo); @@ -174,9 +169,7 @@ void mpgl_set_backend_cocoa(MPGLContext *ctx) ctx->config_window = config_window_cocoa; ctx->releaseGlContext = releaseGlContext_cocoa; ctx->swapGlBuffers = swapGlBuffers_cocoa; - ctx->start_frame = start_frame_cocoa; ctx->vo_init = vo_cocoa_init; - ctx->register_resize_callback = vo_cocoa_register_resize_callback; ctx->vo_uninit = vo_cocoa_uninit; ctx->vo_control = vo_cocoa_control; ctx->set_current = set_current_cocoa;