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 //! How many parts the OSD may consist of at most
48 #define MAX_OSD_PARTS 20
51 #define MASK_ALL_YUV (~(1 << YUV_CONVERSION_NONE))
52 #define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS)))
53 #define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT))
68 GLuint osdtex
[MAX_OSD_PARTS
];
69 //! Alpha textures for OSD
70 GLuint osdatex
[MAX_OSD_PARTS
];
72 int eosd_texture_width
, eosd_texture_height
;
73 struct bitmap_packer
*eosd
;
74 struct vertex_eosd
*eosd_va
;
75 int eosd_render_count
;
76 unsigned int bitmap_id
;
77 unsigned int bitmap_pos_id
;
78 //! Display lists that draw the OSD parts
79 GLuint osdDispList
[MAX_OSD_PARTS
];
80 GLuint osdaDispList
[MAX_OSD_PARTS
];
81 //! How many parts the OSD currently consists of
87 struct mp_csp_details colorspace
;
91 float filter_strength
;
97 uint32_t image_height
;
98 uint32_t image_format
;
99 uint32_t image_d_width
;
100 uint32_t image_d_height
;
116 void *bufferptr_uv
[2];
118 GLuint default_texs
[22];
126 struct mp_csp_equalizer video_eq
;
132 int ass_border_x
, ass_border_y
;
134 unsigned int slice_height
;
137 static void resize(struct vo
*vo
, int x
, int y
)
139 struct gl_priv
*p
= vo
->priv
;
142 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Resize: %dx%d\n", x
, y
);
144 int left
= 0, top
= 0, w
= x
, h
= y
;
145 geometry(&left
, &top
, &w
, &h
, vo
->dwidth
, vo
->dheight
);
147 gl
->Viewport(left
, top
, w
, h
);
149 gl
->Viewport(0, 0, x
, y
);
151 gl
->MatrixMode(GL_PROJECTION
);
153 p
->ass_border_x
= p
->ass_border_y
= 0;
154 if (aspect_scaling()) {
156 GLdouble scale_x
, scale_y
;
157 aspect(vo
, &new_w
, &new_h
, A_WINZOOM
);
158 panscan_calc_windowed(vo
);
159 new_w
+= vo
->panscan_x
;
160 new_h
+= vo
->panscan_y
;
161 scale_x
= (GLdouble
)new_w
/ (GLdouble
)x
;
162 scale_y
= (GLdouble
)new_h
/ (GLdouble
)y
;
163 gl
->Scaled(scale_x
, scale_y
, 1);
164 p
->ass_border_x
= (vo
->dwidth
- new_w
) / 2;
165 p
->ass_border_y
= (vo
->dheight
- new_h
) / 2;
167 gl
->Ortho(0, p
->image_width
, p
->image_height
, 0, -1, 1);
169 gl
->MatrixMode(GL_MODELVIEW
);
173 vo_osd_changed(OSDTYPE_OSD
);
175 gl
->Clear(GL_COLOR_BUFFER_BIT
);
176 vo
->want_redraw
= true;
179 static void texSize(struct vo
*vo
, int w
, int h
, int *texw
, int *texh
)
181 struct gl_priv
*p
= vo
->priv
;
183 if (p
->use_rectangle
) {
195 *texw
= (*texw
+ 511) & ~511;
198 //! maximum size of custom fragment program
199 #define MAX_CUSTOM_PROG_SIZE (1024 * 1024)
200 static void update_yuvconv(struct vo
*vo
)
202 struct gl_priv
*p
= vo
->priv
;
206 struct mp_csp_params cparams
= { .colorspace
= p
->colorspace
};
207 mp_csp_copy_equalizer_values(&cparams
, &p
->video_eq
);
208 gl_conversion_params_t params
= {
209 p
->target
, p
->yuvconvtype
, cparams
,
210 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_subbitmaps(p
->eosd
, imgs
, 0);
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 const char *vendor
= p
->gl
->GetString(GL_VENDOR
);
443 return !renderer
|| strcmp(renderer
, "Software Rasterizer") == 0 ||
444 strstr(renderer
, "llvmpipe") ||
445 strcmp(vendor
, "Microsoft Corporation") == 0;
448 static void autodetectGlExtensions(struct vo
*vo
)
450 struct gl_priv
*p
= vo
->priv
;
453 const char *extensions
= gl
->GetString(GL_EXTENSIONS
);
454 const char *vendor
= gl
->GetString(GL_VENDOR
);
455 const char *version
= gl
->GetString(GL_VERSION
);
456 const char *renderer
= gl
->GetString(GL_RENDERER
);
457 int is_ati
= vendor
&& strstr(vendor
, "ATI") != NULL
;
458 int ati_broken_pbo
= 0;
459 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Running on OpenGL '%s' by '%s', version '%s'\n",
460 renderer
, vendor
, version
);
461 if (is_ati
&& strncmp(version
, "2.1.", 4) == 0) {
462 int ver
= atoi(version
+ 4);
463 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Detected ATI driver version: %i\n", ver
);
464 ati_broken_pbo
= ver
&& ver
< 8395;
466 if (p
->ati_hack
== -1)
467 p
->ati_hack
= ati_broken_pbo
;
468 if (p
->force_pbo
== -1) {
470 if (extensions
&& strstr(extensions
, "_pixel_buffer_object"))
471 p
->force_pbo
= is_ati
;
473 p
->have_texture_rg
= extensions
&& strstr(extensions
, "GL_ARB_texture_rg");
474 if (p
->use_rectangle
== -1) {
475 p
->use_rectangle
= 0;
477 // if (strstr(extensions, "_texture_non_power_of_two"))
478 if (strstr(extensions
, "_texture_rectangle"))
479 p
->use_rectangle
= renderer
480 && strstr(renderer
, "Mesa DRI R200") ? 1 : 0;
483 if (p
->use_osd
== -1)
484 p
->use_osd
= gl
->BindTexture
!= NULL
;
485 if (p
->use_yuv
== -1)
486 p
->use_yuv
= glAutodetectYUVConversion(gl
);
489 int yuv_mask
= (1 << p
->use_yuv
);
490 if (!(yuv_mask
& MASK_NOT_COMBINERS
)) {
492 eq_caps
= (1 << MP_CSP_EQ_HUE
) | (1 << MP_CSP_EQ_SATURATION
);
493 } else if (yuv_mask
& MASK_ALL_YUV
) {
494 eq_caps
= MP_CSP_EQ_CAPS_COLORMATRIX
;
495 if (yuv_mask
& MASK_GAMMA_SUPPORT
)
496 eq_caps
|= MP_CSP_EQ_CAPS_GAMMA
;
498 p
->video_eq
.capabilities
= eq_caps
;
500 if (is_ati
&& (p
->lscale
== 1 || p
->lscale
== 2 || p
->cscale
== 1 || p
->cscale
== 2))
501 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] Selected scaling mode may be broken on"
503 "Tell _them_ to fix GL_REPEAT if you have issues.\n");
504 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Settings after autodetection: ati-hack = %i, "
505 "force-pbo = %i, rectangle = %i, yuv = %i\n",
506 p
->ati_hack
, p
->force_pbo
, p
->use_rectangle
, p
->use_yuv
);
509 static GLint
get_scale_type(struct vo
*vo
, int chroma
)
511 struct gl_priv
*p
= vo
->priv
;
513 int nearest
= (chroma
? p
->cscale
: p
->lscale
) & 64;
515 return p
->mipmap_gen
? GL_NEAREST_MIPMAP_NEAREST
: GL_NEAREST
;
516 return p
->mipmap_gen
? GL_LINEAR_MIPMAP_NEAREST
: GL_LINEAR
;
519 // Return the high byte of the value that represents white in chroma (U/V)
520 static int get_chroma_clear_val(int bit_depth
)
522 return 1 << (bit_depth
- 1 & 7);
526 * \brief Initialize a (new or reused) OpenGL context.
527 * set global gl-related variables to their default values
529 static int initGl(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
)
531 struct gl_priv
*p
= vo
->priv
;
534 GLint scale_type
= get_scale_type(vo
, 0);
535 autodetectGlExtensions(vo
);
536 p
->target
= p
->use_rectangle
== 1 ? GL_TEXTURE_RECTANGLE
: GL_TEXTURE_2D
;
537 p
->yuvconvtype
= SET_YUV_CONVERSION(p
->use_yuv
) |
538 SET_YUV_LUM_SCALER(p
->lscale
) |
539 SET_YUV_CHROM_SCALER(p
->cscale
);
541 texSize(vo
, p
->image_width
, p
->image_height
,
542 &p
->texture_width
, &p
->texture_height
);
544 gl
->Disable(GL_BLEND
);
545 gl
->Disable(GL_DEPTH_TEST
);
546 gl
->DepthMask(GL_FALSE
);
547 gl
->Disable(GL_CULL_FACE
);
548 gl
->Enable(p
->target
);
549 gl
->DrawBuffer(vo_doublebuffering
? GL_BACK
: GL_FRONT
);
550 gl
->TexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
552 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Creating %dx%d texture...\n",
553 p
->texture_width
, p
->texture_height
);
555 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
556 p
->gl_type
, scale_type
,
557 p
->texture_width
, p
->texture_height
, 0);
560 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
565 scale_type
= get_scale_type(vo
, 1);
566 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &depth
);
567 int clear
= get_chroma_clear_val(depth
);
568 gl
->GenTextures(21, p
->default_texs
);
569 p
->default_texs
[21] = 0;
570 for (i
= 0; i
< 7; i
++) {
571 gl
->ActiveTexture(GL_TEXTURE1
+ i
);
572 gl
->BindTexture(GL_TEXTURE_2D
, p
->default_texs
[i
]);
573 gl
->BindTexture(GL_TEXTURE_RECTANGLE
, p
->default_texs
[i
+ 7]);
574 gl
->BindTexture(GL_TEXTURE_3D
, p
->default_texs
[i
+ 14]);
576 gl
->ActiveTexture(GL_TEXTURE1
);
577 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
578 p
->gl_type
, scale_type
,
579 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
582 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
583 gl
->ActiveTexture(GL_TEXTURE2
);
584 glCreateClearTex(gl
, p
->target
, p
->texfmt
, p
->gl_format
,
585 p
->gl_type
, scale_type
,
586 p
->texture_width
>> xs
, p
->texture_height
>> ys
,
589 gl
->TexParameteri(p
->target
, GL_GENERATE_MIPMAP
, GL_TRUE
);
590 gl
->ActiveTexture(GL_TEXTURE0
);
591 gl
->BindTexture(p
->target
, 0);
593 if (p
->is_yuv
|| p
->custom_prog
) {
594 if ((MASK_NOT_COMBINERS
& (1 << p
->use_yuv
)) || p
->custom_prog
) {
595 if (!gl
->GenPrograms
|| !gl
->BindProgram
)
596 mp_msg(MSGT_VO
, MSGL_ERR
,
597 "[gl] fragment program functions missing!\n");
599 gl
->GenPrograms(1, &p
->fragprog
);
600 gl
->BindProgram(GL_FRAGMENT_PROGRAM
, p
->fragprog
);
606 GLint max_texture_size
;
607 gl
->GetIntegerv(GL_MAX_TEXTURE_SIZE
, &max_texture_size
);
608 p
->eosd
->w_max
= p
->eosd
->h_max
= max_texture_size
;
610 resize(vo
, d_width
, d_height
);
612 gl
->ClearColor(0.0f
, 0.0f
, 0.0f
, 0.0f
);
613 gl
->Clear(GL_COLOR_BUFFER_BIT
);
614 if (gl
->SwapInterval
&& p
->swap_interval
>= 0)
615 gl
->SwapInterval(p
->swap_interval
);
619 static int create_window(struct vo
*vo
, uint32_t d_width
, uint32_t d_height
,
622 struct gl_priv
*p
= vo
->priv
;
624 if (p
->stereo_mode
== GL_3D_QUADBUFFER
)
625 flags
|= VOFLAG_STEREO
;
627 return p
->glctx
->create_window(p
->glctx
, d_width
, d_height
, flags
);
630 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
631 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
634 struct gl_priv
*p
= vo
->priv
;
637 p
->image_height
= height
;
638 p
->image_width
= width
;
639 p
->image_format
= format
;
640 p
->image_d_width
= d_width
;
641 p
->image_d_height
= d_height
;
642 p
->is_yuv
= mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
) > 0;
643 p
->is_yuv
|= (xs
<< 8) | (ys
<< 16);
644 glFindFormat(format
, p
->have_texture_rg
, NULL
, &p
->texfmt
, &p
->gl_format
,
647 p
->vo_flipped
= !!(flags
& VOFLAG_FLIPPING
);
649 if (create_window(vo
, d_width
, d_height
, flags
) < 0)
652 if (vo
->config_count
)
654 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
656 initGl(vo
, vo
->dwidth
, vo
->dheight
);
661 static void check_events(struct vo
*vo
)
663 struct gl_priv
*p
= vo
->priv
;
665 int e
= p
->glctx
->check_events(vo
);
666 if (e
& VO_EVENT_REINIT
) {
668 initGl(vo
, vo
->dwidth
, vo
->dheight
);
670 if (e
& VO_EVENT_RESIZE
)
671 resize(vo
, vo
->dwidth
, vo
->dheight
);
672 if (e
& VO_EVENT_EXPOSE
)
673 vo
->want_redraw
= true;
677 * Creates the textures and the display list needed for displaying
679 * Callback function for osd_draw_text_ext().
681 static void create_osd_texture(void *ctx
, int x0
, int y0
, int w
, int h
,
682 unsigned char *src
, unsigned char *srca
,
686 struct gl_priv
*p
= vo
->priv
;
689 // initialize to 8 to avoid special-casing on alignment
691 GLint scale_type
= p
->scaled_osd
? GL_LINEAR
: GL_NEAREST
;
693 if (w
<= 0 || h
<= 0 || stride
< w
) {
694 mp_msg(MSGT_VO
, MSGL_V
, "Invalid dimensions OSD for part!\n");
697 texSize(vo
, w
, h
, &sx
, &sy
);
699 if (p
->osdtexCnt
>= MAX_OSD_PARTS
) {
700 mp_msg(MSGT_VO
, MSGL_ERR
, "Too many OSD parts, contact the developers!\n");
704 // create Textures for OSD part
705 gl
->GenTextures(1, &p
->osdtex
[p
->osdtexCnt
]);
706 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
707 glCreateClearTex(gl
, p
->target
, GL_LUMINANCE
, GL_LUMINANCE
,
708 GL_UNSIGNED_BYTE
, scale_type
, sx
, sy
, 0);
709 glUploadTex(gl
, p
->target
, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, src
, stride
,
712 gl
->GenTextures(1, &p
->osdatex
[p
->osdtexCnt
]);
713 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
714 glCreateClearTex(gl
, p
->target
, GL_ALPHA
, GL_ALPHA
, GL_UNSIGNED_BYTE
,
715 scale_type
, sx
, sy
, 0);
718 char *tmp
= malloc(stride
* h
);
719 // convert alpha from weird MPlayer scale.
720 // in-place is not possible since it is reused for future OSDs
721 for (i
= h
* stride
- 1; i
>= 0; i
--)
723 glUploadTex(gl
, p
->target
, GL_ALPHA
, GL_UNSIGNED_BYTE
, tmp
, stride
,
728 gl
->BindTexture(p
->target
, 0);
730 // Create a list for rendering this OSD part
731 p
->osdaDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
732 gl
->NewList(p
->osdaDispList
[p
->osdtexCnt
], GL_COMPILE
);
734 gl
->BindTexture(p
->target
, p
->osdatex
[p
->osdtexCnt
]);
735 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
737 p
->osdDispList
[p
->osdtexCnt
] = gl
->GenLists(1);
738 gl
->NewList(p
->osdDispList
[p
->osdtexCnt
], GL_COMPILE
);
740 gl
->BindTexture(p
->target
, p
->osdtex
[p
->osdtexCnt
]);
741 glDrawTex(gl
, x0
, y0
, w
, h
, 0, 0, w
, h
, sx
, sy
, p
->use_rectangle
== 1, 0, 0);
748 #define RENDER_EOSD 2
751 * \param type bit 0: render OSD, bit 1: render EOSD
753 static void do_render_osd(struct vo
*vo
, int type
)
755 struct gl_priv
*p
= vo
->priv
;
758 int draw_osd
= (type
& RENDER_OSD
) && p
->osdtexCnt
> 0;
759 int draw_eosd
= (type
& RENDER_EOSD
);
760 if (!draw_osd
&& !draw_eosd
)
762 // set special rendering parameters
763 if (!p
->scaled_osd
) {
764 gl
->MatrixMode(GL_PROJECTION
);
767 gl
->Ortho(0, vo
->dwidth
, vo
->dheight
, 0, -1, 1);
769 gl
->Enable(GL_BLEND
);
771 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
775 gl
->Color4ub((p
->osd_color
>> 16) & 0xff, (p
->osd_color
>> 8) & 0xff,
776 p
->osd_color
& 0xff, 0xff - (p
->osd_color
>> 24));
778 gl
->BlendFunc(GL_ZERO
, GL_ONE_MINUS_SRC_ALPHA
);
779 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdaDispList
);
780 gl
->BlendFunc(GL_SRC_ALPHA
, GL_ONE
);
781 gl
->CallLists(p
->osdtexCnt
, GL_UNSIGNED_INT
, p
->osdDispList
);
783 // set rendering parameters back to defaults
784 gl
->Disable(GL_BLEND
);
787 gl
->BindTexture(p
->target
, 0);
790 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
792 struct gl_priv
*p
= vo
->priv
;
796 if (vo_osd_changed(0)) {
799 osd_w
= p
->scaled_osd
? p
->image_width
: vo
->dwidth
;
800 osd_h
= p
->scaled_osd
? p
->image_height
: vo
->dheight
;
801 osd_draw_text_ext(osd
, osd_w
, osd_h
, p
->ass_border_x
,
802 p
->ass_border_y
, p
->ass_border_x
,
803 p
->ass_border_y
, p
->image_width
,
804 p
->image_height
, create_osd_texture
, vo
);
806 if (vo_doublebuffering
)
807 do_render_osd(vo
, RENDER_OSD
);
810 static void do_render(struct vo
*vo
)
812 struct gl_priv
*p
= vo
->priv
;
815 // Enable(GL_TEXTURE_2D);
816 // BindTexture(GL_TEXTURE_2D, texture_id);
818 gl
->Color4f(1, 1, 1, 1);
819 if (p
->is_yuv
|| p
->custom_prog
)
820 glEnableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
821 if (p
->stereo_mode
) {
822 glEnable3DLeft(gl
, p
->stereo_mode
);
823 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
824 0, 0, p
->image_width
>> 1, p
->image_height
,
825 p
->texture_width
, p
->texture_height
,
826 p
->use_rectangle
== 1, p
->is_yuv
,
827 p
->mpi_flipped
^ p
->vo_flipped
);
828 glEnable3DRight(gl
, p
->stereo_mode
);
829 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
830 p
->image_width
>> 1, 0, p
->image_width
>> 1,
831 p
->image_height
, p
->texture_width
, p
->texture_height
,
832 p
->use_rectangle
== 1, p
->is_yuv
,
833 p
->mpi_flipped
^ p
->vo_flipped
);
834 glDisable3D(gl
, p
->stereo_mode
);
836 glDrawTex(gl
, 0, 0, p
->image_width
, p
->image_height
,
837 0, 0, p
->image_width
, p
->image_height
,
838 p
->texture_width
, p
->texture_height
,
839 p
->use_rectangle
== 1, p
->is_yuv
,
840 p
->mpi_flipped
^ p
->vo_flipped
);
842 if (p
->is_yuv
|| p
->custom_prog
)
843 glDisableYUVConversion(gl
, p
->target
, p
->yuvconvtype
);
846 static void flip_page(struct vo
*vo
)
848 struct gl_priv
*p
= vo
->priv
;
851 if (vo_doublebuffering
) {
854 p
->glctx
->swapGlBuffers(p
->glctx
);
855 if (aspect_scaling())
856 gl
->Clear(GL_COLOR_BUFFER_BIT
);
859 do_render_osd(vo
, RENDER_OSD
| RENDER_EOSD
);
867 static int draw_slice(struct vo
*vo
, uint8_t *src
[], int stride
[], int w
, int h
,
870 struct gl_priv
*p
= vo
->priv
;
873 p
->mpi_flipped
= stride
[0] < 0;
874 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[0], stride
[0],
875 x
, y
, w
, h
, p
->slice_height
);
878 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
879 gl
->ActiveTexture(GL_TEXTURE1
);
880 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[1], stride
[1],
881 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
882 gl
->ActiveTexture(GL_TEXTURE2
);
883 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, src
[2], stride
[2],
884 x
>> xs
, y
>> ys
, w
>> xs
, h
>> ys
, p
->slice_height
);
885 gl
->ActiveTexture(GL_TEXTURE0
);
890 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
892 struct gl_priv
*p
= vo
->priv
;
896 if (!gl
->GenBuffers
|| !gl
->BindBuffer
|| !gl
->BufferData
|| !gl
->MapBuffer
) {
898 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] extensions missing for dr\n"
899 "Expect a _major_ speed penalty\n");
903 if (mpi
->flags
& MP_IMGFLAG_READABLE
)
905 if (mpi
->type
!= MP_IMGTYPE_STATIC
&& mpi
->type
!= MP_IMGTYPE_TEMP
&&
906 (mpi
->type
!= MP_IMGTYPE_NUMBERED
|| mpi
->number
))
909 mpi
->width
= p
->texture_width
;
910 mpi
->height
= p
->texture_height
;
912 mpi
->stride
[0] = mpi
->width
* mpi
->bpp
/ 8;
913 needed_size
= mpi
->stride
[0] * mpi
->height
;
915 gl
->GenBuffers(1, &p
->buffer
);
916 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
917 if (needed_size
> p
->buffersize
) {
918 p
->buffersize
= needed_size
;
919 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, p
->buffersize
,
920 NULL
, GL_DYNAMIC_DRAW
);
923 p
->bufferptr
= gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_WRITE_ONLY
);
924 mpi
->planes
[0] = p
->bufferptr
;
925 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0);
926 if (!mpi
->planes
[0]) {
928 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] could not acquire buffer for dr\n"
929 "Expect a _major_ speed penalty\n");
935 int xs
, ys
, component_bits
;
936 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
937 int bp
= (component_bits
+ 7) / 8;
938 mpi
->flags
|= MP_IMGFLAG_COMMON_STRIDE
| MP_IMGFLAG_COMMON_PLANE
;
939 mpi
->stride
[0] = mpi
->width
* bp
;
940 mpi
->planes
[1] = mpi
->planes
[0] + mpi
->stride
[0] * mpi
->height
;
941 mpi
->stride
[1] = (mpi
->width
>> xs
) * bp
;
942 mpi
->planes
[2] = mpi
->planes
[1] + mpi
->stride
[1] * (mpi
->height
>> ys
);
943 mpi
->stride
[2] = (mpi
->width
>> xs
) * bp
;
945 mpi
->flags
&= ~MP_IMGFLAG_COMMON_PLANE
;
946 if (!p
->buffer_uv
[0])
947 gl
->GenBuffers(2, p
->buffer_uv
);
948 int buffer_size
= mpi
->stride
[1] * mpi
->height
;
949 if (buffer_size
> p
->buffersize_uv
) {
950 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
951 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
953 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
954 gl
->BufferData(GL_PIXEL_UNPACK_BUFFER
, buffer_size
, NULL
,
956 p
->buffersize_uv
= buffer_size
;
958 if (!p
->bufferptr_uv
[0]) {
959 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
960 p
->bufferptr_uv
[0] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
962 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
963 p
->bufferptr_uv
[1] = gl
->MapBuffer(GL_PIXEL_UNPACK_BUFFER
,
966 mpi
->planes
[1] = p
->bufferptr_uv
[0];
967 mpi
->planes
[2] = p
->bufferptr_uv
[1];
970 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
974 static void clear_border(struct vo
*vo
, uint8_t *dst
, int start
, int stride
,
975 int height
, int full_height
, int value
)
977 int right_border
= stride
- start
;
978 int bottom_border
= full_height
- height
;
980 if (right_border
> 0)
981 memset(dst
+ start
, value
, right_border
);
985 if (bottom_border
> 0)
986 memset(dst
, value
, stride
* bottom_border
);
989 static uint32_t draw_image(struct vo
*vo
, mp_image_t
*mpi
)
991 struct gl_priv
*p
= vo
->priv
;
994 int slice
= p
->slice_height
;
996 unsigned char *planes
[3];
997 mp_image_t mpi2
= *mpi
;
998 int w
= mpi
->w
, h
= mpi
->h
;
999 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
1002 mpi2
.type
= MP_IMGTYPE_TEMP
;
1003 mpi2
.width
= mpi2
.w
;
1004 mpi2
.height
= mpi2
.h
;
1005 if (p
->force_pbo
&& !(mpi
->flags
& MP_IMGFLAG_DIRECT
) && !p
->bufferptr
1006 && get_image(vo
, &mpi2
) == VO_TRUE
)
1008 int bp
= mpi
->bpp
/ 8;
1009 int xs
, ys
, component_bits
;
1010 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, &component_bits
);
1012 bp
= (component_bits
+ 7) / 8;
1013 memcpy_pic(mpi2
.planes
[0], mpi
->planes
[0], mpi
->w
* bp
, mpi
->h
,
1014 mpi2
.stride
[0], mpi
->stride
[0]);
1015 int uv_bytes
= (mpi
->w
>> xs
) * bp
;
1017 memcpy_pic(mpi2
.planes
[1], mpi
->planes
[1], uv_bytes
, mpi
->h
>> ys
,
1018 mpi2
.stride
[1], mpi
->stride
[1]);
1019 memcpy_pic(mpi2
.planes
[2], mpi
->planes
[2], uv_bytes
, mpi
->h
>> ys
,
1020 mpi2
.stride
[2], mpi
->stride
[2]);
1023 // since we have to do a full upload we need to clear the borders
1024 clear_border(vo
, mpi2
.planes
[0], mpi
->w
* bp
, mpi2
.stride
[0],
1025 mpi
->h
, mpi2
.height
, 0);
1027 int clear
= get_chroma_clear_val(component_bits
);
1028 clear_border(vo
, mpi2
.planes
[1], uv_bytes
, mpi2
.stride
[1],
1029 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1030 clear_border(vo
, mpi2
.planes
[2], uv_bytes
, mpi2
.stride
[2],
1031 mpi
->h
>> ys
, mpi2
.height
>> ys
, clear
);
1036 stride
[0] = mpi
->stride
[0];
1037 stride
[1] = mpi
->stride
[1];
1038 stride
[2] = mpi
->stride
[2];
1039 planes
[0] = mpi
->planes
[0];
1040 planes
[1] = mpi
->planes
[1];
1041 planes
[2] = mpi
->planes
[2];
1042 p
->mpi_flipped
= stride
[0] < 0;
1043 if (mpi
->flags
& MP_IMGFLAG_DIRECT
) {
1044 intptr_t base
= (intptr_t)planes
[0];
1046 w
= p
->texture_width
;
1047 h
= p
->texture_height
;
1050 base
+= (mpi
->h
- 1) * stride
[0];
1054 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer
);
1055 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1056 p
->bufferptr
= NULL
;
1057 if (!(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
))
1058 planes
[0] = planes
[1] = planes
[2] = NULL
;
1059 slice
= 0; // always "upload" full texture
1061 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[0],
1062 stride
[0], 0, 0, w
, h
, slice
);
1065 mp_get_chroma_shift(p
->image_format
, &xs
, &ys
, NULL
);
1066 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1067 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[0]);
1068 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1069 p
->bufferptr_uv
[0] = NULL
;
1071 gl
->ActiveTexture(GL_TEXTURE1
);
1072 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[1],
1073 stride
[1], 0, 0, w
>> xs
, h
>> ys
, slice
);
1074 if ((mpi
->flags
& MP_IMGFLAG_DIRECT
) && !(mpi
->flags
& MP_IMGFLAG_COMMON_PLANE
)) {
1075 gl
->BindBuffer(GL_PIXEL_UNPACK_BUFFER
, p
->buffer_uv
[1]);
1076 gl
->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER
);
1077 p
->bufferptr_uv
[1] = NULL
;
1079 gl
->ActiveTexture(GL_TEXTURE2
);
1080 glUploadTex(gl
, p
->target
, p
->gl_format
, p
->gl_type
, planes
[2],
1081 stride
[2], 0, 0, w
>> xs
, h
>> ys
, slice
);
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 backend_valid(void *arg
)
1188 return mpgl_find_backend(*(const char **)arg
) >= 0;
1191 static int preinit(struct vo
*vo
, const char *arg
)
1193 struct gl_priv
*p
= talloc_zero(vo
, struct gl_priv
);
1196 *p
= (struct gl_priv
) {
1200 .colorspace
= MP_CSP_DETAILS_DEFAULTS
,
1201 .filter_strength
= 0.5,
1202 .use_rectangle
= -1,
1206 .custom_prog
= NULL
,
1209 .osd_color
= 0xffffff,
1212 p
->eosd
= talloc_zero(vo
, struct bitmap_packer
);
1215 char *backend_arg
= NULL
;
1217 //essentially unused; for legacy warnings only
1218 int user_colorspace
= 0;
1222 const opt_t subopts
[] = {
1223 {"manyfmts", OPT_ARG_BOOL
, &p
->many_fmts
, NULL
},
1224 {"osd", OPT_ARG_BOOL
, &p
->use_osd
, NULL
},
1225 {"scaled-osd", OPT_ARG_BOOL
, &p
->scaled_osd
, NULL
},
1226 {"ycbcr", OPT_ARG_BOOL
, &p
->use_ycbcr
, NULL
},
1227 {"slice-height", OPT_ARG_INT
, &p
->slice_height
, int_non_neg
},
1228 {"rectangle", OPT_ARG_INT
, &p
->use_rectangle
,int_non_neg
},
1229 {"yuv", OPT_ARG_INT
, &p
->use_yuv
, int_non_neg
},
1230 {"lscale", OPT_ARG_INT
, &p
->lscale
, int_non_neg
},
1231 {"cscale", OPT_ARG_INT
, &p
->cscale
, int_non_neg
},
1232 {"filter-strength", OPT_ARG_FLOAT
, &p
->filter_strength
, NULL
},
1233 {"noise-strength", OPT_ARG_FLOAT
, &p
->noise_strength
, NULL
},
1234 {"ati-hack", OPT_ARG_BOOL
, &p
->ati_hack
, NULL
},
1235 {"force-pbo", OPT_ARG_BOOL
, &p
->force_pbo
, NULL
},
1236 {"glfinish", OPT_ARG_BOOL
, &p
->use_glFinish
, NULL
},
1237 {"swapinterval", OPT_ARG_INT
, &p
->swap_interval
,NULL
},
1238 {"customprog", OPT_ARG_MSTRZ
,&p
->custom_prog
, NULL
},
1239 {"customtex", OPT_ARG_MSTRZ
,&p
->custom_tex
, NULL
},
1240 {"customtlin", OPT_ARG_BOOL
, &p
->custom_tlin
, NULL
},
1241 {"customtrect", OPT_ARG_BOOL
, &p
->custom_trect
, NULL
},
1242 {"mipmapgen", OPT_ARG_BOOL
, &p
->mipmap_gen
, NULL
},
1243 {"osdcolor", OPT_ARG_INT
, &p
->osd_color
, NULL
},
1244 {"stereo", OPT_ARG_INT
, &p
->stereo_mode
, NULL
},
1245 {"sw", OPT_ARG_BOOL
, &allow_sw
, NULL
},
1246 {"backend", OPT_ARG_MSTRZ
,&backend_arg
, backend_valid
},
1248 // They are only parsed to notify the user about the replacements.
1249 {"aspect", OPT_ARG_BOOL
, &aspect
, NULL
},
1250 {"colorspace", OPT_ARG_INT
, &user_colorspace
, NULL
},
1251 {"levelconv", OPT_ARG_INT
, &levelconv
, NULL
},
1255 if (subopt_parse(arg
, subopts
) != 0) {
1256 mp_msg(MSGT_VO
, MSGL_FATAL
,
1257 "\n-vo gl command line help:\n"
1258 "Example: mplayer -vo gl:slice-height=4\n"
1261 " Disable extended color formats for OpenGL 1.2 and later\n"
1262 " slice-height=<0-...>\n"
1263 " Slice size for texture transfer, 0 for whole image\n"
1265 " Do not use OpenGL OSD code\n"
1267 " Render OSD at movie resolution and scale it\n"
1268 " rectangle=<0,1,2>\n"
1269 " 0: use power-of-two textures\n"
1270 " 1: use texture_rectangle\n"
1271 " 2: use texture_non_power_of_two\n"
1273 " Workaround ATI bug with PBOs\n"
1275 " Force use of PBO even if this involves an extra memcpy\n"
1277 " Call glFinish() before swapping buffers\n"
1278 " swapinterval=<n>\n"
1279 " Interval in displayed frames between to buffer swaps.\n"
1280 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
1281 " Requires GLX_SGI_swap_control support to work.\n"
1283 " also try to use the GL_MESA_ycbcr_texture extension\n"
1285 " 0: use software YUV to RGB conversion.\n"
1286 " 1: deprecated, will use yuv=2 (used to be nVidia register combiners).\n"
1287 " 2: use fragment program.\n"
1288 " 3: use fragment program with gamma correction.\n"
1289 " 4: use fragment program with gamma correction via lookup.\n"
1290 " 5: use ATI-specific method (for older cards).\n"
1291 " 6: use lookup via 3D texture.\n"
1293 " 0: use standard bilinear scaling for luma.\n"
1294 " 1: use improved bicubic scaling for luma.\n"
1295 " 2: use cubic in X, linear in Y direction scaling for luma.\n"
1296 " 3: as 1 but without using a lookup texture.\n"
1297 " 4: experimental unsharp masking (sharpening).\n"
1298 " 5: experimental unsharp masking (sharpening) with larger radius.\n"
1300 " as lscale but for chroma (2x slower with little visible effect).\n"
1301 " filter-strength=<value>\n"
1302 " set the effect strength for some lscale/cscale filters\n"
1303 " noise-strength=<value>\n"
1304 " set how much noise to add. 1.0 is suitable for dithering to 6 bit.\n"
1305 " customprog=<filename>\n"
1306 " use a custom YUV conversion program\n"
1307 " customtex=<filename>\n"
1308 " use a custom YUV conversion lookup texture\n"
1310 " use GL_NEAREST scaling for customtex texture\n"
1312 " use texture_rectangle for customtex texture\n"
1314 " generate mipmaps for the video image (use with TXB in customprog)\n"
1315 " osdcolor=<0xAARRGGBB>\n"
1316 " use the given color for the OSD\n"
1318 " 0: normal display\n"
1319 " 1: side-by-side to red-cyan stereo\n"
1320 " 2: side-by-side to green-magenta stereo\n"
1321 " 3: side-by-side to quadbuffer stereo\n"
1323 " allow using a software renderer, if such is detected\n"
1325 " auto: auto-select (default)\n"
1326 " cocoa: Cocoa/OSX\n"
1333 if (user_colorspace
!= 0 || levelconv
!= -1) {
1334 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"colorspace\" and \"levelconv\" "
1335 "suboptions have been removed. Use options --colormatrix and"
1336 " --colormatrix-input-range/--colormatrix-output-range instead.\n");
1340 mp_msg(MSGT_VO
, MSGL_ERR
, "[gl] \"noaspect\" suboption has been "
1341 "removed. Use --noaspect instead.\n");
1344 if (p
->use_yuv
== 1) {
1345 mp_msg(MSGT_VO
, MSGL_WARN
, "[gl] yuv=1 (nVidia register combiners) have"
1346 " been removed, using yuv=2 instead.\n");
1350 int backend
= backend_arg
? mpgl_find_backend(backend_arg
) : GLTYPE_AUTO
;
1353 p
->glctx
= init_mpglcontext(backend
, vo
);
1356 p
->gl
= p
->glctx
->gl
;
1358 if (p
->glctx
->type
== GLTYPE_SDL
&& p
->use_yuv
== -1) {
1359 // Apparently it's not possible to implement VOFLAG_HIDDEN on SDL 1.2,
1360 // so don't do autodetection. Use a sufficiently useful and safe YUV
1362 p
->use_yuv
= YUV_CONVERSION_FRAGMENT
;
1365 if (p
->use_yuv
== -1 || !allow_sw
) {
1366 if (create_window(vo
, 320, 200, VOFLAG_HIDDEN
) < 0)
1368 if (p
->glctx
->setGlWindow(p
->glctx
) == SET_WINDOW_FAILED
)
1370 if (!allow_sw
&& isSoftwareGl(vo
))
1372 autodetectGlExtensions(vo
);
1373 // We created a window to test whether the GL context supports hardware
1374 // acceleration and so on. Destroy that window to make sure all state
1375 // associated with it is lost.
1377 p
->glctx
= init_mpglcontext(backend
, vo
);
1380 p
->gl
= p
->glctx
->gl
;
1383 mp_msg(MSGT_VO
, MSGL_INFO
, "[gl] using extended formats. "
1384 "Use -vo gl:nomanyfmts if playback fails.\n");
1385 mp_msg(MSGT_VO
, MSGL_V
, "[gl] Using %d as slice height "
1386 "(0 means image height).\n", p
->slice_height
);
1395 static int control(struct vo
*vo
, uint32_t request
, void *data
)
1397 struct gl_priv
*p
= vo
->priv
;
1400 case VOCTRL_QUERY_FORMAT
:
1401 return query_format(vo
, *(uint32_t *)data
);
1402 case VOCTRL_GET_IMAGE
:
1403 return get_image(vo
, data
);
1404 case VOCTRL_DRAW_IMAGE
:
1405 return draw_image(vo
, data
);
1406 case VOCTRL_DRAW_EOSD
:
1410 if (vo_doublebuffering
)
1411 do_render_osd(vo
, RENDER_EOSD
);
1413 case VOCTRL_GET_EOSD_RES
: {
1414 mp_eosd_res_t
*r
= data
;
1417 r
->mt
= r
->mb
= r
->ml
= r
->mr
= 0;
1418 if (p
->scaled_osd
) {
1419 r
->w
= p
->image_width
;
1420 r
->h
= p
->image_height
;
1421 } else if (aspect_scaling()) {
1422 r
->ml
= r
->mr
= p
->ass_border_x
;
1423 r
->mt
= r
->mb
= p
->ass_border_y
;
1428 if (!p
->glctx
->ontop
)
1430 p
->glctx
->ontop(vo
);
1432 case VOCTRL_FULLSCREEN
:
1433 p
->glctx
->fullscreen(vo
);
1434 resize(vo
, vo
->dwidth
, vo
->dheight
);
1437 if (!p
->glctx
->border
)
1439 p
->glctx
->border(vo
);
1440 resize(vo
, vo
->dwidth
, vo
->dheight
);
1442 case VOCTRL_GET_PANSCAN
:
1444 case VOCTRL_SET_PANSCAN
:
1445 resize(vo
, vo
->dwidth
, vo
->dheight
);
1447 case VOCTRL_GET_EQUALIZER
:
1449 struct voctrl_get_equalizer_args
*args
= data
;
1450 return mp_csp_equalizer_get(&p
->video_eq
, args
->name
, args
->valueptr
)
1451 >= 0 ? VO_TRUE
: VO_NOTIMPL
;
1454 case VOCTRL_SET_EQUALIZER
:
1456 struct voctrl_set_equalizer_args
*args
= data
;
1457 if (mp_csp_equalizer_set(&p
->video_eq
, args
->name
, args
->value
) < 0)
1460 vo
->want_redraw
= true;
1464 case VOCTRL_SET_YUV_COLORSPACE
: {
1465 bool supports_csp
= (1 << p
->use_yuv
) & MASK_NOT_COMBINERS
;
1466 if (vo
->config_count
&& supports_csp
) {
1467 p
->colorspace
= *(struct mp_csp_details
*)data
;
1469 vo
->want_redraw
= true;
1473 case VOCTRL_GET_YUV_COLORSPACE
:
1474 *(struct mp_csp_details
*)data
= p
->colorspace
;
1476 case VOCTRL_UPDATE_SCREENINFO
:
1477 if (!p
->glctx
->update_xinerama_info
)
1479 p
->glctx
->update_xinerama_info(vo
);
1481 case VOCTRL_REDRAW_FRAME
:
1482 if (vo_doublebuffering
)
1486 if (!p
->glctx
->pause
)
1488 p
->glctx
->pause(vo
);
1491 if (!p
->glctx
->resume
)
1493 p
->glctx
->resume(vo
);
1495 case VOCTRL_SCREENSHOT
: {
1496 struct voctrl_screenshot_args
*args
= data
;
1497 if (args
->full_window
)
1498 args
->out_image
= get_window_screenshot(vo
);
1500 args
->out_image
= get_screenshot(vo
);
1507 const struct vo_driver video_out_gl
= {
1509 .info
= &(const vo_info_t
) {
1512 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1518 .draw_slice
= draw_slice
,
1519 .draw_osd
= draw_osd
,
1520 .flip_page
= flip_page
,
1521 .check_events
= check_events
,
1525 // "-vo gl" used to accept software renderers by default. This is not the case
1526 // anymore: you have to use "-vo gl:sw" to get this. This means gl and gl_nosw
1527 // are exactly the same thing now. Keep gl_nosw to not break user configs.
1528 const struct vo_driver video_out_gl_nosw
=
1531 .info
= &(const vo_info_t
) {
1532 "OpenGL no software rendering",
1534 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1540 .draw_slice
= draw_slice
,
1541 .draw_osd
= draw_osd
,
1542 .flip_page
= flip_page
,
1543 .check_events
= check_events
,