[vlc-devel] [PATCH 1/3] opengl: Use GLSL 1.2 shaders instead of arb extension
Ilkka Ollakka
ileoo at videolan.org
Sat May 5 11:37:06 CEST 2012
Use VBO/VAO as most of the coordinates we use, are static and no need to push them
again in every frame.
OpenGL and OpenGL ES 2.0 support vbo/vao and GLSL shaders, so we can use same
shader codes in both and we can cope with just using core specifications without
extensions.
Use uniform in shaders instead of glColor for transparency
Currently problematic case is unsupported ROW_UNPACK_LENGTH in ES 2.0, which is
used to unpack YUV to separated texture planes. This can be worked around, but
have not yet tested it yet. GLSL 1.2 is used in shader code, which should work in most
reasonably modern linux distributions and in ES 2.0
---
modules/video_output/opengl.c | 618 +++++++++++++++++++++++++----------------
modules/video_output/opengl.h | 1 +
2 files changed, 386 insertions(+), 233 deletions(-)
diff --git a/modules/video_output/opengl.c b/modules/video_output/opengl.c
index 1b5384b..edfa1e1 100644
--- a/modules/video_output/opengl.c
+++ b/modules/video_output/opengl.c
@@ -36,16 +36,6 @@
#include "opengl.h"
// Define USE_OPENGL_ES to the GL ES Version you want to select
-#ifdef __APPLE__
-# define PFNGLGENPROGRAMSARBPROC typeof(glGenProgramsARB)*
-# define PFNGLBINDPROGRAMARBPROC typeof(glBindProgramARB)*
-# define PFNGLPROGRAMSTRINGARBPROC typeof(glProgramStringARB)*
-# define PFNGLDELETEPROGRAMSARBPROC typeof(glDeleteProgramsARB)*
-# define PFNGLPROGRAMLOCALPARAMETER4FVARBPROC typeof(glProgramLocalParameter4fvARB)*
-# define PFNGLACTIVETEXTUREPROC typeof(glActiveTexture)*
-# define PFNGLCLIENTACTIVETEXTUREPROC typeof(glClientActiveTexture)*
-#endif
-
/* RV16 */
#ifndef GL_UNSIGNED_SHORT_5_6_5
# define GL_UNSIGNED_SHORT_5_6_5 0x8363
@@ -54,6 +44,42 @@
# define GL_CLAMP_TO_EDGE 0x812F
#endif
+#ifdef __APPLE__
+# define PFNGLBINDVERTEXARRAYPROC typeof(glBindVertexArrayAPPLE)*
+# define PFNGLDELETEVERTEXARRAYSPROC typeof(glDeleteVertexArraysAPPLE)*
+# define PFNGLGENVERTEXARRAYSPROC typeof(glGenVertexArraysAPPLE)*
+# define PFNGLGENBUFFERSPROC typeof(glGenBuffers)*
+# define PFNGLBINDBUFFERPROC typeof(glBindBuffer)*
+# define PFNGLDELETEBUFFERSPROC typeof(glDeleteBuffers)*
+# define PFNGLBUFFERSUBDATAPROC typeof(glBufferSubData)*
+# define PFNGLBUFFERDATAPROC typeof(glBufferData)*
+# define PFNGLENABLEVERTEXATTRIBARRAYPROC typeof(glEnableVertexAttribArray)*
+# define PFNGLVERTEXATTRIBPOINTERPROC typeof(glVertexAttribPointer)*
+# define PFNGLGETPROGRAMIVPROC typeof(glGetProgramiv)*
+# define PFNGLGETPROGRAMINFOLOGPROC typeof(glGetProgramInfoLog)*
+# define PFNGLGETSHADERIVPROC typeof(glGetShaderiv)*
+# define PFNGLGETSHADERINFOLOGPROC typeof(glGetShaderInfoLog)*
+# define PFNGLGETUNIFORMLOCATIONPROC typeof(glGetUniformLocation)*
+# define PFNGLGETATTRIBLOCATIONPROC typeof(glGetAttribLocation)*
+# define PFNGLUNIFORM4FVPROC typeof(glUniform4fv)*
+# define PFNGLUNIFORM4FPROC typeof(glUniform4f)*
+# define PFNGLUNIFORM1IVPROC typeof(glUniform1iv)*
+# define PFNGLCREATESHADERPROC typeof(glCreateShader)*
+# define PFNGLSHADERSOURCEPROC typeof(glShaderSource)*
+# define PFNGLCOMPILESHADERPROC typeof(glCompileShader)*
+# define PFNGLDETACHSHADERPROC typeof(glDetachShader)*
+# define PFNGLDELETESHADERPROC typeof(glDeleteShader)*
+# define PFNGLCREATEPROGRAMPROC typeof(glCreateProgram)*
+# define PFNGLLINKPROGRAMPROC typeof(glLinkProgram)*
+# define PFNGLUSEPROGRAMPROC typeof(glUseProgram)*
+# define PFNGLDELETEPROGRAMPROC typeof(glDeleteProgram)*
+# define PFNGLATTACHSHADERPROC typeof(glAttachShader)*
+#elif USE_OPENGL_ES
+# define PFNGLBINDVERTEXARRAYPROC typeof(glBindVertexArrayOES)*
+# define PFNGLDELETEVERTEXARRAYSPROC typeof(glDeleteVertexArraysEOS)*
+# define PFNGLGENVERTEXARRAYSPROC typeof(glGenVertexArraysEOS)*
+#endif
+
#if USE_OPENGL_ES
# define VLCGL_TEXTURE_COUNT 1
# define VLCGL_PICTURE_MAX 1
@@ -104,21 +130,60 @@ struct vout_display_opengl_t {
picture_pool_t *pool;
- GLuint program;
+ /* index 0 for normal and 1 for subtitle overlay */
+ GLuint program[2];
+ GLuint shader[2];
+ GLuint vao[2];
+ GLuint buffers[2][2];
int local_count;
- GLfloat local_value[16][4];
+ GLfloat local_value[16];
+
+ /* VAO stuff in opengl ES 2.0 are behind OES mandatory extension */
+ PFNGLBINDVERTEXARRAYPROC BindVertexArray;
+ PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
+ PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
+
+ /* Buffer commands */
+ PFNGLGENBUFFERSPROC GenBuffers;
+ PFNGLBINDBUFFERPROC BindBuffer;
+ PFNGLDELETEBUFFERSPROC DeleteBuffers;
+ PFNGLBUFFERSUBDATAPROC BufferSubData;
+
+ PFNGLBUFFERDATAPROC BufferData;
+
+ /* Vertex Array commands*/
+ PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
+ PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
+
+ PFNGLGETPROGRAMIVPROC GetProgramiv;
+ PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
+ PFNGLGETSHADERIVPROC GetShaderiv;
+ PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
+
+ PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
+ PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
+
+ PFNGLUNIFORM4FVPROC Uniform4fv;
+ PFNGLUNIFORM4FPROC Uniform4f;
+ PFNGLUNIFORM1IVPROC Uniform1iv;
+
+ /* Shader command */
+ PFNGLCREATESHADERPROC CreateShader;
+ PFNGLSHADERSOURCEPROC ShaderSource;
+ PFNGLCOMPILESHADERPROC CompileShader;
+ PFNGLDETACHSHADERPROC DetachShader;
+ PFNGLDELETESHADERPROC DeleteShader;
+
+ PFNGLCREATEPROGRAMPROC CreateProgram;
+ PFNGLLINKPROGRAMPROC LinkProgram;
+ PFNGLUSEPROGRAMPROC UseProgram;
+ PFNGLDELETEPROGRAMPROC DeleteProgram;
+
+ PFNGLATTACHSHADERPROC AttachShader;
- /* fragment_program */
- PFNGLGENPROGRAMSARBPROC GenProgramsARB;
- PFNGLBINDPROGRAMARBPROC BindProgramARB;
- PFNGLPROGRAMSTRINGARBPROC ProgramStringARB;
- PFNGLDELETEPROGRAMSARBPROC DeleteProgramsARB;
- PFNGLPROGRAMLOCALPARAMETER4FVARBPROC ProgramLocalParameter4fvARB;
/* multitexture */
bool use_multitexture;
- PFNGLACTIVETEXTUREPROC ActiveTexture;
- PFNGLCLIENTACTIVETEXTUREPROC ClientActiveTexture;
};
static inline int GetAlignedSize(unsigned size)
@@ -158,46 +223,10 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
return NULL;
}
- const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
-
/* Load extensions */
- bool supports_fp = false;
- if (HasExtension(extensions, "GL_ARB_fragment_program")) {
-#if !defined(MACOS_OPENGL)
- vgl->GenProgramsARB = (PFNGLGENPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenProgramsARB");
- vgl->BindProgramARB = (PFNGLBINDPROGRAMARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindProgramARB");
- vgl->ProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramStringARB");
- vgl->DeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgramsARB");
- vgl->ProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramLocalParameter4fvARB");
-#else
- vgl->GenProgramsARB = glGenProgramsARB;
- vgl->BindProgramARB = glBindProgramARB;
- vgl->ProgramStringARB = glProgramStringARB;
- vgl->DeleteProgramsARB = glDeleteProgramsARB;
- vgl->ProgramLocalParameter4fvARB = glProgramLocalParameter4fvARB;
-#endif
- supports_fp = vgl->GenProgramsARB &&
- vgl->BindProgramARB &&
- vgl->ProgramStringARB &&
- vgl->DeleteProgramsARB &&
- vgl->ProgramLocalParameter4fvARB;
- }
-
- bool supports_multitexture = false;
+ bool supports_fp = true;
GLint max_texture_units = 0;
- if (HasExtension(extensions, "GL_ARB_multitexture")) {
-#if !defined(MACOS_OPENGL)
- vgl->ActiveTexture = (PFNGLACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTexture");
- vgl->ClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glClientActiveTexture");
-#else
- vgl->ActiveTexture = glActiveTexture;
- vgl->ClientActiveTexture = glClientActiveTexture;
-#endif
- supports_multitexture = vgl->ActiveTexture &&
- vgl->ClientActiveTexture;
- if (supports_multitexture)
- glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max_texture_units);
- }
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
/* Initialize with default chroma */
vgl->fmt = *fmt;
@@ -235,7 +264,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
/* Use YUV if possible and needed */
bool need_fs_yuv = false;
float yuv_range_correction = 1.0;
- if (supports_fp && supports_multitexture && max_texture_units >= 3 &&
+ if ( max_texture_units >= 3 &&
vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
while (*list) {
@@ -264,111 +293,288 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
}
}
+/*
+#if USE_OPENGL_ES
+ vgl->BindVertexArray = (PFNGLBINDVERTEXARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindVertexArrayOES");
+ vgl->GenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenVertexArraysOES");
+ vgl->DeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteVertexArraysOES");
+ */
+#ifdef __APPLE__
+ vgl->BindVertexArray = (PFNGLBINDVERTEXARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindVertexArrayAPPLE");
+ vgl->GenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenVertexArraysAPPLE");
+ vgl->DeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteVertexArraysAPPLE");
+#else
+ vgl->BindVertexArray = (PFNGLBINDVERTEXARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindVertexArray");
+ vgl->GenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenVertexArrays");
+ vgl->DeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteVertexArrays");
+#endif
+
+ vgl->GenBuffers = (PFNGLGENBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenBuffers");
+ vgl->BindBuffer = (PFNGLBINDBUFFERPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindBuffer");
+ vgl->BufferData = (PFNGLBUFFERDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferData");
+ vgl->BufferSubData = (PFNGLBUFFERSUBDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferSubData");
+ vgl->DeleteBuffers = (PFNGLDELETEBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteBuffers");
+
+ vgl->EnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glEnableVertexAttribArray");
+ vgl->VertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)vlc_gl_GetProcAddress(vgl->gl, "glVertexAttribPointer");
+
+ vgl->CreateShader = (PFNGLCREATESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateShader");
+ vgl->ShaderSource = (PFNGLSHADERSOURCEPROC)vlc_gl_GetProcAddress(vgl->gl, "glShaderSource");
+ vgl->CompileShader = (PFNGLCOMPILESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCompileShader");
+ vgl->AttachShader = (PFNGLATTACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glAttachShader");
+ vgl->GetProgramiv = (PFNGLGETPROGRAMIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramiv");
+ vgl->GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramInfoLog");
+ vgl->GetShaderiv = (PFNGLGETSHADERIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderiv");
+ vgl->GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderInfoLog");
+ vgl->DetachShader = (PFNGLDETACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDetachShader");
+ vgl->DeleteShader = (PFNGLDELETESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteShader");
+
+ vgl->GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetUniformLocation");
+ vgl->GetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetAttribLocation");
+ vgl->Uniform4fv = (PFNGLUNIFORM4FVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4fv");
+ vgl->Uniform4f = (PFNGLUNIFORM4FPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4f");
+ vgl->Uniform1iv = (PFNGLUNIFORM1IVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform1iv");
+
+ vgl->CreateProgram = (PFNGLCREATEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateProgram");
+ vgl->LinkProgram = (PFNGLLINKPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glLinkProgram");
+ vgl->UseProgram = (PFNGLUSEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glUseProgram");
+ vgl->DeleteProgram = (PFNGLDELETEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgram");
+
vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
vgl->use_multitexture = vgl->chroma->plane_count > 1;
- bool supports_npot = false;
-#if USE_OPENGL_ES == 2
- supports_npot = true;
-#else
- supports_npot |= HasExtension(extensions, "GL_APPLE_texture_2D_limited_npot") ||
- HasExtension(extensions, "GL_ARB_texture_non_power_of_two");
-#endif
/* Texture size */
for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
- if (supports_npot) {
- vgl->tex_width[j] = w;
- vgl->tex_height[j] = h;
- }
- else {
- /* A texture must have a size aligned on a power of 2 */
- vgl->tex_width[j] = GetAlignedSize(w);
- vgl->tex_height[j] = GetAlignedSize(h);
- }
+ vgl->tex_width[j] = w;
+ vgl->tex_height[j] = h;
}
/* Build fragment program if needed */
- vgl->program = 0;
+ vgl->program[0] = 0;
+ vgl->program[1] = 0;
vgl->local_count = 0;
if (supports_fp) {
char *code = NULL;
- if (need_fs_yuv) {
/* [R/G/B][Y U V O] from TV range to full range
* XXX we could also do hue/brightness/constrast/gamma
* by simply changing the coefficients
*/
- const float matrix_bt601_tv2full[3][4] = {
- { 1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 },
- { 1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 },
- { 1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 },
+ const float matrix_bt601_tv2full[12] = {
+ 1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 ,
+ 1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 ,
+ 1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 ,
};
- const float matrix_bt709_tv2full[3][4] = {
- { 1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 },
- { 1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 },
- { 1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 },
+ const float matrix_bt709_tv2full[12] = {
+ 1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 ,
+ 1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 ,
+ 1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 ,
};
- const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
+ const float (*matrix) = fmt->i_height > 576 ? matrix_bt709_tv2full
: matrix_bt601_tv2full;
/* Basic linear YUV -> RGB conversion using bilinear interpolation */
- const char *template_yuv =
- "!!ARBfp1.0"
- "OPTION ARB_precision_hint_fastest;"
-
- "TEMP src;"
- "TEX src.x, fragment.texcoord[0], texture[0], 2D;"
- "TEX src.%c, fragment.texcoord[1], texture[1], 2D;"
- "TEX src.%c, fragment.texcoord[2], texture[2], 2D;"
-
- "PARAM coefficient[4] = { program.local[0..3] };"
-
- "TEMP tmp;"
- "MAD tmp.rgb, src.xxxx, coefficient[0], coefficient[3];"
- "MAD tmp.rgb, src.yyyy, coefficient[1], tmp;"
- "MAD result.color.rgb, src.zzzz, coefficient[2], tmp;"
- "END";
+ const char *template_glsl_yuv =
+ "#version 120\n"
+ "uniform sampler2D Texture[3];"
+ "uniform vec4 coefficient[4];"
+ "varying vec4 textureCoordinates0;"
+ "varying vec4 textureCoordinates1;"
+ "varying vec4 textureCoordinates2;"
+
+ "void main(void) {"
+ " vec4 x,y,z,result;"
+ " x = texture2D(Texture[0], textureCoordinates0.st);"
+ " %c = texture2D(Texture[1], textureCoordinates1.st);"
+ " %c = texture2D(Texture[2], textureCoordinates2.st);"
+
+ " result = x * coefficient[0] + coefficient[3];"
+ " result = (y * coefficient[1]) + result;"
+ " result = (z * coefficient[2]) + result;"
+ " gl_FragColor = result;"
+ "}";
bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
vgl->fmt.i_chroma == VLC_CODEC_YV9;
- if (asprintf(&code, template_yuv,
+ if (asprintf(&code, template_glsl_yuv,
swap_uv ? 'z' : 'y',
swap_uv ? 'y' : 'z') < 0)
code = NULL;
for (int i = 0; i < 4; i++) {
float correction = i < 3 ? yuv_range_correction : 1.0;
- for (int j = 0; j < 4; j++) {
- vgl->local_value[vgl->local_count + i][j] = j < 3 ? correction * matrix[j][i] : 0.0;
- }
+ /* We place coefficient values for coefficient[4] in one array from matrix values.
+ Notice that we fill values from top down instead of left to right.*/
+ for( int j = 0; j < 4; j++ )
+ vgl->local_value[vgl->local_count + i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.0 ;
}
vgl->local_count += 4;
- }
- if (code) {
- // Here you have shaders
- vgl->GenProgramsARB(1, &vgl->program);
- vgl->BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, vgl->program);
- vgl->ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
- GL_PROGRAM_FORMAT_ASCII_ARB,
- strlen(code), (const GLbyte*)code);
- if (glGetError() == GL_INVALID_OPERATION) {
- /* FIXME if the program was needed for YUV, the video will be broken */
-#if 0
- GLint position;
- glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);
-
- const char *msg = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
- fprintf(stderr, "GL_INVALID_OPERATION: error at %d: %s\n", position, msg);
-#endif
- vgl->DeleteProgramsARB(1, &vgl->program);
- vgl->program = 0;
+
+ // Basic vertex shader that we use in both cases
+ const char *vertexShader =
+ "#version 120\n"
+ "varying vec4 textureCoordinates0;"
+ "varying vec4 textureCoordinates1;"
+ "varying vec4 textureCoordinates2;"
+ "attribute vec4 textureC0;"
+ "attribute vec4 textureC1;"
+ "attribute vec4 textureC2;"
+ "attribute vec4 positionCoordinate;"
+ "void main() {"
+ " textureCoordinates0 = textureC0;"
+ " textureCoordinates1 = textureC1;"
+ " textureCoordinates2 = textureC2;"
+ " gl_Position = positionCoordinate; }";
+
+ // Dummy shader for text overlay
+ const char *helloShader =
+ "#version 120\n"
+ "uniform sampler2D Texture;"
+ "uniform vec4 fillColor;"
+ "varying vec4 textureCoordinates0;"
+ "varying vec4 textureCoordinates1;"
+ "varying vec4 textureCoordinates2;"
+ "void main()"
+ "{ vec4 dummy = textureCoordinates1*textureCoordinates2;"
+ " gl_FragColor = texture2D(Texture, textureCoordinates0.st)*fillColor;}";
+
+ GLint vertexShaderId = vgl->CreateShader( GL_VERTEX_SHADER );
+ vgl->ShaderSource( vertexShaderId, 1, (const GLchar **)&vertexShader, NULL);
+ vgl->CompileShader( vertexShaderId );
+
+ /* Create 'dummy' shader that handles subpicture overlay for now*/
+ vgl->shader[1] = vgl->CreateShader( GL_FRAGMENT_SHADER );
+ vgl->ShaderSource( vgl->shader[1], 1, &helloShader, NULL);
+ vgl->CompileShader( vgl->shader[1] );
+ vgl->program[1] = vgl->CreateProgram();
+ vgl->AttachShader( vgl->program[1], vgl->shader[1]);
+ vgl->AttachShader( vgl->program[1], vertexShaderId );
+ vgl->LinkProgram( vgl->program[1] );
+
+ // Create shader from code
+ vgl->shader[0] = vgl->CreateShader( GL_FRAGMENT_SHADER );
+ vgl->program[0] = vgl->CreateProgram();
+ if( need_fs_yuv )
+ {
+ vgl->ShaderSource( vgl->shader[0], 1, (const GLchar **)&code, NULL );
+ vgl->CompileShader( vgl->shader[0]);
+ vgl->AttachShader( vgl->program[0], vgl->shader[0] );
+ } else {
+ /* Use simpler shader if we don't need to to yuv -> rgb,
+ for example when input is allready rgb (.bmp image).*/
+ vgl->AttachShader( vgl->program[0], vgl->shader[1] );
}
+ vgl->AttachShader( vgl->program[0], vertexShaderId );
+
+ vgl->LinkProgram( vgl->program[0] );
+
free(code);
- }
+
+
+ for( GLuint i = 0; i < 2; i++ )
+ {
+ int infoLength = 0;
+ int charsWritten = 0;
+ char *infolog;
+ vgl->GetProgramiv( vgl->program[i], GL_INFO_LOG_LENGTH, &infoLength );
+ if( infoLength > 1 )
+ {
+ /* If there is some message, better to check linking is ok */
+ GLint link_status = GL_TRUE;
+ vgl->GetProgramiv( vgl->program[i], GL_LINK_STATUS, &link_status );
+
+ infolog = (char *)malloc(infoLength);
+ vgl->GetProgramInfoLog( vgl->program[i], infoLength, &charsWritten, infolog );
+ msg_Dbg( vgl->gl, "shader program %d:%s %d",i,infolog,infoLength);
+ free(infolog);
+
+ /* Check shaders messages too */
+ for( GLuint j = 0; j < 2; j++ )
+ {
+ vgl->GetShaderiv( vgl->shader[j], GL_INFO_LOG_LENGTH, &infoLength );
+ if( infoLength > 1 )
+ {
+ infolog = (char *)malloc(infoLength);
+ vgl->GetShaderInfoLog( vgl->shader[j], infoLength, &charsWritten, infolog );
+ msg_Dbg( vgl->gl, "shader %d: %s\n",j,infolog );
+ free( infolog );
+ }
+ }
+
+ if( link_status == GL_FALSE )
+ {
+ msg_Err( vgl->gl, "Unable to use program %d", i );
+ free( vgl );
+ return NULL;
+ }
+ }
+ }
+
+ vgl->UseProgram( vgl->program[0] );
+
+ // Generate VAO
+ vgl->GenVertexArrays(2, vgl->vao );
+ vgl->BindVertexArray( vgl->vao[0] );
+
+ //Bind coefficient values to shader doing yuv->rgb
+ GLint dataLocation = vgl->GetUniformLocation( vgl->program[0], "coefficient" );
+ vgl->Uniform4fv( dataLocation, vgl->local_count, vgl->local_value );
+
+ // Tell shader to use textureUnits 0,1,2
+ GLint texturelocation = vgl->GetUniformLocation( vgl->program[0], "Texture");
+ const GLint textureUnits[] = {0,1,2};
+ vgl->Uniform1iv( texturelocation, 3, textureUnits );
+
+ //0 for vertex coordinates and 1 for texture coordinates
+ vgl->GenBuffers(2, vgl->buffers[0] );
+
+ const GLfloat vertexCoord[] = {
+ -1.0, 1.0,
+ -1.0, -1.0,
+ 1.0, 1.0,
+ 1.0, -1.0,
+ };
+
+ vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[0][0]);
+ vgl->BufferData( GL_ARRAY_BUFFER, sizeof(vertexCoord), vertexCoord, GL_STATIC_DRAW );
+ GLint vertexlocation = vgl->GetAttribLocation( vgl->program[0], "positionCoordinate");
+ vgl->EnableVertexAttribArray( vertexlocation ); //In vertex shader location 0 is vertex coordinates
+ vgl->VertexAttribPointer(vertexlocation, 2, GL_FLOAT, 0, 0, NULL);
+
+ vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[0][1]); // Make room for texture coordinates
+ vgl->BufferData( GL_ARRAY_BUFFER, sizeof(vertexCoord)*3, NULL, GL_STREAM_DRAW );
+ vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[0], "textureC0"));
+ vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[0], "textureC1"));
+ vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[0], "textureC2"));
+ vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], "textureC0"), 2, GL_FLOAT, 0, 0, NULL);
+ vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], "textureC1"), 2, GL_FLOAT, 0, 0, (void *)sizeof(vertexCoord));
+ vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], "textureC2"), 2, GL_FLOAT, 0, 0, (void *)(2*sizeof(vertexCoord)));
+
+ vgl->BindVertexArray( vgl->vao[1] );
+ vgl->GenBuffers(2, vgl->buffers[1] );
+
+ vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[1][1]);
+
+ const GLfloat textureCoord[] = {
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ 1.0, 1.0,
+ };
+
+ vgl->BufferData( GL_ARRAY_BUFFER, sizeof(textureCoord), textureCoord, GL_STATIC_DRAW );
+ vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "textureC0") );
+ vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "textureC0"), 2, GL_FLOAT, 0, 0, NULL);
+
+ vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[1][0] );
+ vgl->BufferData( GL_ARRAY_BUFFER, sizeof(textureCoord), NULL, GL_STREAM_DRAW );
+ vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "positionCoordinate") );
+ vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "positionCoordinate") , 2, GL_FLOAT, 0, 0, NULL);
}
+
/* */
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
@@ -390,11 +596,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
*fmt = vgl->fmt;
if (subpicture_chromas) {
- *subpicture_chromas = NULL;
-#if !USE_OPENGL_ES
- if (supports_npot)
- *subpicture_chromas = gl_subpicture_chromas;
-#endif
+ *subpicture_chromas = gl_subpicture_chromas;
}
return vgl;
}
@@ -414,8 +616,17 @@ void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
}
free(vgl->region);
- if (vgl->program)
- vgl->DeleteProgramsARB(1, &vgl->program);
+ if (vgl->program[0])
+ {
+ for( int i = 0; i < 2; i++ )
+ {
+ vgl->DetachShader( vgl->program[i], vgl->shader[i] );
+ vgl->DeleteShader( vgl->shader[i] );
+ vgl->DeleteProgram( vgl->program[i] );
+ vgl->DeleteBuffers(2, vgl->buffers[i]);
+ }
+ vgl->DeleteVertexArrays(2, vgl->vao );
+ }
vlc_gl_Unlock(vgl->gl);
}
@@ -454,19 +665,15 @@ picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned
if (vlc_gl_Lock(vgl->gl))
return vgl->pool;
+
+
for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
if (vgl->use_multitexture)
- vgl->ActiveTexture(GL_TEXTURE0 + j);
+ glActiveTexture(GL_TEXTURE0 + j);
glBindTexture(vgl->tex_target, vgl->texture[i][j]);
-#if !USE_OPENGL_ES
- /* Set the texture parameters */
- glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-#endif
-
glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -514,7 +721,7 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
/* Update the texture */
for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
if (vgl->use_multitexture)
- vgl->ActiveTexture(GL_TEXTURE0 + j);
+ glActiveTexture(GL_TEXTURE0 + j);
glBindTexture(vgl->tex_target, vgl->texture[0][j]);
glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
glTexSubImage2D(vgl->tex_target, 0,
@@ -540,7 +747,7 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
vgl->region = calloc(count, sizeof(*vgl->region));
if (vgl->use_multitexture)
- vgl->ActiveTexture(GL_TEXTURE0 + 0);
+ glActiveTexture(GL_TEXTURE0 + 0);
int i = 0;
for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
gl_region_t *glr = &vgl->region[i];
@@ -640,48 +847,11 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
glClear(GL_COLOR_BUFFER_BIT);
- if (vgl->program) {
- glEnable(GL_FRAGMENT_PROGRAM_ARB);
- for (int i = 0; i < vgl->local_count; i++)
- vgl->ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, vgl->local_value[i]);
- } else {
- glEnable(vgl->tex_target);
- }
-
-#if USE_OPENGL_ES
- static const GLfloat vertexCoord[] = {
- -1.0f, -1.0f,
- 1.0f, -1.0f,
- -1.0f, 1.0f,
- 1.0f, 1.0f,
- };
-
- const GLfloat textureCoord[8] = {
- left[0], bottom[0],
- right[0], bottom[0],
- left[0], top[0],
- right[0], top[0]
- };
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
- glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisable(vgl->tex_target);
-#else
-
- const GLfloat vertexCoord[] = {
- -1.0, 1.0,
- -1.0, -1.0,
- 1.0, 1.0,
- 1.0, -1.0,
- };
+ /* Program 0 is for yuv2rgb translation */
+ vgl->UseProgram( vgl->program[0] );
+ vgl->BindVertexArray( vgl->vao[0] );
+ vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[0][1] );
for( unsigned j = 0; j < vgl->chroma->plane_count; j++)
{
const GLfloat texCoord[] = {
@@ -690,64 +860,46 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
right[j], top[j],
right[j], bottom[j],
};
- vgl->ActiveTexture( GL_TEXTURE0+j);
- vgl->ClientActiveTexture( GL_TEXTURE0+j);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glActiveTexture( GL_TEXTURE0+j);
glBindTexture(vgl->tex_target, vgl->texture[0][j]);
- glTexCoordPointer(2, GL_FLOAT, 0, texCoord);
+ /* We use one buffer for texture coordinates for all textures */
+ vgl->BufferSubData( GL_ARRAY_BUFFER, sizeof(texCoord)*j, sizeof(texCoord), texCoord);
}
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
+ /* Switch back to texture 0 and do the drawing */
+ glActiveTexture( GL_TEXTURE0);
+
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4);
- glDisableClientState(GL_VERTEX_ARRAY);
- for( int j = vgl->chroma->plane_count; j >= 0;j--)
+ if(vgl->region_count )
{
- vgl->ActiveTexture( GL_TEXTURE0+j);
- vgl->ClientActiveTexture( GL_TEXTURE0+j);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
+ /* If we need to draw subpictures, use simpler program */
+ vgl->UseProgram( vgl->program[1] );
+ vgl->BindVertexArray( vgl->vao[1] );
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
- if (vgl->program)
- glDisable(GL_FRAGMENT_PROGRAM_ARB);
- else
- glDisable(vgl->tex_target);
-
- if (vgl->use_multitexture)
- vgl->ActiveTexture(GL_TEXTURE0 + 0);
- glEnable(GL_TEXTURE_2D);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnableClientState(GL_VERTEX_ARRAY);
- const GLfloat textureCoord[] = {
- 0.0, 0.0,
- 0.0, 1.0,
- 1.0, 0.0,
- 1.0, 1.0,
- };
- for (int i = 0; i < vgl->region_count; i++) {
- gl_region_t *glr = &vgl->region[i];
- const GLfloat vertexCoord[] = {
- glr->left, glr->top,
- glr->left, glr->bottom,
- glr->right, glr->top,
- glr->right,glr->bottom,
- };
- glColor4f(1.0f, 1.0f, 1.0f, glr->alpha);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
- glBindTexture(GL_TEXTURE_2D, glr->texture);
- glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
- glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
- glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisable(GL_BLEND);
- glDisable(GL_TEXTURE_2D);
-#endif
+ for (int i = 0; i < vgl->region_count; i++) {
+
+ gl_region_t *glr = &vgl->region[i];
+ const GLfloat vertexCoord[] = {
+ glr->left, glr->top,
+ glr->left, glr->bottom,
+ glr->right, glr->top,
+ glr->right,glr->bottom,
+ };
+
+ /* We only have one texture plane, so we can use just one buffer for it */
+ vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[1][0] );
+ vgl->BufferData( GL_ARRAY_BUFFER, sizeof(vertexCoord), vertexCoord, GL_STREAM_DRAW );
+ vgl->Uniform4f( vgl->GetUniformLocation( vgl->program[1],"fillColor"), 1.0f,1.0f,1.0f,glr->alpha);
+
+ glBindTexture(vgl->tex_target, glr->texture);
+ glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
+ }
+ glDisable(GL_BLEND);
+ }
vlc_gl_Swap(vgl->gl);
diff --git a/modules/video_output/opengl.h b/modules/video_output/opengl.h
index 7a118df..bdd5729 100644
--- a/modules/video_output/opengl.h
+++ b/modules/video_output/opengl.h
@@ -43,6 +43,7 @@
# ifdef WIN32
# include <GL/glew.h>
# endif
+# include <GL/glx.h>
# include <GL/gl.h>
# endif
#else
--
1.7.9.2
More information about the vlc-devel
mailing list