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 "subopt-helper.h"
33 #include "video_out.h"
34 #include "video_out_internal.h"
35 #include "sub/font_load.h"
38 #include "gl_common.h"
40 #include "fastmemcpy.h"
41 #include "sub/ass_mp.h"
44 #ifdef CONFIG_SDL_SDL_H
51 static const vo_info_t info
=
55 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
59 const LIBVO_EXTERN(gl
)
62 static const vo_info_t info_nosw
=
64 "OpenGL no software rendering",
66 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
69 static int preinit_nosw(const char *arg
);
70 const struct vo_driver video_out_gl_nosw
=
74 .preinit
= old_vo_preinit
,
75 .config
= old_vo_config
,
76 .control
= old_vo_control
,
77 .draw_slice
= old_vo_draw_slice
,
78 .draw_osd
= old_vo_draw_osd
,
79 .flip_page
= old_vo_flip_page
,
80 .check_events
= old_vo_check_events
,
81 .uninit
= old_vo_uninit
,
82 .old_functions
= &(struct vo_old_functions
){
95 static MPGLContext glctx
;
98 static int scaled_osd
;
99 //! How many parts the OSD may consist of at most
100 #define MAX_OSD_PARTS 20
102 static GLuint osdtex
[MAX_OSD_PARTS
];
104 //! Alpha textures for OSD
105 static GLuint osdatex
[MAX_OSD_PARTS
];
107 static GLuint
*eosdtex
;
108 #define LARGE_EOSD_TEX_SIZE 512
109 #define TINYTEX_SIZE 16
110 #define TINYTEX_COLS (LARGE_EOSD_TEX_SIZE/TINYTEX_SIZE)
111 #define TINYTEX_MAX (TINYTEX_COLS*TINYTEX_COLS)
112 #define SMALLTEX_SIZE 32
113 #define SMALLTEX_COLS (LARGE_EOSD_TEX_SIZE/SMALLTEX_SIZE)
114 #define SMALLTEX_MAX (SMALLTEX_COLS*SMALLTEX_COLS)
115 static GLuint largeeosdtex
[2];
116 //! Display lists that draw the OSD parts
117 static GLuint osdDispList
[MAX_OSD_PARTS
];
119 static GLuint osdaDispList
[MAX_OSD_PARTS
];
121 static GLuint eosdDispList
;
122 //! How many parts the OSD currently consists of
123 static int osdtexCnt
;
124 static int eosdtexCnt
;
125 static int osd_color
;
127 static int use_aspect
;
128 static int use_ycbcr
;
129 #define MASK_ALL_YUV (~(1 << YUV_CONVERSION_NONE))
130 #define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS)))
131 #define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT))
133 static struct mp_csp_details colorspace
= MP_CSP_DETAILS_DEFAULTS
;
134 static int user_colorspace
; //essentially unused; legacy warning
135 static int levelconv
; //essentially unused; legacy warning
139 static float filter_strength
;
140 static int yuvconvtype
;
141 static int use_rectangle
;
142 static int err_shown
;
143 static uint32_t image_width
;
144 static uint32_t image_height
;
145 static uint32_t image_format
;
146 static int many_fmts
;
148 static int force_pbo
;
149 static int mesa_buffer
;
150 static int use_glFinish
;
151 static int swap_interval
;
152 static GLenum gl_target
;
153 static GLint gl_texfmt
;
154 static GLenum gl_format
;
155 static GLenum gl_type
;
156 static GLuint gl_buffer
;
157 static GLuint gl_buffer_uv
[2];
158 static int gl_buffersize
;
159 static int gl_buffersize_uv
;
160 static void *gl_bufferptr
;
161 static void *gl_bufferptr_uv
[2];
162 static int mesa_buffersize
;
163 static void *mesa_bufferptr
;
164 static GLuint fragprog
;
165 static GLuint default_texs
[22];
166 static char *custom_prog
;
167 static char *custom_tex
;
168 static int custom_tlin
;
169 static int custom_trect
;
170 static int mipmap_gen
;
171 static int stereo_mode
;
173 static int int_pause
;
175 static struct mp_csp_equalizer video_eq
;
177 static int texture_width
;
178 static int texture_height
;
179 static int mpi_flipped
;
180 static int vo_flipped
;
181 static int ass_border_x
, ass_border_y
;
183 static unsigned int slice_height
= 1;
185 static void redraw(void);
187 static void resize(int x
,int y
){
188 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Resize: %dx%d\n",x
,y
);
190 int left
= 0, top
= 0, w
= x
, h
= y
;
191 geometry(&left
, &top
, &w
, &h
, vo_dwidth
, vo_dheight
);
193 mpglViewport(left
, top
, w
, h
);
195 mpglViewport( 0, 0, x
, y
);
197 mpglMatrixMode(GL_PROJECTION
);
199 ass_border_x
= ass_border_y
= 0;
200 if (aspect_scaling() && use_aspect
) {
202 GLdouble scale_x
, scale_y
;
203 aspect(&new_w
, &new_h
, A_WINZOOM
);
204 panscan_calc_windowed();
205 new_w
+= vo_panscan_x
;
206 new_h
+= vo_panscan_y
;
207 scale_x
= (GLdouble
)new_w
/ (GLdouble
)x
;
208 scale_y
= (GLdouble
)new_h
/ (GLdouble
)y
;
209 mpglScaled(scale_x
, scale_y
, 1);
210 ass_border_x
= (vo_dwidth
- new_w
) / 2;
211 ass_border_y
= (vo_dheight
- new_h
) / 2;
213 mpglOrtho(0, image_width
, image_height
, 0, -1,1);
215 mpglMatrixMode(GL_MODELVIEW
);
219 #ifdef CONFIG_FREETYPE
220 // adjust font size to display size
223 vo_osd_changed(OSDTYPE_OSD
);
225 mpglClear(GL_COLOR_BUFFER_BIT
);
229 static void texSize(int w
, int h
, int *texw
, int *texh
) {
231 *texw
= w
; *texh
= h
;
240 if (mesa_buffer
) *texw
= (*texw
+ 63) & ~63;
241 else if (ati_hack
) *texw
= (*texw
+ 511) & ~511;
244 //! maximum size of custom fragment program
245 #define MAX_CUSTOM_PROG_SIZE (1024 * 1024)
246 static void update_yuvconv(void) {
248 struct mp_csp_params cparams
= { .colorspace
= colorspace
};
249 mp_csp_copy_equalizer_values(&cparams
, &video_eq
);
250 gl_conversion_params_t params
= {gl_target
, yuvconvtype
, cparams
,
251 texture_width
, texture_height
, 0, 0, filter_strength
};
252 mp_get_chroma_shift(image_format
, &xs
, &ys
, &depth
);
253 params
.chrom_texw
= params
.texw
>> xs
;
254 params
.chrom_texh
= params
.texh
>> ys
;
255 params
.csp_params
.input_shift
= -depth
& 7;
256 glSetupYUVConversion(¶ms
);
258 FILE *f
= fopen(custom_prog
, "rb");
260 mp_msg(MSGT_VO
, MSGL_WARN
,
261 "[gl] Could not read customprog %s\n", custom_prog
);
263 char *prog
= calloc(1, MAX_CUSTOM_PROG_SIZE
+ 1);
264 fread(prog
, 1, MAX_CUSTOM_PROG_SIZE
, f
);
266 loadGPUProgram(GL_FRAGMENT_PROGRAM
, prog
);
269 mpglProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 0,
270 1.0 / texture_width
, 1.0 / texture_height
,
271 texture_width
, texture_height
);
274 FILE *f
= fopen(custom_tex
, "rb");
276 mp_msg(MSGT_VO
, MSGL_WARN
,
277 "[gl] Could not read customtex %s\n", custom_tex
);
279 int width
, height
, maxval
;
280 mpglActiveTexture(GL_TEXTURE3
);
281 if (glCreatePPMTex(custom_trect
?GL_TEXTURE_RECTANGLE
:GL_TEXTURE_2D
, 0,
282 custom_tlin
?GL_LINEAR
:GL_NEAREST
,
283 f
, &width
, &height
, &maxval
)) {
284 mpglProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 1,
285 1.0 / width
, 1.0 / height
, width
, height
);
287 mp_msg(MSGT_VO
, MSGL_WARN
,
288 "[gl] Error parsing customtex %s\n", custom_tex
);
290 mpglActiveTexture(GL_TEXTURE0
);
296 * \brief remove all OSD textures and display-lists, thus clearing it.
298 static void clearOSD(void) {
302 mpglDeleteTextures(osdtexCnt
, osdtex
);
304 mpglDeleteTextures(osdtexCnt
, osdatex
);
305 for (i
= 0; i
< osdtexCnt
; i
++)
306 mpglDeleteLists(osdaDispList
[i
], 1);
308 for (i
= 0; i
< osdtexCnt
; i
++)
309 mpglDeleteLists(osdDispList
[i
], 1);
314 * \brief remove textures, display list and free memory used by EOSD
316 static void clearEOSD(void) {
318 mpglDeleteLists(eosdDispList
, 1);
321 mpglDeleteTextures(eosdtexCnt
, eosdtex
);
327 static inline int is_tinytex(ASS_Image
*i
, int tinytexcur
) {
328 return i
->w
< TINYTEX_SIZE
&& i
->h
< TINYTEX_SIZE
&& tinytexcur
< TINYTEX_MAX
;
331 static inline int is_smalltex(ASS_Image
*i
, int smalltexcur
) {
332 return i
->w
< SMALLTEX_SIZE
&& i
->h
< SMALLTEX_SIZE
&& smalltexcur
< SMALLTEX_MAX
;
335 static inline void tinytex_pos(int tinytexcur
, int *x
, int *y
) {
336 *x
= (tinytexcur
% TINYTEX_COLS
) * TINYTEX_SIZE
;
337 *y
= (tinytexcur
/ TINYTEX_COLS
) * TINYTEX_SIZE
;
340 static inline void smalltex_pos(int smalltexcur
, int *x
, int *y
) {
341 *x
= (smalltexcur
% SMALLTEX_COLS
) * SMALLTEX_SIZE
;
342 *y
= (smalltexcur
/ SMALLTEX_COLS
) * SMALLTEX_SIZE
;
346 * \brief construct display list from ass image list
347 * \param img image list to create OSD from.
348 * A value of NULL has the same effect as clearEOSD()
350 static void genEOSD(mp_eosd_images_t
*imgs
) {
355 GLint scale_type
= scaled_osd
? GL_LINEAR
: GL_NEAREST
;
356 ASS_Image
*img
= imgs
->imgs
;
359 if (imgs
->changed
== 0) // there are elements, but they are unchanged
361 if (img
&& imgs
->changed
== 1) // there are elements, but they just moved
367 if (!largeeosdtex
[0]) {
368 mpglGenTextures(2, largeeosdtex
);
369 mpglBindTexture(gl_target
, largeeosdtex
[0]);
370 glCreateClearTex(gl_target
, GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
, scale_type
, LARGE_EOSD_TEX_SIZE
, LARGE_EOSD_TEX_SIZE
, 0);
371 mpglBindTexture(gl_target
, largeeosdtex
[1]);
372 glCreateClearTex(gl_target
, GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
, scale_type
, LARGE_EOSD_TEX_SIZE
, LARGE_EOSD_TEX_SIZE
, 0);
374 for (i
= img
; i
; i
= i
->next
)
376 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
)
378 if (is_tinytex(i
, tinytexcur
))
380 else if (is_smalltex(i
, smalltexcur
))
385 mp_msg(MSGT_VO
, MSGL_DBG2
, "EOSD counts (tiny, small, all): %i, %i, %i\n",
386 tinytexcur
, smalltexcur
, eosdtexCnt
);
388 eosdtex
= calloc(eosdtexCnt
, sizeof(GLuint
));
389 mpglGenTextures(eosdtexCnt
, eosdtex
);
391 tinytexcur
= smalltexcur
= 0;
392 for (i
= img
, curtex
= eosdtex
; i
; i
= i
->next
) {
394 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
) {
395 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
398 if (is_tinytex(i
, tinytexcur
)) {
399 tinytex_pos(tinytexcur
, &x
, &y
);
400 mpglBindTexture(gl_target
, largeeosdtex
[0]);
402 } else if (is_smalltex(i
, smalltexcur
)) {
403 smalltex_pos(smalltexcur
, &x
, &y
);
404 mpglBindTexture(gl_target
, largeeosdtex
[1]);
407 texSize(i
->w
, i
->h
, &sx
, &sy
);
408 mpglBindTexture(gl_target
, *curtex
++);
409 glCreateClearTex(gl_target
, GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
411 glUploadTex(gl_target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, i
->bitmap
, i
->stride
,
412 x
, y
, i
->w
, i
->h
, 0);
414 eosdDispList
= mpglGenLists(1);
416 mpglNewList(eosdDispList
, GL_COMPILE
);
417 tinytexcur
= smalltexcur
= 0;
418 for (i
= img
, curtex
= eosdtex
; i
; i
= i
->next
) {
420 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
)
422 mpglColor4ub(i
->color
>> 24, (i
->color
>> 16) & 0xff, (i
->color
>> 8) & 0xff, 255 - (i
->color
& 0xff));
423 if (is_tinytex(i
, tinytexcur
)) {
424 tinytex_pos(tinytexcur
, &x
, &y
);
425 sx
= sy
= LARGE_EOSD_TEX_SIZE
;
426 mpglBindTexture(gl_target
, largeeosdtex
[0]);
428 } else if (is_smalltex(i
, smalltexcur
)) {
429 smalltex_pos(smalltexcur
, &x
, &y
);
430 sx
= sy
= LARGE_EOSD_TEX_SIZE
;
431 mpglBindTexture(gl_target
, largeeosdtex
[1]);
434 texSize(i
->w
, i
->h
, &sx
, &sy
);
435 mpglBindTexture(gl_target
, *curtex
++);
437 glDrawTex(i
->dst_x
, i
->dst_y
, i
->w
, i
->h
, x
, y
, i
->w
, i
->h
, sx
, sy
, use_rectangle
== 1, 0, 0);
440 mpglBindTexture(gl_target
, 0);
444 * \brief uninitialize OpenGL context, freeing textures, buffers etc.
446 static void uninitGl(void) {
448 if (mpglDeletePrograms
&& fragprog
)
449 mpglDeletePrograms(1, &fragprog
);
451 while (default_texs
[i
] != 0)
454 mpglDeleteTextures(i
, default_texs
);
459 mpglDeleteTextures(2, largeeosdtex
);
461 if (mpglDeleteBuffers
&& gl_buffer
)
462 mpglDeleteBuffers(1, &gl_buffer
);
463 gl_buffer
= 0; gl_buffersize
= 0;
465 if (mpglDeleteBuffers
&& gl_buffer_uv
[0])
466 mpglDeleteBuffers(2, gl_buffer_uv
);
467 gl_buffer_uv
[0] = gl_buffer_uv
[1] = 0; gl_buffersize_uv
= 0;
468 gl_bufferptr_uv
[0] = gl_bufferptr_uv
[1] = 0;
471 mpglFreeMemoryMESA(mDisplay
, mScreen
, mesa_bufferptr
);
473 mesa_bufferptr
= NULL
;
477 static int isSoftwareGl(void)
479 const char *renderer
= mpglGetString(GL_RENDERER
);
480 return !renderer
|| strcmp(renderer
, "Software Rasterizer") == 0 ||
481 strstr(renderer
, "llvmpipe");
484 static void autodetectGlExtensions(void) {
485 const char *extensions
= mpglGetString(GL_EXTENSIONS
);
486 const char *vendor
= mpglGetString(GL_VENDOR
);
487 const char *version
= mpglGetString(GL_VERSION
);
488 const char *renderer
= mpglGetString(GL_RENDERER
);
489 int is_ati
= vendor
&& strstr(vendor
, "ATI") != NULL
;
490 int ati_broken_pbo
= 0;
491 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Running on OpenGL '%s' by '%s', version '%s'\n", renderer
, vendor
, version
);
492 if (is_ati
&& strncmp(version
, "2.1.", 4) == 0) {
493 int ver
= atoi(version
+ 4);
494 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Detected ATI driver version: %i\n", ver
);
495 ati_broken_pbo
= ver
&& ver
< 8395;
497 if (ati_hack
== -1) ati_hack
= ati_broken_pbo
;
498 if (force_pbo
== -1) {
500 if (extensions
&& strstr(extensions
, "_pixel_buffer_object"))
503 if (use_rectangle
== -1) {
506 // if (strstr(extensions, "_texture_non_power_of_two"))
507 if (strstr(extensions
, "_texture_rectangle"))
508 use_rectangle
= renderer
&& strstr(renderer
, "Mesa DRI R200") ? 1 : 0;
512 use_osd
= mpglBindTexture
!= NULL
;
514 use_yuv
= glAutodetectYUVConversion();
517 int yuv_mask
= (1 << use_yuv
);
518 if (!(yuv_mask
& MASK_NOT_COMBINERS
)) {
520 eq_caps
= (1 << MP_CSP_EQ_HUE
) | (1 << MP_CSP_EQ_SATURATION
);
521 } else if (yuv_mask
& MASK_ALL_YUV
) {
522 eq_caps
= MP_CSP_EQ_CAPS_COLORMATRIX
;
523 if (yuv_mask
& MASK_GAMMA_SUPPORT
)
524 eq_caps
|= MP_CSP_EQ_CAPS_GAMMA
;
526 video_eq
.capabilities
= eq_caps
;
528 if (is_ati
&& (lscale
== 1 || lscale
== 2 || cscale
== 1 || cscale
== 2))
529 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] Selected scaling mode may be broken on ATI cards.\n"
530 "Tell _them_ to fix GL_REPEAT if you have issues.\n");
531 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Settings after autodetection: ati-hack = %i, force-pbo = %i, rectangle = %i, yuv = %i\n",
532 ati_hack
, force_pbo
, use_rectangle
, use_yuv
);
535 static GLint
get_scale_type(int chroma
) {
536 int nearest
= (chroma
? cscale
: lscale
) & 64;
538 return mipmap_gen
? GL_NEAREST_MIPMAP_NEAREST
: GL_NEAREST
;
539 return mipmap_gen
? GL_LINEAR_MIPMAP_NEAREST
: GL_LINEAR
;
543 * \brief Initialize a (new or reused) OpenGL context.
544 * set global gl-related variables to their default values
546 static int initGl(uint32_t d_width
, uint32_t d_height
) {
547 GLint scale_type
= get_scale_type(0);
548 autodetectGlExtensions();
549 gl_target
= use_rectangle
== 1 ? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
;
550 yuvconvtype
= SET_YUV_CONVERSION(use_yuv
) |
551 SET_YUV_LUM_SCALER(lscale
) |
552 SET_YUV_CHROM_SCALER(cscale
);
554 texSize(image_width
, image_height
, &texture_width
, &texture_height
);
556 mpglDisable(GL_BLEND
);
557 mpglDisable(GL_DEPTH_TEST
);
558 mpglDepthMask(GL_FALSE
);
559 mpglDisable(GL_CULL_FACE
);
560 mpglEnable(gl_target
);
561 mpglDrawBuffer(vo_doublebuffering
?GL_BACK
:GL_FRONT
);
562 mpglTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
564 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Creating %dx%d texture...\n",
565 texture_width
, texture_height
);
567 glCreateClearTex(gl_target
, gl_texfmt
, gl_format
, gl_type
, scale_type
,
568 texture_width
, texture_height
, 0);
570 mpglTexParameteri(gl_target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
575 int chroma_clear_val
= 128;
576 scale_type
= get_scale_type(1);
577 mp_get_chroma_shift(image_format
, &xs
, &ys
, &depth
);
578 chroma_clear_val
>>= -depth
& 7;
579 mpglGenTextures(21, default_texs
);
580 default_texs
[21] = 0;
581 for (i
= 0; i
< 7; i
++) {
582 mpglActiveTexture(GL_TEXTURE1
+ i
);
583 mpglBindTexture(GL_TEXTURE_2D
, default_texs
[i
]);
584 mpglBindTexture(GL_TEXTURE_RECTANGLE
, default_texs
[i
+ 7]);
585 mpglBindTexture(GL_TEXTURE_3D
, default_texs
[i
+ 14]);
587 mpglActiveTexture(GL_TEXTURE1
);
588 glCreateClearTex(gl_target
, gl_texfmt
, gl_format
, gl_type
, scale_type
,
589 texture_width
>> xs
, texture_height
>> ys
,
592 mpglTexParameteri(gl_target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
593 mpglActiveTexture(GL_TEXTURE2
);
594 glCreateClearTex(gl_target
, gl_texfmt
, gl_format
, gl_type
, scale_type
,
595 texture_width
>> xs
, texture_height
>> ys
,
598 mpglTexParameteri(gl_target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
599 mpglActiveTexture(GL_TEXTURE0
);
600 mpglBindTexture(gl_target
, 0);
602 if (is_yuv
|| custom_prog
)
604 if ((MASK_NOT_COMBINERS
& (1 << use_yuv
)) || custom_prog
) {
605 if (!mpglGenPrograms
|| !mpglBindProgram
) {
606 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] fragment program functions missing!\n");
608 mpglGenPrograms(1, &fragprog
);
609 mpglBindProgram(GL_FRAGMENT_PROGRAM
, fragprog
);
615 resize(d_width
, d_height
);
617 mpglClearColor( 0.0f
,0.0f
,0.0f
,0.0f
);
618 mpglClear( GL_COLOR_BUFFER_BIT
);
619 if (mpglSwapInterval
&& swap_interval
>= 0)
620 mpglSwapInterval(swap_interval
);
624 static int create_window(uint32_t d_width
, uint32_t d_height
, uint32_t flags
, const char *title
)
626 if (stereo_mode
== GL_3D_QUADBUFFER
)
627 flags
|= VOFLAG_STEREO
;
628 #ifdef CONFIG_GL_WIN32
629 if (glctx
.type
== GLTYPE_W32
&& !vo_w32_config(d_width
, d_height
, flags
))
633 if (glctx
.type
== GLTYPE_X11
) {
634 static int default_glx_attribs
[] = {
635 GLX_RGBA
, GLX_RED_SIZE
, 1, GLX_GREEN_SIZE
, 1, GLX_BLUE_SIZE
, 1,
636 GLX_DOUBLEBUFFER
, None
638 static int stereo_glx_attribs
[] = {
639 GLX_RGBA
, GLX_RED_SIZE
, 1, GLX_GREEN_SIZE
, 1, GLX_BLUE_SIZE
, 1,
640 GLX_DOUBLEBUFFER
, GLX_STEREO
, None
642 XVisualInfo
*vinfo
= NULL
;
643 if (stereo_mode
== GL_3D_QUADBUFFER
) {
644 vinfo
= glXChooseVisual(mDisplay
, mScreen
, stereo_glx_attribs
);
646 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] Could not find a stereo visual, "
647 "3D will probably not work!\n");
650 vinfo
= glXChooseVisual(mDisplay
, mScreen
, default_glx_attribs
);
652 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] no GLX support present\n");
655 mp_msg(MSGT_VO
, MSGL_V
, "[gl] GLX chose visual with ID 0x%x\n", (int)vinfo
->visualid
);
657 vo_x11_create_vo_window(vinfo
, vo_dx
, vo_dy
, d_width
, d_height
, flags
,
658 XCreateColormap(mDisplay
, mRootWin
, vinfo
->visual
, AllocNone
),
663 if (glctx
.type
== GLTYPE_SDL
) {
664 SDL_WM_SetCaption(title
, NULL
);
666 vo_dheight
= d_height
;
672 /* connect to server, create and map window,
673 * allocate colors and (shared) memory
676 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
679 image_height
= height
;
681 image_format
= format
;
682 is_yuv
= mp_get_chroma_shift(image_format
, &xs
, &ys
, NULL
) > 0;
683 is_yuv
|= (xs
<< 8) | (ys
<< 16);
684 glFindFormat(format
, NULL
, &gl_texfmt
, &gl_format
, &gl_type
);
686 vo_flipped
= !!(flags
& VOFLAG_FLIPPING
);
688 if (create_window(d_width
, d_height
, flags
, title
) < 0)
693 if (glctx
.setGlWindow(&glctx
) == SET_WINDOW_FAILED
)
695 if (mesa_buffer
&& !mpglAllocateMemoryMESA
) {
696 mp_msg(MSGT_VO
, MSGL_ERR
, "Can not enable mesa-buffer because AllocateMemoryMESA was not found\n");
699 initGl(vo_dwidth
, vo_dheight
);
704 static void check_events(void)
706 int e
=glctx
.check_events();
707 if(e
&VO_EVENT_REINIT
) {
709 initGl(vo_dwidth
, vo_dheight
);
711 if(e
&VO_EVENT_RESIZE
) resize(vo_dwidth
,vo_dheight
);
712 if(e
&VO_EVENT_EXPOSE
&& int_pause
) redraw();
716 * Creates the textures and the display list needed for displaying
718 * Callback function for vo_draw_text().
720 static void create_osd_texture(int x0
, int y0
, int w
, int h
,
721 unsigned char *src
, unsigned char *srca
,
724 // initialize to 8 to avoid special-casing on alignment
726 GLint scale_type
= scaled_osd
? GL_LINEAR
: GL_NEAREST
;
728 if (w
<= 0 || h
<= 0 || stride
< w
) {
729 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
732 texSize(w
, h
, &sx
, &sy
);
734 if (osdtexCnt
>= MAX_OSD_PARTS
) {
735 mp_msg(MSGT_VO
, MSGL_ERR
, "Too many OSD parts, contact the developers!\n");
739 // create Textures for OSD part
740 mpglGenTextures(1, &osdtex
[osdtexCnt
]);
741 mpglBindTexture(gl_target
, osdtex
[osdtexCnt
]);
742 glCreateClearTex(gl_target
, GL_LUMINANCE
, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
743 glUploadTex(gl_target
, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, src
, stride
,
747 mpglGenTextures(1, &osdatex
[osdtexCnt
]);
748 mpglBindTexture(gl_target
, osdatex
[osdtexCnt
]);
749 glCreateClearTex(gl_target
, GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
752 char *tmp
= malloc(stride
* h
);
753 // convert alpha from weird MPlayer scale.
754 // in-place is not possible since it is reused for future OSDs
755 for (i
= h
* stride
- 1; i
>= 0; i
--)
757 glUploadTex(gl_target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, tmp
, stride
,
763 mpglBindTexture(gl_target
, 0);
765 // Create a list for rendering this OSD part
767 osdaDispList
[osdtexCnt
] = mpglGenLists(1);
768 mpglNewList(osdaDispList
[osdtexCnt
], GL_COMPILE
);
770 mpglBindTexture(gl_target
, osdatex
[osdtexCnt
]);
771 glDrawTex(x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, use_rectangle
== 1, 0, 0);
774 osdDispList
[osdtexCnt
] = mpglGenLists(1);
775 mpglNewList(osdDispList
[osdtexCnt
], GL_COMPILE
);
777 mpglBindTexture(gl_target
, osdtex
[osdtexCnt
]);
778 glDrawTex(x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, use_rectangle
== 1, 0, 0);
785 #define RENDER_EOSD 2
788 * \param type bit 0: render OSD, bit 1: render EOSD
790 static void do_render_osd(int type
) {
791 int draw_osd
= (type
& RENDER_OSD
) && osdtexCnt
> 0;
792 int draw_eosd
= (type
& RENDER_EOSD
) && eosdDispList
;
793 if (!draw_osd
&& !draw_eosd
)
795 // set special rendering parameters
797 mpglMatrixMode(GL_PROJECTION
);
800 mpglOrtho(0, vo_dwidth
, vo_dheight
, 0, -1, 1);
802 mpglEnable(GL_BLEND
);
804 mpglBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
805 mpglCallList(eosdDispList
);
808 mpglColor4ub((osd_color
>> 16) & 0xff, (osd_color
>> 8) & 0xff, osd_color
& 0xff, 0xff - (osd_color
>> 24));
811 mpglBlendFunc(GL_ZERO
, GL_ONE_MINUS_SRC_ALPHA
);
812 mpglCallLists(osdtexCnt
, GL_UNSIGNED_INT
, osdaDispList
);
814 mpglBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
815 mpglCallLists(osdtexCnt
, GL_UNSIGNED_INT
, osdDispList
);
817 // set rendering parameters back to defaults
818 mpglDisable(GL_BLEND
);
821 mpglBindTexture(gl_target
, 0);
824 static void draw_osd(void)
826 if (!use_osd
) return;
827 if (vo_osd_changed(0)) {
830 osd_w
= scaled_osd
? image_width
: vo_dwidth
;
831 osd_h
= scaled_osd
? image_height
: vo_dheight
;
832 vo_draw_text_ext(osd_w
, osd_h
, ass_border_x
, ass_border_y
, ass_border_x
, ass_border_y
,
833 image_width
, image_height
, create_osd_texture
);
835 if (vo_doublebuffering
) do_render_osd(RENDER_OSD
);
838 static void do_render(void) {
839 // Enable(GL_TEXTURE_2D);
840 // BindTexture(GL_TEXTURE_2D, texture_id);
843 if (is_yuv
|| custom_prog
)
844 glEnableYUVConversion(gl_target
, yuvconvtype
);
846 glEnable3DLeft(stereo_mode
);
847 glDrawTex(0, 0, image_width
, image_height
,
848 0, 0, image_width
>> 1, image_height
,
849 texture_width
, texture_height
,
850 use_rectangle
== 1, is_yuv
,
851 mpi_flipped
^ vo_flipped
);
852 glEnable3DRight(stereo_mode
);
853 glDrawTex(0, 0, image_width
, image_height
,
854 image_width
>> 1, 0, image_width
>> 1, image_height
,
855 texture_width
, texture_height
,
856 use_rectangle
== 1, is_yuv
,
857 mpi_flipped
^ vo_flipped
);
858 glDisable3D(stereo_mode
);
860 glDrawTex(0, 0, image_width
, image_height
,
861 0, 0, image_width
, image_height
,
862 texture_width
, texture_height
,
863 use_rectangle
== 1, is_yuv
,
864 mpi_flipped
^ vo_flipped
);
866 if (is_yuv
|| custom_prog
)
867 glDisableYUVConversion(gl_target
, yuvconvtype
);
870 static void flip_page(void) {
871 if (vo_doublebuffering
) {
872 if (use_glFinish
) mpglFinish();
873 glctx
.swapGlBuffers(&glctx
);
874 if (aspect_scaling() && use_aspect
)
875 mpglClear(GL_COLOR_BUFFER_BIT
);
878 do_render_osd(RENDER_OSD
| RENDER_EOSD
);
879 if (use_glFinish
) mpglFinish();
884 static void redraw(void) {
885 if (vo_doublebuffering
) { do_render(); do_render_osd(RENDER_OSD
| RENDER_EOSD
); }
889 static int draw_slice(uint8_t *src
[], int stride
[], int w
,int h
,int x
,int y
)
891 mpi_flipped
= stride
[0] < 0;
892 glUploadTex(gl_target
, gl_format
, gl_type
, src
[0], stride
[0],
893 x
, y
, w
, h
, slice_height
);
896 mp_get_chroma_shift(image_format
, &xs
, &ys
, NULL
);
897 mpglActiveTexture(GL_TEXTURE1
);
898 glUploadTex(gl_target
, gl_format
, gl_type
, src
[1], stride
[1],
899 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, slice_height
);
900 mpglActiveTexture(GL_TEXTURE2
);
901 glUploadTex(gl_target
, gl_format
, gl_type
, src
[2], stride
[2],
902 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, slice_height
);
903 mpglActiveTexture(GL_TEXTURE0
);
908 static uint32_t get_image(mp_image_t
*mpi
) {
910 if (!mpglGenBuffers
|| !mpglBindBuffer
|| !mpglBufferData
|| !mpglMapBuffer
) {
912 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] extensions missing for dr\n"
913 "Expect a _major_ speed penalty\n");
917 if (mpi
->flags
& MP_IMGFLAG_READABLE
) return VO_FALSE
;
918 if (mpi
->type
!= MP_IMGTYPE_STATIC
&& mpi
->type
!= MP_IMGTYPE_TEMP
&&
919 (mpi
->type
!= MP_IMGTYPE_NUMBERED
|| mpi
->number
))
921 if (mesa_buffer
) mpi
->width
= texture_width
;
923 mpi
->width
= texture_width
;
924 mpi
->height
= texture_height
;
926 mpi
->stride
[0] = mpi
->width
* mpi
->bpp
/ 8;
927 needed_size
= mpi
->stride
[0] * mpi
->height
;
930 if (mesa_bufferptr
&& needed_size
> mesa_buffersize
) {
931 mpglFreeMemoryMESA(mDisplay
, mScreen
, mesa_bufferptr
);
932 mesa_bufferptr
= NULL
;
935 mesa_bufferptr
= mpglAllocateMemoryMESA(mDisplay
, mScreen
, needed_size
, 0, 1.0, 1.0);
936 mesa_buffersize
= needed_size
;
938 mpi
->planes
[0] = mesa_bufferptr
;
941 mpglGenBuffers(1, &gl_buffer
);
942 mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, gl_buffer
);
943 if (needed_size
> gl_buffersize
) {
944 gl_buffersize
= needed_size
;
945 mpglBufferData(GL_PIXEL_UNPACK_BUFFER
, gl_buffersize
,
946 NULL
, GL_DYNAMIC_DRAW
);
949 gl_bufferptr
= mpglMapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_WRITE_ONLY
);
950 mpi
->planes
[0] = gl_bufferptr
;
951 mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
953 if (!mpi
->planes
[0]) {
955 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] could not acquire buffer for dr\n"
956 "Expect a _major_ speed penalty\n");
962 int xs
, ys
, component_bits
;
963 mp_get_chroma_shift(image_format
, &xs
, &ys
, &component_bits
);
964 int bp
= (component_bits
+ 7) / 8;
965 mpi
->flags
|= MP_IMGFLAG_COMMON_STRIDE
| MP_IMGFLAG_COMMON_PLANE
;
966 mpi
->stride
[0] = mpi
->width
* bp
;
967 mpi
->planes
[1] = mpi
->planes
[0] + mpi
->stride
[0] * mpi
->height
;
968 mpi
->stride
[1] = (mpi
->width
>> xs
) * bp
;
969 mpi
->planes
[2] = mpi
->planes
[1] + mpi
->stride
[1] * (mpi
->height
>> ys
);
970 mpi
->stride
[2] = (mpi
->width
>> xs
) * bp
;
971 if (ati_hack
&& !mesa_buffer
) {
972 mpi
->flags
&= ~MP_IMGFLAG_COMMON_PLANE
;
973 if (!gl_buffer_uv
[0]) mpglGenBuffers(2, gl_buffer_uv
);
974 if (mpi
->stride
[1] * mpi
->height
> gl_buffersize_uv
) {
975 mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, gl_buffer_uv
[0]);
976 mpglBufferData(GL_PIXEL_UNPACK_BUFFER
, mpi
->stride
[1] * mpi
->height
,
977 NULL
, GL_DYNAMIC_DRAW
);
978 mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, gl_buffer_uv
[1]);
979 mpglBufferData(GL_PIXEL_UNPACK_BUFFER
, mpi
->stride
[1] * mpi
->height
,
980 NULL
, GL_DYNAMIC_DRAW
);
981 gl_buffersize_uv
= mpi
->stride
[1] * mpi
->height
;
983 if (!gl_bufferptr_uv
[0]) {
984 mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, gl_buffer_uv
[0]);
985 gl_bufferptr_uv
[0] = mpglMapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_WRITE_ONLY
);
986 mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, gl_buffer_uv
[1]);
987 gl_bufferptr_uv
[1] = mpglMapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_WRITE_ONLY
);
989 mpi
->planes
[1] = gl_bufferptr_uv
[0];
990 mpi
->planes
[2] = gl_bufferptr_uv
[1];
993 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
997 static void clear_border(uint8_t *dst
, int start
, int stride
, int height
, int full_height
, int value
) {
998 int right_border
= stride
- start
;
999 int bottom_border
= full_height
- height
;
1000 while (height
> 0) {
1001 memset(dst
+ start
, value
, right_border
);
1005 if (bottom_border
> 0)
1006 memset(dst
, value
, stride
* bottom_border
);
1009 static uint32_t draw_image(mp_image_t
*mpi
) {
1010 int slice
= slice_height
;
1012 unsigned char *planes
[3];
1013 mp_image_t mpi2
= *mpi
;
1014 int w
= mpi
->w
, h
= mpi
->h
;
1015 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
1017 mpi2
.flags
= 0; mpi2
.type
= MP_IMGTYPE_TEMP
;
1018 mpi2
.width
= mpi2
.w
; mpi2
.height
= mpi2
.h
;
1019 if (force_pbo
&& !(mpi
->flags
& MP_IMGFLAG_DIRECT
) && !gl_bufferptr
&& get_image(&mpi2
) == VO_TRUE
) {
1021 int xs
, ys
, component_bits
;
1022 mp_get_chroma_shift(image_format
, &xs
, &ys
, &component_bits
);
1024 bpp
= component_bits
+ 7;
1025 memcpy_pic(mpi2
.planes
[0], mpi
->planes
[0], mpi
->w
* bpp
/ 8, mpi
->h
, mpi2
.stride
[0], mpi
->stride
[0]);
1027 int bp
= (component_bits
+ 7) / 8;
1028 memcpy_pic(mpi2
.planes
[1], mpi
->planes
[1], (mpi
->w
>> xs
) * bp
, mpi
->h
>> ys
, mpi2
.stride
[1], mpi
->stride
[1]);
1029 memcpy_pic(mpi2
.planes
[2], mpi
->planes
[2], (mpi
->w
>> xs
) * bp
, mpi
->h
>> ys
, mpi2
.stride
[2], mpi
->stride
[2]);
1031 if (ati_hack
) { // since we have to do a full upload we need to clear the borders
1032 clear_border(mpi2
.planes
[0], mpi
->w
* bpp
/ 8, mpi2
.stride
[0], mpi
->h
, mpi2
.height
, 0);
1034 clear_border(mpi2
.planes
[1], mpi
->w
>> xs
, mpi2
.stride
[1], mpi
->h
>> ys
, mpi2
.height
>> ys
, 128);
1035 clear_border(mpi2
.planes
[2], mpi
->w
>> xs
, mpi2
.stride
[2], mpi
->h
>> ys
, mpi2
.height
>> ys
, 128);
1040 stride
[0] = mpi
->stride
[0]; stride
[1] = mpi
->stride
[1]; stride
[2] = mpi
->stride
[2];
1041 planes
[0] = mpi
->planes
[0]; planes
[1] = mpi
->planes
[1]; planes
[2] = mpi
->planes
[2];
1042 mpi_flipped
= stride
[0] < 0;
1043 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1045 mpglPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, 1);
1048 intptr_t base
= (intptr_t)planes
[0];
1049 if (ati_hack
) { w
= texture_width
; h
= texture_height
; }
1051 base
+= (mpi
->h
- 1) * stride
[0];
1055 mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, gl_buffer
);
1056 mpglUnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1057 gl_bufferptr
= NULL
;
1058 if (!(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
))
1059 planes
[0] = planes
[1] = planes
[2] = NULL
;
1061 slice
= 0; // always "upload" full texture
1063 glUploadTex(gl_target
, gl_format
, gl_type
, planes
[0], stride
[0],
1064 mpi
->x
, mpi
->y
, w
, h
, slice
);
1067 mp_get_chroma_shift(image_format
, &xs
, &ys
, NULL
);
1068 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1069 mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, gl_buffer_uv
[0]);
1070 mpglUnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1071 gl_bufferptr_uv
[0] = NULL
;
1073 mpglActiveTexture(GL_TEXTURE1
);
1074 glUploadTex(gl_target
, gl_format
, gl_type
, planes
[1], stride
[1],
1075 mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
, slice
);
1076 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1077 mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, gl_buffer_uv
[1]);
1078 mpglUnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1079 gl_bufferptr_uv
[1] = NULL
;
1081 mpglActiveTexture(GL_TEXTURE2
);
1082 glUploadTex(gl_target
, gl_format
, gl_type
, planes
[2], stride
[2],
1083 mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
, slice
);
1084 mpglActiveTexture(GL_TEXTURE0
);
1086 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1087 if (mesa_buffer
) mpglPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, 0);
1088 else mpglBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1091 if (vo_doublebuffering
) do_render();
1096 draw_frame(uint8_t *src
[])
1102 query_format(uint32_t format
)
1105 int caps
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
|
1107 VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1109 caps
|= VFCAP_OSD
| VFCAP_EOSD
| (scaled_osd
? 0 : VFCAP_EOSD_UNSCALED
);
1110 if (format
== IMGFMT_RGB24
|| format
== IMGFMT_RGBA
)
1112 if (use_yuv
&& mp_get_chroma_shift(format
, NULL
, NULL
, &depth
) &&
1113 (depth
== 8 || depth
== 16 || glYUVLargeRange(use_yuv
)) &&
1114 (IMGFMT_IS_YUVP16_NE(format
) || !IMGFMT_IS_YUVP16(format
)))
1116 // HACK, otherwise we get only b&w with some filters (e.g. -vf eq)
1117 // ideally MPlayer should be fixed instead not to use Y800 when it has the choice
1118 if (!use_yuv
&& (format
== IMGFMT_Y8
|| format
== IMGFMT_Y800
))
1120 if (!use_ycbcr
&& (format
== IMGFMT_UYVY
|| format
== IMGFMT_YVYU
))
1123 glFindFormat(format
, NULL
, NULL
, NULL
, NULL
))
1137 uninit_mpglcontext(&glctx
);
1140 static const opt_t subopts
[] = {
1141 {"manyfmts", OPT_ARG_BOOL
, &many_fmts
, NULL
},
1142 {"osd", OPT_ARG_BOOL
, &use_osd
, NULL
},
1143 {"scaled-osd", OPT_ARG_BOOL
, &scaled_osd
, NULL
},
1144 {"aspect", OPT_ARG_BOOL
, &use_aspect
, NULL
},
1145 {"ycbcr", OPT_ARG_BOOL
, &use_ycbcr
, NULL
},
1146 {"slice-height", OPT_ARG_INT
, &slice_height
, int_non_neg
},
1147 {"rectangle", OPT_ARG_INT
, &use_rectangle
,int_non_neg
},
1148 {"yuv", OPT_ARG_INT
, &use_yuv
, int_non_neg
},
1149 {"colorspace", OPT_ARG_INT
, &user_colorspace
, NULL
},
1150 {"levelconv", OPT_ARG_INT
, &levelconv
, NULL
},
1151 {"lscale", OPT_ARG_INT
, &lscale
, int_non_neg
},
1152 {"cscale", OPT_ARG_INT
, &cscale
, int_non_neg
},
1153 {"filter-strength", OPT_ARG_FLOAT
, &filter_strength
, NULL
},
1154 {"ati-hack", OPT_ARG_BOOL
, &ati_hack
, NULL
},
1155 {"force-pbo", OPT_ARG_BOOL
, &force_pbo
, NULL
},
1156 {"mesa-buffer", OPT_ARG_BOOL
, &mesa_buffer
, NULL
},
1157 {"glfinish", OPT_ARG_BOOL
, &use_glFinish
, NULL
},
1158 {"swapinterval", OPT_ARG_INT
, &swap_interval
,NULL
},
1159 {"customprog", OPT_ARG_MSTRZ
,&custom_prog
, NULL
},
1160 {"customtex", OPT_ARG_MSTRZ
,&custom_tex
, NULL
},
1161 {"customtlin", OPT_ARG_BOOL
, &custom_tlin
, NULL
},
1162 {"customtrect", OPT_ARG_BOOL
, &custom_trect
, NULL
},
1163 {"mipmapgen", OPT_ARG_BOOL
, &mipmap_gen
, NULL
},
1164 {"osdcolor", OPT_ARG_INT
, &osd_color
, NULL
},
1165 {"stereo", OPT_ARG_INT
, &stereo_mode
, NULL
},
1169 static int preinit_internal(const char *arg
, int allow_sw
)
1172 enum MPGLType gltype
= GLTYPE_AUTO
;
1179 user_colorspace
= 0;
1183 filter_strength
= 0.5;
1196 osd_color
= 0xffffff;
1198 if (subopt_parse(arg
, subopts
) != 0) {
1199 mp_msg(MSGT_VO
, MSGL_FATAL
,
1200 "\n-vo gl command line help:\n"
1201 "Example: mplayer -vo gl:slice-height=4\n"
1204 " Disable extended color formats for OpenGL 1.2 and later\n"
1205 " slice-height=<0-...>\n"
1206 " Slice size for texture transfer, 0 for whole image\n"
1208 " Do not use OpenGL OSD code\n"
1210 " Render OSD at movie resolution and scale it\n"
1212 " Do not do aspect scaling\n"
1213 " rectangle=<0,1,2>\n"
1214 " 0: use power-of-two textures\n"
1215 " 1: use texture_rectangle\n"
1216 " 2: use texture_non_power_of_two\n"
1218 " Workaround ATI bug with PBOs\n"
1220 " Force use of PBO even if this involves an extra memcpy\n"
1222 " Call glFinish() before swapping buffers\n"
1223 " swapinterval=<n>\n"
1224 " Interval in displayed frames between to buffer swaps.\n"
1225 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
1226 " Requires GLX_SGI_swap_control support to work.\n"
1228 " also try to use the GL_MESA_ycbcr_texture extension\n"
1230 " 0: use software YUV to RGB conversion.\n"
1231 " 1: use register combiners (nVidia only, for older cards).\n"
1232 " 2: use fragment program.\n"
1233 " 3: use fragment program with gamma correction.\n"
1234 " 4: use fragment program with gamma correction via lookup.\n"
1235 " 5: use ATI-specific method (for older cards).\n"
1236 " 6: use lookup via 3D texture.\n"
1238 " 0: use standard bilinear scaling for luma.\n"
1239 " 1: use improved bicubic scaling for luma.\n"
1240 " 2: use cubic in X, linear in Y direction scaling for luma.\n"
1241 " 3: as 1 but without using a lookup texture.\n"
1242 " 4: experimental unsharp masking (sharpening).\n"
1243 " 5: experimental unsharp masking (sharpening) with larger radius.\n"
1245 " as lscale but for chroma (2x slower with little visible effect).\n"
1246 " filter-strength=<value>\n"
1247 " set the effect strength for some lscale/cscale filters\n"
1248 " customprog=<filename>\n"
1249 " use a custom YUV conversion program\n"
1250 " customtex=<filename>\n"
1251 " use a custom YUV conversion lookup texture\n"
1253 " use GL_NEAREST scaling for customtex texture\n"
1255 " use texture_rectangle for customtex texture\n"
1257 " generate mipmaps for the video image (use with TXB in customprog)\n"
1258 " osdcolor=<0xAARRGGBB>\n"
1259 " use the given color for the OSD\n"
1261 " 0: normal display\n"
1262 " 1: side-by-side to red-cyan stereo\n"
1263 " 2: side-by-side to green-magenta stereo\n"
1264 " 3: side-by-side to quadbuffer stereo\n"
1268 if (user_colorspace
!= 0 || levelconv
!= -1) {
1269 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"colorspace\" and \"levelconv\" "
1270 "suboptions have been removed. Use options --colormatrix and"
1271 " --colormatrix-input-range/--colormatrix-output-range instead.\n");
1274 if (!init_mpglcontext(&glctx
, gltype
))
1276 if (use_yuv
== -1 || !allow_sw
) {
1277 if (create_window(320, 200, VOFLAG_HIDDEN
, NULL
) < 0)
1279 if (glctx
.setGlWindow(&glctx
) == SET_WINDOW_FAILED
)
1281 if (!allow_sw
&& isSoftwareGl())
1283 autodetectGlExtensions();
1286 mp_msg(MSGT_VO
, MSGL_INFO
, "[gl] using extended formats. "
1287 "Use -vo gl:nomanyfmts if playback fails.\n");
1288 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Using %d as slice height "
1289 "(0 means image height).\n", slice_height
);
1298 static int preinit(const char *arg
)
1300 return preinit_internal(arg
, 1);
1303 static int preinit_nosw(const char *arg
)
1305 return preinit_internal(arg
, 0);
1308 static int control(uint32_t request
, void *data
)
1313 int_pause
= (request
== VOCTRL_PAUSE
);
1315 case VOCTRL_QUERY_FORMAT
:
1316 return query_format(*(uint32_t*)data
);
1317 case VOCTRL_GET_IMAGE
:
1318 return get_image(data
);
1319 case VOCTRL_DRAW_IMAGE
:
1320 return draw_image(data
);
1321 case VOCTRL_DRAW_EOSD
:
1325 if (vo_doublebuffering
) do_render_osd(RENDER_EOSD
);
1327 case VOCTRL_GET_EOSD_RES
:
1329 mp_eosd_res_t
*r
= data
;
1330 r
->w
= vo_dwidth
; r
->h
= vo_dheight
;
1331 r
->mt
= r
->mb
= r
->ml
= r
->mr
= 0;
1332 if (scaled_osd
) {r
->w
= image_width
; r
->h
= image_height
;}
1333 else if (aspect_scaling()) {
1334 r
->ml
= r
->mr
= ass_border_x
;
1335 r
->mt
= r
->mb
= ass_border_y
;
1342 case VOCTRL_FULLSCREEN
:
1344 resize(vo_dwidth
, vo_dheight
);
1348 resize(vo_dwidth
, vo_dheight
);
1350 case VOCTRL_GET_PANSCAN
:
1351 if (!use_aspect
) return VO_NOTIMPL
;
1353 case VOCTRL_SET_PANSCAN
:
1354 if (!use_aspect
) return VO_NOTIMPL
;
1355 resize(vo_dwidth
, vo_dheight
);
1357 case VOCTRL_GET_EQUALIZER
:
1359 struct voctrl_get_equalizer_args
*args
= data
;
1360 return mp_csp_equalizer_get(&video_eq
, args
->name
, args
->valueptr
) >= 0 ?
1361 VO_TRUE
: VO_NOTIMPL
;
1364 case VOCTRL_SET_EQUALIZER
:
1366 struct voctrl_set_equalizer_args
*args
= data
;
1367 if (mp_csp_equalizer_set(&video_eq
, args
->name
, args
->value
) < 0)
1373 case VOCTRL_SET_YUV_COLORSPACE
: {
1374 bool supports_csp
= (1 << use_yuv
) & MASK_NOT_COMBINERS
;
1375 if (vo_config_count
&& supports_csp
) {
1376 colorspace
= *(struct mp_csp_details
*)data
;
1381 case VOCTRL_GET_YUV_COLORSPACE
:
1382 *(struct mp_csp_details
*)data
= colorspace
;
1384 case VOCTRL_UPDATE_SCREENINFO
:
1385 glctx
.update_xinerama_info();
1387 case VOCTRL_REDRAW_OSD
:
1388 if (vo_doublebuffering
)
1391 if (vo_doublebuffering
)