Remove legacy parameter from add_string()
[vlc/asuraparaju-public.git] / modules / video_output / opengl.h
blobc54258fc863ea51c38e2bfc134a189d9f6f4636b
1 /*****************************************************************************
2 * opengl.h: OpenGL vout_display helpers
3 *****************************************************************************
4 * Copyright (C) 2004 the VideoLAN team
5 * Copyright (C) 2009 Laurent Aimar
6 * $Id$
8 * Authors: Cyril Deguet <asmax@videolan.org>
9 * Gildas Bazin <gbazin@videolan.org>
10 * Eric Petit <titer@m0k.org>
11 * Cedric Cocquebert <cedric.cocquebert@supelec.fr>
12 * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_picture_pool.h>
31 #include <vlc_vout_opengl.h>
33 #ifdef __APPLE__
34 # include <OpenGL/gl.h>
35 # include <OpenGL/glext.h>
36 #else
37 # include <GL/gl.h>
38 #endif
40 #ifndef YCBCR_MESA
41 # define YCBCR_MESA 0x8757
42 #endif
43 #ifndef UNSIGNED_SHORT_8_8_MESA
44 # define UNSIGNED_SHORT_8_8_MESA 0x85BA
45 #endif
46 /* RV16 */
47 #ifndef GL_UNSIGNED_SHORT_5_6_5
48 # define GL_UNSIGNED_SHORT_5_6_5 0x8363
49 #endif
50 #ifndef GL_CLAMP_TO_EDGE
51 # define GL_CLAMP_TO_EDGE 0x812F
52 #endif
54 #ifdef __APPLE__
55 /* On OS X, use GL_TEXTURE_RECTANGLE_EXT instead of GL_TEXTURE_2D.
56 This allows sizes which are not powers of 2 */
57 # define VLCGL_TARGET GL_TEXTURE_RECTANGLE_EXT
59 /* OS X OpenGL supports YUV. Hehe. */
60 # define VLCGL_FORMAT GL_YCBCR_422_APPLE
61 # define VLCGL_TYPE GL_UNSIGNED_SHORT_8_8_APPLE
63 # define VLCGL_TEXTURE_COUNT (2)
64 #else
66 # define VLCGL_TARGET GL_TEXTURE_2D
68 /* RV32 */
69 # define VLCGL_RGB_FORMAT GL_RGBA
70 # define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
72 /* YUY2 */
73 # define VLCGL_YUV_FORMAT YCBCR_MESA
74 # define VLCGL_YUV_TYPE UNSIGNED_SHORT_8_8_MESA
76 /* Use RGB on Win32/GLX */
77 # define VLCGL_FORMAT VLCGL_RGB_FORMAT
78 # define VLCGL_TYPE VLCGL_RGB_TYPE
80 # define VLCGL_TEXTURE_COUNT (1)
81 #endif
83 static inline int GetAlignedSize(int i_size)
85 /* Return the nearest power of 2 */
86 int i_result = 1;
87 while(i_result < i_size)
88 i_result *= 2;
90 return i_result;
93 typedef struct {
94 vout_opengl_t *gl;
96 video_format_t fmt;
98 int tex_pixel_size;
99 int tex_width;
100 int tex_height;
102 GLuint texture[VLCGL_TEXTURE_COUNT];
103 uint8_t *buffer[VLCGL_TEXTURE_COUNT];
105 picture_pool_t *pool;
106 } vout_display_opengl_t;
108 static int vout_display_opengl_Init(vout_display_opengl_t *vgl,
109 video_format_t *fmt,
110 vout_opengl_t *gl)
112 vgl->gl = gl;
114 /* Find the chroma we will use and update fmt */
115 /* TODO: We use YCbCr on Mac which is Y422, but on OSX it seems to == YUY2. Verify */
116 #if (defined(WORDS_BIGENDIAN) && VLCGL_FORMAT == GL_YCBCR_422_APPLE) || (VLCGL_FORMAT == YCBCR_MESA)
117 fmt->i_chroma = VLC_CODEC_YUYV;
118 vgl->tex_pixel_size = 2;
119 #elif defined(GL_YCBCR_422_APPLE) && (VLCGL_FORMAT == GL_YCBCR_422_APPLE)
120 fmt->i_chroma = VLC_CODEC_UYVY;
121 vgl->tex_pixel_size = 2;
122 #elif VLCGL_FORMAT == GL_RGB
123 # if VLCGL_TYPE == GL_UNSIGNED_BYTE
124 fmt->i_chroma = VLC_CODEC_RGB24;
125 # if defined(WORDS_BIGENDIAN)
126 fmt->i_rmask = 0x00ff0000;
127 fmt->i_gmask = 0x0000ff00;
128 fmt->i_bmask = 0x000000ff;
129 # else
130 fmt->i_rmask = 0x000000ff;
131 fmt->i_gmask = 0x0000ff00;
132 fmt->i_bmask = 0x00ff0000;
133 # endif
134 vgl->tex_pixel_size = 3;
135 # else
136 fmt->i_chroma = VLC_CODEC_RGB16;
137 # if defined(WORDS_BIGENDIAN)
138 fmt->i_rmask = 0x001f;
139 fmt->i_gmask = 0x07e0;
140 fmt->i_bmask = 0xf800;
141 # else
142 fmt->i_rmask = 0xf800;
143 fmt->i_gmask = 0x07e0;
144 fmt->i_bmask = 0x001f;
145 # endif
146 vgl->tex_pixel_size = 2;
147 # endif
148 #else
149 fmt->i_chroma = VLC_CODEC_RGB32;
150 # if defined(WORDS_BIGENDIAN)
151 fmt->i_rmask = 0xff000000;
152 fmt->i_gmask = 0x00ff0000;
153 fmt->i_bmask = 0x0000ff00;
154 # else
155 fmt->i_rmask = 0x000000ff;
156 fmt->i_gmask = 0x0000ff00;
157 fmt->i_bmask = 0x00ff0000;
158 # endif
159 vgl->tex_pixel_size = 4;
160 #endif
162 vgl->fmt = *fmt;
164 /* Texture size */
165 #ifdef __APPLE__
166 vgl->tex_width = fmt->i_width;
167 vgl->tex_height = fmt->i_height;
168 #else
169 /* A texture must have a size aligned on a power of 2 */
170 vgl->tex_width = GetAlignedSize(fmt->i_width);
171 vgl->tex_height = GetAlignedSize(fmt->i_height);
172 #endif
174 /* */
175 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
176 vgl->texture[i] = 0;
177 vgl->buffer[i] = NULL;
179 vgl->pool = NULL;
181 /* */
182 if (!vout_opengl_Lock(vgl->gl)) {
184 glDisable(GL_BLEND);
185 glDisable(GL_DEPTH_TEST);
186 glDepthMask(GL_FALSE);
187 glDisable(GL_CULL_FACE);
188 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
189 glClear(GL_COLOR_BUFFER_BIT);
191 vout_opengl_Unlock(vgl->gl);
193 return VLC_SUCCESS;
195 static void vout_display_opengl_Clean(vout_display_opengl_t *vgl)
197 /* */
198 if (!vout_opengl_Lock(vgl->gl)) {
200 glFinish();
201 glFlush();
202 glDeleteTextures(VLCGL_TEXTURE_COUNT, vgl->texture);
204 vout_opengl_Unlock(vgl->gl);
206 if (vgl->pool) {
207 picture_pool_Delete(vgl->pool);
208 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
209 free(vgl->buffer[i]);
213 static int vout_display_opengl_ResetTextures(vout_display_opengl_t *vgl)
215 if (vout_opengl_Lock(vgl->gl))
216 return VLC_EGENERIC;
218 glDeleteTextures(VLCGL_TEXTURE_COUNT, vgl->texture);
220 glGenTextures(VLCGL_TEXTURE_COUNT, vgl->texture);
221 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
222 glBindTexture(VLCGL_TARGET, vgl->texture[i]);
224 /* Set the texture parameters */
225 glTexParameterf(VLCGL_TARGET, GL_TEXTURE_PRIORITY, 1.0);
227 glTexParameteri(VLCGL_TARGET, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
228 glTexParameteri(VLCGL_TARGET, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
230 glTexParameteri(VLCGL_TARGET, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
231 glTexParameteri(VLCGL_TARGET, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
233 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
235 #ifdef __APPLE__
236 /* Tell the driver not to make a copy of the texture but to use
237 our buffer */
238 glEnable(GL_UNPACK_CLIENT_STORAGE_APPLE);
239 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
241 #if 0
242 /* Use VRAM texturing */
243 glTexParameteri(VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
244 GL_STORAGE_CACHED_APPLE);
245 #else
246 /* Use AGP texturing */
247 glTexParameteri(VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
248 GL_STORAGE_SHARED_APPLE);
249 #endif
250 #endif
252 /* Call glTexImage2D only once, and use glTexSubImage2D later */
253 if (vgl->buffer[i])
254 glTexImage2D(VLCGL_TARGET, 0, 3, vgl->tex_width, vgl->tex_height,
255 0, VLCGL_FORMAT, VLCGL_TYPE, vgl->buffer[i]);
258 vout_opengl_Unlock(vgl->gl);
259 return VLC_SUCCESS;
262 #ifdef __APPLE__
263 /* XXX See comment vout_display_opengl_Prepare */
264 struct picture_sys_t {
265 vout_display_opengl_t *vgl;
266 GLuint *texture;
269 /* Small helper */
270 static inline GLuint get_texture(picture_t *picture)
272 return *picture->p_sys->texture;
275 static int PictureLock(picture_t *picture)
277 if (!picture->p_sys)
278 return VLC_SUCCESS;
280 vout_display_opengl_t *vgl = picture->p_sys->vgl;
281 if (!vout_opengl_Lock(vgl->gl)) {
283 glBindTexture(VLCGL_TARGET, get_texture(picture));
284 glTexSubImage2D(VLCGL_TARGET, 0, 0, 0,
285 vgl->fmt.i_width, vgl->fmt.i_height,
286 VLCGL_FORMAT, VLCGL_TYPE, picture->p[0].p_pixels);
288 vout_opengl_Unlock(vgl->gl);
290 return VLC_SUCCESS;
292 static void PictureUnlock(picture_t *picture)
294 VLC_UNUSED(picture);
296 #endif
298 static picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl)
300 picture_t *picture[VLCGL_TEXTURE_COUNT];
302 int i;
303 for (i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
305 /* TODO memalign would be way better */
306 vgl->buffer[i] = malloc(vgl->tex_width * vgl->tex_height * vgl->tex_pixel_size);
307 if (!vgl->buffer[i])
308 break;
310 picture_resource_t rsc;
311 memset(&rsc, 0, sizeof(rsc));
312 #ifdef __APPLE__
313 rsc.p_sys = malloc(sizeof(*rsc.p_sys));
314 if (rsc.p_sys)
316 rsc.p_sys->vgl = vgl;
317 rsc.p_sys->texture = &vgl->texture[i];
319 #endif
320 rsc.p[0].p_pixels = vgl->buffer[i];
321 rsc.p[0].i_pitch = vgl->fmt.i_width * vgl->tex_pixel_size;
322 rsc.p[0].i_lines = vgl->fmt.i_height;
324 picture[i] = picture_NewFromResource(&vgl->fmt, &rsc);
325 if (!picture[i]) {
326 free(vgl->buffer[i]);
327 vgl->buffer[i] = NULL;
328 break;
331 if (i < VLCGL_TEXTURE_COUNT)
332 goto error;
334 /* */
335 picture_pool_configuration_t cfg;
336 memset(&cfg, 0, sizeof(cfg));
337 cfg.picture_count = i;
338 cfg.picture = picture;
339 #ifdef __APPLE__
340 cfg.lock = PictureLock;
341 cfg.unlock = PictureUnlock;
342 #endif
343 vgl->pool = picture_pool_NewExtended(&cfg);
344 if (!vgl->pool)
345 goto error;
347 vout_display_opengl_ResetTextures(vgl);
349 return vgl->pool;
351 error:
352 for (int j = 0; j < i; j++) {
353 picture_Delete(picture[j]);
354 vgl->buffer[j] = NULL;
356 return NULL;
359 static int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
360 picture_t *picture)
362 /* On Win32/GLX, we do this the usual way:
363 + Fill the buffer with new content,
364 + Reload the texture,
365 + Use the texture.
367 On OS X with VRAM or AGP texturing, the order has to be:
368 + Reload the texture,
369 + Fill the buffer with new content,
370 + Use the texture.
372 (Thanks to gcc from the Arstechnica forums for the tip)
374 Therefore on OSX, we have to use two buffers and textures and use a
375 lock(/unlock) managed picture pool.
378 if (vout_opengl_Lock(vgl->gl))
379 return VLC_EGENERIC;
381 #ifdef __APPLE__
382 /* Bind to the texture for drawing */
383 glBindTexture(VLCGL_TARGET, get_texture(picture));
384 #else
385 /* Update the texture */
386 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
387 vgl->fmt.i_width, vgl->fmt.i_height,
388 VLCGL_FORMAT, VLCGL_TYPE, picture->p[0].p_pixels);
389 #endif
391 vout_opengl_Unlock(vgl->gl);
392 return VLC_SUCCESS;
395 static int vout_display_opengl_Display(vout_display_opengl_t *vgl,
396 const video_format_t *source)
398 if (vout_opengl_Lock(vgl->gl))
399 return VLC_EGENERIC;
401 /* glTexCoord works differently with GL_TEXTURE_2D and
402 GL_TEXTURE_RECTANGLE_EXT */
403 #if VLCGL_TARGET == GL_TEXTURE_2D
404 const float f_normw = vgl->tex_width;
405 const float f_normh = vgl->tex_height;
406 #else
407 assert(VLCGL_TARGET == GL_TEXTURE_RECTANGLE_EXT);
408 const float f_normw = 1.0;
409 const float f_normh = 1.0;
410 #endif
412 float f_x = (source->i_x_offset + 0 ) / f_normw;
413 float f_y = (source->i_y_offset + 0 ) / f_normh;
414 float f_width = (source->i_x_offset + source->i_visible_width ) / f_normw;
415 float f_height = (source->i_y_offset + source->i_visible_height) / f_normh;
417 /* Why drawing here and not in Render()? Because this way, the
418 OpenGL providers can call vout_display_opengl_Display to force redraw.i
419 Currently, the OS X provider uses it to get a smooth window resizing */
421 glClear(GL_COLOR_BUFFER_BIT);
423 glEnable(VLCGL_TARGET);
425 glBegin(GL_POLYGON);
426 glTexCoord2f(f_x, f_y); glVertex2f(-1.0, 1.0);
427 glTexCoord2f(f_width, f_y); glVertex2f( 1.0, 1.0);
428 glTexCoord2f(f_width, f_height); glVertex2f( 1.0, -1.0);
429 glTexCoord2f(f_x, f_height); glVertex2f(-1.0, -1.0);
430 glEnd();
432 glDisable(VLCGL_TARGET);
434 vout_opengl_Swap(vgl->gl);
436 vout_opengl_Unlock(vgl->gl);
437 return VLC_SUCCESS;