Coverage Report

Created: 2025-10-27 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpv/video/out/gpu_next/context.c
Line
Count
Source
1
/*
2
 * This file is part of mpv.
3
 *
4
 * mpv is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * mpv is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with mpv.  If not, see <https://www.gnu.org/licenses/>.
16
 */
17
18
#include <libplacebo/config.h>
19
20
#ifdef PL_HAVE_D3D11
21
#include <libplacebo/d3d11.h>
22
#endif
23
24
#ifdef PL_HAVE_OPENGL
25
#include <libplacebo/opengl.h>
26
#endif
27
28
#include "context.h"
29
#include "config.h"
30
#include "common/common.h"
31
#include "options/m_config.h"
32
#include "video/out/placebo/utils.h"
33
#include "video/out/gpu/video.h"
34
35
#if HAVE_D3D11
36
#include "osdep/windows_utils.h"
37
#include "video/out/d3d11/ra_d3d11.h"
38
#include "video/out/d3d11/context.h"
39
#endif
40
41
#if HAVE_GL
42
#include "video/out/opengl/context.h"
43
#include "video/out/opengl/ra_gl.h"
44
# if HAVE_EGL
45
#include <EGL/egl.h>
46
# endif
47
#endif
48
49
#if HAVE_VULKAN
50
#include "video/out/vulkan/context.h"
51
#endif
52
53
#if HAVE_D3D11
54
static bool d3d11_pl_init(struct vo *vo, struct gpu_ctx *ctx,
55
                          struct ra_ctx_opts *ctx_opts)
