int mpv_opengl_cb_init_gl(struct mpv_opengl_cb_context *ctx, const char *exts, mpv_opengl_cb_get_proc_address_fn get_proc_address, void *get_proc_address_ctx) { if (ctx->renderer) return MPV_ERROR_INVALID_PARAMETER; mpgl_load_functions2(ctx->gl, get_proc_address, get_proc_address_ctx, exts, ctx->log); ctx->renderer = gl_video_init(ctx->gl, ctx->log, ctx->osd); if (!ctx->renderer) return MPV_ERROR_UNSUPPORTED; ctx->hwdec = gl_hwdec_load_api(ctx->log, ctx->gl, ctx->hwapi, &ctx->hwdec_info); gl_video_set_hwdec(ctx->renderer, ctx->hwdec); pthread_mutex_lock(&ctx->lock); for (int n = IMGFMT_START; n < IMGFMT_END; n++) { ctx->imgfmt_supported[n - IMGFMT_START] = gl_video_check_format(ctx->renderer, n); } ctx->initialized = true; pthread_mutex_unlock(&ctx->lock); gl_video_unset_gl_state(ctx->renderer); return 0; }
int mpv_opengl_cb_init_gl(struct mpv_opengl_cb_context *ctx, const char *exts, mpv_opengl_cb_get_proc_address_fn get_proc_address, void *get_proc_address_ctx) { if (ctx->renderer) return MPV_ERROR_INVALID_PARAMETER; ctx->gl = talloc_zero(ctx, GL); mpgl_load_functions2(ctx->gl, get_proc_address, get_proc_address_ctx, exts, ctx->log); ctx->renderer = gl_video_init(ctx->gl, ctx->log, ctx->global); if (!ctx->renderer) return MPV_ERROR_UNSUPPORTED; ctx->hwdec = gl_hwdec_load_api_id(ctx->log, ctx->gl, ctx->global, ctx->hwdec_api); gl_video_set_hwdec(ctx->renderer, ctx->hwdec); if (ctx->hwdec) ctx->hwdec_info.hwctx = ctx->hwdec->hwctx; pthread_mutex_lock(&ctx->lock); // We don't know the exact caps yet - use a known superset ctx->eq.capabilities = MP_CSP_EQ_CAPS_GAMMA | MP_CSP_EQ_CAPS_BRIGHTNESS | MP_CSP_EQ_CAPS_COLORMATRIX; ctx->eq_changed = true; for (int n = IMGFMT_START; n < IMGFMT_END; n++) { ctx->imgfmt_supported[n - IMGFMT_START] = gl_video_check_format(ctx->renderer, n); } ctx->initialized = true; pthread_mutex_unlock(&ctx->lock); gl_video_unset_gl_state(ctx->renderer); return 0; }
int mpv_opengl_cb_render(struct mpv_opengl_cb_context *ctx, int fbo, int vp[4]) { assert(ctx->renderer); gl_video_set_gl_state(ctx->renderer); pthread_mutex_lock(&ctx->lock); struct vo *vo = ctx->active; ctx->force_update |= ctx->reconfigured; int h = vp[3]; bool flip = h < 0 && h > INT_MIN; if (flip) h = -h; struct mp_rect wnd = {vp[0], vp[1], vp[0] + vp[2], vp[1] + h}; if (wnd.x0 != ctx->wnd.x0 || wnd.y0 != ctx->wnd.y0 || wnd.x1 != ctx->wnd.x1 || wnd.y1 != ctx->wnd.y1 || ctx->flip != flip) ctx->force_update = true; if (ctx->force_update && vo) { ctx->force_update = false; ctx->wnd = wnd; struct mp_rect src, dst; struct mp_osd_res osd; mp_get_src_dst_rects(ctx->log, &ctx->vo_opts, vo->driver->caps, &ctx->img_params, wnd.x1 - wnd.x0, wnd.y1 - wnd.y0, 1.0, &src, &dst, &osd); gl_video_resize(ctx->renderer, &wnd, &src, &dst, &osd, !ctx->flip); } if (vo) { struct vo_priv *p = vo->priv; if (ctx->reconfigured) gl_video_config(ctx->renderer, &ctx->img_params); if (ctx->reconfigured || ctx->update_new_opts) { struct vo_priv *opts = p->ctx->new_opts ? p->ctx->new_opts : p; gl_video_set_options(ctx->renderer, opts->renderer_opts); ctx->gl->debug_context = opts->use_gl_debug; gl_video_set_debug(ctx->renderer, opts->use_gl_debug); } ctx->reconfigured = false; ctx->update_new_opts = false; } struct mp_image *mpi = ctx->next_frame; ctx->next_frame = NULL; pthread_mutex_unlock(&ctx->lock); if (mpi) gl_video_upload_image(ctx->renderer, mpi); gl_video_render_frame(ctx->renderer, fbo); gl_video_unset_gl_state(ctx->renderer); return 0; }
int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h) { assert(ctx->renderer); gl_video_set_gl_state(ctx->renderer); pthread_mutex_lock(&ctx->lock); struct vo *vo = ctx->active; ctx->force_update |= ctx->reconfigured; if (ctx->vp_w != vp_w || ctx->vp_h != vp_h) ctx->force_update = true; if (ctx->force_update && vo) { ctx->force_update = false; ctx->vp_w = vp_w; ctx->vp_h = vp_h; struct mp_rect src, dst; struct mp_osd_res osd; mp_get_src_dst_rects(ctx->log, &ctx->vo_opts, vo->driver->caps, &ctx->img_params, vp_w, abs(vp_h), 1.0, &src, &dst, &osd); gl_video_resize(ctx->renderer, vp_w, vp_h, &src, &dst, &osd); } if (ctx->reconfigured) { gl_video_set_osd_source(ctx->renderer, vo ? vo->osd : NULL); gl_video_config(ctx->renderer, &ctx->img_params); } if (ctx->update_new_opts) { struct vo_priv *p = vo ? vo->priv : NULL; struct vo_priv *opts = ctx->new_opts ? ctx->new_opts : p; if (opts) { gl_video_set_options(ctx->renderer, opts->renderer_opts, NULL); ctx->gl->debug_context = opts->use_gl_debug; gl_video_set_debug(ctx->renderer, opts->use_gl_debug); frame_queue_shrink(ctx, opts->frame_queue_size); } } ctx->reconfigured = false; ctx->update_new_opts = false; struct mp_csp_equalizer *eq = gl_video_eq_ptr(ctx->renderer); if (ctx->eq_changed) { memcpy(eq->values, ctx->eq.values, sizeof(eq->values)); gl_video_eq_update(ctx->renderer); } ctx->eq_changed = false; ctx->eq = *eq; struct mp_image *mpi = frame_queue_pop(ctx); pthread_mutex_unlock(&ctx->lock); if (mpi) gl_video_set_image(ctx->renderer, mpi); gl_video_render_frame(ctx->renderer, fbo, NULL); gl_video_unset_gl_state(ctx->renderer); pthread_mutex_lock(&ctx->lock); const int left = ctx->queued_frames; if (vo && left > 0) update(vo->priv); pthread_mutex_unlock(&ctx->lock); return left; }
int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h) { assert(ctx->renderer); gl_video_set_gl_state(ctx->renderer); pthread_mutex_lock(&ctx->lock); struct vo *vo = ctx->active; ctx->force_update |= ctx->reconfigured; if (ctx->vp_w != vp_w || ctx->vp_h != vp_h) ctx->force_update = true; if (ctx->force_update && vo) { ctx->force_update = false; ctx->vp_w = vp_w; ctx->vp_h = vp_h; struct mp_rect src, dst; struct mp_osd_res osd; mp_get_src_dst_rects(ctx->log, &ctx->vo_opts, vo->driver->caps, &ctx->img_params, vp_w, abs(vp_h), 1.0, &src, &dst, &osd); gl_video_resize(ctx->renderer, vp_w, vp_h, &src, &dst, &osd); } if (ctx->reconfigured) { gl_video_set_osd_source(ctx->renderer, vo ? vo->osd : NULL); gl_video_config(ctx->renderer, &ctx->img_params); ctx->eq_changed = true; } if (ctx->update_new_opts) { struct vo_priv *p = vo ? vo->priv : NULL; struct vo_priv *opts = ctx->new_opts ? ctx->new_opts : p; if (opts) { gl_video_set_options(ctx->renderer, opts->renderer_opts); if (vo) gl_video_configure_queue(ctx->renderer, vo); ctx->gl->debug_context = opts->use_gl_debug; gl_video_set_debug(ctx->renderer, opts->use_gl_debug); } } ctx->reconfigured = false; ctx->update_new_opts = false; if (ctx->reset) { gl_video_reset(ctx->renderer); ctx->reset = false; if (ctx->cur_frame) ctx->cur_frame->still = true; } struct mp_csp_equalizer *eq = gl_video_eq_ptr(ctx->renderer); if (ctx->eq_changed) { memcpy(eq->values, ctx->eq.values, sizeof(eq->values)); gl_video_eq_update(ctx->renderer); } ctx->eq_changed = false; struct vo_frame *frame = ctx->next_frame; int64_t wait_present_count = ctx->present_count; if (frame) { ctx->next_frame = NULL; wait_present_count += 1; pthread_cond_signal(&ctx->wakeup); talloc_free(ctx->cur_frame); ctx->cur_frame = vo_frame_ref(frame); } else { frame = vo_frame_ref(ctx->cur_frame); if (frame) frame->redraw = true; MP_STATS(ctx, "glcb-noframe"); } struct vo_frame dummy = {0}; if (!frame) frame = &dummy; pthread_mutex_unlock(&ctx->lock); MP_STATS(ctx, "glcb-render"); gl_video_render_frame(ctx->renderer, frame, fbo); gl_video_unset_gl_state(ctx->renderer); if (frame != &dummy) talloc_free(frame); pthread_mutex_lock(&ctx->lock); while (wait_present_count > ctx->present_count) pthread_cond_wait(&ctx->wakeup, &ctx->lock); pthread_mutex_unlock(&ctx->lock); return 0; }
int mpv_opengl_cb_draw(mpv_opengl_cb_context *ctx, int fbo, int vp_w, int vp_h) { assert(ctx->renderer); gl_video_set_gl_state(ctx->renderer); pthread_mutex_lock(&ctx->lock); struct vo *vo = ctx->active; ctx->force_update |= ctx->reconfigured; if (ctx->vp_w != vp_w || ctx->vp_h != vp_h) ctx->force_update = true; if (ctx->force_update && vo) { ctx->force_update = false; ctx->vp_w = vp_w; ctx->vp_h = vp_h; struct mp_rect src, dst; struct mp_osd_res osd; mp_get_src_dst_rects(ctx->log, &ctx->vo_opts, vo->driver->caps, &ctx->img_params, vp_w, abs(vp_h), 1.0, &src, &dst, &osd); gl_video_resize(ctx->renderer, vp_w, vp_h, &src, &dst, &osd); } if (ctx->reconfigured) { gl_video_set_osd_source(ctx->renderer, vo ? vo->osd : NULL); gl_video_config(ctx->renderer, &ctx->img_params); } if (ctx->update_new_opts) { struct vo_priv *p = vo ? vo->priv : NULL; struct vo_priv *opts = ctx->new_opts ? ctx->new_opts : p; if (opts) { int queue = 0; gl_video_set_options(ctx->renderer, opts->renderer_opts, &queue); ctx->vsync_timed = opts->renderer_opts->interpolation; if (ctx->vsync_timed) queue += 0.050 * 1e6; // disable video timing vo_set_flip_queue_params(vo, queue, false); ctx->gl->debug_context = opts->use_gl_debug; gl_video_set_debug(ctx->renderer, opts->use_gl_debug); frame_queue_shrink(ctx, opts->frame_queue_size); } } ctx->reconfigured = false; ctx->update_new_opts = false; struct mp_csp_equalizer *eq = gl_video_eq_ptr(ctx->renderer); if (ctx->eq_changed) { memcpy(eq->values, ctx->eq.values, sizeof(eq->values)); gl_video_eq_update(ctx->renderer); } ctx->eq_changed = false; ctx->eq = *eq; struct mp_image *mpi = frame_queue_pop(ctx); if (mpi) { struct frame_timing *t = mpi->priv; // set by draw_image_timed if (t) ctx->cur_pts = t->pts; } struct frame_timing timing = { .pts = ctx->cur_pts, }; if (ctx->approx_vsync > 0) { timing.prev_vsync = prev_sync(ctx, mp_time_us()); timing.next_vsync = timing.prev_vsync + ctx->approx_vsync; } pthread_mutex_unlock(&ctx->lock); if (mpi) gl_video_set_image(ctx->renderer, mpi); gl_video_render_frame(ctx->renderer, fbo, timing.pts ? &timing : NULL); gl_video_unset_gl_state(ctx->renderer); pthread_mutex_lock(&ctx->lock); const int left = ctx->queued_frames; if (vo && (left > 0 || ctx->vsync_timed)) update(vo->priv); pthread_mutex_unlock(&ctx->lock); return left; } int mpv_opengl_cb_report_flip(mpv_opengl_cb_context *ctx, int64_t time) { pthread_mutex_lock(&ctx->lock); int64_t next = time > 0 ? time : mp_time_us(); if (ctx->recent_flip) ctx->approx_vsync = next - ctx->recent_flip; ctx->recent_flip = next; pthread_mutex_unlock(&ctx->lock); return 0; }