VTB: release CVBuffer after it actually has been rendered
[xbmc.git] / xbmc / cores / VideoPlayer / VideoRenderers / LinuxRendererGL.cpp
blob4e785f768833392aa30cc595f0209e1c5e074525
1 /*
2 * Copyright (c) 2007 Frodo/jcmarshall/vulkanr/d4rk
3 * Based on XBoxRenderer by Frodo/jcmarshall
4 * Portions Copyright (c) by the authors of ffmpeg / xvid /mplayer
5 * Copyright (C) 2007-2013 Team XBMC
6 * http://xbmc.org
8 * This Program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
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/>.
23 #include "system.h"
24 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
25 #include "config.h"
26 #endif
28 #ifdef HAS_GL
29 #include <locale.h>
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"
53 extern "C" {
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"
62 #endif
64 //! @bug
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
68 #define PBO_OFFSET 16
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));
113 flipindex = 0;
114 hwDec = NULL;
117 CLinuxRendererGL::YUVBUFFER::~YUVBUFFER()
122 CLinuxRendererGL::CLinuxRendererGL()
124 m_textureTarget = GL_TEXTURE_2D;
126 m_renderMethod = RENDER_GLSL;
127 m_renderQuality = RQ_SINGLEPASS;
128 m_iFlags = 0;
129 m_format = RENDER_FMT_NONE;
131 m_iYV12RenderBuffer = 0;
132 m_flipindex = 0;
133 m_currentField = FIELD_FULL;
134 m_reloadShaders = 0;
135 m_pYUVShader = NULL;
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();
143 m_rgbBuffer = NULL;
144 m_rgbBufferSize = 0;
145 m_context = NULL;
146 m_rgbPbo = 0;
147 m_fbo.width = 0.0;
148 m_fbo.height = 0.0;
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;
156 m_pboUsed = false;
157 m_nonLinStretch = false;
158 m_nonLinStretchGui = false;
159 m_pixelRatio = 0.0f;
161 m_ColorManager.reset(new CColorManager());
162 m_tCLUTTex = 0;
163 m_CLUT = NULL;
164 m_CLUTsize = 0;
165 m_cmsToken = -1;
166 m_cmsOn = false;
169 CLinuxRendererGL::~CLinuxRendererGL()
171 UnInit();
173 if (m_rgbPbo)
175 glDeleteBuffersARB(1, &m_rgbPbo);
176 m_rgbPbo = 0;
177 m_rgbBuffer = NULL;
179 else
181 av_free(m_rgbBuffer);
182 m_rgbBuffer = NULL;
185 if (m_context)
187 sws_freeContext(m_context);
188 m_context = NULL;
191 if (m_pYUVShader)
193 m_pYUVShader->Free();
194 delete m_pYUVShader;
195 m_pYUVShader = NULL;
199 bool CLinuxRendererGL::ValidateRenderer()
201 if (!m_bConfigured)
202 return false;
204 // if its first pass, just init textures and return
205 if (ValidateRenderTarget())
206 return false;
208 // this needs to be checked after texture validation
209 if (!m_bImageReady)
210 return false;
212 int index = m_iYV12RenderBuffer;
213 YUVBUFFER& buf = m_buffers[index];
215 if (!buf.fields[FIELD_FULL][0].id)
216 return false;
218 if (buf.image.flags==0)
219 return false;
221 return true;
224 bool CLinuxRendererGL::ValidateRenderTarget()
226 if (!m_bValidated)
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
236 glFinish();
237 for (int i = 0 ; i < NUM_BUFFERS ; i++)
238 DeleteTexture(i);
240 // trigger update of video filters
241 m_scalingMethodGui = (ESCALINGMETHOD)-1;
243 // create the yuv textures
244 LoadShaders();
245 if (m_renderMethod < 0)
246 return false;
248 if (m_textureTarget == GL_TEXTURE_RECTANGLE_ARB)
249 CLog::Log(LOGNOTICE,"Using GL_TEXTURE_RECTANGLE_ARB");
250 else
251 CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D");
253 for (int i = 0 ; i < m_NumYV12Buffers ; i++)
254 CreateTexture(i);
256 m_bValidated = true;
257 return true;
259 return false;
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;
267 m_fps = fps;
269 // Save the flags.
270 m_iFlags = flags;
271 m_format = format;
273 // Calculate the input frame aspect ratio.
274 CalculateFrameAspectRatio(d_width, d_height);
275 SetViewMode(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ViewMode);
276 ManageRenderArea();
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;
293 m_pixelRatio = 1.0;
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;
308 #endif
310 // load 3DLUT
311 if (m_ColorManager->IsEnabled())
313 if (!m_ColorManager->CheckConfiguration(m_cmsToken, m_iFlags))
315 CLog::Log(LOGDEBUG, "CMS configuration changed, reload LUT");
316 if (!LoadCLUT())
317 return false;
319 m_cmsOn = true;
321 else
323 m_cmsOn = false;
326 return true;
329 int CLinuxRendererGL::NextYV12Texture()
331 return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
334 int CLinuxRendererGL::GetImage(YV12Image *image, int source, bool readonly)
336 if (!image)
337 return -1;
339 if (!m_bValidated)
340 return -1;
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");
351 return -1;
354 if( readonly )
355 im.flags |= IMAGE_FLAG_READING;
356 else
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;
370 image->bpp = im.bpp;
372 return source;
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 */
383 if( preserve )
384 im.flags |= IMAGE_FLAG_RESERVED;
386 m_bImageReady = true;
389 void CLinuxRendererGL::GetPlaneTextureSize(YUVPLANE& plane)
391 /* texture is assumed to be bound */
392 GLint width = 0
393 , height = 0
394 , border = 0;
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 */
404 plane.texwidth = 1;
405 plane.texheight = 1;
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;
424 p.width = im->width;
425 p.height = im->height;
427 if(field != FIELD_FULL)
429 /* correct for field offsets and chroma offsets */
430 float offset_y = 0.5;
431 if(plane != 0)
432 offset_y += 0.5;
433 if(field == FIELD_BOT)
434 offset_y *= -1;
436 p.rect.y1 += offset_y;
437 p.rect.y2 += offset_y;
439 /* half the height if this is a field */
440 p.height *= 0.5f;
441 p.rect.y1 *= 0.5f;
442 p.rect.y2 *= 0.5f;
445 if(plane != 0)
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)
460 continue;
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)
488 return;
490 //if no pbo given, use the plane pbo
491 GLuint currPbo;
492 if (pbo)
493 currPbo = *pbo;
494 else
495 currPbo = plane.pbo;
497 if(currPbo)
498 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, currPbo);
500 int bps = bpp * glFormatElementByteCount(type);
502 unsigned datatype;
503 if(bpp == 2)
504 datatype = GL_UNSIGNED_SHORT;
505 else
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
516 , type, datatype
517 , (unsigned char*)data + stride * (height-1));
519 if(width < plane.texwidth)
520 glTexSubImage2D( m_textureTarget, 0
521 , width, 0, 1, height
522 , type, datatype
523 , (unsigned char*)data + bps * (width-1));
525 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
526 glBindTexture(m_textureTarget, 0);
527 if(currPbo)
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()
544 if (!m_bValidated)
545 return;
547 glFinish();
549 for (int i = 0 ; i < m_NumYV12Buffers ; i++)
550 DeleteTexture(i);
552 glFinish();
553 m_bValidated = false;
554 m_fbo.fbo.Cleanup();
555 m_iYV12RenderBuffer = 0;
558 void CLinuxRendererGL::Update()
560 if (!m_bConfigured)
561 return;
562 ManageRenderArea();
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
575 ClearBackBuffer();
577 return;
580 ManageRenderArea();
582 if (clear)
584 //draw black bars when video is not transparent, clear the entire backbuffer when it is
585 if (alpha == 255)
586 DrawBlackBars();
587 else
588 ClearBackBuffer();
591 if (alpha<255)
593 glEnable(GL_BLEND);
594 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
595 glColor4f(1.0f, 1.0f, 1.0f, alpha / 255.0f);
597 else
599 glDisable(GL_BLEND);
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;
612 else
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);
624 else
625 Render(flags, index);
627 VerifyGLState();
628 glEnable(GL_BLEND);
629 glFlush();
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);
645 glDisable(GL_BLEND);
646 glBegin(GL_QUADS);
648 //top quad
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);
657 //bottom quad
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);
666 //left quad
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);
675 //right quad
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);
684 glEnd();
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;
695 else
696 m_iYV12RenderBuffer = NextYV12Texture();
698 BindPbo(m_buffers[m_iYV12RenderBuffer]);
700 m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
702 return;
705 void CLinuxRendererGL::PreInit()
707 CSingleLock lock(g_graphicsContext);
708 m_bConfigured = false;
709 m_bValidated = false;
710 UnInit();
712 m_iYV12RenderBuffer = 0;
714 m_formats.clear();
715 m_formats.push_back(RENDER_FMT_YUV420P);
716 GLint size;
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);
720 if(size >= 16)
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();
746 m_reloadShaders = 1;
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");
754 else
756 m_nonLinStretch = false;
757 CLog::Log(LOGDEBUG, "GL: Disabling non-linear stretch");
761 if (m_scalingMethodGui == CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ScalingMethod && !nonLinStretchChanged && !cmsChanged)
762 return;
763 else
764 m_reloadShaders = 1;
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)
769 m_reloadShaders = 1;
771 if (cmsChanged)
773 if (m_ColorManager->IsEnabled())
775 if (!m_ColorManager->CheckConfiguration(m_cmsToken, m_iFlags))
777 CLog::Log(LOGDEBUG, "CMS configuration changed, reload LUT");
778 LoadCLUT();
780 m_cmsOn = true;
782 else
784 m_cmsOn = false;
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;
803 m_fbo.fbo.Cleanup();
805 VerifyGLState();
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;
815 else
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");
831 break;
834 else
836 m_pVideoFilterShader = new DefaultFilterShader();
837 if (!m_pVideoFilterShader->CompileAndLink())
839 CLog::Log(LOGERROR, "GL: Error compiling and linking video filter shader");
840 break;
843 return;
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");
856 break;
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");
862 break;
866 GLSLOutput *out;
867 out = new GLSLOutput(3,
868 m_useDithering,
869 m_ditherDepth,
870 m_cmsOn ? m_fullRange : false,
871 m_cmsOn ? m_tCLUTTex : 0,
872 m_CLUTsize);
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");
877 break;
880 SetTextureFilter(GL_LINEAR);
881 m_renderQuality = RQ_MULTIPASS;
882 return;
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");
890 break;
892 default:
893 break;
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;
903 m_fbo.fbo.Cleanup();
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);
916 if (m_pYUVShader)
918 m_pYUVShader->Free();
919 delete m_pYUVShader;
920 m_pYUVShader = NULL;
923 bool tryGlsl = true;
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");
931 #endif
933 case RENDER_METHOD_GLSL:
934 // Try GLSL shaders if supported and user requested auto or GLSL.
935 if (tryGlsl)
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,
945 m_CLUTsize);
947 m_pYUVShader = new YUV2RGBProgressiveShader(m_textureTarget==GL_TEXTURE_RECTANGLE_ARB, m_iFlags, m_format,
948 m_nonLinStretch && m_renderQuality == RQ_SINGLEPASS,
949 out);
950 if (!m_cmsOn)
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;
958 UpdateVideoFilter();
959 break;
961 else if (m_pYUVShader)
963 m_pYUVShader->Free();
964 delete m_pYUVShader;
965 m_pYUVShader = NULL;
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;
985 UpdateVideoFilter();
986 break;
988 else if (m_pYUVShader)
990 m_pYUVShader->Free();
991 delete m_pYUVShader;
992 m_pYUVShader = NULL;
994 CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB ARB shader");
995 m_renderMethod = -1;
996 break;
998 default:
1000 m_renderMethod = -1;
1001 CLog::Log(LOGERROR, "GL: Shaders support not present");
1002 break;
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;
1016 else
1017 CLog::Log(LOGNOTICE, "GL: NPOT textures are supported through GL_ARB_texture_rectangle extension");
1019 else
1020 CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
1023 if (m_pboSupported)
1025 CLog::Log(LOGNOTICE, "GL: Using GL_ARB_pixel_buffer_object");
1026 m_pboUsed = true;
1028 else
1029 m_pboUsed = false;
1032 void CLinuxRendererGL::UnInit()
1034 CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
1035 CSingleLock lock(g_graphicsContext);
1037 glFinish();
1039 if (m_rgbPbo)
1041 glDeleteBuffersARB(1, &m_rgbPbo);
1042 m_rgbPbo = 0;
1043 m_rgbBuffer = NULL;
1045 else
1047 av_free(m_rgbBuffer);
1048 m_rgbBuffer = NULL;
1050 m_rgbBufferSize = 0;
1052 if (m_context)
1054 sws_freeContext(m_context);
1055 m_context = NULL;
1058 // YV12 textures
1059 for (int i = 0; i < NUM_BUFFERS; ++i)
1061 DeleteTexture(i);
1064 DeleteCLUT();
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;
1082 else
1083 m_currentField = FIELD_FULL;
1085 // call texture load function
1086 if (!UploadTexture(renderBuffer))
1087 return;
1089 if (RenderHook(renderBuffer))
1091 else if (m_renderMethod & RENDER_GLSL)
1093 UpdateVideoFilter();
1094 switch(m_renderQuality)
1096 case RQ_LOW:
1097 case RQ_SINGLEPASS:
1098 RenderSinglePass(renderBuffer, m_currentField);
1099 VerifyGLState();
1100 break;
1102 case RQ_MULTIPASS:
1103 RenderToFBO(renderBuffer, m_currentField);
1104 RenderFromFBO();
1105 VerifyGLState();
1106 break;
1109 else if (m_renderMethod & RENDER_ARB)
1111 RenderSinglePass(renderBuffer, m_currentField);
1113 else
1115 RenderSoftware(renderBuffer, m_currentField);
1116 VerifyGLState();
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;
1130 LoadShaders(field);
1133 glDisable(GL_DEPTH_TEST);
1135 // Y
1136 glActiveTextureARB(GL_TEXTURE0);
1137 glEnable(m_textureTarget);
1138 glBindTexture(m_textureTarget, planes[0].id);
1140 // U
1141 glActiveTextureARB(GL_TEXTURE1);
1142 glEnable(m_textureTarget);
1143 glBindTexture(m_textureTarget, planes[1].id);
1145 // V
1146 glActiveTextureARB(GL_TEXTURE2);
1147 glEnable(m_textureTarget);
1148 glBindTexture(m_textureTarget, planes[2].id);
1150 glActiveTextureARB(GL_TEXTURE0);
1151 VerifyGLState();
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);
1162 else
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();
1172 glBegin(GL_QUADS);
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
1194 glEnd();
1195 VerifyGLState();
1197 m_pYUVShader->Disable();
1198 VerifyGLState();
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);
1211 VerifyGLState();
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");
1229 return;
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");
1235 return;
1239 glDisable(GL_DEPTH_TEST);
1241 // Y
1242 glEnable(m_textureTarget);
1243 glActiveTextureARB(GL_TEXTURE0);
1244 glBindTexture(m_textureTarget, planes[0].id);
1245 VerifyGLState();
1247 // U
1248 glActiveTextureARB(GL_TEXTURE1);
1249 glEnable(m_textureTarget);
1250 glBindTexture(m_textureTarget, planes[1].id);
1251 VerifyGLState();
1253 // V
1254 glActiveTextureARB(GL_TEXTURE2);
1255 glEnable(m_textureTarget);
1256 glBindTexture(m_textureTarget, planes[2].id);
1257 VerifyGLState();
1259 glActiveTextureARB(GL_TEXTURE0);
1260 VerifyGLState();
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");
1266 return;
1269 m_fbo.fbo.BeginRender();
1270 VerifyGLState();
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);
1282 VerifyGLState();
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;
1313 if (weave)
1314 m_fbo.height *= 2;
1316 // 1st Pass to video frame size
1317 glBegin(GL_QUADS);
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);
1339 glEnd();
1340 VerifyGLState();
1342 m_pYUVShader->Disable();
1344 glMatrixModview.PopLoad();
1345 glMatrixProject.PopLoad();
1347 glPopAttrib(); // pop scissor
1348 glPopAttrib(); // pop viewport
1349 VerifyGLState();
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);
1365 VerifyGLState();
1367 // Use regular normalized texture coordinates
1369 // 2nd Pass to screen size with optional video filter
1371 if (m_pVideoFilterShader)
1373 GLint filter;
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);
1386 else
1387 m_pVideoFilterShader->SetNonLinStretch(pow(CDisplaySettings::GetInstance().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1389 m_pVideoFilterShader->Enable();
1391 else
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);
1398 VerifyGLState();
1400 float imgwidth = m_fbo.width / m_sourceWidth;
1401 float imgheight = m_fbo.height / m_sourceHeight;
1403 glBegin(GL_QUADS);
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 );
1417 glEnd();
1419 VerifyGLState();
1421 if (m_pVideoFilterShader)
1422 m_pVideoFilterShader->Disable();
1424 VerifyGLState();
1426 glBindTexture(GL_TEXTURE_2D, 0);
1427 glDisable(GL_TEXTURE_2D);
1428 VerifyGLState();
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);
1444 RenderFromFBO();
1446 else
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)
1475 GLint filter;
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);
1489 else
1490 m_pVideoFilterShader->SetNonLinStretch(pow(CDisplaySettings::GetInstance().GetPixelRatio(), g_advancedSettings.m_videoNonLinStretchRatio));
1492 m_pVideoFilterShader->Enable();
1494 else
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);
1502 VerifyGLState();
1504 glBegin(GL_QUADS);
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);
1512 else
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);
1519 glEnd();
1520 VerifyGLState();
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);
1541 glBegin(GL_QUADS);
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);
1554 glEnd();
1556 VerifyGLState();
1558 glDisable(m_textureTarget);
1559 VerifyGLState();
1562 bool CLinuxRendererGL::RenderCapture(CRenderCapture* capture)
1564 if (!m_bValidated)
1565 return false;
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());
1574 MarkDirty();
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);
1589 // read pixels
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
1602 return true;
1606 static GLint GetInternalFormat(GLint format, int bpp)
1608 if(bpp == 2)
1610 switch (format)
1612 #ifdef GL_ALPHA16
1613 case GL_ALPHA: return GL_ALPHA16;
1614 #endif
1615 #ifdef GL_LUMINANCE16
1616 case GL_LUMINANCE: return GL_LUMINANCE16;
1617 #endif
1618 default: return format;
1621 else
1622 return format;
1625 //-----------------------------------------------------------------------------
1626 // Textures
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);
1636 else
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);
1647 else
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);
1658 else
1659 return UploadYV12Texture(index);
1661 return false;
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 */
1671 unsigned p;
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;
1681 im.cshift_x = 1;
1682 im.cshift_y = 1;
1685 if(m_format == RENDER_FMT_YUV420P16
1686 || m_format == RENDER_FMT_YUV420P10)
1687 im.bpp = 2;
1688 else
1689 im.bpp = 1;
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;
1700 if (m_pboUsed)
1702 pboSetup = true;
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);
1710 if (pboPtr)
1712 im.plane[i] = (BYTE*) pboPtr + PBO_OFFSET;
1713 memset(im.plane[i], 0, im.planesize[i]);
1715 else
1717 CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
1718 pboSetup = false;
1719 break;
1723 if (!pboSetup)
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);
1737 if (!pboSetup)
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);
1751 VerifyGLState();
1753 fields[f][p].pbo = pbo[p];
1757 // YUV
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)
1790 continue;
1792 glBindTexture(m_textureTarget, plane.id);
1793 GLenum format;
1794 GLint internalformat;
1795 if (p == 2) //V plane needs an alpha texture
1796 format = GL_ALPHA;
1797 else
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);
1806 VerifyGLState();
1809 glDisable(m_textureTarget);
1810 return true;
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))
1820 return false;
1821 bool deinterlacing;
1822 if (m_currentField == FIELD_FULL)
1823 deinterlacing = false;
1824 else
1825 deinterlacing = true;
1827 glEnable(m_textureTarget);
1828 VerifyGLState();
1830 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1832 if (deinterlacing)
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] );
1839 //load Odd Y Field
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] );
1862 else
1864 //Load Y plane
1865 LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
1866 , im->width, im->height
1867 , im->stride[0], im->bpp, im->plane[0] );
1869 //load U plane
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] );
1874 //load V plane
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] );
1880 VerifyGLState();
1882 CalculateTextureSourceRects(source, 3);
1884 glDisable(m_textureTarget);
1885 return true;
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++)
1912 if (pbo[p])
1914 if (im.plane[p])
1916 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[p]);
1917 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
1918 im.plane[p] = NULL;
1919 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
1921 glDeleteBuffersARB(1, pbo + p);
1922 pbo[p] = 0;
1924 else
1926 if (im.plane[p])
1928 delete[] im.plane[p];
1929 im.plane[p] = NULL;
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))
1945 return false;
1946 bool deinterlacing;
1947 if (m_currentField == FIELD_FULL)
1948 deinterlacing = false;
1949 else
1950 deinterlacing = true;
1952 glEnable(m_textureTarget);
1953 VerifyGLState();
1955 glPixelStorei(GL_UNPACK_ALIGNMENT, im->bpp);
1957 if (deinterlacing)
1959 // Load Odd Y field
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] );
1980 else
1982 // Load Y plane
1983 LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
1984 , im->width, im->height
1985 , im->stride[0], im->bpp, im->plane[0] );
1987 // Load UV plane
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] );
1993 VerifyGLState();
1995 CalculateTextureSourceRects(source, 3);
1997 glDisable(m_textureTarget);
1998 return true;
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;
2013 im.cshift_x = 1;
2014 im.cshift_y = 1;
2015 im.bpp = 1;
2017 im.stride[0] = im.width;
2018 im.stride[1] = im.width;
2019 im.stride[2] = 0;
2021 im.plane[0] = NULL;
2022 im.plane[1] = NULL;
2023 im.plane[2] = NULL;
2025 // Y plane
2026 im.planesize[0] = im.stride[0] * im.height;
2027 // packed UV plane
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;
2033 if (m_pboUsed)
2035 pboSetup = true;
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);
2043 if (pboPtr)
2045 im.plane[i] = (BYTE*)pboPtr + PBO_OFFSET;
2046 memset(im.plane[i], 0, im.planesize[i]);
2048 else
2050 CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
2051 pboSetup = false;
2052 break;
2056 if (!pboSetup)
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);
2070 if (!pboSetup)
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);
2084 VerifyGLState();
2086 fields[f][p].pbo = pbo[p];
2088 fields[f][2].id = fields[f][1].id;
2091 // YUV
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)
2124 continue;
2126 glBindTexture(m_textureTarget, plane.id);
2127 if (p == 1)
2128 glTexImage2D(m_textureTarget, 0, GL_LUMINANCE_ALPHA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
2129 else
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);
2136 VerifyGLState();
2139 glDisable(m_textureTarget);
2141 return true;
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++)
2170 if (pbo[p])
2172 if (im.plane[p])
2174 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[p]);
2175 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2176 im.plane[p] = NULL;
2177 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2179 glDeleteBuffersARB(1, pbo + p);
2180 pbo[p] = 0;
2182 else
2184 if (im.plane[p])
2186 delete[] im.plane[p];
2187 im.plane[p] = NULL;
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))
2200 return false;
2202 bool deinterlacing;
2203 if (m_currentField == FIELD_FULL)
2204 deinterlacing = false;
2205 else
2206 deinterlacing = true;
2208 glEnable(m_textureTarget);
2209 VerifyGLState();
2211 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
2213 if (deinterlacing)
2215 // Load YUYV fields
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]) ;
2224 else
2226 // Load YUYV plane
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] );
2232 VerifyGLState();
2234 CalculateTextureSourceRects(source, 3);
2236 glDisable(m_textureTarget);
2237 return true;
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;
2263 if (pbo[0])
2265 if (im.plane[0])
2267 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo[0]);
2268 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
2269 im.plane[0] = NULL;
2270 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2272 glDeleteBuffersARB(1, pbo);
2273 pbo[0] = 0;
2275 else
2277 if (im.plane[0])
2279 delete[] im.plane[0];
2280 im.plane[0] = NULL;
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;
2297 im.cshift_x = 0;
2298 im.cshift_y = 0;
2299 im.bpp = 1;
2301 im.stride[0] = im.width * 2;
2302 im.stride[1] = 0;
2303 im.stride[2] = 0;
2305 im.plane[0] = NULL;
2306 im.plane[1] = NULL;
2307 im.plane[2] = NULL;
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;
2317 if (m_pboUsed)
2319 pboSetup = true;
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);
2325 if (pboPtr)
2327 im.plane[0] = (BYTE*)pboPtr + PBO_OFFSET;
2328 memset(im.plane[0], 0, im.planesize[0]);
2330 else
2332 CLog::Log(LOGWARNING,"GL: failed to set up pixel buffer object");
2333 pboSetup = false;
2336 if (!pboSetup)
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);
2347 if (!pboSetup)
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);
2358 VerifyGLState();
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;
2365 // YUV
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)
2395 continue;
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);
2405 VerifyGLState();
2407 glDisable(m_textureTarget);
2409 return true;
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);
2427 VerifyGLState();
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)
2449 return false;
2451 if(feature == RENDERFEATURE_NOISE)
2452 return false;
2454 if(feature == RENDERFEATURE_SHARPNESS)
2456 return false;
2459 if (feature == RENDERFEATURE_NONLINSTRETCH)
2461 if ((m_renderMethod & RENDER_GLSL) && !(m_renderMethod & RENDER_POT))
2462 return true;
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)
2471 return true;
2473 return false;
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)
2487 return true;
2489 if(method == VS_SCALINGMETHOD_LINEAR
2490 || method == VS_SCALINGMETHOD_AUTO)
2491 return true;
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)
2505 return false;
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)
2512 return true;
2513 else
2514 return g_advancedSettings.m_videoEnableHighQualityHwScalers;
2518 return false;
2521 void CLinuxRendererGL::BindPbo(YUVBUFFER& buff)
2523 bool pbo = false;
2524 for(int plane = 0; plane < MAX_PLANES; plane++)
2526 if(!buff.pbo[plane] || buff.image.plane[plane] == (BYTE*)PBO_OFFSET)
2527 continue;
2528 pbo = true;
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;
2534 if(pbo)
2535 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2538 void CLinuxRendererGL::UnBindPbo(YUVBUFFER& buff)
2540 bool pbo = false;
2541 for(int plane = 0; plane < MAX_PLANES; plane++)
2543 if(!buff.pbo[plane] || buff.image.plane[plane] != (BYTE*)PBO_OFFSET)
2544 continue;
2545 pbo = true;
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;
2551 if(pbo)
2552 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2555 CRenderInfo CLinuxRendererGL::GetRenderInfo()
2557 CRenderInfo info;
2558 info.formats = m_formats;
2559 info.max_buffer_size = NUM_BUFFERS;
2560 info.optimal_buffer_size = 4;
2561 return info;
2564 // Color management helpers
2566 bool CLinuxRendererGL::LoadCLUT()
2568 DeleteCLUT();
2570 // load 3DLUT
2571 if ( !m_ColorManager->GetVideo3dLut(m_iFlags, &m_cmsToken, &m_CLUTsize, &m_CLUT) )
2573 CLog::Log(LOGERROR, "Error loading the LUT");
2574 return false;
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");
2584 return false;
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);
2597 // load 3DLUT data
2598 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16, m_CLUTsize, m_CLUTsize, m_CLUTsize, 0, GL_RGB, GL_UNSIGNED_SHORT, m_CLUT);
2599 free(m_CLUT);
2600 glActiveTexture(GL_TEXTURE0);
2601 return true;
2604 void CLinuxRendererGL::DeleteCLUT()
2606 if (m_tCLUTTex)
2608 CLog::Log(LOGDEBUG, "LinuxRendererGL: deleting 3DLUT");
2609 glDeleteTextures(1, &m_tCLUTTex);
2610 m_tCLUTTex = 0;
2614 #endif