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 "guilib/Texture.h"
41 #include "guilib/LocalizeStrings.h"
42 #include "guilib/MatrixGLES.h"
43 #include "threads/SingleLock.h"
44 #include "utils/log.h"
45 #include "utils/GLUtils.h"
46 #include "utils/StringUtils.h"
47 #include "RenderCapture.h"
48 #include "RenderFormats.h"
49 #include "cores/IPlayer.h"
50 #include "cores/VideoPlayer/DVDCodecs/DVDCodecUtils.h"
51 #include "cores/FFmpeg.h"
54 #include "libswscale/swscale.h"
57 #ifdef TARGET_DARWIN_OSX
58 #include "platform/darwin/osx/CocoaInterface.h"
59 #include <CoreVideo/CoreVideo.h>
60 #include <OpenGL/CGLIOSurface.h>
61 #include "platform/darwin/DarwinUtils.h"
65 //! due to a bug on osx nvidia, using gltexsubimage2d with a pbo bound and a null pointer
66 //! screws up the alpha, an offset fixes this, there might still be a problem if stride + PBO_OFFSET
67 //! is a multiple of 128 and deinterlacing is on
70 using namespace Shaders
;
72 static const GLubyte stipple_weave
[] = {
73 0x00, 0x00, 0x00, 0x00,
74 0xFF, 0xFF, 0xFF, 0xFF,
75 0x00, 0x00, 0x00, 0x00,
76 0xFF, 0xFF, 0xFF, 0xFF,
77 0x00, 0x00, 0x00, 0x00,
78 0xFF, 0xFF, 0xFF, 0xFF,
79 0x00, 0x00, 0x00, 0x00,
80 0xFF, 0xFF, 0xFF, 0xFF,
81 0x00, 0x00, 0x00, 0x00,
82 0xFF, 0xFF, 0xFF, 0xFF,
83 0x00, 0x00, 0x00, 0x00,
84 0xFF, 0xFF, 0xFF, 0xFF,
85 0x00, 0x00, 0x00, 0x00,
86 0xFF, 0xFF, 0xFF, 0xFF,
87 0x00, 0x00, 0x00, 0x00,
88 0xFF, 0xFF, 0xFF, 0xFF,
89 0x00, 0x00, 0x00, 0x00,
90 0xFF, 0xFF, 0xFF, 0xFF,
91 0x00, 0x00, 0x00, 0x00,
92 0xFF, 0xFF, 0xFF, 0xFF,
93 0x00, 0x00, 0x00, 0x00,
94 0xFF, 0xFF, 0xFF, 0xFF,
95 0x00, 0x00, 0x00, 0x00,
96 0xFF, 0xFF, 0xFF, 0xFF,
97 0x00, 0x00, 0x00, 0x00,
98 0xFF, 0xFF, 0xFF, 0xFF,
99 0x00, 0x00, 0x00, 0x00,
100 0xFF, 0xFF, 0xFF, 0xFF,
101 0x00, 0x00, 0x00, 0x00,
102 0xFF, 0xFF, 0xFF, 0xFF,
103 0x00, 0x00, 0x00, 0x00,
104 0xFF, 0xFF, 0xFF, 0xFF,
105 0x00, 0x00, 0x00, 0x00,
108 CLinuxRendererGL::YUVBUFFER::YUVBUFFER()
110 memset(&fields
, 0, sizeof(fields
));
111 memset(&image
, 0, sizeof(image
));
112 memset(&pbo
, 0, sizeof(pbo
));
117 CLinuxRendererGL::YUVBUFFER::~YUVBUFFER()
122 CLinuxRendererGL::CLinuxRendererGL()
124 m_textureTarget
= GL_TEXTURE_2D
;
126 m_renderMethod
= RENDER_GLSL
;
127 m_renderQuality
= RQ_SINGLEPASS
;
129 m_format
= RENDER_FMT_NONE
;
131 m_iYV12RenderBuffer
= 0;
133 m_currentField
= FIELD_FULL
;
136 m_pVideoFilterShader
= NULL
;
137 m_scalingMethod
= VS_SCALINGMETHOD_LINEAR
;
138 m_scalingMethodGui
= (ESCALINGMETHOD
)-1;
139 m_useDithering
= CSettings::GetInstance().GetBool("videoscreen.dither");
140 m_ditherDepth
= CSettings::GetInstance().GetInt("videoscreen.ditherdepth");
141 m_fullRange
= !g_Windowing
.UseLimitedColor();
149 m_NumYV12Buffers
= 0;
150 m_iLastRenderBuffer
= 0;
151 m_bConfigured
= false;
152 m_bValidated
= false;
153 m_bImageReady
= false;
154 m_clearColour
= 0.0f
;
155 m_pboSupported
= false;
157 m_nonLinStretch
= false;
158 m_nonLinStretchGui
= false;
161 m_ColorManager
.reset(new CColorManager());
169 CLinuxRendererGL::~CLinuxRendererGL()
175 glDeleteBuffersARB(1, &m_rgbPbo
);
181 av_free(m_rgbBuffer
);
187 sws_freeContext(m_context
);
193 m_pYUVShader
->Free();
199 bool CLinuxRendererGL::ValidateRenderer()
204 // if its first pass, just init textures and return
205 if (ValidateRenderTarget())
208 // this needs to be checked after texture validation
212 int index
= m_iYV12RenderBuffer
;
213 YUVBUFFER
& buf
= m_buffers
[index
];
215 if (!buf
.fields
[FIELD_FULL
][0].id
)
218 if (buf
.image
.flags
==0)
224 bool CLinuxRendererGL::ValidateRenderTarget()
228 if (!g_Windowing
.IsExtSupported("GL_ARB_texture_non_power_of_two") &&
229 g_Windowing
.IsExtSupported("GL_ARB_texture_rectangle"))
231 m_textureTarget
= GL_TEXTURE_RECTANGLE_ARB
;
234 // function pointer for texture might change in
235 // call to LoadShaders
237 for (int i
= 0 ; i
< NUM_BUFFERS
; i
++)
240 // trigger update of video filters
241 m_scalingMethodGui
= (ESCALINGMETHOD
)-1;
243 // create the yuv textures
245 if (m_renderMethod
< 0)
248 if (m_textureTarget
== GL_TEXTURE_RECTANGLE_ARB
)
249 CLog::Log(LOGNOTICE
,"Using GL_TEXTURE_RECTANGLE_ARB");
251 CLog::Log(LOGNOTICE
,"Using GL_TEXTURE_2D");
253 for (int i
= 0 ; i
< m_NumYV12Buffers
; i
++)
262 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
)
264 m_sourceWidth
= width
;
265 m_sourceHeight
= height
;
266 m_renderOrientation
= orientation
;
273 // Calculate the input frame aspect ratio.
274 CalculateFrameAspectRatio(d_width
, d_height
);
275 SetViewMode(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode
);
278 m_bConfigured
= true;
279 m_bImageReady
= false;
280 m_scalingMethodGui
= (ESCALINGMETHOD
)-1;
282 // Ensure that textures are recreated and rendering starts only after the 1st
283 // frame is loaded after every call to Configure().
284 m_bValidated
= false;
286 for (int i
= 0 ; i
<m_NumYV12Buffers
; i
++)
287 m_buffers
[i
].image
.flags
= 0;
289 m_iLastRenderBuffer
= -1;
291 m_nonLinStretch
= false;
292 m_nonLinStretchGui
= false;
295 m_pboSupported
= g_Windowing
.IsExtSupported("GL_ARB_pixel_buffer_object");
297 #ifdef TARGET_DARWIN_OSX
298 // on osx 10.9 mavericks we get a strange ripple
299 // effect when rendering with pbo
300 // when used on intel gpu - we have to quirk it here
301 if (CDarwinUtils::IsMavericks())
303 std::string rendervendor
= g_Windowing
.GetRenderVendor();
304 StringUtils::ToLower(rendervendor
);
305 if (rendervendor
.find("intel") != std::string::npos
)
306 m_pboSupported
= false;
311 if (m_ColorManager
->IsEnabled())
313 if (!m_ColorManager
->CheckConfiguration(m_cmsToken
, m_iFlags
))
315 CLog::Log(LOGDEBUG
, "CMS configuration changed, reload LUT");
329 int CLinuxRendererGL::NextYV12Texture()
331 return (m_iYV12RenderBuffer
+ 1) % m_NumYV12Buffers
;
334 int CLinuxRendererGL::GetImage(YV12Image
*image
, int source
, bool readonly
)
342 /* take next available buffer */
343 if( source
== AUTOSOURCE
)
344 source
= NextYV12Texture();
346 YV12Image
&im
= m_buffers
[source
].image
;
348 if ((im
.flags
&(~IMAGE_FLAG_READY
)) != 0)
350 CLog::Log(LOGDEBUG
, "CLinuxRenderer::GetImage - request image but none to give");
355 im
.flags
|= IMAGE_FLAG_READING
;
357 im
.flags
|= IMAGE_FLAG_WRITING
;
359 // copy the image - should be operator of YV12Image
360 for (int p
=0;p
<MAX_PLANES
;p
++)
362 image
->plane
[p
] = im
.plane
[p
];
363 image
->stride
[p
] = im
.stride
[p
];
365 image
->width
= im
.width
;
366 image
->height
= im
.height
;
367 image
->flags
= im
.flags
;
368 image
->cshift_x
= im
.cshift_x
;
369 image
->cshift_y
= im
.cshift_y
;
375 void CLinuxRendererGL::ReleaseImage(int source
, bool preserve
)
377 YV12Image
&im
= m_buffers
[source
].image
;
379 im
.flags
&= ~IMAGE_FLAG_INUSE
;
380 im
.flags
|= IMAGE_FLAG_READY
;
381 /* if image should be preserved reserve it so it's not auto seleceted */
384 im
.flags
|= IMAGE_FLAG_RESERVED
;
386 m_bImageReady
= true;
389 void CLinuxRendererGL::GetPlaneTextureSize(YUVPLANE
& plane
)
391 /* texture is assumed to be bound */
395 glGetTexLevelParameteriv(m_textureTarget
, 0, GL_TEXTURE_WIDTH
, &width
);
396 glGetTexLevelParameteriv(m_textureTarget
, 0, GL_TEXTURE_HEIGHT
, &height
);
397 glGetTexLevelParameteriv(m_textureTarget
, 0, GL_TEXTURE_BORDER
, &border
);
398 plane
.texwidth
= width
- 2 * border
;
399 plane
.texheight
= height
- 2 * border
;
400 if(plane
.texwidth
<= 0 || plane
.texheight
<= 0)
402 CLog::Log(LOGDEBUG
, "CLinuxRendererGL::GetPlaneTextureSize - invalid size %dx%d - %d", width
, height
, border
);
403 /* to something that avoid division by zero */
410 void CLinuxRendererGL::CalculateTextureSourceRects(int source
, int num_planes
)
412 YUVBUFFER
& buf
= m_buffers
[source
];
413 YV12Image
* im
= &buf
.image
;
414 YUVFIELDS
& fields
= buf
.fields
;
416 // calculate the source rectangle
417 for(int field
= 0; field
< 3; field
++)
419 for(int plane
= 0; plane
< num_planes
; plane
++)
421 YUVPLANE
& p
= fields
[field
][plane
];
423 p
.rect
= m_sourceRect
;
425 p
.height
= im
->height
;
427 if(field
!= FIELD_FULL
)
429 /* correct for field offsets and chroma offsets */
430 float offset_y
= 0.5;
433 if(field
== FIELD_BOT
)
436 p
.rect
.y1
+= offset_y
;
437 p
.rect
.y2
+= offset_y
;
439 /* half the height if this is a field */
447 p
.width
/= 1 << im
->cshift_x
;
448 p
.height
/= 1 << im
->cshift_y
;
450 p
.rect
.x1
/= 1 << im
->cshift_x
;
451 p
.rect
.x2
/= 1 << im
->cshift_x
;
452 p
.rect
.y1
/= 1 << im
->cshift_y
;
453 p
.rect
.y2
/= 1 << im
->cshift_y
;
456 // protect against division by zero
457 if (p
.texheight
== 0 || p
.texwidth
== 0 ||
458 p
.pixpertex_x
== 0 || p
.pixpertex_y
== 0)
463 p
.height
/= p
.pixpertex_y
;
464 p
.rect
.y1
/= p
.pixpertex_y
;
465 p
.rect
.y2
/= p
.pixpertex_y
;
466 p
.width
/= p
.pixpertex_x
;
467 p
.rect
.x1
/= p
.pixpertex_x
;
468 p
.rect
.x2
/= p
.pixpertex_x
;
470 if (m_textureTarget
== GL_TEXTURE_2D
)
472 p
.height
/= p
.texheight
;
473 p
.rect
.y1
/= p
.texheight
;
474 p
.rect
.y2
/= p
.texheight
;
475 p
.width
/= p
.texwidth
;
476 p
.rect
.x1
/= p
.texwidth
;
477 p
.rect
.x2
/= p
.texwidth
;
483 void CLinuxRendererGL::LoadPlane( YUVPLANE
& plane
, int type
, unsigned flipindex
484 , unsigned width
, unsigned height
485 , int stride
, int bpp
, void* data
, GLuint
* pbo
/*= NULL*/)
487 if(plane
.flipindex
== flipindex
)
490 //if no pbo given, use the plane pbo
498 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, currPbo
);
500 int bps
= bpp
* glFormatElementByteCount(type
);
504 datatype
= GL_UNSIGNED_SHORT
;
506 datatype
= GL_UNSIGNED_BYTE
;
508 glPixelStorei(GL_UNPACK_ROW_LENGTH
, stride
/ bps
);
509 glBindTexture(m_textureTarget
, plane
.id
);
510 glTexSubImage2D(m_textureTarget
, 0, 0, 0, width
, height
, type
, datatype
, data
);
512 /* check if we need to load any border pixels */
513 if(height
< plane
.texheight
)
514 glTexSubImage2D( m_textureTarget
, 0
515 , 0, height
, width
, 1
517 , (unsigned char*)data
+ stride
* (height
-1));
519 if(width
< plane
.texwidth
)
520 glTexSubImage2D( m_textureTarget
, 0
521 , width
, 0, 1, height
523 , (unsigned char*)data
+ bps
* (width
-1));
525 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
526 glBindTexture(m_textureTarget
, 0);
528 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
530 plane
.flipindex
= flipindex
;
533 void CLinuxRendererGL::Reset()
535 for(int i
=0; i
<m_NumYV12Buffers
; i
++)
537 /* reset all image flags, this will cleanup textures later */
538 m_buffers
[i
].image
.flags
= 0;
542 void CLinuxRendererGL::Flush()
549 for (int i
= 0 ; i
< m_NumYV12Buffers
; i
++)
553 m_bValidated
= false;
555 m_iYV12RenderBuffer
= 0;
558 void CLinuxRendererGL::Update()
563 m_scalingMethodGui
= (ESCALINGMETHOD
)-1;
565 ValidateRenderTarget();
568 void CLinuxRendererGL::RenderUpdate(bool clear
, DWORD flags
, DWORD alpha
)
570 int index
= m_iYV12RenderBuffer
;
572 if (!ValidateRenderer())
574 if (clear
) //if clear is set, we're expected to overwrite all backbuffer pixels, even if we have nothing to render
584 //draw black bars when video is not transparent, clear the entire backbuffer when it is
594 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
595 glColor4f(1.0f
, 1.0f
, 1.0f
, alpha
/ 255.0f
);
600 glColor4f(1.0f
, 1.0f
, 1.0f
, 1.0f
);
603 if(flags
& RENDER_FLAG_WEAVE
)
605 int top_index
= index
;
606 int bot_index
= index
;
608 if((flags
& RENDER_FLAG_FIELD0
) && m_iLastRenderBuffer
> -1)
610 if(flags
& RENDER_FLAG_TOP
)
611 bot_index
= m_iLastRenderBuffer
;
613 top_index
= m_iLastRenderBuffer
;
616 glEnable(GL_POLYGON_STIPPLE
);
617 glPolygonStipple(stipple_weave
);
618 Render((flags
& ~RENDER_FLAG_FIELDMASK
) | RENDER_FLAG_TOP
, top_index
);
619 glPolygonStipple(stipple_weave
+4);
620 Render((flags
& ~RENDER_FLAG_FIELDMASK
) | RENDER_FLAG_BOT
, bot_index
);
621 glDisable(GL_POLYGON_STIPPLE
);
625 Render(flags
, index
);
632 void CLinuxRendererGL::ClearBackBuffer()
634 //set the entire backbuffer to black
635 glClearColor(m_clearColour
, m_clearColour
, m_clearColour
, 0);
636 glClear(GL_COLOR_BUFFER_BIT
);
637 glClearColor(0,0,0,0);
640 //draw black bars around the video quad, this is more efficient than glClear()
641 //since it only sets pixels to black that aren't going to be overwritten by the video
642 void CLinuxRendererGL::DrawBlackBars()
644 glColor4f(m_clearColour
, m_clearColour
, m_clearColour
, 1.0f
);
649 if (m_rotatedDestCoords
[0].y
> 0.0)
651 glVertex4f(0.0, 0.0, 0.0, 1.0);
652 glVertex4f(g_graphicsContext
.GetWidth(), 0.0, 0.0, 1.0);
653 glVertex4f(g_graphicsContext
.GetWidth(), m_rotatedDestCoords
[0].y
, 0.0, 1.0);
654 glVertex4f(0.0, m_rotatedDestCoords
[0].y
, 0.0, 1.0);
658 if (m_rotatedDestCoords
[2].y
< g_graphicsContext
.GetHeight())
660 glVertex4f(0.0, m_rotatedDestCoords
[2].y
, 0.0, 1.0);
661 glVertex4f(g_graphicsContext
.GetWidth(), m_rotatedDestCoords
[2].y
, 0.0, 1.0);
662 glVertex4f(g_graphicsContext
.GetWidth(), g_graphicsContext
.GetHeight(), 0.0, 1.0);
663 glVertex4f(0.0, g_graphicsContext
.GetHeight(), 0.0, 1.0);
667 if (m_rotatedDestCoords
[0].x
> 0.0)
669 glVertex4f(0.0, m_rotatedDestCoords
[0].y
, 0.0, 1.0);
670 glVertex4f(m_rotatedDestCoords
[0].x
, m_rotatedDestCoords
[0].y
, 0.0, 1.0);
671 glVertex4f(m_rotatedDestCoords
[0].x
, m_rotatedDestCoords
[2].y
, 0.0, 1.0);
672 glVertex4f(0.0, m_rotatedDestCoords
[2].y
, 0.0, 1.0);
676 if (m_rotatedDestCoords
[2].x
< g_graphicsContext
.GetWidth())
678 glVertex4f(m_rotatedDestCoords
[2].x
, m_rotatedDestCoords
[0].y
, 0.0, 1.0);
679 glVertex4f(g_graphicsContext
.GetWidth(), m_rotatedDestCoords
[0].y
, 0.0, 1.0);
680 glVertex4f(g_graphicsContext
.GetWidth(), m_rotatedDestCoords
[2].y
, 0.0, 1.0);
681 glVertex4f(m_rotatedDestCoords
[2].x
, m_rotatedDestCoords
[2].y
, 0.0, 1.0);
687 void CLinuxRendererGL::FlipPage(int source
)
689 UnBindPbo(m_buffers
[m_iYV12RenderBuffer
]);
691 m_iLastRenderBuffer
= m_iYV12RenderBuffer
;
693 if( source
>= 0 && source
< m_NumYV12Buffers
)
694 m_iYV12RenderBuffer
= source
;
696 m_iYV12RenderBuffer
= NextYV12Texture();
698 BindPbo(m_buffers
[m_iYV12RenderBuffer
]);
700 m_buffers
[m_iYV12RenderBuffer
].flipindex
= ++m_flipindex
;
705 void CLinuxRendererGL::PreInit()
707 CSingleLock
lock(g_graphicsContext
);
708 m_bConfigured
= false;
709 m_bValidated
= false;
712 m_iYV12RenderBuffer
= 0;
715 m_formats
.push_back(RENDER_FMT_YUV420P
);
717 glTexImage2D(GL_PROXY_TEXTURE_2D
, 0, GL_LUMINANCE16
, NP2(1920), NP2(1080), 0, GL_LUMINANCE
, GL_UNSIGNED_SHORT
, NULL
);
718 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D
, 0, GL_TEXTURE_LUMINANCE_SIZE
, &size
);
722 m_formats
.push_back(RENDER_FMT_YUV420P10
);
723 m_formats
.push_back(RENDER_FMT_YUV420P16
);
726 CLog::Log(LOGDEBUG
, "CLinuxRendererGL::PreInit - precision of luminance 16 is %d", size
);
727 m_formats
.push_back(RENDER_FMT_NV12
);
728 m_formats
.push_back(RENDER_FMT_YUYV422
);
729 m_formats
.push_back(RENDER_FMT_UYVY422
);
731 // setup the background colour
732 m_clearColour
= g_Windowing
.UseLimitedColor() ? (16.0f
/ 0xff) : 0.0f
;
735 void CLinuxRendererGL::UpdateVideoFilter()
737 bool pixelRatioChanged
= (CDisplaySettings::GetInstance().GetPixelRatio() > 1.001f
|| CDisplaySettings::GetInstance().GetPixelRatio() < 0.999f
) !=
738 (m_pixelRatio
> 1.001f
|| m_pixelRatio
< 0.999f
);
739 bool nonLinStretchChanged
= false;
740 bool cmsChanged
= (m_cmsOn
!= m_ColorManager
->IsEnabled())
741 || (m_cmsOn
&& !m_ColorManager
->CheckConfiguration(m_cmsToken
, m_iFlags
));
742 if (m_nonLinStretchGui
!= CDisplaySettings::GetInstance().IsNonLinearStretched() || pixelRatioChanged
)
744 m_nonLinStretchGui
= CDisplaySettings::GetInstance().IsNonLinearStretched();
745 m_pixelRatio
= CDisplaySettings::GetInstance().GetPixelRatio();
747 nonLinStretchChanged
= true;
749 if (m_nonLinStretchGui
&& (m_pixelRatio
< 0.999f
|| m_pixelRatio
> 1.001f
) && Supports(RENDERFEATURE_NONLINSTRETCH
))
751 m_nonLinStretch
= true;
752 CLog::Log(LOGDEBUG
, "GL: Enabling non-linear stretch");
756 m_nonLinStretch
= false;
757 CLog::Log(LOGDEBUG
, "GL: Disabling non-linear stretch");
761 if (m_scalingMethodGui
== CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ScalingMethod
&& !nonLinStretchChanged
&& !cmsChanged
)
766 //recompile YUV shader when non-linear stretch is turned on/off
767 //or when it's on and the scaling method changed
768 if (m_nonLinStretch
|| nonLinStretchChanged
)
773 if (m_ColorManager
->IsEnabled())
775 if (!m_ColorManager
->CheckConfiguration(m_cmsToken
, m_iFlags
))
777 CLog::Log(LOGDEBUG
, "CMS configuration changed, reload LUT");
788 m_scalingMethodGui
= CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ScalingMethod
;
789 m_scalingMethod
= m_scalingMethodGui
;
791 if(!Supports(m_scalingMethod
))
793 CLog::Log(LOGWARNING
, "CLinuxRendererGL::UpdateVideoFilter - choosen scaling method %d, is not supported by renderer", (int)m_scalingMethod
);
794 m_scalingMethod
= VS_SCALINGMETHOD_LINEAR
;
797 if (m_pVideoFilterShader
)
799 m_pVideoFilterShader
->Free();
800 delete m_pVideoFilterShader
;
801 m_pVideoFilterShader
= NULL
;
807 if (m_scalingMethod
== VS_SCALINGMETHOD_AUTO
)
809 bool scaleSD
= m_sourceHeight
< 720 && m_sourceWidth
< 1280;
810 bool scaleUp
= (int)m_sourceHeight
< g_graphicsContext
.GetHeight() && (int)m_sourceWidth
< g_graphicsContext
.GetWidth();
811 bool scaleFps
= m_fps
< g_advancedSettings
.m_videoAutoScaleMaxFps
+ 0.01f
;
813 if (Supports(VS_SCALINGMETHOD_LANCZOS3_FAST
) && scaleSD
&& scaleUp
&& scaleFps
)
814 m_scalingMethod
= VS_SCALINGMETHOD_LANCZOS3_FAST
;
816 m_scalingMethod
= VS_SCALINGMETHOD_LINEAR
;
819 switch (m_scalingMethod
)
821 case VS_SCALINGMETHOD_NEAREST
:
822 case VS_SCALINGMETHOD_LINEAR
:
823 SetTextureFilter(m_scalingMethod
== VS_SCALINGMETHOD_NEAREST
? GL_NEAREST
: GL_LINEAR
);
824 m_renderQuality
= RQ_SINGLEPASS
;
825 if (Supports(RENDERFEATURE_NONLINSTRETCH
) && m_nonLinStretch
)
827 m_pVideoFilterShader
= new StretchFilterShader();
828 if (!m_pVideoFilterShader
->CompileAndLink())
830 CLog::Log(LOGERROR
, "GL: Error compiling and linking video filter shader");
836 m_pVideoFilterShader
= new DefaultFilterShader();
837 if (!m_pVideoFilterShader
->CompileAndLink())
839 CLog::Log(LOGERROR
, "GL: Error compiling and linking video filter shader");
845 case VS_SCALINGMETHOD_LANCZOS2
:
846 case VS_SCALINGMETHOD_SPLINE36_FAST
:
847 case VS_SCALINGMETHOD_LANCZOS3_FAST
:
848 case VS_SCALINGMETHOD_SPLINE36
:
849 case VS_SCALINGMETHOD_LANCZOS3
:
850 case VS_SCALINGMETHOD_CUBIC
:
851 if (m_renderMethod
& RENDER_GLSL
)
853 if (!m_fbo
.fbo
.Initialize())
855 CLog::Log(LOGERROR
, "GL: Error initializing FBO");
859 if (!m_fbo
.fbo
.CreateAndBindToTexture(GL_TEXTURE_2D
, m_sourceWidth
, m_sourceHeight
, GL_RGBA16
, GL_SHORT
))
861 CLog::Log(LOGERROR
, "GL: Error creating texture and binding to FBO");
867 out
= new GLSLOutput(3,
870 m_cmsOn
? m_fullRange
: false,
871 m_cmsOn
? m_tCLUTTex
: 0,
873 m_pVideoFilterShader
= new ConvolutionFilterShader(m_scalingMethod
, m_nonLinStretch
, out
);
874 if (!m_pVideoFilterShader
->CompileAndLink())
876 CLog::Log(LOGERROR
, "GL: Error compiling and linking video filter shader");
880 SetTextureFilter(GL_LINEAR
);
881 m_renderQuality
= RQ_MULTIPASS
;
884 case VS_SCALINGMETHOD_BICUBIC_SOFTWARE
:
885 case VS_SCALINGMETHOD_LANCZOS_SOFTWARE
:
886 case VS_SCALINGMETHOD_SINC_SOFTWARE
:
887 case VS_SCALINGMETHOD_SINC8
:
888 case VS_SCALINGMETHOD_NEDI
:
889 CLog::Log(LOGERROR
, "GL: TODO: This scaler has not yet been implemented");
896 CLog::Log(LOGERROR
, "GL: Falling back to bilinear due to failure to init scaler");
897 if (m_pVideoFilterShader
)
899 m_pVideoFilterShader
->Free();
900 delete m_pVideoFilterShader
;
901 m_pVideoFilterShader
= NULL
;
905 SetTextureFilter(GL_LINEAR
);
906 m_renderQuality
= RQ_SINGLEPASS
;
909 void CLinuxRendererGL::LoadShaders(int field
)
911 if (!LoadShadersHook())
913 int requestedMethod
= CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_RENDERMETHOD
);
914 CLog::Log(LOGDEBUG
, "GL: Requested render method: %d", requestedMethod
);
918 m_pYUVShader
->Free();
924 switch(requestedMethod
)
926 case RENDER_METHOD_AUTO
:
927 #if defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
928 //with render method set to auto, don't try glsl on ati if we're on linux
929 //it seems to be broken in a random way with every new driver release
930 tryGlsl
= !StringUtils::StartsWithNoCase(g_Windowing
.GetRenderVendor(), "ati");
933 case RENDER_METHOD_GLSL
:
934 // Try GLSL shaders if supported and user requested auto or GLSL.
937 // create regular progressive scan shader
938 // if single pass, create GLSLOutput helper and pass it to YUV2RGB shader
939 GLSLOutput
*out
= nullptr;
940 if (m_renderQuality
== RQ_SINGLEPASS
)
942 out
= new GLSLOutput(3, m_useDithering
, m_ditherDepth
,
943 m_cmsOn
? m_fullRange
: false,
944 m_cmsOn
? m_tCLUTTex
: 0,
947 m_pYUVShader
= new YUV2RGBProgressiveShader(m_textureTarget
==GL_TEXTURE_RECTANGLE_ARB
, m_iFlags
, m_format
,
948 m_nonLinStretch
&& m_renderQuality
== RQ_SINGLEPASS
,
951 m_pYUVShader
->SetConvertFullColorRange(m_fullRange
);
953 CLog::Log(LOGNOTICE
, "GL: Selecting Single Pass YUV 2 RGB shader");
955 if (m_pYUVShader
&& m_pYUVShader
->CompileAndLink())
957 m_renderMethod
= RENDER_GLSL
;
961 else if (m_pYUVShader
)
963 m_pYUVShader
->Free();
967 CLog::Log(LOGERROR
, "GL: Error enabling YUV2RGB GLSL shader");
968 // drop through and try ARB
970 case RENDER_METHOD_ARB
:
971 // Try ARB shaders if supported and user requested it or GLSL shaders failed.
972 if (g_Windowing
.IsExtSupported("GL_ARB_fragment_program"))
974 CLog::Log(LOGNOTICE
, "GL: ARB shaders support detected");
975 m_renderMethod
= RENDER_ARB
;
977 // create regular progressive scan shader
978 m_pYUVShader
= new YUV2RGBProgressiveShaderARB(m_textureTarget
==GL_TEXTURE_RECTANGLE_ARB
, m_iFlags
, m_format
);
979 m_pYUVShader
->SetConvertFullColorRange(m_fullRange
);
980 CLog::Log(LOGNOTICE
, "GL: Selecting Single Pass ARB YUV2RGB shader");
982 if (m_pYUVShader
&& m_pYUVShader
->CompileAndLink())
984 m_renderMethod
= RENDER_ARB
;
988 else if (m_pYUVShader
)
990 m_pYUVShader
->Free();
994 CLog::Log(LOGERROR
, "GL: Error enabling YUV2RGB ARB shader");
1000 m_renderMethod
= -1;
1001 CLog::Log(LOGERROR
, "GL: Shaders support not present");
1007 // determine whether GPU supports NPOT textures
1008 if (!g_Windowing
.IsExtSupported("GL_ARB_texture_non_power_of_two"))
1010 if (!g_Windowing
.IsExtSupported("GL_ARB_texture_rectangle"))
1012 CLog::Log(LOGNOTICE
, "GL: GL_ARB_texture_rectangle not supported and OpenGL version is not 2.x");
1013 CLog::Log(LOGNOTICE
, "GL: Reverting to POT textures");
1014 m_renderMethod
|= RENDER_POT
;
1017 CLog::Log(LOGNOTICE
, "GL: NPOT textures are supported through GL_ARB_texture_rectangle extension");
1020 CLog::Log(LOGNOTICE
, "GL: NPOT texture support detected");
1025 CLog::Log(LOGNOTICE
, "GL: Using GL_ARB_pixel_buffer_object");
1032 void CLinuxRendererGL::UnInit()
1034 CLog::Log(LOGDEBUG
, "LinuxRendererGL: Cleaning up GL resources");
1035 CSingleLock
lock(g_graphicsContext
);
1041 glDeleteBuffersARB(1, &m_rgbPbo
);
1047 av_free(m_rgbBuffer
);
1050 m_rgbBufferSize
= 0;
1054 sws_freeContext(m_context
);
1059 for (int i
= 0; i
< NUM_BUFFERS
; ++i
)
1066 // cleanup framebuffer object if it was in use
1067 m_fbo
.fbo
.Cleanup();
1068 m_bValidated
= false;
1069 m_bImageReady
= false;
1070 m_bConfigured
= false;
1073 void CLinuxRendererGL::Render(DWORD flags
, int renderBuffer
)
1075 // obtain current field, if interlaced
1076 if( flags
& RENDER_FLAG_TOP
)
1077 m_currentField
= FIELD_TOP
;
1079 else if (flags
& RENDER_FLAG_BOT
)
1080 m_currentField
= FIELD_BOT
;
1083 m_currentField
= FIELD_FULL
;
1085 // call texture load function
1086 if (!UploadTexture(renderBuffer
))
1089 if (RenderHook(renderBuffer
))
1091 else if (m_renderMethod
& RENDER_GLSL
)
1093 UpdateVideoFilter();
1094 switch(m_renderQuality
)
1098 RenderSinglePass(renderBuffer
, m_currentField
);
1103 RenderToFBO(renderBuffer
, m_currentField
);
1109 else if (m_renderMethod
& RENDER_ARB
)
1111 RenderSinglePass(renderBuffer
, m_currentField
);
1115 RenderSoftware(renderBuffer
, m_currentField
);
1119 AfterRenderHook(renderBuffer
);
1122 void CLinuxRendererGL::RenderSinglePass(int index
, int field
)
1124 YUVFIELDS
&fields
= m_buffers
[index
].fields
;
1125 YUVPLANES
&planes
= fields
[field
];
1127 if (m_reloadShaders
)
1129 m_reloadShaders
= 0;
1133 glDisable(GL_DEPTH_TEST
);
1136 glActiveTextureARB(GL_TEXTURE0
);
1137 glEnable(m_textureTarget
);
1138 glBindTexture(m_textureTarget
, planes
[0].id
);
1141 glActiveTextureARB(GL_TEXTURE1
);
1142 glEnable(m_textureTarget
);
1143 glBindTexture(m_textureTarget
, planes
[1].id
);
1146 glActiveTextureARB(GL_TEXTURE2
);
1147 glEnable(m_textureTarget
);
1148 glBindTexture(m_textureTarget
, planes
[2].id
);
1150 glActiveTextureARB(GL_TEXTURE0
);
1153 m_pYUVShader
->SetBlack(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Brightness
* 0.01f
- 0.5f
);
1154 m_pYUVShader
->SetContrast(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Contrast
* 0.02f
);
1155 m_pYUVShader
->SetWidth(planes
[0].texwidth
);
1156 m_pYUVShader
->SetHeight(planes
[0].texheight
);
1158 //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer
1159 //having non-linear stretch on breaks the alignment
1160 if (g_application
.m_pPlayer
->IsInMenu())
1161 m_pYUVShader
->SetNonLinStretch(1.0);
1163 m_pYUVShader
->SetNonLinStretch(pow(CDisplaySettings::GetInstance().GetPixelRatio(), g_advancedSettings
.m_videoNonLinStretchRatio
));
1165 if (field
== FIELD_TOP
)
1166 m_pYUVShader
->SetField(1);
1167 else if(field
== FIELD_BOT
)
1168 m_pYUVShader
->SetField(0);
1170 m_pYUVShader
->Enable();
1174 glMultiTexCoord2fARB(GL_TEXTURE0
, planes
[0].rect
.x1
, planes
[0].rect
.y1
);
1175 glMultiTexCoord2fARB(GL_TEXTURE1
, planes
[1].rect
.x1
, planes
[1].rect
.y1
);
1176 glMultiTexCoord2fARB(GL_TEXTURE2
, planes
[2].rect
.x1
, planes
[2].rect
.y1
);
1177 glVertex4f(m_rotatedDestCoords
[0].x
, m_rotatedDestCoords
[0].y
, 0, 1.0f
);//top left
1179 glMultiTexCoord2fARB(GL_TEXTURE0
, planes
[0].rect
.x2
, planes
[0].rect
.y1
);
1180 glMultiTexCoord2fARB(GL_TEXTURE1
, planes
[1].rect
.x2
, planes
[1].rect
.y1
);
1181 glMultiTexCoord2fARB(GL_TEXTURE2
, planes
[2].rect
.x2
, planes
[2].rect
.y1
);
1182 glVertex4f(m_rotatedDestCoords
[1].x
, m_rotatedDestCoords
[1].y
, 0, 1.0f
);//top right
1184 glMultiTexCoord2fARB(GL_TEXTURE0
, planes
[0].rect
.x2
, planes
[0].rect
.y2
);
1185 glMultiTexCoord2fARB(GL_TEXTURE1
, planes
[1].rect
.x2
, planes
[1].rect
.y2
);
1186 glMultiTexCoord2fARB(GL_TEXTURE2
, planes
[2].rect
.x2
, planes
[2].rect
.y2
);
1187 glVertex4f(m_rotatedDestCoords
[2].x
, m_rotatedDestCoords
[2].y
, 0, 1.0f
);//bottom right
1189 glMultiTexCoord2fARB(GL_TEXTURE0
, planes
[0].rect
.x1
, planes
[0].rect
.y2
);
1190 glMultiTexCoord2fARB(GL_TEXTURE1
, planes
[1].rect
.x1
, planes
[1].rect
.y2
);
1191 glMultiTexCoord2fARB(GL_TEXTURE2
, planes
[2].rect
.x1
, planes
[2].rect
.y2
);
1192 glVertex4f(m_rotatedDestCoords
[3].x
, m_rotatedDestCoords
[3].y
, 0, 1.0f
);//bottom left
1197 m_pYUVShader
->Disable();
1200 glActiveTextureARB(GL_TEXTURE1
);
1201 glDisable(m_textureTarget
);
1203 glActiveTextureARB(GL_TEXTURE2
);
1204 glDisable(m_textureTarget
);
1206 glActiveTextureARB(GL_TEXTURE0
);
1207 glDisable(m_textureTarget
);
1209 glMatrixMode(GL_MODELVIEW
);
1214 void CLinuxRendererGL::RenderToFBO(int index
, int field
, bool weave
/*= false*/)
1216 YUVPLANES
&planes
= m_buffers
[index
].fields
[field
];
1218 if (m_reloadShaders
)
1220 m_reloadShaders
= 0;
1221 LoadShaders(m_currentField
);
1224 if (!m_fbo
.fbo
.IsValid())
1226 if (!m_fbo
.fbo
.Initialize())
1228 CLog::Log(LOGERROR
, "GL: Error initializing FBO");
1232 if (!m_fbo
.fbo
.CreateAndBindToTexture(GL_TEXTURE_2D
, m_sourceWidth
, m_sourceHeight
, GL_RGBA16
, GL_SHORT
))
1234 CLog::Log(LOGERROR
, "GL: Error creating texture and binding to FBO");
1239 glDisable(GL_DEPTH_TEST
);
1242 glEnable(m_textureTarget
);
1243 glActiveTextureARB(GL_TEXTURE0
);
1244 glBindTexture(m_textureTarget
, planes
[0].id
);
1248 glActiveTextureARB(GL_TEXTURE1
);
1249 glEnable(m_textureTarget
);
1250 glBindTexture(m_textureTarget
, planes
[1].id
);
1254 glActiveTextureARB(GL_TEXTURE2
);
1255 glEnable(m_textureTarget
);
1256 glBindTexture(m_textureTarget
, planes
[2].id
);
1259 glActiveTextureARB(GL_TEXTURE0
);
1262 // make sure the yuv shader is loaded and ready to go
1263 if (!m_pYUVShader
|| (!m_pYUVShader
->OK()))
1265 CLog::Log(LOGERROR
, "GL: YUV shader not active, cannot do multipass render");
1269 m_fbo
.fbo
.BeginRender();
1272 m_pYUVShader
->SetBlack(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Brightness
* 0.01f
- 0.5f
);
1273 m_pYUVShader
->SetContrast(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Contrast
* 0.02f
);
1274 m_pYUVShader
->SetWidth(planes
[0].texwidth
);
1275 m_pYUVShader
->SetHeight(planes
[0].texheight
);
1276 m_pYUVShader
->SetNonLinStretch(1.0);
1277 if (field
== FIELD_TOP
)
1278 m_pYUVShader
->SetField(1);
1279 else if(field
== FIELD_BOT
)
1280 m_pYUVShader
->SetField(0);
1284 glPushAttrib(GL_VIEWPORT_BIT
);
1285 glPushAttrib(GL_SCISSOR_BIT
);
1287 glMatrixModview
.Push();
1288 glMatrixModview
->LoadIdentity();
1289 glMatrixModview
.Load();
1291 glMatrixProject
.Push();
1292 glMatrixProject
->LoadIdentity();
1293 glMatrixProject
->Ortho2D(0, m_sourceWidth
, 0, m_sourceHeight
);
1294 glMatrixProject
.Load();
1296 glViewport(0, 0, m_sourceWidth
, m_sourceHeight
);
1297 glScissor (0, 0, m_sourceWidth
, m_sourceHeight
);
1299 if (!m_pYUVShader
->Enable())
1301 CLog::Log(LOGERROR
, "GL: Error enabling YUV shader");
1304 m_fbo
.width
= planes
[0].rect
.x2
- planes
[0].rect
.x1
;
1305 m_fbo
.height
= planes
[0].rect
.y2
- planes
[0].rect
.y1
;
1306 if (m_textureTarget
== GL_TEXTURE_2D
)
1308 m_fbo
.width
*= planes
[0].texwidth
;
1309 m_fbo
.height
*= planes
[0].texheight
;
1311 m_fbo
.width
*= planes
[0].pixpertex_x
;
1312 m_fbo
.height
*= planes
[0].pixpertex_y
;
1316 // 1st Pass to video frame size
1319 glMultiTexCoord2fARB(GL_TEXTURE0
, planes
[0].rect
.x1
, planes
[0].rect
.y1
);
1320 glMultiTexCoord2fARB(GL_TEXTURE1
, planes
[1].rect
.x1
, planes
[1].rect
.y1
);
1321 glMultiTexCoord2fARB(GL_TEXTURE2
, planes
[2].rect
.x1
, planes
[2].rect
.y1
);
1322 glVertex2f(0.0f
, 0.0f
);
1324 glMultiTexCoord2fARB(GL_TEXTURE0
, planes
[0].rect
.x2
, planes
[0].rect
.y1
);
1325 glMultiTexCoord2fARB(GL_TEXTURE1
, planes
[1].rect
.x2
, planes
[1].rect
.y1
);
1326 glMultiTexCoord2fARB(GL_TEXTURE2
, planes
[2].rect
.x2
, planes
[2].rect
.y1
);
1327 glVertex2f(m_fbo
.width
, 0.0f
);
1329 glMultiTexCoord2fARB(GL_TEXTURE0
, planes
[0].rect
.x2
, planes
[0].rect
.y2
);
1330 glMultiTexCoord2fARB(GL_TEXTURE1
, planes
[1].rect
.x2
, planes
[1].rect
.y2
);
1331 glMultiTexCoord2fARB(GL_TEXTURE2
, planes
[2].rect
.x2
, planes
[2].rect
.y2
);
1332 glVertex2f(m_fbo
.width
, m_fbo
.height
);
1334 glMultiTexCoord2fARB(GL_TEXTURE0
, planes
[0].rect
.x1
, planes
[0].rect
.y2
);
1335 glMultiTexCoord2fARB(GL_TEXTURE1
, planes
[1].rect
.x1
, planes
[1].rect
.y2
);
1336 glMultiTexCoord2fARB(GL_TEXTURE2
, planes
[2].rect
.x1
, planes
[2].rect
.y2
);
1337 glVertex2f(0.0f
, m_fbo
.height
);
1342 m_pYUVShader
->Disable();
1344 glMatrixModview
.PopLoad();
1345 glMatrixProject
.PopLoad();
1347 glPopAttrib(); // pop scissor
1348 glPopAttrib(); // pop viewport
1351 m_fbo
.fbo
.EndRender();
1353 glActiveTextureARB(GL_TEXTURE1
);
1354 glDisable(m_textureTarget
);
1355 glActiveTextureARB(GL_TEXTURE2
);
1356 glDisable(m_textureTarget
);
1357 glActiveTextureARB(GL_TEXTURE0
);
1358 glDisable(m_textureTarget
);
1361 void CLinuxRendererGL::RenderFromFBO()
1363 glEnable(GL_TEXTURE_2D
);
1364 glActiveTextureARB(GL_TEXTURE0
);
1367 // Use regular normalized texture coordinates
1369 // 2nd Pass to screen size with optional video filter
1371 if (m_pVideoFilterShader
)
1374 if (!m_pVideoFilterShader
->GetTextureFilter(filter
))
1375 filter
= m_scalingMethod
== VS_SCALINGMETHOD_NEAREST
? GL_NEAREST
: GL_LINEAR
;
1377 m_fbo
.fbo
.SetFiltering(GL_TEXTURE_2D
, filter
);
1378 m_pVideoFilterShader
->SetSourceTexture(0);
1379 m_pVideoFilterShader
->SetWidth(m_sourceWidth
);
1380 m_pVideoFilterShader
->SetHeight(m_sourceHeight
);
1382 //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer
1383 //having non-linear stretch on breaks the alignment
1384 if (g_application
.m_pPlayer
->IsInMenu())
1385 m_pVideoFilterShader
->SetNonLinStretch(1.0);
1387 m_pVideoFilterShader
->SetNonLinStretch(pow(CDisplaySettings::GetInstance().GetPixelRatio(), g_advancedSettings
.m_videoNonLinStretchRatio
));
1389 m_pVideoFilterShader
->Enable();
1393 GLint filter
= m_scalingMethod
== VS_SCALINGMETHOD_NEAREST
? GL_NEAREST
: GL_LINEAR
;
1394 m_fbo
.fbo
.SetFiltering(GL_TEXTURE_2D
, filter
);
1395 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
1400 float imgwidth
= m_fbo
.width
/ m_sourceWidth
;
1401 float imgheight
= m_fbo
.height
/ m_sourceHeight
;
1405 glMultiTexCoord2fARB(GL_TEXTURE0
, 0.0f
, 0.0f
);
1406 glVertex4f(m_rotatedDestCoords
[0].x
, m_rotatedDestCoords
[0].y
, 0, 1.0f
);
1408 glMultiTexCoord2fARB(GL_TEXTURE0
, imgwidth
, 0.0f
);
1409 glVertex4f(m_rotatedDestCoords
[1].x
, m_rotatedDestCoords
[1].y
, 0, 1.0f
);
1411 glMultiTexCoord2fARB(GL_TEXTURE0
, imgwidth
, imgheight
);
1412 glVertex4f(m_rotatedDestCoords
[2].x
, m_rotatedDestCoords
[2].y
, 0, 1.0f
);
1414 glMultiTexCoord2fARB(GL_TEXTURE0
, 0.0f
, imgheight
);
1415 glVertex4f(m_rotatedDestCoords
[3].x
, m_rotatedDestCoords
[3].y
, 0, 1.0f
);
1421 if (m_pVideoFilterShader
)
1422 m_pVideoFilterShader
->Disable();
1426 glBindTexture(GL_TEXTURE_2D
, 0);
1427 glDisable(GL_TEXTURE_2D
);
1431 void CLinuxRendererGL::RenderProgressiveWeave(int index
, int field
)
1433 bool scale
= (int)m_sourceHeight
!= m_destRect
.Height() ||
1434 (int)m_sourceWidth
!= m_destRect
.Width();
1436 if (m_fbo
.fbo
.IsSupported() && (scale
|| m_renderQuality
== RQ_MULTIPASS
))
1438 glEnable(GL_POLYGON_STIPPLE
);
1439 glPolygonStipple(stipple_weave
);
1440 RenderToFBO(index
, FIELD_TOP
, true);
1441 glPolygonStipple(stipple_weave
+4);
1442 RenderToFBO(index
, FIELD_BOT
, true);
1443 glDisable(GL_POLYGON_STIPPLE
);
1448 glEnable(GL_POLYGON_STIPPLE
);
1449 glPolygonStipple(stipple_weave
);
1450 RenderSinglePass(index
, FIELD_TOP
);
1451 glPolygonStipple(stipple_weave
+4);
1452 RenderSinglePass(index
, FIELD_BOT
);
1453 glDisable(GL_POLYGON_STIPPLE
);
1457 void CLinuxRendererGL::RenderRGB(int index
, int field
)
1459 YUVPLANE
&plane
= m_buffers
[index
].fields
[FIELD_FULL
][0];
1461 glEnable(m_textureTarget
);
1462 glActiveTextureARB(GL_TEXTURE0
);
1464 glBindTexture(m_textureTarget
, plane
.id
);
1466 // make sure we know the correct texture size
1467 GetPlaneTextureSize(plane
);
1469 // Try some clamping or wrapping
1470 glTexParameteri(m_textureTarget
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
1471 glTexParameteri(m_textureTarget
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
1473 if (m_pVideoFilterShader
)
1476 if (!m_pVideoFilterShader
->GetTextureFilter(filter
))
1477 filter
= m_scalingMethod
== VS_SCALINGMETHOD_NEAREST
? GL_NEAREST
: GL_LINEAR
;
1479 glTexParameteri(m_textureTarget
, GL_TEXTURE_MAG_FILTER
, filter
);
1480 glTexParameteri(m_textureTarget
, GL_TEXTURE_MIN_FILTER
, filter
);
1481 m_pVideoFilterShader
->SetSourceTexture(0);
1482 m_pVideoFilterShader
->SetWidth(m_sourceWidth
);
1483 m_pVideoFilterShader
->SetHeight(m_sourceHeight
);
1485 //disable non-linear stretch when a dvd menu is shown, parts of the menu are rendered through the overlay renderer
1486 //having non-linear stretch on breaks the alignment
1487 if (g_application
.m_pPlayer
->IsInMenu())
1488 m_pVideoFilterShader
->SetNonLinStretch(1.0);
1490 m_pVideoFilterShader
->SetNonLinStretch(pow(CDisplaySettings::GetInstance().GetPixelRatio(), g_advancedSettings
.m_videoNonLinStretchRatio
));
1492 m_pVideoFilterShader
->Enable();
1496 GLint filter
= m_scalingMethod
== VS_SCALINGMETHOD_NEAREST
? GL_NEAREST
: GL_LINEAR
;
1497 glTexParameteri(m_textureTarget
, GL_TEXTURE_MAG_FILTER
, filter
);
1498 glTexParameteri(m_textureTarget
, GL_TEXTURE_MIN_FILTER
, filter
);
1501 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
1505 if (m_textureTarget
==GL_TEXTURE_2D
)
1507 glTexCoord2f(plane
.rect
.x1
, plane
.rect
.y1
); glVertex2f(m_rotatedDestCoords
[0].x
, m_rotatedDestCoords
[0].y
);
1508 glTexCoord2f(plane
.rect
.x2
, plane
.rect
.y1
); glVertex2f(m_rotatedDestCoords
[1].x
, m_rotatedDestCoords
[1].y
);
1509 glTexCoord2f(plane
.rect
.x2
, plane
.rect
.y2
); glVertex2f(m_rotatedDestCoords
[2].x
, m_rotatedDestCoords
[2].y
);
1510 glTexCoord2f(plane
.rect
.x1
, plane
.rect
.y2
); glVertex2f(m_rotatedDestCoords
[3].x
, m_rotatedDestCoords
[3].y
);
1514 glTexCoord2f(plane
.rect
.x1
, plane
.rect
.y1
); glVertex4f(m_rotatedDestCoords
[0].x
, m_rotatedDestCoords
[0].y
, 0.0f
, 0.0f
);
1515 glTexCoord2f(plane
.rect
.x2
, plane
.rect
.y1
); glVertex4f(m_rotatedDestCoords
[1].x
, m_rotatedDestCoords
[1].y
, 1.0f
, 0.0f
);
1516 glTexCoord2f(plane
.rect
.x2
, plane
.rect
.y2
); glVertex4f(m_rotatedDestCoords
[2].x
, m_rotatedDestCoords
[2].y
, 1.0f
, 1.0f
);
1517 glTexCoord2f(plane
.rect
.x1
, plane
.rect
.y2
); glVertex4f(m_rotatedDestCoords
[3].x
, m_rotatedDestCoords
[3].y
, 0.0f
, 1.0f
);
1522 if (m_pVideoFilterShader
)
1523 m_pVideoFilterShader
->Disable();
1525 glBindTexture (m_textureTarget
, 0);
1526 glDisable(m_textureTarget
);
1529 void CLinuxRendererGL::RenderSoftware(int index
, int field
)
1531 // used for textues uploaded from rgba or CVPixelBuffers.
1532 YUVPLANES
&planes
= m_buffers
[index
].fields
[field
];
1534 glDisable(GL_DEPTH_TEST
);
1536 glEnable(m_textureTarget
);
1537 glActiveTextureARB(GL_TEXTURE0
);
1538 glBindTexture(m_textureTarget
, planes
[0].id
);
1539 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
1542 glTexCoord2f(planes
[0].rect
.x1
, planes
[0].rect
.y1
);
1543 glVertex4f(m_rotatedDestCoords
[0].x
, m_rotatedDestCoords
[0].y
, 0, 1.0f
);
1545 glTexCoord2f(planes
[0].rect
.x2
, planes
[0].rect
.y1
);
1546 glVertex4f(m_rotatedDestCoords
[1].x
, m_rotatedDestCoords
[1].y
, 0, 1.0f
);
1548 glTexCoord2f(planes
[0].rect
.x2
, planes
[0].rect
.y2
);
1549 glVertex4f(m_rotatedDestCoords
[2].x
, m_rotatedDestCoords
[2].y
, 0, 1.0f
);
1551 glTexCoord2f(planes
[0].rect
.x1
, planes
[0].rect
.y2
);
1552 glVertex4f(m_rotatedDestCoords
[3].x
, m_rotatedDestCoords
[3].y
, 0, 1.0f
);
1558 glDisable(m_textureTarget
);
1562 bool CLinuxRendererGL::RenderCapture(CRenderCapture
* capture
)
1567 // save current video rect
1568 CRect saveSize
= m_destRect
;
1570 saveRotatedCoords();//backup current m_rotatedDestCoords
1572 // new video rect is capture size
1573 m_destRect
.SetRect(0, 0, (float)capture
->GetWidth(), (float)capture
->GetHeight());
1575 syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords
1577 //invert Y axis to get non-inverted image
1578 glDisable(GL_BLEND
);
1579 glColor4f(1.0f
, 1.0f
, 1.0f
, 1.0f
);
1581 glMatrixModview
.Push();
1582 glMatrixModview
->Translatef(0.0f
, capture
->GetHeight(), 0.0f
);
1583 glMatrixModview
->Scalef(1.0f
, -1.0f
, 1.0f
);
1584 glMatrixModview
.Load();
1586 capture
->BeginRender();
1588 Render(RENDER_FLAG_NOOSD
, m_iYV12RenderBuffer
);
1590 glReadPixels(0, g_graphicsContext
.GetHeight() - capture
->GetHeight(), capture
->GetWidth(), capture
->GetHeight(),
1591 GL_BGRA
, GL_UNSIGNED_BYTE
, capture
->GetRenderBuffer());
1593 capture
->EndRender();
1595 // revert model view matrix
1596 glMatrixModview
.PopLoad();
1598 // restore original video rect
1599 m_destRect
= saveSize
;
1600 restoreRotatedCoords();//restores the previous state of the rotated dest coords
1606 static GLint
GetInternalFormat(GLint format
, int bpp
)
1613 case GL_ALPHA
: return GL_ALPHA16
;
1615 #ifdef GL_LUMINANCE16
1616 case GL_LUMINANCE
: return GL_LUMINANCE16
;
1618 default: return format
;
1625 //-----------------------------------------------------------------------------
1627 //-----------------------------------------------------------------------------
1629 bool CLinuxRendererGL::CreateTexture(int index
)
1631 if (m_format
== RENDER_FMT_NV12
)
1632 return CreateNV12Texture(index
);
1633 else if (m_format
== RENDER_FMT_YUYV422
||
1634 m_format
== RENDER_FMT_UYVY422
)
1635 return CreateYUV422PackedTexture(index
);
1637 return CreateYV12Texture(index
);
1640 void CLinuxRendererGL::DeleteTexture(int index
)
1642 if (m_format
== RENDER_FMT_NV12
)
1643 DeleteNV12Texture(index
);
1644 else if (m_format
== RENDER_FMT_YUYV422
||
1645 m_format
== RENDER_FMT_UYVY422
)
1646 DeleteYUV422PackedTexture(index
);
1648 DeleteYV12Texture(index
);
1651 bool CLinuxRendererGL::UploadTexture(int index
)
1653 if (m_format
== RENDER_FMT_NV12
)
1654 return UploadNV12Texture(index
);
1655 else if (m_format
== RENDER_FMT_YUYV422
||
1656 m_format
== RENDER_FMT_UYVY422
)
1657 return UploadYUV422PackedTexture(index
);
1659 return UploadYV12Texture(index
);
1664 //********************************************************************************************************
1665 // YV12 Texture creation, deletion, copying + clearing
1666 //********************************************************************************************************
1668 bool CLinuxRendererGL::CreateYV12Texture(int index
)
1670 /* since we also want the field textures, pitch must be texture aligned */
1673 YV12Image
&im
= m_buffers
[index
].image
;
1674 YUVFIELDS
&fields
= m_buffers
[index
].fields
;
1675 GLuint
*pbo
= m_buffers
[index
].pbo
;
1677 DeleteYV12Texture(index
);
1679 im
.height
= m_sourceHeight
;
1680 im
.width
= m_sourceWidth
;
1685 if(m_format
== RENDER_FMT_YUV420P16
1686 || m_format
== RENDER_FMT_YUV420P10
)
1691 im
.stride
[0] = im
.bpp
* im
.width
;
1692 im
.stride
[1] = im
.bpp
* ( im
.width
>> im
.cshift_x
);
1693 im
.stride
[2] = im
.bpp
* ( im
.width
>> im
.cshift_x
);
1695 im
.planesize
[0] = im
.stride
[0] * im
.height
;
1696 im
.planesize
[1] = im
.stride
[1] * ( im
.height
>> im
.cshift_y
);
1697 im
.planesize
[2] = im
.stride
[2] * ( im
.height
>> im
.cshift_y
);
1699 bool pboSetup
= false;
1703 glGenBuffersARB(3, pbo
);
1705 for (int i
= 0; i
< 3; i
++)
1707 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, pbo
[i
]);
1708 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, im
.planesize
[i
] + PBO_OFFSET
, 0, GL_STREAM_DRAW_ARB
);
1709 void* pboPtr
= glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_WRITE_ONLY_ARB
);
1712 im
.plane
[i
] = (BYTE
*) pboPtr
+ PBO_OFFSET
;
1713 memset(im
.plane
[i
], 0, im
.planesize
[i
]);
1717 CLog::Log(LOGWARNING
,"GL: failed to set up pixel buffer object");
1725 for (int i
= 0; i
< 3; i
++)
1727 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, pbo
[i
]);
1728 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
);
1730 glDeleteBuffersARB(3, pbo
);
1731 memset(m_buffers
[index
].pbo
, 0, sizeof(m_buffers
[index
].pbo
));
1734 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
1739 for (int i
= 0; i
< 3; i
++)
1740 im
.plane
[i
] = new BYTE
[im
.planesize
[i
]];
1743 glEnable(m_textureTarget
);
1744 for(int f
= 0;f
<MAX_FIELDS
;f
++)
1746 for(p
= 0;p
<MAX_PLANES
;p
++)
1748 if (!glIsTexture(fields
[f
][p
].id
))
1750 glGenTextures(1, &fields
[f
][p
].id
);
1753 fields
[f
][p
].pbo
= pbo
[p
];
1758 for (int f
= FIELD_FULL
; f
<=FIELD_BOT
; f
++)
1760 int fieldshift
= (f
==FIELD_FULL
) ? 0 : 1;
1761 YUVPLANES
&planes
= fields
[f
];
1763 planes
[0].texwidth
= im
.width
;
1764 planes
[0].texheight
= im
.height
>> fieldshift
;
1766 planes
[1].texwidth
= planes
[0].texwidth
>> im
.cshift_x
;
1767 planes
[1].texheight
= planes
[0].texheight
>> im
.cshift_y
;
1768 planes
[2].texwidth
= planes
[0].texwidth
>> im
.cshift_x
;
1769 planes
[2].texheight
= planes
[0].texheight
>> im
.cshift_y
;
1771 for (int p
= 0; p
< 3; p
++)
1773 planes
[p
].pixpertex_x
= 1;
1774 planes
[p
].pixpertex_y
= 1;
1777 if(m_renderMethod
& RENDER_POT
)
1779 for(int p
= 0; p
< 3; p
++)
1781 planes
[p
].texwidth
= NP2(planes
[p
].texwidth
);
1782 planes
[p
].texheight
= NP2(planes
[p
].texheight
);
1786 for(int p
= 0; p
< 3; p
++)
1788 YUVPLANE
&plane
= planes
[p
];
1789 if (plane
.texwidth
* plane
.texheight
== 0)
1792 glBindTexture(m_textureTarget
, plane
.id
);
1794 GLint internalformat
;
1795 if (p
== 2) //V plane needs an alpha texture
1798 format
= GL_LUMINANCE
;
1799 internalformat
= GetInternalFormat(format
, im
.bpp
);
1800 glTexImage2D(m_textureTarget
, 0, internalformat
, plane
.texwidth
, plane
.texheight
, 0, format
, GL_UNSIGNED_BYTE
, NULL
);
1802 glTexParameteri(m_textureTarget
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
1803 glTexParameteri(m_textureTarget
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
1804 glTexParameteri(m_textureTarget
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
1805 glTexParameteri(m_textureTarget
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
1809 glDisable(m_textureTarget
);
1813 bool CLinuxRendererGL::UploadYV12Texture(int source
)
1815 YUVBUFFER
& buf
= m_buffers
[source
];
1816 YV12Image
* im
= &buf
.image
;
1817 YUVFIELDS
& fields
= buf
.fields
;
1819 if (!(im
->flags
&IMAGE_FLAG_READY
))
1822 if (m_currentField
== FIELD_FULL
)
1823 deinterlacing
= false;
1825 deinterlacing
= true;
1827 glEnable(m_textureTarget
);
1830 glPixelStorei(GL_UNPACK_ALIGNMENT
,1);
1834 // Load Even Y Field
1835 LoadPlane( fields
[FIELD_TOP
][0] , GL_LUMINANCE
, buf
.flipindex
1836 , im
->width
, im
->height
>> 1
1837 , im
->stride
[0]*2, im
->bpp
, im
->plane
[0] );
1840 LoadPlane( fields
[FIELD_BOT
][0], GL_LUMINANCE
, buf
.flipindex
1841 , im
->width
, im
->height
>> 1
1842 , im
->stride
[0]*2, im
->bpp
, im
->plane
[0] + im
->stride
[0]) ;
1844 // Load Even U & V Fields
1845 LoadPlane( fields
[FIELD_TOP
][1], GL_LUMINANCE
, buf
.flipindex
1846 , im
->width
>> im
->cshift_x
, im
->height
>> (im
->cshift_y
+ 1)
1847 , im
->stride
[1]*2, im
->bpp
, im
->plane
[1] );
1849 LoadPlane( fields
[FIELD_TOP
][2], GL_ALPHA
, buf
.flipindex
1850 , im
->width
>> im
->cshift_x
, im
->height
>> (im
->cshift_y
+ 1)
1851 , im
->stride
[2]*2, im
->bpp
, im
->plane
[2] );
1853 // Load Odd U & V Fields
1854 LoadPlane( fields
[FIELD_BOT
][1], GL_LUMINANCE
, buf
.flipindex
1855 , im
->width
>> im
->cshift_x
, im
->height
>> (im
->cshift_y
+ 1)
1856 , im
->stride
[1]*2, im
->bpp
, im
->plane
[1] + im
->stride
[1] );
1858 LoadPlane( fields
[FIELD_BOT
][2], GL_ALPHA
, buf
.flipindex
1859 , im
->width
>> im
->cshift_x
, im
->height
>> (im
->cshift_y
+ 1)
1860 , im
->stride
[2]*2, im
->bpp
, im
->plane
[2] + im
->stride
[2] );
1865 LoadPlane( fields
[FIELD_FULL
][0], GL_LUMINANCE
, buf
.flipindex
1866 , im
->width
, im
->height
1867 , im
->stride
[0], im
->bpp
, im
->plane
[0] );
1870 LoadPlane( fields
[FIELD_FULL
][1], GL_LUMINANCE
, buf
.flipindex
1871 , im
->width
>> im
->cshift_x
, im
->height
>> im
->cshift_y
1872 , im
->stride
[1], im
->bpp
, im
->plane
[1] );
1875 LoadPlane( fields
[FIELD_FULL
][2], GL_ALPHA
, buf
.flipindex
1876 , im
->width
>> im
->cshift_x
, im
->height
>> im
->cshift_y
1877 , im
->stride
[2], im
->bpp
, im
->plane
[2] );
1882 CalculateTextureSourceRects(source
, 3);
1884 glDisable(m_textureTarget
);
1888 void CLinuxRendererGL::DeleteYV12Texture(int index
)
1890 YV12Image
&im
= m_buffers
[index
].image
;
1891 YUVFIELDS
&fields
= m_buffers
[index
].fields
;
1892 GLuint
*pbo
= m_buffers
[index
].pbo
;
1894 if( fields
[FIELD_FULL
][0].id
== 0 ) return;
1896 /* finish up all textures, and delete them */
1897 for(int f
= 0;f
<MAX_FIELDS
;f
++)
1899 for(int p
= 0;p
<MAX_PLANES
;p
++)
1901 if( fields
[f
][p
].id
)
1903 if (glIsTexture(fields
[f
][p
].id
))
1904 glDeleteTextures(1, &fields
[f
][p
].id
);
1905 fields
[f
][p
].id
= 0;
1910 for(int p
= 0;p
<MAX_PLANES
;p
++)
1916 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, pbo
[p
]);
1917 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
);
1919 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
1921 glDeleteBuffersARB(1, pbo
+ p
);
1928 delete[] im
.plane
[p
];
1935 //********************************************************************************************************
1936 // NV12 Texture loading, creation and deletion
1937 //********************************************************************************************************
1938 bool CLinuxRendererGL::UploadNV12Texture(int source
)
1940 YUVBUFFER
& buf
= m_buffers
[source
];
1941 YV12Image
* im
= &buf
.image
;
1942 YUVFIELDS
& fields
= buf
.fields
;
1944 if (!(im
->flags
& IMAGE_FLAG_READY
))
1947 if (m_currentField
== FIELD_FULL
)
1948 deinterlacing
= false;
1950 deinterlacing
= true;
1952 glEnable(m_textureTarget
);
1955 glPixelStorei(GL_UNPACK_ALIGNMENT
, im
->bpp
);
1960 LoadPlane( fields
[FIELD_TOP
][0] , GL_LUMINANCE
, buf
.flipindex
1961 , im
->width
, im
->height
>> 1
1962 , im
->stride
[0]*2, im
->bpp
, im
->plane
[0] );
1964 // Load Even Y field
1965 LoadPlane( fields
[FIELD_BOT
][0], GL_LUMINANCE
, buf
.flipindex
1966 , im
->width
, im
->height
>> 1
1967 , im
->stride
[0]*2, im
->bpp
, im
->plane
[0] + im
->stride
[0]) ;
1969 // Load Odd UV Fields
1970 LoadPlane( fields
[FIELD_TOP
][1], GL_LUMINANCE_ALPHA
, buf
.flipindex
1971 , im
->width
>> im
->cshift_x
, im
->height
>> (im
->cshift_y
+ 1)
1972 , im
->stride
[1]*2, im
->bpp
, im
->plane
[1] );
1974 // Load Even UV Fields
1975 LoadPlane( fields
[FIELD_BOT
][1], GL_LUMINANCE_ALPHA
, buf
.flipindex
1976 , im
->width
>> im
->cshift_x
, im
->height
>> (im
->cshift_y
+ 1)
1977 , im
->stride
[1]*2, im
->bpp
, im
->plane
[1] + im
->stride
[1] );
1983 LoadPlane( fields
[FIELD_FULL
][0], GL_LUMINANCE
, buf
.flipindex
1984 , im
->width
, im
->height
1985 , im
->stride
[0], im
->bpp
, im
->plane
[0] );
1988 LoadPlane( fields
[FIELD_FULL
][1], GL_LUMINANCE_ALPHA
, buf
.flipindex
1989 , im
->width
>> im
->cshift_x
, im
->height
>> im
->cshift_y
1990 , im
->stride
[1], im
->bpp
, im
->plane
[1] );
1995 CalculateTextureSourceRects(source
, 3);
1997 glDisable(m_textureTarget
);
2001 bool CLinuxRendererGL::CreateNV12Texture(int index
)
2003 // since we also want the field textures, pitch must be texture aligned
2004 YV12Image
&im
= m_buffers
[index
].image
;
2005 YUVFIELDS
&fields
= m_buffers
[index
].fields
;
2006 GLuint
*pbo
= m_buffers
[index
].pbo
;
2008 // Delete any old texture
2009 DeleteNV12Texture(index
);
2011 im
.height
= m_sourceHeight
;
2012 im
.width
= m_sourceWidth
;
2017 im
.stride
[0] = im
.width
;
2018 im
.stride
[1] = im
.width
;
2026 im
.planesize
[0] = im
.stride
[0] * im
.height
;
2028 im
.planesize
[1] = im
.stride
[1] * im
.height
/ 2;
2029 // third plane is not used
2030 im
.planesize
[2] = 0;
2032 bool pboSetup
= false;
2036 glGenBuffersARB(2, pbo
);
2038 for (int i
= 0; i
< 2; i
++)
2040 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, pbo
[i
]);
2041 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, im
.planesize
[i
] + PBO_OFFSET
, 0, GL_STREAM_DRAW_ARB
);
2042 void* pboPtr
= glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_WRITE_ONLY_ARB
);
2045 im
.plane
[i
] = (BYTE
*)pboPtr
+ PBO_OFFSET
;
2046 memset(im
.plane
[i
], 0, im
.planesize
[i
]);
2050 CLog::Log(LOGWARNING
,"GL: failed to set up pixel buffer object");
2058 for (int i
= 0; i
< 2; i
++)
2060 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, pbo
[i
]);
2061 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
);
2063 glDeleteBuffersARB(2, pbo
);
2064 memset(m_buffers
[index
].pbo
, 0, sizeof(m_buffers
[index
].pbo
));
2067 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
2072 for (int i
= 0; i
< 2; i
++)
2073 im
.plane
[i
] = new BYTE
[im
.planesize
[i
]];
2076 glEnable(m_textureTarget
);
2077 for(int f
= 0;f
<MAX_FIELDS
;f
++)
2079 for(int p
= 0;p
<2;p
++)
2081 if (!glIsTexture(fields
[f
][p
].id
))
2083 glGenTextures(1, &fields
[f
][p
].id
);
2086 fields
[f
][p
].pbo
= pbo
[p
];
2088 fields
[f
][2].id
= fields
[f
][1].id
;
2092 for (int f
= FIELD_FULL
; f
<=FIELD_BOT
; f
++)
2094 int fieldshift
= (f
==FIELD_FULL
) ? 0 : 1;
2095 YUVPLANES
&planes
= fields
[f
];
2097 planes
[0].texwidth
= im
.width
;
2098 planes
[0].texheight
= im
.height
>> fieldshift
;
2100 planes
[1].texwidth
= planes
[0].texwidth
>> im
.cshift_x
;
2101 planes
[1].texheight
= planes
[0].texheight
>> im
.cshift_y
;
2102 planes
[2].texwidth
= planes
[1].texwidth
;
2103 planes
[2].texheight
= planes
[1].texheight
;
2105 for (int p
= 0; p
< 3; p
++)
2107 planes
[p
].pixpertex_x
= 1;
2108 planes
[p
].pixpertex_y
= 1;
2111 if(m_renderMethod
& RENDER_POT
)
2113 for(int p
= 0; p
< 3; p
++)
2115 planes
[p
].texwidth
= NP2(planes
[p
].texwidth
);
2116 planes
[p
].texheight
= NP2(planes
[p
].texheight
);
2120 for(int p
= 0; p
< 2; p
++)
2122 YUVPLANE
&plane
= planes
[p
];
2123 if (plane
.texwidth
* plane
.texheight
== 0)
2126 glBindTexture(m_textureTarget
, plane
.id
);
2128 glTexImage2D(m_textureTarget
, 0, GL_LUMINANCE_ALPHA
, plane
.texwidth
, plane
.texheight
, 0, GL_LUMINANCE_ALPHA
, GL_UNSIGNED_BYTE
, NULL
);
2130 glTexImage2D(m_textureTarget
, 0, GL_LUMINANCE
, plane
.texwidth
, plane
.texheight
, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, NULL
);
2132 glTexParameteri(m_textureTarget
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
2133 glTexParameteri(m_textureTarget
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
2134 glTexParameteri(m_textureTarget
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2135 glTexParameteri(m_textureTarget
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2139 glDisable(m_textureTarget
);
2143 void CLinuxRendererGL::DeleteNV12Texture(int index
)
2145 YV12Image
&im
= m_buffers
[index
].image
;
2146 YUVFIELDS
&fields
= m_buffers
[index
].fields
;
2147 GLuint
*pbo
= m_buffers
[index
].pbo
;
2149 if( fields
[FIELD_FULL
][0].id
== 0 ) return;
2151 // finish up all textures, and delete them
2152 for(int f
= 0;f
<MAX_FIELDS
;f
++)
2154 for(int p
= 0;p
<2;p
++)
2156 if( fields
[f
][p
].id
)
2158 if (glIsTexture(fields
[f
][p
].id
))
2160 glDeleteTextures(1, &fields
[f
][p
].id
);
2162 fields
[f
][p
].id
= 0;
2165 fields
[f
][2].id
= 0;
2168 for(int p
= 0;p
<2;p
++)
2174 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, pbo
[p
]);
2175 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
);
2177 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
2179 glDeleteBuffersARB(1, pbo
+ p
);
2186 delete[] im
.plane
[p
];
2193 bool CLinuxRendererGL::UploadYUV422PackedTexture(int source
)
2195 YUVBUFFER
& buf
= m_buffers
[source
];
2196 YV12Image
* im
= &buf
.image
;
2197 YUVFIELDS
& fields
= buf
.fields
;
2199 if (!(im
->flags
& IMAGE_FLAG_READY
))
2203 if (m_currentField
== FIELD_FULL
)
2204 deinterlacing
= false;
2206 deinterlacing
= true;
2208 glEnable(m_textureTarget
);
2211 glPixelStorei(GL_UNPACK_ALIGNMENT
,1);
2216 LoadPlane( fields
[FIELD_TOP
][0], GL_BGRA
, buf
.flipindex
2217 , im
->width
/ 2, im
->height
>> 1
2218 , im
->stride
[0] * 2, im
->bpp
, im
->plane
[0] );
2220 LoadPlane( fields
[FIELD_BOT
][0], GL_BGRA
, buf
.flipindex
2221 , im
->width
/ 2, im
->height
>> 1
2222 , im
->stride
[0] * 2, im
->bpp
, im
->plane
[0] + im
->stride
[0]) ;
2227 LoadPlane( fields
[FIELD_FULL
][0], GL_BGRA
, buf
.flipindex
2228 , im
->width
/ 2, im
->height
2229 , im
->stride
[0], im
->bpp
, im
->plane
[0] );
2234 CalculateTextureSourceRects(source
, 3);
2236 glDisable(m_textureTarget
);
2240 void CLinuxRendererGL::DeleteYUV422PackedTexture(int index
)
2242 YV12Image
&im
= m_buffers
[index
].image
;
2243 YUVFIELDS
&fields
= m_buffers
[index
].fields
;
2244 GLuint
*pbo
= m_buffers
[index
].pbo
;
2246 if( fields
[FIELD_FULL
][0].id
== 0 ) return;
2248 // finish up all textures, and delete them
2249 for(int f
= 0;f
<MAX_FIELDS
;f
++)
2251 if( fields
[f
][0].id
)
2253 if (glIsTexture(fields
[f
][0].id
))
2255 glDeleteTextures(1, &fields
[f
][0].id
);
2257 fields
[f
][0].id
= 0;
2259 fields
[f
][1].id
= 0;
2260 fields
[f
][2].id
= 0;
2267 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, pbo
[0]);
2268 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
);
2270 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
2272 glDeleteBuffersARB(1, pbo
);
2279 delete[] im
.plane
[0];
2285 bool CLinuxRendererGL::CreateYUV422PackedTexture(int index
)
2287 // since we also want the field textures, pitch must be texture aligned
2288 YV12Image
&im
= m_buffers
[index
].image
;
2289 YUVFIELDS
&fields
= m_buffers
[index
].fields
;
2290 GLuint
*pbo
= m_buffers
[index
].pbo
;
2292 // Delete any old texture
2293 DeleteYUV422PackedTexture(index
);
2295 im
.height
= m_sourceHeight
;
2296 im
.width
= m_sourceWidth
;
2301 im
.stride
[0] = im
.width
* 2;
2309 // packed YUYV plane
2310 im
.planesize
[0] = im
.stride
[0] * im
.height
;
2311 // second plane is not used
2312 im
.planesize
[1] = 0;
2313 // third plane is not used
2314 im
.planesize
[2] = 0;
2316 bool pboSetup
= false;
2320 glGenBuffersARB(1, pbo
);
2322 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, pbo
[0]);
2323 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, im
.planesize
[0] + PBO_OFFSET
, 0, GL_STREAM_DRAW_ARB
);
2324 void* pboPtr
= glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_WRITE_ONLY_ARB
);
2327 im
.plane
[0] = (BYTE
*)pboPtr
+ PBO_OFFSET
;
2328 memset(im
.plane
[0], 0, im
.planesize
[0]);
2332 CLog::Log(LOGWARNING
,"GL: failed to set up pixel buffer object");
2338 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, *pbo
);
2339 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
);
2340 glDeleteBuffersARB(1, pbo
);
2341 memset(m_buffers
[index
].pbo
, 0, sizeof(m_buffers
[index
].pbo
));
2344 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
2349 im
.plane
[0] = new BYTE
[im
.planesize
[0]];
2352 glEnable(m_textureTarget
);
2353 for(int f
= 0;f
<MAX_FIELDS
;f
++)
2355 if (!glIsTexture(fields
[f
][0].id
))
2357 glGenTextures(1, &fields
[f
][0].id
);
2360 fields
[f
][0].pbo
= pbo
[0];
2361 fields
[f
][1].id
= fields
[f
][0].id
;
2362 fields
[f
][2].id
= fields
[f
][1].id
;
2366 for (int f
= FIELD_FULL
; f
<=FIELD_BOT
; f
++)
2368 int fieldshift
= (f
==FIELD_FULL
) ? 0 : 1;
2369 YUVPLANES
&planes
= fields
[f
];
2371 planes
[0].texwidth
= im
.width
/ 2;
2372 planes
[0].texheight
= im
.height
>> fieldshift
;
2373 planes
[1].texwidth
= planes
[0].texwidth
;
2374 planes
[1].texheight
= planes
[0].texheight
;
2375 planes
[2].texwidth
= planes
[1].texwidth
;
2376 planes
[2].texheight
= planes
[1].texheight
;
2378 for (int p
= 0; p
< 3; p
++)
2380 planes
[p
].pixpertex_x
= 2;
2381 planes
[p
].pixpertex_y
= 1;
2384 if(m_renderMethod
& RENDER_POT
)
2386 for(int p
= 0; p
< 3; p
++)
2388 planes
[p
].texwidth
= NP2(planes
[p
].texwidth
);
2389 planes
[p
].texheight
= NP2(planes
[p
].texheight
);
2393 YUVPLANE
&plane
= planes
[0];
2394 if (plane
.texwidth
* plane
.texheight
== 0)
2397 glBindTexture(m_textureTarget
, plane
.id
);
2399 glTexImage2D(m_textureTarget
, 0, GL_RGBA
, plane
.texwidth
, plane
.texheight
, 0, GL_BGRA
, GL_UNSIGNED_BYTE
, NULL
);
2401 glTexParameteri(m_textureTarget
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
2402 glTexParameteri(m_textureTarget
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
2403 glTexParameteri(m_textureTarget
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2404 glTexParameteri(m_textureTarget
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2407 glDisable(m_textureTarget
);
2412 void CLinuxRendererGL::SetTextureFilter(GLenum method
)
2414 for (int i
= 0 ; i
<m_NumYV12Buffers
; i
++)
2416 YUVFIELDS
&fields
= m_buffers
[i
].fields
;
2418 for (int f
= FIELD_FULL
; f
<=FIELD_BOT
; f
++)
2420 for (int p
= 0; p
< 3; p
++)
2422 if(glIsTexture(fields
[f
][p
].id
))
2424 glBindTexture(m_textureTarget
, fields
[f
][p
].id
);
2425 glTexParameteri(m_textureTarget
, GL_TEXTURE_MIN_FILTER
, method
);
2426 glTexParameteri(m_textureTarget
, GL_TEXTURE_MAG_FILTER
, method
);
2434 bool CLinuxRendererGL::Supports(ERENDERFEATURE feature
)
2436 if(feature
== RENDERFEATURE_BRIGHTNESS
)
2438 return (m_renderMethod
& RENDER_GLSL
) ||
2439 (m_renderMethod
& RENDER_ARB
);
2442 if(feature
== RENDERFEATURE_CONTRAST
)
2444 return (m_renderMethod
& RENDER_GLSL
) ||
2445 (m_renderMethod
& RENDER_ARB
);
2448 if(feature
== RENDERFEATURE_GAMMA
)
2451 if(feature
== RENDERFEATURE_NOISE
)
2454 if(feature
== RENDERFEATURE_SHARPNESS
)
2459 if (feature
== RENDERFEATURE_NONLINSTRETCH
)
2461 if ((m_renderMethod
& RENDER_GLSL
) && !(m_renderMethod
& RENDER_POT
))
2465 if (feature
== RENDERFEATURE_STRETCH
||
2466 feature
== RENDERFEATURE_ZOOM
||
2467 feature
== RENDERFEATURE_VERTICAL_SHIFT
||
2468 feature
== RENDERFEATURE_PIXEL_RATIO
||
2469 feature
== RENDERFEATURE_POSTPROCESS
||
2470 feature
== RENDERFEATURE_ROTATION
)
2476 bool CLinuxRendererGL::SupportsMultiPassRendering()
2478 return g_Windowing
.IsExtSupported("GL_EXT_framebuffer_object");
2481 bool CLinuxRendererGL::Supports(ESCALINGMETHOD method
)
2483 //nearest neighbor doesn't work on YUY2 and UYVY
2484 if (method
== VS_SCALINGMETHOD_NEAREST
&&
2485 m_format
!= RENDER_FMT_YUYV422
&&
2486 m_format
!= RENDER_FMT_UYVY422
)
2489 if(method
== VS_SCALINGMETHOD_LINEAR
2490 || method
== VS_SCALINGMETHOD_AUTO
)
2493 if(method
== VS_SCALINGMETHOD_CUBIC
2494 || method
== VS_SCALINGMETHOD_LANCZOS2
2495 || method
== VS_SCALINGMETHOD_SPLINE36_FAST
2496 || method
== VS_SCALINGMETHOD_LANCZOS3_FAST
2497 || method
== VS_SCALINGMETHOD_SPLINE36
2498 || method
== VS_SCALINGMETHOD_LANCZOS3
)
2500 // if scaling is below level, avoid hq scaling
2501 float scaleX
= fabs(((float)m_sourceWidth
- m_destRect
.Width())/m_sourceWidth
)*100;
2502 float scaleY
= fabs(((float)m_sourceHeight
- m_destRect
.Height())/m_sourceHeight
)*100;
2503 int minScale
= CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_HQSCALERS
);
2504 if (scaleX
< minScale
&& scaleY
< minScale
)
2507 if (g_Windowing
.IsExtSupported("GL_EXT_framebuffer_object") && (m_renderMethod
& RENDER_GLSL
))
2509 // spline36 and lanczos3 are only allowed through advancedsettings.xml
2510 if(method
!= VS_SCALINGMETHOD_SPLINE36
2511 && method
!= VS_SCALINGMETHOD_LANCZOS3
)
2514 return g_advancedSettings
.m_videoEnableHighQualityHwScalers
;
2521 void CLinuxRendererGL::BindPbo(YUVBUFFER
& buff
)
2524 for(int plane
= 0; plane
< MAX_PLANES
; plane
++)
2526 if(!buff
.pbo
[plane
] || buff
.image
.plane
[plane
] == (BYTE
*)PBO_OFFSET
)
2530 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, buff
.pbo
[plane
]);
2531 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
);
2532 buff
.image
.plane
[plane
] = (BYTE
*)PBO_OFFSET
;
2535 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
2538 void CLinuxRendererGL::UnBindPbo(YUVBUFFER
& buff
)
2541 for(int plane
= 0; plane
< MAX_PLANES
; plane
++)
2543 if(!buff
.pbo
[plane
] || buff
.image
.plane
[plane
] != (BYTE
*)PBO_OFFSET
)
2547 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, buff
.pbo
[plane
]);
2548 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, buff
.image
.planesize
[plane
] + PBO_OFFSET
, NULL
, GL_STREAM_DRAW_ARB
);
2549 buff
.image
.plane
[plane
] = (BYTE
*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_WRITE_ONLY_ARB
) + PBO_OFFSET
;
2552 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
2555 CRenderInfo
CLinuxRendererGL::GetRenderInfo()
2558 info
.formats
= m_formats
;
2559 info
.max_buffer_size
= NUM_BUFFERS
;
2560 info
.optimal_buffer_size
= 4;
2564 // Color management helpers
2566 bool CLinuxRendererGL::LoadCLUT()
2571 if ( !m_ColorManager
->GetVideo3dLut(m_iFlags
, &m_cmsToken
, &m_CLUTsize
, &m_CLUT
) )
2573 CLog::Log(LOGERROR
, "Error loading the LUT");
2577 // create 3DLUT texture
2578 CLog::Log(LOGDEBUG
, "LinuxRendererGL: creating 3DLUT");
2579 glGenTextures(1, &m_tCLUTTex
);
2580 glActiveTexture(GL_TEXTURE4
);
2581 if ( m_tCLUTTex
<= 0 )
2583 CLog::Log(LOGERROR
, "Error creating 3DLUT texture");
2587 // bind and set 3DLUT texture parameters
2588 glBindTexture(GL_TEXTURE_3D
, m_tCLUTTex
);
2589 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
2590 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
2591 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
2592 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
2593 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2594 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2595 glTexParameteri(GL_TEXTURE_3D
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
2598 glTexImage3D(GL_TEXTURE_3D
, 0, GL_RGB16
, m_CLUTsize
, m_CLUTsize
, m_CLUTsize
, 0, GL_RGB
, GL_UNSIGNED_SHORT
, m_CLUT
);
2600 glActiveTexture(GL_TEXTURE0
);
2604 void CLinuxRendererGL::DeleteCLUT()
2608 CLog::Log(LOGDEBUG
, "LinuxRendererGL: deleting 3DLUT");
2609 glDeleteTextures(1, &m_tCLUTTex
);