*****************************************************************************
* Copyright (C) 2004 the VideoLAN team
* Copyright (C) 2009 Laurent Aimar
- * $Id$
*
* Authors: Cyril Deguet <asmax@videolan.org>
* Gildas Bazin <gbazin@videolan.org>
#include <vlc_common.h>
#include <vlc_picture_pool.h>
-#include <vlc_vout_opengl.h>
+#include <vlc_opengl.h>
-#ifdef __APPLE__
-# include <OpenGL/gl.h>
-# include <OpenGL/glext.h>
-#else
-# include <GL/gl.h>
-#endif
-
-#ifndef YCBCR_MESA
-# define YCBCR_MESA 0x8757
-#endif
-#ifndef UNSIGNED_SHORT_8_8_MESA
-# define UNSIGNED_SHORT_8_8_MESA 0x85BA
-#endif
-/* RV16 */
-#ifndef GL_UNSIGNED_SHORT_5_6_5
-# define GL_UNSIGNED_SHORT_5_6_5 0x8363
-#endif
-#ifndef GL_CLAMP_TO_EDGE
-# define GL_CLAMP_TO_EDGE 0x812F
-#endif
-
-#ifdef __APPLE__
-/* On OS X, use GL_TEXTURE_RECTANGLE_EXT instead of GL_TEXTURE_2D.
- This allows sizes which are not powers of 2 */
-# define VLCGL_TARGET GL_TEXTURE_RECTANGLE_EXT
-
-/* OS X OpenGL supports YUV. Hehe. */
-# define VLCGL_FORMAT GL_YCBCR_422_APPLE
-# define VLCGL_TYPE GL_UNSIGNED_SHORT_8_8_APPLE
-
-# define VLCGL_TEXTURE_COUNT (2)
-#else
-
-# define VLCGL_TARGET GL_TEXTURE_2D
-
-/* RV32 */
-# define VLCGL_RGB_FORMAT GL_RGBA
-# define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
-
-/* YUY2 */
-# define VLCGL_YUV_FORMAT YCBCR_MESA
-# define VLCGL_YUV_TYPE UNSIGNED_SHORT_8_8_MESA
-
-/* Use RGB on Win32/GLX */
-# define VLCGL_FORMAT VLCGL_RGB_FORMAT
-# define VLCGL_TYPE VLCGL_RGB_TYPE
-
-# define VLCGL_TEXTURE_COUNT (1)
-#endif
-
-static inline int GetAlignedSize(int i_size)
-{
- /* Return the nearest power of 2 */
- int i_result = 1;
- while(i_result < i_size)
- i_result *= 2;
-
- return i_result;
-}
-
-typedef struct {
- vout_opengl_t *gl;
-
- video_format_t fmt;
-
- int tex_pixel_size;
- int tex_width;
- int tex_height;
-
- GLuint texture[VLCGL_TEXTURE_COUNT];
- uint8_t *buffer[VLCGL_TEXTURE_COUNT];
-
- picture_pool_t *pool;
-} vout_display_opengl_t;
-
-static int vout_display_opengl_Init(vout_display_opengl_t *vgl,
- video_format_t *fmt,
- vout_opengl_t *gl)
-{
- vgl->gl = gl;
-
- /* Find the chroma we will use and update fmt */
- /* TODO: We use YCbCr on Mac which is Y422, but on OSX it seems to == YUY2. Verify */
-#if (defined(WORDS_BIGENDIAN) && VLCGL_FORMAT == GL_YCBCR_422_APPLE) || (VLCGL_FORMAT == YCBCR_MESA)
- fmt->i_chroma = VLC_CODEC_YUYV;
- vgl->tex_pixel_size = 2;
-#elif defined(GL_YCBCR_422_APPLE) && (VLCGL_FORMAT == GL_YCBCR_422_APPLE)
- fmt->i_chroma = VLC_CODEC_UYVY;
- vgl->tex_pixel_size = 2;
-#elif VLCGL_FORMAT == GL_RGB
-# if VLCGL_TYPE == GL_UNSIGNED_BYTE
- fmt->i_chroma = VLC_CODEC_RGB24;
-# if defined(WORDS_BIGENDIAN)
- fmt->i_rmask = 0x00ff0000;
- fmt->i_gmask = 0x0000ff00;
- fmt->i_bmask = 0x000000ff;
-# else
- fmt->i_rmask = 0x000000ff;
- fmt->i_gmask = 0x0000ff00;
- fmt->i_bmask = 0x00ff0000;
-# endif
- vgl->tex_pixel_size = 3;
-# else
- fmt->i_chroma = VLC_CODEC_RGB16;
-# if defined(WORDS_BIGENDIAN)
- fmt->i_rmask = 0x001f;
- fmt->i_gmask = 0x07e0;
- fmt->i_bmask = 0xf800;
-# else
- fmt->i_rmask = 0xf800;
- fmt->i_gmask = 0x07e0;
- fmt->i_bmask = 0x001f;
-# endif
- vgl->tex_pixel_size = 2;
-# endif
-#else
- fmt->i_chroma = VLC_CODEC_RGB32;
-# if defined(WORDS_BIGENDIAN)
- fmt->i_rmask = 0xff000000;
- fmt->i_gmask = 0x00ff0000;
- fmt->i_bmask = 0x0000ff00;
-# else
- fmt->i_rmask = 0x000000ff;
- fmt->i_gmask = 0x0000ff00;
- fmt->i_bmask = 0x00ff0000;
-# endif
- vgl->tex_pixel_size = 4;
+// Define USE_OPENGL_ES to the GL ES Version you want to select
+#ifndef USE_OPENGL_ES
+# define USE_OPENGL_ES 0
#endif
- vgl->fmt = *fmt;
-
- /* Texture size */
-#ifdef __APPLE__
- vgl->tex_width = fmt->i_width;
- vgl->tex_height = fmt->i_height;
+#if !defined (__APPLE__)
+# if USE_OPENGL_ES == 2
+# include <GLES2/gl2.h>
+# elif USE_OPENGL_ES == 1
+# include <GLES/gl.h>
+# else
+# ifdef WIN32
+# include <GL/glew.h>
+# endif
+# include <GL/gl.h>
+# endif
#else
- /* A texture must have a size aligned on a power of 2 */
- vgl->tex_width = GetAlignedSize(fmt->i_width);
- vgl->tex_height = GetAlignedSize(fmt->i_height);
+# if USE_OPENGL_ES == 2
+# include <OpenGLES/ES2/gl.h>
+# elif USE_OPENGL_ES == 1
+# include <OpenGLES/ES1/gl.h>
+# else
+# define MACOS_OPENGL
+# include <OpenGL/gl.h>
+# endif
#endif
- /* */
- for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
- vgl->texture[i] = 0;
- vgl->buffer[i] = NULL;
- }
- vgl->pool = NULL;
-
- /* */
- if (!vout_opengl_Lock(vgl->gl)) {
-
- glDisable(GL_BLEND);
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- glDisable(GL_CULL_FACE);
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
-
- vout_opengl_Unlock(vgl->gl);
- }
- return VLC_SUCCESS;
-}
-static void vout_display_opengl_Clean(vout_display_opengl_t *vgl)
+static inline bool HasExtension(const char *apis, const char *api)
{
- /* */
- if (!vout_opengl_Lock(vgl->gl)) {
-
- glFinish();
- glFlush();
- glDeleteTextures(VLCGL_TEXTURE_COUNT, vgl->texture);
-
- vout_opengl_Unlock(vgl->gl);
- }
- if (vgl->pool) {
- picture_pool_Delete(vgl->pool);
- for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
- free(vgl->buffer[i]);
+ size_t apilen = strlen(api);
+ while (apis) {
+ while (*apis == ' ')
+ apis++;
+ if (!strncmp(apis, api, apilen) && memchr(" ", apis[apilen], 2))
+ return true;
+ apis = strchr(apis, ' ');
}
+ return false;
}
-static int vout_display_opengl_ResetTextures(vout_display_opengl_t *vgl)
-{
- if (vout_opengl_Lock(vgl->gl))
- return VLC_EGENERIC;
-
- glDeleteTextures(VLCGL_TEXTURE_COUNT, vgl->texture);
-
- glGenTextures(VLCGL_TEXTURE_COUNT, vgl->texture);
- for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
- glBindTexture(VLCGL_TARGET, vgl->texture[i]);
-
- /* Set the texture parameters */
- glTexParameterf(VLCGL_TARGET, GL_TEXTURE_PRIORITY, 1.0);
-
- glTexParameteri(VLCGL_TARGET, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(VLCGL_TARGET, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glTexParameteri(VLCGL_TARGET, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(VLCGL_TARGET, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+typedef struct vout_display_opengl_t vout_display_opengl_t;
-#ifdef __APPLE__
- /* Tell the driver not to make a copy of the texture but to use
- our buffer */
- glEnable(GL_UNPACK_CLIENT_STORAGE_APPLE);
- glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
-
-#if 0
- /* Use VRAM texturing */
- glTexParameteri(VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
- GL_STORAGE_CACHED_APPLE);
-#else
- /* Use AGP texturing */
- glTexParameteri(VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
- GL_STORAGE_SHARED_APPLE);
-#endif
-#endif
-
- /* Call glTexImage2D only once, and use glTexSubImage2D later */
- if (vgl->buffer[i])
- glTexImage2D(VLCGL_TARGET, 0, 3, vgl->tex_width, vgl->tex_height,
- 0, VLCGL_FORMAT, VLCGL_TYPE, vgl->buffer[i]);
- }
+vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
+ const vlc_fourcc_t **subpicture_chromas,
+ vlc_gl_t *gl);
+void vout_display_opengl_Delete(vout_display_opengl_t *vgl);
- vout_opengl_Unlock(vgl->gl);
- return VLC_SUCCESS;
-}
-
-#ifdef __APPLE__
-/* XXX See comment vout_display_opengl_Prepare */
-struct picture_sys_t {
- vout_display_opengl_t *vgl;
- GLuint texture;
-};
-static int PictureLock(picture_t *picture)
-{
- if (!picture->p_sys)
- return VLC_SUCCESS;
-
- vout_display_opengl_t *vgl = picture->p_sys->vgl;
- if (!vout_opengl_Lock(vgl->gl)) {
-
- glBindTexture(VLCGL_TARGET, picture->p_sys->texture);
- glTexSubImage2D(VLCGL_TARGET, 0, 0, 0,
- vgl->fmt.i_width, vgl->fmt.i_height,
- VLCGL_FORMAT, VLCGL_TYPE, picture->p[0].p_pixels);
-
- vout_opengl_Unlock(vgl->gl);
- }
- return VLC_SUCCESS;
-}
-static void PictureUnlock(picture_t *picture)
-{
- VLC_UNUSED(picture);
-}
-#endif
-
-static picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl)
-{
- picture_t *picture[VLCGL_TEXTURE_COUNT];
-
- int i;
- for (i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
-
- /* TODO memalign would be way better */
- vgl->buffer[i] = malloc(vgl->tex_width * vgl->tex_height * vgl->tex_pixel_size);
- if (!vgl->buffer[i])
- break;
-
- picture_resource_t rsc;
- memset(&rsc, 0, sizeof(rsc));
-#ifdef __APPLE__
- rsc.p_sys = malloc(sizeof(*rsc.p_sys));
- if (rsc.p_sys) {
- rsc.p_sys->vgl = vgl;
- rsc.p_sys->texture = vgl->texture[i];
- }
-#endif
- rsc.p[0].p_pixels = vgl->buffer[i];
- rsc.p[0].i_pitch = vgl->fmt.i_width * vgl->tex_pixel_size;
- rsc.p[0].i_lines = vgl->fmt.i_height;
-
- picture[i] = picture_NewFromResource(&vgl->fmt, &rsc);
- if (!picture[i]) {
- free(vgl->buffer[i]);
- vgl->buffer[i] = NULL;
- break;
- }
- }
- if (i < VLCGL_TEXTURE_COUNT)
- goto error;
-
- /* */
- picture_pool_configuration_t cfg;
- memset(&cfg, 0, sizeof(cfg));
- cfg.picture_count = i;
- cfg.picture = picture;
-#ifdef __APPLE__
- cfg.lock = PictureLock;
- cfg.unlock = PictureUnlock;
-#endif
- vgl->pool = picture_pool_NewExtended(&cfg);
- if (!vgl->pool)
- goto error;
-
- vout_display_opengl_ResetTextures(vgl);
-
- return vgl->pool;
-
-error:
- for (int j = 0; j < i; j++) {
- picture_Delete(picture[j]);
- vgl->buffer[j] = NULL;
- }
- return NULL;
-}
-
-static int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
- picture_t *picture)
-{
- /* On Win32/GLX, we do this the usual way:
- + Fill the buffer with new content,
- + Reload the texture,
- + Use the texture.
-
- On OS X with VRAM or AGP texturing, the order has to be:
- + Reload the texture,
- + Fill the buffer with new content,
- + Use the texture.
-
- (Thanks to gcc from the Arstechnica forums for the tip)
-
- Therefore on OSX, we have to use two buffers and textures and use a
- lock(/unlock) managed picture pool.
- */
-
- if (vout_opengl_Lock(vgl->gl))
- return VLC_EGENERIC;
-
-#ifdef __APPLE__
- /* Bind to the texture for drawing */
- glBindTexture(VLCGL_TARGET, picture->p_sys->texture);
-#else
- /* Update the texture */
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
- vgl->fmt.i_width, vgl->fmt.i_height,
- VLCGL_FORMAT, VLCGL_TYPE, picture->p[0].p_pixels);
-#endif
-
- vout_opengl_Unlock(vgl->gl);
- return VLC_SUCCESS;
-}
-
-static int vout_display_opengl_Display(vout_display_opengl_t *vgl,
- const video_format_t *source)
-{
- if (vout_opengl_Lock(vgl->gl))
- return VLC_EGENERIC;
-
- /* glTexCoord works differently with GL_TEXTURE_2D and
- GL_TEXTURE_RECTANGLE_EXT */
-#if VLCGL_TARGET == GL_TEXTURE_2D
- const float f_normw = vgl->tex_width;
- const float f_normh = vgl->tex_height;
-#else
- assert(VLCGL_TARGET == GL_TEXTURE_RECTANGLE_EXT);
- const float f_normw = 1.0;
- const float f_normh = 1.0;
-#endif
-
- float f_x = (source->i_x_offset + 0 ) / f_normw;
- float f_y = (source->i_y_offset + 0 ) / f_normh;
- float f_width = (source->i_x_offset + source->i_visible_width ) / f_normw;
- float f_height = (source->i_y_offset + source->i_visible_height) / f_normh;
-
- /* Why drawing here and not in Render()? Because this way, the
- OpenGL providers can call vout_display_opengl_Display to force redraw.i
- Currently, the OS X provider uses it to get a smooth window resizing */
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- glEnable(VLCGL_TARGET);
-
- glBegin(GL_POLYGON);
- glTexCoord2f(f_x, f_y); glVertex2f(-1.0, 1.0);
- glTexCoord2f(f_width, f_y); glVertex2f( 1.0, 1.0);
- glTexCoord2f(f_width, f_height); glVertex2f( 1.0, -1.0);
- glTexCoord2f(f_x, f_height); glVertex2f(-1.0, -1.0);
- glEnd();
-
- glDisable(VLCGL_TARGET);
-
- vout_opengl_Swap(vgl->gl);
-
- vout_opengl_Unlock(vgl->gl);
- return VLC_SUCCESS;
-}
+picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned);
+int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
+ picture_t *picture, subpicture_t *subpicture);
+int vout_display_opengl_Display(vout_display_opengl_t *vgl,
+ const video_format_t *source);