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_bits
= depth
;
224 params
.csp_params
.texture_bits
= depth
+7 & ~7;
225 glSetupYUVConversion(gl
, ¶ms
);
226 if (p
->custom_prog
) {
227 FILE *f
= fopen(p
->custom_prog
, "rb");
229 mp_msg(MSGT_VO
, MSGL_WARN
,
230 "[gl] Could not read customprog %s\n", p
->custom_prog
);
232 char *prog
= calloc(1, MAX_CUSTOM_PROG_SIZE
+ 1);
233 fread(prog
, 1, MAX_CUSTOM_PROG_SIZE
, f
);
235 loadGPUProgram(gl
, GL_FRAGMENT_PROGRAM
, prog
);
238 gl
->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 0,
239 1.0 / p
->texture_width
,
240 1.0 / p
->texture_height
,
241 p
->texture_width
, p
->texture_height
);
244 FILE *f
= fopen(p
->custom_tex
, "rb");
246 mp_msg(MSGT_VO
, MSGL_WARN
,
247 "[gl] Could not read customtex %s\n", p
->custom_tex
);
249 int width
, height
, maxval
;
250 gl
->ActiveTexture(GL_TEXTURE3
);
251 if (glCreatePPMTex(gl
, p
->custom_trect
? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
,
252 0, p
->custom_tlin
? GL_LINEAR
: GL_NEAREST
,
253 f
, &width
, &height
, &maxval
)) {
254 gl
->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 1,
255 1.0 / width
, 1.0 / height
,
258 mp_msg(MSGT_VO
, MSGL_WARN
,
259 "[gl] Error parsing customtex %s\n", p
->custom_tex
);
261 gl
->ActiveTexture(GL_TEXTURE0
);
267 * \brief remove all OSD textures and display-lists, thus clearing it.
269 static void clearOSD(struct vo
*vo
)
271 struct gl_priv
*p
= vo
->priv
;
277 gl
->DeleteTextures(p
->osdtexCnt
, p
->osdtex
);
279 gl
->DeleteTextures(p
->osdtexCnt
, p
->osdatex
);
280 for (i
= 0; i
< p
->osdtexCnt
; i
++)
281 gl
->DeleteLists(p
->osdaDispList
[i
], 1);
283 for (i
= 0; i
< p
->osdtexCnt
; i
++)
284 gl
->DeleteLists(p
->osdDispList
[i
], 1);
289 * \brief remove textures, display list and free memory used by EOSD
291 static void clearEOSD(struct vo
*vo
)
293 struct gl_priv
*p
= vo
->priv
;
297 gl
->DeleteLists(p
->eosdDispList
, 1);
300 gl
->DeleteTextures(p
->eosdtexCnt
, p
->eosdtex
);
306 static inline int is_tinytex(ASS_Image
*i
, int tinytexcur
)
308 return i
->w
< TINYTEX_SIZE
&& i
->h
< TINYTEX_SIZE
309 && tinytexcur
< TINYTEX_MAX
;
312 static inline int is_smalltex(ASS_Image
*i
, int smalltexcur
)
314 return i
->w
< SMALLTEX_SIZE
&& i
->h
< SMALLTEX_SIZE
315 && smalltexcur
< SMALLTEX_MAX
;
318 static inline void tinytex_pos(int tinytexcur
, int *x
, int *y
)
320 *x
= (tinytexcur
% TINYTEX_COLS
) * TINYTEX_SIZE
;
321 *y
= (tinytexcur
/ TINYTEX_COLS
) * TINYTEX_SIZE
;
324 static inline void smalltex_pos(int smalltexcur
, int *x
, int *y
)
326 *x
= (smalltexcur
% SMALLTEX_COLS
) * SMALLTEX_SIZE
;
327 *y
= (smalltexcur
/ SMALLTEX_COLS
) * SMALLTEX_SIZE
;
331 * \brief construct display list from ass image list
332 * \param img image list to create OSD from.
333 * A value of NULL has the same effect as clearEOSD()
335 static void genEOSD(struct vo
*vo
, mp_eosd_images_t
*imgs
)
337 struct gl_priv
*p
= vo
->priv
;
344 GLint scale_type
= p
->scaled_osd
? GL_LINEAR
: GL_NEAREST
;
345 ASS_Image
*img
= imgs
->imgs
;
348 if (imgs
->changed
== 0) // there are elements, but they are unchanged
350 if (img
&& imgs
->changed
== 1) // there are elements, but they just moved
356 if (!p
->largeeosdtex
[0]) {
357 gl
->GenTextures(2, p
->largeeosdtex
);
358 for (int n
= 0; n
< 2; n
++) {
359 gl
->BindTexture(p
->target
, p
->largeeosdtex
[n
]);
360 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
,
361 GL_UNSIGNED_BYTE
, scale_type
,
362 LARGE_EOSD_TEX_SIZE
, LARGE_EOSD_TEX_SIZE
, 0);
365 for (i
= img
; i
; i
= i
->next
) {
366 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
)
368 if (is_tinytex(i
, tinytexcur
))
370 else if (is_smalltex(i
, smalltexcur
))
375 mp_msg(MSGT_VO
, MSGL_DBG2
, "EOSD counts (tiny, small, all): %i, %i, %i\n",
376 tinytexcur
, smalltexcur
, p
->eosdtexCnt
);
378 p
->eosdtex
= calloc(p
->eosdtexCnt
, sizeof(GLuint
));
379 gl
->GenTextures(p
->eosdtexCnt
, p
->eosdtex
);
381 tinytexcur
= smalltexcur
= 0;
382 for (i
= img
, curtex
= p
->eosdtex
; i
; i
= i
->next
) {
384 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
) {
385 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
388 if (is_tinytex(i
, tinytexcur
)) {
389 tinytex_pos(tinytexcur
, &x
, &y
);
390 gl
->BindTexture(p
->target
, p
->largeeosdtex
[0]);
392 } else if (is_smalltex(i
, smalltexcur
)) {
393 smalltex_pos(smalltexcur
, &x
, &y
);
394 gl
->BindTexture(p
->target
, p
->largeeosdtex
[1]);
397 texSize(vo
, i
->w
, i
->h
, &sx
, &sy
);
398 gl
->BindTexture(p
->target
, *curtex
++);
399 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
,
400 GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
402 glUploadTex(gl
, p
->target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, i
->bitmap
,
403 i
->stride
, x
, y
, i
->w
, i
->h
, 0);
405 p
->eosdDispList
= gl
->GenLists(1);
407 gl
->NewList(p
->eosdDispList
, GL_COMPILE
);
408 tinytexcur
= smalltexcur
= 0;
409 for (i
= img
, curtex
= p
->eosdtex
; i
; i
= i
->next
) {
411 if (i
->w
<= 0 || i
->h
<= 0 || i
->stride
< i
->w
)
413 gl
->Color4ub(i
->color
>> 24, (i
->color
>> 16) & 0xff,
414 (i
->color
>> 8) & 0xff, 255 - (i
->color
& 0xff));
415 if (is_tinytex(i
, tinytexcur
)) {
416 tinytex_pos(tinytexcur
, &x
, &y
);
417 sx
= sy
= LARGE_EOSD_TEX_SIZE
;
418 gl
->BindTexture(p
->target
, p
->largeeosdtex
[0]);
420 } else if (is_smalltex(i
, smalltexcur
)) {
421 smalltex_pos(smalltexcur
, &x
, &y
);
422 sx
= sy
= LARGE_EOSD_TEX_SIZE
;
423 gl
->BindTexture(p
->target
, p
->largeeosdtex
[1]);
426 texSize(vo
, i
->w
, i
->h
, &sx
, &sy
);
427 gl
->BindTexture(p
->target
, *curtex
++);
429 glDrawTex(gl
, i
->dst_x
, i
->dst_y
, i
->w
, i
->h
, x
, y
, i
->w
, i
->h
, sx
, sy
,
430 p
->use_rectangle
== 1, 0, 0);
433 gl
->BindTexture(p
->target
, 0);
437 * \brief uninitialize OpenGL context, freeing textures, buffers etc.
439 static void uninitGl(struct vo
*vo
)
441 struct gl_priv
*p
= vo
->priv
;
445 if (gl
->DeletePrograms
&& p
->fragprog
)
446 gl
->DeletePrograms(1, &p
->fragprog
);
448 while (p
->default_texs
[i
] != 0)
451 gl
->DeleteTextures(i
, p
->default_texs
);
452 p
->default_texs
[0] = 0;
455 if (p
->largeeosdtex
[0])
456 gl
->DeleteTextures(2, p
->largeeosdtex
);
457 p
->largeeosdtex
[0] = 0;
458 if (gl
->DeleteBuffers
&& p
->buffer
)
459 gl
->DeleteBuffers(1, &p
->buffer
);
463 if (gl
->DeleteBuffers
&& p
->buffer_uv
[0])
464 gl
->DeleteBuffers(2, p
->buffer_uv
);
465 p
->buffer_uv
[0] = p
->buffer_uv
[1] = 0;
466 p
->buffersize_uv
= 0;
467 p
->bufferptr_uv
[0] = p
->bufferptr_uv
[1] = 0;
471 static int isSoftwareGl(struct vo
*vo
)
473 struct gl_priv
*p
= vo
->priv
;
474 const char *renderer
= p
->gl
->GetString(GL_RENDERER
);
475 return !renderer
|| strcmp(renderer
, "Software Rasterizer") == 0 ||
476 strstr(renderer
, "llvmpipe");
479 static void autodetectGlExtensions(struct vo
*vo
)
481 struct gl_priv
*p
= vo
->priv
;
484 const char *extensions
= gl
->GetString(GL_EXTENSIONS
);
485 const char *vendor
= gl
->GetString(GL_VENDOR
);
486 const char *version
= gl
->GetString(GL_VERSION
);
487 const char *renderer
= gl
->GetString(GL_RENDERER
);
488 int is_ati
= vendor
&& strstr(vendor
, "ATI") != NULL
;
489 int ati_broken_pbo
= 0;
490 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Running on OpenGL '%s' by '%s', version '%s'\n",
491 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 (p
->ati_hack
== -1)
498 p
->ati_hack
= ati_broken_pbo
;
499 if (p
->force_pbo
== -1) {
501 if (extensions
&& strstr(extensions
, "_pixel_buffer_object"))
502 p
->force_pbo
= is_ati
;
504 p
->have_texture_rg
= extensions
&& strstr(extensions
, "GL_ARB_texture_rg");
505 if (p
->use_rectangle
== -1) {
506 p
->use_rectangle
= 0;
508 // if (strstr(extensions, "_texture_non_power_of_two"))
509 if (strstr(extensions
, "_texture_rectangle"))
510 p
->use_rectangle
= renderer
511 && strstr(renderer
, "Mesa DRI R200") ? 1 : 0;
514 if (p
->use_osd
== -1)
515 p
->use_osd
= gl
->BindTexture
!= NULL
;
516 if (p
->use_yuv
== -1)
517 p
->use_yuv
= glAutodetectYUVConversion(gl
);
520 int yuv_mask
= (1 << p
->use_yuv
);
521 if (!(yuv_mask
& MASK_NOT_COMBINERS
)) {
523 eq_caps
= (1 << MP_CSP_EQ_HUE
) | (1 << MP_CSP_EQ_SATURATION
);
524 } else if (yuv_mask
& MASK_ALL_YUV
) {
525 eq_caps
= MP_CSP_EQ_CAPS_COLORMATRIX
;
526 if (yuv_mask
& MASK_GAMMA_SUPPORT
)
527 eq_caps
|= MP_CSP_EQ_CAPS_GAMMA
;
529 p
->video_eq
.capabilities
= eq_caps
;
531 if (is_ati
&& (p
->lscale
== 1 || p
->lscale
== 2 || p
->cscale
== 1 || p
->cscale
== 2))
532 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] Selected scaling mode may be broken on"
534 "Tell _them_ to fix GL_REPEAT if you have issues.\n");
535 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Settings after autodetection: ati-hack = %i, "
536 "force-pbo = %i, rectangle = %i, yuv = %i\n",
537 p
->ati_hack
, p
->force_pbo
, p
->use_rectangle
, p
->use_yuv
);
540 static GLint
get_scale_type(struct vo
*vo
, int chroma
)
542 struct gl_priv
*p
= vo
->priv
;
544 int nearest
= (chroma
? p
->cscale
: p
->lscale
) & 64;
546 return p
->mipmap_gen
? GL_NEAREST_MIPMAP_NEAREST
: GL_NEAREST
;
547 return p
->mipmap_gen
? GL_LINEAR_MIPMAP_NEAREST
: GL_LINEAR
;
550 // Return the high byte of the value that represents white in chroma (U/V)
551 static int get_chroma_clear_val(int bit_depth
)
553 return 1 << (bit_depth
- 1 & 7);
557 * \brief Initialize a (new or reused) OpenGL context.
558 * set global gl-related variables to their default values
560 static int initGl(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
)
562 struct gl_priv
*p
= vo
->priv
;
565 GLint scale_type
= get_scale_type(vo
, 0);
566 autodetectGlExtensions(vo
);
567 p
->target
= p
->use_rectangle
== 1 ? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
;
568 p
->yuvconvtype
= SET_YUV_CONVERSION(p
->use_yuv
) |
569 SET_YUV_LUM_SCALER(p
->lscale
) |
570 SET_YUV_CHROM_SCALER(p
->cscale
);
572 texSize(vo
, p
->image_width
, p
->image_height
,
573 &p
->texture_width
, &p
->texture_height
);
575 gl
->Disable(GL_BLEND
);
576 gl
->Disable(GL_DEPTH_TEST
);
577 gl
->DepthMask(GL_FALSE
);
578 gl
->Disable(GL_CULL_FACE
);
579 gl
->Enable(p
->target
);
580 gl
->DrawBuffer(vo_doublebuffering
? GL_BACK
: GL_FRONT
);
581 gl
->TexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
583 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Creating %dx%d texture...\n",
584 p
->texture_width
, p
->texture_height
);
586 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
587 p
->gl_type
, scale_type
,
588 p
->texture_width
, p
->texture_height
, 0);
591 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
596 scale_type
= get_scale_type(vo
, 1);
597 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &depth
);
598 int clear
= get_chroma_clear_val(depth
);
599 gl
->GenTextures(21, p
->default_texs
);
600 p
->default_texs
[21] = 0;
601 for (i
= 0; i
< 7; i
++) {
602 gl
->ActiveTexture(GL_TEXTURE1
+ i
);
603 gl
->BindTexture(GL_TEXTURE_2D
, p
->default_texs
[i
]);
604 gl
->BindTexture(GL_TEXTURE_RECTANGLE
, p
->default_texs
[i
+ 7]);
605 gl
->BindTexture(GL_TEXTURE_3D
, p
->default_texs
[i
+ 14]);
607 gl
->ActiveTexture(GL_TEXTURE1
);
608 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
609 p
->gl_type
, scale_type
,
610 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
613 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
614 gl
->ActiveTexture(GL_TEXTURE2
);
615 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
616 p
->gl_type
, scale_type
,
617 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
620 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
621 gl
->ActiveTexture(GL_TEXTURE0
);
622 gl
->BindTexture(p
->target
, 0);
624 if (p
->is_yuv
|| p
->custom_prog
) {
625 if ((MASK_NOT_COMBINERS
& (1 << p
->use_yuv
)) || p
->custom_prog
) {
626 if (!gl
->GenPrograms
|| !gl
->BindProgram
)
627 mp_msg(MSGT_VO
, MSGL_ERR
,
628 "[gl] fragment program functions missing!\n");
630 gl
->GenPrograms(1, &p
->fragprog
);
631 gl
->BindProgram(GL_FRAGMENT_PROGRAM
, p
->fragprog
);
637 resize(vo
, d_width
, d_height
);
639 gl
->ClearColor(0.0f
, 0.0f
, 0.0f
, 0.0f
);
640 gl
->Clear(GL_COLOR_BUFFER_BIT
);
641 if (gl
->SwapInterval
&& p
->swap_interval
>= 0)
642 gl
->SwapInterval(p
->swap_interval
);
646 static int create_window(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
,
649 struct gl_priv
*p
= vo
->priv
;
651 if (p
->stereo_mode
== GL_3D_QUADBUFFER
)
652 flags
|= VOFLAG_STEREO
;
654 return p
->glctx
->create_window(p
->glctx
, d_width
, d_height
, flags
);
657 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
658 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
661 struct gl_priv
*p
= vo
->priv
;
664 p
->image_height
= height
;
665 p
->image_width
= width
;
666 p
->image_format
= format
;
667 p
->image_d_width
= d_width
;
668 p
->image_d_height
= d_height
;
669 p
->is_yuv
= mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
) > 0;
670 p
->is_yuv
|= (xs
<< 8) | (ys
<< 16);
671 glFindFormat(format
, p
->have_texture_rg
, NULL
, &p
->texfmt
, &p
->gl_format
,
674 p
->vo_flipped
= !!(flags
& VOFLAG_FLIPPING
);
676 if (create_window(vo
, d_width
, d_height
, flags
) < 0)
679 if (vo
->config_count
)
681 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
683 initGl(vo
, vo
->dwidth
, vo
->dheight
);
688 static void check_events(struct vo
*vo
)
690 struct gl_priv
*p
= vo
->priv
;
692 int e
= p
->glctx
->check_events(vo
);
693 if (e
& VO_EVENT_REINIT
) {
695 initGl(vo
, vo
->dwidth
, vo
->dheight
);
697 if (e
& VO_EVENT_RESIZE
)
698 resize(vo
, vo
->dwidth
, vo
->dheight
);
699 if (e
& VO_EVENT_EXPOSE
)
700 vo
->want_redraw
= true;
704 * Creates the textures and the display list needed for displaying
706 * Callback function for osd_draw_text_ext().
708 static void create_osd_texture(void *ctx
, int x0
, int y0
, int w
, int h
,
709 unsigned char *src
, unsigned char *srca
,
713 struct gl_priv
*p
= vo
->priv
;
716 // initialize to 8 to avoid special-casing on alignment
718 GLint scale_type
= p
->scaled_osd
? GL_LINEAR
: GL_NEAREST
;
720 if (w
<= 0 || h
<= 0 || stride
< w
) {
721 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
724 texSize(vo
, w
, h
, &sx
, &sy
);
726 if (p
->osdtexCnt
>= MAX_OSD_PARTS
) {
727 mp_msg(MSGT_VO
, MSGL_ERR
, "Too many OSD parts, contact the developers!\n");
731 // create Textures for OSD part
732 gl
->GenTextures(1, &p
->osdtex
[p
->osdtexCnt
]);
733 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
734 glCreateClearTex(gl
, p
->target
, GL_LUMINANCE
, GL_LUMINANCE
,
735 GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
736 glUploadTex(gl
, p
->target
, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, src
, stride
,
740 gl
->GenTextures(1, &p
->osdatex
[p
->osdtexCnt
]);
741 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
742 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
,
743 scale_type
, sx
, sy
, 0);
746 char *tmp
= malloc(stride
* h
);
747 // convert alpha from weird MPlayer scale.
748 // in-place is not possible since it is reused for future OSDs
749 for (i
= h
* stride
- 1; i
>= 0; i
--)
751 glUploadTex(gl
, p
->target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, tmp
, stride
,
757 gl
->BindTexture(p
->target
, 0);
759 // Create a list for rendering this OSD part
761 p
->osdaDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
762 gl
->NewList(p
->osdaDispList
[p
->osdtexCnt
], GL_COMPILE
);
764 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
765 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
768 p
->osdDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
769 gl
->NewList(p
->osdDispList
[p
->osdtexCnt
], GL_COMPILE
);
771 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
772 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
779 #define RENDER_EOSD 2
782 * \param type bit 0: render OSD, bit 1: render EOSD
784 static void do_render_osd(struct vo
*vo
, int type
)
786 struct gl_priv
*p
= vo
->priv
;
789 int draw_osd
= (type
& RENDER_OSD
) && p
->osdtexCnt
> 0;
790 int draw_eosd
= (type
& RENDER_EOSD
) && p
->eosdDispList
;
791 if (!draw_osd
&& !draw_eosd
)
793 // set special rendering parameters
794 if (!p
->scaled_osd
) {
795 gl
->MatrixMode(GL_PROJECTION
);
798 gl
->Ortho(0, vo
->dwidth
, vo
->dheight
, 0, -1, 1);
800 gl
->Enable(GL_BLEND
);
802 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
803 gl
->CallList(p
->eosdDispList
);
806 gl
->Color4ub((p
->osd_color
>> 16) & 0xff, (p
->osd_color
>> 8) & 0xff,
807 p
->osd_color
& 0xff, 0xff - (p
->osd_color
>> 24));
810 gl
->BlendFunc(GL_ZERO
, GL_ONE_MINUS_SRC_ALPHA
);
811 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdaDispList
);
813 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE
);
814 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdDispList
);
816 // set rendering parameters back to defaults
817 gl
->Disable(GL_BLEND
);
820 gl
->BindTexture(p
->target
, 0);
823 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
825 struct gl_priv
*p
= vo
->priv
;
829 if (vo_osd_changed(0)) {
832 osd_w
= p
->scaled_osd
? p
->image_width
: vo
->dwidth
;
833 osd_h
= p
->scaled_osd
? p
->image_height
: vo
->dheight
;
834 osd_draw_text_ext(osd
, osd_w
, osd_h
, p
->ass_border_x
,
835 p
->ass_border_y
, p
->ass_border_x
,
836 p
->ass_border_y
, p
->image_width
,
837 p
->image_height
, create_osd_texture
, vo
);
839 if (vo_doublebuffering
)
840 do_render_osd(vo
, RENDER_OSD
);
843 static void do_render(struct vo
*vo
)
845 struct gl_priv
*p
= vo
->priv
;
848 // Enable(GL_TEXTURE_2D);
849 // BindTexture(GL_TEXTURE_2D, texture_id);
851 gl
->Color3f(1, 1, 1);
852 if (p
->is_yuv
|| p
->custom_prog
)
853 glEnableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
854 if (p
->stereo_mode
) {
855 glEnable3DLeft(gl
, p
->stereo_mode
);
856 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
857 0, 0, p
->image_width
>> 1, p
->image_height
,
858 p
->texture_width
, p
->texture_height
,
859 p
->use_rectangle
== 1, p
->is_yuv
,
860 p
->mpi_flipped
^ p
->vo_flipped
);
861 glEnable3DRight(gl
, p
->stereo_mode
);
862 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
863 p
->image_width
>> 1, 0, p
->image_width
>> 1,
864 p
->image_height
, p
->texture_width
, p
->texture_height
,
865 p
->use_rectangle
== 1, p
->is_yuv
,
866 p
->mpi_flipped
^ p
->vo_flipped
);
867 glDisable3D(gl
, p
->stereo_mode
);
869 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
870 0, 0, p
->image_width
, p
->image_height
,
871 p
->texture_width
, p
->texture_height
,
872 p
->use_rectangle
== 1, p
->is_yuv
,
873 p
->mpi_flipped
^ p
->vo_flipped
);
875 if (p
->is_yuv
|| p
->custom_prog
)
876 glDisableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
879 static void flip_page(struct vo
*vo
)
881 struct gl_priv
*p
= vo
->priv
;
884 if (vo_doublebuffering
) {
887 p
->glctx
->swapGlBuffers(p
->glctx
);
888 if (aspect_scaling())
889 gl
->Clear(GL_COLOR_BUFFER_BIT
);
892 do_render_osd(vo
, RENDER_OSD
| RENDER_EOSD
);
900 static int draw_slice(struct vo
*vo
, uint8_t *src
[], int stride
[], int w
, int h
,
903 struct gl_priv
*p
= vo
->priv
;
906 p
->mpi_flipped
= stride
[0] < 0;
907 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[0], stride
[0],
908 x
, y
, w
, h
, p
->slice_height
);
911 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
912 gl
->ActiveTexture(GL_TEXTURE1
);
913 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[1], stride
[1],
914 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
915 gl
->ActiveTexture(GL_TEXTURE2
);
916 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[2], stride
[2],
917 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
918 gl
->ActiveTexture(GL_TEXTURE0
);
923 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
925 struct gl_priv
*p
= vo
->priv
;
929 if (!gl
->GenBuffers
|| !gl
->BindBuffer
|| !gl
->BufferData
|| !gl
->MapBuffer
) {
931 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] extensions missing for dr\n"
932 "Expect a _major_ speed penalty\n");
936 if (mpi
->flags
& MP_IMGFLAG_READABLE
)
938 if (mpi
->type
!= MP_IMGTYPE_STATIC
&& mpi
->type
!= MP_IMGTYPE_TEMP
&&
939 (mpi
->type
!= MP_IMGTYPE_NUMBERED
|| mpi
->number
))
942 mpi
->width
= p
->texture_width
;
943 mpi
->height
= p
->texture_height
;
945 mpi
->stride
[0] = mpi
->width
* mpi
->bpp
/ 8;
946 needed_size
= mpi
->stride
[0] * mpi
->height
;
948 gl
->GenBuffers(1, &p
->buffer
);
949 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
950 if (needed_size
> p
->buffersize
) {
951 p
->buffersize
= needed_size
;
952 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, p
->buffersize
,
953 NULL
, GL_DYNAMIC_DRAW
);
956 p
->bufferptr
= gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_WRITE_ONLY
);
957 mpi
->planes
[0] = p
->bufferptr
;
958 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
959 if (!mpi
->planes
[0]) {
961 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] could not acquire buffer for dr\n"
962 "Expect a _major_ speed penalty\n");
968 int xs
, ys
, component_bits
;
969 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
970 int bp
= (component_bits
+ 7) / 8;
971 mpi
->flags
|= MP_IMGFLAG_COMMON_STRIDE
| MP_IMGFLAG_COMMON_PLANE
;
972 mpi
->stride
[0] = mpi
->width
* bp
;
973 mpi
->planes
[1] = mpi
->planes
[0] + mpi
->stride
[0] * mpi
->height
;
974 mpi
->stride
[1] = (mpi
->width
>> xs
) * bp
;
975 mpi
->planes
[2] = mpi
->planes
[1] + mpi
->stride
[1] * (mpi
->height
>> ys
);
976 mpi
->stride
[2] = (mpi
->width
>> xs
) * bp
;
978 mpi
->flags
&= ~MP_IMGFLAG_COMMON_PLANE
;
979 if (!p
->buffer_uv
[0])
980 gl
->GenBuffers(2, p
->buffer_uv
);
981 int buffer_size
= mpi
->stride
[1] * mpi
->height
;
982 if (buffer_size
> p
->buffersize_uv
) {
983 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
984 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
986 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
987 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
989 p
->buffersize_uv
= buffer_size
;
991 if (!p
->bufferptr_uv
[0]) {
992 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
993 p
->bufferptr_uv
[0] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
995 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
996 p
->bufferptr_uv
[1] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
999 mpi
->planes
[1] = p
->bufferptr_uv
[0];
1000 mpi
->planes
[2] = p
->bufferptr_uv
[1];
1003 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1007 static void clear_border(struct vo
*vo
, uint8_t *dst
, int start
, int stride
,
1008 int height
, int full_height
, int value
)
1010 int right_border
= stride
- start
;
1011 int bottom_border
= full_height
- height
;
1012 while (height
> 0) {
1013 if (right_border
> 0)
1014 memset(dst
+ start
, value
, right_border
);
1018 if (bottom_border
> 0)
1019 memset(dst
, value
, stride
* bottom_border
);
1022 static uint32_t draw_image(struct vo
*vo
, mp_image_t
*mpi
)
1024 struct gl_priv
*p
= vo
->priv
;
1027 int slice
= p
->slice_height
;
1029 unsigned char *planes
[3];
1030 mp_image_t mpi2
= *mpi
;
1031 int w
= mpi
->w
, h
= mpi
->h
;
1032 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
1035 mpi2
.type
= MP_IMGTYPE_TEMP
;
1036 mpi2
.width
= mpi2
.w
;
1037 mpi2
.height
= mpi2
.h
;
1038 if (p
->force_pbo
&& !(mpi
->flags
& MP_IMGFLAG_DIRECT
) && !p
->bufferptr
1039 && get_image(vo
, &mpi2
) == VO_TRUE
)
1041 int bp
= mpi
->bpp
/ 8;
1042 int xs
, ys
, component_bits
;
1043 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
1045 bp
= (component_bits
+ 7) / 8;
1046 memcpy_pic(mpi2
.planes
[0], mpi
->planes
[0], mpi
->w
* bp
, mpi
->h
,
1047 mpi2
.stride
[0], mpi
->stride
[0]);
1048 int uv_bytes
= (mpi
->w
>> xs
) * bp
;
1050 memcpy_pic(mpi2
.planes
[1], mpi
->planes
[1], uv_bytes
, mpi
->h
>> ys
,
1051 mpi2
.stride
[1], mpi
->stride
[1]);
1052 memcpy_pic(mpi2
.planes
[2], mpi
->planes
[2], uv_bytes
, mpi
->h
>> ys
,
1053 mpi2
.stride
[2], mpi
->stride
[2]);
1056 // since we have to do a full upload we need to clear the borders
1057 clear_border(vo
, mpi2
.planes
[0], mpi
->w
* bp
, mpi2
.stride
[0],
1058 mpi
->h
, mpi2
.height
, 0);
1060 int clear
= get_chroma_clear_val(component_bits
);
1061 clear_border(vo
, mpi2
.planes
[1], uv_bytes
, mpi2
.stride
[1],
1062 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1063 clear_border(vo
, mpi2
.planes
[2], uv_bytes
, mpi2
.stride
[2],
1064 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1069 stride
[0] = mpi
->stride
[0];
1070 stride
[1] = mpi
->stride
[1];
1071 stride
[2] = mpi
->stride
[2];
1072 planes
[0] = mpi
->planes
[0];
1073 planes
[1] = mpi
->planes
[1];
1074 planes
[2] = mpi
->planes
[2];
1075 p
->mpi_flipped
= stride
[0] < 0;
1076 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1077 intptr_t base
= (intptr_t)planes
[0];
1079 w
= p
->texture_width
;
1080 h
= p
->texture_height
;
1083 base
+= (mpi
->h
- 1) * stride
[0];
1087 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
1088 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1089 p
->bufferptr
= NULL
;
1090 if (!(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
))
1091 planes
[0] = planes
[1] = planes
[2] = NULL
;
1092 slice
= 0; // always "upload" full texture
1094 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[0],
1095 stride
[0], mpi
->x
, mpi
->y
, w
, h
, slice
);
1098 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
1099 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1100 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
1101 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1102 p
->bufferptr_uv
[0] = NULL
;
1104 gl
->ActiveTexture(GL_TEXTURE1
);
1105 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[1],
1106 stride
[1], mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
,
1108 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1109 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
1110 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1111 p
->bufferptr_uv
[1] = NULL
;
1113 gl
->ActiveTexture(GL_TEXTURE2
);
1114 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[2],
1115 stride
[2], mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
,
1117 gl
->ActiveTexture(GL_TEXTURE0
);
1119 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1120 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1123 if (vo_doublebuffering
)
1128 static mp_image_t
*get_screenshot(struct vo
*vo
)
1130 struct gl_priv
*p
= vo
->priv
;
1133 mp_image_t
*image
= alloc_mpi(p
->texture_width
, p
->texture_height
,
1136 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[0],
1140 gl
->ActiveTexture(GL_TEXTURE1
);
1141 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[1],
1143 gl
->ActiveTexture(GL_TEXTURE2
);
1144 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[2],
1146 gl
->ActiveTexture(GL_TEXTURE0
);
1149 image
->width
= p
->image_width
;
1150 image
->height
= p
->image_height
;
1152 image
->w
= p
->image_d_width
;
1153 image
->h
= p
->image_d_height
;
1158 static mp_image_t
*get_window_screenshot(struct vo
*vo
)
1160 struct gl_priv
*p
= vo
->priv
;
1163 GLint vp
[4]; //x, y, w, h
1164 gl
->GetIntegerv(GL_VIEWPORT
, vp
);
1165 mp_image_t
*image
= alloc_mpi(vp
[2], vp
[3], IMGFMT_RGB24
);
1166 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1167 gl
->PixelStorei(GL_PACK_ALIGNMENT
, 0);
1168 gl
->PixelStorei(GL_PACK_ROW_LENGTH
, 0);
1169 gl
->ReadBuffer(GL_FRONT
);
1170 //flip image while reading
1171 for (int y
= 0; y
< vp
[3]; y
++) {
1172 gl
->ReadPixels(vp
[0], vp
[1] + vp
[3] - y
- 1, vp
[2], 1,
1173 GL_RGB
, GL_UNSIGNED_BYTE
,
1174 image
->planes
[0] + y
* image
->stride
[0]);
1179 static int query_format(struct vo
*vo
, uint32_t format
)
1181 struct gl_priv
*p
= vo
->priv
;
1184 int caps
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_FLIP
|
1185 VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1187 caps
|= VFCAP_OSD
| VFCAP_EOSD
| (p
->scaled_osd
? 0 : VFCAP_EOSD_UNSCALED
);
1188 if (format
== IMGFMT_RGB24
|| format
== IMGFMT_RGBA
)
1190 if (p
->use_yuv
&& mp_get_chroma_shift(format
, NULL
, NULL
, &depth
) &&
1191 (depth
== 8 || depth
== 16 || glYUVLargeRange(p
->use_yuv
)) &&
1192 (IMGFMT_IS_YUVP16_NE(format
) || !IMGFMT_IS_YUVP16(format
)))
1194 // HACK, otherwise we get only b&w with some filters (e.g. -vf eq)
1195 // ideally MPlayer should be fixed instead not to use Y800 when it has the choice
1196 if (!p
->use_yuv
&& (format
== IMGFMT_Y8
|| format
== IMGFMT_Y800
))
1198 if (!p
->use_ycbcr
&& (format
== IMGFMT_UYVY
|| format
== IMGFMT_YVYU
))
1201 glFindFormat(format
, p
->have_texture_rg
, NULL
, NULL
, NULL
, NULL
))
1206 static void uninit(struct vo
*vo
)
1208 struct gl_priv
*p
= vo
->priv
;
1212 free(p
->custom_prog
);
1213 p
->custom_prog
= NULL
;
1214 free(p
->custom_tex
);
1215 p
->custom_tex
= NULL
;
1216 uninit_mpglcontext(p
->glctx
);
1221 static int preinit_internal(struct vo
*vo
, const char *arg
, int allow_sw
,
1222 enum MPGLType gltype
)
1224 struct gl_priv
*p
= talloc_zero(vo
, struct gl_priv
);
1227 *p
= (struct gl_priv
) {
1231 .colorspace
= MP_CSP_DETAILS_DEFAULTS
,
1232 .filter_strength
= 0.5,
1233 .use_rectangle
= -1,
1237 .custom_prog
= NULL
,
1240 .osd_color
= 0xffffff,
1243 //essentially unused; for legacy warnings only
1244 int user_colorspace
= 0;
1248 const opt_t subopts
[] = {
1249 {"manyfmts", OPT_ARG_BOOL
, &p
->many_fmts
, NULL
},
1250 {"osd", OPT_ARG_BOOL
, &p
->use_osd
, NULL
},
1251 {"scaled-osd", OPT_ARG_BOOL
, &p
->scaled_osd
, NULL
},
1252 {"ycbcr", OPT_ARG_BOOL
, &p
->use_ycbcr
, NULL
},
1253 {"slice-height", OPT_ARG_INT
, &p
->slice_height
, int_non_neg
},
1254 {"rectangle", OPT_ARG_INT
, &p
->use_rectangle
,int_non_neg
},
1255 {"yuv", OPT_ARG_INT
, &p
->use_yuv
, int_non_neg
},
1256 {"lscale", OPT_ARG_INT
, &p
->lscale
, int_non_neg
},
1257 {"cscale", OPT_ARG_INT
, &p
->cscale
, int_non_neg
},
1258 {"filter-strength", OPT_ARG_FLOAT
, &p
->filter_strength
, NULL
},
1259 {"ati-hack", OPT_ARG_BOOL
, &p
->ati_hack
, NULL
},
1260 {"force-pbo", OPT_ARG_BOOL
, &p
->force_pbo
, NULL
},
1261 {"glfinish", OPT_ARG_BOOL
, &p
->use_glFinish
, NULL
},
1262 {"swapinterval", OPT_ARG_INT
, &p
->swap_interval
,NULL
},
1263 {"customprog", OPT_ARG_MSTRZ
,&p
->custom_prog
, NULL
},
1264 {"customtex", OPT_ARG_MSTRZ
,&p
->custom_tex
, NULL
},
1265 {"customtlin", OPT_ARG_BOOL
, &p
->custom_tlin
, NULL
},
1266 {"customtrect", OPT_ARG_BOOL
, &p
->custom_trect
, NULL
},
1267 {"mipmapgen", OPT_ARG_BOOL
, &p
->mipmap_gen
, NULL
},
1268 {"osdcolor", OPT_ARG_INT
, &p
->osd_color
, NULL
},
1269 {"stereo", OPT_ARG_INT
, &p
->stereo_mode
, NULL
},
1271 // They are only parsed to notify the user about the replacements.
1272 {"aspect", OPT_ARG_BOOL
, &aspect
, NULL
},
1273 {"colorspace", OPT_ARG_INT
, &user_colorspace
, NULL
},
1274 {"levelconv", OPT_ARG_INT
, &levelconv
, NULL
},
1278 if (subopt_parse(arg
, subopts
) != 0) {
1279 mp_msg(MSGT_VO
, MSGL_FATAL
,
1280 "\n-vo gl command line help:\n"
1281 "Example: mplayer -vo gl:slice-height=4\n"
1284 " Disable extended color formats for OpenGL 1.2 and later\n"
1285 " slice-height=<0-...>\n"
1286 " Slice size for texture transfer, 0 for whole image\n"
1288 " Do not use OpenGL OSD code\n"
1290 " Render OSD at movie resolution and scale it\n"
1291 " rectangle=<0,1,2>\n"
1292 " 0: use power-of-two textures\n"
1293 " 1: use texture_rectangle\n"
1294 " 2: use texture_non_power_of_two\n"
1296 " Workaround ATI bug with PBOs\n"
1298 " Force use of PBO even if this involves an extra memcpy\n"
1300 " Call glFinish() before swapping buffers\n"
1301 " swapinterval=<n>\n"
1302 " Interval in displayed frames between to buffer swaps.\n"
1303 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
1304 " Requires GLX_SGI_swap_control support to work.\n"
1306 " also try to use the GL_MESA_ycbcr_texture extension\n"
1308 " 0: use software YUV to RGB conversion.\n"
1309 " 1: deprecated, will use yuv=2 (used to be nVidia register combiners).\n"
1310 " 2: use fragment program.\n"
1311 " 3: use fragment program with gamma correction.\n"
1312 " 4: use fragment program with gamma correction via lookup.\n"
1313 " 5: use ATI-specific method (for older cards).\n"
1314 " 6: use lookup via 3D texture.\n"
1316 " 0: use standard bilinear scaling for luma.\n"
1317 " 1: use improved bicubic scaling for luma.\n"
1318 " 2: use cubic in X, linear in Y direction scaling for luma.\n"
1319 " 3: as 1 but without using a lookup texture.\n"
1320 " 4: experimental unsharp masking (sharpening).\n"
1321 " 5: experimental unsharp masking (sharpening) with larger radius.\n"
1323 " as lscale but for chroma (2x slower with little visible effect).\n"
1324 " filter-strength=<value>\n"
1325 " set the effect strength for some lscale/cscale filters\n"
1326 " customprog=<filename>\n"
1327 " use a custom YUV conversion program\n"
1328 " customtex=<filename>\n"
1329 " use a custom YUV conversion lookup texture\n"
1331 " use GL_NEAREST scaling for customtex texture\n"
1333 " use texture_rectangle for customtex texture\n"
1335 " generate mipmaps for the video image (use with TXB in customprog)\n"
1336 " osdcolor=<0xAARRGGBB>\n"
1337 " use the given color for the OSD\n"
1339 " 0: normal display\n"
1340 " 1: side-by-side to red-cyan stereo\n"
1341 " 2: side-by-side to green-magenta stereo\n"
1342 " 3: side-by-side to quadbuffer stereo\n"
1346 if (user_colorspace
!= 0 || levelconv
!= -1) {
1347 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"colorspace\" and \"levelconv\" "
1348 "suboptions have been removed. Use options --colormatrix and"
1349 " --colormatrix-input-range/--colormatrix-output-range instead.\n");
1353 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"noaspect\" suboption has been "
1354 "removed. Use --noaspect instead.\n");
1357 if (p
->use_yuv
== 1) {
1358 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] yuv=1 (nVidia register combiners) have"
1359 " been removed, using yuv=2 instead.\n");
1362 p
->glctx
= init_mpglcontext(gltype
, vo
);
1365 p
->gl
= p
->glctx
->gl
;
1367 if (p
->glctx
->type
== GLTYPE_SDL
&& p
->use_yuv
== -1) {
1368 // Apparently it's not possible to implement VOFLAG_HIDDEN on SDL 1.2,
1369 // so don't do autodetection. Use a sufficiently useful and safe YUV
1371 p
->use_yuv
= YUV_CONVERSION_FRAGMENT
;
1374 if (p
->use_yuv
== -1 || !allow_sw
) {
1375 if (create_window(vo
, 320, 200, VOFLAG_HIDDEN
) < 0)
1377 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
1379 if (!allow_sw
&& isSoftwareGl(vo
))
1381 autodetectGlExtensions(vo
);
1382 // We created a window to test whether the GL context supports hardware
1383 // acceleration and so on. Destroy that window to make sure all state
1384 // associated with it is lost.
1386 p
->glctx
= init_mpglcontext(gltype
, vo
);
1389 p
->gl
= p
->glctx
->gl
;
1392 mp_msg(MSGT_VO
, MSGL_INFO
, "[gl] using extended formats. "
1393 "Use -vo gl:nomanyfmts if playback fails.\n");
1394 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Using %d as slice height "
1395 "(0 means image height).\n", p
->slice_height
);
1404 static int preinit(struct vo
*vo
, const char *arg
)
1406 return preinit_internal(vo
, arg
, 1, GLTYPE_AUTO
);
1409 static int control(struct vo
*vo
, uint32_t request
, void *data
)
1411 struct gl_priv
*p
= vo
->priv
;
1414 case VOCTRL_QUERY_FORMAT
:
1415 return query_format(vo
, *(uint32_t *)data
);
1416 case VOCTRL_GET_IMAGE
:
1417 return get_image(vo
, data
);
1418 case VOCTRL_DRAW_IMAGE
:
1419 return draw_image(vo
, data
);
1420 case VOCTRL_DRAW_EOSD
:
1424 if (vo_doublebuffering
)
1425 do_render_osd(vo
, RENDER_EOSD
);
1427 case VOCTRL_GET_EOSD_RES
: {
1428 mp_eosd_res_t
*r
= data
;
1431 r
->mt
= r
->mb
= r
->ml
= r
->mr
= 0;
1432 if (p
->scaled_osd
) {
1433 r
->w
= p
->image_width
;
1434 r
->h
= p
->image_height
;
1435 } else if (aspect_scaling()) {
1436 r
->ml
= r
->mr
= p
->ass_border_x
;
1437 r
->mt
= r
->mb
= p
->ass_border_y
;
1442 if (!p
->glctx
->ontop
)
1444 p
->glctx
->ontop(vo
);
1446 case VOCTRL_FULLSCREEN
:
1447 p
->glctx
->fullscreen(vo
);
1448 resize(vo
, vo
->dwidth
, vo
->dheight
);
1451 if (!p
->glctx
->border
)
1453 p
->glctx
->border(vo
);
1454 resize(vo
, vo
->dwidth
, vo
->dheight
);
1456 case VOCTRL_GET_PANSCAN
:
1458 case VOCTRL_SET_PANSCAN
:
1459 resize(vo
, vo
->dwidth
, vo
->dheight
);
1461 case VOCTRL_GET_EQUALIZER
:
1463 struct voctrl_get_equalizer_args
*args
= data
;
1464 return mp_csp_equalizer_get(&p
->video_eq
, args
->name
, args
->valueptr
)
1465 >= 0 ? VO_TRUE
: VO_NOTIMPL
;
1468 case VOCTRL_SET_EQUALIZER
:
1470 struct voctrl_set_equalizer_args
*args
= data
;
1471 if (mp_csp_equalizer_set(&p
->video_eq
, args
->name
, args
->value
) < 0)
1474 vo
->want_redraw
= true;
1478 case VOCTRL_SET_YUV_COLORSPACE
: {
1479 bool supports_csp
= (1 << p
->use_yuv
) & MASK_NOT_COMBINERS
;
1480 if (vo
->config_count
&& supports_csp
) {
1481 p
->colorspace
= *(struct mp_csp_details
*)data
;
1483 vo
->want_redraw
= true;
1487 case VOCTRL_GET_YUV_COLORSPACE
:
1488 *(struct mp_csp_details
*)data
= p
->colorspace
;
1490 case VOCTRL_UPDATE_SCREENINFO
:
1491 if (!p
->glctx
->update_xinerama_info
)
1493 p
->glctx
->update_xinerama_info(vo
);
1495 case VOCTRL_REDRAW_FRAME
:
1496 if (vo_doublebuffering
)
1499 case VOCTRL_SCREENSHOT
: {
1500 struct voctrl_screenshot_args
*args
= data
;
1501 if (args
->full_window
)
1502 args
->out_image
= get_window_screenshot(vo
);
1504 args
->out_image
= get_screenshot(vo
);
1511 const struct vo_driver video_out_gl
= {
1513 .info
= &(const vo_info_t
) {
1516 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1522 .draw_slice
= draw_slice
,
1523 .draw_osd
= draw_osd
,
1524 .flip_page
= flip_page
,
1525 .check_events
= check_events
,
1529 static int preinit_nosw(struct vo
*vo
, const char *arg
)
1531 return preinit_internal(vo
, arg
, 0, GLTYPE_AUTO
);
1534 const struct vo_driver video_out_gl_nosw
=
1537 .info
= &(const vo_info_t
) {
1538 "OpenGL no software rendering",
1540 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1543 .preinit
= preinit_nosw
,
1546 .draw_slice
= draw_slice
,
1547 .draw_osd
= draw_osd
,
1548 .flip_page
= flip_page
,
1549 .check_events
= check_events
,
1553 #ifdef CONFIG_GL_SDL
1554 static int preinit_sdl(struct vo
*vo
, const char *arg
)
1556 return preinit_internal(vo
, arg
, 1, GLTYPE_SDL
);
1559 const struct vo_driver video_out_gl_sdl
= {
1561 .info
= &(const vo_info_t
) {
1564 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1567 .preinit
= preinit_sdl
,
1570 .draw_slice
= draw_slice
,
1571 .draw_osd
= draw_osd
,
1572 .flip_page
= flip_page
,
1573 .check_events
= check_events
,