summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristophe Thommeret <hftom@free.fr>2012-07-13 22:06:02 +0300
committerChristophe Thommeret <hftom@free.fr>2012-07-13 22:06:02 +0300
commit0971be62956b6d39bf3d6b063d269dfc6276d21f (patch)
tree9627b3b8efb29d53c943dc4cdad368c51a88b063 /src
parentf26c4bb84d272309dcdd65f804625d120f3157aa (diff)
downloadxine-lib-0971be62956b6d39bf3d6b063d269dfc6276d21f.tar.gz
xine-lib-0971be62956b6d39bf3d6b063d269dfc6276d21f.tar.bz2
OpenGL 2 video out plugin
Diffstat (limited to 'src')
-rw-r--r--src/video_out/video_out_opengl2.c1682
1 files changed, 1682 insertions, 0 deletions
diff --git a/src/video_out/video_out_opengl2.c b/src/video_out/video_out_opengl2.c
new file mode 100644
index 000000000..9ae0c5710
--- /dev/null
+++ b/src/video_out/video_out_opengl2.c
@@ -0,0 +1,1682 @@
+/*
+ * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; remove-trailing-space on;
+ * Copyright (C) 20012 the xine project
+ * Copyright (C) 20012 Christophe Thommeret <hftom@free.fr>
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ *
+ * video_out_opengl2.c, a video output plugin using opengl 2.0
+ *
+ *
+ */
+
+/* #define LOG */
+#define LOG_MODULE "video_out_opengl2"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pthread.h>
+
+#include <xine.h>
+#include <xine/video_out.h>
+#include <xine/vo_scale.h>
+#include <xine/xine_internal.h>
+#include <xine/xineutils.h>
+
+#include "yuv2rgb.h"
+
+#ifdef HAVE_FFMPEG_AVUTIL_H
+# include <mem.h>
+#else
+# include <libavutil/mem.h>
+#endif
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glx.h>
+
+
+
+typedef int (*GLXSWAPINTERVALSGI) ( int );
+
+typedef struct {
+ vo_frame_t vo_frame;
+ int width, height, format, flags;
+ double ratio;
+} opengl2_frame_t;
+
+
+
+typedef struct {
+ uint8_t *ovl_rgba;
+ int ovl_w, ovl_h;
+ int ovl_x, ovl_y;
+
+ GLuint tex;
+ int tex_w, tex_h;
+
+ int unscaled;
+ int vid_scale;
+} opengl2_overlay_t;
+
+
+
+typedef struct {
+ int compiled;
+ GLuint shader;
+ GLuint program;
+} opengl2_program_t;
+
+
+
+typedef struct {
+ GLuint y, u, v;
+ GLuint yuv;
+ int width;
+ int height;
+} opengl2_yuvtex_t;
+
+
+
+typedef struct {
+
+ vo_driver_t vo_driver;
+ vo_scale_t sc;
+
+ Display *display;
+ int screen;
+ Drawable drawable;
+ GLXContext context;
+
+ int texture_float;
+ opengl2_program_t yuv420_program;
+ opengl2_program_t yuv422_program;
+ opengl2_yuvtex_t yuvtex;
+ GLuint videoPBO;
+ GLuint fbo;
+ GLuint videoTex, videoTex2;
+ GLXSWAPINTERVALSGI mglXSwapInterval;
+
+ int ovl_changed;
+ int ovl_vid_scale;
+ int num_ovls;
+ opengl2_overlay_t overlays[XINE_VORAW_MAX_OVL];
+ yuv2rgb_factory_t *yuv2rgb_factory;
+ yuv2rgb_t *ovl_yuv2rgb;
+
+ opengl2_program_t sharpness_program;
+ float csc_matrix[3 * 4];
+ float *color_standard;
+ int update_csc;
+ int saturation;
+ int contrast;
+ int brightness;
+ int hue;
+ int sharpness;
+
+ opengl2_program_t bicubic_pass1_program;
+ opengl2_program_t bicubic_pass2_program;
+ GLuint bicubic_lut_texture;
+ GLuint bicubic_pass1_texture;
+ int bicubic_pass1_texture_width;
+ int bicubic_pass1_texture_height;
+ GLuint bicubic_fbo;
+ int scale_bicubic;
+
+ pthread_mutex_t drawable_lock;
+ uint32_t display_width;
+ uint32_t display_height;
+
+ config_values_t *config;
+
+ uint32_t capabilities;
+ xine_t *xine;
+
+ int zoom_x;
+ int zoom_y;
+} opengl2_driver_t;
+
+
+
+typedef struct {
+ video_driver_class_t driver_class;
+ GLXContext ctx;
+ xine_t *xine;
+} opengl2_class_t;
+
+
+
+static const char *bicubic_pass1_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect tex, lut;\n"
+"uniform float spline;\n"
+"void main() {\n"
+" vec2 coord = gl_TexCoord[0].xy;\n"
+" vec2 TexCoord = vec2( floor( coord.x - 0.5 ) + 0.5, coord.y );\n"
+" vec4 sum = vec4( 0.0 );\n"
+" float coefsum = 0.0;\n"
+" mat4 wlut;\n"
+" wlut[0] = texture2DRect( lut, vec2( abs( coord.x - TexCoord.x ) * 1000.0, spline ) );\n"
+" for( int x = -1; x <= 2; x++ ) {\n"
+" vec4 col = texture2DRect( tex, TexCoord + vec2( float( x ), 0.0) );\n"
+" sum += col * wlut[0][x+1];\n"
+" coefsum += wlut[0][x+1];\n"
+" }\n"
+" gl_FragColor = sum / coefsum;\n"
+"}\n";
+
+
+
+static const char *bicubic_pass2_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect tex, lut;\n"
+"uniform float spline;\n"
+"void main() {\n"
+" vec2 coord = gl_TexCoord[0].xy;\n"
+" vec2 TexCoord = vec2( coord.x, floor( coord.y - 0.5 ) + 0.5 );\n"
+" vec4 sum = vec4( 0.0 );\n"
+" float coefsum = 0.0;\n"
+" mat4 wlut;\n"
+" wlut[0] = texture2DRect( lut, vec2( abs( coord.y - TexCoord.y ) * 1000.0, spline ) );\n"
+" for( int y = -1; y <= 2; y++ ) {\n"
+" vec4 col = texture2DRect( tex, TexCoord + vec2( 0.0, float( y ) ) );\n"
+" sum += col * wlut[0][y+1];\n"
+" coefsum += wlut[0][y+1];\n"
+" }\n"
+" gl_FragColor = sum / coefsum;\n"
+"}\n";
+
+
+
+#define PI 3.14159265359
+#define LUTWIDTH 1000
+#define N_SPLINES 2
+#define CATMULLROM_SPLINE 0
+#define COS_SPLINE 1
+
+static float compute_cos_spline( float x )
+{
+ if ( x < 0.0 )
+ x = -x;
+ return 0.5 * cos( PI * x / 2.0 ) + 0.5;
+}
+
+static float compute_catmullrom_spline( float x )
+{
+ if ( x < 0.0 )
+ x = -x;
+ if ( x < 1.0 )
+ return ((9.0 * (x * x * x)) - (15.0 * (x * x)) + 6.0) / 6.0;
+ if ( x <= 2.0 )
+ return ((-3.0 * (x * x * x)) + (15.0 * (x * x)) - (24.0 * x) + 12.0) / 6.0;
+ return 0.0;
+}
+
+static int create_lut_texture( opengl2_driver_t *that )
+{
+ int i = 0;
+ float *lut = calloc( sizeof(float) * LUTWIDTH * 4 * N_SPLINES, 1 );
+ float t;
+ while ( i < LUTWIDTH ) {
+ t = (float)i / (float)LUTWIDTH;
+
+ lut[i * 4] = compute_catmullrom_spline( t + 1.0 );
+ lut[(i * 4) + 1] = compute_catmullrom_spline( t );
+ lut[(i * 4) + 2] = compute_catmullrom_spline( t - 1.0 );
+ lut[(i * 4) + 3] = compute_catmullrom_spline( t - 2.0 );
+
+ lut[(i * 4) + (LUTWIDTH * 4)] = compute_cos_spline( t + 1.0 );
+ lut[(i * 4) + (LUTWIDTH * 4) + 1] = compute_cos_spline( t );
+ lut[(i * 4) + (LUTWIDTH * 4) + 2] = compute_cos_spline( t - 1.0 );
+ lut[(i * 4) + (LUTWIDTH * 4) + 3] = compute_cos_spline( t - 2.0 );
+
+ ++i;
+ }
+
+ that->bicubic_lut_texture = 0;
+ glGenTextures( 1, &that->bicubic_lut_texture );
+ if ( !that->bicubic_lut_texture )
+ return 0;
+
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_lut_texture );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F, LUTWIDTH, N_SPLINES, 0, GL_RGBA, GL_FLOAT, lut );
+ free( lut );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+ return 1;
+}
+
+
+
+static const char *blur_sharpen_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect tex;\n"
+"uniform float value;\n"
+"void main() {\n"
+" vec2 pos = gl_TexCoord[0].xy;\n"
+" vec4 c1;\n"
+" float K;\n"
+" if ( value < 0.0 )\n"
+" K = value / 8.0;\n"
+" else\n"
+" K = value / 4.0;\n"
+" c1 = texture2DRect( tex, pos ) * (1.0 + (8.0 * K));\n"
+" c1 -= texture2DRect( tex, pos + vec2( 1.0, 0.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( -1.0, 0.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( 0.0, 1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( 0.0, -1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( 1.0, 1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( -1.0, 1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( -1.0, -1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( 1.0, -1.0 ) ) * K;\n"
+" gl_FragColor = c1 ;\n"
+"}\n";
+
+
+
+static const char *yuv420_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect texY, texU, texV;\n"
+"uniform vec4 r_coefs, g_coefs, b_coefs;\n"
+"void main(void) {\n"
+" vec3 rgb;\n"
+" vec4 yuv;\n"
+" vec2 coord = gl_TexCoord[0].xy;\n"
+" yuv.r = texture2DRect(texY, vec2(coord.x, coord.y)).r;\n"
+" yuv.g = texture2DRect(texU, vec2(coord.x/2.0, coord.y/2.0)).r;\n"
+" yuv.b = texture2DRect(texV, vec2(coord.x/2.0, coord.y/2.0)).r;\n"
+" yuv.a = 1.0;\n"
+" rgb.r = dot( yuv, r_coefs );\n"
+" rgb.g = dot( yuv, g_coefs );\n"
+" rgb.b = dot( yuv, b_coefs );\n"
+" gl_FragColor = vec4(rgb, 1.0);\n"
+"}\n";
+
+
+
+static const char *yuv422_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect texYUV;\n"
+"uniform vec4 r_coefs, g_coefs, b_coefs;\n"
+"void main(void) {\n"
+" vec3 rgb;\n"
+" vec4 yuv;\n"
+" vec4 coord = gl_TexCoord[0].xyxx;\n"
+" coord.z -= step(1.0, mod(coord.x, 2.0));\n"
+" coord.w = coord.z + 1.0;\n"
+" yuv.r = texture2DRect(texYUV, coord.xy).r;\n"
+" yuv.g = texture2DRect(texYUV, coord.zy).a;\n"
+" yuv.b = texture2DRect(texYUV, coord.wy).a;\n"
+" yuv.a = 1.0;\n"
+" rgb.r = dot( yuv, r_coefs );\n"
+" rgb.g = dot( yuv, g_coefs );\n"
+" rgb.b = dot( yuv, b_coefs );\n"
+" gl_FragColor = vec4(rgb, 1.0);\n"
+"}\n";
+
+
+
+float yuv_601[] = {
+ 1.16438, 0.00000, 1.59603, -0.87420,
+ 1.16438, -0.39176, -0.81297, 0.53167,
+ 1.16438, 2.01723, 0.00000, -1.08563
+};
+
+float yuv_709[] = {
+ 1.16438, 0.00000, 1.79274, -0.97295,
+ 1.16438, -0.21325, -0.53291, 0.30148,
+ 1.16438, 2.11240, 0.00000, -1.13340
+};
+
+float yuv_240[] = {
+ 1.16438, 0.00000, 1.79411, -0.97363,
+ 1.16438, -0.25798, -0.54258, 0.32879,
+ 1.16438, 2.07871, 0.00000, -1.11649
+};
+
+static void load_csc_matrix( GLuint prog, float *cf )
+{
+ glUniform4f( glGetUniformLocationARB( prog, "r_coefs" ), cf[0], cf[1], cf[2], cf[3] );
+ glUniform4f( glGetUniformLocationARB( prog, "g_coefs" ), cf[4], cf[5], cf[6], cf[7] );
+ glUniform4f( glGetUniformLocationARB( prog, "b_coefs" ), cf[8], cf[9], cf[10], cf[11] );
+}
+
+
+
+static int opengl2_build_program( opengl2_program_t *prog, const char **source, const char *name )
+{
+ fprintf(stderr, "vo_opengl2 : compiling shader %s\n", name);
+ if ( !(prog->shader = glCreateShader( GL_FRAGMENT_SHADER )) )
+ return 0;
+ if ( !(prog->program = glCreateProgram()) )
+ return 0;
+
+ glShaderSource( prog->shader, 1, source, NULL );
+ glCompileShader( prog->shader );
+
+ GLint length;
+ GLchar *log;
+ glGetShaderiv( prog->shader, GL_INFO_LOG_LENGTH, &length );
+ log = (GLchar*)malloc( length );
+ if ( !log )
+ return 0;
+
+ glGetShaderInfoLog( prog->shader, length, &length, log );
+ if ( length ) {
+ fprintf( stderr, "Shader %s Compilation Log:\n", name );
+ fprintf( stderr, "%s", log );
+ }
+ free( log );
+
+ glAttachShader( prog->program, prog->shader );
+ glLinkProgram( prog->program );
+ glGetProgramiv( prog->program, GL_INFO_LOG_LENGTH, &length );
+ log = (GLchar*)malloc( length );
+ if ( !log )
+ return 0;
+
+ glGetProgramInfoLog( prog->program, length, &length, log );
+ if ( length ) {
+ fprintf( stderr, "Linking Log:\n" );
+ fprintf( stderr, "%s", log );
+ }
+ free( log );
+
+ prog->compiled = 1;
+
+ return 1;
+}
+
+
+
+static void opengl2_delete_program( opengl2_program_t *prog )
+{
+ glDeleteProgram( prog->program );
+ glDeleteShader( prog->shader );
+}
+
+
+
+static int opengl2_check_textures_size( opengl2_driver_t *this_gen, int w, int h )
+{
+ opengl2_driver_t *this = this_gen;
+ opengl2_yuvtex_t *ytex = &this->yuvtex;
+
+ if ( (w == ytex->width) && (h == ytex->height) )
+ return 1;
+
+ if ( ytex->y )
+ glDeleteTextures( 1, &ytex->y );
+ if ( ytex->u )
+ glDeleteTextures( 1, &ytex->u );
+ if ( ytex->v )
+ glDeleteTextures( 1, &ytex->v );
+ if ( ytex->yuv )
+ glDeleteTextures( 1, &ytex->yuv );
+ if ( this->videoTex )
+ glDeleteTextures( 1, &this->videoTex );
+ if ( this->videoTex2 )
+ glDeleteTextures( 1, &this->videoTex2 );
+
+ if ( !this->videoPBO ) {
+ glGenBuffers( 1, &this->videoPBO );
+ if ( !this->videoPBO )
+ return 0;
+ }
+
+ if ( !this->fbo ) {
+ glGenFramebuffers( 1, &this->fbo );
+ if ( !this->fbo )
+ return 0;
+ }
+
+ glGenTextures( 1, &this->videoTex );
+ if ( !this->videoTex )
+ return 0;
+
+ glGenTextures( 1, &this->videoTex2 );
+ if ( !this->videoTex2 )
+ return 0;
+
+ glGenTextures( 1, &ytex->y );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, ytex->y );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glGenTextures( 1, &ytex->u );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, ytex->u );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, w/2, h/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glGenTextures( 1, &ytex->v );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, ytex->v );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, w/2, h/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glGenTextures( 1, &ytex->yuv );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, ytex->yuv );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+
+ ytex->width = w;
+ ytex->height = h;
+
+ glGenTextures( 1, &this->videoTex );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, this->videoTex );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+
+ glGenTextures( 1, &this->videoTex2 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, this->videoTex2 );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, this->videoPBO );
+ glBufferData( GL_PIXEL_UNPACK_BUFFER_ARB, w * h * 2, NULL, GL_STREAM_DRAW );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
+
+ glBindFramebuffer( GL_FRAMEBUFFER, this->fbo );
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, this->videoTex, 0 );
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE_ARB, this->videoTex2, 0 );
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ return 1;
+}
+
+
+
+static void opengl2_overlay_clut_yuv2rgb(opengl2_driver_t *this, vo_overlay_t *overlay, opengl2_frame_t *frame)
+{
+ //fprintf(stderr, "opengl2_overlay_clut_yuv2rgb\n");
+ int i;
+ clut_t* clut = (clut_t*) overlay->color;
+
+ if (!overlay->rgb_clut) {
+ for ( i=0; i<sizeof(overlay->color)/sizeof(overlay->color[0]); i++ ) {
+ *((uint32_t *)&clut[i]) = this->ovl_yuv2rgb->yuv2rgb_single_pixel_fun(this->ovl_yuv2rgb, clut[i].y, clut[i].cb, clut[i].cr);
+ }
+ overlay->rgb_clut++;
+ }
+ if (!overlay->hili_rgb_clut) {
+ clut = (clut_t*) overlay->hili_color;
+ for ( i=0; i<sizeof(overlay->color)/sizeof(overlay->color[0]); i++) {
+ *((uint32_t *)&clut[i]) = this->ovl_yuv2rgb->yuv2rgb_single_pixel_fun(this->ovl_yuv2rgb, clut[i].y, clut[i].cb, clut[i].cr);
+ }
+ overlay->hili_rgb_clut++;
+ }
+}
+
+
+static int opengl2_process_ovl( opengl2_driver_t *this_gen, vo_overlay_t *overlay )
+{
+ //fprintf(stderr, "opengl2_process_ovl\n");
+ opengl2_overlay_t *ovl = &this_gen->overlays[this_gen->ovl_changed-1];
+
+ if ( overlay->width<=0 || overlay->height<=0 )
+ return 0;
+
+ if ( (overlay->width*overlay->height)!=(ovl->ovl_w*ovl->ovl_h) )
+ ovl->ovl_rgba = (uint8_t*)realloc( ovl->ovl_rgba, overlay->width*overlay->height*4 );
+ ovl->ovl_w = overlay->width;
+ ovl->ovl_h = overlay->height;
+ ovl->ovl_x = overlay->x;
+ ovl->ovl_y = overlay->y;
+ ovl->unscaled = overlay->unscaled;
+ if ( overlay->extent_width == -1 )
+ ovl->vid_scale = 1;
+ else
+ ovl->vid_scale = 0;
+
+ int num_rle = overlay->num_rle;
+ rle_elem_t *rle = overlay->rle;
+ uint8_t *rgba = ovl->ovl_rgba;
+ clut_t *low_colors = (clut_t*)overlay->color;
+ clut_t *hili_colors = (clut_t*)overlay->hili_color;
+ uint8_t *low_trans = overlay->trans;
+ uint8_t *hili_trans = overlay->hili_trans;
+ clut_t *colors;
+ uint8_t *trans;
+ uint8_t alpha;
+ int rlelen = 0;
+ uint8_t clr = 0;
+ int i, pos=0, x, y;
+
+ while ( num_rle>0 ) {
+ x = pos%ovl->ovl_w;
+ y = pos/ovl->ovl_w;
+ if ( (x>=overlay->hili_left && x<=overlay->hili_right) && (y>=overlay->hili_top && y<=overlay->hili_bottom) ) {
+ colors = hili_colors;
+ trans = hili_trans;
+ }
+ else {
+ colors = low_colors;
+ trans = low_trans;
+ }
+ rlelen = rle->len;
+ clr = rle->color;
+ alpha = trans[clr];
+ for ( i=0; i<rlelen; ++i ) {
+ if ( alpha == 0 ) {
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
+ }
+ else {
+ rgba[0] = colors[clr].y;
+ rgba[1] = colors[clr].cr;
+ rgba[2] = colors[clr].cb;
+ rgba[3] = alpha*255/15;
+ }
+ rgba+= 4;
+ ++pos;
+ }
+ ++rle;
+ --num_rle;
+ }
+ return 1;
+}
+
+
+static void opengl2_overlay_begin (vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed)
+{
+ //fprintf(stderr, "opengl2_overlay_begin\n");
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ if ( changed )
+ this->ovl_changed = 1;
+}
+
+
+static void opengl2_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay)
+{
+ //fprintf(stderr, "opengl2_overlay_blend\n");
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+ opengl2_frame_t *frame = (opengl2_frame_t *) frame_gen;
+
+ if ( !this->ovl_changed || this->ovl_changed>XINE_VORAW_MAX_OVL )
+ return;
+
+ if (overlay->rle) {
+ if (!overlay->rgb_clut || !overlay->hili_rgb_clut)
+ opengl2_overlay_clut_yuv2rgb(this, overlay, frame);
+ if ( opengl2_process_ovl( this, overlay ) )
+ ++this->ovl_changed;
+ }
+}
+
+
+static void opengl2_overlay_end (vo_driver_t *this_gen, vo_frame_t *vo_img)
+{
+ //fprintf(stderr, "opengl2_overlay_end\n");
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ if ( !this->ovl_changed )
+ return;
+
+ this->num_ovls = this->ovl_changed - 1;
+}
+
+
+
+
+static void opengl2_frame_proc_slice( vo_frame_t *vo_img, uint8_t **src )
+{
+ vo_img->proc_called = 1;
+}
+
+
+
+static void opengl2_frame_field( vo_frame_t *vo_img, int which_field )
+{
+}
+
+
+
+static void opengl2_frame_dispose( vo_frame_t *vo_img )
+{
+ opengl2_frame_t *frame = (opengl2_frame_t *) vo_img ;
+
+ av_free (frame->vo_frame.base[0]);
+ av_free (frame->vo_frame.base[1]);
+ av_free (frame->vo_frame.base[2]);
+ free (frame);
+}
+
+
+
+static vo_frame_t *opengl2_alloc_frame( vo_driver_t *this_gen )
+{
+ opengl2_frame_t *frame;
+
+ frame = (opengl2_frame_t *) calloc(1, sizeof(opengl2_frame_t));
+
+ if (!frame)
+ return NULL;
+
+ frame->vo_frame.base[0] = frame->vo_frame.base[1] = frame->vo_frame.base[2] = NULL;
+ frame->width = frame->height = frame->format = frame->flags = 0;
+
+ pthread_mutex_init (&frame->vo_frame.mutex, NULL);
+
+ /*
+ * supply required functions/fields
+ */
+ frame->vo_frame.proc_slice = opengl2_frame_proc_slice;
+ frame->vo_frame.proc_frame = NULL;
+ frame->vo_frame.field = opengl2_frame_field;
+ frame->vo_frame.dispose = opengl2_frame_dispose;
+ frame->vo_frame.driver = this_gen;
+
+ return (vo_frame_t *) frame;
+}
+
+
+
+static void opengl2_update_frame_format( vo_driver_t *this_gen, vo_frame_t *frame_gen,
+ uint32_t width, uint32_t height, double ratio, int format, int flags )
+{
+ opengl2_frame_t *frame = (opengl2_frame_t *) frame_gen;
+
+ /* Check frame size and format and reallocate if necessary */
+ if ( (frame->width != width) || (frame->height != height) || (frame->format != format) || (frame->flags != flags) ) {
+
+ /* (re-) allocate render space */
+ av_freep (&frame->vo_frame.base[0]);
+ av_freep (&frame->vo_frame.base[1]);
+ av_freep (&frame->vo_frame.base[2]);
+
+ if (format == XINE_IMGFMT_YV12) {
+ frame->vo_frame.pitches[0] = 8*((width + 7) / 8);
+ frame->vo_frame.pitches[1] = 8*((width + 15) / 16);
+ frame->vo_frame.pitches[2] = 8*((width + 15) / 16);
+ frame->vo_frame.base[0] = av_mallocz (frame->vo_frame.pitches[0] * height);
+ frame->vo_frame.base[1] = av_mallocz (frame->vo_frame.pitches[1] * ((height+1)/2));
+ frame->vo_frame.base[2] = av_mallocz (frame->vo_frame.pitches[2] * ((height+1)/2));
+ } else if (format == XINE_IMGFMT_YUY2){
+ frame->vo_frame.pitches[0] = 8*((width + 3) / 4);
+ frame->vo_frame.base[0] = av_mallocz (frame->vo_frame.pitches[0] * height);
+ }
+
+ frame->width = width;
+ frame->height = height;
+ frame->format = format;
+ frame->flags = flags;
+ }
+
+ frame->ratio = ratio;
+}
+
+
+
+static int opengl2_redraw_needed( vo_driver_t *this_gen )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ _x_vo_scale_compute_ideal_size( &this->sc );
+ if ( _x_vo_scale_redraw_needed( &this->sc ) ) {
+ _x_vo_scale_compute_output_size( &this->sc );
+ return 1;
+ }
+ return 0;
+}
+
+
+
+static void opengl2_update_csc_matrix( opengl2_driver_t *that, opengl2_frame_t *frame )
+{
+ float *color_standard = (frame->height > 576) ? yuv_709 : yuv_601;
+
+ if ( that->update_csc || that->color_standard != color_standard ) {
+ float hue = that->hue/100.0;
+ float saturation = that->saturation/100.0;
+ float contrast = that->contrast/100.0;
+ float brightness = that->brightness/100.0;
+ float uvcos = saturation * cos( hue );
+ float uvsin = saturation * sin( hue );
+ float uc, vc;
+ int i;
+
+ for (i=0; i<3; ++i ) {
+ that->csc_matrix[(i * 4) + 0] = color_standard[(i * 4) + 0];
+ uc = color_standard[(i * 4) + 1];
+ vc = color_standard[(i * 4) + 2];
+
+ that->csc_matrix[(i * 4) + 3] = brightness - (16.0/219.0);
+ that->csc_matrix[(i * 4) + 1] = (uvcos * uc) + (uvsin * vc);
+ that->csc_matrix[(i * 4) + 3] += ((-128.0 / 255.0) * uvcos * uc) - ((128.0 / 255.0) * uvsin * vc);
+ that->csc_matrix[(i * 4) + 2] = (uvsin * uc) + (uvcos * vc);
+ that->csc_matrix[(i * 4) + 3] += ((-128.0 / 255.0) * uvsin * uc) - ((128.0 / 255.0) * uvcos * vc);
+
+ that->csc_matrix[(i * 4) + 0] *= contrast;
+ that->csc_matrix[(i * 4) + 1] *= contrast;
+ that->csc_matrix[(i * 4) + 2] *= contrast;
+ that->csc_matrix[(i * 4) + 3] *= contrast;
+ }
+
+ that->color_standard = color_standard;
+ that->update_csc = 0;
+ }
+}
+
+
+
+static void opengl2_update_overlays( opengl2_driver_t *that )
+{
+ int i, vid_scale=0, cancel_vid_scale=0;
+ opengl2_overlay_t *o;
+
+ if ( that->ovl_changed ) {
+ that->ovl_vid_scale = 0;
+ for ( i=0; i<that->num_ovls; ++i ) {
+ o = &that->overlays[i];
+
+ /* handle DVB subs scaling, e.g. 720x576->1920x1080 */
+ if ( o->vid_scale ) {
+ vid_scale = 1;
+ if ( o->ovl_w > 720 || o->ovl_h > 576 )
+ cancel_vid_scale = 1;
+ }
+
+ if ( o->tex && ((o->tex_w != o->ovl_w) || (o->tex_h != o->ovl_h)) ) {
+ glDeleteTextures( 1, &o->tex );
+ o->tex = 0;
+ }
+ if ( !o->tex ) {
+ glGenTextures( 1, &o->tex );
+ o->tex_w = o->ovl_w;
+ o->tex_h = o->ovl_h;
+ }
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, o->tex );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, o->tex_w, o->tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, o->ovl_rgba );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+ }
+ }
+
+ if ( that->ovl_changed && vid_scale && !cancel_vid_scale )
+ that->ovl_vid_scale = 1;
+
+ that->ovl_changed = 0;
+}
+
+
+
+static void opengl2_draw_scaled_overlays( opengl2_driver_t *that, opengl2_frame_t *frame )
+{
+ int i, ox, oy, ow, oh;
+ opengl2_overlay_t *o;
+
+ glEnable( GL_BLEND );
+ for ( i=0; i<that->num_ovls; ++i ) {
+ o = &that->overlays[i];
+ if ( o->unscaled )
+ continue;
+ ox = o->ovl_x; oy = o->ovl_y;
+ ow = o->ovl_w; oh = o->ovl_h;
+ if ( o->vid_scale && that->ovl_vid_scale ) {
+ float fx = frame->width / 720.0, fy = frame->height / 576.0;
+ ox *= fx; oy *= fy;
+ ow *= fx; oh *= fy;
+ }
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, o->tex );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0, 0 ); glVertex3f( ox, oy, 0.);
+ glTexCoord2f( 0, o->tex_h ); glVertex3f( ox, oy + oh, 0.);
+ glTexCoord2f( o->tex_w, o->tex_h ); glVertex3f( ox + ow, oy + oh, 0.);
+ glTexCoord2f( o->tex_w, 0 ); glVertex3f( ox + ow, oy, 0.);
+ glEnd();
+ }
+ glDisable( GL_BLEND );
+}
+
+
+
+static void opengl2_draw_unscaled_overlays( opengl2_driver_t *that )
+{
+ int i;
+ opengl2_overlay_t *o;
+
+ glEnable( GL_BLEND );
+ for ( i=0; i<that->num_ovls; ++i ) {
+ o = &that->overlays[i];
+ if ( !o->unscaled )
+ continue;
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, o->tex );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0, 0 ); glVertex3f( o->ovl_x, o->ovl_y, 0.);
+ glTexCoord2f( 0, o->tex_h ); glVertex3f( o->ovl_x, o->ovl_y + o->ovl_h, 0.);
+ glTexCoord2f( o->tex_w, o->tex_h ); glVertex3f( o->ovl_x + o->ovl_w, o->ovl_y + o->ovl_h, 0.);
+ glTexCoord2f( o->tex_w, 0 ); glVertex3f( o->ovl_x + o->ovl_w, o->ovl_y, 0.);
+ glEnd();
+ }
+ glDisable( GL_BLEND );
+}
+
+
+
+static GLuint opengl2_swap_textures( opengl2_driver_t *that, GLuint current_dest )
+{
+ if ( current_dest == that->videoTex ) {
+ glDrawBuffer( GL_COLOR_ATTACHMENT1 );
+ return that->videoTex2;
+ }
+
+ glDrawBuffer( GL_COLOR_ATTACHMENT0 );
+ return that->videoTex;
+}
+
+
+
+static GLuint opengl2_sharpness( opengl2_driver_t *that, opengl2_frame_t *frame, GLuint video_texture )
+{
+ GLuint ret = video_texture;
+
+ if ( !that->sharpness_program.compiled ) {
+ if ( !opengl2_build_program( &that->sharpness_program, &blur_sharpen_frag, "blur_sharpen_frag" ) )
+ return ret;
+ }
+
+ ret = opengl2_swap_textures( that, video_texture );
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, video_texture );
+
+ float value = that->sharpness / 100.0 * frame->width / 1920.0;
+
+ glUseProgram( that->sharpness_program.program );
+ glUniform1i( glGetUniformLocationARB( that->sharpness_program.program, "tex" ), 0 );
+ glUniform1f( glGetUniformLocationARB( that->sharpness_program.program, "value" ), value );
+ //fprintf(stderr, "vo_opengl2 : sharpness = %f\n", value);
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0, 0 ); glVertex3f( 0, 0, 0.);
+ glTexCoord2f( 0, frame->height ); glVertex3f( 0, frame->height, 0.);
+ glTexCoord2f( frame->width, frame->height ); glVertex3f( frame->width, frame->height, 0.);
+ glTexCoord2f( frame->width, 0 ); glVertex3f( frame->width, 0, 0.);
+ glEnd();
+
+ glUseProgram( 0 );
+
+ return ret;
+}
+
+
+
+static int opengl2_draw_video_bicubic( opengl2_driver_t *that, int guiw, int guih, GLfloat u, GLfloat v, GLfloat u1, GLfloat v1,
+ GLfloat x, GLfloat y, GLfloat x1, GLfloat y1, GLuint video_texture )
+{
+ if ( !that->bicubic_lut_texture ) {
+ if ( !create_lut_texture( that ) )
+ return 0;
+ }
+
+ if ( !that->bicubic_pass1_program.compiled && !opengl2_build_program( &that->bicubic_pass1_program, &bicubic_pass1_frag, "bicubic_pass1_frag" ) )
+ return 0;
+ if ( !that->bicubic_pass2_program.compiled && !opengl2_build_program( &that->bicubic_pass2_program, &bicubic_pass2_frag, "bicubic_pass2_frag" ) )
+ return 0;
+ if ( !that->bicubic_fbo ) {
+ glGenFramebuffers( 1, &that->bicubic_fbo );
+ if ( !that->bicubic_fbo )
+ return 0;
+ }
+ if ( (that->bicubic_pass1_texture_width != (x1 - x)) || (that->bicubic_pass1_texture_height != (v1 - v) ) ) {
+ if ( that->bicubic_pass1_texture )
+ glDeleteTextures( 1, &that->bicubic_pass1_texture );
+ glGenTextures( 1, &that->bicubic_pass1_texture );
+ if ( !that->bicubic_pass1_texture )
+ return 0;
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_pass1_texture );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, x1 - x, v1 - v, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+ that->bicubic_pass1_texture_width = x1 - x;
+ that->bicubic_pass1_texture_height = v1 - v;
+ }
+ glBindFramebuffer( GL_FRAMEBUFFER, that->bicubic_fbo );
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, that->bicubic_pass1_texture, 0 );
+
+ glViewport( 0, 0, x1 - x, v1 - v );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, x1 - x, 0.0, v1 - v, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, video_texture );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glActiveTexture( GL_TEXTURE1 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_lut_texture );
+ glUseProgram( that->bicubic_pass1_program.program );
+ glUniform1i( glGetUniformLocationARB( that->bicubic_pass1_program.program, "tex" ), 0 );
+ glUniform1i( glGetUniformLocationARB( that->bicubic_pass1_program.program, "lut" ), 1 );
+ glUniform1f( glGetUniformLocationARB( that->bicubic_pass1_program.program, "spline" ), CATMULLROM_SPLINE );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( u, v ); glVertex3f( 0.0, 0.0, 0.);
+ glTexCoord2f( u, v1 ); glVertex3f( 0.0, v1 - v, 0.);
+ glTexCoord2f( u1, v1 ); glVertex3f( x1 - x, v1 - v, 0.);
+ glTexCoord2f( u1, v ); glVertex3f( x1 - x, 0.0, 0.);
+ glEnd();
+
+ glActiveTexture( GL_TEXTURE0 );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ glViewport( 0, 0, guiw, guih );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, guiw, guih, 0.0, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_pass1_texture );
+ glActiveTexture( GL_TEXTURE1 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_lut_texture );
+ glUseProgram( that->bicubic_pass2_program.program );
+ glUniform1i( glGetUniformLocationARB( that->bicubic_pass2_program.program, "tex" ), 0 );
+ glUniform1i( glGetUniformLocationARB( that->bicubic_pass2_program.program, "lut" ), 1 );
+ glUniform1f( glGetUniformLocationARB( that->bicubic_pass2_program.program, "spline" ), CATMULLROM_SPLINE );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0.0, 0.0 ); glVertex3f( x, y, 0.);
+ glTexCoord2f( 0.0, v1 - v ); glVertex3f( x, y1, 0.);
+ glTexCoord2f( x1 - x, v1 - v ); glVertex3f( x1, y1, 0.);
+ glTexCoord2f( x1 - x, 0.0 ); glVertex3f( x1, y, 0.);
+ glEnd();
+
+ glUseProgram( 0 );
+
+ return 1;
+}
+
+
+
+static void opengl2_draw_video_bilinear( opengl2_driver_t *that, int guiw, int guih, GLfloat u, GLfloat v, GLfloat u1, GLfloat v1,
+ GLfloat x, GLfloat y, GLfloat x1, GLfloat y1, GLuint video_texture )
+{
+ glViewport( 0, 0, guiw, guih );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, guiw, guih, 0.0, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, video_texture );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( u, v ); glVertex3f( x, y, 0.);
+ glTexCoord2f( u, v1 ); glVertex3f( x, y1, 0.);
+ glTexCoord2f( u1, v1 ); glVertex3f( x1, y1, 0.);
+ glTexCoord2f( u1, v ); glVertex3f( x1, y, 0.);
+ glEnd();
+}
+
+
+
+static void opengl2_draw( opengl2_driver_t *that, opengl2_frame_t *frame )
+{
+ glXMakeCurrent( that->display, that->drawable, that->context );
+
+ if ( !opengl2_check_textures_size( that, frame->width, frame->height ) ) {
+ glXMakeCurrent( that->display, None, NULL );
+ return;
+ }
+
+ opengl2_update_csc_matrix( that, frame );
+
+ glBindFramebuffer( GL_FRAMEBUFFER, that->fbo );
+
+ if ( frame->format == XINE_IMGFMT_YV12 ) {
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->yuvtex.y );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, that->videoPBO );
+ void *mem = glMapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY );
+ memcpy( mem, frame->vo_frame.base[0], frame->vo_frame.pitches[0] * frame->height );
+ glUnmapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB );
+ glTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, frame->width, frame->height, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0 );
+ glActiveTexture( GL_TEXTURE1 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->yuvtex.u );
+ mem = glMapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY );
+ memcpy( mem, frame->vo_frame.base[1], frame->vo_frame.pitches[1] * ((frame->height+1)/2) );
+ glUnmapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB );
+ glTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, frame->width/2, frame->height/2, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0 );
+ glActiveTexture( GL_TEXTURE2 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->yuvtex.v );
+ mem = glMapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY );
+ memcpy( mem, frame->vo_frame.base[2], frame->vo_frame.pitches[2] * ((frame->height+1)/2) );
+ glUnmapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB );
+ glTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, frame->width/2, frame->height/2, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0 );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
+
+ glUseProgram( that->yuv420_program.program );
+ glUniform1i( glGetUniformLocationARB( that->yuv420_program.program, "texY" ), 0 );
+ glUniform1i( glGetUniformLocationARB( that->yuv420_program.program, "texU" ), 1 );
+ glUniform1i( glGetUniformLocationARB( that->yuv420_program.program, "texV" ), 2 );
+ load_csc_matrix( that->yuv420_program.program, that->csc_matrix );
+ }
+ else if ( frame->format == XINE_IMGFMT_YUY2 ) {
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->yuvtex.yuv );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, that->videoPBO );
+ void *mem = glMapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY );
+ memcpy( mem, frame->vo_frame.base[0], frame->vo_frame.pitches[0] * frame->height );
+ glUnmapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB );
+ glTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, frame->width, frame->height, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 0 );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
+
+ glUseProgram( that->yuv422_program.program );
+ glUniform1i( glGetUniformLocationARB( that->yuv422_program.program, "texYUV" ), 0 );
+ load_csc_matrix( that->yuv422_program.program, that->csc_matrix );
+ }
+ else {
+ /* unknown format */
+ fprintf(stderr, "vo_opengl2: unknown image format\n" );
+ }
+
+ glViewport( 0, 0, frame->width, frame->height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, frame->width, 0.0, frame->height, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ GLuint video_texture = that->videoTex;
+ glDrawBuffer( GL_COLOR_ATTACHMENT0 );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0, 0 ); glVertex3f( 0, 0, 0.);
+ glTexCoord2f( 0, frame->height ); glVertex3f( 0, frame->height, 0.);
+ glTexCoord2f( frame->width, frame->height ); glVertex3f( frame->width, frame->height, 0.);
+ glTexCoord2f( frame->width, 0 ); glVertex3f( frame->width, 0, 0.);
+ glEnd();
+
+ glUseProgram( 0 );
+
+ // post-processing
+ if ( that->sharpness != 0 )
+ video_texture = opengl2_sharpness( that, frame, video_texture );
+
+ // draw scaled overlays
+ opengl2_update_overlays( that );
+ opengl2_draw_scaled_overlays( that, frame );
+
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ // draw on screen
+ GLfloat u, u1, v, v1, x, x1, y, y1;
+
+ u = that->sc.displayed_xoffset;
+ v = that->sc.displayed_yoffset;
+ u1 = that->sc.displayed_width + that->sc.displayed_xoffset;
+ v1 = that->sc.displayed_height + that->sc.displayed_yoffset;
+ x = that->sc.output_xoffset;
+ y = that->sc.output_yoffset;
+ x1 = that->sc.output_xoffset + that->sc.output_width;
+ y1 = that->sc.output_yoffset + that->sc.output_height;
+
+ if ( that->scale_bicubic ) {
+ if ( !opengl2_draw_video_bicubic( that, that->sc.gui_width, that->sc.gui_height, u, v, u1, v1, x, y, x1, y1, video_texture ) )
+ opengl2_draw_video_bilinear( that, that->sc.gui_width, that->sc.gui_height, u, v, u1, v1, x, y, x1, y1, video_texture );
+ }
+ else
+ opengl2_draw_video_bilinear( that, that->sc.gui_width, that->sc.gui_height, u, v, u1, v1, x, y, x1, y1, video_texture );
+
+ // draw unscaled overlays
+ opengl2_draw_unscaled_overlays( that );
+
+ //if ( that->mglXSwapInterval )
+ //that->mglXSwapInterval( 1 );
+
+ glXSwapBuffers( that->display, that->drawable );
+
+ glXMakeCurrent( that->display, None, NULL );
+}
+
+
+
+static void opengl2_display_frame( vo_driver_t *this_gen, vo_frame_t *frame_gen )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+ opengl2_frame_t *frame = (opengl2_frame_t *) frame_gen;
+
+ if ( (frame->width != this->sc.delivered_width) ||
+ (frame->height != this->sc.delivered_height) ||
+ (frame->ratio != this->sc.delivered_ratio) ||
+ (frame->vo_frame.crop_left != this->sc.crop_left) ||
+ (frame->vo_frame.crop_right != this->sc.crop_right) ||
+ (frame->vo_frame.crop_top != this->sc.crop_top) ||
+ (frame->vo_frame.crop_bottom != this->sc.crop_bottom) ) {
+ this->sc.force_redraw = 1; /* trigger re-calc of output size */
+ }
+
+ this->sc.delivered_height = frame->height;
+ this->sc.delivered_width = frame->width;
+ this->sc.delivered_ratio = frame->ratio;
+ this->sc.crop_left = frame->vo_frame.crop_left;
+ this->sc.crop_right = frame->vo_frame.crop_right;
+ this->sc.crop_top = frame->vo_frame.crop_top;
+ this->sc.crop_bottom = frame->vo_frame.crop_bottom;
+
+ opengl2_redraw_needed( this_gen );
+
+ pthread_mutex_lock(&this->drawable_lock); /* protect drawable from being changed */
+ opengl2_draw( this, frame );
+ pthread_mutex_unlock(&this->drawable_lock); /* allow changing drawable again */
+
+ frame->vo_frame.free( &frame->vo_frame );
+}
+
+
+
+static int opengl2_get_property( vo_driver_t *this_gen, int property )
+{
+ opengl2_driver_t *this = (opengl2_driver_t*)this_gen;
+
+ switch (property) {
+ case VO_PROP_MAX_NUM_FRAMES:
+ return 15;
+ case VO_PROP_WINDOW_WIDTH:
+ return this->sc.gui_width;
+ case VO_PROP_WINDOW_HEIGHT:
+ return this->sc.gui_height;
+ case VO_PROP_OUTPUT_WIDTH:
+ return this->sc.output_width;
+ case VO_PROP_OUTPUT_HEIGHT:
+ return this->sc.output_height;
+ case VO_PROP_OUTPUT_XOFFSET:
+ return this->sc.output_xoffset;
+ case VO_PROP_OUTPUT_YOFFSET:
+ return this->sc.output_yoffset;
+ case VO_PROP_HUE:
+ return this->hue;
+ case VO_PROP_SATURATION:
+ return this->saturation;
+ case VO_PROP_CONTRAST:
+ return this->contrast;
+ case VO_PROP_BRIGHTNESS:
+ return this->brightness;
+ case VO_PROP_SHARPNESS:
+ return this->sharpness;
+ case VO_PROP_ZOOM_X:
+ return this->zoom_x;
+ case VO_PROP_ZOOM_Y:
+ return this->zoom_y;
+ case VO_PROP_ASPECT_RATIO:
+ return this->sc.user_ratio;
+ }
+
+ return -1;
+}
+
+
+
+static int opengl2_set_property( vo_driver_t *this_gen, int property, int value )
+{
+ opengl2_driver_t *this = (opengl2_driver_t*)this_gen;
+
+ //fprintf(stderr,"opengl2_set_property: property=%d, value=%d\n", property, value );
+
+ switch (property) {
+ case VO_PROP_ZOOM_X:
+ if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) {
+ this->zoom_x = value;
+ this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP;
+ _x_vo_scale_compute_ideal_size( &this->sc );
+ this->sc.force_redraw = 1; //trigger re-calc of output size
+ }
+ break;
+ case VO_PROP_ZOOM_Y:
+ if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) {
+ this->zoom_y = value;
+ this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP;
+ _x_vo_scale_compute_ideal_size( &this->sc );
+ this->sc.force_redraw = 1; // trigger re-calc of output size
+ }
+ break;
+ case VO_PROP_ASPECT_RATIO:
+ if ( value>=XINE_VO_ASPECT_NUM_RATIOS )
+ value = XINE_VO_ASPECT_AUTO;
+ this->sc.user_ratio = value;
+ this->sc.force_redraw = 1; // trigger re-calc of output size
+ break;
+ case VO_PROP_HUE: this->hue = value; this->update_csc = 1; break;
+ case VO_PROP_SATURATION: this->saturation = value; this->update_csc = 1; break;
+ case VO_PROP_CONTRAST: this->contrast = value; this->update_csc = 1; break;
+ case VO_PROP_BRIGHTNESS: this->brightness = value; this->update_csc = 1; break;
+ case VO_PROP_SHARPNESS: this->sharpness = value; break;
+ }
+
+ return value;
+}
+
+
+
+static void opengl2_get_property_min_max( vo_driver_t *this_gen, int property, int *min, int *max )
+{
+ switch ( property ) {
+ case VO_PROP_HUE:
+ *max = 314; *min = -314; break;
+ case VO_PROP_SATURATION:
+ *max = 1000; *min = 0; break;
+ case VO_PROP_CONTRAST:
+ *max = 1000; *min = 0; break;
+ case VO_PROP_BRIGHTNESS:
+ *max = 100; *min = -100; break;
+ case VO_PROP_SHARPNESS:
+ *max = 100; *min = -100; break;
+ default:
+ *max = 0; *min = 0;
+ }
+}
+
+
+
+static int opengl2_gui_data_exchange( vo_driver_t *this_gen, int data_type, void *data )
+{
+ opengl2_driver_t *this = (opengl2_driver_t*)this_gen;
+
+ switch (data_type) {
+#ifndef XINE_DISABLE_DEPRECATED_FEATURES
+ case XINE_GUI_SEND_COMPLETION_EVENT:
+ break;
+#endif
+
+ case XINE_GUI_SEND_EXPOSE_EVENT: {
+ this->sc.force_redraw = 1;
+ break;
+ }
+
+ case XINE_GUI_SEND_DRAWABLE_CHANGED: {
+ pthread_mutex_lock(&this->drawable_lock); /* wait for other thread which is currently displaying */
+ this->drawable = (Drawable)data;
+ pthread_mutex_unlock(&this->drawable_lock);
+ this->sc.force_redraw = 1;
+ break;
+ }
+
+ case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: {
+ int x1, y1, x2, y2;
+ x11_rectangle_t *rect = data;
+
+ _x_vo_scale_translate_gui2video(&this->sc, rect->x, rect->y, &x1, &y1);
+ _x_vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h, &x2, &y2);
+ rect->x = x1;
+ rect->y = y1;
+ rect->w = x2-x1;
+ rect->h = y2-y1;
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+static uint32_t opengl2_get_capabilities( vo_driver_t *this_gen )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ return this->capabilities;
+}
+
+
+
+static void opengl2_set_bicubic( void *this_gen, xine_cfg_entry_t *entry )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ this->scale_bicubic = entry->num_value;
+ fprintf(stderr, "vo_opengl2: scale_bicubic=%d\n", this->scale_bicubic );
+}
+
+
+
+static void opengl2_dispose( vo_driver_t *this_gen )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ pthread_mutex_destroy(&this->drawable_lock);
+
+ glXMakeCurrent( this->display, this->drawable, this->context );
+
+ opengl2_delete_program( &this->yuv420_program );
+ opengl2_delete_program( &this->yuv422_program );
+
+ if ( this->sharpness_program.compiled )
+ opengl2_delete_program( &this->sharpness_program );
+
+ if ( this->bicubic_pass1_program.compiled )
+ opengl2_delete_program( &this->bicubic_pass1_program );
+ if ( this->bicubic_pass2_program.compiled )
+ opengl2_delete_program( &this->bicubic_pass2_program );
+ if ( this->bicubic_lut_texture )
+ glDeleteTextures( 1, &this->bicubic_lut_texture );
+ if ( this->bicubic_pass1_texture )
+ glDeleteTextures( 1, &this->bicubic_pass1_texture );
+ if ( this->bicubic_fbo )
+ glDeleteFramebuffers( 1, &this->bicubic_fbo );
+
+ if ( this->yuvtex.y )
+ glDeleteTextures( 1, &this->yuvtex.y );
+ if ( this->yuvtex.u )
+ glDeleteTextures( 1, &this->yuvtex.u );
+ if ( this->yuvtex.v )
+ glDeleteTextures( 1, &this->yuvtex.v );
+ if ( this->yuvtex.yuv )
+ glDeleteTextures( 1, &this->yuvtex.yuv );
+ if ( this->videoTex )
+ glDeleteTextures( 1, &this->videoTex );
+ if ( this->videoTex2 )
+ glDeleteTextures( 1, &this->videoTex2 );
+ if ( this->fbo )
+ glDeleteFramebuffers( 1, &this->fbo );
+ if ( this->videoPBO )
+ glDeleteBuffers( 1, &this->videoPBO );
+
+ int i;
+ for ( i=0; i<XINE_VORAW_MAX_OVL; ++i ) {
+ free( this->overlays[i].ovl_rgba );
+ glDeleteTextures( 1, &this->overlays[i].tex );
+ }
+
+ glXMakeCurrent( this->display, None, NULL );
+
+ glXDestroyContext( this->display, this->context );
+
+ this->ovl_yuv2rgb->dispose(this->ovl_yuv2rgb);
+ this->yuv2rgb_factory->dispose (this->yuv2rgb_factory);
+
+ free (this);
+}
+
+
+
+static vo_driver_t *opengl2_open_plugin( video_driver_class_t *class_gen, const void *visual_gen )
+{
+ opengl2_class_t *class = (opengl2_class_t *) class_gen;
+ x11_visual_t *visual = (x11_visual_t *) visual_gen;
+ opengl2_driver_t *this;
+ config_values_t *config = class->xine->config;
+
+ this = (opengl2_driver_t *) calloc(1, sizeof(opengl2_driver_t));
+
+ if (!this)
+ return NULL;
+
+ this->display = visual->display;
+ this->screen = visual->screen;
+ this->drawable = visual->d;
+ this->context = class->ctx;
+ pthread_mutex_init(&this->drawable_lock, 0);
+
+ _x_vo_scale_init(&this->sc, 1, 0, config);
+ this->sc.frame_output_cb = visual->frame_output_cb;
+ this->sc.dest_size_cb = visual->dest_size_cb;
+ this->sc.user_data = visual->user_data;
+ this->sc.user_ratio = XINE_VO_ASPECT_AUTO;
+
+ this->zoom_x = 100;
+ this->zoom_y = 100;
+
+ this->xine = class->xine;
+ this->config = config;
+
+ this->vo_driver.get_capabilities = opengl2_get_capabilities;
+ this->vo_driver.alloc_frame = opengl2_alloc_frame;
+ this->vo_driver.update_frame_format = opengl2_update_frame_format;
+ this->vo_driver.overlay_begin = opengl2_overlay_begin;
+ this->vo_driver.overlay_blend = opengl2_overlay_blend;
+ this->vo_driver.overlay_end = opengl2_overlay_end;
+ this->vo_driver.display_frame = opengl2_display_frame;
+ this->vo_driver.get_property = opengl2_get_property;
+ this->vo_driver.set_property = opengl2_set_property;
+ this->vo_driver.get_property_min_max = opengl2_get_property_min_max;
+ this->vo_driver.gui_data_exchange = opengl2_gui_data_exchange;
+ this->vo_driver.dispose = opengl2_dispose;
+ this->vo_driver.redraw_needed = opengl2_redraw_needed;
+
+ if ( !glXMakeCurrent( this->display, this->drawable, this->context ) ) {
+ fprintf(stderr, "vo_opengl2: MakeCurrent failed\n");
+ return NULL;
+ }
+
+ glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
+ glClearDepth( 1.0f );
+ glDepthFunc( GL_LEQUAL );
+ glDisable( GL_DEPTH_TEST );
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ glDisable( GL_BLEND );
+ glShadeModel( GL_SMOOTH );
+ glEnable( GL_TEXTURE_RECTANGLE_ARB );
+ glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+
+ const char *extensions = glGetString( GL_EXTENSIONS );
+ if ( strstr( extensions, "ARB_texture_float" ) )
+ this->texture_float = 1;
+ else
+ this->texture_float = 0;
+
+#define INITWIDTH 720
+#define INITHEIGHT 576
+
+ this->yuvtex.y = this->yuvtex.u = this->yuvtex.v = this->yuvtex.yuv = 0;
+ this->yuvtex.width = this->yuvtex.height = 0;
+ this->fbo = this->videoPBO = this->videoTex = this->videoTex2 = 0;
+ if ( !opengl2_check_textures_size( this, INITWIDTH, INITHEIGHT ) )
+ return 0;
+
+ if ( !opengl2_build_program( &this->yuv420_program, &yuv420_frag, "yuv420_frag" ) )
+ return NULL;
+ if ( !opengl2_build_program( &this->yuv422_program, &yuv422_frag, "yuv422_frag" ) )
+ return NULL;
+
+ this->mglXSwapInterval = (GLXSWAPINTERVALSGI)glXGetProcAddressARB( (const GLubyte*)"glXSwapIntervalSGI" );
+
+ glXMakeCurrent( this->display, None, NULL );
+
+ this->capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP | VO_CAP_UNSCALED_OVERLAY | VO_CAP_CUSTOM_EXTENT_OVERLAY;// | VO_CAP_ARGB_LAYER_OVERLAY | VO_CAP_VIDEO_WINDOW_OVERLAY;
+
+ this->capabilities |= VO_CAP_HUE;
+ this->capabilities |= VO_CAP_SATURATION;
+ this->capabilities |= VO_CAP_CONTRAST;
+ this->capabilities |= VO_CAP_BRIGHTNESS;
+
+ this->update_csc = 1;
+ this->color_standard = yuv_601;
+ this->hue = 0;
+ this->saturation = 100;
+ this->contrast = 100;
+ this->brightness = 0;
+ this->sharpness = 0;
+ this->sharpness_program.compiled = 0;
+
+ this->bicubic_pass1_program.compiled = 0;
+ this->bicubic_pass2_program.compiled = 0;
+ this->bicubic_lut_texture = 0;
+ this->bicubic_pass1_texture = 0;
+ this->bicubic_pass1_texture_width = 0;
+ this->bicubic_pass1_texture_height = 0;
+ this->bicubic_fbo = 0;
+
+ int i;
+ for ( i=0; i<XINE_VORAW_MAX_OVL; ++i ) {
+ this->overlays[i].ovl_w = this->overlays[i].ovl_h = 0;
+ this->overlays[i].ovl_rgba = (uint8_t*)malloc(2*2*4);
+ this->overlays[i].ovl_x = this->overlays[i].ovl_y = 0;
+ this->overlays[i].unscaled = 0;
+ this->overlays[i].tex = 0;
+ this->overlays[i].tex_w = this->overlays[i].tex_h = 0;
+ }
+ this->ovl_changed = 0;
+ this->num_ovls = 0;
+
+ this->yuv2rgb_factory = yuv2rgb_factory_init (MODE_24_BGR, 0, NULL);
+ this->ovl_yuv2rgb = this->yuv2rgb_factory->create_converter( this->yuv2rgb_factory );
+
+ if ( this->texture_float ) {
+ this->scale_bicubic = config->register_bool( config, "video.output.opengl2_bicubic_scaling", 0,
+ _("opengl2: use a bicubic algo to scale the video"),
+ _("Set to true if you want bicubic scaling.\n\n"),
+ 10, opengl2_set_bicubic, this );
+ }
+ else
+ this->scale_bicubic = 0;
+
+ fprintf(stderr, "vo_opengl2: initialized.\n");
+
+ return &this->vo_driver;
+}
+
+
+
+static int opengl2_check_platform( opengl2_class_t *this_gen, x11_visual_t *vis )
+{
+ int attribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 16, None };
+
+ Window root;
+ XVisualInfo *visinfo;
+ GLXContext ctx;
+ int ret = 1;
+
+ if ( !vis || !vis->display || !( root = RootWindow( vis->display, vis->screen ) ) )
+ return 0;
+
+ if ( !( visinfo = glXChooseVisual( vis->display, vis->screen, attribs ) ) )
+ return 0;
+
+ if ( !( ctx = glXCreateContext( vis->display, visinfo, NULL, GL_TRUE ) ) )
+ return 0;
+
+ if ( glXMakeCurrent( vis->display, root, ctx ) ) {
+ if ( !glXIsDirect( vis->display, ctx ) )
+ ret = 0;
+ const char *extensions = glGetString( GL_EXTENSIONS );
+ if ( !strstr( extensions, "ARB_texture_rectangle" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_texture_non_power_of_two" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_pixel_buffer_object" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_framebuffer_object" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_fragment_shader" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_vertex_shader" ) )
+ ret = 0;
+ glXMakeCurrent( vis->display, None, NULL );
+ }
+ else
+ ret = 0;
+
+ if ( !ret )
+ glXDestroyContext( vis->display, ctx );
+ else
+ this_gen->ctx = ctx;
+
+ return ret;
+}
+
+/*
+ * class functions
+ */
+
+static void *opengl2_init_class( xine_t *xine, void *visual_gen )
+{
+ opengl2_class_t *this = (opengl2_class_t *) calloc(1, sizeof(opengl2_class_t));
+
+ if ( !opengl2_check_platform( this, (x11_visual_t *)visual_gen ) )
+ return NULL;
+
+ this->driver_class.open_plugin = opengl2_open_plugin;
+ this->driver_class.identifier = "opengl2";
+ this->driver_class.description = N_("xine video output plugin using opengl 2.0");
+ this->driver_class.dispose = default_video_driver_class_dispose;
+ this->xine = xine;
+
+ return this;
+}
+
+
+
+static const vo_info_t vo_info_opengl2 = {
+ 7, /* priority */
+ XINE_VISUAL_TYPE_X11 /* visual type */
+};
+
+
+/*
+ * exported plugin catalog entry
+ */
+
+const plugin_info_t xine_plugin_info[] EXPORTED = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_VIDEO_OUT, 22, "opengl2", XINE_VERSION_CODE, &vo_info_opengl2, opengl2_init_class },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};