summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-05-12 22:31:03 +0200
committerwm4 <wm4@nowhere>2015-05-12 22:31:03 +0200
commit7735b297329ed730f410b0b3cb6503eeea04ee90 (patch)
treeda08f366b88b5ebeea671c662d0be7eb1e09fe7a
parent434343d634177f4ca1d245d22107b905fbec0b74 (diff)
downloadmpv-7735b297329ed730f410b0b3cb6503eeea04ee90.tar.bz2
mpv-7735b297329ed730f410b0b3cb6503eeea04ee90.tar.xz
cocoa: handle live-resizing differently
Instead of requiring a complicated mechanism to share the entire OpenGL and renderer state between VO and Cocoa thread just to do the redrawing during live-resize on the Cocoa thread, let the Cocoa thread wait on the VO thread. This wil allow some major simplifications and cleanups in the future. One problem with this is that it can enter a deadlock whenever the VO tries to sync with the Cocoa thread. To deal with this, the Cocoa thread waits with a timeout. This can probably be improved later, though in general this situation can always happen, unless the Cocoa thread waits in a reentrant way. Some other details aren't completely clean either. For example, pending_events should be accessed atomically. This will also be fixed later.
-rw-r--r--video/out/cocoa_common.h4
-rw-r--r--video/out/cocoa_common.m72
-rw-r--r--video/out/gl_cocoa.c7
3 files changed, 41 insertions, 42 deletions
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)
+void vo_cocoa_swap_buffers(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
- s->skip_swap_buffer = false;
- return true;
-}
+ // Don't swap a frame with wrong size
+ if (s->pending_events & VO_EVENT_RESIZE)
+ return;
-void vo_cocoa_swap_buffers(struct vo *vo)
-{
- struct vo_cocoa_state *s = vo->cocoa;
+ [s->gl_ctx flushBuffer];
- if (s->skip_swap_buffer && !s->waiting_frame) {
- s->skip_swap_buffer = false;
- s->pending_events |= VO_EVENT_EXPOSE;
- } else {
- [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;