56
{
57
#if !defined(PL_HAVE_D3D11)
58
    MP_MSG(ctx, vo->probing ? MSGL_V : MSGL_ERR,
59
           "libplacebo was built without D3D11 support.\n");
60
    return false;
61
#else // defined(PL_HAVE_D3D11)
62
    bool success = false;
63
64
    ID3D11Device   *device    = ra_d3d11_get_device(ctx->ra_ctx->ra);
65
    IDXGISwapChain *swapchain = ra_d3d11_ctx_get_swapchain(ctx->ra_ctx);
66
    if (!device || !swapchain) {
67
        mp_err(ctx->log,
68
               "Failed to receive required components from the mpv d3d11 "
69
               "context! (device: %s, swap chain: %s)\n",
70
               device    ? "OK" : "failed",
71
               swapchain ? "OK" : "failed");
72
        goto err_out;
73
    }
74
75
    pl_d3d11 d3d11 = pl_d3d11_create(ctx->pllog,
76
        pl_d3d11_params(
77
            .device = device,
78
        )
79
    );
80
    if (!d3d11) {
81
        mp_err(ctx->log, "Failed to acquire a d3d11 libplacebo context!\n");
82
        goto err_out;
83
    }
84
    ctx->gpu = d3d11->gpu;
85
86
    mppl_log_set_probing(ctx->pllog, false);
87
88
    ctx->swapchain = pl_d3d11_create_swapchain(d3d11,
89
        pl_d3d11_swapchain_params(
90
            .swapchain = swapchain,
91
            .disable_10bit_sdr = ra_d3d11_ctx_prefer_8bit_output_format(ctx->ra_ctx),
92
        )
93
    );
94
    if (!ctx->swapchain) {
95
        mp_err(ctx->log, "Failed to acquire a d3d11 libplacebo swap chain!\n");
96
        goto err_out;
97
    }
98
99
    success = true;
100
101
err_out:
102
    SAFE_RELEASE(swapchain);
103
    SAFE_RELEASE(device);
104
105
    return success;
106
#endif // defined(PL_HAVE_D3D11)
107
}
108
#endif // HAVE_D3D11
109
110
struct gpu_ctx *gpu_ctx_create(struct vo *vo, struct ra_ctx_opts *ctx_opts)
111
203
{
112
203
    struct gpu_ctx *ctx = talloc_zero(NULL, struct gpu_ctx);
113
203
    ctx->log = vo->log;
114
203
    ctx->ra_ctx = ra_ctx_create(vo, *ctx_opts);
115
203
    if (!ctx->ra_ctx)
116
203
        goto err_out;
117
118
#if HAVE_VULKAN
119
    struct mpvk_ctx *vkctx = ra_vk_ctx_get(ctx->ra_ctx);
120
    if (vkctx) {
121
        ctx->pllog = vkctx->pllog;
122
        ctx->gpu = vkctx->gpu;
123
        ctx->swapchain = vkctx->swapchain;
124
        return ctx;
125
    }
126
#endif
127
128
0
    ctx->pllog = mppl_log_create(ctx, ctx->log);
129
0
    if (!ctx->pllog)
130
0
        goto err_out;
131
132
0
    mppl_log_set_probing(ctx->pllog, vo->probing);
133
134
#if HAVE_D3D11
135
    if (ra_is_d3d11(ctx->ra_ctx->ra)) {
136
        if (!d3d11_pl_init(vo, ctx, ctx_opts))
137
            goto err_out;
138
139
        return ctx;
140
    }
141
#endif
142
143
0
#if HAVE_GL && defined(PL_HAVE_OPENGL)
144
0
    if (ra_is_gl(ctx->ra_ctx->ra)) {
145
0
        struct GL *gl = ra_gl_get(ctx->ra_ctx->ra);
146
0
        struct pl_opengl_params params = *pl_opengl_params(
147
0
            .debug = ctx_opts->debug,
148
0
            .allow_software = ctx_opts->allow_sw,
149
0
            .get_proc_addr_ex = (void *) gl->get_fn,
150
0
            .proc_ctx = gl->fn_ctx,
151
0
        );
152
# if HAVE_EGL
153
        params.egl_display = eglGetCurrentDisplay();
154
        params.egl_context = eglGetCurrentContext();
155
# endif
156
0
        pl_opengl opengl = pl_opengl_create(ctx->pllog, &params);
157
0
        if (!opengl)
158
0
            goto err_out;
159
0
        ctx->gpu = opengl->gpu;
160
161
0
        mppl_log_set_probing(ctx->pllog, false);
162
163
0
        ctx->swapchain = pl_opengl_create_swapchain(opengl, pl_opengl_swapchain_params(
164
0
            .max_swapchain_depth = vo->opts->swapchain_depth,
165
0
            .framebuffer.flipped = gl->flipped,
166
0
        ));
167
0
        if (!ctx->swapchain)
168
0
            goto err_out;
169
170
0
        return ctx;
171
0
    }
172
#elif HAVE_GL
173
    if (ra_is_gl(ctx->ra_ctx->ra)) {
174
        MP_MSG(ctx, vo->probing ? MSGL_V : MSGL_ERR,
175
            "libplacebo was built without OpenGL support.\n");
176
    }
177
#endif
178
179
203
err_out:
180
203
    gpu_ctx_destroy(&ctx);
181
203
    return NULL;
182
0
}
183
184
bool gpu_ctx_resize(struct gpu_ctx *ctx, int w, int h)
185
0
{
186
#if HAVE_VULKAN
187
    if (ra_vk_ctx_get(ctx->ra_ctx))
188
        // vulkan RA handles this by itself
189
        return true;
190
#endif
191
192
0
    return pl_swapchain_resize(ctx->swapchain, &w, &h);
193
0
}
194
195
void gpu_ctx_destroy(struct gpu_ctx **ctxp)
196
406
{
197
406
    struct gpu_ctx *ctx = *ctxp;
198
406
    if (!ctx)
199
203
        return;
200
203
    if (!ctx->ra_ctx)
201
203
        goto skip_common_pl_cleanup;
202
203
#if HAVE_VULKAN
204
    if (ra_vk_ctx_get(ctx->ra_ctx))
205
        // vulkan RA context handles pl cleanup by itself,
206
        // skip common local clean-up.
207
        goto skip_common_pl_cleanup;
208
#endif
209
210
0
    if (ctx->swapchain)
211
0
        pl_swapchain_destroy(&ctx->swapchain);
212
213
0
    if (ctx->gpu) {
214
0
#if HAVE_GL && defined(PL_HAVE_OPENGL)
215
0
        if (ra_is_gl(ctx->ra_ctx->ra)) {
216
0
            pl_opengl opengl = pl_opengl_get(ctx->gpu);
217
0
            pl_opengl_destroy(&opengl);
218
0
        }
219
0
#endif
220
221
#if HAVE_D3D11 && defined(PL_HAVE_D3D11)
222
        if (ra_is_d3d11(ctx->ra_ctx->ra)) {
223
            pl_d3d11 d3d11 = pl_d3d11_get(ctx->gpu);
224
            pl_d3d11_destroy(&d3d11);
225
        }
226
#endif
227
0
    }
228
229
0
    if (ctx->pllog)
230
0
        pl_log_destroy(&ctx->pllog);
231
232
203
skip_common_pl_cleanup:
233
203
    ra_ctx_destroy(&ctx->ra_ctx);
234
235
203
    talloc_free(ctx);
236
    *ctxp = NULL;
237
203
}