libvo: remove title argument from struct vo_driver.config
[mplayer.git] / libvo / vo_gl.c
blobdbaef279d8f96ade9abdd59cdc93f4a0caf53811
1 /*
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.
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28 #include <stdbool.h>
30 #include "config.h"
31 #include "talloc.h"
32 #include "mp_msg.h"
33 #include "subopt-helper.h"
34 #include "video_out.h"
35 #include "libmpcodecs/vfcap.h"
36 #include "libmpcodecs/mp_image.h"
37 #include "geometry.h"
38 #include "osd.h"
39 #include "sub/font_load.h"
40 #include "sub/sub.h"
42 #include "gl_common.h"
43 #include "aspect.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)
60 //for gl_priv.use_yuv
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))
65 struct gl_priv {
66 MPGLContext *glctx;
67 GL *gl;
69 int use_osd;
70 int scaled_osd;
71 //! Textures for OSD
72 GLuint osdtex[MAX_OSD_PARTS];
73 #ifndef FAST_OSD
74 //! Alpha textures for OSD
75 GLuint osdatex[MAX_OSD_PARTS];
76 #endif
77 GLuint *eosdtex;
78 GLuint largeeosdtex[2];
79 //! Display lists that draw the OSD parts
80 GLuint osdDispList[MAX_OSD_PARTS];
81 #ifndef FAST_OSD
82 GLuint osdaDispList[MAX_OSD_PARTS];
83 #endif
84 GLuint eosdDispList;
85 //! How many parts the OSD currently consists of
86 int osdtexCnt;
87 int eosdtexCnt;
88 int osd_color;
90 int use_ycbcr;
91 int use_yuv;
92 struct mp_csp_details colorspace;
93 int is_yuv;
94 int lscale;
95 int cscale;
96 float filter_strength;
97 int yuvconvtype;
98 int use_rectangle;
99 int err_shown;
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;
105 int many_fmts;
106 int have_texture_rg;
107 int ati_hack;
108 int force_pbo;
109 int use_glFinish;
110 int swap_interval;
111 GLenum target;
112 GLint texfmt;
113 GLenum gl_format;
114 GLenum gl_type;
115 GLuint buffer;
116 GLuint buffer_uv[2];
117 int buffersize;
118 int buffersize_uv;
119 void *bufferptr;
120 void *bufferptr_uv[2];
121 GLuint fragprog;
122 GLuint default_texs[22];
123 char *custom_prog;
124 char *custom_tex;
125 int custom_tlin;
126 int custom_trect;
127 int mipmap_gen;
128 int stereo_mode;
130 int int_pause;
132 struct mp_csp_equalizer video_eq;
134 int texture_width;
135 int texture_height;
136 int mpi_flipped;
137 int vo_flipped;
138 int ass_border_x, ass_border_y;
140 unsigned int slice_height;
143 static void redraw(struct vo *vo);
145 static void resize(struct vo *vo, int x, int y)
147 struct gl_priv *p = vo->priv;
148 GL *gl = p->gl;
150 mp_msg(MSGT_VO, MSGL_V, "[gl] Resize: %dx%d\n", x, y);
151 if (WinID >= 0) {
152 int left = 0, top = 0, w = x, h = y;
153 geometry(&left, &top, &w, &h, vo->dwidth, vo->dheight);
154 top = y - h - top;
155 gl->Viewport(left, top, w, h);
156 } else
157 gl->Viewport(0, 0, x, y);
159 gl->MatrixMode(GL_PROJECTION);
160 gl->LoadIdentity();
161 p->ass_border_x = p->ass_border_y = 0;
162 if (aspect_scaling()) {
163 int new_w, new_h;
164 GLdouble scale_x, scale_y;
165 aspect(vo, &new_w, &new_h, A_WINZOOM);
166 panscan_calc_windowed(vo);
167 new_w += vo->panscan_x;
168 new_h += vo->panscan_y;
169 scale_x = (GLdouble)new_w / (GLdouble)x;
170 scale_y = (GLdouble)new_h / (GLdouble)y;
171 gl->Scaled(scale_x, scale_y, 1);
172 p->ass_border_x = (vo->dwidth - new_w) / 2;
173 p->ass_border_y = (vo->dheight - new_h) / 2;
175 gl->Ortho(0, p->image_width, p->image_height, 0, -1, 1);
177 gl->MatrixMode(GL_MODELVIEW);
178 gl->LoadIdentity();
180 if (!p->scaled_osd) {
181 #ifdef CONFIG_FREETYPE
182 // adjust font size to display size
183 force_load_font = 1;
184 #endif
185 vo_osd_changed(OSDTYPE_OSD);
187 gl->Clear(GL_COLOR_BUFFER_BIT);
188 redraw(vo);
191 static void texSize(struct vo *vo, int w, int h, int *texw, int *texh)
193 struct gl_priv *p = vo->priv;
195 if (p->use_rectangle) {
196 *texw = w;
197 *texh = h;
198 } else {
199 *texw = 32;
200 while (*texw < w)
201 *texw *= 2;
202 *texh = 32;
203 while (*texh < h)
204 *texh *= 2;
206 if (p->ati_hack)
207 *texw = (*texw + 511) & ~511;
210 //! maximum size of custom fragment program
211 #define MAX_CUSTOM_PROG_SIZE (1024 * 1024)
212 static void update_yuvconv(struct vo *vo)
214 struct gl_priv *p = vo->priv;
215 GL *gl = p->gl;
217 int xs, ys, depth;
218 struct mp_csp_params cparams = { .colorspace = p->colorspace };
219 mp_csp_copy_equalizer_values(&cparams, &p->video_eq);
220 gl_conversion_params_t params = {
221 p->target, p->yuvconvtype, cparams,
222 p->texture_width, p->texture_height, 0, 0, p->filter_strength
224 mp_get_chroma_shift(p->image_format, &xs, &ys, &depth);
225 params.chrom_texw = params.texw >> xs;
226 params.chrom_texh = params.texh >> ys;
227 params.csp_params.input_shift = -depth & 7;
228 glSetupYUVConversion(gl, &params);
229 if (p->custom_prog) {
230 FILE *f = fopen(p->custom_prog, "rb");
231 if (!f) {
232 mp_msg(MSGT_VO, MSGL_WARN,
233 "[gl] Could not read customprog %s\n", p->custom_prog);
234 } else {
235 char *prog = calloc(1, MAX_CUSTOM_PROG_SIZE + 1);
236 fread(prog, 1, MAX_CUSTOM_PROG_SIZE, f);
237 fclose(f);
238 loadGPUProgram(gl, GL_FRAGMENT_PROGRAM, prog);
239 free(prog);
241 gl->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM, 0,
242 1.0 / p->texture_width,
243 1.0 / p->texture_height,
244 p->texture_width, p->texture_height);
246 if (p->custom_tex) {
247 FILE *f = fopen(p->custom_tex, "rb");
248 if (!f) {
249 mp_msg(MSGT_VO, MSGL_WARN,
250 "[gl] Could not read customtex %s\n", p->custom_tex);
251 } else {
252 int width, height, maxval;
253 gl->ActiveTexture(GL_TEXTURE3);
254 if (glCreatePPMTex(gl, p->custom_trect ? GL_TEXTURE_RECTANGLE : GL_TEXTURE_2D,
255 0, p->custom_tlin ? GL_LINEAR : GL_NEAREST,
256 f, &width, &height, &maxval)) {
257 gl->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM, 1,
258 1.0 / width, 1.0 / height,
259 width, height);
260 } else
261 mp_msg(MSGT_VO, MSGL_WARN,
262 "[gl] Error parsing customtex %s\n", p->custom_tex);
263 fclose(f);
264 gl->ActiveTexture(GL_TEXTURE0);
270 * \brief remove all OSD textures and display-lists, thus clearing it.
272 static void clearOSD(struct vo *vo)
274 struct gl_priv *p = vo->priv;
275 GL *gl = p->gl;
277 int i;
278 if (!p->osdtexCnt)
279 return;
280 gl->DeleteTextures(p->osdtexCnt, p->osdtex);
281 #ifndef FAST_OSD
282 gl->DeleteTextures(p->osdtexCnt, p->osdatex);
283 for (i = 0; i < p->osdtexCnt; i++)
284 gl->DeleteLists(p->osdaDispList[i], 1);
285 #endif
286 for (i = 0; i < p->osdtexCnt; i++)
287 gl->DeleteLists(p->osdDispList[i], 1);
288 p->osdtexCnt = 0;
292 * \brief remove textures, display list and free memory used by EOSD
294 static void clearEOSD(struct vo *vo)
296 struct gl_priv *p = vo->priv;
297 GL *gl = p->gl;
299 if (p->eosdDispList)
300 gl->DeleteLists(p->eosdDispList, 1);
301 p->eosdDispList = 0;
302 if (p->eosdtexCnt)
303 gl->DeleteTextures(p->eosdtexCnt, p->eosdtex);
304 p->eosdtexCnt = 0;
305 free(p->eosdtex);
306 p->eosdtex = NULL;
309 static inline int is_tinytex(ASS_Image *i, int tinytexcur)
311 return i->w < TINYTEX_SIZE && i->h < TINYTEX_SIZE
312 && tinytexcur < TINYTEX_MAX;
315 static inline int is_smalltex(ASS_Image *i, int smalltexcur)
317 return i->w < SMALLTEX_SIZE && i->h < SMALLTEX_SIZE
318 && smalltexcur < SMALLTEX_MAX;
321 static inline void tinytex_pos(int tinytexcur, int *x, int *y)
323 *x = (tinytexcur % TINYTEX_COLS) * TINYTEX_SIZE;
324 *y = (tinytexcur / TINYTEX_COLS) * TINYTEX_SIZE;
327 static inline void smalltex_pos(int smalltexcur, int *x, int *y)
329 *x = (smalltexcur % SMALLTEX_COLS) * SMALLTEX_SIZE;
330 *y = (smalltexcur / SMALLTEX_COLS) * SMALLTEX_SIZE;
334 * \brief construct display list from ass image list
335 * \param img image list to create OSD from.
336 * A value of NULL has the same effect as clearEOSD()
338 static void genEOSD(struct vo *vo, mp_eosd_images_t *imgs)
340 struct gl_priv *p = vo->priv;
341 GL *gl = p->gl;
343 int sx, sy;
344 int tinytexcur = 0;
345 int smalltexcur = 0;
346 GLuint *curtex;
347 GLint scale_type = p->scaled_osd ? GL_LINEAR : GL_NEAREST;
348 ASS_Image *img = imgs->imgs;
349 ASS_Image *i;
351 if (imgs->changed == 0) // there are elements, but they are unchanged
352 return;
353 if (img && imgs->changed == 1) // there are elements, but they just moved
354 goto skip_upload;
356 clearEOSD(vo);
357 if (!img)
358 return;
359 if (!p->largeeosdtex[0]) {
360 gl->GenTextures(2, p->largeeosdtex);
361 for (int n = 0; n < 2; n++) {
362 gl->BindTexture(p->target, p->largeeosdtex[n]);
363 glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA,
364 GL_UNSIGNED_BYTE, scale_type,
365 LARGE_EOSD_TEX_SIZE, LARGE_EOSD_TEX_SIZE, 0);
368 for (i = img; i; i = i->next) {
369 if (i->w <= 0 || i->h <= 0 || i->stride < i->w)
370 continue;
371 if (is_tinytex(i, tinytexcur))
372 tinytexcur++;
373 else if (is_smalltex(i, smalltexcur))
374 smalltexcur++;
375 else
376 p->eosdtexCnt++;
378 mp_msg(MSGT_VO, MSGL_DBG2, "EOSD counts (tiny, small, all): %i, %i, %i\n",
379 tinytexcur, smalltexcur, p->eosdtexCnt);
380 if (p->eosdtexCnt) {
381 p->eosdtex = calloc(p->eosdtexCnt, sizeof(GLuint));
382 gl->GenTextures(p->eosdtexCnt, p->eosdtex);
384 tinytexcur = smalltexcur = 0;
385 for (i = img, curtex = p->eosdtex; i; i = i->next) {
386 int x = 0, y = 0;
387 if (i->w <= 0 || i->h <= 0 || i->stride < i->w) {
388 mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n");
389 continue;
391 if (is_tinytex(i, tinytexcur)) {
392 tinytex_pos(tinytexcur, &x, &y);
393 gl->BindTexture(p->target, p->largeeosdtex[0]);
394 tinytexcur++;
395 } else if (is_smalltex(i, smalltexcur)) {
396 smalltex_pos(smalltexcur, &x, &y);
397 gl->BindTexture(p->target, p->largeeosdtex[1]);
398 smalltexcur++;
399 } else {
400 texSize(vo, i->w, i->h, &sx, &sy);
401 gl->BindTexture(p->target, *curtex++);
402 glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA,
403 GL_UNSIGNED_BYTE, scale_type, sx, sy, 0);
405 glUploadTex(gl, p->target, GL_ALPHA, GL_UNSIGNED_BYTE, i->bitmap,
406 i->stride, x, y, i->w, i->h, 0);
408 p->eosdDispList = gl->GenLists(1);
409 skip_upload:
410 gl->NewList(p->eosdDispList, GL_COMPILE);
411 tinytexcur = smalltexcur = 0;
412 for (i = img, curtex = p->eosdtex; i; i = i->next) {
413 int x = 0, y = 0;
414 if (i->w <= 0 || i->h <= 0 || i->stride < i->w)
415 continue;
416 gl->Color4ub(i->color >> 24, (i->color >> 16) & 0xff,
417 (i->color >> 8) & 0xff, 255 - (i->color & 0xff));
418 if (is_tinytex(i, tinytexcur)) {
419 tinytex_pos(tinytexcur, &x, &y);
420 sx = sy = LARGE_EOSD_TEX_SIZE;
421 gl->BindTexture(p->target, p->largeeosdtex[0]);
422 tinytexcur++;
423 } else if (is_smalltex(i, smalltexcur)) {
424 smalltex_pos(smalltexcur, &x, &y);
425 sx = sy = LARGE_EOSD_TEX_SIZE;
426 gl->BindTexture(p->target, p->largeeosdtex[1]);
427 smalltexcur++;
428 } else {
429 texSize(vo, i->w, i->h, &sx, &sy);
430 gl->BindTexture(p->target, *curtex++);
432 glDrawTex(gl, i->dst_x, i->dst_y, i->w, i->h, x, y, i->w, i->h, sx, sy,
433 p->use_rectangle == 1, 0, 0);
435 gl->EndList();
436 gl->BindTexture(p->target, 0);
440 * \brief uninitialize OpenGL context, freeing textures, buffers etc.
442 static void uninitGl(struct vo *vo)
444 struct gl_priv *p = vo->priv;
445 GL *gl = p->gl;
447 int i = 0;
448 if (gl->DeletePrograms && p->fragprog)
449 gl->DeletePrograms(1, &p->fragprog);
450 p->fragprog = 0;
451 while (p->default_texs[i] != 0)
452 i++;
453 if (i)
454 gl->DeleteTextures(i, p->default_texs);
455 p->default_texs[0] = 0;
456 clearOSD(vo);
457 clearEOSD(vo);
458 if (p->largeeosdtex[0])
459 gl->DeleteTextures(2, p->largeeosdtex);
460 p->largeeosdtex[0] = 0;
461 if (gl->DeleteBuffers && p->buffer)
462 gl->DeleteBuffers(1, &p->buffer);
463 p->buffer = 0;
464 p->buffersize = 0;
465 p->bufferptr = NULL;
466 if (gl->DeleteBuffers && p->buffer_uv[0])
467 gl->DeleteBuffers(2, p->buffer_uv);
468 p->buffer_uv[0] = p->buffer_uv[1] = 0;
469 p->buffersize_uv = 0;
470 p->bufferptr_uv[0] = p->bufferptr_uv[1] = 0;
471 p->err_shown = 0;
474 static int isSoftwareGl(struct vo *vo)
476 struct gl_priv *p = vo->priv;
477 const char *renderer = p->gl->GetString(GL_RENDERER);
478 return !renderer || strcmp(renderer, "Software Rasterizer") == 0 ||
479 strstr(renderer, "llvmpipe");
482 static void autodetectGlExtensions(struct vo *vo)
484 struct gl_priv *p = vo->priv;
485 GL *gl = p->gl;
487 const char *extensions = gl->GetString(GL_EXTENSIONS);
488 const char *vendor = gl->GetString(GL_VENDOR);
489 const char *version = gl->GetString(GL_VERSION);
490 const char *renderer = gl->GetString(GL_RENDERER);
491 int is_ati = vendor && strstr(vendor, "ATI") != NULL;
492 int ati_broken_pbo = 0;
493 mp_msg(MSGT_VO, MSGL_V, "[gl] Running on OpenGL '%s' by '%s', version '%s'\n",
494 renderer, vendor, version);
495 if (is_ati && strncmp(version, "2.1.", 4) == 0) {
496 int ver = atoi(version + 4);
497 mp_msg(MSGT_VO, MSGL_V, "[gl] Detected ATI driver version: %i\n", ver);
498 ati_broken_pbo = ver && ver < 8395;
500 if (p->ati_hack == -1)
501 p->ati_hack = ati_broken_pbo;
502 if (p->force_pbo == -1) {
503 p->force_pbo = 0;
504 if (extensions && strstr(extensions, "_pixel_buffer_object"))
505 p->force_pbo = is_ati;
507 p->have_texture_rg = extensions && strstr(extensions, "GL_ARB_texture_rg");
508 if (p->use_rectangle == -1) {
509 p->use_rectangle = 0;
510 if (extensions) {
511 // if (strstr(extensions, "_texture_non_power_of_two"))
512 if (strstr(extensions, "_texture_rectangle"))
513 p->use_rectangle = renderer
514 && strstr(renderer, "Mesa DRI R200") ? 1 : 0;
517 if (p->use_osd == -1)
518 p->use_osd = gl->BindTexture != NULL;
519 if (p->use_yuv == -1)
520 p->use_yuv = glAutodetectYUVConversion(gl);
522 int eq_caps = 0;
523 int yuv_mask = (1 << p->use_yuv);
524 if (!(yuv_mask & MASK_NOT_COMBINERS)) {
525 // combiners
526 eq_caps = (1 << MP_CSP_EQ_HUE) | (1 << MP_CSP_EQ_SATURATION);
527 } else if (yuv_mask & MASK_ALL_YUV) {
528 eq_caps = MP_CSP_EQ_CAPS_COLORMATRIX;
529 if (yuv_mask & MASK_GAMMA_SUPPORT)
530 eq_caps |= MP_CSP_EQ_CAPS_GAMMA;
532 p->video_eq.capabilities = eq_caps;
534 if (is_ati && (p->lscale == 1 || p->lscale == 2 || p->cscale == 1 || p->cscale == 2))
535 mp_msg(MSGT_VO, MSGL_WARN, "[gl] Selected scaling mode may be broken on"
536 " ATI cards.\n"
537 "Tell _them_ to fix GL_REPEAT if you have issues.\n");
538 mp_msg(MSGT_VO, MSGL_V, "[gl] Settings after autodetection: ati-hack = %i, "
539 "force-pbo = %i, rectangle = %i, yuv = %i\n",
540 p->ati_hack, p->force_pbo, p->use_rectangle, p->use_yuv);
543 static GLint get_scale_type(struct vo *vo, int chroma)
545 struct gl_priv *p = vo->priv;
547 int nearest = (chroma ? p->cscale : p->lscale) & 64;
548 if (nearest)
549 return p->mipmap_gen ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
550 return p->mipmap_gen ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR;
553 // Return the high byte of the value that represents white in chroma (U/V)
554 static int get_chroma_clear_val(int bit_depth)
556 return 1 << (bit_depth - 1 & 7);
560 * \brief Initialize a (new or reused) OpenGL context.
561 * set global gl-related variables to their default values
563 static int initGl(struct vo *vo, uint32_t d_width, uint32_t d_height)
565 struct gl_priv *p = vo->priv;
566 GL *gl = p->gl;
568 GLint scale_type = get_scale_type(vo, 0);
569 autodetectGlExtensions(vo);
570 p->target = p->use_rectangle == 1 ? GL_TEXTURE_RECTANGLE : GL_TEXTURE_2D;
571 p->yuvconvtype = SET_YUV_CONVERSION(p->use_yuv) |
572 SET_YUV_LUM_SCALER(p->lscale) |
573 SET_YUV_CHROM_SCALER(p->cscale);
575 texSize(vo, p->image_width, p->image_height,
576 &p->texture_width, &p->texture_height);
578 gl->Disable(GL_BLEND);
579 gl->Disable(GL_DEPTH_TEST);
580 gl->DepthMask(GL_FALSE);
581 gl->Disable(GL_CULL_FACE);
582 gl->Enable(p->target);
583 gl->DrawBuffer(vo_doublebuffering ? GL_BACK : GL_FRONT);
584 gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
586 mp_msg(MSGT_VO, MSGL_V, "[gl] Creating %dx%d texture...\n",
587 p->texture_width, p->texture_height);
589 glCreateClearTex(gl, p->target, p->texfmt, p->gl_format,
590 p->gl_type, scale_type,
591 p->texture_width, p->texture_height, 0);
593 if (p->mipmap_gen)
594 gl->TexParameteri(p->target, GL_GENERATE_MIPMAP, GL_TRUE);
596 if (p->is_yuv) {
597 int i;
598 int xs, ys, depth;
599 scale_type = get_scale_type(vo, 1);
600 mp_get_chroma_shift(p->image_format, &xs, &ys, &depth);
601 int clear = get_chroma_clear_val(depth);
602 gl->GenTextures(21, p->default_texs);
603 p->default_texs[21] = 0;
604 for (i = 0; i < 7; i++) {
605 gl->ActiveTexture(GL_TEXTURE1 + i);
606 gl->BindTexture(GL_TEXTURE_2D, p->default_texs[i]);
607 gl->BindTexture(GL_TEXTURE_RECTANGLE, p->default_texs[i + 7]);
608 gl->BindTexture(GL_TEXTURE_3D, p->default_texs[i + 14]);
610 gl->ActiveTexture(GL_TEXTURE1);
611 glCreateClearTex(gl, p->target, p->texfmt, p->gl_format,
612 p->gl_type, scale_type,
613 p->texture_width >> xs, p->texture_height >> ys,
614 clear);
615 if (p->mipmap_gen)
616 gl->TexParameteri(p->target, GL_GENERATE_MIPMAP, GL_TRUE);
617 gl->ActiveTexture(GL_TEXTURE2);
618 glCreateClearTex(gl, p->target, p->texfmt, p->gl_format,
619 p->gl_type, scale_type,
620 p->texture_width >> xs, p->texture_height >> ys,
621 clear);
622 if (p->mipmap_gen)
623 gl->TexParameteri(p->target, GL_GENERATE_MIPMAP, GL_TRUE);
624 gl->ActiveTexture(GL_TEXTURE0);
625 gl->BindTexture(p->target, 0);
627 if (p->is_yuv || p->custom_prog) {
628 if ((MASK_NOT_COMBINERS & (1 << p->use_yuv)) || p->custom_prog) {
629 if (!gl->GenPrograms || !gl->BindProgram)
630 mp_msg(MSGT_VO, MSGL_ERR,
631 "[gl] fragment program functions missing!\n");
632 else {
633 gl->GenPrograms(1, &p->fragprog);
634 gl->BindProgram(GL_FRAGMENT_PROGRAM, p->fragprog);
637 update_yuvconv(vo);
640 resize(vo, d_width, d_height);
642 gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
643 gl->Clear(GL_COLOR_BUFFER_BIT);
644 if (gl->SwapInterval && p->swap_interval >= 0)
645 gl->SwapInterval(p->swap_interval);
646 return 1;
649 static int create_window(struct vo *vo, uint32_t d_width, uint32_t d_height,
650 uint32_t flags)
652 struct gl_priv *p = vo->priv;
654 if (p->stereo_mode == GL_3D_QUADBUFFER)
655 flags |= VOFLAG_STEREO;
657 return p->glctx->create_window(p->glctx, d_width, d_height, flags);
660 static int config(struct vo *vo, uint32_t width, uint32_t height,
661 uint32_t d_width, uint32_t d_height, uint32_t flags,
662 uint32_t format)
664 struct gl_priv *p = vo->priv;
666 int xs, ys;
667 p->image_height = height;
668 p->image_width = width;
669 p->image_format = format;
670 p->image_d_width = d_width;
671 p->image_d_height = d_height;
672 p->is_yuv = mp_get_chroma_shift(p->image_format, &xs, &ys, NULL) > 0;
673 p->is_yuv |= (xs << 8) | (ys << 16);
674 glFindFormat(format, p->have_texture_rg, NULL, &p->texfmt, &p->gl_format,
675 &p->gl_type);
677 p->vo_flipped = !!(flags & VOFLAG_FLIPPING);
679 if (create_window(vo, d_width, d_height, flags) < 0)
680 return -1;
682 if (vo->config_count)
683 uninitGl(vo);
684 if (p->glctx->setGlWindow(p->glctx) == SET_WINDOW_FAILED)
685 return -1;
686 initGl(vo, vo->dwidth, vo->dheight);
688 return 0;
691 static void check_events(struct vo *vo)
693 struct gl_priv *p = vo->priv;
695 int e = p->glctx->check_events(vo);
696 if (e & VO_EVENT_REINIT) {
697 uninitGl(vo);
698 initGl(vo, vo->dwidth, vo->dheight);
700 if (e & VO_EVENT_RESIZE)
701 resize(vo, vo->dwidth, vo->dheight);
702 if (e & VO_EVENT_EXPOSE && p->int_pause)
703 redraw(vo);
707 * Creates the textures and the display list needed for displaying
708 * an OSD part.
709 * Callback function for osd_draw_text_ext().
711 static void create_osd_texture(void *ctx, int x0, int y0, int w, int h,
712 unsigned char *src, unsigned char *srca,
713 int stride)
715 struct vo *vo = ctx;
716 struct gl_priv *p = vo->priv;
717 GL *gl = p->gl;
719 // initialize to 8 to avoid special-casing on alignment
720 int sx = 8, sy = 8;
721 GLint scale_type = p->scaled_osd ? GL_LINEAR : GL_NEAREST;
723 if (w <= 0 || h <= 0 || stride < w) {
724 mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n");
725 return;
727 texSize(vo, w, h, &sx, &sy);
729 if (p->osdtexCnt >= MAX_OSD_PARTS) {
730 mp_msg(MSGT_VO, MSGL_ERR, "Too many OSD parts, contact the developers!\n");
731 return;
734 // create Textures for OSD part
735 gl->GenTextures(1, &p->osdtex[p->osdtexCnt]);
736 gl->BindTexture(p->target, p->osdtex[p->osdtexCnt]);
737 glCreateClearTex(gl, p->target, GL_LUMINANCE, GL_LUMINANCE,
738 GL_UNSIGNED_BYTE, scale_type, sx, sy, 0);
739 glUploadTex(gl, p->target, GL_LUMINANCE, GL_UNSIGNED_BYTE, src, stride,
740 0, 0, w, h, 0);
742 #ifndef FAST_OSD
743 gl->GenTextures(1, &p->osdatex[p->osdtexCnt]);
744 gl->BindTexture(p->target, p->osdatex[p->osdtexCnt]);
745 glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE,
746 scale_type, sx, sy, 0);
748 int i;
749 char *tmp = malloc(stride * h);
750 // convert alpha from weird MPlayer scale.
751 // in-place is not possible since it is reused for future OSDs
752 for (i = h * stride - 1; i >= 0; i--)
753 tmp[i] = -srca[i];
754 glUploadTex(gl, p->target, GL_ALPHA, GL_UNSIGNED_BYTE, tmp, stride,
755 0, 0, w, h, 0);
756 free(tmp);
758 #endif
760 gl->BindTexture(p->target, 0);
762 // Create a list for rendering this OSD part
763 #ifndef FAST_OSD
764 p->osdaDispList[p->osdtexCnt] = gl->GenLists(1);
765 gl->NewList(p->osdaDispList[p->osdtexCnt], GL_COMPILE);
766 // render alpha
767 gl->BindTexture(p->target, p->osdatex[p->osdtexCnt]);
768 glDrawTex(gl, x0, y0, w, h, 0, 0, w, h, sx, sy, p->use_rectangle == 1, 0, 0);
769 gl->EndList();
770 #endif
771 p->osdDispList[p->osdtexCnt] = gl->GenLists(1);
772 gl->NewList(p->osdDispList[p->osdtexCnt], GL_COMPILE);
773 // render OSD
774 gl->BindTexture(p->target, p->osdtex[p->osdtexCnt]);
775 glDrawTex(gl, x0, y0, w, h, 0, 0, w, h, sx, sy, p->use_rectangle == 1, 0, 0);
776 gl->EndList();
778 p->osdtexCnt++;
781 #define RENDER_OSD 1
782 #define RENDER_EOSD 2
785 * \param type bit 0: render OSD, bit 1: render EOSD
787 static void do_render_osd(struct vo *vo, int type)
789 struct gl_priv *p = vo->priv;
790 GL *gl = p->gl;
792 int draw_osd = (type & RENDER_OSD) && p->osdtexCnt > 0;
793 int draw_eosd = (type & RENDER_EOSD) && p->eosdDispList;
794 if (!draw_osd && !draw_eosd)
795 return;
796 // set special rendering parameters
797 if (!p->scaled_osd) {
798 gl->MatrixMode(GL_PROJECTION);
799 gl->PushMatrix();
800 gl->LoadIdentity();
801 gl->Ortho(0, vo->dwidth, vo->dheight, 0, -1, 1);
803 gl->Enable(GL_BLEND);
804 if (draw_eosd) {
805 gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
806 gl->CallList(p->eosdDispList);
808 if (draw_osd) {
809 gl->Color4ub((p->osd_color >> 16) & 0xff, (p->osd_color >> 8) & 0xff,
810 p->osd_color & 0xff, 0xff - (p->osd_color >> 24));
811 // draw OSD
812 #ifndef FAST_OSD
813 gl->BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
814 gl->CallLists(p->osdtexCnt, GL_UNSIGNED_INT, p->osdaDispList);
815 #endif
816 gl->BlendFunc(GL_SRC_ALPHA, GL_ONE);
817 gl->CallLists(p->osdtexCnt, GL_UNSIGNED_INT, p->osdDispList);
819 // set rendering parameters back to defaults
820 gl->Disable(GL_BLEND);
821 if (!p->scaled_osd)
822 gl->PopMatrix();
823 gl->BindTexture(p->target, 0);
826 static void draw_osd(struct vo *vo, struct osd_state *osd)
828 struct gl_priv *p = vo->priv;
830 if (!p->use_osd)
831 return;
832 if (vo_osd_changed(0)) {
833 int osd_h, osd_w;
834 clearOSD(vo);
835 osd_w = p->scaled_osd ? p->image_width : vo->dwidth;
836 osd_h = p->scaled_osd ? p->image_height : vo->dheight;
837 osd_draw_text_ext(osd, osd_w, osd_h, p->ass_border_x,
838 p->ass_border_y, p->ass_border_x,
839 p->ass_border_y, p->image_width,
840 p->image_height, create_osd_texture, vo);
842 if (vo_doublebuffering)
843 do_render_osd(vo, RENDER_OSD);
846 static void do_render(struct vo *vo)
848 struct gl_priv *p = vo->priv;
849 GL *gl = p->gl;
851 // Enable(GL_TEXTURE_2D);
852 // BindTexture(GL_TEXTURE_2D, texture_id);
854 gl->Color3f(1, 1, 1);
855 if (p->is_yuv || p->custom_prog)
856 glEnableYUVConversion(gl, p->target, p->yuvconvtype);
857 if (p->stereo_mode) {
858 glEnable3DLeft(gl, p->stereo_mode);
859 glDrawTex(gl, 0, 0, p->image_width, p->image_height,
860 0, 0, p->image_width >> 1, p->image_height,
861 p->texture_width, p->texture_height,
862 p->use_rectangle == 1, p->is_yuv,
863 p->mpi_flipped ^ p->vo_flipped);
864 glEnable3DRight(gl, p->stereo_mode);
865 glDrawTex(gl, 0, 0, p->image_width, p->image_height,
866 p->image_width >> 1, 0, p->image_width >> 1,
867 p->image_height, p->texture_width, p->texture_height,
868 p->use_rectangle == 1, p->is_yuv,
869 p->mpi_flipped ^ p->vo_flipped);
870 glDisable3D(gl, p->stereo_mode);
871 } else {
872 glDrawTex(gl, 0, 0, p->image_width, p->image_height,
873 0, 0, p->image_width, p->image_height,
874 p->texture_width, p->texture_height,
875 p->use_rectangle == 1, p->is_yuv,
876 p->mpi_flipped ^ p->vo_flipped);
878 if (p->is_yuv || p->custom_prog)
879 glDisableYUVConversion(gl, p->target, p->yuvconvtype);
882 static void flip_page(struct vo *vo)
884 struct gl_priv *p = vo->priv;
885 GL *gl = p->gl;
887 if (vo_doublebuffering) {
888 if (p->use_glFinish)
889 gl->Finish();
890 p->glctx->swapGlBuffers(p->glctx);
891 if (aspect_scaling())
892 gl->Clear(GL_COLOR_BUFFER_BIT);
893 } else {
894 do_render(vo);
895 do_render_osd(vo, RENDER_OSD | RENDER_EOSD);
896 if (p->use_glFinish)
897 gl->Finish();
898 else
899 gl->Flush();
903 static void redraw(struct vo *vo)
905 if (vo_doublebuffering) {
906 do_render(vo);
907 do_render_osd(vo, RENDER_OSD | RENDER_EOSD);
909 flip_page(vo);
912 static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h,
913 int x, int y)
915 struct gl_priv *p = vo->priv;
916 GL *gl = p->gl;
918 p->mpi_flipped = stride[0] < 0;
919 glUploadTex(gl, p->target, p->gl_format, p->gl_type, src[0], stride[0],
920 x, y, w, h, p->slice_height);
921 if (p->is_yuv) {
922 int xs, ys;
923 mp_get_chroma_shift(p->image_format, &xs, &ys, NULL);
924 gl->ActiveTexture(GL_TEXTURE1);
925 glUploadTex(gl, p->target, p->gl_format, p->gl_type, src[1], stride[1],
926 x >> xs, y >> ys, w >> xs, h >> ys, p->slice_height);
927 gl->ActiveTexture(GL_TEXTURE2);
928 glUploadTex(gl, p->target, p->gl_format, p->gl_type, src[2], stride[2],
929 x >> xs, y >> ys, w >> xs, h >> ys, p->slice_height);
930 gl->ActiveTexture(GL_TEXTURE0);
932 return 0;
935 static uint32_t get_image(struct vo *vo, mp_image_t *mpi)
937 struct gl_priv *p = vo->priv;
938 GL *gl = p->gl;
940 int needed_size;
941 if (!gl->GenBuffers || !gl->BindBuffer || !gl->BufferData || !gl->MapBuffer) {
942 if (!p->err_shown)
943 mp_msg(MSGT_VO, MSGL_ERR, "[gl] extensions missing for dr\n"
944 "Expect a _major_ speed penalty\n");
945 p->err_shown = 1;
946 return VO_FALSE;
948 if (mpi->flags & MP_IMGFLAG_READABLE)
949 return VO_FALSE;
950 if (mpi->type != MP_IMGTYPE_STATIC && mpi->type != MP_IMGTYPE_TEMP &&
951 (mpi->type != MP_IMGTYPE_NUMBERED || mpi->number))
952 return VO_FALSE;
953 if (p->ati_hack) {
954 mpi->width = p->texture_width;
955 mpi->height = p->texture_height;
957 mpi->stride[0] = mpi->width * mpi->bpp / 8;
958 needed_size = mpi->stride[0] * mpi->height;
959 if (!p->buffer)
960 gl->GenBuffers(1, &p->buffer);
961 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer);
962 if (needed_size > p->buffersize) {
963 p->buffersize = needed_size;
964 gl->BufferData(GL_PIXEL_UNPACK_BUFFER, p->buffersize,
965 NULL, GL_DYNAMIC_DRAW);
967 if (!p->bufferptr)
968 p->bufferptr = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
969 mpi->planes[0] = p->bufferptr;
970 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
971 if (!mpi->planes[0]) {
972 if (!p->err_shown)
973 mp_msg(MSGT_VO, MSGL_ERR, "[gl] could not acquire buffer for dr\n"
974 "Expect a _major_ speed penalty\n");
975 p->err_shown = 1;
976 return VO_FALSE;
978 if (p->is_yuv) {
979 // planar YUV
980 int xs, ys, component_bits;
981 mp_get_chroma_shift(p->image_format, &xs, &ys, &component_bits);
982 int bp = (component_bits + 7) / 8;
983 mpi->flags |= MP_IMGFLAG_COMMON_STRIDE | MP_IMGFLAG_COMMON_PLANE;
984 mpi->stride[0] = mpi->width * bp;
985 mpi->planes[1] = mpi->planes[0] + mpi->stride[0] * mpi->height;
986 mpi->stride[1] = (mpi->width >> xs) * bp;
987 mpi->planes[2] = mpi->planes[1] + mpi->stride[1] * (mpi->height >> ys);
988 mpi->stride[2] = (mpi->width >> xs) * bp;
989 if (p->ati_hack) {
990 mpi->flags &= ~MP_IMGFLAG_COMMON_PLANE;
991 if (!p->buffer_uv[0])
992 gl->GenBuffers(2, p->buffer_uv);
993 int buffer_size = mpi->stride[1] * mpi->height;
994 if (buffer_size > p->buffersize_uv) {
995 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[0]);
996 gl->BufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size, NULL,
997 GL_DYNAMIC_DRAW);
998 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[1]);
999 gl->BufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size, NULL,
1000 GL_DYNAMIC_DRAW);
1001 p->buffersize_uv = buffer_size;
1003 if (!p->bufferptr_uv[0]) {
1004 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[0]);
1005 p->bufferptr_uv[0] = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER,
1006 GL_WRITE_ONLY);
1007 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[1]);
1008 p->bufferptr_uv[1] = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER,
1009 GL_WRITE_ONLY);
1011 mpi->planes[1] = p->bufferptr_uv[0];
1012 mpi->planes[2] = p->bufferptr_uv[1];
1015 mpi->flags |= MP_IMGFLAG_DIRECT;
1016 return VO_TRUE;
1019 static void clear_border(struct vo *vo, uint8_t *dst, int start, int stride,
1020 int height, int full_height, int value)
1022 int right_border = stride - start;
1023 int bottom_border = full_height - height;
1024 while (height > 0) {
1025 if (right_border > 0)
1026 memset(dst + start, value, right_border);
1027 dst += stride;
1028 height--;
1030 if (bottom_border > 0)
1031 memset(dst, value, stride * bottom_border);
1034 static uint32_t draw_image(struct vo *vo, mp_image_t *mpi)
1036 struct gl_priv *p = vo->priv;
1037 GL *gl = p->gl;
1039 int slice = p->slice_height;
1040 int stride[3];
1041 unsigned char *planes[3];
1042 mp_image_t mpi2 = *mpi;
1043 int w = mpi->w, h = mpi->h;
1044 if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
1045 goto skip_upload;
1046 mpi2.flags = 0;
1047 mpi2.type = MP_IMGTYPE_TEMP;
1048 mpi2.width = mpi2.w;
1049 mpi2.height = mpi2.h;
1050 if (p->force_pbo && !(mpi->flags & MP_IMGFLAG_DIRECT) && !p->bufferptr
1051 && get_image(vo, &mpi2) == VO_TRUE)
1053 int bp = mpi->bpp / 8;
1054 int xs, ys, component_bits;
1055 mp_get_chroma_shift(p->image_format, &xs, &ys, &component_bits);
1056 if (p->is_yuv)
1057 bp = (component_bits + 7) / 8;
1058 memcpy_pic(mpi2.planes[0], mpi->planes[0], mpi->w * bp, mpi->h,
1059 mpi2.stride[0], mpi->stride[0]);
1060 int uv_bytes = (mpi->w >> xs) * bp;
1061 if (p->is_yuv) {
1062 memcpy_pic(mpi2.planes[1], mpi->planes[1], uv_bytes, mpi->h >> ys,
1063 mpi2.stride[1], mpi->stride[1]);
1064 memcpy_pic(mpi2.planes[2], mpi->planes[2], uv_bytes, mpi->h >> ys,
1065 mpi2.stride[2], mpi->stride[2]);
1067 if (p->ati_hack) {
1068 // since we have to do a full upload we need to clear the borders
1069 clear_border(vo, mpi2.planes[0], mpi->w * bp, mpi2.stride[0],
1070 mpi->h, mpi2.height, 0);
1071 if (p->is_yuv) {
1072 int clear = get_chroma_clear_val(component_bits);
1073 clear_border(vo, mpi2.planes[1], uv_bytes, mpi2.stride[1],
1074 mpi->h >> ys, mpi2.height >> ys, clear);
1075 clear_border(vo, mpi2.planes[2], uv_bytes, mpi2.stride[2],
1076 mpi->h >> ys, mpi2.height >> ys, clear);
1079 mpi = &mpi2;
1081 stride[0] = mpi->stride[0];
1082 stride[1] = mpi->stride[1];
1083 stride[2] = mpi->stride[2];
1084 planes[0] = mpi->planes[0];
1085 planes[1] = mpi->planes[1];
1086 planes[2] = mpi->planes[2];
1087 p->mpi_flipped = stride[0] < 0;
1088 if (mpi->flags & MP_IMGFLAG_DIRECT) {
1089 intptr_t base = (intptr_t)planes[0];
1090 if (p->ati_hack) {
1091 w = p->texture_width;
1092 h = p->texture_height;
1094 if (p->mpi_flipped)
1095 base += (mpi->h - 1) * stride[0];
1096 planes[0] -= base;
1097 planes[1] -= base;
1098 planes[2] -= base;
1099 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer);
1100 gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
1101 p->bufferptr = NULL;
1102 if (!(mpi->flags & MP_IMGFLAG_COMMON_PLANE))
1103 planes[0] = planes[1] = planes[2] = NULL;
1104 slice = 0; // always "upload" full texture
1106 glUploadTex(gl, p->target, p->gl_format, p->gl_type, planes[0],
1107 stride[0], mpi->x, mpi->y, w, h, slice);
1108 if (p->is_yuv) {
1109 int xs, ys;
1110 mp_get_chroma_shift(p->image_format, &xs, &ys, NULL);
1111 if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) {
1112 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[0]);
1113 gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
1114 p->bufferptr_uv[0] = NULL;
1116 gl->ActiveTexture(GL_TEXTURE1);
1117 glUploadTex(gl, p->target, p->gl_format, p->gl_type, planes[1],
1118 stride[1], mpi->x >> xs, mpi->y >> ys, w >> xs, h >> ys,
1119 slice);
1120 if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) {
1121 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[1]);
1122 gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
1123 p->bufferptr_uv[1] = NULL;
1125 gl->ActiveTexture(GL_TEXTURE2);
1126 glUploadTex(gl, p->target, p->gl_format, p->gl_type, planes[2],
1127 stride[2], mpi->x >> xs, mpi->y >> ys, w >> xs, h >> ys,
1128 slice);
1129 gl->ActiveTexture(GL_TEXTURE0);
1131 if (mpi->flags & MP_IMGFLAG_DIRECT) {
1132 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1134 skip_upload:
1135 if (vo_doublebuffering)
1136 do_render(vo);
1137 return VO_TRUE;
1140 static mp_image_t *get_screenshot(struct vo *vo)
1142 struct gl_priv *p = vo->priv;
1143 GL *gl = p->gl;
1145 mp_image_t *image = alloc_mpi(p->texture_width, p->texture_height,
1146 p->image_format);
1148 glDownloadTex(gl, p->target, p->gl_format, p->gl_type, image->planes[0],
1149 image->stride[0]);
1151 if (p->is_yuv) {
1152 gl->ActiveTexture(GL_TEXTURE1);
1153 glDownloadTex(gl, p->target, p->gl_format, p->gl_type, image->planes[1],
1154 image->stride[1]);
1155 gl->ActiveTexture(GL_TEXTURE2);
1156 glDownloadTex(gl, p->target, p->gl_format, p->gl_type, image->planes[2],
1157 image->stride[2]);
1158 gl->ActiveTexture(GL_TEXTURE0);
1161 image->width = p->image_width;
1162 image->height = p->image_height;
1164 image->w = p->image_d_width;
1165 image->h = p->image_d_height;
1167 return image;
1170 static mp_image_t *get_window_screenshot(struct vo *vo)
1172 struct gl_priv *p = vo->priv;
1173 GL *gl = p->gl;
1175 GLint vp[4]; //x, y, w, h
1176 gl->GetIntegerv(GL_VIEWPORT, vp);
1177 mp_image_t *image = alloc_mpi(vp[2], vp[3], IMGFMT_RGB24);
1178 gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1179 gl->PixelStorei(GL_PACK_ALIGNMENT, 0);
1180 gl->PixelStorei(GL_PACK_ROW_LENGTH, 0);
1181 gl->ReadBuffer(GL_FRONT);
1182 //flip image while reading
1183 for (int y = 0; y < vp[3]; y++) {
1184 gl->ReadPixels(vp[0], vp[1] + vp[3] - y - 1, vp[2], 1,
1185 GL_RGB, GL_UNSIGNED_BYTE,
1186 image->planes[0] + y * image->stride[0]);
1188 return image;
1191 static int query_format(struct vo *vo, uint32_t format)
1193 struct gl_priv *p = vo->priv;
1195 int depth;
1196 int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP |
1197 VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE;
1198 if (p->use_osd)
1199 caps |= VFCAP_OSD | VFCAP_EOSD | (p->scaled_osd ? 0 : VFCAP_EOSD_UNSCALED);
1200 if (format == IMGFMT_RGB24 || format == IMGFMT_RGBA)
1201 return caps;
1202 if (p->use_yuv && mp_get_chroma_shift(format, NULL, NULL, &depth) &&
1203 (depth == 8 || depth == 16 || glYUVLargeRange(p->use_yuv)) &&
1204 (IMGFMT_IS_YUVP16_NE(format) || !IMGFMT_IS_YUVP16(format)))
1205 return caps;
1206 // HACK, otherwise we get only b&w with some filters (e.g. -vf eq)
1207 // ideally MPlayer should be fixed instead not to use Y800 when it has the choice
1208 if (!p->use_yuv && (format == IMGFMT_Y8 || format == IMGFMT_Y800))
1209 return 0;
1210 if (!p->use_ycbcr && (format == IMGFMT_UYVY || format == IMGFMT_YVYU))
1211 return 0;
1212 if (p->many_fmts &&
1213 glFindFormat(format, p->have_texture_rg, NULL, NULL, NULL, NULL))
1214 return caps;
1215 return 0;
1218 static void uninit(struct vo *vo)
1220 struct gl_priv *p = vo->priv;
1222 if (p->glctx)
1223 uninitGl(vo);
1224 free(p->custom_prog);
1225 p->custom_prog = NULL;
1226 free(p->custom_tex);
1227 p->custom_tex = NULL;
1228 uninit_mpglcontext(p->glctx);
1229 p->glctx = NULL;
1230 p->gl = NULL;
1233 static int preinit_internal(struct vo *vo, const char *arg, int allow_sw,
1234 enum MPGLType gltype)
1236 struct gl_priv *p = talloc_zero(vo, struct gl_priv);
1237 vo->priv = p;
1239 *p = (struct gl_priv) {
1240 .many_fmts = 1,
1241 .use_osd = -1,
1242 .use_yuv = -1,
1243 .colorspace = MP_CSP_DETAILS_DEFAULTS,
1244 .filter_strength = 0.5,
1245 .use_rectangle = -1,
1246 .ati_hack = -1,
1247 .force_pbo = -1,
1248 .swap_interval = 1,
1249 .custom_prog = NULL,
1250 .custom_tex = NULL,
1251 .custom_tlin = 1,
1252 .osd_color = 0xffffff,
1255 //essentially unused; for legacy warnings only
1256 int user_colorspace = 0;
1257 int levelconv = -1;
1258 int aspect = -1;
1260 const opt_t subopts[] = {
1261 {"manyfmts", OPT_ARG_BOOL, &p->many_fmts, NULL},
1262 {"osd", OPT_ARG_BOOL, &p->use_osd, NULL},
1263 {"scaled-osd", OPT_ARG_BOOL, &p->scaled_osd, NULL},
1264 {"ycbcr", OPT_ARG_BOOL, &p->use_ycbcr, NULL},
1265 {"slice-height", OPT_ARG_INT, &p->slice_height, int_non_neg},
1266 {"rectangle", OPT_ARG_INT, &p->use_rectangle,int_non_neg},
1267 {"yuv", OPT_ARG_INT, &p->use_yuv, int_non_neg},
1268 {"lscale", OPT_ARG_INT, &p->lscale, int_non_neg},
1269 {"cscale", OPT_ARG_INT, &p->cscale, int_non_neg},
1270 {"filter-strength", OPT_ARG_FLOAT, &p->filter_strength, NULL},
1271 {"ati-hack", OPT_ARG_BOOL, &p->ati_hack, NULL},
1272 {"force-pbo", OPT_ARG_BOOL, &p->force_pbo, NULL},
1273 {"glfinish", OPT_ARG_BOOL, &p->use_glFinish, NULL},
1274 {"swapinterval", OPT_ARG_INT, &p->swap_interval,NULL},
1275 {"customprog", OPT_ARG_MSTRZ,&p->custom_prog, NULL},
1276 {"customtex", OPT_ARG_MSTRZ,&p->custom_tex, NULL},
1277 {"customtlin", OPT_ARG_BOOL, &p->custom_tlin, NULL},
1278 {"customtrect", OPT_ARG_BOOL, &p->custom_trect, NULL},
1279 {"mipmapgen", OPT_ARG_BOOL, &p->mipmap_gen, NULL},
1280 {"osdcolor", OPT_ARG_INT, &p->osd_color, NULL},
1281 {"stereo", OPT_ARG_INT, &p->stereo_mode, NULL},
1282 // Removed options.
1283 // They are only parsed to notify the user about the replacements.
1284 {"aspect", OPT_ARG_BOOL, &aspect, NULL},
1285 {"colorspace", OPT_ARG_INT, &user_colorspace, NULL},
1286 {"levelconv", OPT_ARG_INT, &levelconv, NULL},
1287 {NULL}
1290 if (subopt_parse(arg, subopts) != 0) {
1291 mp_msg(MSGT_VO, MSGL_FATAL,
1292 "\n-vo gl command line help:\n"
1293 "Example: mplayer -vo gl:slice-height=4\n"
1294 "\nOptions:\n"
1295 " nomanyfmts\n"
1296 " Disable extended color formats for OpenGL 1.2 and later\n"
1297 " slice-height=<0-...>\n"
1298 " Slice size for texture transfer, 0 for whole image\n"
1299 " noosd\n"
1300 " Do not use OpenGL OSD code\n"
1301 " scaled-osd\n"
1302 " Render OSD at movie resolution and scale it\n"
1303 " rectangle=<0,1,2>\n"
1304 " 0: use power-of-two textures\n"
1305 " 1: use texture_rectangle\n"
1306 " 2: use texture_non_power_of_two\n"
1307 " ati-hack\n"
1308 " Workaround ATI bug with PBOs\n"
1309 " force-pbo\n"
1310 " Force use of PBO even if this involves an extra memcpy\n"
1311 " glfinish\n"
1312 " Call glFinish() before swapping buffers\n"
1313 " swapinterval=<n>\n"
1314 " Interval in displayed frames between to buffer swaps.\n"
1315 " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
1316 " Requires GLX_SGI_swap_control support to work.\n"
1317 " ycbcr\n"
1318 " also try to use the GL_MESA_ycbcr_texture extension\n"
1319 " yuv=<n>\n"
1320 " 0: use software YUV to RGB conversion.\n"
1321 " 1: deprecated, will use yuv=2 (used to be nVidia register combiners).\n"
1322 " 2: use fragment program.\n"
1323 " 3: use fragment program with gamma correction.\n"
1324 " 4: use fragment program with gamma correction via lookup.\n"
1325 " 5: use ATI-specific method (for older cards).\n"
1326 " 6: use lookup via 3D texture.\n"
1327 " lscale=<n>\n"
1328 " 0: use standard bilinear scaling for luma.\n"
1329 " 1: use improved bicubic scaling for luma.\n"
1330 " 2: use cubic in X, linear in Y direction scaling for luma.\n"
1331 " 3: as 1 but without using a lookup texture.\n"
1332 " 4: experimental unsharp masking (sharpening).\n"
1333 " 5: experimental unsharp masking (sharpening) with larger radius.\n"
1334 " cscale=<n>\n"
1335 " as lscale but for chroma (2x slower with little visible effect).\n"
1336 " filter-strength=<value>\n"
1337 " set the effect strength for some lscale/cscale filters\n"
1338 " customprog=<filename>\n"
1339 " use a custom YUV conversion program\n"
1340 " customtex=<filename>\n"
1341 " use a custom YUV conversion lookup texture\n"
1342 " nocustomtlin\n"
1343 " use GL_NEAREST scaling for customtex texture\n"
1344 " customtrect\n"
1345 " use texture_rectangle for customtex texture\n"
1346 " mipmapgen\n"
1347 " generate mipmaps for the video image (use with TXB in customprog)\n"
1348 " osdcolor=<0xAARRGGBB>\n"
1349 " use the given color for the OSD\n"
1350 " stereo=<n>\n"
1351 " 0: normal display\n"
1352 " 1: side-by-side to red-cyan stereo\n"
1353 " 2: side-by-side to green-magenta stereo\n"
1354 " 3: side-by-side to quadbuffer stereo\n"
1355 "\n");
1356 return -1;
1358 if (user_colorspace != 0 || levelconv != -1) {
1359 mp_msg(MSGT_VO, MSGL_ERR, "[gl] \"colorspace\" and \"levelconv\" "
1360 "suboptions have been removed. Use options --colormatrix and"
1361 " --colormatrix-input-range/--colormatrix-output-range instead.\n");
1362 return -1;
1364 if (aspect != -1) {
1365 mp_msg(MSGT_VO, MSGL_ERR, "[gl] \"noaspect\" suboption has been "
1366 "removed. Use --noaspect instead.\n");
1367 return -1;
1369 if (p->use_yuv == 1) {
1370 mp_msg(MSGT_VO, MSGL_WARN, "[gl] yuv=1 (nVidia register combiners) have"
1371 " been removed, using yuv=2 instead.\n");
1372 p->use_yuv = 2;
1374 p->glctx = init_mpglcontext(gltype, vo);
1375 if (!p->glctx)
1376 goto err_out;
1377 p->gl = p->glctx->gl;
1379 if (p->glctx->type == GLTYPE_SDL && p->use_yuv == -1) {
1380 // Apparently it's not possible to implement VOFLAG_HIDDEN on SDL 1.2,
1381 // so don't do autodetection. Use a sufficiently useful and safe YUV
1382 // conversion mode.
1383 p->use_yuv = YUV_CONVERSION_FRAGMENT;
1386 if (p->use_yuv == -1 || !allow_sw) {
1387 if (create_window(vo, 320, 200, VOFLAG_HIDDEN) < 0)
1388 goto err_out;
1389 if (p->glctx->setGlWindow(p->glctx) == SET_WINDOW_FAILED)
1390 goto err_out;
1391 if (!allow_sw && isSoftwareGl(vo))
1392 goto err_out;
1393 autodetectGlExtensions(vo);
1394 // We created a window to test whether the GL context supports hardware
1395 // acceleration and so on. Destroy that window to make sure all state
1396 // associated with it is lost.
1397 uninit(vo);
1398 p->glctx = init_mpglcontext(gltype, vo);
1399 if (!p->glctx)
1400 goto err_out;
1401 p->gl = p->glctx->gl;
1403 if (p->many_fmts)
1404 mp_msg(MSGT_VO, MSGL_INFO, "[gl] using extended formats. "
1405 "Use -vo gl:nomanyfmts if playback fails.\n");
1406 mp_msg(MSGT_VO, MSGL_V, "[gl] Using %d as slice height "
1407 "(0 means image height).\n", p->slice_height);
1409 return 0;
1411 err_out:
1412 uninit(vo);
1413 return -1;
1416 static int preinit(struct vo *vo, const char *arg)
1418 return preinit_internal(vo, arg, 1, GLTYPE_AUTO);
1421 static int control(struct vo *vo, uint32_t request, void *data)
1423 struct gl_priv *p = vo->priv;
1425 switch (request) {
1426 case VOCTRL_PAUSE:
1427 case VOCTRL_RESUME:
1428 p->int_pause = (request == VOCTRL_PAUSE);
1429 return VO_TRUE;
1430 case VOCTRL_QUERY_FORMAT:
1431 return query_format(vo, *(uint32_t *)data);
1432 case VOCTRL_GET_IMAGE:
1433 return get_image(vo, data);
1434 case VOCTRL_DRAW_IMAGE:
1435 return draw_image(vo, data);
1436 case VOCTRL_DRAW_EOSD:
1437 if (!data)
1438 return VO_FALSE;
1439 genEOSD(vo, data);
1440 if (vo_doublebuffering)
1441 do_render_osd(vo, RENDER_EOSD);
1442 return VO_TRUE;
1443 case VOCTRL_GET_EOSD_RES: {
1444 mp_eosd_res_t *r = data;
1445 r->w = vo->dwidth;
1446 r->h = vo->dheight;
1447 r->mt = r->mb = r->ml = r->mr = 0;
1448 if (p->scaled_osd) {
1449 r->w = p->image_width;
1450 r->h = p->image_height;
1451 } else if (aspect_scaling()) {
1452 r->ml = r->mr = p->ass_border_x;
1453 r->mt = r->mb = p->ass_border_y;
1455 return VO_TRUE;
1457 case VOCTRL_ONTOP:
1458 if (!p->glctx->ontop)
1459 break;
1460 p->glctx->ontop(vo);
1461 return VO_TRUE;
1462 case VOCTRL_FULLSCREEN:
1463 p->glctx->fullscreen(vo);
1464 resize(vo, vo->dwidth, vo->dheight);
1465 return VO_TRUE;
1466 case VOCTRL_BORDER:
1467 if (!p->glctx->border)
1468 break;
1469 p->glctx->border(vo);
1470 resize(vo, vo->dwidth, vo->dheight);
1471 return VO_TRUE;
1472 case VOCTRL_GET_PANSCAN:
1473 return VO_TRUE;
1474 case VOCTRL_SET_PANSCAN:
1475 resize(vo, vo->dwidth, vo->dheight);
1476 return VO_TRUE;
1477 case VOCTRL_GET_EQUALIZER:
1478 if (p->is_yuv) {
1479 struct voctrl_get_equalizer_args *args = data;
1480 return mp_csp_equalizer_get(&p->video_eq, args->name, args->valueptr)
1481 >= 0 ? VO_TRUE : VO_NOTIMPL;
1483 break;
1484 case VOCTRL_SET_EQUALIZER:
1485 if (p->is_yuv) {
1486 struct voctrl_set_equalizer_args *args = data;
1487 if (mp_csp_equalizer_set(&p->video_eq, args->name, args->value) < 0)
1488 return VO_NOTIMPL;
1489 update_yuvconv(vo);
1490 return VO_TRUE;
1492 break;
1493 case VOCTRL_SET_YUV_COLORSPACE: {
1494 bool supports_csp = (1 << p->use_yuv) & MASK_NOT_COMBINERS;
1495 if (vo->config_count && supports_csp) {
1496 p->colorspace = *(struct mp_csp_details *)data;
1497 update_yuvconv(vo);
1499 return VO_TRUE;
1501 case VOCTRL_GET_YUV_COLORSPACE:
1502 *(struct mp_csp_details *)data = p->colorspace;
1503 return VO_TRUE;
1504 case VOCTRL_UPDATE_SCREENINFO:
1505 if (!p->glctx->update_xinerama_info)
1506 break;
1507 p->glctx->update_xinerama_info(vo);
1508 return VO_TRUE;
1509 case VOCTRL_REDRAW_OSD:
1510 if (vo_doublebuffering)
1511 do_render(vo);
1512 draw_osd(vo, data);
1513 if (vo_doublebuffering)
1514 do_render_osd(vo, 2);
1515 flip_page(vo);
1516 return VO_TRUE;
1517 case VOCTRL_SCREENSHOT: {
1518 struct voctrl_screenshot_args *args = data;
1519 if (args->full_window)
1520 args->out_image = get_window_screenshot(vo);
1521 else
1522 args->out_image = get_screenshot(vo);
1523 return true;
1526 return VO_NOTIMPL;
1529 const struct vo_driver video_out_gl = {
1530 .is_new = true,
1531 .info = &(const vo_info_t) {
1532 "OpenGL",
1533 "gl",
1534 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1537 .preinit = preinit,
1538 .config = config,
1539 .control = control,
1540 .draw_slice = draw_slice,
1541 .draw_osd = draw_osd,
1542 .flip_page = flip_page,
1543 .check_events = check_events,
1544 .uninit = uninit,
1547 static int preinit_nosw(struct vo *vo, const char *arg)
1549 return preinit_internal(vo, arg, 0, GLTYPE_AUTO);
1552 const struct vo_driver video_out_gl_nosw =
1554 .is_new = true,
1555 .info = &(const vo_info_t) {
1556 "OpenGL no software rendering",
1557 "gl_nosw",
1558 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1561 .preinit = preinit_nosw,
1562 .config = config,
1563 .control = control,
1564 .draw_slice = draw_slice,
1565 .draw_osd = draw_osd,
1566 .flip_page = flip_page,
1567 .check_events = check_events,
1568 .uninit = uninit,
1571 #ifdef CONFIG_GL_SDL
1572 static int preinit_sdl(struct vo *vo, const char *arg)
1574 return preinit_internal(vo, arg, 1, GLTYPE_SDL);
1577 const struct vo_driver video_out_gl_sdl = {
1578 .is_new = true,
1579 .info = &(const vo_info_t) {
1580 "OpenGL with SDL",
1581 "gl_sdl",
1582 "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>",
1585 .preinit = preinit_sdl,
1586 .config = config,
1587 .control = control,
1588 .draw_slice = draw_slice,
1589 .draw_osd = draw_osd,
1590 .flip_page = flip_page,
1591 .check_events = check_events,
1592 .uninit = uninit,
1594 #endif