DVDCodecs: Amlogic: Handle conditions in which amcodec should be opened during Open()
[vuplus_xbmc] / xbmc / cores / VideoRenderers / LinuxRendererGL.cpp
1 /*
2  *      Copyright (c) 2007 Frodo/jcmarshall/vulkanr/d4rk
3  *      Based on XBoxRenderer by Frodo/jcmarshall
4  *      Portions Copyright (c) by the authors of ffmpeg / xvid /mplayer
5  *      Copyright (C) 2007-2013 Team XBMC
6  *      http://xbmc.org
7  *
8  *  This Program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2, or (at your option)
11  *  any later version.
12  *
13  *  This Program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with XBMC; see the file COPYING.  If not, see
20  *  <http://www.gnu.org/licenses/>.
21  *
22  */
23 #include "system.h"
24 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
25   #include "config.h"
26 #endif
27
28 #ifdef HAS_GL
29 #include <locale.h>
30
31 #include "LinuxRendererGL.h"
32 #include "Application.h"
33 #include "settings/AdvancedSettings.h"
34 #include "settings/DisplaySettings.h"
35 #include "settings/MediaSettings.h"
36 #include "settings/Settings.h"
37 #include "VideoShaders/YUV2RGBShader.h"
38 #include "VideoShaders/VideoFilterShader.h"
39 #include "windowing/WindowingFactory.h"
40 #include "dialogs/GUIDialogKaiToast.h"
41 #include "guilib/Texture.h"
42 #include "guilib/LocalizeStrings.h"
43 #include "threads/SingleLock.h"
44 #include "DllSwScale.h"
45 #include "utils/log.h"
46 #include "utils/GLUtils.h"
47 #include "utils/StringUtils.h"
48 #include "RenderCapture.h"
49 #include "RenderFormats.h"
50 #include "cores/IPlayer.h"
51 #include "cores/dvdplayer/DVDCodecs/DVDCodecUtils.h"
52
53 #ifdef HAVE_LIBVDPAU
54 #include "cores/dvdplayer/DVDCodecs/Video/VDPAU.h"
55 #endif
56 #ifdef HAVE_LIBVA
57 #include <va/va.h>
58 #include <va/va_x11.h>
59 #include <va/va_glx.h>
60 #include "cores/dvdplayer/DVDCodecs/Video/VAAPI.h"
61
62 #define USE_VAAPI_GLX_BIND                                \
63     (VA_MAJOR_VERSION == 0 &&                             \
64      ((VA_MINOR_VERSION == 30 &&                          \
65        VA_MICRO_VERSION == 4 && VA_SDS_VERSION >= 5) ||   \
66       (VA_MINOR_VERSION == 31 &&                          \
67        VA_MICRO_VERSION == 0 && VA_SDS_VERSION < 5)))
68
69 #endif
70
71 #ifdef TARGET_DARWIN
72   #include "osx/CocoaInterface.h"
73   #include <CoreVideo/CoreVideo.h>
74   #include <OpenGL/CGLIOSurface.h>
75   #ifdef TARGET_DARWIN_OSX
76     #include "osx/DarwinUtils.h"
77   #endif
78 #endif
79
80 #ifdef HAS_GLX
81 #include <GL/glx.h>
82 #endif
83
84 //due to a bug on osx nvidia, using gltexsubimage2d with a pbo bound and a null pointer
85 //screws up the alpha, an offset fixes this, there might still be a problem if stride + PBO_OFFSET
86 //is a multiple of 128 and deinterlacing is on
87 #define PBO_OFFSET 16
88
89 using namespace Shaders;
90
91 static const GLubyte stipple_weave[] = {
92   0x00, 0x00, 0x00, 0x00,
93   0xFF, 0xFF, 0xFF, 0xFF,
94   0x00, 0x00, 0x00, 0x00,
95   0xFF, 0xFF, 0xFF, 0xFF,
96   0x00, 0x00, 0x00, 0x00,
97   0xFF, 0xFF, 0xFF, 0xFF,
98   0x00, 0x00, 0x00, 0x00,
99   0xFF, 0xFF, 0xFF, 0xFF,
100   0x00, 0x00, 0x00, 0x00,
101   0xFF, 0xFF, 0xFF, 0xFF,
102   0x00, 0x00, 0x00, 0x00,
103   0xFF, 0xFF, 0xFF, 0xFF,
104   0x00, 0x00, 0x00, 0x00,
105   0xFF, 0xFF, 0xFF, 0xFF,
106   0x00, 0x00, 0x00, 0x00,
107   0xFF, 0xFF, 0xFF, 0xFF,
108   0x00, 0x00, 0x00, 0x00,
109   0xFF, 0xFF, 0xFF, 0xFF,
110   0x00, 0x00, 0x00, 0x00,
111   0xFF, 0xFF, 0xFF, 0xFF,
112   0x00, 0x00, 0x00, 0x00,
113   0xFF, 0xFF, 0xFF, 0xFF,
114   0x00, 0x00, 0x00, 0x00,
115   0xFF, 0xFF, 0xFF, 0xFF,
116   0x00, 0x00, 0x00, 0x00,
117   0xFF, 0xFF, 0xFF, 0xFF,
118   0x00, 0x00, 0x00, 0x00,
119   0xFF, 0xFF, 0xFF, 0xFF,
120   0x00, 0x00, 0x00, 0x00,
121   0xFF, 0xFF, 0xFF, 0xFF,
122   0x00, 0x00, 0x00, 0x00,
123   0xFF, 0xFF, 0xFF, 0xFF,
124   0x00, 0x00, 0x00, 0x00,
125 };
126
127 CLinuxRendererGL::YUVBUFFER::YUVBUFFER()
128 #ifdef HAVE_LIBVA
129  : vaapi(*(new VAAPI::CHolder()))
130 #endif
131 {
132   memset(&fields, 0, sizeof(fields));
133   memset(&image , 0, sizeof(image));
134   memset(&pbo   , 0, sizeof(pbo));
135   flipindex = 0;
136 #ifdef HAVE_LIBVDPAU
137   vdpau = NULL;
138 #endif
139 #ifdef TARGET_DARWIN_OSX
140   cvBufferRef = NULL;
141 #endif
142 }
143
144 CLinuxRendererGL::YUVBUFFER::~YUVBUFFER()
145 {
146 #ifdef HAVE_LIBVA
147   delete &vaapi;
148 #endif
149 #ifdef TARGET_DARWIN_OSX
150   if (cvBufferRef)
151     CVBufferRelease(cvBufferRef);
152 #endif
153 }
154
155 CLinuxRendererGL::CLinuxRendererGL()
156 {
157   m_textureTarget = GL_TEXTURE_2D;
158
159   m_renderMethod = RENDER_GLSL;
160   m_renderQuality = RQ_SINGLEPASS;
161   m_iFlags = 0;
162   m_format = RENDER_FMT_NONE;
163
164   m_iYV12RenderBuffer = 0;
165   m_flipindex = 0;
166   m_currentField = FIELD_FULL;
167   m_reloadShaders = 0;
168   m_pYUVShader = NULL;
169   m_pVideoFilterShader = NULL;
170   m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
171   m_scalingMethodGui = (ESCALINGMETHOD)-1;
172
173   // default texture handlers to YUV
174   m_textureUpload = &CLinuxRendererGL::UploadYV12Texture;
175   m_textureCreate = &CLinuxRendererGL::CreateYV12Texture;
176   m_textureDelete = &CLinuxRendererGL::DeleteYV12Texture;
177
178   m_rgbBuffer = NULL;
179   m_rgbBufferSize = 0;
180   m_context = NULL;
181   m_rgbPbo = 0;
182   m_fbo.width = 0.0;
183   m_fbo.height = 0.0;
184   m_NumYV12Buffers = 0;
185   m_iLastRenderBuffer = 0;
186   m_bConfigured = false;
187   m_bValidated = false;
188   m_bImageReady = false;
189   m_clearColour = 0.0f;
190   m_pboSupported = false;
191   m_pboUsed = false;
192   m_nonLinStretch = false;
193   m_nonLinStretchGui = false;
194   m_pixelRatio = 0.0f;
195
196   m_dllSwScale = new DllSwScale;
197 }
198
199 CLinuxRendererGL::~CLinuxRendererGL()
200 {
201   UnInit();
202
203   if (m_rgbPbo)
204   {
205     glDeleteBuffersARB(1, &m_rgbPbo);
206     m_rgbPbo = 0;
207     m_rgbBuffer = NULL;
208   }
209   else
210   {
211     delete [] m_rgbBuffer;
212     m_rgbBuffer = NULL;
213   }
214
215   if (m_context)
216   {
217     m_dllSwScale->sws_freeContext(m_context);
218     m_context = NULL;
219   }
220
221   if (m_pYUVShader)
222   {
223     m_pYUVShader->Free();
224     delete m_pYUVShader;
225     m_pYUVShader = NULL;
226   }
227
228   delete m_dllSwScale;
229 }
230
231 bool CLinuxRendererGL::ValidateRenderer()
232 {
233   if (!m_bConfigured)
234     return false;
235
236   // if its first pass, just init textures and return
237   if (ValidateRenderTarget())
238     return false;
239
240   // this needs to be checked after texture validation
241   if (!m_bImageReady)
242     return false;
243
244   int index = m_iYV12RenderBuffer;
245   YUVBUFFER& buf =  m_buffers[index];
246
247   if (!buf.fields[FIELD_FULL][0].id)
248     return false;
249
250   if (buf.image.flags==0)
251     return false;
252
253   return true;
254 }
255
256 bool CLinuxRendererGL::ValidateRenderTarget()
257 {
258   if (!m_bValidated)
259   {
260     if ((m_format == RENDER_FMT_CVBREF) ||
261         (!glewIsSupported("GL_ARB_texture_non_power_of_two") && glewIsSupported("GL_ARB_texture_rectangle")))
262     {
263       CLog::Log(LOGNOTICE,"Using GL_TEXTURE_RECTANGLE_ARB");
264       m_textureTarget = GL_TEXTURE_RECTANGLE_ARB;
265     }
266     else
267       CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D");
268
269     // function pointer for texture might change in
270     // call to LoadShaders
271     glFinish();
272     for (int i = 0 ; i < NUM_BUFFERS ; i++)
273       (this->*m_textureDelete)(i);
274
275     // trigger update of video filters
276     m_scalingMethodGui = (ESCALINGMETHOD)-1;
277
278      // create the yuv textures
279     LoadShaders();
280
281     for (int i = 0 ; i < m_NumYV12Buffers ; i++)
282       (this->*m_textureCreate)(i);
283
284     m_bValidated = true;
285     return true;
286   }
287   return false;
288 }
289
290 bool CLinuxRendererGL::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation)
291 {
292   m_sourceWidth = width;
293   m_sourceHeight = height;
294   m_renderOrientation = orientation;
295   m_fps = fps;
296
297   // Save the flags.
298   m_iFlags = flags;
299   m_format = format;
300
301   // Calculate the input frame aspect ratio.
302   CalculateFrameAspectRatio(d_width, d_height);
303   ChooseBestResolution(fps);
304   SetViewMode(CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode);
305   ManageDisplay();
306
307   m_bConfigured = true;
308   m_bImageReady = false;
309   m_scalingMethodGui = (ESCALINGMETHOD)-1;
310
311   // Ensure that textures are recreated and rendering starts only after the 1st
312   // frame is loaded after every call to Configure().
313   m_bValidated = false;
314
315   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
316     m_buffers[i].image.flags = 0;
317
318   m_iLastRenderBuffer = -1;
319
320   m_nonLinStretch    = false;
321   m_nonLinStretchGui = false;
322   m_pixelRatio       = 1.0;
323
324   m_pboSupported = glewIsSupported("GL_ARB_pixel_buffer_object") && CSettings::Get().GetBool("videoplayer.usepbo");
325
326 #ifdef TARGET_DARWIN_OSX
327   // on osx 10.9 mavericks we get a strange ripple
328   // effect when rendering with pbo
329   // when used on intel gpu - we have to quirk it here
330   if (DarwinIsMavericks())
331   {
332     std::string rendervendor = g_Windowing.GetRenderVendor();
333     StringUtils::ToLower(rendervendor);
334     if (rendervendor.find("intel") != std::string::npos)
335       m_pboSupported = false;
336   }
337 #endif
338
339   return true;
340 }
341
342 int CLinuxRendererGL::NextYV12Texture()
343 {
344   return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
345 }
346
347 int CLinuxRendererGL::GetImage(YV12Image *image, int source, bool readonly)
348 {
349   if (!image) return -1;
350   if (!m_bValidated) return -1;
351
352   /* take next available buffer */
353   if( source == AUTOSOURCE )
354     source = NextYV12Texture();
355
356   YV12Image &im = m_buffers[source].image;
357
358   if ((im.flags&(~IMAGE_FLAG_READY)) != 0)
359   {
360      CLog::Log(LOGDEBUG, "CLinuxRenderer::GetImage - request image but none to give");
361      return -1;
362   }
363
364   if( readonly )
365     im.flags |= IMAGE_FLAG_READING;
366   else
367     im.flags |= IMAGE_FLAG_WRITING;
368
369   // copy the image - should be operator of YV12Image
370   for (int p=0;p<MAX_PLANES;p++)
371   {
372     image->plane[p]  = im.plane[p];
373     image->stride[p] = im.stride[p];
374   }
375   image->width    = im.width;
376   image->height   = im.height;
377   image->flags    = im.flags;
378   image->cshift_x = im.cshift_x;
379   image->cshift_y = im.cshift_y;
380   image->bpp      = im.bpp;
381
382   return source;
383 }
384
385 void CLinuxRendererGL::ReleaseImage(int source, bool preserve)
386 {
387   YV12Image &im = m_buffers[source].image;
388
389   im.flags &= ~IMAGE_FLAG_INUSE;
390   im.flags |= IMAGE_FLAG_READY;
391   /* if image should be preserved reserve it so it's not auto seleceted */
392
393   if( preserve )
394     im.flags |= IMAGE_FLAG_RESERVED;
395
396   m_bImageReady = true;
397 }
398
399 void CLinuxRendererGL::GetPlaneTextureSize(YUVPLANE& plane)
400 {
401   /* texture is assumed to be bound */
402   GLint width  = 0
403       , height = 0
404       , border = 0;
405   glGetTexLevelParameteriv(m_textureTarget, 0, GL_TEXTURE_WIDTH , &width);
406   glGetTexLevelParameteriv(m_textureTarget, 0, GL_TEXTURE_HEIGHT, &height);
407   glGetTexLevelParameteriv(m_textureTarget, 0, GL_TEXTURE_BORDER, &border);
408   plane.texwidth  = width  - 2 * border;
409   plane.texheight = height - 2 * border;
410   if(plane.texwidth <= 0 || plane.texheight <= 0)
411   {
412     CLog::Log(LOGDEBUG, "CLinuxRendererGL::GetPlaneTextureSize - invalid size %dx%d - %d", width, height, border);
413     /* to something that avoid division by zero */
414     plane.texwidth  = 1;
415     plane.texheight = 1;
416   }
417
418 }
419
420 void CLinuxRendererGL::CalculateTextureSourceRects(int source, int num_planes)
421 {
422   YUVBUFFER& buf    =  m_buffers[source];
423   YV12Image* im     = &buf.image;
424   YUVFIELDS& fields =  buf.fields;
425
426   // calculate the source rectangle
427   for(int field = 0; field < 3; field++)
428   {
429     for(int plane = 0; plane < num_planes; plane++)
430     {
431       YUVPLANE& p = fields[field][plane];
432
433       p.rect = m_sourceRect;
434       p.width  = im->width;
435       p.height = im->height;
436
437       if(field != FIELD_FULL)
438       {
439         /* correct for field offsets and chroma offsets */
440         float offset_y = 0.5;
441         if(plane != 0)
442           offset_y += 0.5;
443         if(field == FIELD_BOT)
444           offset_y *= -1;
445
446         p.rect.y1 += offset_y;
447         p.rect.y2 += offset_y;
448
449         /* half the height if this is a field */
450         p.height  *= 0.5f;
451         p.rect.y1 *= 0.5f;
452         p.rect.y2 *= 0.5f;
453       }
454
455       if(plane != 0)
456       {
457         p.width   /= 1 << im->cshift_x;
458         p.height  /= 1 << im->cshift_y;
459
460         p.rect.x1 /= 1 << im->cshift_x;
461         p.rect.x2 /= 1 << im->cshift_x;
462         p.rect.y1 /= 1 << im->cshift_y;
463         p.rect.y2 /= 1 << im->cshift_y;
464       }
465
466       // protect against division by zero
467       if (p.texheight == 0 || p.texwidth == 0 ||
468           p.pixpertex_x == 0 || p.pixpertex_y == 0)
469       {
470         continue;
471       }
472
473       p.height  /= p.pixpertex_y;
474       p.rect.y1 /= p.pixpertex_y;
475       p.rect.y2 /= p.pixpertex_y;
476       p.width   /= p.pixpertex_x;
477       p.rect.x1 /= p.pixpertex_x;
478       p.rect.x2 /= p.pixpertex_x;
479
480       if (m_textureTarget == GL_TEXTURE_2D)
481       {
482         p.height  /= p.texheight;
483         p.rect.y1 /= p.texheight;
484         p.rect.y2 /= p.texheight;
485         p.width   /= p.texwidth;
486         p.rect.x1 /= p.texwidth;
487         p.rect.x2 /= p.texwidth;
488       }
489     }
490   }
491 }
492
493 void CLinuxRendererGL::LoadPlane( YUVPLANE& plane, int type, unsigned flipindex
494                                 , unsigned width, unsigned height
495                                 , int stride, int bpp, void* data, GLuint* pbo/*= NULL*/)
496 {
497   if(plane.flipindex == flipindex)
498     return;
499
500   //if no pbo given, use the plane pbo
501   GLuint currPbo;
502   if (pbo)
503     currPbo = *pbo;
504   else
505     currPbo = plane.pbo;
506
507   if(currPbo)
508     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, currPbo);
509
510   int bps = bpp * glFormatElementByteCount(type);
511
512   unsigned datatype;
513   if(bpp == 2)
514     datatype = GL_UNSIGNED_SHORT;
515   else
516     datatype = GL_UNSIGNED_BYTE;
517
518   glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / bps);
519   glBindTexture(m_textureTarget, plane.id);
520   glTexSubImage2D(m_textureTarget, 0, 0, 0, width, height, type, datatype, data);
521
522   /* check if we need to load any border pixels */
523   if(height < plane.texheight)
524     glTexSubImage2D( m_textureTarget, 0
525                    , 0, height, width, 1
526                    , type, datatype
527                    , (unsigned char*)data + stride * (height-1));
528
529   if(width  < plane.texwidth)
530     glTexSubImage2D( m_textureTarget, 0
531                    , width, 0, 1, height
532                    , type, datatype
533                    , (unsigned char*)data + bps * (width-1));
534
535   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
536   glBindTexture(m_textureTarget, 0);
537   if(currPbo)
538     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
539
540   plane.flipindex = flipindex;
541 }
542
543 void CLinuxRendererGL::Reset()
544 {
545   for(int i=0; i<m_NumYV12Buffers; i++)
546   {
547     /* reset all image flags, this will cleanup textures later */
548     m_buffers[i].image.flags = 0;
549   }
550 }
551
552 void CLinuxRendererGL::Flush()
553 {
554   if (!m_bValidated)
555     return;
556
557   glFinish();
558
559   for (int i = 0 ; i < m_NumYV12Buffers ; i++)
560     (this->*m_textureDelete)(i);
561
562   glFinish();
563   m_bValidated = false;
564   m_fbo.fbo.Cleanup();
565   m_iYV12RenderBuffer = 0;
566 }
567
568 void CLinuxRendererGL::ReleaseBuffer(int idx)
569 {
570 #if defined(HAVE_LIBVDPAU) || defined(HAVE_LIBVA) || defined(TARGET_DARWIN)
571   YUVBUFFER &buf = m_buffers[idx];
572 #endif
573 #ifdef HAVE_LIBVDPAU
574   SAFE_RELEASE(buf.vdpau);
575 #endif
576 #ifdef HAVE_LIBVA
577   buf.vaapi.surface.reset();
578 #endif
579 #ifdef TARGET_DARWIN
580   if (buf.cvBufferRef)
581     CVBufferRelease(buf.cvBufferRef);
582   buf.cvBufferRef = NULL;
583 #endif
584 }
585
586 void CLinuxRendererGL::Update()
587 {
588   if (!m_bConfigured) return;
589   ManageDisplay();
590   m_scalingMethodGui = (ESCALINGMETHOD)-1;
591 }
592
593 void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
594 {
595   int index = m_iYV12RenderBuffer;
596
597   if (!ValidateRenderer())
598   {
599     if (clear) //if clear is set, we're expected to overwrite all backbuffer pixels, even if we have nothing to render
600       ClearBackBuffer();
601
602     return;
603   }
604
605   ManageDisplay();
606
607   g_graphicsContext.BeginPaint();
608
609   if (clear)
610   {
611     //draw black bars when video is not transparent, clear the entire backbuffer when it is
612     if (alpha == 255)
613       DrawBlackBars();
614     else
615       ClearBackBuffer();
616   }
617
618   if (alpha<255)
619   {
620     glEnable(GL_BLEND);
621     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
622     glColor4f(1.0f, 1.0f, 1.0f, alpha / 255.0f);
623   }
624   else
625   {
626     glDisable(GL_BLEND);
627     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
628   }
629
630   if(flags & RENDER_FLAG_WEAVE)
631   {
632     int top_index = index;
633     int bot_index = index;
634
635     if((flags & RENDER_FLAG_FIELD0) && m_iLastRenderBuffer > -1)
636     {
637       if(flags & RENDER_FLAG_TOP)
638         bot_index = m_iLastRenderBuffer;
639       else
640         top_index = m_iLastRenderBuffer;
641     }
642
643     glEnable(GL_POLYGON_STIPPLE);
644     glPolygonStipple(stipple_weave);
645     Render((flags & ~RENDER_FLAG_FIELDMASK) | RENDER_FLAG_TOP, top_index);
646     glPolygonStipple(stipple_weave+4);
647     Render((flags & ~RENDER_FLAG_FIELDMASK) | RENDER_FLAG_BOT, bot_index);
648     glDisable(GL_POLYGON_STIPPLE);
649
650   }
651   else
652     Render(flags, index);
653
654   VerifyGLState();
655   glEnable(GL_BLEND);
656   glFlush();
657
658   g_graphicsContext.EndPaint();
659 }
660
661 void CLinuxRendererGL::ClearBackBuffer()
662 {
663   //set the entire backbuffer to black
664   glClearColor(m_clearColour, m_clearColour, m_clearColour, 0);
665   glClear(GL_COLOR_BUFFER_BIT);
666   glClearColor(0,0,0,0);
667 }
668
669 //draw black bars around the video quad, this is more efficient than glClear()
670 //since it only sets pixels to black that aren't going to be overwritten by the video
671 void CLinuxRendererGL::DrawBlackBars()
672 {
673   glColor4f(m_clearColour, m_clearColour, m_clearColour, 1.0f);
674   glDisable(GL_BLEND);
675   glBegin(GL_QUADS);
676
677   //top quad
678   if (m_rotatedDestCoords[0].y > 0.0)
679   {
680     glVertex4f(0.0,                          0.0,                      0.0, 1.0);
681     glVertex4f(g_graphicsContext.GetWidth(), 0.0,                      0.0, 1.0);
682     glVertex4f(g_graphicsContext.GetWidth(), m_rotatedDestCoords[0].y, 0.0, 1.0);
683     glVertex4f(0.0,                          m_rotatedDestCoords[0].y, 0.0, 1.0);
684   }
685
686   //bottom quad
687   if (m_rotatedDestCoords[2].y < g_graphicsContext.GetHeight())
688   {
689     glVertex4f(0.0,                          m_rotatedDestCoords[2].y,      0.0, 1.0);
690     glVertex4f(g_graphicsContext.GetWidth(), m_rotatedDestCoords[2].y,      0.0, 1.0);
691     glVertex4f(g_graphicsContext.GetWidth(), g_graphicsContext.GetHeight(), 0.0, 1.0);
692     glVertex4f(0.0,                          g_graphicsContext.GetHeight(), 0.0, 1.0);
693   }
694
695   //left quad
696   if (m_rotatedDestCoords[0].x > 0.0)
697   {
698     glVertex4f(0.0,                      m_rotatedDestCoords[0].y, 0.0, 1.0);
699     glVertex4f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y, 0.0, 1.0);
700     glVertex4f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[2].y, 0.0, 1.0);
701     glVertex4f(0.0,                      m_rotatedDestCoords[2].y, 0.0, 1.0);
702   }
703
704   //right quad
705   if (m_rotatedDestCoords[2].x < g_graphicsContext.GetWidth())
706   {
707     glVertex4f(m_rotatedDestCoords[2].x,     m_rotatedDestCoords[0].y, 0.0, 1.0);
708     glVertex4f(g_graphicsContext.GetWidth(), m_rotatedDestCoords[0].y, 0.0, 1.0);
709     glVertex4f(g_graphicsContext.GetWidth(), m_rotatedDestCoords[2].y, 0.0, 1.0);
710     glVertex4f(m_rotatedDestCoords[2].x,     m_rotatedDestCoords[2].y, 0.0, 1.0);
711   }
712
713   glEnd();
714 }
715
716 void CLinuxRendererGL::FlipPage(int source)
717 {
718   UnBindPbo(m_buffers[m_iYV12RenderBuffer]);
719
720   m_iLastRenderBuffer = m_iYV12RenderBuffer;
721
722   if( source >= 0 && source < m_NumYV12Buffers )
723     m_iYV12RenderBuffer = source;
724   else
725     m_iYV12RenderBuffer = NextYV12Texture();
726
727   BindPbo(m_buffers[m_iYV12RenderBuffer]);
728
729   m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
730
731   return;
732 }
733
734 unsigned int CLinuxRendererGL::PreInit()
735 {
736   CSingleLock lock(g_graphicsContext);
737   m_bConfigured = false;
738   m_bValidated = false;
739   UnInit();
740   m_resolution = CDisplaySettings::Get().GetCurrentResolution();
741   if ( m_resolution == RES_WINDOW )
742     m_resolution = RES_DESKTOP;
743
744   m_iYV12RenderBuffer = 0;
745
746   m_formats.clear();
747   m_formats.push_back(RENDER_FMT_YUV420P);
748   GLint size;
749   glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_LUMINANCE16, NP2(1920), NP2(1080), 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
750   glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
751 #ifdef TARGET_DARWIN_OSX
752   /* From VLC commit 701d1347faa29f52b0a04c587724deb6de1ae28e
753    * OpenGL 1.x on OS X does _not_ support 16bit shaders, but pretends to.
754    * That's why we enforce return false here, even though the actual code below
755    * would return true.
756    * This fixes playback of 10bit content on the Intel GMA 950 chipset, which is
757    * the only "GPU" supported by 10.6 and 10.7 with just an OpenGL 1.4 driver.
758    *
759    * Presumely, this also improves playback on the GMA 3100, GeForce FX 5200,
760    * GeForce4 Ti, GeForce3, GeForce2 MX/4 MX and the Radeon 8500 when
761    * running OS X 10.5. */
762   unsigned int maj, min;
763   g_Windowing.GetRenderVersion(maj, min);
764   if (maj < 2)
765     size = 8;
766 #endif
767   if(size >= 16)
768   {
769     m_formats.push_back(RENDER_FMT_YUV420P10);
770     m_formats.push_back(RENDER_FMT_YUV420P16);
771   }
772   CLog::Log(LOGDEBUG, "CLinuxRendererGL::PreInit - precision of luminance 16 is %d", size);
773   m_formats.push_back(RENDER_FMT_NV12);
774   m_formats.push_back(RENDER_FMT_YUYV422);
775   m_formats.push_back(RENDER_FMT_UYVY422);
776 #ifdef TARGET_DARWIN
777   m_formats.push_back(RENDER_FMT_CVBREF);
778 #endif
779
780   // setup the background colour
781   m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
782
783   if (!m_dllSwScale->Load())
784     CLog::Log(LOGERROR,"CLinuxRendererGL::PreInit - failed to load rescale libraries!");
785
786   return true;
787 }
788
789 void CLinuxRendererGL::UpdateVideoFilter()
790 {
791   bool pixelRatioChanged    = (CDisplaySettings::Get().GetPixelRatio() > 1.001f || CDisplaySettings::Get().GetPixelRatio() < 0.999f) !=
792                               (m_pixelRatio > 1.001f || m_pixelRatio < 0.999f);
793   bool nonLinStretchChanged = false;
794   if (m_nonLinStretchGui != CDisplaySettings::Get().IsNonLinearStretched() || pixelRatioChanged)
795   {
796     m_nonLinStretchGui   = CDisplaySettings::Get().IsNonLinearStretched();
797     m_pixelRatio         = CDisplaySettings::Get().GetPixelRatio();
798     m_reloadShaders      = 1;
799     nonLinStretchChanged = true;
800
801     if (m_nonLinStretchGui && (m_pixelRatio < 0.999f || m_pixelRatio > 1.001f) && Supports(RENDERFEATURE_NONLINSTRETCH))
802     {
803       m_nonLinStretch = true;
804       CLog::Log(LOGDEBUG, "GL: Enabling non-linear stretch");
805     }
806     else
807     {
808       m_nonLinStretch = false;
809       CLog::Log(LOGDEBUG, "GL: Disabling non-linear stretch");
810     }
811   }
812
813   if (m_scalingMethodGui == CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod && !nonLinStretchChanged)
814     return;
815
816   //recompile YUV shader when non-linear stretch is turned on/off
817   //or when it's on and the scaling method changed
818   if (m_nonLinStretch || nonLinStretchChanged)
819     m_reloadShaders = 1;
820
821   m_scalingMethodGui = CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod;
822   m_scalingMethod    = m_scalingMethodGui;
823
824   if(!Supports(m_scalingMethod))
825   {
826     CLog::Log(LOGWARNING, "CLinuxRendererGL::UpdateVideoFilter - choosen scaling method %d, is not supported by renderer", (int)m_scalingMethod);
827     m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
828   }
829
830   if (m_pVideoFilterShader)
831   {
832     m_pVideoFilterShader->Free();
833     delete m_pVideoFilterShader;
834     m_pVideoFilterShader = NULL;
835   }
836   m_fbo.fbo.Cleanup();
837
838   VerifyGLState();
839
840   if (m_scalingMethod == VS_SCALINGMETHOD_AUTO)
841   {
842     bool scaleSD = m_sourceHeight < 720 && m_sourceWidth < 1280;
843     bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() && (int)m_sourceWidth < g_graphicsContext.GetWidth();
844     bool scaleFps = m_fps < g_advancedSettings.m_videoAutoScaleMaxFps + 0.01f;
845
846     if (Supports(VS_SCALINGMETHOD_LANCZOS3_FAST) && scaleSD && scaleUp && scaleFps)
847       m_scalingMethod = VS_SCALINGMETHOD_LANCZOS3_FAST;
848     else
849       m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
850   }
851
852   switch (m_scalingMethod)
853   {
854   case VS_SCALINGMETHOD_NEAREST:
855   case VS_SCALINGMETHOD_LINEAR:
856     SetTextureFilter(m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR);
857     m_renderQuality = RQ_SINGLEPASS;
858     if (((m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI)) && m_nonLinStretch)
859     {
860       m_pVideoFilterShader = new StretchFilterShader();
861       if (!m_pVideoFilterShader->CompileAndLink())
862       {
863         CLog::Log(LOGERROR, "GL: Error compiling and linking video filter shader");
864         break;
865       }
866     }
867     else
868     {
869       m_pVideoFilterShader = new DefaultFilterShader();
870       if (!m_pVideoFilterShader->CompileAndLink())
871       {
872         CLog::Log(LOGERROR, "GL: Error compiling and linking video filter shader");
873         break;
874       }
875     }
876     return;
877
878   case VS_SCALINGMETHOD_LANCZOS2:
879   case VS_SCALINGMETHOD_SPLINE36_FAST:
880   case VS_SCALINGMETHOD_LANCZOS3_FAST:
881   case VS_SCALINGMETHOD_SPLINE36:
882   case VS_SCALINGMETHOD_LANCZOS3:
883   case VS_SCALINGMETHOD_CUBIC:
884     if (m_renderMethod & RENDER_GLSL)
885     {
886       if (!m_fbo.fbo.Initialize())
887       {
888         CLog::Log(LOGERROR, "GL: Error initializing FBO");
889         break;
890       }
891
892       if (!m_fbo.fbo.CreateAndBindToTexture(GL_TEXTURE_2D, m_sourceWidth, m_sourceHeight, GL_RGBA))
893       {
894         CLog::Log(LOGERROR, "GL: Error creating texture and binding to FBO");
895         break;
896       }
897     }
898
899     m_pVideoFilterShader = new ConvolutionFilterShader(m_scalingMethod, m_nonLinStretch);
900     if (!m_pVideoFilterShader->CompileAndLink())
901     {
902       CLog::Log(LOGERROR, "GL: Error compiling and linking video filter shader");
903       break;
904     }
905
906     SetTextureFilter(GL_LINEAR);
907     m_renderQuality = RQ_MULTIPASS;
908     return;
909
910   case VS_SCALINGMETHOD_BICUBIC_SOFTWARE:
911   case VS_SCALINGMETHOD_LANCZOS_SOFTWARE:
912   case VS_SCALINGMETHOD_SINC_SOFTWARE:
913   case VS_SCALINGMETHOD_SINC8:
914   case VS_SCALINGMETHOD_NEDI:
915     CLog::Log(LOGERROR, "GL: TODO: This scaler has not yet been implemented");
916     break;
917
918   default:
919     break;
920   }
921
922   CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(34400), g_localizeStrings.Get(34401));
923   CLog::Log(LOGERROR, "GL: Falling back to bilinear due to failure to init scaler");
924   if (m_pVideoFilterShader)
925   {
926     m_pVideoFilterShader->Free();
927     delete m_pVideoFilterShader;
928     m_pVideoFilterShader = NULL;
929   }
930   m_fbo.fbo.Cleanup();
931
932   SetTextureFilter(GL_LINEAR);
933   m_renderQuality = RQ_SINGLEPASS;
934 }
935
936 void CLinuxRendererGL::LoadShaders(int field)
937 {
938   if (m_format == RENDER_FMT_VDPAU)
939   {
940     CLog::Log(LOGNOTICE, "GL: Using VDPAU render method");
941     m_renderMethod = RENDER_VDPAU;
942   }
943   else if (m_format == RENDER_FMT_VAAPI)
944   {
945     CLog::Log(LOGNOTICE, "GL: Using VAAPI render method");
946     m_renderMethod = RENDER_VAAPI;
947   }
948   else if (m_format == RENDER_FMT_CVBREF)
949   {
950     CLog::Log(LOGNOTICE, "GL: Using CVBREF render method");
951     m_renderMethod = RENDER_CVREF;
952   }
953   else
954   {
955     int requestedMethod = CSettings::Get().GetInt("videoplayer.rendermethod");
956     CLog::Log(LOGDEBUG, "GL: Requested render method: %d", requestedMethod);
957
958     if (m_pYUVShader)
959     {
960       m_pYUVShader->Free();
961       delete m_pYUVShader;
962       m_pYUVShader = NULL;
963     }
964
965     bool tryGlsl = true;
966     switch(requestedMethod)
967     {
968       case RENDER_METHOD_AUTO:
969 #if defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
970        //with render method set to auto, don't try glsl on ati if we're on linux
971        //it seems to be broken in a random way with every new driver release
972        tryGlsl = !StringUtils::StartsWithNoCase(g_Windowing.GetRenderVendor(), "ati");
973 #endif
974       
975       case RENDER_METHOD_GLSL:
976       // Try GLSL shaders if supported and user requested auto or GLSL.
977       if (glCreateProgram && tryGlsl)
978       {
979         // create regular progressive scan shader
980         m_pYUVShader = new YUV2RGBProgressiveShader(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags, m_format,
981                                                     m_nonLinStretch && m_renderQuality == RQ_SINGLEPASS);
982
983         CLog::Log(LOGNOTICE, "GL: Selecting Single Pass YUV 2 RGB shader");
984
985         if (m_pYUVShader && m_pYUVShader->CompileAndLink())
986         {
987           m_renderMethod = RENDER_GLSL;
988           UpdateVideoFilter();
989           break;
990         }
991         else if (m_pYUVShader)
992         {
993           m_pYUVShader->Free();
994           delete m_pYUVShader;
995           m_pYUVShader = NULL;
996         }
997         CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB GLSL shader");
998         // drop through and try ARB
999       }
1000       case RENDER_METHOD_ARB:
1001       // Try ARB shaders if supported and user requested it or GLSL shaders failed.
1002       if (glewIsSupported("GL_ARB_fragment_program"))
1003       {
1004         CLog::Log(LOGNOTICE, "GL: ARB shaders support detected");
1005         m_renderMethod = RENDER_ARB ;
1006
1007         // create regular progressive scan shader
1008         m_pYUVShader = new YUV2RGBProgressiveShaderARB(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags, m_format);
1009         CLog::Log(LOGNOTICE, "GL: Selecting Single Pass ARB YUV2RGB shader");
1010
1011         if (m_pYUVShader && m_pYUVShader->CompileAndLink())
1012         {
1013           m_renderMethod = RENDER_ARB;
1014           UpdateVideoFilter();
1015           break;
1016         }
1017         else if (m_pYUVShader)
1018         {
1019           m_pYUVShader->Free();
1020           delete m_pYUVShader;
1021           m_pYUVShader = NULL;
1022         }
1023         CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB ARB shader");
1024         // drop through and use SW
1025       }
1026       case RENDER_METHOD_SOFTWARE:
1027       default:
1028       // Use software YUV 2 RGB conversion if user requested it or GLSL and/or ARB shaders failed
1029       {
1030         m_renderMethod = RENDER_SW ;
1031         CLog::Log(LOGNOTICE, "GL: Shaders support not present, falling back to SW mode");
1032         break;
1033       }
1034     }
1035   }
1036
1037   // determine whether GPU supports NPOT textures
1038   if (!glewIsSupported("GL_ARB_texture_non_power_of_two"))
1039   {
1040     if (!glewIsSupported("GL_ARB_texture_rectangle"))
1041     {
1042       CLog::Log(LOGNOTICE, "GL: GL_ARB_texture_rectangle not supported and OpenGL version is not 2.x");
1043       CLog::Log(LOGNOTICE, "GL: Reverting to POT textures");
1044       m_renderMethod |= RENDER_POT;
1045     }
1046     else
1047       CLog::Log(LOGNOTICE, "GL: NPOT textures are supported through GL_ARB_texture_rectangle extension");
1048   }
1049   else
1050     CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
1051
1052   
1053   if (m_pboSupported &&
1054     !(m_renderMethod & RENDER_SW) && 
1055     !(m_renderMethod & RENDER_CVREF))
1056   {
1057     CLog::Log(LOGNOTICE, "GL: Using GL_ARB_pixel_buffer_object");
1058     m_pboUsed = true;
1059   }
1060   else
1061     m_pboUsed = false;
1062
1063   // Now that we now the render method, setup texture function handlers
1064   if (m_format == RENDER_FMT_NV12)
1065   {
1066     m_textureUpload = &CLinuxRendererGL::UploadNV12Texture;
1067     m_textureCreate = &CLinuxRendererGL::CreateNV12Texture;
1068     m_textureDelete = &CLinuxRendererGL::DeleteNV12Texture;
1069   }
1070   else if (m_format == RENDER_FMT_YUYV422 ||
1071            m_format == RENDER_FMT_UYVY422)
1072   {
1073     m_textureUpload = &CLinuxRendererGL::UploadYUV422PackedTexture;
1074     m_textureCreate = &CLinuxRendererGL::CreateYUV422PackedTexture;
1075     m_textureDelete = &CLinuxRendererGL::DeleteYUV422PackedTexture;
1076   }
1077   else if (m_format == RENDER_FMT_VDPAU)
1078   {
1079     m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture;
1080     m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture;
1081     m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture;
1082   }
1083   else if (m_format == RENDER_FMT_VDPAU_420)
1084   {
1085     m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture420;
1086     m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture420;
1087     m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture420;
1088   }
1089   else if (m_format == RENDER_FMT_VAAPI)
1090   {
1091     m_textureUpload = &CLinuxRendererGL::UploadVAAPITexture;
1092     m_textureCreate = &CLinuxRendererGL::CreateVAAPITexture;
1093     m_textureDelete = &CLinuxRendererGL::DeleteVAAPITexture;
1094   }
1095   else if (m_format == RENDER_FMT_CVBREF)
1096   {
1097     m_textureUpload = &CLinuxRendererGL::UploadCVRefTexture;
1098     m_textureCreate = &CLinuxRendererGL::CreateCVRefTexture;
1099     m_textureDelete = &CLinuxRendererGL::DeleteCVRefTexture;
1100   }
1101   else
1102   {
1103     // setup default YV12 texture handlers
1104     m_textureUpload = &CLinuxRendererGL::UploadYV12Texture;
1105     m_textureCreate = &CLinuxRendererGL::CreateYV12Texture;
1106     m_textureDelete = &CLinuxRendererGL::DeleteYV12Texture;
1107   }
1108
1109   //in case of software colorspace conversion, all formats are handled by the same method
1110   if (m_renderMethod & RENDER_SW)
1111     m_textureUpload = &CLinuxRendererGL::UploadRGBTexture;
1112 }
1113
1114 void CLinuxRendererGL::UnInit()
1115 {
1116   CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
1117   CSingleLock lock(g_graphicsContext);
1118
1119   glFinish();
1120
1121   if (m_rgbPbo)
1122   {
1123     glDeleteBuffersARB(1, &m_rgbPbo);
1124     m_rgbPbo = 0;
1125     m_rgbBuffer = NULL;
1126   }
1127   else
1128   {
1129     delete [] m_rgbBuffer;
1130     m_rgbBuffer = NULL;
1131   }
1132   m_rgbBufferSize = 0;
1133
1134   if (m_context)
1135   {
1136     m_dllSwScale->sws_freeContext(m_context);
1137     m_context = NULL;
1138   }
1139
1140   // YV12 textures
1141   for (int i = 0; i < NUM_BUFFERS; ++i)
1142     (this->*m_textureDelete)(i);
1143
1144   // cleanup framebuffer object if it was in use
1145   m_fbo.fbo.Cleanup();
1146   m_bValidated = false;
1147   m_bImageReady = false;
1148   m_bConfigured = false;
1149 }
1150
1151 void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
1152 {
1153   // obtain current field, if interlaced
1154   if( flags & RENDER_FLAG_TOP)
1155     m_currentField = FIELD_TOP;
1156
1157   else if (flags & RENDER_FLAG_BOT)
1158     m_currentField = FIELD_BOT;
1159
1160   else
1161     m_currentField = FIELD_FULL;
1162
1163   // call texture load function
1164   if (!(this->*m_textureUpload)(renderBuffer))
1165     return;
1166
1167   if (m_renderMethod & RENDER_GLSL)
1168   {
1169     UpdateVideoFilter();
1170     switch(m_renderQuality)
1171     {
1172     case RQ_LOW:
1173     case RQ_SINGLEPASS:
1174       if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL)
1175         RenderProgressiveWeave(renderBuffer, m_currentField);
1176       else
1177         RenderSinglePass(renderBuffer, m_currentField);
1178       VerifyGLState();
1179       break;
1180
1181     case RQ_MULTIPASS:
1182       if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL)
1183         RenderProgressiveWeave(renderBuffer, m_currentField);
1184       else
1185       {
1186         RenderToFBO(renderBuffer, m_currentField);
1187         RenderFromFBO();
1188       }
1189       VerifyGLState();
1190       break;
1191     }
1192   }
1193   else if (m_renderMethod & RENDER_ARB)
1194   {
1195     RenderSinglePass(renderBuffer, m_currentField);
1196   }
1197 #ifdef HAVE_LIBVDPAU
1198   else if (m_renderMethod & RENDER_VDPAU)
1199   {
1200     UpdateVideoFilter();
1201     RenderVDPAU(renderBuffer, m_currentField);
1202   }
1203 #endif
1204 #ifdef HAVE_LIBVA
1205   else if (m_renderMethod & RENDER_VAAPI)
1206   {
1207     UpdateVideoFilter();
1208     RenderVAAPI(renderBuffer, m_currentField);
1209   }
1210 #endif
1211   else
1212   {
1213     // RENDER_CVREF uses the same render as the default case
1214     RenderSoftware(renderBuffer, m_currentField);
1215     VerifyGLState();
1216   }
1217
1218 #ifdef HAVE_LIBVDPAU
1219   if (m_format == RENDER_FMT_VDPAU || m_format == RENDER_FMT_VDPAU_420)
1220   {
1221     YUVBUFFER &buf = m_buffers[renderBuffer];
1222     if (buf.vdpau)
1223     {
1224       buf.vdpau->Sync();
1225     }
1226   }
1227 #endif
1228 }
1229
1230 void CLinuxRendererGL::RenderSinglePass(int index, int field)
1231 {
1232   YUVFIELDS &fields = m_buffers[index].fields;
1233   YUVPLANES &planes = fields[field];
1234
1235   if (m_reloadShaders)
1236   {
1237     m_reloadShaders = 0;
1238     LoadShaders(field);
1239   }
1240
1241   glDisable(GL_DEPTH_TEST);
1242
1243   // Y
1244   glActiveTextureARB(GL_TEXTURE0);
1245   glEnable(m_textureTarget);
1246   glBindTexture(m_textureTarget, planes[0].id);
1247
1248   // U
1249   glActiveTextureARB(GL_TEXTURE1);
1250   glEnable(m_textureTarget);
1251   glBindTexture(m_textureTarget, planes[1].id);
1252
1253   // V
1254   glActiveTextureARB(GL_TEXTURE2);
1255   glEnable(m_textureTarget);
1256   glBindTexture(m_textureTarget, planes[2].id);
1257
1258   glActiveTextureARB(GL_TEXTURE0);
1259   VerifyGLState();
1260
1261   m_pYUVShader->SetBlack(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * 0.01f - 0.5f);
1262   m_pYUVShader->SetContrast(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast * 0.02f);
1263   m_pYUVShader->SetWidth(planes[0].texwidth);
1264   m_pYUVShader->SetHeight(planes[0].texheight);
1265
1266   //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer
1267   //having non-linear stretch on breaks the alignment
1268   if (g_application.m_pPlayer->IsInMenu())
1269     m_pYUVShader->SetNonLinStretch(1.0);
1270   else
1271     m_pYUVShader->SetNonLinStretch(pow(CDisplaySettings::Get().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1272
1273   if     (field == FIELD_TOP)
1274     m_pYUVShader->SetField(1);
1275   else if(field == FIELD_BOT)
1276     m_pYUVShader->SetField(0);
1277
1278   m_pYUVShader->Enable();
1279
1280   glBegin(GL_QUADS);
1281
1282   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
1283   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y1);
1284   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y1);
1285   glVertex4f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y, 0, 1.0f );//top left
1286
1287   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y1);
1288   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y1);
1289   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y1);
1290   glVertex4f(m_rotatedDestCoords[1].x, m_rotatedDestCoords[1].y, 0, 1.0f );//top right
1291
1292   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y2);
1293   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y2);
1294   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y2);
1295   glVertex4f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y, 0, 1.0f );//bottom right
1296
1297   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y2);
1298   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y2);
1299   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y2);
1300   glVertex4f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y, 0, 1.0f );//bottom left
1301
1302   glEnd();
1303   VerifyGLState();
1304
1305   m_pYUVShader->Disable();
1306   VerifyGLState();
1307
1308   glActiveTextureARB(GL_TEXTURE1);
1309   glDisable(m_textureTarget);
1310
1311   glActiveTextureARB(GL_TEXTURE2);
1312   glDisable(m_textureTarget);
1313
1314   glActiveTextureARB(GL_TEXTURE0);
1315   glDisable(m_textureTarget);
1316
1317   glMatrixMode(GL_MODELVIEW);
1318
1319   VerifyGLState();
1320 }
1321
1322 void CLinuxRendererGL::RenderToFBO(int index, int field, bool weave /*= false*/)
1323 {
1324   YUVPLANES &planes = m_buffers[index].fields[field];
1325
1326   if (m_reloadShaders)
1327   {
1328     m_reloadShaders = 0;
1329     LoadShaders(m_currentField);
1330   }
1331
1332   if (!m_fbo.fbo.IsValid())
1333   {
1334     if (!m_fbo.fbo.Initialize())
1335     {
1336       CLog::Log(LOGERROR, "GL: Error initializing FBO");
1337       return;
1338     }
1339
1340     if (!m_fbo.fbo.CreateAndBindToTexture(GL_TEXTURE_2D, m_sourceWidth, m_sourceHeight, GL_RGBA))
1341     {
1342       CLog::Log(LOGERROR, "GL: Error creating texture and binding to FBO");
1343       return;
1344     }
1345   }
1346
1347   glDisable(GL_DEPTH_TEST);
1348
1349   // Y
1350   glEnable(m_textureTarget);
1351   glActiveTextureARB(GL_TEXTURE0);
1352   glBindTexture(m_textureTarget, planes[0].id);
1353   VerifyGLState();
1354
1355   // U
1356   glActiveTextureARB(GL_TEXTURE1);
1357   glEnable(m_textureTarget);
1358   glBindTexture(m_textureTarget, planes[1].id);
1359   VerifyGLState();
1360
1361   // V
1362   glActiveTextureARB(GL_TEXTURE2);
1363   glEnable(m_textureTarget);
1364   glBindTexture(m_textureTarget, planes[2].id);
1365   VerifyGLState();
1366
1367   glActiveTextureARB(GL_TEXTURE0);
1368   VerifyGLState();
1369
1370   // make sure the yuv shader is loaded and ready to go
1371   if (!m_pYUVShader || (!m_pYUVShader->OK()))
1372   {
1373     CLog::Log(LOGERROR, "GL: YUV shader not active, cannot do multipass render");
1374     return;
1375   }
1376
1377   m_fbo.fbo.BeginRender();
1378   VerifyGLState();
1379
1380   m_pYUVShader->SetBlack(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * 0.01f - 0.5f);
1381   m_pYUVShader->SetContrast(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast * 0.02f);
1382   m_pYUVShader->SetWidth(planes[0].texwidth);
1383   m_pYUVShader->SetHeight(planes[0].texheight);
1384   m_pYUVShader->SetNonLinStretch(1.0);
1385   if     (field == FIELD_TOP)
1386     m_pYUVShader->SetField(1);
1387   else if(field == FIELD_BOT)
1388     m_pYUVShader->SetField(0);
1389
1390   VerifyGLState();
1391
1392   glPushAttrib(GL_VIEWPORT_BIT);
1393   glPushAttrib(GL_SCISSOR_BIT);
1394   glMatrixMode(GL_MODELVIEW);
1395   glPushMatrix();
1396   glLoadIdentity();
1397   VerifyGLState();
1398
1399   glMatrixMode(GL_PROJECTION);
1400   glPushMatrix();
1401   glLoadIdentity();
1402   VerifyGLState();
1403   gluOrtho2D(0, m_sourceWidth, 0, m_sourceHeight);
1404   glViewport(0, 0, m_sourceWidth, m_sourceHeight);
1405   glScissor (0, 0, m_sourceWidth, m_sourceHeight);
1406   glMatrixMode(GL_MODELVIEW);
1407   VerifyGLState();
1408
1409
1410   if (!m_pYUVShader->Enable())
1411   {
1412     CLog::Log(LOGERROR, "GL: Error enabling YUV shader");
1413   }
1414
1415   m_fbo.width  = planes[0].rect.x2 - planes[0].rect.x1;
1416   m_fbo.height = planes[0].rect.y2 - planes[0].rect.y1;
1417   if (m_textureTarget == GL_TEXTURE_2D)
1418   {
1419     m_fbo.width  *= planes[0].texwidth;
1420     m_fbo.height *= planes[0].texheight;
1421   }
1422   m_fbo.width  *= planes[0].pixpertex_x;
1423   m_fbo.height *= planes[0].pixpertex_y;
1424   if (weave)
1425     m_fbo.height *= 2;
1426
1427   // 1st Pass to video frame size
1428   glBegin(GL_QUADS);
1429
1430   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
1431   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y1);
1432   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y1);
1433   glVertex2f(0.0f    , 0.0f);
1434
1435   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y1);
1436   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y1);
1437   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y1);
1438   glVertex2f(m_fbo.width, 0.0f);
1439
1440   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y2);
1441   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y2);
1442   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y2);
1443   glVertex2f(m_fbo.width, m_fbo.height);
1444
1445   glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y2);
1446   glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y2);
1447   glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y2);
1448   glVertex2f(0.0f    , m_fbo.height);
1449
1450   glEnd();
1451   VerifyGLState();
1452
1453   m_pYUVShader->Disable();
1454
1455   glMatrixMode(GL_MODELVIEW);
1456   glPopMatrix(); // pop modelview
1457   glMatrixMode(GL_PROJECTION);
1458   glPopMatrix(); // pop projection
1459   glPopAttrib(); // pop scissor
1460   glPopAttrib(); // pop viewport
1461   glMatrixMode(GL_MODELVIEW);
1462   VerifyGLState();
1463
1464   m_fbo.fbo.EndRender();
1465
1466   glActiveTextureARB(GL_TEXTURE1);
1467   glDisable(m_textureTarget);
1468   glActiveTextureARB(GL_TEXTURE2);
1469   glDisable(m_textureTarget);
1470   glActiveTextureARB(GL_TEXTURE0);
1471   glDisable(m_textureTarget);
1472 }
1473
1474 void CLinuxRendererGL::RenderFromFBO()
1475 {
1476   glEnable(m_textureTarget);
1477   glActiveTextureARB(GL_TEXTURE0);
1478   VerifyGLState();
1479
1480   // Use regular normalized texture coordinates
1481
1482   // 2nd Pass to screen size with optional video filter
1483
1484   if (m_pVideoFilterShader)
1485   {
1486     GLint filter;
1487     if (!m_pVideoFilterShader->GetTextureFilter(filter))
1488       filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
1489
1490     m_fbo.fbo.SetFiltering(m_textureTarget, filter);
1491     m_pVideoFilterShader->SetSourceTexture(0);
1492     m_pVideoFilterShader->SetWidth(m_sourceWidth);
1493     m_pVideoFilterShader->SetHeight(m_sourceHeight);
1494
1495     //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer
1496     //having non-linear stretch on breaks the alignment
1497     if (g_application.m_pPlayer->IsInMenu())
1498       m_pVideoFilterShader->SetNonLinStretch(1.0);
1499     else
1500       m_pVideoFilterShader->SetNonLinStretch(pow(CDisplaySettings::Get().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1501
1502     m_pVideoFilterShader->Enable();
1503   }
1504   else
1505   {
1506     GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
1507     m_fbo.fbo.SetFiltering(m_textureTarget, filter);
1508     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1509   }
1510
1511   VerifyGLState();
1512
1513   float imgwidth = m_fbo.width / m_sourceWidth;
1514   float imgheight = m_fbo.height / m_sourceHeight;
1515
1516   glBegin(GL_QUADS);
1517
1518   glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f, 0.0f);
1519   glVertex4f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y, 0, 1.0f );
1520
1521   glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, 0.0f);
1522   glVertex4f(m_rotatedDestCoords[1].x, m_rotatedDestCoords[1].y, 0, 1.0f );
1523
1524   glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, imgheight);
1525   glVertex4f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y, 0, 1.0f );
1526   
1527   glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f, imgheight);
1528   glVertex4f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y, 0, 1.0f );
1529
1530   glEnd();
1531
1532   VerifyGLState();
1533
1534   if (m_pVideoFilterShader)
1535     m_pVideoFilterShader->Disable();
1536
1537   VerifyGLState();
1538
1539   glBindTexture(m_textureTarget, 0);
1540   glDisable(m_textureTarget);
1541   VerifyGLState();
1542 }
1543
1544 void CLinuxRendererGL::RenderProgressiveWeave(int index, int field)
1545 {
1546   bool scale = (int)m_sourceHeight != m_destRect.Height() ||
1547                (int)m_sourceWidth != m_destRect.Width();
1548
1549   if (m_fbo.fbo.IsSupported() && (scale || m_renderQuality == RQ_MULTIPASS))
1550   {
1551     glEnable(GL_POLYGON_STIPPLE);
1552     glPolygonStipple(stipple_weave);
1553     RenderToFBO(index, FIELD_TOP, true);
1554     glPolygonStipple(stipple_weave+4);
1555     RenderToFBO(index, FIELD_BOT, true);
1556     glDisable(GL_POLYGON_STIPPLE);
1557     RenderFromFBO();
1558   }
1559   else
1560   {
1561     glEnable(GL_POLYGON_STIPPLE);
1562     glPolygonStipple(stipple_weave);
1563     RenderSinglePass(index, FIELD_TOP);
1564     glPolygonStipple(stipple_weave+4);
1565     RenderSinglePass(index, FIELD_BOT);
1566     glDisable(GL_POLYGON_STIPPLE);
1567   }
1568 }
1569
1570 void CLinuxRendererGL::RenderVDPAU(int index, int field)
1571 {
1572 #ifdef HAVE_LIBVDPAU
1573   YUVPLANE &plane = m_buffers[index].fields[FIELD_FULL][0];
1574
1575   glEnable(m_textureTarget);
1576   glActiveTextureARB(GL_TEXTURE0);
1577
1578   glBindTexture(m_textureTarget, plane.id);
1579
1580   // make sure we know the correct texture size
1581   GetPlaneTextureSize(plane);
1582
1583   // Try some clamping or wrapping
1584   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1585   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1586
1587   if (m_pVideoFilterShader)
1588   {
1589     GLint filter;
1590     if (!m_pVideoFilterShader->GetTextureFilter(filter))
1591       filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
1592
1593     glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
1594     glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
1595     m_pVideoFilterShader->SetSourceTexture(0);
1596     m_pVideoFilterShader->SetWidth(m_sourceWidth);
1597     m_pVideoFilterShader->SetHeight(m_sourceHeight);
1598
1599     //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer
1600     //having non-linear stretch on breaks the alignment
1601     if (g_application.m_pPlayer->IsInMenu())
1602       m_pVideoFilterShader->SetNonLinStretch(1.0);
1603     else
1604       m_pVideoFilterShader->SetNonLinStretch(pow(CDisplaySettings::Get().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1605
1606     m_pVideoFilterShader->Enable();
1607   }
1608   else
1609   {
1610     GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
1611     glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
1612     glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
1613   }
1614
1615   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1616   VerifyGLState();
1617
1618   glBegin(GL_QUADS);
1619   if (m_textureTarget==GL_TEXTURE_2D)
1620   {
1621     glTexCoord2f(plane.rect.x1, plane.rect.y1);  glVertex2f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y);
1622     glTexCoord2f(plane.rect.x2, plane.rect.y1);  glVertex2f(m_rotatedDestCoords[1].x, m_rotatedDestCoords[1].y);
1623     glTexCoord2f(plane.rect.x2, plane.rect.y2);  glVertex2f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y);
1624     glTexCoord2f(plane.rect.x1, plane.rect.y2);  glVertex2f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y);
1625   }
1626   else
1627   {
1628     glTexCoord2f(plane.rect.x1, plane.rect.y1); glVertex4f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y, 0.0f, 0.0f);
1629     glTexCoord2f(plane.rect.x2, plane.rect.y1); glVertex4f(m_rotatedDestCoords[1].x, m_rotatedDestCoords[1].y, 1.0f, 0.0f);
1630     glTexCoord2f(plane.rect.x2, plane.rect.y2); glVertex4f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y, 1.0f, 1.0f);
1631     glTexCoord2f(plane.rect.x1, plane.rect.y2); glVertex4f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y, 0.0f, 1.0f);
1632   }
1633   glEnd();
1634   VerifyGLState();
1635
1636   if (m_pVideoFilterShader)
1637     m_pVideoFilterShader->Disable();
1638
1639   glBindTexture (m_textureTarget, 0);
1640   glDisable(m_textureTarget);
1641 #endif
1642 }
1643
1644 void CLinuxRendererGL::RenderVAAPI(int index, int field)
1645 {
1646 #ifdef HAVE_LIBVA
1647   YUVPLANE       &plane = m_buffers[index].fields[0][0];
1648   VAAPI::CHolder &va    = m_buffers[index].vaapi;
1649
1650   if(!va.surface)
1651   {
1652     CLog::Log(LOGINFO, "CLinuxRendererGL::RenderVAAPI - no vaapi object");
1653     return;
1654   }
1655   VAAPI::CDisplayPtr& display(va.surface->m_display);
1656   CSingleLock lock(*display);
1657
1658   glEnable(m_textureTarget);
1659   glActiveTextureARB(GL_TEXTURE0);
1660   glBindTexture(m_textureTarget, plane.id);
1661
1662 #if USE_VAAPI_GLX_BIND
1663   VAStatus status;
1664   status = vaBeginRenderSurfaceGLX(display->get(), va.surfglx->m_id);
1665   if(status != VA_STATUS_SUCCESS)
1666   {
1667     CLog::Log(LOGERROR, "CLinuxRendererGL::RenderVAAPI - vaBeginRenderSurfaceGLX failed (%d)", status);
1668     return;
1669   }
1670 #endif
1671
1672   // make sure we know the correct texture size
1673   GetPlaneTextureSize(plane);
1674   CalculateTextureSourceRects(index, 1);
1675
1676   // Try some clamping or wrapping
1677   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1678   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1679
1680   if (m_pVideoFilterShader)
1681   {
1682     GLint filter;
1683     if (!m_pVideoFilterShader->GetTextureFilter(filter))
1684       filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
1685
1686     glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
1687     glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
1688     m_pVideoFilterShader->SetSourceTexture(0);
1689     m_pVideoFilterShader->SetWidth(m_sourceWidth);
1690     m_pVideoFilterShader->SetHeight(m_sourceHeight);
1691
1692     //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer
1693     //having non-linear stretch on breaks the alignment
1694     if (g_application.m_pPlayer->IsInMenu())
1695       m_pVideoFilterShader->SetNonLinStretch(1.0);
1696     else
1697       m_pVideoFilterShader->SetNonLinStretch(pow(CDisplaySettings::Get().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1698
1699     m_pVideoFilterShader->Enable();
1700   }
1701   else
1702   {
1703     GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
1704     glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
1705     glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
1706   }
1707
1708   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1709   VerifyGLState();
1710
1711   glBegin(GL_QUADS);
1712   glTexCoord2f(plane.rect.x1, plane.rect.y1);  glVertex2f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y);
1713   glTexCoord2f(plane.rect.x2, plane.rect.y1);  glVertex2f(m_rotatedDestCoords[1].x, m_rotatedDestCoords[1].y);
1714   glTexCoord2f(plane.rect.x2, plane.rect.y2);  glVertex2f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y);
1715   glTexCoord2f(plane.rect.x1, plane.rect.y2);  glVertex2f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y);
1716   glEnd();
1717
1718   VerifyGLState();
1719
1720   if (m_pVideoFilterShader)
1721     m_pVideoFilterShader->Disable();
1722
1723 #if USE_VAAPI_GLX_BIND
1724   status = vaEndRenderSurfaceGLX(display->get(), va.surfglx->m_id);
1725   if(status != VA_STATUS_SUCCESS)
1726   {
1727     CLog::Log(LOGERROR, "CLinuxRendererGL::RenderVAAPI - vaEndRenderSurfaceGLX failed (%d)", status);
1728     return;
1729   }
1730 #endif
1731
1732   glBindTexture (m_textureTarget, 0);
1733   glDisable(m_textureTarget);
1734 #endif
1735 }
1736
1737 void CLinuxRendererGL::RenderSoftware(int index, int field)
1738 {
1739   // used for textues uploaded from rgba or CVPixelBuffers.
1740   YUVPLANES &planes = m_buffers[index].fields[field];
1741
1742   glDisable(GL_DEPTH_TEST);
1743
1744   glEnable(m_textureTarget);
1745   glActiveTextureARB(GL_TEXTURE0);
1746   glBindTexture(m_textureTarget, planes[0].id);
1747   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1748
1749   glBegin(GL_QUADS);
1750   glTexCoord2f(planes[0].rect.x1, planes[0].rect.y1);
1751   glVertex4f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y, 0, 1.0f );
1752
1753   glTexCoord2f(planes[0].rect.x2, planes[0].rect.y1);
1754   glVertex4f(m_rotatedDestCoords[1].x, m_rotatedDestCoords[1].y, 0, 1.0f);
1755
1756   glTexCoord2f(planes[0].rect.x2, planes[0].rect.y2);
1757   glVertex4f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y, 0, 1.0f);
1758
1759   glTexCoord2f(planes[0].rect.x1, planes[0].rect.y2);
1760   glVertex4f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y, 0, 1.0f);
1761
1762   glEnd();
1763
1764   VerifyGLState();
1765
1766   glDisable(m_textureTarget);
1767   VerifyGLState();
1768 }
1769
1770 bool CLinuxRendererGL::RenderCapture(CRenderCapture* capture)
1771 {
1772   if (!m_bValidated)
1773     return false;
1774
1775   // save current video rect
1776   CRect saveSize = m_destRect;
1777   
1778   saveRotatedCoords();//backup current m_rotatedDestCoords
1779       
1780   // new video rect is capture size
1781   m_destRect.SetRect(0, 0, (float)capture->GetWidth(), (float)capture->GetHeight());
1782   MarkDirty();
1783   syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords
1784
1785   //invert Y axis to get non-inverted image
1786   glDisable(GL_BLEND);
1787   glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1788   glMatrixMode(GL_MODELVIEW);
1789   glPushMatrix();
1790   glTranslatef(0, capture->GetHeight(), 0);
1791   glScalef(1.0, -1.0f, 1.0f);
1792
1793   capture->BeginRender();
1794
1795   Render(RENDER_FLAG_NOOSD, m_iYV12RenderBuffer);
1796   // read pixels
1797   glReadPixels(0, g_graphicsContext.GetHeight() - capture->GetHeight(), capture->GetWidth(), capture->GetHeight(),
1798                GL_BGRA, GL_UNSIGNED_BYTE, capture->GetRenderBuffer());
1799
1800   capture->EndRender();
1801
1802   // revert model view matrix
1803   glMatrixMode(GL_MODELVIEW);
1804   glPopMatrix();
1805
1806   // restore original video rect
1807   m_destRect = saveSize;
1808   restoreRotatedCoords();//restores the previous state of the rotated dest coords
1809
1810   return true;
1811 }
1812
1813 //********************************************************************************************************
1814 // YV12 Texture creation, deletion, copying + clearing
1815 //********************************************************************************************************
1816 bool CLinuxRendererGL::UploadYV12Texture(int source)
1817 {
1818   YUVBUFFER& buf    =  m_buffers[source];
1819   YV12Image* im     = &buf.image;
1820   YUVFIELDS& fields =  buf.fields;
1821
1822   if (!(im->flags&IMAGE_FLAG_READY))
1823     return false;
1824   bool deinterlacing;
1825   if (m_currentField == FIELD_FULL)
1826     deinterlacing = false;
1827   else
1828     deinterlacing = true;
1829
1830   glEnable(m_textureTarget);
1831   VerifyGLState();
1832
1833   glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1834
1835   if (deinterlacing)
1836   {
1837     // Load Even Y Field
1838     LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex
1839              , im->width, im->height >> 1
1840              , im->stride[0]*2, im->bpp, im->plane[0] );
1841
1842     //load Odd Y Field
1843     LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex
1844              , im->width, im->height >> 1
1845              , im->stride[0]*2, im->bpp, im->plane[0] + im->stride[0]) ;
1846
1847     // Load Even U & V Fields
1848     LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE, buf.flipindex
1849              , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1850              , im->stride[1]*2, im->bpp, im->plane[1] );
1851
1852     LoadPlane( fields[FIELD_TOP][2], GL_ALPHA, buf.flipindex
1853              , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1854              , im->stride[2]*2, im->bpp, im->plane[2] );
1855
1856     // Load Odd U & V Fields
1857     LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE, buf.flipindex
1858              , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1859              , im->stride[1]*2, im->bpp, im->plane[1] + im->stride[1] );
1860
1861     LoadPlane( fields[FIELD_BOT][2], GL_ALPHA, buf.flipindex
1862              , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1863              , im->stride[2]*2, im->bpp, im->plane[2] + im->stride[2] );
1864   }
1865   else
1866   {
1867     //Load Y plane
1868     LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
1869              , im->width, im->height
1870              , im->stride[0], im->bpp, im->plane[0] );
1871
1872     //load U plane
1873     LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, buf.flipindex
1874              , im->width >> im->cshift_x, im->height >> im->cshift_y
1875              , im->stride[1], im->bpp, im->plane[1] );
1876
1877     //load V plane
1878     LoadPlane( fields[FIELD_FULL][2], GL_ALPHA, buf.flipindex
1879              , im->width >> im->cshift_x, im->height >> im->cshift_y
1880              , im->stride[2], im->bpp, im->plane[2] );
1881   }
1882
1883   VerifyGLState();
1884
1885   CalculateTextureSourceRects(source, 3);
1886
1887   glDisable(m_textureTarget);
1888   return true;
1889 }
1890
1891 void CLinuxRendererGL::DeleteYV12Texture(int index)
1892 {
1893   YV12Image &im     = m_buffers[index].image;
1894   YUVFIELDS &fields = m_buffers[index].fields;
1895   GLuint    *pbo    = m_buffers[index].pbo;
1896
1897   if( fields[FIELD_FULL][0].id == 0 ) return;
1898
1899   /* finish up all textures, and delete them */
1900   g_graphicsContext.BeginPaint();  //FIXME
1901   for(int f = 0;f<MAX_FIELDS;f++)
1902   {
1903     for(int p = 0;p<MAX_PLANES;p++)
1904     {
1905       if( fields[f][p].id )
1906       {
1907         if (glIsTexture(fields[f][p].id))
1908           glDeleteTextures(1, &fields[f][p].id);
1909         fields[f][p].id = 0;
1910       }
1911     }
1912   }
1913   g_graphicsContext.EndPaint();
1914
1915   for(int p = 0;p<MAX_PLANES;p++)
1916   {
1917     if (pbo[p])
1918     {
1919       if (im.plane[p])
1920       {
1921         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[p]);
1922         glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
1923         im.plane[p] = NULL;
1924         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
1925       }
1926       glDeleteBuffersARB(1, pbo + p);
1927       pbo[p] = 0;
1928     }
1929     else
1930     {
1931       if (im.plane[p])
1932       {
1933         delete[] im.plane[p];
1934         im.plane[p] = NULL;
1935       }
1936     }
1937   }
1938 }
1939
1940 static GLint GetInternalFormat(GLint format, int bpp)
1941 {
1942   if(bpp == 2)
1943   {
1944     switch (format)
1945     {
1946 #ifdef GL_ALPHA16
1947       case GL_ALPHA:     return GL_ALPHA16;
1948 #endif
1949 #ifdef GL_LUMINANCE16
1950       case GL_LUMINANCE: return GL_LUMINANCE16;
1951 #endif
1952       default:           return format;
1953     }
1954   }
1955   else
1956     return format;
1957 }
1958
1959 bool CLinuxRendererGL::CreateYV12Texture(int index)
1960 {
1961   /* since we also want the field textures, pitch must be texture aligned */
1962   unsigned p;
1963
1964   YV12Image &im     = m_buffers[index].image;
1965   YUVFIELDS &fields = m_buffers[index].fields;
1966   GLuint    *pbo    = m_buffers[index].pbo;
1967
1968   DeleteYV12Texture(index);
1969
1970   im.height = m_sourceHeight;
1971   im.width  = m_sourceWidth;
1972   im.cshift_x = 1;
1973   im.cshift_y = 1;
1974
1975
1976   if(m_format == RENDER_FMT_YUV420P16
1977   || m_format == RENDER_FMT_YUV420P10)
1978     im.bpp = 2;
1979   else
1980     im.bpp = 1;
1981
1982   im.stride[0] = im.bpp *   im.width;
1983   im.stride[1] = im.bpp * ( im.width >> im.cshift_x );
1984   im.stride[2] = im.bpp * ( im.width >> im.cshift_x );
1985
1986   im.planesize[0] = im.stride[0] *   im.height;
1987   im.planesize[1] = im.stride[1] * ( im.height >> im.cshift_y );
1988   im.planesize[2] = im.stride[2] * ( im.height >> im.cshift_y );
1989
1990   bool pboSetup = false;
1991   if (m_pboUsed)
1992   {
1993     pboSetup = true;
1994     glGenBuffersARB(3, pbo);
1995
1996     for (int i = 0; i < 3; i++)
1997     {
1998       glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[i]);
1999       glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, im.planesize[i] + PBO_OFFSET, 0, GL_STREAM_DRAW_ARB);
2000       void* pboPtr = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB);
2001       if (pboPtr)
2002       {
2003         im.plane[i] = (BYTE*) pboPtr + PBO_OFFSET;
2004         memset(im.plane[i], 0, im.planesize[i]);
2005       }
2006       else
2007       {
2008         CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
2009         pboSetup = false;
2010         break;
2011       }
2012     }
2013
2014     if (!pboSetup)
2015     {
2016       for (int i = 0; i < 3; i++)
2017       {
2018         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[i]);
2019         glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2020       }
2021       glDeleteBuffersARB(3, pbo);
2022       memset(m_buffers[index].pbo, 0, sizeof(m_buffers[index].pbo));
2023     }
2024
2025     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2026   }
2027
2028   if (!pboSetup)
2029   {
2030     for (int i = 0; i < 3; i++)
2031       im.plane[i] = new BYTE[im.planesize[i]];
2032   }
2033
2034   glEnable(m_textureTarget);
2035   for(int f = 0;f<MAX_FIELDS;f++)
2036   {
2037     for(p = 0;p<MAX_PLANES;p++)
2038     {
2039       if (!glIsTexture(fields[f][p].id))
2040       {
2041         glGenTextures(1, &fields[f][p].id);
2042         VerifyGLState();
2043       }
2044       fields[f][p].pbo = pbo[p];
2045     }
2046   }
2047
2048   // YUV
2049   for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
2050   {
2051     int fieldshift = (f==FIELD_FULL) ? 0 : 1;
2052     YUVPLANES &planes = fields[f];
2053
2054     planes[0].texwidth  = im.width;
2055     planes[0].texheight = im.height >> fieldshift;
2056
2057     if (m_renderMethod & RENDER_SW)
2058     {
2059       planes[1].texwidth  = 0;
2060       planes[1].texheight = 0;
2061       planes[2].texwidth  = 0;
2062       planes[2].texheight = 0;
2063     }
2064     else
2065     {
2066       planes[1].texwidth  = planes[0].texwidth  >> im.cshift_x;
2067       planes[1].texheight = planes[0].texheight >> im.cshift_y;
2068       planes[2].texwidth  = planes[0].texwidth  >> im.cshift_x;
2069       planes[2].texheight = planes[0].texheight >> im.cshift_y;
2070     }
2071
2072     for (int p = 0; p < 3; p++)
2073     {
2074       planes[p].pixpertex_x = 1;
2075       planes[p].pixpertex_y = 1;
2076     }
2077
2078     if(m_renderMethod & RENDER_POT)
2079     {
2080       for(int p = 0; p < 3; p++)
2081       {
2082         planes[p].texwidth  = NP2(planes[p].texwidth);
2083         planes[p].texheight = NP2(planes[p].texheight);
2084       }
2085     }
2086
2087     for(int p = 0; p < 3; p++)
2088     {
2089       YUVPLANE &plane = planes[p];
2090       if (plane.texwidth * plane.texheight == 0)
2091         continue;
2092
2093       glBindTexture(m_textureTarget, plane.id);
2094       if (m_renderMethod & RENDER_SW)
2095       {
2096         glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2097       }
2098       else
2099       {
2100         GLenum format;
2101         GLint internalformat;
2102         if (p == 2) //V plane needs an alpha texture
2103           format = GL_ALPHA;
2104         else
2105           format = GL_LUMINANCE;
2106         internalformat = GetInternalFormat(format, im.bpp);
2107
2108         glTexImage2D(m_textureTarget, 0, internalformat, plane.texwidth, plane.texheight, 0, format, GL_UNSIGNED_BYTE, NULL);
2109       }
2110
2111       glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2112       glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2113       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2114       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2115       VerifyGLState();
2116     }
2117   }
2118   glDisable(m_textureTarget);
2119   return true;
2120 }
2121
2122 //********************************************************************************************************
2123 // NV12 Texture loading, creation and deletion
2124 //********************************************************************************************************
2125 bool CLinuxRendererGL::UploadNV12Texture(int source)
2126 {
2127   YUVBUFFER& buf    =  m_buffers[source];
2128   YV12Image* im     = &buf.image;
2129   YUVFIELDS& fields =  buf.fields;
2130
2131   if (!(im->flags & IMAGE_FLAG_READY))
2132     return false;
2133   bool deinterlacing;
2134   if (m_currentField == FIELD_FULL)
2135     deinterlacing = false;
2136   else
2137     deinterlacing = true;
2138
2139   glEnable(m_textureTarget);
2140   VerifyGLState();
2141
2142   glPixelStorei(GL_UNPACK_ALIGNMENT, im->bpp);
2143
2144   if (deinterlacing)
2145   {
2146     // Load Odd Y field
2147     LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex
2148              , im->width, im->height >> 1
2149              , im->stride[0]*2, im->bpp, im->plane[0] );
2150
2151     // Load Even Y field
2152     LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex
2153              , im->width, im->height >> 1
2154              , im->stride[0]*2, im->bpp, im->plane[0] + im->stride[0]) ;
2155
2156     // Load Odd UV Fields
2157     LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE_ALPHA, buf.flipindex
2158              , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
2159              , im->stride[1]*2, im->bpp, im->plane[1] );
2160
2161     // Load Even UV Fields
2162     LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE_ALPHA, buf.flipindex
2163              , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
2164              , im->stride[1]*2, im->bpp, im->plane[1] + im->stride[1] );
2165
2166   }
2167   else
2168   {
2169     // Load Y plane
2170     LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
2171              , im->width, im->height
2172              , im->stride[0], im->bpp, im->plane[0] );
2173
2174     // Load UV plane
2175     LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE_ALPHA, buf.flipindex
2176              , im->width >> im->cshift_x, im->height >> im->cshift_y
2177              , im->stride[1], im->bpp, im->plane[1] );
2178   }
2179
2180   VerifyGLState();
2181
2182   CalculateTextureSourceRects(source, 3);
2183
2184   glDisable(m_textureTarget);
2185   return true;
2186 }
2187
2188 bool CLinuxRendererGL::CreateNV12Texture(int index)
2189 {
2190   // since we also want the field textures, pitch must be texture aligned
2191   YV12Image &im     = m_buffers[index].image;
2192   YUVFIELDS &fields = m_buffers[index].fields;
2193   GLuint    *pbo    = m_buffers[index].pbo;
2194
2195   // Delete any old texture
2196   DeleteNV12Texture(index);
2197
2198   im.height = m_sourceHeight;
2199   im.width  = m_sourceWidth;
2200   im.cshift_x = 1;
2201   im.cshift_y = 1;
2202   im.bpp = 1;
2203
2204   im.stride[0] = im.width;
2205   im.stride[1] = im.width;
2206   im.stride[2] = 0;
2207
2208   im.plane[0] = NULL;
2209   im.plane[1] = NULL;
2210   im.plane[2] = NULL;
2211
2212   // Y plane
2213   im.planesize[0] = im.stride[0] * im.height;
2214   // packed UV plane
2215   im.planesize[1] = im.stride[1] * im.height / 2;
2216   // third plane is not used
2217   im.planesize[2] = 0;
2218
2219   bool pboSetup = false;
2220   if (m_pboUsed)
2221   {
2222     pboSetup = true;
2223     glGenBuffersARB(2, pbo);
2224
2225     for (int i = 0; i < 2; i++)
2226     {
2227       glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[i]);
2228       glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, im.planesize[i] + PBO_OFFSET, 0, GL_STREAM_DRAW_ARB);
2229       void* pboPtr = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB);
2230       if (pboPtr)
2231       {
2232         im.plane[i] = (BYTE*)pboPtr + PBO_OFFSET;
2233         memset(im.plane[i], 0, im.planesize[i]);
2234       }
2235       else
2236       {
2237         CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
2238         pboSetup = false;
2239         break;
2240       }
2241     }
2242
2243     if (!pboSetup)
2244     {
2245       for (int i = 0; i < 2; i++)
2246       {
2247         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[i]);
2248         glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2249       }
2250       glDeleteBuffersARB(2, pbo);
2251       memset(m_buffers[index].pbo, 0, sizeof(m_buffers[index].pbo));
2252     }
2253
2254     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2255   }
2256
2257   if (!pboSetup)
2258   {
2259     for (int i = 0; i < 2; i++)
2260       im.plane[i] = new BYTE[im.planesize[i]];
2261   }
2262
2263   glEnable(m_textureTarget);
2264   for(int f = 0;f<MAX_FIELDS;f++)
2265   {
2266     for(int p = 0;p<2;p++)
2267     {
2268       if (!glIsTexture(fields[f][p].id))
2269       {
2270         glGenTextures(1, &fields[f][p].id);
2271         VerifyGLState();
2272       }
2273       fields[f][p].pbo = pbo[p];
2274     }
2275     fields[f][2].id = fields[f][1].id;
2276   }
2277
2278   // YUV
2279   for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
2280   {
2281     int fieldshift = (f==FIELD_FULL) ? 0 : 1;
2282     YUVPLANES &planes = fields[f];
2283
2284     planes[0].texwidth  = im.width;
2285     planes[0].texheight = im.height >> fieldshift;
2286
2287     if (m_renderMethod & RENDER_SW)
2288     {
2289       planes[1].texwidth  = 0;
2290       planes[1].texheight = 0;
2291       planes[2].texwidth  = 0;
2292       planes[2].texheight = 0;
2293     }
2294     else
2295     {
2296       planes[1].texwidth  = planes[0].texwidth  >> im.cshift_x;
2297       planes[1].texheight = planes[0].texheight >> im.cshift_y;
2298       planes[2].texwidth  = planes[1].texwidth;
2299       planes[2].texheight = planes[1].texheight;
2300     }
2301
2302     for (int p = 0; p < 3; p++)
2303     {
2304       planes[p].pixpertex_x = 1;
2305       planes[p].pixpertex_y = 1;
2306     }
2307
2308     if(m_renderMethod & RENDER_POT)
2309     {
2310       for(int p = 0; p < 3; p++)
2311       {
2312         planes[p].texwidth  = NP2(planes[p].texwidth);
2313         planes[p].texheight = NP2(planes[p].texheight);
2314       }
2315     }
2316
2317     for(int p = 0; p < 2; p++)
2318     {
2319       YUVPLANE &plane = planes[p];
2320       if (plane.texwidth * plane.texheight == 0)
2321         continue;
2322
2323       glBindTexture(m_textureTarget, plane.id);
2324       if (m_renderMethod & RENDER_SW)
2325       {
2326         glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2327       }
2328       else
2329       {
2330         if (p == 1)
2331           glTexImage2D(m_textureTarget, 0, GL_LUMINANCE_ALPHA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
2332         else
2333           glTexImage2D(m_textureTarget, 0, GL_LUMINANCE, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2334       }
2335
2336       glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2337       glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2338       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2339       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2340       VerifyGLState();
2341     }
2342   }
2343   glDisable(m_textureTarget);
2344
2345   return true;
2346 }
2347 void CLinuxRendererGL::DeleteNV12Texture(int index)
2348 {
2349   YV12Image &im     = m_buffers[index].image;
2350   YUVFIELDS &fields = m_buffers[index].fields;
2351   GLuint    *pbo    = m_buffers[index].pbo;
2352
2353   if( fields[FIELD_FULL][0].id == 0 ) return;
2354
2355   // finish up all textures, and delete them
2356   g_graphicsContext.BeginPaint();  //FIXME
2357   for(int f = 0;f<MAX_FIELDS;f++)
2358   {
2359     for(int p = 0;p<2;p++)
2360     {
2361       if( fields[f][p].id )
2362       {
2363         if (glIsTexture(fields[f][p].id))
2364         {
2365           glDeleteTextures(1, &fields[f][p].id);
2366         }
2367         fields[f][p].id = 0;
2368       }
2369     }
2370     fields[f][2].id = 0;
2371   }
2372   g_graphicsContext.EndPaint();
2373
2374   for(int p = 0;p<2;p++)
2375   {
2376     if (pbo[p])
2377     {
2378       if (im.plane[p])
2379       {
2380         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[p]);
2381         glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2382         im.plane[p] = NULL;
2383         glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2384       }
2385       glDeleteBuffersARB(1, pbo + p);
2386       pbo[p] = 0;
2387     }
2388     else
2389     {
2390       if (im.plane[p])
2391       {
2392         delete[] im.plane[p];
2393         im.plane[p] = NULL;
2394       }
2395     }
2396   }
2397 }
2398
2399 void CLinuxRendererGL::DeleteVDPAUTexture(int index)
2400 {
2401 #ifdef HAVE_LIBVDPAU
2402   YUVPLANE &plane = m_buffers[index].fields[FIELD_FULL][0];
2403
2404   SAFE_RELEASE(m_buffers[index].vdpau);
2405
2406   plane.id = 0;
2407 #endif
2408 }
2409
2410 bool CLinuxRendererGL::CreateVDPAUTexture(int index)
2411 {
2412 #ifdef HAVE_LIBVDPAU
2413   YV12Image &im     = m_buffers[index].image;
2414   YUVFIELDS &fields = m_buffers[index].fields;
2415   YUVPLANE  &plane  = fields[FIELD_FULL][0];
2416
2417   DeleteVDPAUTexture(index);
2418
2419   memset(&im    , 0, sizeof(im));
2420   memset(&fields, 0, sizeof(fields));
2421   im.height = m_sourceHeight;
2422   im.width  = m_sourceWidth;
2423
2424   plane.texwidth  = im.width;
2425   plane.texheight = im.height;
2426
2427   plane.pixpertex_x = 1;
2428   plane.pixpertex_y = 1;
2429
2430   plane.id = 1;
2431
2432 #endif
2433   return true;
2434 }
2435
2436 bool CLinuxRendererGL::UploadVDPAUTexture(int index)
2437 {
2438 #ifdef HAVE_LIBVDPAU
2439   VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau;
2440
2441   YV12Image &im     = m_buffers[index].image;
2442   YUVFIELDS &fields = m_buffers[index].fields;
2443   YUVPLANE &plane = fields[FIELD_FULL][0];
2444
2445   if (!vdpau || !vdpau->valid)
2446   {
2447     return false;
2448   }
2449
2450   plane.id = vdpau->texture[0];
2451
2452   // in stereoscopic mode sourceRect may only
2453   // be a part of the source video surface
2454   plane.rect = m_sourceRect;
2455
2456   // clip rect
2457   if (vdpau->crop.x1 > plane.rect.x1)
2458     plane.rect.x1 = vdpau->crop.x1;
2459   if (vdpau->crop.x2 < plane.rect.x2)
2460     plane.rect.x2 = vdpau->crop.x2;
2461   if (vdpau->crop.y1 > plane.rect.y1)
2462     plane.rect.y1 = vdpau->crop.y1;
2463   if (vdpau->crop.y2 < plane.rect.y2)
2464     plane.rect.y2 = vdpau->crop.y2;
2465
2466   plane.texheight = vdpau->texHeight;
2467   plane.texwidth  = vdpau->texWidth;
2468
2469   if (m_textureTarget == GL_TEXTURE_2D)
2470   {
2471     plane.rect.y1 /= plane.texheight;
2472     plane.rect.y2 /= plane.texheight;
2473     plane.rect.x1 /= plane.texwidth;
2474     plane.rect.x2 /= plane.texwidth;
2475   }
2476
2477 #endif
2478   return true;
2479 }
2480
2481 void CLinuxRendererGL::DeleteVDPAUTexture420(int index)
2482 {
2483 #ifdef HAVE_LIBVDPAU
2484   YUVFIELDS &fields = m_buffers[index].fields;
2485
2486   SAFE_RELEASE(m_buffers[index].vdpau);
2487
2488   fields[0][0].id = 0;
2489   fields[1][0].id = 0;
2490   fields[1][1].id = 0;
2491   fields[2][0].id = 0;
2492   fields[2][1].id = 0;
2493
2494 #endif
2495 }
2496
2497 bool CLinuxRendererGL::CreateVDPAUTexture420(int index)
2498 {
2499 #ifdef HAVE_LIBVDPAU
2500   YV12Image &im     = m_buffers[index].image;
2501   YUVFIELDS &fields = m_buffers[index].fields;
2502   YUVPLANE &plane = fields[0][0];
2503   GLuint    *pbo    = m_buffers[index].pbo;
2504
2505   DeleteVDPAUTexture420(index);
2506
2507   memset(&im    , 0, sizeof(im));
2508   memset(&fields, 0, sizeof(fields));
2509
2510   im.cshift_x = 1;
2511   im.cshift_y = 1;
2512
2513   im.plane[0] = NULL;
2514   im.plane[1] = NULL;
2515   im.plane[2] = NULL;
2516
2517   for(int p=0; p<3; p++)
2518   {
2519     pbo[p] = None;
2520   }
2521
2522   plane.id = 1;
2523
2524 #endif
2525   return true;
2526 }
2527
2528 bool CLinuxRendererGL::UploadVDPAUTexture420(int index)
2529 {
2530 #ifdef HAVE_LIBVDPAU
2531   VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau;
2532   YV12Image &im = m_buffers[index].image;
2533
2534   YUVFIELDS &fields = m_buffers[index].fields;
2535
2536   if (!vdpau || !vdpau->valid)
2537   {
2538     return false;
2539   }
2540
2541   im.height = vdpau->texHeight;
2542   im.width  = vdpau->texWidth;
2543
2544   // YUV
2545   for (int f = FIELD_TOP; f<=FIELD_BOT ; f++)
2546   {
2547     YUVPLANES &planes = fields[f];
2548
2549     planes[0].texwidth  = im.width;
2550     planes[0].texheight = im.height >> 1;
2551
2552     planes[1].texwidth  = planes[0].texwidth  >> im.cshift_x;
2553     planes[1].texheight = planes[0].texheight >> im.cshift_y;
2554     planes[2].texwidth  = planes[1].texwidth;
2555     planes[2].texheight = planes[1].texheight;
2556
2557     for (int p = 0; p < 3; p++)
2558     {
2559       planes[p].pixpertex_x = 1;
2560       planes[p].pixpertex_y = 1;
2561     }
2562   }
2563   // crop
2564 //  m_sourceRect.x1 += vdpau->crop.x1;
2565 //  m_sourceRect.x2 -= vdpau->crop.x2;
2566 //  m_sourceRect.y1 += vdpau->crop.y1;
2567 //  m_sourceRect.y2 -= vdpau->crop.y2;
2568
2569   // set textures
2570   fields[1][0].id = vdpau->texture[0];
2571   fields[1][1].id = vdpau->texture[2];
2572   fields[1][2].id = vdpau->texture[2];
2573   fields[2][0].id = vdpau->texture[1];
2574   fields[2][1].id = vdpau->texture[3];
2575   fields[2][2].id = vdpau->texture[3];
2576
2577   glEnable(m_textureTarget);
2578   for (int f = FIELD_TOP; f <= FIELD_BOT; f++)
2579   {
2580     for (int p=0; p<2; p++)
2581     {
2582       glBindTexture(m_textureTarget,fields[f][p].id);
2583       glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2584       glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2585       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2586       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2587
2588       glBindTexture(m_textureTarget,0);
2589       VerifyGLState();
2590     }
2591   }
2592   CalculateTextureSourceRects(index, 3);
2593   glDisable(m_textureTarget);
2594
2595 #endif
2596   return true;
2597 }
2598
2599 void CLinuxRendererGL::DeleteVAAPITexture(int index)
2600 {
2601 #ifdef HAVE_LIBVA
2602   YUVPLANE       &plane = m_buffers[index].fields[0][0];
2603   VAAPI::CHolder &va    = m_buffers[index].vaapi;
2604
2605   va.display.reset();
2606   va.surface.reset();
2607   va.surfglx.reset();
2608
2609   if(plane.id && glIsTexture(plane.id))
2610     glDeleteTextures(1, &plane.id);
2611   plane.id = 0;
2612
2613 #endif
2614 }
2615
2616 bool CLinuxRendererGL::CreateVAAPITexture(int index)
2617 {
2618 #ifdef HAVE_LIBVA
2619   YV12Image &im     = m_buffers[index].image;
2620   YUVFIELDS &fields = m_buffers[index].fields;
2621   YUVPLANE  &plane  = fields[0][0];
2622
2623   DeleteVAAPITexture(index);
2624
2625   memset(&im    , 0, sizeof(im));
2626   memset(&fields, 0, sizeof(fields));
2627   im.height = m_sourceHeight;
2628   im.width  = m_sourceWidth;
2629
2630   plane.texwidth  = im.width;
2631   plane.texheight = im.height;
2632
2633   plane.pixpertex_x = 1;
2634   plane.pixpertex_y = 1;
2635
2636   if(m_renderMethod & RENDER_POT)
2637   {
2638     plane.texwidth  = NP2(plane.texwidth);
2639     plane.texheight = NP2(plane.texheight);
2640   }
2641
2642   glEnable(m_textureTarget);
2643   glGenTextures(1, &plane.id);
2644   VerifyGLState();
2645
2646   glBindTexture(m_textureTarget, plane.id);
2647   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2648   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2649   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2650   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2651   glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
2652   glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
2653   glBindTexture(m_textureTarget, 0);
2654   glDisable(m_textureTarget);
2655 #endif
2656   return true;
2657 }
2658
2659 bool CLinuxRendererGL::UploadVAAPITexture(int index)
2660 {
2661 #ifdef HAVE_LIBVA
2662   YUVPLANE       &plane = m_buffers[index].fields[0][0];
2663   VAAPI::CHolder &va    = m_buffers[index].vaapi;
2664   VAStatus status;
2665
2666   if(!va.surface)
2667     return false;
2668
2669   if(va.display && va.surface->m_display != va.display)
2670   {
2671     CLog::Log(LOGDEBUG, "CLinuxRendererGL::UploadVAAPITexture - context changed %d", index);
2672     va.surfglx.reset();
2673   }
2674   va.display = va.surface->m_display;
2675
2676   CSingleLock lock(*va.display);
2677
2678   if(va.display->lost())
2679     return false;
2680
2681   if(!va.surfglx)
2682   {
2683     CLog::Log(LOGDEBUG, "CLinuxRendererGL::UploadVAAPITexture - creating vaapi surface for texture %d", index);
2684     void* surface;
2685     status = vaCreateSurfaceGLX(va.display->get()
2686                               , m_textureTarget
2687                               , plane.id
2688                               , &surface);
2689     if(status != VA_STATUS_SUCCESS)
2690     {
2691       CLog::Log(LOGERROR, "CLinuxRendererGL::UploadVAAPITexture - failed to create vaapi glx surface (%d)", status);
2692       return false;
2693     }
2694     va.surfglx = VAAPI::CSurfaceGLPtr(new VAAPI::CSurfaceGL(surface, va.display));
2695   }
2696   int colorspace;
2697   if(CONF_FLAGS_YUVCOEF_MASK(m_iFlags) == CONF_FLAGS_YUVCOEF_BT709)
2698     colorspace = VA_SRC_BT709;
2699   else
2700     colorspace = VA_SRC_BT601;
2701
2702   int field;
2703   if      (m_currentField == FIELD_TOP)
2704     field = VA_TOP_FIELD;
2705   else if (m_currentField == FIELD_BOT)
2706     field = VA_BOTTOM_FIELD;
2707   else
2708     field = VA_FRAME_PICTURE;
2709
2710 #if USE_VAAPI_GLX_BIND
2711   status = vaAssociateSurfaceGLX(va.display->get()
2712                                , va.surfglx->m_id
2713                                , va.surface->m_id
2714                                , field | colorspace);
2715 #else
2716   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2717   status = vaCopySurfaceGLX(va.display->get()
2718                           , va.surfglx->m_id
2719                           , va.surface->m_id
2720                           , field | colorspace);
2721 #endif
2722
2723   // when a vaapi backend is lost (vdpau), we start getting these errors
2724   if(status == VA_STATUS_ERROR_INVALID_SURFACE
2725   || status == VA_STATUS_ERROR_INVALID_DISPLAY)
2726   {
2727     va.display->lost(true);
2728     for(int i = 0; i < m_NumYV12Buffers; i++)
2729     {
2730       m_buffers[i].vaapi.display.reset();
2731       m_buffers[i].vaapi.surface.reset();
2732       m_buffers[i].vaapi.surfglx.reset();
2733     }
2734   }
2735
2736   if(status != VA_STATUS_SUCCESS)
2737     CLog::Log(LOGERROR, "CLinuxRendererGL::UploadVAAPITexture - failed to copy surface to glx %d - %s", status, vaErrorStr(status));
2738
2739 #endif
2740   return true;
2741 }
2742
2743 //********************************************************************************************************
2744 // CoreVideoRef Texture creation, deletion, copying + clearing
2745 //********************************************************************************************************
2746 bool CLinuxRendererGL::UploadCVRefTexture(int index)
2747 {
2748 #ifdef TARGET_DARWIN
2749   CVBufferRef cvBufferRef = m_buffers[index].cvBufferRef;
2750
2751   glEnable(m_textureTarget);
2752
2753   if (cvBufferRef)
2754   {
2755     YUVFIELDS &fields = m_buffers[index].fields;
2756     YUVPLANE  &plane  = fields[0][0];
2757
2758     if (Cocoa_GetOSVersion() >= 0x1074)
2759     {
2760       // 10.7.4 for Retina Macbooks on Lion breaks CGLTexImageIOSurface2D/GL_YCBCR_422_APPLE,
2761       // 10.8 Mountain Lion breaks CGLTexImageIOSurface2D/GL_YCBCR_422_APPLE,
2762       // upload the old way.
2763       CVPixelBufferLockBaseAddress(cvBufferRef, kCVPixelBufferLock_ReadOnly);
2764
2765       GLsizei       texHeight   = CVPixelBufferGetHeight(cvBufferRef);
2766       size_t        rowbytes    = CVPixelBufferGetBytesPerRow(cvBufferRef);
2767       unsigned char *bufferBase = (unsigned char*)CVPixelBufferGetBaseAddress(cvBufferRef);
2768
2769       glBindTexture(m_textureTarget, plane.id);
2770       glTexSubImage2D(m_textureTarget, 0, 0, 0, rowbytes/2, texHeight, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, bufferBase);
2771       glBindTexture(m_textureTarget, 0);
2772
2773       CVPixelBufferUnlockBaseAddress(cvBufferRef, kCVPixelBufferLock_ReadOnly);
2774     }
2775     else
2776     {
2777       // It is the fastest way to render a CVPixelBuffer backed
2778       // with an IOSurface as there is no CPU -> GPU upload.
2779       CGLContextObj cgl_ctx  = (CGLContextObj)g_Windowing.GetCGLContextObj();
2780       IOSurfaceRef      surface  = CVPixelBufferGetIOSurface(cvBufferRef);
2781       GLsizei       texWidth = IOSurfaceGetWidth(surface);
2782       GLsizei       texHeight= IOSurfaceGetHeight(surface);
2783       OSType        format_type = CVPixelBufferGetPixelFormatType(cvBufferRef);
2784
2785       glBindTexture(m_textureTarget, plane.id);
2786
2787       if (format_type == kCVPixelFormatType_422YpCbCr8)
2788         CGLTexImageIOSurface2D(cgl_ctx, m_textureTarget, GL_RGB8,
2789           texWidth, texHeight, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, surface, 0);
2790       else if (format_type == kCVPixelFormatType_32BGRA)
2791         CGLTexImageIOSurface2D(cgl_ctx, m_textureTarget, GL_RGBA8,
2792           texWidth, texHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, surface, 0);
2793
2794       glBindTexture(m_textureTarget, 0);
2795     }
2796
2797     CVBufferRelease(cvBufferRef);
2798     m_buffers[index].cvBufferRef = NULL;
2799
2800     plane.flipindex = m_buffers[index].flipindex;
2801   }
2802
2803
2804   CalculateTextureSourceRects(index, 3);
2805   glDisable(m_textureTarget);
2806
2807 #endif
2808   return true;
2809 }
2810
2811 void CLinuxRendererGL::DeleteCVRefTexture(int index)
2812 {
2813 #ifdef TARGET_DARWIN
2814   YUVPLANE  &plane = m_buffers[index].fields[0][0];
2815
2816   if (m_buffers[index].cvBufferRef)
2817     CVBufferRelease(m_buffers[index].cvBufferRef);
2818   m_buffers[index].cvBufferRef = NULL;
2819
2820   if (plane.id && glIsTexture(plane.id))
2821     glDeleteTextures(1, &plane.id), plane.id = 0;
2822 #endif
2823 }
2824
2825 bool CLinuxRendererGL::CreateCVRefTexture(int index)
2826 {
2827 #ifdef TARGET_DARWIN
2828   YV12Image &im     = m_buffers[index].image;
2829   YUVFIELDS &fields = m_buffers[index].fields;
2830   YUVPLANE  &plane  = fields[0][0];
2831
2832   DeleteCVRefTexture(index);
2833
2834   memset(&im    , 0, sizeof(im));
2835   memset(&fields, 0, sizeof(fields));
2836
2837   im.bpp    = 1;
2838   im.width  = m_sourceWidth;
2839   im.height = m_sourceHeight;
2840   im.cshift_x = 0;
2841   im.cshift_y = 0;
2842
2843   plane.texwidth  = NP2(im.width);
2844   plane.texheight = NP2(im.height);
2845   plane.pixpertex_x = 1;
2846   plane.pixpertex_y = 1;
2847
2848   glEnable(m_textureTarget);
2849   glGenTextures(1, &plane.id);
2850   if (Cocoa_GetOSVersion() >= 0x1074)
2851   {
2852     // 10.7.4 for Retina Macbooks on Lion breaks CGLTexImageIOSurface2D/GL_YCBCR_422_APPLE,
2853     // 10.8 Mountain Lion breaks CGLTexImageIOSurface2D/GL_YCBCR_422_APPLE,
2854     // upload the old way.
2855     glBindTexture(m_textureTarget, plane.id);
2856     glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2857     glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2858     // This is necessary for non-power-of-two textures
2859     glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2860     glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2861     glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, NULL);
2862     glBindTexture(m_textureTarget, 0);
2863   }
2864   glDisable(m_textureTarget);
2865
2866 #endif
2867   return true;
2868 }
2869
2870 bool CLinuxRendererGL::UploadYUV422PackedTexture(int source)
2871 {
2872   YUVBUFFER& buf    =  m_buffers[source];
2873   YV12Image* im     = &buf.image;
2874   YUVFIELDS& fields =  buf.fields;
2875
2876   if (!(im->flags & IMAGE_FLAG_READY))
2877     return false;
2878
2879   bool deinterlacing;
2880   if (m_currentField == FIELD_FULL)
2881     deinterlacing = false;
2882   else
2883     deinterlacing = true;
2884
2885   glEnable(m_textureTarget);
2886   VerifyGLState();
2887
2888   glPixelStorei(GL_UNPACK_ALIGNMENT,1);
2889
2890   if (deinterlacing)
2891   {
2892     // Load YUYV fields
2893     LoadPlane( fields[FIELD_TOP][0], GL_BGRA, buf.flipindex
2894              , im->width / 2, im->height >> 1
2895              , im->stride[0] * 2, im->bpp, im->plane[0] );
2896
2897     LoadPlane( fields[FIELD_BOT][0], GL_BGRA, buf.flipindex
2898              , im->width / 2, im->height >> 1
2899              , im->stride[0] * 2, im->bpp, im->plane[0] + im->stride[0]) ;
2900   }
2901   else
2902   {
2903     // Load YUYV plane
2904     LoadPlane( fields[FIELD_FULL][0], GL_BGRA, buf.flipindex
2905              , im->width / 2, im->height
2906              , im->stride[0], im->bpp, im->plane[0] );
2907   }
2908
2909   VerifyGLState();
2910
2911   CalculateTextureSourceRects(source, 3);
2912
2913   glDisable(m_textureTarget);
2914   return true;
2915 }
2916
2917 void CLinuxRendererGL::DeleteYUV422PackedTexture(int index)
2918 {
2919   YV12Image &im     = m_buffers[index].image;
2920   YUVFIELDS &fields = m_buffers[index].fields;
2921   GLuint    *pbo    = m_buffers[index].pbo;
2922
2923   if( fields[FIELD_FULL][0].id == 0 ) return;
2924
2925   // finish up all textures, and delete them
2926   g_graphicsContext.BeginPaint();  //FIXME
2927   for(int f = 0;f<MAX_FIELDS;f++)
2928   {
2929     if( fields[f][0].id )
2930     {
2931       if (glIsTexture(fields[f][0].id))
2932       {
2933         glDeleteTextures(1, &fields[f][0].id);
2934       }
2935       fields[f][0].id = 0;
2936     }
2937     fields[f][1].id = 0;
2938     fields[f][2].id = 0;
2939   }
2940   g_graphicsContext.EndPaint();
2941
2942   if (pbo[0])
2943   {
2944     if (im.plane[0])
2945     {
2946       glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[0]);
2947       glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2948       im.plane[0] = NULL;
2949       glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2950     }
2951     glDeleteBuffersARB(1, pbo);
2952     pbo[0] = 0;
2953   }
2954   else
2955   {
2956     if (im.plane[0])
2957     {
2958       delete[] im.plane[0];
2959       im.plane[0] = NULL;
2960     }
2961   }
2962 }
2963
2964 bool CLinuxRendererGL::CreateYUV422PackedTexture(int index)
2965 {
2966   // since we also want the field textures, pitch must be texture aligned
2967   YV12Image &im     = m_buffers[index].image;
2968   YUVFIELDS &fields = m_buffers[index].fields;
2969   GLuint    *pbo    = m_buffers[index].pbo;
2970
2971   // Delete any old texture
2972   DeleteYUV422PackedTexture(index);
2973
2974   im.height = m_sourceHeight;
2975   im.width  = m_sourceWidth;
2976   im.cshift_x = 0;
2977   im.cshift_y = 0;
2978   im.bpp = 1;
2979
2980   im.stride[0] = im.width * 2;
2981   im.stride[1] = 0;
2982   im.stride[2] = 0;
2983
2984   im.plane[0] = NULL;
2985   im.plane[1] = NULL;
2986   im.plane[2] = NULL;
2987
2988   // packed YUYV plane
2989   im.planesize[0] = im.stride[0] * im.height;
2990   // second plane is not used
2991   im.planesize[1] = 0;
2992   // third plane is not used
2993   im.planesize[2] = 0;
2994
2995   bool pboSetup = false;
2996   if (m_pboUsed)
2997   {
2998     pboSetup = true;
2999     glGenBuffersARB(1, pbo);
3000
3001     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[0]);
3002     glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, im.planesize[0] + PBO_OFFSET, 0, GL_STREAM_DRAW_ARB);
3003     void* pboPtr = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB);
3004     if (pboPtr)
3005     {
3006       im.plane[0] = (BYTE*)pboPtr + PBO_OFFSET;
3007       memset(im.plane[0], 0, im.planesize[0]);
3008     }
3009     else
3010     {
3011       CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
3012       pboSetup = false;
3013     }
3014
3015     if (!pboSetup)
3016     {
3017       glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, *pbo);
3018       glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
3019       glDeleteBuffersARB(1, pbo);
3020       memset(m_buffers[index].pbo, 0, sizeof(m_buffers[index].pbo));
3021     }
3022
3023     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3024   }
3025
3026   if (!pboSetup)
3027   {
3028     im.plane[0] = new BYTE[im.planesize[0]];
3029   }
3030
3031   glEnable(m_textureTarget);
3032   for(int f = 0;f<MAX_FIELDS;f++)
3033   {
3034     if (!glIsTexture(fields[f][0].id))
3035     {
3036       glGenTextures(1, &fields[f][0].id);
3037       VerifyGLState();
3038     }
3039     fields[f][0].pbo = pbo[0];
3040     fields[f][1].id = fields[f][0].id;
3041     fields[f][2].id = fields[f][1].id;
3042   }
3043
3044   // YUV
3045   for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
3046   {
3047     int fieldshift = (f==FIELD_FULL) ? 0 : 1;
3048     YUVPLANES &planes = fields[f];
3049
3050     if (m_renderMethod & RENDER_SW)
3051     {
3052       planes[0].texwidth  = im.width;
3053       planes[0].texheight = im.height >> fieldshift;
3054       planes[1].texwidth  = 0;
3055       planes[1].texheight = 0;
3056       planes[2].texwidth  = 0;
3057       planes[2].texheight = 0;
3058
3059       for (int p = 0; p < 3; p++)
3060       {
3061         planes[p].pixpertex_x = 1;
3062         planes[p].pixpertex_y = 1;
3063       }
3064     }
3065     else
3066     {
3067       planes[0].texwidth  = im.width / 2;
3068       planes[0].texheight = im.height >> fieldshift;
3069       planes[1].texwidth  = planes[0].texwidth;
3070       planes[1].texheight = planes[0].texheight;
3071       planes[2].texwidth  = planes[1].texwidth;
3072       planes[2].texheight = planes[1].texheight;
3073
3074       for (int p = 0; p < 3; p++)
3075       {
3076         planes[p].pixpertex_x = 2;
3077         planes[p].pixpertex_y = 1;
3078       }
3079     }
3080
3081     if(m_renderMethod & RENDER_POT)
3082     {
3083       for(int p = 0; p < 3; p++)
3084       {
3085         planes[p].texwidth  = NP2(planes[p].texwidth);
3086         planes[p].texheight = NP2(planes[p].texheight);
3087       }
3088     }
3089
3090     YUVPLANE &plane = planes[0];
3091     if (plane.texwidth * plane.texheight == 0)
3092       continue;
3093
3094     glBindTexture(m_textureTarget, plane.id);
3095
3096     glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
3097
3098     glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3099     glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3100     glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3101     glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3102     VerifyGLState();
3103   }
3104   glDisable(m_textureTarget);
3105
3106   return true;
3107 }
3108
3109 void CLinuxRendererGL::ToRGBFrame(YV12Image* im, unsigned flipIndexPlane, unsigned flipIndexBuf)
3110 {
3111   if(m_rgbBufferSize != m_sourceWidth * m_sourceHeight * 4)
3112     SetupRGBBuffer();
3113   else if(flipIndexPlane == flipIndexBuf)
3114     return; //conversion already done on the previous iteration
3115
3116   uint8_t *src[4]       = {};
3117   int      srcStride[4] = {};
3118   int      srcFormat    = -1;
3119
3120   if (m_format == RENDER_FMT_YUV420P ||
3121       m_format == RENDER_FMT_YUV420P10 ||
3122       m_format == RENDER_FMT_YUV420P16)
3123   {
3124     srcFormat = CDVDCodecUtils::PixfmtFromEFormat(m_format);
3125     for (int i = 0; i < 3; i++)
3126     {
3127       src[i]       = im->plane[i];
3128       srcStride[i] = im->stride[i];
3129     }
3130   }
3131   else if (m_format == RENDER_FMT_NV12)
3132   {
3133     srcFormat = PIX_FMT_NV12;
3134     for (int i = 0; i < 2; i++)
3135     {
3136       src[i]       = im->plane[i];
3137       srcStride[i] = im->stride[i];
3138     }
3139   }
3140   else if (m_format == RENDER_FMT_YUYV422)
3141   {
3142     srcFormat    = PIX_FMT_YUYV422;
3143     src[0]       = im->plane[0];
3144     srcStride[0] = im->stride[0];
3145   }
3146   else if (m_format == RENDER_FMT_UYVY422)
3147   {
3148     srcFormat    = PIX_FMT_UYVY422;
3149     src[0]       = im->plane[0];
3150     srcStride[0] = im->stride[0];
3151   }
3152   else //should never happen
3153   {
3154     CLog::Log(LOGERROR, "CLinuxRendererGL::ToRGBFrame: called with unsupported format %i", m_format);
3155     return;
3156   }
3157
3158   if (m_rgbPbo)
3159   {
3160     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, m_rgbPbo);
3161     m_rgbBuffer = (BYTE*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB) + PBO_OFFSET;
3162   }
3163
3164   m_context = m_dllSwScale->sws_getCachedContext(m_context,
3165                                                  im->width, im->height, srcFormat,
3166                                                  im->width, im->height, PIX_FMT_BGRA,
3167                                                  SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
3168
3169   uint8_t *dst[]       = { m_rgbBuffer, 0, 0, 0 };
3170   int      dstStride[] = { (int)m_sourceWidth * 4, 0, 0, 0 };
3171   m_dllSwScale->sws_scale(m_context, src, srcStride, 0, im->height, dst, dstStride);
3172
3173   if (m_rgbPbo)
3174   {
3175     glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
3176     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3177     m_rgbBuffer = (BYTE*)PBO_OFFSET;
3178   }
3179 }
3180
3181 void CLinuxRendererGL::ToRGBFields(YV12Image* im, unsigned flipIndexPlaneTop, unsigned flipIndexPlaneBot, unsigned flipIndexBuf)
3182 {
3183   if(m_rgbBufferSize != m_sourceWidth * m_sourceHeight * 4)
3184     SetupRGBBuffer();
3185   else if(flipIndexPlaneTop == flipIndexBuf && flipIndexPlaneBot == flipIndexBuf)
3186     return; //conversion already done on the previous iteration
3187
3188   uint8_t *srcTop[4]       = {};
3189   int      srcStrideTop[4] = {};
3190   uint8_t *srcBot[4]       = {};
3191   int      srcStrideBot[4] = {};
3192   int      srcFormat       = -1;
3193
3194   if (m_format == RENDER_FMT_YUV420P)
3195   {
3196     srcFormat = PIX_FMT_YUV420P;
3197     for (int i = 0; i < 3; i++)
3198     {
3199       srcTop[i]       = im->plane[i];
3200       srcStrideTop[i] = im->stride[i] * 2;
3201       srcBot[i]       = im->plane[i] + im->stride[i];
3202       srcStrideBot[i] = im->stride[i] * 2;
3203     }
3204   }
3205   else if (m_format == RENDER_FMT_NV12)
3206   {
3207     srcFormat = PIX_FMT_NV12;
3208     for (int i = 0; i < 2; i++)
3209     {
3210       srcTop[i]       = im->plane[i];
3211       srcStrideTop[i] = im->stride[i] * 2;
3212       srcBot[i]       = im->plane[i] + im->stride[i];
3213       srcStrideBot[i] = im->stride[i] * 2;
3214     }
3215   }
3216   else if (m_format == RENDER_FMT_YUYV422)
3217   {
3218     srcFormat       = PIX_FMT_YUYV422;
3219     srcTop[0]       = im->plane[0];
3220     srcStrideTop[0] = im->stride[0] * 2;
3221     srcBot[0]       = im->plane[0] + im->stride[0];
3222     srcStrideBot[0] = im->stride[0] * 2;
3223   }
3224   else if (m_format == RENDER_FMT_UYVY422)
3225   {
3226     srcFormat       = PIX_FMT_UYVY422;
3227     srcTop[0]       = im->plane[0];
3228     srcStrideTop[0] = im->stride[0] * 2;
3229     srcBot[0]       = im->plane[0] + im->stride[0];
3230     srcStrideBot[0] = im->stride[0] * 2;
3231   }
3232   else //should never happen
3233   {
3234     CLog::Log(LOGERROR, "CLinuxRendererGL::ToRGBFields: called with unsupported format %i", m_format);
3235     return;
3236   }
3237
3238   if (m_rgbPbo)
3239   {
3240     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, m_rgbPbo);
3241     m_rgbBuffer = (BYTE*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB) + PBO_OFFSET;
3242   }
3243
3244   m_context = m_dllSwScale->sws_getCachedContext(m_context,
3245                                                  im->width, im->height >> 1, srcFormat,
3246                                                  im->width, im->height >> 1, PIX_FMT_BGRA,
3247                                                  SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
3248   uint8_t *dstTop[]    = { m_rgbBuffer, 0, 0, 0 };
3249   uint8_t *dstBot[]    = { m_rgbBuffer + m_sourceWidth * m_sourceHeight * 2, 0, 0, 0 };
3250   int      dstStride[] = { (int)m_sourceWidth * 4, 0, 0, 0 };
3251
3252   //convert each YUV field to an RGB field, the top field is placed at the top of the rgb buffer
3253   //the bottom field is placed at the bottom of the rgb buffer
3254   m_dllSwScale->sws_scale(m_context, srcTop, srcStrideTop, 0, im->height >> 1, dstTop, dstStride);
3255   m_dllSwScale->sws_scale(m_context, srcBot, srcStrideBot, 0, im->height >> 1, dstBot, dstStride);
3256
3257   if (m_rgbPbo)
3258   {
3259     glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
3260     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3261     m_rgbBuffer = (BYTE*)PBO_OFFSET;
3262   }
3263 }
3264
3265 void CLinuxRendererGL::SetupRGBBuffer()
3266 {
3267   m_rgbBufferSize = m_sourceWidth * m_sourceHeight * 4;
3268
3269   if (!m_rgbPbo)
3270     delete [] m_rgbBuffer;
3271
3272   if (m_pboSupported)
3273   {
3274     CLog::Log(LOGNOTICE, "GL: Using GL_ARB_pixel_buffer_object");
3275
3276     if (!m_rgbPbo)
3277       glGenBuffersARB(1, &m_rgbPbo);
3278
3279     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, m_rgbPbo);
3280     glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, m_rgbBufferSize + PBO_OFFSET, 0, GL_STREAM_DRAW_ARB);
3281     m_rgbBuffer = (BYTE*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB) + PBO_OFFSET;
3282
3283     if (!m_rgbBuffer)
3284     {
3285       CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
3286       glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3287       glDeleteBuffersARB(1, &m_rgbPbo);
3288       m_rgbPbo = 0;
3289     }
3290     else
3291     {
3292       glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
3293       glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3294       m_rgbBuffer = (BYTE*)PBO_OFFSET;
3295     }
3296   }
3297
3298   if (!m_rgbPbo)
3299     m_rgbBuffer = new BYTE[m_rgbBufferSize];
3300 }
3301
3302 bool CLinuxRendererGL::UploadRGBTexture(int source)
3303 {
3304   YUVBUFFER& buf    =  m_buffers[source];
3305   YV12Image* im     = &buf.image;
3306   YUVFIELDS& fields =  buf.fields;
3307
3308   if (!(im->flags&IMAGE_FLAG_READY))
3309     return false;
3310
3311   bool deinterlacing;
3312   if (m_currentField == FIELD_FULL)
3313     deinterlacing = false;
3314   else
3315     deinterlacing = true;
3316
3317   glEnable(m_textureTarget);
3318   VerifyGLState();
3319
3320   if (deinterlacing)
3321     ToRGBFields(im, fields[FIELD_TOP][0].flipindex, fields[FIELD_BOT][0].flipindex, buf.flipindex);
3322   else
3323     ToRGBFrame(im, fields[FIELD_FULL][0].flipindex, buf.flipindex);
3324
3325   static int imaging = -1;
3326   if (imaging==-1)
3327   {
3328     imaging = 0;
3329     if (glewIsSupported("GL_ARB_imaging"))
3330     {
3331       CLog::Log(LOGINFO, "GL: ARB Imaging extension supported");
3332       imaging = 1;
3333     }
3334     else
3335     {
3336       unsigned int maj=0, min=0;
3337       g_Windowing.GetRenderVersion(maj, min);
3338       if (maj>=2)
3339       {
3340         imaging = 1;
3341       }
3342       else if (min>=2)
3343       {
3344         imaging = 1;
3345       }
3346     }
3347   }
3348
3349   if (imaging==1 &&
3350       ((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness!=50) ||
3351        (CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast!=50)))
3352   {
3353     GLfloat brightness = ((GLfloat)CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness - 50.0f)/100.0f;;
3354     GLfloat contrast   = ((GLfloat)CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)/50.0f;
3355
3356     glPixelTransferf(GL_RED_SCALE  , contrast);
3357     glPixelTransferf(GL_GREEN_SCALE, contrast);
3358     glPixelTransferf(GL_BLUE_SCALE , contrast);
3359     glPixelTransferf(GL_RED_BIAS   , brightness);
3360     glPixelTransferf(GL_GREEN_BIAS , brightness);
3361     glPixelTransferf(GL_BLUE_BIAS  , brightness);
3362     VerifyGLState();
3363     imaging++;
3364   }
3365
3366   glPixelStorei(GL_UNPACK_ALIGNMENT,1);
3367
3368   // Load RGB image
3369   if (deinterlacing)
3370   {
3371     LoadPlane( fields[FIELD_TOP][0] , GL_BGRA, buf.flipindex
3372              , im->width, im->height >> 1
3373              , m_sourceWidth*4, 1, m_rgbBuffer, &m_rgbPbo );
3374
3375     LoadPlane( fields[FIELD_BOT][0], GL_BGRA, buf.flipindex
3376              , im->width, im->height >> 1
3377              , m_sourceWidth*4, 1, m_rgbBuffer + m_sourceWidth*m_sourceHeight*2, &m_rgbPbo );
3378   }
3379   else
3380   {
3381     LoadPlane( fields[FIELD_FULL][0], GL_BGRA, buf.flipindex
3382              , im->width, im->height
3383              , m_sourceWidth*4, 1, m_rgbBuffer, &m_rgbPbo );
3384   }
3385
3386   //after using the pbo to upload, allocate a new buffer so we don't have to wait
3387   //for the upload to finish when mapping the buffer 
3388   if (m_rgbPbo)
3389   {
3390     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, m_rgbPbo);
3391     glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, m_rgbBufferSize + PBO_OFFSET, 0, GL_STREAM_DRAW_ARB);
3392     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3393   }
3394
3395   if (imaging==2)
3396   {
3397     imaging--;
3398     glPixelTransferf(GL_RED_SCALE, 1.0);
3399     glPixelTransferf(GL_GREEN_SCALE, 1.0);
3400     glPixelTransferf(GL_BLUE_SCALE, 1.0);
3401     glPixelTransferf(GL_RED_BIAS, 0.0);
3402     glPixelTransferf(GL_GREEN_BIAS, 0.0);
3403     glPixelTransferf(GL_BLUE_BIAS, 0.0);
3404     VerifyGLState();
3405   }
3406
3407   VerifyGLState();
3408
3409   CalculateTextureSourceRects(source, 3);
3410
3411   glDisable(m_textureTarget);
3412   return true;
3413 }
3414
3415 void CLinuxRendererGL::SetTextureFilter(GLenum method)
3416 {
3417   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
3418   {
3419     YUVFIELDS &fields = m_buffers[i].fields;
3420
3421     for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
3422     {
3423       for (int p = 0; p < 3; p++)
3424       {
3425         if(glIsTexture(fields[f][p].id))
3426         {
3427           glBindTexture(m_textureTarget, fields[f][p].id);
3428           glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
3429           glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
3430           VerifyGLState();
3431         }
3432       }
3433     }
3434   }
3435 }
3436
3437 bool CLinuxRendererGL::Supports(ERENDERFEATURE feature)
3438 {
3439   if(feature == RENDERFEATURE_BRIGHTNESS)
3440   {
3441     if ((m_renderMethod & RENDER_VDPAU) && !CSettings::Get().GetBool("videoscreen.limitedrange"))
3442       return true;
3443
3444     if (m_renderMethod & RENDER_VAAPI)
3445       return false;
3446
3447     return (m_renderMethod & RENDER_GLSL)
3448         || (m_renderMethod & RENDER_ARB)
3449         || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE);
3450   }
3451   
3452   if(feature == RENDERFEATURE_CONTRAST)
3453   {
3454     if ((m_renderMethod & RENDER_VDPAU) && !CSettings::Get().GetBool("videoscreen.limitedrange"))
3455       return true;
3456
3457     if (m_renderMethod & RENDER_VAAPI)
3458       return false;
3459
3460     return (m_renderMethod & RENDER_GLSL)
3461         || (m_renderMethod & RENDER_ARB)
3462         || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE);
3463   }
3464
3465   if(feature == RENDERFEATURE_GAMMA)
3466     return false;
3467   
3468   if(feature == RENDERFEATURE_NOISE)
3469   {
3470     if(m_renderMethod & RENDER_VDPAU)
3471       return true;
3472   }
3473
3474   if(feature == RENDERFEATURE_SHARPNESS)
3475   {
3476     if(m_renderMethod & RENDER_VDPAU)
3477       return true;
3478   }
3479
3480   if (feature == RENDERFEATURE_NONLINSTRETCH)
3481   {
3482     if (((m_renderMethod & RENDER_GLSL) && !(m_renderMethod & RENDER_POT)) ||
3483         (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI))
3484       return true;
3485   }
3486
3487   if (feature == RENDERFEATURE_STRETCH         ||
3488       feature == RENDERFEATURE_CROP            ||
3489       feature == RENDERFEATURE_ZOOM            ||
3490       feature == RENDERFEATURE_VERTICAL_SHIFT  ||
3491       feature == RENDERFEATURE_PIXEL_RATIO     ||
3492       feature == RENDERFEATURE_POSTPROCESS     ||
3493       feature == RENDERFEATURE_ROTATION)
3494     return true;
3495
3496   return false;
3497 }
3498
3499 bool CLinuxRendererGL::SupportsMultiPassRendering()
3500 {
3501   return glewIsSupported("GL_EXT_framebuffer_object") && glCreateProgram;
3502 }
3503
3504 bool CLinuxRendererGL::Supports(EDEINTERLACEMODE mode)
3505 {
3506   if(m_renderMethod & RENDER_CVREF)
3507     return false;
3508
3509   if(mode == VS_DEINTERLACEMODE_OFF
3510   || mode == VS_DEINTERLACEMODE_AUTO
3511   || mode == VS_DEINTERLACEMODE_FORCE)
3512     return true;
3513
3514   return false;
3515 }
3516
3517 bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method)
3518 {
3519   if(m_renderMethod & RENDER_CVREF)
3520     return false;
3521
3522   if(method == VS_INTERLACEMETHOD_AUTO)
3523     return true;
3524
3525   if(m_renderMethod & RENDER_VDPAU ||
3526       m_format == RENDER_FMT_VDPAU_420)
3527   {
3528 #ifdef HAVE_LIBVDPAU
3529     VDPAU::CVdpauRenderPicture *vdpauPic = m_buffers[m_iYV12RenderBuffer].vdpau;
3530     if(vdpauPic && vdpauPic->vdpau)
3531       return vdpauPic->vdpau->Supports(method);
3532 #endif
3533     return false;
3534   }
3535
3536   if(m_renderMethod & RENDER_VAAPI)
3537   {
3538 #ifdef HAVE_LIBVA
3539     VAAPI::CDisplayPtr disp = m_buffers[m_iYV12RenderBuffer].vaapi.display;
3540     if(disp)
3541     {
3542       CSingleLock lock(*disp);
3543
3544       if(disp->support_deinterlace())
3545       {
3546         if( method == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED
3547         ||  method == VS_INTERLACEMETHOD_RENDER_BOB )
3548           return true;
3549       }
3550     }
3551 #endif
3552     return false;
3553   }
3554
3555 #ifdef TARGET_DARWIN
3556   // YADIF too slow for HD but we have no methods to fall back
3557   // to something that works so just turn it off.
3558   if(method == VS_INTERLACEMETHOD_DEINTERLACE)
3559     return false;
3560 #endif
3561   
3562   if(method == VS_INTERLACEMETHOD_DEINTERLACE
3563   || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF
3564   || method == VS_INTERLACEMETHOD_SW_BLEND)
3565     return true;
3566
3567   if((method == VS_INTERLACEMETHOD_RENDER_BLEND
3568   ||  method == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED
3569   ||  method == VS_INTERLACEMETHOD_RENDER_WEAVE
3570   ||  method == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED
3571   ||  method == VS_INTERLACEMETHOD_RENDER_BOB))
3572     return true;
3573
3574   return false;
3575 }
3576
3577 bool CLinuxRendererGL::Supports(ESCALINGMETHOD method)
3578 {
3579   //nearest neighbor doesn't work on YUY2 and UYVY
3580   if (method == VS_SCALINGMETHOD_NEAREST &&
3581       m_format != RENDER_FMT_YUYV422 &&
3582       m_format != RENDER_FMT_UYVY422)
3583     return true;
3584
3585   if(method == VS_SCALINGMETHOD_LINEAR
3586   || method == VS_SCALINGMETHOD_AUTO)
3587     return true;
3588
3589   if(method == VS_SCALINGMETHOD_CUBIC
3590   || method == VS_SCALINGMETHOD_LANCZOS2
3591   || method == VS_SCALINGMETHOD_SPLINE36_FAST
3592   || method == VS_SCALINGMETHOD_LANCZOS3_FAST
3593   || method == VS_SCALINGMETHOD_SPLINE36
3594   || method == VS_SCALINGMETHOD_LANCZOS3)
3595   {
3596     // if scaling is below level, avoid hq scaling
3597     float scaleX = fabs(((float)m_sourceWidth - m_destRect.Width())/m_sourceWidth)*100;
3598     float scaleY = fabs(((float)m_sourceHeight - m_destRect.Height())/m_sourceHeight)*100;
3599     int minScale = CSettings::Get().GetInt("videoplayer.hqscalers");
3600     if (scaleX < minScale && scaleY < minScale)
3601       return false;
3602
3603     if ((glewIsSupported("GL_EXT_framebuffer_object") && (m_renderMethod & RENDER_GLSL)) ||
3604         (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI))
3605     {
3606       // spline36 and lanczos3 are only allowed through advancedsettings.xml
3607       if(method != VS_SCALINGMETHOD_SPLINE36
3608       && method != VS_SCALINGMETHOD_LANCZOS3)
3609         return true;
3610       else
3611         return g_advancedSettings.m_videoEnableHighQualityHwScalers;
3612     }
3613   }
3614  
3615   return false;
3616 }
3617
3618 EINTERLACEMETHOD CLinuxRendererGL::AutoInterlaceMethod()
3619 {
3620   if(m_renderMethod & RENDER_CVREF)
3621     return VS_INTERLACEMETHOD_NONE;
3622
3623   if(m_renderMethod & RENDER_VDPAU)
3624     return VS_INTERLACEMETHOD_NONE;
3625
3626   if(Supports(VS_INTERLACEMETHOD_RENDER_BOB))
3627     return VS_INTERLACEMETHOD_RENDER_BOB;
3628
3629   return VS_INTERLACEMETHOD_NONE;
3630 }
3631
3632 void CLinuxRendererGL::BindPbo(YUVBUFFER& buff)
3633 {
3634   bool pbo = false;
3635   for(int plane = 0; plane < MAX_PLANES; plane++)
3636   {
3637     if(!buff.pbo[plane] || buff.image.plane[plane] == (BYTE*)PBO_OFFSET)
3638       continue;
3639     pbo = true;
3640
3641     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, buff.pbo[plane]);
3642     glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
3643     buff.image.plane[plane] = (BYTE*)PBO_OFFSET;
3644   }
3645   if(pbo)
3646     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3647 }
3648
3649 void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff)
3650 {
3651   bool pbo = false;
3652   for(int plane = 0; plane < MAX_PLANES; plane++)
3653   {
3654     if(!buff.pbo[plane] || buff.image.plane[plane] != (BYTE*)PBO_OFFSET)
3655       continue;
3656     pbo = true;
3657
3658     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, buff.pbo[plane]);
3659     glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, buff.image.planesize[plane] + PBO_OFFSET, NULL, GL_STREAM_DRAW_ARB);
3660     buff.image.plane[plane] = (BYTE*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB) + PBO_OFFSET;
3661   }
3662   if(pbo)
3663     glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3664 }
3665
3666 unsigned int CLinuxRendererGL::GetProcessorSize()
3667 {
3668   if(m_format == RENDER_FMT_VDPAU
3669   || m_format == RENDER_FMT_VDPAU_420
3670   || m_format == RENDER_FMT_VAAPI
3671   || m_format == RENDER_FMT_CVBREF)
3672     return 1;
3673   else
3674     return 0;
3675 }
3676
3677 #ifdef HAVE_LIBVDPAU
3678 void CLinuxRendererGL::AddProcessor(VDPAU::CVdpauRenderPicture *vdpau, int index)
3679 {
3680   YUVBUFFER &buf = m_buffers[index];
3681   VDPAU::CVdpauRenderPicture *pic = vdpau->Acquire();
3682   SAFE_RELEASE(buf.vdpau);
3683   buf.vdpau = pic;
3684 }
3685 #endif
3686
3687 #ifdef HAVE_LIBVA
3688 void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder, int index)
3689 {
3690   YUVBUFFER &buf = m_buffers[index];
3691   buf.vaapi.surface = holder.surface;
3692 }
3693 #endif
3694
3695 #ifdef TARGET_DARWIN
3696 void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
3697 {
3698   YUVBUFFER &buf = m_buffers[index];
3699   if (buf.cvBufferRef)
3700     CVBufferRelease(buf.cvBufferRef);
3701   buf.cvBufferRef = cvBufferRef;
3702   // retain another reference, this way dvdplayer and renderer can issue releases.
3703   CVBufferRetain(buf.cvBufferRef);
3704 }
3705 #endif
3706
3707 #endif