/src/mpv/video/out/gpu/libmpv_gpu.c
Line | Count | Source |
1 | | #include "config.h" |
2 | | #include "hwdec.h" |
3 | | #include "libmpv_gpu.h" |
4 | | #include "mpv/render_gl.h" |
5 | | #include "video.h" |
6 | | #include "video/out/libmpv.h" |
7 | | |
8 | | static const struct libmpv_gpu_context_fns *context_backends[] = { |
9 | | #if HAVE_GL |
10 | | &libmpv_gpu_context_gl, |
11 | | #endif |
12 | | NULL |
13 | | }; |
14 | | |
15 | | struct priv { |
16 | | struct libmpv_gpu_context *context; |
17 | | |
18 | | struct gl_video *renderer; |
19 | | }; |
20 | | |
21 | | struct native_resource_entry { |
22 | | const char *name; // ra_add_native_resource() internal name argument |
23 | | size_t size; // size of struct pointed to (0 for no copy) |
24 | | }; |
25 | | |
26 | | static const struct native_resource_entry native_resource_map[] = { |
27 | | [MPV_RENDER_PARAM_X11_DISPLAY] = { |
28 | | .name = "x11", |
29 | | .size = 0, |
30 | | }, |
31 | | [MPV_RENDER_PARAM_WL_DISPLAY] = { |
32 | | .name = "wl", |
33 | | .size = 0, |
34 | | }, |
35 | | [MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE] = { |
36 | | .name = "drm_draw_surface_size", |
37 | | .size = sizeof (mpv_opengl_drm_draw_surface_size), |
38 | | }, |
39 | | [MPV_RENDER_PARAM_DRM_DISPLAY_V2] = { |
40 | | .name = "drm_params_v2", |
41 | | .size = sizeof (mpv_opengl_drm_params_v2), |
42 | | }, |
43 | | }; |
44 | | |
45 | | static int init(struct render_backend *ctx, mpv_render_param *params) |
46 | 0 | { |
47 | 0 | ctx->priv = talloc_zero(NULL, struct priv); |
48 | 0 | struct priv *p = ctx->priv; |
49 | |
|
50 | 0 | char *api = get_mpv_render_param(params, MPV_RENDER_PARAM_API_TYPE, NULL); |
51 | 0 | if (!api) |
52 | 0 | return MPV_ERROR_INVALID_PARAMETER; |
53 | | |
54 | 0 | for (int n = 0; context_backends[n]; n++) { |
55 | 0 | const struct libmpv_gpu_context_fns *backend = context_backends[n]; |
56 | 0 | if (strcmp(backend->api_name, api) == 0) { |
57 | 0 | p->context = talloc_zero(NULL, struct libmpv_gpu_context); |
58 | 0 | *p->context = (struct libmpv_gpu_context){ |
59 | 0 | .global = ctx->global, |
60 | 0 | .log = ctx->log, |
61 | 0 | .fns = backend, |
62 | 0 | }; |
63 | 0 | break; |
64 | 0 | } |
65 | 0 | } |
66 | |
|
67 | 0 | if (!p->context) |
68 | 0 | return MPV_ERROR_NOT_IMPLEMENTED; |
69 | | |
70 | 0 | int err = p->context->fns->init(p->context, params); |
71 | 0 | if (err < 0) |
72 | 0 | return err; |
73 | | |
74 | 0 | for (int n = 0; params && params[n].type; n++) { |
75 | 0 | if (params[n].type > 0 && |
76 | 0 | params[n].type < MP_ARRAY_SIZE(native_resource_map) && |
77 | 0 | native_resource_map[params[n].type].name) |
78 | 0 | { |
79 | 0 | const struct native_resource_entry *entry = |
80 | 0 | &native_resource_map[params[n].type]; |
81 | 0 | void *data = params[n].data; |
82 | 0 | if (entry->size) |
83 | 0 | data = talloc_memdup(p, data, entry->size); |
84 | 0 | ra_add_native_resource(p->context->ra_ctx->ra, entry->name, data); |
85 | 0 | } |
86 | 0 | } |
87 | |
|
88 | 0 | p->renderer = gl_video_init(p->context->ra_ctx->ra, ctx->log, ctx->global); |
89 | |
|
90 | 0 | ctx->hwdec_devs = hwdec_devices_create(); |
91 | 0 | gl_video_init_hwdecs(p->renderer, p->context->ra_ctx, ctx->hwdec_devs, true); |
92 | 0 | ctx->driver_caps = VO_CAP_ROTATE90 | VO_CAP_VFLIP; |
93 | 0 | return 0; |
94 | 0 | } |
95 | | |
96 | | static bool check_format(struct render_backend *ctx, int imgfmt) |
97 | 0 | { |
98 | 0 | struct priv *p = ctx->priv; |
99 | |
|
100 | 0 | return gl_video_check_format(p->renderer, imgfmt); |
101 | 0 | } |
102 | | |
103 | | static int set_parameter(struct render_backend *ctx, mpv_render_param param) |
104 | 0 | { |
105 | 0 | struct priv *p = ctx->priv; |
106 | |
|
107 | 0 | switch (param.type) { |
108 | 0 | case MPV_RENDER_PARAM_ICC_PROFILE: { |
109 | 0 | mpv_byte_array *data = param.data; |
110 | 0 | gl_video_set_icc_profile(p->renderer, bstrdup(NULL, (bstr){data->data, data->size})); |
111 | 0 | return 0; |
112 | 0 | } |
113 | 0 | case MPV_RENDER_PARAM_AMBIENT_LIGHT: { |
114 | 0 | MP_WARN(ctx, "MPV_RENDER_PARAM_AMBIENT_LIGHT is deprecated and might be " |
115 | 0 | "removed in the future (replacement: gamma-auto.lua)\n"); |
116 | 0 | int lux = *(int *)param.data; |
117 | 0 | gl_video_set_ambient_lux(p->renderer, (double)lux); |
118 | 0 | return 0; |
119 | 0 | } |
120 | 0 | default: |
121 | 0 | return MPV_ERROR_NOT_IMPLEMENTED; |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | static void reconfig(struct render_backend *ctx, struct mp_image_params *params) |
126 | 0 | { |
127 | 0 | struct priv *p = ctx->priv; |
128 | |
|
129 | 0 | gl_video_config(p->renderer, params); |
130 | 0 | } |
131 | | |
132 | | static void reset(struct render_backend *ctx) |
133 | 0 | { |
134 | 0 | struct priv *p = ctx->priv; |
135 | |
|
136 | 0 | gl_video_reset(p->renderer); |
137 | 0 | } |
138 | | |
139 | | static void update_external(struct render_backend *ctx, struct vo *vo) |
140 | 0 | { |
141 | 0 | struct priv *p = ctx->priv; |
142 | |
|
143 | 0 | gl_video_set_osd_source(p->renderer, vo ? vo->osd : NULL); |
144 | 0 | if (vo) |
145 | 0 | gl_video_configure_queue(p->renderer, vo); |
146 | 0 | } |
147 | | |
148 | | static void resize(struct render_backend *ctx, struct mp_rect *src, |
149 | | struct mp_rect *dst, struct mp_osd_res *osd) |
150 | 0 | { |
151 | 0 | struct priv *p = ctx->priv; |
152 | |
|
153 | 0 | gl_video_resize(p->renderer, src, dst, osd); |
154 | 0 | } |
155 | | |
156 | | static int get_target_size(struct render_backend *ctx, mpv_render_param *params, |
157 | | int *out_w, int *out_h) |
158 | 0 | { |
159 | 0 | struct priv *p = ctx->priv; |
160 | | |
161 | | // Mapping the surface is cheap, better than adding new backend entrypoints. |
162 | 0 | struct ra_tex *tex; |
163 | 0 | int err = p->context->fns->wrap_fbo(p->context, params, &tex); |
164 | 0 | if (err < 0) |
165 | 0 | return err; |
166 | 0 | *out_w = tex->params.w; |
167 | 0 | *out_h = tex->params.h; |
168 | 0 | return 0; |
169 | 0 | } |
170 | | |
171 | | static int render(struct render_backend *ctx, mpv_render_param *params, |
172 | | struct vo_frame *frame) |
173 | 0 | { |
174 | 0 | struct priv *p = ctx->priv; |
175 | | |
176 | | // Mapping the surface is cheap, better than adding new backend entrypoints. |
177 | 0 | struct ra_tex *tex; |
178 | 0 | int err = p->context->fns->wrap_fbo(p->context, params, &tex); |
179 | 0 | if (err < 0) |
180 | 0 | return err; |
181 | | |
182 | 0 | int depth = *(int *)get_mpv_render_param(params, MPV_RENDER_PARAM_DEPTH, |
183 | 0 | &(int){0}); |
184 | 0 | gl_video_set_fb_depth(p->renderer, depth); |
185 | |
|
186 | 0 | bool flip = *(int *)get_mpv_render_param(params, MPV_RENDER_PARAM_FLIP_Y, |
187 | 0 | &(int){0}); |
188 | |
|
189 | 0 | struct ra_fbo target = {.tex = tex, .flip = flip}; |
190 | 0 | gl_video_render_frame(p->renderer, frame, &target, RENDER_FRAME_DEF); |
191 | 0 | p->context->fns->done_frame(p->context, frame->display_synced); |
192 | |
|
193 | 0 | return 0; |
194 | 0 | } |
195 | | |
196 | | static struct mp_image *get_image(struct render_backend *ctx, int imgfmt, |
197 | | int w, int h, int stride_align, int flags) |
198 | 0 | { |
199 | 0 | struct priv *p = ctx->priv; |
200 | |
|
201 | 0 | return gl_video_get_image(p->renderer, imgfmt, w, h, stride_align, flags); |
202 | 0 | } |
203 | | |
204 | | static void screenshot(struct render_backend *ctx, struct vo_frame *frame, |
205 | | struct voctrl_screenshot *args) |
206 | 0 | { |
207 | 0 | struct priv *p = ctx->priv; |
208 | |
|
209 | 0 | gl_video_screenshot(p->renderer, frame, args); |
210 | 0 | } |
211 | | |
212 | | static void perfdata(struct render_backend *ctx, |
213 | | struct voctrl_performance_data *out) |
214 | 0 | { |
215 | 0 | struct priv *p = ctx->priv; |
216 | |
|
217 | 0 | gl_video_perfdata(p->renderer, out); |
218 | 0 | } |
219 | | |
220 | | static void destroy(struct render_backend *ctx) |
221 | 0 | { |
222 | 0 | struct priv *p = ctx->priv; |
223 | |
|
224 | 0 | if (p->renderer) |
225 | 0 | gl_video_uninit(p->renderer); |
226 | |
|
227 | 0 | hwdec_devices_destroy(ctx->hwdec_devs); |
228 | |
|
229 | 0 | if (p->context) { |
230 | 0 | p->context->fns->destroy(p->context); |
231 | 0 | talloc_free(p->context->priv); |
232 | 0 | talloc_free(p->context); |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | | const struct render_backend_fns render_backend_gpu = { |
237 | | .init = init, |
238 | | .check_format = check_format, |
239 | | .set_parameter = set_parameter, |
240 | | .reconfig = reconfig, |
241 | | .reset = reset, |
242 | | .update_external = update_external, |
243 | | .resize = resize, |
244 | | .get_target_size = get_target_size, |
245 | | .render = render, |
246 | | .get_image = get_image, |
247 | | .screenshot = screenshot, |
248 | | .perfdata = perfdata, |
249 | | .destroy = destroy, |
250 | | }; |