changed: rename parameter to LoadShader to what it really is
[xbmc:xbmc-antiquated.git] / XBMC / xbmc / cores / VideoRenderers / LinuxRendererGL.cpp
1 /*
2 * XBMC Media Center
3 * Linux OpenGL Renderer
4 * Copyright (c) 2007 Frodo/jcmarshall/vulkanr/d4rk
5 *
6 * Based on XBoxRenderer by Frodo/jcmarshall
7 * Portions Copyright (c) by the authors of ffmpeg / xvid /mplayer
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 #include "stdafx.h"
24 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
25   #include "config.h"
26 #endif
27 #ifndef HAS_SDL_2D
28 #include <locale.h>
29 #include "LinuxRendererGL.h"
30 #include "../../Application.h"
31 #include "../../Util.h"
32 #include "../../Settings.h"
33 #include "../../XBVideoConfig.h"
34 #include "../../../guilib/Surface.h"
35 #include "../../../guilib/FrameBufferObject.h"
36
37 #ifdef HAVE_LIBVDPAU
38 #include "cores/dvdplayer/DVDCodecs/Video/VDPAU.h"
39 #endif
40
41 #ifdef HAS_SDL_OPENGL
42 #include <GL/glew.h>
43 #endif
44 #ifdef HAS_GLX
45 #include <GL/glx.h>
46 #endif
47
48 #ifdef HAS_SDL_OPENGL
49
50 using namespace Surface;
51 using namespace Shaders;
52
53 static const GLubyte stipple_weave[] = {
54   0xFF, 0xFF, 0xFF, 0xFF,
55   0x00, 0x00, 0x00, 0x00,
56   0xFF, 0xFF, 0xFF, 0xFF,
57   0x00, 0x00, 0x00, 0x00,
58   0xFF, 0xFF, 0xFF, 0xFF,
59   0x00, 0x00, 0x00, 0x00,
60   0xFF, 0xFF, 0xFF, 0xFF,
61   0x00, 0x00, 0x00, 0x00,
62   0xFF, 0xFF, 0xFF, 0xFF,
63   0x00, 0x00, 0x00, 0x00,
64   0xFF, 0xFF, 0xFF, 0xFF,
65   0x00, 0x00, 0x00, 0x00,
66   0xFF, 0xFF, 0xFF, 0xFF,
67   0x00, 0x00, 0x00, 0x00,
68   0xFF, 0xFF, 0xFF, 0xFF,
69   0x00, 0x00, 0x00, 0x00,
70   0xFF, 0xFF, 0xFF, 0xFF,
71   0x00, 0x00, 0x00, 0x00,
72   0xFF, 0xFF, 0xFF, 0xFF,
73   0x00, 0x00, 0x00, 0x00,
74   0xFF, 0xFF, 0xFF, 0xFF,
75   0x00, 0x00, 0x00, 0x00,
76   0xFF, 0xFF, 0xFF, 0xFF,
77   0x00, 0x00, 0x00, 0x00,
78   0xFF, 0xFF, 0xFF, 0xFF,
79   0x00, 0x00, 0x00, 0x00,
80   0xFF, 0xFF, 0xFF, 0xFF,
81   0x00, 0x00, 0x00, 0x00,
82   0xFF, 0xFF, 0xFF, 0xFF,
83   0x00, 0x00, 0x00, 0x00,
84   0xFF, 0xFF, 0xFF, 0xFF,
85   0x00, 0x00, 0x00, 0x00,
86   0xFF, 0xFF, 0xFF, 0xFF,
87 };
88
89 CLinuxRendererGL::CLinuxRendererGL()
90 {
91   m_textureTarget = GL_TEXTURE_2D;
92   m_fSourceFrameRatio = 1.0f;
93   m_iResolution = PAL_4x3;
94   for (int i = 0; i < NUM_BUFFERS; i++)
95     m_eventTexturesDone[i] = CreateEvent(NULL,FALSE,TRUE,NULL);
96
97   m_renderMethod = RENDER_GLSL;
98   m_renderQuality = RQ_SINGLEPASS;
99   m_iFlags = 0;
100
101   m_iYV12RenderBuffer = 0;
102   m_flipindex = 0;
103   m_currentField = FIELD_FULL;
104   m_reloadShaders = 0;
105   m_pYUVShader = NULL;
106   m_pVideoFilterShader = NULL;
107   m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
108
109   m_upscalingWidth = 0;
110   m_upscalingHeight = 0;
111   memset(&m_imScaled, 0, sizeof(m_imScaled));
112   m_isSoftwareUpscaling = false;
113
114   memset(m_image, 0, sizeof(m_image));
115   memset(m_YUVTexture, 0, sizeof(m_YUVTexture));
116
117   m_rgbBuffer = NULL;
118   m_rgbBufferSize = 0;
119
120 #ifdef HAVE_LIBVDPAU
121   m_StrictBinding = g_guiSettings.GetBool("videoplayer.strictbinding");
122 #endif
123 }
124
125 CLinuxRendererGL::~CLinuxRendererGL()
126 {
127   UnInit();
128   for (int i = 0; i < NUM_BUFFERS; i++)
129     CloseHandle(m_eventTexturesDone[i]);
130
131   if (m_rgbBuffer != NULL) {
132     delete [] m_rgbBuffer;
133     m_rgbBuffer = NULL;
134   }
135   for (int i=0; i<3; i++)
136   {
137     if (m_imScaled.plane[i])
138     {
139       delete [] m_imScaled.plane[i];
140       m_imScaled.plane[i] = 0;
141     }
142   }
143
144   if (m_pYUVShader)
145   {
146     m_pYUVShader->Free();
147     delete m_pYUVShader;
148     m_pYUVShader = NULL;
149   }
150 }
151
152 //***************************************************************************************
153 // CalculateFrameAspectRatio()
154 //
155 // Considers the source frame size and output frame size (as suggested by mplayer)
156 // to determine if the pixels in the source are not square.  It calculates the aspect
157 // ratio of the output frame.  We consider the cases of VCD, SVCD and DVD separately,
158 // as these are intended to be viewed on a non-square pixel TV set, so the pixels are
159 // defined to be the same ratio as the intended display pixels.
160 // These formats are determined by frame size.
161 //***************************************************************************************
162 void CLinuxRendererGL::CalculateFrameAspectRatio(int desired_width, int desired_height)
163 {
164   m_fSourceFrameRatio = (float)desired_width / desired_height;
165
166   // Check whether mplayer has decided that the size of the video file should be changed
167   // This indicates either a scaling has taken place (which we didn't ask for) or it has
168   // found an aspect ratio parameter from the file, and is changing the frame size based
169   // on that.
170   if (m_iSourceWidth == (unsigned int) desired_width && m_iSourceHeight == (unsigned int) desired_height)
171     return ;
172
173   // mplayer is scaling in one or both directions.  We must alter our Source Pixel Ratio
174   float fImageFrameRatio = (float)m_iSourceWidth / m_iSourceHeight;
175
176   // OK, most sources will be correct now, except those that are intended
177   // to be displayed on non-square pixel based output devices (ie PAL or NTSC TVs)
178   // This includes VCD, SVCD, and DVD (and possibly others that we are not doing yet)
179   // For this, we can base the pixel ratio on the pixel ratios of PAL and NTSC,
180   // though we will need to adjust for anamorphic sources (ie those whose
181   // output frame ratio is not 4:3) and for SVCDs which have 2/3rds the
182   // horizontal resolution of the default NTSC or PAL frame sizes
183
184   // The following are the defined standard ratios for PAL and NTSC pixels
185   float fPALPixelRatio = 128.0f / 117.0f;
186   float fNTSCPixelRatio = 4320.0f / 4739.0f;
187
188   // Calculate the correction needed for anamorphic sources
189   float fNon4by3Correction = m_fSourceFrameRatio / (4.0f / 3.0f);
190
191   // Finally, check for a VCD, SVCD or DVD frame size as these need special aspect ratios
192   if (m_iSourceWidth == 352)
193   { // VCD?
194     if (m_iSourceHeight == 240) // NTSC
195       m_fSourceFrameRatio = fImageFrameRatio * fNTSCPixelRatio;
196     if (m_iSourceHeight == 288) // PAL
197       m_fSourceFrameRatio = fImageFrameRatio * fPALPixelRatio;
198   }
199   if (m_iSourceWidth == 480)
200   { // SVCD?
201     if (m_iSourceHeight == 480) // NTSC
202       m_fSourceFrameRatio = fImageFrameRatio * 3.0f / 2.0f * fNTSCPixelRatio * fNon4by3Correction;
203     if (m_iSourceHeight == 576) // PAL
204       m_fSourceFrameRatio = fImageFrameRatio * 3.0f / 2.0f * fPALPixelRatio * fNon4by3Correction;
205   }
206   if (m_iSourceWidth == 720)
207   { // DVD?
208     if (m_iSourceHeight == 480) // NTSC
209       m_fSourceFrameRatio = fImageFrameRatio * fNTSCPixelRatio * fNon4by3Correction;
210     if (m_iSourceHeight == 576) // PAL
211       m_fSourceFrameRatio = fImageFrameRatio * fPALPixelRatio * fNon4by3Correction;
212   }
213 }
214
215 //********************************************************************************************************
216 //Get resolution based on current mode.
217 RESOLUTION CLinuxRendererGL::GetResolution()
218 {
219   if (g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating())
220   {
221     return m_iResolution;
222   }
223   return g_graphicsContext.GetVideoResolution();
224 }
225
226 float CLinuxRendererGL::GetAspectRatio()
227 {
228   float fWidth = (float)m_iSourceWidth - g_stSettings.m_currentVideoSettings.m_CropLeft - g_stSettings.m_currentVideoSettings.m_CropRight;
229   float fHeight = (float)m_iSourceHeight - g_stSettings.m_currentVideoSettings.m_CropTop - g_stSettings.m_currentVideoSettings.m_CropBottom;
230   return m_fSourceFrameRatio * fWidth / fHeight * m_iSourceHeight / m_iSourceWidth;
231 }
232
233 void CLinuxRendererGL::GetVideoRect(RECT &rectSrc, RECT &rectDest)
234 {
235   rectSrc = rs;
236   rectDest = rd;
237 }
238
239 void CLinuxRendererGL::CalcNormalDisplayRect(float fOffsetX1, float fOffsetY1, float fScreenWidth, float fScreenHeight, float fInputFrameRatio, float fZoomAmount)
240 {
241   // scale up image as much as possible
242   // and keep the aspect ratio (introduces with black bars)
243   // calculate the correct output frame ratio (using the users pixel ratio setting
244   // and the output pixel ratio setting)
245
246   float fOutputFrameRatio = fInputFrameRatio / g_settings.m_ResInfo[GetResolution()].fPixelRatio;
247
248   // maximize the movie width
249   float fNewWidth = fScreenWidth;
250   float fNewHeight = fNewWidth / fOutputFrameRatio;
251
252   if (fNewHeight > fScreenHeight)
253   {
254     fNewHeight = fScreenHeight;
255     fNewWidth = fNewHeight * fOutputFrameRatio;
256   }
257
258   // Scale the movie up by set zoom amount
259   fNewWidth *= fZoomAmount;
260   fNewHeight *= fZoomAmount;
261
262   // Centre the movie
263   float fPosY = (fScreenHeight - fNewHeight) / 2;
264   float fPosX = (fScreenWidth - fNewWidth) / 2;
265
266   rd.left = (int)(fPosX + fOffsetX1);
267   rd.right = (int)(rd.left + fNewWidth + 0.5f);
268   rd.top = (int)(fPosY + fOffsetY1);
269   rd.bottom = (int)(rd.top + fNewHeight + 0.5f);
270 }
271
272
273 void CLinuxRendererGL::ManageTextures()
274 {
275   m_NumYV12Buffers = 2;
276   //m_iYV12RenderBuffer = 0;
277   return;
278 }
279
280 void CLinuxRendererGL::ManageDisplay()
281 {
282   const RECT& rv = g_graphicsContext.GetViewWindow();
283   float fScreenWidth = (float)rv.right - rv.left;
284   float fScreenHeight = (float)rv.bottom - rv.top;
285   float fOffsetX1 = (float)rv.left;
286   float fOffsetY1 = (float)rv.top;
287
288   // source rect
289   rs.left = g_stSettings.m_currentVideoSettings.m_CropLeft;
290   rs.top = g_stSettings.m_currentVideoSettings.m_CropTop;
291   rs.right = m_iSourceWidth - g_stSettings.m_currentVideoSettings.m_CropRight;
292   rs.bottom = m_iSourceHeight - g_stSettings.m_currentVideoSettings.m_CropBottom;
293
294   CalcNormalDisplayRect(fOffsetX1, fOffsetY1, fScreenWidth, fScreenHeight, GetAspectRatio() * g_stSettings.m_fPixelRatio, g_stSettings.m_fZoomAmount);
295 }
296
297 void CLinuxRendererGL::ChooseBestResolution(float fps)
298 {
299   RESOLUTION DisplayRes = (RESOLUTION) g_guiSettings.GetInt("videoplayer.displayresolution");
300   if ( DisplayRes == AUTORES )
301     m_iResolution = g_graphicsContext.GetVideoResolution();
302   else
303     m_iResolution = DisplayRes;
304
305   // Adjust refreshrate to match source fps
306 #if !defined(__APPLE__)
307   if (g_guiSettings.GetBool("videoplayer.adjustrefreshrate"))
308   {
309     // Find closest refresh rate
310     for (int i = (int)CUSTOM; i<(CUSTOM+g_videoConfig.GetNumberOfResolutions()) ; i++)
311     {
312       RESOLUTION_INFO &curr = g_settings.m_ResInfo[m_iResolution];
313       RESOLUTION_INFO &info = g_settings.m_ResInfo[i];
314
315       if (info.iWidth  != curr.iWidth 
316       ||  info.iHeight != curr.iHeight)
317         continue;
318
319       // we assume just a tad lower fps since this calculation will discard
320       // any refreshrate that is smaller by just the smallest amount
321       int c_weight = (int)(1000 * fmodf(curr.fRefreshRate, fps - 0.01) / curr.fRefreshRate);
322       int i_weight = (int)(1000 * fmodf(info.fRefreshRate, fps - 0.01) / info.fRefreshRate);
323
324       // Closer the better, prefer higher refresh rate if the same
325       if ((i_weight <  c_weight)
326       ||  (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate))
327         m_iResolution = (RESOLUTION)i;
328     }
329
330     CLog::Log(LOGNOTICE, "Display resolution ADJUST : %s (%d)", g_settings.m_ResInfo[m_iResolution].strMode, m_iResolution);
331   }
332   else
333 #endif
334     CLog::Log(LOGNOTICE, "Display resolution %s : %s (%d)", DisplayRes == AUTORES ? "AUTO" : "USER", g_settings.m_ResInfo[m_iResolution].strMode, m_iResolution);
335 }
336
337 bool CLinuxRendererGL::ValidateRenderTarget()
338 {
339   if (!m_bValidated)
340   {
341     if (!glewIsSupported("GL_ARB_texture_non_power_of_two") && glewIsSupported("GL_ARB_texture_rectangle"))
342     {
343       CLog::Log(LOGNOTICE,"Using GL_TEXTURE_RECTANGLE_ARB");
344       m_textureTarget = GL_TEXTURE_RECTANGLE_ARB;
345     }
346     else
347       CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D");
348
349      // create the yuv textures    
350     LoadShaders();
351     for (int i = 0 ; i < m_NumYV12Buffers ; i++)
352     {
353       CreateYV12Texture(i);
354     }
355     m_bValidated = true;
356     return true;
357   }
358   return false;  
359 }
360
361 bool CLinuxRendererGL::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags)
362 {
363   m_fps = fps;
364   m_iSourceWidth = width;
365   m_iSourceHeight = height;
366
367   // Save the flags.
368   m_iFlags = flags;
369
370   // Calculate the input frame aspect ratio.
371   CalculateFrameAspectRatio(d_width, d_height);
372   ChooseBestResolution(m_fps);
373   SetViewMode(g_stSettings.m_currentVideoSettings.m_ViewMode);
374   ManageDisplay();
375
376   m_upscalingWidth = rd.right-rd.left;
377   m_upscalingHeight = rd.bottom-rd.top;
378   m_scalingMethod = GetDefaultUpscalingMethod();
379
380   if (m_rgbBuffer != NULL)
381   {
382      delete [] m_rgbBuffer;
383      m_rgbBuffer = NULL;
384   }
385
386   m_rgbBufferSize = width*height*4;
387   m_rgbBuffer = new BYTE[m_rgbBufferSize];
388   m_bConfigured = true;
389   m_bImageReady = false;
390
391   // Ensure that textures are recreated and rendering starts only after the 1st 
392   // frame is loaded after every call to Configure().
393   m_bValidated = false;
394
395   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
396   {
397     m_image[i].flags = 0;
398   }
399   m_iLastRenderBuffer = -1;
400   return true;
401 }
402
403 ESCALINGMETHOD CLinuxRendererGL::GetDefaultUpscalingMethod()
404 {
405   int upscale = g_guiSettings.GetInt("videoplayer.highqualityupscaling");
406   
407   // See if we're a candiate for upscaling.
408   bool candidateForUpscaling = false;
409   if (upscale != SOFTWARE_UPSCALING_DISABLED && (int)m_iSourceHeight < m_upscalingWidth && (int)m_iSourceHeight < m_upscalingHeight)
410   {
411     CLog::Log(LOGWARNING, "Upscale: possible given resolution increase.");
412     candidateForUpscaling = true;
413   }
414
415   // Turn if off if we're told to upscale HD content and we're not always on.
416   if (upscale == SOFTWARE_UPSCALING_SD_CONTENT && (m_iSourceHeight >= 720 || m_iSourceWidth >= 1280))
417   {
418     CLog::Log(LOGWARNING, "Upscale: Disabled due to HD source.");
419     candidateForUpscaling = false;
420   }
421
422   ESCALINGMETHOD ret = VS_SCALINGMETHOD_LINEAR;
423
424   if (candidateForUpscaling)
425   {
426     ret = (ESCALINGMETHOD)g_guiSettings.GetInt("videoplayer.upscalingalgorithm");
427
428     // Make sure to override the default setting for the video
429     g_stSettings.m_currentVideoSettings.m_ScalingMethod = ret;
430
431     // Initialize software upscaling.
432     InitializeSoftwareUpscaling();
433   }
434
435   CLog::Log(LOGWARNING, "Upscale: selected algorithm %d", ret);
436
437   return ret;
438 }
439
440 void CLinuxRendererGL::InitializeSoftwareUpscaling()
441 {
442   // Allocate a new destination image.
443   m_imScaled.cshift_x = m_imScaled.cshift_y = 1;
444
445   // Free the old planes if they exist.
446   for (int i=0; i<3; i++)
447   {
448     if (m_imScaled.plane[i])
449     {
450       delete [] m_imScaled.plane[i];
451       m_imScaled.plane[i] = 0;
452     }
453   }
454
455   m_imScaled.stride[0] = ALIGN((m_upscalingWidth)   , 16);
456   m_imScaled.stride[1] = ALIGN((m_upscalingWidth>>1), 16);
457   m_imScaled.stride[2] = ALIGN((m_upscalingWidth>>1), 16);
458   m_imScaled.plane[0] = new BYTE[m_imScaled.stride[0] * ALIGN((m_upscalingHeight)   , 16)];
459   m_imScaled.plane[1] = new BYTE[m_imScaled.stride[1] * ALIGN((m_upscalingHeight>>1), 16)];
460   m_imScaled.plane[2] = new BYTE[m_imScaled.stride[2] * ALIGN((m_upscalingHeight>>1), 16)];
461   m_imScaled.width = m_upscalingWidth;
462   m_imScaled.height = m_upscalingHeight;
463   m_imScaled.flags = 0;
464 }
465
466 bool CLinuxRendererGL::IsSoftwareUpscaling()
467 {
468   // See if we should be performing software upscaling on this frame.
469   if (m_scalingMethod < VS_SCALINGMETHOD_BICUBIC_SOFTWARE ||
470        (m_currentField != FIELD_FULL && 
471         g_stSettings.m_currentVideoSettings.m_InterlaceMethod!=VS_INTERLACEMETHOD_NONE && 
472         g_stSettings.m_currentVideoSettings.m_InterlaceMethod!=VS_INTERLACEMETHOD_DEINTERLACE))
473   {
474     return false;
475   }
476
477   return true;
478 }
479
480 int CLinuxRendererGL::NextYV12Texture()
481 {
482   return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
483 }
484
485 int CLinuxRendererGL::GetImage(YV12Image *image, int source, bool readonly)
486 {
487   if (!image) return -1;
488   if (!m_bValidated) return -1;
489
490   /* take next available buffer */
491   if( source == AUTOSOURCE )
492     source = NextYV12Texture();
493
494   if (!m_image[source].plane[0])
495   {
496      CLog::Log(LOGDEBUG, "CLinuxRenderer::GetImage - image planes not allocated");
497      return -1;
498   }
499
500   if ((m_image[source].flags&(~IMAGE_FLAG_READY)) != 0)
501   {
502      CLog::Log(LOGDEBUG, "CLinuxRenderer::GetImage - request image but none to give");
503      return -1;
504   }
505
506   if( source >= 0 && m_image[source].plane[0] )
507   {
508     if( readonly )
509       m_image[source].flags |= IMAGE_FLAG_READING;
510     else
511     {
512       if( WaitForSingleObject(m_eventTexturesDone[source], 500) == WAIT_TIMEOUT )
513         CLog::Log(LOGWARNING, "%s - Timeout waiting for texture %d", __FUNCTION__, source);
514
515       m_image[source].flags |= IMAGE_FLAG_WRITING;
516     }
517
518     // copy the image - should be operator of YV12Image
519     for (int p=0;p<MAX_PLANES;p++)
520     {
521       image->plane[p]=m_image[source].plane[p];
522       image->stride[p] = m_image[source].stride[p];
523     }
524     image->width = m_image[source].width;
525     image->height = m_image[source].height;
526     image->flags = m_image[source].flags;
527     image->cshift_x = m_image[source].cshift_x;
528     image->cshift_y = m_image[source].cshift_y;
529
530     return source;
531   }
532
533   return -1;
534 }
535
536 void CLinuxRendererGL::ReleaseImage(int source, bool preserve)
537 {
538   if( m_image[source].flags & IMAGE_FLAG_WRITING )
539     SetEvent(m_eventTexturesDone[source]);
540
541   m_image[source].flags &= ~IMAGE_FLAG_INUSE;
542   m_image[source].flags |= IMAGE_FLAG_READY;
543   /* if image should be preserved reserve it so it's not auto seleceted */
544
545   if( preserve )
546     m_image[source].flags |= IMAGE_FLAG_RESERVED;
547
548   m_bImageReady = true;
549 }
550
551 void CLinuxRendererGL::LoadPlane( YUVPLANE& plane, int type, unsigned flipindex
552                                 , unsigned width, unsigned height
553                                 , int stride, void* data )
554 {
555   if(plane.flipindex == flipindex)
556     return;
557
558   glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
559   glBindTexture(m_textureTarget, plane.id);
560   glTexSubImage2D(m_textureTarget, 0, 0, 0, width, height, type, GL_UNSIGNED_BYTE, data);
561
562   /* check if we need to load any border pixels */
563   if(height < plane.texheight)
564     glTexSubImage2D( m_textureTarget, 0
565                    , 0, height, width, 1
566                    , type, GL_UNSIGNED_BYTE
567                    , (unsigned char*)data + stride * (height-1));
568
569   if(width  < plane.texwidth)
570     glTexSubImage2D( m_textureTarget, 0
571                    , width, 0, 1, height
572                    , type, GL_UNSIGNED_BYTE
573                    , (unsigned char*)data + stride - 1);
574
575   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
576   glBindTexture(m_textureTarget, 0);
577
578   plane.flipindex = flipindex;
579 }
580
581 void CLinuxRendererGL::LoadTextures(int source)
582 {
583   YV12Image* im = &m_image[source];
584   YUVFIELDS& fields = m_YUVTexture[source];
585 #ifdef HAVE_LIBVDPAU
586   if ((m_renderMethod & RENDER_VDPAU) && g_VDPAU)
587   {
588     g_VDPAU->CheckRecover();
589     SetEvent(m_eventTexturesDone[source]);
590     return;
591   }
592 #endif
593   if (!(im->flags&IMAGE_FLAG_READY))
594   {
595     SetEvent(m_eventTexturesDone[source]);
596     return;
597   }
598
599   // See if we need to recreate textures.
600   if (m_isSoftwareUpscaling != IsSoftwareUpscaling())
601   {
602     for (int i = 0 ; i < m_NumYV12Buffers ; i++)
603       CreateYV12Texture(i);
604
605     im->flags = IMAGE_FLAG_READY;
606   }
607
608   // if we don't have a shader, fallback to SW YUV2RGB for now
609   if (m_renderMethod & RENDER_SW)
610   {
611     struct SwsContext *context = m_dllSwScale.sws_getContext(im->width, im->height, PIX_FMT_YUV420P,
612                                                              im->width, im->height, PIX_FMT_BGRA,
613                                                              SWS_FAST_BILINEAR, NULL, NULL, NULL);
614     uint8_t *src[] = { im->plane[0], im->plane[1], im->plane[2] };
615     int     srcStride[] = { im->stride[0], im->stride[1], im->stride[2] };
616     uint8_t *dst[] = { m_rgbBuffer, 0, 0 };
617     int     dstStride[] = { m_iSourceWidth*4, 0, 0 };
618     m_dllSwScale.sws_scale(context, src, srcStride, 0, im->height, dst, dstStride);
619     m_dllSwScale.sws_freeContext(context);
620     SetEvent(m_eventTexturesDone[source]);
621   }
622   else if (IsSoftwareUpscaling()) // FIXME: s/w upscaling + RENDER_SW => broken
623   {
624     // Perform the scaling.
625     uint8_t* src[] =       { im->plane[0],  im->plane[1],  im->plane[2] };
626     int      srcStride[] = { im->stride[0], im->stride[1], im->stride[2] };
627     uint8_t* dst[] =       { m_imScaled.plane[0],  m_imScaled.plane[1],  m_imScaled.plane[2] };
628     int      dstStride[] = { m_imScaled.stride[0], m_imScaled.stride[1], m_imScaled.stride[2] };
629     int      algorithm   = 0;
630
631     switch (m_scalingMethod)
632     {
633     case VS_SCALINGMETHOD_BICUBIC_SOFTWARE: algorithm = SWS_BICUBIC; break;
634     case VS_SCALINGMETHOD_LANCZOS_SOFTWARE: algorithm = SWS_LANCZOS; break;
635     case VS_SCALINGMETHOD_SINC_SOFTWARE:    algorithm = SWS_SINC;    break;
636     default: break;
637     }
638
639     struct SwsContext *ctx = m_dllSwScale.sws_getContext(im->width, im->height, PIX_FMT_YUV420P,
640                                                          m_upscalingWidth, m_upscalingHeight, PIX_FMT_YUV420P,
641                                                          algorithm, NULL, NULL, NULL);
642     m_dllSwScale.sws_scale(ctx, src, srcStride, 0, im->height, dst, dstStride);
643     m_dllSwScale.sws_freeContext(ctx);
644
645     m_imScaled.flipindex = im->flipindex;
646     im = &m_imScaled;
647     im->flags = IMAGE_FLAG_READY;
648   }
649
650   static int imaging = -1;
651   bool deinterlacing;
652   if (m_currentField == FIELD_FULL)
653     deinterlacing = false;
654   else
655     deinterlacing = true;
656
657   if (imaging==-1)
658   {
659     imaging = 0;
660     if (glewIsSupported("GL_ARB_imaging"))
661     {
662       CLog::Log(LOGINFO, "GL: ARB Imaging extension supported");
663       imaging = 1;
664     }
665     else
666     {
667       int maj=0, min=0;
668       g_graphicsContext.getScreenSurface()->GetGLVersion(maj, min);
669       if (maj>=2)
670       {
671         imaging = 1;
672       }
673       else if (min>=2)
674       {
675         imaging = 1;
676       }
677     }
678   }
679
680   glEnable(m_textureTarget);
681   VerifyGLState();
682
683   if (m_renderMethod & RENDER_SW)
684   {
685     if (imaging==1 &&
686         ((g_stSettings.m_currentVideoSettings.m_Brightness!=50) ||
687          (g_stSettings.m_currentVideoSettings.m_Contrast!=50)))
688     {
689       GLfloat brightness = ((GLfloat)g_stSettings.m_currentVideoSettings.m_Brightness - 50.0f)/100.0f;;
690       GLfloat contrast   = ((GLfloat)g_stSettings.m_currentVideoSettings.m_Contrast)/50.0f;
691
692       glPixelTransferf(GL_RED_SCALE  , contrast);
693       glPixelTransferf(GL_GREEN_SCALE, contrast);
694       glPixelTransferf(GL_BLUE_SCALE , contrast);
695       glPixelTransferf(GL_RED_BIAS   , brightness);
696       glPixelTransferf(GL_GREEN_BIAS , brightness);
697       glPixelTransferf(GL_BLUE_BIAS  , brightness);
698       VerifyGLState();
699       imaging++;
700     }
701
702     // Load RGB image
703     if (deinterlacing)
704     {
705       LoadPlane( fields[FIELD_ODD][0] , GL_BGRA, im->flipindex
706                , im->width, im->height >> 1
707                , m_iSourceWidth*2, m_rgbBuffer );
708
709       LoadPlane( fields[FIELD_EVEN][0], GL_BGRA, im->flipindex
710                , im->width, im->height >> 1
711                , m_iSourceWidth*2, m_rgbBuffer + m_iSourceWidth*4);      
712     }
713     else
714     {
715       LoadPlane( fields[FIELD_FULL][0], GL_BGRA, im->flipindex
716                , im->width, im->height
717                , m_iSourceWidth, m_rgbBuffer );
718     }
719
720     if (imaging==2)
721     {
722       imaging--;
723       glPixelTransferf(GL_RED_SCALE, 1.0);
724       glPixelTransferf(GL_GREEN_SCALE, 1.0);
725       glPixelTransferf(GL_BLUE_SCALE, 1.0);
726       glPixelTransferf(GL_RED_BIAS, 0.0);
727       glPixelTransferf(GL_GREEN_BIAS, 0.0);
728       glPixelTransferf(GL_BLUE_BIAS, 0.0);
729       VerifyGLState();
730     }
731   }
732   else
733   {
734     glPixelStorei(GL_UNPACK_ALIGNMENT,1);
735
736     if (deinterlacing)
737     {
738       // Load Y fields
739       LoadPlane( fields[FIELD_ODD][0] , GL_LUMINANCE, im->flipindex
740                , im->width, im->height >> 1
741                , im->stride[0]*2, im->plane[0] );
742
743       LoadPlane( fields[FIELD_EVEN][0], GL_LUMINANCE, im->flipindex
744                , im->width, im->height >> 1
745                , im->stride[0]*2, im->plane[0] + im->stride[0]) ;     
746     }
747     else
748     {
749       // Load Y plane
750       LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, im->flipindex
751                , im->width, im->height
752                , im->stride[0], im->plane[0] );
753     }
754   }
755
756   VerifyGLState();
757
758   if (!(m_renderMethod & RENDER_SW))
759   {
760     glPixelStorei(GL_UNPACK_ALIGNMENT,1);
761
762     if (deinterlacing)
763     {
764       // Load Even U & V Fields
765       LoadPlane( fields[FIELD_ODD][1], GL_LUMINANCE, im->flipindex
766                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
767                , im->stride[1]*2, im->plane[1] );
768
769       LoadPlane( fields[FIELD_ODD][2], GL_LUMINANCE, im->flipindex
770                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
771                , im->stride[2]*2, im->plane[2] );
772       
773       // Load Odd U & V Fields
774       LoadPlane( fields[FIELD_EVEN][1], GL_LUMINANCE, im->flipindex
775                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
776                , im->stride[1]*2, im->plane[1] + im->stride[1] );
777
778       LoadPlane( fields[FIELD_EVEN][2], GL_LUMINANCE, im->flipindex
779                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
780                , im->stride[2]*2, im->plane[2] + im->stride[2] );
781       
782     }
783     else
784     {
785       LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, im->flipindex
786                , im->width >> im->cshift_x, im->height >> im->cshift_y
787                , im->stride[1], im->plane[1] );
788
789       LoadPlane( fields[FIELD_FULL][2], GL_LUMINANCE, im->flipindex
790                , im->width >> im->cshift_x, im->height >> im->cshift_y
791                , im->stride[2], im->plane[2] );
792     }
793   }
794   SetEvent(m_eventTexturesDone[source]);
795
796   // calculate the source rectangle
797   for(int field = 0; field < 3; field++)
798   {
799     for(int plane = 0; plane < 3; plane++)
800     {
801       YUVPLANE& p = fields[field][plane];
802
803       /* software upscaling is precropped */
804       if(IsSoftwareUpscaling())
805         p.rect.SetRect(0, 0, im->width, im->height);
806       else      
807         p.rect.SetRect(rs.left, rs.top, rs.right, rs.bottom);
808
809       p.width  = im->width;
810       p.height = im->height;
811
812       if(field != FIELD_FULL)
813       {
814         /* correct for field offsets and chroma offsets */
815         float offset_y = 0.5;
816         if(plane != 0)
817           offset_y += 0.5;
818         if(field == FIELD_EVEN)
819           offset_y *= -1;
820
821         p.rect.y1 += offset_y;
822         p.rect.y2 += offset_y;
823
824         /* half the height if this is a field */
825         p.height  *= 0.5f;
826         p.rect.y1 *= 0.5f; 
827         p.rect.y2 *= 0.5f;
828       }
829
830       if(plane != 0)
831       {
832         p.width   /= 1 << im->cshift_x;
833         p.height  /= 1 << im->cshift_y;
834
835         p.rect.x1 /= 1 << im->cshift_x;
836         p.rect.x2 /= 1 << im->cshift_x;
837         p.rect.y1 /= 1 << im->cshift_y;
838         p.rect.y2 /= 1 << im->cshift_y;
839       }
840
841       if (m_textureTarget == GL_TEXTURE_2D)
842       {
843         p.height  /= p.texheight;
844         p.rect.y1 /= p.texheight;
845         p.rect.y2 /= p.texheight;
846         p.width   /= p.texwidth;
847         p.rect.x1 /= p.texwidth;
848         p.rect.x2 /= p.texwidth;
849       }
850     }
851   }
852
853   glDisable(m_textureTarget);
854 }
855
856 void CLinuxRendererGL::Reset()
857 {
858   for(int i=0; i<m_NumYV12Buffers; i++)
859   {
860     /* reset all image flags, this will cleanup textures later */
861     m_image[i].flags = 0;
862     /* reset texture locks, a bit ugly, could result in tearing */
863     SetEvent(m_eventTexturesDone[i]);
864   }
865 }
866
867 void CLinuxRendererGL::Update(bool bPauseDrawing)
868 {
869   if (!m_bConfigured) return;
870   ManageDisplay();
871   ManageTextures();
872 }
873
874 void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
875 {
876   if (!m_bConfigured) return;
877
878   // if its first pass, just init textures and return
879   if (ValidateRenderTarget())
880     return;
881
882   // this needs to be checked after texture validation
883   if (!m_bImageReady) return;
884
885   int index = m_iYV12RenderBuffer;
886
887   if (!m_YUVTexture[index][FIELD_FULL][0].id) return ;
888
889   if (m_image[index].flags==0)
890     return;
891
892   ManageDisplay();
893   ManageTextures();
894
895   g_graphicsContext.BeginPaint();
896
897   if( WaitForSingleObject(m_eventTexturesDone[index], 500) == WAIT_TIMEOUT )
898   {
899     CLog::Log(LOGWARNING, "%s - Timeout waiting for texture %d", __FUNCTION__, index);
900
901     // render the previous frame if this one isn't ready yet
902     if (m_iLastRenderBuffer > -1)
903     {
904       m_iYV12RenderBuffer = m_iLastRenderBuffer;
905       index = m_iYV12RenderBuffer;
906     }
907   }
908   else
909   {
910     m_iLastRenderBuffer = index;
911     LoadTextures(index);
912   }
913
914   if (clear)
915   {
916     glClearColor(m_clearColour, m_clearColour, m_clearColour, 0);
917     glClear(GL_COLOR_BUFFER_BIT);
918     glClearColor(0,0,0,0);
919   }
920
921   if (alpha<255)
922   {
923     glEnable(GL_BLEND);
924     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
925     glColor4f(1.0f, 1.0f, 1.0f, alpha / 255.0f);
926   }
927   else
928   {
929     glDisable(GL_BLEND);
930     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
931   }
932
933   if( (flags & RENDER_FLAG_ODD)
934    && (flags & RENDER_FLAG_EVEN) )
935   {
936     glEnable(GL_POLYGON_STIPPLE);
937
938     glPolygonStipple(stipple_weave);
939     Render(flags & ~RENDER_FLAG_EVEN, index);
940     glPolygonStipple(stipple_weave+4);
941     Render(flags & ~RENDER_FLAG_ODD , index);
942
943     glDisable(GL_POLYGON_STIPPLE);
944   }
945   else
946     Render(flags, index);
947
948   VerifyGLState();
949   glEnable(GL_BLEND);
950   glFlush();
951
952   if (g_graphicsContext.IsFullScreenVideo() && !g_application.IsPaused() && !(flags & RENDER_FLAG_NOOSD))
953   {
954     if (g_application.NeedRenderFullScreen())
955       g_application.RenderFullScreen();
956     g_application.RenderMemoryStatus();
957   }
958
959   g_graphicsContext.EndPaint();
960 }
961
962 void CLinuxRendererGL::FlipPage(int source)
963 {
964 #ifdef HAVE_LIBVDPAU
965   if (g_VDPAU)
966     g_VDPAU->Present();
967 #endif
968
969   if( source >= 0 && source < m_NumYV12Buffers )
970     m_iYV12RenderBuffer = source;
971   else
972     m_iYV12RenderBuffer = NextYV12Texture();
973
974   m_image[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
975
976   return;
977 }
978
979
980 unsigned int CLinuxRendererGL::DrawSlice(unsigned char *src[], int stride[], int w, int h, int x, int y)
981 {
982   BYTE *s;
983   BYTE *d;
984   int i, p;
985
986   int index = NextYV12Texture();
987   if( index < 0 )
988     return -1;
989
990   YV12Image &im = m_image[index];
991   // copy Y
992   p = 0;
993   d = (BYTE*)im.plane[p] + im.stride[p] * y + x;
994   s = src[p];
995   for (i = 0;i < h;i++)
996   {
997     memcpy(d, s, w);
998     s += stride[p];
999     d += im.stride[p];
1000   }
1001
1002   w >>= im.cshift_x; h >>= im.cshift_y;
1003   x >>= im.cshift_x; y >>= im.cshift_y;
1004
1005   // copy U
1006   p = 1;
1007   d = (BYTE*)im.plane[p] + im.stride[p] * y + x;
1008   s = src[p];
1009   for (i = 0;i < h;i++)
1010   {
1011     memcpy(d, s, w);
1012     s += stride[p];
1013     d += im.stride[p];
1014   }
1015
1016   // copy V
1017   p = 2;
1018   d = (BYTE*)im.plane[p] + im.stride[p] * y + x;
1019   s = src[p];
1020   for (i = 0;i < h;i++)
1021   {
1022     memcpy(d, s, w);
1023     s += stride[p];
1024     d += im.stride[p];
1025   }
1026
1027   SetEvent(m_eventTexturesDone[index]);
1028   return 0;
1029 }
1030
1031 unsigned int CLinuxRendererGL::PreInit()
1032 {
1033   CSingleLock lock(g_graphicsContext);
1034   m_bConfigured = false;
1035   m_bValidated = false;
1036   UnInit();
1037   m_iResolution = PAL_4x3;
1038
1039   m_iYV12RenderBuffer = 0;
1040   m_NumYV12Buffers = 2;
1041
1042   // setup the background colour
1043   m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
1044
1045   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwScale.Load())
1046     CLog::Log(LOGERROR,"CLinuxRendererGL::PreInit - failed to load rescale libraries!");
1047
1048   #if (! defined USE_EXTERNAL_FFMPEG)
1049     m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
1050   #elif (defined HAVE_LIBSWSCALE_RGB2RGB_H) || (defined HAVE_FFMPEG_RGB2RGB_H)
1051     m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
1052   #endif
1053
1054   return true;
1055 }
1056
1057 void CLinuxRendererGL::UpdateVideoFilter()
1058 {
1059   if (m_scalingMethod == g_stSettings.m_currentVideoSettings.m_ScalingMethod)
1060     return;
1061
1062   if (m_pVideoFilterShader)
1063   {
1064     m_pVideoFilterShader->Free();
1065     delete m_pVideoFilterShader;
1066     m_pVideoFilterShader = NULL;
1067   }
1068
1069   VerifyGLState();
1070   m_scalingMethod = g_stSettings.m_currentVideoSettings.m_ScalingMethod;
1071
1072   switch (g_stSettings.m_currentVideoSettings.m_ScalingMethod)
1073   {
1074   case VS_SCALINGMETHOD_NEAREST:
1075     m_renderQuality = RQ_SINGLEPASS;
1076     SetTextureFilter(GL_NEAREST);
1077     break;
1078
1079   case VS_SCALINGMETHOD_LINEAR:
1080     SetTextureFilter(GL_LINEAR);
1081     m_renderQuality = RQ_SINGLEPASS;
1082     break;
1083
1084   case VS_SCALINGMETHOD_CUBIC:
1085     SetTextureFilter(GL_LINEAR);
1086     m_renderQuality = RQ_MULTIPASS;
1087     m_pVideoFilterShader = new BicubicFilterShader(0.3f, 0.3f);
1088     if (m_pVideoFilterShader && m_pVideoFilterShader->CompileAndLink())
1089     {
1090       VerifyGLState();
1091       if (!m_pVideoFilterShader->CompileAndLink())
1092       {
1093         CLog::Log(LOGERROR, "GL: Error compiling and linking video filter shader");
1094         m_pVideoFilterShader->Free();
1095         delete m_pVideoFilterShader;
1096         m_pVideoFilterShader = NULL;
1097       }
1098     }
1099     break;
1100
1101   case VS_SCALINGMETHOD_LANCZOS2:
1102   case VS_SCALINGMETHOD_LANCZOS3:
1103   case VS_SCALINGMETHOD_SINC8:
1104   case VS_SCALINGMETHOD_NEDI:
1105     CLog::Log(LOGERROR, "GL: TODO: This scaler has not yet been implemented");
1106     m_renderQuality = RQ_SINGLEPASS;
1107     break;
1108
1109   case VS_SCALINGMETHOD_BICUBIC_SOFTWARE:
1110   case VS_SCALINGMETHOD_LANCZOS_SOFTWARE:
1111   case VS_SCALINGMETHOD_SINC_SOFTWARE:
1112     InitializeSoftwareUpscaling();
1113     break;
1114   }
1115 }
1116
1117 void CLinuxRendererGL::LoadShaders(int field)
1118 {
1119   int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod");
1120   CLog::Log(LOGDEBUG, "GL: Requested render method: %d", requestedMethod);
1121   bool err = false;
1122
1123 #ifdef HAVE_LIBVDPAU
1124   if (g_VDPAU)
1125   {
1126     CLog::Log(LOGNOTICE, "GL: Using VDPAU render method");
1127     m_renderMethod = RENDER_VDPAU;
1128   }
1129   else 
1130 #endif //HAVE_LIBVDPAU
1131   /*
1132     Try GLSL shaders if they're supported and if the user has
1133     requested for it. (settings -> video -> player -> rendermethod)
1134    */
1135   if (glCreateProgram // TODO: proper check
1136       && (requestedMethod==RENDER_METHOD_AUTO || requestedMethod==RENDER_METHOD_GLSL
1137             || requestedMethod==RENDER_METHOD_VDPAU))
1138   {
1139     if (m_pYUVShader)
1140     {
1141       m_pYUVShader->Free();
1142       delete m_pYUVShader;
1143       m_pYUVShader = NULL;
1144     }
1145
1146     if (field & (FIELD_ODD|FIELD_EVEN))
1147     {
1148       if (m_renderQuality == RQ_SINGLEPASS)
1149       {
1150         // create regular progressive scan shader
1151         m_pYUVShader = new YUV2RGBProgressiveShader(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags);
1152         CLog::Log(LOGNOTICE, "GL: Selecting Single Pass YUV 2 RGB shader");
1153       }
1154       else if (m_renderQuality == RQ_MULTIPASS)
1155       {
1156         // create bob deinterlacing shader
1157         m_pYUVShader = new YUV2RGBBobShader(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags);
1158         CLog::Log(LOGNOTICE, "GL: Selecting Multipass Pass YUV 2 RGB shader");
1159       }
1160     }
1161     else
1162     {
1163       // create regular progressive scan shader
1164       m_pYUVShader = new YUV2RGBProgressiveShader(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags);
1165       CLog::Log(LOGNOTICE, "GL: Selecting YUV 2 RGB Progressive Shader");
1166     }
1167
1168     if (m_pYUVShader && m_pYUVShader->CompileAndLink())
1169     {
1170       m_renderMethod = RENDER_GLSL;
1171       UpdateVideoFilter();
1172     }
1173     else
1174     {
1175       m_pYUVShader->Free();
1176       delete m_pYUVShader;
1177       m_pYUVShader = NULL;
1178       err = true;
1179       CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB GLSL shader");
1180     }
1181   }
1182
1183   /*
1184     Try ARB shaders if the extension is supported AND either:
1185       1) user requested it
1186       2) or GLSL shaders failed and user selected AUTO
1187    */
1188   else if (glewIsSupported("GL_ARB_fragment_program")  
1189            && ((requestedMethod==RENDER_METHOD_AUTO || requestedMethod==RENDER_METHOD_ARB)
1190                || err))
1191   {
1192     err = false;
1193     CLog::Log(LOGNOTICE, "GL: ARB shaders support detected");
1194     m_renderMethod = RENDER_ARB ;
1195     if (m_pYUVShader)
1196     {
1197       m_pYUVShader->Free();
1198       delete m_pYUVShader;
1199       m_pYUVShader = NULL;
1200     }
1201
1202     // create regular progressive scan shader
1203     m_pYUVShader = new YUV2RGBProgressiveShaderARB(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags);
1204     CLog::Log(LOGNOTICE, "GL: Selecting Single Pass ARB YUV2RGB shader");
1205
1206     if (m_pYUVShader && m_pYUVShader->CompileAndLink())
1207     {
1208       m_renderMethod = RENDER_ARB;
1209       UpdateVideoFilter();
1210     }
1211     else
1212     {
1213       m_pYUVShader->Free();
1214       delete m_pYUVShader;
1215       m_pYUVShader = NULL;
1216       err = true;
1217       CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB ARB shader");
1218     }
1219   }
1220
1221   /*
1222     Fall back to software YUV 2 RGB conversion if
1223       1) user requested it
1224       2) or GLSL and/or ARB shaders failed
1225    */
1226   else
1227   {
1228     m_renderMethod = RENDER_SW ;
1229     CLog::Log(LOGNOTICE, "GL: Shaders support not present, falling back to SW mode");
1230   }
1231
1232   if (err==true)
1233   {
1234     CLog::Log(LOGERROR, "GL: Falling back to Software YUV2RGB");
1235     m_renderMethod = RENDER_SW;
1236   }
1237
1238   // determine whether GPU supports NPOT textures
1239   if (!glewIsSupported("GL_ARB_texture_non_power_of_two"))
1240   {
1241     if (!glewIsSupported("GL_ARB_texture_rectangle"))
1242     {
1243       CLog::Log(LOGNOTICE, "GL: GL_ARB_texture_rectangle not supported and OpenGL version is not 2.x");
1244       CLog::Log(LOGNOTICE, "GL: Reverting to POT textures");
1245       m_renderMethod |= RENDER_POT;
1246     }
1247     else
1248       CLog::Log(LOGNOTICE, "GL: NPOT textures are supported through GL_ARB_texture_rectangle extension");
1249   }
1250   else
1251     CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
1252 }
1253
1254 void CLinuxRendererGL::UnInit()
1255 {
1256   CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
1257   CSingleLock lock(g_graphicsContext);
1258
1259   if (m_rgbBuffer != NULL)
1260   {
1261     delete [] m_rgbBuffer;
1262     m_rgbBuffer = NULL;
1263   }
1264
1265 #ifdef HAVE_LIBVDPAU
1266   if (g_VDPAU)
1267     g_VDPAU->ReleasePixmap();
1268 #endif
1269   // YV12 textures
1270   for (int i = 0; i < NUM_BUFFERS; ++i)
1271     DeleteYV12Texture(i);
1272
1273   // cleanup framebuffer object if it was in use
1274   m_fbo.Cleanup();
1275   m_bValidated = false;
1276   m_bImageReady = false;
1277   m_bConfigured = false;
1278 }
1279
1280 void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
1281 {
1282   // obtain current field, if interlaced
1283   if( flags & RENDER_FLAG_ODD)
1284   {
1285     if (m_currentField == FIELD_FULL)
1286       m_reloadShaders = 1;
1287     m_currentField = FIELD_ODD;
1288   } // even field
1289   else if (flags & RENDER_FLAG_EVEN)
1290   {
1291     if (m_currentField == FIELD_FULL)
1292       m_reloadShaders = 1;
1293     m_currentField = FIELD_EVEN;
1294   }
1295   else if (flags & RENDER_FLAG_LAST)
1296   {
1297     switch(m_currentField)
1298     {
1299     case FIELD_ODD:
1300       flags = RENDER_FLAG_ODD;
1301       break;
1302
1303     case FIELD_EVEN:
1304       flags = RENDER_FLAG_EVEN;
1305       break;
1306     }
1307   }
1308   else
1309   {
1310     if (m_currentField != FIELD_FULL)
1311       m_reloadShaders = 1;
1312     m_currentField = FIELD_FULL;
1313   }
1314
1315   if (m_renderMethod & RENDER_GLSL)
1316   {
1317     UpdateVideoFilter();
1318     switch(m_renderQuality)
1319     {
1320     case RQ_LOW:
1321     case RQ_SINGLEPASS:
1322       RenderSinglePass(renderBuffer, m_currentField);
1323       VerifyGLState();
1324       break;
1325
1326     case RQ_MULTIPASS:
1327       RenderMultiPass(renderBuffer, m_currentField);
1328       VerifyGLState();
1329       break;
1330
1331     case RQ_SOFTWARE:
1332       RenderSoftware(renderBuffer, m_currentField);
1333       VerifyGLState();
1334       break;
1335     }
1336   }
1337   else if (m_renderMethod & RENDER_ARB)
1338   {
1339     RenderSinglePass(renderBuffer, m_currentField);
1340   }
1341 #ifdef HAVE_LIBVDPAU
1342   else if (m_renderMethod & RENDER_VDPAU)
1343   {
1344     RenderVDPAU(renderBuffer, m_currentField);
1345   }
1346 #endif
1347   else
1348   {
1349     RenderSoftware(renderBuffer, m_currentField);
1350     VerifyGLState();
1351   }
1352 }
1353
1354 void CLinuxRendererGL::SetViewMode(int iViewMode)
1355 {
1356   if (iViewMode < VIEW_MODE_NORMAL || iViewMode > VIEW_MODE_CUSTOM) iViewMode = VIEW_MODE_NORMAL;
1357   g_stSettings.m_currentVideoSettings.m_ViewMode = iViewMode;
1358
1359   if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_NORMAL)
1360   { // normal mode...
1361     g_stSettings.m_fPixelRatio = 1.0;
1362     g_stSettings.m_fZoomAmount = 1.0;
1363     return ;
1364   }
1365   if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_CUSTOM)
1366   {
1367     g_stSettings.m_fZoomAmount = g_stSettings.m_currentVideoSettings.m_CustomZoomAmount;
1368     g_stSettings.m_fPixelRatio = g_stSettings.m_currentVideoSettings.m_CustomPixelRatio;
1369     return ;
1370   }
1371
1372   // get our calibrated full screen resolution
1373   //float fOffsetX1 = (float)g_settings.m_ResInfo[m_iResolution].Overscan.left;
1374   //float fOffsetY1 = (float)g_settings.m_ResInfo[m_iResolution].Overscan.top;
1375   float fScreenWidth = (float)(g_settings.m_ResInfo[m_iResolution].Overscan.right - g_settings.m_ResInfo[m_iResolution].Overscan.left);
1376   float fScreenHeight = (float)(g_settings.m_ResInfo[m_iResolution].Overscan.bottom - g_settings.m_ResInfo[m_iResolution].Overscan.top);
1377   // and the source frame ratio
1378   float fSourceFrameRatio = GetAspectRatio();
1379
1380   if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_ZOOM)
1381   { // zoom image so no black bars
1382     g_stSettings.m_fPixelRatio = 1.0;
1383     // calculate the desired output ratio
1384     float fOutputFrameRatio = fSourceFrameRatio * g_stSettings.m_fPixelRatio / g_settings.m_ResInfo[m_iResolution].fPixelRatio;
1385     // now calculate the correct zoom amount.  First zoom to full height.
1386     float fNewHeight = fScreenHeight;
1387     float fNewWidth = fNewHeight * fOutputFrameRatio;
1388     g_stSettings.m_fZoomAmount = fNewWidth / fScreenWidth;
1389     if (fNewWidth < fScreenWidth)
1390     { // zoom to full width
1391       fNewWidth = fScreenWidth;
1392       fNewHeight = fNewWidth / fOutputFrameRatio;
1393       g_stSettings.m_fZoomAmount = fNewHeight / fScreenHeight;
1394     }
1395   }
1396   else if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_STRETCH_4x3)
1397   { // stretch image to 4:3 ratio
1398     g_stSettings.m_fZoomAmount = 1.0;
1399     if (m_iResolution == PAL_4x3 || m_iResolution == PAL60_4x3 || m_iResolution == NTSC_4x3 || m_iResolution == HDTV_480p_4x3)
1400     { // stretch to the limits of the 4:3 screen.
1401       // incorrect behaviour, but it's what the users want, so...
1402       g_stSettings.m_fPixelRatio = (fScreenWidth / fScreenHeight) * g_settings.m_ResInfo[m_iResolution].fPixelRatio / fSourceFrameRatio;
1403     }
1404     else
1405     {
1406       // now we need to set g_stSettings.m_fPixelRatio so that
1407       // fOutputFrameRatio = 4:3.
1408       g_stSettings.m_fPixelRatio = (4.0f / 3.0f) / fSourceFrameRatio;
1409     }
1410   }
1411   else if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_STRETCH_14x9)
1412   { // stretch image to 14:9 ratio
1413     // now we need to set g_stSettings.m_fPixelRatio so that
1414     // fOutputFrameRatio = 14:9.
1415     g_stSettings.m_fPixelRatio = (14.0f / 9.0f) / fSourceFrameRatio;
1416     // calculate the desired output ratio
1417     float fOutputFrameRatio = fSourceFrameRatio * g_stSettings.m_fPixelRatio / g_settings.m_ResInfo[m_iResolution].fPixelRatio;
1418     // now calculate the correct zoom amount.  First zoom to full height.
1419     float fNewHeight = fScreenHeight;
1420     float fNewWidth = fNewHeight * fOutputFrameRatio;
1421     g_stSettings.m_fZoomAmount = fNewWidth / fScreenWidth;
1422     if (fNewWidth < fScreenWidth)
1423     { // zoom to full width
1424       fNewWidth = fScreenWidth;
1425       fNewHeight = fNewWidth / fOutputFrameRatio;
1426       g_stSettings.m_fZoomAmount = fNewHeight / fScreenHeight;
1427     }
1428   }
1429   else if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_STRETCH_16x9)
1430   { // stretch image to 16:9 ratio
1431     g_stSettings.m_fZoomAmount = 1.0;
1432     if (m_iResolution == PAL_4x3 || m_iResolution == PAL60_4x3 || m_iResolution == NTSC_4x3 || m_iResolution == HDTV_480p_4x3)
1433     { // now we need to set g_stSettings.m_fPixelRatio so that
1434       // fOutputFrameRatio = 16:9.
1435       g_stSettings.m_fPixelRatio = (16.0f / 9.0f) / fSourceFrameRatio;
1436     }
1437     else
1438     { // stretch to the limits of the 16:9 screen.
1439       // incorrect behaviour, but it's what the users want, so...
1440       g_stSettings.m_fPixelRatio = (fScreenWidth / fScreenHeight) * g_settings.m_ResInfo[m_iResolution].fPixelRatio / fSourceFrameRatio;
1441     }
1442   }
1443   else // if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_ORIGINAL)
1444   { // zoom image so that the height is the original size
1445     g_stSettings.m_fPixelRatio = 1.0;
1446     // get the size of the media file
1447     // calculate the desired output ratio
1448     float fOutputFrameRatio = fSourceFrameRatio * g_stSettings.m_fPixelRatio / g_settings.m_ResInfo[m_iResolution].fPixelRatio;
1449     // now calculate the correct zoom amount.  First zoom to full width.
1450     float fNewWidth = fScreenWidth;
1451     float fNewHeight = fNewWidth / fOutputFrameRatio;
1452     if (fNewHeight > fScreenHeight)
1453     { // zoom to full height
1454       fNewHeight = fScreenHeight;
1455       fNewWidth = fNewHeight * fOutputFrameRatio;
1456     }
1457     // now work out the zoom amount so that no zoom is done
1458     g_stSettings.m_fZoomAmount = (m_iSourceHeight - g_stSettings.m_currentVideoSettings.m_CropTop - g_stSettings.m_currentVideoSettings.m_CropBottom) / fNewHeight;
1459   }
1460 }
1461
1462 void CLinuxRendererGL::AutoCrop(bool bCrop)
1463 {
1464   if (!m_YUVTexture[0][FIELD_FULL][PLANE_Y].id) return ;
1465   // FIXME: no cropping for now
1466   { // reset to defaults
1467     g_stSettings.m_currentVideoSettings.m_CropLeft = 0;
1468     g_stSettings.m_currentVideoSettings.m_CropRight = 0;
1469     g_stSettings.m_currentVideoSettings.m_CropTop = 0;
1470     g_stSettings.m_currentVideoSettings.m_CropBottom = 0;
1471   }
1472   SetViewMode(g_stSettings.m_currentVideoSettings.m_ViewMode);
1473 }
1474
1475 void CLinuxRendererGL::RenderSinglePass(int index, int field)
1476 {
1477   YUVFIELDS &fields = m_YUVTexture[index];
1478   YUVPLANES &planes = fields[field];
1479
1480   // set scissors if we are not in fullscreen video
1481   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1482     g_graphicsContext.ClipToViewWindow();
1483
1484   glDisable(GL_DEPTH_TEST);
1485
1486   //See RGB renderer for comment on this
1487 #define CHROMAOFFSET_HORIZ 0.25f
1488
1489   // Y
1490   glActiveTextureARB(GL_TEXTURE0);
1491   glEnable(m_textureTarget);
1492   glBindTexture(m_textureTarget, planes[0].id);
1493
1494   // U
1495   glActiveTextureARB(GL_TEXTURE1);
1496   glEnable(m_textureTarget);
1497   glBindTexture(m_textureTarget, planes[1].id);
1498
1499   // V
1500   glActiveTextureARB(GL_TEXTURE2);
1501   glEnable(m_textureTarget);
1502   glBindTexture(m_textureTarget, planes[2].id);
1503
1504   glActiveTextureARB(GL_TEXTURE0);
1505   VerifyGLState();
1506
1507   if (m_reloadShaders)
1508   {
1509     m_reloadShaders = 0;
1510     LoadShaders(field);
1511
1512     if (m_currentField==FIELD_FULL)
1513       SetTextureFilter(GL_LINEAR);
1514     else
1515       SetTextureFilter(GL_LINEAR);
1516   }
1517
1518   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetYTexture(0);
1519   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetUTexture(1);
1520   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetVTexture(2);
1521   if     (field == FIELD_ODD)
1522     ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetField(1);
1523   else if(field == FIELD_EVEN)
1524     ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetField(0);
1525
1526   m_pYUVShader->Enable();
1527
1528   glBegin(GL_QUADS);
1529
1530   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
1531   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y1);
1532   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y1);
1533   glVertex4f((float)rd.left, (float)rd.top, 0, 1.0f );
1534
1535   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y1);
1536   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y1);
1537   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y1);
1538   glVertex4f((float)rd.right, (float)rd.top, 0, 1.0f);
1539
1540   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y2);
1541   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y2);
1542   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y2);
1543   glVertex4f((float)rd.right, (float)rd.bottom, 0, 1.0f);
1544
1545   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y2);
1546   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y2);
1547   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y2);
1548   glVertex4f((float)rd.left, (float)rd.bottom, 0, 1.0f);
1549
1550   glEnd();
1551   VerifyGLState();
1552
1553   m_pYUVShader->Disable();
1554   VerifyGLState();
1555
1556   glActiveTextureARB(GL_TEXTURE1);
1557   glDisable(m_textureTarget);
1558
1559   glActiveTextureARB(GL_TEXTURE2);
1560   glDisable(m_textureTarget);
1561
1562   glActiveTextureARB(GL_TEXTURE0);
1563   glDisable(m_textureTarget);
1564
1565   glMatrixMode(GL_MODELVIEW);
1566
1567   VerifyGLState();
1568 }
1569
1570 void CLinuxRendererGL::RenderMultiPass(int index, int field)
1571 {
1572   YV12Image &im = m_image[index];
1573   YUVPLANES &planes = m_YUVTexture[index][field];
1574
1575   // set scissors if we are not in fullscreen video
1576   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1577     g_graphicsContext.ClipToViewWindow();
1578
1579   glDisable(GL_DEPTH_TEST);
1580   VerifyGLState();
1581
1582   //See RGB renderer for comment on this
1583 #define CHROMAOFFSET_HORIZ 0.25f
1584
1585   // Y
1586   glEnable(m_textureTarget);
1587   glActiveTextureARB(GL_TEXTURE0);
1588   glBindTexture(m_textureTarget, planes[0].id);
1589   VerifyGLState();
1590
1591   // U
1592   glActiveTextureARB(GL_TEXTURE1);
1593   glEnable(m_textureTarget);
1594   glBindTexture(m_textureTarget, planes[1].id);
1595   VerifyGLState();
1596
1597   // V
1598   glActiveTextureARB(GL_TEXTURE2);
1599   glEnable(m_textureTarget);
1600   glBindTexture(m_textureTarget, planes[2].id);
1601   VerifyGLState();
1602
1603   glActiveTextureARB(GL_TEXTURE0);
1604   VerifyGLState();
1605
1606   if (m_reloadShaders)
1607   {
1608     m_reloadShaders = 0;
1609     m_fbo.Cleanup();
1610     LoadShaders(m_currentField);
1611     VerifyGLState();
1612     SetTextureFilter(GL_LINEAR);
1613     VerifyGLState();
1614   }
1615
1616   // make sure the yuv shader is loaded and ready to go
1617   if (!m_pYUVShader || (!m_pYUVShader->OK()))
1618   {
1619     CLog::Log(LOGERROR, "GL: YUV shader not active, cannot do multipass render");
1620     return;
1621   }
1622
1623   int imgheight;
1624
1625   if(field == FIELD_FULL)
1626     imgheight = im.height;
1627   else
1628     imgheight = im.height/2;
1629
1630   // make sure FBO is valid and ready to go
1631   if (!m_fbo.IsValid())
1632   {
1633     m_fbo.Initialize();
1634     if (!m_fbo.CreateAndBindToTexture(GL_TEXTURE_2D, im.width, imgheight, GL_RGBA))
1635       CLog::Log(LOGERROR, "GL: Error creating texture and binding to FBO");
1636   }
1637
1638   m_fbo.BeginRender();
1639   VerifyGLState();
1640
1641   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetYTexture(0);
1642   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetUTexture(1);
1643   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetVTexture(2);
1644   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetWidth(im.width);
1645   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetHeight(im.height);
1646   if     (field == FIELD_ODD)
1647     ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetField(1);
1648   else if(field == FIELD_EVEN)
1649     ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetField(0);
1650
1651   VerifyGLState();
1652
1653   glPushAttrib(GL_VIEWPORT_BIT);
1654   glPushAttrib(GL_SCISSOR_BIT);
1655   glMatrixMode(GL_MODELVIEW);
1656   glPushMatrix();
1657   glLoadIdentity();
1658   VerifyGLState();
1659
1660   glMatrixMode(GL_PROJECTION);
1661   glPushMatrix();
1662   glLoadIdentity();
1663   VerifyGLState();
1664   gluOrtho2D(0, im.width, 0, imgheight);
1665   glViewport(0, 0, im.width, imgheight);
1666   glScissor(0, 0, im.width, imgheight);
1667   glMatrixMode(GL_MODELVIEW);
1668   VerifyGLState();
1669
1670
1671   if (!m_pYUVShader->Enable())
1672   {
1673     CLog::Log(LOGERROR, "GL: Error enabling YUV shader");
1674   }
1675
1676   // 1st Pass to video frame size
1677
1678   glBegin(GL_QUADS);
1679
1680   glMultiTexCoord2fARB(GL_TEXTURE0, 0              , 0);
1681   glMultiTexCoord2fARB(GL_TEXTURE1, 0              , 0);
1682   glMultiTexCoord2fARB(GL_TEXTURE2, 0              , 0);
1683   glVertex2f((float)0, (float)0);
1684
1685   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].width, 0);
1686   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].width, 0);
1687   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].width, 0);
1688   glVertex2f((float)im.width, (float)0);
1689
1690   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].width, planes[0].height);
1691   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].width, planes[1].height);
1692   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].width, planes[2].height);
1693   glVertex2f((float)im.width, (float)imgheight);
1694
1695   glMultiTexCoord2fARB(GL_TEXTURE0, 0              , planes[0].height);
1696   glMultiTexCoord2fARB(GL_TEXTURE1, 0              , planes[1].height);
1697   glMultiTexCoord2fARB(GL_TEXTURE2, 0              , planes[2].height);
1698   glVertex2f((float)0, (float)imgheight);
1699
1700   glEnd();
1701   VerifyGLState();
1702
1703   m_pYUVShader->Disable();
1704
1705   glMatrixMode(GL_MODELVIEW);
1706   glPopMatrix(); // pop modelview
1707   glMatrixMode(GL_PROJECTION);
1708   glPopMatrix(); // pop projection
1709   glPopAttrib(); // pop scissor
1710   glPopAttrib(); // pop viewport
1711   glMatrixMode(GL_MODELVIEW);
1712   VerifyGLState();
1713
1714   m_fbo.EndRender();
1715
1716   glActiveTextureARB(GL_TEXTURE1);
1717   glDisable(m_textureTarget);
1718   glActiveTextureARB(GL_TEXTURE2);
1719   glDisable(m_textureTarget);
1720   glActiveTextureARB(GL_TEXTURE0);
1721   glDisable(m_textureTarget);
1722
1723   glEnable(GL_TEXTURE_2D);
1724   glBindTexture(GL_TEXTURE_2D, m_fbo.Texture());
1725   VerifyGLState();
1726
1727   // Use regular normalized texture coordinates
1728
1729   // 2nd Pass to screen size with optional video filter
1730
1731   if (m_pVideoFilterShader)
1732   {
1733     m_fbo.SetFiltering(GL_TEXTURE_2D, GL_NEAREST);
1734     m_pVideoFilterShader->SetSourceTexture(0);
1735     m_pVideoFilterShader->SetWidth(im.width);
1736     m_pVideoFilterShader->SetHeight(imgheight);
1737     m_pVideoFilterShader->Enable();
1738   }
1739   else
1740     m_fbo.SetFiltering(GL_TEXTURE_2D, GL_LINEAR);
1741
1742   VerifyGLState();
1743
1744   // TODO - recalculate based source rectangle so crop works
1745   //        but to do so we need the source texture size of the framebuffer
1746
1747   glBegin(GL_QUADS);
1748
1749   glMultiTexCoord2fARB(GL_TEXTURE0, 0, 0);
1750   glVertex4f((float)rd.left, (float)rd.top, 0, 1.0f );
1751
1752   glMultiTexCoord2fARB(GL_TEXTURE0, 1, 0);
1753   glVertex4f((float)rd.right, (float)rd.top, 0, 1.0f);
1754
1755   glMultiTexCoord2fARB(GL_TEXTURE0, 1, 1);
1756   glVertex4f((float)rd.right, (float)rd.bottom, 0, 1.0f);
1757
1758   glMultiTexCoord2fARB(GL_TEXTURE0, 0, 1);
1759   glVertex4f((float)rd.left, (float)rd.bottom, 0, 1.0f);
1760
1761   glEnd();
1762
1763   VerifyGLState();
1764
1765   if (m_pVideoFilterShader)
1766     m_pVideoFilterShader->Disable();
1767
1768   VerifyGLState();
1769
1770   glDisable(m_textureTarget);
1771   VerifyGLState();
1772 }
1773
1774 void CLinuxRendererGL::RenderVDPAU(int index, int field)
1775 {
1776 #ifdef HAVE_LIBVDPAU
1777   if (!g_VDPAU)
1778   {
1779     CLog::Log(LOGERROR,"(VDPAU) m_Surface is NULL");
1780     return;
1781   }
1782
1783   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1784     g_graphicsContext.ClipToViewWindow();
1785
1786   glEnable(m_textureTarget);
1787
1788   glBindTexture(m_textureTarget, g_VDPAU->m_glPixmapTexture);
1789   g_VDPAU->BindPixmap();
1790
1791   glActiveTextureARB(GL_TEXTURE0);
1792
1793   // Try some clamping or wrapping
1794   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP);
1795   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP);
1796   glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1797   glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1798
1799   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1800   VerifyGLState();
1801
1802   glBegin(GL_QUADS);
1803   if (m_textureTarget==GL_TEXTURE_2D)
1804   {
1805     glTexCoord2f(0.0, 0.0);  glVertex2d((float)rd.left, (float)rd.top);
1806     glTexCoord2f(1.0, 0.0);  glVertex2d((float)rd.right, (float)rd.top);
1807     glTexCoord2f(1.0, 1.0);  glVertex2d((float)rd.right, (float)rd.bottom);
1808     glTexCoord2f(0.0, 1.0);  glVertex2d((float)rd.left, (float)rd.bottom);
1809   }
1810   else
1811   {
1812     glTexCoord2f((float)rs.left,  (float)rs.top);    glVertex4f((float)rd.left,  (float)rd.top,    0, 1.0f);
1813     glTexCoord2f((float)rs.right, (float)rs.top);    glVertex4f((float)rd.right, (float)rd.top,    0, 1.0f);
1814     glTexCoord2f((float)rs.right, (float)rs.bottom); glVertex4f((float)rd.right, (float)rd.bottom, 0, 1.0f);
1815     glTexCoord2f((float)rs.left,  (float)rs.bottom); glVertex4f((float)rd.left,  (float)rd.bottom, 0, 1.0f);
1816   }
1817   glEnd();
1818   VerifyGLState();
1819   if (m_StrictBinding)
1820   {
1821     glBindTexture(m_textureTarget, g_VDPAU->m_glPixmapTexture);
1822     g_VDPAU->ReleasePixmap();
1823   }
1824
1825   glBindTexture (m_textureTarget, 0);
1826   glDisable(m_textureTarget);
1827 #endif
1828 }
1829
1830
1831 void CLinuxRendererGL::RenderSoftware(int index, int field)
1832 {
1833   YUVPLANES &planes = m_YUVTexture[index][field];
1834
1835   // set scissors if we are not in fullscreen video
1836   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1837     g_graphicsContext.ClipToViewWindow();
1838
1839   glDisable(GL_DEPTH_TEST);
1840
1841   // Y
1842   glEnable(m_textureTarget);
1843   glActiveTextureARB(GL_TEXTURE0);
1844   glBindTexture(m_textureTarget, planes[0].id);
1845   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1846
1847   glBegin(GL_QUADS);
1848   glTexCoord2f(planes[0].rect.x1, planes[0].rect.y1);
1849   glVertex4f((float)rd.left, (float)rd.top, 0, 1.0f );
1850
1851   glTexCoord2f(planes[0].rect.x2, planes[0].rect.y1);
1852   glVertex4f((float)rd.right, (float)rd.top, 0, 1.0f);
1853
1854   glTexCoord2f(planes[0].rect.x2, planes[0].rect.y2);
1855   glVertex4f((float)rd.right, (float)rd.bottom, 0, 1.0f);
1856
1857   glTexCoord2f(planes[0].rect.x1, planes[0].rect.y2);
1858   glVertex4f((float)rd.left, (float)rd.bottom, 0, 1.0f);
1859
1860   glEnd();
1861
1862   VerifyGLState();
1863
1864   glDisable(m_textureTarget);
1865   VerifyGLState();
1866 }
1867
1868 void CLinuxRendererGL::CreateThumbnail(SDL_Surface* surface, unsigned int width, unsigned int height)
1869 {
1870   // get our screen rect
1871   const RECT& rv = g_graphicsContext.GetViewWindow();
1872
1873   // save current video rect
1874   RECT saveSize = rd;
1875
1876   // new video rect is thumbnail size
1877   rd.left = rd.top = 0;
1878   rd.right = width;
1879   rd.bottom = height;
1880
1881   // clear framebuffer and invert Y axis to get non-inverted image
1882   glClear(GL_COLOR_BUFFER_BIT);
1883   glMatrixMode(GL_MODELVIEW);
1884   glPushMatrix();
1885   glTranslatef(0, height, 0);
1886   glScalef(1.0, -1.0f, 1.0f);
1887   Render(RENDER_FLAG_NOOSD, m_iYV12RenderBuffer);
1888
1889   // read pixels
1890   glReadPixels(0, rv.bottom-height, width, height, GL_BGRA, GL_UNSIGNED_BYTE, surface->pixels);
1891
1892   // revert model view matrix
1893   glMatrixMode(GL_MODELVIEW);
1894   glPopMatrix();
1895
1896   // restore original video rect
1897   rd = saveSize;
1898 }
1899
1900 //********************************************************************************************************
1901 // YV12 Texture creation, deletion, copying + clearing
1902 //********************************************************************************************************
1903 void CLinuxRendererGL::DeleteYV12Texture(int index)
1904 {
1905   YV12Image &im = m_image[index];
1906   YUVFIELDS &fields = m_YUVTexture[index];
1907
1908   if( fields[FIELD_FULL][0].id == 0 ) return;
1909
1910   CLog::Log(LOGDEBUG, "Deleted YV12 texture %i", index);
1911   /* finish up all textures, and delete them */
1912   g_graphicsContext.BeginPaint();  //FIXME
1913   for(int f = 0;f<MAX_FIELDS;f++)
1914   {
1915     for(int p = 0;p<MAX_PLANES;p++)
1916     {
1917       if( fields[f][p].id )
1918       {
1919         if (glIsTexture(fields[f][p].id))
1920         {
1921           glDeleteTextures(1, &fields[f][p].id);
1922           CLog::Log(LOGDEBUG, "GL: Deleting texture field %d plane %d", f+1, p+1);
1923         }
1924         fields[f][p].id = 0;
1925       }
1926     }
1927   }
1928   g_graphicsContext.EndPaint();
1929
1930   for(int p = 0;p<MAX_PLANES;p++)
1931   {
1932     if (im.plane[p])
1933     {
1934       delete[] im.plane[p];
1935       im.plane[p] = NULL;
1936     }
1937   }
1938 }
1939
1940 void CLinuxRendererGL::ClearYV12Texture(int index)
1941 {
1942   //YV12Image &im = m_image[index];
1943
1944   //memset(im.plane[0], 0,   im.stride[0] * im.height);
1945   //memset(im.plane[1], 128, im.stride[1] * im.height>>im.cshift_y );
1946   //memset(im.plane[2], 128, im.stride[2] * im.height>>im.cshift_y );
1947   //SetEvent(m_eventTexturesDone[index]);
1948 }
1949
1950 bool CLinuxRendererGL::CreateYV12Texture(int index, bool clear)
1951 {
1952 /*
1953 #ifdef HAVE_LIBVDPAU
1954   if (m_renderMethod & RENDER_VDPAU)
1955   {
1956     SetEvent(m_eventTexturesDone[index]);
1957     return true;
1958   }
1959 #endif
1960 */
1961   // Remember if we're software upscaling.
1962   m_isSoftwareUpscaling = IsSoftwareUpscaling();
1963
1964   /* since we also want the field textures, pitch must be texture aligned */
1965   unsigned p;
1966
1967   YV12Image &im = m_image[index];
1968   YUVFIELDS &fields = m_YUVTexture[index];
1969
1970   if (clear)
1971   {
1972     DeleteYV12Texture(index);
1973
1974     im.height = m_iSourceHeight;
1975     im.width  = m_iSourceWidth;
1976     im.cshift_x = 1;
1977     im.cshift_y = 1;
1978
1979     im.stride[0] = im.width;
1980     im.stride[1] = im.width >> im.cshift_x;
1981     im.stride[2] = im.width >> im.cshift_x;
1982     im.plane[0] = new BYTE[im.stride[0] * im.height];
1983     im.plane[1] = new BYTE[im.stride[1] * ( im.height >> im.cshift_y )];
1984     im.plane[2] = new BYTE[im.stride[2] * ( im.height >> im.cshift_y )];
1985   }
1986
1987   glEnable(m_textureTarget);
1988   for(int f = 0;f<MAX_FIELDS;f++)
1989   {
1990     for(p = 0;p<MAX_PLANES;p++)
1991     {
1992       if (!glIsTexture(fields[f][p].id))
1993       {
1994         glGenTextures(1, &fields[f][p].id);
1995         VerifyGLState();
1996       }
1997     }
1998   }
1999
2000   // YUV
2001   for (int f = FIELD_FULL; f<=FIELD_EVEN ; f++)
2002   {
2003     int fieldshift = (f==FIELD_FULL) ? 0 : 1;
2004     YUVPLANES &planes = fields[f];
2005
2006     if(m_isSoftwareUpscaling)
2007     {
2008       planes[0].texwidth  = m_upscalingWidth;
2009       planes[0].texheight = m_upscalingHeight >> fieldshift;
2010     }
2011     else
2012     {
2013       planes[0].texwidth  = im.width;
2014       planes[0].texheight = im.height >> fieldshift;
2015     }
2016
2017     if (m_renderMethod & RENDER_SW)
2018     {
2019       planes[1].texwidth  = 0;
2020       planes[1].texheight = 0;
2021       planes[2].texwidth  = 0;
2022       planes[2].texheight = 0;
2023     }
2024     else
2025     {
2026       planes[1].texwidth  = planes[0].texwidth  >> im.cshift_x;
2027       planes[1].texheight = planes[0].texheight >> im.cshift_y;
2028       planes[2].texwidth  = planes[0].texwidth  >> im.cshift_x;
2029       planes[2].texheight = planes[0].texheight >> im.cshift_y;
2030     }
2031
2032     if(m_renderMethod & RENDER_POT)
2033     {
2034       for(int p = 0; p < 3; p++)
2035       {
2036         planes[p].texwidth  = NP2(planes[p].texwidth);
2037         planes[p].texheight = NP2(planes[p].texheight);
2038       }
2039     }
2040
2041     for(int p = 0; p < 3; p++)
2042     {
2043       YUVPLANE &plane = planes[p];
2044       if (plane.texwidth * plane.texheight == 0)
2045         continue;
2046
2047       glBindTexture(m_textureTarget, plane.id);
2048       if (m_renderMethod & RENDER_SW)
2049       {
2050         if(m_renderMethod & RENDER_POT)
2051           CLog::Log(LOGNOTICE, "GL: Creating RGB POT texture of size %d x %d",  plane.texwidth, plane.texheight);
2052         else
2053           CLog::Log(LOGDEBUG,  "GL: Creating RGB NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
2054
2055         glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2056       } 
2057       else
2058       {
2059         if(m_renderMethod & RENDER_POT)
2060           CLog::Log(LOGNOTICE, "GL: Creating YUV POT texture of size %d x %d",  plane.texwidth, plane.texheight);
2061         else
2062           CLog::Log(LOGDEBUG,  "GL: Creating YUV NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
2063
2064         glTexImage2D(m_textureTarget, 0, GL_LUMINANCE, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2065       }
2066
2067       glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2068       glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2069       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2070       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2071       VerifyGLState();
2072     }
2073   }
2074   glDisable(m_textureTarget);
2075   SetEvent(m_eventTexturesDone[index]);
2076   return true;
2077 }
2078
2079 void CLinuxRendererGL::SetTextureFilter(GLenum method)
2080 {
2081   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
2082   {
2083     YUVFIELDS &fields = m_YUVTexture[i];
2084
2085     for (int f = FIELD_FULL; f<=FIELD_EVEN ; f++)
2086     {
2087       glBindTexture(m_textureTarget, fields[f][0].id);
2088       glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2089       glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2090       VerifyGLState();
2091
2092       if (!(m_renderMethod & RENDER_SW))
2093       {
2094         glBindTexture(m_textureTarget, fields[f][1].id);
2095         glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2096         glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2097         VerifyGLState();
2098
2099         glBindTexture(m_textureTarget, fields[f][2].id);
2100         glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2101         glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2102         VerifyGLState();
2103       }
2104     }
2105   }
2106 }
2107
2108 bool CLinuxRendererGL::SupportsBrightness()
2109 {
2110   return glewIsSupported("GL_ARB_imaging") == GL_TRUE;
2111 }
2112
2113 bool CLinuxRendererGL::SupportsContrast()
2114 {
2115   return glewIsSupported("GL_ARB_imaging") == GL_TRUE;
2116 }
2117
2118 bool CLinuxRendererGL::SupportsGamma()
2119 {
2120   return false;
2121 }
2122
2123 bool CLinuxRendererGL::SupportsMultiPassRendering()
2124 {
2125   return glewIsSupported("GL_EXT_framebuffer_object") && glCreateProgram;
2126 }
2127
2128 #endif
2129
2130 #endif