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];
132 struct mp_csp_equalizer video_eq
;
138 int ass_border_x
, ass_border_y
;
140 unsigned int slice_height
;
143 static void redraw(struct vo
*vo
);
145 static void resize(struct vo
*vo
, int x
, int y
)
147 struct gl_priv
*p
= vo
->priv
;
150 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Resize: %dx%d\n", x
, y
);
152 int left
= 0, top
= 0, w
= x
, h
= y
;
153 geometry(&left
, &top
, &w
, &h
, vo
->dwidth
, vo
->dheight
);
155 gl
->Viewport(left
, top
, w
, h
);
157 gl
->Viewport(0, 0, x
, y
);
159 gl
->MatrixMode(GL_PROJECTION
);
161 p
->ass_border_x
= p
->ass_border_y
= 0;
162 if (aspect_scaling()) {
164 GLdouble scale_x
, scale_y
;
165 aspect(vo
, &new_w
, &new_h
, A_WINZOOM
);
166 panscan_calc_windowed(vo
);
167 new_w
+= vo
->panscan_x
;
168 new_h
+= vo
->panscan_y
;
169 scale_x
= (GLdouble
)new_w
/ (GLdouble
)x
;
170 scale_y
= (GLdouble
)new_h
/ (GLdouble
)y
;
171 gl
->Scaled(scale_x
, scale_y
, 1);
172 p
->ass_border_x
= (vo
->dwidth
- new_w
) / 2;
173 p
->ass_border_y
= (vo
->dheight
- new_h
) / 2;
175 gl
->Ortho(0, p
->image_width
, p
->image_height
, 0, -1, 1);
177 gl
->MatrixMode(GL_MODELVIEW
);
180 if (!p
->scaled_osd
) {
181 #ifdef CONFIG_FREETYPE
182 // adjust font size to display size
185 vo_osd_changed(OSDTYPE_OSD
);
187 gl
->Clear(GL_COLOR_BUFFER_BIT
);
191 static void texSize(struct vo
*vo
, int w
, int h
, int *texw
, int *texh
)
193 struct gl_priv
*p
= vo
->priv
;
195 if (p
->use_rectangle
) {
207 *texw
= (*texw
+ 511) & ~511;
210 //! maximum size of custom fragment program
211 #define MAX_CUSTOM_PROG_SIZE (1024 * 1024)
212 static void update_yuvconv(struct vo
*vo
)
214 struct gl_priv
*p
= vo
->priv
;
218 struct mp_csp_params cparams
= { .colorspace
= p
->colorspace
};
219 mp_csp_copy_equalizer_values(&cparams
, &p
->video_eq
);
220 gl_conversion_params_t params
= {
221 p
->target
, p
->yuvconvtype
, cparams
,
222 p
->texture_width
, p
->texture_height
, 0, 0, p
->filter_strength
224 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &depth
);
225 params
.chrom_texw
= params
.texw
>> xs
;
226 params
.chrom_texh
= params
.texh
>> ys
;
227 params
.csp_params
.input_shift
= -depth
& 7;
228 glSetupYUVConversion(gl
, ¶ms
);
229 if (p
->custom_prog
) {
230 FILE *f
= fopen(p
->custom_prog
, "rb");
232 mp_msg(MSGT_VO
, MSGL_WARN
,
233 "[gl] Could not read customprog %s\n", p
->custom_prog
);
235 char *prog
= calloc(1, MAX_CUSTOM_PROG_SIZE
+ 1);
236 fread(prog
, 1, MAX_CUSTOM_PROG_SIZE
, f
);
238 loadGPUProgram(gl
, GL_FRAGMENT_PROGRAM
, prog
);
241 gl
->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 0,
242 1.0 / p
->texture_width
,
243 1.0 / p
->texture_height
,
244 p
->texture_width
, p
->texture_height
);
247 FILE *f
= fopen(p
->custom_tex
, "rb");
249 mp_msg(MSGT_VO
, MSGL_WARN
,
250 "[gl] Could not read customtex %s\n", p
->custom_tex
);
252 int width
, height
, maxval
;
253 gl
->ActiveTexture(GL_TEXTURE3
);
254 if (glCreatePPMTex(gl
, p
->custom_trect
? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
,
255 0, p
->custom_tlin
? GL_LINEAR
: GL_NEAREST
,
256 f
, &width
, &height
, &maxval
)) {
257 gl
->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 1,
258 1.0 / width
, 1.0 / height
,
261 mp_msg(MSGT_VO
, MSGL_WARN
,
262 "[gl] Error parsing customtex %s\n", p
->custom_tex
);
264 gl
->ActiveTexture(GL_TEXTURE0
);
270 * \brief remove all OSD textures and display-lists, thus clearing it.
272 static void clearOSD(struct vo
*vo
)
274 struct gl_priv
*p
= vo
->priv
;
280 gl
->DeleteTextures(p
->osdtexCnt
, p
->osdtex
);
282 gl
->DeleteTextures(p
->osdtexCnt
, p
->osdatex
);
283 for (i
= 0; i
< p
->osdtexCnt
; i
++)
284 gl
->DeleteLists(p
->osdaDispList
[i
], 1);
286 for (i
= 0; i
< p
->osdtexCnt
; i
++)
287 gl
->DeleteLists(p
->osdDispList
[i
], 1);
292 * \brief remove textures, display list and free memory used by EOSD
294 static void clearEOSD(struct vo
*vo
)
296 struct gl_priv
*p
= vo
->priv
;
300 gl
->DeleteLists(p
->eosdDispList
, 1);
303 gl
->DeleteTextures(p
->eosdtexCnt
, p
->eosdtex
);
309 static inline int is_tinytex(ASS_Image
*i
, int tinytexcur
)
311 return i
->w
< TINYTEX_SIZE
&& i
->h
< TINYTEX_SIZE
312 && tinytexcur
< TINYTEX_MAX
;
315 static inline int is_smalltex(ASS_Image
*i
, int smalltexcur
)
317 return i
->w
< SMALLTEX_SIZE
&& i
->h
< SMALLTEX_SIZE
318 && smalltexcur
< SMALLTEX_MAX
;
321 static inline void tinytex_pos(int tinytexcur
, int *x
, int *y
)
323 *x
= (tinytexcur
% TINYTEX_COLS
) * TINYTEX_SIZE
;
324 *y
= (tinytexcur
/ TINYTEX_COLS
) * TINYTEX_SIZE
;
327 static inline void smalltex_pos(int smalltexcur
, int *x
, int *y
)
329 *x
= (smalltexcur
% SMALLTEX_COLS
) * SMALLTEX_SIZE
;
330 *y
= (smalltexcur
/ SMALLTEX_COLS
) * SMALLTEX_SIZE
;
334 * \brief construct display list from ass image list
335 * \param img image list to create OSD from.
336 * A value of NULL has the same effect as clearEOSD()
338 static void genEOSD(struct vo
*vo
, mp_eosd_images_t
*imgs
)
340 struct gl_priv
*p
= vo
->priv
;
347 GLint scale_type
= p
->scaled_osd
? GL_LINEAR
: GL_NEAREST
;
348 ASS_Image
*img
= imgs
->imgs
;
351 if (imgs
->changed
== 0) // there are elements, but they are unchanged
353 if (img
&& imgs
->changed
== 1) // there are elements, but they just moved
359 if (!p
->largeeosdtex
[0]) {
360 gl
->GenTextures(2, p
->largeeosdtex
);
361 for (int n
= 0; n
< 2; n
++) {
362 gl
->BindTexture(p
->target
, p
->largeeosdtex
[n
]);
363 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
,
364 GL_UNSIGNED_BYTE
, scale_type
,
365 LARGE_EOSD_TEX_SIZE
, LARGE_EOSD_TEX_SIZE
, 0);
368 for (i
= img
; i
; i
= i
->next
) {
369 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
)
371 if (is_tinytex(i
, tinytexcur
))
373 else if (is_smalltex(i
, smalltexcur
))
378 mp_msg(MSGT_VO
, MSGL_DBG2
, "EOSD counts (tiny, small, all): %i, %i, %i\n",
379 tinytexcur
, smalltexcur
, p
->eosdtexCnt
);
381 p
->eosdtex
= calloc(p
->eosdtexCnt
, sizeof(GLuint
));
382 gl
->GenTextures(p
->eosdtexCnt
, p
->eosdtex
);
384 tinytexcur
= smalltexcur
= 0;
385 for (i
= img
, curtex
= p
->eosdtex
; i
; i
= i
->next
) {
387 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
) {
388 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
391 if (is_tinytex(i
, tinytexcur
)) {
392 tinytex_pos(tinytexcur
, &x
, &y
);
393 gl
->BindTexture(p
->target
, p
->largeeosdtex
[0]);
395 } else if (is_smalltex(i
, smalltexcur
)) {
396 smalltex_pos(smalltexcur
, &x
, &y
);
397 gl
->BindTexture(p
->target
, p
->largeeosdtex
[1]);
400 texSize(vo
, i
->w
, i
->h
, &sx
, &sy
);
401 gl
->BindTexture(p
->target
, *curtex
++);
402 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
,
403 GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
405 glUploadTex(gl
, p
->target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, i
->bitmap
,
406 i
->stride
, x
, y
, i
->w
, i
->h
, 0);
408 p
->eosdDispList
= gl
->GenLists(1);
410 gl
->NewList(p
->eosdDispList
, GL_COMPILE
);
411 tinytexcur
= smalltexcur
= 0;
412 for (i
= img
, curtex
= p
->eosdtex
; i
; i
= i
->next
) {
414 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
)
416 gl
->Color4ub(i
->color
>> 24, (i
->color
>> 16) & 0xff,
417 (i
->color
>> 8) & 0xff, 255 - (i
->color
& 0xff));
418 if (is_tinytex(i
, tinytexcur
)) {
419 tinytex_pos(tinytexcur
, &x
, &y
);
420 sx
= sy
= LARGE_EOSD_TEX_SIZE
;
421 gl
->BindTexture(p
->target
, p
->largeeosdtex
[0]);
423 } else if (is_smalltex(i
, smalltexcur
)) {
424 smalltex_pos(smalltexcur
, &x
, &y
);
425 sx
= sy
= LARGE_EOSD_TEX_SIZE
;
426 gl
->BindTexture(p
->target
, p
->largeeosdtex
[1]);
429 texSize(vo
, i
->w
, i
->h
, &sx
, &sy
);
430 gl
->BindTexture(p
->target
, *curtex
++);
432 glDrawTex(gl
, i
->dst_x
, i
->dst_y
, i
->w
, i
->h
, x
, y
, i
->w
, i
->h
, sx
, sy
,
433 p
->use_rectangle
== 1, 0, 0);
436 gl
->BindTexture(p
->target
, 0);
440 * \brief uninitialize OpenGL context, freeing textures, buffers etc.
442 static void uninitGl(struct vo
*vo
)
444 struct gl_priv
*p
= vo
->priv
;
448 if (gl
->DeletePrograms
&& p
->fragprog
)
449 gl
->DeletePrograms(1, &p
->fragprog
);
451 while (p
->default_texs
[i
] != 0)
454 gl
->DeleteTextures(i
, p
->default_texs
);
455 p
->default_texs
[0] = 0;
458 if (p
->largeeosdtex
[0])
459 gl
->DeleteTextures(2, p
->largeeosdtex
);
460 p
->largeeosdtex
[0] = 0;
461 if (gl
->DeleteBuffers
&& p
->buffer
)
462 gl
->DeleteBuffers(1, &p
->buffer
);
466 if (gl
->DeleteBuffers
&& p
->buffer_uv
[0])
467 gl
->DeleteBuffers(2, p
->buffer_uv
);
468 p
->buffer_uv
[0] = p
->buffer_uv
[1] = 0;
469 p
->buffersize_uv
= 0;
470 p
->bufferptr_uv
[0] = p
->bufferptr_uv
[1] = 0;
474 static int isSoftwareGl(struct vo
*vo
)
476 struct gl_priv
*p
= vo
->priv
;
477 const char *renderer
= p
->gl
->GetString(GL_RENDERER
);
478 return !renderer
|| strcmp(renderer
, "Software Rasterizer") == 0 ||
479 strstr(renderer
, "llvmpipe");
482 static void autodetectGlExtensions(struct vo
*vo
)
484 struct gl_priv
*p
= vo
->priv
;
487 const char *extensions
= gl
->GetString(GL_EXTENSIONS
);
488 const char *vendor
= gl
->GetString(GL_VENDOR
);
489 const char *version
= gl
->GetString(GL_VERSION
);
490 const char *renderer
= gl
->GetString(GL_RENDERER
);
491 int is_ati
= vendor
&& strstr(vendor
, "ATI") != NULL
;
492 int ati_broken_pbo
= 0;
493 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Running on OpenGL '%s' by '%s', version '%s'\n",
494 renderer
, vendor
, version
);
495 if (is_ati
&& strncmp(version
, "2.1.", 4) == 0) {
496 int ver
= atoi(version
+ 4);
497 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Detected ATI driver version: %i\n", ver
);
498 ati_broken_pbo
= ver
&& ver
< 8395;
500 if (p
->ati_hack
== -1)
501 p
->ati_hack
= ati_broken_pbo
;
502 if (p
->force_pbo
== -1) {
504 if (extensions
&& strstr(extensions
, "_pixel_buffer_object"))
505 p
->force_pbo
= is_ati
;
507 p
->have_texture_rg
= extensions
&& strstr(extensions
, "GL_ARB_texture_rg");
508 if (p
->use_rectangle
== -1) {
509 p
->use_rectangle
= 0;
511 // if (strstr(extensions, "_texture_non_power_of_two"))
512 if (strstr(extensions
, "_texture_rectangle"))
513 p
->use_rectangle
= renderer
514 && strstr(renderer
, "Mesa DRI R200") ? 1 : 0;
517 if (p
->use_osd
== -1)
518 p
->use_osd
= gl
->BindTexture
!= NULL
;
519 if (p
->use_yuv
== -1)
520 p
->use_yuv
= glAutodetectYUVConversion(gl
);
523 int yuv_mask
= (1 << p
->use_yuv
);
524 if (!(yuv_mask
& MASK_NOT_COMBINERS
)) {
526 eq_caps
= (1 << MP_CSP_EQ_HUE
) | (1 << MP_CSP_EQ_SATURATION
);
527 } else if (yuv_mask
& MASK_ALL_YUV
) {
528 eq_caps
= MP_CSP_EQ_CAPS_COLORMATRIX
;
529 if (yuv_mask
& MASK_GAMMA_SUPPORT
)
530 eq_caps
|= MP_CSP_EQ_CAPS_GAMMA
;
532 p
->video_eq
.capabilities
= eq_caps
;
534 if (is_ati
&& (p
->lscale
== 1 || p
->lscale
== 2 || p
->cscale
== 1 || p
->cscale
== 2))
535 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] Selected scaling mode may be broken on"
537 "Tell _them_ to fix GL_REPEAT if you have issues.\n");
538 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Settings after autodetection: ati-hack = %i, "
539 "force-pbo = %i, rectangle = %i, yuv = %i\n",
540 p
->ati_hack
, p
->force_pbo
, p
->use_rectangle
, p
->use_yuv
);
543 static GLint
get_scale_type(struct vo
*vo
, int chroma
)
545 struct gl_priv
*p
= vo
->priv
;
547 int nearest
= (chroma
? p
->cscale
: p
->lscale
) & 64;
549 return p
->mipmap_gen
? GL_NEAREST_MIPMAP_NEAREST
: GL_NEAREST
;
550 return p
->mipmap_gen
? GL_LINEAR_MIPMAP_NEAREST
: GL_LINEAR
;
553 // Return the high byte of the value that represents white in chroma (U/V)
554 static int get_chroma_clear_val(int bit_depth
)
556 return 1 << (bit_depth
- 1 & 7);
560 * \brief Initialize a (new or reused) OpenGL context.
561 * set global gl-related variables to their default values
563 static int initGl(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
)
565 struct gl_priv
*p
= vo
->priv
;
568 GLint scale_type
= get_scale_type(vo
, 0);
569 autodetectGlExtensions(vo
);
570 p
->target
= p
->use_rectangle
== 1 ? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
;
571 p
->yuvconvtype
= SET_YUV_CONVERSION(p
->use_yuv
) |
572 SET_YUV_LUM_SCALER(p
->lscale
) |
573 SET_YUV_CHROM_SCALER(p
->cscale
);
575 texSize(vo
, p
->image_width
, p
->image_height
,
576 &p
->texture_width
, &p
->texture_height
);
578 gl
->Disable(GL_BLEND
);
579 gl
->Disable(GL_DEPTH_TEST
);
580 gl
->DepthMask(GL_FALSE
);
581 gl
->Disable(GL_CULL_FACE
);
582 gl
->Enable(p
->target
);
583 gl
->DrawBuffer(vo_doublebuffering
? GL_BACK
: GL_FRONT
);
584 gl
->TexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
586 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Creating %dx%d texture...\n",
587 p
->texture_width
, p
->texture_height
);
589 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
590 p
->gl_type
, scale_type
,
591 p
->texture_width
, p
->texture_height
, 0);
594 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
599 scale_type
= get_scale_type(vo
, 1);
600 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &depth
);
601 int clear
= get_chroma_clear_val(depth
);
602 gl
->GenTextures(21, p
->default_texs
);
603 p
->default_texs
[21] = 0;
604 for (i
= 0; i
< 7; i
++) {
605 gl
->ActiveTexture(GL_TEXTURE1
+ i
);
606 gl
->BindTexture(GL_TEXTURE_2D
, p
->default_texs
[i
]);
607 gl
->BindTexture(GL_TEXTURE_RECTANGLE
, p
->default_texs
[i
+ 7]);
608 gl
->BindTexture(GL_TEXTURE_3D
, p
->default_texs
[i
+ 14]);
610 gl
->ActiveTexture(GL_TEXTURE1
);
611 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
612 p
->gl_type
, scale_type
,
613 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
616 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
617 gl
->ActiveTexture(GL_TEXTURE2
);
618 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
619 p
->gl_type
, scale_type
,
620 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
623 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
624 gl
->ActiveTexture(GL_TEXTURE0
);
625 gl
->BindTexture(p
->target
, 0);
627 if (p
->is_yuv
|| p
->custom_prog
) {
628 if ((MASK_NOT_COMBINERS
& (1 << p
->use_yuv
)) || p
->custom_prog
) {
629 if (!gl
->GenPrograms
|| !gl
->BindProgram
)
630 mp_msg(MSGT_VO
, MSGL_ERR
,
631 "[gl] fragment program functions missing!\n");
633 gl
->GenPrograms(1, &p
->fragprog
);
634 gl
->BindProgram(GL_FRAGMENT_PROGRAM
, p
->fragprog
);
640 resize(vo
, d_width
, d_height
);
642 gl
->ClearColor(0.0f
, 0.0f
, 0.0f
, 0.0f
);
643 gl
->Clear(GL_COLOR_BUFFER_BIT
);
644 if (gl
->SwapInterval
&& p
->swap_interval
>= 0)
645 gl
->SwapInterval(p
->swap_interval
);
649 static int create_window(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
,
652 struct gl_priv
*p
= vo
->priv
;
654 if (p
->stereo_mode
== GL_3D_QUADBUFFER
)
655 flags
|= VOFLAG_STEREO
;
657 return p
->glctx
->create_window(p
->glctx
, d_width
, d_height
, flags
);
660 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
661 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
664 struct gl_priv
*p
= vo
->priv
;
667 p
->image_height
= height
;
668 p
->image_width
= width
;
669 p
->image_format
= format
;
670 p
->image_d_width
= d_width
;
671 p
->image_d_height
= d_height
;
672 p
->is_yuv
= mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
) > 0;
673 p
->is_yuv
|= (xs
<< 8) | (ys
<< 16);
674 glFindFormat(format
, p
->have_texture_rg
, NULL
, &p
->texfmt
, &p
->gl_format
,
677 p
->vo_flipped
= !!(flags
& VOFLAG_FLIPPING
);
679 if (create_window(vo
, d_width
, d_height
, flags
) < 0)
682 if (vo
->config_count
)
684 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
686 initGl(vo
, vo
->dwidth
, vo
->dheight
);
691 static void check_events(struct vo
*vo
)
693 struct gl_priv
*p
= vo
->priv
;
695 int e
= p
->glctx
->check_events(vo
);
696 if (e
& VO_EVENT_REINIT
) {
698 initGl(vo
, vo
->dwidth
, vo
->dheight
);
700 if (e
& VO_EVENT_RESIZE
)
701 resize(vo
, vo
->dwidth
, vo
->dheight
);
702 if (e
& VO_EVENT_EXPOSE
&& p
->int_pause
)
707 * Creates the textures and the display list needed for displaying
709 * Callback function for osd_draw_text_ext().
711 static void create_osd_texture(void *ctx
, int x0
, int y0
, int w
, int h
,
712 unsigned char *src
, unsigned char *srca
,
716 struct gl_priv
*p
= vo
->priv
;
719 // initialize to 8 to avoid special-casing on alignment
721 GLint scale_type
= p
->scaled_osd
? GL_LINEAR
: GL_NEAREST
;
723 if (w
<= 0 || h
<= 0 || stride
< w
) {
724 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
727 texSize(vo
, w
, h
, &sx
, &sy
);
729 if (p
->osdtexCnt
>= MAX_OSD_PARTS
) {
730 mp_msg(MSGT_VO
, MSGL_ERR
, "Too many OSD parts, contact the developers!\n");
734 // create Textures for OSD part
735 gl
->GenTextures(1, &p
->osdtex
[p
->osdtexCnt
]);
736 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
737 glCreateClearTex(gl
, p
->target
, GL_LUMINANCE
, GL_LUMINANCE
,
738 GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
739 glUploadTex(gl
, p
->target
, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, src
, stride
,
743 gl
->GenTextures(1, &p
->osdatex
[p
->osdtexCnt
]);
744 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
745 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
,
746 scale_type
, sx
, sy
, 0);
749 char *tmp
= malloc(stride
* h
);
750 // convert alpha from weird MPlayer scale.
751 // in-place is not possible since it is reused for future OSDs
752 for (i
= h
* stride
- 1; i
>= 0; i
--)
754 glUploadTex(gl
, p
->target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, tmp
, stride
,
760 gl
->BindTexture(p
->target
, 0);
762 // Create a list for rendering this OSD part
764 p
->osdaDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
765 gl
->NewList(p
->osdaDispList
[p
->osdtexCnt
], GL_COMPILE
);
767 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
768 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
771 p
->osdDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
772 gl
->NewList(p
->osdDispList
[p
->osdtexCnt
], GL_COMPILE
);
774 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
775 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
782 #define RENDER_EOSD 2
785 * \param type bit 0: render OSD, bit 1: render EOSD
787 static void do_render_osd(struct vo
*vo
, int type
)
789 struct gl_priv
*p
= vo
->priv
;
792 int draw_osd
= (type
& RENDER_OSD
) && p
->osdtexCnt
> 0;
793 int draw_eosd
= (type
& RENDER_EOSD
) && p
->eosdDispList
;
794 if (!draw_osd
&& !draw_eosd
)
796 // set special rendering parameters
797 if (!p
->scaled_osd
) {
798 gl
->MatrixMode(GL_PROJECTION
);
801 gl
->Ortho(0, vo
->dwidth
, vo
->dheight
, 0, -1, 1);
803 gl
->Enable(GL_BLEND
);
805 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
806 gl
->CallList(p
->eosdDispList
);
809 gl
->Color4ub((p
->osd_color
>> 16) & 0xff, (p
->osd_color
>> 8) & 0xff,
810 p
->osd_color
& 0xff, 0xff - (p
->osd_color
>> 24));
813 gl
->BlendFunc(GL_ZERO
, GL_ONE_MINUS_SRC_ALPHA
);
814 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdaDispList
);
816 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE
);
817 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdDispList
);
819 // set rendering parameters back to defaults
820 gl
->Disable(GL_BLEND
);
823 gl
->BindTexture(p
->target
, 0);
826 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
828 struct gl_priv
*p
= vo
->priv
;
832 if (vo_osd_changed(0)) {
835 osd_w
= p
->scaled_osd
? p
->image_width
: vo
->dwidth
;
836 osd_h
= p
->scaled_osd
? p
->image_height
: vo
->dheight
;
837 osd_draw_text_ext(osd
, osd_w
, osd_h
, p
->ass_border_x
,
838 p
->ass_border_y
, p
->ass_border_x
,
839 p
->ass_border_y
, p
->image_width
,
840 p
->image_height
, create_osd_texture
, vo
);
842 if (vo_doublebuffering
)
843 do_render_osd(vo
, RENDER_OSD
);
846 static void do_render(struct vo
*vo
)
848 struct gl_priv
*p
= vo
->priv
;
851 // Enable(GL_TEXTURE_2D);
852 // BindTexture(GL_TEXTURE_2D, texture_id);
854 gl
->Color3f(1, 1, 1);
855 if (p
->is_yuv
|| p
->custom_prog
)
856 glEnableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
857 if (p
->stereo_mode
) {
858 glEnable3DLeft(gl
, p
->stereo_mode
);
859 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
860 0, 0, p
->image_width
>> 1, p
->image_height
,
861 p
->texture_width
, p
->texture_height
,
862 p
->use_rectangle
== 1, p
->is_yuv
,
863 p
->mpi_flipped
^ p
->vo_flipped
);
864 glEnable3DRight(gl
, p
->stereo_mode
);
865 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
866 p
->image_width
>> 1, 0, p
->image_width
>> 1,
867 p
->image_height
, p
->texture_width
, p
->texture_height
,
868 p
->use_rectangle
== 1, p
->is_yuv
,
869 p
->mpi_flipped
^ p
->vo_flipped
);
870 glDisable3D(gl
, p
->stereo_mode
);
872 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
873 0, 0, p
->image_width
, p
->image_height
,
874 p
->texture_width
, p
->texture_height
,
875 p
->use_rectangle
== 1, p
->is_yuv
,
876 p
->mpi_flipped
^ p
->vo_flipped
);
878 if (p
->is_yuv
|| p
->custom_prog
)
879 glDisableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
882 static void flip_page(struct vo
*vo
)
884 struct gl_priv
*p
= vo
->priv
;
887 if (vo_doublebuffering
) {
890 p
->glctx
->swapGlBuffers(p
->glctx
);
891 if (aspect_scaling())
892 gl
->Clear(GL_COLOR_BUFFER_BIT
);
895 do_render_osd(vo
, RENDER_OSD
| RENDER_EOSD
);
903 static void redraw(struct vo
*vo
)
905 if (vo_doublebuffering
) {
907 do_render_osd(vo
, RENDER_OSD
| RENDER_EOSD
);
912 static int draw_slice(struct vo
*vo
, uint8_t *src
[], int stride
[], int w
, int h
,
915 struct gl_priv
*p
= vo
->priv
;
918 p
->mpi_flipped
= stride
[0] < 0;
919 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[0], stride
[0],
920 x
, y
, w
, h
, p
->slice_height
);
923 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
924 gl
->ActiveTexture(GL_TEXTURE1
);
925 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[1], stride
[1],
926 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
927 gl
->ActiveTexture(GL_TEXTURE2
);
928 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[2], stride
[2],
929 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
930 gl
->ActiveTexture(GL_TEXTURE0
);
935 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
937 struct gl_priv
*p
= vo
->priv
;
941 if (!gl
->GenBuffers
|| !gl
->BindBuffer
|| !gl
->BufferData
|| !gl
->MapBuffer
) {
943 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] extensions missing for dr\n"
944 "Expect a _major_ speed penalty\n");
948 if (mpi
->flags
& MP_IMGFLAG_READABLE
)
950 if (mpi
->type
!= MP_IMGTYPE_STATIC
&& mpi
->type
!= MP_IMGTYPE_TEMP
&&
951 (mpi
->type
!= MP_IMGTYPE_NUMBERED
|| mpi
->number
))
954 mpi
->width
= p
->texture_width
;
955 mpi
->height
= p
->texture_height
;
957 mpi
->stride
[0] = mpi
->width
* mpi
->bpp
/ 8;
958 needed_size
= mpi
->stride
[0] * mpi
->height
;
960 gl
->GenBuffers(1, &p
->buffer
);
961 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
962 if (needed_size
> p
->buffersize
) {
963 p
->buffersize
= needed_size
;
964 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, p
->buffersize
,
965 NULL
, GL_DYNAMIC_DRAW
);
968 p
->bufferptr
= gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_WRITE_ONLY
);
969 mpi
->planes
[0] = p
->bufferptr
;
970 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
971 if (!mpi
->planes
[0]) {
973 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] could not acquire buffer for dr\n"
974 "Expect a _major_ speed penalty\n");
980 int xs
, ys
, component_bits
;
981 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
982 int bp
= (component_bits
+ 7) / 8;
983 mpi
->flags
|= MP_IMGFLAG_COMMON_STRIDE
| MP_IMGFLAG_COMMON_PLANE
;
984 mpi
->stride
[0] = mpi
->width
* bp
;
985 mpi
->planes
[1] = mpi
->planes
[0] + mpi
->stride
[0] * mpi
->height
;
986 mpi
->stride
[1] = (mpi
->width
>> xs
) * bp
;
987 mpi
->planes
[2] = mpi
->planes
[1] + mpi
->stride
[1] * (mpi
->height
>> ys
);
988 mpi
->stride
[2] = (mpi
->width
>> xs
) * bp
;
990 mpi
->flags
&= ~MP_IMGFLAG_COMMON_PLANE
;
991 if (!p
->buffer_uv
[0])
992 gl
->GenBuffers(2, p
->buffer_uv
);
993 int buffer_size
= mpi
->stride
[1] * mpi
->height
;
994 if (buffer_size
> p
->buffersize_uv
) {
995 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
996 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
998 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
999 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
1001 p
->buffersize_uv
= buffer_size
;
1003 if (!p
->bufferptr_uv
[0]) {
1004 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
1005 p
->bufferptr_uv
[0] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
1007 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
1008 p
->bufferptr_uv
[1] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
1011 mpi
->planes
[1] = p
->bufferptr_uv
[0];
1012 mpi
->planes
[2] = p
->bufferptr_uv
[1];
1015 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1019 static void clear_border(struct vo
*vo
, uint8_t *dst
, int start
, int stride
,
1020 int height
, int full_height
, int value
)
1022 int right_border
= stride
- start
;
1023 int bottom_border
= full_height
- height
;
1024 while (height
> 0) {
1025 if (right_border
> 0)
1026 memset(dst
+ start
, value
, right_border
);
1030 if (bottom_border
> 0)
1031 memset(dst
, value
, stride
* bottom_border
);
1034 static uint32_t draw_image(struct vo
*vo
, mp_image_t
*mpi
)
1036 struct gl_priv
*p
= vo
->priv
;
1039 int slice
= p
->slice_height
;
1041 unsigned char *planes
[3];
1042 mp_image_t mpi2
= *mpi
;
1043 int w
= mpi
->w
, h
= mpi
->h
;
1044 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
1047 mpi2
.type
= MP_IMGTYPE_TEMP
;
1048 mpi2
.width
= mpi2
.w
;
1049 mpi2
.height
= mpi2
.h
;
1050 if (p
->force_pbo
&& !(mpi
->flags
& MP_IMGFLAG_DIRECT
) && !p
->bufferptr
1051 && get_image(vo
, &mpi2
) == VO_TRUE
)
1053 int bp
= mpi
->bpp
/ 8;
1054 int xs
, ys
, component_bits
;
1055 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
1057 bp
= (component_bits
+ 7) / 8;
1058 memcpy_pic(mpi2
.planes
[0], mpi
->planes
[0], mpi
->w
* bp
, mpi
->h
,
1059 mpi2
.stride
[0], mpi
->stride
[0]);
1060 int uv_bytes
= (mpi
->w
>> xs
) * bp
;
1062 memcpy_pic(mpi2
.planes
[1], mpi
->planes
[1], uv_bytes
, mpi
->h
>> ys
,
1063 mpi2
.stride
[1], mpi
->stride
[1]);
1064 memcpy_pic(mpi2
.planes
[2], mpi
->planes
[2], uv_bytes
, mpi
->h
>> ys
,
1065 mpi2
.stride
[2], mpi
->stride
[2]);
1068 // since we have to do a full upload we need to clear the borders
1069 clear_border(vo
, mpi2
.planes
[0], mpi
->w
* bp
, mpi2
.stride
[0],
1070 mpi
->h
, mpi2
.height
, 0);
1072 int clear
= get_chroma_clear_val(component_bits
);
1073 clear_border(vo
, mpi2
.planes
[1], uv_bytes
, mpi2
.stride
[1],
1074 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1075 clear_border(vo
, mpi2
.planes
[2], uv_bytes
, mpi2
.stride
[2],
1076 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1081 stride
[0] = mpi
->stride
[0];
1082 stride
[1] = mpi
->stride
[1];
1083 stride
[2] = mpi
->stride
[2];
1084 planes
[0] = mpi
->planes
[0];
1085 planes
[1] = mpi
->planes
[1];
1086 planes
[2] = mpi
->planes
[2];
1087 p
->mpi_flipped
= stride
[0] < 0;
1088 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1089 intptr_t base
= (intptr_t)planes
[0];
1091 w
= p
->texture_width
;
1092 h
= p
->texture_height
;
1095 base
+= (mpi
->h
- 1) * stride
[0];
1099 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
1100 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1101 p
->bufferptr
= NULL
;
1102 if (!(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
))
1103 planes
[0] = planes
[1] = planes
[2] = NULL
;
1104 slice
= 0; // always "upload" full texture
1106 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[0],
1107 stride
[0], mpi
->x
, mpi
->y
, w
, h
, slice
);
1110 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
1111 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1112 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
1113 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1114 p
->bufferptr_uv
[0] = NULL
;
1116 gl
->ActiveTexture(GL_TEXTURE1
);
1117 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[1],
1118 stride
[1], mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
,
1120 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1121 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
1122 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1123 p
->bufferptr_uv
[1] = NULL
;
1125 gl
->ActiveTexture(GL_TEXTURE2
);
1126 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[2],
1127 stride
[2], mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
,
1129 gl
->ActiveTexture(GL_TEXTURE0
);
1131 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1132 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1135 if (vo_doublebuffering
)
1140 static mp_image_t
*get_screenshot(struct vo
*vo
)
1142 struct gl_priv
*p
= vo
->priv
;
1145 mp_image_t
*image
= alloc_mpi(p
->texture_width
, p
->texture_height
,
1148 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[0],
1152 gl
->ActiveTexture(GL_TEXTURE1
);
1153 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[1],
1155 gl
->ActiveTexture(GL_TEXTURE2
);
1156 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[2],
1158 gl
->ActiveTexture(GL_TEXTURE0
);
1161 image
->width
= p
->image_width
;
1162 image
->height
= p
->image_height
;
1164 image
->w
= p
->image_d_width
;
1165 image
->h
= p
->image_d_height
;
1170 static mp_image_t
*get_window_screenshot(struct vo
*vo
)
1172 struct gl_priv
*p
= vo
->priv
;
1175 GLint vp
[4]; //x, y, w, h
1176 gl
->GetIntegerv(GL_VIEWPORT
, vp
);
1177 mp_image_t
*image
= alloc_mpi(vp
[2], vp
[3], IMGFMT_RGB24
);
1178 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1179 gl
->PixelStorei(GL_PACK_ALIGNMENT
, 0);
1180 gl
->PixelStorei(GL_PACK_ROW_LENGTH
, 0);
1181 gl
->ReadBuffer(GL_FRONT
);
1182 //flip image while reading
1183 for (int y
= 0; y
< vp
[3]; y
++) {
1184 gl
->ReadPixels(vp
[0], vp
[1] + vp
[3] - y
- 1, vp
[2], 1,
1185 GL_RGB
, GL_UNSIGNED_BYTE
,
1186 image
->planes
[0] + y
* image
->stride
[0]);
1191 static int query_format(struct vo
*vo
, uint32_t format
)
1193 struct gl_priv
*p
= vo
->priv
;
1196 int caps
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_FLIP
|
1197 VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1199 caps
|= VFCAP_OSD
| VFCAP_EOSD
| (p
->scaled_osd
? 0 : VFCAP_EOSD_UNSCALED
);
1200 if (format
== IMGFMT_RGB24
|| format
== IMGFMT_RGBA
)
1202 if (p
->use_yuv
&& mp_get_chroma_shift(format
, NULL
, NULL
, &depth
) &&
1203 (depth
== 8 || depth
== 16 || glYUVLargeRange(p
->use_yuv
)) &&
1204 (IMGFMT_IS_YUVP16_NE(format
) || !IMGFMT_IS_YUVP16(format
)))
1206 // HACK, otherwise we get only b&w with some filters (e.g. -vf eq)
1207 // ideally MPlayer should be fixed instead not to use Y800 when it has the choice
1208 if (!p
->use_yuv
&& (format
== IMGFMT_Y8
|| format
== IMGFMT_Y800
))
1210 if (!p
->use_ycbcr
&& (format
== IMGFMT_UYVY
|| format
== IMGFMT_YVYU
))
1213 glFindFormat(format
, p
->have_texture_rg
, NULL
, NULL
, NULL
, NULL
))
1218 static void uninit(struct vo
*vo
)
1220 struct gl_priv
*p
= vo
->priv
;
1224 free(p
->custom_prog
);
1225 p
->custom_prog
= NULL
;
1226 free(p
->custom_tex
);
1227 p
->custom_tex
= NULL
;
1228 uninit_mpglcontext(p
->glctx
);
1233 static int preinit_internal(struct vo
*vo
, const char *arg
, int allow_sw
,
1234 enum MPGLType gltype
)
1236 struct gl_priv
*p
= talloc_zero(vo
, struct gl_priv
);
1239 *p
= (struct gl_priv
) {
1243 .colorspace
= MP_CSP_DETAILS_DEFAULTS
,
1244 .filter_strength
= 0.5,
1245 .use_rectangle
= -1,
1249 .custom_prog
= NULL
,
1252 .osd_color
= 0xffffff,
1255 //essentially unused; for legacy warnings only
1256 int user_colorspace
= 0;
1260 const opt_t subopts
[] = {
1261 {"manyfmts", OPT_ARG_BOOL
, &p
->many_fmts
, NULL
},
1262 {"osd", OPT_ARG_BOOL
, &p
->use_osd
, NULL
},
1263 {"scaled-osd", OPT_ARG_BOOL
, &p
->scaled_osd
, NULL
},
1264 {"ycbcr", OPT_ARG_BOOL
, &p
->use_ycbcr
, NULL
},
1265 {"slice-height", OPT_ARG_INT
, &p
->slice_height
, int_non_neg
},
1266 {"rectangle", OPT_ARG_INT
, &p
->use_rectangle
,int_non_neg
},
1267 {"yuv", OPT_ARG_INT
, &p
->use_yuv
, int_non_neg
},
1268 {"lscale", OPT_ARG_INT
, &p
->lscale
, int_non_neg
},
1269 {"cscale", OPT_ARG_INT
, &p
->cscale
, int_non_neg
},
1270 {"filter-strength", OPT_ARG_FLOAT
, &p
->filter_strength
, NULL
},
1271 {"ati-hack", OPT_ARG_BOOL
, &p
->ati_hack
, NULL
},
1272 {"force-pbo", OPT_ARG_BOOL
, &p
->force_pbo
, NULL
},
1273 {"glfinish", OPT_ARG_BOOL
, &p
->use_glFinish
, NULL
},
1274 {"swapinterval", OPT_ARG_INT
, &p
->swap_interval
,NULL
},
1275 {"customprog", OPT_ARG_MSTRZ
,&p
->custom_prog
, NULL
},
1276 {"customtex", OPT_ARG_MSTRZ
,&p
->custom_tex
, NULL
},
1277 {"customtlin", OPT_ARG_BOOL
, &p
->custom_tlin
, NULL
},
1278 {"customtrect", OPT_ARG_BOOL
, &p
->custom_trect
, NULL
},
1279 {"mipmapgen", OPT_ARG_BOOL
, &p
->mipmap_gen
, NULL
},
1280 {"osdcolor", OPT_ARG_INT
, &p
->osd_color
, NULL
},
1281 {"stereo", OPT_ARG_INT
, &p
->stereo_mode
, NULL
},
1283 // They are only parsed to notify the user about the replacements.
1284 {"aspect", OPT_ARG_BOOL
, &aspect
, NULL
},
1285 {"colorspace", OPT_ARG_INT
, &user_colorspace
, NULL
},
1286 {"levelconv", OPT_ARG_INT
, &levelconv
, NULL
},
1290 if (subopt_parse(arg
, subopts
) != 0) {
1291 mp_msg(MSGT_VO
, MSGL_FATAL
,
1292 "\n-vo gl command line help:\n"
1293 "Example: mplayer -vo gl:slice-height=4\n"
1296 " Disable extended color formats for OpenGL 1.2 and later\n"
1297 " slice-height=<0-...>\n"
1298 " Slice size for texture transfer, 0 for whole image\n"
1300 " Do not use OpenGL OSD code\n"
1302 " Render OSD at movie resolution and scale it\n"
1303 " rectangle=<0,1,2>\n"
1304 " 0: use power-of-two textures\n"
1305 " 1: use texture_rectangle\n"
1306 " 2: use texture_non_power_of_two\n"
1308 " Workaround ATI bug with PBOs\n"
1310 " Force use of PBO even if this involves an extra memcpy\n"
1312 " Call glFinish() before swapping buffers\n"
1313 " swapinterval=<n>\n"
1314 " Interval in displayed frames between to buffer swaps.\n"
1315 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
1316 " Requires GLX_SGI_swap_control support to work.\n"
1318 " also try to use the GL_MESA_ycbcr_texture extension\n"
1320 " 0: use software YUV to RGB conversion.\n"
1321 " 1: deprecated, will use yuv=2 (used to be nVidia register combiners).\n"
1322 " 2: use fragment program.\n"
1323 " 3: use fragment program with gamma correction.\n"
1324 " 4: use fragment program with gamma correction via lookup.\n"
1325 " 5: use ATI-specific method (for older cards).\n"
1326 " 6: use lookup via 3D texture.\n"
1328 " 0: use standard bilinear scaling for luma.\n"
1329 " 1: use improved bicubic scaling for luma.\n"
1330 " 2: use cubic in X, linear in Y direction scaling for luma.\n"
1331 " 3: as 1 but without using a lookup texture.\n"
1332 " 4: experimental unsharp masking (sharpening).\n"
1333 " 5: experimental unsharp masking (sharpening) with larger radius.\n"
1335 " as lscale but for chroma (2x slower with little visible effect).\n"
1336 " filter-strength=<value>\n"
1337 " set the effect strength for some lscale/cscale filters\n"
1338 " customprog=<filename>\n"
1339 " use a custom YUV conversion program\n"
1340 " customtex=<filename>\n"
1341 " use a custom YUV conversion lookup texture\n"
1343 " use GL_NEAREST scaling for customtex texture\n"
1345 " use texture_rectangle for customtex texture\n"
1347 " generate mipmaps for the video image (use with TXB in customprog)\n"
1348 " osdcolor=<0xAARRGGBB>\n"
1349 " use the given color for the OSD\n"
1351 " 0: normal display\n"
1352 " 1: side-by-side to red-cyan stereo\n"
1353 " 2: side-by-side to green-magenta stereo\n"
1354 " 3: side-by-side to quadbuffer stereo\n"
1358 if (user_colorspace
!= 0 || levelconv
!= -1) {
1359 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"colorspace\" and \"levelconv\" "
1360 "suboptions have been removed. Use options --colormatrix and"
1361 " --colormatrix-input-range/--colormatrix-output-range instead.\n");
1365 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"noaspect\" suboption has been "
1366 "removed. Use --noaspect instead.\n");
1369 if (p
->use_yuv
== 1) {
1370 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] yuv=1 (nVidia register combiners) have"
1371 " been removed, using yuv=2 instead.\n");
1374 p
->glctx
= init_mpglcontext(gltype
, vo
);
1377 p
->gl
= p
->glctx
->gl
;
1379 if (p
->glctx
->type
== GLTYPE_SDL
&& p
->use_yuv
== -1) {
1380 // Apparently it's not possible to implement VOFLAG_HIDDEN on SDL 1.2,
1381 // so don't do autodetection. Use a sufficiently useful and safe YUV
1383 p
->use_yuv
= YUV_CONVERSION_FRAGMENT
;
1386 if (p
->use_yuv
== -1 || !allow_sw
) {
1387 if (create_window(vo
, 320, 200, VOFLAG_HIDDEN
) < 0)
1389 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
1391 if (!allow_sw
&& isSoftwareGl(vo
))
1393 autodetectGlExtensions(vo
);
1394 // We created a window to test whether the GL context supports hardware
1395 // acceleration and so on. Destroy that window to make sure all state
1396 // associated with it is lost.
1398 p
->glctx
= init_mpglcontext(gltype
, vo
);
1401 p
->gl
= p
->glctx
->gl
;
1404 mp_msg(MSGT_VO
, MSGL_INFO
, "[gl] using extended formats. "
1405 "Use -vo gl:nomanyfmts if playback fails.\n");
1406 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Using %d as slice height "
1407 "(0 means image height).\n", p
->slice_height
);
1416 static int preinit(struct vo
*vo
, const char *arg
)
1418 return preinit_internal(vo
, arg
, 1, GLTYPE_AUTO
);
1421 static int control(struct vo
*vo
, uint32_t request
, void *data
)
1423 struct gl_priv
*p
= vo
->priv
;
1428 p
->int_pause
= (request
== VOCTRL_PAUSE
);
1430 case VOCTRL_QUERY_FORMAT
:
1431 return query_format(vo
, *(uint32_t *)data
);
1432 case VOCTRL_GET_IMAGE
:
1433 return get_image(vo
, data
);
1434 case VOCTRL_DRAW_IMAGE
:
1435 return draw_image(vo
, data
);
1436 case VOCTRL_DRAW_EOSD
:
1440 if (vo_doublebuffering
)
1441 do_render_osd(vo
, RENDER_EOSD
);
1443 case VOCTRL_GET_EOSD_RES
: {
1444 mp_eosd_res_t
*r
= data
;
1447 r
->mt
= r
->mb
= r
->ml
= r
->mr
= 0;
1448 if (p
->scaled_osd
) {
1449 r
->w
= p
->image_width
;
1450 r
->h
= p
->image_height
;
1451 } else if (aspect_scaling()) {
1452 r
->ml
= r
->mr
= p
->ass_border_x
;
1453 r
->mt
= r
->mb
= p
->ass_border_y
;
1458 if (!p
->glctx
->ontop
)
1460 p
->glctx
->ontop(vo
);
1462 case VOCTRL_FULLSCREEN
:
1463 p
->glctx
->fullscreen(vo
);
1464 resize(vo
, vo
->dwidth
, vo
->dheight
);
1467 if (!p
->glctx
->border
)
1469 p
->glctx
->border(vo
);
1470 resize(vo
, vo
->dwidth
, vo
->dheight
);
1472 case VOCTRL_GET_PANSCAN
:
1474 case VOCTRL_SET_PANSCAN
:
1475 resize(vo
, vo
->dwidth
, vo
->dheight
);
1477 case VOCTRL_GET_EQUALIZER
:
1479 struct voctrl_get_equalizer_args
*args
= data
;
1480 return mp_csp_equalizer_get(&p
->video_eq
, args
->name
, args
->valueptr
)
1481 >= 0 ? VO_TRUE
: VO_NOTIMPL
;
1484 case VOCTRL_SET_EQUALIZER
:
1486 struct voctrl_set_equalizer_args
*args
= data
;
1487 if (mp_csp_equalizer_set(&p
->video_eq
, args
->name
, args
->value
) < 0)
1493 case VOCTRL_SET_YUV_COLORSPACE
: {
1494 bool supports_csp
= (1 << p
->use_yuv
) & MASK_NOT_COMBINERS
;
1495 if (vo
->config_count
&& supports_csp
) {
1496 p
->colorspace
= *(struct mp_csp_details
*)data
;
1501 case VOCTRL_GET_YUV_COLORSPACE
:
1502 *(struct mp_csp_details
*)data
= p
->colorspace
;
1504 case VOCTRL_UPDATE_SCREENINFO
:
1505 if (!p
->glctx
->update_xinerama_info
)
1507 p
->glctx
->update_xinerama_info(vo
);
1509 case VOCTRL_REDRAW_OSD
:
1510 if (vo_doublebuffering
)
1513 if (vo_doublebuffering
)
1514 do_render_osd(vo
, 2);
1517 case VOCTRL_SCREENSHOT
: {
1518 struct voctrl_screenshot_args
*args
= data
;
1519 if (args
->full_window
)
1520 args
->out_image
= get_window_screenshot(vo
);
1522 args
->out_image
= get_screenshot(vo
);
1529 const struct vo_driver video_out_gl
= {
1531 .info
= &(const vo_info_t
) {
1534 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1540 .draw_slice
= draw_slice
,
1541 .draw_osd
= draw_osd
,
1542 .flip_page
= flip_page
,
1543 .check_events
= check_events
,
1547 static int preinit_nosw(struct vo
*vo
, const char *arg
)
1549 return preinit_internal(vo
, arg
, 0, GLTYPE_AUTO
);
1552 const struct vo_driver video_out_gl_nosw
=
1555 .info
= &(const vo_info_t
) {
1556 "OpenGL no software rendering",
1558 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1561 .preinit
= preinit_nosw
,
1564 .draw_slice
= draw_slice
,
1565 .draw_osd
= draw_osd
,
1566 .flip_page
= flip_page
,
1567 .check_events
= check_events
,
1571 #ifdef CONFIG_GL_SDL
1572 static int preinit_sdl(struct vo
*vo
, const char *arg
)
1574 return preinit_internal(vo
, arg
, 1, GLTYPE_SDL
);
1577 const struct vo_driver video_out_gl_sdl
= {
1579 .info
= &(const vo_info_t
) {
1582 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1585 .preinit
= preinit_sdl
,
1588 .draw_slice
= draw_slice
,
1589 .draw_osd
= draw_osd
,
1590 .flip_page
= flip_page
,
1591 .check_events
= check_events
,