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"
40 #include "bitmap_packer.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
53 #define MASK_ALL_YUV (~(1 << YUV_CONVERSION_NONE))
54 #define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS)))
55 #define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT))
70 GLuint osdtex
[MAX_OSD_PARTS
];
71 //! Alpha textures for OSD
72 GLuint osdatex
[MAX_OSD_PARTS
];
74 int eosd_texture_width
, eosd_texture_height
;
75 struct bitmap_packer
*eosd
;
76 struct vertex_eosd
*eosd_va
;
77 int eosd_render_count
;
78 unsigned int bitmap_id
;
79 unsigned int bitmap_pos_id
;
80 //! Display lists that draw the OSD parts
81 GLuint osdDispList
[MAX_OSD_PARTS
];
82 GLuint osdaDispList
[MAX_OSD_PARTS
];
83 //! How many parts the OSD currently consists of
89 struct mp_csp_details colorspace
;
93 float filter_strength
;
98 uint32_t image_height
;
99 uint32_t image_format
;
100 uint32_t image_d_width
;
101 uint32_t image_d_height
;
117 void *bufferptr_uv
[2];
119 GLuint default_texs
[22];
127 struct mp_csp_equalizer video_eq
;
133 int ass_border_x
, ass_border_y
;
135 unsigned int slice_height
;
138 static void resize(struct vo
*vo
, int x
, int y
)
140 struct gl_priv
*p
= vo
->priv
;
143 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Resize: %dx%d\n", x
, y
);
145 int left
= 0, top
= 0, w
= x
, h
= y
;
146 geometry(&left
, &top
, &w
, &h
, vo
->dwidth
, vo
->dheight
);
148 gl
->Viewport(left
, top
, w
, h
);
150 gl
->Viewport(0, 0, x
, y
);
152 gl
->MatrixMode(GL_PROJECTION
);
154 p
->ass_border_x
= p
->ass_border_y
= 0;
155 if (aspect_scaling()) {
157 GLdouble scale_x
, scale_y
;
158 aspect(vo
, &new_w
, &new_h
, A_WINZOOM
);
159 panscan_calc_windowed(vo
);
160 new_w
+= vo
->panscan_x
;
161 new_h
+= vo
->panscan_y
;
162 scale_x
= (GLdouble
)new_w
/ (GLdouble
)x
;
163 scale_y
= (GLdouble
)new_h
/ (GLdouble
)y
;
164 gl
->Scaled(scale_x
, scale_y
, 1);
165 p
->ass_border_x
= (vo
->dwidth
- new_w
) / 2;
166 p
->ass_border_y
= (vo
->dheight
- new_h
) / 2;
168 gl
->Ortho(0, p
->image_width
, p
->image_height
, 0, -1, 1);
170 gl
->MatrixMode(GL_MODELVIEW
);
174 vo_osd_changed(OSDTYPE_OSD
);
176 gl
->Clear(GL_COLOR_BUFFER_BIT
);
177 vo
->want_redraw
= true;
180 static void texSize(struct vo
*vo
, int w
, int h
, int *texw
, int *texh
)
182 struct gl_priv
*p
= vo
->priv
;
184 if (p
->use_rectangle
) {
196 *texw
= (*texw
+ 511) & ~511;
199 //! maximum size of custom fragment program
200 #define MAX_CUSTOM_PROG_SIZE (1024 * 1024)
201 static void update_yuvconv(struct vo
*vo
)
203 struct gl_priv
*p
= vo
->priv
;
207 struct mp_csp_params cparams
= { .colorspace
= p
->colorspace
};
208 mp_csp_copy_equalizer_values(&cparams
, &p
->video_eq
);
209 gl_conversion_params_t params
= {
210 p
->target
, p
->yuvconvtype
, cparams
,
211 p
->texture_width
, p
->texture_height
, 0, 0, p
->filter_strength
213 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &depth
);
214 params
.chrom_texw
= params
.texw
>> xs
;
215 params
.chrom_texh
= params
.texh
>> ys
;
216 params
.csp_params
.input_bits
= depth
;
217 params
.csp_params
.texture_bits
= depth
+7 & ~7;
218 glSetupYUVConversion(gl
, ¶ms
);
219 if (p
->custom_prog
) {
220 FILE *f
= fopen(p
->custom_prog
, "rb");
222 mp_msg(MSGT_VO
, MSGL_WARN
,
223 "[gl] Could not read customprog %s\n", p
->custom_prog
);
225 char *prog
= calloc(1, MAX_CUSTOM_PROG_SIZE
+ 1);
226 fread(prog
, 1, MAX_CUSTOM_PROG_SIZE
, f
);
228 loadGPUProgram(gl
, GL_FRAGMENT_PROGRAM
, prog
);
231 gl
->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 0,
232 1.0 / p
->texture_width
,
233 1.0 / p
->texture_height
,
234 p
->texture_width
, p
->texture_height
);
237 FILE *f
= fopen(p
->custom_tex
, "rb");
239 mp_msg(MSGT_VO
, MSGL_WARN
,
240 "[gl] Could not read customtex %s\n", p
->custom_tex
);
242 int width
, height
, maxval
;
243 gl
->ActiveTexture(GL_TEXTURE3
);
244 if (glCreatePPMTex(gl
, p
->custom_trect
? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
,
245 0, p
->custom_tlin
? GL_LINEAR
: GL_NEAREST
,
246 f
, &width
, &height
, &maxval
)) {
247 gl
->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM
, 1,
248 1.0 / width
, 1.0 / height
,
251 mp_msg(MSGT_VO
, MSGL_WARN
,
252 "[gl] Error parsing customtex %s\n", p
->custom_tex
);
254 gl
->ActiveTexture(GL_TEXTURE0
);
260 * \brief remove all OSD textures and display-lists, thus clearing it.
262 static void clearOSD(struct vo
*vo
)
264 struct gl_priv
*p
= vo
->priv
;
270 gl
->DeleteTextures(p
->osdtexCnt
, p
->osdtex
);
271 gl
->DeleteTextures(p
->osdtexCnt
, p
->osdatex
);
272 for (i
= 0; i
< p
->osdtexCnt
; i
++)
273 gl
->DeleteLists(p
->osdaDispList
[i
], 1);
274 for (i
= 0; i
< p
->osdtexCnt
; i
++)
275 gl
->DeleteLists(p
->osdDispList
[i
], 1);
280 * \brief construct display list from ass image list
281 * \param img image list to create OSD from.
283 static void genEOSD(struct vo
*vo
, mp_eosd_images_t
*imgs
)
285 struct gl_priv
*p
= vo
->priv
;
288 if (imgs
->bitmap_pos_id
== p
->bitmap_pos_id
)
291 if (!p
->eosd_texture
)
292 gl
->GenTextures(1, &p
->eosd_texture
);
294 gl
->BindTexture(p
->target
, p
->eosd_texture
);
296 p
->eosd_render_count
= 0;
297 bool need_upload
= false;
299 if (imgs
->bitmap_id
!= p
->bitmap_id
) {
301 int res
= packer_pack_from_assimg(p
->eosd
, imgs
->imgs
);
303 mp_msg(MSGT_VO
, MSGL_ERR
,
304 "[gl] subtitle bitmaps do not fit in maximum texture\n");
308 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Allocating a %dx%d texture for "
309 "subtitle bitmaps.\n", p
->eosd
->w
, p
->eosd
->h
);
310 texSize(vo
, p
->eosd
->w
, p
->eosd
->h
,
311 &p
->eosd_texture_width
, &p
->eosd_texture_height
);
312 // xxx it doesn't need to be cleared, that's a waste of time
313 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
,
314 GL_UNSIGNED_BYTE
, GL_NEAREST
,
315 p
->eosd_texture_width
,
316 p
->eosd_texture_height
, 0);
320 // 2 triangles primitives per quad = 6 vertices per quad
321 // not using GL_QUADS, as it is deprecated in OpenGL 3.x and later
322 p
->eosd_va
= talloc_realloc_size(p
->eosd
, p
->eosd_va
,
324 sizeof(struct vertex_eosd
) * 6);
326 float eosd_w
= p
->eosd_texture_width
;
327 float eosd_h
= p
->eosd_texture_height
;
329 if (p
->use_rectangle
== 1)
330 eosd_w
= eosd_h
= 1.0f
;
332 ASS_Image
*i
= imgs
->imgs
;
333 struct pos
*spos
= p
->eosd
->result
;
334 for (int n
= 0; n
< p
->eosd
->count
; n
++, i
= i
->next
) {
335 if (i
->w
== 0 || i
->h
== 0)
339 glUploadTex(gl
, p
->target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, i
->bitmap
,
340 i
->stride
, spos
[n
].x
, spos
[n
].y
, i
->w
, i
->h
, 0);
342 uint8_t color
[4] = { i
->color
>> 24, (i
->color
>> 16) & 0xff,
343 (i
->color
>> 8) & 0xff, 255 - (i
->color
& 0xff) };
347 float x1
= i
->dst_x
+ i
->w
;
348 float y1
= i
->dst_y
+ i
->h
;
349 float tx0
= spos
[n
].x
/ eosd_w
;
350 float ty0
= spos
[n
].y
/ eosd_h
;
351 float tx1
= (spos
[n
].x
+ i
->w
) / eosd_w
;
352 float ty1
= (spos
[n
].y
+ i
->h
) / eosd_h
;
354 #define COLOR_INIT {color[0], color[1], color[2], color[3]}
355 struct vertex_eosd
*va
= &p
->eosd_va
[p
->eosd_render_count
* 6];
356 va
[0] = (struct vertex_eosd
) { x0
, y0
, COLOR_INIT
, tx0
, ty0
};
357 va
[1] = (struct vertex_eosd
) { x0
, y1
, COLOR_INIT
, tx0
, ty1
};
358 va
[2] = (struct vertex_eosd
) { x1
, y0
, COLOR_INIT
, tx1
, ty0
};
359 va
[3] = (struct vertex_eosd
) { x1
, y1
, COLOR_INIT
, tx1
, ty1
};
363 p
->eosd_render_count
++;
366 gl
->BindTexture(p
->target
, 0);
367 p
->bitmap_id
= imgs
->bitmap_id
;
368 p
->bitmap_pos_id
= imgs
->bitmap_pos_id
;
371 // Note: relies on state being setup, like projection matrix and blending
372 static void drawEOSD(struct vo
*vo
)
374 struct gl_priv
*p
= vo
->priv
;
377 if (p
->eosd_render_count
== 0)
380 gl
->BindTexture(p
->target
, p
->eosd_texture
);
382 struct vertex_eosd
*va
= p
->eosd_va
;
383 size_t stride
= sizeof(struct vertex_eosd
);
385 gl
->VertexPointer(2, GL_FLOAT
, stride
, &va
[0].x
);
386 gl
->ColorPointer(4, GL_UNSIGNED_BYTE
, stride
, &va
[0].color
[0]);
387 gl
->TexCoordPointer(2, GL_FLOAT
, stride
, &va
[0].u
);
389 gl
->EnableClientState(GL_VERTEX_ARRAY
);
390 gl
->EnableClientState(GL_TEXTURE_COORD_ARRAY
);
391 gl
->EnableClientState(GL_COLOR_ARRAY
);
393 gl
->DrawArrays(GL_TRIANGLES
, 0, p
->eosd_render_count
* 6);
395 gl
->DisableClientState(GL_VERTEX_ARRAY
);
396 gl
->DisableClientState(GL_TEXTURE_COORD_ARRAY
);
397 gl
->DisableClientState(GL_COLOR_ARRAY
);
399 gl
->BindTexture(p
->target
, 0);
403 * \brief uninitialize OpenGL context, freeing textures, buffers etc.
405 static void uninitGl(struct vo
*vo
)
407 struct gl_priv
*p
= vo
->priv
;
411 if (gl
->DeletePrograms
&& p
->fragprog
)
412 gl
->DeletePrograms(1, &p
->fragprog
);
414 while (p
->default_texs
[i
] != 0)
417 gl
->DeleteTextures(i
, p
->default_texs
);
418 p
->default_texs
[0] = 0;
421 gl
->DeleteTextures(1, &p
->eosd_texture
);
422 p
->bitmap_id
= p
->bitmap_pos_id
= 0;
423 p
->eosd
->w
= p
->eosd
->h
= 0;
425 if (gl
->DeleteBuffers
&& p
->buffer
)
426 gl
->DeleteBuffers(1, &p
->buffer
);
430 if (gl
->DeleteBuffers
&& p
->buffer_uv
[0])
431 gl
->DeleteBuffers(2, p
->buffer_uv
);
432 p
->buffer_uv
[0] = p
->buffer_uv
[1] = 0;
433 p
->buffersize_uv
= 0;
434 p
->bufferptr_uv
[0] = p
->bufferptr_uv
[1] = 0;
438 static int isSoftwareGl(struct vo
*vo
)
440 struct gl_priv
*p
= vo
->priv
;
441 const char *renderer
= p
->gl
->GetString(GL_RENDERER
);
442 return !renderer
|| strcmp(renderer
, "Software Rasterizer") == 0 ||
443 strstr(renderer
, "llvmpipe");
446 static void autodetectGlExtensions(struct vo
*vo
)
448 struct gl_priv
*p
= vo
->priv
;
451 const char *extensions
= gl
->GetString(GL_EXTENSIONS
);
452 const char *vendor
= gl
->GetString(GL_VENDOR
);
453 const char *version
= gl
->GetString(GL_VERSION
);
454 const char *renderer
= gl
->GetString(GL_RENDERER
);
455 int is_ati
= vendor
&& strstr(vendor
, "ATI") != NULL
;
456 int ati_broken_pbo
= 0;
457 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Running on OpenGL '%s' by '%s', version '%s'\n",
458 renderer
, vendor
, version
);
459 if (is_ati
&& strncmp(version
, "2.1.", 4) == 0) {
460 int ver
= atoi(version
+ 4);
461 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Detected ATI driver version: %i\n", ver
);
462 ati_broken_pbo
= ver
&& ver
< 8395;
464 if (p
->ati_hack
== -1)
465 p
->ati_hack
= ati_broken_pbo
;
466 if (p
->force_pbo
== -1) {
468 if (extensions
&& strstr(extensions
, "_pixel_buffer_object"))
469 p
->force_pbo
= is_ati
;
471 p
->have_texture_rg
= extensions
&& strstr(extensions
, "GL_ARB_texture_rg");
472 if (p
->use_rectangle
== -1) {
473 p
->use_rectangle
= 0;
475 // if (strstr(extensions, "_texture_non_power_of_two"))
476 if (strstr(extensions
, "_texture_rectangle"))
477 p
->use_rectangle
= renderer
478 && strstr(renderer
, "Mesa DRI R200") ? 1 : 0;
481 if (p
->use_osd
== -1)
482 p
->use_osd
= gl
->BindTexture
!= NULL
;
483 if (p
->use_yuv
== -1)
484 p
->use_yuv
= glAutodetectYUVConversion(gl
);
487 int yuv_mask
= (1 << p
->use_yuv
);
488 if (!(yuv_mask
& MASK_NOT_COMBINERS
)) {
490 eq_caps
= (1 << MP_CSP_EQ_HUE
) | (1 << MP_CSP_EQ_SATURATION
);
491 } else if (yuv_mask
& MASK_ALL_YUV
) {
492 eq_caps
= MP_CSP_EQ_CAPS_COLORMATRIX
;
493 if (yuv_mask
& MASK_GAMMA_SUPPORT
)
494 eq_caps
|= MP_CSP_EQ_CAPS_GAMMA
;
496 p
->video_eq
.capabilities
= eq_caps
;
498 if (is_ati
&& (p
->lscale
== 1 || p
->lscale
== 2 || p
->cscale
== 1 || p
->cscale
== 2))
499 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] Selected scaling mode may be broken on"
501 "Tell _them_ to fix GL_REPEAT if you have issues.\n");
502 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Settings after autodetection: ati-hack = %i, "
503 "force-pbo = %i, rectangle = %i, yuv = %i\n",
504 p
->ati_hack
, p
->force_pbo
, p
->use_rectangle
, p
->use_yuv
);
507 static GLint
get_scale_type(struct vo
*vo
, int chroma
)
509 struct gl_priv
*p
= vo
->priv
;
511 int nearest
= (chroma
? p
->cscale
: p
->lscale
) & 64;
513 return p
->mipmap_gen
? GL_NEAREST_MIPMAP_NEAREST
: GL_NEAREST
;
514 return p
->mipmap_gen
? GL_LINEAR_MIPMAP_NEAREST
: GL_LINEAR
;
517 // Return the high byte of the value that represents white in chroma (U/V)
518 static int get_chroma_clear_val(int bit_depth
)
520 return 1 << (bit_depth
- 1 & 7);
524 * \brief Initialize a (new or reused) OpenGL context.
525 * set global gl-related variables to their default values
527 static int initGl(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
)
529 struct gl_priv
*p
= vo
->priv
;
532 GLint scale_type
= get_scale_type(vo
, 0);
533 autodetectGlExtensions(vo
);
534 p
->target
= p
->use_rectangle
== 1 ? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
;
535 p
->yuvconvtype
= SET_YUV_CONVERSION(p
->use_yuv
) |
536 SET_YUV_LUM_SCALER(p
->lscale
) |
537 SET_YUV_CHROM_SCALER(p
->cscale
);
539 texSize(vo
, p
->image_width
, p
->image_height
,
540 &p
->texture_width
, &p
->texture_height
);
542 gl
->Disable(GL_BLEND
);
543 gl
->Disable(GL_DEPTH_TEST
);
544 gl
->DepthMask(GL_FALSE
);
545 gl
->Disable(GL_CULL_FACE
);
546 gl
->Enable(p
->target
);
547 gl
->DrawBuffer(vo_doublebuffering
? GL_BACK
: GL_FRONT
);
548 gl
->TexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
550 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Creating %dx%d texture...\n",
551 p
->texture_width
, p
->texture_height
);
553 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
554 p
->gl_type
, scale_type
,
555 p
->texture_width
, p
->texture_height
, 0);
558 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
563 scale_type
= get_scale_type(vo
, 1);
564 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &depth
);
565 int clear
= get_chroma_clear_val(depth
);
566 gl
->GenTextures(21, p
->default_texs
);
567 p
->default_texs
[21] = 0;
568 for (i
= 0; i
< 7; i
++) {
569 gl
->ActiveTexture(GL_TEXTURE1
+ i
);
570 gl
->BindTexture(GL_TEXTURE_2D
, p
->default_texs
[i
]);
571 gl
->BindTexture(GL_TEXTURE_RECTANGLE
, p
->default_texs
[i
+ 7]);
572 gl
->BindTexture(GL_TEXTURE_3D
, p
->default_texs
[i
+ 14]);
574 gl
->ActiveTexture(GL_TEXTURE1
);
575 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
576 p
->gl_type
, scale_type
,
577 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
580 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
581 gl
->ActiveTexture(GL_TEXTURE2
);
582 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
583 p
->gl_type
, scale_type
,
584 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
587 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
588 gl
->ActiveTexture(GL_TEXTURE0
);
589 gl
->BindTexture(p
->target
, 0);
591 if (p
->is_yuv
|| p
->custom_prog
) {
592 if ((MASK_NOT_COMBINERS
& (1 << p
->use_yuv
)) || p
->custom_prog
) {
593 if (!gl
->GenPrograms
|| !gl
->BindProgram
)
594 mp_msg(MSGT_VO
, MSGL_ERR
,
595 "[gl] fragment program functions missing!\n");
597 gl
->GenPrograms(1, &p
->fragprog
);
598 gl
->BindProgram(GL_FRAGMENT_PROGRAM
, p
->fragprog
);
604 GLint max_texture_size
;
605 gl
->GetIntegerv(GL_MAX_TEXTURE_SIZE
, &max_texture_size
);
606 p
->eosd
->w_max
= p
->eosd
->h_max
= max_texture_size
;
608 resize(vo
, d_width
, d_height
);
610 gl
->ClearColor(0.0f
, 0.0f
, 0.0f
, 0.0f
);
611 gl
->Clear(GL_COLOR_BUFFER_BIT
);
612 if (gl
->SwapInterval
&& p
->swap_interval
>= 0)
613 gl
->SwapInterval(p
->swap_interval
);
617 static int create_window(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
,
620 struct gl_priv
*p
= vo
->priv
;
622 if (p
->stereo_mode
== GL_3D_QUADBUFFER
)
623 flags
|= VOFLAG_STEREO
;
625 return p
->glctx
->create_window(p
->glctx
, d_width
, d_height
, flags
);
628 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
629 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
632 struct gl_priv
*p
= vo
->priv
;
635 p
->image_height
= height
;
636 p
->image_width
= width
;
637 p
->image_format
= format
;
638 p
->image_d_width
= d_width
;
639 p
->image_d_height
= d_height
;
640 p
->is_yuv
= mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
) > 0;
641 p
->is_yuv
|= (xs
<< 8) | (ys
<< 16);
642 glFindFormat(format
, p
->have_texture_rg
, NULL
, &p
->texfmt
, &p
->gl_format
,
645 p
->vo_flipped
= !!(flags
& VOFLAG_FLIPPING
);
647 if (create_window(vo
, d_width
, d_height
, flags
) < 0)
650 if (vo
->config_count
)
652 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
654 initGl(vo
, vo
->dwidth
, vo
->dheight
);
659 static void check_events(struct vo
*vo
)
661 struct gl_priv
*p
= vo
->priv
;
663 int e
= p
->glctx
->check_events(vo
);
664 if (e
& VO_EVENT_REINIT
) {
666 initGl(vo
, vo
->dwidth
, vo
->dheight
);
668 if (e
& VO_EVENT_RESIZE
)
669 resize(vo
, vo
->dwidth
, vo
->dheight
);
670 if (e
& VO_EVENT_EXPOSE
)
671 vo
->want_redraw
= true;
675 * Creates the textures and the display list needed for displaying
677 * Callback function for osd_draw_text_ext().
679 static void create_osd_texture(void *ctx
, int x0
, int y0
, int w
, int h
,
680 unsigned char *src
, unsigned char *srca
,
684 struct gl_priv
*p
= vo
->priv
;
687 // initialize to 8 to avoid special-casing on alignment
689 GLint scale_type
= p
->scaled_osd
? GL_LINEAR
: GL_NEAREST
;
691 if (w
<= 0 || h
<= 0 || stride
< w
) {
692 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
695 texSize(vo
, w
, h
, &sx
, &sy
);
697 if (p
->osdtexCnt
>= MAX_OSD_PARTS
) {
698 mp_msg(MSGT_VO
, MSGL_ERR
, "Too many OSD parts, contact the developers!\n");
702 // create Textures for OSD part
703 gl
->GenTextures(1, &p
->osdtex
[p
->osdtexCnt
]);
704 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
705 glCreateClearTex(gl
, p
->target
, GL_LUMINANCE
, GL_LUMINANCE
,
706 GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
707 glUploadTex(gl
, p
->target
, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, src
, stride
,
710 gl
->GenTextures(1, &p
->osdatex
[p
->osdtexCnt
]);
711 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
712 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
,
713 scale_type
, sx
, sy
, 0);
716 char *tmp
= malloc(stride
* h
);
717 // convert alpha from weird MPlayer scale.
718 // in-place is not possible since it is reused for future OSDs
719 for (i
= h
* stride
- 1; i
>= 0; i
--)
721 glUploadTex(gl
, p
->target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, tmp
, stride
,
726 gl
->BindTexture(p
->target
, 0);
728 // Create a list for rendering this OSD part
729 p
->osdaDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
730 gl
->NewList(p
->osdaDispList
[p
->osdtexCnt
], GL_COMPILE
);
732 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
733 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
735 p
->osdDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
736 gl
->NewList(p
->osdDispList
[p
->osdtexCnt
], GL_COMPILE
);
738 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
739 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
746 #define RENDER_EOSD 2
749 * \param type bit 0: render OSD, bit 1: render EOSD
751 static void do_render_osd(struct vo
*vo
, int type
)
753 struct gl_priv
*p
= vo
->priv
;
756 int draw_osd
= (type
& RENDER_OSD
) && p
->osdtexCnt
> 0;
757 int draw_eosd
= (type
& RENDER_EOSD
);
758 if (!draw_osd
&& !draw_eosd
)
760 // set special rendering parameters
761 if (!p
->scaled_osd
) {
762 gl
->MatrixMode(GL_PROJECTION
);
765 gl
->Ortho(0, vo
->dwidth
, vo
->dheight
, 0, -1, 1);
767 gl
->Enable(GL_BLEND
);
769 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
773 gl
->Color4ub((p
->osd_color
>> 16) & 0xff, (p
->osd_color
>> 8) & 0xff,
774 p
->osd_color
& 0xff, 0xff - (p
->osd_color
>> 24));
776 gl
->BlendFunc(GL_ZERO
, GL_ONE_MINUS_SRC_ALPHA
);
777 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdaDispList
);
778 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE
);
779 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdDispList
);
781 // set rendering parameters back to defaults
782 gl
->Disable(GL_BLEND
);
785 gl
->BindTexture(p
->target
, 0);
788 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
790 struct gl_priv
*p
= vo
->priv
;
794 if (vo_osd_changed(0)) {
797 osd_w
= p
->scaled_osd
? p
->image_width
: vo
->dwidth
;
798 osd_h
= p
->scaled_osd
? p
->image_height
: vo
->dheight
;
799 osd_draw_text_ext(osd
, osd_w
, osd_h
, p
->ass_border_x
,
800 p
->ass_border_y
, p
->ass_border_x
,
801 p
->ass_border_y
, p
->image_width
,
802 p
->image_height
, create_osd_texture
, vo
);
804 if (vo_doublebuffering
)
805 do_render_osd(vo
, RENDER_OSD
);
808 static void do_render(struct vo
*vo
)
810 struct gl_priv
*p
= vo
->priv
;
813 // Enable(GL_TEXTURE_2D);
814 // BindTexture(GL_TEXTURE_2D, texture_id);
816 gl
->Color3f(1, 1, 1);
817 if (p
->is_yuv
|| p
->custom_prog
)
818 glEnableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
819 if (p
->stereo_mode
) {
820 glEnable3DLeft(gl
, p
->stereo_mode
);
821 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
822 0, 0, p
->image_width
>> 1, p
->image_height
,
823 p
->texture_width
, p
->texture_height
,
824 p
->use_rectangle
== 1, p
->is_yuv
,
825 p
->mpi_flipped
^ p
->vo_flipped
);
826 glEnable3DRight(gl
, p
->stereo_mode
);
827 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
828 p
->image_width
>> 1, 0, p
->image_width
>> 1,
829 p
->image_height
, p
->texture_width
, p
->texture_height
,
830 p
->use_rectangle
== 1, p
->is_yuv
,
831 p
->mpi_flipped
^ p
->vo_flipped
);
832 glDisable3D(gl
, p
->stereo_mode
);
834 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
835 0, 0, p
->image_width
, p
->image_height
,
836 p
->texture_width
, p
->texture_height
,
837 p
->use_rectangle
== 1, p
->is_yuv
,
838 p
->mpi_flipped
^ p
->vo_flipped
);
840 if (p
->is_yuv
|| p
->custom_prog
)
841 glDisableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
844 static void flip_page(struct vo
*vo
)
846 struct gl_priv
*p
= vo
->priv
;
849 if (vo_doublebuffering
) {
852 p
->glctx
->swapGlBuffers(p
->glctx
);
853 if (aspect_scaling())
854 gl
->Clear(GL_COLOR_BUFFER_BIT
);
857 do_render_osd(vo
, RENDER_OSD
| RENDER_EOSD
);
865 static int draw_slice(struct vo
*vo
, uint8_t *src
[], int stride
[], int w
, int h
,
868 struct gl_priv
*p
= vo
->priv
;
871 p
->mpi_flipped
= stride
[0] < 0;
872 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[0], stride
[0],
873 x
, y
, w
, h
, p
->slice_height
);
876 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
877 gl
->ActiveTexture(GL_TEXTURE1
);
878 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[1], stride
[1],
879 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
880 gl
->ActiveTexture(GL_TEXTURE2
);
881 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[2], stride
[2],
882 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
883 gl
->ActiveTexture(GL_TEXTURE0
);
888 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
890 struct gl_priv
*p
= vo
->priv
;
894 if (!gl
->GenBuffers
|| !gl
->BindBuffer
|| !gl
->BufferData
|| !gl
->MapBuffer
) {
896 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] extensions missing for dr\n"
897 "Expect a _major_ speed penalty\n");
901 if (mpi
->flags
& MP_IMGFLAG_READABLE
)
903 if (mpi
->type
!= MP_IMGTYPE_STATIC
&& mpi
->type
!= MP_IMGTYPE_TEMP
&&
904 (mpi
->type
!= MP_IMGTYPE_NUMBERED
|| mpi
->number
))
907 mpi
->width
= p
->texture_width
;
908 mpi
->height
= p
->texture_height
;
910 mpi
->stride
[0] = mpi
->width
* mpi
->bpp
/ 8;
911 needed_size
= mpi
->stride
[0] * mpi
->height
;
913 gl
->GenBuffers(1, &p
->buffer
);
914 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
915 if (needed_size
> p
->buffersize
) {
916 p
->buffersize
= needed_size
;
917 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, p
->buffersize
,
918 NULL
, GL_DYNAMIC_DRAW
);
921 p
->bufferptr
= gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_WRITE_ONLY
);
922 mpi
->planes
[0] = p
->bufferptr
;
923 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
924 if (!mpi
->planes
[0]) {
926 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] could not acquire buffer for dr\n"
927 "Expect a _major_ speed penalty\n");
933 int xs
, ys
, component_bits
;
934 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
935 int bp
= (component_bits
+ 7) / 8;
936 mpi
->flags
|= MP_IMGFLAG_COMMON_STRIDE
| MP_IMGFLAG_COMMON_PLANE
;
937 mpi
->stride
[0] = mpi
->width
* bp
;
938 mpi
->planes
[1] = mpi
->planes
[0] + mpi
->stride
[0] * mpi
->height
;
939 mpi
->stride
[1] = (mpi
->width
>> xs
) * bp
;
940 mpi
->planes
[2] = mpi
->planes
[1] + mpi
->stride
[1] * (mpi
->height
>> ys
);
941 mpi
->stride
[2] = (mpi
->width
>> xs
) * bp
;
943 mpi
->flags
&= ~MP_IMGFLAG_COMMON_PLANE
;
944 if (!p
->buffer_uv
[0])
945 gl
->GenBuffers(2, p
->buffer_uv
);
946 int buffer_size
= mpi
->stride
[1] * mpi
->height
;
947 if (buffer_size
> p
->buffersize_uv
) {
948 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
949 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
951 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
952 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
954 p
->buffersize_uv
= buffer_size
;
956 if (!p
->bufferptr_uv
[0]) {
957 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
958 p
->bufferptr_uv
[0] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
960 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
961 p
->bufferptr_uv
[1] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
964 mpi
->planes
[1] = p
->bufferptr_uv
[0];
965 mpi
->planes
[2] = p
->bufferptr_uv
[1];
968 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
972 static void clear_border(struct vo
*vo
, uint8_t *dst
, int start
, int stride
,
973 int height
, int full_height
, int value
)
975 int right_border
= stride
- start
;
976 int bottom_border
= full_height
- height
;
978 if (right_border
> 0)
979 memset(dst
+ start
, value
, right_border
);
983 if (bottom_border
> 0)
984 memset(dst
, value
, stride
* bottom_border
);
987 static uint32_t draw_image(struct vo
*vo
, mp_image_t
*mpi
)
989 struct gl_priv
*p
= vo
->priv
;
992 int slice
= p
->slice_height
;
994 unsigned char *planes
[3];
995 mp_image_t mpi2
= *mpi
;
996 int w
= mpi
->w
, h
= mpi
->h
;
997 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
1000 mpi2
.type
= MP_IMGTYPE_TEMP
;
1001 mpi2
.width
= mpi2
.w
;
1002 mpi2
.height
= mpi2
.h
;
1003 if (p
->force_pbo
&& !(mpi
->flags
& MP_IMGFLAG_DIRECT
) && !p
->bufferptr
1004 && get_image(vo
, &mpi2
) == VO_TRUE
)
1006 int bp
= mpi
->bpp
/ 8;
1007 int xs
, ys
, component_bits
;
1008 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
1010 bp
= (component_bits
+ 7) / 8;
1011 memcpy_pic(mpi2
.planes
[0], mpi
->planes
[0], mpi
->w
* bp
, mpi
->h
,
1012 mpi2
.stride
[0], mpi
->stride
[0]);
1013 int uv_bytes
= (mpi
->w
>> xs
) * bp
;
1015 memcpy_pic(mpi2
.planes
[1], mpi
->planes
[1], uv_bytes
, mpi
->h
>> ys
,
1016 mpi2
.stride
[1], mpi
->stride
[1]);
1017 memcpy_pic(mpi2
.planes
[2], mpi
->planes
[2], uv_bytes
, mpi
->h
>> ys
,
1018 mpi2
.stride
[2], mpi
->stride
[2]);
1021 // since we have to do a full upload we need to clear the borders
1022 clear_border(vo
, mpi2
.planes
[0], mpi
->w
* bp
, mpi2
.stride
[0],
1023 mpi
->h
, mpi2
.height
, 0);
1025 int clear
= get_chroma_clear_val(component_bits
);
1026 clear_border(vo
, mpi2
.planes
[1], uv_bytes
, mpi2
.stride
[1],
1027 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1028 clear_border(vo
, mpi2
.planes
[2], uv_bytes
, mpi2
.stride
[2],
1029 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1034 stride
[0] = mpi
->stride
[0];
1035 stride
[1] = mpi
->stride
[1];
1036 stride
[2] = mpi
->stride
[2];
1037 planes
[0] = mpi
->planes
[0];
1038 planes
[1] = mpi
->planes
[1];
1039 planes
[2] = mpi
->planes
[2];
1040 p
->mpi_flipped
= stride
[0] < 0;
1041 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1042 intptr_t base
= (intptr_t)planes
[0];
1044 w
= p
->texture_width
;
1045 h
= p
->texture_height
;
1048 base
+= (mpi
->h
- 1) * stride
[0];
1052 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
1053 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1054 p
->bufferptr
= NULL
;
1055 if (!(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
))
1056 planes
[0] = planes
[1] = planes
[2] = NULL
;
1057 slice
= 0; // always "upload" full texture
1059 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[0],
1060 stride
[0], mpi
->x
, mpi
->y
, w
, h
, slice
);
1063 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
1064 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1065 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
1066 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1067 p
->bufferptr_uv
[0] = NULL
;
1069 gl
->ActiveTexture(GL_TEXTURE1
);
1070 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[1],
1071 stride
[1], mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
,
1073 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1074 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
1075 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1076 p
->bufferptr_uv
[1] = NULL
;
1078 gl
->ActiveTexture(GL_TEXTURE2
);
1079 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[2],
1080 stride
[2], mpi
->x
>> xs
, mpi
->y
>> ys
, w
>> xs
, h
>> ys
,
1082 gl
->ActiveTexture(GL_TEXTURE0
);
1084 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1085 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1088 if (vo_doublebuffering
)
1093 static mp_image_t
*get_screenshot(struct vo
*vo
)
1095 struct gl_priv
*p
= vo
->priv
;
1098 mp_image_t
*image
= alloc_mpi(p
->texture_width
, p
->texture_height
,
1101 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[0],
1105 gl
->ActiveTexture(GL_TEXTURE1
);
1106 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[1],
1108 gl
->ActiveTexture(GL_TEXTURE2
);
1109 glDownloadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, image
->planes
[2],
1111 gl
->ActiveTexture(GL_TEXTURE0
);
1114 image
->width
= p
->image_width
;
1115 image
->height
= p
->image_height
;
1117 image
->w
= p
->image_d_width
;
1118 image
->h
= p
->image_d_height
;
1123 static mp_image_t
*get_window_screenshot(struct vo
*vo
)
1125 struct gl_priv
*p
= vo
->priv
;
1128 GLint vp
[4]; //x, y, w, h
1129 gl
->GetIntegerv(GL_VIEWPORT
, vp
);
1130 mp_image_t
*image
= alloc_mpi(vp
[2], vp
[3], IMGFMT_RGB24
);
1131 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
1132 gl
->PixelStorei(GL_PACK_ALIGNMENT
, 0);
1133 gl
->PixelStorei(GL_PACK_ROW_LENGTH
, 0);
1134 gl
->ReadBuffer(GL_FRONT
);
1135 //flip image while reading
1136 for (int y
= 0; y
< vp
[3]; y
++) {
1137 gl
->ReadPixels(vp
[0], vp
[1] + vp
[3] - y
- 1, vp
[2], 1,
1138 GL_RGB
, GL_UNSIGNED_BYTE
,
1139 image
->planes
[0] + y
* image
->stride
[0]);
1144 static int query_format(struct vo
*vo
, uint32_t format
)
1146 struct gl_priv
*p
= vo
->priv
;
1149 int caps
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_FLIP
|
1150 VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_ACCEPT_STRIDE
;
1152 caps
|= VFCAP_OSD
| VFCAP_EOSD
| (p
->scaled_osd
? 0 : VFCAP_EOSD_UNSCALED
);
1153 if (format
== IMGFMT_RGB24
|| format
== IMGFMT_RGBA
)
1155 if (p
->use_yuv
&& mp_get_chroma_shift(format
, NULL
, NULL
, &depth
) &&
1156 (depth
== 8 || depth
== 16 || glYUVLargeRange(p
->use_yuv
)) &&
1157 (IMGFMT_IS_YUVP16_NE(format
) || !IMGFMT_IS_YUVP16(format
)))
1159 // HACK, otherwise we get only b&w with some filters (e.g. -vf eq)
1160 // ideally MPlayer should be fixed instead not to use Y800 when it has the choice
1161 if (!p
->use_yuv
&& (format
== IMGFMT_Y8
|| format
== IMGFMT_Y800
))
1163 if (!p
->use_ycbcr
&& (format
== IMGFMT_UYVY
|| format
== IMGFMT_YVYU
))
1166 glFindFormat(format
, p
->have_texture_rg
, NULL
, NULL
, NULL
, NULL
))
1171 static void uninit(struct vo
*vo
)
1173 struct gl_priv
*p
= vo
->priv
;
1177 free(p
->custom_prog
);
1178 p
->custom_prog
= NULL
;
1179 free(p
->custom_tex
);
1180 p
->custom_tex
= NULL
;
1181 uninit_mpglcontext(p
->glctx
);
1186 static int preinit_internal(struct vo
*vo
, const char *arg
, int allow_sw
,
1187 enum MPGLType gltype
)
1189 struct gl_priv
*p
= talloc_zero(vo
, struct gl_priv
);
1192 *p
= (struct gl_priv
) {
1196 .colorspace
= MP_CSP_DETAILS_DEFAULTS
,
1197 .filter_strength
= 0.5,
1198 .use_rectangle
= -1,
1202 .custom_prog
= NULL
,
1205 .osd_color
= 0xffffff,
1208 p
->eosd
= talloc_zero(vo
, struct bitmap_packer
);
1210 //essentially unused; for legacy warnings only
1211 int user_colorspace
= 0;
1215 const opt_t subopts
[] = {
1216 {"manyfmts", OPT_ARG_BOOL
, &p
->many_fmts
, NULL
},
1217 {"osd", OPT_ARG_BOOL
, &p
->use_osd
, NULL
},
1218 {"scaled-osd", OPT_ARG_BOOL
, &p
->scaled_osd
, NULL
},
1219 {"ycbcr", OPT_ARG_BOOL
, &p
->use_ycbcr
, NULL
},
1220 {"slice-height", OPT_ARG_INT
, &p
->slice_height
, int_non_neg
},
1221 {"rectangle", OPT_ARG_INT
, &p
->use_rectangle
,int_non_neg
},
1222 {"yuv", OPT_ARG_INT
, &p
->use_yuv
, int_non_neg
},
1223 {"lscale", OPT_ARG_INT
, &p
->lscale
, int_non_neg
},
1224 {"cscale", OPT_ARG_INT
, &p
->cscale
, int_non_neg
},
1225 {"filter-strength", OPT_ARG_FLOAT
, &p
->filter_strength
, NULL
},
1226 {"ati-hack", OPT_ARG_BOOL
, &p
->ati_hack
, NULL
},
1227 {"force-pbo", OPT_ARG_BOOL
, &p
->force_pbo
, NULL
},
1228 {"glfinish", OPT_ARG_BOOL
, &p
->use_glFinish
, NULL
},
1229 {"swapinterval", OPT_ARG_INT
, &p
->swap_interval
,NULL
},
1230 {"customprog", OPT_ARG_MSTRZ
,&p
->custom_prog
, NULL
},
1231 {"customtex", OPT_ARG_MSTRZ
,&p
->custom_tex
, NULL
},
1232 {"customtlin", OPT_ARG_BOOL
, &p
->custom_tlin
, NULL
},
1233 {"customtrect", OPT_ARG_BOOL
, &p
->custom_trect
, NULL
},
1234 {"mipmapgen", OPT_ARG_BOOL
, &p
->mipmap_gen
, NULL
},
1235 {"osdcolor", OPT_ARG_INT
, &p
->osd_color
, NULL
},
1236 {"stereo", OPT_ARG_INT
, &p
->stereo_mode
, NULL
},
1238 // They are only parsed to notify the user about the replacements.
1239 {"aspect", OPT_ARG_BOOL
, &aspect
, NULL
},
1240 {"colorspace", OPT_ARG_INT
, &user_colorspace
, NULL
},
1241 {"levelconv", OPT_ARG_INT
, &levelconv
, NULL
},
1245 if (subopt_parse(arg
, subopts
) != 0) {
1246 mp_msg(MSGT_VO
, MSGL_FATAL
,
1247 "\n-vo gl command line help:\n"
1248 "Example: mplayer -vo gl:slice-height=4\n"
1251 " Disable extended color formats for OpenGL 1.2 and later\n"
1252 " slice-height=<0-...>\n"
1253 " Slice size for texture transfer, 0 for whole image\n"
1255 " Do not use OpenGL OSD code\n"
1257 " Render OSD at movie resolution and scale it\n"
1258 " rectangle=<0,1,2>\n"
1259 " 0: use power-of-two textures\n"
1260 " 1: use texture_rectangle\n"
1261 " 2: use texture_non_power_of_two\n"
1263 " Workaround ATI bug with PBOs\n"
1265 " Force use of PBO even if this involves an extra memcpy\n"
1267 " Call glFinish() before swapping buffers\n"
1268 " swapinterval=<n>\n"
1269 " Interval in displayed frames between to buffer swaps.\n"
1270 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
1271 " Requires GLX_SGI_swap_control support to work.\n"
1273 " also try to use the GL_MESA_ycbcr_texture extension\n"
1275 " 0: use software YUV to RGB conversion.\n"
1276 " 1: deprecated, will use yuv=2 (used to be nVidia register combiners).\n"
1277 " 2: use fragment program.\n"
1278 " 3: use fragment program with gamma correction.\n"
1279 " 4: use fragment program with gamma correction via lookup.\n"
1280 " 5: use ATI-specific method (for older cards).\n"
1281 " 6: use lookup via 3D texture.\n"
1283 " 0: use standard bilinear scaling for luma.\n"
1284 " 1: use improved bicubic scaling for luma.\n"
1285 " 2: use cubic in X, linear in Y direction scaling for luma.\n"
1286 " 3: as 1 but without using a lookup texture.\n"
1287 " 4: experimental unsharp masking (sharpening).\n"
1288 " 5: experimental unsharp masking (sharpening) with larger radius.\n"
1290 " as lscale but for chroma (2x slower with little visible effect).\n"
1291 " filter-strength=<value>\n"
1292 " set the effect strength for some lscale/cscale filters\n"
1293 " customprog=<filename>\n"
1294 " use a custom YUV conversion program\n"
1295 " customtex=<filename>\n"
1296 " use a custom YUV conversion lookup texture\n"
1298 " use GL_NEAREST scaling for customtex texture\n"
1300 " use texture_rectangle for customtex texture\n"
1302 " generate mipmaps for the video image (use with TXB in customprog)\n"
1303 " osdcolor=<0xAARRGGBB>\n"
1304 " use the given color for the OSD\n"
1306 " 0: normal display\n"
1307 " 1: side-by-side to red-cyan stereo\n"
1308 " 2: side-by-side to green-magenta stereo\n"
1309 " 3: side-by-side to quadbuffer stereo\n"
1313 if (user_colorspace
!= 0 || levelconv
!= -1) {
1314 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"colorspace\" and \"levelconv\" "
1315 "suboptions have been removed. Use options --colormatrix and"
1316 " --colormatrix-input-range/--colormatrix-output-range instead.\n");
1320 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"noaspect\" suboption has been "
1321 "removed. Use --noaspect instead.\n");
1324 if (p
->use_yuv
== 1) {
1325 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] yuv=1 (nVidia register combiners) have"
1326 " been removed, using yuv=2 instead.\n");
1329 p
->glctx
= init_mpglcontext(gltype
, vo
);
1332 p
->gl
= p
->glctx
->gl
;
1334 if (p
->glctx
->type
== GLTYPE_SDL
&& p
->use_yuv
== -1) {
1335 // Apparently it's not possible to implement VOFLAG_HIDDEN on SDL 1.2,
1336 // so don't do autodetection. Use a sufficiently useful and safe YUV
1338 p
->use_yuv
= YUV_CONVERSION_FRAGMENT
;
1341 if (p
->use_yuv
== -1 || !allow_sw
) {
1342 if (create_window(vo
, 320, 200, VOFLAG_HIDDEN
) < 0)
1344 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
1346 if (!allow_sw
&& isSoftwareGl(vo
))
1348 autodetectGlExtensions(vo
);
1349 // We created a window to test whether the GL context supports hardware
1350 // acceleration and so on. Destroy that window to make sure all state
1351 // associated with it is lost.
1353 p
->glctx
= init_mpglcontext(gltype
, vo
);
1356 p
->gl
= p
->glctx
->gl
;
1359 mp_msg(MSGT_VO
, MSGL_INFO
, "[gl] using extended formats. "
1360 "Use -vo gl:nomanyfmts if playback fails.\n");
1361 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Using %d as slice height "
1362 "(0 means image height).\n", p
->slice_height
);
1371 static int preinit(struct vo
*vo
, const char *arg
)
1373 return preinit_internal(vo
, arg
, 1, GLTYPE_AUTO
);
1376 static int control(struct vo
*vo
, uint32_t request
, void *data
)
1378 struct gl_priv
*p
= vo
->priv
;
1381 case VOCTRL_QUERY_FORMAT
:
1382 return query_format(vo
, *(uint32_t *)data
);
1383 case VOCTRL_GET_IMAGE
:
1384 return get_image(vo
, data
);
1385 case VOCTRL_DRAW_IMAGE
:
1386 return draw_image(vo
, data
);
1387 case VOCTRL_DRAW_EOSD
:
1391 if (vo_doublebuffering
)
1392 do_render_osd(vo
, RENDER_EOSD
);
1394 case VOCTRL_GET_EOSD_RES
: {
1395 mp_eosd_res_t
*r
= data
;
1398 r
->mt
= r
->mb
= r
->ml
= r
->mr
= 0;
1399 if (p
->scaled_osd
) {
1400 r
->w
= p
->image_width
;
1401 r
->h
= p
->image_height
;
1402 } else if (aspect_scaling()) {
1403 r
->ml
= r
->mr
= p
->ass_border_x
;
1404 r
->mt
= r
->mb
= p
->ass_border_y
;
1409 if (!p
->glctx
->ontop
)
1411 p
->glctx
->ontop(vo
);
1413 case VOCTRL_FULLSCREEN
:
1414 p
->glctx
->fullscreen(vo
);
1415 resize(vo
, vo
->dwidth
, vo
->dheight
);
1418 if (!p
->glctx
->border
)
1420 p
->glctx
->border(vo
);
1421 resize(vo
, vo
->dwidth
, vo
->dheight
);
1423 case VOCTRL_GET_PANSCAN
:
1425 case VOCTRL_SET_PANSCAN
:
1426 resize(vo
, vo
->dwidth
, vo
->dheight
);
1428 case VOCTRL_GET_EQUALIZER
:
1430 struct voctrl_get_equalizer_args
*args
= data
;
1431 return mp_csp_equalizer_get(&p
->video_eq
, args
->name
, args
->valueptr
)
1432 >= 0 ? VO_TRUE
: VO_NOTIMPL
;
1435 case VOCTRL_SET_EQUALIZER
:
1437 struct voctrl_set_equalizer_args
*args
= data
;
1438 if (mp_csp_equalizer_set(&p
->video_eq
, args
->name
, args
->value
) < 0)
1441 vo
->want_redraw
= true;
1445 case VOCTRL_SET_YUV_COLORSPACE
: {
1446 bool supports_csp
= (1 << p
->use_yuv
) & MASK_NOT_COMBINERS
;
1447 if (vo
->config_count
&& supports_csp
) {
1448 p
->colorspace
= *(struct mp_csp_details
*)data
;
1450 vo
->want_redraw
= true;
1454 case VOCTRL_GET_YUV_COLORSPACE
:
1455 *(struct mp_csp_details
*)data
= p
->colorspace
;
1457 case VOCTRL_UPDATE_SCREENINFO
:
1458 if (!p
->glctx
->update_xinerama_info
)
1460 p
->glctx
->update_xinerama_info(vo
);
1462 case VOCTRL_REDRAW_FRAME
:
1463 if (vo_doublebuffering
)
1466 case VOCTRL_SCREENSHOT
: {
1467 struct voctrl_screenshot_args
*args
= data
;
1468 if (args
->full_window
)
1469 args
->out_image
= get_window_screenshot(vo
);
1471 args
->out_image
= get_screenshot(vo
);
1478 const struct vo_driver video_out_gl
= {
1480 .info
= &(const vo_info_t
) {
1483 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1489 .draw_slice
= draw_slice
,
1490 .draw_osd
= draw_osd
,
1491 .flip_page
= flip_page
,
1492 .check_events
= check_events
,
1496 static int preinit_nosw(struct vo
*vo
, const char *arg
)
1498 return preinit_internal(vo
, arg
, 0, GLTYPE_AUTO
);
1501 const struct vo_driver video_out_gl_nosw
=
1504 .info
= &(const vo_info_t
) {
1505 "OpenGL no software rendering",
1507 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1510 .preinit
= preinit_nosw
,
1513 .draw_slice
= draw_slice
,
1514 .draw_osd
= draw_osd
,
1515 .flip_page
= flip_page
,
1516 .check_events
= check_events
,
1520 #ifdef CONFIG_GL_SDL
1521 static int preinit_sdl(struct vo
*vo
, const char *arg
)
1523 return preinit_internal(vo
, arg
, 1, GLTYPE_SDL
);
1526 const struct vo_driver video_out_gl_sdl
= {
1528 .info
= &(const vo_info_t
) {
1531 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1534 .preinit
= preinit_sdl
,
1537 .draw_slice
= draw_slice
,
1538 .draw_osd
= draw_osd
,
1539 .flip_page
= flip_page
,
1540 .check_events
= check_events
,