Coverage Report

Created: 2026-03-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpv/video/out/opengl/libmpv_gl.c
Line
Count
Source
1
#include "common.h"
2
#include "context.h"
3
#include "ra_gl.h"
4
#include "options/m_config.h"
5
#include "mpv/render_gl.h"
6
#include "video/out/gpu/libmpv_gpu.h"
7
#include "video/out/gpu/ra.h"
8
9
struct priv {
10
    GL *gl;
11
    struct ra_ctx *ra_ctx;
12
};
13
14
static int init(struct libmpv_gpu_context *ctx, mpv_render_param *params)
15
0
{
16
0
    ctx->priv = talloc_zero(NULL, struct priv);
17
0
    struct priv *p = ctx->priv;
18
19
0
    mpv_opengl_init_params *init_params =
20
0
        get_mpv_render_param(params, MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, NULL);
21
0
    if (!init_params)
22
0
        return MPV_ERROR_INVALID_PARAMETER;
23
24
0
    p->gl = talloc_zero(p, GL);
25
26
0
    mpgl_load_functions2(p->gl, init_params->get_proc_address,
27
0
                         init_params->get_proc_address_ctx,
28
0
                         NULL, ctx->log);
29
0
    if (!p->gl->version && !p->gl->es) {
30
0
        MP_FATAL(ctx, "OpenGL not initialized.\n");
31
0
        return MPV_ERROR_UNSUPPORTED;
32
0
    }
33
34
    // initialize a blank ra_ctx to reuse ra_gl_ctx
35
0
    p->ra_ctx = talloc_zero(p, struct ra_ctx);
36
0
    p->ra_ctx->log = ctx->log;
37
0
    p->ra_ctx->global = ctx->global;
38
0
    p->ra_ctx->opts = (struct ra_ctx_opts) {
39
0
        .allow_sw = true,
40
0
    };
41
42
    // vo_libmpv is essentially like a gigantic external swapchain where
43
    // the user is in charge of presentation / swapping etc. But we don't
44
    // actually need to provide any of these functions, since we can just
45
    // not call them to begin with - so just set it to an empty object to
46
    // signal to ra_gl_p that we don't care about its latency emulation
47
    // functionality
48
0
    struct ra_ctx_params gl_params = {0};
49
0
    p->gl->SwapInterval = NULL; // we shouldn't randomly change this, so lock it
50
0
    if (!ra_gl_ctx_init(p->ra_ctx, p->gl, gl_params))
51
0
        return MPV_ERROR_UNSUPPORTED;
52
53
0
    struct ra_ctx_opts *ctx_opts = mp_get_config_group(ctx, ctx->global, &ra_ctx_conf);
54
0
    p->ra_ctx->opts.debug = ctx_opts->debug;
55
0
    p->gl->debug_context = ctx_opts->debug;
56
0
    ra_gl_set_debug(p->ra_ctx->ra, ctx_opts->debug);
57
0
    talloc_free(ctx_opts);
58
59
0
    ctx->ra_ctx = p->ra_ctx;
60
61
0
    return 0;
62
0
}
63
64
static int wrap_fbo(struct libmpv_gpu_context *ctx, mpv_render_param *params,
65
                    struct ra_tex **out)
66
0
{
67
0
    struct priv *p = ctx->priv;
68
69
0
    mpv_opengl_fbo *fbo =
70
0
        get_mpv_render_param(params, MPV_RENDER_PARAM_OPENGL_FBO, NULL);
71
0
    if (!fbo)
72
0
        return MPV_ERROR_INVALID_PARAMETER;
73
74
0
    if (fbo->fbo && !(p->gl->mpgl_caps & MPGL_CAP_FB)) {
75
0
        MP_FATAL(ctx, "Rendering to FBO requested, but no FBO extension found!\n");
76
0
        return MPV_ERROR_UNSUPPORTED;
77
0
    }
78
79
0
    struct ra_swapchain *sw = p->ra_ctx->swapchain;
80
0
    struct ra_fbo target;
81
0
    ra_gl_ctx_resize(sw, fbo->w, fbo->h, fbo->fbo);
82
0
    ra_gl_ctx_start_frame(sw, &target);
83
0
    *out = target.tex;
84
0
    return 0;
85
0
}
86
87
static void done_frame(struct libmpv_gpu_context *ctx, bool ds)
88
0
{
89
0
    struct priv *p = ctx->priv;
90
91
0
    struct ra_swapchain *sw = p->ra_ctx->swapchain;
92
0
    struct vo_frame dummy = {.display_synced = ds};
93
0
    ra_gl_ctx_submit_frame(sw, &dummy);
94
0
}
95
96
static void destroy(struct libmpv_gpu_context *ctx)
97
0
{
98
0
    struct priv *p = ctx->priv;
99
100
0
    if (p->ra_ctx)
101
0
        ra_gl_ctx_uninit(p->ra_ctx);
102
0
}
103
104
const struct libmpv_gpu_context_fns libmpv_gpu_context_gl = {
105
    .api_name = MPV_RENDER_API_TYPE_OPENGL,
106
    .init = init,
107
    .wrap_fbo = wrap_fbo,
108
    .done_frame = done_frame,
109
    .destroy = destroy,
110
};