vo_gl: move window creation functions from vo_gl.c into gl_common.c
[mplayer.git] / libvo / gl_common.c
blobb04136734e125452051d9a70340a3fd5f649d19d
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);
76 struct gl_name_map_struct {
77 GLint value;
78 const char *name;
81 #undef MAP
82 #define MAP(a) {a, # a}
83 //! mapping table for the glValName function
84 static const struct gl_name_map_struct gl_name_map[] = {
85 // internal format
86 MAP(GL_R3_G3_B2), MAP(GL_RGB4), MAP(GL_RGB5), MAP(GL_RGB8),
87 MAP(GL_RGB10), MAP(GL_RGB12), MAP(GL_RGB16), MAP(GL_RGBA2),
88 MAP(GL_RGBA4), MAP(GL_RGB5_A1), MAP(GL_RGBA8), MAP(GL_RGB10_A2),
89 MAP(GL_RGBA12), MAP(GL_RGBA16), MAP(GL_LUMINANCE8), MAP(GL_LUMINANCE16),
91 // format
92 MAP(GL_RGB), MAP(GL_RGBA), MAP(GL_RED), MAP(GL_GREEN), MAP(GL_BLUE),
93 MAP(GL_ALPHA), MAP(GL_LUMINANCE), MAP(GL_LUMINANCE_ALPHA),
94 MAP(GL_COLOR_INDEX),
95 // rest 1.2 only
96 MAP(GL_BGR), MAP(GL_BGRA),
98 //type
99 MAP(GL_BYTE), MAP(GL_UNSIGNED_BYTE), MAP(GL_SHORT), MAP(GL_UNSIGNED_SHORT),
100 MAP(GL_INT), MAP(GL_UNSIGNED_INT), MAP(GL_FLOAT), MAP(GL_DOUBLE),
101 MAP(GL_2_BYTES), MAP(GL_3_BYTES), MAP(GL_4_BYTES),
102 // rest 1.2 only
103 MAP(GL_UNSIGNED_BYTE_3_3_2), MAP(GL_UNSIGNED_BYTE_2_3_3_REV),
104 MAP(GL_UNSIGNED_SHORT_5_6_5), MAP(GL_UNSIGNED_SHORT_5_6_5_REV),
105 MAP(GL_UNSIGNED_SHORT_4_4_4_4), MAP(GL_UNSIGNED_SHORT_4_4_4_4_REV),
106 MAP(GL_UNSIGNED_SHORT_5_5_5_1), MAP(GL_UNSIGNED_SHORT_1_5_5_5_REV),
107 MAP(GL_UNSIGNED_INT_8_8_8_8), MAP(GL_UNSIGNED_INT_8_8_8_8_REV),
108 MAP(GL_UNSIGNED_INT_10_10_10_2), MAP(GL_UNSIGNED_INT_2_10_10_10_REV),
109 {0, 0}
111 #undef MAP
114 * \brief return the name of an OpenGL constant
115 * \param value the constant
116 * \return name of the constant or "Unknown format!"
117 * \ingroup glgeneral
119 const char *glValName(GLint value)
121 int i = 0;
123 while (gl_name_map[i].name) {
124 if (gl_name_map[i].value == value)
125 return gl_name_map[i].name;
126 i++;
128 return "Unknown format!";
131 //! always return this format as internal texture format in glFindFormat
132 #define TEXTUREFORMAT_ALWAYS GL_RGB8
133 #undef TEXTUREFORMAT_ALWAYS
136 * \brief find the OpenGL settings coresponding to format.
138 * All parameters may be NULL.
139 * \param fmt MPlayer format to analyze.
140 * \param bpp [OUT] bits per pixel of that format.
141 * \param gl_texfmt [OUT] internal texture format that fits the
142 * image format, not necessarily the best for performance.
143 * \param gl_format [OUT] OpenGL format for this image format.
144 * \param gl_type [OUT] OpenGL type for this image format.
145 * \return 1 if format is supported by OpenGL, 0 if not.
146 * \ingroup gltexture
148 int glFindFormat(uint32_t fmt, int *bpp, GLint *gl_texfmt,
149 GLenum *gl_format, GLenum *gl_type)
151 int supported = 1;
152 int dummy1;
153 GLenum dummy2;
154 GLint dummy3;
155 if (!bpp)
156 bpp = &dummy1;
157 if (!gl_texfmt)
158 gl_texfmt = &dummy3;
159 if (!gl_format)
160 gl_format = &dummy2;
161 if (!gl_type)
162 gl_type = &dummy2;
164 if (mp_get_chroma_shift(fmt, NULL, NULL, NULL)) {
165 // reduce the possible cases a bit
166 if (IMGFMT_IS_YUVP16_LE(fmt))
167 fmt = IMGFMT_420P16_LE;
168 else if (IMGFMT_IS_YUVP16_BE(fmt))
169 fmt = IMGFMT_420P16_BE;
170 else
171 fmt = IMGFMT_YV12;
174 *bpp = IMGFMT_IS_BGR(fmt) ? IMGFMT_BGR_DEPTH(fmt) : IMGFMT_RGB_DEPTH(fmt);
175 *gl_texfmt = 3;
176 switch (fmt) {
177 case IMGFMT_RGB48NE:
178 *gl_format = GL_RGB;
179 *gl_type = GL_UNSIGNED_SHORT;
180 break;
181 case IMGFMT_RGB24:
182 *gl_format = GL_RGB;
183 *gl_type = GL_UNSIGNED_BYTE;
184 break;
185 case IMGFMT_RGBA:
186 *gl_texfmt = 4;
187 *gl_format = GL_RGBA;
188 *gl_type = GL_UNSIGNED_BYTE;
189 break;
190 case IMGFMT_420P16:
191 supported = 0; // no native YUV support
192 *gl_texfmt = GL_LUMINANCE16;
193 *bpp = 16;
194 *gl_format = GL_LUMINANCE;
195 *gl_type = GL_UNSIGNED_SHORT;
196 break;
197 case IMGFMT_YV12:
198 supported = 0; // no native YV12 support
199 case IMGFMT_Y800:
200 case IMGFMT_Y8:
201 *gl_texfmt = 1;
202 *bpp = 8;
203 *gl_format = GL_LUMINANCE;
204 *gl_type = GL_UNSIGNED_BYTE;
205 break;
206 case IMGFMT_UYVY:
207 // IMGFMT_YUY2 would be more logical for the _REV format,
208 // but gives clearly swapped colors.
209 case IMGFMT_YVYU:
210 *gl_texfmt = GL_YCBCR_MESA;
211 *bpp = 16;
212 *gl_format = GL_YCBCR_MESA;
213 *gl_type = fmt == IMGFMT_UYVY ? GL_UNSIGNED_SHORT_8_8 : GL_UNSIGNED_SHORT_8_8_REV;
214 break;
215 #if 0
216 // we do not support palettized formats, although the format the
217 // swscale produces works
218 case IMGFMT_RGB8:
219 gl_format = GL_RGB;
220 gl_type = GL_UNSIGNED_BYTE_2_3_3_REV;
221 break;
222 #endif
223 case IMGFMT_RGB15:
224 *gl_format = GL_RGBA;
225 *gl_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
226 break;
227 case IMGFMT_RGB16:
228 *gl_format = GL_RGB;
229 *gl_type = GL_UNSIGNED_SHORT_5_6_5_REV;
230 break;
231 #if 0
232 case IMGFMT_BGR8:
233 // special case as red and blue have a differen number of bits.
234 // GL_BGR and GL_UNSIGNED_BYTE_3_3_2 isn't supported at least
235 // by nVidia drivers, and in addition would give more bits to
236 // blue than to red, which isn't wanted
237 gl_format = GL_RGB;
238 gl_type = GL_UNSIGNED_BYTE_3_3_2;
239 break;
240 #endif
241 case IMGFMT_BGR15:
242 *gl_format = GL_BGRA;
243 *gl_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
244 break;
245 case IMGFMT_BGR16:
246 *gl_format = GL_RGB;
247 *gl_type = GL_UNSIGNED_SHORT_5_6_5;
248 break;
249 case IMGFMT_BGR24:
250 *gl_format = GL_BGR;
251 *gl_type = GL_UNSIGNED_BYTE;
252 break;
253 case IMGFMT_BGRA:
254 *gl_texfmt = 4;
255 *gl_format = GL_BGRA;
256 *gl_type = GL_UNSIGNED_BYTE;
257 break;
258 default:
259 *gl_texfmt = 4;
260 *gl_format = GL_RGBA;
261 *gl_type = GL_UNSIGNED_BYTE;
262 supported = 0;
264 #ifdef TEXTUREFORMAT_ALWAYS
265 *gl_texfmt = TEXTUREFORMAT_ALWAYS;
266 #endif
267 return supported;
270 #ifdef HAVE_LIBDL
271 #include <dlfcn.h>
272 #endif
274 * \brief find address of a linked function
275 * \param s name of function to find
276 * \return address of function or NULL if not found
278 static void *getdladdr(const char *s)
280 void *ret = NULL;
281 #ifdef HAVE_LIBDL
282 void *handle = dlopen(NULL, RTLD_LAZY);
283 if (!handle)
284 return NULL;
285 ret = dlsym(handle, s);
286 dlclose(handle);
287 #endif
288 return ret;
291 typedef struct {
292 ptrdiff_t offset; // offset to the function pointer in struct GL
293 const char *extstr;
294 const char *funcnames[7];
295 void *fallback;
296 } extfunc_desc_t;
298 #define DEF_FUNC_DESC(name) \
299 {offsetof(GL, name), NULL, {"gl" # name, NULL}, gl ## name}
300 #define DEF_EXT_FUNCS(...) __VA_ARGS__
301 #define DEF_EXT_DESC(name, ext, funcnames) \
302 {offsetof(GL, name), ext, {DEF_EXT_FUNCS funcnames}}
304 static const extfunc_desc_t extfuncs[] = {
305 // these aren't extension functions but we query them anyway to allow
306 // different "backends" with one binary
307 DEF_FUNC_DESC(Begin),
308 DEF_FUNC_DESC(End),
309 DEF_FUNC_DESC(Viewport),
310 DEF_FUNC_DESC(MatrixMode),
311 DEF_FUNC_DESC(LoadIdentity),
312 DEF_FUNC_DESC(Translated),
313 DEF_FUNC_DESC(Scaled),
314 DEF_FUNC_DESC(Ortho),
315 DEF_FUNC_DESC(Frustum),
316 DEF_FUNC_DESC(PushMatrix),
317 DEF_FUNC_DESC(PopMatrix),
318 DEF_FUNC_DESC(Clear),
319 DEF_FUNC_DESC(GenLists),
320 DEF_FUNC_DESC(DeleteLists),
321 DEF_FUNC_DESC(NewList),
322 DEF_FUNC_DESC(EndList),
323 DEF_FUNC_DESC(CallList),
324 DEF_FUNC_DESC(CallLists),
325 DEF_FUNC_DESC(GenTextures),
326 DEF_FUNC_DESC(DeleteTextures),
327 DEF_FUNC_DESC(TexEnvf),
328 DEF_FUNC_DESC(TexEnvi),
329 DEF_FUNC_DESC(Color4ub),
330 DEF_FUNC_DESC(Color3f),
331 DEF_FUNC_DESC(Color4f),
332 DEF_FUNC_DESC(ClearColor),
333 DEF_FUNC_DESC(ClearDepth),
334 DEF_FUNC_DESC(DepthFunc),
335 DEF_FUNC_DESC(Enable),
336 DEF_FUNC_DESC(Disable),
337 DEF_FUNC_DESC(DrawBuffer),
338 DEF_FUNC_DESC(DepthMask),
339 DEF_FUNC_DESC(BlendFunc),
340 DEF_FUNC_DESC(Flush),
341 DEF_FUNC_DESC(Finish),
342 DEF_FUNC_DESC(PixelStorei),
343 DEF_FUNC_DESC(TexImage1D),
344 DEF_FUNC_DESC(TexImage2D),
345 DEF_FUNC_DESC(TexSubImage2D),
346 DEF_FUNC_DESC(GetTexImage),
347 DEF_FUNC_DESC(TexParameteri),
348 DEF_FUNC_DESC(TexParameterf),
349 DEF_FUNC_DESC(TexParameterfv),
350 DEF_FUNC_DESC(TexCoord2f),
351 DEF_FUNC_DESC(Vertex2f),
352 DEF_FUNC_DESC(Vertex3f),
353 DEF_FUNC_DESC(Normal3f),
354 DEF_FUNC_DESC(Lightfv),
355 DEF_FUNC_DESC(ColorMaterial),
356 DEF_FUNC_DESC(ShadeModel),
357 DEF_FUNC_DESC(GetIntegerv),
358 DEF_FUNC_DESC(ColorMask),
359 DEF_FUNC_DESC(ReadPixels),
360 DEF_FUNC_DESC(ReadBuffer),
362 DEF_EXT_DESC(GenBuffers, NULL,
363 ("glGenBuffers", "glGenBuffersARB")),
364 DEF_EXT_DESC(DeleteBuffers, NULL,
365 ("glDeleteBuffers", "glDeleteBuffersARB")),
366 DEF_EXT_DESC(BindBuffer, NULL,
367 ("glBindBuffer", "glBindBufferARB")),
368 DEF_EXT_DESC(MapBuffer, NULL,
369 ("glMapBuffer", "glMapBufferARB")),
370 DEF_EXT_DESC(UnmapBuffer, NULL,
371 ("glUnmapBuffer", "glUnmapBufferARB")),
372 DEF_EXT_DESC(BufferData, NULL,
373 ("glBufferData", "glBufferDataARB")),
374 DEF_EXT_DESC(CombinerParameterfv, "NV_register_combiners",
375 ("glCombinerParameterfv", "glCombinerParameterfvNV")),
376 DEF_EXT_DESC(CombinerParameteri, "NV_register_combiners",
377 ("glCombinerParameteri", "glCombinerParameteriNV")),
378 DEF_EXT_DESC(CombinerInput, "NV_register_combiners",
379 ("glCombinerInput", "glCombinerInputNV")),
380 DEF_EXT_DESC(CombinerOutput, "NV_register_combiners",
381 ("glCombinerOutput", "glCombinerOutputNV")),
382 DEF_EXT_DESC(BeginFragmentShader, "ATI_fragment_shader",
383 ("glBeginFragmentShaderATI")),
384 DEF_EXT_DESC(EndFragmentShader, "ATI_fragment_shader",
385 ("glEndFragmentShaderATI")),
386 DEF_EXT_DESC(SampleMap, "ATI_fragment_shader",
387 ("glSampleMapATI")),
388 DEF_EXT_DESC(ColorFragmentOp2, "ATI_fragment_shader",
389 ("glColorFragmentOp2ATI")),
390 DEF_EXT_DESC(ColorFragmentOp3, "ATI_fragment_shader",
391 ("glColorFragmentOp3ATI")),
392 DEF_EXT_DESC(SetFragmentShaderConstant, "ATI_fragment_shader",
393 ("glSetFragmentShaderConstantATI")),
394 DEF_EXT_DESC(ActiveTexture, NULL,
395 ("glActiveTexture", "glActiveTextureARB")),
396 DEF_EXT_DESC(BindTexture, NULL,
397 ("glBindTexture", "glBindTextureARB", "glBindTextureEXT")),
398 DEF_EXT_DESC(MultiTexCoord2f, NULL,
399 ("glMultiTexCoord2f", "glMultiTexCoord2fARB")),
400 DEF_EXT_DESC(GenPrograms, "_program",
401 ("glGenProgramsARB")),
402 DEF_EXT_DESC(DeletePrograms, "_program",
403 ("glDeleteProgramsARB")),
404 DEF_EXT_DESC(BindProgram, "_program",
405 ("glBindProgramARB")),
406 DEF_EXT_DESC(ProgramString, "_program",
407 ("glProgramStringARB")),
408 DEF_EXT_DESC(GetProgramiv, "_program",
409 ("glGetProgramivARB")),
410 DEF_EXT_DESC(ProgramEnvParameter4f, "_program",
411 ("glProgramEnvParameter4fARB")),
412 DEF_EXT_DESC(SwapInterval, "_swap_control",
413 ("glXSwapIntervalSGI", "glXSwapInterval", "wglSwapIntervalSGI",
414 "wglSwapInterval", "wglSwapIntervalEXT")),
415 DEF_EXT_DESC(TexImage3D, NULL,
416 ("glTexImage3D")),
417 DEF_EXT_DESC(AllocateMemoryMESA, "GLX_MESA_allocate_memory",
418 ("glXAllocateMemoryMESA")),
419 DEF_EXT_DESC(FreeMemoryMESA, "GLX_MESA_allocate_memory",
420 ("glXFreeMemoryMESA")),
421 {-1}
425 * \brief find the function pointers of some useful OpenGL extensions
426 * \param getProcAddress function to resolve function names, may be NULL
427 * \param ext2 an extra extension string
429 static void getFunctions(GL *gl, void *(*getProcAddress)(const GLubyte *),
430 const char *ext2)
432 const extfunc_desc_t *dsc;
433 const char *extensions;
434 char *allexts;
436 if (!getProcAddress)
437 getProcAddress = (void *)getdladdr;
439 // special case, we need glGetString before starting to find the other functions
440 gl->GetString = getProcAddress("glGetString");
441 if (!gl->GetString)
442 gl->GetString = glGetString;
444 extensions = (const char *)gl->GetString(GL_EXTENSIONS);
445 if (!extensions)
446 extensions = "";
447 if (!ext2)
448 ext2 = "";
449 allexts = malloc(strlen(extensions) + strlen(ext2) + 2);
450 strcpy(allexts, extensions);
451 strcat(allexts, " ");
452 strcat(allexts, ext2);
453 mp_msg(MSGT_VO, MSGL_DBG2, "OpenGL extensions string:\n%s\n", allexts);
454 for (dsc = extfuncs; dsc->offset >= 0; dsc++) {
455 void *ptr = NULL;
456 int i;
457 if (!dsc->extstr || strstr(allexts, dsc->extstr)) {
458 for (i = 0; !ptr && dsc->funcnames[i]; i++)
459 ptr = getProcAddress((const GLubyte *)dsc->funcnames[i]);
461 if (!ptr)
462 ptr = dsc->fallback;
463 void **funcptr = (void**)(((char*)gl) + dsc->offset);
464 *funcptr = ptr;
466 free(allexts);
470 * \brief create a texture and set some defaults
471 * \param target texture taget, usually GL_TEXTURE_2D
472 * \param fmt internal texture format
473 * \param format texture host data format
474 * \param type texture host data type
475 * \param filter filter used for scaling, e.g. GL_LINEAR
476 * \param w texture width
477 * \param h texture height
478 * \param val luminance value to fill texture with
479 * \ingroup gltexture
481 void glCreateClearTex(GL *gl, GLenum target, GLenum fmt, GLenum format,
482 GLenum type, GLint filter, int w, int h,
483 unsigned char val)
485 GLfloat fval = (GLfloat)val / 255.0;
486 GLfloat border[4] = {
487 fval, fval, fval, fval
489 int stride;
490 char *init;
491 if (w == 0)
492 w = 1;
493 if (h == 0)
494 h = 1;
495 stride = w * glFmt2bpp(format, type);
496 if (!stride)
497 return;
498 init = malloc(stride * h);
499 memset(init, val, stride * h);
500 glAdjustAlignment(gl, stride);
501 gl->PixelStorei(GL_UNPACK_ROW_LENGTH, w);
502 gl->TexImage2D(target, 0, fmt, w, h, 0, format, type, init);
503 gl->TexParameterf(target, GL_TEXTURE_PRIORITY, 1.0);
504 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
505 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
506 gl->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
507 gl->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
508 // Border texels should not be used with CLAMP_TO_EDGE
509 // We set a sane default anyway.
510 gl->TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, border);
511 free(init);
514 static GLint detect_hqtexfmt(GL *gl)
516 const char *extensions = (const char *)gl->GetString(GL_EXTENSIONS);
517 if (strstr(extensions, "_texture_float"))
518 return GL_RGB32F;
519 else if (strstr(extensions, "NV_float_buffer"))
520 return GL_FLOAT_RGB32_NV;
521 return GL_RGB16;
525 * \brief creates a texture from a PPM file
526 * \param target texture taget, usually GL_TEXTURE_2D
527 * \param fmt internal texture format, 0 for default
528 * \param filter filter used for scaling, e.g. GL_LINEAR
529 * \param f file to read PPM from
530 * \param width [out] width of texture
531 * \param height [out] height of texture
532 * \param maxval [out] maxval value from PPM file
533 * \return 0 on error, 1 otherwise
534 * \ingroup gltexture
536 int glCreatePPMTex(GL *gl, GLenum target, GLenum fmt, GLint filter,
537 FILE *f, int *width, int *height, int *maxval)
539 int w, h, m, bpp;
540 GLenum type;
541 uint8_t *data = read_pnm(f, &w, &h, &bpp, &m);
542 GLint hqtexfmt = detect_hqtexfmt(gl);
543 if (!data || (bpp != 3 && bpp != 6)) {
544 free(data);
545 return 0;
547 if (!fmt) {
548 fmt = bpp == 6 ? hqtexfmt : 3;
549 if (fmt == GL_FLOAT_RGB32_NV && target != GL_TEXTURE_RECTANGLE)
550 fmt = GL_RGB16;
552 type = bpp == 6 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
553 glCreateClearTex(gl, target, fmt, GL_RGB, type, filter, w, h, 0);
554 glUploadTex(gl, target, GL_RGB, type,
555 data, w * bpp, 0, 0, w, h, 0);
556 free(data);
557 if (width)
558 *width = w;
559 if (height)
560 *height = h;
561 if (maxval)
562 *maxval = m;
563 return 1;
567 * \brief return the number of bytes per pixel for the given format
568 * \param format OpenGL format
569 * \param type OpenGL type
570 * \return bytes per pixel
571 * \ingroup glgeneral
573 * Does not handle all possible variants, just those used by MPlayer
575 int glFmt2bpp(GLenum format, GLenum type)
577 int component_size = 0;
578 switch (type) {
579 case GL_UNSIGNED_BYTE_3_3_2:
580 case GL_UNSIGNED_BYTE_2_3_3_REV:
581 return 1;
582 case GL_UNSIGNED_SHORT_5_5_5_1:
583 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
584 case GL_UNSIGNED_SHORT_5_6_5:
585 case GL_UNSIGNED_SHORT_5_6_5_REV:
586 return 2;
587 case GL_UNSIGNED_BYTE:
588 component_size = 1;
589 break;
590 case GL_UNSIGNED_SHORT:
591 component_size = 2;
592 break;
594 switch (format) {
595 case GL_LUMINANCE:
596 case GL_ALPHA:
597 return component_size;
598 case GL_YCBCR_MESA:
599 return 2;
600 case GL_RGB:
601 case GL_BGR:
602 return 3 * component_size;
603 case GL_RGBA:
604 case GL_BGRA:
605 return 4 * component_size;
607 return 0; // unknown
611 * \brief upload a texture, handling things like stride and slices
612 * \param target texture target, usually GL_TEXTURE_2D
613 * \param format OpenGL format of data
614 * \param type OpenGL type of data
615 * \param dataptr data to upload
616 * \param stride data stride
617 * \param x x offset in texture
618 * \param y y offset in texture
619 * \param w width of the texture part to upload
620 * \param h height of the texture part to upload
621 * \param slice height of an upload slice, 0 for all at once
622 * \ingroup gltexture
624 void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type,
625 const void *dataptr, int stride,
626 int x, int y, int w, int h, int slice)
628 const uint8_t *data = dataptr;
629 int y_max = y + h;
630 if (w <= 0 || h <= 0)
631 return;
632 if (slice <= 0)
633 slice = h;
634 if (stride < 0) {
635 data += (h - 1) * stride;
636 stride = -stride;
638 // this is not always correct, but should work for MPlayer
639 glAdjustAlignment(gl, stride);
640 gl->PixelStorei(GL_UNPACK_ROW_LENGTH, stride / glFmt2bpp(format, type));
641 for (; y + slice <= y_max; y += slice) {
642 gl->TexSubImage2D(target, 0, x, y, w, slice, format, type, data);
643 data += stride * slice;
645 if (y < y_max)
646 gl->TexSubImage2D(target, 0, x, y, w, y_max - y, format, type, data);
649 static void fillUVcoeff(GLfloat *ucoef, GLfloat *vcoef,
650 float uvcos, float uvsin)
652 int i;
653 ucoef[0] = 0 * uvcos + 1.403 * uvsin;
654 vcoef[0] = 0 * uvsin + 1.403 * uvcos;
655 ucoef[1] = -0.344 * uvcos + -0.714 * uvsin;
656 vcoef[1] = -0.344 * uvsin + -0.714 * uvcos;
657 ucoef[2] = 1.770 * uvcos + 0 * uvsin;
658 vcoef[2] = 1.770 * uvsin + 0 * uvcos;
659 ucoef[3] = 0;
660 vcoef[3] = 0;
661 // Coefficients (probably) must be in [0, 1] range, whereas they originally
662 // are in [-2, 2] range, so here comes the trick:
663 // First put them in the [-0.5, 0.5] range, then add 0.5.
664 // This can be undone with the HALF_BIAS and SCALE_BY_FOUR arguments
665 // for CombinerInput and CombinerOutput (or the respective ATI variants)
666 for (i = 0; i < 4; i++) {
667 ucoef[i] = ucoef[i] * 0.25 + 0.5;
668 vcoef[i] = vcoef[i] * 0.25 + 0.5;
673 * \brief Setup register combiners for YUV to RGB conversion.
674 * \param uvcos used for saturation and hue adjustment
675 * \param uvsin used for saturation and hue adjustment
677 static void glSetupYUVCombiners(GL *gl, float uvcos, float uvsin)
679 GLfloat ucoef[4];
680 GLfloat vcoef[4];
681 GLint i;
682 if (!gl->CombinerInput || !gl->CombinerOutput ||
683 !gl->CombinerParameterfv || !gl->CombinerParameteri) {
684 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner functions missing!\n");
685 return;
687 gl->GetIntegerv(GL_MAX_GENERAL_COMBINERS_NV, &i);
688 if (i < 2)
689 mp_msg(MSGT_VO, MSGL_ERR,
690 "[gl] 2 general combiners needed for YUV combiner support (found %i)\n", i);
691 gl->GetIntegerv(GL_MAX_TEXTURE_UNITS, &i);
692 if (i < 3)
693 mp_msg(MSGT_VO, MSGL_ERR,
694 "[gl] 3 texture units needed for YUV combiner support (found %i)\n", i);
695 fillUVcoeff(ucoef, vcoef, uvcos, uvsin);
696 gl->CombinerParameterfv(GL_CONSTANT_COLOR0_NV, ucoef);
697 gl->CombinerParameterfv(GL_CONSTANT_COLOR1_NV, vcoef);
699 // UV first, like this green component cannot overflow
700 gl->CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
701 GL_TEXTURE1, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
702 gl->CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
703 GL_CONSTANT_COLOR0_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
704 gl->CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV,
705 GL_TEXTURE2, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
706 gl->CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV,
707 GL_CONSTANT_COLOR1_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
708 gl->CombinerOutput(GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV,
709 GL_SPARE0_NV, GL_SCALE_BY_FOUR_NV, GL_NONE, GL_FALSE,
710 GL_FALSE, GL_FALSE);
712 // stage 2
713 gl->CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_SPARE0_NV,
714 GL_SIGNED_IDENTITY_NV, GL_RGB);
715 gl->CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO,
716 GL_UNSIGNED_INVERT_NV, GL_RGB);
717 gl->CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_C_NV,
718 GL_TEXTURE0, GL_SIGNED_IDENTITY_NV, GL_RGB);
719 gl->CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO,
720 GL_UNSIGNED_INVERT_NV, GL_RGB);
721 gl->CombinerOutput(GL_COMBINER1_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV,
722 GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE,
723 GL_FALSE, GL_FALSE);
725 // leave final combiner stage in default mode
726 gl->CombinerParameteri(GL_NUM_GENERAL_COMBINERS_NV, 2);
730 * \brief Setup ATI version of register combiners for YUV to RGB conversion.
731 * \param csp_params parameters used for colorspace conversion
732 * \param text if set use the GL_ATI_text_fragment_shader API as
733 * used on OS X.
735 static void glSetupYUVFragmentATI(GL *gl, struct mp_csp_params *csp_params,
736 int text)
738 GLint i;
739 float yuv2rgb[3][4];
741 gl->GetIntegerv(GL_MAX_TEXTURE_UNITS, &i);
742 if (i < 3)
743 mp_msg(MSGT_VO, MSGL_ERR,
744 "[gl] 3 texture units needed for YUV combiner (ATI) support (found %i)\n", i);
746 mp_get_yuv2rgb_coeffs(csp_params, yuv2rgb);
747 for (i = 0; i < 3; i++) {
748 int j;
749 yuv2rgb[i][3] -= -0.5 * (yuv2rgb[i][1] + yuv2rgb[i][2]);
750 for (j = 0; j < 4; j++) {
751 yuv2rgb[i][j] *= 0.125;
752 yuv2rgb[i][j] += 0.5;
753 if (yuv2rgb[i][j] > 1)
754 yuv2rgb[i][j] = 1;
755 if (yuv2rgb[i][j] < 0)
756 yuv2rgb[i][j] = 0;
759 if (text == 0) {
760 GLfloat c0[4] = { yuv2rgb[0][0], yuv2rgb[1][0], yuv2rgb[2][0] };
761 GLfloat c1[4] = { yuv2rgb[0][1], yuv2rgb[1][1], yuv2rgb[2][1] };
762 GLfloat c2[4] = { yuv2rgb[0][2], yuv2rgb[1][2], yuv2rgb[2][2] };
763 GLfloat c3[4] = { yuv2rgb[0][3], yuv2rgb[1][3], yuv2rgb[2][3] };
764 if (!gl->BeginFragmentShader || !gl->EndFragmentShader ||
765 !gl->SetFragmentShaderConstant || !gl->SampleMap ||
766 !gl->ColorFragmentOp2 || !gl->ColorFragmentOp3) {
767 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner (ATI) functions missing!\n");
768 return;
770 gl->GetIntegerv(GL_NUM_FRAGMENT_REGISTERS_ATI, &i);
771 if (i < 3)
772 mp_msg(MSGT_VO, MSGL_ERR,
773 "[gl] 3 registers needed for YUV combiner (ATI) support (found %i)\n", i);
774 gl->BeginFragmentShader();
775 gl->SetFragmentShaderConstant(GL_CON_0_ATI, c0);
776 gl->SetFragmentShaderConstant(GL_CON_1_ATI, c1);
777 gl->SetFragmentShaderConstant(GL_CON_2_ATI, c2);
778 gl->SetFragmentShaderConstant(GL_CON_3_ATI, c3);
779 gl->SampleMap(GL_REG_0_ATI, GL_TEXTURE0, GL_SWIZZLE_STR_ATI);
780 gl->SampleMap(GL_REG_1_ATI, GL_TEXTURE1, GL_SWIZZLE_STR_ATI);
781 gl->SampleMap(GL_REG_2_ATI, GL_TEXTURE2, GL_SWIZZLE_STR_ATI);
782 gl->ColorFragmentOp2(GL_MUL_ATI, GL_REG_1_ATI, GL_NONE, GL_NONE,
783 GL_REG_1_ATI, GL_NONE, GL_BIAS_BIT_ATI,
784 GL_CON_1_ATI, GL_NONE, GL_BIAS_BIT_ATI);
785 gl->ColorFragmentOp3(GL_MAD_ATI, GL_REG_2_ATI, GL_NONE, GL_NONE,
786 GL_REG_2_ATI, GL_NONE, GL_BIAS_BIT_ATI,
787 GL_CON_2_ATI, GL_NONE, GL_BIAS_BIT_ATI,
788 GL_REG_1_ATI, GL_NONE, GL_NONE);
789 gl->ColorFragmentOp3(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
790 GL_REG_0_ATI, GL_NONE, GL_NONE,
791 GL_CON_0_ATI, GL_NONE, GL_BIAS_BIT_ATI,
792 GL_REG_2_ATI, GL_NONE, GL_NONE);
793 gl->ColorFragmentOp2(GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, GL_8X_BIT_ATI,
794 GL_REG_0_ATI, GL_NONE, GL_NONE,
795 GL_CON_3_ATI, GL_NONE, GL_BIAS_BIT_ATI);
796 gl->EndFragmentShader();
797 } else {
798 static const char template[] =
799 "!!ATIfs1.0\n"
800 "StartConstants;\n"
801 " CONSTANT c0 = {%e, %e, %e};\n"
802 " CONSTANT c1 = {%e, %e, %e};\n"
803 " CONSTANT c2 = {%e, %e, %e};\n"
804 " CONSTANT c3 = {%e, %e, %e};\n"
805 "EndConstants;\n"
806 "StartOutputPass;\n"
807 " SampleMap r0, t0.str;\n"
808 " SampleMap r1, t1.str;\n"
809 " SampleMap r2, t2.str;\n"
810 " MUL r1.rgb, r1.bias, c1.bias;\n"
811 " MAD r2.rgb, r2.bias, c2.bias, r1;\n"
812 " MAD r0.rgb, r0, c0.bias, r2;\n"
813 " ADD r0.rgb.8x, r0, c3.bias;\n"
814 "EndPass;\n";
815 char buffer[512];
816 snprintf(buffer, sizeof(buffer), template,
817 yuv2rgb[0][0], yuv2rgb[1][0], yuv2rgb[2][0],
818 yuv2rgb[0][1], yuv2rgb[1][1], yuv2rgb[2][1],
819 yuv2rgb[0][2], yuv2rgb[1][2], yuv2rgb[2][2],
820 yuv2rgb[0][3], yuv2rgb[1][3], yuv2rgb[2][3]);
821 mp_msg(MSGT_VO, MSGL_DBG2, "[gl] generated fragment program:\n%s\n",
822 buffer);
823 loadGPUProgram(gl, GL_TEXT_FRAGMENT_SHADER_ATI, buffer);
828 * \brief helper function for gen_spline_lookup_tex
829 * \param x subpixel-position ((0,1) range) to calculate weights for
830 * \param dst where to store transformed weights, must provide space for 4 GLfloats
832 * calculates the weights and stores them after appropriate transformation
833 * for the scaler fragment program.
835 static void store_weights(float x, GLfloat *dst)
837 float w0 = (((-1 * x + 3) * x - 3) * x + 1) / 6;
838 float w1 = (((3 * x - 6) * x + 0) * x + 4) / 6;
839 float w2 = (((-3 * x + 3) * x + 3) * x + 1) / 6;
840 float w3 = (((1 * x + 0) * x + 0) * x + 0) / 6;
841 *dst++ = 1 + x - w1 / (w0 + w1);
842 *dst++ = 1 - x + w3 / (w2 + w3);
843 *dst++ = w0 + w1;
844 *dst++ = 0;
847 //! to avoid artefacts this should be rather large
848 #define LOOKUP_BSPLINE_RES (2 * 1024)
850 * \brief creates the 1D lookup texture needed for fast higher-order filtering
851 * \param unit texture unit to attach texture to
853 static void gen_spline_lookup_tex(GL *gl, GLenum unit)
855 GLfloat *tex = calloc(4 * LOOKUP_BSPLINE_RES, sizeof(*tex));
856 GLfloat *tp = tex;
857 int i;
858 for (i = 0; i < LOOKUP_BSPLINE_RES; i++) {
859 float x = (float)(i + 0.5) / LOOKUP_BSPLINE_RES;
860 store_weights(x, tp);
861 tp += 4;
863 store_weights(0, tex);
864 store_weights(1, &tex[4 * (LOOKUP_BSPLINE_RES - 1)]);
865 gl->ActiveTexture(unit);
866 gl->TexImage1D(GL_TEXTURE_1D, 0, GL_RGBA16, LOOKUP_BSPLINE_RES, 0, GL_RGBA,
867 GL_FLOAT, tex);
868 gl->TexParameterf(GL_TEXTURE_1D, GL_TEXTURE_PRIORITY, 1.0);
869 gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
870 gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
871 gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
872 gl->ActiveTexture(GL_TEXTURE0);
873 free(tex);
876 static const char *bilin_filt_template =
877 "TEX yuv.%c, fragment.texcoord[%c], texture[%c], %s;\n";
879 #define BICUB_FILT_MAIN(textype) \
880 /* first y-interpolation */ \
881 "ADD coord, fragment.texcoord[%c].xyxy, cdelta.xyxw;\n" \
882 "ADD coord2, fragment.texcoord[%c].xyxy, cdelta.zyzw;\n" \
883 "TEX a.r, coord.xyxy, texture[%c], "textype ";\n" \
884 "TEX a.g, coord.zwzw, texture[%c], "textype ";\n" \
885 /* second y-interpolation */ \
886 "TEX b.r, coord2.xyxy, texture[%c], "textype ";\n" \
887 "TEX b.g, coord2.zwzw, texture[%c], "textype ";\n" \
888 "LRP a.b, parmy.b, a.rrrr, a.gggg;\n" \
889 "LRP a.a, parmy.b, b.rrrr, b.gggg;\n" \
890 /* x-interpolation */ \
891 "LRP yuv.%c, parmx.b, a.bbbb, a.aaaa;\n"
893 static const char *bicub_filt_template_2D =
894 "MAD coord.xy, fragment.texcoord[%c], {%e, %e}, {0.5, 0.5};\n"
895 "TEX parmx, coord.x, texture[%c], 1D;\n"
896 "MUL cdelta.xz, parmx.rrgg, {-%e, 0, %e, 0};\n"
897 "TEX parmy, coord.y, texture[%c], 1D;\n"
898 "MUL cdelta.yw, parmy.rrgg, {0, -%e, 0, %e};\n"
899 BICUB_FILT_MAIN("2D");
901 static const char *bicub_filt_template_RECT =
902 "ADD coord, fragment.texcoord[%c], {0.5, 0.5};\n"
903 "TEX parmx, coord.x, texture[%c], 1D;\n"
904 "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};\n"
905 "TEX parmy, coord.y, texture[%c], 1D;\n"
906 "MUL cdelta.yw, parmy.rrgg, {0, -1, 0, 1};\n"
907 BICUB_FILT_MAIN("RECT");
909 #define CALCWEIGHTS(t, s) \
910 "MAD "t ", {-0.5, 0.1666, 0.3333, -0.3333}, "s ", {1, 0, -0.5, 0.5};\n" \
911 "MAD "t ", "t ", "s ", {0, 0, -0.5, 0.5};\n" \
912 "MAD "t ", "t ", "s ", {-0.6666, 0, 0.8333, 0.1666};\n" \
913 "RCP a.x, "t ".z;\n" \
914 "RCP a.y, "t ".w;\n" \
915 "MAD "t ".xy, "t ".xyxy, a.xyxy, {1, 1, 0, 0};\n" \
916 "ADD "t ".x, "t ".xxxx, "s ";\n" \
917 "SUB "t ".y, "t ".yyyy, "s ";\n"
919 static const char *bicub_notex_filt_template_2D =
920 "MAD coord.xy, fragment.texcoord[%c], {%e, %e}, {0.5, 0.5};\n"
921 "FRC coord.xy, coord.xyxy;\n"
922 CALCWEIGHTS("parmx", "coord.xxxx")
923 "MUL cdelta.xz, parmx.rrgg, {-%e, 0, %e, 0};\n"
924 CALCWEIGHTS("parmy", "coord.yyyy")
925 "MUL cdelta.yw, parmy.rrgg, {0, -%e, 0, %e};\n"
926 BICUB_FILT_MAIN("2D");
928 static const char *bicub_notex_filt_template_RECT =
929 "ADD coord, fragment.texcoord[%c], {0.5, 0.5};\n"
930 "FRC coord.xy, coord.xyxy;\n"
931 CALCWEIGHTS("parmx", "coord.xxxx")
932 "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};\n"
933 CALCWEIGHTS("parmy", "coord.yyyy")
934 "MUL cdelta.yw, parmy.rrgg, {0, -1, 0, 1};\n"
935 BICUB_FILT_MAIN("RECT");
937 #define BICUB_X_FILT_MAIN(textype) \
938 "ADD coord.xy, fragment.texcoord[%c].xyxy, cdelta.xyxy;\n" \
939 "ADD coord2.xy, fragment.texcoord[%c].xyxy, cdelta.zyzy;\n" \
940 "TEX a.r, coord, texture[%c], "textype ";\n" \
941 "TEX b.r, coord2, texture[%c], "textype ";\n" \
942 /* x-interpolation */ \
943 "LRP yuv.%c, parmx.b, a.rrrr, b.rrrr;\n"
945 static const char *bicub_x_filt_template_2D =
946 "MAD coord.x, fragment.texcoord[%c], {%e}, {0.5};\n"
947 "TEX parmx, coord, texture[%c], 1D;\n"
948 "MUL cdelta.xyz, parmx.rrgg, {-%e, 0, %e};\n"
949 BICUB_X_FILT_MAIN("2D");
951 static const char *bicub_x_filt_template_RECT =
952 "ADD coord.x, fragment.texcoord[%c], {0.5};\n"
953 "TEX parmx, coord, texture[%c], 1D;\n"
954 "MUL cdelta.xyz, parmx.rrgg, {-1, 0, 1};\n"
955 BICUB_X_FILT_MAIN("RECT");
957 static const char *unsharp_filt_template =
958 "PARAM dcoord%c = {%e, %e, %e, %e};\n"
959 "ADD coord, fragment.texcoord[%c].xyxy, dcoord%c;\n"
960 "SUB coord2, fragment.texcoord[%c].xyxy, dcoord%c;\n"
961 "TEX a.r, fragment.texcoord[%c], texture[%c], %s;\n"
962 "TEX b.r, coord.xyxy, texture[%c], %s;\n"
963 "TEX b.g, coord.zwzw, texture[%c], %s;\n"
964 "ADD b.r, b.r, b.g;\n"
965 "TEX b.b, coord2.xyxy, texture[%c], %s;\n"
966 "TEX b.g, coord2.zwzw, texture[%c], %s;\n"
967 "DP3 b, b, {0.25, 0.25, 0.25};\n"
968 "SUB b.r, a.r, b.r;\n"
969 "MAD yuv.%c, b.r, {%e}, a.r;\n";
971 static const char *unsharp_filt_template2 =
972 "PARAM dcoord%c = {%e, %e, %e, %e};\n"
973 "PARAM dcoord2%c = {%e, 0, 0, %e};\n"
974 "ADD coord, fragment.texcoord[%c].xyxy, dcoord%c;\n"
975 "SUB coord2, fragment.texcoord[%c].xyxy, dcoord%c;\n"
976 "TEX a.r, fragment.texcoord[%c], texture[%c], %s;\n"
977 "TEX b.r, coord.xyxy, texture[%c], %s;\n"
978 "TEX b.g, coord.zwzw, texture[%c], %s;\n"
979 "ADD b.r, b.r, b.g;\n"
980 "TEX b.b, coord2.xyxy, texture[%c], %s;\n"
981 "TEX b.g, coord2.zwzw, texture[%c], %s;\n"
982 "ADD b.r, b.r, b.b;\n"
983 "ADD b.a, b.r, b.g;\n"
984 "ADD coord, fragment.texcoord[%c].xyxy, dcoord2%c;\n"
985 "SUB coord2, fragment.texcoord[%c].xyxy, dcoord2%c;\n"
986 "TEX b.r, coord.xyxy, texture[%c], %s;\n"
987 "TEX b.g, coord.zwzw, texture[%c], %s;\n"
988 "ADD b.r, b.r, b.g;\n"
989 "TEX b.b, coord2.xyxy, texture[%c], %s;\n"
990 "TEX b.g, coord2.zwzw, texture[%c], %s;\n"
991 "DP4 b.r, b, {-0.1171875, -0.1171875, -0.1171875, -0.09765625};\n"
992 "MAD b.r, a.r, {0.859375}, b.r;\n"
993 "MAD yuv.%c, b.r, {%e}, a.r;\n";
995 static const char *yuv_prog_template =
996 "PARAM ycoef = {%e, %e, %e};\n"
997 "PARAM ucoef = {%e, %e, %e};\n"
998 "PARAM vcoef = {%e, %e, %e};\n"
999 "PARAM offsets = {%e, %e, %e};\n"
1000 "TEMP res;\n"
1001 "MAD res.rgb, yuv.rrrr, ycoef, offsets;\n"
1002 "MAD res.rgb, yuv.gggg, ucoef, res;\n"
1003 "MAD result.color.rgb, yuv.bbbb, vcoef, res;\n"
1004 "END";
1006 static const char *yuv_pow_prog_template =
1007 "PARAM ycoef = {%e, %e, %e};\n"
1008 "PARAM ucoef = {%e, %e, %e};\n"
1009 "PARAM vcoef = {%e, %e, %e};\n"
1010 "PARAM offsets = {%e, %e, %e};\n"
1011 "PARAM gamma = {%e, %e, %e};\n"
1012 "TEMP res;\n"
1013 "MAD res.rgb, yuv.rrrr, ycoef, offsets;\n"
1014 "MAD res.rgb, yuv.gggg, ucoef, res;\n"
1015 "MAD_SAT res.rgb, yuv.bbbb, vcoef, res;\n"
1016 "POW result.color.r, res.r, gamma.r;\n"
1017 "POW result.color.g, res.g, gamma.g;\n"
1018 "POW result.color.b, res.b, gamma.b;\n"
1019 "END";
1021 static const char *yuv_lookup_prog_template =
1022 "PARAM ycoef = {%e, %e, %e, 0};\n"
1023 "PARAM ucoef = {%e, %e, %e, 0};\n"
1024 "PARAM vcoef = {%e, %e, %e, 0};\n"
1025 "PARAM offsets = {%e, %e, %e, 0.125};\n"
1026 "TEMP res;\n"
1027 "MAD res, yuv.rrrr, ycoef, offsets;\n"
1028 "MAD res.rgb, yuv.gggg, ucoef, res;\n"
1029 "MAD res.rgb, yuv.bbbb, vcoef, res;\n"
1030 "TEX result.color.r, res.raaa, texture[%c], 2D;\n"
1031 "ADD res.a, res.a, 0.25;\n"
1032 "TEX result.color.g, res.gaaa, texture[%c], 2D;\n"
1033 "ADD res.a, res.a, 0.25;\n"
1034 "TEX result.color.b, res.baaa, texture[%c], 2D;\n"
1035 "END";
1037 static const char *yuv_lookup3d_prog_template =
1038 "TEX result.color, yuv, texture[%c], 3D;\n"
1039 "END";
1042 * \brief creates and initializes helper textures needed for scaling texture read
1043 * \param scaler scaler type to create texture for
1044 * \param texu contains next free texture unit number
1045 * \param texs texture unit ids for the scaler are stored in this array
1047 static void create_scaler_textures(GL *gl, int scaler, int *texu, char *texs)
1049 switch (scaler) {
1050 case YUV_SCALER_BILIN:
1051 case YUV_SCALER_BICUB_NOTEX:
1052 case YUV_SCALER_UNSHARP:
1053 case YUV_SCALER_UNSHARP2:
1054 break;
1055 case YUV_SCALER_BICUB:
1056 case YUV_SCALER_BICUB_X:
1057 texs[0] = (*texu)++;
1058 gen_spline_lookup_tex(gl, GL_TEXTURE0 + texs[0]);
1059 texs[0] += '0';
1060 break;
1061 default:
1062 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown scaler type %i\n", scaler);
1066 //! resolution of texture for gamma lookup table
1067 #define LOOKUP_RES 512
1068 //! resolution for 3D yuv->rgb conversion lookup table
1069 #define LOOKUP_3DRES 32
1071 * \brief creates and initializes helper textures needed for yuv conversion
1072 * \param params struct containing parameters like brightness, gamma, ...
1073 * \param texu contains next free texture unit number
1074 * \param texs texture unit ids for the conversion are stored in this array
1076 static void create_conv_textures(GL *gl, gl_conversion_params_t *params,
1077 int *texu, char *texs)
1079 unsigned char *lookup_data = NULL;
1080 int conv = YUV_CONVERSION(params->type);
1081 switch (conv) {
1082 case YUV_CONVERSION_FRAGMENT:
1083 case YUV_CONVERSION_FRAGMENT_POW:
1084 break;
1085 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1086 texs[0] = (*texu)++;
1087 gl->ActiveTexture(GL_TEXTURE0 + texs[0]);
1088 lookup_data = malloc(4 * LOOKUP_RES);
1089 mp_gen_gamma_map(lookup_data, LOOKUP_RES, params->csp_params.rgamma);
1090 mp_gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES,
1091 params->csp_params.ggamma);
1092 mp_gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES,
1093 params->csp_params.bgamma);
1094 glCreateClearTex(gl, GL_TEXTURE_2D, GL_LUMINANCE8, GL_LUMINANCE,
1095 GL_UNSIGNED_BYTE, GL_LINEAR, LOOKUP_RES, 4, 0);
1096 glUploadTex(gl, GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE,
1097 lookup_data, LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0);
1098 gl->ActiveTexture(GL_TEXTURE0);
1099 texs[0] += '0';
1100 break;
1101 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1103 int sz = LOOKUP_3DRES + 2; // texture size including borders
1104 if (!gl->TexImage3D) {
1105 mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing 3D texture function!\n");
1106 break;
1108 texs[0] = (*texu)++;
1109 gl->ActiveTexture(GL_TEXTURE0 + texs[0]);
1110 lookup_data = malloc(3 * sz * sz * sz);
1111 mp_gen_yuv2rgb_map(&params->csp_params, lookup_data, LOOKUP_3DRES);
1112 glAdjustAlignment(gl, sz);
1113 gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1114 gl->TexImage3D(GL_TEXTURE_3D, 0, 3, sz, sz, sz, 1,
1115 GL_RGB, GL_UNSIGNED_BYTE, lookup_data);
1116 gl->TexParameterf(GL_TEXTURE_3D, GL_TEXTURE_PRIORITY, 1.0);
1117 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1118 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1119 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
1120 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
1121 gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
1122 gl->ActiveTexture(GL_TEXTURE0);
1123 texs[0] += '0';
1125 break;
1126 default:
1127 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", conv);
1129 free(lookup_data);
1133 * \brief adds a scaling texture read at the current fragment program position
1134 * \param scaler type of scaler to insert
1135 * \param prog_pos current position in fragment program
1136 * \param remain how many bytes remain in the buffer given by prog_pos
1137 * \param texs array containing the texture unit identifiers for this scaler
1138 * \param in_tex texture unit the scaler should read from
1139 * \param out_comp component of the yuv variable the scaler stores the result in
1140 * \param rect if rectangular (pixel) adressing should be used for in_tex
1141 * \param texw width of the in_tex texture
1142 * \param texh height of the in_tex texture
1143 * \param strength strength of filter effect if the scaler does some kind of filtering
1145 static void add_scaler(int scaler, char **prog_pos, int *remain, char *texs,
1146 char in_tex, char out_comp, int rect, int texw, int texh,
1147 double strength)
1149 const char *ttype = rect ? "RECT" : "2D";
1150 const float ptw = rect ? 1.0 : 1.0 / texw;
1151 const float pth = rect ? 1.0 : 1.0 / texh;
1152 switch (scaler) {
1153 case YUV_SCALER_BILIN:
1154 snprintf(*prog_pos, *remain, bilin_filt_template, out_comp, in_tex,
1155 in_tex, ttype);
1156 break;
1157 case YUV_SCALER_BICUB:
1158 if (rect)
1159 snprintf(*prog_pos, *remain, bicub_filt_template_RECT,
1160 in_tex, texs[0], texs[0],
1161 in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp);
1162 else
1163 snprintf(*prog_pos, *remain, bicub_filt_template_2D,
1164 in_tex, (float)texw, (float)texh,
1165 texs[0], ptw, ptw, texs[0], pth, pth,
1166 in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp);
1167 break;
1168 case YUV_SCALER_BICUB_X:
1169 if (rect)
1170 snprintf(*prog_pos, *remain, bicub_x_filt_template_RECT,
1171 in_tex, texs[0],
1172 in_tex, in_tex, in_tex, in_tex, out_comp);
1173 else
1174 snprintf(*prog_pos, *remain, bicub_x_filt_template_2D,
1175 in_tex, (float)texw,
1176 texs[0], ptw, ptw,
1177 in_tex, in_tex, in_tex, in_tex, out_comp);
1178 break;
1179 case YUV_SCALER_BICUB_NOTEX:
1180 if (rect)
1181 snprintf(*prog_pos, *remain, bicub_notex_filt_template_RECT,
1182 in_tex,
1183 in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp);
1184 else
1185 snprintf(*prog_pos, *remain, bicub_notex_filt_template_2D,
1186 in_tex, (float)texw, (float)texh, ptw, ptw, pth, pth,
1187 in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp);
1188 break;
1189 case YUV_SCALER_UNSHARP:
1190 snprintf(*prog_pos, *remain, unsharp_filt_template,
1191 out_comp, 0.5 * ptw, 0.5 * pth, 0.5 * ptw, -0.5 * pth,
1192 in_tex, out_comp, in_tex, out_comp, in_tex,
1193 in_tex, ttype, in_tex, ttype, in_tex, ttype, in_tex, ttype,
1194 in_tex, ttype, out_comp, strength);
1195 break;
1196 case YUV_SCALER_UNSHARP2:
1197 snprintf(*prog_pos, *remain, unsharp_filt_template2,
1198 out_comp, 1.2 * ptw, 1.2 * pth, 1.2 * ptw, -1.2 * pth,
1199 out_comp, 1.5 * ptw, 1.5 * pth,
1200 in_tex, out_comp, in_tex, out_comp, in_tex,
1201 in_tex, ttype, in_tex, ttype, in_tex, ttype, in_tex, ttype,
1202 in_tex, ttype, in_tex, out_comp, in_tex, out_comp,
1203 in_tex, ttype, in_tex, ttype, in_tex, ttype,
1204 in_tex, ttype, out_comp, strength);
1205 break;
1207 *remain -= strlen(*prog_pos);
1208 *prog_pos += strlen(*prog_pos);
1211 static const struct {
1212 const char *name;
1213 GLenum cur;
1214 GLenum max;
1215 } progstats[] = {
1216 {"instructions", 0x88A0, 0x88A1},
1217 {"native instructions", 0x88A2, 0x88A3},
1218 {"temporaries", 0x88A4, 0x88A5},
1219 {"native temporaries", 0x88A6, 0x88A7},
1220 {"parameters", 0x88A8, 0x88A9},
1221 {"native parameters", 0x88AA, 0x88AB},
1222 {"attribs", 0x88AC, 0x88AD},
1223 {"native attribs", 0x88AE, 0x88AF},
1224 {"ALU instructions", 0x8805, 0x880B},
1225 {"TEX instructions", 0x8806, 0x880C},
1226 {"TEX indirections", 0x8807, 0x880D},
1227 {"native ALU instructions", 0x8808, 0x880E},
1228 {"native TEX instructions", 0x8809, 0x880F},
1229 {"native TEX indirections", 0x880A, 0x8810},
1230 {NULL, 0, 0}
1234 * \brief load the specified GPU Program
1235 * \param target program target to load into, only GL_FRAGMENT_PROGRAM is tested
1236 * \param prog program string
1237 * \return 1 on success, 0 otherwise
1239 int loadGPUProgram(GL *gl, GLenum target, char *prog)
1241 int i;
1242 GLint cur = 0, max = 0, err = 0;
1243 if (!gl->ProgramString) {
1244 mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing GPU program function\n");
1245 return 0;
1247 gl->ProgramString(target, GL_PROGRAM_FORMAT_ASCII, strlen(prog), prog);
1248 gl->GetIntegerv(GL_PROGRAM_ERROR_POSITION, &err);
1249 if (err != -1) {
1250 mp_msg(MSGT_VO, MSGL_ERR,
1251 "[gl] Error compiling fragment program, make sure your card supports\n"
1252 "[gl] GL_ARB_fragment_program (use glxinfo to check).\n"
1253 "[gl] Error message:\n %s at %.10s\n",
1254 gl->GetString(GL_PROGRAM_ERROR_STRING), &prog[err]);
1255 return 0;
1257 if (!gl->GetProgramiv || !mp_msg_test(MSGT_VO, MSGL_DBG2))
1258 return 1;
1259 mp_msg(MSGT_VO, MSGL_V, "[gl] Program statistics:\n");
1260 for (i = 0; progstats[i].name; i++) {
1261 gl->GetProgramiv(target, progstats[i].cur, &cur);
1262 gl->GetProgramiv(target, progstats[i].max, &max);
1263 mp_msg(MSGT_VO, MSGL_V, "[gl] %s: %i/%i\n", progstats[i].name, cur,
1264 max);
1266 return 1;
1269 #define MAX_PROGSZ (1024 * 1024)
1272 * \brief setup a fragment program that will do YUV->RGB conversion
1273 * \param parms struct containing parameters like conversion and scaler type,
1274 * brightness, ...
1276 static void glSetupYUVFragprog(GL *gl, gl_conversion_params_t *params)
1278 int type = params->type;
1279 int texw = params->texw;
1280 int texh = params->texh;
1281 int rect = params->target == GL_TEXTURE_RECTANGLE;
1282 static const char prog_hdr[] =
1283 "!!ARBfp1.0\n"
1284 "OPTION ARB_precision_hint_fastest;\n"
1285 // all scaler variables must go here so they aren't defined
1286 // multiple times when the same scaler is used more than once
1287 "TEMP coord, coord2, cdelta, parmx, parmy, a, b, yuv;\n";
1288 int prog_remain;
1289 char *yuv_prog, *prog_pos;
1290 int cur_texu = 3;
1291 char lum_scale_texs[1];
1292 char chrom_scale_texs[1];
1293 char conv_texs[1];
1294 GLint i;
1295 // this is the conversion matrix, with y, u, v factors
1296 // for red, green, blue and the constant offsets
1297 float yuv2rgb[3][4];
1298 create_conv_textures(gl, params, &cur_texu, conv_texs);
1299 create_scaler_textures(gl, YUV_LUM_SCALER(type), &cur_texu, lum_scale_texs);
1300 if (YUV_CHROM_SCALER(type) == YUV_LUM_SCALER(type))
1301 memcpy(chrom_scale_texs, lum_scale_texs, sizeof(chrom_scale_texs));
1302 else
1303 create_scaler_textures(gl, YUV_CHROM_SCALER(type), &cur_texu,
1304 chrom_scale_texs);
1305 gl->GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &i);
1306 if (i < cur_texu)
1307 mp_msg(MSGT_VO, MSGL_ERR,
1308 "[gl] %i texture units needed for this type of YUV fragment support (found %i)\n",
1309 cur_texu, i);
1310 if (!gl->ProgramString) {
1311 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] ProgramString function missing!\n");
1312 return;
1314 yuv_prog = malloc(MAX_PROGSZ);
1315 strcpy(yuv_prog, prog_hdr);
1316 prog_pos = yuv_prog + sizeof(prog_hdr) - 1;
1317 prog_remain = MAX_PROGSZ - sizeof(prog_hdr);
1318 add_scaler(YUV_LUM_SCALER(type), &prog_pos, &prog_remain, lum_scale_texs,
1319 '0', 'r', rect, texw, texh, params->filter_strength);
1320 add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain,
1321 chrom_scale_texs, '1', 'g', rect, params->chrom_texw,
1322 params->chrom_texh, params->filter_strength);
1323 add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain,
1324 chrom_scale_texs, '2', 'b', rect, params->chrom_texw,
1325 params->chrom_texh, params->filter_strength);
1326 mp_get_yuv2rgb_coeffs(&params->csp_params, yuv2rgb);
1327 switch (YUV_CONVERSION(type)) {
1328 case YUV_CONVERSION_FRAGMENT:
1329 snprintf(prog_pos, prog_remain, yuv_prog_template,
1330 yuv2rgb[ROW_R][COL_Y], yuv2rgb[ROW_G][COL_Y], yuv2rgb[ROW_B][COL_Y],
1331 yuv2rgb[ROW_R][COL_U], yuv2rgb[ROW_G][COL_U], yuv2rgb[ROW_B][COL_U],
1332 yuv2rgb[ROW_R][COL_V], yuv2rgb[ROW_G][COL_V], yuv2rgb[ROW_B][COL_V],
1333 yuv2rgb[ROW_R][COL_C], yuv2rgb[ROW_G][COL_C], yuv2rgb[ROW_B][COL_C]);
1334 break;
1335 case YUV_CONVERSION_FRAGMENT_POW:
1336 snprintf(prog_pos, prog_remain, yuv_pow_prog_template,
1337 yuv2rgb[ROW_R][COL_Y], yuv2rgb[ROW_G][COL_Y], yuv2rgb[ROW_B][COL_Y],
1338 yuv2rgb[ROW_R][COL_U], yuv2rgb[ROW_G][COL_U], yuv2rgb[ROW_B][COL_U],
1339 yuv2rgb[ROW_R][COL_V], yuv2rgb[ROW_G][COL_V], yuv2rgb[ROW_B][COL_V],
1340 yuv2rgb[ROW_R][COL_C], yuv2rgb[ROW_G][COL_C], yuv2rgb[ROW_B][COL_C],
1341 (float)1.0 / params->csp_params.rgamma,
1342 (float)1.0 / params->csp_params.bgamma,
1343 (float)1.0 / params->csp_params.bgamma);
1344 break;
1345 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1346 snprintf(prog_pos, prog_remain, yuv_lookup_prog_template,
1347 yuv2rgb[ROW_R][COL_Y], yuv2rgb[ROW_G][COL_Y], yuv2rgb[ROW_B][COL_Y],
1348 yuv2rgb[ROW_R][COL_U], yuv2rgb[ROW_G][COL_U], yuv2rgb[ROW_B][COL_U],
1349 yuv2rgb[ROW_R][COL_V], yuv2rgb[ROW_G][COL_V], yuv2rgb[ROW_B][COL_V],
1350 yuv2rgb[ROW_R][COL_C], yuv2rgb[ROW_G][COL_C], yuv2rgb[ROW_B][COL_C],
1351 conv_texs[0], conv_texs[0], conv_texs[0]);
1352 break;
1353 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1354 snprintf(prog_pos, prog_remain, yuv_lookup3d_prog_template,
1355 conv_texs[0]);
1356 break;
1357 default:
1358 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n",
1359 YUV_CONVERSION(type));
1360 break;
1362 mp_msg(MSGT_VO, MSGL_DBG2, "[gl] generated fragment program:\n%s\n",
1363 yuv_prog);
1364 loadGPUProgram(gl, GL_FRAGMENT_PROGRAM, yuv_prog);
1365 free(yuv_prog);
1369 * \brief detect the best YUV->RGB conversion method available
1371 int glAutodetectYUVConversion(GL *gl)
1373 const char *extensions = gl->GetString(GL_EXTENSIONS);
1374 if (!extensions || !gl->MultiTexCoord2f)
1375 return YUV_CONVERSION_NONE;
1376 if (strstr(extensions, "GL_ARB_fragment_program"))
1377 return YUV_CONVERSION_FRAGMENT;
1378 if (strstr(extensions, "GL_ATI_text_fragment_shader"))
1379 return YUV_CONVERSION_TEXT_FRAGMENT;
1380 if (strstr(extensions, "GL_ATI_fragment_shader"))
1381 return YUV_CONVERSION_COMBINERS_ATI;
1382 return YUV_CONVERSION_NONE;
1386 * \brief setup YUV->RGB conversion
1387 * \param parms struct containing parameters like conversion and scaler type,
1388 * brightness, ...
1389 * \ingroup glconversion
1391 void glSetupYUVConversion(GL *gl, gl_conversion_params_t *params)
1393 float uvcos = params->csp_params.saturation * cos(params->csp_params.hue);
1394 float uvsin = params->csp_params.saturation * sin(params->csp_params.hue);
1395 if (params->chrom_texw == 0)
1396 params->chrom_texw = 1;
1397 if (params->chrom_texh == 0)
1398 params->chrom_texh = 1;
1399 switch (YUV_CONVERSION(params->type)) {
1400 case YUV_CONVERSION_COMBINERS:
1401 glSetupYUVCombiners(gl, uvcos, uvsin);
1402 break;
1403 case YUV_CONVERSION_COMBINERS_ATI:
1404 glSetupYUVFragmentATI(gl, &params->csp_params, 0);
1405 break;
1406 case YUV_CONVERSION_TEXT_FRAGMENT:
1407 glSetupYUVFragmentATI(gl, &params->csp_params, 1);
1408 break;
1409 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1410 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1411 case YUV_CONVERSION_FRAGMENT:
1412 case YUV_CONVERSION_FRAGMENT_POW:
1413 glSetupYUVFragprog(gl, params);
1414 break;
1415 case YUV_CONVERSION_NONE:
1416 break;
1417 default:
1418 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n",
1419 YUV_CONVERSION(params->type));
1424 * \brief enable the specified YUV conversion
1425 * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D)
1426 * \param type type of YUV conversion
1427 * \ingroup glconversion
1429 void glEnableYUVConversion(GL *gl, GLenum target, int type)
1431 switch (YUV_CONVERSION(type)) {
1432 case YUV_CONVERSION_COMBINERS:
1433 gl->ActiveTexture(GL_TEXTURE1);
1434 gl->Enable(target);
1435 gl->ActiveTexture(GL_TEXTURE2);
1436 gl->Enable(target);
1437 gl->ActiveTexture(GL_TEXTURE0);
1438 gl->Enable(GL_REGISTER_COMBINERS_NV);
1439 break;
1440 case YUV_CONVERSION_COMBINERS_ATI:
1441 gl->ActiveTexture(GL_TEXTURE1);
1442 gl->Enable(target);
1443 gl->ActiveTexture(GL_TEXTURE2);
1444 gl->Enable(target);
1445 gl->ActiveTexture(GL_TEXTURE0);
1446 gl->Enable(GL_FRAGMENT_SHADER_ATI);
1447 break;
1448 case YUV_CONVERSION_TEXT_FRAGMENT:
1449 gl->ActiveTexture(GL_TEXTURE1);
1450 gl->Enable(target);
1451 gl->ActiveTexture(GL_TEXTURE2);
1452 gl->Enable(target);
1453 gl->ActiveTexture(GL_TEXTURE0);
1454 gl->Enable(GL_TEXT_FRAGMENT_SHADER_ATI);
1455 break;
1456 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1457 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1458 case YUV_CONVERSION_FRAGMENT_POW:
1459 case YUV_CONVERSION_FRAGMENT:
1460 case YUV_CONVERSION_NONE:
1461 gl->Enable(GL_FRAGMENT_PROGRAM);
1462 break;
1467 * \brief disable the specified YUV conversion
1468 * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D)
1469 * \param type type of YUV conversion
1470 * \ingroup glconversion
1472 void glDisableYUVConversion(GL *gl, GLenum target, int type)
1474 switch (YUV_CONVERSION(type)) {
1475 case YUV_CONVERSION_COMBINERS:
1476 gl->ActiveTexture(GL_TEXTURE1);
1477 gl->Disable(target);
1478 gl->ActiveTexture(GL_TEXTURE2);
1479 gl->Disable(target);
1480 gl->ActiveTexture(GL_TEXTURE0);
1481 gl->Disable(GL_REGISTER_COMBINERS_NV);
1482 break;
1483 case YUV_CONVERSION_COMBINERS_ATI:
1484 gl->ActiveTexture(GL_TEXTURE1);
1485 gl->Disable(target);
1486 gl->ActiveTexture(GL_TEXTURE2);
1487 gl->Disable(target);
1488 gl->ActiveTexture(GL_TEXTURE0);
1489 gl->Disable(GL_FRAGMENT_SHADER_ATI);
1490 break;
1491 case YUV_CONVERSION_TEXT_FRAGMENT:
1492 gl->Disable(GL_TEXT_FRAGMENT_SHADER_ATI);
1493 // HACK: at least the Mac OS X 10.5 PPC Radeon drivers are broken and
1494 // without this disable the texture units while the program is still
1495 // running (10.4 PPC seems to work without this though).
1496 gl->Flush();
1497 gl->ActiveTexture(GL_TEXTURE1);
1498 gl->Disable(target);
1499 gl->ActiveTexture(GL_TEXTURE2);
1500 gl->Disable(target);
1501 gl->ActiveTexture(GL_TEXTURE0);
1502 break;
1503 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1504 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1505 case YUV_CONVERSION_FRAGMENT_POW:
1506 case YUV_CONVERSION_FRAGMENT:
1507 case YUV_CONVERSION_NONE:
1508 gl->Disable(GL_FRAGMENT_PROGRAM);
1509 break;
1513 void glEnable3DLeft(GL *gl, int type)
1515 GLint buffer;
1516 switch (type) {
1517 case GL_3D_RED_CYAN:
1518 gl->ColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
1519 break;
1520 case GL_3D_GREEN_MAGENTA:
1521 gl->ColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
1522 break;
1523 case GL_3D_QUADBUFFER:
1524 gl->GetIntegerv(GL_DRAW_BUFFER, &buffer);
1525 switch (buffer) {
1526 case GL_FRONT:
1527 case GL_FRONT_LEFT:
1528 case GL_FRONT_RIGHT:
1529 buffer = GL_FRONT_LEFT;
1530 break;
1531 case GL_BACK:
1532 case GL_BACK_LEFT:
1533 case GL_BACK_RIGHT:
1534 buffer = GL_BACK_LEFT;
1535 break;
1537 gl->DrawBuffer(buffer);
1538 break;
1542 void glEnable3DRight(GL *gl, int type)
1544 GLint buffer;
1545 switch (type) {
1546 case GL_3D_RED_CYAN:
1547 gl->ColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_FALSE);
1548 break;
1549 case GL_3D_GREEN_MAGENTA:
1550 gl->ColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE);
1551 break;
1552 case GL_3D_QUADBUFFER:
1553 gl->GetIntegerv(GL_DRAW_BUFFER, &buffer);
1554 switch (buffer) {
1555 case GL_FRONT:
1556 case GL_FRONT_LEFT:
1557 case GL_FRONT_RIGHT:
1558 buffer = GL_FRONT_RIGHT;
1559 break;
1560 case GL_BACK:
1561 case GL_BACK_LEFT:
1562 case GL_BACK_RIGHT:
1563 buffer = GL_BACK_RIGHT;
1564 break;
1566 gl->DrawBuffer(buffer);
1567 break;
1571 void glDisable3D(GL *gl, int type)
1573 GLint buffer;
1574 switch (type) {
1575 case GL_3D_RED_CYAN:
1576 case GL_3D_GREEN_MAGENTA:
1577 gl->ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1578 break;
1579 case GL_3D_QUADBUFFER:
1580 gl->DrawBuffer(vo_doublebuffering ? GL_BACK : GL_FRONT);
1581 gl->GetIntegerv(GL_DRAW_BUFFER, &buffer);
1582 switch (buffer) {
1583 case GL_FRONT:
1584 case GL_FRONT_LEFT:
1585 case GL_FRONT_RIGHT:
1586 buffer = GL_FRONT;
1587 break;
1588 case GL_BACK:
1589 case GL_BACK_LEFT:
1590 case GL_BACK_RIGHT:
1591 buffer = GL_BACK;
1592 break;
1594 gl->DrawBuffer(buffer);
1595 break;
1600 * \brief draw a texture part at given 2D coordinates
1601 * \param x screen top coordinate
1602 * \param y screen left coordinate
1603 * \param w screen width coordinate
1604 * \param h screen height coordinate
1605 * \param tx texture top coordinate in pixels
1606 * \param ty texture left coordinate in pixels
1607 * \param tw texture part width in pixels
1608 * \param th texture part height in pixels
1609 * \param sx width of texture in pixels
1610 * \param sy height of texture in pixels
1611 * \param rect_tex whether this texture uses texture_rectangle extension
1612 * \param is_yv12 if != 0, also draw the textures from units 1 and 2,
1613 * bits 8 - 15 and 16 - 23 specify the x and y scaling of those textures
1614 * \param flip flip the texture upside down
1615 * \ingroup gltexture
1617 void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h,
1618 GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th,
1619 int sx, int sy, int rect_tex, int is_yv12, int flip)
1621 int chroma_x_shift = (is_yv12 >> 8) & 31;
1622 int chroma_y_shift = (is_yv12 >> 16) & 31;
1623 GLfloat xscale = 1 << chroma_x_shift;
1624 GLfloat yscale = 1 << chroma_y_shift;
1625 GLfloat tx2 = tx / xscale, ty2 = ty / yscale, tw2 = tw / xscale, th2 = th / yscale;
1626 if (!rect_tex) {
1627 tx /= sx;
1628 ty /= sy;
1629 tw /= sx;
1630 th /= sy;
1631 tx2 = tx, ty2 = ty, tw2 = tw, th2 = th;
1633 if (flip) {
1634 y += h;
1635 h = -h;
1637 gl->Begin(GL_QUADS);
1638 gl->TexCoord2f(tx, ty);
1639 if (is_yv12) {
1640 gl->MultiTexCoord2f(GL_TEXTURE1, tx2, ty2);
1641 gl->MultiTexCoord2f(GL_TEXTURE2, tx2, ty2);
1643 gl->Vertex2f(x, y);
1644 gl->TexCoord2f(tx, ty + th);
1645 if (is_yv12) {
1646 gl->MultiTexCoord2f(GL_TEXTURE1, tx2, ty2 + th2);
1647 gl->MultiTexCoord2f(GL_TEXTURE2, tx2, ty2 + th2);
1649 gl->Vertex2f(x, y + h);
1650 gl->TexCoord2f(tx + tw, ty + th);
1651 if (is_yv12) {
1652 gl->MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2 + th2);
1653 gl->MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2 + th2);
1655 gl->Vertex2f(x + w, y + h);
1656 gl->TexCoord2f(tx + tw, ty);
1657 if (is_yv12) {
1658 gl->MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2);
1659 gl->MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2);
1661 gl->Vertex2f(x + w, y);
1662 gl->End();
1665 #ifdef CONFIG_GL_WIN32
1666 #include "w32_common.h"
1668 static int create_window_w32(struct MPGLContext *ctx, uint32_t d_width,
1669 uint32_t d_height, uint32_t flags,
1670 const char *title)
1672 if (!vo_w32_config(d_width, d_height, flags))
1673 return -1;
1674 return 0;
1678 * \brief little helper since wglGetProcAddress definition does not fit our
1679 * getProcAddress
1680 * \param procName name of function to look up
1681 * \return function pointer returned by wglGetProcAddress
1683 static void *w32gpa(const GLubyte *procName)
1685 HMODULE oglmod;
1686 void *res = wglGetProcAddress(procName);
1687 if (res)
1688 return res;
1689 oglmod = GetModuleHandle("opengl32.dll");
1690 return GetProcAddress(oglmod, procName);
1693 static int setGlWindow_w32(MPGLContext *ctx)
1695 HWND win = vo_w32_window;
1696 int *vinfo = &ctx->vinfo.w32;
1697 HGLRC *context = &ctx->context.w32;
1698 int new_vinfo;
1699 HDC windc = vo_w32_get_dc(win);
1700 HGLRC new_context = 0;
1701 int keep_context = 0;
1702 int res = SET_WINDOW_FAILED;
1703 GL *gl = ctx->gl;
1705 // should only be needed when keeping context, but not doing glFinish
1706 // can cause flickering even when we do not keep it.
1707 if (*context)
1708 gl->Finish();
1709 new_vinfo = GetPixelFormat(windc);
1710 if (*context && *vinfo && new_vinfo && *vinfo == new_vinfo) {
1711 // we can keep the wglContext
1712 new_context = *context;
1713 keep_context = 1;
1714 } else {
1715 // create a context
1716 new_context = wglCreateContext(windc);
1717 if (!new_context) {
1718 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GL context!\n");
1719 goto out;
1723 // set context
1724 if (!wglMakeCurrent(windc, new_context)) {
1725 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL context!\n");
1726 if (!keep_context)
1727 wglDeleteContext(new_context);
1728 goto out;
1731 // set new values
1732 vo_w32_window = win;
1734 RECT rect;
1735 GetClientRect(win, &rect);
1736 ctx->vo->dwidth = rect.right;
1737 ctx->vo->dheight = rect.bottom;
1739 if (!keep_context) {
1740 if (*context)
1741 wglDeleteContext(*context);
1742 *context = new_context;
1743 *vinfo = new_vinfo;
1744 getFunctions(gl, w32gpa, NULL);
1746 // and inform that reinit is neccessary
1747 res = SET_WINDOW_REINIT;
1748 } else
1749 res = SET_WINDOW_OK;
1751 out:
1752 vo_w32_release_dc(win, windc);
1753 return res;
1756 static void releaseGlContext_w32(MPGLContext *ctx)
1758 int *vinfo = &ctx->vinfo.w32;
1759 HGLRC *context = &ctx->context.w32;
1760 *vinfo = 0;
1761 if (*context) {
1762 wglMakeCurrent(0, 0);
1763 wglDeleteContext(*context);
1765 *context = 0;
1768 static void swapGlBuffers_w32(MPGLContext *ctx)
1770 HDC vo_hdc = vo_w32_get_dc(vo_w32_window);
1771 SwapBuffers(vo_hdc);
1772 vo_w32_release_dc(vo_w32_window, vo_hdc);
1775 //trivial wrappers (w32 code uses old vo API)
1776 static void new_vo_w32_ontop(struct vo *vo) { vo_w32_ontop(); }
1777 static void new_vo_w32_border(struct vo *vo) { vo_w32_border(); }
1778 static void new_vo_w32_fullscreen(struct vo *vo) { vo_w32_fullscreen(); }
1779 static int new_vo_w32_check_events(struct vo *vo) { return vo_w32_check_events(); }
1780 static void new_w32_update_xinerama_info(struct vo *vo) { w32_update_xinerama_info(); }
1781 #endif
1782 #ifdef CONFIG_GL_X11
1783 #include "x11_common.h"
1785 static int create_window_x11(struct MPGLContext *ctx, uint32_t d_width,
1786 uint32_t d_height, uint32_t flags,
1787 const char *title)
1789 struct vo *vo = ctx->vo;
1791 static int default_glx_attribs[] = {
1792 GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
1793 GLX_DOUBLEBUFFER, None
1795 static int stereo_glx_attribs[] = {
1796 GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
1797 GLX_DOUBLEBUFFER, GLX_STEREO, None
1799 XVisualInfo *vinfo = NULL;
1800 if (flags & VOFLAG_STEREO) {
1801 vinfo = glXChooseVisual(vo->x11->display, vo->x11->screen,
1802 stereo_glx_attribs);
1803 if (!vinfo)
1804 mp_msg(MSGT_VO, MSGL_ERR, "[gl] Could not find a stereo visual,"
1805 " 3D will probably not work!\n");
1807 if (!vinfo)
1808 vinfo = glXChooseVisual(vo->x11->display, vo->x11->screen,
1809 default_glx_attribs);
1810 if (!vinfo) {
1811 mp_msg(MSGT_VO, MSGL_ERR, "[gl] no GLX support present\n");
1812 return -1;
1814 mp_msg(MSGT_VO, MSGL_V, "[gl] GLX chose visual with ID 0x%x\n",
1815 (int)vinfo->visualid);
1817 Colormap colormap = XCreateColormap(vo->x11->display, vo->x11->rootwin,
1818 vinfo->visual, AllocNone);
1819 vo_x11_create_vo_window(vo, vinfo, vo->dx, vo->dy, d_width, d_height,
1820 flags, colormap, "gl", title);
1822 return 0;
1826 * \brief Returns the XVisualInfo associated with Window win.
1827 * \param win Window whose XVisualInfo is returne.
1828 * \return XVisualInfo of the window. Caller must use XFree to free it.
1830 static XVisualInfo *getWindowVisualInfo(MPGLContext *ctx, Window win)
1832 XWindowAttributes xw_attr;
1833 XVisualInfo vinfo_template;
1834 int tmp;
1835 XGetWindowAttributes(ctx->vo->x11->display, win, &xw_attr);
1836 vinfo_template.visualid = XVisualIDFromVisual(xw_attr.visual);
1837 return XGetVisualInfo(ctx->vo->x11->display, VisualIDMask, &vinfo_template, &tmp);
1840 static void appendstr(char **dst, const char *str)
1842 int newsize;
1843 char *newstr;
1844 if (!str)
1845 return;
1846 newsize = strlen(*dst) + 1 + strlen(str) + 1;
1847 newstr = realloc(*dst, newsize);
1848 if (!newstr)
1849 return;
1850 *dst = newstr;
1851 strcat(*dst, " ");
1852 strcat(*dst, str);
1856 * \brief Changes the window in which video is displayed.
1857 * If possible only transfers the context to the new window, otherwise
1858 * creates a new one, which must be initialized by the caller.
1859 * \param vinfo Currently used visual.
1860 * \param context Currently used context.
1861 * \param win window that should be used for drawing.
1862 * \return one of SET_WINDOW_FAILED, SET_WINDOW_OK or SET_WINDOW_REINIT.
1863 * In case of SET_WINDOW_REINIT the context could not be transfered
1864 * and the caller must initialize it correctly.
1865 * \ingroup glcontext
1867 static int setGlWindow_x11(MPGLContext *ctx)
1869 XVisualInfo **vinfo = &ctx->vinfo.x11;
1870 GLXContext *context = &ctx->context.x11;
1871 Display *display = ctx->vo->x11->display;
1872 Window win = ctx->vo->x11->window;
1873 XVisualInfo *new_vinfo;
1874 GLXContext new_context = NULL;
1875 int keep_context = 0;
1876 GL *gl = ctx->gl;
1878 // should only be needed when keeping context, but not doing glFinish
1879 // can cause flickering even when we do not keep it.
1880 if (*context)
1881 gl->Finish();
1882 new_vinfo = getWindowVisualInfo(ctx, win);
1883 if (*context && *vinfo && new_vinfo &&
1884 (*vinfo)->visualid == new_vinfo->visualid) {
1885 // we can keep the GLXContext
1886 new_context = *context;
1887 XFree(new_vinfo);
1888 new_vinfo = *vinfo;
1889 keep_context = 1;
1890 } else {
1891 // create a context
1892 new_context = glXCreateContext(display, new_vinfo, NULL, True);
1893 if (!new_context) {
1894 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n");
1895 XFree(new_vinfo);
1896 return SET_WINDOW_FAILED;
1900 // set context
1901 if (!glXMakeCurrent(display, ctx->vo->x11->window, new_context)) {
1902 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n");
1903 if (!keep_context) {
1904 glXDestroyContext(display, new_context);
1905 XFree(new_vinfo);
1907 return SET_WINDOW_FAILED;
1910 // set new values
1911 ctx->vo->x11->window = win;
1912 vo_x11_update_geometry(ctx->vo, 1);
1913 if (!keep_context) {
1914 void *(*getProcAddress)(const GLubyte *);
1915 const char *(*glXExtStr)(Display *, int);
1916 char *glxstr = strdup("");
1917 if (*context)
1918 glXDestroyContext(display, *context);
1919 *context = new_context;
1920 if (*vinfo)
1921 XFree(*vinfo);
1922 *vinfo = new_vinfo;
1923 getProcAddress = getdladdr("glXGetProcAddress");
1924 if (!getProcAddress)
1925 getProcAddress = getdladdr("glXGetProcAddressARB");
1926 glXExtStr = getdladdr("glXQueryExtensionsString");
1927 if (glXExtStr)
1928 appendstr(&glxstr, glXExtStr(display, DefaultScreen(display)));
1929 glXExtStr = getdladdr("glXGetClientString");
1930 if (glXExtStr)
1931 appendstr(&glxstr, glXExtStr(display, GLX_EXTENSIONS));
1932 glXExtStr = getdladdr("glXGetServerString");
1933 if (glXExtStr)
1934 appendstr(&glxstr, glXExtStr(display, GLX_EXTENSIONS));
1936 getFunctions(gl, getProcAddress, glxstr);
1937 if (!gl->GenPrograms && gl->GetString &&
1938 getProcAddress &&
1939 strstr(gl->GetString(GL_EXTENSIONS), "GL_ARB_vertex_program")) {
1940 mp_msg(MSGT_VO, MSGL_WARN,
1941 "Broken glXGetProcAddress detected, trying workaround\n");
1942 getFunctions(gl, NULL, glxstr);
1944 free(glxstr);
1946 // and inform that reinit is neccessary
1947 return SET_WINDOW_REINIT;
1949 return SET_WINDOW_OK;
1953 * \brief free the VisualInfo and GLXContext of an OpenGL context.
1954 * \ingroup glcontext
1956 static void releaseGlContext_x11(MPGLContext *ctx)
1958 XVisualInfo **vinfo = &ctx->vinfo.x11;
1959 GLXContext *context = &ctx->context.x11;
1960 Display *display = ctx->vo->x11->display;
1961 GL *gl = ctx->gl;
1962 if (*vinfo)
1963 XFree(*vinfo);
1964 *vinfo = NULL;
1965 if (*context) {
1966 gl->Finish();
1967 glXMakeCurrent(display, None, NULL);
1968 glXDestroyContext(display, *context);
1970 *context = 0;
1973 static void swapGlBuffers_x11(MPGLContext *ctx)
1975 glXSwapBuffers(ctx->vo->x11->display, ctx->vo->x11->window);
1977 #endif
1979 #ifdef CONFIG_GL_SDL
1980 #include "sdl_common.h"
1982 static int create_window_sdl(struct MPGLContext *ctx, uint32_t d_width,
1983 uint32_t d_height, uint32_t flags,
1984 const char *title)
1986 SDL_WM_SetCaption(title, NULL);
1987 ctx->vo->dwidth = d_width;
1988 ctx->vo->dheight = d_height;
1989 return 0;
1992 static void swapGlBuffers_sdl(MPGLContext *ctx)
1994 SDL_GL_SwapBuffers();
1997 static void *sdlgpa(const GLubyte *name)
1999 return SDL_GL_GetProcAddress(name);
2002 static int setGlWindow_sdl(MPGLContext *ctx)
2004 if (sdl_set_mode(0, SDL_OPENGL | SDL_RESIZABLE) < 0)
2005 return SET_WINDOW_FAILED;
2006 SDL_GL_LoadLibrary(NULL);
2007 getFunctions(ctx->gl, sdlgpa, NULL);
2008 return SET_WINDOW_OK;
2011 static void releaseGlContext_sdl(MPGLContext *ctx)
2015 static int sdl_check_events(struct vo *vo)
2017 int res = 0;
2018 SDL_Event event;
2019 while (SDL_PollEvent(&event))
2020 res |= sdl_default_handle_event(&event);
2021 // poll "events" from within MPlayer code
2022 res |= sdl_default_handle_event(NULL);
2023 if (res & VO_EVENT_RESIZE)
2024 sdl_set_mode(0, SDL_OPENGL | SDL_RESIZABLE);
2025 return res;
2028 static void new_sdl_update_xinerama_info(struct vo *vo) { sdl_update_xinerama_info(); }
2029 static void new_vo_sdl_fullscreen(struct vo *vo) { vo_sdl_fullscreen(); }
2031 #endif
2033 MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo)
2035 MPGLContext *ctx;
2036 if (type == GLTYPE_AUTO) {
2037 ctx = init_mpglcontext(GLTYPE_W32, vo);
2038 if (ctx)
2039 return ctx;
2040 ctx = init_mpglcontext(GLTYPE_X11, vo);
2041 if (ctx)
2042 return ctx;
2043 return init_mpglcontext(GLTYPE_SDL, vo);
2045 ctx = talloc_zero(NULL, MPGLContext);
2046 ctx->gl = talloc_zero(ctx, GL);
2047 ctx->type = type;
2048 ctx->vo = vo;
2049 switch (ctx->type) {
2050 #ifdef CONFIG_GL_WIN32
2051 case GLTYPE_W32:
2052 ctx->create_window = create_window_w32;
2053 ctx->setGlWindow = setGlWindow_w32;
2054 ctx->releaseGlContext = releaseGlContext_w32;
2055 ctx->swapGlBuffers = swapGlBuffers_w32;
2056 ctx->update_xinerama_info = new_w32_update_xinerama_info;
2057 ctx->border = new_vo_w32_border;
2058 ctx->check_events = new_vo_w32_check_events;
2059 ctx->fullscreen = new_vo_w32_fullscreen;
2060 ctx->ontop = new_vo_w32_ontop;
2061 //the win32 code is hardcoded to use the deprecated vo API
2062 global_vo = vo;
2063 if (vo_w32_init())
2064 return ctx;
2065 break;
2066 #endif
2067 #ifdef CONFIG_GL_X11
2068 case GLTYPE_X11:
2069 ctx->create_window = create_window_x11;
2070 ctx->setGlWindow = setGlWindow_x11;
2071 ctx->releaseGlContext = releaseGlContext_x11;
2072 ctx->swapGlBuffers = swapGlBuffers_x11;
2073 ctx->update_xinerama_info = update_xinerama_info;
2074 ctx->border = vo_x11_border;
2075 ctx->check_events = vo_x11_check_events;
2076 ctx->fullscreen = vo_x11_fullscreen;
2077 ctx->ontop = vo_x11_ontop;
2078 if (vo_init(vo))
2079 return ctx;
2080 break;
2081 #endif
2082 #ifdef CONFIG_GL_SDL
2083 case GLTYPE_SDL:
2084 ctx->create_window = create_window_sdl;
2085 ctx->setGlWindow = setGlWindow_sdl;
2086 ctx->releaseGlContext = releaseGlContext_sdl;
2087 ctx->swapGlBuffers = swapGlBuffers_sdl;
2088 ctx->update_xinerama_info = new_sdl_update_xinerama_info;
2089 ctx->check_events = sdl_check_events;
2090 ctx->fullscreen = new_vo_sdl_fullscreen;
2091 //the SDL code is hardcoded to use the deprecated vo API
2092 global_vo = vo;
2093 if (vo_sdl_init())
2094 return ctx;
2095 break;
2096 #endif
2098 talloc_free(ctx);
2099 return NULL;
2102 void uninit_mpglcontext(MPGLContext *ctx)
2104 if (!ctx)
2105 return;
2106 ctx->releaseGlContext(ctx);
2107 switch (ctx->type) {
2108 #ifdef CONFIG_GL_WIN32
2109 case GLTYPE_W32:
2110 vo_w32_uninit();
2111 break;
2112 #endif
2113 #ifdef CONFIG_GL_X11
2114 case GLTYPE_X11:
2115 vo_x11_uninit(ctx->vo);
2116 break;
2117 #endif
2118 #ifdef CONFIG_GL_SDL
2119 case GLTYPE_SDL:
2120 vo_sdl_uninit();
2121 break;
2122 #endif
2124 talloc_free(ctx);