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
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)
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.
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/>.
24 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
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"
54 #include "cores/dvdplayer/DVDCodecs/Video/VDPAU.h"
58 #include <va/va_x11.h>
59 #include <va/va_glx.h>
60 #include "cores/dvdplayer/DVDCodecs/Video/VAAPI.h"
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)))
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"
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
89 using namespace Shaders;
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,
127 CLinuxRendererGL::YUVBUFFER::YUVBUFFER()
129 : vaapi(*(new VAAPI::CHolder()))
132 memset(&fields, 0, sizeof(fields));
133 memset(&image , 0, sizeof(image));
134 memset(&pbo , 0, sizeof(pbo));
139 #ifdef TARGET_DARWIN_OSX
144 CLinuxRendererGL::YUVBUFFER::~YUVBUFFER()
149 #ifdef TARGET_DARWIN_OSX
151 CVBufferRelease(cvBufferRef);
155 CLinuxRendererGL::CLinuxRendererGL()
157 m_textureTarget = GL_TEXTURE_2D;
159 m_renderMethod = RENDER_GLSL;
160 m_renderQuality = RQ_SINGLEPASS;
162 m_format = RENDER_FMT_NONE;
164 m_iYV12RenderBuffer = 0;
166 m_currentField = FIELD_FULL;
169 m_pVideoFilterShader = NULL;
170 m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
171 m_scalingMethodGui = (ESCALINGMETHOD)-1;
173 // default texture handlers to YUV
174 m_textureUpload = &CLinuxRendererGL::UploadYV12Texture;
175 m_textureCreate = &CLinuxRendererGL::CreateYV12Texture;
176 m_textureDelete = &CLinuxRendererGL::DeleteYV12Texture;
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;
192 m_nonLinStretch = false;
193 m_nonLinStretchGui = false;
196 m_dllSwScale = new DllSwScale;
199 CLinuxRendererGL::~CLinuxRendererGL()
205 glDeleteBuffersARB(1, &m_rgbPbo);
211 delete [] m_rgbBuffer;
217 m_dllSwScale->sws_freeContext(m_context);
223 m_pYUVShader->Free();
231 bool CLinuxRendererGL::ValidateRenderer()
236 // if its first pass, just init textures and return
237 if (ValidateRenderTarget())
240 // this needs to be checked after texture validation
244 int index = m_iYV12RenderBuffer;
245 YUVBUFFER& buf = m_buffers[index];
247 if (!buf.fields[FIELD_FULL][0].id)
250 if (buf.image.flags==0)
256 bool CLinuxRendererGL::ValidateRenderTarget()
260 if ((m_format == RENDER_FMT_CVBREF) ||
261 (!glewIsSupported("GL_ARB_texture_non_power_of_two") && glewIsSupported("GL_ARB_texture_rectangle")))
263 CLog::Log(LOGNOTICE,"Using GL_TEXTURE_RECTANGLE_ARB");
264 m_textureTarget = GL_TEXTURE_RECTANGLE_ARB;
267 CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D");
269 // function pointer for texture might change in
270 // call to LoadShaders
272 for (int i = 0 ; i < NUM_BUFFERS ; i++)
273 (this->*m_textureDelete)(i);
275 // trigger update of video filters
276 m_scalingMethodGui = (ESCALINGMETHOD)-1;
278 // create the yuv textures
281 for (int i = 0 ; i < m_NumYV12Buffers ; i++)
282 (this->*m_textureCreate)(i);
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)
292 m_sourceWidth = width;
293 m_sourceHeight = height;
294 m_renderOrientation = orientation;
301 // Calculate the input frame aspect ratio.
302 CalculateFrameAspectRatio(d_width, d_height);
303 ChooseBestResolution(fps);
304 SetViewMode(CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode);
307 m_bConfigured = true;
308 m_bImageReady = false;
309 m_scalingMethodGui = (ESCALINGMETHOD)-1;
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;
315 for (int i = 0 ; i<m_NumYV12Buffers ; i++)
316 m_buffers[i].image.flags = 0;
318 m_iLastRenderBuffer = -1;
320 m_nonLinStretch = false;
321 m_nonLinStretchGui = false;
324 m_pboSupported = glewIsSupported("GL_ARB_pixel_buffer_object") && CSettings::Get().GetBool("videoplayer.usepbo");
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())
332 std::string rendervendor = g_Windowing.GetRenderVendor();
333 StringUtils::ToLower(rendervendor);
334 if (rendervendor.find("intel") != std::string::npos)
335 m_pboSupported = false;
342 int CLinuxRendererGL::NextYV12Texture()
344 return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
347 int CLinuxRendererGL::GetImage(YV12Image *image, int source, bool readonly)
349 if (!image) return -1;
350 if (!m_bValidated) return -1;
352 /* take next available buffer */
353 if( source == AUTOSOURCE )
354 source = NextYV12Texture();
356 YV12Image &im = m_buffers[source].image;
358 if ((im.flags&(~IMAGE_FLAG_READY)) != 0)
360 CLog::Log(LOGDEBUG, "CLinuxRenderer::GetImage - request image but none to give");
365 im.flags |= IMAGE_FLAG_READING;
367 im.flags |= IMAGE_FLAG_WRITING;
369 // copy the image - should be operator of YV12Image
370 for (int p=0;p<MAX_PLANES;p++)
372 image->plane[p] = im.plane[p];
373 image->stride[p] = im.stride[p];
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;
385 void CLinuxRendererGL::ReleaseImage(int source, bool preserve)
387 YV12Image &im = m_buffers[source].image;
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 */
394 im.flags |= IMAGE_FLAG_RESERVED;
396 m_bImageReady = true;
399 void CLinuxRendererGL::GetPlaneTextureSize(YUVPLANE& plane)
401 /* texture is assumed to be bound */
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)
412 CLog::Log(LOGDEBUG, "CLinuxRendererGL::GetPlaneTextureSize - invalid size %dx%d - %d", width, height, border);
413 /* to something that avoid division by zero */
420 void CLinuxRendererGL::CalculateTextureSourceRects(int source, int num_planes)
422 YUVBUFFER& buf = m_buffers[source];
423 YV12Image* im = &buf.image;
424 YUVFIELDS& fields = buf.fields;
426 // calculate the source rectangle
427 for(int field = 0; field < 3; field++)
429 for(int plane = 0; plane < num_planes; plane++)
431 YUVPLANE& p = fields[field][plane];
433 p.rect = m_sourceRect;
435 p.height = im->height;
437 if(field != FIELD_FULL)
439 /* correct for field offsets and chroma offsets */
440 float offset_y = 0.5;
443 if(field == FIELD_BOT)
446 p.rect.y1 += offset_y;
447 p.rect.y2 += offset_y;
449 /* half the height if this is a field */
457 p.width /= 1 << im->cshift_x;
458 p.height /= 1 << im->cshift_y;
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;
466 // protect against division by zero
467 if (p.texheight == 0 || p.texwidth == 0 ||
468 p.pixpertex_x == 0 || p.pixpertex_y == 0)
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;
480 if (m_textureTarget == GL_TEXTURE_2D)
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;
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*/)
497 if(plane.flipindex == flipindex)
500 //if no pbo given, use the plane pbo
508 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, currPbo);
510 int bps = bpp * glFormatElementByteCount(type);
514 datatype = GL_UNSIGNED_SHORT;
516 datatype = GL_UNSIGNED_BYTE;
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);
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
527 , (unsigned char*)data + stride * (height-1));
529 if(width < plane.texwidth)
530 glTexSubImage2D( m_textureTarget, 0
531 , width, 0, 1, height
533 , (unsigned char*)data + bps * (width-1));
535 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
536 glBindTexture(m_textureTarget, 0);
538 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
540 plane.flipindex = flipindex;
543 void CLinuxRendererGL::Reset()
545 for(int i=0; i<m_NumYV12Buffers; i++)
547 /* reset all image flags, this will cleanup textures later */
548 m_buffers[i].image.flags = 0;
552 void CLinuxRendererGL::Flush()
559 for (int i = 0 ; i < m_NumYV12Buffers ; i++)
560 (this->*m_textureDelete)(i);
563 m_bValidated = false;
565 m_iYV12RenderBuffer = 0;
568 void CLinuxRendererGL::ReleaseBuffer(int idx)
570 #if defined(HAVE_LIBVDPAU) || defined(HAVE_LIBVA) || defined(TARGET_DARWIN)
571 YUVBUFFER &buf = m_buffers[idx];
574 SAFE_RELEASE(buf.vdpau);
577 buf.vaapi.surface.reset();
581 CVBufferRelease(buf.cvBufferRef);
582 buf.cvBufferRef = NULL;
586 void CLinuxRendererGL::Update()
588 if (!m_bConfigured) return;
590 m_scalingMethodGui = (ESCALINGMETHOD)-1;
593 void CLinuxRendererGL::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
595 int index = m_iYV12RenderBuffer;
597 if (!ValidateRenderer())
599 if (clear) //if clear is set, we're expected to overwrite all backbuffer pixels, even if we have nothing to render
607 g_graphicsContext.BeginPaint();
611 //draw black bars when video is not transparent, clear the entire backbuffer when it is
621 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
622 glColor4f(1.0f, 1.0f, 1.0f, alpha / 255.0f);
627 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
630 if(flags & RENDER_FLAG_WEAVE)
632 int top_index = index;
633 int bot_index = index;
635 if((flags & RENDER_FLAG_FIELD0) && m_iLastRenderBuffer > -1)
637 if(flags & RENDER_FLAG_TOP)
638 bot_index = m_iLastRenderBuffer;
640 top_index = m_iLastRenderBuffer;
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);
652 Render(flags, index);
658 g_graphicsContext.EndPaint();
661 void CLinuxRendererGL::ClearBackBuffer()
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);
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()
673 glColor4f(m_clearColour, m_clearColour, m_clearColour, 1.0f);
678 if (m_rotatedDestCoords[0].y > 0.0)
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);
687 if (m_rotatedDestCoords[2].y < g_graphicsContext.GetHeight())
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);
696 if (m_rotatedDestCoords[0].x > 0.0)
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);
705 if (m_rotatedDestCoords[2].x < g_graphicsContext.GetWidth())
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);
716 void CLinuxRendererGL::FlipPage(int source)
718 UnBindPbo(m_buffers[m_iYV12RenderBuffer]);
720 m_iLastRenderBuffer = m_iYV12RenderBuffer;
722 if( source >= 0 && source < m_NumYV12Buffers )
723 m_iYV12RenderBuffer = source;
725 m_iYV12RenderBuffer = NextYV12Texture();
727 BindPbo(m_buffers[m_iYV12RenderBuffer]);
729 m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
734 unsigned int CLinuxRendererGL::PreInit()
736 CSingleLock lock(g_graphicsContext);
737 m_bConfigured = false;
738 m_bValidated = false;
740 m_resolution = CDisplaySettings::Get().GetCurrentResolution();
741 if ( m_resolution == RES_WINDOW )
742 m_resolution = RES_DESKTOP;
744 m_iYV12RenderBuffer = 0;
747 m_formats.push_back(RENDER_FMT_YUV420P);
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
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.
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);
769 m_formats.push_back(RENDER_FMT_YUV420P10);
770 m_formats.push_back(RENDER_FMT_YUV420P16);
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);
777 m_formats.push_back(RENDER_FMT_CVBREF);
780 // setup the background colour
781 m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
783 if (!m_dllSwScale->Load())
784 CLog::Log(LOGERROR,"CLinuxRendererGL::PreInit - failed to load rescale libraries!");
789 void CLinuxRendererGL::UpdateVideoFilter()
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)
796 m_nonLinStretchGui = CDisplaySettings::Get().IsNonLinearStretched();
797 m_pixelRatio = CDisplaySettings::Get().GetPixelRatio();
799 nonLinStretchChanged = true;
801 if (m_nonLinStretchGui && (m_pixelRatio < 0.999f || m_pixelRatio > 1.001f) && Supports(RENDERFEATURE_NONLINSTRETCH))
803 m_nonLinStretch = true;
804 CLog::Log(LOGDEBUG, "GL: Enabling non-linear stretch");
808 m_nonLinStretch = false;
809 CLog::Log(LOGDEBUG, "GL: Disabling non-linear stretch");
813 if (m_scalingMethodGui == CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod && !nonLinStretchChanged)
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)
821 m_scalingMethodGui = CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod;
822 m_scalingMethod = m_scalingMethodGui;
824 if(!Supports(m_scalingMethod))
826 CLog::Log(LOGWARNING, "CLinuxRendererGL::UpdateVideoFilter - choosen scaling method %d, is not supported by renderer", (int)m_scalingMethod);
827 m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
830 if (m_pVideoFilterShader)
832 m_pVideoFilterShader->Free();
833 delete m_pVideoFilterShader;
834 m_pVideoFilterShader = NULL;
840 if (m_scalingMethod == VS_SCALINGMETHOD_AUTO)
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;
846 if (Supports(VS_SCALINGMETHOD_LANCZOS3_FAST) && scaleSD && scaleUp && scaleFps)
847 m_scalingMethod = VS_SCALINGMETHOD_LANCZOS3_FAST;
849 m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
852 switch (m_scalingMethod)
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)
860 m_pVideoFilterShader = new StretchFilterShader();
861 if (!m_pVideoFilterShader->CompileAndLink())
863 CLog::Log(LOGERROR, "GL: Error compiling and linking video filter shader");
869 m_pVideoFilterShader = new DefaultFilterShader();
870 if (!m_pVideoFilterShader->CompileAndLink())
872 CLog::Log(LOGERROR, "GL: Error compiling and linking video filter shader");
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)
886 if (!m_fbo.fbo.Initialize())
888 CLog::Log(LOGERROR, "GL: Error initializing FBO");
892 if (!m_fbo.fbo.CreateAndBindToTexture(GL_TEXTURE_2D, m_sourceWidth, m_sourceHeight, GL_RGBA))
894 CLog::Log(LOGERROR, "GL: Error creating texture and binding to FBO");
899 m_pVideoFilterShader = new ConvolutionFilterShader(m_scalingMethod, m_nonLinStretch);
900 if (!m_pVideoFilterShader->CompileAndLink())
902 CLog::Log(LOGERROR, "GL: Error compiling and linking video filter shader");
906 SetTextureFilter(GL_LINEAR);
907 m_renderQuality = RQ_MULTIPASS;
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");
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)
926 m_pVideoFilterShader->Free();
927 delete m_pVideoFilterShader;
928 m_pVideoFilterShader = NULL;
932 SetTextureFilter(GL_LINEAR);
933 m_renderQuality = RQ_SINGLEPASS;
936 void CLinuxRendererGL::LoadShaders(int field)
938 if (m_format == RENDER_FMT_VDPAU)
940 CLog::Log(LOGNOTICE, "GL: Using VDPAU render method");
941 m_renderMethod = RENDER_VDPAU;
943 else if (m_format == RENDER_FMT_VAAPI)
945 CLog::Log(LOGNOTICE, "GL: Using VAAPI render method");
946 m_renderMethod = RENDER_VAAPI;
948 else if (m_format == RENDER_FMT_CVBREF)
950 CLog::Log(LOGNOTICE, "GL: Using CVBREF render method");
951 m_renderMethod = RENDER_CVREF;
955 int requestedMethod = CSettings::Get().GetInt("videoplayer.rendermethod");
956 CLog::Log(LOGDEBUG, "GL: Requested render method: %d", requestedMethod);
960 m_pYUVShader->Free();
966 switch(requestedMethod)
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");
975 case RENDER_METHOD_GLSL:
976 // Try GLSL shaders if supported and user requested auto or GLSL.
977 if (glCreateProgram && tryGlsl)
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);
983 CLog::Log(LOGNOTICE, "GL: Selecting Single Pass YUV 2 RGB shader");
985 if (m_pYUVShader && m_pYUVShader->CompileAndLink())
987 m_renderMethod = RENDER_GLSL;
991 else if (m_pYUVShader)
993 m_pYUVShader->Free();
997 CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB GLSL shader");
998 // drop through and try ARB
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"))
1004 CLog::Log(LOGNOTICE, "GL: ARB shaders support detected");
1005 m_renderMethod = RENDER_ARB ;
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");
1011 if (m_pYUVShader && m_pYUVShader->CompileAndLink())
1013 m_renderMethod = RENDER_ARB;
1014 UpdateVideoFilter();
1017 else if (m_pYUVShader)
1019 m_pYUVShader->Free();
1020 delete m_pYUVShader;
1021 m_pYUVShader = NULL;
1023 CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB ARB shader");
1024 // drop through and use SW
1026 case RENDER_METHOD_SOFTWARE:
1028 // Use software YUV 2 RGB conversion if user requested it or GLSL and/or ARB shaders failed
1030 m_renderMethod = RENDER_SW ;
1031 CLog::Log(LOGNOTICE, "GL: Shaders support not present, falling back to SW mode");
1037 // determine whether GPU supports NPOT textures
1038 if (!glewIsSupported("GL_ARB_texture_non_power_of_two"))
1040 if (!glewIsSupported("GL_ARB_texture_rectangle"))
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;
1047 CLog::Log(LOGNOTICE, "GL: NPOT textures are supported through GL_ARB_texture_rectangle extension");
1050 CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
1053 if (m_pboSupported &&
1054 !(m_renderMethod & RENDER_SW) &&
1055 !(m_renderMethod & RENDER_CVREF))
1057 CLog::Log(LOGNOTICE, "GL: Using GL_ARB_pixel_buffer_object");
1063 // Now that we now the render method, setup texture function handlers
1064 if (m_format == RENDER_FMT_NV12)
1066 m_textureUpload = &CLinuxRendererGL::UploadNV12Texture;
1067 m_textureCreate = &CLinuxRendererGL::CreateNV12Texture;
1068 m_textureDelete = &CLinuxRendererGL::DeleteNV12Texture;
1070 else if (m_format == RENDER_FMT_YUYV422 ||
1071 m_format == RENDER_FMT_UYVY422)
1073 m_textureUpload = &CLinuxRendererGL::UploadYUV422PackedTexture;
1074 m_textureCreate = &CLinuxRendererGL::CreateYUV422PackedTexture;
1075 m_textureDelete = &CLinuxRendererGL::DeleteYUV422PackedTexture;
1077 else if (m_format == RENDER_FMT_VDPAU)
1079 m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture;
1080 m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture;
1081 m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture;
1083 else if (m_format == RENDER_FMT_VDPAU_420)
1085 m_textureUpload = &CLinuxRendererGL::UploadVDPAUTexture420;
1086 m_textureCreate = &CLinuxRendererGL::CreateVDPAUTexture420;
1087 m_textureDelete = &CLinuxRendererGL::DeleteVDPAUTexture420;
1089 else if (m_format == RENDER_FMT_VAAPI)
1091 m_textureUpload = &CLinuxRendererGL::UploadVAAPITexture;
1092 m_textureCreate = &CLinuxRendererGL::CreateVAAPITexture;
1093 m_textureDelete = &CLinuxRendererGL::DeleteVAAPITexture;
1095 else if (m_format == RENDER_FMT_CVBREF)
1097 m_textureUpload = &CLinuxRendererGL::UploadCVRefTexture;
1098 m_textureCreate = &CLinuxRendererGL::CreateCVRefTexture;
1099 m_textureDelete = &CLinuxRendererGL::DeleteCVRefTexture;
1103 // setup default YV12 texture handlers
1104 m_textureUpload = &CLinuxRendererGL::UploadYV12Texture;
1105 m_textureCreate = &CLinuxRendererGL::CreateYV12Texture;
1106 m_textureDelete = &CLinuxRendererGL::DeleteYV12Texture;
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;
1114 void CLinuxRendererGL::UnInit()
1116 CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
1117 CSingleLock lock(g_graphicsContext);
1123 glDeleteBuffersARB(1, &m_rgbPbo);
1129 delete [] m_rgbBuffer;
1132 m_rgbBufferSize = 0;
1136 m_dllSwScale->sws_freeContext(m_context);
1141 for (int i = 0; i < NUM_BUFFERS; ++i)
1142 (this->*m_textureDelete)(i);
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;
1151 void CLinuxRendererGL::Render(DWORD flags, int renderBuffer)
1153 // obtain current field, if interlaced
1154 if( flags & RENDER_FLAG_TOP)
1155 m_currentField = FIELD_TOP;
1157 else if (flags & RENDER_FLAG_BOT)
1158 m_currentField = FIELD_BOT;
1161 m_currentField = FIELD_FULL;
1163 // call texture load function
1164 if (!(this->*m_textureUpload)(renderBuffer))
1167 if (m_renderMethod & RENDER_GLSL)
1169 UpdateVideoFilter();
1170 switch(m_renderQuality)
1174 if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL)
1175 RenderProgressiveWeave(renderBuffer, m_currentField);
1177 RenderSinglePass(renderBuffer, m_currentField);
1182 if (m_format == RENDER_FMT_VDPAU_420 && m_currentField == FIELD_FULL)
1183 RenderProgressiveWeave(renderBuffer, m_currentField);
1186 RenderToFBO(renderBuffer, m_currentField);
1193 else if (m_renderMethod & RENDER_ARB)
1195 RenderSinglePass(renderBuffer, m_currentField);
1197 #ifdef HAVE_LIBVDPAU
1198 else if (m_renderMethod & RENDER_VDPAU)
1200 UpdateVideoFilter();
1201 RenderVDPAU(renderBuffer, m_currentField);
1205 else if (m_renderMethod & RENDER_VAAPI)
1207 UpdateVideoFilter();
1208 RenderVAAPI(renderBuffer, m_currentField);
1213 // RENDER_CVREF uses the same render as the default case
1214 RenderSoftware(renderBuffer, m_currentField);
1218 #ifdef HAVE_LIBVDPAU
1219 if (m_format == RENDER_FMT_VDPAU || m_format == RENDER_FMT_VDPAU_420)
1221 YUVBUFFER &buf = m_buffers[renderBuffer];
1230 void CLinuxRendererGL::RenderSinglePass(int index, int field)
1232 YUVFIELDS &fields = m_buffers[index].fields;
1233 YUVPLANES &planes = fields[field];
1235 if (m_reloadShaders)
1237 m_reloadShaders = 0;
1241 glDisable(GL_DEPTH_TEST);
1244 glActiveTextureARB(GL_TEXTURE0);
1245 glEnable(m_textureTarget);
1246 glBindTexture(m_textureTarget, planes[0].id);
1249 glActiveTextureARB(GL_TEXTURE1);
1250 glEnable(m_textureTarget);
1251 glBindTexture(m_textureTarget, planes[1].id);
1254 glActiveTextureARB(GL_TEXTURE2);
1255 glEnable(m_textureTarget);
1256 glBindTexture(m_textureTarget, planes[2].id);
1258 glActiveTextureARB(GL_TEXTURE0);
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);
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);
1271 m_pYUVShader->SetNonLinStretch(pow(CDisplaySettings::Get().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1273 if (field == FIELD_TOP)
1274 m_pYUVShader->SetField(1);
1275 else if(field == FIELD_BOT)
1276 m_pYUVShader->SetField(0);
1278 m_pYUVShader->Enable();
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
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
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
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
1305 m_pYUVShader->Disable();
1308 glActiveTextureARB(GL_TEXTURE1);
1309 glDisable(m_textureTarget);
1311 glActiveTextureARB(GL_TEXTURE2);
1312 glDisable(m_textureTarget);
1314 glActiveTextureARB(GL_TEXTURE0);
1315 glDisable(m_textureTarget);
1317 glMatrixMode(GL_MODELVIEW);
1322 void CLinuxRendererGL::RenderToFBO(int index, int field, bool weave /*= false*/)
1324 YUVPLANES &planes = m_buffers[index].fields[field];
1326 if (m_reloadShaders)
1328 m_reloadShaders = 0;
1329 LoadShaders(m_currentField);
1332 if (!m_fbo.fbo.IsValid())
1334 if (!m_fbo.fbo.Initialize())
1336 CLog::Log(LOGERROR, "GL: Error initializing FBO");
1340 if (!m_fbo.fbo.CreateAndBindToTexture(GL_TEXTURE_2D, m_sourceWidth, m_sourceHeight, GL_RGBA))
1342 CLog::Log(LOGERROR, "GL: Error creating texture and binding to FBO");
1347 glDisable(GL_DEPTH_TEST);
1350 glEnable(m_textureTarget);
1351 glActiveTextureARB(GL_TEXTURE0);
1352 glBindTexture(m_textureTarget, planes[0].id);
1356 glActiveTextureARB(GL_TEXTURE1);
1357 glEnable(m_textureTarget);
1358 glBindTexture(m_textureTarget, planes[1].id);
1362 glActiveTextureARB(GL_TEXTURE2);
1363 glEnable(m_textureTarget);
1364 glBindTexture(m_textureTarget, planes[2].id);
1367 glActiveTextureARB(GL_TEXTURE0);
1370 // make sure the yuv shader is loaded and ready to go
1371 if (!m_pYUVShader || (!m_pYUVShader->OK()))
1373 CLog::Log(LOGERROR, "GL: YUV shader not active, cannot do multipass render");
1377 m_fbo.fbo.BeginRender();
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);
1392 glPushAttrib(GL_VIEWPORT_BIT);
1393 glPushAttrib(GL_SCISSOR_BIT);
1394 glMatrixMode(GL_MODELVIEW);
1399 glMatrixMode(GL_PROJECTION);
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);
1410 if (!m_pYUVShader->Enable())
1412 CLog::Log(LOGERROR, "GL: Error enabling YUV shader");
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)
1419 m_fbo.width *= planes[0].texwidth;
1420 m_fbo.height *= planes[0].texheight;
1422 m_fbo.width *= planes[0].pixpertex_x;
1423 m_fbo.height *= planes[0].pixpertex_y;
1427 // 1st Pass to video frame size
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);
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);
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);
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);
1453 m_pYUVShader->Disable();
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);
1464 m_fbo.fbo.EndRender();
1466 glActiveTextureARB(GL_TEXTURE1);
1467 glDisable(m_textureTarget);
1468 glActiveTextureARB(GL_TEXTURE2);
1469 glDisable(m_textureTarget);
1470 glActiveTextureARB(GL_TEXTURE0);
1471 glDisable(m_textureTarget);
1474 void CLinuxRendererGL::RenderFromFBO()
1476 glEnable(m_textureTarget);
1477 glActiveTextureARB(GL_TEXTURE0);
1480 // Use regular normalized texture coordinates
1482 // 2nd Pass to screen size with optional video filter
1484 if (m_pVideoFilterShader)
1487 if (!m_pVideoFilterShader->GetTextureFilter(filter))
1488 filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
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);
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);
1500 m_pVideoFilterShader->SetNonLinStretch(pow(CDisplaySettings::Get().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1502 m_pVideoFilterShader->Enable();
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);
1513 float imgwidth = m_fbo.width / m_sourceWidth;
1514 float imgheight = m_fbo.height / m_sourceHeight;
1518 glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f, 0.0f);
1519 glVertex4f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y, 0, 1.0f );
1521 glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, 0.0f);
1522 glVertex4f(m_rotatedDestCoords[1].x, m_rotatedDestCoords[1].y, 0, 1.0f );
1524 glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, imgheight);
1525 glVertex4f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y, 0, 1.0f );
1527 glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f, imgheight);
1528 glVertex4f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y, 0, 1.0f );
1534 if (m_pVideoFilterShader)
1535 m_pVideoFilterShader->Disable();
1539 glBindTexture(m_textureTarget, 0);
1540 glDisable(m_textureTarget);
1544 void CLinuxRendererGL::RenderProgressiveWeave(int index, int field)
1546 bool scale = (int)m_sourceHeight != m_destRect.Height() ||
1547 (int)m_sourceWidth != m_destRect.Width();
1549 if (m_fbo.fbo.IsSupported() && (scale || m_renderQuality == RQ_MULTIPASS))
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);
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);
1570 void CLinuxRendererGL::RenderVDPAU(int index, int field)
1572 #ifdef HAVE_LIBVDPAU
1573 YUVPLANE &plane = m_buffers[index].fields[FIELD_FULL][0];
1575 glEnable(m_textureTarget);
1576 glActiveTextureARB(GL_TEXTURE0);
1578 glBindTexture(m_textureTarget, plane.id);
1580 // make sure we know the correct texture size
1581 GetPlaneTextureSize(plane);
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);
1587 if (m_pVideoFilterShader)
1590 if (!m_pVideoFilterShader->GetTextureFilter(filter))
1591 filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
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);
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);
1604 m_pVideoFilterShader->SetNonLinStretch(pow(CDisplaySettings::Get().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1606 m_pVideoFilterShader->Enable();
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);
1615 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1619 if (m_textureTarget==GL_TEXTURE_2D)
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);
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);
1636 if (m_pVideoFilterShader)
1637 m_pVideoFilterShader->Disable();
1639 glBindTexture (m_textureTarget, 0);
1640 glDisable(m_textureTarget);
1644 void CLinuxRendererGL::RenderVAAPI(int index, int field)
1647 YUVPLANE &plane = m_buffers[index].fields[0][0];
1648 VAAPI::CHolder &va = m_buffers[index].vaapi;
1652 CLog::Log(LOGINFO, "CLinuxRendererGL::RenderVAAPI - no vaapi object");
1655 VAAPI::CDisplayPtr& display(va.surface->m_display);
1656 CSingleLock lock(*display);
1658 glEnable(m_textureTarget);
1659 glActiveTextureARB(GL_TEXTURE0);
1660 glBindTexture(m_textureTarget, plane.id);
1662 #if USE_VAAPI_GLX_BIND
1664 status = vaBeginRenderSurfaceGLX(display->get(), va.surfglx->m_id);
1665 if(status != VA_STATUS_SUCCESS)
1667 CLog::Log(LOGERROR, "CLinuxRendererGL::RenderVAAPI - vaBeginRenderSurfaceGLX failed (%d)", status);
1672 // make sure we know the correct texture size
1673 GetPlaneTextureSize(plane);
1674 CalculateTextureSourceRects(index, 1);
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);
1680 if (m_pVideoFilterShader)
1683 if (!m_pVideoFilterShader->GetTextureFilter(filter))
1684 filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
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);
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);
1697 m_pVideoFilterShader->SetNonLinStretch(pow(CDisplaySettings::Get().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1699 m_pVideoFilterShader->Enable();
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);
1708 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
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);
1720 if (m_pVideoFilterShader)
1721 m_pVideoFilterShader->Disable();
1723 #if USE_VAAPI_GLX_BIND
1724 status = vaEndRenderSurfaceGLX(display->get(), va.surfglx->m_id);
1725 if(status != VA_STATUS_SUCCESS)
1727 CLog::Log(LOGERROR, "CLinuxRendererGL::RenderVAAPI - vaEndRenderSurfaceGLX failed (%d)", status);
1732 glBindTexture (m_textureTarget, 0);
1733 glDisable(m_textureTarget);
1737 void CLinuxRendererGL::RenderSoftware(int index, int field)
1739 // used for textues uploaded from rgba or CVPixelBuffers.
1740 YUVPLANES &planes = m_buffers[index].fields[field];
1742 glDisable(GL_DEPTH_TEST);
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);
1750 glTexCoord2f(planes[0].rect.x1, planes[0].rect.y1);
1751 glVertex4f(m_rotatedDestCoords[0].x, m_rotatedDestCoords[0].y, 0, 1.0f );
1753 glTexCoord2f(planes[0].rect.x2, planes[0].rect.y1);
1754 glVertex4f(m_rotatedDestCoords[1].x, m_rotatedDestCoords[1].y, 0, 1.0f);
1756 glTexCoord2f(planes[0].rect.x2, planes[0].rect.y2);
1757 glVertex4f(m_rotatedDestCoords[2].x, m_rotatedDestCoords[2].y, 0, 1.0f);
1759 glTexCoord2f(planes[0].rect.x1, planes[0].rect.y2);
1760 glVertex4f(m_rotatedDestCoords[3].x, m_rotatedDestCoords[3].y, 0, 1.0f);
1766 glDisable(m_textureTarget);
1770 bool CLinuxRendererGL::RenderCapture(CRenderCapture* capture)
1775 // save current video rect
1776 CRect saveSize = m_destRect;
1778 saveRotatedCoords();//backup current m_rotatedDestCoords
1780 // new video rect is capture size
1781 m_destRect.SetRect(0, 0, (float)capture->GetWidth(), (float)capture->GetHeight());
1783 syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords
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);
1790 glTranslatef(0, capture->GetHeight(), 0);
1791 glScalef(1.0, -1.0f, 1.0f);
1793 capture->BeginRender();
1795 Render(RENDER_FLAG_NOOSD, m_iYV12RenderBuffer);
1797 glReadPixels(0, g_graphicsContext.GetHeight() - capture->GetHeight(), capture->GetWidth(), capture->GetHeight(),
1798 GL_BGRA, GL_UNSIGNED_BYTE, capture->GetRenderBuffer());
1800 capture->EndRender();
1802 // revert model view matrix
1803 glMatrixMode(GL_MODELVIEW);
1806 // restore original video rect
1807 m_destRect = saveSize;
1808 restoreRotatedCoords();//restores the previous state of the rotated dest coords
1813 //********************************************************************************************************
1814 // YV12 Texture creation, deletion, copying + clearing
1815 //********************************************************************************************************
1816 bool CLinuxRendererGL::UploadYV12Texture(int source)
1818 YUVBUFFER& buf = m_buffers[source];
1819 YV12Image* im = &buf.image;
1820 YUVFIELDS& fields = buf.fields;
1822 if (!(im->flags&IMAGE_FLAG_READY))
1825 if (m_currentField == FIELD_FULL)
1826 deinterlacing = false;
1828 deinterlacing = true;
1830 glEnable(m_textureTarget);
1833 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
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] );
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]) ;
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] );
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] );
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] );
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] );
1868 LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
1869 , im->width, im->height
1870 , im->stride[0], im->bpp, im->plane[0] );
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] );
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] );
1885 CalculateTextureSourceRects(source, 3);
1887 glDisable(m_textureTarget);
1891 void CLinuxRendererGL::DeleteYV12Texture(int index)
1893 YV12Image &im = m_buffers[index].image;
1894 YUVFIELDS &fields = m_buffers[index].fields;
1895 GLuint *pbo = m_buffers[index].pbo;
1897 if( fields[FIELD_FULL][0].id == 0 ) return;
1899 /* finish up all textures, and delete them */
1900 g_graphicsContext.BeginPaint(); //FIXME
1901 for(int f = 0;f<MAX_FIELDS;f++)
1903 for(int p = 0;p<MAX_PLANES;p++)
1905 if( fields[f][p].id )
1907 if (glIsTexture(fields[f][p].id))
1908 glDeleteTextures(1, &fields[f][p].id);
1909 fields[f][p].id = 0;
1913 g_graphicsContext.EndPaint();
1915 for(int p = 0;p<MAX_PLANES;p++)
1921 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[p]);
1922 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
1924 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
1926 glDeleteBuffersARB(1, pbo + p);
1933 delete[] im.plane[p];
1940 static GLint GetInternalFormat(GLint format, int bpp)
1947 case GL_ALPHA: return GL_ALPHA16;
1949 #ifdef GL_LUMINANCE16
1950 case GL_LUMINANCE: return GL_LUMINANCE16;
1952 default: return format;
1959 bool CLinuxRendererGL::CreateYV12Texture(int index)
1961 /* since we also want the field textures, pitch must be texture aligned */
1964 YV12Image &im = m_buffers[index].image;
1965 YUVFIELDS &fields = m_buffers[index].fields;
1966 GLuint *pbo = m_buffers[index].pbo;
1968 DeleteYV12Texture(index);
1970 im.height = m_sourceHeight;
1971 im.width = m_sourceWidth;
1976 if(m_format == RENDER_FMT_YUV420P16
1977 || m_format == RENDER_FMT_YUV420P10)
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 );
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 );
1990 bool pboSetup = false;
1994 glGenBuffersARB(3, pbo);
1996 for (int i = 0; i < 3; i++)
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);
2003 im.plane[i] = (BYTE*) pboPtr + PBO_OFFSET;
2004 memset(im.plane[i], 0, im.planesize[i]);
2008 CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
2016 for (int i = 0; i < 3; i++)
2018 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[i]);
2019 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2021 glDeleteBuffersARB(3, pbo);
2022 memset(m_buffers[index].pbo, 0, sizeof(m_buffers[index].pbo));
2025 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2030 for (int i = 0; i < 3; i++)
2031 im.plane[i] = new BYTE[im.planesize[i]];
2034 glEnable(m_textureTarget);
2035 for(int f = 0;f<MAX_FIELDS;f++)
2037 for(p = 0;p<MAX_PLANES;p++)
2039 if (!glIsTexture(fields[f][p].id))
2041 glGenTextures(1, &fields[f][p].id);
2044 fields[f][p].pbo = pbo[p];
2049 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
2051 int fieldshift = (f==FIELD_FULL) ? 0 : 1;
2052 YUVPLANES &planes = fields[f];
2054 planes[0].texwidth = im.width;
2055 planes[0].texheight = im.height >> fieldshift;
2057 if (m_renderMethod & RENDER_SW)
2059 planes[1].texwidth = 0;
2060 planes[1].texheight = 0;
2061 planes[2].texwidth = 0;
2062 planes[2].texheight = 0;
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;
2072 for (int p = 0; p < 3; p++)
2074 planes[p].pixpertex_x = 1;
2075 planes[p].pixpertex_y = 1;
2078 if(m_renderMethod & RENDER_POT)
2080 for(int p = 0; p < 3; p++)
2082 planes[p].texwidth = NP2(planes[p].texwidth);
2083 planes[p].texheight = NP2(planes[p].texheight);
2087 for(int p = 0; p < 3; p++)
2089 YUVPLANE &plane = planes[p];
2090 if (plane.texwidth * plane.texheight == 0)
2093 glBindTexture(m_textureTarget, plane.id);
2094 if (m_renderMethod & RENDER_SW)
2096 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2101 GLint internalformat;
2102 if (p == 2) //V plane needs an alpha texture
2105 format = GL_LUMINANCE;
2106 internalformat = GetInternalFormat(format, im.bpp);
2108 glTexImage2D(m_textureTarget, 0, internalformat, plane.texwidth, plane.texheight, 0, format, GL_UNSIGNED_BYTE, NULL);
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);
2118 glDisable(m_textureTarget);
2122 //********************************************************************************************************
2123 // NV12 Texture loading, creation and deletion
2124 //********************************************************************************************************
2125 bool CLinuxRendererGL::UploadNV12Texture(int source)
2127 YUVBUFFER& buf = m_buffers[source];
2128 YV12Image* im = &buf.image;
2129 YUVFIELDS& fields = buf.fields;
2131 if (!(im->flags & IMAGE_FLAG_READY))
2134 if (m_currentField == FIELD_FULL)
2135 deinterlacing = false;
2137 deinterlacing = true;
2139 glEnable(m_textureTarget);
2142 glPixelStorei(GL_UNPACK_ALIGNMENT, im->bpp);
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] );
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]) ;
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] );
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] );
2170 LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
2171 , im->width, im->height
2172 , im->stride[0], im->bpp, im->plane[0] );
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] );
2182 CalculateTextureSourceRects(source, 3);
2184 glDisable(m_textureTarget);
2188 bool CLinuxRendererGL::CreateNV12Texture(int index)
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;
2195 // Delete any old texture
2196 DeleteNV12Texture(index);
2198 im.height = m_sourceHeight;
2199 im.width = m_sourceWidth;
2204 im.stride[0] = im.width;
2205 im.stride[1] = im.width;
2213 im.planesize[0] = im.stride[0] * im.height;
2215 im.planesize[1] = im.stride[1] * im.height / 2;
2216 // third plane is not used
2217 im.planesize[2] = 0;
2219 bool pboSetup = false;
2223 glGenBuffersARB(2, pbo);
2225 for (int i = 0; i < 2; i++)
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);
2232 im.plane[i] = (BYTE*)pboPtr + PBO_OFFSET;
2233 memset(im.plane[i], 0, im.planesize[i]);
2237 CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
2245 for (int i = 0; i < 2; i++)
2247 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[i]);
2248 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2250 glDeleteBuffersARB(2, pbo);
2251 memset(m_buffers[index].pbo, 0, sizeof(m_buffers[index].pbo));
2254 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2259 for (int i = 0; i < 2; i++)
2260 im.plane[i] = new BYTE[im.planesize[i]];
2263 glEnable(m_textureTarget);
2264 for(int f = 0;f<MAX_FIELDS;f++)
2266 for(int p = 0;p<2;p++)
2268 if (!glIsTexture(fields[f][p].id))
2270 glGenTextures(1, &fields[f][p].id);
2273 fields[f][p].pbo = pbo[p];
2275 fields[f][2].id = fields[f][1].id;
2279 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
2281 int fieldshift = (f==FIELD_FULL) ? 0 : 1;
2282 YUVPLANES &planes = fields[f];
2284 planes[0].texwidth = im.width;
2285 planes[0].texheight = im.height >> fieldshift;
2287 if (m_renderMethod & RENDER_SW)
2289 planes[1].texwidth = 0;
2290 planes[1].texheight = 0;
2291 planes[2].texwidth = 0;
2292 planes[2].texheight = 0;
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;
2302 for (int p = 0; p < 3; p++)
2304 planes[p].pixpertex_x = 1;
2305 planes[p].pixpertex_y = 1;
2308 if(m_renderMethod & RENDER_POT)
2310 for(int p = 0; p < 3; p++)
2312 planes[p].texwidth = NP2(planes[p].texwidth);
2313 planes[p].texheight = NP2(planes[p].texheight);
2317 for(int p = 0; p < 2; p++)
2319 YUVPLANE &plane = planes[p];
2320 if (plane.texwidth * plane.texheight == 0)
2323 glBindTexture(m_textureTarget, plane.id);
2324 if (m_renderMethod & RENDER_SW)
2326 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2331 glTexImage2D(m_textureTarget, 0, GL_LUMINANCE_ALPHA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
2333 glTexImage2D(m_textureTarget, 0, GL_LUMINANCE, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
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);
2343 glDisable(m_textureTarget);
2347 void CLinuxRendererGL::DeleteNV12Texture(int index)
2349 YV12Image &im = m_buffers[index].image;
2350 YUVFIELDS &fields = m_buffers[index].fields;
2351 GLuint *pbo = m_buffers[index].pbo;
2353 if( fields[FIELD_FULL][0].id == 0 ) return;
2355 // finish up all textures, and delete them
2356 g_graphicsContext.BeginPaint(); //FIXME
2357 for(int f = 0;f<MAX_FIELDS;f++)
2359 for(int p = 0;p<2;p++)
2361 if( fields[f][p].id )
2363 if (glIsTexture(fields[f][p].id))
2365 glDeleteTextures(1, &fields[f][p].id);
2367 fields[f][p].id = 0;
2370 fields[f][2].id = 0;
2372 g_graphicsContext.EndPaint();
2374 for(int p = 0;p<2;p++)
2380 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[p]);
2381 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2383 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2385 glDeleteBuffersARB(1, pbo + p);
2392 delete[] im.plane[p];
2399 void CLinuxRendererGL::DeleteVDPAUTexture(int index)
2401 #ifdef HAVE_LIBVDPAU
2402 YUVPLANE &plane = m_buffers[index].fields[FIELD_FULL][0];
2404 SAFE_RELEASE(m_buffers[index].vdpau);
2410 bool CLinuxRendererGL::CreateVDPAUTexture(int index)
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];
2417 DeleteVDPAUTexture(index);
2419 memset(&im , 0, sizeof(im));
2420 memset(&fields, 0, sizeof(fields));
2421 im.height = m_sourceHeight;
2422 im.width = m_sourceWidth;
2424 plane.texwidth = im.width;
2425 plane.texheight = im.height;
2427 plane.pixpertex_x = 1;
2428 plane.pixpertex_y = 1;
2436 bool CLinuxRendererGL::UploadVDPAUTexture(int index)
2438 #ifdef HAVE_LIBVDPAU
2439 VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau;
2441 YV12Image &im = m_buffers[index].image;
2442 YUVFIELDS &fields = m_buffers[index].fields;
2443 YUVPLANE &plane = fields[FIELD_FULL][0];
2445 if (!vdpau || !vdpau->valid)
2450 plane.id = vdpau->texture[0];
2452 // in stereoscopic mode sourceRect may only
2453 // be a part of the source video surface
2454 plane.rect = m_sourceRect;
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;
2466 plane.texheight = vdpau->texHeight;
2467 plane.texwidth = vdpau->texWidth;
2469 if (m_textureTarget == GL_TEXTURE_2D)
2471 plane.rect.y1 /= plane.texheight;
2472 plane.rect.y2 /= plane.texheight;
2473 plane.rect.x1 /= plane.texwidth;
2474 plane.rect.x2 /= plane.texwidth;
2481 void CLinuxRendererGL::DeleteVDPAUTexture420(int index)
2483 #ifdef HAVE_LIBVDPAU
2484 YUVFIELDS &fields = m_buffers[index].fields;
2486 SAFE_RELEASE(m_buffers[index].vdpau);
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;
2497 bool CLinuxRendererGL::CreateVDPAUTexture420(int index)
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;
2505 DeleteVDPAUTexture420(index);
2507 memset(&im , 0, sizeof(im));
2508 memset(&fields, 0, sizeof(fields));
2517 for(int p=0; p<3; p++)
2528 bool CLinuxRendererGL::UploadVDPAUTexture420(int index)
2530 #ifdef HAVE_LIBVDPAU
2531 VDPAU::CVdpauRenderPicture *vdpau = m_buffers[index].vdpau;
2532 YV12Image &im = m_buffers[index].image;
2534 YUVFIELDS &fields = m_buffers[index].fields;
2536 if (!vdpau || !vdpau->valid)
2541 im.height = vdpau->texHeight;
2542 im.width = vdpau->texWidth;
2545 for (int f = FIELD_TOP; f<=FIELD_BOT ; f++)
2547 YUVPLANES &planes = fields[f];
2549 planes[0].texwidth = im.width;
2550 planes[0].texheight = im.height >> 1;
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;
2557 for (int p = 0; p < 3; p++)
2559 planes[p].pixpertex_x = 1;
2560 planes[p].pixpertex_y = 1;
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;
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];
2577 glEnable(m_textureTarget);
2578 for (int f = FIELD_TOP; f <= FIELD_BOT; f++)
2580 for (int p=0; p<2; p++)
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);
2588 glBindTexture(m_textureTarget,0);
2592 CalculateTextureSourceRects(index, 3);
2593 glDisable(m_textureTarget);
2599 void CLinuxRendererGL::DeleteVAAPITexture(int index)
2602 YUVPLANE &plane = m_buffers[index].fields[0][0];
2603 VAAPI::CHolder &va = m_buffers[index].vaapi;
2609 if(plane.id && glIsTexture(plane.id))
2610 glDeleteTextures(1, &plane.id);
2616 bool CLinuxRendererGL::CreateVAAPITexture(int index)
2619 YV12Image &im = m_buffers[index].image;
2620 YUVFIELDS &fields = m_buffers[index].fields;
2621 YUVPLANE &plane = fields[0][0];
2623 DeleteVAAPITexture(index);
2625 memset(&im , 0, sizeof(im));
2626 memset(&fields, 0, sizeof(fields));
2627 im.height = m_sourceHeight;
2628 im.width = m_sourceWidth;
2630 plane.texwidth = im.width;
2631 plane.texheight = im.height;
2633 plane.pixpertex_x = 1;
2634 plane.pixpertex_y = 1;
2636 if(m_renderMethod & RENDER_POT)
2638 plane.texwidth = NP2(plane.texwidth);
2639 plane.texheight = NP2(plane.texheight);
2642 glEnable(m_textureTarget);
2643 glGenTextures(1, &plane.id);
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);
2659 bool CLinuxRendererGL::UploadVAAPITexture(int index)
2662 YUVPLANE &plane = m_buffers[index].fields[0][0];
2663 VAAPI::CHolder &va = m_buffers[index].vaapi;
2669 if(va.display && va.surface->m_display != va.display)
2671 CLog::Log(LOGDEBUG, "CLinuxRendererGL::UploadVAAPITexture - context changed %d", index);
2674 va.display = va.surface->m_display;
2676 CSingleLock lock(*va.display);
2678 if(va.display->lost())
2683 CLog::Log(LOGDEBUG, "CLinuxRendererGL::UploadVAAPITexture - creating vaapi surface for texture %d", index);
2685 status = vaCreateSurfaceGLX(va.display->get()
2689 if(status != VA_STATUS_SUCCESS)
2691 CLog::Log(LOGERROR, "CLinuxRendererGL::UploadVAAPITexture - failed to create vaapi glx surface (%d)", status);
2694 va.surfglx = VAAPI::CSurfaceGLPtr(new VAAPI::CSurfaceGL(surface, va.display));
2697 if(CONF_FLAGS_YUVCOEF_MASK(m_iFlags) == CONF_FLAGS_YUVCOEF_BT709)
2698 colorspace = VA_SRC_BT709;
2700 colorspace = VA_SRC_BT601;
2703 if (m_currentField == FIELD_TOP)
2704 field = VA_TOP_FIELD;
2705 else if (m_currentField == FIELD_BOT)
2706 field = VA_BOTTOM_FIELD;
2708 field = VA_FRAME_PICTURE;
2710 #if USE_VAAPI_GLX_BIND
2711 status = vaAssociateSurfaceGLX(va.display->get()
2714 , field | colorspace);
2716 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2717 status = vaCopySurfaceGLX(va.display->get()
2720 , field | colorspace);
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)
2727 va.display->lost(true);
2728 for(int i = 0; i < m_NumYV12Buffers; i++)
2730 m_buffers[i].vaapi.display.reset();
2731 m_buffers[i].vaapi.surface.reset();
2732 m_buffers[i].vaapi.surfglx.reset();
2736 if(status != VA_STATUS_SUCCESS)
2737 CLog::Log(LOGERROR, "CLinuxRendererGL::UploadVAAPITexture - failed to copy surface to glx %d - %s", status, vaErrorStr(status));
2743 //********************************************************************************************************
2744 // CoreVideoRef Texture creation, deletion, copying + clearing
2745 //********************************************************************************************************
2746 bool CLinuxRendererGL::UploadCVRefTexture(int index)
2748 #ifdef TARGET_DARWIN
2749 CVBufferRef cvBufferRef = m_buffers[index].cvBufferRef;
2751 glEnable(m_textureTarget);
2755 YUVFIELDS &fields = m_buffers[index].fields;
2756 YUVPLANE &plane = fields[0][0];
2758 if (Cocoa_GetOSVersion() >= 0x1074)
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);
2765 GLsizei texHeight = CVPixelBufferGetHeight(cvBufferRef);
2766 size_t rowbytes = CVPixelBufferGetBytesPerRow(cvBufferRef);
2767 unsigned char *bufferBase = (unsigned char*)CVPixelBufferGetBaseAddress(cvBufferRef);
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);
2773 CVPixelBufferUnlockBaseAddress(cvBufferRef, kCVPixelBufferLock_ReadOnly);
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);
2785 glBindTexture(m_textureTarget, plane.id);
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);
2794 glBindTexture(m_textureTarget, 0);
2797 CVBufferRelease(cvBufferRef);
2798 m_buffers[index].cvBufferRef = NULL;
2800 plane.flipindex = m_buffers[index].flipindex;
2804 CalculateTextureSourceRects(index, 3);
2805 glDisable(m_textureTarget);
2811 void CLinuxRendererGL::DeleteCVRefTexture(int index)
2813 #ifdef TARGET_DARWIN
2814 YUVPLANE &plane = m_buffers[index].fields[0][0];
2816 if (m_buffers[index].cvBufferRef)
2817 CVBufferRelease(m_buffers[index].cvBufferRef);
2818 m_buffers[index].cvBufferRef = NULL;
2820 if (plane.id && glIsTexture(plane.id))
2821 glDeleteTextures(1, &plane.id), plane.id = 0;
2825 bool CLinuxRendererGL::CreateCVRefTexture(int index)
2827 #ifdef TARGET_DARWIN
2828 YV12Image &im = m_buffers[index].image;
2829 YUVFIELDS &fields = m_buffers[index].fields;
2830 YUVPLANE &plane = fields[0][0];
2832 DeleteCVRefTexture(index);
2834 memset(&im , 0, sizeof(im));
2835 memset(&fields, 0, sizeof(fields));
2838 im.width = m_sourceWidth;
2839 im.height = m_sourceHeight;
2843 plane.texwidth = NP2(im.width);
2844 plane.texheight = NP2(im.height);
2845 plane.pixpertex_x = 1;
2846 plane.pixpertex_y = 1;
2848 glEnable(m_textureTarget);
2849 glGenTextures(1, &plane.id);
2850 if (Cocoa_GetOSVersion() >= 0x1074)
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);
2864 glDisable(m_textureTarget);
2870 bool CLinuxRendererGL::UploadYUV422PackedTexture(int source)
2872 YUVBUFFER& buf = m_buffers[source];
2873 YV12Image* im = &buf.image;
2874 YUVFIELDS& fields = buf.fields;
2876 if (!(im->flags & IMAGE_FLAG_READY))
2880 if (m_currentField == FIELD_FULL)
2881 deinterlacing = false;
2883 deinterlacing = true;
2885 glEnable(m_textureTarget);
2888 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
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] );
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]) ;
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] );
2911 CalculateTextureSourceRects(source, 3);
2913 glDisable(m_textureTarget);
2917 void CLinuxRendererGL::DeleteYUV422PackedTexture(int index)
2919 YV12Image &im = m_buffers[index].image;
2920 YUVFIELDS &fields = m_buffers[index].fields;
2921 GLuint *pbo = m_buffers[index].pbo;
2923 if( fields[FIELD_FULL][0].id == 0 ) return;
2925 // finish up all textures, and delete them
2926 g_graphicsContext.BeginPaint(); //FIXME
2927 for(int f = 0;f<MAX_FIELDS;f++)
2929 if( fields[f][0].id )
2931 if (glIsTexture(fields[f][0].id))
2933 glDeleteTextures(1, &fields[f][0].id);
2935 fields[f][0].id = 0;
2937 fields[f][1].id = 0;
2938 fields[f][2].id = 0;
2940 g_graphicsContext.EndPaint();
2946 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[0]);
2947 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2949 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2951 glDeleteBuffersARB(1, pbo);
2958 delete[] im.plane[0];
2964 bool CLinuxRendererGL::CreateYUV422PackedTexture(int index)
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;
2971 // Delete any old texture
2972 DeleteYUV422PackedTexture(index);
2974 im.height = m_sourceHeight;
2975 im.width = m_sourceWidth;
2980 im.stride[0] = im.width * 2;
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;
2995 bool pboSetup = false;
2999 glGenBuffersARB(1, pbo);
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);
3006 im.plane[0] = (BYTE*)pboPtr + PBO_OFFSET;
3007 memset(im.plane[0], 0, im.planesize[0]);
3011 CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
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));
3023 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3028 im.plane[0] = new BYTE[im.planesize[0]];
3031 glEnable(m_textureTarget);
3032 for(int f = 0;f<MAX_FIELDS;f++)
3034 if (!glIsTexture(fields[f][0].id))
3036 glGenTextures(1, &fields[f][0].id);
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;
3045 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
3047 int fieldshift = (f==FIELD_FULL) ? 0 : 1;
3048 YUVPLANES &planes = fields[f];
3050 if (m_renderMethod & RENDER_SW)
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;
3059 for (int p = 0; p < 3; p++)
3061 planes[p].pixpertex_x = 1;
3062 planes[p].pixpertex_y = 1;
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;
3074 for (int p = 0; p < 3; p++)
3076 planes[p].pixpertex_x = 2;
3077 planes[p].pixpertex_y = 1;
3081 if(m_renderMethod & RENDER_POT)
3083 for(int p = 0; p < 3; p++)
3085 planes[p].texwidth = NP2(planes[p].texwidth);
3086 planes[p].texheight = NP2(planes[p].texheight);
3090 YUVPLANE &plane = planes[0];
3091 if (plane.texwidth * plane.texheight == 0)
3094 glBindTexture(m_textureTarget, plane.id);
3096 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
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);
3104 glDisable(m_textureTarget);
3109 void CLinuxRendererGL::ToRGBFrame(YV12Image* im, unsigned flipIndexPlane, unsigned flipIndexBuf)
3111 if(m_rgbBufferSize != m_sourceWidth * m_sourceHeight * 4)
3113 else if(flipIndexPlane == flipIndexBuf)
3114 return; //conversion already done on the previous iteration
3116 uint8_t *src[4] = {};
3117 int srcStride[4] = {};
3120 if (m_format == RENDER_FMT_YUV420P ||
3121 m_format == RENDER_FMT_YUV420P10 ||
3122 m_format == RENDER_FMT_YUV420P16)
3124 srcFormat = CDVDCodecUtils::PixfmtFromEFormat(m_format);
3125 for (int i = 0; i < 3; i++)
3127 src[i] = im->plane[i];
3128 srcStride[i] = im->stride[i];
3131 else if (m_format == RENDER_FMT_NV12)
3133 srcFormat = PIX_FMT_NV12;
3134 for (int i = 0; i < 2; i++)
3136 src[i] = im->plane[i];
3137 srcStride[i] = im->stride[i];
3140 else if (m_format == RENDER_FMT_YUYV422)
3142 srcFormat = PIX_FMT_YUYV422;
3143 src[0] = im->plane[0];
3144 srcStride[0] = im->stride[0];
3146 else if (m_format == RENDER_FMT_UYVY422)
3148 srcFormat = PIX_FMT_UYVY422;
3149 src[0] = im->plane[0];
3150 srcStride[0] = im->stride[0];
3152 else //should never happen
3154 CLog::Log(LOGERROR, "CLinuxRendererGL::ToRGBFrame: called with unsupported format %i", m_format);
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;
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);
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);
3175 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
3176 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3177 m_rgbBuffer = (BYTE*)PBO_OFFSET;
3181 void CLinuxRendererGL::ToRGBFields(YV12Image* im, unsigned flipIndexPlaneTop, unsigned flipIndexPlaneBot, unsigned flipIndexBuf)
3183 if(m_rgbBufferSize != m_sourceWidth * m_sourceHeight * 4)
3185 else if(flipIndexPlaneTop == flipIndexBuf && flipIndexPlaneBot == flipIndexBuf)
3186 return; //conversion already done on the previous iteration
3188 uint8_t *srcTop[4] = {};
3189 int srcStrideTop[4] = {};
3190 uint8_t *srcBot[4] = {};
3191 int srcStrideBot[4] = {};
3194 if (m_format == RENDER_FMT_YUV420P)
3196 srcFormat = PIX_FMT_YUV420P;
3197 for (int i = 0; i < 3; i++)
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;
3205 else if (m_format == RENDER_FMT_NV12)
3207 srcFormat = PIX_FMT_NV12;
3208 for (int i = 0; i < 2; i++)
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;
3216 else if (m_format == RENDER_FMT_YUYV422)
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;
3224 else if (m_format == RENDER_FMT_UYVY422)
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;
3232 else //should never happen
3234 CLog::Log(LOGERROR, "CLinuxRendererGL::ToRGBFields: called with unsupported format %i", m_format);
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;
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 };
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);
3259 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
3260 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3261 m_rgbBuffer = (BYTE*)PBO_OFFSET;
3265 void CLinuxRendererGL::SetupRGBBuffer()
3267 m_rgbBufferSize = m_sourceWidth * m_sourceHeight * 4;
3270 delete [] m_rgbBuffer;
3274 CLog::Log(LOGNOTICE, "GL: Using GL_ARB_pixel_buffer_object");
3277 glGenBuffersARB(1, &m_rgbPbo);
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;
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);
3292 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
3293 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3294 m_rgbBuffer = (BYTE*)PBO_OFFSET;
3299 m_rgbBuffer = new BYTE[m_rgbBufferSize];
3302 bool CLinuxRendererGL::UploadRGBTexture(int source)
3304 YUVBUFFER& buf = m_buffers[source];
3305 YV12Image* im = &buf.image;
3306 YUVFIELDS& fields = buf.fields;
3308 if (!(im->flags&IMAGE_FLAG_READY))
3312 if (m_currentField == FIELD_FULL)
3313 deinterlacing = false;
3315 deinterlacing = true;
3317 glEnable(m_textureTarget);
3321 ToRGBFields(im, fields[FIELD_TOP][0].flipindex, fields[FIELD_BOT][0].flipindex, buf.flipindex);
3323 ToRGBFrame(im, fields[FIELD_FULL][0].flipindex, buf.flipindex);
3325 static int imaging = -1;
3329 if (glewIsSupported("GL_ARB_imaging"))
3331 CLog::Log(LOGINFO, "GL: ARB Imaging extension supported");
3336 unsigned int maj=0, min=0;
3337 g_Windowing.GetRenderVersion(maj, min);
3350 ((CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness!=50) ||
3351 (CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast!=50)))
3353 GLfloat brightness = ((GLfloat)CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness - 50.0f)/100.0f;;
3354 GLfloat contrast = ((GLfloat)CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast)/50.0f;
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);
3366 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
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 );
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 );
3381 LoadPlane( fields[FIELD_FULL][0], GL_BGRA, buf.flipindex
3382 , im->width, im->height
3383 , m_sourceWidth*4, 1, m_rgbBuffer, &m_rgbPbo );
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
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);
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);
3409 CalculateTextureSourceRects(source, 3);
3411 glDisable(m_textureTarget);
3415 void CLinuxRendererGL::SetTextureFilter(GLenum method)
3417 for (int i = 0 ; i<m_NumYV12Buffers ; i++)
3419 YUVFIELDS &fields = m_buffers[i].fields;
3421 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
3423 for (int p = 0; p < 3; p++)
3425 if(glIsTexture(fields[f][p].id))
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);
3437 bool CLinuxRendererGL::Supports(ERENDERFEATURE feature)
3439 if(feature == RENDERFEATURE_BRIGHTNESS)
3441 if ((m_renderMethod & RENDER_VDPAU) && !CSettings::Get().GetBool("videoscreen.limitedrange"))
3444 if (m_renderMethod & RENDER_VAAPI)
3447 return (m_renderMethod & RENDER_GLSL)
3448 || (m_renderMethod & RENDER_ARB)
3449 || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE);
3452 if(feature == RENDERFEATURE_CONTRAST)
3454 if ((m_renderMethod & RENDER_VDPAU) && !CSettings::Get().GetBool("videoscreen.limitedrange"))
3457 if (m_renderMethod & RENDER_VAAPI)
3460 return (m_renderMethod & RENDER_GLSL)
3461 || (m_renderMethod & RENDER_ARB)
3462 || ((m_renderMethod & RENDER_SW) && glewIsSupported("GL_ARB_imaging") == GL_TRUE);
3465 if(feature == RENDERFEATURE_GAMMA)
3468 if(feature == RENDERFEATURE_NOISE)
3470 if(m_renderMethod & RENDER_VDPAU)
3474 if(feature == RENDERFEATURE_SHARPNESS)
3476 if(m_renderMethod & RENDER_VDPAU)
3480 if (feature == RENDERFEATURE_NONLINSTRETCH)
3482 if (((m_renderMethod & RENDER_GLSL) && !(m_renderMethod & RENDER_POT)) ||
3483 (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI))
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)
3499 bool CLinuxRendererGL::SupportsMultiPassRendering()
3501 return glewIsSupported("GL_EXT_framebuffer_object") && glCreateProgram;
3504 bool CLinuxRendererGL::Supports(EDEINTERLACEMODE mode)
3506 if(m_renderMethod & RENDER_CVREF)
3509 if(mode == VS_DEINTERLACEMODE_OFF
3510 || mode == VS_DEINTERLACEMODE_AUTO
3511 || mode == VS_DEINTERLACEMODE_FORCE)
3517 bool CLinuxRendererGL::Supports(EINTERLACEMETHOD method)
3519 if(m_renderMethod & RENDER_CVREF)
3522 if(method == VS_INTERLACEMETHOD_AUTO)
3525 if(m_renderMethod & RENDER_VDPAU ||
3526 m_format == RENDER_FMT_VDPAU_420)
3528 #ifdef HAVE_LIBVDPAU
3529 VDPAU::CVdpauRenderPicture *vdpauPic = m_buffers[m_iYV12RenderBuffer].vdpau;
3530 if(vdpauPic && vdpauPic->vdpau)
3531 return vdpauPic->vdpau->Supports(method);
3536 if(m_renderMethod & RENDER_VAAPI)
3539 VAAPI::CDisplayPtr disp = m_buffers[m_iYV12RenderBuffer].vaapi.display;
3542 CSingleLock lock(*disp);
3544 if(disp->support_deinterlace())
3546 if( method == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED
3547 || method == VS_INTERLACEMETHOD_RENDER_BOB )
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)
3562 if(method == VS_INTERLACEMETHOD_DEINTERLACE
3563 || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF
3564 || method == VS_INTERLACEMETHOD_SW_BLEND)
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))
3577 bool CLinuxRendererGL::Supports(ESCALINGMETHOD method)
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)
3585 if(method == VS_SCALINGMETHOD_LINEAR
3586 || method == VS_SCALINGMETHOD_AUTO)
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)
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)
3603 if ((glewIsSupported("GL_EXT_framebuffer_object") && (m_renderMethod & RENDER_GLSL)) ||
3604 (m_renderMethod & RENDER_VDPAU) || (m_renderMethod & RENDER_VAAPI))
3606 // spline36 and lanczos3 are only allowed through advancedsettings.xml
3607 if(method != VS_SCALINGMETHOD_SPLINE36
3608 && method != VS_SCALINGMETHOD_LANCZOS3)
3611 return g_advancedSettings.m_videoEnableHighQualityHwScalers;
3618 EINTERLACEMETHOD CLinuxRendererGL::AutoInterlaceMethod()
3620 if(m_renderMethod & RENDER_CVREF)
3621 return VS_INTERLACEMETHOD_NONE;
3623 if(m_renderMethod & RENDER_VDPAU)
3624 return VS_INTERLACEMETHOD_NONE;
3626 if(Supports(VS_INTERLACEMETHOD_RENDER_BOB))
3627 return VS_INTERLACEMETHOD_RENDER_BOB;
3629 return VS_INTERLACEMETHOD_NONE;
3632 void CLinuxRendererGL::BindPbo(YUVBUFFER& buff)
3635 for(int plane = 0; plane < MAX_PLANES; plane++)
3637 if(!buff.pbo[plane] || buff.image.plane[plane] == (BYTE*)PBO_OFFSET)
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;
3646 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3649 void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff)
3652 for(int plane = 0; plane < MAX_PLANES; plane++)
3654 if(!buff.pbo[plane] || buff.image.plane[plane] != (BYTE*)PBO_OFFSET)
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;
3663 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
3666 unsigned int CLinuxRendererGL::GetProcessorSize()
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)
3677 #ifdef HAVE_LIBVDPAU
3678 void CLinuxRendererGL::AddProcessor(VDPAU::CVdpauRenderPicture *vdpau, int index)
3680 YUVBUFFER &buf = m_buffers[index];
3681 VDPAU::CVdpauRenderPicture *pic = vdpau->Acquire();
3682 SAFE_RELEASE(buf.vdpau);
3688 void CLinuxRendererGL::AddProcessor(VAAPI::CHolder& holder, int index)
3690 YUVBUFFER &buf = m_buffers[index];
3691 buf.vaapi.surface = holder.surface;
3695 #ifdef TARGET_DARWIN
3696 void CLinuxRendererGL::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
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);