Remove unused static variable pass, fixes the warning:
[mplayer/greg.git] / libvo / gl_common.c
blob8c0a70f451cdbad71bed815b83baaf1caff161bb
1 /**
2 * \file gl_common.c
3 * \brief OpenGL helper functions used by vo_gl.c and vo_gl2.c
5 * Common OpenGL routines.
6 * Copyleft (C) Reimar Döffinger <Reimar.Doeffinger@stud.uni-karlsruhe.de>, 2005
7 * Licensed under the GNU GPL v2 or later.
8 * Special thanks go to the xine team and Matthias Hopf, whose video_out_opengl.c
9 * gave me lots of good ideas.
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <math.h>
16 #include "gl_common.h"
18 /**
19 * \defgroup glextfunctions OpenGL extension functions
21 * the pointers to these functions are acquired when the OpenGL
22 * context is created
23 * \{
25 void (APIENTRY *GenBuffers)(GLsizei, GLuint *);
26 void (APIENTRY *DeleteBuffers)(GLsizei, const GLuint *);
27 void (APIENTRY *BindBuffer)(GLenum, GLuint);
28 GLvoid* (APIENTRY *MapBuffer)(GLenum, GLenum);
29 GLboolean (APIENTRY *UnmapBuffer)(GLenum);
30 void (APIENTRY *BufferData)(GLenum, intptr_t, const GLvoid *, GLenum);
31 void (APIENTRY *CombinerParameterfv)(GLenum, const GLfloat *);
32 void (APIENTRY *CombinerParameteri)(GLenum, GLint);
33 void (APIENTRY *CombinerInput)(GLenum, GLenum, GLenum, GLenum, GLenum,
34 GLenum);
35 void (APIENTRY *CombinerOutput)(GLenum, GLenum, GLenum, GLenum, GLenum,
36 GLenum, GLenum, GLboolean, GLboolean,
37 GLboolean);
38 void (APIENTRY *BeginFragmentShader)(void);
39 void (APIENTRY *EndFragmentShader)(void);
40 void (APIENTRY *SampleMap)(GLuint, GLuint, GLenum);
41 void (APIENTRY *ColorFragmentOp2)(GLenum, GLuint, GLuint, GLuint, GLuint,
42 GLuint, GLuint, GLuint, GLuint, GLuint);
43 void (APIENTRY *ColorFragmentOp3)(GLenum, GLuint, GLuint, GLuint, GLuint,
44 GLuint, GLuint, GLuint, GLuint, GLuint,
45 GLuint, GLuint, GLuint);
46 void (APIENTRY *SetFragmentShaderConstant)(GLuint, const GLfloat *);
47 void (APIENTRY *ActiveTexture)(GLenum);
48 void (APIENTRY *BindTexture)(GLenum, GLuint);
49 void (APIENTRY *MultiTexCoord2f)(GLenum, GLfloat, GLfloat);
50 void (APIENTRY *GenPrograms)(GLsizei, GLuint *);
51 void (APIENTRY *DeletePrograms)(GLsizei, const GLuint *);
52 void (APIENTRY *BindProgram)(GLenum, GLuint);
53 void (APIENTRY *ProgramString)(GLenum, GLenum, GLsizei, const GLvoid *);
54 void (APIENTRY *GetProgramiv)(GLenum, GLenum, GLint *);
55 void (APIENTRY *ProgramEnvParameter4f)(GLenum, GLuint, GLfloat, GLfloat,
56 GLfloat, GLfloat);
57 int (APIENTRY *SwapInterval)(int);
58 void (APIENTRY *TexImage3D)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei,
59 GLint, GLenum, GLenum, const GLvoid *);
60 /** \} */ // end of glextfunctions group
62 //! \defgroup glgeneral OpenGL general helper functions
64 //! \defgroup glcontext OpenGL context management helper functions
66 //! \defgroup gltexture OpenGL texture handling helper functions
68 //! \defgroup glconversion OpenGL conversion helper functions
70 static GLint hqtexfmt;
72 /**
73 * \brief adjusts the GL_UNPACK_ALIGNMENT to fit the stride.
74 * \param stride number of bytes per line for which alignment should fit.
75 * \ingroup glgeneral
77 void glAdjustAlignment(int stride) {
78 GLint gl_alignment;
79 if (stride % 8 == 0)
80 gl_alignment=8;
81 else if (stride % 4 == 0)
82 gl_alignment=4;
83 else if (stride % 2 == 0)
84 gl_alignment=2;
85 else
86 gl_alignment=1;
87 glPixelStorei (GL_UNPACK_ALIGNMENT, gl_alignment);
90 struct gl_name_map_struct {
91 GLint value;
92 const char *name;
95 #undef MAP
96 #define MAP(a) {a, #a}
97 //! mapping table for the glValName function
98 static const struct gl_name_map_struct gl_name_map[] = {
99 // internal format
100 MAP(GL_R3_G3_B2), MAP(GL_RGB4), MAP(GL_RGB5), MAP(GL_RGB8),
101 MAP(GL_RGB10), MAP(GL_RGB12), MAP(GL_RGB16), MAP(GL_RGBA2),
102 MAP(GL_RGBA4), MAP(GL_RGB5_A1), MAP(GL_RGBA8), MAP(GL_RGB10_A2),
103 MAP(GL_RGBA12), MAP(GL_RGBA16), MAP(GL_LUMINANCE8),
105 // format
106 MAP(GL_RGB), MAP(GL_RGBA), MAP(GL_RED), MAP(GL_GREEN), MAP(GL_BLUE),
107 MAP(GL_ALPHA), MAP(GL_LUMINANCE), MAP(GL_LUMINANCE_ALPHA),
108 MAP(GL_COLOR_INDEX),
109 // rest 1.2 only
110 MAP(GL_BGR), MAP(GL_BGRA),
112 //type
113 MAP(GL_BYTE), MAP(GL_UNSIGNED_BYTE), MAP(GL_SHORT), MAP(GL_UNSIGNED_SHORT),
114 MAP(GL_INT), MAP(GL_UNSIGNED_INT), MAP(GL_FLOAT), MAP(GL_DOUBLE),
115 MAP(GL_2_BYTES), MAP(GL_3_BYTES), MAP(GL_4_BYTES),
116 // rest 1.2 only
117 MAP(GL_UNSIGNED_BYTE_3_3_2), MAP(GL_UNSIGNED_BYTE_2_3_3_REV),
118 MAP(GL_UNSIGNED_SHORT_5_6_5), MAP(GL_UNSIGNED_SHORT_5_6_5_REV),
119 MAP(GL_UNSIGNED_SHORT_4_4_4_4), MAP(GL_UNSIGNED_SHORT_4_4_4_4_REV),
120 MAP(GL_UNSIGNED_SHORT_5_5_5_1), MAP(GL_UNSIGNED_SHORT_1_5_5_5_REV),
121 MAP(GL_UNSIGNED_INT_8_8_8_8), MAP(GL_UNSIGNED_INT_8_8_8_8_REV),
122 MAP(GL_UNSIGNED_INT_10_10_10_2), MAP(GL_UNSIGNED_INT_2_10_10_10_REV),
123 {0, 0}
125 #undef MAP
128 * \brief return the name of an OpenGL constant
129 * \param value the constant
130 * \return name of the constant or "Unknown format!"
131 * \ingroup glgeneral
133 const char *glValName(GLint value)
135 int i = 0;
137 while (gl_name_map[i].name) {
138 if (gl_name_map[i].value == value)
139 return gl_name_map[i].name;
140 i++;
142 return "Unknown format!";
145 //! always return this format as internal texture format in glFindFormat
146 #define TEXTUREFORMAT_ALWAYS GL_RGB8
147 #undef TEXTUREFORMAT_ALWAYS
150 * \brief find the OpenGL settings coresponding to format.
152 * All parameters may be NULL.
153 * \param fmt MPlayer format to analyze.
154 * \param bpp [OUT] bits per pixel of that format.
155 * \param gl_texfmt [OUT] internal texture format that fits the
156 * image format, not necessarily the best for performance.
157 * \param gl_format [OUT] OpenGL format for this image format.
158 * \param gl_type [OUT] OpenGL type for this image format.
159 * \return 1 if format is supported by OpenGL, 0 if not.
160 * \ingroup gltexture
162 int glFindFormat(uint32_t fmt, int *bpp, GLint *gl_texfmt,
163 GLenum *gl_format, GLenum *gl_type)
165 int supported = 1;
166 int dummy1;
167 GLenum dummy2;
168 GLint dummy3;
169 if (bpp == NULL) bpp = &dummy1;
170 if (gl_texfmt == NULL) gl_texfmt = &dummy3;
171 if (gl_format == NULL) gl_format = &dummy2;
172 if (gl_type == NULL) gl_type = &dummy2;
174 *bpp = IMGFMT_IS_BGR(fmt)?IMGFMT_BGR_DEPTH(fmt):IMGFMT_RGB_DEPTH(fmt);
175 *gl_texfmt = 3;
176 switch (fmt) {
177 case IMGFMT_RGB24:
178 *gl_format = GL_RGB;
179 *gl_type = GL_UNSIGNED_BYTE;
180 break;
181 case IMGFMT_RGBA:
182 *gl_texfmt = 4;
183 *gl_format = GL_RGBA;
184 *gl_type = GL_UNSIGNED_BYTE;
185 break;
186 case IMGFMT_YV12:
187 supported = 0; // no native YV12 support
188 case IMGFMT_Y800:
189 case IMGFMT_Y8:
190 *gl_texfmt = 1;
191 *bpp = 8;
192 *gl_format = GL_LUMINANCE;
193 *gl_type = GL_UNSIGNED_BYTE;
194 break;
195 #if 0
196 // we do not support palettized formats, although the format the
197 // swscale produces works
198 case IMGFMT_RGB8:
199 gl_format = GL_RGB;
200 gl_type = GL_UNSIGNED_BYTE_2_3_3_REV;
201 break;
202 #endif
203 case IMGFMT_RGB15:
204 *gl_format = GL_RGBA;
205 *gl_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
206 break;
207 case IMGFMT_RGB16:
208 *gl_format = GL_RGB;
209 *gl_type = GL_UNSIGNED_SHORT_5_6_5_REV;
210 break;
211 #if 0
212 case IMGFMT_BGR8:
213 // special case as red and blue have a differen number of bits.
214 // GL_BGR and GL_UNSIGNED_BYTE_3_3_2 isn't supported at least
215 // by nVidia drivers, and in addition would give more bits to
216 // blue than to red, which isn't wanted
217 gl_format = GL_RGB;
218 gl_type = GL_UNSIGNED_BYTE_3_3_2;
219 break;
220 #endif
221 case IMGFMT_BGR15:
222 *gl_format = GL_BGRA;
223 *gl_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
224 break;
225 case IMGFMT_BGR16:
226 *gl_format = GL_RGB;
227 *gl_type = GL_UNSIGNED_SHORT_5_6_5;
228 break;
229 case IMGFMT_BGR24:
230 *gl_format = GL_BGR;
231 *gl_type = GL_UNSIGNED_BYTE;
232 break;
233 case IMGFMT_BGRA:
234 *gl_texfmt = 4;
235 *gl_format = GL_BGRA;
236 *gl_type = GL_UNSIGNED_BYTE;
237 break;
238 default:
239 *gl_texfmt = 4;
240 *gl_format = GL_RGBA;
241 *gl_type = GL_UNSIGNED_BYTE;
242 supported = 0;
244 #ifdef TEXTUREFORMAT_ALWAYS
245 *gl_texfmt = TEXTUREFORMAT_ALWAYS;
246 #endif
247 return supported;
250 static void *setNull(const GLubyte *s) {
251 return NULL;
254 typedef struct {
255 void **funcptr;
256 const char *extstr;
257 const char *funcnames[7];
258 } extfunc_desc_t;
260 static const extfunc_desc_t extfuncs[] = {
261 {(void **)&GenBuffers, NULL, {"glGenBuffers", "glGenBuffersARB", NULL}},
262 {(void **)&DeleteBuffers, NULL, {"glDeleteBuffers", "glDeleteBuffersARB", NULL}},
263 {(void **)&BindBuffer, NULL, {"glBindBuffer", "glBindBufferARB", NULL}},
264 {(void **)&MapBuffer, NULL, {"glMapBuffer", "glMapBufferARB", NULL}},
265 {(void **)&UnmapBuffer, NULL, {"glUnmapBuffer", "glUnmapBufferARB", NULL}},
266 {(void **)&BufferData, NULL, {"glBufferData", "glBufferDataARB", NULL}},
267 {(void **)&CombinerParameterfv, "NV_register_combiners", {"glCombinerParameterfv", "glCombinerParameterfvNV", NULL}},
268 {(void **)&CombinerParameteri, "NV_register_combiners", {"glCombinerParameteri", "glCombinerParameteriNV", NULL}},
269 {(void **)&CombinerInput, "NV_register_combiners", {"glCombinerInput", "glCombinerInputNV", NULL}},
270 {(void **)&CombinerOutput, "NV_register_combiners", {"glCombinerOutput", "glCombinerOutputNV", NULL}},
271 {(void **)&BeginFragmentShader, "ATI_fragment_shader", {"glBeginFragmentShaderATI", NULL}},
272 {(void **)&EndFragmentShader, "ATI_fragment_shader", {"glEndFragmentShaderATI", NULL}},
273 {(void **)&SampleMap, "ATI_fragment_shader", {"glSampleMapATI", NULL}},
274 {(void **)&ColorFragmentOp2, "ATI_fragment_shader", {"glColorFragmentOp2ATI", NULL}},
275 {(void **)&ColorFragmentOp3, "ATI_fragment_shader", {"glColorFragmentOp3ATI", NULL}},
276 {(void **)&SetFragmentShaderConstant, "ATI_fragment_shader", {"glSetFragmentShaderConstantATI", NULL}},
277 {(void **)&ActiveTexture, NULL, {"glActiveTexture", "glActiveTextureARB", NULL}},
278 {(void **)&BindTexture, NULL, {"glBindTexture", "glBindTextureARB", "glBindTextureEXT", NULL}},
279 {(void **)&MultiTexCoord2f, NULL, {"glMultiTexCoord2f", "glMultiTexCoord2fARB", NULL}},
280 {(void **)&GenPrograms, "_program", {"glGenProgramsARB", NULL}},
281 {(void **)&DeletePrograms, "_program", {"glDeleteProgramsARB", NULL}},
282 {(void **)&BindProgram, "_program", {"glBindProgramARB", NULL}},
283 {(void **)&ProgramString, "_program", {"glProgramStringARB", NULL}},
284 {(void **)&GetProgramiv, "_program", {"glGetProgramivARB", NULL}},
285 {(void **)&ProgramEnvParameter4f, "_program", {"glProgramEnvParameter4fARB", NULL}},
286 {(void **)&SwapInterval, "_swap_control", {"glXSwapInterval", "glXSwapIntervalEXT", "glXSwapIntervalSGI", "wglSwapInterval", "wglSwapIntervalEXT", "wglSwapIntervalSGI", NULL}},
287 {(void **)&TexImage3D, NULL, {"glTexImage3D", NULL}},
288 {NULL}
292 * \brief find the function pointers of some useful OpenGL extensions
293 * \param getProcAddress function to resolve function names, may be NULL
294 * \param ext2 an extra extension string
296 static void getFunctions(void *(*getProcAddress)(const GLubyte *),
297 const char *ext2) {
298 const extfunc_desc_t *dsc;
299 const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
300 char *allexts;
301 if (!extensions) extensions = "";
302 if (!ext2) ext2 = "";
303 allexts = malloc(strlen(extensions) + strlen(ext2) + 2);
304 strcpy(allexts, extensions);
305 strcat(allexts, " ");
306 strcat(allexts, ext2);
307 mp_msg(MSGT_VO, MSGL_V, "OpenGL extensions string:\n%s\n", allexts);
308 if (!getProcAddress)
309 getProcAddress = setNull;
310 for (dsc = extfuncs; dsc->funcptr; dsc++) {
311 void *ptr = NULL;
312 int i;
313 if (!dsc->extstr || strstr(allexts, dsc->extstr)) {
314 for (i = 0; !ptr && dsc->funcnames[i]; i++)
315 ptr = getProcAddress((const GLubyte *)dsc->funcnames[i]);
317 *(dsc->funcptr) = ptr;
319 if (strstr(allexts, "_texture_float"))
320 hqtexfmt = GL_RGB32F;
321 else if (strstr(allexts, "NV_float_buffer"))
322 hqtexfmt = GL_FLOAT_RGB32_NV;
323 else
324 hqtexfmt = GL_RGB16;
325 free(allexts);
329 * \brief create a texture and set some defaults
330 * \param target texture taget, usually GL_TEXTURE_2D
331 * \param fmt internal texture format
332 * \param filter filter used for scaling, e.g. GL_LINEAR
333 * \param w texture width
334 * \param h texture height
335 * \param val luminance value to fill texture with
336 * \ingroup gltexture
338 void glCreateClearTex(GLenum target, GLenum fmt, GLint filter,
339 int w, int h, unsigned char val) {
340 GLfloat fval = (GLfloat)val / 255.0;
341 GLfloat border[4] = {fval, fval, fval, fval};
342 GLenum clrfmt = (fmt == GL_ALPHA) ? GL_ALPHA : GL_LUMINANCE;
343 char *init = malloc(w * h);
344 memset(init, val, w * h);
345 glAdjustAlignment(w);
346 glPixelStorei(GL_UNPACK_ROW_LENGTH, w);
347 glTexImage2D(target, 0, fmt, w, h, 0, clrfmt, GL_UNSIGNED_BYTE, init);
348 glTexParameterf(target, GL_TEXTURE_PRIORITY, 1.0);
349 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
350 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
351 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
352 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
353 // Border texels should not be used with CLAMP_TO_EDGE
354 // We set a sane default anyway.
355 glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, border);
356 free(init);
360 * \brief skips whitespace and comments
361 * \param f file to read from
363 static void ppm_skip(FILE *f) {
364 int c, comment = 0;
365 do {
366 c = fgetc(f);
367 if (c == '#')
368 comment = 1;
369 if (c == '\n')
370 comment = 0;
371 } while (c != EOF && (isspace(c) || comment));
372 if (c != EOF)
373 ungetc(c, f);
376 #define MAXDIM (16 * 1024)
379 * \brief creates a texture from a PPM file
380 * \param target texture taget, usually GL_TEXTURE_2D
381 * \param fmt internal texture format, 0 for default
382 * \param filter filter used for scaling, e.g. GL_LINEAR
383 * \param f file to read PPM from
384 * \param width [out] width of texture
385 * \param height [out] height of texture
386 * \param maxval [out] maxval value from PPM file
387 * \return 0 on error, 1 otherwise
388 * \ingroup gltexture
390 int glCreatePPMTex(GLenum target, GLenum fmt, GLint filter,
391 FILE *f, int *width, int *height, int *maxval) {
392 unsigned w, h, m, val, bpp;
393 char *data;
394 ppm_skip(f);
395 if (fgetc(f) != 'P' || fgetc(f) != '6')
396 return 0;
397 ppm_skip(f);
398 if (fscanf(f, "%u", &w) != 1)
399 return 0;
400 ppm_skip(f);
401 if (fscanf(f, "%u", &h) != 1)
402 return 0;
403 ppm_skip(f);
404 if (fscanf(f, "%u", &m) != 1)
405 return 0;
406 val = fgetc(f);
407 if (!isspace(val))
408 return 0;
409 if (w > MAXDIM || h > MAXDIM)
410 return 0;
411 bpp = (m > 255) ? 6 : 3;
412 data = malloc(w * h * bpp);
413 if (fread(data, w * bpp, h, f) != h)
414 return 0;
415 if (!fmt) {
416 fmt = (m > 255) ? hqtexfmt : 3;
417 if (fmt == GL_FLOAT_RGB32_NV && target != GL_TEXTURE_RECTANGLE)
418 fmt = GL_RGB16;
420 glCreateClearTex(target, fmt, filter, w, h, 0);
421 glUploadTex(target, GL_RGB, (m > 255) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE,
422 data, w * bpp, 0, 0, w, h, 0);
423 free(data);
424 if (width) *width = w;
425 if (height) *height = h;
426 if (maxval) *maxval = m;
427 return 1;
431 * \brief return the number of bytes per pixel for the given format
432 * \param format OpenGL format
433 * \param type OpenGL type
434 * \return bytes per pixel
435 * \ingroup glgeneral
437 * Does not handle all possible variants, just those used by MPlayer
439 int glFmt2bpp(GLenum format, GLenum type) {
440 int component_size = 0;
441 switch (type) {
442 case GL_UNSIGNED_BYTE_3_3_2:
443 case GL_UNSIGNED_BYTE_2_3_3_REV:
444 return 1;
445 case GL_UNSIGNED_SHORT_5_5_5_1:
446 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
447 case GL_UNSIGNED_SHORT_5_6_5:
448 case GL_UNSIGNED_SHORT_5_6_5_REV:
449 return 2;
450 case GL_UNSIGNED_BYTE:
451 component_size = 1;
452 break;
453 case GL_UNSIGNED_SHORT:
454 component_size = 2;
455 break;
457 switch (format) {
458 case GL_LUMINANCE:
459 case GL_ALPHA:
460 return component_size;
461 case GL_RGB:
462 case GL_BGR:
463 return 3 * component_size;
464 case GL_RGBA:
465 case GL_BGRA:
466 return 4 * component_size;
468 return 0; // unknown
472 * \brief upload a texture, handling things like stride and slices
473 * \param target texture target, usually GL_TEXTURE_2D
474 * \param format OpenGL format of data
475 * \param type OpenGL type of data
476 * \param dataptr data to upload
477 * \param stride data stride
478 * \param x x offset in texture
479 * \param y y offset in texture
480 * \param w width of the texture part to upload
481 * \param h height of the texture part to upload
482 * \param slice height of an upload slice, 0 for all at once
483 * \ingroup gltexture
485 void glUploadTex(GLenum target, GLenum format, GLenum type,
486 const void *dataptr, int stride,
487 int x, int y, int w, int h, int slice) {
488 const uint8_t *data = dataptr;
489 int y_max = y + h;
490 if (w <= 0 || h <= 0) return;
491 if (slice <= 0)
492 slice = h;
493 if (stride < 0) {
494 data += (h - 1) * stride;
495 stride = -stride;
497 // this is not always correct, but should work for MPlayer
498 glAdjustAlignment(stride);
499 glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / glFmt2bpp(format, type));
500 for (; y + slice <= y_max; y += slice) {
501 glTexSubImage2D(target, 0, x, y, w, slice, format, type, data);
502 data += stride * slice;
504 if (y < y_max)
505 glTexSubImage2D(target, 0, x, y, w, y_max - y, format, type, data);
508 static void fillUVcoeff(GLfloat *ucoef, GLfloat *vcoef,
509 float uvcos, float uvsin) {
510 int i;
511 ucoef[0] = 0 * uvcos + 1.403 * uvsin;
512 vcoef[0] = 0 * uvsin + 1.403 * uvcos;
513 ucoef[1] = -0.344 * uvcos + -0.714 * uvsin;
514 vcoef[1] = -0.344 * uvsin + -0.714 * uvcos;
515 ucoef[2] = 1.770 * uvcos + 0 * uvsin;
516 vcoef[2] = 1.770 * uvsin + 0 * uvcos;
517 ucoef[3] = 0;
518 vcoef[3] = 0;
519 // Coefficients (probably) must be in [0, 1] range, whereas they originally
520 // are in [-2, 2] range, so here comes the trick:
521 // First put them in the [-0.5, 0.5] range, then add 0.5.
522 // This can be undone with the HALF_BIAS and SCALE_BY_FOUR arguments
523 // for CombinerInput and CombinerOutput (or the respective ATI variants)
524 for (i = 0; i < 4; i++) {
525 ucoef[i] = ucoef[i] * 0.25 + 0.5;
526 vcoef[i] = vcoef[i] * 0.25 + 0.5;
531 * \brief Setup register combiners for YUV to RGB conversion.
532 * \param uvcos used for saturation and hue adjustment
533 * \param uvsin used for saturation and hue adjustment
535 static void glSetupYUVCombiners(float uvcos, float uvsin) {
536 GLfloat ucoef[4];
537 GLfloat vcoef[4];
538 GLint i;
539 if (!CombinerInput || !CombinerOutput ||
540 !CombinerParameterfv || !CombinerParameteri) {
541 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner functions missing!\n");
542 return;
544 glGetIntegerv(GL_MAX_GENERAL_COMBINERS_NV, &i);
545 if (i < 2)
546 mp_msg(MSGT_VO, MSGL_ERR,
547 "[gl] 2 general combiners needed for YUV combiner support (found %i)\n", i);
548 glGetIntegerv (GL_MAX_TEXTURE_UNITS, &i);
549 if (i < 3)
550 mp_msg(MSGT_VO, MSGL_ERR,
551 "[gl] 3 texture units needed for YUV combiner support (found %i)\n", i);
552 fillUVcoeff(ucoef, vcoef, uvcos, uvsin);
553 CombinerParameterfv(GL_CONSTANT_COLOR0_NV, ucoef);
554 CombinerParameterfv(GL_CONSTANT_COLOR1_NV, vcoef);
556 // UV first, like this green component cannot overflow
557 CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
558 GL_TEXTURE1, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
559 CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
560 GL_CONSTANT_COLOR0_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
561 CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV,
562 GL_TEXTURE2, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
563 CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV,
564 GL_CONSTANT_COLOR1_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
565 CombinerOutput(GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV,
566 GL_SPARE0_NV, GL_SCALE_BY_FOUR_NV, GL_NONE, GL_FALSE,
567 GL_FALSE, GL_FALSE);
569 // stage 2
570 CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_SPARE0_NV,
571 GL_SIGNED_IDENTITY_NV, GL_RGB);
572 CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO,
573 GL_UNSIGNED_INVERT_NV, GL_RGB);
574 CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_C_NV,
575 GL_TEXTURE0, GL_SIGNED_IDENTITY_NV, GL_RGB);
576 CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO,
577 GL_UNSIGNED_INVERT_NV, GL_RGB);
578 CombinerOutput(GL_COMBINER1_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV,
579 GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE,
580 GL_FALSE, GL_FALSE);
582 // leave final combiner stage in default mode
583 CombinerParameteri(GL_NUM_GENERAL_COMBINERS_NV, 2);
587 * \brief Setup ATI version of register combiners for YUV to RGB conversion.
588 * \param uvcos used for saturation and hue adjustment
589 * \param uvsin used for saturation and hue adjustment
591 * ATI called this fragment shader, but the name is confusing in the
592 * light of a very different OpenGL 2.0 extension with the same name
594 static void glSetupYUVCombinersATI(float uvcos, float uvsin) {
595 GLfloat ucoef[4];
596 GLfloat vcoef[4];
597 GLint i;
598 if (!BeginFragmentShader || !EndFragmentShader ||
599 !SetFragmentShaderConstant || !SampleMap ||
600 !ColorFragmentOp2 || !ColorFragmentOp3) {
601 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner (ATI) functions missing!\n");
602 return;
604 glGetIntegerv(GL_NUM_FRAGMENT_REGISTERS_ATI, &i);
605 if (i < 3)
606 mp_msg(MSGT_VO, MSGL_ERR,
607 "[gl] 3 registers needed for YUV combiner (ATI) support (found %i)\n", i);
608 glGetIntegerv (GL_MAX_TEXTURE_UNITS, &i);
609 if (i < 3)
610 mp_msg(MSGT_VO, MSGL_ERR,
611 "[gl] 3 texture units needed for YUV combiner (ATI) support (found %i)\n", i);
612 fillUVcoeff(ucoef, vcoef, uvcos, uvsin);
613 BeginFragmentShader();
614 SetFragmentShaderConstant(GL_CON_0_ATI, ucoef);
615 SetFragmentShaderConstant(GL_CON_1_ATI, vcoef);
616 SampleMap(GL_REG_0_ATI, GL_TEXTURE0, GL_SWIZZLE_STR_ATI);
617 SampleMap(GL_REG_1_ATI, GL_TEXTURE1, GL_SWIZZLE_STR_ATI);
618 SampleMap(GL_REG_2_ATI, GL_TEXTURE2, GL_SWIZZLE_STR_ATI);
619 // UV first, like this green component cannot overflow
620 ColorFragmentOp2(GL_MUL_ATI, GL_REG_1_ATI, GL_NONE, GL_NONE,
621 GL_REG_1_ATI, GL_NONE, GL_BIAS_BIT_ATI,
622 GL_CON_0_ATI, GL_NONE, GL_BIAS_BIT_ATI);
623 ColorFragmentOp3(GL_MAD_ATI, GL_REG_2_ATI, GL_NONE, GL_4X_BIT_ATI,
624 GL_REG_2_ATI, GL_NONE, GL_BIAS_BIT_ATI,
625 GL_CON_1_ATI, GL_NONE, GL_BIAS_BIT_ATI,
626 GL_REG_1_ATI, GL_NONE, GL_NONE);
627 ColorFragmentOp2(GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
628 GL_REG_0_ATI, GL_NONE, GL_NONE,
629 GL_REG_2_ATI, GL_NONE, GL_NONE);
630 EndFragmentShader();
634 * \brief helper function for gen_spline_lookup_tex
635 * \param x subpixel-position ((0,1) range) to calculate weights for
636 * \param dst where to store transformed weights, must provide space for 4 GLfloats
638 * calculates the weights and stores them after appropriate transformation
639 * for the scaler fragment program.
641 static void store_weights(float x, GLfloat *dst) {
642 float w0 = (((-1 * x + 3) * x - 3) * x + 1) / 6;
643 float w1 = ((( 3 * x - 6) * x + 0) * x + 4) / 6;
644 float w2 = (((-3 * x + 3) * x + 3) * x + 1) / 6;
645 float w3 = ((( 1 * x + 0) * x + 0) * x + 0) / 6;
646 *dst++ = 1 + x - w1 / (w0 + w1);
647 *dst++ = 1 - x + w3 / (w2 + w3);
648 *dst++ = w0 + w1;
649 *dst++ = 0;
652 //! to avoid artefacts this should be rather large
653 #define LOOKUP_BSPLINE_RES (2 * 1024)
655 * \brief creates the 1D lookup texture needed for fast higher-order filtering
656 * \param unit texture unit to attach texture to
658 static void gen_spline_lookup_tex(GLenum unit) {
659 GLfloat tex[4 * LOOKUP_BSPLINE_RES];
660 GLfloat *tp = tex;
661 int i;
662 for (i = 0; i < LOOKUP_BSPLINE_RES; i++) {
663 float x = (float)(i + 0.5) / LOOKUP_BSPLINE_RES;
664 store_weights(x, tp);
665 tp += 4;
667 store_weights(0, tex);
668 store_weights(1, &tex[4 * (LOOKUP_BSPLINE_RES - 1)]);
669 ActiveTexture(unit);
670 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA16, LOOKUP_BSPLINE_RES, 0, GL_RGBA, GL_FLOAT, tex);
671 glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_PRIORITY, 1.0);
672 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
673 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
674 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
675 ActiveTexture(GL_TEXTURE0);
678 static const char *bilin_filt_template =
679 "TEX yuv.%c, fragment.texcoord[%c], texture[%c], %s;";
681 #define BICUB_FILT_MAIN(textype) \
682 /* first y-interpolation */ \
683 "ADD coord, fragment.texcoord[%c].xyxy, cdelta.xyxw;" \
684 "ADD coord2, fragment.texcoord[%c].xyxy, cdelta.zyzw;" \
685 "TEX a.r, coord.xyxy, texture[%c], "textype";" \
686 "TEX a.g, coord.zwzw, texture[%c], "textype";" \
687 /* second y-interpolation */ \
688 "TEX b.r, coord2.xyxy, texture[%c], "textype";" \
689 "TEX b.g, coord2.zwzw, texture[%c], "textype";" \
690 "LRP a.b, parmy.b, a.rrrr, a.gggg;" \
691 "LRP a.a, parmy.b, b.rrrr, b.gggg;" \
692 /* x-interpolation */ \
693 "LRP yuv.%c, parmx.b, a.bbbb, a.aaaa;"
695 static const char *bicub_filt_template_2D =
696 "MAD coord.xy, fragment.texcoord[%c], {%f, %f}, {0.5, 0.5};"
697 "TEX parmx, coord.x, texture[%c], 1D;"
698 "MUL cdelta.xz, parmx.rrgg, {-%f, 0, %f, 0};"
699 "TEX parmy, coord.y, texture[%c], 1D;"
700 "MUL cdelta.yw, parmy.rrgg, {0, -%f, 0, %f};"
701 BICUB_FILT_MAIN("2D");
703 static const char *bicub_filt_template_RECT =
704 "ADD coord, fragment.texcoord[%c], {0.5, 0.5};"
705 "TEX parmx, coord.x, texture[%c], 1D;"
706 "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};"
707 "TEX parmy, coord.y, texture[%c], 1D;"
708 "MUL cdelta.yw, parmy.rrgg, {0, -1, 0, 1};"
709 BICUB_FILT_MAIN("RECT");
711 #define CALCWEIGHTS(t, s) \
712 "MAD "t", {-0.5, 0.1666, 0.3333, -0.3333}, "s", {1, 0, -0.5, 0.5};" \
713 "MAD "t", "t", "s", {0, 0, -0.5, 0.5};" \
714 "MAD "t", "t", "s", {-0.6666, 0, 0.8333, 0.1666};" \
715 "RCP a.x, "t".z;" \
716 "RCP a.y, "t".w;" \
717 "MAD "t".xy, "t".xyxy, a.xyxy, {1, 1, 0, 0};" \
718 "ADD "t".x, "t".xxxx, "s";" \
719 "SUB "t".y, "t".yyyy, "s";"
721 static const char *bicub_notex_filt_template_2D =
722 "MAD coord.xy, fragment.texcoord[%c], {%f, %f}, {0.5, 0.5};"
723 "FRC coord.xy, coord.xyxy;"
724 CALCWEIGHTS("parmx", "coord.xxxx")
725 "MUL cdelta.xz, parmx.rrgg, {-%f, 0, %f, 0};"
726 CALCWEIGHTS("parmy", "coord.yyyy")
727 "MUL cdelta.yw, parmy.rrgg, {0, -%f, 0, %f};"
728 BICUB_FILT_MAIN("2D");
730 static const char *bicub_notex_filt_template_RECT =
731 "ADD coord, fragment.texcoord[%c], {0.5, 0.5};"
732 "FRC coord.xy, coord.xyxy;"
733 CALCWEIGHTS("parmx", "coord.xxxx")
734 "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};"
735 CALCWEIGHTS("parmy", "coord.yyyy")
736 "MUL cdelta.yw, parmy.rrgg, {0, -1, 0, 1};"
737 BICUB_FILT_MAIN("RECT");
739 #define BICUB_X_FILT_MAIN(textype) \
740 "ADD coord, fragment.texcoord[%c].xyxy, cdelta.xyxw;" \
741 "ADD coord2, fragment.texcoord[%c].xyxy, cdelta.zyzw;" \
742 "TEX a.r, coord, texture[%c], "textype";" \
743 "TEX b.r, coord2, texture[%c], "textype";" \
744 /* x-interpolation */ \
745 "LRP yuv.%c, parmx.b, a.rrrr, b.rrrr;"
747 static const char *bicub_x_filt_template_2D =
748 "MAD coord.x, fragment.texcoord[%c], {%f, %f}, {0.5, 0.5};"
749 "TEX parmx, coord, texture[%c], 1D;"
750 "MUL cdelta.xz, parmx.rrgg, {-%f, 0, %f, 0};"
751 BICUB_X_FILT_MAIN("2D");
753 static const char *bicub_x_filt_template_RECT =
754 "ADD coord.x, fragment.texcoord[%c], {0.5, 0.5};"
755 "TEX parmx, coord, texture[%c], 1D;"
756 "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};"
757 BICUB_X_FILT_MAIN("RECT");
759 static const char *yuv_prog_template =
760 "PARAM ycoef = {%.4f, %.4f, %.4f};"
761 "PARAM ucoef = {%.4f, %.4f, %.4f};"
762 "PARAM vcoef = {%.4f, %.4f, %.4f};"
763 "PARAM offsets = {%.4f, %.4f, %.4f};"
764 "TEMP res;"
765 "MAD res.rgb, yuv.rrrr, ycoef, offsets;"
766 "MAD res.rgb, yuv.gggg, ucoef, res;"
767 "MAD result.color.rgb, yuv.bbbb, vcoef, res;"
768 "END";
770 static const char *yuv_pow_prog_template =
771 "PARAM ycoef = {%.4f, %.4f, %.4f};"
772 "PARAM ucoef = {%.4f, %.4f, %.4f};"
773 "PARAM vcoef = {%.4f, %.4f, %.4f};"
774 "PARAM offsets = {%.4f, %.4f, %.4f};"
775 "PARAM gamma = {%.4f, %.4f, %.4f};"
776 "TEMP res;"
777 "MAD res.rgb, yuv.rrrr, ycoef, offsets;"
778 "MAD res.rgb, yuv.gggg, ucoef, res;"
779 "MAD_SAT res.rgb, yuv.bbbb, vcoef, res;"
780 "POW result.color.r, res.r, gamma.r;"
781 "POW result.color.g, res.g, gamma.g;"
782 "POW result.color.b, res.b, gamma.b;"
783 "END";
785 static const char *yuv_lookup_prog_template =
786 "PARAM ycoef = {%.4f, %.4f, %.4f, 0};"
787 "PARAM ucoef = {%.4f, %.4f, %.4f, 0};"
788 "PARAM vcoef = {%.4f, %.4f, %.4f, 0};"
789 "PARAM offsets = {%.4f, %.4f, %.4f, 0.125};"
790 "TEMP res;"
791 "MAD res, yuv.rrrr, ycoef, offsets;"
792 "MAD res.rgb, yuv.gggg, ucoef, res;"
793 "MAD res.rgb, yuv.bbbb, vcoef, res;"
794 "TEX result.color.r, res.raaa, texture[%c], 2D;"
795 "ADD res.a, res.a, 0.25;"
796 "TEX result.color.g, res.gaaa, texture[%c], 2D;"
797 "ADD res.a, res.a, 0.25;"
798 "TEX result.color.b, res.baaa, texture[%c], 2D;"
799 "END";
801 static const char *yuv_lookup3d_prog_template =
802 "TEX result.color, yuv, texture[%c], 3D;"
803 "END";
806 * \brief creates and initializes helper textures needed for scaling texture read
807 * \param scaler scaler type to create texture for
808 * \param texu contains next free texture unit number
809 * \param texs texture unit ids for the scaler are stored in this array
811 static void create_scaler_textures(int scaler, int *texu, char *texs) {
812 switch (scaler) {
813 case YUV_SCALER_BILIN:
814 break;
815 case YUV_SCALER_BICUB:
816 case YUV_SCALER_BICUB_X:
817 texs[0] = (*texu)++;
818 gen_spline_lookup_tex(GL_TEXTURE0 + texs[0]);
819 texs[0] += '0';
820 break;
821 default:
822 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown scaler type %i\n", scaler);
826 static void gen_gamma_map(unsigned char *map, int size, float gamma);
828 static void get_yuv2rgb_coeffs(float brightness, float contrast, float uvcos, float uvsin,
829 float *ry, float *ru, float *rv, float *rc,
830 float *gy, float *gu, float *gv, float *gc,
831 float *by, float *bu, float *bv, float *bc) {
832 *ry = 1.164 * contrast;
833 *gy = 1.164 * contrast;
834 *by = 1.164 * contrast;
835 *ru = 0 * uvcos + 1.596 * uvsin;
836 *rv = 0 * uvsin + 1.596 * uvcos;
837 *gu = -0.391 * uvcos + -0.813 * uvsin;
838 *gv = -0.391 * uvsin + -0.813 * uvcos;
839 *bu = 2.018 * uvcos + 0 * uvsin;
840 *bv = 2.018 * uvsin + 0 * uvcos;
841 *rc = (-16 * *ry + (-128) * *ru + (-128) * *rv) / 255.0 + brightness;
842 *gc = (-16 * *gy + (-128) * *gu + (-128) * *gv) / 255.0 + brightness;
843 *bc = (-16 * *by + (-128) * *bu + (-128) * *bv) / 255.0 + brightness;
844 // these "center" contrast control so that e.g. a contrast of 0
845 // leads to a grey image, not a black one
846 *rc += 0.5 - contrast / 2.0;
847 *gc += 0.5 - contrast / 2.0;
848 *bc += 0.5 - contrast / 2.0;
851 //! size of gamma map use to avoid slow exp function in gen_yuv2rgb_map
852 #define GMAP_SIZE (1024)
854 * \brief generate a 3D YUV -> RGB map
855 * \param map where to store map. Must provide space for (size + 2)^3 elements
856 * \param size size of the map, excluding border
857 * \param brightness desired brightness adjustment for conversion
858 * \param contrast desired contrast adjustment for conversion
859 * \param uvcos desired hue/saturation adjustment for conversion
860 * \param uvsin desired hue/saturation adjustment for conversion
861 * \param rgamma desired red gamma adjustment for conversion
862 * \param ggamma desired green gamma adjustment for conversion
863 * \param bgamma desired blue gamma adjustment for conversion
865 static void gen_yuv2rgb_map(unsigned char *map, int size, float brightness,
866 float contrast, float uvcos, float uvsin,
867 float rgamma, float ggamma, float bgamma) {
868 int i, j, k;
869 float step = 1.0 / size;
870 float y, u, v;
871 float r, g, b;
872 float ry, ru, rv, rc;
873 float gy, gu, gv, gc;
874 float by, bu, bv, bc;
875 unsigned char gmaps[3][GMAP_SIZE];
876 gen_gamma_map(gmaps[0], GMAP_SIZE, rgamma);
877 gen_gamma_map(gmaps[1], GMAP_SIZE, ggamma);
878 gen_gamma_map(gmaps[2], GMAP_SIZE, bgamma);
879 get_yuv2rgb_coeffs(brightness, contrast, uvcos, uvsin,
880 &ry, &ru, &rv, &rc, &gy, &gu, &gv, &gc, &by, &bu, &bv, &bc);
881 ry *= GMAP_SIZE - 1; ru *= GMAP_SIZE - 1; rv *= GMAP_SIZE - 1; rc *= GMAP_SIZE - 1;
882 gy *= GMAP_SIZE - 1; gu *= GMAP_SIZE - 1; gv *= GMAP_SIZE - 1; gc *= GMAP_SIZE - 1;
883 by *= GMAP_SIZE - 1; bu *= GMAP_SIZE - 1; bv *= GMAP_SIZE - 1; bc *= GMAP_SIZE - 1;
884 v = 0;
885 for (i = -1; i <= size; i++) {
886 u = 0;
887 for (j = -1; j <= size; j++) {
888 y = 0;
889 for (k = -1; k <= size; k++) {
890 r = ry * y + ru * u + rv * v + rc;
891 g = gy * y + gu * u + gv * v + gc;
892 b = by * y + bu * u + bv * v + bc;
893 if (r > GMAP_SIZE - 1) r = GMAP_SIZE - 1;
894 if (r < 0) r = 0;
895 if (g > GMAP_SIZE - 1) g = GMAP_SIZE - 1;
896 if (g < 0) g = 0;
897 if (b > GMAP_SIZE - 1) b = GMAP_SIZE - 1;
898 if (b < 0) b = 0;
899 *map++ = gmaps[0][(int)r];
900 *map++ = gmaps[1][(int)g];
901 *map++ = gmaps[2][(int)b];
902 y += (k == -1 || k == size - 1) ? step / 2 : step;
904 u += (j == -1 || j == size - 1) ? step / 2 : step;
906 v += (i == -1 || i == size - 1) ? step / 2 : step;
910 //! resolution of texture for gamma lookup table
911 #define LOOKUP_RES 512
912 //! resolution for 3D yuv->rgb conversion lookup table
913 #define LOOKUP_3DRES 32
915 * \brief creates and initializes helper textures needed for yuv conversion
916 * \param texu contains next free texture unit number
917 * \param texs texture unit ids for the conversion are stored in this array
918 * \param brightness desired brightness adjustment for conversion
919 * \param contrast desired contrast adjustment for conversion
920 * \param uvcos desired hue/saturation adjustment for conversion
921 * \param uvsin desired hue/saturation adjustment for conversion
922 * \param rgamma desired red gamma adjustment for conversion
923 * \param ggamma desired green gamma adjustment for conversion
924 * \param bgamma desired blue gamma adjustment for conversion
926 static void create_conv_textures(int conv, int *texu, char *texs,
927 float brightness, float contrast, float uvcos, float uvsin,
928 float rgamma, float ggamma, float bgamma) {
929 unsigned char *lookup_data = NULL;
930 switch (conv) {
931 case YUV_CONVERSION_FRAGMENT:
932 case YUV_CONVERSION_FRAGMENT_POW:
933 break;
934 case YUV_CONVERSION_FRAGMENT_LOOKUP:
935 texs[0] = (*texu)++;
936 ActiveTexture(GL_TEXTURE0 + texs[0]);
937 lookup_data = malloc(4 * LOOKUP_RES);
938 gen_gamma_map(lookup_data, LOOKUP_RES, rgamma);
939 gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, ggamma);
940 gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, bgamma);
941 glCreateClearTex(GL_TEXTURE_2D, GL_LUMINANCE8, GL_LINEAR,
942 LOOKUP_RES, 4, 0);
943 glUploadTex(GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE, lookup_data,
944 LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0);
945 ActiveTexture(GL_TEXTURE0);
946 texs[0] += '0';
947 break;
948 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
950 int sz = LOOKUP_3DRES + 2; // texture size including borders
951 if (!TexImage3D) {
952 mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing 3D texture function!\n");
953 break;
955 texs[0] = (*texu)++;
956 ActiveTexture(GL_TEXTURE0 + texs[0]);
957 lookup_data = malloc(3 * sz * sz * sz);
958 gen_yuv2rgb_map(lookup_data, LOOKUP_3DRES, brightness, contrast,
959 uvcos, uvsin, rgamma, ggamma, bgamma);
960 glAdjustAlignment(sz);
961 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
962 TexImage3D(GL_TEXTURE_3D, 0, 3, sz, sz, sz, 1,
963 GL_RGB, GL_UNSIGNED_BYTE, lookup_data);
964 glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_PRIORITY, 1.0);
965 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
966 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
967 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
968 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
969 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
970 ActiveTexture(GL_TEXTURE0);
971 texs[0] += '0';
973 break;
974 default:
975 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", conv);
977 if (lookup_data)
978 free(lookup_data);
982 * \brief adds a scaling texture read at the current fragment program position
983 * \param scaler type of scaler to insert
984 * \param prog_pos current position in fragment program
985 * \param remain how many bytes remain in the buffer given by prog_pos
986 * \param texs array containing the texture unit identifiers for this scaler
987 * \param in_tex texture unit the scaler should read from
988 * \param out_comp component of the yuv variable the scaler stores the result in
989 * \param rect if rectangular (pixel) adressing should be used for in_tex
990 * \param texw width of the in_tex texture
991 * \param texh height of the in_tex texture
993 static void add_scaler(int scaler, char **prog_pos, int *remain, char *texs,
994 char in_tex, char out_comp, int rect, int texw, int texh) {
995 switch (scaler) {
996 case YUV_SCALER_BILIN:
997 snprintf(*prog_pos, *remain, bilin_filt_template, out_comp, in_tex,
998 in_tex, rect ? "RECT" : "2D");
999 break;
1000 case YUV_SCALER_BICUB:
1001 if (rect)
1002 snprintf(*prog_pos, *remain, bicub_filt_template_RECT,
1003 in_tex, texs[0], texs[0],
1004 in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp);
1005 else
1006 snprintf(*prog_pos, *remain, bicub_filt_template_2D,
1007 in_tex, (float)texw, (float)texh,
1008 texs[0], (float)1.0 / texw, (float)1.0 / texw,
1009 texs[0], (float)1.0 / texh, (float)1.0 / texh,
1010 in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp);
1011 break;
1012 case YUV_SCALER_BICUB_X:
1013 if (rect)
1014 snprintf(*prog_pos, *remain, bicub_x_filt_template_RECT,
1015 in_tex, texs[0],
1016 in_tex, in_tex, in_tex, in_tex, out_comp);
1017 else
1018 snprintf(*prog_pos, *remain, bicub_x_filt_template_2D,
1019 in_tex, (float)texw, (float)texh,
1020 texs[0], (float)1.0 / texw, (float)1.0 / texw,
1021 in_tex, in_tex, in_tex, in_tex, out_comp);
1022 break;
1023 case YUV_SCALER_BICUB_NOTEX:
1024 if (rect)
1025 snprintf(*prog_pos, *remain, bicub_notex_filt_template_RECT,
1026 in_tex,
1027 in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp);
1028 else
1029 snprintf(*prog_pos, *remain, bicub_notex_filt_template_2D,
1030 in_tex, (float)texw, (float)texh,
1031 (float)1.0 / texw, (float)1.0 / texw,
1032 (float)1.0 / texh, (float)1.0 / texh,
1033 in_tex, in_tex, in_tex, in_tex, in_tex, in_tex, out_comp);
1034 break;
1036 *remain -= strlen(*prog_pos);
1037 *prog_pos += strlen(*prog_pos);
1040 static const struct {
1041 const char *name;
1042 GLenum cur;
1043 GLenum max;
1044 } progstats[] = {
1045 {"instructions", 0x88A0, 0x88A1},
1046 {"native instructions", 0x88A2, 0x88A3},
1047 {"temporaries", 0x88A4, 0x88A5},
1048 {"native temporaries", 0x88A6, 0x88A7},
1049 {"parameters", 0x88A8, 0x88A9},
1050 {"native parameters", 0x88AA, 0x88AB},
1051 {"attribs", 0x88AC, 0x88AD},
1052 {"native attribs", 0x88AE, 0x88AF},
1053 {"ALU instructions", 0x8805, 0x880B},
1054 {"TEX instructions", 0x8806, 0x880C},
1055 {"TEX indirections", 0x8807, 0x880D},
1056 {"native ALU instructions", 0x8808, 0x880E},
1057 {"native TEX instructions", 0x8809, 0x880F},
1058 {"native TEX indirections", 0x880A, 0x8810},
1059 {NULL, 0, 0}
1063 * \brief load the specified GPU Program
1064 * \param target program target to load into, only GL_FRAGMENT_PROGRAM is tested
1065 * \param prog program string
1066 * \return 1 on success, 0 otherwise
1068 int loadGPUProgram(GLenum target, char *prog) {
1069 int i;
1070 GLint cur = 0, max = 0, err = 0;
1071 if (!ProgramString) {
1072 mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing GPU program function\n");
1073 return 0;
1075 ProgramString(target, GL_PROGRAM_FORMAT_ASCII, strlen(prog), prog);
1076 glGetIntegerv(GL_PROGRAM_ERROR_POSITION, &err);
1077 if (err != -1) {
1078 mp_msg(MSGT_VO, MSGL_ERR,
1079 "[gl] Error compiling fragment program, make sure your card supports\n"
1080 "[gl] GL_ARB_fragment_program (use glxinfo to check).\n"
1081 "[gl] Error message:\n %s at %.10s\n",
1082 glGetString(GL_PROGRAM_ERROR_STRING), &prog[err]);
1083 return 0;
1085 if (!GetProgramiv || !mp_msg_test(MSGT_VO, MSGL_V))
1086 return 1;
1087 mp_msg(MSGT_VO, MSGL_V, "[gl] Program statistics:\n");
1088 for (i = 0; progstats[i].name; i++) {
1089 GetProgramiv(target, progstats[i].cur, &cur);
1090 GetProgramiv(target, progstats[i].max, &max);
1091 mp_msg(MSGT_VO, MSGL_V, "[gl] %s: %i/%i\n", progstats[i].name, cur, max);
1093 return 1;
1097 * \brief setup a fragment program that will do YUV->RGB conversion
1098 * \param brightness brightness adjustment offset
1099 * \param contrast contrast adjustment factor
1100 * \param uvcos used for saturation and hue adjustment
1101 * \param uvsin used for saturation and hue adjustment
1102 * \param lookup use fragment program that uses texture unit 4 to
1103 * do additional conversion via lookup.
1105 static void glSetupYUVFragprog(float brightness, float contrast,
1106 float uvcos, float uvsin, float rgamma,
1107 float ggamma, float bgamma, int type, int rect,
1108 int texw, int texh) {
1109 char yuv_prog[4000] =
1110 "!!ARBfp1.0\n"
1111 "OPTION ARB_precision_hint_fastest;"
1112 // all scaler variables must go here so they aren't defined
1113 // multiple times when the same scaler is used more than once
1114 "TEMP coord, coord2, cdelta, parmx, parmy, a, b, yuv;";
1115 int prog_remain = sizeof(yuv_prog) - strlen(yuv_prog);
1116 char *prog_pos = &yuv_prog[strlen(yuv_prog)];
1117 int cur_texu = 3;
1118 char lum_scale_texs[1];
1119 char chrom_scale_texs[1];
1120 char conv_texs[1];
1121 GLint i;
1122 // this is the conversion matrix, with y, u, v factors
1123 // for red, green, blue and the constant offsets
1124 float ry, ru, rv, rc;
1125 float gy, gu, gv, gc;
1126 float by, bu, bv, bc;
1127 create_scaler_textures(YUV_LUM_SCALER(type), &cur_texu, lum_scale_texs);
1128 if (YUV_CHROM_SCALER(type) == YUV_LUM_SCALER(type))
1129 memcpy(chrom_scale_texs, lum_scale_texs, sizeof(chrom_scale_texs));
1130 else
1131 create_scaler_textures(YUV_CHROM_SCALER(type), &cur_texu, chrom_scale_texs);
1132 create_conv_textures(YUV_CONVERSION(type), &cur_texu, conv_texs,
1133 brightness, contrast, uvcos, uvsin, rgamma, ggamma, bgamma);
1134 glGetIntegerv(GL_MAX_TEXTURE_UNITS, &i);
1135 if (i < cur_texu)
1136 mp_msg(MSGT_VO, MSGL_ERR,
1137 "[gl] %i texture units needed for this type of YUV fragment support (found %i)\n",
1138 cur_texu, i);
1139 if (!ProgramString) {
1140 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] ProgramString function missing!\n");
1141 return;
1143 add_scaler(YUV_LUM_SCALER(type), &prog_pos, &prog_remain, lum_scale_texs,
1144 '0', 'r', rect, texw, texh);
1145 add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs,
1146 '1', 'g', rect, texw / 2, texh / 2);
1147 add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs,
1148 '2', 'b', rect, texw / 2, texh / 2);
1149 get_yuv2rgb_coeffs(brightness, contrast, uvcos, uvsin,
1150 &ry, &ru, &rv, &rc, &gy, &gu, &gv, &gc, &by, &bu, &bv, &bc);
1151 switch (YUV_CONVERSION(type)) {
1152 case YUV_CONVERSION_FRAGMENT:
1153 snprintf(prog_pos, prog_remain, yuv_prog_template,
1154 ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc);
1155 break;
1156 case YUV_CONVERSION_FRAGMENT_POW:
1157 snprintf(prog_pos, prog_remain, yuv_pow_prog_template,
1158 ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc,
1159 (float)1.0 / rgamma, (float)1.0 / bgamma, (float)1.0 / bgamma);
1160 break;
1161 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1162 snprintf(prog_pos, prog_remain, yuv_lookup_prog_template,
1163 ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc,
1164 conv_texs[0], conv_texs[0], conv_texs[0]);
1165 break;
1166 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1167 snprintf(prog_pos, prog_remain, yuv_lookup3d_prog_template, conv_texs[0]);
1168 break;
1169 default:
1170 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", YUV_CONVERSION(type));
1171 break;
1173 mp_msg(MSGT_VO, MSGL_V, "[gl] generated fragment program:\n%s\n", yuv_prog);
1174 loadGPUProgram(GL_FRAGMENT_PROGRAM, yuv_prog);
1178 * \brief little helper function to create a lookup table for gamma
1179 * \param map buffer to create map into
1180 * \param size size of buffer
1181 * \param gamma gamma value
1183 static void gen_gamma_map(unsigned char *map, int size, float gamma) {
1184 int i;
1185 if (gamma == 1.0) {
1186 for (i = 0; i < size; i++)
1187 map[i] = 255 * i / (size - 1);
1188 return;
1190 gamma = 1.0 / gamma;
1191 for (i = 0; i < size; i++) {
1192 float tmp = (float)i / (size - 1.0);
1193 tmp = pow(tmp, gamma);
1194 if (tmp > 1.0) tmp = 1.0;
1195 if (tmp < 0.0) tmp = 0.0;
1196 map[i] = 255 * tmp;
1201 * \brief setup YUV->RGB conversion
1202 * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D)
1203 * \param type YUV conversion type
1204 * \param brightness brightness adjustment offset
1205 * \param contrast contrast adjustment factor
1206 * \param hue hue adjustment angle
1207 * \param saturation saturation adjustment factor
1208 * \param rgamma gamma value for red channel
1209 * \param ggamma gamma value for green channel
1210 * \param bgamma gamma value for blue channel
1211 * \ingroup glconversion
1213 void glSetupYUVConversion(GLenum target, int type,
1214 float brightness, float contrast,
1215 float hue, float saturation,
1216 float rgamma, float ggamma, float bgamma,
1217 int texw, int texh) {
1218 float uvcos = saturation * cos(hue);
1219 float uvsin = saturation * sin(hue);
1220 switch (YUV_CONVERSION(type)) {
1221 case YUV_CONVERSION_COMBINERS:
1222 glSetupYUVCombiners(uvcos, uvsin);
1223 break;
1224 case YUV_CONVERSION_COMBINERS_ATI:
1225 glSetupYUVCombinersATI(uvcos, uvsin);
1226 break;
1227 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1228 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1229 case YUV_CONVERSION_FRAGMENT:
1230 case YUV_CONVERSION_FRAGMENT_POW:
1231 glSetupYUVFragprog(brightness, contrast, uvcos, uvsin,
1232 rgamma, ggamma, bgamma, type,
1233 target == GL_TEXTURE_RECTANGLE,
1234 texw, texh);
1235 break;
1236 default:
1237 mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", YUV_CONVERSION(type));
1242 * \brief enable the specified YUV conversion
1243 * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D)
1244 * \param type type of YUV conversion
1245 * \ingroup glconversion
1247 void glEnableYUVConversion(GLenum target, int type) {
1248 if (type <= 0) return;
1249 switch (YUV_CONVERSION(type)) {
1250 case YUV_CONVERSION_COMBINERS:
1251 ActiveTexture(GL_TEXTURE1);
1252 glEnable(target);
1253 ActiveTexture(GL_TEXTURE2);
1254 glEnable(target);
1255 ActiveTexture(GL_TEXTURE0);
1256 glEnable(GL_REGISTER_COMBINERS_NV);
1257 break;
1258 case YUV_CONVERSION_COMBINERS_ATI:
1259 ActiveTexture(GL_TEXTURE1);
1260 glEnable(target);
1261 ActiveTexture(GL_TEXTURE2);
1262 glEnable(target);
1263 ActiveTexture(GL_TEXTURE0);
1264 glEnable(GL_FRAGMENT_SHADER_ATI);
1265 break;
1266 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1267 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1268 case YUV_CONVERSION_FRAGMENT_POW:
1269 case YUV_CONVERSION_FRAGMENT:
1270 glEnable(GL_FRAGMENT_PROGRAM);
1271 break;
1276 * \brief disable the specified YUV conversion
1277 * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D)
1278 * \param type type of YUV conversion
1279 * \ingroup glconversion
1281 void glDisableYUVConversion(GLenum target, int type) {
1282 if (type <= 0) return;
1283 switch (YUV_CONVERSION(type)) {
1284 case YUV_CONVERSION_COMBINERS:
1285 ActiveTexture(GL_TEXTURE1);
1286 glDisable(target);
1287 ActiveTexture(GL_TEXTURE2);
1288 glDisable(target);
1289 ActiveTexture(GL_TEXTURE0);
1290 glDisable(GL_REGISTER_COMBINERS_NV);
1291 break;
1292 case YUV_CONVERSION_COMBINERS_ATI:
1293 ActiveTexture(GL_TEXTURE1);
1294 glDisable(target);
1295 ActiveTexture(GL_TEXTURE2);
1296 glDisable(target);
1297 ActiveTexture(GL_TEXTURE0);
1298 glDisable(GL_FRAGMENT_SHADER_ATI);
1299 break;
1300 case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
1301 case YUV_CONVERSION_FRAGMENT_LOOKUP:
1302 case YUV_CONVERSION_FRAGMENT_POW:
1303 case YUV_CONVERSION_FRAGMENT:
1304 glDisable(GL_FRAGMENT_PROGRAM);
1305 break;
1310 * \brief draw a texture part at given 2D coordinates
1311 * \param x screen top coordinate
1312 * \param y screen left coordinate
1313 * \param w screen width coordinate
1314 * \param h screen height coordinate
1315 * \param tx texture top coordinate in pixels
1316 * \param ty texture left coordinate in pixels
1317 * \param tw texture part width in pixels
1318 * \param th texture part height in pixels
1319 * \param sx width of texture in pixels
1320 * \param sy height of texture in pixels
1321 * \param rect_tex whether this texture uses texture_rectangle extension
1322 * \param is_yv12 if set, also draw the textures from units 1 and 2
1323 * \param flip flip the texture upside down
1324 * \ingroup gltexture
1326 void glDrawTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h,
1327 GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th,
1328 int sx, int sy, int rect_tex, int is_yv12, int flip) {
1329 GLfloat tx2 = tx / 2, ty2 = ty / 2, tw2 = tw / 2, th2 = th / 2;
1330 if (!rect_tex) {
1331 tx /= sx; ty /= sy; tw /= sx; th /= sy;
1332 tx2 = tx, ty2 = ty, tw2 = tw, th2 = th;
1334 if (flip) {
1335 y += h;
1336 h = -h;
1338 glBegin(GL_QUADS);
1339 glTexCoord2f(tx, ty);
1340 if (is_yv12) {
1341 MultiTexCoord2f(GL_TEXTURE1, tx2, ty2);
1342 MultiTexCoord2f(GL_TEXTURE2, tx2, ty2);
1344 glVertex2f(x, y);
1345 glTexCoord2f(tx, ty + th);
1346 if (is_yv12) {
1347 MultiTexCoord2f(GL_TEXTURE1, tx2, ty2 + th2);
1348 MultiTexCoord2f(GL_TEXTURE2, tx2, ty2 + th2);
1350 glVertex2f(x, y + h);
1351 glTexCoord2f(tx + tw, ty + th);
1352 if (is_yv12) {
1353 MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2 + th2);
1354 MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2 + th2);
1356 glVertex2f(x + w, y + h);
1357 glTexCoord2f(tx + tw, ty);
1358 if (is_yv12) {
1359 MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2);
1360 MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2);
1362 glVertex2f(x + w, y);
1363 glEnd();
1366 #ifdef GL_WIN32
1367 #include "w32_common.h"
1369 * \brief little helper since wglGetProcAddress definition does not fit our
1370 * getProcAddress
1371 * \param procName name of function to look up
1372 * \return function pointer returned by wglGetProcAddress
1374 static void *w32gpa(const GLubyte *procName) {
1375 return wglGetProcAddress(procName);
1378 int setGlWindow(int *vinfo, HGLRC *context, HWND win)
1380 int new_vinfo;
1381 HDC windc = GetDC(win);
1382 HGLRC new_context = 0;
1383 int keep_context = 0;
1384 int res = SET_WINDOW_FAILED;
1386 // should only be needed when keeping context, but not doing glFinish
1387 // can cause flickering even when we do not keep it.
1388 if (*context)
1389 glFinish();
1390 new_vinfo = GetPixelFormat(windc);
1391 if (*context && *vinfo && new_vinfo && *vinfo == new_vinfo) {
1392 // we can keep the wglContext
1393 new_context = *context;
1394 keep_context = 1;
1395 } else {
1396 // create a context
1397 new_context = wglCreateContext(windc);
1398 if (!new_context) {
1399 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GL context!\n");
1400 goto out;
1404 // set context
1405 if (!wglMakeCurrent(windc, new_context)) {
1406 mp_msg (MSGT_VO, MSGL_FATAL, "[gl] Could not set GL context!\n");
1407 if (!keep_context) {
1408 wglDeleteContext(new_context);
1410 goto out;
1413 // set new values
1414 vo_w32_window = win;
1416 RECT rect;
1417 GetClientRect(win, &rect);
1418 vo_dwidth = rect.right;
1419 vo_dheight = rect.bottom;
1421 if (!keep_context) {
1422 if (*context)
1423 wglDeleteContext(*context);
1424 *context = new_context;
1425 *vinfo = new_vinfo;
1426 getFunctions(w32gpa, NULL);
1428 // and inform that reinit is neccessary
1429 res = SET_WINDOW_REINIT;
1430 } else
1431 res = SET_WINDOW_OK;
1433 out:
1434 ReleaseDC(win, windc);
1435 return res;
1438 void releaseGlContext(int *vinfo, HGLRC *context) {
1439 *vinfo = 0;
1440 if (*context) {
1441 wglMakeCurrent(0, 0);
1442 wglDeleteContext(*context);
1444 *context = 0;
1447 void swapGlBuffers() {
1448 HDC vo_hdc = GetDC(vo_w32_window);
1449 SwapBuffers(vo_hdc);
1450 ReleaseDC(vo_w32_window, vo_hdc);
1452 #else
1453 #ifdef HAVE_LIBDL
1454 #include <dlfcn.h>
1455 #endif
1456 #include "x11_common.h"
1458 * \brief find address of a linked function
1459 * \param s name of function to find
1460 * \return address of function or NULL if not found
1462 * Copied from xine
1464 static void *getdladdr(const char *s) {
1465 #ifdef HAVE_LIBDL
1466 #if defined(__sun) || defined(__sgi)
1467 static void *handle = NULL;
1468 if (!handle)
1469 handle = dlopen(NULL, RTLD_LAZY);
1470 return dlsym(handle, s);
1471 #else
1472 return dlsym(0, s);
1473 #endif
1474 #else
1475 return NULL;
1476 #endif
1480 * \brief Returns the XVisualInfo associated with Window win.
1481 * \param win Window whose XVisualInfo is returne.
1482 * \return XVisualInfo of the window. Caller must use XFree to free it.
1484 static XVisualInfo *getWindowVisualInfo(Window win) {
1485 XWindowAttributes xw_attr;
1486 XVisualInfo vinfo_template;
1487 int tmp;
1488 XGetWindowAttributes(mDisplay, win, &xw_attr);
1489 vinfo_template.visualid = XVisualIDFromVisual(xw_attr.visual);
1490 return XGetVisualInfo(mDisplay, VisualIDMask, &vinfo_template, &tmp);
1494 * \brief Changes the window in which video is displayed.
1495 * If possible only transfers the context to the new window, otherwise
1496 * creates a new one, which must be initialized by the caller.
1497 * \param vinfo Currently used visual.
1498 * \param context Currently used context.
1499 * \param win window that should be used for drawing.
1500 * \return one of SET_WINDOW_FAILED, SET_WINDOW_OK or SET_WINDOW_REINIT.
1501 * In case of SET_WINDOW_REINIT the context could not be transfered
1502 * and the caller must initialize it correctly.
1503 * \ingroup glcontext
1505 int setGlWindow(XVisualInfo **vinfo, GLXContext *context, Window win)
1507 XVisualInfo *new_vinfo;
1508 GLXContext new_context = NULL;
1509 int keep_context = 0;
1511 // should only be needed when keeping context, but not doing glFinish
1512 // can cause flickering even when we do not keep it.
1513 if (*context)
1514 glFinish();
1515 new_vinfo = getWindowVisualInfo(win);
1516 if (*context && *vinfo && new_vinfo &&
1517 (*vinfo)->visualid == new_vinfo->visualid) {
1518 // we can keep the GLXContext
1519 new_context = *context;
1520 XFree(new_vinfo);
1521 new_vinfo = *vinfo;
1522 keep_context = 1;
1523 } else {
1524 // create a context
1525 new_context = glXCreateContext(mDisplay, new_vinfo, NULL, True);
1526 if (!new_context) {
1527 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n");
1528 XFree(new_vinfo);
1529 return SET_WINDOW_FAILED;
1533 // set context
1534 if (!glXMakeCurrent(mDisplay, vo_window, new_context)) {
1535 mp_msg (MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n");
1536 if (!keep_context) {
1537 glXDestroyContext (mDisplay, new_context);
1538 XFree(new_vinfo);
1540 return SET_WINDOW_FAILED;
1543 // set new values
1544 vo_window = win;
1546 Window root;
1547 int tmp;
1548 unsigned utmp;
1549 XGetGeometry(mDisplay, vo_window, &root, &tmp, &tmp,
1550 (unsigned *)&vo_dwidth, (unsigned *)&vo_dheight, &utmp, &utmp);
1552 if (!keep_context) {
1553 void *(*getProcAddress)(const GLubyte *);
1554 const char *(*glXExtStr)(Display *, int);
1555 if (*context)
1556 glXDestroyContext(mDisplay, *context);
1557 *context = new_context;
1558 if (*vinfo)
1559 XFree(*vinfo);
1560 *vinfo = new_vinfo;
1561 getProcAddress = getdladdr("glXGetProcAddress");
1562 if (!getProcAddress)
1563 getProcAddress = getdladdr("glXGetProcAddressARB");
1564 if (!getProcAddress)
1565 getProcAddress = (void *)getdladdr;
1566 glXExtStr = getdladdr("glXQueryExtensionsString");
1567 getFunctions(getProcAddress, !glXExtStr ? NULL :
1568 glXExtStr(mDisplay, DefaultScreen(mDisplay)));
1570 // and inform that reinit is neccessary
1571 return SET_WINDOW_REINIT;
1573 return SET_WINDOW_OK;
1577 * \brief free the VisualInfo and GLXContext of an OpenGL context.
1578 * \ingroup glcontext
1580 void releaseGlContext(XVisualInfo **vinfo, GLXContext *context) {
1581 if (*vinfo)
1582 XFree(*vinfo);
1583 *vinfo = NULL;
1584 if (*context)
1586 glFinish();
1587 glXMakeCurrent(mDisplay, None, NULL);
1588 glXDestroyContext(mDisplay, *context);
1590 *context = 0;
1593 void swapGlBuffers(void) {
1594 glXSwapBuffers(mDisplay, vo_window);
1596 #endif