changed: remove unused static brightness and contrast variables and calculate them...
[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   bool deinterlacing;
615   if (m_currentField == FIELD_FULL)
616     deinterlacing = false;
617   else
618     deinterlacing = false;
619
620   if (imaging==-1)
621   {
622     imaging = 0;
623     if (glewIsSupported("GL_ARB_imaging"))
624     {
625       CLog::Log(LOGINFO, "GL: ARB Imaging extension supported");
626       imaging = 1;
627     }
628     else
629     {
630       int maj=0, min=0;
631       g_graphicsContext.getScreenSurface()->GetGLVersion(maj, min);
632       if (maj>=2)
633       {
634         imaging = 1;
635       }
636       else if (min>=2)
637       {
638         imaging = 1;
639       }
640     }
641   }
642
643   if (imaging==1 &&
644       ((g_stSettings.m_currentVideoSettings.m_Brightness!=50) ||
645        (g_stSettings.m_currentVideoSettings.m_Contrast!=50)))
646   {
647     GLfloat brightness = ((GLfloat)g_stSettings.m_currentVideoSettings.m_Brightness - 50.0f)/100.0f;;
648     GLfloat contrast   = ((GLfloat)g_stSettings.m_currentVideoSettings.m_Contrast)/50.0f;
649
650     glPixelTransferf(GL_RED_SCALE, contrast);
651     glPixelTransferf(GL_GREEN_SCALE, contrast);
652     glPixelTransferf(GL_BLUE_SCALE, contrast);
653     glPixelTransferf(GL_RED_BIAS, brightness);
654     glPixelTransferf(GL_GREEN_BIAS, brightness);
655     glPixelTransferf(GL_BLUE_BIAS, brightness);
656     VerifyGLState();
657     imaging++;
658   }
659
660   glEnable(m_textureTarget);
661   VerifyGLState();
662
663   if (m_renderMethod & RENDER_SW)
664   {
665     // Load RGB image
666     if (deinterlacing)
667     {
668       LoadPlane( fields[FIELD_ODD][0] , GL_BGRA, im->flipindex
669                , im->width, im->height >> 1
670                , m_iSourceWidth*2, m_rgbBuffer );
671
672       LoadPlane( fields[FIELD_EVEN][0], GL_BGRA, im->flipindex
673                , im->width, im->height >> 1
674                , m_iSourceWidth*2, m_rgbBuffer + m_iSourceWidth*4);      
675     }
676     else
677     {
678       LoadPlane( fields[FIELD_FULL][0], GL_BGRA, im->flipindex
679                , im->width, im->height
680                , m_iSourceWidth, m_rgbBuffer );
681     }
682   }
683   else
684   {
685     glPixelStorei(GL_UNPACK_ALIGNMENT,1);
686
687     if (deinterlacing)
688     {
689       // Load Y fields
690       LoadPlane( fields[FIELD_ODD][0] , GL_LUMINANCE, im->flipindex
691                , im->width, im->height >> 1
692                , im->stride[0]*2, im->plane[0] );
693
694       LoadPlane( fields[FIELD_EVEN][0], GL_LUMINANCE, im->flipindex
695                , im->width, im->height >> 1
696                , im->stride[0]*2, im->plane[0] + im->stride[0]) ;     
697     }
698     else
699     {
700       // Load Y plane
701       LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, im->flipindex
702                , im->width, im->height
703                , im->stride[0], im->plane[0] );
704     }
705   }
706
707   VerifyGLState();
708
709   if (imaging==2)
710   {
711     imaging--;
712     glPixelTransferf(GL_RED_SCALE, 1.0);
713     glPixelTransferf(GL_GREEN_SCALE, 1.0);
714     glPixelTransferf(GL_BLUE_SCALE, 1.0);
715     glPixelTransferf(GL_RED_BIAS, 0.0);
716     glPixelTransferf(GL_GREEN_BIAS, 0.0);
717     glPixelTransferf(GL_BLUE_BIAS, 0.0);
718     VerifyGLState();
719   }
720
721   if (!(m_renderMethod & RENDER_SW))
722   {
723     glPixelStorei(GL_UNPACK_ALIGNMENT,1);
724
725     if (deinterlacing)
726     {
727       // Load Even U & V Fields
728       LoadPlane( fields[FIELD_ODD][1], GL_LUMINANCE, im->flipindex
729                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
730                , im->stride[1]*2, im->plane[1] );
731
732       LoadPlane( fields[FIELD_ODD][2], GL_LUMINANCE, im->flipindex
733                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
734                , im->stride[2]*2, im->plane[2] );
735       
736       // Load Odd U & V Fields
737       LoadPlane( fields[FIELD_EVEN][1], GL_LUMINANCE, im->flipindex
738                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
739                , im->stride[1]*2, im->plane[1] + im->stride[1] );
740
741       LoadPlane( fields[FIELD_EVEN][2], GL_LUMINANCE, im->flipindex
742                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
743                , im->stride[2]*2, im->plane[2] + im->stride[2] );
744       
745     }
746     else
747     {
748       LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, im->flipindex
749                , im->width >> im->cshift_x, im->height >> im->cshift_y
750                , im->stride[1], im->plane[1] );
751
752       LoadPlane( fields[FIELD_FULL][2], GL_LUMINANCE, im->flipindex
753                , im->width >> im->cshift_x, im->height >> im->cshift_y
754                , im->stride[2], im->plane[2] );
755     }
756   }
757   SetEvent(m_eventTexturesDone[source]);
758
759   // calculate the source rectangle
760   for(int field = 0; field < 3; field++)
761   {
762     for(int plane = 0; plane < 3; plane++)
763     {
764       YUVPLANE& p = fields[field][plane];
765
766       /* software upscaling is precropped */
767       if(IsSoftwareUpscaling())
768         p.rect.SetRect(0, 0, im->width, im->height);
769       else      
770         p.rect.SetRect(rs.left, rs.top, rs.right, rs.bottom);
771
772       p.width  = im->width;
773       p.height = im->height;
774
775       if(field != FIELD_FULL)
776       {
777         /* correct for field offsets and chroma offsets */
778         float offset_y = 0.5;
779         if(plane != 0)
780           offset_y += 0.5;
781         if(field == FIELD_EVEN)
782           offset_y *= -1;
783
784         p.rect.y1 += offset_y;
785         p.rect.y2 += offset_y;
786
787         /* half the height if this is a field */
788         p.height  *= 0.5f;
789         p.rect.y1 *= 0.5f; 
790         p.rect.y2 *= 0.5f;
791       }
792
793       if(plane != 0)
794       {
795         p.width   /= 1 << im->cshift_x;
796         p.height  /= 1 << im->cshift_y;
797
798         p.rect.x1 /= 1 << im->cshift_x;
799         p.rect.x2 /= 1 << im->cshift_x;
800         p.rect.y1 /= 1 << im->cshift_y;
801         p.rect.y2 /= 1 << im->cshift_y;
802       }
803
804       if (m_textureTarget == GL_TEXTURE_2D)
805       {
806         p.height  /= p.texheight;
807         p.rect.y1 /= p.texheight;
808         p.rect.y2 /= p.texheight;
809         p.width   /= p.texwidth;
810         p.rect.x1 /= p.texwidth;
811         p.rect.x2 /= p.texwidth;
812       }
813     }
814   }
815
816   glDisable(m_textureTarget);
817 }
818
819 void CLinuxRendererGL::Reset()
820 {
821   for(int i=0; i<m_NumYV12Buffers; i++)
822   {
823     /* reset all image flags, this will cleanup textures later */
824     m_image[i].flags = 0;
825     /* reset texture locks, a bit ugly, could result in tearing */
826     SetEvent(m_eventTexturesDone[i]);
827   }
828 }
829
830 void CLinuxRendererGL::Update(bool bPauseDrawing)
831 {
832   if (!m_bConfigured) return;
833   ManageDisplay();
834   ManageTextures();
835 }
836
837 void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
838 {
839   if (!m_bConfigured) return;
840
841   // if its first pass, just init textures and return
842   if (ValidateRenderTarget())
843     return;
844
845   // this needs to be checked after texture validation
846   if (!m_bImageReady) return;
847
848   int index = m_iYV12RenderBuffer;
849
850   if (!m_YUVTexture[index][FIELD_FULL][0].id) return ;
851
852   if (m_image[index].flags==0)
853     return;
854
855   ManageDisplay();
856   ManageTextures();
857
858   g_graphicsContext.BeginPaint();
859
860   if( WaitForSingleObject(m_eventTexturesDone[index], 500) == WAIT_TIMEOUT )
861   {
862     CLog::Log(LOGWARNING, "%s - Timeout waiting for texture %d", __FUNCTION__, index);
863
864     // render the previous frame if this one isn't ready yet
865     if (m_iLastRenderBuffer > -1)
866     {
867       m_iYV12RenderBuffer = m_iLastRenderBuffer;
868       index = m_iYV12RenderBuffer;
869     }
870   }
871   else
872   {
873     m_iLastRenderBuffer = index;
874     LoadTextures(index);
875   }
876
877   if (clear)
878   {
879     glClearColor(m_clearColour, m_clearColour, m_clearColour, 0);
880     glClear(GL_COLOR_BUFFER_BIT);
881     glClearColor(0,0,0,0);
882   }
883
884   if (alpha<255)
885   {
886     glEnable(GL_BLEND);
887     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
888     glColor4f(1.0f, 1.0f, 1.0f, alpha / 255.0f);
889   }
890   else
891   {
892     glDisable(GL_BLEND);
893     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
894   }
895
896   Render(flags, index);
897   VerifyGLState();
898   glEnable(GL_BLEND);
899   glFlush();
900   g_graphicsContext.EndPaint();
901 }
902
903 void CLinuxRendererGL::FlipPage(int source)
904 {
905 #ifdef HAVE_LIBVDPAU
906   if (g_VDPAU)
907     g_VDPAU->Present();
908 #endif
909
910   if( source >= 0 && source < m_NumYV12Buffers )
911     m_iYV12RenderBuffer = source;
912   else
913     m_iYV12RenderBuffer = NextYV12Texture();
914
915   m_image[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
916
917   return;
918 }
919
920
921 unsigned int CLinuxRendererGL::DrawSlice(unsigned char *src[], int stride[], int w, int h, int x, int y)
922 {
923   BYTE *s;
924   BYTE *d;
925   int i, p;
926
927   int index = NextYV12Texture();
928   if( index < 0 )
929     return -1;
930
931   YV12Image &im = m_image[index];
932   // copy Y
933   p = 0;
934   d = (BYTE*)im.plane[p] + im.stride[p] * y + x;
935   s = src[p];
936   for (i = 0;i < h;i++)
937   {
938     memcpy(d, s, w);
939     s += stride[p];
940     d += im.stride[p];
941   }
942
943   w >>= im.cshift_x; h >>= im.cshift_y;
944   x >>= im.cshift_x; y >>= im.cshift_y;
945
946   // copy U
947   p = 1;
948   d = (BYTE*)im.plane[p] + im.stride[p] * y + x;
949   s = src[p];
950   for (i = 0;i < h;i++)
951   {
952     memcpy(d, s, w);
953     s += stride[p];
954     d += im.stride[p];
955   }
956
957   // copy V
958   p = 2;
959   d = (BYTE*)im.plane[p] + im.stride[p] * y + x;
960   s = src[p];
961   for (i = 0;i < h;i++)
962   {
963     memcpy(d, s, w);
964     s += stride[p];
965     d += im.stride[p];
966   }
967
968   SetEvent(m_eventTexturesDone[index]);
969   return 0;
970 }
971
972 unsigned int CLinuxRendererGL::PreInit()
973 {
974   CSingleLock lock(g_graphicsContext);
975   m_bConfigured = false;
976   m_bValidated = false;
977   UnInit();
978   m_iResolution = PAL_4x3;
979
980   m_iYV12RenderBuffer = 0;
981   m_NumYV12Buffers = 2;
982
983   // setup the background colour
984   m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
985
986   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwScale.Load())
987     CLog::Log(LOGERROR,"CLinuxRendererGL::PreInit - failed to load rescale libraries!");
988
989   #if (! defined USE_EXTERNAL_FFMPEG)
990     m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
991   #elif (defined HAVE_LIBSWSCALE_RGB2RGB_H) || (defined HAVE_FFMPEG_RGB2RGB_H)
992     m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
993   #endif
994
995   return true;
996 }
997
998 void CLinuxRendererGL::UpdateVideoFilter()
999 {
1000   if (m_scalingMethod == g_stSettings.m_currentVideoSettings.m_ScalingMethod)
1001     return;
1002
1003   if (m_pVideoFilterShader)
1004   {
1005     m_pVideoFilterShader->Free();
1006     delete m_pVideoFilterShader;
1007     m_pVideoFilterShader = NULL;
1008   }
1009
1010   VerifyGLState();
1011   m_scalingMethod = g_stSettings.m_currentVideoSettings.m_ScalingMethod;
1012
1013   switch (g_stSettings.m_currentVideoSettings.m_ScalingMethod)
1014   {
1015   case VS_SCALINGMETHOD_NEAREST:
1016     m_renderQuality = RQ_SINGLEPASS;
1017     SetTextureFilter(GL_NEAREST);
1018     break;
1019
1020   case VS_SCALINGMETHOD_LINEAR:
1021     SetTextureFilter(GL_LINEAR);
1022     m_renderQuality = RQ_SINGLEPASS;
1023     break;
1024
1025   case VS_SCALINGMETHOD_CUBIC:
1026     SetTextureFilter(GL_LINEAR);
1027     m_renderQuality = RQ_MULTIPASS;
1028     m_pVideoFilterShader = new BicubicFilterShader(0.3f, 0.3f);
1029     if (m_pVideoFilterShader && m_pVideoFilterShader->CompileAndLink())
1030     {
1031       VerifyGLState();
1032       if (!m_pVideoFilterShader->CompileAndLink())
1033       {
1034         CLog::Log(LOGERROR, "GL: Error compiling and linking video filter shader");
1035         m_pVideoFilterShader->Free();
1036         delete m_pVideoFilterShader;
1037         m_pVideoFilterShader = NULL;
1038       }
1039     }
1040     break;
1041
1042   case VS_SCALINGMETHOD_LANCZOS2:
1043   case VS_SCALINGMETHOD_LANCZOS3:
1044   case VS_SCALINGMETHOD_SINC8:
1045   case VS_SCALINGMETHOD_NEDI:
1046     CLog::Log(LOGERROR, "GL: TODO: This scaler has not yet been implemented");
1047     m_renderQuality = RQ_SINGLEPASS;
1048     break;
1049
1050   case VS_SCALINGMETHOD_BICUBIC_SOFTWARE:
1051   case VS_SCALINGMETHOD_LANCZOS_SOFTWARE:
1052   case VS_SCALINGMETHOD_SINC_SOFTWARE:
1053     InitializeSoftwareUpscaling();
1054     break;
1055   }
1056 }
1057
1058 void CLinuxRendererGL::LoadShaders(int renderMethod)
1059 {
1060   int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod");
1061   CLog::Log(LOGDEBUG, "GL: Requested render method: %d", requestedMethod);
1062   bool err = false;
1063
1064 #ifdef HAVE_LIBVDPAU
1065   if (g_VDPAU)
1066   {
1067     CLog::Log(LOGNOTICE, "GL: Using VDPAU render method");
1068     m_renderMethod = RENDER_VDPAU;
1069   }
1070   else 
1071 #endif //HAVE_LIBVDPAU
1072   /*
1073     Try GLSL shaders if they're supported and if the user has
1074     requested for it. (settings -> video -> player -> rendermethod)
1075    */
1076   if (glCreateProgram // TODO: proper check
1077       && (requestedMethod==RENDER_METHOD_AUTO || requestedMethod==RENDER_METHOD_GLSL
1078             || requestedMethod==RENDER_METHOD_VDPAU))
1079   {
1080     if (m_pYUVShader)
1081     {
1082       m_pYUVShader->Free();
1083       delete m_pYUVShader;
1084       m_pYUVShader = NULL;
1085     }
1086
1087     if (renderMethod & (FIELD_ODD|FIELD_EVEN))
1088     {
1089       if (m_renderQuality == RQ_SINGLEPASS)
1090       {
1091         // create regular progressive scan shader
1092         m_pYUVShader = new YUV2RGBProgressiveShader(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags);
1093         CLog::Log(LOGNOTICE, "GL: Selecting Single Pass YUV 2 RGB shader");
1094       }
1095       else if (m_renderQuality == RQ_MULTIPASS)
1096       {
1097         // create bob deinterlacing shader
1098         m_pYUVShader = new YUV2RGBBobShader(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags);
1099         CLog::Log(LOGNOTICE, "GL: Selecting Multipass Pass YUV 2 RGB shader");
1100       }
1101     }
1102     else
1103     {
1104       // create regular progressive scan shader
1105       m_pYUVShader = new YUV2RGBProgressiveShader(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags);
1106       CLog::Log(LOGNOTICE, "GL: Selecting YUV 2 RGB Progressive Shader");
1107     }
1108
1109     if (m_pYUVShader && m_pYUVShader->CompileAndLink())
1110     {
1111       m_renderMethod = RENDER_GLSL;
1112       UpdateVideoFilter();
1113     }
1114     else
1115     {
1116       m_pYUVShader->Free();
1117       delete m_pYUVShader;
1118       m_pYUVShader = NULL;
1119       err = true;
1120       CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB GLSL shader");
1121     }
1122   }
1123
1124   /*
1125     Try ARB shaders if the extension is supported AND either:
1126       1) user requested it
1127       2) or GLSL shaders failed and user selected AUTO
1128    */
1129   else if (glewIsSupported("GL_ARB_fragment_program")  
1130            && ((requestedMethod==RENDER_METHOD_AUTO || requestedMethod==RENDER_METHOD_ARB)
1131                || err))
1132   {
1133     err = false;
1134     CLog::Log(LOGNOTICE, "GL: ARB shaders support detected");
1135     m_renderMethod = RENDER_ARB ;
1136     if (m_pYUVShader)
1137     {
1138       m_pYUVShader->Free();
1139       delete m_pYUVShader;
1140       m_pYUVShader = NULL;
1141     }
1142
1143     // create regular progressive scan shader
1144     m_pYUVShader = new YUV2RGBProgressiveShaderARB(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags);
1145     CLog::Log(LOGNOTICE, "GL: Selecting Single Pass ARB YUV2RGB shader");
1146
1147     if (m_pYUVShader && m_pYUVShader->CompileAndLink())
1148     {
1149       m_renderMethod = RENDER_ARB;
1150       UpdateVideoFilter();
1151     }
1152     else
1153     {
1154       m_pYUVShader->Free();
1155       delete m_pYUVShader;
1156       m_pYUVShader = NULL;
1157       err = true;
1158       CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB ARB shader");
1159     }
1160   }
1161
1162   /*
1163     Fall back to software YUV 2 RGB conversion if
1164       1) user requested it
1165       2) or GLSL and/or ARB shaders failed
1166    */
1167   else
1168   {
1169     m_renderMethod = RENDER_SW ;
1170     CLog::Log(LOGNOTICE, "GL: Shaders support not present, falling back to SW mode");
1171   }
1172
1173   if (err==true)
1174   {
1175     CLog::Log(LOGERROR, "GL: Falling back to Software YUV2RGB");
1176     m_renderMethod = RENDER_SW;
1177   }
1178
1179   // determine whether GPU supports NPOT textures
1180   if (!glewIsSupported("GL_ARB_texture_non_power_of_two"))
1181   {
1182     if (!glewIsSupported("GL_ARB_texture_rectangle"))
1183     {
1184       CLog::Log(LOGNOTICE, "GL: GL_ARB_texture_rectangle not supported and OpenGL version is not 2.x");
1185       CLog::Log(LOGNOTICE, "GL: Reverting to POT textures");
1186       m_renderMethod |= RENDER_POT;
1187     }
1188     else
1189       CLog::Log(LOGNOTICE, "GL: NPOT textures are supported through GL_ARB_texture_rectangle extension");
1190   }
1191   else
1192     CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
1193 }
1194
1195 void CLinuxRendererGL::UnInit()
1196 {
1197   CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
1198   CSingleLock lock(g_graphicsContext);
1199
1200   if (m_rgbBuffer != NULL)
1201   {
1202     delete [] m_rgbBuffer;
1203     m_rgbBuffer = NULL;
1204   }
1205
1206 #ifdef HAVE_LIBVDPAU
1207   if (g_VDPAU)
1208     g_VDPAU->ReleasePixmap();
1209 #endif
1210   // YV12 textures
1211   for (int i = 0; i < NUM_BUFFERS; ++i)
1212     DeleteYV12Texture(i);
1213
1214   // cleanup framebuffer object if it was in use
1215   m_fbo.Cleanup();
1216   m_bValidated = false;
1217   m_bImageReady = false;
1218   m_bConfigured = false;
1219 }
1220
1221 void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
1222 {
1223   // obtain current field, if interlaced
1224   if( flags & RENDER_FLAG_ODD)
1225   {
1226     if (m_currentField == FIELD_FULL)
1227       m_reloadShaders = 1;
1228     m_currentField = FIELD_ODD;
1229   } // even field
1230   else if (flags & RENDER_FLAG_EVEN)
1231   {
1232     if (m_currentField == FIELD_FULL)
1233       m_reloadShaders = 1;
1234     m_currentField = FIELD_EVEN;
1235   }
1236   else if (flags & RENDER_FLAG_LAST)
1237   {
1238     switch(m_currentField)
1239     {
1240     case FIELD_ODD:
1241       flags = RENDER_FLAG_ODD;
1242       break;
1243
1244     case FIELD_EVEN:
1245       flags = RENDER_FLAG_EVEN;
1246       break;
1247     }
1248   }
1249   else
1250   {
1251     if (m_currentField != FIELD_FULL)
1252       m_reloadShaders = 1;
1253     m_currentField = FIELD_FULL;
1254   }
1255
1256   if (m_renderMethod & RENDER_GLSL)
1257   {
1258     UpdateVideoFilter();
1259     switch(m_renderQuality)
1260     {
1261     case RQ_LOW:
1262     case RQ_SINGLEPASS:
1263       RenderSinglePass(flags, renderBuffer);
1264       VerifyGLState();
1265       break;
1266
1267     case RQ_MULTIPASS:
1268       RenderMultiPass(flags, renderBuffer);
1269       VerifyGLState();
1270       break;
1271
1272     case RQ_SOFTWARE:
1273       RenderSoftware(flags, renderBuffer);
1274       VerifyGLState();
1275       break;
1276     }
1277   }
1278   else if (m_renderMethod & RENDER_ARB)
1279   {
1280     RenderSinglePass(flags, renderBuffer);
1281   }
1282 #ifdef HAVE_LIBVDPAU
1283   else if (m_renderMethod & RENDER_VDPAU)
1284   {
1285     RenderVDPAU(flags, renderBuffer);
1286   }
1287 #endif
1288   else
1289   {
1290     RenderSoftware(flags, renderBuffer);
1291     VerifyGLState();
1292   }
1293
1294   /* general stuff */
1295
1296   if( flags & RENDER_FLAG_NOOSD )
1297     return;
1298
1299   if (g_graphicsContext.IsFullScreenVideo() && !g_application.IsPaused())
1300   {
1301     if (g_application.NeedRenderFullScreen())
1302     { // render our subtitles and osd
1303       g_application.RenderFullScreen();
1304       VerifyGLState();
1305     }
1306     g_application.RenderMemoryStatus();
1307     VerifyGLState();
1308   }
1309 }
1310
1311 void CLinuxRendererGL::SetViewMode(int iViewMode)
1312 {
1313   if (iViewMode < VIEW_MODE_NORMAL || iViewMode > VIEW_MODE_CUSTOM) iViewMode = VIEW_MODE_NORMAL;
1314   g_stSettings.m_currentVideoSettings.m_ViewMode = iViewMode;
1315
1316   if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_NORMAL)
1317   { // normal mode...
1318     g_stSettings.m_fPixelRatio = 1.0;
1319     g_stSettings.m_fZoomAmount = 1.0;
1320     return ;
1321   }
1322   if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_CUSTOM)
1323   {
1324     g_stSettings.m_fZoomAmount = g_stSettings.m_currentVideoSettings.m_CustomZoomAmount;
1325     g_stSettings.m_fPixelRatio = g_stSettings.m_currentVideoSettings.m_CustomPixelRatio;
1326     return ;
1327   }
1328
1329   // get our calibrated full screen resolution
1330   //float fOffsetX1 = (float)g_settings.m_ResInfo[m_iResolution].Overscan.left;
1331   //float fOffsetY1 = (float)g_settings.m_ResInfo[m_iResolution].Overscan.top;
1332   float fScreenWidth = (float)(g_settings.m_ResInfo[m_iResolution].Overscan.right - g_settings.m_ResInfo[m_iResolution].Overscan.left);
1333   float fScreenHeight = (float)(g_settings.m_ResInfo[m_iResolution].Overscan.bottom - g_settings.m_ResInfo[m_iResolution].Overscan.top);
1334   // and the source frame ratio
1335   float fSourceFrameRatio = GetAspectRatio();
1336
1337   if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_ZOOM)
1338   { // zoom image so no black bars
1339     g_stSettings.m_fPixelRatio = 1.0;
1340     // calculate the desired output ratio
1341     float fOutputFrameRatio = fSourceFrameRatio * g_stSettings.m_fPixelRatio / g_settings.m_ResInfo[m_iResolution].fPixelRatio;
1342     // now calculate the correct zoom amount.  First zoom to full height.
1343     float fNewHeight = fScreenHeight;
1344     float fNewWidth = fNewHeight * fOutputFrameRatio;
1345     g_stSettings.m_fZoomAmount = fNewWidth / fScreenWidth;
1346     if (fNewWidth < fScreenWidth)
1347     { // zoom to full width
1348       fNewWidth = fScreenWidth;
1349       fNewHeight = fNewWidth / fOutputFrameRatio;
1350       g_stSettings.m_fZoomAmount = fNewHeight / fScreenHeight;
1351     }
1352   }
1353   else if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_STRETCH_4x3)
1354   { // stretch image to 4:3 ratio
1355     g_stSettings.m_fZoomAmount = 1.0;
1356     if (m_iResolution == PAL_4x3 || m_iResolution == PAL60_4x3 || m_iResolution == NTSC_4x3 || m_iResolution == HDTV_480p_4x3)
1357     { // stretch to the limits of the 4:3 screen.
1358       // incorrect behaviour, but it's what the users want, so...
1359       g_stSettings.m_fPixelRatio = (fScreenWidth / fScreenHeight) * g_settings.m_ResInfo[m_iResolution].fPixelRatio / fSourceFrameRatio;
1360     }
1361     else
1362     {
1363       // now we need to set g_stSettings.m_fPixelRatio so that
1364       // fOutputFrameRatio = 4:3.
1365       g_stSettings.m_fPixelRatio = (4.0f / 3.0f) / fSourceFrameRatio;
1366     }
1367   }
1368   else if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_STRETCH_14x9)
1369   { // stretch image to 14:9 ratio
1370     // now we need to set g_stSettings.m_fPixelRatio so that
1371     // fOutputFrameRatio = 14:9.
1372     g_stSettings.m_fPixelRatio = (14.0f / 9.0f) / fSourceFrameRatio;
1373     // calculate the desired output ratio
1374     float fOutputFrameRatio = fSourceFrameRatio * g_stSettings.m_fPixelRatio / g_settings.m_ResInfo[m_iResolution].fPixelRatio;
1375     // now calculate the correct zoom amount.  First zoom to full height.
1376     float fNewHeight = fScreenHeight;
1377     float fNewWidth = fNewHeight * fOutputFrameRatio;
1378     g_stSettings.m_fZoomAmount = fNewWidth / fScreenWidth;
1379     if (fNewWidth < fScreenWidth)
1380     { // zoom to full width
1381       fNewWidth = fScreenWidth;
1382       fNewHeight = fNewWidth / fOutputFrameRatio;
1383       g_stSettings.m_fZoomAmount = fNewHeight / fScreenHeight;
1384     }
1385   }
1386   else if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_STRETCH_16x9)
1387   { // stretch image to 16:9 ratio
1388     g_stSettings.m_fZoomAmount = 1.0;
1389     if (m_iResolution == PAL_4x3 || m_iResolution == PAL60_4x3 || m_iResolution == NTSC_4x3 || m_iResolution == HDTV_480p_4x3)
1390     { // now we need to set g_stSettings.m_fPixelRatio so that
1391       // fOutputFrameRatio = 16:9.
1392       g_stSettings.m_fPixelRatio = (16.0f / 9.0f) / fSourceFrameRatio;
1393     }
1394     else
1395     { // stretch to the limits of the 16:9 screen.
1396       // incorrect behaviour, but it's what the users want, so...
1397       g_stSettings.m_fPixelRatio = (fScreenWidth / fScreenHeight) * g_settings.m_ResInfo[m_iResolution].fPixelRatio / fSourceFrameRatio;
1398     }
1399   }
1400   else // if (g_stSettings.m_currentVideoSettings.m_ViewMode == VIEW_MODE_ORIGINAL)
1401   { // zoom image so that the height is the original size
1402     g_stSettings.m_fPixelRatio = 1.0;
1403     // get the size of the media file
1404     // calculate the desired output ratio
1405     float fOutputFrameRatio = fSourceFrameRatio * g_stSettings.m_fPixelRatio / g_settings.m_ResInfo[m_iResolution].fPixelRatio;
1406     // now calculate the correct zoom amount.  First zoom to full width.
1407     float fNewWidth = fScreenWidth;
1408     float fNewHeight = fNewWidth / fOutputFrameRatio;
1409     if (fNewHeight > fScreenHeight)
1410     { // zoom to full height
1411       fNewHeight = fScreenHeight;
1412       fNewWidth = fNewHeight * fOutputFrameRatio;
1413     }
1414     // now work out the zoom amount so that no zoom is done
1415     g_stSettings.m_fZoomAmount = (m_iSourceHeight - g_stSettings.m_currentVideoSettings.m_CropTop - g_stSettings.m_currentVideoSettings.m_CropBottom) / fNewHeight;
1416   }
1417 }
1418
1419 void CLinuxRendererGL::AutoCrop(bool bCrop)
1420 {
1421   if (!m_YUVTexture[0][FIELD_FULL][PLANE_Y].id) return ;
1422   // FIXME: no cropping for now
1423   { // reset to defaults
1424     g_stSettings.m_currentVideoSettings.m_CropLeft = 0;
1425     g_stSettings.m_currentVideoSettings.m_CropRight = 0;
1426     g_stSettings.m_currentVideoSettings.m_CropTop = 0;
1427     g_stSettings.m_currentVideoSettings.m_CropBottom = 0;
1428   }
1429   SetViewMode(g_stSettings.m_currentVideoSettings.m_ViewMode);
1430 }
1431
1432 void CLinuxRendererGL::RenderSinglePass(DWORD flags, int index)
1433 {
1434   int field = FIELD_FULL;
1435   DWORD fieldmask = (flags&RENDER_FLAG_FIELDMASK);
1436
1437   if (fieldmask)
1438   {
1439     if (fieldmask == RENDER_FLAG_BOTH)
1440       field = FIELD_FULL;
1441     else if (fieldmask == RENDER_FLAG_EVEN)
1442       field = FIELD_EVEN;
1443     else
1444       field = FIELD_ODD;
1445   }
1446
1447   YUVFIELDS &fields = m_YUVTexture[index];
1448   YUVPLANES &planes = fields[field];
1449
1450   // set scissors if we are not in fullscreen video
1451   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1452     g_graphicsContext.ClipToViewWindow();
1453
1454   glDisable(GL_DEPTH_TEST);
1455
1456   //See RGB renderer for comment on this
1457 #define CHROMAOFFSET_HORIZ 0.25f
1458
1459   // Y
1460   glActiveTextureARB(GL_TEXTURE0);
1461   glEnable(m_textureTarget);
1462   glBindTexture(m_textureTarget, planes[0].id);
1463
1464   // U
1465   glActiveTextureARB(GL_TEXTURE1);
1466   glEnable(m_textureTarget);
1467   glBindTexture(m_textureTarget, planes[1].id);
1468
1469   // V
1470   glActiveTextureARB(GL_TEXTURE2);
1471   glEnable(m_textureTarget);
1472   glBindTexture(m_textureTarget, planes[2].id);
1473
1474   glActiveTextureARB(GL_TEXTURE0);
1475   VerifyGLState();
1476
1477   if (m_reloadShaders)
1478   {
1479     m_reloadShaders = 0;
1480     LoadShaders(m_currentField);
1481
1482     if (m_currentField==FIELD_FULL)
1483       SetTextureFilter(GL_LINEAR);
1484     else
1485       SetTextureFilter(GL_LINEAR);
1486   }
1487
1488   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetYTexture(0);
1489   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetUTexture(1);
1490   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetVTexture(2);
1491   if(field == FIELD_ODD)
1492     ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetField(1);
1493   else if(field == FIELD_EVEN)
1494     ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetField(0);
1495
1496   m_pYUVShader->Enable();
1497
1498   glBegin(GL_QUADS);
1499
1500   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
1501   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y1);
1502   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y1);
1503   glVertex4f((float)rd.left, (float)rd.top, 0, 1.0f );
1504
1505   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y1);
1506   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y1);
1507   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y1);
1508   glVertex4f((float)rd.right, (float)rd.top, 0, 1.0f);
1509
1510   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y2);
1511   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y2);
1512   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y2);
1513   glVertex4f((float)rd.right, (float)rd.bottom, 0, 1.0f);
1514
1515   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y2);
1516   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y2);
1517   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y2);
1518   glVertex4f((float)rd.left, (float)rd.bottom, 0, 1.0f);
1519
1520   glEnd();
1521   VerifyGLState();
1522
1523   m_pYUVShader->Disable();
1524   VerifyGLState();
1525
1526   glActiveTextureARB(GL_TEXTURE1);
1527   glDisable(m_textureTarget);
1528
1529   glActiveTextureARB(GL_TEXTURE2);
1530   glDisable(m_textureTarget);
1531
1532   glActiveTextureARB(GL_TEXTURE0);
1533   glDisable(m_textureTarget);
1534
1535   glMatrixMode(GL_MODELVIEW);
1536
1537   VerifyGLState();
1538 }
1539
1540 void CLinuxRendererGL::RenderMultiPass(DWORD flags, int index)
1541 {
1542   YV12Image &im = m_image[index];
1543   YUVPLANES &planes = m_YUVTexture[index][m_currentField];
1544
1545   // set scissors if we are not in fullscreen video
1546   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1547     g_graphicsContext.ClipToViewWindow();
1548
1549   glDisable(GL_DEPTH_TEST);
1550   VerifyGLState();
1551
1552   //See RGB renderer for comment on this
1553 #define CHROMAOFFSET_HORIZ 0.25f
1554
1555   // Y
1556   glEnable(m_textureTarget);
1557   glActiveTextureARB(GL_TEXTURE0);
1558   glBindTexture(m_textureTarget, planes[0].id);
1559   VerifyGLState();
1560
1561   // U
1562   glActiveTextureARB(GL_TEXTURE1);
1563   glEnable(m_textureTarget);
1564   glBindTexture(m_textureTarget, planes[1].id);
1565   VerifyGLState();
1566
1567   // V
1568   glActiveTextureARB(GL_TEXTURE2);
1569   glEnable(m_textureTarget);
1570   glBindTexture(m_textureTarget, planes[2].id);
1571   VerifyGLState();
1572
1573   glActiveTextureARB(GL_TEXTURE0);
1574   VerifyGLState();
1575
1576   if (m_reloadShaders)
1577   {
1578     m_reloadShaders = 0;
1579     m_fbo.Cleanup();
1580     LoadShaders(m_currentField);
1581     VerifyGLState();
1582     SetTextureFilter(GL_LINEAR);
1583     VerifyGLState();
1584   }
1585
1586   // make sure the yuv shader is loaded and ready to go
1587   if (!m_pYUVShader || (!m_pYUVShader->OK()))
1588   {
1589     CLog::Log(LOGERROR, "GL: YUV shader not active, cannot do multipass render");
1590     return;
1591   }
1592
1593   int imgheight;
1594
1595   if(m_currentField == FIELD_FULL)
1596     imgheight = im.height;
1597   else
1598     imgheight = im.height/2;
1599
1600   // make sure FBO is valid and ready to go
1601   if (!m_fbo.IsValid())
1602   {
1603     m_fbo.Initialize();
1604     if (!m_fbo.CreateAndBindToTexture(GL_TEXTURE_2D, im.width, imgheight, GL_RGBA))
1605       CLog::Log(LOGERROR, "GL: Error creating texture and binding to FBO");
1606   }
1607
1608   m_fbo.BeginRender();
1609   VerifyGLState();
1610
1611   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetYTexture(0);
1612   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetUTexture(1);
1613   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetVTexture(2);
1614   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetWidth(im.width);
1615   ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetHeight(im.height);
1616   if     (m_currentField == FIELD_ODD)
1617     ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetField(1);
1618   else if(m_currentField == FIELD_EVEN)
1619     ((BaseYUV2RGBGLSLShader*)m_pYUVShader)->SetField(0);
1620
1621   VerifyGLState();
1622
1623   glPushAttrib(GL_VIEWPORT_BIT);
1624   glPushAttrib(GL_SCISSOR_BIT);
1625   glMatrixMode(GL_MODELVIEW);
1626   glPushMatrix();
1627   glLoadIdentity();
1628   VerifyGLState();
1629
1630   glMatrixMode(GL_PROJECTION);
1631   glPushMatrix();
1632   glLoadIdentity();
1633   VerifyGLState();
1634   gluOrtho2D(0, im.width, 0, imgheight);
1635   glViewport(0, 0, im.width, imgheight);
1636   glScissor(0, 0, im.width, imgheight);
1637   glMatrixMode(GL_MODELVIEW);
1638   VerifyGLState();
1639
1640
1641   if (!m_pYUVShader->Enable())
1642   {
1643     CLog::Log(LOGERROR, "GL: Error enabling YUV shader");
1644   }
1645
1646   // 1st Pass to video frame size
1647
1648   glBegin(GL_QUADS);
1649
1650   glMultiTexCoord2fARB(GL_TEXTURE0, 0              , 0);
1651   glMultiTexCoord2fARB(GL_TEXTURE1, 0              , 0);
1652   glMultiTexCoord2fARB(GL_TEXTURE2, 0              , 0);
1653   glVertex2f((float)0, (float)0);
1654
1655   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].width, 0);
1656   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].width, 0);
1657   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].width, 0);
1658   glVertex2f((float)im.width, (float)0);
1659
1660   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].width, planes[0].height);
1661   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].width, planes[1].height);
1662   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].width, planes[2].height);
1663   glVertex2f((float)im.width, (float)imgheight);
1664
1665   glMultiTexCoord2fARB(GL_TEXTURE0, 0              , planes[0].height);
1666   glMultiTexCoord2fARB(GL_TEXTURE1, 0              , planes[1].height);
1667   glMultiTexCoord2fARB(GL_TEXTURE2, 0              , planes[2].height);
1668   glVertex2f((float)0, (float)imgheight);
1669
1670   glEnd();
1671   VerifyGLState();
1672
1673   m_pYUVShader->Disable();
1674
1675   glMatrixMode(GL_MODELVIEW);
1676   glPopMatrix(); // pop modelview
1677   glMatrixMode(GL_PROJECTION);
1678   glPopMatrix(); // pop projection
1679   glPopAttrib(); // pop scissor
1680   glPopAttrib(); // pop viewport
1681   glMatrixMode(GL_MODELVIEW);
1682   VerifyGLState();
1683
1684   m_fbo.EndRender();
1685
1686   glActiveTextureARB(GL_TEXTURE1);
1687   glDisable(m_textureTarget);
1688   glActiveTextureARB(GL_TEXTURE2);
1689   glDisable(m_textureTarget);
1690   glActiveTextureARB(GL_TEXTURE0);
1691   glDisable(m_textureTarget);
1692
1693   glEnable(GL_TEXTURE_2D);
1694   glBindTexture(GL_TEXTURE_2D, m_fbo.Texture());
1695   VerifyGLState();
1696
1697   // Use regular normalized texture coordinates
1698
1699   // 2nd Pass to screen size with optional video filter
1700
1701   if (m_pVideoFilterShader)
1702   {
1703     m_fbo.SetFiltering(GL_TEXTURE_2D, GL_NEAREST);
1704     m_pVideoFilterShader->SetSourceTexture(0);
1705     m_pVideoFilterShader->SetWidth(im.width);
1706     m_pVideoFilterShader->SetHeight(imgheight);
1707     m_pVideoFilterShader->Enable();
1708   }
1709   else
1710     m_fbo.SetFiltering(GL_TEXTURE_2D, GL_LINEAR);
1711
1712   VerifyGLState();
1713
1714   // TODO - recalculate based source rectangle so crop works
1715   //        but to do so we need the source texture size of the framebuffer
1716
1717   glBegin(GL_QUADS);
1718
1719   glMultiTexCoord2fARB(GL_TEXTURE0, 0, 0);
1720   glVertex4f((float)rd.left, (float)rd.top, 0, 1.0f );
1721
1722   glMultiTexCoord2fARB(GL_TEXTURE0, 1, 0);
1723   glVertex4f((float)rd.right, (float)rd.top, 0, 1.0f);
1724
1725   glMultiTexCoord2fARB(GL_TEXTURE0, 1, 1);
1726   glVertex4f((float)rd.right, (float)rd.bottom, 0, 1.0f);
1727
1728   glMultiTexCoord2fARB(GL_TEXTURE0, 0, 1);
1729   glVertex4f((float)rd.left, (float)rd.bottom, 0, 1.0f);
1730
1731   glEnd();
1732
1733   VerifyGLState();
1734
1735   if (m_pVideoFilterShader)
1736     m_pVideoFilterShader->Disable();
1737
1738   VerifyGLState();
1739
1740   glDisable(m_textureTarget);
1741   VerifyGLState();
1742 }
1743
1744 void CLinuxRendererGL::RenderVDPAU(DWORD flags, int index)
1745 {
1746 #ifdef HAVE_LIBVDPAU
1747   if (!g_VDPAU)
1748   {
1749     CLog::Log(LOGERROR,"(VDPAU) m_Surface is NULL");
1750     return;
1751   }
1752
1753   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1754     g_graphicsContext.ClipToViewWindow();
1755
1756   glEnable(m_textureTarget);
1757
1758   glBindTexture(m_textureTarget, g_VDPAU->m_glPixmapTexture);
1759   g_VDPAU->BindPixmap();
1760
1761   glActiveTextureARB(GL_TEXTURE0);
1762
1763   // Try some clamping or wrapping
1764   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP);
1765   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP);
1766   glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1767   glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1768
1769   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1770   VerifyGLState();
1771
1772   glBegin(GL_QUADS);
1773   if (m_textureTarget==GL_TEXTURE_2D)
1774   {
1775     glTexCoord2f(0.0, 0.0);  glVertex2d((float)rd.left, (float)rd.top);
1776     glTexCoord2f(1.0, 0.0);  glVertex2d((float)rd.right, (float)rd.top);
1777     glTexCoord2f(1.0, 1.0);  glVertex2d((float)rd.right, (float)rd.bottom);
1778     glTexCoord2f(0.0, 1.0);  glVertex2d((float)rd.left, (float)rd.bottom);
1779   }
1780   else
1781   {
1782     glTexCoord2f((float)rs.left,  (float)rs.top);    glVertex4f((float)rd.left,  (float)rd.top,    0, 1.0f);
1783     glTexCoord2f((float)rs.right, (float)rs.top);    glVertex4f((float)rd.right, (float)rd.top,    0, 1.0f);
1784     glTexCoord2f((float)rs.right, (float)rs.bottom); glVertex4f((float)rd.right, (float)rd.bottom, 0, 1.0f);
1785     glTexCoord2f((float)rs.left,  (float)rs.bottom); glVertex4f((float)rd.left,  (float)rd.bottom, 0, 1.0f);
1786   }
1787   glEnd();
1788   VerifyGLState();
1789   if (m_StrictBinding)
1790   {
1791     glBindTexture(m_textureTarget, g_VDPAU->m_glPixmapTexture);
1792     g_VDPAU->ReleasePixmap();
1793   }
1794
1795   glBindTexture (m_textureTarget, 0);
1796   glDisable(m_textureTarget);
1797 #endif
1798 }
1799
1800
1801 void CLinuxRendererGL::RenderSoftware(DWORD flags, int index)
1802 {
1803   int field = FIELD_FULL;
1804   DWORD fieldmask = (flags&RENDER_FLAG_FIELDMASK);
1805
1806   if (fieldmask)
1807   {
1808     if (fieldmask == RENDER_FLAG_BOTH)
1809       field = FIELD_FULL;
1810     else if (fieldmask == RENDER_FLAG_EVEN)
1811       field = FIELD_EVEN;
1812     else
1813       field = FIELD_ODD;
1814   }
1815
1816   YUVPLANES &planes = m_YUVTexture[index][field];
1817
1818   // set scissors if we are not in fullscreen video
1819   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1820     g_graphicsContext.ClipToViewWindow();
1821
1822   glDisable(GL_DEPTH_TEST);
1823
1824   // Y
1825   glEnable(m_textureTarget);
1826   glActiveTextureARB(GL_TEXTURE0);
1827   glBindTexture(m_textureTarget, planes[0].id);
1828   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1829
1830   glBegin(GL_QUADS);
1831   glTexCoord2f(planes[0].rect.x1, planes[0].rect.y1);
1832   glVertex4f((float)rd.left, (float)rd.top, 0, 1.0f );
1833
1834   glTexCoord2f(planes[0].rect.x2, planes[0].rect.y1);
1835   glVertex4f((float)rd.right, (float)rd.top, 0, 1.0f);
1836
1837   glTexCoord2f(planes[0].rect.x2, planes[0].rect.y2);
1838   glVertex4f((float)rd.right, (float)rd.bottom, 0, 1.0f);
1839
1840   glTexCoord2f(planes[0].rect.x1, planes[0].rect.y2);
1841   glVertex4f((float)rd.left, (float)rd.bottom, 0, 1.0f);
1842
1843   glEnd();
1844
1845   VerifyGLState();
1846
1847   glDisable(m_textureTarget);
1848   VerifyGLState();
1849 }
1850
1851 void CLinuxRendererGL::CreateThumbnail(SDL_Surface* surface, unsigned int width, unsigned int height)
1852 {
1853   // get our screen rect
1854   const RECT& rv = g_graphicsContext.GetViewWindow();
1855
1856   // save current video rect
1857   RECT saveSize = rd;
1858
1859   // new video rect is thumbnail size
1860   rd.left = rd.top = 0;
1861   rd.right = width;
1862   rd.bottom = height;
1863
1864   // clear framebuffer and invert Y axis to get non-inverted image
1865   glClear(GL_COLOR_BUFFER_BIT);
1866   glMatrixMode(GL_MODELVIEW);
1867   glPushMatrix();
1868   glTranslatef(0, height, 0);
1869   glScalef(1.0, -1.0f, 1.0f);
1870   Render(RENDER_FLAG_NOOSD, m_iYV12RenderBuffer);
1871
1872   // read pixels
1873   glReadPixels(0, rv.bottom-height, width, height, GL_BGRA, GL_UNSIGNED_BYTE, surface->pixels);
1874
1875   // revert model view matrix
1876   glMatrixMode(GL_MODELVIEW);
1877   glPopMatrix();
1878
1879   // restore original video rect
1880   rd = saveSize;
1881 }
1882
1883 //********************************************************************************************************
1884 // YV12 Texture creation, deletion, copying + clearing
1885 //********************************************************************************************************
1886 void CLinuxRendererGL::DeleteYV12Texture(int index)
1887 {
1888   YV12Image &im = m_image[index];
1889   YUVFIELDS &fields = m_YUVTexture[index];
1890
1891   if( fields[FIELD_FULL][0].id == 0 ) return;
1892
1893   CLog::Log(LOGDEBUG, "Deleted YV12 texture %i", index);
1894   /* finish up all textures, and delete them */
1895   g_graphicsContext.BeginPaint();  //FIXME
1896   for(int f = 0;f<MAX_FIELDS;f++)
1897   {
1898     for(int p = 0;p<MAX_PLANES;p++)
1899     {
1900       if( fields[f][p].id )
1901       {
1902         if (glIsTexture(fields[f][p].id))
1903         {
1904           glDeleteTextures(1, &fields[f][p].id);
1905           CLog::Log(LOGDEBUG, "GL: Deleting texture field %d plane %d", f+1, p+1);
1906         }
1907         fields[f][p].id = 0;
1908       }
1909     }
1910   }
1911   g_graphicsContext.EndPaint();
1912
1913   for(int p = 0;p<MAX_PLANES;p++)
1914   {
1915     if (im.plane[p])
1916     {
1917       delete[] im.plane[p];
1918       im.plane[p] = NULL;
1919     }
1920   }
1921 }
1922
1923 void CLinuxRendererGL::ClearYV12Texture(int index)
1924 {
1925   //YV12Image &im = m_image[index];
1926
1927   //memset(im.plane[0], 0,   im.stride[0] * im.height);
1928   //memset(im.plane[1], 128, im.stride[1] * im.height>>im.cshift_y );
1929   //memset(im.plane[2], 128, im.stride[2] * im.height>>im.cshift_y );
1930   //SetEvent(m_eventTexturesDone[index]);
1931 }
1932
1933 bool CLinuxRendererGL::CreateYV12Texture(int index, bool clear)
1934 {
1935 /*
1936 #ifdef HAVE_LIBVDPAU
1937   if (m_renderMethod & RENDER_VDPAU)
1938   {
1939     SetEvent(m_eventTexturesDone[index]);
1940     return true;
1941   }
1942 #endif
1943 */
1944   // Remember if we're software upscaling.
1945   m_isSoftwareUpscaling = IsSoftwareUpscaling();
1946
1947   /* since we also want the field textures, pitch must be texture aligned */
1948   unsigned p;
1949
1950   YV12Image &im = m_image[index];
1951   YUVFIELDS &fields = m_YUVTexture[index];
1952
1953   if (clear)
1954   {
1955     DeleteYV12Texture(index);
1956
1957     im.height = m_iSourceHeight;
1958     im.width  = m_iSourceWidth;
1959     im.cshift_x = 1;
1960     im.cshift_y = 1;
1961
1962     im.stride[0] = im.width;
1963     im.stride[1] = im.width >> im.cshift_x;
1964     im.stride[2] = im.width >> im.cshift_x;
1965     im.plane[0] = new BYTE[im.stride[0] * im.height];
1966     im.plane[1] = new BYTE[im.stride[1] * ( im.height << im.cshift_y )];
1967     im.plane[2] = new BYTE[im.stride[2] * ( im.height << im.cshift_y )];
1968   }
1969
1970   glEnable(m_textureTarget);
1971   for(int f = 0;f<MAX_FIELDS;f++)
1972   {
1973     for(p = 0;p<MAX_PLANES;p++)
1974     {
1975       if (!glIsTexture(fields[f][p].id))
1976       {
1977         glGenTextures(1, &fields[f][p].id);
1978         VerifyGLState();
1979       }
1980     }
1981   }
1982
1983   // YUV
1984   for (int f = FIELD_FULL; f<=FIELD_EVEN ; f++)
1985   {
1986     int fieldshift = (f==FIELD_FULL) ? 0 : 1;
1987     YUVPLANES &planes = fields[f];
1988
1989     if(m_isSoftwareUpscaling)
1990     {
1991       planes[0].texwidth  = m_upscalingWidth;
1992       planes[0].texheight = m_upscalingHeight >> fieldshift;
1993     }
1994     else
1995     {
1996       planes[0].texwidth  = im.width;
1997       planes[0].texheight = im.height >> fieldshift;
1998     }
1999
2000     if (m_renderMethod & RENDER_SW)
2001     {
2002       planes[1].texwidth  = 0;
2003       planes[1].texheight = 0;
2004       planes[2].texwidth  = 0;
2005       planes[2].texheight = 0;
2006     }
2007     else
2008     {
2009       planes[1].texwidth  = planes[0].texwidth  >> im.cshift_x;
2010       planes[1].texheight = planes[0].texheight >> im.cshift_y;
2011       planes[2].texwidth  = planes[0].texwidth  >> im.cshift_x;
2012       planes[2].texheight = planes[0].texheight >> im.cshift_y;
2013     }
2014
2015     if(m_renderMethod & RENDER_POT)
2016     {
2017       for(int p = 0; p < 3; p++)
2018       {
2019         planes[p].texwidth  = NP2(planes[p].texwidth);
2020         planes[p].texheight = NP2(planes[p].texheight);
2021       }
2022     }
2023
2024     for(int p = 0; p < 3; p++)
2025     {
2026       YUVPLANE &plane = planes[p];
2027       if (plane.texwidth * plane.texheight == 0)
2028         continue;
2029
2030       glBindTexture(m_textureTarget, plane.id);
2031       if (m_renderMethod & RENDER_SW)
2032       {
2033         if(m_renderMethod & RENDER_POT)
2034           CLog::Log(LOGNOTICE, "GL: Creating RGB POT texture of size %d x %d",  plane.texwidth, plane.texheight);
2035         else
2036           CLog::Log(LOGDEBUG,  "GL: Creating RGB NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
2037
2038         glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2039       } 
2040       else
2041       {
2042         if(m_renderMethod & RENDER_POT)
2043           CLog::Log(LOGNOTICE, "GL: Creating YUV POT texture of size %d x %d",  plane.texwidth, plane.texheight);
2044         else
2045           CLog::Log(LOGDEBUG,  "GL: Creating YUV NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
2046
2047         glTexImage2D(m_textureTarget, 0, GL_LUMINANCE, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2048       }
2049
2050       glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2051       glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2052       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2053       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2054       VerifyGLState();
2055     }
2056   }
2057   glDisable(m_textureTarget);
2058   SetEvent(m_eventTexturesDone[index]);
2059   return true;
2060 }
2061
2062 void CLinuxRendererGL::SetTextureFilter(GLenum method)
2063 {
2064   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
2065   {
2066     YUVFIELDS &fields = m_YUVTexture[i];
2067
2068     for (int f = FIELD_FULL; f<=FIELD_EVEN ; f++)
2069     {
2070       glBindTexture(m_textureTarget, fields[f][0].id);
2071       glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2072       glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2073       VerifyGLState();
2074
2075       if (!(m_renderMethod & RENDER_SW))
2076       {
2077         glBindTexture(m_textureTarget, fields[f][1].id);
2078         glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2079         glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2080         VerifyGLState();
2081
2082         glBindTexture(m_textureTarget, fields[f][2].id);
2083         glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2084         glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2085         VerifyGLState();
2086       }
2087     }
2088   }
2089 }
2090
2091 bool CLinuxRendererGL::SupportsBrightness()
2092 {
2093   return glewIsSupported("GL_ARB_imaging") == GL_TRUE;
2094 }
2095
2096 bool CLinuxRendererGL::SupportsContrast()
2097 {
2098   return glewIsSupported("GL_ARB_imaging") == GL_TRUE;
2099 }
2100
2101 bool CLinuxRendererGL::SupportsGamma()
2102 {
2103   return false;
2104 }
2105
2106 bool CLinuxRendererGL::SupportsMultiPassRendering()
2107 {
2108   return glewIsSupported("GL_EXT_framebuffer_object") && glCreateProgram;
2109 }
2110
2111 #endif
2112
2113 #endif