mixer: fix lowering hw volume while muted
[mplayer.git] / libvo / vo_gl3.c
blobb36173502a53a19c40cde1be8f03ccf9e494af28
1 /*
2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer 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 General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * You can alternatively redistribute this file and/or
19 * modify it under the terms of the GNU Lesser General Public
20 * License as published by the Free Software Foundation; either
21 * version 2.1 of the License, or (at your option) any later version.
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28 #include <stdbool.h>
29 #include <assert.h>
30 #include "config.h"
32 #include <libavutil/common.h>
34 #ifdef CONFIG_LCMS2
35 #include <lcms2.h>
36 #include "stream/stream.h"
37 #endif
39 #include "talloc.h"
40 #include "bstr.h"
41 #include "mp_msg.h"
42 #include "subopt-helper.h"
43 #include "video_out.h"
44 #include "libmpcodecs/vfcap.h"
45 #include "libmpcodecs/mp_image.h"
46 #include "geometry.h"
47 #include "osd.h"
48 #include "sub/sub.h"
49 #include "bitmap_packer.h"
51 #include "gl_common.h"
52 #include "filter_kernels.h"
53 #include "aspect.h"
54 #include "fastmemcpy.h"
55 #include "sub/ass_mp.h"
57 static const char vo_gl3_shaders[] =
58 // Generated from libvo/vo_gl3_shaders.glsl
59 #include "libvo/vo_gl3_shaders.h"
62 // How many parts the OSD may consist of at most.
63 #define MAX_OSD_PARTS 20
65 // Pixel width of 1D lookup textures.
66 #define LOOKUP_TEXTURE_SIZE 256
68 // Texture units 0-2 are used by the video, with unit 0 for free use.
69 // Units 3-4 are used for scaler LUTs.
70 #define TEXUNIT_SCALERS 3
71 #define TEXUNIT_3DLUT 5
72 #define TEXUNIT_DITHER 6
74 // lscale/cscale arguments that map directly to shader filter routines.
75 // Note that the convolution filters are not included in this list.
76 static const char *fixed_scale_filters[] = {
77 "bilinear",
78 "bicubic_fast",
79 "sharpen3",
80 "sharpen5",
81 NULL
84 struct lut_tex_format {
85 int pixels;
86 GLint internal_format;
87 GLenum format;
90 // Indexed with filter_kernel->size.
91 // This must match the weightsN functions in the shader.
92 // Each entry uses (size+3)/4 pixels per LUT entry, and size/pixels components
93 // per pixel.
94 struct lut_tex_format lut_tex_formats[] = {
95 [2] = {1, GL_RG16F, GL_RG},
96 [4] = {1, GL_RGBA16F, GL_RGBA},
97 [6] = {2, GL_RGB16F, GL_RGB},
98 [8] = {2, GL_RGBA16F, GL_RGBA},
99 [12] = {3, GL_RGBA16F, GL_RGBA},
100 [16] = {4, GL_RGBA16F, GL_RGBA},
103 // must be sorted, and terminated with 0
104 static const int filter_sizes[] = {2, 4, 6, 8, 12, 16, 0};
106 struct vertex {
107 float position[2];
108 uint8_t color[4];
109 float texcoord[2];
112 #define VERTEX_ATTRIB_POSITION 0
113 #define VERTEX_ATTRIB_COLOR 1
114 #define VERTEX_ATTRIB_TEXCOORD 2
116 // 2 triangles primitives per quad = 6 vertices per quad
117 // (GL_QUAD is deprecated, strips can't be used with EOSD image lists)
118 #define VERTICES_PER_QUAD 6
120 struct texplane {
121 int shift_x, shift_y;
122 GLuint gl_texture;
123 int gl_buffer;
124 int buffer_size;
125 void *buffer_ptr;
128 struct scaler {
129 int index;
130 const char *name;
131 float params[2];
132 struct filter_kernel *kernel;
133 GLuint gl_lut;
134 const char *lut_name;
136 // kernel points here
137 struct filter_kernel kernel_storage;
140 struct fbotex {
141 GLuint fbo;
142 GLuint texture;
143 int tex_w, tex_h; // size of .texture
144 int vp_w, vp_h; // viewport of fbo / used part of the texture
147 struct gl_priv {
148 struct vo *vo;
149 MPGLContext *glctx;
150 GL *gl;
151 const char *shader_version;
153 int use_indirect;
154 int use_gamma;
155 int use_srgb;
156 int use_scale_sep;
157 int use_fancy_downscaling;
158 int use_lut_3d;
159 int use_npot;
160 int use_pbo;
161 int use_glFinish;
162 int use_gl_debug;
163 int use_gl2;
165 int dither_depth;
166 int swap_interval;
167 GLint fbo_format;
168 int stereo_mode;
170 GLuint vertex_buffer;
171 GLuint vao;
173 GLuint osd_program, eosd_program;
174 GLuint indirect_program, scale_sep_program, final_program;
176 GLuint osd_textures[MAX_OSD_PARTS];
177 int osd_textures_count;
178 struct vertex osd_va[MAX_OSD_PARTS * VERTICES_PER_QUAD];
180 GLuint eosd_texture;
181 int eosd_texture_width, eosd_texture_height;
182 GLuint eosd_buffer;
183 struct vertex *eosd_va;
184 struct bitmap_packer *eosd;
185 int eosd_render_count;
186 unsigned int bitmap_id;
187 unsigned int bitmap_pos_id;
189 GLuint lut_3d_texture;
190 int lut_3d_w, lut_3d_h, lut_3d_d;
191 void *lut_3d_data;
193 GLuint dither_texture;
194 float dither_quantization;
195 float dither_multiply;
197 uint32_t image_width;
198 uint32_t image_height;
199 uint32_t image_format;
200 int texture_width;
201 int texture_height;
203 bool is_yuv;
204 bool is_linear_rgb;
206 // per pixel (full pixel when packed, each component when planar)
207 int plane_bytes;
208 int plane_bits;
209 int component_bits;
211 GLint gl_internal_format;
212 GLenum gl_format;
213 GLenum gl_type;
215 int plane_count;
216 struct texplane planes[3];
218 struct fbotex indirect_fbo; // RGB target
219 struct fbotex scale_sep_fbo; // first pass when doing 2 pass scaling
221 // state for luma (0) and chroma (1) scalers
222 struct scaler scalers[2];
223 // luma scaler parameters (the same are used for chroma)
224 float scaler_params[2];
226 struct mp_csp_details colorspace;
227 struct mp_csp_equalizer video_eq;
229 int mpi_flipped;
230 int vo_flipped;
232 struct vo_rect src_rect; // displayed part of the source video
233 struct vo_rect dst_rect; // video rectangle on output window
234 int border_x, border_y; // OSD borders
235 int vp_x, vp_y, vp_w, vp_h; // GL viewport
238 struct fmt_entry {
239 int mp_format;
240 GLint internal_format;
241 GLenum format;
242 int component_bits;
243 GLenum type;
246 static const struct fmt_entry mp_to_gl_formats[] = {
247 {IMGFMT_RGB48NE, GL_RGB16, GL_RGB, 16, GL_UNSIGNED_SHORT},
248 {IMGFMT_RGB24, GL_RGB, GL_RGB, 8, GL_UNSIGNED_BYTE},
249 {IMGFMT_RGBA, GL_RGBA, GL_RGBA, 8, GL_UNSIGNED_BYTE},
250 {IMGFMT_RGB15, GL_RGBA, GL_RGBA, 5, GL_UNSIGNED_SHORT_1_5_5_5_REV},
251 {IMGFMT_RGB16, GL_RGB, GL_RGB, 6, GL_UNSIGNED_SHORT_5_6_5_REV},
252 {IMGFMT_BGR15, GL_RGBA, GL_BGRA, 5, GL_UNSIGNED_SHORT_1_5_5_5_REV},
253 {IMGFMT_BGR16, GL_RGB, GL_RGB, 6, GL_UNSIGNED_SHORT_5_6_5},
254 {IMGFMT_BGR24, GL_RGB, GL_BGR, 8, GL_UNSIGNED_BYTE},
255 {IMGFMT_BGRA, GL_RGBA, GL_BGRA, 8, GL_UNSIGNED_BYTE},
256 {0},
260 static const char help_text[];
262 static void uninit_rendering(struct gl_priv *p);
263 static void delete_shaders(struct gl_priv *p);
266 static void default_tex_params(struct GL *gl, GLenum target, GLint filter)
268 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
269 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
270 gl->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
271 gl->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
274 static void debug_check_gl(struct gl_priv *p, const char *msg)
276 if (p->use_gl_debug)
277 glCheckError(p->gl, msg);
280 static void tex_size(struct gl_priv *p, int w, int h, int *texw, int *texh)
282 if (p->use_npot) {
283 *texw = w;
284 *texh = h;
285 } else {
286 *texw = 32;
287 while (*texw < w)
288 *texw *= 2;
289 *texh = 32;
290 while (*texh < h)
291 *texh *= 2;
295 static void draw_triangles(struct gl_priv *p, struct vertex *vb, int vert_count)
297 GL *gl = p->gl;
299 assert(vert_count % 3 == 0);
301 gl->BindBuffer(GL_ARRAY_BUFFER, p->vertex_buffer);
302 gl->BufferData(GL_ARRAY_BUFFER, vert_count * sizeof(struct vertex), vb,
303 GL_DYNAMIC_DRAW);
304 gl->BindBuffer(GL_ARRAY_BUFFER, 0);
306 gl->BindVertexArray(p->vao);
307 gl->DrawArrays(GL_TRIANGLES, 0, vert_count);
308 gl->BindVertexArray(0);
310 debug_check_gl(p, "after rendering");
313 // Write a textured quad to a vertex array.
314 // va = destination vertex array, VERTICES_PER_QUAD entries will be overwritten
315 // x0, y0, x1, y1 = destination coordinates of the quad
316 // tx0, ty0, tx1, ty1 = source texture coordinates (usually in pixels)
317 // texture_w, texture_h = size of the texture, or an inverse factor
318 // color = optional color for all vertices, NULL for opaque white
319 // flip = flip vertically
320 static void write_quad(struct vertex *va,
321 float x0, float y0, float x1, float y1,
322 float tx0, float ty0, float tx1, float ty1,
323 float texture_w, float texture_h,
324 const uint8_t color[4], bool flip)
326 static const uint8_t white[4] = { 255, 255, 255, 255 };
328 if (!color)
329 color = white;
331 tx0 /= texture_w;
332 ty0 /= texture_h;
333 tx1 /= texture_w;
334 ty1 /= texture_h;
336 if (flip) {
337 float tmp = ty0;
338 ty0 = ty1;
339 ty1 = tmp;
342 #define COLOR_INIT {color[0], color[1], color[2], color[3]}
343 va[0] = (struct vertex) { {x0, y0}, COLOR_INIT, {tx0, ty0} };
344 va[1] = (struct vertex) { {x0, y1}, COLOR_INIT, {tx0, ty1} };
345 va[2] = (struct vertex) { {x1, y0}, COLOR_INIT, {tx1, ty0} };
346 va[3] = (struct vertex) { {x1, y1}, COLOR_INIT, {tx1, ty1} };
347 va[4] = va[2];
348 va[5] = va[1];
349 #undef COLOR_INIT
352 static void fbotex_init(struct gl_priv *p, struct fbotex *fbo, int w, int h)
354 GL *gl = p->gl;
356 assert(!fbo->fbo);
357 assert(!fbo->texture);
359 tex_size(p, w, h, &fbo->tex_w, &fbo->tex_h);
361 fbo->vp_w = w;
362 fbo->vp_h = h;
364 mp_msg(MSGT_VO, MSGL_V, "[gl] Create FBO: %dx%d\n", fbo->tex_w, fbo->tex_h);
366 gl->GenFramebuffers(1, &fbo->fbo);
367 gl->GenTextures(1, &fbo->texture);
368 gl->BindTexture(GL_TEXTURE_2D, fbo->texture);
369 gl->TexImage2D(GL_TEXTURE_2D, 0, p->fbo_format, fbo->tex_w, fbo->tex_h, 0,
370 GL_RGB, GL_UNSIGNED_BYTE, NULL);
371 default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR);
372 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo->fbo);
373 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
374 GL_TEXTURE_2D, fbo->texture, 0);
376 if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER)
377 != GL_FRAMEBUFFER_COMPLETE)
379 mp_msg(MSGT_VO, MSGL_ERR, "[gl] Error: framebuffer completeness "
380 "check failed!\n");
383 gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
385 debug_check_gl(p, "after creating framebuffer & associated texture");
388 static void fbotex_uninit(struct gl_priv *p, struct fbotex *fbo)
390 GL *gl = p->gl;
392 gl->DeleteFramebuffers(1, &fbo->fbo);
393 gl->DeleteTextures(1, &fbo->texture);
394 *fbo = (struct fbotex) {0};
397 static void matrix_ortho2d(float m[3][3], float x0, float x1,
398 float y0, float y1)
400 memset(m, 0, 9 * sizeof(float));
401 m[0][0] = 2.0f / (x1 - x0);
402 m[1][1] = 2.0f / (y1 - y0);
403 m[2][0] = -(x1 + x0) / (x1 - x0);
404 m[2][1] = -(y1 + y0) / (y1 - y0);
405 m[2][2] = 1.0f;
408 static void update_uniforms(struct gl_priv *p, GLuint program)
410 GL *gl = p->gl;
411 GLint loc;
413 if (program == 0)
414 return;
416 gl->UseProgram(program);
418 struct mp_csp_params cparams = {
419 .colorspace = p->colorspace,
420 .input_bits = p->plane_bits,
421 .texture_bits = (p->plane_bits + 7) & ~7,
423 mp_csp_copy_equalizer_values(&cparams, &p->video_eq);
425 loc = gl->GetUniformLocation(program, "transform");
426 if (loc >= 0) {
427 float matrix[3][3];
428 matrix_ortho2d(matrix, 0, p->vp_w, p->vp_h, 0);
429 gl->UniformMatrix3fv(loc, 1, GL_FALSE, &matrix[0][0]);
432 loc = gl->GetUniformLocation(program, "colormatrix");
433 if (loc >= 0) {
434 float yuv2rgb[3][4] = {{0}};
435 if (p->is_yuv)
436 mp_get_yuv2rgb_coeffs(&cparams, yuv2rgb);
437 gl->UniformMatrix4x3fv(loc, 1, GL_TRUE, &yuv2rgb[0][0]);
440 gl->Uniform3f(gl->GetUniformLocation(program, "inv_gamma"),
441 1.0 / cparams.rgamma,
442 1.0 / cparams.ggamma,
443 1.0 / cparams.bgamma);
445 gl->Uniform1i(gl->GetUniformLocation(program, "texture1"), 0);
446 gl->Uniform1i(gl->GetUniformLocation(program, "texture2"), 1);
447 gl->Uniform1i(gl->GetUniformLocation(program, "texture3"), 2);
449 gl->Uniform1i(gl->GetUniformLocation(program, "lut_3d"), TEXUNIT_3DLUT);
451 for (int n = 0; n < 2; n++) {
452 const char *lut = p->scalers[n].lut_name;
453 if (lut)
454 gl->Uniform1i(gl->GetUniformLocation(program, lut),
455 TEXUNIT_SCALERS + n);
458 gl->Uniform1i(gl->GetUniformLocation(program, "dither"), TEXUNIT_DITHER);
459 gl->Uniform1f(gl->GetUniformLocation(program, "dither_quantization"),
460 p->dither_quantization);
461 gl->Uniform1f(gl->GetUniformLocation(program, "dither_multiply"),
462 p->dither_multiply);
464 float sparam1 = p->scaler_params[0];
465 gl->Uniform1f(gl->GetUniformLocation(program, "filter_param1"),
466 isnan(sparam1) ? 0.5f : sparam1);
468 gl->UseProgram(0);
470 debug_check_gl(p, "update_uniforms()");
473 static void update_all_uniforms(struct gl_priv *p)
475 update_uniforms(p, p->osd_program);
476 update_uniforms(p, p->eosd_program);
477 update_uniforms(p, p->indirect_program);
478 update_uniforms(p, p->scale_sep_program);
479 update_uniforms(p, p->final_program);
482 #define SECTION_HEADER "#!section "
484 static char *get_section(void *talloc_ctx, struct bstr source,
485 const char *section)
487 char *res = talloc_strdup(talloc_ctx, "");
488 bool copy = false;
489 while (source.len) {
490 struct bstr line = bstr_getline(source, &source);
491 if (bstr_eatstart(&line, bstr(SECTION_HEADER))) {
492 copy = bstrcmp0(bstr_strip(line), section) == 0;
493 } else if (copy) {
494 res = talloc_asprintf_append_buffer(res, "%.*s", BSTR_P(line));
497 return res;
500 static char *t_concat(void *talloc_ctx, const char *s1, const char *s2)
502 return talloc_asprintf(talloc_ctx, "%s%s", s1, s2);
505 static GLuint create_shader(GL *gl, GLenum type, const char *header,
506 const char *source)
508 void *tmp = talloc_new(NULL);
509 const char *full_source = t_concat(tmp, header, source);
511 GLuint shader = gl->CreateShader(type);
512 gl->ShaderSource(shader, 1, &full_source, NULL);
513 gl->CompileShader(shader);
514 GLint status;
515 gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
516 GLint log_length;
517 gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
519 int pri = status ? (log_length > 1 ? MSGL_V : MSGL_DBG2) : MSGL_ERR;
520 const char *typestr = type == GL_VERTEX_SHADER ? "vertex" : "fragment";
521 if (mp_msg_test(MSGT_VO, pri)) {
522 mp_msg(MSGT_VO, pri, "[gl] %s shader source:\n", typestr);
523 mp_log_source(MSGT_VO, pri, full_source);
525 if (log_length > 1) {
526 GLchar *log = talloc_zero_size(tmp, log_length + 1);
527 gl->GetShaderInfoLog(shader, log_length, NULL, log);
528 mp_msg(MSGT_VO, pri, "[gl] %s shader compile log (status=%d):\n%s\n",
529 typestr, status, log);
532 talloc_free(tmp);
534 return shader;
537 static void prog_create_shader(GL *gl, GLuint program, GLenum type,
538 const char *header, const char *source)
540 GLuint shader = create_shader(gl, type, header, source);
541 gl->AttachShader(program, shader);
542 gl->DeleteShader(shader);
545 static void link_shader(GL *gl, GLuint program)
547 gl->LinkProgram(program);
548 GLint status;
549 gl->GetProgramiv(program, GL_LINK_STATUS, &status);
550 GLint log_length;
551 gl->GetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
553 int pri = status ? (log_length > 1 ? MSGL_V : MSGL_DBG2) : MSGL_ERR;
554 if (mp_msg_test(MSGT_VO, pri)) {
555 GLchar *log = talloc_zero_size(NULL, log_length + 1);
556 gl->GetProgramInfoLog(program, log_length, NULL, log);
557 mp_msg(MSGT_VO, pri, "[gl] shader link log (status=%d): %s\n",
558 status, log);
559 talloc_free(log);
563 static void bind_attrib_locs(GL *gl, GLuint program)
565 gl->BindAttribLocation(program, VERTEX_ATTRIB_POSITION, "vertex_position");
566 gl->BindAttribLocation(program, VERTEX_ATTRIB_COLOR, "vertex_color");
567 gl->BindAttribLocation(program, VERTEX_ATTRIB_TEXCOORD, "vertex_texcoord");
570 static GLuint create_program(GL *gl, const char *name, const char *header,
571 const char *vertex, const char *frag)
573 mp_msg(MSGT_VO, MSGL_V, "[gl] compiling shader program '%s'\n", name);
574 mp_msg(MSGT_VO, MSGL_V, "[gl] header:\n");
575 mp_log_source(MSGT_VO, MSGL_V, header);
576 GLuint prog = gl->CreateProgram();
577 prog_create_shader(gl, prog, GL_VERTEX_SHADER, header, vertex);
578 prog_create_shader(gl, prog, GL_FRAGMENT_SHADER, header, frag);
579 bind_attrib_locs(gl, prog);
580 link_shader(gl, prog);
581 return prog;
584 static void shader_def(char **shader, const char *name,
585 const char *value)
587 *shader = talloc_asprintf_append(*shader, "#define %s %s\n", name, value);
590 static void shader_def_opt(char **shader, const char *name, bool b)
592 if (b)
593 shader_def(shader, name, "1");
596 static void shader_setup_scaler(char **shader, struct scaler *scaler, int pass)
598 const char *target = scaler->index == 0 ? "SAMPLE_L" : "SAMPLE_C";
599 if (!scaler->kernel) {
600 *shader = talloc_asprintf_append(*shader, "#define %s sample_%s\n",
601 target, scaler->name);
602 } else {
603 int size = scaler->kernel->size;
604 if (pass != -1) {
605 // The direction/pass assignment is rather arbitrary, but fixed in
606 // other parts of the code (like FBO setup).
607 const char *direction = pass == 0 ? "0, 1" : "1, 0";
608 *shader = talloc_asprintf_append(*shader, "#define %s(p0, p1) "
609 "sample_convolution_sep%d(vec2(%s), %s, p0, p1)\n",
610 target, size, direction, scaler->lut_name);
611 } else {
612 *shader = talloc_asprintf_append(*shader, "#define %s(p0, p1) "
613 "sample_convolution%d(%s, p0, p1)\n",
614 target, size, scaler->lut_name);
619 // return false if RGB or 4:4:4 YUV
620 static bool input_is_subsampled(struct gl_priv *p)
622 for (int i = 0; i < p->plane_count; i++)
623 if (p->planes[i].shift_x || p->planes[i].shift_y)
624 return true;
625 return false;
628 static void compile_shaders(struct gl_priv *p)
630 GL *gl = p->gl;
632 delete_shaders(p);
634 void *tmp = talloc_new(NULL);
636 struct bstr src = bstr(vo_gl3_shaders);
637 char *vertex_shader = get_section(tmp, src, "vertex_all");
638 char *shader_prelude = get_section(tmp, src, "prelude");
639 char *s_video = get_section(tmp, src, "frag_video");
640 char *s_eosd = get_section(tmp, src, "frag_eosd");
641 char *s_osd = get_section(tmp, src, "frag_osd");
643 char *header = talloc_asprintf(tmp, "#version %s\n%s", p->shader_version,
644 shader_prelude);
646 char *header_eosd = talloc_strdup(tmp, header);
647 shader_def_opt(&header_eosd, "USE_3DLUT", p->use_lut_3d);
649 p->eosd_program =
650 create_program(gl, "eosd", header_eosd, vertex_shader, s_eosd);
652 p->osd_program =
653 create_program(gl, "osd", header, vertex_shader, s_osd);
655 char *header_conv = talloc_strdup(tmp, "");
656 char *header_final = talloc_strdup(tmp, "");
657 char *header_sep = NULL;
659 bool convert_input_to_linear = !p->is_linear_rgb
660 && (p->use_srgb || p->use_lut_3d);
662 shader_def_opt(&header_conv, "USE_PLANAR", p->plane_count > 1);
663 shader_def_opt(&header_conv, "USE_GBRP", p->image_format == IMGFMT_GBRP);
664 shader_def_opt(&header_conv, "USE_YGRAY", p->is_yuv && p->plane_count == 1);
665 shader_def_opt(&header_conv, "USE_COLORMATRIX", p->is_yuv);
666 shader_def_opt(&header_conv, "USE_LINEAR_CONV", convert_input_to_linear);
668 shader_def_opt(&header_final, "USE_LINEAR_CONV_INV", p->use_lut_3d);
669 shader_def_opt(&header_final, "USE_GAMMA_POW", p->use_gamma);
670 shader_def_opt(&header_final, "USE_3DLUT", p->use_lut_3d);
671 shader_def_opt(&header_final, "USE_DITHER", p->dither_texture != 0);
673 if (p->use_scale_sep && p->scalers[0].kernel) {
674 header_sep = talloc_strdup(tmp, "");
675 shader_def_opt(&header_sep, "FIXED_SCALE", true);
676 shader_setup_scaler(&header_sep, &p->scalers[0], 0);
677 shader_setup_scaler(&header_final, &p->scalers[0], 1);
678 } else {
679 shader_setup_scaler(&header_final, &p->scalers[0], -1);
682 // We want to do scaling in linear light. Scaling is closely connected to
683 // texture sampling due to how the shader is structured (or if GL bilinear
684 // scaling is used). The purpose of the "indirect" pass is to convert the
685 // input video to linear RGB.
686 // Another purpose is reducing input to a single texture for scaling.
687 bool use_indirect = p->use_indirect;
689 // Don't sample from input video textures before converting the input to
690 // linear light. (Unneeded when sRGB textures are used.)
691 if (convert_input_to_linear)
692 use_indirect = true;
694 // It doesn't make sense to scale the chroma with cscale in the 1. scale
695 // step and with lscale in the 2. step. If the chroma is subsampled, a
696 // convolution filter wouldn't even work entirely correctly, because the
697 // luma scaler would sample two texels instead of one per tap for chroma.
698 // Also, even with 4:4:4 YUV or planar RGB, the indirection might be faster,
699 // because the shader can't use one scaler for sampling from 3 textures. It
700 // has to fetch the coefficients for each texture separately, even though
701 // they're the same (this is not an inherent restriction, but would require
702 // to restructure the shader).
703 if (header_sep && p->plane_count > 1)
704 use_indirect = true;
706 if (input_is_subsampled(p)) {
707 shader_setup_scaler(&header_conv, &p->scalers[1], -1);
708 } else {
709 // Force using the luma scaler on chroma. If the "indirect" stage is
710 // used, the actual scaling will happen in the next stage.
711 shader_def(&header_conv, "SAMPLE_C",
712 use_indirect ? "sample_bilinear" : "SAMPLE_L");
715 if (use_indirect) {
716 // We don't use filtering for the Y-plane (luma), because it's never
717 // scaled in this scenario.
718 shader_def(&header_conv, "SAMPLE_L", "sample_bilinear");
719 shader_def_opt(&header_conv, "FIXED_SCALE", true);
720 header_conv = t_concat(tmp, header, header_conv);
721 p->indirect_program =
722 create_program(gl, "indirect", header_conv, vertex_shader, s_video);
723 } else if (header_sep) {
724 header_sep = t_concat(tmp, header_sep, header_conv);
725 } else {
726 header_final = t_concat(tmp, header_final, header_conv);
729 if (header_sep) {
730 header_sep = t_concat(tmp, header, header_sep);
731 p->scale_sep_program =
732 create_program(gl, "scale_sep", header_sep, vertex_shader, s_video);
735 header_final = t_concat(tmp, header, header_final);
736 p->final_program =
737 create_program(gl, "final", header_final, vertex_shader, s_video);
739 debug_check_gl(p, "shader compilation");
741 talloc_free(tmp);
744 static void delete_program(GL *gl, GLuint *prog)
746 gl->DeleteProgram(*prog);
747 *prog = 0;
750 static void delete_shaders(struct gl_priv *p)
752 GL *gl = p->gl;
754 delete_program(gl, &p->osd_program);
755 delete_program(gl, &p->eosd_program);
756 delete_program(gl, &p->indirect_program);
757 delete_program(gl, &p->scale_sep_program);
758 delete_program(gl, &p->final_program);
761 static double get_scale_factor(struct gl_priv *p)
763 double sx = p->dst_rect.width / (double)p->src_rect.width;
764 double sy = p->dst_rect.height / (double)p->src_rect.height;
765 // xxx: actually we should use different scalers in X/Y directions if the
766 // scale factors are different due to anamorphic content
767 return FFMIN(sx, sy);
770 static bool update_scale_factor(struct gl_priv *p, struct filter_kernel *kernel)
772 double scale = get_scale_factor(p);
773 if (!p->use_fancy_downscaling && scale < 1.0)
774 scale = 1.0;
775 return mp_init_filter(kernel, filter_sizes, FFMAX(1.0, 1.0 / scale));
778 static void init_scaler(struct gl_priv *p, struct scaler *scaler)
780 GL *gl = p->gl;
782 assert(scaler->name);
784 scaler->kernel = NULL;
786 const struct filter_kernel *t_kernel = mp_find_filter_kernel(scaler->name);
787 if (!t_kernel)
788 return;
790 scaler->kernel_storage = *t_kernel;
791 scaler->kernel = &scaler->kernel_storage;
793 for (int n = 0; n < 2; n++) {
794 if (!isnan(p->scaler_params[n]))
795 scaler->kernel->params[n] = p->scaler_params[n];
798 update_scale_factor(p, scaler->kernel);
800 int size = scaler->kernel->size;
801 assert(size < FF_ARRAY_ELEMS(lut_tex_formats));
802 struct lut_tex_format *fmt = &lut_tex_formats[size];
803 bool use_2d = fmt->pixels > 1;
804 bool is_luma = scaler->index == 0;
805 scaler->lut_name = use_2d
806 ? (is_luma ? "lut_l_2d" : "lut_c_2d")
807 : (is_luma ? "lut_l_1d" : "lut_c_1d");
809 gl->ActiveTexture(GL_TEXTURE0 + TEXUNIT_SCALERS + scaler->index);
810 GLenum target = use_2d ? GL_TEXTURE_2D : GL_TEXTURE_1D;
812 if (!scaler->gl_lut)
813 gl->GenTextures(1, &scaler->gl_lut);
815 gl->BindTexture(target, scaler->gl_lut);
816 gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
817 gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
819 float *weights = talloc_array(NULL, float, LOOKUP_TEXTURE_SIZE * size);
820 mp_compute_lut(scaler->kernel, LOOKUP_TEXTURE_SIZE, weights);
821 if (use_2d) {
822 gl->TexImage2D(GL_TEXTURE_2D, 0, fmt->internal_format, fmt->pixels,
823 LOOKUP_TEXTURE_SIZE, 0, fmt->format, GL_FLOAT,
824 weights);
825 } else {
826 gl->TexImage1D(GL_TEXTURE_1D, 0, fmt->internal_format,
827 LOOKUP_TEXTURE_SIZE, 0, fmt->format, GL_FLOAT,
828 weights);
830 talloc_free(weights);
832 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
833 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
834 gl->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
835 gl->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
837 gl->ActiveTexture(GL_TEXTURE0);
839 debug_check_gl(p, "after initializing scaler");
842 static void make_dither_matrix(unsigned char *m, int size)
844 m[0] = 0;
845 for (int sz = 1; sz < size; sz *= 2) {
846 int offset[] = {sz*size, sz, sz * (size+1), 0};
847 for (int i = 0; i < 4; i++)
848 for (int y = 0; y < sz * size; y += size)
849 for (int x = 0; x < sz; x++)
850 m[x+y+offset[i]] = m[x+y] * 4 + (3-i) * 256/size/size;
854 static void init_dither(struct gl_priv *p)
856 GL *gl = p->gl;
858 // Assume 8 bits per component if unknown.
859 int dst_depth = p->glctx->depth_g ? p->glctx->depth_g : 8;
860 if (p->dither_depth > 0)
861 dst_depth = p->dither_depth;
863 int src_depth = p->component_bits;
864 if (p->use_lut_3d)
865 src_depth = 16;
867 if (dst_depth >= src_depth || p->dither_depth < 0 || src_depth < 0)
868 return;
870 mp_msg(MSGT_VO, MSGL_V, "[gl] Dither %d->%d.\n", src_depth, dst_depth);
872 // This defines how many bits are considered significant for output on
873 // screen. The superfluous bits will be used for rounded according to the
874 // dither matrix. The precision of the source implicitly decides how many
875 // dither patterns can be visible.
876 p->dither_quantization = (1 << dst_depth) - 1;
877 int size = 8;
878 p->dither_multiply = p->dither_quantization + 1.0 / (size*size);
879 unsigned char dither[256];
880 make_dither_matrix(dither, size);
882 gl->ActiveTexture(GL_TEXTURE0 + TEXUNIT_DITHER);
883 gl->GenTextures(1, &p->dither_texture);
884 gl->BindTexture(GL_TEXTURE_2D, p->dither_texture);
885 gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
886 gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
887 gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RED, size, size, 0, GL_RED,
888 GL_UNSIGNED_BYTE, dither);
889 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
890 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
891 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
892 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
893 gl->ActiveTexture(GL_TEXTURE0);
896 static void reinit_rendering(struct gl_priv *p)
898 mp_msg(MSGT_VO, MSGL_V, "[gl] Reinit rendering.\n");
900 debug_check_gl(p, "before scaler initialization");
902 uninit_rendering(p);
904 init_dither(p);
906 init_scaler(p, &p->scalers[0]);
907 init_scaler(p, &p->scalers[1]);
909 compile_shaders(p);
911 if (p->indirect_program && !p->indirect_fbo.fbo)
912 fbotex_init(p, &p->indirect_fbo, p->texture_width, p->texture_height);
915 static void uninit_rendering(struct gl_priv *p)
917 GL *gl = p->gl;
919 delete_shaders(p);
921 for (int n = 0; n < 2; n++) {
922 gl->DeleteTextures(1, &p->scalers->gl_lut);
923 p->scalers->gl_lut = 0;
924 p->scalers->lut_name = NULL;
925 p->scalers->kernel = NULL;
928 gl->DeleteTextures(1, &p->dither_texture);
929 p->dither_texture = 0;
932 static void init_lut_3d(struct gl_priv *p)
934 GL *gl = p->gl;
936 gl->GenTextures(1, &p->lut_3d_texture);
937 gl->ActiveTexture(GL_TEXTURE0 + TEXUNIT_3DLUT);
938 gl->BindTexture(GL_TEXTURE_3D, p->lut_3d_texture);
939 gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
940 gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
941 gl->TexImage3D(GL_TEXTURE_3D, 0, GL_RGB16, p->lut_3d_w, p->lut_3d_h,
942 p->lut_3d_d, 0, GL_RGB, GL_UNSIGNED_SHORT, p->lut_3d_data);
943 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
944 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
945 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
946 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
947 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
948 gl->ActiveTexture(GL_TEXTURE0);
950 debug_check_gl(p, "after 3d lut creation");
953 static void init_video(struct gl_priv *p)
955 GL *gl = p->gl;
957 if (p->use_lut_3d && !p->lut_3d_texture)
958 init_lut_3d(p);
960 if (!p->is_yuv && (p->use_srgb || p->use_lut_3d)) {
961 p->is_linear_rgb = true;
962 p->gl_internal_format = GL_SRGB;
965 int eq_caps = MP_CSP_EQ_CAPS_GAMMA;
966 if (p->is_yuv)
967 eq_caps |= MP_CSP_EQ_CAPS_COLORMATRIX;
968 p->video_eq.capabilities = eq_caps;
970 debug_check_gl(p, "before video texture creation");
972 tex_size(p, p->image_width, p->image_height,
973 &p->texture_width, &p->texture_height);
975 for (int n = 0; n < p->plane_count; n++) {
976 struct texplane *plane = &p->planes[n];
978 int w = p->texture_width >> plane->shift_x;
979 int h = p->texture_height >> plane->shift_y;
981 mp_msg(MSGT_VO, MSGL_V, "[gl] Texture for plane %d: %dx%d\n", n, w, h);
983 gl->ActiveTexture(GL_TEXTURE0 + n);
984 gl->GenTextures(1, &plane->gl_texture);
985 gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
987 gl->TexImage2D(GL_TEXTURE_2D, 0, p->gl_internal_format, w, h, 0,
988 p->gl_format, p->gl_type, NULL);
989 default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR);
991 gl->ActiveTexture(GL_TEXTURE0);
993 debug_check_gl(p, "after video texture creation");
995 reinit_rendering(p);
998 static void uninit_video(struct gl_priv *p)
1000 GL *gl = p->gl;
1002 uninit_rendering(p);
1004 for (int n = 0; n < 3; n++) {
1005 struct texplane *plane = &p->planes[n];
1007 gl->DeleteTextures(1, &plane->gl_texture);
1008 plane->gl_texture = 0;
1009 gl->DeleteBuffers(1, &plane->gl_buffer);
1010 plane->gl_buffer = 0;
1011 plane->buffer_ptr = NULL;
1012 plane->buffer_size = 0;
1015 fbotex_uninit(p, &p->indirect_fbo);
1016 fbotex_uninit(p, &p->scale_sep_fbo);
1019 static void render_to_fbo(struct gl_priv *p, struct fbotex *fbo, int w, int h,
1020 int tex_w, int tex_h)
1022 GL *gl = p->gl;
1024 gl->Viewport(0, 0, fbo->vp_w, fbo->vp_h);
1025 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo->fbo);
1027 struct vertex vb[VERTICES_PER_QUAD];
1028 write_quad(vb, -1, -1, 1, 1,
1029 0, 0, w, h,
1030 tex_w, tex_h,
1031 NULL, false);
1032 draw_triangles(p, vb, VERTICES_PER_QUAD);
1034 gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
1035 gl->Viewport(p->vp_x, p->vp_y, p->vp_w, p->vp_h);
1039 static void handle_pass(struct gl_priv *p, struct fbotex **source,
1040 struct fbotex *fbo, GLuint program)
1042 GL *gl = p->gl;
1044 if (!program)
1045 return;
1047 gl->BindTexture(GL_TEXTURE_2D, (*source)->texture);
1048 gl->UseProgram(program);
1049 render_to_fbo(p, fbo, (*source)->vp_w, (*source)->vp_h,
1050 (*source)->tex_w, (*source)->tex_h);
1051 *source = fbo;
1054 static void do_render(struct gl_priv *p)
1056 GL *gl = p->gl;
1057 struct vertex vb[VERTICES_PER_QUAD];
1058 bool is_flipped = p->mpi_flipped ^ p->vo_flipped;
1060 // Order of processing:
1061 // [indirect -> [scale_sep ->]] final
1063 struct fbotex dummy = {
1064 .vp_w = p->image_width, .vp_h = p->image_height,
1065 .tex_w = p->texture_width, .tex_h = p->texture_height,
1066 .texture = p->planes[0].gl_texture,
1068 struct fbotex *source = &dummy;
1070 handle_pass(p, &source, &p->indirect_fbo, p->indirect_program);
1071 handle_pass(p, &source, &p->scale_sep_fbo, p->scale_sep_program);
1073 gl->BindTexture(GL_TEXTURE_2D, source->texture);
1074 gl->UseProgram(p->final_program);
1076 float final_texw = p->image_width * source->tex_w / (float)source->vp_w;
1077 float final_texh = p->image_height * source->tex_h / (float)source->vp_h;
1079 if (p->use_srgb && !p->use_lut_3d)
1080 gl->Enable(GL_FRAMEBUFFER_SRGB);
1082 if (p->stereo_mode) {
1083 int w = p->src_rect.width;
1084 int imgw = p->image_width;
1086 glEnable3DLeft(gl, p->stereo_mode);
1088 write_quad(vb,
1089 p->dst_rect.left, p->dst_rect.top,
1090 p->dst_rect.right, p->dst_rect.bottom,
1091 p->src_rect.left / 2, p->src_rect.top,
1092 p->src_rect.left / 2 + w / 2, p->src_rect.bottom,
1093 final_texw, final_texh,
1094 NULL, is_flipped);
1095 draw_triangles(p, vb, VERTICES_PER_QUAD);
1097 glEnable3DRight(gl, p->stereo_mode);
1099 write_quad(vb,
1100 p->dst_rect.left, p->dst_rect.top,
1101 p->dst_rect.right, p->dst_rect.bottom,
1102 p->src_rect.left / 2 + imgw / 2, p->src_rect.top,
1103 p->src_rect.left / 2 + imgw / 2 + w / 2, p->src_rect.bottom,
1104 final_texw, final_texh,
1105 NULL, is_flipped);
1106 draw_triangles(p, vb, VERTICES_PER_QUAD);
1108 glDisable3D(gl, p->stereo_mode);
1109 } else {
1110 write_quad(vb,
1111 p->dst_rect.left, p->dst_rect.top,
1112 p->dst_rect.right, p->dst_rect.bottom,
1113 p->src_rect.left, p->src_rect.top,
1114 p->src_rect.right, p->src_rect.bottom,
1115 final_texw, final_texh,
1116 NULL, is_flipped);
1117 draw_triangles(p, vb, VERTICES_PER_QUAD);
1120 gl->Disable(GL_FRAMEBUFFER_SRGB);
1122 gl->UseProgram(0);
1124 debug_check_gl(p, "after video rendering");
1127 static void update_window_sized_objects(struct gl_priv *p)
1129 if (p->scale_sep_program) {
1130 if (p->dst_rect.height > p->scale_sep_fbo.tex_h) {
1131 fbotex_uninit(p, &p->scale_sep_fbo);
1132 // Round up to an arbitrary alignment to make window resizing or
1133 // panscan controls smoother (less texture reallocations).
1134 int height = FFALIGN(p->dst_rect.height, 256);
1135 fbotex_init(p, &p->scale_sep_fbo, p->image_width, height);
1137 p->scale_sep_fbo.vp_w = p->image_width;
1138 p->scale_sep_fbo.vp_h = p->dst_rect.height;
1142 static void resize(struct gl_priv *p)
1144 GL *gl = p->gl;
1145 struct vo *vo = p->vo;
1147 mp_msg(MSGT_VO, MSGL_V, "[gl] Resize: %dx%d\n", vo->dwidth, vo->dheight);
1148 p->vp_x = 0, p->vp_y = 0;
1149 if (WinID >= 0) {
1150 int w = vo->dwidth, h = vo->dheight;
1151 int old_y = vo->dheight;
1152 geometry(&p->vp_x, &p->vp_y, &w, &h, vo->dwidth, vo->dheight);
1153 p->vp_y = old_y - h - p->vp_y;
1155 p->vp_w = vo->dwidth, p->vp_h = vo->dheight;
1156 gl->Viewport(p->vp_x, p->vp_y, p->vp_w, p->vp_h);
1158 struct vo_rect borders;
1159 calc_src_dst_rects(vo, p->image_width, p->image_height, &p->src_rect,
1160 &p->dst_rect, &borders, NULL);
1161 p->border_x = borders.left;
1162 p->border_y = borders.top;
1164 bool need_scaler_reinit = false; // filter size change needed
1165 bool need_scaler_update = false; // filter LUT change needed
1166 bool too_small = false;
1167 for (int n = 0; n < 2; n++) {
1168 if (p->scalers[n].kernel) {
1169 struct filter_kernel tkernel = *p->scalers[n].kernel;
1170 struct filter_kernel old = tkernel;
1171 bool ok = update_scale_factor(p, &tkernel);
1172 too_small |= !ok;
1173 need_scaler_reinit |= (tkernel.size != old.size);
1174 need_scaler_update |= (tkernel.inv_scale != old.inv_scale);
1177 if (need_scaler_reinit) {
1178 reinit_rendering(p);
1179 } else if (need_scaler_update) {
1180 init_scaler(p, &p->scalers[0]);
1181 init_scaler(p, &p->scalers[1]);
1183 if (too_small)
1184 mp_msg(MSGT_VO, MSGL_WARN, "[gl] Can't downscale that much, window "
1185 "output may look suboptimal.\n");
1187 update_window_sized_objects(p);
1188 update_all_uniforms(p);
1190 vo_osd_changed(OSDTYPE_OSD);
1192 gl->Clear(GL_COLOR_BUFFER_BIT);
1193 vo->want_redraw = true;
1196 static void flip_page(struct vo *vo)
1198 struct gl_priv *p = vo->priv;
1199 GL *gl = p->gl;
1201 if (p->use_glFinish)
1202 gl->Finish();
1204 p->glctx->swapGlBuffers(p->glctx);
1206 if (p->dst_rect.left > p->vp_x || p->dst_rect.top > p->vp_y
1207 || p->dst_rect.right < p->vp_x + p->vp_w
1208 || p->dst_rect.bottom < p->vp_y + p->vp_h)
1210 gl->Clear(GL_COLOR_BUFFER_BIT);
1214 static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h,
1215 int x, int y)
1217 struct gl_priv *p = vo->priv;
1218 GL *gl = p->gl;
1220 p->mpi_flipped = stride[0] < 0;
1222 for (int n = 0; n < p->plane_count; n++) {
1223 gl->ActiveTexture(GL_TEXTURE0 + n);
1224 gl->BindTexture(GL_TEXTURE_2D, p->planes[n].gl_texture);
1225 int xs = p->planes[n].shift_x, ys = p->planes[n].shift_y;
1226 glUploadTex(gl, GL_TEXTURE_2D, p->gl_format, p->gl_type, src[n],
1227 stride[n], x >> xs, y >> ys, w >> xs, h >> ys, 0);
1229 gl->ActiveTexture(GL_TEXTURE0);
1231 return 0;
1234 static uint32_t get_image(struct vo *vo, mp_image_t *mpi)
1236 struct gl_priv *p = vo->priv;
1237 GL *gl = p->gl;
1239 if (!p->use_pbo)
1240 return VO_FALSE;
1242 // We don't support alpha planes. (Disabling PBOs with normal draw calls is
1243 // an undesired, but harmless side-effect.)
1244 if (mpi->num_planes != p->plane_count)
1245 return VO_FALSE;
1247 if (mpi->flags & MP_IMGFLAG_READABLE)
1248 return VO_FALSE;
1249 if (mpi->type != MP_IMGTYPE_STATIC && mpi->type != MP_IMGTYPE_TEMP &&
1250 (mpi->type != MP_IMGTYPE_NUMBERED || mpi->number))
1251 return VO_FALSE;
1252 mpi->flags &= ~MP_IMGFLAG_COMMON_PLANE;
1253 for (int n = 0; n < p->plane_count; n++) {
1254 struct texplane *plane = &p->planes[n];
1255 mpi->stride[n] = (mpi->width >> plane->shift_x) * p->plane_bytes;
1256 int needed_size = (mpi->height >> plane->shift_y) * mpi->stride[n];
1257 if (!plane->gl_buffer)
1258 gl->GenBuffers(1, &plane->gl_buffer);
1259 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, plane->gl_buffer);
1260 if (needed_size > plane->buffer_size) {
1261 plane->buffer_size = needed_size;
1262 gl->BufferData(GL_PIXEL_UNPACK_BUFFER, plane->buffer_size,
1263 NULL, GL_DYNAMIC_DRAW);
1265 if (!plane->buffer_ptr)
1266 plane->buffer_ptr = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER,
1267 GL_WRITE_ONLY);
1268 mpi->planes[n] = plane->buffer_ptr;
1269 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1271 mpi->flags |= MP_IMGFLAG_DIRECT;
1272 return VO_TRUE;
1275 static uint32_t draw_image(struct gl_priv *p, mp_image_t *mpi)
1277 GL *gl = p->gl;
1278 int n;
1280 assert(mpi->num_planes >= p->plane_count);
1282 mp_image_t mpi2 = *mpi;
1283 int w = mpi->w, h = mpi->h;
1284 if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
1285 goto skip_upload;
1286 mpi2.flags = 0;
1287 mpi2.type = MP_IMGTYPE_TEMP;
1288 mpi2.width = mpi2.w;
1289 mpi2.height = mpi2.h;
1290 if (!(mpi->flags & MP_IMGFLAG_DIRECT)
1291 && !p->planes[0].buffer_ptr
1292 && get_image(p->vo, &mpi2) == VO_TRUE)
1294 for (n = 0; n < p->plane_count; n++) {
1295 struct texplane *plane = &p->planes[n];
1296 int xs = plane->shift_x, ys = plane->shift_y;
1297 int line_bytes = (mpi->w >> xs) * p->plane_bytes;
1298 memcpy_pic(mpi2.planes[n], mpi->planes[n], line_bytes, mpi->h >> ys,
1299 mpi2.stride[n], mpi->stride[n]);
1301 mpi = &mpi2;
1303 p->mpi_flipped = mpi->stride[0] < 0;
1304 for (n = 0; n < p->plane_count; n++) {
1305 struct texplane *plane = &p->planes[n];
1306 int xs = plane->shift_x, ys = plane->shift_y;
1307 void *plane_ptr = mpi->planes[n];
1308 if (mpi->flags & MP_IMGFLAG_DIRECT) {
1309 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, plane->gl_buffer);
1310 if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER))
1311 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Video PBO upload failed. "
1312 "Remove the 'pbo' suboption.\n");
1313 plane->buffer_ptr = NULL;
1314 plane_ptr = NULL; // PBO offset 0
1316 gl->ActiveTexture(GL_TEXTURE0 + n);
1317 gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
1318 glUploadTex(gl, GL_TEXTURE_2D, p->gl_format, p->gl_type, plane_ptr,
1319 mpi->stride[n], 0, 0, w >> xs, h >> ys, 0);
1321 gl->ActiveTexture(GL_TEXTURE0);
1322 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1323 skip_upload:
1324 do_render(p);
1325 return VO_TRUE;
1328 static mp_image_t *get_screenshot(struct gl_priv *p)
1330 GL *gl = p->gl;
1332 mp_image_t *image = alloc_mpi(p->texture_width, p->texture_height,
1333 p->image_format);
1335 // NOTE about image formats with alpha plane: we don't even have the alpha
1336 // anymore. We never upload it to any texture, as it would be a waste of
1337 // time. On the other hand, we can't find a "similar", non-alpha image
1338 // format easily. So we just leave the alpha plane of the newly allocated
1339 // image as-is, and hope that the alpha is ignored by the receiver of the
1340 // screenshot. (If not, code should be added to make it fully opaque.)
1342 for (int n = 0; n < p->plane_count; n++) {
1343 gl->ActiveTexture(GL_TEXTURE0 + n);
1344 gl->BindTexture(GL_TEXTURE_2D, p->planes[n].gl_texture);
1345 glDownloadTex(gl, GL_TEXTURE_2D, p->gl_format, p->gl_type,
1346 image->planes[n], image->stride[n]);
1348 gl->ActiveTexture(GL_TEXTURE0);
1350 image->width = p->image_width;
1351 image->height = p->image_height;
1353 image->w = p->vo->aspdat.prew;
1354 image->h = p->vo->aspdat.preh;
1356 return image;
1359 static mp_image_t *get_window_screenshot(struct gl_priv *p)
1361 GL *gl = p->gl;
1363 mp_image_t *image = alloc_mpi(p->vp_w, p->vp_h, IMGFMT_RGB24);
1364 gl->PixelStorei(GL_PACK_ALIGNMENT, 4);
1365 gl->PixelStorei(GL_PACK_ROW_LENGTH, 0);
1366 gl->ReadBuffer(GL_FRONT);
1367 // flip image while reading
1368 for (int y = 0; y < p->vp_h; y++) {
1369 gl->ReadPixels(p->vp_x, p->vp_y + p->vp_h - y - 1, p->vp_w, 1,
1370 GL_RGB, GL_UNSIGNED_BYTE,
1371 image->planes[0] + y * image->stride[0]);
1373 return image;
1376 static void clear_osd(struct gl_priv *p)
1378 GL *gl = p->gl;
1380 if (!p->osd_textures_count)
1381 return;
1382 gl->DeleteTextures(p->osd_textures_count, p->osd_textures);
1383 p->osd_textures_count = 0;
1386 static void create_osd_texture(void *ctx, int x0, int y0, int w, int h,
1387 unsigned char *src, unsigned char *srca,
1388 int stride)
1390 struct gl_priv *p = ctx;
1391 GL *gl = p->gl;
1393 if (w <= 0 || h <= 0 || stride < w) {
1394 mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n");
1395 return;
1398 if (p->osd_textures_count >= MAX_OSD_PARTS) {
1399 mp_msg(MSGT_VO, MSGL_ERR, "Too many OSD parts, contact the developers!\n");
1400 return;
1403 int sx, sy;
1404 tex_size(p, w, h, &sx, &sy);
1406 gl->GenTextures(1, &p->osd_textures[p->osd_textures_count]);
1407 gl->BindTexture(GL_TEXTURE_2D, p->osd_textures[p->osd_textures_count]);
1408 gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RG, sx, sy, 0, GL_RG, GL_UNSIGNED_BYTE,
1409 NULL);
1410 default_tex_params(gl, GL_TEXTURE_2D, GL_NEAREST);
1411 unsigned char *tmp = malloc(stride * h * 2);
1412 // Convert alpha from weird MPlayer scale.
1413 for (int i = 0; i < h * stride; i++) {
1414 tmp[i*2+0] = src[i];
1415 tmp[i*2+1] = -srca[i];
1417 glUploadTex(gl, GL_TEXTURE_2D, GL_RG, GL_UNSIGNED_BYTE, tmp, stride * 2,
1418 0, 0, w, h, 0);
1419 free(tmp);
1421 gl->BindTexture(GL_TEXTURE_2D, 0);
1423 unsigned int osd_color = 0xffffff;
1424 uint8_t color[4] = {(osd_color >> 16) & 0xff, (osd_color >> 8) & 0xff,
1425 osd_color & 0xff, 0xff - (osd_color >> 24)};
1427 write_quad(&p->osd_va[p->osd_textures_count * VERTICES_PER_QUAD],
1428 x0, y0, x0 + w, y0 + h, 0, 0, w, h,
1429 sx, sy, color, false);
1431 p->osd_textures_count++;
1434 static void draw_osd(struct vo *vo, struct osd_state *osd)
1436 struct gl_priv *p = vo->priv;
1437 GL *gl = p->gl;
1439 if (vo_osd_changed(0)) {
1440 clear_osd(p);
1441 osd_draw_text_ext(osd, vo->dwidth, vo->dheight, p->border_x,
1442 p->border_y, p->border_x,
1443 p->border_y, p->image_width,
1444 p->image_height, create_osd_texture, p);
1447 if (p->osd_textures_count > 0) {
1448 gl->Enable(GL_BLEND);
1449 // OSD bitmaps use premultiplied alpha.
1450 gl->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1452 gl->UseProgram(p->osd_program);
1454 for (int n = 0; n < p->osd_textures_count; n++) {
1455 gl->BindTexture(GL_TEXTURE_2D, p->osd_textures[n]);
1456 draw_triangles(p, &p->osd_va[n * VERTICES_PER_QUAD],
1457 VERTICES_PER_QUAD);
1460 gl->UseProgram(0);
1462 gl->Disable(GL_BLEND);
1463 gl->BindTexture(GL_TEXTURE_2D, 0);
1467 static void gen_eosd(struct gl_priv *p, mp_eosd_images_t *imgs)
1469 GL *gl = p->gl;
1471 if (imgs->bitmap_pos_id == p->bitmap_pos_id)
1472 return;
1474 if (!p->eosd_texture) {
1475 gl->GenTextures(1, &p->eosd_texture);
1476 gl->GenBuffers(1, &p->eosd_buffer);
1479 gl->BindTexture(GL_TEXTURE_2D, p->eosd_texture);
1481 p->eosd_render_count = 0;
1482 bool need_upload = false;
1484 if (imgs->bitmap_id != p->bitmap_id) {
1485 need_upload = true;
1486 int res = packer_pack_from_subbitmaps(p->eosd, imgs, 0);
1487 if (res < 0) {
1488 mp_msg(MSGT_VO, MSGL_ERR,
1489 "[gl] subtitle bitmaps do not fit in maximum texture\n");
1490 return;
1492 if (res == 1) {
1493 mp_msg(MSGT_VO, MSGL_V, "[gl] Allocating a %dx%d texture for "
1494 "subtitle bitmaps.\n", p->eosd->w, p->eosd->h);
1495 tex_size(p, p->eosd->w, p->eosd->h,
1496 &p->eosd_texture_width, &p->eosd_texture_height);
1497 gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RED,
1498 p->eosd_texture_width, p->eosd_texture_height, 0,
1499 GL_RED, GL_UNSIGNED_BYTE, NULL);
1500 default_tex_params(gl, GL_TEXTURE_2D, GL_NEAREST);
1501 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->eosd_buffer);
1502 gl->BufferData(GL_PIXEL_UNPACK_BUFFER,
1503 p->eosd->w * p->eosd->h, NULL, GL_DYNAMIC_COPY);
1504 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1507 p->bitmap_id = imgs->bitmap_id;
1508 p->bitmap_pos_id = imgs->bitmap_pos_id;
1509 if (p->eosd->used_width == 0)
1510 return;
1512 p->eosd_va = talloc_realloc_size(p->eosd, p->eosd_va,
1513 p->eosd->count
1514 * sizeof(struct vertex)
1515 * VERTICES_PER_QUAD);
1517 if (need_upload && p->use_pbo) {
1518 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->eosd_buffer);
1519 char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
1520 if (!data) {
1521 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error: can't upload subtitles! "
1522 "Subtitles will look corrupted.\n");
1523 } else {
1524 ASS_Image *i = imgs->imgs;
1525 struct pos *spos = p->eosd->result;
1526 for (int n = 0; n < p->eosd->count; n++, i = i->next) {
1527 if (i->w == 0 || i->h == 0)
1528 continue;
1530 void *pdata = data + spos[n].y * p->eosd->w + spos[n].x;
1531 memcpy_pic(pdata, i->bitmap, i->w, i->h,
1532 p->eosd->w, i->stride);
1534 if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER))
1535 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] EOSD PBO upload failed. "
1536 "Remove the 'pbo' suboption.\n");
1537 glUploadTex(gl, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, NULL,
1538 p->eosd->w, 0, 0,
1539 p->eosd->used_width, p->eosd->used_height, 0);
1541 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1542 } else if (need_upload) {
1543 // non-PBO upload
1544 ASS_Image *i = imgs->imgs;
1545 struct pos *spos = p->eosd->result;
1546 for (int n = 0; n < p->eosd->count; n++, i = i->next) {
1547 if (i->w == 0 || i->h == 0)
1548 continue;
1549 glUploadTex(gl, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, i->bitmap,
1550 i->stride, spos[n].x, spos[n].y, i->w, i->h, 0);
1554 gl->BindTexture(GL_TEXTURE_2D, 0);
1556 debug_check_gl(p, "EOSD upload");
1558 ASS_Image *i = imgs->imgs;
1559 struct pos *spos = p->eosd->result;
1560 for (int n = 0; n < p->eosd->count; n++, i = i->next) {
1561 if (i->w == 0 || i->h == 0)
1562 continue;
1563 uint8_t color[4] = { i->color >> 24, (i->color >> 16) & 0xff,
1564 (i->color >> 8) & 0xff, 255 - (i->color & 0xff) };
1566 write_quad(&p->eosd_va[p->eosd_render_count * VERTICES_PER_QUAD],
1567 i->dst_x, i->dst_y,
1568 i->dst_x + i->w, i->dst_y + i->h,
1569 spos[n].x, spos[n].y,
1570 spos[n].x + i->w, spos[n].y + i->h,
1571 p->eosd_texture_width, p->eosd_texture_height,
1572 color, false);
1573 p->eosd_render_count++;
1577 static void draw_eosd(struct gl_priv *p, mp_eosd_images_t *imgs)
1579 GL *gl = p->gl;
1581 gen_eosd(p, imgs);
1583 if (p->eosd_render_count == 0)
1584 return;
1586 gl->Enable(GL_BLEND);
1587 gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1588 gl->BindTexture(GL_TEXTURE_2D, p->eosd_texture);
1589 gl->UseProgram(p->eosd_program);
1590 draw_triangles(p, p->eosd_va, p->eosd_render_count * VERTICES_PER_QUAD);
1591 gl->UseProgram(0);
1592 gl->BindTexture(GL_TEXTURE_2D, 0);
1593 gl->Disable(GL_BLEND);
1596 static void setup_vertex_array(GL *gl)
1598 size_t stride = sizeof(struct vertex);
1600 gl->EnableVertexAttribArray(VERTEX_ATTRIB_POSITION);
1601 gl->VertexAttribPointer(VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE,
1602 stride, (void*)offsetof(struct vertex, position));
1604 gl->EnableVertexAttribArray(VERTEX_ATTRIB_COLOR);
1605 gl->VertexAttribPointer(VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE,
1606 stride, (void*)offsetof(struct vertex, color));
1608 gl->EnableVertexAttribArray(VERTEX_ATTRIB_TEXCOORD);
1609 gl->VertexAttribPointer(VERTEX_ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE,
1610 stride, (void*)offsetof(struct vertex, texcoord));
1613 static int init_gl(struct gl_priv *p)
1615 GL *gl = p->gl;
1617 debug_check_gl(p, "before init_gl");
1619 const char *vendor = gl->GetString(GL_VENDOR);
1620 const char *version = gl->GetString(GL_VERSION);
1621 const char *renderer = gl->GetString(GL_RENDERER);
1622 const char *glsl = gl->GetString(GL_SHADING_LANGUAGE_VERSION);
1623 mp_msg(MSGT_VO, MSGL_V, "[gl] GL_RENDERER='%s', GL_VENDOR='%s', "
1624 "GL_VERSION='%s', GL_SHADING_LANGUAGE_VERSION='%s'"
1625 "\n", renderer, vendor, version, glsl);
1626 mp_msg(MSGT_VO, MSGL_V, "[gl] Display depth: R=%d, G=%d, B=%d\n",
1627 p->glctx->depth_r, p->glctx->depth_g, p->glctx->depth_b);
1629 GLint major, minor;
1630 gl->GetIntegerv(GL_MAJOR_VERSION, &major);
1631 gl->GetIntegerv(GL_MINOR_VERSION, &minor);
1633 p->shader_version = "130";
1635 // Hack for OSX: it only creates 3.2 contexts.
1636 if (MPGL_VER(major, minor) >= MPGL_VER(3, 2))
1637 p->shader_version = "150";
1639 gl->Disable(GL_DITHER);
1640 gl->Disable(GL_BLEND);
1641 gl->Disable(GL_DEPTH_TEST);
1642 gl->DepthMask(GL_FALSE);
1643 gl->Disable(GL_CULL_FACE);
1644 gl->DrawBuffer(GL_BACK);
1646 gl->GenBuffers(1, &p->vertex_buffer);
1647 gl->GenVertexArrays(1, &p->vao);
1649 gl->BindBuffer(GL_ARRAY_BUFFER, p->vertex_buffer);
1650 gl->BindVertexArray(p->vao);
1651 setup_vertex_array(gl);
1652 gl->BindBuffer(GL_ARRAY_BUFFER, 0);
1653 gl->BindVertexArray(0);
1655 GLint max_texture_size;
1656 gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
1657 p->eosd->w_max = p->eosd->h_max = max_texture_size;
1659 gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1660 gl->Clear(GL_COLOR_BUFFER_BIT);
1661 if (gl->SwapInterval && p->swap_interval >= 0)
1662 gl->SwapInterval(p->swap_interval);
1664 debug_check_gl(p, "after init_gl");
1666 return 1;
1669 static void uninit_gl(struct gl_priv *p)
1671 GL *gl = p->gl;
1673 // NOTE: GL functions might not be loaded yet
1674 if (!(p->glctx && p->gl->DeleteTextures))
1675 return;
1677 uninit_video(p);
1679 gl->DeleteVertexArrays(1, &p->vao);
1680 p->vao = 0;
1681 gl->DeleteBuffers(1, &p->vertex_buffer);
1682 p->vertex_buffer = 0;
1684 clear_osd(p);
1685 gl->DeleteTextures(1, &p->eosd_texture);
1686 p->eosd_texture = 0;
1687 gl->DeleteBuffers(1, &p->eosd_buffer);
1688 p->eosd_buffer = 0;
1689 p->bitmap_id = p->bitmap_pos_id = 0;
1690 p->eosd->w = p->eosd->h = 0;
1692 gl->DeleteTextures(1, &p->lut_3d_texture);
1693 p->lut_3d_texture = 0;
1696 static bool init_format(int fmt, struct gl_priv *init)
1698 bool supported = false;
1699 struct gl_priv dummy;
1700 if (!init)
1701 init = &dummy;
1703 mp_image_t dummy_img = {0};
1704 mp_image_setfmt(&dummy_img, fmt);
1706 init->image_format = fmt;
1707 init->component_bits = -1;
1709 // RGB/packed formats
1710 for (const struct fmt_entry *e = mp_to_gl_formats; e->mp_format; e++) {
1711 if (e->mp_format == fmt) {
1712 supported = true;
1713 init->plane_bits = dummy_img.bpp;
1714 init->gl_format = e->format;
1715 init->gl_internal_format = e->internal_format;
1716 init->component_bits = e->component_bits;
1717 init->gl_type = e->type;
1718 break;
1722 // YUV/planar formats
1723 if (!supported && mp_get_chroma_shift(fmt, NULL, NULL, &init->plane_bits)) {
1724 init->gl_format = GL_RED;
1725 init->component_bits = init->plane_bits;
1726 if (init->plane_bits == 8) {
1727 supported = true;
1728 init->gl_internal_format = GL_RED;
1729 init->gl_type = GL_UNSIGNED_BYTE;
1730 } else if (IMGFMT_IS_YUVP16_NE(fmt)) {
1731 supported = true;
1732 init->gl_internal_format = GL_R16;
1733 init->gl_type = GL_UNSIGNED_SHORT;
1737 // RGB/planar
1738 if (!supported && fmt == IMGFMT_GBRP) {
1739 supported = true;
1740 init->plane_bits = init->component_bits = 8;
1741 init->gl_format = GL_RED;
1742 init->gl_internal_format = GL_RED;
1743 init->gl_type = GL_UNSIGNED_BYTE;
1746 if (!supported)
1747 return false;
1749 init->plane_bytes = (init->plane_bits + 7) / 8;
1750 init->is_yuv = dummy_img.flags & MP_IMGFLAG_YUV;
1751 init->is_linear_rgb = false;
1753 // NOTE: we throw away the additional alpha plane, if one exists.
1754 init->plane_count = dummy_img.num_planes > 2 ? 3 : 1;
1755 assert(dummy_img.num_planes >= init->plane_count);
1756 assert(dummy_img.num_planes <= init->plane_count + 1);
1758 for (int n = 0; n < init->plane_count; n++) {
1759 struct texplane *plane = &init->planes[n];
1761 plane->shift_x = n > 0 ? dummy_img.chroma_x_shift : 0;
1762 plane->shift_y = n > 0 ? dummy_img.chroma_y_shift : 0;
1765 return true;
1768 static int query_format(uint32_t format)
1770 int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP |
1771 VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE |
1772 VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED;
1773 if (!init_format(format, NULL))
1774 return 0;
1775 return caps;
1778 static bool config_window(struct gl_priv *p, uint32_t d_width,
1779 uint32_t d_height, uint32_t flags)
1781 if (p->stereo_mode == GL_3D_QUADBUFFER)
1782 flags |= VOFLAG_STEREO;
1784 int mpgl_version = MPGL_VER(3, 0);
1785 int mpgl_flags = p->use_gl_debug ? MPGLFLAG_DEBUG : 0;
1787 if (p->use_gl2)
1788 mpgl_version = MPGL_VER(2, 1);
1790 if (create_mpglcontext(p->glctx, mpgl_flags, mpgl_version, d_width,
1791 d_height, flags) == SET_WINDOW_FAILED)
1792 return false;
1794 if (!p->vertex_buffer)
1795 init_gl(p);
1797 return true;
1800 static int config(struct vo *vo, uint32_t width, uint32_t height,
1801 uint32_t d_width, uint32_t d_height, uint32_t flags,
1802 uint32_t format)
1804 struct gl_priv *p = vo->priv;
1806 if (!config_window(p, d_width, d_height, flags))
1807 return -1;
1809 p->vo_flipped = !!(flags & VOFLAG_FLIPPING);
1811 if (p->image_format != format || p->image_width != width
1812 || p->image_height != height)
1814 uninit_video(p);
1815 p->image_height = height;
1816 p->image_width = width;
1817 init_format(format, p);
1818 init_video(p);
1821 resize(p);
1823 return 0;
1826 static void check_events(struct vo *vo)
1828 struct gl_priv *p = vo->priv;
1830 int e = p->glctx->check_events(vo);
1831 if (e & VO_EVENT_REINIT) {
1832 uninit_gl(p);
1833 init_gl(p);
1834 init_video(p);
1835 resize(p);
1837 if (e & VO_EVENT_RESIZE)
1838 resize(p);
1839 if (e & VO_EVENT_EXPOSE)
1840 vo->want_redraw = true;
1843 static int control(struct vo *vo, uint32_t request, void *data)
1845 struct gl_priv *p = vo->priv;
1847 switch (request) {
1848 case VOCTRL_QUERY_FORMAT:
1849 return query_format(*(uint32_t *)data);
1850 case VOCTRL_GET_IMAGE:
1851 return get_image(vo, data);
1852 case VOCTRL_DRAW_IMAGE:
1853 return draw_image(p, data);
1854 case VOCTRL_DRAW_EOSD:
1855 if (!data)
1856 return VO_FALSE;
1857 draw_eosd(p, data);
1858 return VO_TRUE;
1859 case VOCTRL_GET_EOSD_RES: {
1860 mp_eosd_res_t *r = data;
1861 r->w = vo->dwidth;
1862 r->h = vo->dheight;
1863 r->ml = r->mr = p->border_x;
1864 r->mt = r->mb = p->border_y;
1865 return VO_TRUE;
1867 case VOCTRL_ONTOP:
1868 if (!p->glctx->ontop)
1869 break;
1870 p->glctx->ontop(vo);
1871 return VO_TRUE;
1872 case VOCTRL_FULLSCREEN:
1873 p->glctx->fullscreen(vo);
1874 resize(p);
1875 return VO_TRUE;
1876 case VOCTRL_BORDER:
1877 if (!p->glctx->border)
1878 break;
1879 p->glctx->border(vo);
1880 resize(p);
1881 return VO_TRUE;
1882 case VOCTRL_GET_PANSCAN:
1883 return VO_TRUE;
1884 case VOCTRL_SET_PANSCAN:
1885 resize(p);
1886 return VO_TRUE;
1887 case VOCTRL_GET_EQUALIZER: {
1888 struct voctrl_get_equalizer_args *args = data;
1889 return mp_csp_equalizer_get(&p->video_eq, args->name, args->valueptr)
1890 >= 0 ? VO_TRUE : VO_NOTIMPL;
1892 case VOCTRL_SET_EQUALIZER: {
1893 struct voctrl_set_equalizer_args *args = data;
1894 if (mp_csp_equalizer_set(&p->video_eq, args->name, args->value) < 0)
1895 return VO_NOTIMPL;
1896 if (!p->use_gamma && p->video_eq.values[MP_CSP_EQ_GAMMA] != 0) {
1897 mp_msg(MSGT_VO, MSGL_V, "[gl] Auto-enabling gamma.\n");
1898 p->use_gamma = true;
1899 compile_shaders(p);
1901 update_all_uniforms(p);
1902 vo->want_redraw = true;
1903 return VO_TRUE;
1905 case VOCTRL_SET_YUV_COLORSPACE: {
1906 if (p->is_yuv) {
1907 p->colorspace = *(struct mp_csp_details *)data;
1908 update_all_uniforms(p);
1909 vo->want_redraw = true;
1911 return VO_TRUE;
1913 case VOCTRL_GET_YUV_COLORSPACE:
1914 *(struct mp_csp_details *)data = p->colorspace;
1915 return VO_TRUE;
1916 case VOCTRL_UPDATE_SCREENINFO:
1917 if (!p->glctx->update_xinerama_info)
1918 break;
1919 p->glctx->update_xinerama_info(vo);
1920 return VO_TRUE;
1921 case VOCTRL_SCREENSHOT: {
1922 struct voctrl_screenshot_args *args = data;
1923 if (args->full_window)
1924 args->out_image = get_window_screenshot(p);
1925 else
1926 args->out_image = get_screenshot(p);
1927 return true;
1929 case VOCTRL_REDRAW_FRAME:
1930 do_render(p);
1931 return true;
1933 return VO_NOTIMPL;
1936 static void uninit(struct vo *vo)
1938 struct gl_priv *p = vo->priv;
1940 uninit_gl(p);
1941 uninit_mpglcontext(p->glctx);
1942 p->glctx = NULL;
1943 p->gl = NULL;
1946 #ifdef CONFIG_LCMS2
1948 static void lcms2_error_handler(cmsContext ctx, cmsUInt32Number code,
1949 const char *msg)
1951 mp_msg(MSGT_VO, MSGL_ERR, "[gl] lcms2: %s\n", msg);
1954 static struct bstr load_file(struct gl_priv *p, void *talloc_ctx,
1955 const char *filename)
1957 struct bstr res = {0};
1958 stream_t *s = open_stream(filename, p->vo->opts, NULL);
1959 if (s) {
1960 res = stream_read_complete(s, talloc_ctx, 1000000000, 0);
1961 free_stream(s);
1963 return res;
1966 #define LUT3D_CACHE_HEADER "mplayer2 3dlut cache 1.0\n"
1968 static bool load_icc(struct gl_priv *p, const char *icc_file,
1969 const char *icc_cache, int icc_intent,
1970 int s_r, int s_g, int s_b)
1972 void *tmp = talloc_new(p);
1973 uint16_t *output = talloc_array(tmp, uint16_t, s_r * s_g * s_b * 3);
1975 if (icc_intent == -1)
1976 icc_intent = INTENT_ABSOLUTE_COLORIMETRIC;
1978 mp_msg(MSGT_VO, MSGL_INFO, "[gl] Opening ICC profile '%s'\n", icc_file);
1979 struct bstr iccdata = load_file(p, tmp, icc_file);
1980 if (!iccdata.len)
1981 goto error_exit;
1983 char *cache_info = talloc_asprintf(tmp, "intent=%d, size=%dx%dx%d\n",
1984 icc_intent, s_r, s_g, s_b);
1986 // check cache
1987 if (icc_cache) {
1988 mp_msg(MSGT_VO, MSGL_INFO, "[gl] Opening 3D LUT cache in file '%s'.\n",
1989 icc_cache);
1990 struct bstr cachedata = load_file(p, tmp, icc_cache);
1991 if (bstr_eatstart(&cachedata, bstr(LUT3D_CACHE_HEADER))
1992 && bstr_eatstart(&cachedata, bstr(cache_info))
1993 && bstr_eatstart(&cachedata, iccdata)
1994 && cachedata.len == talloc_get_size(output))
1996 memcpy(output, cachedata.start, cachedata.len);
1997 goto done;
1998 } else {
1999 mp_msg(MSGT_VO, MSGL_WARN, "[gl] 3D LUT cache invalid!\n");
2003 cmsSetLogErrorHandler(lcms2_error_handler);
2005 cmsHPROFILE profile = cmsOpenProfileFromMem(iccdata.start, iccdata.len);
2006 if (!profile)
2007 goto error_exit;
2009 cmsCIExyY d65;
2010 cmsWhitePointFromTemp(&d65, 6504);
2011 static const cmsCIExyYTRIPLE bt709prim = {
2012 .Red = {0.64, 0.33, 1.0},
2013 .Green = {0.30, 0.60, 1.0},
2014 .Blue = {0.15, 0.06, 1.0},
2016 cmsToneCurve *tonecurve = cmsBuildGamma(NULL, 2.2);
2017 cmsHPROFILE vid_profile = cmsCreateRGBProfile(&d65, &bt709prim,
2018 (cmsToneCurve*[3]){tonecurve, tonecurve, tonecurve});
2019 cmsFreeToneCurve(tonecurve);
2020 cmsHTRANSFORM trafo = cmsCreateTransform(vid_profile, TYPE_RGB_16,
2021 profile, TYPE_RGB_16,
2022 icc_intent,
2023 cmsFLAGS_HIGHRESPRECALC);
2024 cmsCloseProfile(profile);
2025 cmsCloseProfile(vid_profile);
2027 if (!trafo)
2028 goto error_exit;
2030 // transform a (s_r)x(s_g)x(s_b) cube, with 3 components per channel
2031 uint16_t *input = talloc_array(tmp, uint16_t, s_r * 3);
2032 for (int b = 0; b < s_b; b++) {
2033 for (int g = 0; g < s_g; g++) {
2034 for (int r = 0; r < s_r; r++) {
2035 input[r * 3 + 0] = r * 65535 / (s_r - 1);
2036 input[r * 3 + 1] = g * 65535 / (s_g - 1);
2037 input[r * 3 + 2] = b * 65535 / (s_b - 1);
2039 size_t base = (b * s_r * s_g + g * s_r) * 3;
2040 cmsDoTransform(trafo, input, output + base, s_r);
2044 cmsDeleteTransform(trafo);
2046 if (icc_cache) {
2047 FILE *out = fopen(icc_cache, "wb");
2048 if (out) {
2049 fprintf(out, "%s%s", LUT3D_CACHE_HEADER, cache_info);
2050 fwrite(iccdata.start, iccdata.len, 1, out);
2051 fwrite(output, talloc_get_size(output), 1, out);
2052 fclose(out);
2056 done:
2058 p->lut_3d_data = talloc_steal(p, output);
2059 p->lut_3d_w = s_r, p->lut_3d_h = s_g, p->lut_3d_d = s_b;
2060 p->use_lut_3d = true;
2062 talloc_free(tmp);
2063 return true;
2065 error_exit:
2066 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error loading ICC profile.\n");
2067 talloc_free(tmp);
2068 return false;
2071 #else /* CONFIG_LCMS2 */
2073 static bool load_icc(struct gl_priv *p, ...)
2075 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] LCMS2 support not compiled.\n");
2076 return false;
2079 #endif /* CONFIG_LCMS2 */
2081 static bool parse_3dlut_size(const char *s, int *p1, int *p2, int *p3)
2083 if (sscanf(s, "%dx%dx%d", p1, p2, p3) != 3)
2084 return false;
2085 for (int n = 0; n < 3; n++) {
2086 int s = ((int[]) { *p1, *p2, *p3 })[n];
2087 if (s < 2 || s > 256 || ((s - 1) & s))
2088 return false;
2090 return true;
2093 static int lut3d_size_valid(void *arg)
2095 char *s = *(char **)arg;
2096 int p1, p2, p3;
2097 return parse_3dlut_size(s, &p1, &p2, &p3);
2100 static int backend_valid(void *arg)
2102 return mpgl_find_backend(*(const char **)arg) >= 0;
2105 struct fbo_format {
2106 const char *name;
2107 GLint format;
2110 const struct fbo_format fbo_formats[] = {
2111 {"rgb", GL_RGB},
2112 {"rgba", GL_RGBA},
2113 {"rgb8", GL_RGB8},
2114 {"rgb16", GL_RGB16},
2115 {"rgb16f", GL_RGB16F},
2116 {"rgb32f", GL_RGB32F},
2120 static GLint find_fbo_format(const char *name)
2122 for (const struct fbo_format *fmt = fbo_formats; fmt->name; fmt++) {
2123 if (strcmp(fmt->name, name) == 0)
2124 return fmt->format;
2126 return -1;
2129 static int fbo_format_valid(void *arg)
2131 return find_fbo_format(*(const char **)arg) >= 0;
2134 static bool can_use_filter_kernel(const struct filter_kernel *kernel)
2136 if (!kernel)
2137 return false;
2138 struct filter_kernel k = *kernel;
2139 return mp_init_filter(&k, filter_sizes, 1);
2142 static const char* handle_scaler_opt(const char *name)
2144 const struct filter_kernel *kernel = mp_find_filter_kernel(name);
2145 if (can_use_filter_kernel(kernel))
2146 return kernel->name;
2148 for (const char **filter = fixed_scale_filters; *filter; filter++) {
2149 if (strcmp(*filter, name) == 0)
2150 return *filter;
2153 return NULL;
2156 static int scaler_valid(void *arg)
2158 return handle_scaler_opt(*(const char **)arg) != NULL;
2161 #if 0
2162 static void print_scalers(void)
2164 mp_msg(MSGT_VO, MSGL_INFO, "Available scalers:\n");
2165 for (const char **e = fixed_scale_filters; *e; e++) {
2166 mp_msg(MSGT_VO, MSGL_INFO, " %s\n", *e);
2168 for (const struct filter_kernel *e = mp_filter_kernels; e->name; e++) {
2169 if (can_use_filter_kernel(e))
2170 mp_msg(MSGT_VO, MSGL_INFO, " %s\n", e->name);
2173 #endif
2175 static int preinit(struct vo *vo, const char *arg)
2177 struct gl_priv *p = talloc_zero(vo, struct gl_priv);
2178 vo->priv = p;
2180 *p = (struct gl_priv) {
2181 .vo = vo,
2182 .colorspace = MP_CSP_DETAILS_DEFAULTS,
2183 .use_npot = 1,
2184 .use_pbo = 0,
2185 .swap_interval = 1,
2186 .fbo_format = GL_RGB16,
2187 .use_scale_sep = 1,
2188 .use_fancy_downscaling = 1,
2189 .scalers = {
2190 { .index = 0, .name = "lanczos2" },
2191 { .index = 1, .name = "bilinear" },
2193 .scaler_params = {NAN, NAN},
2197 char *scalers[2] = {0};
2198 char *backend_arg = NULL;
2199 char *fbo_format = NULL;
2200 char *icc_profile = NULL;
2201 char *icc_cache = NULL;
2202 int icc_intent = -1;
2203 char *icc_size_str = NULL;
2205 const opt_t subopts[] = {
2206 {"gamma", OPT_ARG_BOOL, &p->use_gamma},
2207 {"srgb", OPT_ARG_BOOL, &p->use_srgb},
2208 {"npot", OPT_ARG_BOOL, &p->use_npot},
2209 {"pbo", OPT_ARG_BOOL, &p->use_pbo},
2210 {"glfinish", OPT_ARG_BOOL, &p->use_glFinish},
2211 {"swapinterval", OPT_ARG_INT, &p->swap_interval},
2212 {"stereo", OPT_ARG_INT, &p->stereo_mode},
2213 {"lscale", OPT_ARG_MSTRZ, &scalers[0], scaler_valid},
2214 {"cscale", OPT_ARG_MSTRZ, &scalers[1], scaler_valid},
2215 {"lparam1", OPT_ARG_FLOAT, &p->scaler_params[0]},
2216 {"lparam2", OPT_ARG_FLOAT, &p->scaler_params[1]},
2217 {"fancy-downscaling", OPT_ARG_BOOL, &p->use_fancy_downscaling},
2218 {"debug", OPT_ARG_BOOL, &p->use_gl_debug},
2219 {"force-gl2", OPT_ARG_BOOL, &p->use_gl2},
2220 {"indirect", OPT_ARG_BOOL, &p->use_indirect},
2221 {"scale-sep", OPT_ARG_BOOL, &p->use_scale_sep},
2222 {"fbo-format", OPT_ARG_MSTRZ, &fbo_format, fbo_format_valid},
2223 {"backend", OPT_ARG_MSTRZ, &backend_arg, backend_valid},
2224 {"icc-profile", OPT_ARG_MSTRZ, &icc_profile},
2225 {"icc-cache", OPT_ARG_MSTRZ, &icc_cache},
2226 {"icc-intent", OPT_ARG_INT, &icc_intent},
2227 {"3dlut-size", OPT_ARG_MSTRZ, &icc_size_str,
2228 lut3d_size_valid},
2229 {"dither-depth", OPT_ARG_INT, &p->dither_depth},
2230 {NULL}
2233 if (subopt_parse(arg, subopts) != 0) {
2234 mp_msg(MSGT_VO, MSGL_FATAL, help_text);
2235 goto err_out;
2238 int backend = backend_arg ? mpgl_find_backend(backend_arg) : GLTYPE_AUTO;
2239 free(backend_arg);
2241 if (fbo_format)
2242 p->fbo_format = find_fbo_format(fbo_format);
2243 free(fbo_format);
2245 for (int n = 0; n < 2; n++) {
2246 if (scalers[n])
2247 p->scalers[n].name = handle_scaler_opt(scalers[n]);
2248 free(scalers[n]);
2251 int s_r = 128, s_g = 256, s_b = 64;
2252 if (icc_size_str)
2253 parse_3dlut_size(icc_size_str, &s_r, &s_g, &s_b);
2254 free(icc_size_str);
2256 bool success = true;
2257 if (icc_profile) {
2258 success = load_icc(p, icc_profile, icc_cache, icc_intent,
2259 s_r, s_g, s_b);
2261 free(icc_profile);
2262 free(icc_cache);
2264 if (!success)
2265 goto err_out;
2267 p->eosd = talloc_zero(vo, struct bitmap_packer);
2269 p->glctx = init_mpglcontext(backend, vo);
2270 if (!p->glctx)
2271 goto err_out;
2272 p->gl = p->glctx->gl;
2274 if (true) {
2275 if (!config_window(p, 320, 200, VOFLAG_HIDDEN))
2276 goto err_out;
2277 // We created a window to test whether the GL context could be
2278 // created and so on. Destroy that window to make sure all state
2279 // associated with it is lost.
2280 uninit(vo);
2281 p->glctx = init_mpglcontext(backend, vo);
2282 if (!p->glctx)
2283 goto err_out;
2284 p->gl = p->glctx->gl;
2287 return 0;
2289 err_out:
2290 uninit(vo);
2291 return -1;
2294 const struct vo_driver video_out_gl3 = {
2295 .is_new = true,
2296 .info = &(const vo_info_t) {
2297 "OpenGL 3.x",
2298 "gl3",
2299 "Based on vo_gl.c by Reimar Doeffinger",
2302 .preinit = preinit,
2303 .config = config,
2304 .control = control,
2305 .draw_slice = draw_slice,
2306 .draw_osd = draw_osd,
2307 .flip_page = flip_page,
2308 .check_events = check_events,
2309 .uninit = uninit,
2312 static const char help_text[] =
2313 "\n--vo=gl3 command line help:\n"
2314 "Example: mplayer --vo=gl3:scale-sep:lscale=lanczos2\n"
2315 "\nOptions:\n"
2316 " lscale=<filter>\n"
2317 " Set the scaling filter. Possible choices:\n"
2318 " bilinear: bilinear texture filtering (fastest).\n"
2319 " bicubic_fast: bicubic filter (without lookup texture).\n"
2320 " sharpen3: unsharp masking (sharpening) with radius=3.\n"
2321 " sharpen5: unsharp masking (sharpening) with radius=5.\n"
2322 " lanczos2: Lanczos with radius=2 (default, recommended).\n"
2323 " lanczos3: Lanczos with radius=3 (not recommended).\n"
2324 " mitchell: Mitchell-Netravali.\n"
2325 " Default: lanczos2\n"
2326 " lparam1=<value> / lparam2=<value>\n"
2327 " Set parameters for configurable filters. Affects chroma scaler\n"
2328 " as well.\n"
2329 " Filters which use this:\n"
2330 " mitchell: b and c params (defaults: b=1/3 c=1/3)\n"
2331 " kaiser: (defaults: 6.33 6.33)\n"
2332 " sharpen3: lparam1 sets sharpening strength (default: 0.5)\n"
2333 " sharpen5: as with sharpen3\n"
2334 " stereo=<n>\n"
2335 " 0: normal display\n"
2336 " 1: side-by-side to red-cyan stereo\n"
2337 " 2: side-by-side to green-magenta stereo\n"
2338 " 3: side-by-side to quadbuffer stereo\n"
2339 " srgb\n"
2340 " Enable gamma-correct scaling by working in linear light. This\n"
2341 " makes use of sRGB textures and framebuffers.\n"
2342 " This option forces the options 'indirect' and 'gamma'.\n"
2343 " NOTE: for BT.709 colorspaces, a gamma of 2.35 is assumed. For\n"
2344 " other YUV colorspaces, 2.2 is assumed. RGB input is always\n"
2345 " assumed to be in sRGB.\n"
2346 " pbo\n"
2347 " Enable use of PBOs. This is faster, but can sometimes lead to\n"
2348 " sporadic and temporary image corruption.\n"
2349 " dither-depth=<n>\n"
2350 " Positive non-zero values select the target bit depth.\n"
2351 " -1: Disable any dithering done by mplayer.\n"
2352 " 0: Automatic selection. If output bit depth can't be detected,\n"
2353 " 8 bits per component are assumed.\n"
2354 " 8: Dither to 8 bit output.\n"
2355 " Default: 0.\n"
2356 " Note that dithering will always be disabled if the bit depth\n"
2357 " of the video is lower or qual to the detected dither-depth.\n"
2358 " If color management is enabled, input depth is assumed to be\n"
2359 " 16 bits, because the 3D LUT output is 16 bit wide.\n"
2360 " debug\n"
2361 " Check for OpenGL errors, i.e. call glGetError(). Also request a\n"
2362 " debug OpenGL context.\n"
2363 "Less useful options:\n"
2364 " swapinterval=<n>\n"
2365 " Interval in displayed frames between to buffer swaps.\n"
2366 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
2367 " no-scale-sep\n"
2368 " When using a separable scale filter for luma, usually two filter\n"
2369 " passes are done. This is often faster. However, it forces\n"
2370 " conversion to RGB in an extra pass, so it can actually be slower\n"
2371 " if used with fast filters on small screen resolutions. Using\n"
2372 " this options will make rendering a single operation.\n"
2373 " Note that chroma scalers are always done as 1-pass filters.\n"
2374 " cscale=<n>\n"
2375 " As lscale but for chroma (2x slower with little visible effect).\n"
2376 " Note that with some scaling filters, upscaling is always done in\n"
2377 " RGB. If chroma is not subsampled, this option is ignored, and the\n"
2378 " luma scaler is used instead. Setting this option is often useless.\n"
2379 " no-fancy-downscaling\n"
2380 " When using convolution based filters, don't extend the filter\n"
2381 " size when downscaling. Trades downscaling performance for\n"
2382 " reduced quality.\n"
2383 " no-npot\n"
2384 " Force use of power-of-2 texture sizes. For debugging only.\n"
2385 " Borders will look discolored due to filtering.\n"
2386 " glfinish\n"
2387 " Call glFinish() before swapping buffers\n"
2388 " backend=<sys>\n"
2389 " auto: auto-select (default)\n"
2390 " cocoa: Cocoa/OSX\n"
2391 " win: Win32/WGL\n"
2392 " x11: X11/GLX\n"
2393 " indirect\n"
2394 " Do YUV conversion and scaling as separate passes. This will\n"
2395 " first render the video into a video-sized RGB texture, and\n"
2396 " draw the result on screen. The luma scaler is used to scale\n"
2397 " the RGB image when rendering to screen. The chroma scaler\n"
2398 " is used only on YUV conversion, and only if the video uses\n"
2399 " chroma-subsampling.\n"
2400 " This mechanism is disabled on RGB input.\n"
2401 " fbo-format=<fmt>\n"
2402 " Selects the internal format of any FBO textures used.\n"
2403 " fmt can be one of: rgb, rgba, rgb8, rgb16, rgb16f, rgb32f\n"
2404 " Default: rgb16.\n"
2405 " gamma\n"
2406 " Always enable gamma control. (Disables delayed enabling.)\n"
2407 " force-gl2\n"
2408 " Create a legacy GL context. This will randomly malfunction\n"
2409 " if the proper extensions are not supported.\n"
2410 "Color management:\n"
2411 " icc-profile=<file>\n"
2412 " Load an ICC profile and use it to transform linear RGB to\n"
2413 " screen output. Needs LittleCMS2 support compiled in.\n"
2414 " icc-cache=<file>\n"
2415 " Store and load the 3D LUT created from the ICC profile in\n"
2416 " this file. This can be used to speed up loading, since\n"
2417 " LittleCMS2 can take a while to create the 3D LUT.\n"
2418 " Note that this file will be at most about 100 MB big.\n"
2419 " icc-intent=<value>\n"
2420 " 0: perceptual\n"
2421 " 1: relative colorimetric\n"
2422 " 2: saturation\n"
2423 " 3: absolute colorimetric (default)\n"
2424 " 3dlut-size=<r>x<g>x<b>\n"
2425 " Size of the 3D LUT generated from the ICC profile in each\n"
2426 " dimension. Default is 128x256x64.\n"
2427 " Sizes must be a power of two, and 256 at most.\n"
2428 "\n";