vo_corevideo: restructure this video output
[mplayer.git] / libvo / gl_common.c
blob30ed50e95ecb7c4497a5ca405368149ca41956bd
1 /*
2 * common OpenGL routines
4 * copyleft (C) 2005-2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
5 * Special thanks go to the xine team and Matthias Hopf, whose video_out_opengl.c
6 * gave me lots of good ideas.
8 * This file is part of MPlayer.
10 * MPlayer is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * MPlayer is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * You can alternatively redistribute this file and/or
25 * modify it under the terms of the GNU Lesser General Public
26 * License as published by the Free Software Foundation; either
27 * version 2.1 of the License, or (at your option) any later version.
30 /**
31 * \file gl_common.c
32 * \brief OpenGL helper functions used by vo_gl.c and vo_gl2.c
35 #include <stddef.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <math.h>
41 #include "talloc.h"
42 #include "gl_common.h"
43 #include "old_vo_wrapper.h"
44 #include "csputils.h"
45 #include "aspect.h"
46 #include "pnm_loader.h"
47 #include "options.h"
49 //! \defgroup glgeneral OpenGL general helper functions
51 //! \defgroup glcontext OpenGL context management helper functions
53 //! \defgroup gltexture OpenGL texture handling helper functions
55 //! \defgroup glconversion OpenGL conversion helper functions
57 /**
58 * \brief adjusts the GL_UNPACK_ALIGNMENT to fit the stride.
59 * \param stride number of bytes per line for which alignment should fit.
60 * \ingroup glgeneral
62 void glAdjustAlignment(GL *gl, int stride)
64 GLint gl_alignment;
65 if (stride % 8 == 0)
66 gl_alignment = 8;
67 else if (stride % 4 == 0)
68 gl_alignment = 4;
69 else if (stride % 2 == 0)
70 gl_alignment = 2;
71 else
72 gl_alignment = 1;
73 gl->PixelStorei(GL_UNPACK_ALIGNMENT, gl_alignment);
74 gl->PixelStorei(GL_PACK_ALIGNMENT, gl_alignment);
77 struct gl_name_map_struct {
78 GLint value;
79 const char *name;
82 #undef MAP
83 #define MAP(a) {a, # a}
84 //! mapping table for the glValName function
85 static const struct gl_name_map_struct gl_name_map[] = {
86 // internal format
87 MAP(GL_R3_G3_B2), MAP(GL_RGB4), MAP(GL_RGB5), MAP(GL_RGB8),
88 MAP(GL_RGB10), MAP(GL_RGB12), MAP(GL_RGB16), MAP(GL_RGBA2),
89 MAP(GL_RGBA4), MAP(GL_RGB5_A1), MAP(GL_RGBA8), MAP(GL_RGB10_A2),
90 MAP(GL_RGBA12), MAP(GL_RGBA16), MAP(GL_LUMINANCE8), MAP(GL_LUMINANCE16),
91 MAP(GL_R16),
93 // format
94 MAP(GL_RGB), MAP(GL_RGBA), MAP(GL_RED), MAP(GL_GREEN), MAP(GL_BLUE),
95 MAP(GL_ALPHA), MAP(GL_LUMINANCE), MAP(GL_LUMINANCE_ALPHA),
96 MAP(GL_COLOR_INDEX),
97 // rest 1.2 only
98 MAP(GL_BGR), MAP(GL_BGRA),
100 //type
101 MAP(GL_BYTE), MAP(GL_UNSIGNED_BYTE), MAP(GL_SHORT), MAP(GL_UNSIGNED_SHORT),
102 MAP(GL_INT), MAP(GL_UNSIGNED_INT), MAP(GL_FLOAT), MAP(GL_DOUBLE),
103 MAP(GL_2_BYTES), MAP(GL_3_BYTES), MAP(GL_4_BYTES),
104 // rest 1.2 only
105 MAP(GL_UNSIGNED_BYTE_3_3_2), MAP(GL_UNSIGNED_BYTE_2_3_3_REV),
106 MAP(GL_UNSIGNED_SHORT_5_6_5), MAP(GL_UNSIGNED_SHORT_5_6_5_REV),
107 MAP(GL_UNSIGNED_SHORT_4_4_4_4), MAP(GL_UNSIGNED_SHORT_4_4_4_4_REV),
108 MAP(GL_UNSIGNED_SHORT_5_5_5_1), MAP(GL_UNSIGNED_SHORT_1_5_5_5_REV),
109 MAP(GL_UNSIGNED_INT_8_8_8_8), MAP(GL_UNSIGNED_INT_8_8_8_8_REV),
110 MAP(GL_UNSIGNED_INT_10_10_10_2), MAP(GL_UNSIGNED_INT_2_10_10_10_REV),
111 {0, 0}
113 #undef MAP
116 * \brief return the name of an OpenGL constant
117 * \param value the constant
118 * \return name of the constant or "Unknown format!"
119 * \ingroup glgeneral
121 const char *glValName(GLint value)
123 int i = 0;
125 while (gl_name_map[i].name) {
126 if (gl_name_map[i].value == value)
127 return gl_name_map[i].name;
128 i++;
130 return "Unknown format!";
133 //! always return this format as internal texture format in glFindFormat
134 #define TEXTUREFORMAT_ALWAYS GL_RGB8
135 #undef TEXTUREFORMAT_ALWAYS
138 * \brief find the OpenGL settings coresponding to format.
140 * All parameters may be NULL.
141 * \param fmt MPlayer format to analyze.
142 * \param bpp [OUT] bits per pixel of that format.
143 * \param gl_texfmt [OUT] internal texture format that fits the
144 * image format, not necessarily the best for performance.
145 * \param gl_format [OUT] OpenGL format for this image format.
146 * \param gl_type [OUT] OpenGL type for this image format.
147 * \return 1 if format is supported by OpenGL, 0 if not.
148 * \ingroup gltexture
150 int glFindFormat(uint32_t fmt, int have_texture_rg, int *bpp, GLint *gl_texfmt,
151 GLenum *gl_format, GLenum *gl_type)
153 int supported = 1;
154 int dummy1;
155 GLenum dummy2;
156 GLint dummy3;
157 if (!bpp)
158 bpp = &dummy1;
159 if (!gl_texfmt)
160 gl_texfmt = &dummy3;
161 if (!gl_format)
162 gl_format = &dummy2;
163 if (!gl_type)
164 gl_type = &dummy2;
166 if (mp_get_chroma_shift(fmt, NULL, NULL, NULL)) {
167 // reduce the possible cases a bit
168 if (IMGFMT_IS_YUVP16_LE(fmt))
169 fmt = IMGFMT_420P16_LE;
170 else if (IMGFMT_IS_YUVP16_BE(fmt))
171 fmt = IMGFMT_420P16_BE;
172 else
173 fmt = IMGFMT_YV12;
176 *bpp = IMGFMT_IS_BGR(fmt) ? IMGFMT_BGR_DEPTH(fmt) : IMGFMT_RGB_DEPTH(fmt);
177 *gl_texfmt = 3;
178 switch (fmt) {
179 case IMGFMT_RGB48NE:
180 *gl_format = GL_RGB;
181 *gl_type = GL_UNSIGNED_SHORT;
182 break;
183 case IMGFMT_RGB24:
184 *gl_format = GL_RGB;
185 *gl_type = GL_UNSIGNED_BYTE;
186 break;
187 case IMGFMT_RGBA:
188 *gl_texfmt = 4;
189 *gl_format = GL_RGBA;
190 *gl_type = GL_UNSIGNED_BYTE;
191 break;
192 case IMGFMT_420P16:
193 supported = 0; // no native YUV support
194 *gl_texfmt = have_texture_rg ? GL_R16 : GL_LUMINANCE16;
195 *bpp = 16;
196 *gl_format = have_texture_rg ? GL_RED : GL_LUMINANCE;
197 *gl_type = GL_UNSIGNED_SHORT;
198 break;
199 case IMGFMT_YV12:
200 supported = 0; // no native YV12 support
201 case IMGFMT_Y800:
202 case IMGFMT_Y8:
203 *gl_texfmt = 1;
204 *bpp = 8;
205 *gl_format = GL_LUMINANCE;
206 *gl_type = GL_UNSIGNED_BYTE;
207 break;
208 case IMGFMT_UYVY:
209 // IMGFMT_YUY2 would be more logical for the _REV format,
210 // but gives clearly swapped colors.
211 case IMGFMT_YVYU:
212 *gl_texfmt = GL_YCBCR_MESA;
213 *bpp = 16;
214 *gl_format = GL_YCBCR_MESA;
215 *gl_type = fmt == IMGFMT_UYVY ? GL_UNSIGNED_SHORT_8_8 : GL_UNSIGNED_SHORT_8_8_REV;
216 break;
217 #if 0
218 // we do not support palettized formats, although the format the
219 // swscale produces works
220 case IMGFMT_RGB8:
221 gl_format = GL_RGB;
222 gl_type = GL_UNSIGNED_BYTE_2_3_3_REV;
223 break;
224 #endif
225 case IMGFMT_RGB15:
226 *gl_format = GL_RGBA;
227 *gl_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
228 break;
229 case IMGFMT_RGB16:
230 *gl_format = GL_RGB;
231 *gl_type = GL_UNSIGNED_SHORT_5_6_5_REV;
232 break;
233 #if 0
234 case IMGFMT_BGR8:
235 // special case as red and blue have a differen number of bits.
236 // GL_BGR and GL_UNSIGNED_BYTE_3_3_2 isn't supported at least
237 // by nVidia drivers, and in addition would give more bits to
238 // blue than to red, which isn't wanted
239 gl_format = GL_RGB;
240 gl_type = GL_UNSIGNED_BYTE_3_3_2;
241 break;
242 #endif
243 case IMGFMT_BGR15:
244 *gl_format = GL_BGRA;
245 *gl_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
246 break;
247 case IMGFMT_BGR16:
248 *gl_format = GL_RGB;
249 *gl_type = GL_UNSIGNED_SHORT_5_6_5;
250 break;
251 case IMGFMT_BGR24:
252 *gl_format = GL_BGR;
253 *gl_type = GL_UNSIGNED_BYTE;
254 break;
255 case IMGFMT_BGRA:
256 *gl_texfmt = 4;
257 *gl_format = GL_BGRA;
258 *gl_type = GL_UNSIGNED_BYTE;
259 break;
260 default:
261 *gl_texfmt = 4;
262 *gl_format = GL_RGBA;
263 *gl_type = GL_UNSIGNED_BYTE;
264 supported = 0;
266 #ifdef TEXTUREFORMAT_ALWAYS
267 *gl_texfmt = TEXTUREFORMAT_ALWAYS;
268 #endif
269 return supported;
272 #ifdef HAVE_LIBDL
273 #include <dlfcn.h>
274 #endif
276 * \brief find address of a linked function
277 * \param s name of function to find
278 * \return address of function or NULL if not found
280 static void *getdladdr(const char *s)
282 void *ret = NULL;
283 #ifdef HAVE_LIBDL
284 void *handle = dlopen(NULL, RTLD_LAZY);
285 if (!handle)
286 return NULL;
287 ret = dlsym(handle, s);
288 dlclose(handle);
289 #endif
290 return ret;
293 typedef struct {
294 ptrdiff_t offset; // offset to the function pointer in struct GL
295 const char *extstr;
296 const char *funcnames[7];
297 void *fallback;
298 } extfunc_desc_t;
300 #define DEF_FUNC_DESC(name) \
301 {offsetof(GL, name), NULL, {"gl" # name, NULL}, gl ## name}
302 #define DEF_EXT_FUNCS(...) __VA_ARGS__
303 #define DEF_EXT_DESC(name, ext, funcnames) \
304 {offsetof(GL, name), ext, {DEF_EXT_FUNCS funcnames}}
306 static const extfunc_desc_t extfuncs[] = {
307 // these aren't extension functions but we query them anyway to allow
308 // different "backends" with one binary
309 DEF_FUNC_DESC(Begin),
310 DEF_FUNC_DESC(End),
311 DEF_FUNC_DESC(Viewport),
312 DEF_FUNC_DESC(MatrixMode),
313 DEF_FUNC_DESC(LoadIdentity),
314 DEF_FUNC_DESC(Translated),
315 DEF_FUNC_DESC(Scaled),
316 DEF_FUNC_DESC(Ortho),
317 DEF_FUNC_DESC(Frustum),
318 DEF_FUNC_DESC(PushMatrix),
319 DEF_FUNC_DESC(PopMatrix),
320 DEF_FUNC_DESC(Clear),
321 DEF_FUNC_DESC(GenLists),
322 DEF_FUNC_DESC(DeleteLists),
323 DEF_FUNC_DESC(NewList),
324 DEF_FUNC_DESC(EndList),
325 DEF_FUNC_DESC(CallList),
326 DEF_FUNC_DESC(CallLists),
327 DEF_FUNC_DESC(GenTextures),
328 DEF_FUNC_DESC(DeleteTextures),
329 DEF_FUNC_DESC(TexEnvf),
330 DEF_FUNC_DESC(TexEnvi),
331 DEF_FUNC_DESC(Color4ub),
332 DEF_FUNC_DESC(Color3f),
333 DEF_FUNC_DESC(Color4f),
334 DEF_FUNC_DESC(ClearColor),
335 DEF_FUNC_DESC(ClearDepth),
336 DEF_FUNC_DESC(DepthFunc),
337 DEF_FUNC_DESC(Enable),
338 DEF_FUNC_DESC(Disable),
339 DEF_FUNC_DESC(DrawBuffer),
340 DEF_FUNC_DESC(DepthMask),
341 DEF_FUNC_DESC(BlendFunc),
342 DEF_FUNC_DESC(Flush),
343 DEF_FUNC_DESC(Finish),
344 DEF_FUNC_DESC(PixelStorei),
345 DEF_FUNC_DESC(TexImage1D),
346 DEF_FUNC_DESC(TexImage2D),
347 DEF_FUNC_DESC(TexSubImage2D),
348 DEF_FUNC_DESC(GetTexImage),
349 DEF_FUNC_DESC(TexParameteri),
350 DEF_FUNC_DESC(TexParameterf),
351 DEF_FUNC_DESC(TexParameterfv),
352 DEF_FUNC_DESC(TexCoord2f),
353 DEF_FUNC_DESC(TexCoord2fv),
354 DEF_FUNC_DESC(Vertex2f),
355 DEF_FUNC_DESC(Vertex3f),
356 DEF_FUNC_DESC(Normal3f),
357 DEF_FUNC_DESC(Lightfv),
358 DEF_FUNC_DESC(ColorMaterial),
359 DEF_FUNC_DESC(ShadeModel),
360 DEF_FUNC_DESC(GetIntegerv),
361 DEF_FUNC_DESC(ColorMask),
362 DEF_FUNC_DESC(ReadPixels),
363 DEF_FUNC_DESC(ReadBuffer),
365 DEF_EXT_DESC(GenBuffers, NULL,
366 ("glGenBuffers", "glGenBuffersARB")),
367 DEF_EXT_DESC(DeleteBuffers, NULL,
368 ("glDeleteBuffers", "glDeleteBuffersARB")),
369 DEF_EXT_DESC(BindBuffer, NULL,
370 ("glBindBuffer", "glBindBufferARB")),
371 DEF_EXT_DESC(MapBuffer, NULL,
372 ("glMapBuffer", "glMapBufferARB")),
373 DEF_EXT_DESC(UnmapBuffer, NULL,
374 ("glUnmapBuffer", "glUnmapBufferARB")),
375 DEF_EXT_DESC(BufferData, NULL,
376 ("glBufferData", "glBufferDataARB")),
377 DEF_EXT_DESC(BeginFragmentShader, "ATI_fragment_shader",
378 ("glBeginFragmentShaderATI")),
379 DEF_EXT_DESC(EndFragmentShader, "ATI_fragment_shader",
380 ("glEndFragmentShaderATI")),
381 DEF_EXT_DESC(SampleMap, "ATI_fragment_shader",
382 ("glSampleMapATI")),
383 DEF_EXT_DESC(ColorFragmentOp2, "ATI_fragment_shader",
384 ("glColorFragmentOp2ATI")),
385 DEF_EXT_DESC(ColorFragmentOp3, "ATI_fragment_shader",
386 ("glColorFragmentOp3ATI")),
387 DEF_EXT_DESC(SetFragmentShaderConstant, "ATI_fragment_shader",
388 ("glSetFragmentShaderConstantATI")),
389 DEF_EXT_DESC(ActiveTexture, NULL,
390 ("glActiveTexture", "glActiveTextureARB")),
391 DEF_EXT_DESC(BindTexture, NULL,
392 ("glBindTexture", "glBindTextureARB", "glBindTextureEXT")),
393 DEF_EXT_DESC(MultiTexCoord2f, NULL,
394 ("glMultiTexCoord2f", "glMultiTexCoord2fARB")),
395 DEF_EXT_DESC(GenPrograms, "_program",
396 ("glGenProgramsARB")),
397 DEF_EXT_DESC(DeletePrograms, "_program",
398 ("glDeleteProgramsARB")),
399 DEF_EXT_DESC(BindProgram, "_program",
400 ("glBindProgramARB")),
401 DEF_EXT_DESC(ProgramString, "_program",
402 ("glProgramStringARB")),
403 DEF_EXT_DESC(GetProgramiv, "_program",
404 ("glGetProgramivARB")),
405 DEF_EXT_DESC(ProgramEnvParameter4f, "_program",
406 ("glProgramEnvParameter4fARB")),
407 DEF_EXT_DESC(SwapInterval, "_swap_control",
408 ("glXSwapIntervalSGI", "glXSwapInterval", "wglSwapIntervalSGI",
409 "wglSwapInterval", "wglSwapIntervalEXT")),
410 DEF_EXT_DESC(TexImage3D, NULL,
411 ("glTexImage3D")),
412 {-1}
416 * \brief find the function pointers of some useful OpenGL extensions
417 * \param getProcAddress function to resolve function names, may be NULL
418 * \param ext2 an extra extension string
420 static void getFunctions(GL *gl, void *(*getProcAddress)(const GLubyte *),
421 const char *ext2)
423 const extfunc_desc_t *dsc;
424 const char *extensions;
425 char *allexts;
427 if (!getProcAddress)
428 getProcAddress = (void *)getdladdr;
430 // special case, we need glGetString before starting to find the other functions
431 gl->GetString = getProcAddress("glGetString");
432 if (!gl->GetString)
433 gl->GetString = glGetString;
435 extensions = (const char *)gl->GetString(GL_EXTENSIONS);
436 if (!extensions)
437 extensions = "";
438 if (!ext2)
439 ext2 = "";
440 allexts = malloc(strlen(extensions) + strlen(ext2) + 2);
441 strcpy(allexts, extensions);
442 strcat(allexts, " ");
443 strcat(allexts, ext2);
444 mp_msg(MSGT_VO, MSGL_DBG2, "OpenGL extensions string:\n%s\n", allexts);
445 for (dsc = extfuncs; dsc->offset >= 0; dsc++) {
446 void *ptr = NULL;
447 int i;
448 if (!dsc->extstr || strstr(allexts, dsc->extstr)) {
449 for (i = 0; !ptr && dsc->funcnames[i]; i++)
450 ptr = getProcAddress((const GLubyte *)dsc->funcnames[i]);
452 if (!ptr)
453 ptr = dsc->fallback;
454 void **funcptr = (void**)(((char*)gl) + dsc->offset);
455 *funcptr = ptr;
457 free(allexts);
461 * \brief create a texture and set some defaults
462 * \param target texture taget, usually GL_TEXTURE_2D
463 * \param fmt internal texture format
464 * \param format texture host data format
465 * \param type texture host data type
466 * \param filter filter used for scaling, e.g. GL_LINEAR
467 * \param w texture width
468 * \param h texture height
469 * \param val luminance value to fill texture with
470 * \ingroup gltexture
472 void glCreateClearTex(GL *gl, GLenum target, GLenum fmt, GLenum format,
473 GLenum type, GLint filter, int w, int h,
474 unsigned char val)
476 GLfloat fval = (GLfloat)val / 255.0;
477 GLfloat border[4] = {
478 fval, fval, fval, fval
480 int stride;
481 char *init;
482 if (w == 0)
483 w = 1;
484 if (h == 0)
485 h = 1;
486 stride = w * glFmt2bpp(format, type);
487 if (!stride)
488 return;
489 init = malloc(stride * h);
490 memset(init, val, stride * h);
491 glAdjustAlignment(gl, stride);
492 gl->PixelStorei(GL_UNPACK_ROW_LENGTH, w);
493 gl->TexImage2D(target, 0, fmt, w, h, 0, format, type, init);
494 gl->TexParameterf(target, GL_TEXTURE_PRIORITY, 1.0);
495 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
496 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
497 gl->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
498 gl->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
499 // Border texels should not be used with CLAMP_TO_EDGE
500 // We set a sane default anyway.
501 gl->TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, border);
502 free(init);
505 static GLint detect_hqtexfmt(GL *gl)
507 const char *extensions = (const char *)gl->GetString(GL_EXTENSIONS);
508 if (strstr(extensions, "_texture_float"))
509 return GL_RGB32F;
510 else if (strstr(extensions, "NV_float_buffer"))
511 return GL_FLOAT_RGB32_NV;
512 return GL_RGB16;
516 * \brief creates a texture from a PPM file
517 * \param target texture taget, usually GL_TEXTURE_2D
518 * \param fmt internal texture format, 0 for default
519 * \param filter filter used for scaling, e.g. GL_LINEAR
520 * \param f file to read PPM from
521 * \param width [out] width of texture
522 * \param height [out] height of texture
523 * \param maxval [out] maxval value from PPM file
524 * \return 0 on error, 1 otherwise
525 * \ingroup gltexture
527 int glCreatePPMTex(GL *gl, GLenum target, GLenum fmt, GLint filter,
528 FILE *f, int *width, int *height, int *maxval)
530 int w, h, m, bpp;
531 GLenum type;
532 uint8_t *data = read_pnm(f, &w, &h, &bpp, &m);
533 GLint hqtexfmt = detect_hqtexfmt(gl);
534 if (!data || (bpp != 3 && bpp != 6)) {
535 free(data);
536 return 0;
538 if (!fmt) {
539 fmt = bpp == 6 ? hqtexfmt : 3;
540 if (fmt == GL_FLOAT_RGB32_NV && target != GL_TEXTURE_RECTANGLE)
541 fmt = GL_RGB16;
543 type = bpp == 6 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
544 glCreateClearTex(gl, target, fmt, GL_RGB, type, filter, w, h, 0);
545 glUploadTex(gl, target, GL_RGB, type,
546 data, w * bpp, 0, 0, w, h, 0);
547 free(data);
548 if (width)
549 *width = w;
550 if (height)
551 *height = h;
552 if (maxval)
553 *maxval = m;
554 return 1;
558 * \brief return the number of bytes per pixel for the given format
559 * \param format OpenGL format
560 * \param type OpenGL type
561 * \return bytes per pixel
562 * \ingroup glgeneral
564 * Does not handle all possible variants, just those used by MPlayer
566 int glFmt2bpp(GLenum format, GLenum type)
568 int component_size = 0;
569 switch (type) {
570 case GL_UNSIGNED_BYTE_3_3_2:
571 case GL_UNSIGNED_BYTE_2_3_3_REV:
572 return 1;
573 case GL_UNSIGNED_SHORT_5_5_5_1:
574 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
575 case GL_UNSIGNED_SHORT_5_6_5:
576 case GL_UNSIGNED_SHORT_5_6_5_REV:
577 return 2;
578 case GL_UNSIGNED_BYTE:
579 component_size = 1;
580 break;
581 case GL_UNSIGNED_SHORT:
582 component_size = 2;
583 break;
585 switch (format) {
586 case GL_LUMINANCE:
587 case GL_ALPHA:
588 return component_size;
589 case GL_YCBCR_MESA:
590 return 2;
591 case GL_RGB:
592 case GL_BGR:
593 return 3 * component_size;
594 case GL_RGBA:
595 case GL_BGRA:
596 return 4 * component_size;
597 case GL_RED:
598 return component_size;
599 case GL_RG:
600 case GL_LUMINANCE_ALPHA:
601 return 2 * component_size;
603 return 0; // unknown
607 * \brief upload a texture, handling things like stride and slices
608 * \param target texture target, usually GL_TEXTURE_2D
609 * \param format OpenGL format of data
610 * \param type OpenGL type of data
611 * \param dataptr data to upload
612 * \param stride data stride
613 * \param x x offset in texture
614 * \param y y offset in texture
615 * \param w width of the texture part to upload
616 * \param h height of the texture part to upload
617 * \param slice height of an upload slice, 0 for all at once
618 * \ingroup gltexture
620 void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type,
621 const void *dataptr, int stride,
622 int x, int y, int w, int h, int slice)
624 const uint8_t *data = dataptr;
625 int y_max = y + h;
626 if (w <= 0 || h <= 0)
627 return;
628 if (slice <= 0)
629 slice = h;
630 if (stride < 0) {
631 data += (h - 1) * stride;
632 stride = -stride;
634 // this is not always correct, but should work for MPlayer
635 glAdjustAlignment(gl, stride);
636 gl->PixelStorei(GL_UNPACK_ROW_LENGTH, stride / glFmt2bpp(format, type));
637 for (; y + slice <= y_max; y += slice) {
638 gl->TexSubImage2D(target, 0, x, y, w, slice, format, type, data);
639 data += stride * slice;
641 if (y < y_max)
642 gl->TexSubImage2D(target, 0, x, y, w, y_max - y, format, type, data);
646 * \brief download a texture, handling things like stride and slices
647 * \param target texture target, usually GL_TEXTURE_2D
648 * \param format OpenGL format of data
649 * \param type OpenGL type of data
650 * \param dataptr destination memory for download
651 * \param stride data stride (must be positive)
652 * \ingroup gltexture
654 void glDownloadTex(GL *gl, GLenum target, GLenum format, GLenum type,
655 void *dataptr, int stride)
657 // this is not always correct, but should work for MPlayer
658 glAdjustAlignment(gl, stride);
659 gl->PixelStorei(GL_PACK_ROW_LENGTH, stride / glFmt2bpp(format, type));
660 gl->GetTexImage(target, 0, format, type, dataptr);
664 * \brief Setup ATI version of register combiners for YUV to RGB conversion.
665 * \param csp_params parameters used for colorspace conversion
666 * \param text if set use the GL_ATI_text_fragment_shader API as
667 * used on OS X.
669 static void glSetupYUVFragmentATI(GL *gl, struct mp_csp_params *csp_params,
670 int text)
672 GLint i;
673 float yuv2rgb[3][4];
675 gl->GetIntegerv(GL_MAX_TEXTURE_UNITS, &i);
676 if (i < 3)
677 mp_msg(MSGT_VO, MSGL_ERR,
678 "[gl] 3 texture units needed for YUV combiner (ATI) support (found %i)\n", i);
680 mp_get_yuv2rgb_coeffs(csp_params, yuv2rgb);
681 for (i = 0; i < 3; i++) {
682 int j;
683 yuv2rgb[i][3] -= -0.5 * (yuv2rgb[i][1] + yuv2rgb[i][2]);
684 for (j = 0; j < 4; j++) {
685 yuv2rgb[i][j] *= 0.125;
686 yuv2rgb[i][j] += 0.5;
687 if (yuv2rgb[i][j] > 1)
688 yuv2rgb[i][j] = 1;
689 if (yuv2rgb[i][j] < 0)
690 yuv2rgb[i][j] = 0;
693 if (text == 0) {
694 GLfloat c0[4] = { yuv2rgb[0][0], yuv2rgb[1][0], yuv2rgb[2][0] };
695 GLfloat c1[4] = { yuv2rgb[0][1], yuv2rgb[1][1], yuv2rgb[2][1] };
696 GLfloat c2[4] = { yuv2rgb[0][2], yuv2rgb[1][2], yuv2rgb[2][2] };
697 GLfloat c3[4] = { yuv2rgb[0][3], yuv2rgb[1][3], yuv2rgb[2][3] };
698 if (!gl->BeginFragmentShader || !gl->EndFragmentShader ||
699 !gl->SetFragmentShaderConstant || !gl->SampleMap ||
700 !gl->ColorFragmentOp2 || !gl->ColorFragmentOp3) {
701 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner (ATI) functions missing!\n");
702 return;
704 gl->GetIntegerv(GL_NUM_FRAGMENT_REGISTERS_ATI, &i);
705 if (i < 3)
706 mp_msg(MSGT_VO, MSGL_ERR,
707 "[gl] 3 registers needed for YUV combiner (ATI) support (found %i)\n", i);
708 gl->BeginFragmentShader();
709 gl->SetFragmentShaderConstant(GL_CON_0_ATI, c0);
710 gl->SetFragmentShaderConstant(GL_CON_1_ATI, c1);
711 gl->SetFragmentShaderConstant(GL_CON_2_ATI, c2);
712 gl->SetFragmentShaderConstant(GL_CON_3_ATI, c3);
713 gl->SampleMap(GL_REG_0_ATI, GL_TEXTURE0, GL_SWIZZLE_STR_ATI);
714 gl->SampleMap(GL_REG_1_ATI, GL_TEXTURE1, GL_SWIZZLE_STR_ATI);
715 gl->SampleMap(GL_REG_2_ATI, GL_TEXTURE2, GL_SWIZZLE_STR_ATI);
716 gl->ColorFragmentOp2(GL_MUL_ATI, GL_REG_1_ATI, GL_NONE, GL_NONE,
717 GL_REG_1_ATI, GL_NONE, GL_BIAS_BIT_ATI,
718 GL_CON_1_ATI, GL_NONE, GL_BIAS_BIT_ATI);
719 gl->ColorFragmentOp3(GL_MAD_ATI, GL_REG_2_ATI, GL_NONE, GL_NONE,
720 GL_REG_2_ATI, GL_NONE, GL_BIAS_BIT_ATI,
721 GL_CON_2_ATI, GL_NONE, GL_BIAS_BIT_ATI,
722 GL_REG_1_ATI, GL_NONE, GL_NONE);
723 gl->ColorFragmentOp3(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
724 GL_REG_0_ATI, GL_NONE, GL_NONE,
725 GL_CON_0_ATI, GL_NONE, GL_BIAS_BIT_ATI,
726 GL_REG_2_ATI, GL_NONE, GL_NONE);
727 gl->ColorFragmentOp2(GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, GL_8X_BIT_ATI,
728 GL_REG_0_ATI, GL_NONE, GL_NONE,
729 GL_CON_3_ATI, GL_NONE, GL_BIAS_BIT_ATI);
730 gl->EndFragmentShader();
731 } else {
732 static const char template[] =
733 "!!ATIfs1.0\n"
734 "StartConstants;\n"
735 " CONSTANT c0 = {%e, %e, %e};\n"
736 " CONSTANT c1 = {%e, %e, %e};\n"
737 " CONSTANT c2 = {%e, %e, %e};\n"
738 " CONSTANT c3 = {%e, %e, %e};\n"
739 "EndConstants;\n"
740 "StartOutputPass;\n"
741 " SampleMap r0, t0.str;\n"
742 " SampleMap r1, t1.str;\n"
743 " SampleMap r2, t2.str;\n"
744 " MUL r1.rgb, r1.bias, c1.bias;\n"
745 " MAD r2.rgb, r2.bias, c2.bias, r1;\n"
746 " MAD r0.rgb, r0, c0.bias, r2;\n"
747 " ADD r0.rgb.8x, r0, c3.bias;\n"
748 "EndPass;\n";
749 char buffer[512];
750 snprintf(buffer, sizeof(buffer), template,
751 yuv2rgb[0][0], yuv2rgb[1][0], yuv2rgb[2][0],
752 yuv2rgb[0][1], yuv2rgb[1][1], yuv2rgb[2][1],
753 yuv2rgb[0][2], yuv2rgb[1][2], yuv2rgb[2][2],
754 yuv2rgb[0][3], yuv2rgb[1][3], yuv2rgb[2][3]);
755 mp_msg(MSGT_VO, MSGL_DBG2, "[gl] generated fragment program:\n%s\n",
756 buffer);
757 loadGPUProgram(gl, GL_TEXT_FRAGMENT_SHADER_ATI, buffer);
761 // Replace all occurances of variables named "$"+name (e.g. $foo) in *text with
762 // replace, and return the result. *text must have been allocated with talloc.
763 static void replace_var_str(char **text, const char *name, const char *replace)
765 size_t namelen = strlen(name);
766 char *nextvar = *text;
767 void *parent = talloc_parent(*text);
768 for (;;) {
769 nextvar = strchr(nextvar, '$');
770 if (!nextvar)
771 break;
772 char *until = nextvar;
773 nextvar++;
774 if (strncmp(nextvar, name, namelen) != 0)
775 continue;
776 nextvar += namelen;
777 // try not to replace prefixes of other vars (e.g. $foo vs. $foo_bar)
778 char term = nextvar[0];
779 if (isalnum(term) || term == '_')
780 continue;
781 int prelength = until - *text;
782 int postlength = nextvar - *text;
783 char *n = talloc_asprintf(parent, "%.*s%s%s", prelength, *text, replace,
784 nextvar);
785 talloc_free(*text);
786 *text = n;
787 nextvar = *text + postlength;
791 static void replace_var_float(char **text, const char *name, float replace)
793 char *s = talloc_asprintf(NULL, "%e", replace);
794 replace_var_str(text, name, s);
795 talloc_free(s);
798 static void replace_var_char(char **text, const char *name, char replace)
800 char s[2] = { replace, '\0' };
801 replace_var_str(text, name, s);
804 // Append template to *text. Possibly initialize *text if it's NULL.
805 static void append_template(char **text, const char* template)
807 if (!text)
808 *text = talloc_strdup(NULL, template);
809 else
810 *text = talloc_strdup_append(*text, template);
814 * \brief helper function for gen_spline_lookup_tex
815 * \param x subpixel-position ((0,1) range) to calculate weights for
816 * \param dst where to store transformed weights, must provide space for 4 GLfloats
818 * calculates the weights and stores them after appropriate transformation
819 * for the scaler fragment program.
821 static void store_weights(float x, GLfloat *dst)
823 float w0 = (((-1 * x + 3) * x - 3) * x + 1) / 6;
824 float w1 = (((3 * x - 6) * x + 0) * x + 4) / 6;
825 float w2 = (((-3 * x + 3) * x + 3) * x + 1) / 6;
826 float w3 = (((1 * x + 0) * x + 0) * x + 0) / 6;
827 *dst++ = 1 + x - w1 / (w0 + w1);
828 *dst++ = 1 - x + w3 / (w2 + w3);
829 *dst++ = w0 + w1;
830 *dst++ = 0;
833 //! to avoid artefacts this should be rather large
834 #define LOOKUP_BSPLINE_RES (2 * 1024)
836 * \brief creates the 1D lookup texture needed for fast higher-order filtering
837 * \param unit texture unit to attach texture to
839 static void gen_spline_lookup_tex(GL *gl, GLenum unit)
841 GLfloat *tex = calloc(4 * LOOKUP_BSPLINE_RES, sizeof(*tex));
842 GLfloat *tp = tex;
843 int i;
844 for (i = 0; i < LOOKUP_BSPLINE_RES; i++) {
845 float x = (float)(i + 0.5) / LOOKUP_BSPLINE_RES;
846 store_weights(x, tp);
847 tp += 4;
849 store_weights(0, tex);
850 store_weights(1, &tex[4 * (LOOKUP_BSPLINE_RES - 1)]);
851 gl->ActiveTexture(unit);
852 gl->TexImage1D(GL_TEXTURE_1D, 0, GL_RGBA16, LOOKUP_BSPLINE_RES, 0, GL_RGBA,
853 GL_FLOAT, tex);
854 gl->TexParameterf(GL_TEXTURE_1D, GL_TEXTURE_PRIORITY, 1.0);
855 gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
856 gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
857 gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
858 gl->ActiveTexture(GL_TEXTURE0);
859 free(tex);
862 #define SAMPLE(dest, coord, texture) \
863 "TEX textemp, " coord ", " texture ", $tex_type;\n" \
864 "MOV " dest ", textemp.r;\n"
866 static const char *bilin_filt_template =
867 SAMPLE("yuv.$out_comp","fragment.texcoord[$in_tex]","texture[$in_tex]");
869 #define BICUB_FILT_MAIN \
870 /* first y-interpolation */ \
871 "ADD coord, fragment.texcoord[$in_tex].xyxy, cdelta.xyxw;\n" \
872 "ADD coord2, fragment.texcoord[$in_tex].xyxy, cdelta.zyzw;\n" \
873 SAMPLE("a.r","coord.xyxy","texture[$in_tex]") \
874 SAMPLE("a.g","coord.zwzw","texture[$in_tex]") \
875 /* second y-interpolation */ \
876 SAMPLE("b.r","coord2.xyxy","texture[$in_tex]") \
877 SAMPLE("b.g","coord2.zwzw","texture[$in_tex]") \
878 "LRP a.b, parmy.b, a.rrrr, a.gggg;\n" \
879 "LRP a.a, parmy.b, b.rrrr, b.gggg;\n" \
880 /* x-interpolation */ \
881 "LRP yuv.$out_comp, parmx.b, a.bbbb, a.aaaa;\n"
883 static const char *bicub_filt_template_2D =
884 "MAD coord.xy, fragment.texcoord[$in_tex], {$texw, $texh}, {0.5, 0.5};\n"
885 "TEX parmx, coord.x, texture[$texs], 1D;\n"
886 "MUL cdelta.xz, parmx.rrgg, {-$ptw, 0, $ptw, 0};\n"
887 "TEX parmy, coord.y, texture[$texs], 1D;\n"
888 "MUL cdelta.yw, parmy.rrgg, {0, -$pth, 0, $pth};\n"
889 BICUB_FILT_MAIN;
891 static const char *bicub_filt_template_RECT =
892 "ADD coord, fragment.texcoord[$in_tex], {0.5, 0.5};\n"
893 "TEX parmx, coord.x, texture[$texs], 1D;\n"
894 "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};\n"
895 "TEX parmy, coord.y, texture[$texs], 1D;\n"
896 "MUL cdelta.yw, parmy.rrgg, {0, -1, 0, 1};\n"
897 BICUB_FILT_MAIN;
899 #define CALCWEIGHTS(t, s) \
900 "MAD "t ", {-0.5, 0.1666, 0.3333, -0.3333}, "s ", {1, 0, -0.5, 0.5};\n" \
901 "MAD "t ", "t ", "s ", {0, 0, -0.5, 0.5};\n" \
902 "MAD "t ", "t ", "s ", {-0.6666, 0, 0.8333, 0.1666};\n" \
903 "RCP a.x, "t ".z;\n" \
904 "RCP a.y, "t ".w;\n" \
905 "MAD "t ".xy, "t ".xyxy, a.xyxy, {1, 1, 0, 0};\n" \
906 "ADD "t ".x, "t ".xxxx, "s ";\n" \
907 "SUB "t ".y, "t ".yyyy, "s ";\n"
909 static const char *bicub_notex_filt_template_2D =
910 "MAD coord.xy, fragment.texcoord[$in_tex], {$texw, $texh}, {0.5, 0.5};\n"
911 "FRC coord.xy, coord.xyxy;\n"
912 CALCWEIGHTS("parmx", "coord.xxxx")
913 "MUL cdelta.xz, parmx.rrgg, {-$ptw, 0, $ptw, 0};\n"
914 CALCWEIGHTS("parmy", "coord.yyyy")
915 "MUL cdelta.yw, parmy.rrgg, {0, -$pth, 0, $pth};\n"
916 BICUB_FILT_MAIN;
918 static const char *bicub_notex_filt_template_RECT =
919 "ADD coord, fragment.texcoord[$in_tex], {0.5, 0.5};\n"
920 "FRC coord.xy, coord.xyxy;\n"
921 CALCWEIGHTS("parmx", "coord.xxxx")
922 "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};\n"
923 CALCWEIGHTS("parmy", "coord.yyyy")
924 "MUL cdelta.yw, parmy.rrgg, {0, -1, 0, 1};\n"
925 BICUB_FILT_MAIN;
927 #define BICUB_X_FILT_MAIN \
928 "ADD coord.xy, fragment.texcoord[$in_tex].xyxy, cdelta.xyxy;\n" \
929 "ADD coord2.xy, fragment.texcoord[$in_tex].xyxy, cdelta.zyzy;\n" \
930 SAMPLE("a.r","coord","texture[$in_tex]") \
931 SAMPLE("b.r","coord2","texture[$in_tex]") \
932 /* x-interpolation */ \
933 "LRP yuv.$out_comp, parmx.b, a.rrrr, b.rrrr;\n"
935 static const char *bicub_x_filt_template_2D =
936 "MAD coord.x, fragment.texcoord[$in_tex], {$texw}, {0.5};\n"
937 "TEX parmx, coord, texture[$texs], 1D;\n"
938 "MUL cdelta.xyz, parmx.rrgg, {-$ptw, 0, $ptw};\n"
939 BICUB_X_FILT_MAIN;
941 static const char *bicub_x_filt_template_RECT =
942 "ADD coord.x, fragment.texcoord[$in_tex], {0.5};\n"
943 "TEX parmx, coord, texture[$texs], 1D;\n"
944 "MUL cdelta.xyz, parmx.rrgg, {-1, 0, 1};\n"
945 BICUB_X_FILT_MAIN;
947 static const char *unsharp_filt_template =
948 "PARAM dcoord$out_comp = {$ptw_05, $pth_05, $ptw_05, -$pth_05};\n"
949 "ADD coord, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n"
950 "SUB coord2, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n"
951 SAMPLE("a.r","fragment.texcoord[$in_tex]","texture[$in_tex]")
952 SAMPLE("b.r","coord.xyxy","texture[$in_tex]")
953 SAMPLE("b.g","coord.zwzw","texture[$in_tex]")
954 "ADD b.r, b.r, b.g;\n"
955 SAMPLE("b.b","coord2.xyxy","texture[$in_tex]")
956 SAMPLE("b.g","coord2.zwzw","texture[$in_tex]")
957 "DP3 b, b, {0.25, 0.25, 0.25};\n"
958 "SUB b.r, a.r, b.r;\n"
959 "MAD textemp.r, b.r, {$strength}, a.r;\n"
960 "MOV yuv.$out_comp, textemp.r;\n";
962 static const char *unsharp_filt_template2 =
963 "PARAM dcoord$out_comp = {$ptw_12, $pth_12, $ptw_12, -$pth_12};\n"
964 "PARAM dcoord2$out_comp = {$ptw_15, 0, 0, $pth_15};\n"
965 "ADD coord, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n"
966 "SUB coord2, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n"
967 SAMPLE("a.r","fragment.texcoord[$in_tex]","texture[$in_tex]")
968 SAMPLE("b.r","coord.xyxy","texture[$in_tex]")
969 SAMPLE("b.g","coord.zwzw","texture[$in_tex]")
970 "ADD b.r, b.r, b.g;\n"
971 SAMPLE("b.b","coord2.xyxy","texture[$in_tex]")
972 SAMPLE("b.g","coord2.zwzw","texture[$in_tex]")
973 "ADD b.r, b.r, b.b;\n"
974 "ADD b.a, b.r, b.g;\n"
975 "ADD coord, fragment.texcoord[$in_tex].xyxy, dcoord2$out_comp;\n"
976 "SUB coord2, fragment.texcoord[$in_tex].xyxy, dcoord2$out_comp;\n"
977 SAMPLE("b.r","coord.xyxy","texture[$in_tex]")
978 SAMPLE("b.g","coord.zwzw","texture[$in_tex]")
979 "ADD b.r, b.r, b.g;\n"
980 SAMPLE("b.b","coord2.xyxy","texture[$in_tex]")
981 SAMPLE("b.g","coord2.zwzw","texture[$in_tex]")
982 "DP4 b.r, b, {-0.1171875, -0.1171875, -0.1171875, -0.09765625};\n"
983 "MAD b.r, a.r, {0.859375}, b.r;\n"
984 "MAD textemp.r, b.r, {$strength}, a.r;\n"
985 "MOV yuv.$out_comp, textemp.r;\n";
987 static const char *yuv_prog_template =
988 "PARAM ycoef = {$cm11, $cm21, $cm31};\n"
989 "PARAM ucoef = {$cm12, $cm22, $cm32};\n"
990 "PARAM vcoef = {$cm13, $cm23, $cm33};\n"
991 "PARAM offsets = {$cm14, $cm24, $cm34};\n"
992 "TEMP res;\n"
993 "MAD res.rgb, yuv.rrrr, ycoef, offsets;\n"
994 "MAD res.rgb, yuv.gggg, ucoef, res;\n"
995 "MAD result.color.rgb, yuv.bbbb, vcoef, res;\n"
996 "END";
998 static const char *yuv_pow_prog_template =
999 "PARAM ycoef = {$cm11, $cm21, $cm31};\n"
1000 "PARAM ucoef = {$cm12, $cm22, $cm32};\n"
1001 "PARAM vcoef = {$cm13, $cm23, $cm33};\n"
1002 "PARAM offsets = {$cm14, $cm24, $cm34};\n"
1003 "PARAM gamma = {$gamma_r, $gamma_g, $gamma_b};\n"
1004 "TEMP res;\n"
1005 "MAD res.rgb, yuv.rrrr, ycoef, offsets;\n"
1006 "MAD res.rgb, yuv.gggg, ucoef, res;\n"
1007 "MAD_SAT res.rgb, yuv.bbbb, vcoef, res;\n"
1008 "POW result.color.r, res.r, gamma.r;\n"
1009 "POW result.color.g, res.g, gamma.g;\n"
1010 "POW result.color.b, res.b, gamma.b;\n"
1011 "END";
1013 static const char *yuv_lookup_prog_template =
1014 "PARAM ycoef = {$cm11, $cm21, $cm31, 0};\n"
1015 "PARAM ucoef = {$cm12, $cm22, $cm32, 0};\n"
1016 "PARAM vcoef = {$cm13, $cm23, $cm33, 0};\n"
1017 "PARAM offsets = {$cm14, $cm24, $cm34, 0.125};\n"
1018 "TEMP res;\n"
1019 "MAD res, yuv.rrrr, ycoef, offsets;\n"
1020 "MAD res.rgb, yuv.gggg, ucoef, res;\n"
1021 "MAD res.rgb, yuv.bbbb, vcoef, res;\n"
1022 "TEX result.color.r, res.raaa, texture[$conv_tex0], 2D;\n"
1023 "ADD res.a, res.a, 0.25;\n"
1024 "TEX result.color.g, res.gaaa, texture[$conv_tex0], 2D;\n"
1025 "ADD res.a, res.a, 0.25;\n"
1026 "TEX result.color.b, res.baaa, texture[$conv_tex0], 2D;\n"
1027 "END";
1029 static const char *yuv_lookup3d_prog_template =
1030 "TEX result.color, yuv, texture[$conv_tex0], 3D;\n"
1031 "END";
1034 * \brief creates and initializes helper textures needed for scaling texture read
1035 * \param scaler scaler type to create texture for
1036 * \param texu contains next free texture unit number
1037 * \param texs texture unit ids for the scaler are stored in this array
1039 static void create_scaler_textures(GL *gl, int scaler, int *texu, char *texs)
1041 switch (scaler) {
1042 case YUV_SCALER_BILIN:
1043 case YUV_SCALER_BICUB_NOTEX:
1044 case YUV_SCALER_UNSHARP:
1045 case YUV_SCALER_UNSHARP2:
1046 break;
1047 case YUV_SCALER_BICUB:
1048 case YUV_SCALER_BICUB_X:
1049 texs[0] = (*texu)++;
1050 gen_spline_lookup_tex(gl, GL_TEXTURE0 + texs[0]);
1051 texs[0] += '0';
1052 break;
1053 default:
1054 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown scaler type %i\n", scaler);
1058 //! resolution of texture for gamma lookup table
1059 #define LOOKUP_RES 512
1060 //! resolution for 3D yuv->rgb conversion lookup table
1061 #define LOOKUP_3DRES 32
1063 * \brief creates and initializes helper textures needed for yuv conversion
1064 * \param params struct containing parameters like brightness, gamma, ...
1065 * \param texu contains next free texture unit number
1066 * \param texs texture unit ids for the conversion are stored in this array
1068 static void create_conv_textures(GL *gl, gl_conversion_params_t *params,
1069 int *texu, char *texs)
1071 unsigned char *lookup_data = NULL;
1072 int conv = YUV_CONVERSION(params->type);
1073 switch (conv) {
1074 case YUV_CONVERSION_FRAGMENT:
1075 case YUV_CONVERSION_FRAGMENT_POW:
1076 break;
1077 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1078 texs[0] = (*texu)++;
1079 gl->ActiveTexture(GL_TEXTURE0 + texs[0]);
1080 lookup_data = malloc(4 * LOOKUP_RES);
1081 mp_gen_gamma_map(lookup_data, LOOKUP_RES, params->csp_params.rgamma);
1082 mp_gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES,
1083 params->csp_params.ggamma);
1084 mp_gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES,
1085 params->csp_params.bgamma);
1086 glCreateClearTex(gl, GL_TEXTURE_2D, GL_LUMINANCE8, GL_LUMINANCE,
1087 GL_UNSIGNED_BYTE, GL_LINEAR, LOOKUP_RES, 4, 0);
1088 glUploadTex(gl, GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE,
1089 lookup_data, LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0);
1090 gl->ActiveTexture(GL_TEXTURE0);
1091 texs[0] += '0';
1092 break;
1093 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1095 int sz = LOOKUP_3DRES + 2; // texture size including borders
1096 if (!gl->TexImage3D) {
1097 mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing 3D texture function!\n");
1098 break;
1100 texs[0] = (*texu)++;
1101 gl->ActiveTexture(GL_TEXTURE0 + texs[0]);
1102 lookup_data = malloc(3 * sz * sz * sz);
1103 mp_gen_yuv2rgb_map(&params->csp_params, lookup_data, LOOKUP_3DRES);
1104 glAdjustAlignment(gl, sz);
1105 gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1106 gl->TexImage3D(GL_TEXTURE_3D, 0, 3, sz, sz, sz, 1,
1107 GL_RGB, GL_UNSIGNED_BYTE, lookup_data);
1108 gl->TexParameterf(GL_TEXTURE_3D, GL_TEXTURE_PRIORITY, 1.0);
1109 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1110 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1111 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1112 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1113 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
1114 gl->ActiveTexture(GL_TEXTURE0);
1115 texs[0] += '0';
1117 break;
1118 default:
1119 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", conv);
1121 free(lookup_data);
1125 * \brief adds a scaling texture read at the current fragment program position
1126 * \param scaler type of scaler to insert
1127 * \param prog pointer to fragment program so far
1128 * \param texs array containing the texture unit identifiers for this scaler
1129 * \param in_tex texture unit the scaler should read from
1130 * \param out_comp component of the yuv variable the scaler stores the result in
1131 * \param rect if rectangular (pixel) adressing should be used for in_tex
1132 * \param texw width of the in_tex texture
1133 * \param texh height of the in_tex texture
1134 * \param strength strength of filter effect if the scaler does some kind of filtering
1136 static void add_scaler(int scaler, char **prog, char *texs,
1137 char in_tex, char out_comp, int rect, int texw, int texh,
1138 double strength)
1140 const char *ttype = rect ? "RECT" : "2D";
1141 const float ptw = rect ? 1.0 : 1.0 / texw;
1142 const float pth = rect ? 1.0 : 1.0 / texh;
1143 switch (scaler) {
1144 case YUV_SCALER_BILIN:
1145 append_template(prog, bilin_filt_template);
1146 break;
1147 case YUV_SCALER_BICUB:
1148 if (rect)
1149 append_template(prog, bicub_filt_template_RECT);
1150 else
1151 append_template(prog, bicub_filt_template_2D);
1152 break;
1153 case YUV_SCALER_BICUB_X:
1154 if (rect)
1155 append_template(prog, bicub_x_filt_template_RECT);
1156 else
1157 append_template(prog, bicub_x_filt_template_2D);
1158 break;
1159 case YUV_SCALER_BICUB_NOTEX:
1160 if (rect)
1161 append_template(prog, bicub_notex_filt_template_RECT);
1162 else
1163 append_template(prog, bicub_notex_filt_template_2D);
1164 break;
1165 case YUV_SCALER_UNSHARP:
1166 append_template(prog, unsharp_filt_template);
1167 break;
1168 case YUV_SCALER_UNSHARP2:
1169 append_template(prog, unsharp_filt_template2);
1170 break;
1173 replace_var_char(prog, "texs", texs[0]);
1174 replace_var_char(prog, "in_tex", in_tex);
1175 replace_var_char(prog, "out_comp", out_comp);
1176 replace_var_str(prog, "tex_type", ttype);
1177 replace_var_float(prog, "texw", texw);
1178 replace_var_float(prog, "texh", texh);
1179 replace_var_float(prog, "ptw", ptw);
1180 replace_var_float(prog, "pth", pth);
1182 // this is silly, not sure if that couldn't be in the shader source instead
1183 replace_var_float(prog, "ptw_05", ptw * 0.5);
1184 replace_var_float(prog, "pth_05", pth * 0.5);
1185 replace_var_float(prog, "ptw_15", ptw * 1.5);
1186 replace_var_float(prog, "pth_15", pth * 1.5);
1187 replace_var_float(prog, "ptw_12", ptw * 1.2);
1188 replace_var_float(prog, "pth_12", pth * 1.2);
1190 replace_var_float(prog, "strength", strength);
1193 static const struct {
1194 const char *name;
1195 GLenum cur;
1196 GLenum max;
1197 } progstats[] = {
1198 {"instructions", 0x88A0, 0x88A1},
1199 {"native instructions", 0x88A2, 0x88A3},
1200 {"temporaries", 0x88A4, 0x88A5},
1201 {"native temporaries", 0x88A6, 0x88A7},
1202 {"parameters", 0x88A8, 0x88A9},
1203 {"native parameters", 0x88AA, 0x88AB},
1204 {"attribs", 0x88AC, 0x88AD},
1205 {"native attribs", 0x88AE, 0x88AF},
1206 {"ALU instructions", 0x8805, 0x880B},
1207 {"TEX instructions", 0x8806, 0x880C},
1208 {"TEX indirections", 0x8807, 0x880D},
1209 {"native ALU instructions", 0x8808, 0x880E},
1210 {"native TEX instructions", 0x8809, 0x880F},
1211 {"native TEX indirections", 0x880A, 0x8810},
1212 {NULL, 0, 0}
1216 * \brief load the specified GPU Program
1217 * \param target program target to load into, only GL_FRAGMENT_PROGRAM is tested
1218 * \param prog program string
1219 * \return 1 on success, 0 otherwise
1221 int loadGPUProgram(GL *gl, GLenum target, char *prog)
1223 int i;
1224 GLint cur = 0, max = 0, err = 0;
1225 if (!gl->ProgramString) {
1226 mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing GPU program function\n");
1227 return 0;
1229 gl->ProgramString(target, GL_PROGRAM_FORMAT_ASCII, strlen(prog), prog);
1230 gl->GetIntegerv(GL_PROGRAM_ERROR_POSITION, &err);
1231 if (err != -1) {
1232 mp_msg(MSGT_VO, MSGL_ERR,
1233 "[gl] Error compiling fragment program, make sure your card supports\n"
1234 "[gl] GL_ARB_fragment_program (use glxinfo to check).\n"
1235 "[gl] Error message:\n %s at %.10s\n",
1236 gl->GetString(GL_PROGRAM_ERROR_STRING), &prog[err]);
1237 return 0;
1239 if (!gl->GetProgramiv || !mp_msg_test(MSGT_VO, MSGL_DBG2))
1240 return 1;
1241 mp_msg(MSGT_VO, MSGL_V, "[gl] Program statistics:\n");
1242 for (i = 0; progstats[i].name; i++) {
1243 gl->GetProgramiv(target, progstats[i].cur, &cur);
1244 gl->GetProgramiv(target, progstats[i].max, &max);
1245 mp_msg(MSGT_VO, MSGL_V, "[gl] %s: %i/%i\n", progstats[i].name, cur,
1246 max);
1248 return 1;
1251 #define MAX_PROGSZ (1024 * 1024)
1254 * \brief setup a fragment program that will do YUV->RGB conversion
1255 * \param parms struct containing parameters like conversion and scaler type,
1256 * brightness, ...
1258 static void glSetupYUVFragprog(GL *gl, gl_conversion_params_t *params)
1260 int type = params->type;
1261 int texw = params->texw;
1262 int texh = params->texh;
1263 int rect = params->target == GL_TEXTURE_RECTANGLE;
1264 static const char prog_hdr[] =
1265 "!!ARBfp1.0\n"
1266 "OPTION ARB_precision_hint_fastest;\n"
1267 // all scaler variables must go here so they aren't defined
1268 // multiple times when the same scaler is used more than once
1269 "TEMP coord, coord2, cdelta, parmx, parmy, a, b, yuv, textemp;\n";
1270 char *yuv_prog = NULL;
1271 char **prog = &yuv_prog;
1272 int cur_texu = 3;
1273 char lum_scale_texs[1];
1274 char chrom_scale_texs[1];
1275 char conv_texs[1];
1276 GLint i;
1277 // this is the conversion matrix, with y, u, v factors
1278 // for red, green, blue and the constant offsets
1279 float yuv2rgb[3][4];
1280 create_conv_textures(gl, params, &cur_texu, conv_texs);
1281 create_scaler_textures(gl, YUV_LUM_SCALER(type), &cur_texu, lum_scale_texs);
1282 if (YUV_CHROM_SCALER(type) == YUV_LUM_SCALER(type))
1283 memcpy(chrom_scale_texs, lum_scale_texs, sizeof(chrom_scale_texs));
1284 else
1285 create_scaler_textures(gl, YUV_CHROM_SCALER(type), &cur_texu,
1286 chrom_scale_texs);
1287 gl->GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &i);
1288 if (i < cur_texu)
1289 mp_msg(MSGT_VO, MSGL_ERR,
1290 "[gl] %i texture units needed for this type of YUV fragment support (found %i)\n",
1291 cur_texu, i);
1292 if (!gl->ProgramString) {
1293 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] ProgramString function missing!\n");
1294 return;
1296 append_template(prog, prog_hdr);
1297 add_scaler(YUV_LUM_SCALER(type), prog, lum_scale_texs,
1298 '0', 'r', rect, texw, texh, params->filter_strength);
1299 add_scaler(YUV_CHROM_SCALER(type), prog,
1300 chrom_scale_texs, '1', 'g', rect, params->chrom_texw,
1301 params->chrom_texh, params->filter_strength);
1302 add_scaler(YUV_CHROM_SCALER(type), prog,
1303 chrom_scale_texs, '2', 'b', rect, params->chrom_texw,
1304 params->chrom_texh, params->filter_strength);
1305 mp_get_yuv2rgb_coeffs(&params->csp_params, yuv2rgb);
1306 switch (YUV_CONVERSION(type)) {
1307 case YUV_CONVERSION_FRAGMENT:
1308 append_template(prog, yuv_prog_template);
1309 break;
1310 case YUV_CONVERSION_FRAGMENT_POW:
1311 append_template(prog, yuv_pow_prog_template);
1312 break;
1313 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1314 append_template(prog, yuv_lookup_prog_template);
1315 break;
1316 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1317 append_template(prog, yuv_lookup3d_prog_template);
1318 break;
1319 default:
1320 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n",
1321 YUV_CONVERSION(type));
1322 break;
1324 for (int r = 0; r < 3; r++) {
1325 for (int c = 0; c < 4; c++) {
1326 // "cmRC"
1327 char var[] = { 'c', 'm', '1' + r, '1' + c, '\0' };
1328 replace_var_float(prog, var, yuv2rgb[r][c]);
1331 replace_var_float(prog, "gamma_r", (float)1.0 / params->csp_params.rgamma);
1332 replace_var_float(prog, "gamma_g", (float)1.0 / params->csp_params.ggamma);
1333 replace_var_float(prog, "gamma_b", (float)1.0 / params->csp_params.bgamma);
1334 replace_var_char(prog, "conv_tex0", conv_texs[0]);
1335 mp_msg(MSGT_VO, MSGL_DBG2, "[gl] generated fragment program:\n%s\n",
1336 yuv_prog);
1337 loadGPUProgram(gl, GL_FRAGMENT_PROGRAM, yuv_prog);
1338 talloc_free(yuv_prog);
1342 * \brief detect the best YUV->RGB conversion method available
1344 int glAutodetectYUVConversion(GL *gl)
1346 const char *extensions = gl->GetString(GL_EXTENSIONS);
1347 if (!extensions || !gl->MultiTexCoord2f)
1348 return YUV_CONVERSION_NONE;
1349 if (strstr(extensions, "GL_ARB_fragment_program"))
1350 return YUV_CONVERSION_FRAGMENT;
1351 if (strstr(extensions, "GL_ATI_text_fragment_shader"))
1352 return YUV_CONVERSION_TEXT_FRAGMENT;
1353 if (strstr(extensions, "GL_ATI_fragment_shader"))
1354 return YUV_CONVERSION_COMBINERS_ATI;
1355 return YUV_CONVERSION_NONE;
1359 * \brief setup YUV->RGB conversion
1360 * \param parms struct containing parameters like conversion and scaler type,
1361 * brightness, ...
1362 * \ingroup glconversion
1364 void glSetupYUVConversion(GL *gl, gl_conversion_params_t *params)
1366 if (params->chrom_texw == 0)
1367 params->chrom_texw = 1;
1368 if (params->chrom_texh == 0)
1369 params->chrom_texh = 1;
1370 switch (YUV_CONVERSION(params->type)) {
1371 case YUV_CONVERSION_COMBINERS_ATI:
1372 glSetupYUVFragmentATI(gl, &params->csp_params, 0);
1373 break;
1374 case YUV_CONVERSION_TEXT_FRAGMENT:
1375 glSetupYUVFragmentATI(gl, &params->csp_params, 1);
1376 break;
1377 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1378 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1379 case YUV_CONVERSION_FRAGMENT:
1380 case YUV_CONVERSION_FRAGMENT_POW:
1381 glSetupYUVFragprog(gl, params);
1382 break;
1383 case YUV_CONVERSION_NONE:
1384 break;
1385 default:
1386 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n",
1387 YUV_CONVERSION(params->type));
1392 * \brief enable the specified YUV conversion
1393 * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D)
1394 * \param type type of YUV conversion
1395 * \ingroup glconversion
1397 void glEnableYUVConversion(GL *gl, GLenum target, int type)
1399 switch (YUV_CONVERSION(type)) {
1400 case YUV_CONVERSION_COMBINERS_ATI:
1401 gl->ActiveTexture(GL_TEXTURE1);
1402 gl->Enable(target);
1403 gl->ActiveTexture(GL_TEXTURE2);
1404 gl->Enable(target);
1405 gl->ActiveTexture(GL_TEXTURE0);
1406 gl->Enable(GL_FRAGMENT_SHADER_ATI);
1407 break;
1408 case YUV_CONVERSION_TEXT_FRAGMENT:
1409 gl->ActiveTexture(GL_TEXTURE1);
1410 gl->Enable(target);
1411 gl->ActiveTexture(GL_TEXTURE2);
1412 gl->Enable(target);
1413 gl->ActiveTexture(GL_TEXTURE0);
1414 gl->Enable(GL_TEXT_FRAGMENT_SHADER_ATI);
1415 break;
1416 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1417 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1418 case YUV_CONVERSION_FRAGMENT_POW:
1419 case YUV_CONVERSION_FRAGMENT:
1420 case YUV_CONVERSION_NONE:
1421 gl->Enable(GL_FRAGMENT_PROGRAM);
1422 break;
1427 * \brief disable the specified YUV conversion
1428 * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D)
1429 * \param type type of YUV conversion
1430 * \ingroup glconversion
1432 void glDisableYUVConversion(GL *gl, GLenum target, int type)
1434 switch (YUV_CONVERSION(type)) {
1435 case YUV_CONVERSION_COMBINERS_ATI:
1436 gl->ActiveTexture(GL_TEXTURE1);
1437 gl->Disable(target);
1438 gl->ActiveTexture(GL_TEXTURE2);
1439 gl->Disable(target);
1440 gl->ActiveTexture(GL_TEXTURE0);
1441 gl->Disable(GL_FRAGMENT_SHADER_ATI);
1442 break;
1443 case YUV_CONVERSION_TEXT_FRAGMENT:
1444 gl->Disable(GL_TEXT_FRAGMENT_SHADER_ATI);
1445 // HACK: at least the Mac OS X 10.5 PPC Radeon drivers are broken and
1446 // without this disable the texture units while the program is still
1447 // running (10.4 PPC seems to work without this though).
1448 gl->Flush();
1449 gl->ActiveTexture(GL_TEXTURE1);
1450 gl->Disable(target);
1451 gl->ActiveTexture(GL_TEXTURE2);
1452 gl->Disable(target);
1453 gl->ActiveTexture(GL_TEXTURE0);
1454 break;
1455 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1456 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1457 case YUV_CONVERSION_FRAGMENT_POW:
1458 case YUV_CONVERSION_FRAGMENT:
1459 case YUV_CONVERSION_NONE:
1460 gl->Disable(GL_FRAGMENT_PROGRAM);
1461 break;
1465 void glEnable3DLeft(GL *gl, int type)
1467 GLint buffer;
1468 switch (type) {
1469 case GL_3D_RED_CYAN:
1470 gl->ColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
1471 break;
1472 case GL_3D_GREEN_MAGENTA:
1473 gl->ColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
1474 break;
1475 case GL_3D_QUADBUFFER:
1476 gl->GetIntegerv(GL_DRAW_BUFFER, &buffer);
1477 switch (buffer) {
1478 case GL_FRONT:
1479 case GL_FRONT_LEFT:
1480 case GL_FRONT_RIGHT:
1481 buffer = GL_FRONT_LEFT;
1482 break;
1483 case GL_BACK:
1484 case GL_BACK_LEFT:
1485 case GL_BACK_RIGHT:
1486 buffer = GL_BACK_LEFT;
1487 break;
1489 gl->DrawBuffer(buffer);
1490 break;
1494 void glEnable3DRight(GL *gl, int type)
1496 GLint buffer;
1497 switch (type) {
1498 case GL_3D_RED_CYAN:
1499 gl->ColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_FALSE);
1500 break;
1501 case GL_3D_GREEN_MAGENTA:
1502 gl->ColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE);
1503 break;
1504 case GL_3D_QUADBUFFER:
1505 gl->GetIntegerv(GL_DRAW_BUFFER, &buffer);
1506 switch (buffer) {
1507 case GL_FRONT:
1508 case GL_FRONT_LEFT:
1509 case GL_FRONT_RIGHT:
1510 buffer = GL_FRONT_RIGHT;
1511 break;
1512 case GL_BACK:
1513 case GL_BACK_LEFT:
1514 case GL_BACK_RIGHT:
1515 buffer = GL_BACK_RIGHT;
1516 break;
1518 gl->DrawBuffer(buffer);
1519 break;
1523 void glDisable3D(GL *gl, int type)
1525 GLint buffer;
1526 switch (type) {
1527 case GL_3D_RED_CYAN:
1528 case GL_3D_GREEN_MAGENTA:
1529 gl->ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1530 break;
1531 case GL_3D_QUADBUFFER:
1532 gl->DrawBuffer(vo_doublebuffering ? GL_BACK : GL_FRONT);
1533 gl->GetIntegerv(GL_DRAW_BUFFER, &buffer);
1534 switch (buffer) {
1535 case GL_FRONT:
1536 case GL_FRONT_LEFT:
1537 case GL_FRONT_RIGHT:
1538 buffer = GL_FRONT;
1539 break;
1540 case GL_BACK:
1541 case GL_BACK_LEFT:
1542 case GL_BACK_RIGHT:
1543 buffer = GL_BACK;
1544 break;
1546 gl->DrawBuffer(buffer);
1547 break;
1552 * \brief draw a texture part at given 2D coordinates
1553 * \param x screen top coordinate
1554 * \param y screen left coordinate
1555 * \param w screen width coordinate
1556 * \param h screen height coordinate
1557 * \param tx texture top coordinate in pixels
1558 * \param ty texture left coordinate in pixels
1559 * \param tw texture part width in pixels
1560 * \param th texture part height in pixels
1561 * \param sx width of texture in pixels
1562 * \param sy height of texture in pixels
1563 * \param rect_tex whether this texture uses texture_rectangle extension
1564 * \param is_yv12 if != 0, also draw the textures from units 1 and 2,
1565 * bits 8 - 15 and 16 - 23 specify the x and y scaling of those textures
1566 * \param flip flip the texture upside down
1567 * \ingroup gltexture
1569 void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h,
1570 GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th,
1571 int sx, int sy, int rect_tex, int is_yv12, int flip)
1573 int chroma_x_shift = (is_yv12 >> 8) & 31;
1574 int chroma_y_shift = (is_yv12 >> 16) & 31;
1575 GLfloat xscale = 1 << chroma_x_shift;
1576 GLfloat yscale = 1 << chroma_y_shift;
1577 GLfloat tx2 = tx / xscale, ty2 = ty / yscale, tw2 = tw / xscale, th2 = th / yscale;
1578 if (!rect_tex) {
1579 tx /= sx;
1580 ty /= sy;
1581 tw /= sx;
1582 th /= sy;
1583 tx2 = tx, ty2 = ty, tw2 = tw, th2 = th;
1585 if (flip) {
1586 y += h;
1587 h = -h;
1589 gl->Begin(GL_QUADS);
1590 gl->TexCoord2f(tx, ty);
1591 if (is_yv12) {
1592 gl->MultiTexCoord2f(GL_TEXTURE1, tx2, ty2);
1593 gl->MultiTexCoord2f(GL_TEXTURE2, tx2, ty2);
1595 gl->Vertex2f(x, y);
1596 gl->TexCoord2f(tx, ty + th);
1597 if (is_yv12) {
1598 gl->MultiTexCoord2f(GL_TEXTURE1, tx2, ty2 + th2);
1599 gl->MultiTexCoord2f(GL_TEXTURE2, tx2, ty2 + th2);
1601 gl->Vertex2f(x, y + h);
1602 gl->TexCoord2f(tx + tw, ty + th);
1603 if (is_yv12) {
1604 gl->MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2 + th2);
1605 gl->MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2 + th2);
1607 gl->Vertex2f(x + w, y + h);
1608 gl->TexCoord2f(tx + tw, ty);
1609 if (is_yv12) {
1610 gl->MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2);
1611 gl->MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2);
1613 gl->Vertex2f(x + w, y);
1614 gl->End();
1617 #ifdef CONFIG_GL_COCOA
1618 #include "cocoa_common.h"
1619 static int create_window_cocoa(struct MPGLContext *ctx, uint32_t d_width,
1620 uint32_t d_height, uint32_t flags)
1622 if (vo_cocoa_create_window(ctx->vo, d_width, d_height, flags) == 0) {
1623 return SET_WINDOW_OK;
1624 } else {
1625 return SET_WINDOW_FAILED;
1628 static int setGlWindow_cocoa(MPGLContext *ctx)
1630 vo_cocoa_change_attributes(ctx->vo);
1631 getFunctions(ctx->gl, (void *)getdladdr, NULL);
1632 if (!ctx->gl->SwapInterval)
1633 ctx->gl->SwapInterval = vo_cocoa_swap_interval;
1634 return SET_WINDOW_OK;
1637 static void releaseGlContext_cocoa(MPGLContext *ctx)
1641 static void swapGlBuffers_cocoa(MPGLContext *ctx)
1643 vo_cocoa_swap_buffers();
1646 static int cocoa_check_events(struct vo *vo)
1648 return vo_cocoa_check_events(vo);
1651 static void cocoa_update_xinerama_info(struct vo *vo)
1653 vo_cocoa_update_xinerama_info(vo);
1656 static void cocoa_fullscreen(struct vo *vo)
1658 vo_cocoa_fullscreen(vo);
1660 #endif
1662 #ifdef CONFIG_GL_WIN32
1663 #include "w32_common.h"
1665 static int create_window_w32(struct MPGLContext *ctx, uint32_t d_width,
1666 uint32_t d_height, uint32_t flags)
1668 if (!vo_w32_config(d_width, d_height, flags))
1669 return -1;
1670 return 0;
1674 * \brief little helper since wglGetProcAddress definition does not fit our
1675 * getProcAddress
1676 * \param procName name of function to look up
1677 * \return function pointer returned by wglGetProcAddress
1679 static void *w32gpa(const GLubyte *procName)
1681 HMODULE oglmod;
1682 void *res = wglGetProcAddress(procName);
1683 if (res)
1684 return res;
1685 oglmod = GetModuleHandle("opengl32.dll");
1686 return GetProcAddress(oglmod, procName);
1689 static int setGlWindow_w32(MPGLContext *ctx)
1691 HWND win = vo_w32_window;
1692 int *vinfo = &ctx->vinfo.w32;
1693 HGLRC *context = &ctx->context.w32;
1694 int new_vinfo;
1695 HDC windc = vo_w32_get_dc(win);
1696 HGLRC new_context = 0;
1697 int keep_context = 0;
1698 int res = SET_WINDOW_FAILED;
1699 GL *gl = ctx->gl;
1701 // should only be needed when keeping context, but not doing glFinish
1702 // can cause flickering even when we do not keep it.
1703 if (*context)
1704 gl->Finish();
1705 new_vinfo = GetPixelFormat(windc);
1706 if (*context && *vinfo && new_vinfo && *vinfo == new_vinfo) {
1707 // we can keep the wglContext
1708 new_context = *context;
1709 keep_context = 1;
1710 } else {
1711 // create a context
1712 new_context = wglCreateContext(windc);
1713 if (!new_context) {
1714 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GL context!\n");
1715 goto out;
1719 // set context
1720 if (!wglMakeCurrent(windc, new_context)) {
1721 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL context!\n");
1722 if (!keep_context)
1723 wglDeleteContext(new_context);
1724 goto out;
1727 // set new values
1728 vo_w32_window = win;
1730 RECT rect;
1731 GetClientRect(win, &rect);
1732 ctx->vo->dwidth = rect.right;
1733 ctx->vo->dheight = rect.bottom;
1735 if (!keep_context) {
1736 if (*context)
1737 wglDeleteContext(*context);
1738 *context = new_context;
1739 *vinfo = new_vinfo;
1740 getFunctions(gl, w32gpa, NULL);
1742 // and inform that reinit is neccessary
1743 res = SET_WINDOW_REINIT;
1744 } else
1745 res = SET_WINDOW_OK;
1747 out:
1748 vo_w32_release_dc(win, windc);
1749 return res;
1752 static void releaseGlContext_w32(MPGLContext *ctx)
1754 int *vinfo = &ctx->vinfo.w32;
1755 HGLRC *context = &ctx->context.w32;
1756 *vinfo = 0;
1757 if (*context) {
1758 wglMakeCurrent(0, 0);
1759 wglDeleteContext(*context);
1761 *context = 0;
1764 static void swapGlBuffers_w32(MPGLContext *ctx)
1766 HDC vo_hdc = vo_w32_get_dc(vo_w32_window);
1767 SwapBuffers(vo_hdc);
1768 vo_w32_release_dc(vo_w32_window, vo_hdc);
1771 //trivial wrappers (w32 code uses old vo API)
1772 static void new_vo_w32_ontop(struct vo *vo) { vo_w32_ontop(); }
1773 static void new_vo_w32_border(struct vo *vo) { vo_w32_border(); }
1774 static void new_vo_w32_fullscreen(struct vo *vo) { vo_w32_fullscreen(); }
1775 static int new_vo_w32_check_events(struct vo *vo) { return vo_w32_check_events(); }
1776 static void new_w32_update_xinerama_info(struct vo *vo) { w32_update_xinerama_info(); }
1777 #endif
1778 #ifdef CONFIG_GL_X11
1779 #include "x11_common.h"
1781 static int create_window_x11(struct MPGLContext *ctx, uint32_t d_width,
1782 uint32_t d_height, uint32_t flags)
1784 struct vo *vo = ctx->vo;
1786 static int default_glx_attribs[] = {
1787 GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
1788 GLX_DOUBLEBUFFER, None
1790 static int stereo_glx_attribs[] = {
1791 GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
1792 GLX_DOUBLEBUFFER, GLX_STEREO, None
1794 XVisualInfo *vinfo = NULL;
1795 if (flags & VOFLAG_STEREO) {
1796 vinfo = glXChooseVisual(vo->x11->display, vo->x11->screen,
1797 stereo_glx_attribs);
1798 if (!vinfo)
1799 mp_msg(MSGT_VO, MSGL_ERR, "[gl] Could not find a stereo visual,"
1800 " 3D will probably not work!\n");
1802 if (!vinfo)
1803 vinfo = glXChooseVisual(vo->x11->display, vo->x11->screen,
1804 default_glx_attribs);
1805 if (!vinfo) {
1806 mp_msg(MSGT_VO, MSGL_ERR, "[gl] no GLX support present\n");
1807 return -1;
1809 mp_msg(MSGT_VO, MSGL_V, "[gl] GLX chose visual with ID 0x%x\n",
1810 (int)vinfo->visualid);
1812 Colormap colormap = XCreateColormap(vo->x11->display, vo->x11->rootwin,
1813 vinfo->visual, AllocNone);
1814 vo_x11_create_vo_window(vo, vinfo, vo->dx, vo->dy, d_width, d_height,
1815 flags, colormap, "gl");
1817 return 0;
1821 * \brief Returns the XVisualInfo associated with Window win.
1822 * \param win Window whose XVisualInfo is returne.
1823 * \return XVisualInfo of the window. Caller must use XFree to free it.
1825 static XVisualInfo *getWindowVisualInfo(MPGLContext *ctx, Window win)
1827 XWindowAttributes xw_attr;
1828 XVisualInfo vinfo_template;
1829 int tmp;
1830 XGetWindowAttributes(ctx->vo->x11->display, win, &xw_attr);
1831 vinfo_template.visualid = XVisualIDFromVisual(xw_attr.visual);
1832 return XGetVisualInfo(ctx->vo->x11->display, VisualIDMask, &vinfo_template, &tmp);
1835 static void appendstr(char **dst, const char *str)
1837 int newsize;
1838 char *newstr;
1839 if (!str)
1840 return;
1841 newsize = strlen(*dst) + 1 + strlen(str) + 1;
1842 newstr = realloc(*dst, newsize);
1843 if (!newstr)
1844 return;
1845 *dst = newstr;
1846 strcat(*dst, " ");
1847 strcat(*dst, str);
1851 * \brief Changes the window in which video is displayed.
1852 * If possible only transfers the context to the new window, otherwise
1853 * creates a new one, which must be initialized by the caller.
1854 * \param vinfo Currently used visual.
1855 * \param context Currently used context.
1856 * \param win window that should be used for drawing.
1857 * \return one of SET_WINDOW_FAILED, SET_WINDOW_OK or SET_WINDOW_REINIT.
1858 * In case of SET_WINDOW_REINIT the context could not be transfered
1859 * and the caller must initialize it correctly.
1860 * \ingroup glcontext
1862 static int setGlWindow_x11(MPGLContext *ctx)
1864 XVisualInfo **vinfo = &ctx->vinfo.x11;
1865 GLXContext *context = &ctx->context.x11;
1866 Display *display = ctx->vo->x11->display;
1867 Window win = ctx->vo->x11->window;
1868 XVisualInfo *new_vinfo;
1869 GLXContext new_context = NULL;
1870 int keep_context = 0;
1871 GL *gl = ctx->gl;
1873 // should only be needed when keeping context, but not doing glFinish
1874 // can cause flickering even when we do not keep it.
1875 if (*context)
1876 gl->Finish();
1877 new_vinfo = getWindowVisualInfo(ctx, win);
1878 if (*context && *vinfo && new_vinfo &&
1879 (*vinfo)->visualid == new_vinfo->visualid) {
1880 // we can keep the GLXContext
1881 new_context = *context;
1882 XFree(new_vinfo);
1883 new_vinfo = *vinfo;
1884 keep_context = 1;
1885 } else {
1886 // create a context
1887 new_context = glXCreateContext(display, new_vinfo, NULL, True);
1888 if (!new_context) {
1889 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n");
1890 XFree(new_vinfo);
1891 return SET_WINDOW_FAILED;
1895 // set context
1896 if (!glXMakeCurrent(display, ctx->vo->x11->window, new_context)) {
1897 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n");
1898 if (!keep_context) {
1899 glXDestroyContext(display, new_context);
1900 XFree(new_vinfo);
1902 return SET_WINDOW_FAILED;
1905 // set new values
1906 ctx->vo->x11->window = win;
1907 vo_x11_update_geometry(ctx->vo, 1);
1908 if (!keep_context) {
1909 void *(*getProcAddress)(const GLubyte *);
1910 const char *(*glXExtStr)(Display *, int);
1911 char *glxstr = strdup("");
1912 if (*context)
1913 glXDestroyContext(display, *context);
1914 *context = new_context;
1915 if (*vinfo)
1916 XFree(*vinfo);
1917 *vinfo = new_vinfo;
1918 getProcAddress = getdladdr("glXGetProcAddress");
1919 if (!getProcAddress)
1920 getProcAddress = getdladdr("glXGetProcAddressARB");
1921 glXExtStr = getdladdr("glXQueryExtensionsString");
1922 if (glXExtStr)
1923 appendstr(&glxstr, glXExtStr(display, DefaultScreen(display)));
1924 glXExtStr = getdladdr("glXGetClientString");
1925 if (glXExtStr)
1926 appendstr(&glxstr, glXExtStr(display, GLX_EXTENSIONS));
1927 glXExtStr = getdladdr("glXGetServerString");
1928 if (glXExtStr)
1929 appendstr(&glxstr, glXExtStr(display, GLX_EXTENSIONS));
1931 getFunctions(gl, getProcAddress, glxstr);
1932 if (!gl->GenPrograms && gl->GetString &&
1933 getProcAddress &&
1934 strstr(gl->GetString(GL_EXTENSIONS), "GL_ARB_vertex_program")) {
1935 mp_msg(MSGT_VO, MSGL_WARN,
1936 "Broken glXGetProcAddress detected, trying workaround\n");
1937 getFunctions(gl, NULL, glxstr);
1939 free(glxstr);
1941 // and inform that reinit is neccessary
1942 return SET_WINDOW_REINIT;
1944 return SET_WINDOW_OK;
1948 * \brief free the VisualInfo and GLXContext of an OpenGL context.
1949 * \ingroup glcontext
1951 static void releaseGlContext_x11(MPGLContext *ctx)
1953 XVisualInfo **vinfo = &ctx->vinfo.x11;
1954 GLXContext *context = &ctx->context.x11;
1955 Display *display = ctx->vo->x11->display;
1956 GL *gl = ctx->gl;
1957 if (*vinfo)
1958 XFree(*vinfo);
1959 *vinfo = NULL;
1960 if (*context) {
1961 gl->Finish();
1962 glXMakeCurrent(display, None, NULL);
1963 glXDestroyContext(display, *context);
1965 *context = 0;
1968 static void swapGlBuffers_x11(MPGLContext *ctx)
1970 glXSwapBuffers(ctx->vo->x11->display, ctx->vo->x11->window);
1972 #endif
1974 #ifdef CONFIG_GL_SDL
1975 #include "sdl_common.h"
1977 static int create_window_sdl(struct MPGLContext *ctx, uint32_t d_width,
1978 uint32_t d_height, uint32_t flags)
1980 SDL_WM_SetCaption(vo_get_window_title(ctx->vo), NULL);
1981 ctx->vo->dwidth = d_width;
1982 ctx->vo->dheight = d_height;
1983 return 0;
1986 static void swapGlBuffers_sdl(MPGLContext *ctx)
1988 SDL_GL_SwapBuffers();
1991 static void *sdlgpa(const GLubyte *name)
1993 return SDL_GL_GetProcAddress(name);
1996 static int setGlWindow_sdl(MPGLContext *ctx)
1998 if (sdl_set_mode(0, SDL_OPENGL | SDL_RESIZABLE) < 0)
1999 return SET_WINDOW_FAILED;
2000 SDL_GL_LoadLibrary(NULL);
2001 getFunctions(ctx->gl, sdlgpa, NULL);
2002 return SET_WINDOW_OK;
2005 static void releaseGlContext_sdl(MPGLContext *ctx)
2009 static int sdl_check_events(struct vo *vo)
2011 int res = 0;
2012 SDL_Event event;
2013 while (SDL_PollEvent(&event))
2014 res |= sdl_default_handle_event(&event);
2015 // poll "events" from within MPlayer code
2016 res |= sdl_default_handle_event(NULL);
2017 if (res & VO_EVENT_RESIZE)
2018 sdl_set_mode(0, SDL_OPENGL | SDL_RESIZABLE);
2019 return res;
2022 static void new_sdl_update_xinerama_info(struct vo *vo) { sdl_update_xinerama_info(); }
2023 static void new_vo_sdl_fullscreen(struct vo *vo) { vo_sdl_fullscreen(); }
2025 #endif
2027 MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo)
2029 MPGLContext *ctx;
2030 if (type == GLTYPE_AUTO) {
2031 ctx = init_mpglcontext(GLTYPE_COCOA, vo);
2032 if (ctx)
2033 return ctx;
2034 ctx = init_mpglcontext(GLTYPE_W32, vo);
2035 if (ctx)
2036 return ctx;
2037 ctx = init_mpglcontext(GLTYPE_X11, vo);
2038 if (ctx)
2039 return ctx;
2040 return init_mpglcontext(GLTYPE_SDL, vo);
2042 ctx = talloc_zero(NULL, MPGLContext);
2043 ctx->gl = talloc_zero(ctx, GL);
2044 ctx->type = type;
2045 ctx->vo = vo;
2046 switch (ctx->type) {
2047 #ifdef CONFIG_GL_COCOA
2048 case GLTYPE_COCOA:
2049 ctx->create_window = create_window_cocoa;
2050 ctx->setGlWindow = setGlWindow_cocoa;
2051 ctx->releaseGlContext = releaseGlContext_cocoa;
2052 ctx->swapGlBuffers = swapGlBuffers_cocoa;
2053 ctx->check_events = cocoa_check_events;
2054 ctx->update_xinerama_info = cocoa_update_xinerama_info;
2055 ctx->fullscreen = cocoa_fullscreen;
2056 ctx->ontop = vo_cocoa_ontop;
2057 if (vo_cocoa_init(vo))
2058 return ctx;
2059 break;
2060 #endif
2061 #ifdef CONFIG_GL_WIN32
2062 case GLTYPE_W32:
2063 ctx->create_window = create_window_w32;
2064 ctx->setGlWindow = setGlWindow_w32;
2065 ctx->releaseGlContext = releaseGlContext_w32;
2066 ctx->swapGlBuffers = swapGlBuffers_w32;
2067 ctx->update_xinerama_info = new_w32_update_xinerama_info;
2068 ctx->border = new_vo_w32_border;
2069 ctx->check_events = new_vo_w32_check_events;
2070 ctx->fullscreen = new_vo_w32_fullscreen;
2071 ctx->ontop = new_vo_w32_ontop;
2072 //the win32 code is hardcoded to use the deprecated vo API
2073 global_vo = vo;
2074 if (vo_w32_init())
2075 return ctx;
2076 break;
2077 #endif
2078 #ifdef CONFIG_GL_X11
2079 case GLTYPE_X11:
2080 ctx->create_window = create_window_x11;
2081 ctx->setGlWindow = setGlWindow_x11;
2082 ctx->releaseGlContext = releaseGlContext_x11;
2083 ctx->swapGlBuffers = swapGlBuffers_x11;
2084 ctx->update_xinerama_info = update_xinerama_info;
2085 ctx->border = vo_x11_border;
2086 ctx->check_events = vo_x11_check_events;
2087 ctx->fullscreen = vo_x11_fullscreen;
2088 ctx->ontop = vo_x11_ontop;
2089 if (vo_init(vo))
2090 return ctx;
2091 break;
2092 #endif
2093 #ifdef CONFIG_GL_SDL
2094 case GLTYPE_SDL:
2095 ctx->create_window = create_window_sdl;
2096 ctx->setGlWindow = setGlWindow_sdl;
2097 ctx->releaseGlContext = releaseGlContext_sdl;
2098 ctx->swapGlBuffers = swapGlBuffers_sdl;
2099 ctx->update_xinerama_info = new_sdl_update_xinerama_info;
2100 ctx->check_events = sdl_check_events;
2101 ctx->fullscreen = new_vo_sdl_fullscreen;
2102 //the SDL code is hardcoded to use the deprecated vo API
2103 global_vo = vo;
2104 if (vo_sdl_init())
2105 return ctx;
2106 break;
2107 #endif
2109 talloc_free(ctx);
2110 return NULL;
2113 void uninit_mpglcontext(MPGLContext *ctx)
2115 if (!ctx)
2116 return;
2117 ctx->releaseGlContext(ctx);
2118 switch (ctx->type) {
2119 #ifdef CONFIG_GL_COCOA
2120 case GLTYPE_COCOA:
2121 vo_cocoa_uninit(ctx->vo);
2122 break;
2123 #endif
2124 #ifdef CONFIG_GL_WIN32
2125 case GLTYPE_W32:
2126 vo_w32_uninit();
2127 break;
2128 #endif
2129 #ifdef CONFIG_GL_X11
2130 case GLTYPE_X11:
2131 vo_x11_uninit(ctx->vo);
2132 break;
2133 #endif
2134 #ifdef CONFIG_GL_SDL
2135 case GLTYPE_SDL:
2136 vo_sdl_uninit();
2137 break;
2138 #endif
2140 talloc_free(ctx);