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.
32 #include <libavutil/common.h>
36 #include "stream/stream.h"
42 #include "subopt-helper.h"
43 #include "video_out.h"
44 #include "libmpcodecs/vfcap.h"
45 #include "libmpcodecs/mp_image.h"
49 #include "bitmap_packer.h"
51 #include "gl_common.h"
52 #include "filter_kernels.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
[] = {
84 struct lut_tex_format
{
86 GLint internal_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
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};
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
121 int shift_x
, shift_y
;
132 struct filter_kernel
*kernel
;
134 const char *lut_name
;
136 // kernel points here
137 struct filter_kernel kernel_storage
;
143 int tex_w
, tex_h
; // size of .texture
144 int vp_w
, vp_h
; // viewport of fbo / used part of the texture
151 const char *shader_version
;
157 int use_fancy_downscaling
;
170 GLuint vertex_buffer
;
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
];
181 int eosd_texture_width
, eosd_texture_height
;
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
;
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
;
206 // per pixel (full pixel when packed, each component when planar)
211 GLint gl_internal_format
;
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
;
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
240 GLint internal_format
;
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
},
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
)
277 glCheckError(p
->gl
, msg
);
280 static void tex_size(struct gl_priv
*p
, int w
, int h
, int *texw
, int *texh
)
295 static void draw_triangles(struct gl_priv
*p
, struct vertex
*vb
, int vert_count
)
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
,
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 };
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
} };
352 static void fbotex_init(struct gl_priv
*p
, struct fbotex
*fbo
, int w
, int h
)
357 assert(!fbo
->texture
);
359 tex_size(p
, w
, h
, &fbo
->tex_w
, &fbo
->tex_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 "
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
)
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
,
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
);
408 static void update_uniforms(struct gl_priv
*p
, GLuint program
)
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");
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");
434 float yuv2rgb
[3][4] = {{0}};
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
;
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"),
464 float sparam1
= p
->scaler_params
[0];
465 gl
->Uniform1f(gl
->GetUniformLocation(program
, "filter_param1"),
466 isnan(sparam1
) ? 0.5f
: sparam1
);
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
,
487 char *res
= talloc_strdup(talloc_ctx
, "");
490 struct bstr line
= bstr_getline(source
, &source
);
491 if (bstr_eatstart(&line
, bstr(SECTION_HEADER
))) {
492 copy
= bstrcmp0(bstr_strip(line
), section
) == 0;
494 res
= talloc_asprintf_append_buffer(res
, "%.*s", BSTR_P(line
));
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
,
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
);
515 gl
->GetShaderiv(shader
, GL_COMPILE_STATUS
, &status
);
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
);
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
);
549 gl
->GetProgramiv(program
, GL_LINK_STATUS
, &status
);
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",
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
);
584 static void shader_def(char **shader
, const char *name
,
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
)
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
);
603 int size
= scaler
->kernel
->size
;
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
);
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
)
628 static void compile_shaders(struct gl_priv
*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
,
646 char *header_eosd
= talloc_strdup(tmp
, header
);
647 shader_def_opt(&header_eosd
, "USE_3DLUT", p
->use_lut_3d
);
650 create_program(gl
, "eosd", header_eosd
, vertex_shader
, s_eosd
);
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);
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
)
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)
706 if (input_is_subsampled(p
)) {
707 shader_setup_scaler(&header_conv
, &p
->scalers
[1], -1);
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");
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
);
726 header_final
= t_concat(tmp
, header_final
, header_conv
);
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
);
737 create_program(gl
, "final", header_final
, vertex_shader
, s_video
);
739 debug_check_gl(p
, "shader compilation");
744 static void delete_program(GL
*gl
, GLuint
*prog
)
746 gl
->DeleteProgram(*prog
);
750 static void delete_shaders(struct gl_priv
*p
)
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)
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
)
782 assert(scaler
->name
);
784 scaler
->kernel
= NULL
;
786 const struct filter_kernel
*t_kernel
= mp_find_filter_kernel(scaler
->name
);
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
;
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
);
822 gl
->TexImage2D(GL_TEXTURE_2D
, 0, fmt
->internal_format
, fmt
->pixels
,
823 LOOKUP_TEXTURE_SIZE
, 0, fmt
->format
, GL_FLOAT
,
826 gl
->TexImage1D(GL_TEXTURE_1D
, 0, fmt
->internal_format
,
827 LOOKUP_TEXTURE_SIZE
, 0, fmt
->format
, GL_FLOAT
,
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
)
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
)
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
;
867 if (dst_depth
>= src_depth
|| p
->dither_depth
< 0 || src_depth
< 0)
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;
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");
906 init_scaler(p
, &p
->scalers
[0]);
907 init_scaler(p
, &p
->scalers
[1]);
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
)
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
)
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
)
957 if (p
->use_lut_3d
&& !p
->lut_3d_texture
)
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
;
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");
998 static void uninit_video(struct gl_priv
*p
)
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
)
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,
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
)
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
);
1054 static void do_render(struct gl_priv
*p
)
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
);
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
,
1095 draw_triangles(p
, vb
, VERTICES_PER_QUAD
);
1097 glEnable3DRight(gl
, p
->stereo_mode
);
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
,
1106 draw_triangles(p
, vb
, VERTICES_PER_QUAD
);
1108 glDisable3D(gl
, p
->stereo_mode
);
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
,
1117 draw_triangles(p
, vb
, VERTICES_PER_QUAD
);
1120 gl
->Disable(GL_FRAMEBUFFER_SRGB
);
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
)
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;
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
);
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]);
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
;
1201 if (p
->use_glFinish
)
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
,
1217 struct gl_priv
*p
= vo
->priv
;
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
);
1234 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
1236 struct gl_priv
*p
= vo
->priv
;
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
)
1247 if (mpi
->flags
& MP_IMGFLAG_READABLE
)
1249 if (mpi
->type
!= MP_IMGTYPE_STATIC
&& mpi
->type
!= MP_IMGTYPE_TEMP
&&
1250 (mpi
->type
!= MP_IMGTYPE_NUMBERED
|| mpi
->number
))
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
,
1268 mpi
->planes
[n
] = plane
->buffer_ptr
;
1269 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1271 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1275 static uint32_t draw_image(struct gl_priv
*p
, mp_image_t
*mpi
)
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
)
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
]);
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);
1328 static mp_image_t
*get_screenshot(struct gl_priv
*p
)
1332 mp_image_t
*image
= alloc_mpi(p
->texture_width
, p
->texture_height
,
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
;
1359 static mp_image_t
*get_window_screenshot(struct gl_priv
*p
)
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]);
1376 static void clear_osd(struct gl_priv
*p
)
1380 if (!p
->osd_textures_count
)
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
,
1390 struct gl_priv
*p
= ctx
;
1393 if (w
<= 0 || h
<= 0 || stride
< w
) {
1394 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
1398 if (p
->osd_textures_count
>= MAX_OSD_PARTS
) {
1399 mp_msg(MSGT_VO
, MSGL_ERR
, "Too many OSD parts, contact the developers!\n");
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
,
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,
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
;
1439 if (vo_osd_changed(0)) {
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
],
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
)
1471 if (imgs
->bitmap_pos_id
== p
->bitmap_pos_id
)
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
) {
1486 int res
= packer_pack_from_subbitmaps(p
->eosd
, imgs
, 0);
1488 mp_msg(MSGT_VO
, MSGL_ERR
,
1489 "[gl] subtitle bitmaps do not fit in maximum texture\n");
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)
1512 p
->eosd_va
= talloc_realloc_size(p
->eosd
, p
->eosd_va
,
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
);
1521 mp_msg(MSGT_VO
, MSGL_FATAL
, "[gl] Error: can't upload subtitles! "
1522 "Subtitles will look corrupted.\n");
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)
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
,
1539 p
->eosd
->used_width
, p
->eosd
->used_height
, 0);
1541 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1542 } else if (need_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)
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)
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
],
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
,
1573 p
->eosd_render_count
++;
1577 static void draw_eosd(struct gl_priv
*p
, mp_eosd_images_t
*imgs
)
1583 if (p
->eosd_render_count
== 0)
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
);
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
)
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
);
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");
1669 static void uninit_gl(struct gl_priv
*p
)
1673 // NOTE: GL functions might not be loaded yet
1674 if (!(p
->glctx
&& p
->gl
->DeleteTextures
))
1679 gl
->DeleteVertexArrays(1, &p
->vao
);
1681 gl
->DeleteBuffers(1, &p
->vertex_buffer
);
1682 p
->vertex_buffer
= 0;
1685 gl
->DeleteTextures(1, &p
->eosd_texture
);
1686 p
->eosd_texture
= 0;
1687 gl
->DeleteBuffers(1, &p
->eosd_buffer
);
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
;
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
) {
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
;
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) {
1728 init
->gl_internal_format
= GL_RED
;
1729 init
->gl_type
= GL_UNSIGNED_BYTE
;
1730 } else if (IMGFMT_IS_YUVP16_NE(fmt
)) {
1732 init
->gl_internal_format
= GL_R16
;
1733 init
->gl_type
= GL_UNSIGNED_SHORT
;
1738 if (!supported
&& fmt
== IMGFMT_GBRP
) {
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
;
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;
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
))
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;
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
)
1794 if (!p
->vertex_buffer
)
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
,
1804 struct gl_priv
*p
= vo
->priv
;
1806 if (!config_window(p
, d_width
, d_height
, flags
))
1809 p
->vo_flipped
= !!(flags
& VOFLAG_FLIPPING
);
1811 if (p
->image_format
!= format
|| p
->image_width
!= width
1812 || p
->image_height
!= height
)
1815 p
->image_height
= height
;
1816 p
->image_width
= width
;
1817 init_format(format
, p
);
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
) {
1837 if (e
& VO_EVENT_RESIZE
)
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
;
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
:
1859 case VOCTRL_GET_EOSD_RES
: {
1860 mp_eosd_res_t
*r
= data
;
1863 r
->ml
= r
->mr
= p
->border_x
;
1864 r
->mt
= r
->mb
= p
->border_y
;
1868 if (!p
->glctx
->ontop
)
1870 p
->glctx
->ontop(vo
);
1873 if (!p
->glctx
->pause
)
1875 p
->glctx
->pause(vo
);
1878 if (!p
->glctx
->resume
)
1880 p
->glctx
->resume(vo
);
1882 case VOCTRL_FULLSCREEN
:
1883 p
->glctx
->fullscreen(vo
);
1887 if (!p
->glctx
->border
)
1889 p
->glctx
->border(vo
);
1892 case VOCTRL_GET_PANSCAN
:
1894 case VOCTRL_SET_PANSCAN
:
1897 case VOCTRL_GET_EQUALIZER
: {
1898 struct voctrl_get_equalizer_args
*args
= data
;
1899 return mp_csp_equalizer_get(&p
->video_eq
, args
->name
, args
->valueptr
)
1900 >= 0 ? VO_TRUE
: VO_NOTIMPL
;
1902 case VOCTRL_SET_EQUALIZER
: {
1903 struct voctrl_set_equalizer_args
*args
= data
;
1904 if (mp_csp_equalizer_set(&p
->video_eq
, args
->name
, args
->value
) < 0)
1906 if (!p
->use_gamma
&& p
->video_eq
.values
[MP_CSP_EQ_GAMMA
] != 0) {
1907 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Auto-enabling gamma.\n");
1908 p
->use_gamma
= true;
1911 update_all_uniforms(p
);
1912 vo
->want_redraw
= true;
1915 case VOCTRL_SET_YUV_COLORSPACE
: {
1917 p
->colorspace
= *(struct mp_csp_details
*)data
;
1918 update_all_uniforms(p
);
1919 vo
->want_redraw
= true;
1923 case VOCTRL_GET_YUV_COLORSPACE
:
1924 *(struct mp_csp_details
*)data
= p
->colorspace
;
1926 case VOCTRL_UPDATE_SCREENINFO
:
1927 if (!p
->glctx
->update_xinerama_info
)
1929 p
->glctx
->update_xinerama_info(vo
);
1931 case VOCTRL_SCREENSHOT
: {
1932 struct voctrl_screenshot_args
*args
= data
;
1933 if (args
->full_window
)
1934 args
->out_image
= get_window_screenshot(p
);
1936 args
->out_image
= get_screenshot(p
);
1939 case VOCTRL_REDRAW_FRAME
:
1946 static void uninit(struct vo
*vo
)
1948 struct gl_priv
*p
= vo
->priv
;
1951 uninit_mpglcontext(p
->glctx
);
1958 static void lcms2_error_handler(cmsContext ctx
, cmsUInt32Number code
,
1961 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] lcms2: %s\n", msg
);
1964 static struct bstr
load_file(struct gl_priv
*p
, void *talloc_ctx
,
1965 const char *filename
)
1967 struct bstr res
= {0};
1968 stream_t
*s
= open_stream(filename
, p
->vo
->opts
, NULL
);
1970 res
= stream_read_complete(s
, talloc_ctx
, 1000000000, 0);
1976 #define LUT3D_CACHE_HEADER "mplayer2 3dlut cache 1.0\n"
1978 static bool load_icc(struct gl_priv
*p
, const char *icc_file
,
1979 const char *icc_cache
, int icc_intent
,
1980 int s_r
, int s_g
, int s_b
)
1982 void *tmp
= talloc_new(p
);
1983 uint16_t *output
= talloc_array(tmp
, uint16_t, s_r
* s_g
* s_b
* 3);
1985 if (icc_intent
== -1)
1986 icc_intent
= INTENT_ABSOLUTE_COLORIMETRIC
;
1988 mp_msg(MSGT_VO
, MSGL_INFO
, "[gl] Opening ICC profile '%s'\n", icc_file
);
1989 struct bstr iccdata
= load_file(p
, tmp
, icc_file
);
1993 char *cache_info
= talloc_asprintf(tmp
, "intent=%d, size=%dx%dx%d\n",
1994 icc_intent
, s_r
, s_g
, s_b
);
1998 mp_msg(MSGT_VO
, MSGL_INFO
, "[gl] Opening 3D LUT cache in file '%s'.\n",
2000 struct bstr cachedata
= load_file(p
, tmp
, icc_cache
);
2001 if (bstr_eatstart(&cachedata
, bstr(LUT3D_CACHE_HEADER
))
2002 && bstr_eatstart(&cachedata
, bstr(cache_info
))
2003 && bstr_eatstart(&cachedata
, iccdata
)
2004 && cachedata
.len
== talloc_get_size(output
))
2006 memcpy(output
, cachedata
.start
, cachedata
.len
);
2009 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] 3D LUT cache invalid!\n");
2013 cmsSetLogErrorHandler(lcms2_error_handler
);
2015 cmsHPROFILE profile
= cmsOpenProfileFromMem(iccdata
.start
, iccdata
.len
);
2020 cmsWhitePointFromTemp(&d65
, 6504);
2021 static const cmsCIExyYTRIPLE bt709prim
= {
2022 .Red
= {0.64, 0.33, 1.0},
2023 .Green
= {0.30, 0.60, 1.0},
2024 .Blue
= {0.15, 0.06, 1.0},
2026 cmsToneCurve
*tonecurve
= cmsBuildGamma(NULL
, 2.2);
2027 cmsHPROFILE vid_profile
= cmsCreateRGBProfile(&d65
, &bt709prim
,
2028 (cmsToneCurve
*[3]){tonecurve
, tonecurve
, tonecurve
});
2029 cmsFreeToneCurve(tonecurve
);
2030 cmsHTRANSFORM trafo
= cmsCreateTransform(vid_profile
, TYPE_RGB_16
,
2031 profile
, TYPE_RGB_16
,
2033 cmsFLAGS_HIGHRESPRECALC
);
2034 cmsCloseProfile(profile
);
2035 cmsCloseProfile(vid_profile
);
2040 // transform a (s_r)x(s_g)x(s_b) cube, with 3 components per channel
2041 uint16_t *input
= talloc_array(tmp
, uint16_t, s_r
* 3);
2042 for (int b
= 0; b
< s_b
; b
++) {
2043 for (int g
= 0; g
< s_g
; g
++) {
2044 for (int r
= 0; r
< s_r
; r
++) {
2045 input
[r
* 3 + 0] = r
* 65535 / (s_r
- 1);
2046 input
[r
* 3 + 1] = g
* 65535 / (s_g
- 1);
2047 input
[r
* 3 + 2] = b
* 65535 / (s_b
- 1);
2049 size_t base
= (b
* s_r
* s_g
+ g
* s_r
) * 3;
2050 cmsDoTransform(trafo
, input
, output
+ base
, s_r
);
2054 cmsDeleteTransform(trafo
);
2057 FILE *out
= fopen(icc_cache
, "wb");
2059 fprintf(out
, "%s%s", LUT3D_CACHE_HEADER
, cache_info
);
2060 fwrite(iccdata
.start
, iccdata
.len
, 1, out
);
2061 fwrite(output
, talloc_get_size(output
), 1, out
);
2068 p
->lut_3d_data
= talloc_steal(p
, output
);
2069 p
->lut_3d_w
= s_r
, p
->lut_3d_h
= s_g
, p
->lut_3d_d
= s_b
;
2070 p
->use_lut_3d
= true;
2076 mp_msg(MSGT_VO
, MSGL_FATAL
, "[gl] Error loading ICC profile.\n");
2081 #else /* CONFIG_LCMS2 */
2083 static bool load_icc(struct gl_priv
*p
, ...)
2085 mp_msg(MSGT_VO
, MSGL_FATAL
, "[gl] LCMS2 support not compiled.\n");
2089 #endif /* CONFIG_LCMS2 */
2091 static bool parse_3dlut_size(const char *s
, int *p1
, int *p2
, int *p3
)
2093 if (sscanf(s
, "%dx%dx%d", p1
, p2
, p3
) != 3)
2095 for (int n
= 0; n
< 3; n
++) {
2096 int s
= ((int[]) { *p1
, *p2
, *p3
})[n
];
2097 if (s
< 2 || s
> 256 || ((s
- 1) & s
))
2103 static int lut3d_size_valid(void *arg
)
2105 char *s
= *(char **)arg
;
2107 return parse_3dlut_size(s
, &p1
, &p2
, &p3
);
2110 static int backend_valid(void *arg
)
2112 return mpgl_find_backend(*(const char **)arg
) >= 0;
2120 const struct fbo_format fbo_formats
[] = {
2124 {"rgb16", GL_RGB16
},
2125 {"rgb16f", GL_RGB16F
},
2126 {"rgb32f", GL_RGB32F
},
2130 static GLint
find_fbo_format(const char *name
)
2132 for (const struct fbo_format
*fmt
= fbo_formats
; fmt
->name
; fmt
++) {
2133 if (strcmp(fmt
->name
, name
) == 0)
2139 static int fbo_format_valid(void *arg
)
2141 return find_fbo_format(*(const char **)arg
) >= 0;
2144 static bool can_use_filter_kernel(const struct filter_kernel
*kernel
)
2148 struct filter_kernel k
= *kernel
;
2149 return mp_init_filter(&k
, filter_sizes
, 1);
2152 static const char* handle_scaler_opt(const char *name
)
2154 const struct filter_kernel
*kernel
= mp_find_filter_kernel(name
);
2155 if (can_use_filter_kernel(kernel
))
2156 return kernel
->name
;
2158 for (const char **filter
= fixed_scale_filters
; *filter
; filter
++) {
2159 if (strcmp(*filter
, name
) == 0)
2166 static int scaler_valid(void *arg
)
2168 return handle_scaler_opt(*(const char **)arg
) != NULL
;
2172 static void print_scalers(void)
2174 mp_msg(MSGT_VO
, MSGL_INFO
, "Available scalers:\n");
2175 for (const char **e
= fixed_scale_filters
; *e
; e
++) {
2176 mp_msg(MSGT_VO
, MSGL_INFO
, " %s\n", *e
);
2178 for (const struct filter_kernel
*e
= mp_filter_kernels
; e
->name
; e
++) {
2179 if (can_use_filter_kernel(e
))
2180 mp_msg(MSGT_VO
, MSGL_INFO
, " %s\n", e
->name
);
2185 static int preinit(struct vo
*vo
, const char *arg
)
2187 struct gl_priv
*p
= talloc_zero(vo
, struct gl_priv
);
2190 *p
= (struct gl_priv
) {
2192 .colorspace
= MP_CSP_DETAILS_DEFAULTS
,
2196 .fbo_format
= GL_RGB16
,
2198 .use_fancy_downscaling
= 1,
2200 { .index
= 0, .name
= "lanczos2" },
2201 { .index
= 1, .name
= "bilinear" },
2203 .scaler_params
= {NAN
, NAN
},
2207 char *scalers
[2] = {0};
2208 char *backend_arg
= NULL
;
2209 char *fbo_format
= NULL
;
2210 char *icc_profile
= NULL
;
2211 char *icc_cache
= NULL
;
2212 int icc_intent
= -1;
2213 char *icc_size_str
= NULL
;
2215 const opt_t subopts
[] = {
2216 {"gamma", OPT_ARG_BOOL
, &p
->use_gamma
},
2217 {"srgb", OPT_ARG_BOOL
, &p
->use_srgb
},
2218 {"npot", OPT_ARG_BOOL
, &p
->use_npot
},
2219 {"pbo", OPT_ARG_BOOL
, &p
->use_pbo
},
2220 {"glfinish", OPT_ARG_BOOL
, &p
->use_glFinish
},
2221 {"swapinterval", OPT_ARG_INT
, &p
->swap_interval
},
2222 {"stereo", OPT_ARG_INT
, &p
->stereo_mode
},
2223 {"lscale", OPT_ARG_MSTRZ
, &scalers
[0], scaler_valid
},
2224 {"cscale", OPT_ARG_MSTRZ
, &scalers
[1], scaler_valid
},
2225 {"lparam1", OPT_ARG_FLOAT
, &p
->scaler_params
[0]},
2226 {"lparam2", OPT_ARG_FLOAT
, &p
->scaler_params
[1]},
2227 {"fancy-downscaling", OPT_ARG_BOOL
, &p
->use_fancy_downscaling
},
2228 {"debug", OPT_ARG_BOOL
, &p
->use_gl_debug
},
2229 {"force-gl2", OPT_ARG_BOOL
, &p
->use_gl2
},
2230 {"indirect", OPT_ARG_BOOL
, &p
->use_indirect
},
2231 {"scale-sep", OPT_ARG_BOOL
, &p
->use_scale_sep
},
2232 {"fbo-format", OPT_ARG_MSTRZ
, &fbo_format
, fbo_format_valid
},
2233 {"backend", OPT_ARG_MSTRZ
, &backend_arg
, backend_valid
},
2234 {"icc-profile", OPT_ARG_MSTRZ
, &icc_profile
},
2235 {"icc-cache", OPT_ARG_MSTRZ
, &icc_cache
},
2236 {"icc-intent", OPT_ARG_INT
, &icc_intent
},
2237 {"3dlut-size", OPT_ARG_MSTRZ
, &icc_size_str
,
2239 {"dither-depth", OPT_ARG_INT
, &p
->dither_depth
},
2243 if (subopt_parse(arg
, subopts
) != 0) {
2244 mp_msg(MSGT_VO
, MSGL_FATAL
, "%s", help_text
);
2248 int backend
= backend_arg
? mpgl_find_backend(backend_arg
) : GLTYPE_AUTO
;
2252 p
->fbo_format
= find_fbo_format(fbo_format
);
2255 for (int n
= 0; n
< 2; n
++) {
2257 p
->scalers
[n
].name
= handle_scaler_opt(scalers
[n
]);
2261 int s_r
= 128, s_g
= 256, s_b
= 64;
2263 parse_3dlut_size(icc_size_str
, &s_r
, &s_g
, &s_b
);
2266 bool success
= true;
2268 success
= load_icc(p
, icc_profile
, icc_cache
, icc_intent
,
2277 p
->eosd
= talloc_zero(vo
, struct bitmap_packer
);
2279 p
->glctx
= init_mpglcontext(backend
, vo
);
2282 p
->gl
= p
->glctx
->gl
;
2285 if (!config_window(p
, 320, 200, VOFLAG_HIDDEN
))
2287 // We created a window to test whether the GL context could be
2288 // created and so on. Destroy that window to make sure all state
2289 // associated with it is lost.
2291 p
->glctx
= init_mpglcontext(backend
, vo
);
2294 p
->gl
= p
->glctx
->gl
;
2304 const struct vo_driver video_out_gl3
= {
2306 .info
= &(const vo_info_t
) {
2309 "Based on vo_gl.c by Reimar Doeffinger",
2315 .draw_slice
= draw_slice
,
2316 .draw_osd
= draw_osd
,
2317 .flip_page
= flip_page
,
2318 .check_events
= check_events
,
2322 static const char help_text
[] =
2323 "\n--vo=gl3 command line help:\n"
2324 "Example: mplayer --vo=gl3:scale-sep:lscale=lanczos2\n"
2326 " lscale=<filter>\n"
2327 " Set the scaling filter. Possible choices:\n"
2328 " bilinear: bilinear texture filtering (fastest).\n"
2329 " bicubic_fast: bicubic filter (without lookup texture).\n"
2330 " sharpen3: unsharp masking (sharpening) with radius=3.\n"
2331 " sharpen5: unsharp masking (sharpening) with radius=5.\n"
2332 " lanczos2: Lanczos with radius=2 (default, recommended).\n"
2333 " lanczos3: Lanczos with radius=3 (not recommended).\n"
2334 " mitchell: Mitchell-Netravali.\n"
2335 " Default: lanczos2\n"
2336 " lparam1=<value> / lparam2=<value>\n"
2337 " Set parameters for configurable filters. Affects chroma scaler\n"
2339 " Filters which use this:\n"
2340 " mitchell: b and c params (defaults: b=1/3 c=1/3)\n"
2341 " kaiser: (defaults: 6.33 6.33)\n"
2342 " sharpen3: lparam1 sets sharpening strength (default: 0.5)\n"
2343 " sharpen5: as with sharpen3\n"
2345 " 0: normal display\n"
2346 " 1: side-by-side to red-cyan stereo\n"
2347 " 2: side-by-side to green-magenta stereo\n"
2348 " 3: side-by-side to quadbuffer stereo\n"
2350 " Enable gamma-correct scaling by working in linear light. This\n"
2351 " makes use of sRGB textures and framebuffers.\n"
2352 " This option forces the options 'indirect' and 'gamma'.\n"
2353 " NOTE: for BT.709 colorspaces, a gamma of 2.35 is assumed. For\n"
2354 " other YUV colorspaces, 2.2 is assumed. RGB input is always\n"
2355 " assumed to be in sRGB.\n"
2357 " Enable use of PBOs. This is faster, but can sometimes lead to\n"
2358 " sporadic and temporary image corruption.\n"
2359 " dither-depth=<n>\n"
2360 " Positive non-zero values select the target bit depth.\n"
2361 " -1: Disable any dithering done by mplayer.\n"
2362 " 0: Automatic selection. If output bit depth can't be detected,\n"
2363 " 8 bits per component are assumed.\n"
2364 " 8: Dither to 8 bit output.\n"
2366 " Note that dithering will always be disabled if the bit depth\n"
2367 " of the video is lower or qual to the detected dither-depth.\n"
2368 " If color management is enabled, input depth is assumed to be\n"
2369 " 16 bits, because the 3D LUT output is 16 bit wide.\n"
2371 " Check for OpenGL errors, i.e. call glGetError(). Also request a\n"
2372 " debug OpenGL context.\n"
2373 "Less useful options:\n"
2374 " swapinterval=<n>\n"
2375 " Interval in displayed frames between to buffer swaps.\n"
2376 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
2378 " When using a separable scale filter for luma, usually two filter\n"
2379 " passes are done. This is often faster. However, it forces\n"
2380 " conversion to RGB in an extra pass, so it can actually be slower\n"
2381 " if used with fast filters on small screen resolutions. Using\n"
2382 " this options will make rendering a single operation.\n"
2383 " Note that chroma scalers are always done as 1-pass filters.\n"
2385 " As lscale but for chroma (2x slower with little visible effect).\n"
2386 " Note that with some scaling filters, upscaling is always done in\n"
2387 " RGB. If chroma is not subsampled, this option is ignored, and the\n"
2388 " luma scaler is used instead. Setting this option is often useless.\n"
2389 " no-fancy-downscaling\n"
2390 " When using convolution based filters, don't extend the filter\n"
2391 " size when downscaling. Trades downscaling performance for\n"
2392 " reduced quality.\n"
2394 " Force use of power-of-2 texture sizes. For debugging only.\n"
2395 " Borders will look discolored due to filtering.\n"
2397 " Call glFinish() before swapping buffers\n"
2399 " auto: auto-select (default)\n"
2400 " cocoa: Cocoa/OSX\n"
2404 " Do YUV conversion and scaling as separate passes. This will\n"
2405 " first render the video into a video-sized RGB texture, and\n"
2406 " draw the result on screen. The luma scaler is used to scale\n"
2407 " the RGB image when rendering to screen. The chroma scaler\n"
2408 " is used only on YUV conversion, and only if the video uses\n"
2409 " chroma-subsampling.\n"
2410 " This mechanism is disabled on RGB input.\n"
2411 " fbo-format=<fmt>\n"
2412 " Selects the internal format of any FBO textures used.\n"
2413 " fmt can be one of: rgb, rgba, rgb8, rgb16, rgb16f, rgb32f\n"
2414 " Default: rgb16.\n"
2416 " Always enable gamma control. (Disables delayed enabling.)\n"
2418 " Create a legacy GL context. This will randomly malfunction\n"
2419 " if the proper extensions are not supported.\n"
2420 "Color management:\n"
2421 " icc-profile=<file>\n"
2422 " Load an ICC profile and use it to transform linear RGB to\n"
2423 " screen output. Needs LittleCMS2 support compiled in.\n"
2424 " icc-cache=<file>\n"
2425 " Store and load the 3D LUT created from the ICC profile in\n"
2426 " this file. This can be used to speed up loading, since\n"
2427 " LittleCMS2 can take a while to create the 3D LUT.\n"
2428 " Note that this file will be at most about 100 MB big.\n"
2429 " icc-intent=<value>\n"
2431 " 1: relative colorimetric\n"
2433 " 3: absolute colorimetric (default)\n"
2434 " 3dlut-size=<r>x<g>x<b>\n"
2435 " Size of the 3D LUT generated from the ICC profile in each\n"
2436 " dimension. Default is 128x256x64.\n"
2437 " Sizes must be a power of two, and 256 at most.\n"