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