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.
33 #include "subopt-helper.h"
34 #include "video_out.h"
35 #include "libmpcodecs/vfcap.h"
36 #include "libmpcodecs/mp_image.h"
39 #include "sub/font_load.h"
42 #include "gl_common.h"
44 #include "fastmemcpy.h"
45 #include "sub/ass_mp.h"
47 static int preinit_nosw(struct vo
*vo
, const char *arg
);
49 //! How many parts the OSD may consist of at most
50 #define MAX_OSD_PARTS 20
52 #define LARGE_EOSD_TEX_SIZE 512
53 #define TINYTEX_SIZE 16
54 #define TINYTEX_COLS (LARGE_EOSD_TEX_SIZE / TINYTEX_SIZE)
55 #define TINYTEX_MAX (TINYTEX_COLS * TINYTEX_COLS)
56 #define SMALLTEX_SIZE 32
57 #define SMALLTEX_COLS (LARGE_EOSD_TEX_SIZE / SMALLTEX_SIZE)
58 #define SMALLTEX_MAX (SMALLTEX_COLS * SMALLTEX_COLS)
61 #define MASK_ALL_YUV (~(1 << YUV_CONVERSION_NONE))
62 #define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS)))
63 #define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT))
72 GLuint osdtex
[MAX_OSD_PARTS
];
74 //! Alpha textures for OSD
75 GLuint osdatex
[MAX_OSD_PARTS
];
78 GLuint largeeosdtex
[2];
79 //! Display lists that draw the OSD parts
80 GLuint osdDispList
[MAX_OSD_PARTS
];
82 GLuint osdaDispList
[MAX_OSD_PARTS
];
85 //! How many parts the OSD currently consists of
92 struct mp_csp_details colorspace
;
96 float filter_strength
;
100 uint32_t image_width
;
101 uint32_t image_height
;
102 uint32_t image_format
;
103 uint32_t image_d_width
;
104 uint32_t image_d_height
;
120 void *bufferptr_uv
[2];
122 GLuint default_texs
[22];
130 struct mp_csp_equalizer video_eq
;
136 int ass_border_x
, ass_border_y
;
138 unsigned int slice_height
;
141 static void resize(struct vo
*vo
, int x
, int y
)
143 struct gl_priv
*p
= vo
->priv
;
146 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Resize: %dx%d\n", x
, y
);
148 int left
= 0, top
= 0, w
= x
, h
= y
;
149 geometry(&left
, &top
, &w
, &h
, vo
->dwidth
, vo
->dheight
);
151 gl
->Viewport(left
, top
, w
, h
);
153 gl
->Viewport(0, 0, x
, y
);
155 gl
->MatrixMode(GL_PROJECTION
);
157 p
->ass_border_x
= p
->ass_border_y
= 0;
158 if (aspect_scaling()) {
160 GLdouble scale_x
, scale_y
;
161 aspect(vo
, &new_w
, &new_h
, A_WINZOOM
);
162 panscan_calc_windowed(vo
);
163 new_w
+= vo
->panscan_x
;
164 new_h
+= vo
->panscan_y
;
165 scale_x
= (GLdouble
)new_w
/ (GLdouble
)x
;
166 scale_y
= (GLdouble
)new_h
/ (GLdouble
)y
;
167 gl
->Scaled(scale_x
, scale_y
, 1);
168 p
->ass_border_x
= (vo
->dwidth
- new_w
) / 2;
169 p
->ass_border_y
= (vo
->dheight
- new_h
) / 2;
171 gl
->Ortho(0, p
->image_width
, p
->image_height
, 0, -1, 1);
173 gl
->MatrixMode(GL_MODELVIEW
);
176 if (!p
->scaled_osd
) {
177 #ifdef CONFIG_FREETYPE
178 // adjust font size to display size
181 vo_osd_changed(OSDTYPE_OSD
);
183 gl
->Clear(GL_COLOR_BUFFER_BIT
);
184 vo
->want_redraw
= true;
187 static void texSize(struct vo
*vo
, int w
, int h
, int *texw
, int *texh
)
189 struct gl_priv
*p
= vo
->priv
;
191 if (p
->use_rectangle
) {
203 *texw
= (*texw
+ 511) & ~511;
206 //! maximum size of custom fragment program
207 #define MAX_CUSTOM_PROG_SIZE (1024 * 1024)
208 static void update_yuvconv(struct vo
*vo
)
210 struct gl_priv
*p
= vo
->priv
;
214 struct mp_csp_params cparams
= { .colorspace
= p
->colorspace
};
215 mp_csp_copy_equalizer_values(&cparams
, &p
->video_eq
);
216 gl_conversion_params_t params
= {
217 p
->target
, p
->yuvconvtype
, cparams
,
218 p
->texture_width
, p
->texture_height
, 0, 0, p
->filter_strength
220 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &depth
);
221 params
.chrom_texw
= params
.texw
>> xs
;
222 params
.chrom_texh
= params
.texh
>> ys
;
223 params
.csp_params
.input_shift
= -depth
& 7;
224 glSetupYUVConversion(gl
, ¶ms
);
225 if (p
->custom_prog
) {
226 FILE *f
= fopen(p
->custom_prog
, "rb");
228 mp_msg(MSGT_VO
, MSGL_WARN
,
229 "[gl] Could not read customprog %s\n", p
->custom_prog
);
231 char *prog
= calloc(1, MAX_CUSTOM_PROG_SIZE
+ 1);
232 fread(prog
, 1, MAX_CUSTOM_PROG_SIZE
, f
);
234 loadGPUProgram(gl
, GL_FRAGMENT_PROGRAM
, prog
);
237 gl
->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 0,
238 1.0 / p
->texture_width
,
239 1.0 / p
->texture_height
,
240 p
->texture_width
, p
->texture_height
);
243 FILE *f
= fopen(p
->custom_tex
, "rb");
245 mp_msg(MSGT_VO
, MSGL_WARN
,
246 "[gl] Could not read customtex %s\n", p
->custom_tex
);
248 int width
, height
, maxval
;
249 gl
->ActiveTexture(GL_TEXTURE3
);
250 if (glCreatePPMTex(gl
, p
->custom_trect
? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
,
251 0, p
->custom_tlin
? GL_LINEAR
: GL_NEAREST
,
252 f
, &width
, &height
, &maxval
)) {
253 gl
->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 1,
254 1.0 / width
, 1.0 / height
,
257 mp_msg(MSGT_VO
, MSGL_WARN
,
258 "[gl] Error parsing customtex %s\n", p
->custom_tex
);
260 gl
->ActiveTexture(GL_TEXTURE0
);
266 * \brief remove all OSD textures and display-lists, thus clearing it.
268 static void clearOSD(struct vo
*vo
)
270 struct gl_priv
*p
= vo
->priv
;
276 gl
->DeleteTextures(p
->osdtexCnt
, p
->osdtex
);
278 gl
->DeleteTextures(p
->osdtexCnt
, p
->osdatex
);
279 for (i
= 0; i
< p
->osdtexCnt
; i
++)
280 gl
->DeleteLists(p
->osdaDispList
[i
], 1);
282 for (i
= 0; i
< p
->osdtexCnt
; i
++)
283 gl
->DeleteLists(p
->osdDispList
[i
], 1);
288 * \brief remove textures, display list and free memory used by EOSD
290 static void clearEOSD(struct vo
*vo
)
292 struct gl_priv
*p
= vo
->priv
;
296 gl
->DeleteLists(p
->eosdDispList
, 1);
299 gl
->DeleteTextures(p
->eosdtexCnt
, p
->eosdtex
);
305 static inline int is_tinytex(ASS_Image
*i
, int tinytexcur
)
307 return i
->w
< TINYTEX_SIZE
&& i
->h
< TINYTEX_SIZE
308 && tinytexcur
< TINYTEX_MAX
;
311 static inline int is_smalltex(ASS_Image
*i
, int smalltexcur
)
313 return i
->w
< SMALLTEX_SIZE
&& i
->h
< SMALLTEX_SIZE
314 && smalltexcur
< SMALLTEX_MAX
;
317 static inline void tinytex_pos(int tinytexcur
, int *x
, int *y
)
319 *x
= (tinytexcur
% TINYTEX_COLS
) * TINYTEX_SIZE
;
320 *y
= (tinytexcur
/ TINYTEX_COLS
) * TINYTEX_SIZE
;
323 static inline void smalltex_pos(int smalltexcur
, int *x
, int *y
)
325 *x
= (smalltexcur
% SMALLTEX_COLS
) * SMALLTEX_SIZE
;
326 *y
= (smalltexcur
/ SMALLTEX_COLS
) * SMALLTEX_SIZE
;
330 * \brief construct display list from ass image list
331 * \param img image list to create OSD from.
332 * A value of NULL has the same effect as clearEOSD()
334 static void genEOSD(struct vo
*vo
, mp_eosd_images_t
*imgs
)
336 struct gl_priv
*p
= vo
->priv
;
343 GLint scale_type
= p
->scaled_osd
? GL_LINEAR
: GL_NEAREST
;
344 ASS_Image
*img
= imgs
->imgs
;
347 if (imgs
->changed
== 0) // there are elements, but they are unchanged
349 if (img
&& imgs
->changed
== 1) // there are elements, but they just moved
355 if (!p
->largeeosdtex
[0]) {
356 gl
->GenTextures(2, p
->largeeosdtex
);
357 for (int n
= 0; n
< 2; n
++) {
358 gl
->BindTexture(p
->target
, p
->largeeosdtex
[n
]);
359 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
,
360 GL_UNSIGNED_BYTE
, scale_type
,
361 LARGE_EOSD_TEX_SIZE
, LARGE_EOSD_TEX_SIZE
, 0);
364 for (i
= img
; i
; i
= i
->next
) {
365 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
)
367 if (is_tinytex(i
, tinytexcur
))
369 else if (is_smalltex(i
, smalltexcur
))
374 mp_msg(MSGT_VO
, MSGL_DBG2
, "EOSD counts (tiny, small, all): %i, %i, %i\n",
375 tinytexcur
, smalltexcur
, p
->eosdtexCnt
);
377 p
->eosdtex
= calloc(p
->eosdtexCnt
, sizeof(GLuint
));
378 gl
->GenTextures(p
->eosdtexCnt
, p
->eosdtex
);
380 tinytexcur
= smalltexcur
= 0;
381 for (i
= img
, curtex
= p
->eosdtex
; i
; i
= i
->next
) {
383 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
) {
384 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
387 if (is_tinytex(i
, tinytexcur
)) {
388 tinytex_pos(tinytexcur
, &x
, &y
);
389 gl
->BindTexture(p
->target
, p
->largeeosdtex
[0]);
391 } else if (is_smalltex(i
, smalltexcur
)) {
392 smalltex_pos(smalltexcur
, &x
, &y
);
393 gl
->BindTexture(p
->target
, p
->largeeosdtex
[1]);
396 texSize(vo
, i
->w
, i
->h
, &sx
, &sy
);
397 gl
->BindTexture(p
->target
, *curtex
++);
398 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
,
399 GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
401 glUploadTex(gl
, p
->target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, i
->bitmap
,
402 i
->stride
, x
, y
, i
->w
, i
->h
, 0);
404 p
->eosdDispList
= gl
->GenLists(1);
406 gl
->NewList(p
->eosdDispList
, GL_COMPILE
);
407 tinytexcur
= smalltexcur
= 0;
408 for (i
= img
, curtex
= p
->eosdtex
; i
; i
= i
->next
) {
410 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
)
412 gl
->Color4ub(i
->color
>> 24, (i
->color
>> 16) & 0xff,
413 (i
->color
>> 8) & 0xff, 255 - (i
->color
& 0xff));
414 if (is_tinytex(i
, tinytexcur
)) {
415 tinytex_pos(tinytexcur
, &x
, &y
);
416 sx
= sy
= LARGE_EOSD_TEX_SIZE
;
417 gl
->BindTexture(p
->target
, p
->largeeosdtex
[0]);
419 } else if (is_smalltex(i
, smalltexcur
)) {
420 smalltex_pos(smalltexcur
, &x
, &y
);
421 sx
= sy
= LARGE_EOSD_TEX_SIZE
;
422 gl
->BindTexture(p
->target
, p
->largeeosdtex
[1]);
425 texSize(vo
, i
->w
, i
->h
, &sx
, &sy
);
426 gl
->BindTexture(p
->target
, *curtex
++);
428 glDrawTex(gl
, i
->dst_x
, i
->dst_y
, i
->w
, i
->h
, x
, y
, i
->w
, i
->h
, sx
, sy
,
429 p
->use_rectangle
== 1, 0, 0);
432 gl
->BindTexture(p
->target
, 0);
436 * \brief uninitialize OpenGL context, freeing textures, buffers etc.
438 static void uninitGl(struct vo
*vo
)
440 struct gl_priv
*p
= vo
->priv
;
444 if (gl
->DeletePrograms
&& p
->fragprog
)
445 gl
->DeletePrograms(1, &p
->fragprog
);
447 while (p
->default_texs
[i
] != 0)
450 gl
->DeleteTextures(i
, p
->default_texs
);
451 p
->default_texs
[0] = 0;
454 if (p
->largeeosdtex
[0])
455 gl
->DeleteTextures(2, p
->largeeosdtex
);
456 p
->largeeosdtex
[0] = 0;
457 if (gl
->DeleteBuffers
&& p
->buffer
)
458 gl
->DeleteBuffers(1, &p
->buffer
);
462 if (gl
->DeleteBuffers
&& p
->buffer_uv
[0])
463 gl
->DeleteBuffers(2, p
->buffer_uv
);
464 p
->buffer_uv
[0] = p
->buffer_uv
[1] = 0;
465 p
->buffersize_uv
= 0;
466 p
->bufferptr_uv
[0] = p
->bufferptr_uv
[1] = 0;
470 static int isSoftwareGl(struct vo
*vo
)
472 struct gl_priv
*p
= vo
->priv
;
473 const char *renderer
= p
->gl
->GetString(GL_RENDERER
);
474 return !renderer
|| strcmp(renderer
, "Software Rasterizer") == 0 ||
475 strstr(renderer
, "llvmpipe");
478 static void autodetectGlExtensions(struct vo
*vo
)
480 struct gl_priv
*p
= vo
->priv
;
483 const char *extensions
= gl
->GetString(GL_EXTENSIONS
);
484 const char *vendor
= gl
->GetString(GL_VENDOR
);
485 const char *version
= gl
->GetString(GL_VERSION
);
486 const char *renderer
= gl
->GetString(GL_RENDERER
);
487 int is_ati
= vendor
&& strstr(vendor
, "ATI") != NULL
;
488 int ati_broken_pbo
= 0;
489 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Running on OpenGL '%s' by '%s', version '%s'\n",
490 renderer
, vendor
, version
);
491 if (is_ati
&& strncmp(version
, "2.1.", 4) == 0) {
492 int ver
= atoi(version
+ 4);
493 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Detected ATI driver version: %i\n", ver
);
494 ati_broken_pbo
= ver
&& ver
< 8395;
496 if (p
->ati_hack
== -1)
497 p
->ati_hack
= ati_broken_pbo
;
498 if (p
->force_pbo
== -1) {
500 if (extensions
&& strstr(extensions
, "_pixel_buffer_object"))
501 p
->force_pbo
= is_ati
;
503 p
->have_texture_rg
= extensions
&& strstr(extensions
, "GL_ARB_texture_rg");
504 if (p
->use_rectangle
== -1) {
505 p
->use_rectangle
= 0;
507 // if (strstr(extensions, "_texture_non_power_of_two"))
508 if (strstr(extensions
, "_texture_rectangle"))
509 p
->use_rectangle
= renderer
510 && strstr(renderer
, "Mesa DRI R200") ? 1 : 0;
513 if (p
->use_osd
== -1)
514 p
->use_osd
= gl
->BindTexture
!= NULL
;
515 if (p
->use_yuv
== -1)
516 p
->use_yuv
= glAutodetectYUVConversion(gl
);
519 int yuv_mask
= (1 << p
->use_yuv
);
520 if (!(yuv_mask
& MASK_NOT_COMBINERS
)) {
522 eq_caps
= (1 << MP_CSP_EQ_HUE
) | (1 << MP_CSP_EQ_SATURATION
);
523 } else if (yuv_mask
& MASK_ALL_YUV
) {
524 eq_caps
= MP_CSP_EQ_CAPS_COLORMATRIX
;
525 if (yuv_mask
& MASK_GAMMA_SUPPORT
)
526 eq_caps
|= MP_CSP_EQ_CAPS_GAMMA
;
528 p
->video_eq
.capabilities
= eq_caps
;
530 if (is_ati
&& (p
->lscale
== 1 || p
->lscale
== 2 || p
->cscale
== 1 || p
->cscale
== 2))
531 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] Selected scaling mode may be broken on"
533 "Tell _them_ to fix GL_REPEAT if you have issues.\n");
534 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Settings after autodetection: ati-hack = %i, "
535 "force-pbo = %i, rectangle = %i, yuv = %i\n",
536 p
->ati_hack
, p
->force_pbo
, p
->use_rectangle
, p
->use_yuv
);
539 static GLint
get_scale_type(struct vo
*vo
, int chroma
)
541 struct gl_priv
*p
= vo
->priv
;
543 int nearest
= (chroma
? p
->cscale
: p
->lscale
) & 64;
545 return p
->mipmap_gen
? GL_NEAREST_MIPMAP_NEAREST
: GL_NEAREST
;
546 return p
->mipmap_gen
? GL_LINEAR_MIPMAP_NEAREST
: GL_LINEAR
;
549 // Return the high byte of the value that represents white in chroma (U/V)
550 static int get_chroma_clear_val(int bit_depth
)
552 return 1 << (bit_depth
- 1 & 7);
556 * \brief Initialize a (new or reused) OpenGL context.
557 * set global gl-related variables to their default values
559 static int initGl(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
)
561 struct gl_priv
*p
= vo
->priv
;
564 GLint scale_type
= get_scale_type(vo
, 0);
565 autodetectGlExtensions(vo
);
566 p
->target
= p
->use_rectangle
== 1 ? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
;
567 p
->yuvconvtype
= SET_YUV_CONVERSION(p
->use_yuv
) |
568 SET_YUV_LUM_SCALER(p
->lscale
) |
569 SET_YUV_CHROM_SCALER(p
->cscale
);
571 texSize(vo
, p
->image_width
, p
->image_height
,
572 &p
->texture_width
, &p
->texture_height
);
574 gl
->Disable(GL_BLEND
);
575 gl
->Disable(GL_DEPTH_TEST
);
576 gl
->DepthMask(GL_FALSE
);
577 gl
->Disable(GL_CULL_FACE
);
578 gl
->Enable(p
->target
);
579 gl
->DrawBuffer(vo_doublebuffering
? GL_BACK
: GL_FRONT
);
580 gl
->TexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
582 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Creating %dx%d texture...\n",
583 p
->texture_width
, p
->texture_height
);
585 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
586 p
->gl_type
, scale_type
,
587 p
->texture_width
, p
->texture_height
, 0);
590 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
595 scale_type
= get_scale_type(vo
, 1);
596 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &depth
);
597 int clear
= get_chroma_clear_val(depth
);
598 gl
->GenTextures(21, p
->default_texs
);
599 p
->default_texs
[21] = 0;
600 for (i
= 0; i
< 7; i
++) {
601 gl
->ActiveTexture(GL_TEXTURE1
+ i
);
602 gl
->BindTexture(GL_TEXTURE_2D
, p
->default_texs
[i
]);
603 gl
->BindTexture(GL_TEXTURE_RECTANGLE
, p
->default_texs
[i
+ 7]);
604 gl
->BindTexture(GL_TEXTURE_3D
, p
->default_texs
[i
+ 14]);
606 gl
->ActiveTexture(GL_TEXTURE1
);
607 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
608 p
->gl_type
, scale_type
,
609 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
612 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
613 gl
->ActiveTexture(GL_TEXTURE2
);
614 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
615 p
->gl_type
, scale_type
,
616 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
619 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
620 gl
->ActiveTexture(GL_TEXTURE0
);
621 gl
->BindTexture(p
->target
, 0);
623 if (p
->is_yuv
|| p
->custom_prog
) {
624 if ((MASK_NOT_COMBINERS
& (1 << p
->use_yuv
)) || p
->custom_prog
) {
625 if (!gl
->GenPrograms
|| !gl
->BindProgram
)
626 mp_msg(MSGT_VO
, MSGL_ERR
,
627 "[gl] fragment program functions missing!\n");
629 gl
->GenPrograms(1, &p
->fragprog
);
630 gl
->BindProgram(GL_FRAGMENT_PROGRAM
, p
->fragprog
);
636 resize(vo
, d_width
, d_height
);
638 gl
->ClearColor(0.0f
, 0.0f
, 0.0f
, 0.0f
);
639 gl
->Clear(GL_COLOR_BUFFER_BIT
);
640 if (gl
->SwapInterval
&& p
->swap_interval
>= 0)
641 gl
->SwapInterval(p
->swap_interval
);
645 static int create_window(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
,
648 struct gl_priv
*p
= vo
->priv
;
650 if (p
->stereo_mode
== GL_3D_QUADBUFFER
)
651 flags
|= VOFLAG_STEREO
;
653 return p
->glctx
->create_window(p
->glctx
, d_width
, d_height
, flags
);
656 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
657 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
660 struct gl_priv
*p
= vo
->priv
;
663 p
->image_height
= height
;
664 p
->image_width
= width
;
665 p
->image_format
= format
;
666 p
->image_d_width
= d_width
;
667 p
->image_d_height
= d_height
;
668 p
->is_yuv
= mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
) > 0;
669 p
->is_yuv
|= (xs
<< 8) | (ys
<< 16);
670 glFindFormat(format
, p
->have_texture_rg
, NULL
, &p
->texfmt
, &p
->gl_format
,
673 p
->vo_flipped
= !!(flags
& VOFLAG_FLIPPING
);
675 if (create_window(vo
, d_width
, d_height
, flags
) < 0)
678 if (vo
->config_count
)
680 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
682 initGl(vo
, vo
->dwidth
, vo
->dheight
);
687 static void check_events(struct vo
*vo
)
689 struct gl_priv
*p
= vo
->priv
;
691 int e
= p
->glctx
->check_events(vo
);
692 if (e
& VO_EVENT_REINIT
) {
694 initGl(vo
, vo
->dwidth
, vo
->dheight
);
696 if (e
& VO_EVENT_RESIZE
)
697 resize(vo
, vo
->dwidth
, vo
->dheight
);
698 if (e
& VO_EVENT_EXPOSE
)
699 vo
->want_redraw
= true;
703 * Creates the textures and the display list needed for displaying
705 * Callback function for osd_draw_text_ext().
707 static void create_osd_texture(void *ctx
, int x0
, int y0
, int w
, int h
,
708 unsigned char *src
, unsigned char *srca
,
712 struct gl_priv
*p
= vo
->priv
;
715 // initialize to 8 to avoid special-casing on alignment
717 GLint scale_type
= p
->scaled_osd
? GL_LINEAR
: GL_NEAREST
;
719 if (w
<= 0 || h
<= 0 || stride
< w
) {
720 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
723 texSize(vo
, w
, h
, &sx
, &sy
);
725 if (p
->osdtexCnt
>= MAX_OSD_PARTS
) {
726 mp_msg(MSGT_VO
, MSGL_ERR
, "Too many OSD parts, contact the developers!\n");
730 // create Textures for OSD part
731 gl
->GenTextures(1, &p
->osdtex
[p
->osdtexCnt
]);
732 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
733 glCreateClearTex(gl
, p
->target
, GL_LUMINANCE
, GL_LUMINANCE
,
734 GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
735 glUploadTex(gl
, p
->target
, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, src
, stride
,
739 gl
->GenTextures(1, &p
->osdatex
[p
->osdtexCnt
]);
740 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
741 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
,
742 scale_type
, sx
, sy
, 0);
745 char *tmp
= malloc(stride
* h
);
746 // convert alpha from weird MPlayer scale.
747 // in-place is not possible since it is reused for future OSDs
748 for (i
= h
* stride
- 1; i
>= 0; i
--)
750 glUploadTex(gl
, p
->target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, tmp
, stride
,
756 gl
->BindTexture(p
->target
, 0);
758 // Create a list for rendering this OSD part
760 p
->osdaDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
761 gl
->NewList(p
->osdaDispList
[p
->osdtexCnt
], GL_COMPILE
);
763 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
764 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
767 p
->osdDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
768 gl
->NewList(p
->osdDispList
[p
->osdtexCnt
], GL_COMPILE
);
770 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
771 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
778 #define RENDER_EOSD 2
781 * \param type bit 0: render OSD, bit 1: render EOSD
783 static void do_render_osd(struct vo
*vo
, int type
)
785 struct gl_priv
*p
= vo
->priv
;
788 int draw_osd
= (type
& RENDER_OSD
) && p
->osdtexCnt
> 0;
789 int draw_eosd
= (type
& RENDER_EOSD
) && p
->eosdDispList
;
790 if (!draw_osd
&& !draw_eosd
)
792 // set special rendering parameters
793 if (!p
->scaled_osd
) {
794 gl
->MatrixMode(GL_PROJECTION
);
797 gl
->Ortho(0, vo
->dwidth
, vo
->dheight
, 0, -1, 1);
799 gl
->Enable(GL_BLEND
);
801 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
802 gl
->CallList(p
->eosdDispList
);
805 gl
->Color4ub((p
->osd_color
>> 16) & 0xff, (p
->osd_color
>> 8) & 0xff,
806 p
->osd_color
& 0xff, 0xff - (p
->osd_color
>> 24));
809 gl
->BlendFunc(GL_ZERO
, GL_ONE_MINUS_SRC_ALPHA
);
810 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdaDispList
);
812 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE
);
813 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdDispList
);
815 // set rendering parameters back to defaults
816 gl
->Disable(GL_BLEND
);
819 gl
->BindTexture(p
->target
, 0);
822 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
824 struct gl_priv
*p
= vo
->priv
;
828 if (vo_osd_changed(0)) {
831 osd_w
= p
->scaled_osd
? p
->image_width
: vo
->dwidth
;
832 osd_h
= p
->scaled_osd
? p
->image_height
: vo
->dheight
;
833 osd_draw_text_ext(osd
, osd_w
, osd_h
, p
->ass_border_x
,
834 p
->ass_border_y
, p
->ass_border_x
,
835 p
->ass_border_y
, p
->image_width
,
836 p
->image_height
, create_osd_texture
, vo
);
838 if (vo_doublebuffering
)
839 do_render_osd(vo
, RENDER_OSD
);
842 static void do_render(struct vo
*vo
)
844 struct gl_priv
*p
= vo
->priv
;
847 // Enable(GL_TEXTURE_2D);
848 // BindTexture(GL_TEXTURE_2D, texture_id);
850 gl
->Color3f(1, 1, 1);
851 if (p
->is_yuv
|| p
->custom_prog
)
852 glEnableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
853 if (p
->stereo_mode
) {
854 glEnable3DLeft(gl
, p
->stereo_mode
);
855 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
856 0, 0, p
->image_width
>> 1, p
->image_height
,
857 p
->texture_width
, p
->texture_height
,
858 p
->use_rectangle
== 1, p
->is_yuv
,
859 p
->mpi_flipped
^ p
->vo_flipped
);
860 glEnable3DRight(gl
, p
->stereo_mode
);
861 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
862 p
->image_width
>> 1, 0, p
->image_width
>> 1,
863 p
->image_height
, p
->texture_width
, p
->texture_height
,
864 p
->use_rectangle
== 1, p
->is_yuv
,
865 p
->mpi_flipped
^ p
->vo_flipped
);
866 glDisable3D(gl
, p
->stereo_mode
);
868 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
869 0, 0, p
->image_width
, p
->image_height
,
870 p
->texture_width
, p
->texture_height
,
871 p
->use_rectangle
== 1, p
->is_yuv
,
872 p
->mpi_flipped
^ p
->vo_flipped
);
874 if (p
->is_yuv
|| p
->custom_prog
)
875 glDisableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
878 static void flip_page(struct vo
*vo
)
880 struct gl_priv
*p
= vo
->priv
;
883 if (vo_doublebuffering
) {
886 p
->glctx
->swapGlBuffers(p
->glctx
);
887 if (aspect_scaling())
888 gl
->Clear(GL_COLOR_BUFFER_BIT
);
891 do_render_osd(vo
, RENDER_OSD
| RENDER_EOSD
);
899 static int draw_slice(struct vo
*vo
, uint8_t *src
[], int stride
[], int w
, int h
,
902 struct gl_priv
*p
= vo
->priv
;
905 p
->mpi_flipped
= stride
[0] < 0;
906 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[0], stride
[0],
907 x
, y
, w
, h
, p
->slice_height
);
910 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
911 gl
->ActiveTexture(GL_TEXTURE1
);
912 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[1], stride
[1],
913 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
914 gl
->ActiveTexture(GL_TEXTURE2
);
915 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[2], stride
[2],
916 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
917 gl
->ActiveTexture(GL_TEXTURE0
);
922 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
924 struct gl_priv
*p
= vo
->priv
;
928 if (!gl
->GenBuffers
|| !gl
->BindBuffer
|| !gl
->BufferData
|| !gl
->MapBuffer
) {
930 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] extensions missing for dr\n"
931 "Expect a _major_ speed penalty\n");
935 if (mpi
->flags
& MP_IMGFLAG_READABLE
)
937 if (mpi
->type
!= MP_IMGTYPE_STATIC
&& mpi
->type
!= MP_IMGTYPE_TEMP
&&
938 (mpi
->type
!= MP_IMGTYPE_NUMBERED
|| mpi
->number
))
941 mpi
->width
= p
->texture_width
;
942 mpi
->height
= p
->texture_height
;
944 mpi
->stride
[0] = mpi
->width
* mpi
->bpp
/ 8;
945 needed_size
= mpi
->stride
[0] * mpi
->height
;
947 gl
->GenBuffers(1, &p
->buffer
);
948 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
949 if (needed_size
> p
->buffersize
) {
950 p
->buffersize
= needed_size
;
951 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, p
->buffersize
,
952 NULL
, GL_DYNAMIC_DRAW
);
955 p
->bufferptr
= gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_WRITE_ONLY
);
956 mpi
->planes
[0] = p
->bufferptr
;
957 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
958 if (!mpi
->planes
[0]) {
960 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] could not acquire buffer for dr\n"
961 "Expect a _major_ speed penalty\n");
967 int xs
, ys
, component_bits
;
968 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
969 int bp
= (component_bits
+ 7) / 8;
970 mpi
->flags
|= MP_IMGFLAG_COMMON_STRIDE
| MP_IMGFLAG_COMMON_PLANE
;
971 mpi
->stride
[0] = mpi
->width
* bp
;
972 mpi
->planes
[1] = mpi
->planes
[0] + mpi
->stride
[0] * mpi
->height
;
973 mpi
->stride
[1] = (mpi
->width
>> xs
) * bp
;
974 mpi
->planes
[2] = mpi
->planes
[1] + mpi
->stride
[1] * (mpi
->height
>> ys
);
975 mpi
->stride
[2] = (mpi
->width
>> xs
) * bp
;
977 mpi
->flags
&= ~MP_IMGFLAG_COMMON_PLANE
;
978 if (!p
->buffer_uv
[0])
979 gl
->GenBuffers(2, p
->buffer_uv
);
980 int buffer_size
= mpi
->stride
[1] * mpi
->height
;
981 if (buffer_size
> p
->buffersize_uv
) {
982 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
983 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
985 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
986 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
988 p
->buffersize_uv
= buffer_size
;
990 if (!p
->bufferptr_uv
[0]) {
991 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
992 p
->bufferptr_uv
[0] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
994 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
995 p
->bufferptr_uv
[1] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
998 mpi
->planes
[1] = p
->bufferptr_uv
[0];
999 mpi
->planes
[2] = p
->bufferptr_uv
[1];
1002 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1006 static void clear_border(struct vo
*vo
, uint8_t *dst
, int start
, int stride
,
1007 int height
, int full_height
, int value
)
1009 int right_border
= stride
- start
;
1010 int bottom_border
= full_height
- height
;
1011 while (height
> 0) {
1012 if (right_border
> 0)
1013 memset(dst
+ start
, value
, right_border
);
1017 if (bottom_border
> 0)
1018 memset(dst
, value
, stride
* bottom_border
);
1021 static uint32_t draw_image(struct vo
*vo
, mp_image_t
*mpi
)
1023 struct gl_priv
*p
= vo
->priv
;
1026 int slice
= p
->slice_height
;
1028 unsigned char *planes
[3];
1029 mp_image_t mpi2
= *mpi
;
1030 int w
= mpi
->w
, h
= mpi
->h
;
1031 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
1034 mpi2
.type
= MP_IMGTYPE_TEMP
;
1035 mpi2
.width
= mpi2
.w
;
1036 mpi2
.height
= mpi2
.h
;
1037 if (p
->force_pbo
&& !(mpi
->flags
& MP_IMGFLAG_DIRECT
) && !p
->bufferptr
1038 && get_image(vo
, &mpi2
) == VO_TRUE
)
1040 int bp
= mpi
->bpp
/ 8;
1041 int xs
, ys
, component_bits
;
1042 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
1044 bp
= (component_bits
+ 7) / 8;
1045 memcpy_pic(mpi2
.planes
[0], mpi
->planes
[0], mpi
->w
* bp
, mpi
->h
,
1046 mpi2
.stride
[0], mpi
->stride
[0]);
1047 int uv_bytes
= (mpi
->w
>> xs
) * bp
;
1049 memcpy_pic(mpi2
.planes
[1], mpi
->planes
[1], uv_bytes
, mpi
->h
>> ys
,
1050 mpi2
.stride
[1], mpi
->stride
[1]);
1051 memcpy_pic(mpi2
.planes
[2], mpi
->planes
[2], uv_bytes
, mpi
->h
>> ys
,
1052 mpi2
.stride
[2], mpi
->stride
[2]);
1055 // since we have to do a full upload we need to clear the borders
1056 clear_border(vo
, mpi2
.planes
[0], mpi
->w
* bp
, mpi2
.stride
[0],
1057 mpi
->h
, mpi2
.height
, 0);
1059 int clear
= get_chroma_clear_val(component_bits
);
1060 clear_border(vo
, mpi2
.planes
[1], uv_bytes
, mpi2
.stride
[1],
1061 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1062 clear_border(vo
, mpi2
.planes
[2], uv_bytes
, mpi2
.stride
[2],
1063 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1068 stride
[0] = mpi
->stride
[0];
1069 stride
[1] = mpi
->stride
[1];
1070 stride
[2] = mpi
->stride
[2];
1071 planes
[0] = mpi
->planes
[0];
1072 planes
[1] = mpi
->planes
[1];
1073 planes
[2] = mpi
->planes
[2];
1074 p
->mpi_flipped
= stride
[0] < 0;
1075 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1076 intptr_t base
= (intptr_t)planes
[0];
1078 w
= p
->texture_width
;
1079 h
= p
->texture_height
;
1082 base
+= (mpi
->h
- 1) * stride
[0];
1086 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
1087 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1088 p
->bufferptr
= NULL
;
1089 if (!(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
))
1090 planes
[0] = planes
[1] = planes
[2] = NULL
;
1091 slice
= 0; // always "upload" full texture
1093 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[0],
1094 stride
[0], mpi
->x
, mpi
->y
, w
, h
, slice
);
1097 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
1098 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1099 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
1100 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1101 p
->bufferptr_uv
[0] = NULL
;
1103 gl
->ActiveTexture(GL_TEXTURE1
);
1104 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[1],
1105 stride
[1], mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
,
1107 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1108 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
1109 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1110 p
->bufferptr_uv
[1] = NULL
;
1112 gl
->ActiveTexture(GL_TEXTURE2
);
1113 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[2],
1114 stride
[2], mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
,
1116 gl
->ActiveTexture(GL_TEXTURE0
);
1118 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1119 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1122 if (vo_doublebuffering
)
1127 static mp_image_t
*get_screenshot(struct vo
*vo
)
1129 struct gl_priv
*p
= vo
->priv
;
1132 mp_image_t
*image
= alloc_mpi(p
->texture_width
, p
->texture_height
,
1135 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[0],
1139 gl
->ActiveTexture(GL_TEXTURE1
);
1140 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[1],
1142 gl
->ActiveTexture(GL_TEXTURE2
);
1143 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[2],
1145 gl
->ActiveTexture(GL_TEXTURE0
);
1148 image
->width
= p
->image_width
;
1149 image
->height
= p
->image_height
;
1151 image
->w
= p
->image_d_width
;
1152 image
->h
= p
->image_d_height
;
1157 static mp_image_t
*get_window_screenshot(struct vo
*vo
)
1159 struct gl_priv
*p
= vo
->priv
;
1162 GLint vp
[4]; //x, y, w, h
1163 gl
->GetIntegerv(GL_VIEWPORT
, vp
);
1164 mp_image_t
*image
= alloc_mpi(vp
[2], vp
[3], IMGFMT_RGB24
);
1165 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1166 gl
->PixelStorei(GL_PACK_ALIGNMENT
, 0);
1167 gl
->PixelStorei(GL_PACK_ROW_LENGTH
, 0);
1168 gl
->ReadBuffer(GL_FRONT
);
1169 //flip image while reading
1170 for (int y
= 0; y
< vp
[3]; y
++) {
1171 gl
->ReadPixels(vp
[0], vp
[1] + vp
[3] - y
- 1, vp
[2], 1,
1172 GL_RGB
, GL_UNSIGNED_BYTE
,
1173 image
->planes
[0] + y
* image
->stride
[0]);
1178 static int query_format(struct vo
*vo
, uint32_t format
)
1180 struct gl_priv
*p
= vo
->priv
;
1183 int caps
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_FLIP
|
1184 VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1186 caps
|= VFCAP_OSD
| VFCAP_EOSD
| (p
->scaled_osd
? 0 : VFCAP_EOSD_UNSCALED
);
1187 if (format
== IMGFMT_RGB24
|| format
== IMGFMT_RGBA
)
1189 if (p
->use_yuv
&& mp_get_chroma_shift(format
, NULL
, NULL
, &depth
) &&
1190 (depth
== 8 || depth
== 16 || glYUVLargeRange(p
->use_yuv
)) &&
1191 (IMGFMT_IS_YUVP16_NE(format
) || !IMGFMT_IS_YUVP16(format
)))
1193 // HACK, otherwise we get only b&w with some filters (e.g. -vf eq)
1194 // ideally MPlayer should be fixed instead not to use Y800 when it has the choice
1195 if (!p
->use_yuv
&& (format
== IMGFMT_Y8
|| format
== IMGFMT_Y800
))
1197 if (!p
->use_ycbcr
&& (format
== IMGFMT_UYVY
|| format
== IMGFMT_YVYU
))
1200 glFindFormat(format
, p
->have_texture_rg
, NULL
, NULL
, NULL
, NULL
))
1205 static void uninit(struct vo
*vo
)
1207 struct gl_priv
*p
= vo
->priv
;
1211 free(p
->custom_prog
);
1212 p
->custom_prog
= NULL
;
1213 free(p
->custom_tex
);
1214 p
->custom_tex
= NULL
;
1215 uninit_mpglcontext(p
->glctx
);
1220 static int preinit_internal(struct vo
*vo
, const char *arg
, int allow_sw
,
1221 enum MPGLType gltype
)
1223 struct gl_priv
*p
= talloc_zero(vo
, struct gl_priv
);
1226 *p
= (struct gl_priv
) {
1230 .colorspace
= MP_CSP_DETAILS_DEFAULTS
,
1231 .filter_strength
= 0.5,
1232 .use_rectangle
= -1,
1236 .custom_prog
= NULL
,
1239 .osd_color
= 0xffffff,
1242 //essentially unused; for legacy warnings only
1243 int user_colorspace
= 0;
1247 const opt_t subopts
[] = {
1248 {"manyfmts", OPT_ARG_BOOL
, &p
->many_fmts
, NULL
},
1249 {"osd", OPT_ARG_BOOL
, &p
->use_osd
, NULL
},
1250 {"scaled-osd", OPT_ARG_BOOL
, &p
->scaled_osd
, NULL
},
1251 {"ycbcr", OPT_ARG_BOOL
, &p
->use_ycbcr
, NULL
},
1252 {"slice-height", OPT_ARG_INT
, &p
->slice_height
, int_non_neg
},
1253 {"rectangle", OPT_ARG_INT
, &p
->use_rectangle
,int_non_neg
},
1254 {"yuv", OPT_ARG_INT
, &p
->use_yuv
, int_non_neg
},
1255 {"lscale", OPT_ARG_INT
, &p
->lscale
, int_non_neg
},
1256 {"cscale", OPT_ARG_INT
, &p
->cscale
, int_non_neg
},
1257 {"filter-strength", OPT_ARG_FLOAT
, &p
->filter_strength
, NULL
},
1258 {"ati-hack", OPT_ARG_BOOL
, &p
->ati_hack
, NULL
},
1259 {"force-pbo", OPT_ARG_BOOL
, &p
->force_pbo
, NULL
},
1260 {"glfinish", OPT_ARG_BOOL
, &p
->use_glFinish
, NULL
},
1261 {"swapinterval", OPT_ARG_INT
, &p
->swap_interval
,NULL
},
1262 {"customprog", OPT_ARG_MSTRZ
,&p
->custom_prog
, NULL
},
1263 {"customtex", OPT_ARG_MSTRZ
,&p
->custom_tex
, NULL
},
1264 {"customtlin", OPT_ARG_BOOL
, &p
->custom_tlin
, NULL
},
1265 {"customtrect", OPT_ARG_BOOL
, &p
->custom_trect
, NULL
},
1266 {"mipmapgen", OPT_ARG_BOOL
, &p
->mipmap_gen
, NULL
},
1267 {"osdcolor", OPT_ARG_INT
, &p
->osd_color
, NULL
},
1268 {"stereo", OPT_ARG_INT
, &p
->stereo_mode
, NULL
},
1270 // They are only parsed to notify the user about the replacements.
1271 {"aspect", OPT_ARG_BOOL
, &aspect
, NULL
},
1272 {"colorspace", OPT_ARG_INT
, &user_colorspace
, NULL
},
1273 {"levelconv", OPT_ARG_INT
, &levelconv
, NULL
},
1277 if (subopt_parse(arg
, subopts
) != 0) {
1278 mp_msg(MSGT_VO
, MSGL_FATAL
,
1279 "\n-vo gl command line help:\n"
1280 "Example: mplayer -vo gl:slice-height=4\n"
1283 " Disable extended color formats for OpenGL 1.2 and later\n"
1284 " slice-height=<0-...>\n"
1285 " Slice size for texture transfer, 0 for whole image\n"
1287 " Do not use OpenGL OSD code\n"
1289 " Render OSD at movie resolution and scale it\n"
1290 " rectangle=<0,1,2>\n"
1291 " 0: use power-of-two textures\n"
1292 " 1: use texture_rectangle\n"
1293 " 2: use texture_non_power_of_two\n"
1295 " Workaround ATI bug with PBOs\n"
1297 " Force use of PBO even if this involves an extra memcpy\n"
1299 " Call glFinish() before swapping buffers\n"
1300 " swapinterval=<n>\n"
1301 " Interval in displayed frames between to buffer swaps.\n"
1302 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
1303 " Requires GLX_SGI_swap_control support to work.\n"
1305 " also try to use the GL_MESA_ycbcr_texture extension\n"
1307 " 0: use software YUV to RGB conversion.\n"
1308 " 1: deprecated, will use yuv=2 (used to be nVidia register combiners).\n"
1309 " 2: use fragment program.\n"
1310 " 3: use fragment program with gamma correction.\n"
1311 " 4: use fragment program with gamma correction via lookup.\n"
1312 " 5: use ATI-specific method (for older cards).\n"
1313 " 6: use lookup via 3D texture.\n"
1315 " 0: use standard bilinear scaling for luma.\n"
1316 " 1: use improved bicubic scaling for luma.\n"
1317 " 2: use cubic in X, linear in Y direction scaling for luma.\n"
1318 " 3: as 1 but without using a lookup texture.\n"
1319 " 4: experimental unsharp masking (sharpening).\n"
1320 " 5: experimental unsharp masking (sharpening) with larger radius.\n"
1322 " as lscale but for chroma (2x slower with little visible effect).\n"
1323 " filter-strength=<value>\n"
1324 " set the effect strength for some lscale/cscale filters\n"
1325 " customprog=<filename>\n"
1326 " use a custom YUV conversion program\n"
1327 " customtex=<filename>\n"
1328 " use a custom YUV conversion lookup texture\n"
1330 " use GL_NEAREST scaling for customtex texture\n"
1332 " use texture_rectangle for customtex texture\n"
1334 " generate mipmaps for the video image (use with TXB in customprog)\n"
1335 " osdcolor=<0xAARRGGBB>\n"
1336 " use the given color for the OSD\n"
1338 " 0: normal display\n"
1339 " 1: side-by-side to red-cyan stereo\n"
1340 " 2: side-by-side to green-magenta stereo\n"
1341 " 3: side-by-side to quadbuffer stereo\n"
1345 if (user_colorspace
!= 0 || levelconv
!= -1) {
1346 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"colorspace\" and \"levelconv\" "
1347 "suboptions have been removed. Use options --colormatrix and"
1348 " --colormatrix-input-range/--colormatrix-output-range instead.\n");
1352 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"noaspect\" suboption has been "
1353 "removed. Use --noaspect instead.\n");
1356 if (p
->use_yuv
== 1) {
1357 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] yuv=1 (nVidia register combiners) have"
1358 " been removed, using yuv=2 instead.\n");
1361 p
->glctx
= init_mpglcontext(gltype
, vo
);
1364 p
->gl
= p
->glctx
->gl
;
1366 if (p
->glctx
->type
== GLTYPE_SDL
&& p
->use_yuv
== -1) {
1367 // Apparently it's not possible to implement VOFLAG_HIDDEN on SDL 1.2,
1368 // so don't do autodetection. Use a sufficiently useful and safe YUV
1370 p
->use_yuv
= YUV_CONVERSION_FRAGMENT
;
1373 if (p
->use_yuv
== -1 || !allow_sw
) {
1374 if (create_window(vo
, 320, 200, VOFLAG_HIDDEN
) < 0)
1376 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
1378 if (!allow_sw
&& isSoftwareGl(vo
))
1380 autodetectGlExtensions(vo
);
1381 // We created a window to test whether the GL context supports hardware
1382 // acceleration and so on. Destroy that window to make sure all state
1383 // associated with it is lost.
1385 p
->glctx
= init_mpglcontext(gltype
, vo
);
1388 p
->gl
= p
->glctx
->gl
;
1391 mp_msg(MSGT_VO
, MSGL_INFO
, "[gl] using extended formats. "
1392 "Use -vo gl:nomanyfmts if playback fails.\n");
1393 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Using %d as slice height "
1394 "(0 means image height).\n", p
->slice_height
);
1403 static int preinit(struct vo
*vo
, const char *arg
)
1405 return preinit_internal(vo
, arg
, 1, GLTYPE_AUTO
);
1408 static int control(struct vo
*vo
, uint32_t request
, void *data
)
1410 struct gl_priv
*p
= vo
->priv
;
1413 case VOCTRL_QUERY_FORMAT
:
1414 return query_format(vo
, *(uint32_t *)data
);
1415 case VOCTRL_GET_IMAGE
:
1416 return get_image(vo
, data
);
1417 case VOCTRL_DRAW_IMAGE
:
1418 return draw_image(vo
, data
);
1419 case VOCTRL_DRAW_EOSD
:
1423 if (vo_doublebuffering
)
1424 do_render_osd(vo
, RENDER_EOSD
);
1426 case VOCTRL_GET_EOSD_RES
: {
1427 mp_eosd_res_t
*r
= data
;
1430 r
->mt
= r
->mb
= r
->ml
= r
->mr
= 0;
1431 if (p
->scaled_osd
) {
1432 r
->w
= p
->image_width
;
1433 r
->h
= p
->image_height
;
1434 } else if (aspect_scaling()) {
1435 r
->ml
= r
->mr
= p
->ass_border_x
;
1436 r
->mt
= r
->mb
= p
->ass_border_y
;
1441 if (!p
->glctx
->ontop
)
1443 p
->glctx
->ontop(vo
);
1445 case VOCTRL_FULLSCREEN
:
1446 p
->glctx
->fullscreen(vo
);
1447 resize(vo
, vo
->dwidth
, vo
->dheight
);
1450 if (!p
->glctx
->border
)
1452 p
->glctx
->border(vo
);
1453 resize(vo
, vo
->dwidth
, vo
->dheight
);
1455 case VOCTRL_GET_PANSCAN
:
1457 case VOCTRL_SET_PANSCAN
:
1458 resize(vo
, vo
->dwidth
, vo
->dheight
);
1460 case VOCTRL_GET_EQUALIZER
:
1462 struct voctrl_get_equalizer_args
*args
= data
;
1463 return mp_csp_equalizer_get(&p
->video_eq
, args
->name
, args
->valueptr
)
1464 >= 0 ? VO_TRUE
: VO_NOTIMPL
;
1467 case VOCTRL_SET_EQUALIZER
:
1469 struct voctrl_set_equalizer_args
*args
= data
;
1470 if (mp_csp_equalizer_set(&p
->video_eq
, args
->name
, args
->value
) < 0)
1473 vo
->want_redraw
= true;
1477 case VOCTRL_SET_YUV_COLORSPACE
: {
1478 bool supports_csp
= (1 << p
->use_yuv
) & MASK_NOT_COMBINERS
;
1479 if (vo
->config_count
&& supports_csp
) {
1480 p
->colorspace
= *(struct mp_csp_details
*)data
;
1482 vo
->want_redraw
= true;
1486 case VOCTRL_GET_YUV_COLORSPACE
:
1487 *(struct mp_csp_details
*)data
= p
->colorspace
;
1489 case VOCTRL_UPDATE_SCREENINFO
:
1490 if (!p
->glctx
->update_xinerama_info
)
1492 p
->glctx
->update_xinerama_info(vo
);
1494 case VOCTRL_REDRAW_FRAME
:
1495 if (vo_doublebuffering
)
1498 case VOCTRL_SCREENSHOT
: {
1499 struct voctrl_screenshot_args
*args
= data
;
1500 if (args
->full_window
)
1501 args
->out_image
= get_window_screenshot(vo
);
1503 args
->out_image
= get_screenshot(vo
);
1510 const struct vo_driver video_out_gl
= {
1512 .info
= &(const vo_info_t
) {
1515 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1521 .draw_slice
= draw_slice
,
1522 .draw_osd
= draw_osd
,
1523 .flip_page
= flip_page
,
1524 .check_events
= check_events
,
1528 static int preinit_nosw(struct vo
*vo
, const char *arg
)
1530 return preinit_internal(vo
, arg
, 0, GLTYPE_AUTO
);
1533 const struct vo_driver video_out_gl_nosw
=
1536 .info
= &(const vo_info_t
) {
1537 "OpenGL no software rendering",
1539 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1542 .preinit
= preinit_nosw
,
1545 .draw_slice
= draw_slice
,
1546 .draw_osd
= draw_osd
,
1547 .flip_page
= flip_page
,
1548 .check_events
= check_events
,
1552 #ifdef CONFIG_GL_SDL
1553 static int preinit_sdl(struct vo
*vo
, const char *arg
)
1555 return preinit_internal(vo
, arg
, 1, GLTYPE_SDL
);
1558 const struct vo_driver video_out_gl_sdl
= {
1560 .info
= &(const vo_info_t
) {
1563 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1566 .preinit
= preinit_sdl
,
1569 .draw_slice
= draw_slice
,
1570 .draw_osd
= draw_osd
,
1571 .flip_page
= flip_page
,
1572 .check_events
= check_events
,