vo_gl3: call glFlush() after frame drawing is complete
[mplayer.git] / libvo / vo_gl3.c
blob9647c85d150779a5a9533cb6de18d9c83c9a6048
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);
1466 // The playloop calls this last before waiting some time until it decides
1467 // to call flip_page(). Tell OpenGL to start execution of the GPU commands
1468 // while we sleep (this happens asynchronously).
1469 gl->Flush();
1472 static void gen_eosd(struct gl_priv *p, mp_eosd_images_t *imgs)
1474 GL *gl = p->gl;
1476 if (imgs->bitmap_pos_id == p->bitmap_pos_id)
1477 return;
1479 if (!p->eosd_texture) {
1480 gl->GenTextures(1, &p->eosd_texture);
1481 gl->GenBuffers(1, &p->eosd_buffer);
1484 gl->BindTexture(GL_TEXTURE_2D, p->eosd_texture);
1486 p->eosd_render_count = 0;
1487 bool need_upload = false;
1489 if (imgs->bitmap_id != p->bitmap_id) {
1490 need_upload = true;
1491 int res = packer_pack_from_subbitmaps(p->eosd, imgs, 0);
1492 if (res < 0) {
1493 mp_msg(MSGT_VO, MSGL_ERR,
1494 "[gl] subtitle bitmaps do not fit in maximum texture\n");
1495 return;
1497 if (res == 1) {
1498 mp_msg(MSGT_VO, MSGL_V, "[gl] Allocating a %dx%d texture for "
1499 "subtitle bitmaps.\n", p->eosd->w, p->eosd->h);
1500 tex_size(p, p->eosd->w, p->eosd->h,
1501 &p->eosd_texture_width, &p->eosd_texture_height);
1502 gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RED,
1503 p->eosd_texture_width, p->eosd_texture_height, 0,
1504 GL_RED, GL_UNSIGNED_BYTE, NULL);
1505 default_tex_params(gl, GL_TEXTURE_2D, GL_NEAREST);
1506 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->eosd_buffer);
1507 gl->BufferData(GL_PIXEL_UNPACK_BUFFER,
1508 p->eosd->w * p->eosd->h, NULL, GL_DYNAMIC_COPY);
1509 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1512 p->bitmap_id = imgs->bitmap_id;
1513 p->bitmap_pos_id = imgs->bitmap_pos_id;
1514 if (p->eosd->used_width == 0)
1515 return;
1517 p->eosd_va = talloc_realloc_size(p->eosd, p->eosd_va,
1518 p->eosd->count
1519 * sizeof(struct vertex)
1520 * VERTICES_PER_QUAD);
1522 if (need_upload && p->use_pbo) {
1523 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->eosd_buffer);
1524 char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
1525 if (!data) {
1526 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error: can't upload subtitles! "
1527 "Subtitles will look corrupted.\n");
1528 } else {
1529 ASS_Image *i = imgs->imgs;
1530 struct pos *spos = p->eosd->result;
1531 for (int n = 0; n < p->eosd->count; n++, i = i->next) {
1532 if (i->w == 0 || i->h == 0)
1533 continue;
1535 void *pdata = data + spos[n].y * p->eosd->w + spos[n].x;
1536 memcpy_pic(pdata, i->bitmap, i->w, i->h,
1537 p->eosd->w, i->stride);
1539 if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER))
1540 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] EOSD PBO upload failed. "
1541 "Remove the 'pbo' suboption.\n");
1542 glUploadTex(gl, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, NULL,
1543 p->eosd->w, 0, 0,
1544 p->eosd->used_width, p->eosd->used_height, 0);
1546 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1547 } else if (need_upload) {
1548 // non-PBO upload
1549 ASS_Image *i = imgs->imgs;
1550 struct pos *spos = p->eosd->result;
1551 for (int n = 0; n < p->eosd->count; n++, i = i->next) {
1552 if (i->w == 0 || i->h == 0)
1553 continue;
1554 glUploadTex(gl, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, i->bitmap,
1555 i->stride, spos[n].x, spos[n].y, i->w, i->h, 0);
1559 gl->BindTexture(GL_TEXTURE_2D, 0);
1561 debug_check_gl(p, "EOSD upload");
1563 ASS_Image *i = imgs->imgs;
1564 struct pos *spos = p->eosd->result;
1565 for (int n = 0; n < p->eosd->count; n++, i = i->next) {
1566 if (i->w == 0 || i->h == 0)
1567 continue;
1568 uint8_t color[4] = { i->color >> 24, (i->color >> 16) & 0xff,
1569 (i->color >> 8) & 0xff, 255 - (i->color & 0xff) };
1571 write_quad(&p->eosd_va[p->eosd_render_count * VERTICES_PER_QUAD],
1572 i->dst_x, i->dst_y,
1573 i->dst_x + i->w, i->dst_y + i->h,
1574 spos[n].x, spos[n].y,
1575 spos[n].x + i->w, spos[n].y + i->h,
1576 p->eosd_texture_width, p->eosd_texture_height,
1577 color, false);
1578 p->eosd_render_count++;
1582 static void draw_eosd(struct gl_priv *p, mp_eosd_images_t *imgs)
1584 GL *gl = p->gl;
1586 gen_eosd(p, imgs);
1588 if (p->eosd_render_count == 0)
1589 return;
1591 gl->Enable(GL_BLEND);
1592 gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1593 gl->BindTexture(GL_TEXTURE_2D, p->eosd_texture);
1594 gl->UseProgram(p->eosd_program);
1595 draw_triangles(p, p->eosd_va, p->eosd_render_count * VERTICES_PER_QUAD);
1596 gl->UseProgram(0);
1597 gl->BindTexture(GL_TEXTURE_2D, 0);
1598 gl->Disable(GL_BLEND);
1601 static void setup_vertex_array(GL *gl)
1603 size_t stride = sizeof(struct vertex);
1605 gl->EnableVertexAttribArray(VERTEX_ATTRIB_POSITION);
1606 gl->VertexAttribPointer(VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE,
1607 stride, (void*)offsetof(struct vertex, position));
1609 gl->EnableVertexAttribArray(VERTEX_ATTRIB_COLOR);
1610 gl->VertexAttribPointer(VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE,
1611 stride, (void*)offsetof(struct vertex, color));
1613 gl->EnableVertexAttribArray(VERTEX_ATTRIB_TEXCOORD);
1614 gl->VertexAttribPointer(VERTEX_ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE,
1615 stride, (void*)offsetof(struct vertex, texcoord));
1618 static int init_gl(struct gl_priv *p)
1620 GL *gl = p->gl;
1622 debug_check_gl(p, "before init_gl");
1624 const char *vendor = gl->GetString(GL_VENDOR);
1625 const char *version = gl->GetString(GL_VERSION);
1626 const char *renderer = gl->GetString(GL_RENDERER);
1627 const char *glsl = gl->GetString(GL_SHADING_LANGUAGE_VERSION);
1628 mp_msg(MSGT_VO, MSGL_V, "[gl] GL_RENDERER='%s', GL_VENDOR='%s', "
1629 "GL_VERSION='%s', GL_SHADING_LANGUAGE_VERSION='%s'"
1630 "\n", renderer, vendor, version, glsl);
1631 mp_msg(MSGT_VO, MSGL_V, "[gl] Display depth: R=%d, G=%d, B=%d\n",
1632 p->glctx->depth_r, p->glctx->depth_g, p->glctx->depth_b);
1634 GLint major, minor;
1635 gl->GetIntegerv(GL_MAJOR_VERSION, &major);
1636 gl->GetIntegerv(GL_MINOR_VERSION, &minor);
1638 p->shader_version = "130";
1640 // Hack for OSX: it only creates 3.2 contexts.
1641 if (MPGL_VER(major, minor) >= MPGL_VER(3, 2))
1642 p->shader_version = "150";
1644 gl->Disable(GL_DITHER);
1645 gl->Disable(GL_BLEND);
1646 gl->Disable(GL_DEPTH_TEST);
1647 gl->DepthMask(GL_FALSE);
1648 gl->Disable(GL_CULL_FACE);
1649 gl->DrawBuffer(GL_BACK);
1651 gl->GenBuffers(1, &p->vertex_buffer);
1652 gl->GenVertexArrays(1, &p->vao);
1654 gl->BindBuffer(GL_ARRAY_BUFFER, p->vertex_buffer);
1655 gl->BindVertexArray(p->vao);
1656 setup_vertex_array(gl);
1657 gl->BindBuffer(GL_ARRAY_BUFFER, 0);
1658 gl->BindVertexArray(0);
1660 GLint max_texture_size;
1661 gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
1662 p->eosd->w_max = p->eosd->h_max = max_texture_size;
1664 gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1665 gl->Clear(GL_COLOR_BUFFER_BIT);
1666 if (gl->SwapInterval && p->swap_interval >= 0)
1667 gl->SwapInterval(p->swap_interval);
1669 debug_check_gl(p, "after init_gl");
1671 return 1;
1674 static void uninit_gl(struct gl_priv *p)
1676 GL *gl = p->gl;
1678 // NOTE: GL functions might not be loaded yet
1679 if (!(p->glctx && p->gl->DeleteTextures))
1680 return;
1682 uninit_video(p);
1684 gl->DeleteVertexArrays(1, &p->vao);
1685 p->vao = 0;
1686 gl->DeleteBuffers(1, &p->vertex_buffer);
1687 p->vertex_buffer = 0;
1689 clear_osd(p);
1690 gl->DeleteTextures(1, &p->eosd_texture);
1691 p->eosd_texture = 0;
1692 gl->DeleteBuffers(1, &p->eosd_buffer);
1693 p->eosd_buffer = 0;
1694 p->bitmap_id = p->bitmap_pos_id = 0;
1695 p->eosd->w = p->eosd->h = 0;
1697 gl->DeleteTextures(1, &p->lut_3d_texture);
1698 p->lut_3d_texture = 0;
1701 static bool init_format(int fmt, struct gl_priv *init)
1703 bool supported = false;
1704 struct gl_priv dummy;
1705 if (!init)
1706 init = &dummy;
1708 mp_image_t dummy_img = {0};
1709 mp_image_setfmt(&dummy_img, fmt);
1711 init->image_format = fmt;
1712 init->component_bits = -1;
1714 // RGB/packed formats
1715 for (const struct fmt_entry *e = mp_to_gl_formats; e->mp_format; e++) {
1716 if (e->mp_format == fmt) {
1717 supported = true;
1718 init->plane_bits = dummy_img.bpp;
1719 init->gl_format = e->format;
1720 init->gl_internal_format = e->internal_format;
1721 init->component_bits = e->component_bits;
1722 init->gl_type = e->type;
1723 break;
1727 // YUV/planar formats
1728 if (!supported && mp_get_chroma_shift(fmt, NULL, NULL, &init->plane_bits)) {
1729 init->gl_format = GL_RED;
1730 init->component_bits = init->plane_bits;
1731 if (init->plane_bits == 8) {
1732 supported = true;
1733 init->gl_internal_format = GL_RED;
1734 init->gl_type = GL_UNSIGNED_BYTE;
1735 } else if (IMGFMT_IS_YUVP16_NE(fmt)) {
1736 supported = true;
1737 init->gl_internal_format = GL_R16;
1738 init->gl_type = GL_UNSIGNED_SHORT;
1742 // RGB/planar
1743 if (!supported && fmt == IMGFMT_GBRP) {
1744 supported = true;
1745 init->plane_bits = init->component_bits = 8;
1746 init->gl_format = GL_RED;
1747 init->gl_internal_format = GL_RED;
1748 init->gl_type = GL_UNSIGNED_BYTE;
1751 if (!supported)
1752 return false;
1754 init->plane_bytes = (init->plane_bits + 7) / 8;
1755 init->is_yuv = dummy_img.flags & MP_IMGFLAG_YUV;
1756 init->is_linear_rgb = false;
1758 // NOTE: we throw away the additional alpha plane, if one exists.
1759 init->plane_count = dummy_img.num_planes > 2 ? 3 : 1;
1760 assert(dummy_img.num_planes >= init->plane_count);
1761 assert(dummy_img.num_planes <= init->plane_count + 1);
1763 for (int n = 0; n < init->plane_count; n++) {
1764 struct texplane *plane = &init->planes[n];
1766 plane->shift_x = n > 0 ? dummy_img.chroma_x_shift : 0;
1767 plane->shift_y = n > 0 ? dummy_img.chroma_y_shift : 0;
1770 return true;
1773 static int query_format(uint32_t format)
1775 int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP |
1776 VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE |
1777 VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED;
1778 if (!init_format(format, NULL))
1779 return 0;
1780 return caps;
1783 static bool config_window(struct gl_priv *p, uint32_t d_width,
1784 uint32_t d_height, uint32_t flags)
1786 if (p->stereo_mode == GL_3D_QUADBUFFER)
1787 flags |= VOFLAG_STEREO;
1789 int mpgl_version = MPGL_VER(3, 0);
1790 int mpgl_flags = p->use_gl_debug ? MPGLFLAG_DEBUG : 0;
1792 if (p->use_gl2)
1793 mpgl_version = MPGL_VER(2, 1);
1795 if (create_mpglcontext(p->glctx, mpgl_flags, mpgl_version, d_width,
1796 d_height, flags) == SET_WINDOW_FAILED)
1797 return false;
1799 if (!p->vertex_buffer)
1800 init_gl(p);
1802 return true;
1805 static int config(struct vo *vo, uint32_t width, uint32_t height,
1806 uint32_t d_width, uint32_t d_height, uint32_t flags,
1807 uint32_t format)
1809 struct gl_priv *p = vo->priv;
1811 if (!config_window(p, d_width, d_height, flags))
1812 return -1;
1814 p->vo_flipped = !!(flags & VOFLAG_FLIPPING);
1816 if (p->image_format != format || p->image_width != width
1817 || p->image_height != height)
1819 uninit_video(p);
1820 p->image_height = height;
1821 p->image_width = width;
1822 init_format(format, p);
1823 init_video(p);
1826 resize(p);
1828 return 0;
1831 static void check_events(struct vo *vo)
1833 struct gl_priv *p = vo->priv;
1835 int e = p->glctx->check_events(vo);
1836 if (e & VO_EVENT_REINIT) {
1837 uninit_gl(p);
1838 init_gl(p);
1839 init_video(p);
1840 resize(p);
1842 if (e & VO_EVENT_RESIZE)
1843 resize(p);
1844 if (e & VO_EVENT_EXPOSE)
1845 vo->want_redraw = true;
1848 static int control(struct vo *vo, uint32_t request, void *data)
1850 struct gl_priv *p = vo->priv;
1852 switch (request) {
1853 case VOCTRL_QUERY_FORMAT:
1854 return query_format(*(uint32_t *)data);
1855 case VOCTRL_GET_IMAGE:
1856 return get_image(vo, data);
1857 case VOCTRL_DRAW_IMAGE:
1858 return draw_image(p, data);
1859 case VOCTRL_DRAW_EOSD:
1860 if (!data)
1861 return VO_FALSE;
1862 draw_eosd(p, data);
1863 return VO_TRUE;
1864 case VOCTRL_GET_EOSD_RES: {
1865 mp_eosd_res_t *r = data;
1866 r->w = vo->dwidth;
1867 r->h = vo->dheight;
1868 r->ml = r->mr = p->border_x;
1869 r->mt = r->mb = p->border_y;
1870 return VO_TRUE;
1872 case VOCTRL_ONTOP:
1873 if (!p->glctx->ontop)
1874 break;
1875 p->glctx->ontop(vo);
1876 return VO_TRUE;
1877 case VOCTRL_PAUSE:
1878 if (!p->glctx->pause)
1879 break;
1880 p->glctx->pause(vo);
1881 return VO_TRUE;
1882 case VOCTRL_RESUME:
1883 if (!p->glctx->resume)
1884 break;
1885 p->glctx->resume(vo);
1886 return VO_TRUE;
1887 case VOCTRL_FULLSCREEN:
1888 p->glctx->fullscreen(vo);
1889 resize(p);
1890 return VO_TRUE;
1891 case VOCTRL_BORDER:
1892 if (!p->glctx->border)
1893 break;
1894 p->glctx->border(vo);
1895 resize(p);
1896 return VO_TRUE;
1897 case VOCTRL_GET_PANSCAN:
1898 return VO_TRUE;
1899 case VOCTRL_SET_PANSCAN:
1900 resize(p);
1901 return VO_TRUE;
1902 case VOCTRL_GET_EQUALIZER: {
1903 struct voctrl_get_equalizer_args *args = data;
1904 return mp_csp_equalizer_get(&p->video_eq, args->name, args->valueptr)
1905 >= 0 ? VO_TRUE : VO_NOTIMPL;
1907 case VOCTRL_SET_EQUALIZER: {
1908 struct voctrl_set_equalizer_args *args = data;
1909 if (mp_csp_equalizer_set(&p->video_eq, args->name, args->value) < 0)
1910 return VO_NOTIMPL;
1911 if (!p->use_gamma && p->video_eq.values[MP_CSP_EQ_GAMMA] != 0) {
1912 mp_msg(MSGT_VO, MSGL_V, "[gl] Auto-enabling gamma.\n");
1913 p->use_gamma = true;
1914 compile_shaders(p);
1916 update_all_uniforms(p);
1917 vo->want_redraw = true;
1918 return VO_TRUE;
1920 case VOCTRL_SET_YUV_COLORSPACE: {
1921 if (p->is_yuv) {
1922 p->colorspace = *(struct mp_csp_details *)data;
1923 update_all_uniforms(p);
1924 vo->want_redraw = true;
1926 return VO_TRUE;
1928 case VOCTRL_GET_YUV_COLORSPACE:
1929 *(struct mp_csp_details *)data = p->colorspace;
1930 return VO_TRUE;
1931 case VOCTRL_UPDATE_SCREENINFO:
1932 if (!p->glctx->update_xinerama_info)
1933 break;
1934 p->glctx->update_xinerama_info(vo);
1935 return VO_TRUE;
1936 case VOCTRL_SCREENSHOT: {
1937 struct voctrl_screenshot_args *args = data;
1938 if (args->full_window)
1939 args->out_image = get_window_screenshot(p);
1940 else
1941 args->out_image = get_screenshot(p);
1942 return true;
1944 case VOCTRL_REDRAW_FRAME:
1945 do_render(p);
1946 return true;
1948 return VO_NOTIMPL;
1951 static void uninit(struct vo *vo)
1953 struct gl_priv *p = vo->priv;
1955 uninit_gl(p);
1956 uninit_mpglcontext(p->glctx);
1957 p->glctx = NULL;
1958 p->gl = NULL;
1961 #ifdef CONFIG_LCMS2
1963 static void lcms2_error_handler(cmsContext ctx, cmsUInt32Number code,
1964 const char *msg)
1966 mp_msg(MSGT_VO, MSGL_ERR, "[gl] lcms2: %s\n", msg);
1969 static struct bstr load_file(struct gl_priv *p, void *talloc_ctx,
1970 const char *filename)
1972 struct bstr res = {0};
1973 stream_t *s = open_stream(filename, p->vo->opts, NULL);
1974 if (s) {
1975 res = stream_read_complete(s, talloc_ctx, 1000000000, 0);
1976 free_stream(s);
1978 return res;
1981 #define LUT3D_CACHE_HEADER "mplayer2 3dlut cache 1.0\n"
1983 static bool load_icc(struct gl_priv *p, const char *icc_file,
1984 const char *icc_cache, int icc_intent,
1985 int s_r, int s_g, int s_b)
1987 void *tmp = talloc_new(p);
1988 uint16_t *output = talloc_array(tmp, uint16_t, s_r * s_g * s_b * 3);
1990 if (icc_intent == -1)
1991 icc_intent = INTENT_ABSOLUTE_COLORIMETRIC;
1993 mp_msg(MSGT_VO, MSGL_INFO, "[gl] Opening ICC profile '%s'\n", icc_file);
1994 struct bstr iccdata = load_file(p, tmp, icc_file);
1995 if (!iccdata.len)
1996 goto error_exit;
1998 char *cache_info = talloc_asprintf(tmp, "intent=%d, size=%dx%dx%d\n",
1999 icc_intent, s_r, s_g, s_b);
2001 // check cache
2002 if (icc_cache) {
2003 mp_msg(MSGT_VO, MSGL_INFO, "[gl] Opening 3D LUT cache in file '%s'.\n",
2004 icc_cache);
2005 struct bstr cachedata = load_file(p, tmp, icc_cache);
2006 if (bstr_eatstart(&cachedata, bstr(LUT3D_CACHE_HEADER))
2007 && bstr_eatstart(&cachedata, bstr(cache_info))
2008 && bstr_eatstart(&cachedata, iccdata)
2009 && cachedata.len == talloc_get_size(output))
2011 memcpy(output, cachedata.start, cachedata.len);
2012 goto done;
2013 } else {
2014 mp_msg(MSGT_VO, MSGL_WARN, "[gl] 3D LUT cache invalid!\n");
2018 cmsSetLogErrorHandler(lcms2_error_handler);
2020 cmsHPROFILE profile = cmsOpenProfileFromMem(iccdata.start, iccdata.len);
2021 if (!profile)
2022 goto error_exit;
2024 cmsCIExyY d65;
2025 cmsWhitePointFromTemp(&d65, 6504);
2026 static const cmsCIExyYTRIPLE bt709prim = {
2027 .Red = {0.64, 0.33, 1.0},
2028 .Green = {0.30, 0.60, 1.0},
2029 .Blue = {0.15, 0.06, 1.0},
2031 cmsToneCurve *tonecurve = cmsBuildGamma(NULL, 2.2);
2032 cmsHPROFILE vid_profile = cmsCreateRGBProfile(&d65, &bt709prim,
2033 (cmsToneCurve*[3]){tonecurve, tonecurve, tonecurve});
2034 cmsFreeToneCurve(tonecurve);
2035 cmsHTRANSFORM trafo = cmsCreateTransform(vid_profile, TYPE_RGB_16,
2036 profile, TYPE_RGB_16,
2037 icc_intent,
2038 cmsFLAGS_HIGHRESPRECALC);
2039 cmsCloseProfile(profile);
2040 cmsCloseProfile(vid_profile);
2042 if (!trafo)
2043 goto error_exit;
2045 // transform a (s_r)x(s_g)x(s_b) cube, with 3 components per channel
2046 uint16_t *input = talloc_array(tmp, uint16_t, s_r * 3);
2047 for (int b = 0; b < s_b; b++) {
2048 for (int g = 0; g < s_g; g++) {
2049 for (int r = 0; r < s_r; r++) {
2050 input[r * 3 + 0] = r * 65535 / (s_r - 1);
2051 input[r * 3 + 1] = g * 65535 / (s_g - 1);
2052 input[r * 3 + 2] = b * 65535 / (s_b - 1);
2054 size_t base = (b * s_r * s_g + g * s_r) * 3;
2055 cmsDoTransform(trafo, input, output + base, s_r);
2059 cmsDeleteTransform(trafo);
2061 if (icc_cache) {
2062 FILE *out = fopen(icc_cache, "wb");
2063 if (out) {
2064 fprintf(out, "%s%s", LUT3D_CACHE_HEADER, cache_info);
2065 fwrite(iccdata.start, iccdata.len, 1, out);
2066 fwrite(output, talloc_get_size(output), 1, out);
2067 fclose(out);
2071 done:
2073 p->lut_3d_data = talloc_steal(p, output);
2074 p->lut_3d_w = s_r, p->lut_3d_h = s_g, p->lut_3d_d = s_b;
2075 p->use_lut_3d = true;
2077 talloc_free(tmp);
2078 return true;
2080 error_exit:
2081 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error loading ICC profile.\n");
2082 talloc_free(tmp);
2083 return false;
2086 #else /* CONFIG_LCMS2 */
2088 static bool load_icc(struct gl_priv *p, ...)
2090 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] LCMS2 support not compiled.\n");
2091 return false;
2094 #endif /* CONFIG_LCMS2 */
2096 static bool parse_3dlut_size(const char *s, int *p1, int *p2, int *p3)
2098 if (sscanf(s, "%dx%dx%d", p1, p2, p3) != 3)
2099 return false;
2100 for (int n = 0; n < 3; n++) {
2101 int s = ((int[]) { *p1, *p2, *p3 })[n];
2102 if (s < 2 || s > 256 || ((s - 1) & s))
2103 return false;
2105 return true;
2108 static int lut3d_size_valid(void *arg)
2110 char *s = *(char **)arg;
2111 int p1, p2, p3;
2112 return parse_3dlut_size(s, &p1, &p2, &p3);
2115 static int backend_valid(void *arg)
2117 return mpgl_find_backend(*(const char **)arg) >= 0;
2120 struct fbo_format {
2121 const char *name;
2122 GLint format;
2125 const struct fbo_format fbo_formats[] = {
2126 {"rgb", GL_RGB},
2127 {"rgba", GL_RGBA},
2128 {"rgb8", GL_RGB8},
2129 {"rgb16", GL_RGB16},
2130 {"rgb16f", GL_RGB16F},
2131 {"rgb32f", GL_RGB32F},
2135 static GLint find_fbo_format(const char *name)
2137 for (const struct fbo_format *fmt = fbo_formats; fmt->name; fmt++) {
2138 if (strcmp(fmt->name, name) == 0)
2139 return fmt->format;
2141 return -1;
2144 static int fbo_format_valid(void *arg)
2146 return find_fbo_format(*(const char **)arg) >= 0;
2149 static bool can_use_filter_kernel(const struct filter_kernel *kernel)
2151 if (!kernel)
2152 return false;
2153 struct filter_kernel k = *kernel;
2154 return mp_init_filter(&k, filter_sizes, 1);
2157 static const char* handle_scaler_opt(const char *name)
2159 const struct filter_kernel *kernel = mp_find_filter_kernel(name);
2160 if (can_use_filter_kernel(kernel))
2161 return kernel->name;
2163 for (const char **filter = fixed_scale_filters; *filter; filter++) {
2164 if (strcmp(*filter, name) == 0)
2165 return *filter;
2168 return NULL;
2171 static int scaler_valid(void *arg)
2173 return handle_scaler_opt(*(const char **)arg) != NULL;
2176 #if 0
2177 static void print_scalers(void)
2179 mp_msg(MSGT_VO, MSGL_INFO, "Available scalers:\n");
2180 for (const char **e = fixed_scale_filters; *e; e++) {
2181 mp_msg(MSGT_VO, MSGL_INFO, " %s\n", *e);
2183 for (const struct filter_kernel *e = mp_filter_kernels; e->name; e++) {
2184 if (can_use_filter_kernel(e))
2185 mp_msg(MSGT_VO, MSGL_INFO, " %s\n", e->name);
2188 #endif
2190 static int preinit(struct vo *vo, const char *arg)
2192 struct gl_priv *p = talloc_zero(vo, struct gl_priv);
2193 vo->priv = p;
2195 *p = (struct gl_priv) {
2196 .vo = vo,
2197 .colorspace = MP_CSP_DETAILS_DEFAULTS,
2198 .use_npot = 1,
2199 .use_pbo = 0,
2200 .swap_interval = 1,
2201 .fbo_format = GL_RGB16,
2202 .use_scale_sep = 1,
2203 .use_fancy_downscaling = 1,
2204 .scalers = {
2205 { .index = 0, .name = "lanczos2" },
2206 { .index = 1, .name = "bilinear" },
2208 .scaler_params = {NAN, NAN},
2212 char *scalers[2] = {0};
2213 char *backend_arg = NULL;
2214 char *fbo_format = NULL;
2215 char *icc_profile = NULL;
2216 char *icc_cache = NULL;
2217 int icc_intent = -1;
2218 char *icc_size_str = NULL;
2220 const opt_t subopts[] = {
2221 {"gamma", OPT_ARG_BOOL, &p->use_gamma},
2222 {"srgb", OPT_ARG_BOOL, &p->use_srgb},
2223 {"npot", OPT_ARG_BOOL, &p->use_npot},
2224 {"pbo", OPT_ARG_BOOL, &p->use_pbo},
2225 {"glfinish", OPT_ARG_BOOL, &p->use_glFinish},
2226 {"swapinterval", OPT_ARG_INT, &p->swap_interval},
2227 {"stereo", OPT_ARG_INT, &p->stereo_mode},
2228 {"lscale", OPT_ARG_MSTRZ, &scalers[0], scaler_valid},
2229 {"cscale", OPT_ARG_MSTRZ, &scalers[1], scaler_valid},
2230 {"lparam1", OPT_ARG_FLOAT, &p->scaler_params[0]},
2231 {"lparam2", OPT_ARG_FLOAT, &p->scaler_params[1]},
2232 {"fancy-downscaling", OPT_ARG_BOOL, &p->use_fancy_downscaling},
2233 {"debug", OPT_ARG_BOOL, &p->use_gl_debug},
2234 {"force-gl2", OPT_ARG_BOOL, &p->use_gl2},
2235 {"indirect", OPT_ARG_BOOL, &p->use_indirect},
2236 {"scale-sep", OPT_ARG_BOOL, &p->use_scale_sep},
2237 {"fbo-format", OPT_ARG_MSTRZ, &fbo_format, fbo_format_valid},
2238 {"backend", OPT_ARG_MSTRZ, &backend_arg, backend_valid},
2239 {"icc-profile", OPT_ARG_MSTRZ, &icc_profile},
2240 {"icc-cache", OPT_ARG_MSTRZ, &icc_cache},
2241 {"icc-intent", OPT_ARG_INT, &icc_intent},
2242 {"3dlut-size", OPT_ARG_MSTRZ, &icc_size_str,
2243 lut3d_size_valid},
2244 {"dither-depth", OPT_ARG_INT, &p->dither_depth},
2245 {NULL}
2248 if (subopt_parse(arg, subopts) != 0) {
2249 mp_msg(MSGT_VO, MSGL_FATAL, "%s", help_text);
2250 goto err_out;
2253 int backend = backend_arg ? mpgl_find_backend(backend_arg) : GLTYPE_AUTO;
2254 free(backend_arg);
2256 if (fbo_format)
2257 p->fbo_format = find_fbo_format(fbo_format);
2258 free(fbo_format);
2260 for (int n = 0; n < 2; n++) {
2261 if (scalers[n])
2262 p->scalers[n].name = handle_scaler_opt(scalers[n]);
2263 free(scalers[n]);
2266 int s_r = 128, s_g = 256, s_b = 64;
2267 if (icc_size_str)
2268 parse_3dlut_size(icc_size_str, &s_r, &s_g, &s_b);
2269 free(icc_size_str);
2271 bool success = true;
2272 if (icc_profile) {
2273 success = load_icc(p, icc_profile, icc_cache, icc_intent,
2274 s_r, s_g, s_b);
2276 free(icc_profile);
2277 free(icc_cache);
2279 if (!success)
2280 goto err_out;
2282 p->eosd = talloc_zero(vo, struct bitmap_packer);
2284 p->glctx = init_mpglcontext(backend, vo);
2285 if (!p->glctx)
2286 goto err_out;
2287 p->gl = p->glctx->gl;
2289 if (true) {
2290 if (!config_window(p, 320, 200, VOFLAG_HIDDEN))
2291 goto err_out;
2292 // We created a window to test whether the GL context could be
2293 // created and so on. Destroy that window to make sure all state
2294 // associated with it is lost.
2295 uninit(vo);
2296 p->glctx = init_mpglcontext(backend, vo);
2297 if (!p->glctx)
2298 goto err_out;
2299 p->gl = p->glctx->gl;
2302 return 0;
2304 err_out:
2305 uninit(vo);
2306 return -1;
2309 const struct vo_driver video_out_gl3 = {
2310 .is_new = true,
2311 .info = &(const vo_info_t) {
2312 "OpenGL 3.x",
2313 "gl3",
2314 "Based on vo_gl.c by Reimar Doeffinger",
2317 .preinit = preinit,
2318 .config = config,
2319 .control = control,
2320 .draw_slice = draw_slice,
2321 .draw_osd = draw_osd,
2322 .flip_page = flip_page,
2323 .check_events = check_events,
2324 .uninit = uninit,
2327 static const char help_text[] =
2328 "\n--vo=gl3 command line help:\n"
2329 "Example: mplayer --vo=gl3:scale-sep:lscale=lanczos2\n"
2330 "\nOptions:\n"
2331 " lscale=<filter>\n"
2332 " Set the scaling filter. Possible choices:\n"
2333 " bilinear: bilinear texture filtering (fastest).\n"
2334 " bicubic_fast: bicubic filter (without lookup texture).\n"
2335 " sharpen3: unsharp masking (sharpening) with radius=3.\n"
2336 " sharpen5: unsharp masking (sharpening) with radius=5.\n"
2337 " lanczos2: Lanczos with radius=2 (default, recommended).\n"
2338 " lanczos3: Lanczos with radius=3 (not recommended).\n"
2339 " mitchell: Mitchell-Netravali.\n"
2340 " Default: lanczos2\n"
2341 " lparam1=<value> / lparam2=<value>\n"
2342 " Set parameters for configurable filters. Affects chroma scaler\n"
2343 " as well.\n"
2344 " Filters which use this:\n"
2345 " mitchell: b and c params (defaults: b=1/3 c=1/3)\n"
2346 " kaiser: (defaults: 6.33 6.33)\n"
2347 " sharpen3: lparam1 sets sharpening strength (default: 0.5)\n"
2348 " sharpen5: as with sharpen3\n"
2349 " stereo=<n>\n"
2350 " 0: normal display\n"
2351 " 1: side-by-side to red-cyan stereo\n"
2352 " 2: side-by-side to green-magenta stereo\n"
2353 " 3: side-by-side to quadbuffer stereo\n"
2354 " srgb\n"
2355 " Enable gamma-correct scaling by working in linear light. This\n"
2356 " makes use of sRGB textures and framebuffers.\n"
2357 " This option forces the options 'indirect' and 'gamma'.\n"
2358 " NOTE: for BT.709 colorspaces, a gamma of 2.35 is assumed. For\n"
2359 " other YUV colorspaces, 2.2 is assumed. RGB input is always\n"
2360 " assumed to be in sRGB.\n"
2361 " pbo\n"
2362 " Enable use of PBOs. This is faster, but can sometimes lead to\n"
2363 " sporadic and temporary image corruption.\n"
2364 " dither-depth=<n>\n"
2365 " Positive non-zero values select the target bit depth.\n"
2366 " -1: Disable any dithering done by mplayer.\n"
2367 " 0: Automatic selection. If output bit depth can't be detected,\n"
2368 " 8 bits per component are assumed.\n"
2369 " 8: Dither to 8 bit output.\n"
2370 " Default: 0.\n"
2371 " Note that dithering will always be disabled if the bit depth\n"
2372 " of the video is lower or qual to the detected dither-depth.\n"
2373 " If color management is enabled, input depth is assumed to be\n"
2374 " 16 bits, because the 3D LUT output is 16 bit wide.\n"
2375 " debug\n"
2376 " Check for OpenGL errors, i.e. call glGetError(). Also request a\n"
2377 " debug OpenGL context.\n"
2378 "Less useful options:\n"
2379 " swapinterval=<n>\n"
2380 " Interval in displayed frames between to buffer swaps.\n"
2381 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
2382 " no-scale-sep\n"
2383 " When using a separable scale filter for luma, usually two filter\n"
2384 " passes are done. This is often faster. However, it forces\n"
2385 " conversion to RGB in an extra pass, so it can actually be slower\n"
2386 " if used with fast filters on small screen resolutions. Using\n"
2387 " this options will make rendering a single operation.\n"
2388 " Note that chroma scalers are always done as 1-pass filters.\n"
2389 " cscale=<n>\n"
2390 " As lscale but for chroma (2x slower with little visible effect).\n"
2391 " Note that with some scaling filters, upscaling is always done in\n"
2392 " RGB. If chroma is not subsampled, this option is ignored, and the\n"
2393 " luma scaler is used instead. Setting this option is often useless.\n"
2394 " no-fancy-downscaling\n"
2395 " When using convolution based filters, don't extend the filter\n"
2396 " size when downscaling. Trades downscaling performance for\n"
2397 " reduced quality.\n"
2398 " no-npot\n"
2399 " Force use of power-of-2 texture sizes. For debugging only.\n"
2400 " Borders will look discolored due to filtering.\n"
2401 " glfinish\n"
2402 " Call glFinish() before swapping buffers\n"
2403 " backend=<sys>\n"
2404 " auto: auto-select (default)\n"
2405 " cocoa: Cocoa/OSX\n"
2406 " win: Win32/WGL\n"
2407 " x11: X11/GLX\n"
2408 " indirect\n"
2409 " Do YUV conversion and scaling as separate passes. This will\n"
2410 " first render the video into a video-sized RGB texture, and\n"
2411 " draw the result on screen. The luma scaler is used to scale\n"
2412 " the RGB image when rendering to screen. The chroma scaler\n"
2413 " is used only on YUV conversion, and only if the video uses\n"
2414 " chroma-subsampling.\n"
2415 " This mechanism is disabled on RGB input.\n"
2416 " fbo-format=<fmt>\n"
2417 " Selects the internal format of any FBO textures used.\n"
2418 " fmt can be one of: rgb, rgba, rgb8, rgb16, rgb16f, rgb32f\n"
2419 " Default: rgb16.\n"
2420 " gamma\n"
2421 " Always enable gamma control. (Disables delayed enabling.)\n"
2422 " force-gl2\n"
2423 " Create a legacy GL context. This will randomly malfunction\n"
2424 " if the proper extensions are not supported.\n"
2425 "Color management:\n"
2426 " icc-profile=<file>\n"
2427 " Load an ICC profile and use it to transform linear RGB to\n"
2428 " screen output. Needs LittleCMS2 support compiled in.\n"
2429 " icc-cache=<file>\n"
2430 " Store and load the 3D LUT created from the ICC profile in\n"
2431 " this file. This can be used to speed up loading, since\n"
2432 " LittleCMS2 can take a while to create the 3D LUT.\n"
2433 " Note that this file will be at most about 100 MB big.\n"
2434 " icc-intent=<value>\n"
2435 " 0: perceptual\n"
2436 " 1: relative colorimetric\n"
2437 " 2: saturation\n"
2438 " 3: absolute colorimetric (default)\n"
2439 " 3dlut-size=<r>x<g>x<b>\n"
2440 " Size of the 3D LUT generated from the ICC profile in each\n"
2441 " dimension. Default is 128x256x64.\n"
2442 " Sizes must be a power of two, and 256 at most.\n"
2443 "\n";