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 <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <stdlib.h>
19 #include <assert.h>
20 #include <limits.h>
21 
22 #include "common/common.h"
23 #include "common/msg.h"
24 #include "video/csputils.h"
25 #include "video/mp_image.h"
26 #include "osd.h"
27 
28 #define GLSL(x) gl_sc_add(sc, #x "\n");
29 
30 // glBlendFuncSeparate() arguments
31 static const int blend_factors[SUBBITMAP_COUNT][4] = {
32     [SUBBITMAP_LIBASS] = {RA_BLEND_SRC_ALPHA, RA_BLEND_ONE_MINUS_SRC_ALPHA,
33                           RA_BLEND_ONE,       RA_BLEND_ONE_MINUS_SRC_ALPHA},
34     [SUBBITMAP_RGBA] =   {RA_BLEND_ONE,       RA_BLEND_ONE_MINUS_SRC_ALPHA,
35                           RA_BLEND_ONE,       RA_BLEND_ONE_MINUS_SRC_ALPHA},
36 };
37 
38 struct vertex {
39     float position[2];
40     float texcoord[2];
41     uint8_t ass_color[4];
42 };
43 
44 static const struct ra_renderpass_input vertex_vao[] = {
45     {"position",  RA_VARTYPE_FLOAT,      2, 1, offsetof(struct vertex, position)},
46     {"texcoord" , RA_VARTYPE_FLOAT,      2, 1, offsetof(struct vertex, texcoord)},
47     {"ass_color", RA_VARTYPE_BYTE_UNORM, 4, 1, offsetof(struct vertex, ass_color)},
48 };
49 
50 struct mpgl_osd_part {
51     enum sub_bitmap_format format;
52     int change_id;
53     struct ra_tex *texture;
54     int w, h;
55     int num_subparts;
56     int prev_num_subparts;
57     struct sub_bitmap *subparts;
58     int num_vertices;
59     struct vertex *vertices;
60 };
61 
62 struct mpgl_osd {
63     struct mp_log *log;
64     struct osd_state *osd;
65     struct ra *ra;
66     struct mpgl_osd_part *parts[MAX_OSD_PARTS];
67     const struct ra_format *fmt_table[SUBBITMAP_COUNT];
68     bool formats[SUBBITMAP_COUNT];
69     bool change_flag; // for reporting to API user only
70     // temporary
71     int stereo_mode;
72     struct mp_osd_res osd_res;
73     void *scratch;
74 };
75 
mpgl_osd_init(struct ra * ra,struct mp_log * log,struct osd_state * osd)76 struct mpgl_osd *mpgl_osd_init(struct ra *ra, struct mp_log *log,
77                                struct osd_state *osd)
78 {
79     struct mpgl_osd *ctx = talloc_ptrtype(NULL, ctx);
80     *ctx = (struct mpgl_osd) {
81         .log = log,
82         .osd = osd,
83         .ra = ra,
84         .change_flag = true,
85         .scratch = talloc_zero_size(ctx, 1),
86     };
87 
88     ctx->fmt_table[SUBBITMAP_LIBASS] = ra_find_unorm_format(ra, 1, 1);
89     ctx->fmt_table[SUBBITMAP_RGBA]   = ra_find_unorm_format(ra, 1, 4);
90 
91     for (int n = 0; n < MAX_OSD_PARTS; n++)
92         ctx->parts[n] = talloc_zero(ctx, struct mpgl_osd_part);
93 
94     for (int n = 0; n < SUBBITMAP_COUNT; n++)
95         ctx->formats[n] = !!ctx->fmt_table[n];
96 
97     return ctx;
98 }
99 
mpgl_osd_destroy(struct mpgl_osd * ctx)100 void mpgl_osd_destroy(struct mpgl_osd *ctx)
101 {
102     if (!ctx)
103         return;
104 
105     for (int n = 0; n < MAX_OSD_PARTS; n++) {
106         struct mpgl_osd_part *p = ctx->parts[n];
107         ra_tex_free(ctx->ra, &p->texture);
108     }
109     talloc_free(ctx);
110 }
111 
next_pow2(int v)112 static int next_pow2(int v)
113 {
114     for (int x = 0; x < 30; x++) {
115         if ((1 << x) >= v)
116             return 1 << x;
117     }
118     return INT_MAX;
119 }
120 
upload_osd(struct mpgl_osd * ctx,struct mpgl_osd_part * osd,struct sub_bitmaps * imgs)121 static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd,
122                        struct sub_bitmaps *imgs)
123 {
124     struct ra *ra = ctx->ra;
125     bool ok = false;
126 
127     assert(imgs->packed);
128 
129     int req_w = next_pow2(imgs->packed_w);
130     int req_h = next_pow2(imgs->packed_h);
131 
132     const struct ra_format *fmt = ctx->fmt_table[imgs->format];
133     assert(fmt);
134 
135     if (!osd->texture || req_w > osd->w || req_h > osd->h ||
136         osd->format != imgs->format)
137     {
138         ra_tex_free(ra, &osd->texture);
139 
140         osd->format = imgs->format;
141         osd->w = MPMAX(32, req_w);
142         osd->h = MPMAX(32, req_h);
143 
144         MP_VERBOSE(ctx, "Reallocating OSD texture to %dx%d.\n", osd->w, osd->h);
145 
146         if (osd->w > ra->max_texture_wh || osd->h > ra->max_texture_wh) {
147             MP_ERR(ctx, "OSD bitmaps do not fit on a surface with the maximum "
148                    "supported size %dx%d.\n", ra->max_texture_wh,
149                    ra->max_texture_wh);
150             goto done;
151         }
152 
153         struct ra_tex_params params = {
154             .dimensions = 2,
155             .w = osd->w,
156             .h = osd->h,
157             .d = 1,
158             .format = fmt,
159             .render_src = true,
160             .src_linear = true,
161             .host_mutable = true,
162         };
163         osd->texture = ra_tex_create(ra, &params);
164         if (!osd->texture)
165             goto done;
166     }
167 
168     struct ra_tex_upload_params params = {
169         .tex = osd->texture,
170         .src = imgs->packed->planes[0],
171         .invalidate = true,
172         .rc = &(struct mp_rect){0, 0, imgs->packed_w, imgs->packed_h},
173         .stride = imgs->packed->stride[0],
174     };
175 
176     ok = ra->fns->tex_upload(ra, &params);
177 
178 done:
179     return ok;
180 }
181 
gen_osd_cb(void * pctx,struct sub_bitmaps * imgs)182 static void gen_osd_cb(void *pctx, struct sub_bitmaps *imgs)
183 {
184     struct mpgl_osd *ctx = pctx;
185 
186     if (imgs->num_parts == 0 || !ctx->formats[imgs->format])
187         return;
188 
189     struct mpgl_osd_part *osd = ctx->parts[imgs->render_index];
190 
191     bool ok = true;
192     if (imgs->change_id != osd->change_id) {
193         if (!upload_osd(ctx, osd, imgs))
194             ok = false;
195 
196         osd->change_id = imgs->change_id;
197         ctx->change_flag = true;
198     }
199     osd->num_subparts = ok ? imgs->num_parts : 0;
200 
201     MP_TARRAY_GROW(osd, osd->subparts, osd->num_subparts);
202     memcpy(osd->subparts, imgs->parts,
203            osd->num_subparts * sizeof(osd->subparts[0]));
204 }
205 
mpgl_osd_draw_prepare(struct mpgl_osd * ctx,int index,struct gl_shader_cache * sc)206 bool mpgl_osd_draw_prepare(struct mpgl_osd *ctx, int index,
207                            struct gl_shader_cache *sc)
208 {
209     assert(index >= 0 && index < MAX_OSD_PARTS);
210     struct mpgl_osd_part *part = ctx->parts[index];
211 
212     enum sub_bitmap_format fmt = part->format;
213     if (!fmt || !part->num_subparts || !part->texture)
214         return false;
215 
216     gl_sc_uniform_texture(sc, "osdtex", part->texture);
217     switch (fmt) {
218     case SUBBITMAP_RGBA: {
219         GLSL(color = texture(osdtex, texcoord).bgra;)
220         break;
221     }
222     case SUBBITMAP_LIBASS: {
223         GLSL(color =
224             vec4(ass_color.rgb, ass_color.a * texture(osdtex, texcoord).r);)
225         break;
226     }
227     default:
228         abort();
229     }
230 
231     return true;
232 }
233 
write_quad(struct vertex * va,struct gl_transform t,float x0,float y0,float x1,float y1,float tx0,float ty0,float tx1,float ty1,float tex_w,float tex_h,const uint8_t color[4])234 static void write_quad(struct vertex *va, struct gl_transform t,
235                        float x0, float y0, float x1, float y1,
236                        float tx0, float ty0, float tx1, float ty1,
237                        float tex_w, float tex_h, const uint8_t color[4])
238 {
239     gl_transform_vec(t, &x0, &y0);
240     gl_transform_vec(t, &x1, &y1);
241 
242 #define COLOR_INIT {color[0], color[1], color[2], color[3]}
243     va[0] = (struct vertex){ {x0, y0}, {tx0 / tex_w, ty0 / tex_h}, COLOR_INIT };
244     va[1] = (struct vertex){ {x0, y1}, {tx0 / tex_w, ty1 / tex_h}, COLOR_INIT };
245     va[2] = (struct vertex){ {x1, y0}, {tx1 / tex_w, ty0 / tex_h}, COLOR_INIT };
246     va[3] = (struct vertex){ {x1, y1}, {tx1 / tex_w, ty1 / tex_h}, COLOR_INIT };
247     va[4] = va[2];
248     va[5] = va[1];
249 #undef COLOR_INIT
250 }
251 
generate_verts(struct mpgl_osd_part * part,struct gl_transform t)252 static void generate_verts(struct mpgl_osd_part *part, struct gl_transform t)
253 {
254     MP_TARRAY_GROW(part, part->vertices,
255                    part->num_vertices + part->num_subparts * 6);
256 
257     for (int n = 0; n < part->num_subparts; n++) {
258         struct sub_bitmap *b = &part->subparts[n];
259         struct vertex *va = &part->vertices[part->num_vertices];
260 
261         // NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it
262         //       doesn't matter that we upload garbage for the other formats
263         uint32_t c = b->libass.color;
264         uint8_t color[4] = { c >> 24, (c >> 16) & 0xff,
265                             (c >> 8) & 0xff, 255 - (c & 0xff) };
266 
267         write_quad(va, t,
268                    b->x, b->y, b->x + b->dw, b->y + b->dh,
269                    b->src_x, b->src_y, b->src_x + b->w, b->src_y + b->h,
270                    part->w, part->h, color);
271 
272         part->num_vertices += 6;
273     }
274 }
275 
276 // number of screen divisions per axis (x=0, y=1) for the current 3D mode
get_3d_side_by_side(int stereo_mode,int div[2])277 static void get_3d_side_by_side(int stereo_mode, int div[2])
278 {
279     div[0] = div[1] = 1;
280     switch (stereo_mode) {
281     case MP_STEREO3D_SBS2L:
282     case MP_STEREO3D_SBS2R: div[0] = 2; break;
283     case MP_STEREO3D_AB2R:
284     case MP_STEREO3D_AB2L:  div[1] = 2; break;
285     }
286 }
287 
mpgl_osd_draw_finish(struct mpgl_osd * ctx,int index,struct gl_shader_cache * sc,struct ra_fbo fbo)288 void mpgl_osd_draw_finish(struct mpgl_osd *ctx, int index,
289                           struct gl_shader_cache *sc, struct ra_fbo fbo)
290 {
291     struct mpgl_osd_part *part = ctx->parts[index];
292 
293     int div[2];
294     get_3d_side_by_side(ctx->stereo_mode, div);
295 
296     part->num_vertices = 0;
297 
298     for (int x = 0; x < div[0]; x++) {
299         for (int y = 0; y < div[1]; y++) {
300             struct gl_transform t;
301             gl_transform_ortho_fbo(&t, fbo);
302 
303             float a_x = ctx->osd_res.w * x;
304             float a_y = ctx->osd_res.h * y;
305             t.t[0] += a_x * t.m[0][0] + a_y * t.m[1][0];
306             t.t[1] += a_x * t.m[0][1] + a_y * t.m[1][1];
307 
308             generate_verts(part, t);
309         }
310     }
311 
312     const int *factors = &blend_factors[part->format][0];
313     gl_sc_blend(sc, factors[0], factors[1], factors[2], factors[3]);
314 
315     gl_sc_dispatch_draw(sc, fbo.tex, false, vertex_vao, MP_ARRAY_SIZE(vertex_vao),
316                         sizeof(struct vertex), part->vertices, part->num_vertices);
317 }
318 
set_res(struct mpgl_osd * ctx,struct mp_osd_res res,int stereo_mode)319 static void set_res(struct mpgl_osd *ctx, struct mp_osd_res res, int stereo_mode)
320 {
321     int div[2];
322     get_3d_side_by_side(stereo_mode, div);
323 
324     res.w /= div[0];
325     res.h /= div[1];
326     ctx->osd_res = res;
327 }
328 
mpgl_osd_generate(struct mpgl_osd * ctx,struct mp_osd_res res,double pts,int stereo_mode,int draw_flags)329 void mpgl_osd_generate(struct mpgl_osd *ctx, struct mp_osd_res res, double pts,
330                        int stereo_mode, int draw_flags)
331 {
332     for (int n = 0; n < MAX_OSD_PARTS; n++)
333         ctx->parts[n]->num_subparts = 0;
334 
335     set_res(ctx, res, stereo_mode);
336 
337     osd_draw(ctx->osd, ctx->osd_res, pts, draw_flags, ctx->formats, gen_osd_cb, ctx);
338     ctx->stereo_mode = stereo_mode;
339 
340     // Parts going away does not necessarily result in gen_osd_cb() being called
341     // (not even with num_parts==0), so check this separately.
342     for (int n = 0; n < MAX_OSD_PARTS; n++) {
343         struct mpgl_osd_part *part = ctx->parts[n];
344         if (part->num_subparts !=  part->prev_num_subparts)
345             ctx->change_flag = true;
346         part->prev_num_subparts = part->num_subparts;
347     }
348 }
349 
350 // See osd_resize() for remarks. This function is an optional optimization too.
mpgl_osd_resize(struct mpgl_osd * ctx,struct mp_osd_res res,int stereo_mode)351 void mpgl_osd_resize(struct mpgl_osd *ctx, struct mp_osd_res res, int stereo_mode)
352 {
353     set_res(ctx, res, stereo_mode);
354     osd_resize(ctx->osd, ctx->osd_res);
355 }
356 
mpgl_osd_check_change(struct mpgl_osd * ctx,struct mp_osd_res * res,double pts)357 bool mpgl_osd_check_change(struct mpgl_osd *ctx, struct mp_osd_res *res,
358                            double pts)
359 {
360     ctx->change_flag = false;
361     mpgl_osd_generate(ctx, *res, pts, 0, 0);
362     return ctx->change_flag;
363 }
364