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