Mercurial > mplayer.hg
comparison libvo/vo_gl_tiled.c @ 35058:7f7dedf76624
Move file vo_gl2.c to vo_gl_tiled.c to reflect rename.
author | reimar |
---|---|
date | Fri, 07 Sep 2012 17:25:21 +0000 |
parents | libvo/vo_gl2.c@b291f44d864a |
children | 4129ba181ad7 |
comparison
equal
deleted
inserted
replaced
35057:08f284d173f6 | 35058:7f7dedf76624 |
---|---|
1 /* | |
2 * X11/OpenGL interface | |
3 * based on video_out_x11 by Aaron Holtzman, | |
4 * and WS opengl window manager by Pontscho/Fresh! | |
5 * | |
6 * This file is part of MPlayer. | |
7 * | |
8 * MPlayer is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * MPlayer is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License along | |
19 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 */ | |
22 | |
23 #include <stdio.h> | |
24 #include <stdlib.h> | |
25 #include <string.h> | |
26 | |
27 #include "config.h" | |
28 #include "mp_msg.h" | |
29 #include "subopt-helper.h" | |
30 #include "video_out.h" | |
31 #include "video_out_internal.h" | |
32 #include "libmpcodecs/vf.h" | |
33 #include "sub/sub.h" | |
34 | |
35 #include "gl_common.h" | |
36 #include "aspect.h" | |
37 | |
38 #undef TEXTUREFORMAT_ALWAYS | |
39 #ifdef __APPLE__ | |
40 #define TEXTUREFORMAT_ALWAYS GL_RGBA8 | |
41 #endif | |
42 | |
43 //! force texture height, useful for debugging | |
44 #define TEXTURE_HEIGHT 128 | |
45 #undef TEXTURE_HEIGHT | |
46 //! force texture width, useful for debugging | |
47 #define TEXTURE_WIDTH 128 | |
48 #undef TEXTURE_WIDTH | |
49 | |
50 static const vo_info_t info = | |
51 { | |
52 "X11 (OpenGL) - multiple textures version", | |
53 "gl_tiled", | |
54 "Arpad Gereoffy & Sven Goethel", | |
55 "" | |
56 }; | |
57 | |
58 const LIBVO_EXTERN(gl_tiled) | |
59 | |
60 /* local data */ | |
61 static unsigned char *ImageData=NULL; | |
62 | |
63 static MPGLContext glctx; | |
64 | |
65 static uint32_t image_width; | |
66 static uint32_t image_height; | |
67 static uint32_t image_format; | |
68 static uint32_t image_bpp; | |
69 static uint32_t image_bytes; | |
70 | |
71 static int int_pause; | |
72 | |
73 static uint32_t texture_width; | |
74 static uint32_t texture_height; | |
75 static int texnumx, texnumy, raw_line_len; | |
76 static int texdirty; | |
77 static struct TexSquare * texgrid = NULL; | |
78 static GLuint fragprog; | |
79 static GLuint lookupTex; | |
80 static GLint gl_internal_format; | |
81 static int rgb_sz, r_sz, g_sz, b_sz, a_sz; | |
82 static GLenum gl_bitmap_format; | |
83 static GLenum gl_bitmap_type; | |
84 static int isGL12 = GL_FALSE; | |
85 | |
86 static int gl_bilinear=1; | |
87 static int gl_antialias=0; | |
88 static int use_yuv; | |
89 static int is_yuv; | |
90 static int use_glFinish; | |
91 | |
92 | |
93 /* The squares that are tiled to make up the game screen polygon */ | |
94 | |
95 struct TexSquare | |
96 { | |
97 GLubyte *texture; | |
98 GLuint texobj; | |
99 GLuint uvtexobjs[2]; | |
100 GLfloat fx, fy, fw, fh; | |
101 }; | |
102 | |
103 static GLint getInternalFormat(void) | |
104 { | |
105 switch (glctx.type) { | |
106 #ifdef CONFIG_GL_WIN32 | |
107 case GLTYPE_W32: | |
108 { | |
109 PIXELFORMATDESCRIPTOR pfd; | |
110 HDC vo_hdc = vo_w32_get_dc(vo_w32_window); | |
111 int pf = GetPixelFormat(vo_hdc); | |
112 if (!DescribePixelFormat(vo_hdc, pf, sizeof pfd, &pfd)) { | |
113 r_sz = g_sz = b_sz = a_sz = 0; | |
114 } else { | |
115 r_sz = pfd.cRedBits; | |
116 g_sz = pfd.cGreenBits; | |
117 b_sz = pfd.cBlueBits; | |
118 a_sz = pfd.cAlphaBits; | |
119 } | |
120 vo_w32_release_dc(vo_w32_window, vo_hdc); | |
121 } | |
122 break; | |
123 #endif | |
124 #ifdef CONFIG_GL_X11 | |
125 case GLTYPE_X11: | |
126 if (glXGetConfig(mDisplay, glctx.vinfo.x11, GLX_RED_SIZE, &r_sz) != 0) r_sz = 0; | |
127 if (glXGetConfig(mDisplay, glctx.vinfo.x11, GLX_GREEN_SIZE, &g_sz) != 0) g_sz = 0; | |
128 if (glXGetConfig(mDisplay, glctx.vinfo.x11, GLX_BLUE_SIZE, &b_sz) != 0) b_sz = 0; | |
129 if (glXGetConfig(mDisplay, glctx.vinfo.x11, GLX_ALPHA_SIZE, &a_sz) != 0) a_sz = 0; | |
130 break; | |
131 #endif | |
132 } | |
133 | |
134 rgb_sz=r_sz+g_sz+b_sz; | |
135 if(rgb_sz<=0) rgb_sz=24; | |
136 | |
137 #ifdef TEXTUREFORMAT_ALWAYS | |
138 return TEXTUREFORMAT_ALWAYS; | |
139 #else | |
140 if(r_sz==3 && g_sz==3 && b_sz==2 && a_sz==0) | |
141 return GL_R3_G3_B2; | |
142 if(r_sz==4 && g_sz==4 && b_sz==4 && a_sz==0) | |
143 return GL_RGB4; | |
144 if(r_sz==5 && g_sz==5 && b_sz==5 && a_sz==0) | |
145 return GL_RGB5; | |
146 if(r_sz==8 && g_sz==8 && b_sz==8 && a_sz==0) | |
147 return GL_RGB8; | |
148 if(r_sz==10 && g_sz==10 && b_sz==10 && a_sz==0) | |
149 return GL_RGB10; | |
150 if(r_sz==2 && g_sz==2 && b_sz==2 && a_sz==2) | |
151 return GL_RGBA2; | |
152 if(r_sz==4 && g_sz==4 && b_sz==4 && a_sz==4) | |
153 return GL_RGBA4; | |
154 if(r_sz==5 && g_sz==5 && b_sz==5 && a_sz==1) | |
155 return GL_RGB5_A1; | |
156 if(r_sz==8 && g_sz==8 && b_sz==8 && a_sz==8) | |
157 return GL_RGBA8; | |
158 if(r_sz==10 && g_sz==10 && b_sz==10 && a_sz==2) | |
159 return GL_RGB10_A2; | |
160 #endif | |
161 return GL_RGB; | |
162 } | |
163 | |
164 static int initTextures(void) | |
165 { | |
166 struct TexSquare *tsq=0; | |
167 GLfloat texpercx, texpercy; | |
168 int s; | |
169 int x=0, y=0; | |
170 | |
171 // textures smaller than 64x64 might not be supported | |
172 s=64; | |
173 while (s<image_width) | |
174 s*=2; | |
175 texture_width=s; | |
176 | |
177 s=64; | |
178 while (s<image_height) | |
179 s*=2; | |
180 texture_height=s; | |
181 | |
182 if (!is_yuv) | |
183 gl_internal_format = getInternalFormat(); | |
184 | |
185 /* Test the max texture size */ | |
186 do { | |
187 GLint w; | |
188 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, | |
189 gl_internal_format, | |
190 texture_width, texture_height, | |
191 0, gl_bitmap_format, gl_bitmap_type, NULL); | |
192 | |
193 glGetTexLevelParameteriv | |
194 (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); | |
195 | |
196 if (w >= texture_width) | |
197 break; | |
198 | |
199 mp_msg (MSGT_VO, MSGL_V, "[gl_tiled] Needed texture [%dx%d] too big, trying ", | |
200 texture_width, texture_height); | |
201 | |
202 if (texture_width > texture_height) | |
203 texture_width /= 2; | |
204 else | |
205 texture_height /= 2; | |
206 | |
207 mp_msg (MSGT_VO, MSGL_V, "[%dx%d] !\n", texture_width, texture_height); | |
208 | |
209 if(texture_width < 64 || texture_height < 64) { | |
210 mp_msg (MSGT_VO, MSGL_FATAL, "[gl_tiled] Give up .. usable texture size not available, or texture config error !\n"); | |
211 return -1; | |
212 } | |
213 } while (texture_width > 1 && texture_height > 1); | |
214 #ifdef TEXTURE_WIDTH | |
215 texture_width = TEXTURE_WIDTH; | |
216 #endif | |
217 #ifdef TEXTURE_HEIGHT | |
218 texture_height = TEXTURE_HEIGHT; | |
219 #endif | |
220 | |
221 texnumx = image_width / texture_width; | |
222 if ((image_width % texture_width) > 0) | |
223 texnumx++; | |
224 | |
225 texnumy = image_height / texture_height; | |
226 if ((image_height % texture_height) > 0) | |
227 texnumy++; | |
228 | |
229 mp_msg(MSGT_VO, MSGL_V, "[gl_tiled] Creating %dx%d textures of size %dx%d ...\n", | |
230 texnumx, texnumy, texture_width,texture_height); | |
231 | |
232 /* Allocate the texture memory */ | |
233 | |
234 texpercx = (GLfloat) texture_width / (GLfloat) image_width; | |
235 texpercy = (GLfloat) texture_height / (GLfloat) image_height; | |
236 | |
237 free(texgrid); | |
238 texgrid = calloc (texnumx * texnumy, sizeof (struct TexSquare)); | |
239 | |
240 raw_line_len = image_width * image_bytes; | |
241 | |
242 mp_msg (MSGT_VO, MSGL_DBG2, "[gl_tiled] texture-usage %d*width=%d, %d*height=%d\n", | |
243 (int) texnumx, (int) texture_width, (int) texnumy, | |
244 (int) texture_height); | |
245 | |
246 tsq = texgrid; | |
247 for (y = 0; y < texnumy; y++) { | |
248 for (x = 0; x < texnumx; x++) { | |
249 tsq->fx = x * texpercx; | |
250 tsq->fy = y * texpercy; | |
251 tsq->fw = texpercx; | |
252 tsq->fh = texpercy; | |
253 | |
254 tsq->texobj=0; | |
255 tsq->uvtexobjs[0] = tsq->uvtexobjs[1] = 0; | |
256 | |
257 glGenTextures (1, &(tsq->texobj)); | |
258 | |
259 glBindTexture (GL_TEXTURE_2D, tsq->texobj); | |
260 if (is_yuv) { | |
261 glGenTextures(2, tsq->uvtexobjs); | |
262 mpglActiveTexture(GL_TEXTURE1); | |
263 glBindTexture (GL_TEXTURE_2D, tsq->uvtexobjs[0]); | |
264 mpglActiveTexture(GL_TEXTURE2); | |
265 glBindTexture (GL_TEXTURE_2D, tsq->uvtexobjs[1]); | |
266 mpglActiveTexture(GL_TEXTURE0); | |
267 } | |
268 | |
269 glCreateClearTex(GL_TEXTURE_2D, gl_internal_format, gl_bitmap_format, gl_bitmap_type, GL_LINEAR, | |
270 texture_width, texture_height, 0); | |
271 | |
272 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
273 if (is_yuv) { | |
274 int xs, ys, depth; | |
275 int chroma_clear_val = 128; | |
276 mp_get_chroma_shift(image_format, &xs, &ys, &depth); | |
277 chroma_clear_val >>= -depth & 7; | |
278 mpglActiveTexture(GL_TEXTURE1); | |
279 glCreateClearTex(GL_TEXTURE_2D, gl_internal_format, gl_bitmap_format, gl_bitmap_type, GL_LINEAR, | |
280 texture_width >> xs, texture_height >> ys, | |
281 chroma_clear_val); | |
282 mpglActiveTexture(GL_TEXTURE2); | |
283 glCreateClearTex(GL_TEXTURE_2D, gl_internal_format, gl_bitmap_format, gl_bitmap_type, GL_LINEAR, | |
284 texture_width >> xs, texture_height >> ys, | |
285 chroma_clear_val); | |
286 mpglActiveTexture(GL_TEXTURE0); | |
287 } | |
288 | |
289 tsq++; | |
290 } /* for all texnumx */ | |
291 } /* for all texnumy */ | |
292 | |
293 return 0; | |
294 } | |
295 | |
296 static void resetTexturePointers(unsigned char *imageSource) | |
297 { | |
298 unsigned char *texdata_start, *line_start; | |
299 struct TexSquare *tsq = texgrid; | |
300 int x=0, y=0; | |
301 | |
302 line_start = (unsigned char *) imageSource; | |
303 | |
304 for (y = 0; y < texnumy; y++) { | |
305 texdata_start = line_start; | |
306 for (x = 0; x < texnumx; x++) { | |
307 tsq->texture = texdata_start; | |
308 texdata_start += texture_width * image_bytes; | |
309 tsq++; | |
310 } /* for all texnumx */ | |
311 line_start += texture_height * raw_line_len; | |
312 } /* for all texnumy */ | |
313 } | |
314 | |
315 static void gl_set_bilinear (int val) | |
316 { | |
317 int x, y; | |
318 | |
319 if(val>=0) | |
320 gl_bilinear = val; | |
321 else | |
322 gl_bilinear++; | |
323 | |
324 gl_bilinear=gl_bilinear%2; | |
325 /* no mipmap yet .. */ | |
326 | |
327 for (y = 0; y < texnumy; y++) { | |
328 for (x = 0; x < texnumx; x++) { | |
329 glBindTexture (GL_TEXTURE_2D, texgrid[y * texnumx + x].texobj); | |
330 | |
331 switch (gl_bilinear) { | |
332 case 0: | |
333 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
334 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
335 mp_msg(MSGT_VO, MSGL_INFO, "[gl_tiled] bilinear off\n"); | |
336 break; | |
337 case 1: | |
338 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
339 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
340 mp_msg(MSGT_VO, MSGL_INFO, "[gl_tiled] bilinear linear\n"); | |
341 break; | |
342 case 2: | |
343 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); | |
344 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST); | |
345 mp_msg(MSGT_VO, MSGL_INFO, "[gl_tiled] bilinear mipmap nearest\n"); | |
346 break; | |
347 case 3: | |
348 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | |
349 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); | |
350 mp_msg(MSGT_VO, MSGL_INFO, "[gl_tiled] bilinear mipmap linear\n"); | |
351 break; | |
352 } | |
353 } | |
354 } | |
355 } | |
356 | |
357 static void gl_set_antialias (int val) | |
358 { | |
359 gl_antialias=val; | |
360 | |
361 if (gl_antialias) { | |
362 glShadeModel (GL_SMOOTH); | |
363 glEnable (GL_POLYGON_SMOOTH); | |
364 glEnable (GL_LINE_SMOOTH); | |
365 glEnable (GL_POINT_SMOOTH); | |
366 mp_msg(MSGT_VO, MSGL_INFO, "[gl_tiled] antialiasing on\n"); | |
367 } else { | |
368 glShadeModel (GL_FLAT); | |
369 glDisable (GL_POLYGON_SMOOTH); | |
370 glDisable (GL_LINE_SMOOTH); | |
371 glDisable (GL_POINT_SMOOTH); | |
372 mp_msg(MSGT_VO, MSGL_INFO, "[gl_tiled] antialiasing off\n"); | |
373 } | |
374 } | |
375 | |
376 | |
377 static void drawTextureDisplay (void) | |
378 { | |
379 struct TexSquare *square = texgrid; | |
380 int x, y; | |
381 | |
382 glColor4f(1.0,1.0,1.0,1.0); | |
383 | |
384 if (is_yuv) | |
385 glEnableYUVConversion(GL_TEXTURE_2D, use_yuv); | |
386 for (y = 0; y < texnumy; y++) { | |
387 int thish = texture_height; | |
388 if (y == texnumy - 1 && image_height % texture_height) | |
389 thish = image_height % texture_height; | |
390 for (x = 0; x < texnumx; x++) { | |
391 int thisw = texture_width; | |
392 if (x == texnumx - 1 && image_width % texture_width) | |
393 thisw = image_width % texture_width; | |
394 glBindTexture (GL_TEXTURE_2D, square->texobj); | |
395 if (is_yuv) { | |
396 mpglActiveTexture(GL_TEXTURE1); | |
397 glBindTexture (GL_TEXTURE_2D, square->uvtexobjs[0]); | |
398 mpglActiveTexture(GL_TEXTURE2); | |
399 glBindTexture (GL_TEXTURE_2D, square->uvtexobjs[1]); | |
400 mpglActiveTexture(GL_TEXTURE0); | |
401 } | |
402 | |
403 if (texdirty) { | |
404 glUploadTex(GL_TEXTURE_2D, gl_bitmap_format, gl_bitmap_type, | |
405 square->texture, image_width * image_bytes, | |
406 0, 0, thisw, thish, 0); | |
407 } | |
408 | |
409 glDrawTex(square->fx, square->fy, square->fw, square->fh, | |
410 0, 0, texture_width, texture_height, | |
411 texture_width, texture_height, | |
412 0, is_yuv, 0, 0); | |
413 square++; | |
414 } /* for all texnumx */ | |
415 } /* for all texnumy */ | |
416 if (is_yuv) | |
417 glDisableYUVConversion(GL_TEXTURE_2D, use_yuv); | |
418 texdirty = 0; | |
419 } | |
420 | |
421 | |
422 static void resize(int x,int y){ | |
423 // simple orthogonal projection for 0-1;0-1 | |
424 static const float matrix[16] = { | |
425 2, 0, 0, 0, | |
426 0, -2, 0, 0, | |
427 0, 0, 0, 0, | |
428 -1, 1, 0, 1, | |
429 }; | |
430 mp_msg(MSGT_VO,MSGL_V,"[gl_tiled] Resize: %dx%d\n",x,y); | |
431 if(aspect_scaling()) { | |
432 glClear(GL_COLOR_BUFFER_BIT); | |
433 aspect(&x, &y, A_WINZOOM); | |
434 panscan_calc_windowed(); | |
435 x += vo_panscan_x; | |
436 y += vo_panscan_y; | |
437 glViewport( (vo_dwidth-x)/2, (vo_dheight-y)/2, x, y); | |
438 } else { | |
439 //aspect(x, y, A_NOZOOM); | |
440 if (WinID >= 0) { | |
441 int left = 0, top = 0, w = x, h = y; | |
442 geometry(&left, &top, &w, &h, vo_dwidth, vo_dheight); | |
443 top = y - h - top; | |
444 glViewport(left, top, w, h); | |
445 } else | |
446 glViewport( 0, 0, x, y ); | |
447 } | |
448 | |
449 glMatrixMode(GL_PROJECTION); | |
450 glLoadMatrixf(matrix); | |
451 | |
452 glMatrixMode(GL_MODELVIEW); | |
453 glLoadIdentity(); | |
454 } | |
455 | |
456 static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){ | |
457 int bpp = pixel_stride(image_format); | |
458 vo_draw_alpha_func draw = vo_get_draw_alpha(image_format); | |
459 if (!draw) return; | |
460 draw(w,h,src,srca,stride,ImageData+bpp*(y0*image_width+x0),bpp*image_width); | |
461 } | |
462 | |
463 #ifdef CONFIG_GL_WIN32 | |
464 | |
465 static int config_w32(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { | |
466 if (!vo_w32_config(d_width, d_height, flags)) | |
467 return -1; | |
468 | |
469 return 0; | |
470 } | |
471 | |
472 #endif | |
473 | |
474 #ifdef CONFIG_GL_X11 | |
475 static int choose_glx_visual(Display *dpy, int scr, XVisualInfo *res_vi) | |
476 { | |
477 XVisualInfo template, *vi_list; | |
478 int vi_num, i, best_i, best_weight; | |
479 | |
480 template.screen = scr; | |
481 vi_list = XGetVisualInfo(dpy, VisualScreenMask, &template, &vi_num); | |
482 if (!vi_list) return -1; | |
483 best_weight = 1000000; best_i=0; | |
484 for (i = 0; i < vi_num; i++) { | |
485 int val, res, w = 0; | |
486 /* of course, the visual must support OpenGL rendering... */ | |
487 res = glXGetConfig(dpy, vi_list + i, GLX_USE_GL, &val); | |
488 if (res || val == False) continue; | |
489 /* also it must be doublebuffered ... */ | |
490 res = glXGetConfig(dpy, vi_list + i, GLX_DOUBLEBUFFER, &val); | |
491 if (res || val == False) continue; | |
492 /* furthermore it must be RGBA (not color indexed) ... */ | |
493 res = glXGetConfig(dpy, vi_list + i, GLX_RGBA, &val); | |
494 if (res || val == False) continue; | |
495 /* prefer less depth buffer size, */ | |
496 res = glXGetConfig(dpy, vi_list + i, GLX_DEPTH_SIZE, &val); | |
497 if (res) continue; | |
498 w += val*2; | |
499 /* stencil buffer size */ | |
500 res = glXGetConfig(dpy, vi_list + i, GLX_STENCIL_SIZE, &val); | |
501 if (res) continue; | |
502 w += val*2; | |
503 /* and colorbuffer alpha size */ | |
504 res = glXGetConfig(dpy, vi_list + i, GLX_ALPHA_SIZE, &val); | |
505 if (res) continue; | |
506 w += val; | |
507 /* and finally, prefer DirectColor-ed visuals to allow color corrections */ | |
508 if (vi_list[i].class != DirectColor) w += 100; | |
509 | |
510 // avoid bad-looking visual with less that 8bit per color | |
511 res = glXGetConfig(dpy, vi_list + i, GLX_RED_SIZE, &val); | |
512 if (res) continue; | |
513 if (val < 8) w += 50; | |
514 res = glXGetConfig(dpy, vi_list + i, GLX_GREEN_SIZE, &val); | |
515 if (res) continue; | |
516 if (val < 8) w += 70; | |
517 res = glXGetConfig(dpy, vi_list + i, GLX_BLUE_SIZE, &val); | |
518 if (res) continue; | |
519 if (val < 8) w += 50; | |
520 | |
521 if (w < best_weight) { | |
522 best_weight = w; | |
523 best_i = i; | |
524 } | |
525 } | |
526 if (best_weight < 1000000) *res_vi = vi_list[best_i]; | |
527 XFree(vi_list); | |
528 return (best_weight < 1000000) ? 0 : -1; | |
529 } | |
530 | |
531 static int config_glx(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { | |
532 XVisualInfo *vinfo, vinfo_buf; | |
533 vinfo = choose_glx_visual(mDisplay,mScreen,&vinfo_buf) < 0 ? NULL : &vinfo_buf; | |
534 if (vinfo == NULL) { | |
535 mp_msg(MSGT_VO, MSGL_FATAL, "[gl_tiled] no GLX support present\n"); | |
536 return -1; | |
537 } | |
538 | |
539 vo_x11_create_vo_window(vinfo, vo_dx, vo_dy, d_width, d_height, | |
540 flags, vo_x11_create_colormap(vinfo), "gl_tiled", title); | |
541 | |
542 return 0; | |
543 } | |
544 #endif | |
545 | |
546 static int initGl(uint32_t d_width, uint32_t d_height) | |
547 { | |
548 fragprog = lookupTex = 0; | |
549 if (initTextures() < 0) | |
550 return -1; | |
551 | |
552 glDisable(GL_BLEND); | |
553 glDisable(GL_DEPTH_TEST); | |
554 glDepthMask(GL_FALSE); | |
555 glDisable(GL_CULL_FACE); | |
556 glEnable (GL_TEXTURE_2D); | |
557 if (is_yuv) { | |
558 int xs, ys, depth; | |
559 gl_conversion_params_t params = {GL_TEXTURE_2D, use_yuv, | |
560 {-1, -1, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0}, | |
561 texture_width, texture_height, 0, 0, 0}; | |
562 switch (use_yuv) { | |
563 case YUV_CONVERSION_FRAGMENT_LOOKUP: | |
564 glGenTextures(1, &lookupTex); | |
565 mpglActiveTexture(GL_TEXTURE3); | |
566 glBindTexture(GL_TEXTURE_2D, lookupTex); | |
567 mpglActiveTexture(GL_TEXTURE0); | |
568 glBindTexture(GL_TEXTURE_2D, 0); | |
569 case YUV_CONVERSION_FRAGMENT_POW: | |
570 case YUV_CONVERSION_FRAGMENT: | |
571 if (!mpglGenPrograms || !mpglBindProgram) { | |
572 mp_msg(MSGT_VO, MSGL_ERR, "[gl] fragment program functions missing!\n"); | |
573 break; | |
574 } | |
575 mpglGenPrograms(1, &fragprog); | |
576 mpglBindProgram(GL_FRAGMENT_PROGRAM, fragprog); | |
577 break; | |
578 } | |
579 mp_get_chroma_shift(image_format, &xs, &ys, &depth); | |
580 params.chrom_texw = params.texw >> xs; | |
581 params.chrom_texh = params.texh >> ys; | |
582 params.csp_params.input_shift = -depth & 7; | |
583 glSetupYUVConversion(¶ms); | |
584 } | |
585 | |
586 gl_set_antialias(0); | |
587 gl_set_bilinear(1); | |
588 | |
589 mp_msg(MSGT_VO, MSGL_V, "[gl_tiled] Using image_bpp=%d, image_bytes=%d, \n\tgl_bitmap_format=%s, gl_bitmap_type=%s, \n\trgb_size=%d (%d,%d,%d), a_sz=%d, \n\tgl_internal_format=%s\n", | |
590 image_bpp, image_bytes, | |
591 glValName(gl_bitmap_format), glValName(gl_bitmap_type), | |
592 rgb_sz, r_sz, g_sz, b_sz, a_sz, glValName(gl_internal_format)); | |
593 | |
594 resize(d_width, d_height); | |
595 | |
596 glClearColor( 0.0f,0.0f,0.0f,0.0f ); | |
597 glClear( GL_COLOR_BUFFER_BIT ); | |
598 | |
599 drawTextureDisplay (); | |
600 | |
601 return 0; | |
602 } | |
603 | |
604 /* connect to server, create and map window, | |
605 * allocate colors and (shared) memory | |
606 */ | |
607 static int | |
608 config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) | |
609 { | |
610 int xs, ys; | |
611 const unsigned char * glVersion; | |
612 | |
613 image_height = height; | |
614 image_width = width; | |
615 image_format = format; | |
616 is_yuv = mp_get_chroma_shift(image_format, &xs, &ys, NULL) > 0; | |
617 is_yuv |= (xs << 8) | (ys << 16); | |
618 | |
619 int_pause = 0; | |
620 | |
621 #ifdef CONFIG_GL_WIN32 | |
622 if (config_w32(width, height, d_width, d_height, flags, title, format) == -1) | |
623 #endif | |
624 #ifdef CONFIG_GL_X11 | |
625 if (config_glx(width, height, d_width, d_height, flags, title, format) == -1) | |
626 #endif | |
627 return -1; | |
628 | |
629 if (glctx.setGlWindow(&glctx) == SET_WINDOW_FAILED) | |
630 return -1; | |
631 | |
632 glVersion = glGetString(GL_VERSION); | |
633 | |
634 mp_msg(MSGT_VO, MSGL_V, "[gl_tiled] OpenGL Driver Information:\n"); | |
635 mp_msg(MSGT_VO, MSGL_V, "\tvendor: %s,\n\trenderer %s,\n\tversion %s\n", | |
636 glGetString(GL_VENDOR), glGetString(GL_RENDERER), glVersion); | |
637 | |
638 if(glVersion[0]>'1' || (glVersion[0]=='1' && glVersion[2]>='2') ) | |
639 isGL12 = GL_TRUE; | |
640 else | |
641 isGL12 = GL_FALSE; | |
642 | |
643 if(isGL12) { | |
644 mp_msg(MSGT_VO, MSGL_INFO, "[gl_tiled] You have OpenGL >= 1.2 capable drivers, GOOD (16bpp and BGR is ok!)\n"); | |
645 } else { | |
646 mp_msg(MSGT_VO, MSGL_INFO, "[gl_tiled] You have OpenGL < 1.2 drivers, BAD (16bpp and BGR may be damaged!)\n"); | |
647 } | |
648 | |
649 glFindFormat(format, &image_bpp, &gl_internal_format, &gl_bitmap_format, &gl_bitmap_type); | |
650 | |
651 image_bytes=(image_bpp+7)/8; | |
652 | |
653 if (initGl(vo_dwidth, vo_dheight) == -1) | |
654 return -1; | |
655 | |
656 return 0; | |
657 } | |
658 | |
659 #ifdef CONFIG_GL_X11 | |
660 static int gl_handlekey(int key) | |
661 { | |
662 if(key=='a'||key=='A') { | |
663 gl_set_antialias(!gl_antialias); | |
664 return 0; | |
665 } else if(key=='b'||key=='B') { | |
666 gl_set_bilinear(-1); | |
667 return 0; | |
668 } | |
669 return 1; | |
670 } | |
671 #endif | |
672 | |
673 static void check_events(void) | |
674 { | |
675 int e; | |
676 #ifdef CONFIG_GL_X11 | |
677 XEvent Event; | |
678 char buf[100]; | |
679 KeySym keySym; | |
680 int key; | |
681 static XComposeStatus stat; | |
682 | |
683 while ( XPending( mDisplay ) ) { | |
684 XNextEvent( mDisplay,&Event ); | |
685 if( Event.type == KeyPress ) { | |
686 XLookupString( &Event.xkey,buf,sizeof(buf),&keySym,&stat ); | |
687 key = (keySym&0xff00) != 0 ? (keySym&0x00ff) + 256 : keySym; | |
688 if(gl_handlekey(key)) | |
689 XPutBackEvent(mDisplay, &Event); | |
690 break; | |
691 } else { | |
692 XPutBackEvent(mDisplay, &Event); | |
693 break; | |
694 } | |
695 } | |
696 #endif | |
697 e=glctx.check_events(); | |
698 if(e&VO_EVENT_RESIZE) resize(vo_dwidth, vo_dheight); | |
699 if(e&VO_EVENT_EXPOSE && int_pause) flip_page(); | |
700 } | |
701 | |
702 static void draw_osd(void) | |
703 { | |
704 if (ImageData) | |
705 vo_draw_text(image_width,image_height,draw_alpha); | |
706 } | |
707 | |
708 static void | |
709 flip_page(void) | |
710 { | |
711 drawTextureDisplay(); | |
712 | |
713 // glFlush(); | |
714 if (use_glFinish) | |
715 glFinish(); | |
716 glctx.swapGlBuffers(&glctx); | |
717 | |
718 if (aspect_scaling()) // Avoid flickering borders in fullscreen mode | |
719 glClear (GL_COLOR_BUFFER_BIT); | |
720 } | |
721 | |
722 static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) | |
723 { | |
724 uint8_t *yptr = src[0], *uptr = src[1], *vptr = src[2]; | |
725 int ystride = stride[0], ustride = stride[1], vstride = stride[2]; | |
726 int rem_h = h; | |
727 struct TexSquare *texline = &texgrid[y / texture_height * texnumx]; | |
728 int subtex_y = y % texture_width; | |
729 int xs, ys; | |
730 mp_get_chroma_shift(image_format, &xs, &ys, NULL); | |
731 while (rem_h > 0) { | |
732 int rem_w = w; | |
733 struct TexSquare *tsq = &texline[x / texture_width]; | |
734 int subtex_x = x % texture_height; | |
735 int subtex_h = rem_h; | |
736 if (subtex_y + subtex_h > texture_height) | |
737 subtex_h = texture_height - subtex_y; | |
738 while (rem_w > 0) { | |
739 int subtex_w = rem_w; | |
740 if (subtex_x + subtex_w > texture_width) | |
741 subtex_w = texture_width - subtex_x; | |
742 mpglActiveTexture(GL_TEXTURE0); | |
743 glBindTexture(GL_TEXTURE_2D, tsq->texobj); | |
744 glUploadTex(GL_TEXTURE_2D, gl_bitmap_format, gl_bitmap_type, | |
745 yptr, ystride, subtex_x, subtex_y, | |
746 subtex_w, subtex_h, 0); | |
747 mpglActiveTexture(GL_TEXTURE1); | |
748 glBindTexture(GL_TEXTURE_2D, tsq->uvtexobjs[0]); | |
749 glUploadTex(GL_TEXTURE_2D, gl_bitmap_format, gl_bitmap_type, | |
750 uptr, ustride, subtex_x >> xs, subtex_y >> ys, | |
751 subtex_w >> xs, subtex_h >> ys, 0); | |
752 mpglActiveTexture(GL_TEXTURE2); | |
753 glBindTexture(GL_TEXTURE_2D, tsq->uvtexobjs[1]); | |
754 glUploadTex(GL_TEXTURE_2D, gl_bitmap_format, gl_bitmap_type, | |
755 vptr, vstride, subtex_x >> xs, subtex_y >> ys, | |
756 subtex_w >> xs, subtex_h >> ys, 0); | |
757 subtex_x = 0; | |
758 yptr += subtex_w; | |
759 uptr += subtex_w >> xs; | |
760 vptr += subtex_w >> xs; | |
761 tsq++; | |
762 rem_w -= subtex_w; | |
763 } | |
764 subtex_y = 0; | |
765 yptr += subtex_h * ystride - w; | |
766 uptr += (subtex_h >> ys) * ustride - (w >> xs); | |
767 vptr += (subtex_h >> ys) * vstride - (w >> xs); | |
768 texline += texnumx; | |
769 rem_h -= subtex_h; | |
770 } | |
771 mpglActiveTexture(GL_TEXTURE0); | |
772 return 0; | |
773 } | |
774 | |
775 static int | |
776 draw_frame(uint8_t *src[]) | |
777 { | |
778 if (is_yuv) { | |
779 mp_msg(MSGT_VO, MSGL_ERR, "[gl_tiled] error: draw_frame called for YV12!\n"); | |
780 return 0; | |
781 } | |
782 ImageData=(unsigned char *)src[0]; | |
783 resetTexturePointers(ImageData); | |
784 texdirty = 1; | |
785 return 0; | |
786 } | |
787 | |
788 static int | |
789 query_format(uint32_t format) | |
790 { | |
791 int depth; | |
792 if (use_yuv && mp_get_chroma_shift(format, NULL, NULL, &depth) && | |
793 (depth == 8 || depth == 16 || glYUVLargeRange(use_yuv)) && | |
794 (IMGFMT_IS_YUVP16_NE(format) || !IMGFMT_IS_YUVP16(format))) | |
795 return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | | |
796 VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE; | |
797 switch(format) { | |
798 #ifdef __APPLE__ | |
799 case IMGFMT_RGB32: | |
800 #else | |
801 case IMGFMT_RGB24: | |
802 case IMGFMT_BGR24: | |
803 // case IMGFMT_RGB32: | |
804 // case IMGFMT_BGR32: | |
805 #endif | |
806 return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD; | |
807 } | |
808 return 0; | |
809 } | |
810 | |
811 | |
812 static void | |
813 uninit(void) | |
814 { | |
815 if ( !vo_config_count ) return; | |
816 free(texgrid); | |
817 texgrid = NULL; | |
818 uninit_mpglcontext(&glctx); | |
819 } | |
820 | |
821 static const opt_t subopts[] = { | |
822 {"yuv", OPT_ARG_INT, &use_yuv, int_non_neg}, | |
823 {"glfinish", OPT_ARG_BOOL, &use_glFinish, NULL}, | |
824 {NULL} | |
825 }; | |
826 | |
827 static int preinit(const char *arg) | |
828 { | |
829 enum MPGLType gltype = GLTYPE_X11; | |
830 // set defaults | |
831 #ifdef CONFIG_GL_WIN32 | |
832 gltype = GLTYPE_W32; | |
833 #endif | |
834 use_yuv = -1; | |
835 use_glFinish = 1; | |
836 if (subopt_parse(arg, subopts) != 0) { | |
837 mp_msg(MSGT_VO, MSGL_FATAL, | |
838 "\n-vo gl_tiled command line help:\n" | |
839 "Example: mplayer -vo gl_tiled:noglfinish\n" | |
840 "\nOptions:\n" | |
841 " noglfinish\n" | |
842 " Do not call glFinish() before swapping buffers\n" | |
843 " yuv=<n>\n" | |
844 " 0: use software YUV to RGB conversion.\n" | |
845 " 1: use register combiners (nVidia only, for older cards).\n" | |
846 " 2: use fragment program.\n" | |
847 " 3: use fragment program with gamma correction.\n" | |
848 " 4: use fragment program with gamma correction via lookup.\n" | |
849 " 5: use ATI-specific method (for older cards).\n" | |
850 "\n" ); | |
851 return -1; | |
852 } | |
853 if(!init_mpglcontext(&glctx, gltype)) goto err_out; | |
854 if (use_yuv == -1) { | |
855 #ifdef CONFIG_GL_WIN32 | |
856 if (config_w32(320, 200, 320, 200, VOFLAG_HIDDEN, "", 0) == -1) | |
857 #endif | |
858 #ifdef CONFIG_GL_X11 | |
859 if (config_glx(320, 200, 320, 200, VOFLAG_HIDDEN, "", 0) == -1) | |
860 #endif | |
861 goto err_out; | |
862 if (glctx.setGlWindow(&glctx) == SET_WINDOW_FAILED) | |
863 goto err_out; | |
864 use_yuv = glAutodetectYUVConversion(); | |
865 } | |
866 return 0; | |
867 | |
868 err_out: | |
869 uninit(); | |
870 return -1; | |
871 } | |
872 | |
873 static int control(uint32_t request, void *data) | |
874 { | |
875 switch (request) { | |
876 case VOCTRL_PAUSE: | |
877 case VOCTRL_RESUME: | |
878 int_pause = (request == VOCTRL_PAUSE); | |
879 return VO_TRUE; | |
880 case VOCTRL_QUERY_FORMAT: | |
881 return query_format(*((uint32_t*)data)); | |
882 case VOCTRL_GUISUPPORT: | |
883 return VO_TRUE; | |
884 case VOCTRL_ONTOP: | |
885 glctx.ontop(); | |
886 return VO_TRUE; | |
887 case VOCTRL_FULLSCREEN: | |
888 glctx.fullscreen(); | |
889 if (glctx.setGlWindow(&glctx) == SET_WINDOW_REINIT) | |
890 initGl(vo_dwidth, vo_dheight); | |
891 resize(vo_dwidth, vo_dheight); | |
892 return VO_TRUE; | |
893 case VOCTRL_BORDER: | |
894 glctx.border(); | |
895 return VO_TRUE; | |
896 case VOCTRL_GET_PANSCAN: | |
897 return VO_TRUE; | |
898 case VOCTRL_SET_PANSCAN: | |
899 resize(vo_dwidth, vo_dheight); | |
900 return VO_TRUE; | |
901 #ifdef CONFIG_GL_X11 | |
902 case VOCTRL_SET_EQUALIZER: | |
903 { | |
904 vf_equalizer_t *eq=data; | |
905 return vo_x11_set_equalizer(eq->item, eq->value); | |
906 } | |
907 case VOCTRL_GET_EQUALIZER: | |
908 { | |
909 vf_equalizer_t *eq=data; | |
910 return vo_x11_get_equalizer(eq->item, &eq->value); | |
911 } | |
912 #endif | |
913 case VOCTRL_UPDATE_SCREENINFO: | |
914 glctx.update_xinerama_info(); | |
915 return VO_TRUE; | |
916 } | |
917 return VO_NOTIMPL; | |
918 } |