2 * Copyright (C) 2010-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 //#define DEBUG_VERBOSE 1
24 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
29 #include "system_gl.h"
32 #include "guilib/MatrixGLES.h"
33 #include "LinuxRendererGLES.h"
34 #include "utils/fastmemcpy.h"
35 #include "utils/MathUtils.h"
36 #include "utils/GLUtils.h"
37 #include "settings/AdvancedSettings.h"
38 #include "settings/DisplaySettings.h"
39 #include "settings/MediaSettings.h"
40 #include "settings/Settings.h"
41 #include "guilib/FrameBufferObject.h"
42 #include "VideoShaders/YUV2RGBShader.h"
43 #include "VideoShaders/VideoFilterShader.h"
44 #include "windowing/WindowingFactory.h"
45 #include "dialogs/GUIDialogKaiToast.h"
46 #include "guilib/Texture.h"
47 #include "lib/DllSwScale.h"
48 #include "../dvdplayer/DVDCodecs/Video/OpenMaxVideo.h"
49 #include "threads/SingleLock.h"
50 #include "RenderCapture.h"
51 #include "RenderFormats.h"
52 #include "xbmc/Application.h"
53 #include "cores/IPlayer.h"
55 #if defined(__ARM_NEON__)
56 #include "yuv2rgb.neon.h"
57 #include "utils/CPUInfo.h"
59 #ifdef HAVE_VIDEOTOOLBOXDECODER
60 #include "DVDCodecs/Video/DVDVideoCodecVideoToolBox.h"
61 #include <CoreVideo/CoreVideo.h>
63 #ifdef TARGET_DARWIN_IOS
64 #include "osx/DarwinUtils.h"
66 #if defined(HAS_LIBSTAGEFRIGHT)
68 #include <EGL/eglext.h>
69 #include "windowing/egl/EGLWrapper.h"
70 #include "android/activity/XBMCApp.h"
71 #include "DVDCodecs/Video/DVDVideoCodecStageFright.h"
73 // EGL extension functions
74 static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
75 static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
76 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
79 #if defined(TARGET_ANDROID)
80 #include "DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h"
83 using namespace Shaders;
85 CLinuxRendererGLES::YUVBUFFER::YUVBUFFER()
87 memset(&fields, 0, sizeof(fields));
88 memset(&image , 0, sizeof(image));
90 #ifdef HAVE_LIBOPENMAX
93 #ifdef HAVE_VIDEOTOOLBOXDECODER
96 #ifdef HAS_LIBSTAGEFRIGHT
98 eglimg = EGL_NO_IMAGE_KHR;
100 #if defined(TARGET_ANDROID)
105 CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER()
109 CLinuxRendererGLES::CLinuxRendererGLES()
111 m_textureTarget = GL_TEXTURE_2D;
113 m_renderMethod = RENDER_GLSL;
114 m_oldRenderMethod = m_renderMethod;
115 m_renderQuality = RQ_SINGLEPASS;
117 m_format = RENDER_FMT_NONE;
119 m_iYV12RenderBuffer = 0;
121 m_currentField = FIELD_FULL;
124 m_pVideoFilterShader = NULL;
125 m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
126 m_scalingMethodGui = (ESCALINGMETHOD)-1;
128 // default texture handlers to YUV
129 m_textureUpload = &CLinuxRendererGLES::UploadYV12Texture;
130 m_textureCreate = &CLinuxRendererGLES::CreateYV12Texture;
131 m_textureDelete = &CLinuxRendererGLES::DeleteYV12Texture;
136 m_dllSwScale = new DllSwScale;
138 m_NumYV12Buffers = 0;
139 m_iLastRenderBuffer = 0;
140 m_bConfigured = false;
141 m_bValidated = false;
142 m_bImageReady = false;
143 m_StrictBinding = false;
144 m_clearColour = 0.0f;
146 #ifdef HAS_LIBSTAGEFRIGHT
147 if (!eglCreateImageKHR)
148 eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglCreateImageKHR");
149 if (!eglDestroyImageKHR)
150 eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglDestroyImageKHR");
151 if (!glEGLImageTargetTexture2DOES)
152 glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) CEGLWrapper::GetProcAddress("glEGLImageTargetTexture2DOES");
156 CLinuxRendererGLES::~CLinuxRendererGLES()
160 if (m_rgbBuffer != NULL) {
161 delete [] m_rgbBuffer;
167 m_pYUVShader->Free();
175 bool CLinuxRendererGLES::ValidateRenderTarget()
179 CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D");
181 // function pointer for texture might change in
182 // call to LoadShaders
184 for (int i = 0 ; i < NUM_BUFFERS ; i++)
185 (this->*m_textureDelete)(i);
187 // create the yuv textures
190 for (int i = 0 ; i < m_NumYV12Buffers ; i++)
191 (this->*m_textureCreate)(i);
199 bool CLinuxRendererGLES::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)
201 m_sourceWidth = width;
202 m_sourceHeight = height;
203 m_renderOrientation = orientation;
209 // Calculate the input frame aspect ratio.
210 CalculateFrameAspectRatio(d_width, d_height);
211 ChooseBestResolution(fps);
212 SetViewMode(CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode);
215 m_bConfigured = true;
216 m_bImageReady = false;
217 m_scalingMethodGui = (ESCALINGMETHOD)-1;
219 // Ensure that textures are recreated and rendering starts only after the 1st
220 // frame is loaded after every call to Configure().
221 m_bValidated = false;
223 for (int i = 0 ; i<m_NumYV12Buffers ; i++)
224 m_buffers[i].image.flags = 0;
226 m_iLastRenderBuffer = -1;
228 m_RenderUpdateCallBackFn = NULL;
229 m_RenderUpdateCallBackCtx = NULL;
230 if ((m_format == RENDER_FMT_BYPASS) && g_application.GetCurrentPlayer())
232 m_renderFeatures.clear();
233 m_scalingMethods.clear();
234 m_deinterlaceModes.clear();
235 m_deinterlaceMethods.clear();
237 if (m_RenderFeaturesCallBackFn)
239 (*m_RenderFeaturesCallBackFn)(m_RenderFeaturesCallBackCtx, m_renderFeatures);
240 // after setting up m_renderFeatures, we are done with the callback
241 m_RenderFeaturesCallBackFn = NULL;
242 m_RenderFeaturesCallBackCtx = NULL;
244 g_application.m_pPlayer->GetRenderFeatures(m_renderFeatures);
245 g_application.m_pPlayer->GetDeinterlaceMethods(m_deinterlaceMethods);
246 g_application.m_pPlayer->GetDeinterlaceModes(m_deinterlaceModes);
247 g_application.m_pPlayer->GetScalingMethods(m_scalingMethods);
253 int CLinuxRendererGLES::NextYV12Texture()
255 return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
258 int CLinuxRendererGLES::GetImage(YV12Image *image, int source, bool readonly)
260 if (!image) return -1;
261 if (!m_bValidated) return -1;
263 /* take next available buffer */
264 if( source == AUTOSOURCE )
265 source = NextYV12Texture();
267 if ( m_renderMethod & RENDER_OMXEGL )
271 #ifdef HAS_LIBSTAGEFRIGHT
272 if ( m_renderMethod & RENDER_EGLIMG )
278 if ( m_renderMethod & RENDER_MEDIACODEC )
283 #ifdef HAVE_VIDEOTOOLBOXDECODER
284 if (m_renderMethod & RENDER_CVREF )
290 YV12Image &im = m_buffers[source].image;
292 if ((im.flags&(~IMAGE_FLAG_READY)) != 0)
294 CLog::Log(LOGDEBUG, "CLinuxRenderer::GetImage - request image but none to give");
299 im.flags |= IMAGE_FLAG_READING;
301 im.flags |= IMAGE_FLAG_WRITING;
303 // copy the image - should be operator of YV12Image
304 for (int p=0;p<MAX_PLANES;p++)
306 image->plane[p] = im.plane[p];
307 image->stride[p] = im.stride[p];
309 image->width = im.width;
310 image->height = im.height;
311 image->flags = im.flags;
312 image->cshift_x = im.cshift_x;
313 image->cshift_y = im.cshift_y;
319 void CLinuxRendererGLES::ReleaseImage(int source, bool preserve)
321 YV12Image &im = m_buffers[source].image;
323 im.flags &= ~IMAGE_FLAG_INUSE;
324 im.flags |= IMAGE_FLAG_READY;
325 /* if image should be preserved reserve it so it's not auto seleceted */
328 im.flags |= IMAGE_FLAG_RESERVED;
330 m_bImageReady = true;
333 void CLinuxRendererGLES::CalculateTextureSourceRects(int source, int num_planes)
335 YUVBUFFER& buf = m_buffers[source];
336 YV12Image* im = &buf.image;
337 YUVFIELDS& fields = buf.fields;
339 // calculate the source rectangle
340 for(int field = 0; field < 3; field++)
342 for(int plane = 0; plane < num_planes; plane++)
344 YUVPLANE& p = fields[field][plane];
346 p.rect = m_sourceRect;
348 p.height = im->height;
350 if(field != FIELD_FULL)
352 /* correct for field offsets and chroma offsets */
353 float offset_y = 0.5;
356 if(field == FIELD_BOT)
359 p.rect.y1 += offset_y;
360 p.rect.y2 += offset_y;
362 /* half the height if this is a field */
370 p.width /= 1 << im->cshift_x;
371 p.height /= 1 << im->cshift_y;
373 p.rect.x1 /= 1 << im->cshift_x;
374 p.rect.x2 /= 1 << im->cshift_x;
375 p.rect.y1 /= 1 << im->cshift_y;
376 p.rect.y2 /= 1 << im->cshift_y;
379 if (m_textureTarget == GL_TEXTURE_2D)
381 p.height /= p.texheight;
382 p.rect.y1 /= p.texheight;
383 p.rect.y2 /= p.texheight;
384 p.width /= p.texwidth;
385 p.rect.x1 /= p.texwidth;
386 p.rect.x2 /= p.texwidth;
392 void CLinuxRendererGLES::LoadPlane( YUVPLANE& plane, int type, unsigned flipindex
393 , unsigned width, unsigned height
394 , unsigned int stride, void* data )
396 if(plane.flipindex == flipindex)
399 const GLvoid *pixelData = data;
401 int bps = glFormatElementByteCount(type);
403 glBindTexture(m_textureTarget, plane.id);
405 // OpenGL ES does not support strided texture input.
406 if(stride != width * bps)
408 unsigned char* src = (unsigned char*)data;
409 for (unsigned int y = 0; y < height;++y, src += stride)
410 glTexSubImage2D(m_textureTarget, 0, 0, y, width, 1, type, GL_UNSIGNED_BYTE, src);
412 glTexSubImage2D(m_textureTarget, 0, 0, 0, width, height, type, GL_UNSIGNED_BYTE, pixelData);
415 /* check if we need to load any border pixels */
416 if(height < plane.texheight)
417 glTexSubImage2D( m_textureTarget, 0
418 , 0, height, width, 1
419 , type, GL_UNSIGNED_BYTE
420 , (unsigned char*)pixelData + stride * (height-1));
422 if(width < plane.texwidth)
423 glTexSubImage2D( m_textureTarget, 0
424 , width, 0, 1, height
425 , type, GL_UNSIGNED_BYTE
426 , (unsigned char*)pixelData + bps * (width-1));
428 glBindTexture(m_textureTarget, 0);
430 plane.flipindex = flipindex;
433 void CLinuxRendererGLES::Reset()
435 for(int i=0; i<m_NumYV12Buffers; i++)
437 /* reset all image flags, this will cleanup textures later */
438 m_buffers[i].image.flags = 0;
442 void CLinuxRendererGLES::Flush()
449 for (int i = 0 ; i < m_NumYV12Buffers ; i++)
450 (this->*m_textureDelete)(i);
453 m_bValidated = false;
455 m_iYV12RenderBuffer = 0;
458 void CLinuxRendererGLES::Update()
460 if (!m_bConfigured) return;
464 void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
466 if (!m_bConfigured) return;
468 // if its first pass, just init textures and return
469 if (ValidateRenderTarget())
472 if (m_renderMethod & RENDER_BYPASS)
475 // if running bypass, then the player might need the src/dst rects
476 // for sizing video playback on a layer other than the gles layer.
477 if (m_RenderUpdateCallBackFn)
478 (*m_RenderUpdateCallBackFn)(m_RenderUpdateCallBackCtx, m_sourceRect, m_destRect);
480 CRect old = g_graphicsContext.GetScissors();
482 g_graphicsContext.BeginPaint();
483 g_graphicsContext.SetScissors(m_destRect);
486 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
487 glClearColor(0, 0, 0, 0);
488 glClear(GL_COLOR_BUFFER_BIT);
490 g_graphicsContext.SetScissors(old);
491 g_graphicsContext.EndPaint();
495 // this needs to be checked after texture validation
496 if (!m_bImageReady) return;
498 int index = m_iYV12RenderBuffer;
499 YUVBUFFER& buf = m_buffers[index];
501 if (m_format != RENDER_FMT_OMXEGL && m_format != RENDER_FMT_EGLIMG && m_format != RENDER_FMT_MEDIACODEC)
503 if (!buf.fields[FIELD_FULL][0].id) return;
505 if (buf.image.flags==0)
510 g_graphicsContext.BeginPaint();
512 m_iLastRenderBuffer = index;
516 glClearColor(m_clearColour, m_clearColour, m_clearColour, 0);
517 glClear(GL_COLOR_BUFFER_BIT);
518 glClearColor(0,0,0,0);
524 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
526 m_pYUVShader->SetAlpha(alpha / 255.0f);
532 m_pYUVShader->SetAlpha(1.0f);
535 if ((flags & RENDER_FLAG_TOP) && (flags & RENDER_FLAG_BOT))
536 CLog::Log(LOGERROR, "GLES: Cannot render stipple!");
538 Render(flags, index);
543 g_graphicsContext.EndPaint();
546 void CLinuxRendererGLES::FlipPage(int source)
548 if( source >= 0 && source < m_NumYV12Buffers )
549 m_iYV12RenderBuffer = source;
551 m_iYV12RenderBuffer = NextYV12Texture();
553 m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
558 unsigned int CLinuxRendererGLES::PreInit()
560 CSingleLock lock(g_graphicsContext);
561 m_bConfigured = false;
562 m_bValidated = false;
564 m_resolution = CDisplaySettings::Get().GetCurrentResolution();
565 if ( m_resolution == RES_WINDOW )
566 m_resolution = RES_DESKTOP;
568 m_iYV12RenderBuffer = 0;
569 m_NumYV12Buffers = 2;
571 m_formats.push_back(RENDER_FMT_YUV420P);
572 m_formats.push_back(RENDER_FMT_NV12);
573 m_formats.push_back(RENDER_FMT_BYPASS);
574 #if defined(HAVE_LIBOPENMAX)
575 m_formats.push_back(RENDER_FMT_OMXEGL);
577 #ifdef HAVE_VIDEOTOOLBOXDECODER
578 m_formats.push_back(RENDER_FMT_CVBREF);
580 #ifdef HAS_LIBSTAGEFRIGHT
581 m_formats.push_back(RENDER_FMT_EGLIMG);
583 #if defined(TARGET_ANDROID)
584 m_formats.push_back(RENDER_FMT_MEDIACODEC);
587 // setup the background colour
588 m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
590 if (!m_dllSwScale->Load())
591 CLog::Log(LOGERROR,"CLinuxRendererGL::PreInit - failed to load rescale libraries!");
596 void CLinuxRendererGLES::UpdateVideoFilter()
598 if (m_scalingMethodGui == CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod)
600 m_scalingMethodGui = CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod;
601 m_scalingMethod = m_scalingMethodGui;
603 if(!Supports(m_scalingMethod))
605 CLog::Log(LOGWARNING, "CLinuxRendererGLES::UpdateVideoFilter - choosen scaling method %d, is not supported by renderer", (int)m_scalingMethod);
606 m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
609 if (m_pVideoFilterShader)
611 m_pVideoFilterShader->Free();
612 delete m_pVideoFilterShader;
613 m_pVideoFilterShader = NULL;
619 switch (m_scalingMethod)
621 case VS_SCALINGMETHOD_NEAREST:
622 SetTextureFilter(GL_NEAREST);
623 m_renderQuality = RQ_SINGLEPASS;
626 case VS_SCALINGMETHOD_LINEAR:
627 SetTextureFilter(GL_LINEAR);
628 m_renderQuality = RQ_SINGLEPASS;
631 case VS_SCALINGMETHOD_CUBIC:
632 CLog::Log(LOGERROR, "GLES: CUBIC not supported!");
635 case VS_SCALINGMETHOD_LANCZOS2:
636 case VS_SCALINGMETHOD_LANCZOS3:
637 case VS_SCALINGMETHOD_SINC8:
638 case VS_SCALINGMETHOD_NEDI:
639 CLog::Log(LOGERROR, "GL: TODO: This scaler has not yet been implemented");
646 CGUIDialogKaiToast::QueueNotification("Video Renderering", "Failed to init video filters/scalers, falling back to bilinear scaling");
647 CLog::Log(LOGERROR, "GL: Falling back to bilinear due to failure to init scaler");
648 if (m_pVideoFilterShader)
650 m_pVideoFilterShader->Free();
651 delete m_pVideoFilterShader;
652 m_pVideoFilterShader = NULL;
656 SetTextureFilter(GL_LINEAR);
657 m_renderQuality = RQ_SINGLEPASS;
660 void CLinuxRendererGLES::LoadShaders(int field)
662 #ifdef TARGET_DARWIN_IOS
663 float ios_version = GetIOSVersion();
665 int requestedMethod = CSettings::Get().GetInt("videoplayer.rendermethod");
666 CLog::Log(LOGDEBUG, "GL: Requested render method: %d", requestedMethod);
670 m_pYUVShader->Free();
675 switch(requestedMethod)
677 case RENDER_METHOD_AUTO:
678 case RENDER_METHOD_GLSL:
679 if (m_format == RENDER_FMT_OMXEGL)
681 CLog::Log(LOGNOTICE, "GL: Using OMXEGL RGBA render method");
682 m_renderMethod = RENDER_OMXEGL;
685 else if (m_format == RENDER_FMT_EGLIMG)
687 CLog::Log(LOGNOTICE, "GL: Using EGL Image render method");
688 m_renderMethod = RENDER_EGLIMG;
691 else if (m_format == RENDER_FMT_MEDIACODEC)
693 CLog::Log(LOGNOTICE, "GL: Using MediaCodec render method");
694 m_renderMethod = RENDER_MEDIACODEC;
697 else if (m_format == RENDER_FMT_BYPASS)
699 CLog::Log(LOGNOTICE, "GL: Using BYPASS render method");
700 m_renderMethod = RENDER_BYPASS;
703 else if (m_format == RENDER_FMT_CVBREF)
705 CLog::Log(LOGNOTICE, "GL: Using CoreVideoRef RGBA render method");
706 m_renderMethod = RENDER_CVREF;
709 #if defined(TARGET_DARWIN_IOS)
710 else if (ios_version < 5.0 && m_format == RENDER_FMT_YUV420P)
712 CLog::Log(LOGNOTICE, "GL: Using software color conversion/RGBA render method");
713 m_renderMethod = RENDER_SW;
717 // Try GLSL shaders if supported and user requested auto or GLSL.
720 // create regular progressive scan shader
721 m_pYUVShader = new YUV2RGBProgressiveShader(false, m_iFlags, m_format);
722 CLog::Log(LOGNOTICE, "GL: Selecting Single Pass YUV 2 RGB shader");
724 if (m_pYUVShader && m_pYUVShader->CompileAndLink())
726 m_renderMethod = RENDER_GLSL;
730 else if (m_pYUVShader)
732 m_pYUVShader->Free();
735 CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB GLSL shader");
736 // drop through and try SW
739 case RENDER_METHOD_SOFTWARE:
742 // Use software YUV 2 RGB conversion if user requested it or GLSL failed
743 m_renderMethod = RENDER_SW ;
744 CLog::Log(LOGNOTICE, "GL: Using software color conversion/RGBA rendering");
748 // determine whether GPU supports NPOT textures
749 if (!g_Windowing.IsExtSupported("GL_TEXTURE_NPOT"))
751 CLog::Log(LOGNOTICE, "GL: GL_ARB_texture_rectangle not supported and OpenGL version is not 2.x");
752 CLog::Log(LOGNOTICE, "GL: Reverting to POT textures");
753 m_renderMethod |= RENDER_POT;
756 CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
758 // Now that we now the render method, setup texture function handlers
759 if (m_format == RENDER_FMT_CVBREF)
761 m_textureUpload = &CLinuxRendererGLES::UploadCVRefTexture;
762 m_textureCreate = &CLinuxRendererGLES::CreateCVRefTexture;
763 m_textureDelete = &CLinuxRendererGLES::DeleteCVRefTexture;
765 else if (m_format == RENDER_FMT_BYPASS)
767 m_textureUpload = &CLinuxRendererGLES::UploadBYPASSTexture;
768 m_textureCreate = &CLinuxRendererGLES::CreateBYPASSTexture;
769 m_textureDelete = &CLinuxRendererGLES::DeleteBYPASSTexture;
771 else if (m_format == RENDER_FMT_EGLIMG)
773 m_textureUpload = &CLinuxRendererGLES::UploadEGLIMGTexture;
774 m_textureCreate = &CLinuxRendererGLES::CreateEGLIMGTexture;
775 m_textureDelete = &CLinuxRendererGLES::DeleteEGLIMGTexture;
777 else if (m_format == RENDER_FMT_MEDIACODEC)
779 m_textureUpload = &CLinuxRendererGLES::UploadSurfaceTexture;
780 m_textureCreate = &CLinuxRendererGLES::CreateSurfaceTexture;
781 m_textureDelete = &CLinuxRendererGLES::DeleteSurfaceTexture;
783 else if (m_format == RENDER_FMT_NV12)
785 m_textureUpload = &CLinuxRendererGLES::UploadNV12Texture;
786 m_textureCreate = &CLinuxRendererGLES::CreateNV12Texture;
787 m_textureDelete = &CLinuxRendererGLES::DeleteNV12Texture;
791 // default to YV12 texture handlers
792 m_textureUpload = &CLinuxRendererGLES::UploadYV12Texture;
793 m_textureCreate = &CLinuxRendererGLES::CreateYV12Texture;
794 m_textureDelete = &CLinuxRendererGLES::DeleteYV12Texture;
797 if (m_oldRenderMethod != m_renderMethod)
799 CLog::Log(LOGDEBUG, "CLinuxRendererGLES: Reorder drawpoints due to method change from %i to %i", m_oldRenderMethod, m_renderMethod);
801 m_oldRenderMethod = m_renderMethod;
805 void CLinuxRendererGLES::UnInit()
807 CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
808 CSingleLock lock(g_graphicsContext);
810 if (m_rgbBuffer != NULL)
812 delete [] m_rgbBuffer;
818 for (int i = 0; i < NUM_BUFFERS; ++i)
819 (this->*m_textureDelete)(i);
821 if (m_dllSwScale && m_sw_context)
823 m_dllSwScale->sws_freeContext(m_sw_context);
827 // cleanup framebuffer object if it was in use
829 m_bValidated = false;
830 m_bImageReady = false;
831 m_bConfigured = false;
832 m_RenderUpdateCallBackFn = NULL;
833 m_RenderUpdateCallBackCtx = NULL;
834 m_RenderFeaturesCallBackFn = NULL;
835 m_RenderFeaturesCallBackCtx = NULL;
838 inline void CLinuxRendererGLES::ReorderDrawPoints()
841 CBaseRenderer::ReorderDrawPoints();//call base impl. for rotating the points
843 //corevideo and EGL are flipped in y
844 if(m_renderMethod & RENDER_CVREF)
847 tmp = m_rotatedDestCoords[0];
848 m_rotatedDestCoords[0] = m_rotatedDestCoords[3];
849 m_rotatedDestCoords[3] = tmp;
850 tmp = m_rotatedDestCoords[1];
851 m_rotatedDestCoords[1] = m_rotatedDestCoords[2];
852 m_rotatedDestCoords[2] = tmp;
856 void CLinuxRendererGLES::ReleaseBuffer(int idx)
858 #ifdef HAVE_VIDEOTOOLBOXDECODER
859 YUVBUFFER &buf = m_buffers[idx];
862 CVBufferRelease(buf.cvBufferRef);
863 buf.cvBufferRef = NULL;
865 #if defined(TARGET_ANDROID)
866 YUVBUFFER &buf = m_buffers[idx];
868 SAFE_RELEASE(buf.mediacodec);
872 void CLinuxRendererGLES::Render(DWORD flags, int index)
874 // If rendered directly by the hardware
875 if (m_renderMethod & RENDER_BYPASS)
878 // obtain current field, if interlaced
879 if( flags & RENDER_FLAG_TOP)
880 m_currentField = FIELD_TOP;
882 else if (flags & RENDER_FLAG_BOT)
883 m_currentField = FIELD_BOT;
886 m_currentField = FIELD_FULL;
888 (this->*m_textureUpload)(index);
890 if (m_renderMethod & RENDER_GLSL)
893 switch(m_renderQuality)
897 RenderSinglePass(index, m_currentField);
902 RenderMultiPass(index, m_currentField);
907 RenderSoftware(index, m_currentField);
912 else if (m_renderMethod & RENDER_OMXEGL)
914 RenderOpenMax(index, m_currentField);
917 else if (m_renderMethod & RENDER_EGLIMG)
919 RenderEglImage(index, m_currentField);
922 else if (m_renderMethod & RENDER_CVREF)
924 RenderCoreVideoRef(index, m_currentField);
927 else if (m_renderMethod & RENDER_MEDIACODEC)
929 RenderSurfaceTexture(index, m_currentField);
933 RenderSoftware(index, m_currentField);
938 void CLinuxRendererGLES::RenderSinglePass(int index, int field)
940 YV12Image &im = m_buffers[index].image;
941 YUVFIELDS &fields = m_buffers[index].fields;
942 YUVPLANES &planes = fields[field];
950 glDisable(GL_DEPTH_TEST);
953 glActiveTexture(GL_TEXTURE0);
954 glEnable(m_textureTarget);
955 glBindTexture(m_textureTarget, planes[0].id);
958 glActiveTexture(GL_TEXTURE1);
959 glEnable(m_textureTarget);
960 glBindTexture(m_textureTarget, planes[1].id);
963 glActiveTexture(GL_TEXTURE2);
964 glEnable(m_textureTarget);
965 glBindTexture(m_textureTarget, planes[2].id);
967 glActiveTexture(GL_TEXTURE0);
970 m_pYUVShader->SetBlack(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * 0.01f - 0.5f);
971 m_pYUVShader->SetContrast(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast * 0.02f);
972 m_pYUVShader->SetWidth(im.width);
973 m_pYUVShader->SetHeight(im.height);
974 if (field == FIELD_TOP)
975 m_pYUVShader->SetField(1);
976 else if(field == FIELD_BOT)
977 m_pYUVShader->SetField(0);
979 m_pYUVShader->SetMatrices(g_matrices.GetMatrix(MM_PROJECTION), g_matrices.GetMatrix(MM_MODELVIEW));
980 m_pYUVShader->Enable();
982 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
983 GLfloat m_vert[4][3];
984 GLfloat m_tex[3][4][2];
986 GLint vertLoc = m_pYUVShader->GetVertexLoc();
987 GLint Yloc = m_pYUVShader->GetYcoordLoc();
988 GLint Uloc = m_pYUVShader->GetUcoordLoc();
989 GLint Vloc = m_pYUVShader->GetVcoordLoc();
991 glVertexAttribPointer(vertLoc, 3, GL_FLOAT, 0, 0, m_vert);
992 glVertexAttribPointer(Yloc, 2, GL_FLOAT, 0, 0, m_tex[0]);
993 glVertexAttribPointer(Uloc, 2, GL_FLOAT, 0, 0, m_tex[1]);
994 glVertexAttribPointer(Vloc, 2, GL_FLOAT, 0, 0, m_tex[2]);
996 glEnableVertexAttribArray(vertLoc);
997 glEnableVertexAttribArray(Yloc);
998 glEnableVertexAttribArray(Uloc);
999 glEnableVertexAttribArray(Vloc);
1001 // Setup vertex position values
1002 for(int i = 0; i < 4; i++)
1004 m_vert[i][0] = m_rotatedDestCoords[i].x;
1005 m_vert[i][1] = m_rotatedDestCoords[i].y;
1006 m_vert[i][2] = 0.0f;// set z to 0
1009 // Setup texture coordinates
1010 for (int i=0; i<3; i++)
1012 m_tex[i][0][0] = m_tex[i][3][0] = planes[i].rect.x1;
1013 m_tex[i][0][1] = m_tex[i][1][1] = planes[i].rect.y1;
1014 m_tex[i][1][0] = m_tex[i][2][0] = planes[i].rect.x2;
1015 m_tex[i][2][1] = m_tex[i][3][1] = planes[i].rect.y2;
1018 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1022 m_pYUVShader->Disable();
1025 glDisableVertexAttribArray(vertLoc);
1026 glDisableVertexAttribArray(Yloc);
1027 glDisableVertexAttribArray(Uloc);
1028 glDisableVertexAttribArray(Vloc);
1030 glActiveTexture(GL_TEXTURE1);
1031 glDisable(m_textureTarget);
1033 glActiveTexture(GL_TEXTURE2);
1034 glDisable(m_textureTarget);
1036 glActiveTexture(GL_TEXTURE0);
1037 glDisable(m_textureTarget);
1039 g_matrices.MatrixMode(MM_MODELVIEW);
1044 void CLinuxRendererGLES::RenderMultiPass(int index, int field)
1046 // TODO: Multipass rendering does not currently work! FIX!
1047 CLog::Log(LOGERROR, "GLES: MULTIPASS rendering was called! But it doesnt work!!!");
1050 YV12Image &im = m_buffers[index].image;
1051 YUVPLANES &planes = m_buffers[index].fields[field];
1053 if (m_reloadShaders)
1055 m_reloadShaders = 0;
1056 LoadShaders(m_currentField);
1059 glDisable(GL_DEPTH_TEST);
1062 glEnable(m_textureTarget);
1063 glActiveTexture(GL_TEXTURE0);
1064 glBindTexture(m_textureTarget, planes[0].id);
1068 glActiveTexture(GL_TEXTURE1);
1069 glEnable(m_textureTarget);
1070 glBindTexture(m_textureTarget, planes[1].id);
1074 glActiveTexture(GL_TEXTURE2);
1075 glEnable(m_textureTarget);
1076 glBindTexture(m_textureTarget, planes[2].id);
1079 glActiveTexture(GL_TEXTURE0);
1082 // make sure the yuv shader is loaded and ready to go
1083 if (!m_pYUVShader || (!m_pYUVShader->OK()))
1085 CLog::Log(LOGERROR, "GL: YUV shader not active, cannot do multipass render");
1089 m_fbo.BeginRender();
1092 m_pYUVShader->SetBlack(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * 0.01f - 0.5f);
1093 m_pYUVShader->SetContrast(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast * 0.02f);
1094 m_pYUVShader->SetWidth(im.width);
1095 m_pYUVShader->SetHeight(im.height);
1096 if (field == FIELD_TOP)
1097 m_pYUVShader->SetField(1);
1098 else if(field == FIELD_BOT)
1099 m_pYUVShader->SetField(0);
1103 // glPushAttrib(GL_VIEWPORT_BIT);
1104 // glPushAttrib(GL_SCISSOR_BIT);
1105 g_matrices.MatrixMode(MM_MODELVIEW);
1106 g_matrices.PushMatrix();
1107 g_matrices.LoadIdentity();
1110 g_matrices.MatrixMode(MM_PROJECTION);
1111 g_matrices.PushMatrix();
1112 g_matrices.LoadIdentity();
1114 g_matrices.Ortho2D(0, m_sourceWidth, 0, m_sourceHeight);
1115 glViewport(0, 0, m_sourceWidth, m_sourceHeight);
1116 glScissor(0, 0, m_sourceWidth, m_sourceHeight);
1117 g_matrices.MatrixMode(MM_MODELVIEW);
1121 if (!m_pYUVShader->Enable())
1123 CLog::Log(LOGERROR, "GL: Error enabling YUV shader");
1126 // 1st Pass to video frame size
1128 // float imgwidth = planes[0].rect.x2 - planes[0].rect.x1;
1129 // float imgheight = planes[0].rect.y2 - planes[0].rect.y1;
1130 // if (m_textureTarget == GL_TEXTURE_2D)
1132 // imgwidth *= planes[0].texwidth;
1133 // imgheight *= planes[0].texheight;
1136 // glBegin(GL_QUADS);
1138 // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
1139 // glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y1);
1140 // glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y1);
1141 // glVertex2f(0.0f , 0.0f);
1143 // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y1);
1144 // glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y1);
1145 // glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y1);
1146 // glVertex2f(imgwidth, 0.0f);
1148 // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y2);
1149 // glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y2);
1150 // glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y2);
1151 // glVertex2f(imgwidth, imgheight);
1153 // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y2);
1154 // glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y2);
1155 // glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y2);
1156 // glVertex2f(0.0f , imgheight);
1161 m_pYUVShader->Disable();
1163 g_matrices.MatrixMode(MM_MODELVIEW);
1164 g_matrices.PopMatrix(); // pop modelview
1165 g_matrices.MatrixMode(MM_PROJECTION);
1166 g_matrices.PopMatrix(); // pop projection
1168 // glPopAttrib(); // pop scissor
1169 // glPopAttrib(); // pop viewport
1170 g_matrices.MatrixMode(MM_MODELVIEW);
1175 glActiveTexture(GL_TEXTURE1);
1176 glDisable(m_textureTarget);
1177 glActiveTexture(GL_TEXTURE2);
1178 glDisable(m_textureTarget);
1179 glActiveTexture(GL_TEXTURE0);
1180 glDisable(m_textureTarget);
1182 glEnable(GL_TEXTURE_2D);
1183 glBindTexture(GL_TEXTURE_2D, m_fbo.Texture());
1186 // Use regular normalized texture coordinates
1188 // 2nd Pass to screen size with optional video filter
1190 if (m_pVideoFilterShader)
1192 m_fbo.SetFiltering(GL_TEXTURE_2D, GL_NEAREST);
1193 m_pVideoFilterShader->SetSourceTexture(0);
1194 m_pVideoFilterShader->SetWidth(m_sourceWidth);
1195 m_pVideoFilterShader->SetHeight(m_sourceHeight);
1196 m_pVideoFilterShader->Enable();
1199 m_fbo.SetFiltering(GL_TEXTURE_2D, GL_LINEAR);
1204 // imgwidth /= m_sourceWidth;
1205 // imgheight /= m_sourceHeight;
1207 // glBegin(GL_QUADS);
1209 // glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f , 0.0f);
1210 // glVertex4f(m_destRect.x1, m_destRect.y1, 0, 1.0f );
1212 // glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, 0.0f);
1213 // glVertex4f(m_destRect.x2, m_destRect.y1, 0, 1.0f);
1215 // glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, imgheight);
1216 // glVertex4f(m_destRect.x2, m_destRect.y2, 0, 1.0f);
1218 // glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f , imgheight);
1219 // glVertex4f(m_destRect.x1, m_destRect.y2, 0, 1.0f);
1225 if (m_pVideoFilterShader)
1226 m_pVideoFilterShader->Disable();
1230 glDisable(m_textureTarget);
1234 void CLinuxRendererGLES::RenderSoftware(int index, int field)
1236 YUVPLANES &planes = m_buffers[index].fields[field];
1238 glDisable(GL_DEPTH_TEST);
1241 glEnable(m_textureTarget);
1242 glActiveTexture(GL_TEXTURE0);
1243 glBindTexture(m_textureTarget, planes[0].id);
1245 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1247 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1250 GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1252 GLint posLoc = g_Windowing.GUIShaderGetPos();
1253 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1254 GLint colLoc = g_Windowing.GUIShaderGetCol();
1256 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1257 glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1258 glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1260 glEnableVertexAttribArray(posLoc);
1261 glEnableVertexAttribArray(texLoc);
1262 glEnableVertexAttribArray(colLoc);
1264 // Set vertex coordinates
1265 for(int i = 0; i < 4; i++)
1267 ver[i][0] = m_rotatedDestCoords[i].x;
1268 ver[i][1] = m_rotatedDestCoords[i].y;
1269 ver[i][2] = 0.0f;// set z to 0
1273 // Set texture coordinates
1274 tex[0][0] = tex[3][0] = planes[0].rect.x1;
1275 tex[0][1] = tex[1][1] = planes[0].rect.y1;
1276 tex[1][0] = tex[2][0] = planes[0].rect.x2;
1277 tex[2][1] = tex[3][1] = planes[0].rect.y2;
1279 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1281 glDisableVertexAttribArray(posLoc);
1282 glDisableVertexAttribArray(texLoc);
1283 glDisableVertexAttribArray(colLoc);
1285 g_Windowing.DisableGUIShader();
1289 glDisable(m_textureTarget);
1293 void CLinuxRendererGLES::RenderOpenMax(int index, int field)
1295 #if defined(HAVE_LIBOPENMAX)
1296 GLuint textureId = m_buffers[index].openMaxBuffer->texture_id;
1298 glDisable(GL_DEPTH_TEST);
1301 glEnable(m_textureTarget);
1302 glActiveTexture(GL_TEXTURE0);
1303 glBindTexture(m_textureTarget, textureId);
1305 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1307 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1310 GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1312 GLint posLoc = g_Windowing.GUIShaderGetPos();
1313 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1314 GLint colLoc = g_Windowing.GUIShaderGetCol();
1316 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1317 glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1318 glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1320 glEnableVertexAttribArray(posLoc);
1321 glEnableVertexAttribArray(texLoc);
1322 glEnableVertexAttribArray(colLoc);
1324 // Set vertex coordinates
1325 for(int i = 0; i < 4; i++)
1327 ver[i][0] = m_rotatedDestCoords[i].x;
1328 ver[i][1] = m_rotatedDestCoords[i].y;
1329 ver[i][2] = 0.0f;// set z to 0
1333 // Set texture coordinates
1334 tex[0][0] = tex[3][0] = 0;
1335 tex[0][1] = tex[1][1] = 0;
1336 tex[1][0] = tex[2][0] = 1;
1337 tex[2][1] = tex[3][1] = 1;
1339 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1341 glDisableVertexAttribArray(posLoc);
1342 glDisableVertexAttribArray(texLoc);
1343 glDisableVertexAttribArray(colLoc);
1345 g_Windowing.DisableGUIShader();
1349 glDisable(m_textureTarget);
1354 void CLinuxRendererGLES::RenderEglImage(int index, int field)
1356 #if defined(HAS_LIBSTAGEFRIGHT)
1357 #ifdef DEBUG_VERBOSE
1358 unsigned int time = XbmcThreads::SystemClockMillis();
1361 YUVPLANE &plane = m_buffers[index].fields[field][0];
1363 glDisable(GL_DEPTH_TEST);
1365 glActiveTexture(GL_TEXTURE0);
1366 glBindTexture(m_textureTarget, plane.id);
1368 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1370 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1373 GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1375 GLint posLoc = g_Windowing.GUIShaderGetPos();
1376 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1377 GLint colLoc = g_Windowing.GUIShaderGetCol();
1379 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1380 glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1381 glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1383 glEnableVertexAttribArray(posLoc);
1384 glEnableVertexAttribArray(texLoc);
1385 glEnableVertexAttribArray(colLoc);
1387 // Set vertex coordinates
1388 for(int i = 0; i < 4; i++)
1390 ver[i][0] = m_rotatedDestCoords[i].x;
1391 ver[i][1] = m_rotatedDestCoords[i].y;
1392 ver[i][2] = 0.0f;// set z to 0
1396 // Set texture coordinates (is flipped in y)
1397 tex[0][0] = tex[3][0] = 0;
1398 tex[0][1] = tex[1][1] = 1;
1399 tex[1][0] = tex[2][0] = 1;
1400 tex[2][1] = tex[3][1] = 0;
1402 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1404 glDisableVertexAttribArray(posLoc);
1405 glDisableVertexAttribArray(texLoc);
1406 glDisableVertexAttribArray(colLoc);
1408 g_Windowing.DisableGUIShader();
1411 glBindTexture(m_textureTarget, 0);
1414 #ifdef DEBUG_VERBOSE
1415 CLog::Log(LOGDEBUG, "RenderEglImage %d: tm:%d\n", index, XbmcThreads::SystemClockMillis() - time);
1420 void CLinuxRendererGLES::RenderSurfaceTexture(int index, int field)
1422 #if defined(TARGET_ANDROID)
1423 #ifdef DEBUG_VERBOSE
1424 unsigned int time = XbmcThreads::SystemClockMillis();
1427 YUVPLANE &plane = m_buffers[index].fields[0][0];
1429 glDisable(GL_DEPTH_TEST);
1431 glActiveTexture(GL_TEXTURE0);
1432 glBindTexture(GL_TEXTURE_EXTERNAL_OES, plane.id);
1434 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA_OES);
1436 glUniformMatrix4fv(g_Windowing.GUIShaderGetCoord0Matrix(), 1, GL_FALSE, m_textureMatrix);
1438 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1442 GLint posLoc = g_Windowing.GUIShaderGetPos();
1443 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1446 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1447 glVertexAttribPointer(texLoc, 4, GL_FLOAT, 0, 0, tex);
1449 glEnableVertexAttribArray(posLoc);
1450 glEnableVertexAttribArray(texLoc);
1452 // Set vertex coordinates
1453 for(int i = 0; i < 4; i++)
1455 ver[i][0] = m_rotatedDestCoords[i].x;
1456 ver[i][1] = m_rotatedDestCoords[i].y;
1457 ver[i][2] = 0.0f; // set z to 0
1461 // Set texture coordinates (MediaCodec is flipped in y)
1462 tex[0][0] = tex[3][0] = 0.0f;
1463 tex[0][1] = tex[1][1] = 1.0f;
1464 tex[1][0] = tex[2][0] = 1.0f;
1465 tex[2][1] = tex[3][1] = 0.0f;
1467 for(int i = 0; i < 4; i++)
1473 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1475 glDisableVertexAttribArray(posLoc);
1476 glDisableVertexAttribArray(texLoc);
1478 const float identity[16] = {
1479 1.0f, 0.0f, 0.0f, 0.0f,
1480 0.0f, 1.0f, 0.0f, 0.0f,
1481 0.0f, 0.0f, 1.0f, 0.0f,
1482 0.0f, 0.0f, 0.0f, 1.0f
1484 glUniformMatrix4fv(g_Windowing.GUIShaderGetCoord0Matrix(), 1, GL_FALSE, identity);
1486 g_Windowing.DisableGUIShader();
1489 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
1492 #ifdef DEBUG_VERBOSE
1493 CLog::Log(LOGDEBUG, "RenderMediaCodecImage %d: tm:%d", index, XbmcThreads::SystemClockMillis() - time);
1498 void CLinuxRendererGLES::RenderCoreVideoRef(int index, int field)
1500 #ifdef HAVE_VIDEOTOOLBOXDECODER
1501 YUVPLANE &plane = m_buffers[index].fields[field][0];
1503 glDisable(GL_DEPTH_TEST);
1505 glEnable(m_textureTarget);
1506 glActiveTexture(GL_TEXTURE0);
1507 glBindTexture(m_textureTarget, plane.id);
1509 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1511 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1514 GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1516 GLint posLoc = g_Windowing.GUIShaderGetPos();
1517 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1518 GLint colLoc = g_Windowing.GUIShaderGetCol();
1520 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1521 glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1522 glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1524 glEnableVertexAttribArray(posLoc);
1525 glEnableVertexAttribArray(texLoc);
1526 glEnableVertexAttribArray(colLoc);
1528 // Set vertex coordinates
1529 for(int i = 0; i < 4; i++)
1531 ver[i][0] = m_rotatedDestCoords[i].x;
1532 ver[i][1] = m_rotatedDestCoords[i].y;
1533 ver[i][2] = 0.0f;// set z to 0
1537 // Set texture coordinates (corevideo is flipped in y)
1538 tex[0][0] = tex[3][0] = 0;
1539 tex[0][1] = tex[1][1] = 1;
1540 tex[1][0] = tex[2][0] = 1;
1541 tex[2][1] = tex[3][1] = 0;
1543 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1545 glDisableVertexAttribArray(posLoc);
1546 glDisableVertexAttribArray(texLoc);
1547 glDisableVertexAttribArray(colLoc);
1549 g_Windowing.DisableGUIShader();
1552 glDisable(m_textureTarget);
1557 bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture)
1562 // If rendered directly by the hardware
1563 if (m_renderMethod & RENDER_BYPASS)
1565 capture->BeginRender();
1566 capture->EndRender();
1570 // save current video rect
1571 CRect saveSize = m_destRect;
1572 saveRotatedCoords();//backup current m_rotatedDestCoords
1574 // new video rect is thumbnail size
1575 m_destRect.SetRect(0, 0, (float)capture->GetWidth(), (float)capture->GetHeight());
1577 syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords
1578 // clear framebuffer and invert Y axis to get non-inverted image
1579 glDisable(GL_BLEND);
1581 g_matrices.MatrixMode(MM_MODELVIEW);
1582 g_matrices.PushMatrix();
1583 // fixme - we know that cvref & eglimg are already flipped in y direction
1584 // but somehow this also effects the rendercapture here
1585 // therefore we have to skip the flip here or we get upside down
1587 if (m_renderMethod != RENDER_CVREF)
1589 g_matrices.Translatef(0.0f, capture->GetHeight(), 0.0f);
1590 g_matrices.Scalef(1.0f, -1.0f, 1.0f);
1593 capture->BeginRender();
1595 Render(RENDER_FLAG_NOOSD, m_iYV12RenderBuffer);
1597 glReadPixels(0, g_graphicsContext.GetHeight() - capture->GetHeight(), capture->GetWidth(), capture->GetHeight(),
1598 GL_RGBA, GL_UNSIGNED_BYTE, capture->GetRenderBuffer());
1600 // OpenGLES returns in RGBA order but CRenderCapture needs BGRA order
1601 // XOR Swap RGBA -> BGRA
1602 unsigned char* pixels = (unsigned char*)capture->GetRenderBuffer();
1603 for (unsigned int i = 0; i < capture->GetWidth() * capture->GetHeight(); i++, pixels+=4)
1605 std::swap(pixels[0], pixels[2]);
1608 capture->EndRender();
1610 // revert model view matrix
1611 g_matrices.MatrixMode(MM_MODELVIEW);
1612 g_matrices.PopMatrix();
1614 // restore original video rect
1615 m_destRect = saveSize;
1616 restoreRotatedCoords();//restores the previous state of the rotated dest coords
1621 //********************************************************************************************************
1622 // YV12 Texture creation, deletion, copying + clearing
1623 //********************************************************************************************************
1624 void CLinuxRendererGLES::UploadYV12Texture(int source)
1626 YUVBUFFER& buf = m_buffers[source];
1627 YV12Image* im = &buf.image;
1628 YUVFIELDS& fields = buf.fields;
1631 #if defined(HAVE_LIBOPENMAX)
1632 if (!(im->flags&IMAGE_FLAG_READY) || m_buffers[source].openMaxBuffer)
1634 if (!(im->flags&IMAGE_FLAG_READY))
1640 // if we don't have a shader, fallback to SW YUV2RGB for now
1641 if (m_renderMethod & RENDER_SW)
1643 if(m_rgbBufferSize < m_sourceWidth * m_sourceHeight * 4)
1645 delete [] m_rgbBuffer;
1646 m_rgbBufferSize = m_sourceWidth*m_sourceHeight*4;
1647 m_rgbBuffer = new BYTE[m_rgbBufferSize];
1650 #if defined(__ARM_NEON__)
1651 if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON)
1653 yuv420_2_rgb8888_neon(m_rgbBuffer, im->plane[0], im->plane[2], im->plane[1],
1654 m_sourceWidth, m_sourceHeight, im->stride[0], im->stride[1], m_sourceWidth * 4);
1659 m_sw_context = m_dllSwScale->sws_getCachedContext(m_sw_context,
1660 im->width, im->height, PIX_FMT_YUV420P,
1661 im->width, im->height, PIX_FMT_RGBA,
1662 SWS_FAST_BILINEAR, NULL, NULL, NULL);
1664 uint8_t *src[] = { im->plane[0], im->plane[1], im->plane[2], 0 };
1665 int srcStride[] = { im->stride[0], im->stride[1], im->stride[2], 0 };
1666 uint8_t *dst[] = { m_rgbBuffer, 0, 0, 0 };
1667 int dstStride[] = { m_sourceWidth*4, 0, 0, 0 };
1668 m_dllSwScale->sws_scale(m_sw_context, src, srcStride, 0, im->height, dst, dstStride);
1673 if (m_currentField == FIELD_FULL)
1674 deinterlacing = false;
1676 deinterlacing = true;
1678 glEnable(m_textureTarget);
1681 if (m_renderMethod & RENDER_SW)
1686 LoadPlane( fields[FIELD_TOP][0] , GL_RGBA, buf.flipindex
1687 , im->width, im->height >> 1
1688 , m_sourceWidth*8, m_rgbBuffer );
1690 LoadPlane( fields[FIELD_BOT][0], GL_RGBA, buf.flipindex
1691 , im->width, im->height >> 1
1692 , m_sourceWidth*8, m_rgbBuffer + m_sourceWidth*4);
1696 LoadPlane( fields[FIELD_FULL][0], GL_RGBA, buf.flipindex
1697 , im->width, im->height
1698 , m_sourceWidth*4, m_rgbBuffer );
1703 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1708 LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex
1709 , im->width, im->height >> 1
1710 , im->stride[0]*2, im->plane[0] );
1712 LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex
1713 , im->width, im->height >> 1
1714 , im->stride[0]*2, im->plane[0] + im->stride[0]) ;
1719 LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
1720 , im->width, im->height
1721 , im->stride[0], im->plane[0] );
1727 if (!(m_renderMethod & RENDER_SW))
1729 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1733 // Load Even U & V Fields
1734 LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE, buf.flipindex
1735 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1736 , im->stride[1]*2, im->plane[1] );
1738 LoadPlane( fields[FIELD_TOP][2], GL_ALPHA, buf.flipindex
1739 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1740 , im->stride[2]*2, im->plane[2] );
1742 // Load Odd U & V Fields
1743 LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE, buf.flipindex
1744 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1745 , im->stride[1]*2, im->plane[1] + im->stride[1] );
1747 LoadPlane( fields[FIELD_BOT][2], GL_ALPHA, buf.flipindex
1748 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1749 , im->stride[2]*2, im->plane[2] + im->stride[2] );
1754 LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, buf.flipindex
1755 , im->width >> im->cshift_x, im->height >> im->cshift_y
1756 , im->stride[1], im->plane[1] );
1758 LoadPlane( fields[FIELD_FULL][2], GL_ALPHA, buf.flipindex
1759 , im->width >> im->cshift_x, im->height >> im->cshift_y
1760 , im->stride[2], im->plane[2] );
1763 CalculateTextureSourceRects(source, 3);
1765 glDisable(m_textureTarget);
1768 void CLinuxRendererGLES::DeleteYV12Texture(int index)
1770 YV12Image &im = m_buffers[index].image;
1771 YUVFIELDS &fields = m_buffers[index].fields;
1773 if( fields[FIELD_FULL][0].id == 0 ) return;
1775 /* finish up all textures, and delete them */
1776 g_graphicsContext.BeginPaint(); //FIXME
1777 for(int f = 0;f<MAX_FIELDS;f++)
1779 for(int p = 0;p<MAX_PLANES;p++)
1781 if( fields[f][p].id )
1783 if (glIsTexture(fields[f][p].id))
1784 glDeleteTextures(1, &fields[f][p].id);
1785 fields[f][p].id = 0;
1789 g_graphicsContext.EndPaint();
1791 for(int p = 0;p<MAX_PLANES;p++)
1795 delete[] im.plane[p];
1801 bool CLinuxRendererGLES::CreateYV12Texture(int index)
1803 /* since we also want the field textures, pitch must be texture aligned */
1804 YV12Image &im = m_buffers[index].image;
1805 YUVFIELDS &fields = m_buffers[index].fields;
1807 DeleteYV12Texture(index);
1809 im.height = m_sourceHeight;
1810 im.width = m_sourceWidth;
1814 im.stride[0] = im.width;
1815 im.stride[1] = im.width >> im.cshift_x;
1816 im.stride[2] = im.width >> im.cshift_x;
1818 im.planesize[0] = im.stride[0] * im.height;
1819 im.planesize[1] = im.stride[1] * ( im.height >> im.cshift_y );
1820 im.planesize[2] = im.stride[2] * ( im.height >> im.cshift_y );
1822 for (int i = 0; i < 3; i++)
1823 im.plane[i] = new BYTE[im.planesize[i]];
1825 glEnable(m_textureTarget);
1826 for(int f = 0;f<MAX_FIELDS;f++)
1828 for(int p = 0;p<MAX_PLANES;p++)
1830 if (!glIsTexture(fields[f][p].id))
1832 glGenTextures(1, &fields[f][p].id);
1839 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
1841 int fieldshift = (f==FIELD_FULL) ? 0 : 1;
1842 YUVPLANES &planes = fields[f];
1844 planes[0].texwidth = im.width;
1845 planes[0].texheight = im.height >> fieldshift;
1847 if (m_renderMethod & RENDER_SW)
1849 planes[1].texwidth = 0;
1850 planes[1].texheight = 0;
1851 planes[2].texwidth = 0;
1852 planes[2].texheight = 0;
1856 planes[1].texwidth = planes[0].texwidth >> im.cshift_x;
1857 planes[1].texheight = planes[0].texheight >> im.cshift_y;
1858 planes[2].texwidth = planes[0].texwidth >> im.cshift_x;
1859 planes[2].texheight = planes[0].texheight >> im.cshift_y;
1862 if(m_renderMethod & RENDER_POT)
1864 for(int p = 0; p < 3; p++)
1866 planes[p].texwidth = NP2(planes[p].texwidth);
1867 planes[p].texheight = NP2(planes[p].texheight);
1871 for(int p = 0; p < 3; p++)
1873 YUVPLANE &plane = planes[p];
1874 if (plane.texwidth * plane.texheight == 0)
1877 glBindTexture(m_textureTarget, plane.id);
1878 if (m_renderMethod & RENDER_SW)
1880 if(m_renderMethod & RENDER_POT)
1881 CLog::Log(LOGDEBUG, "GL: Creating RGB POT texture of size %d x %d", plane.texwidth, plane.texheight);
1883 CLog::Log(LOGDEBUG, "GL: Creating RGB NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
1885 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1886 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1891 GLint internalformat;
1892 if (p == 2) //V plane needs an alpha texture
1895 internalformat = GL_ALPHA;
1899 format = GL_LUMINANCE;
1900 internalformat = GL_LUMINANCE;
1903 if(m_renderMethod & RENDER_POT)
1904 CLog::Log(LOGDEBUG, "GL: Creating YUV POT texture of size %d x %d", plane.texwidth, plane.texheight);
1906 CLog::Log(LOGDEBUG, "GL: Creating YUV NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
1908 glTexImage2D(m_textureTarget, 0, internalformat, plane.texwidth, plane.texheight, 0, format, GL_UNSIGNED_BYTE, NULL);
1911 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1912 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1913 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1914 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1918 glDisable(m_textureTarget);
1922 //********************************************************************************************************
1923 // NV12 Texture loading, creation and deletion
1924 //********************************************************************************************************
1925 void CLinuxRendererGLES::UploadNV12Texture(int source)
1927 YUVBUFFER& buf = m_buffers[source];
1928 YV12Image* im = &buf.image;
1929 YUVFIELDS& fields = buf.fields;
1931 if (!(im->flags & IMAGE_FLAG_READY))
1934 if (m_currentField == FIELD_FULL)
1935 deinterlacing = false;
1937 deinterlacing = true;
1939 glEnable(m_textureTarget);
1942 glPixelStorei(GL_UNPACK_ALIGNMENT, im->bpp);
1947 LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex
1948 , im->width, im->height >> 1
1949 , im->stride[0]*2, im->plane[0] );
1951 // Load Even Y field
1952 LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex
1953 , im->width, im->height >> 1
1954 , im->stride[0]*2, im->plane[0] + im->stride[0]) ;
1956 // Load Odd UV Fields
1957 LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE_ALPHA, buf.flipindex
1958 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1959 , im->stride[1]*2, im->plane[1] );
1961 // Load Even UV Fields
1962 LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE_ALPHA, buf.flipindex
1963 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1964 , im->stride[1]*2, im->plane[1] + im->stride[1] );
1970 LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
1971 , im->width, im->height
1972 , im->stride[0], im->plane[0] );
1975 LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE_ALPHA, buf.flipindex
1976 , im->width >> im->cshift_x, im->height >> im->cshift_y
1977 , im->stride[1], im->plane[1] );
1982 CalculateTextureSourceRects(source, 3);
1984 glDisable(m_textureTarget);
1988 bool CLinuxRendererGLES::CreateNV12Texture(int index)
1990 // since we also want the field textures, pitch must be texture aligned
1991 YV12Image &im = m_buffers[index].image;
1992 YUVFIELDS &fields = m_buffers[index].fields;
1994 // Delete any old texture
1995 DeleteNV12Texture(index);
1997 im.height = m_sourceHeight;
1998 im.width = m_sourceWidth;
2003 im.stride[0] = im.width;
2004 im.stride[1] = im.width;
2012 im.planesize[0] = im.stride[0] * im.height;
2014 im.planesize[1] = im.stride[1] * im.height / 2;
2015 // third plane is not used
2016 im.planesize[2] = 0;
2018 for (int i = 0; i < 2; i++)
2019 im.plane[i] = new BYTE[im.planesize[i]];
2021 glEnable(m_textureTarget);
2022 for(int f = 0;f<MAX_FIELDS;f++)
2024 for(int p = 0;p<2;p++)
2026 if (!glIsTexture(fields[f][p].id))
2028 glGenTextures(1, &fields[f][p].id);
2032 fields[f][2].id = fields[f][1].id;
2036 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
2038 int fieldshift = (f==FIELD_FULL) ? 0 : 1;
2039 YUVPLANES &planes = fields[f];
2041 planes[0].texwidth = im.width;
2042 planes[0].texheight = im.height >> fieldshift;
2044 if (m_renderMethod & RENDER_SW)
2046 planes[1].texwidth = 0;
2047 planes[1].texheight = 0;
2048 planes[2].texwidth = 0;
2049 planes[2].texheight = 0;
2053 planes[1].texwidth = planes[0].texwidth >> im.cshift_x;
2054 planes[1].texheight = planes[0].texheight >> im.cshift_y;
2055 planes[2].texwidth = planes[1].texwidth;
2056 planes[2].texheight = planes[1].texheight;
2059 if(m_renderMethod & RENDER_POT)
2061 for(int p = 0; p < 3; p++)
2063 planes[p].texwidth = NP2(planes[p].texwidth);
2064 planes[p].texheight = NP2(planes[p].texheight);
2068 for(int p = 0; p < 2; p++)
2070 YUVPLANE &plane = planes[p];
2071 if (plane.texwidth * plane.texheight == 0)
2074 glBindTexture(m_textureTarget, plane.id);
2075 if (m_renderMethod & RENDER_SW)
2077 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2082 glTexImage2D(m_textureTarget, 0, GL_LUMINANCE_ALPHA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
2084 glTexImage2D(m_textureTarget, 0, GL_LUMINANCE, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2087 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2088 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2089 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2090 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2094 glDisable(m_textureTarget);
2098 void CLinuxRendererGLES::DeleteNV12Texture(int index)
2100 YV12Image &im = m_buffers[index].image;
2101 YUVFIELDS &fields = m_buffers[index].fields;
2103 if( fields[FIELD_FULL][0].id == 0 ) return;
2105 // finish up all textures, and delete them
2106 g_graphicsContext.BeginPaint(); //FIXME
2107 for(int f = 0;f<MAX_FIELDS;f++)
2109 for(int p = 0;p<2;p++)
2111 if( fields[f][p].id )
2113 if (glIsTexture(fields[f][p].id))
2115 glDeleteTextures(1, &fields[f][p].id);
2117 fields[f][p].id = 0;
2120 fields[f][2].id = 0;
2122 g_graphicsContext.EndPaint();
2124 for(int p = 0;p<2;p++)
2128 delete[] im.plane[p];
2134 //********************************************************************************************************
2135 // CoreVideoRef Texture creation, deletion, copying + clearing
2136 //********************************************************************************************************
2137 void CLinuxRendererGLES::UploadCVRefTexture(int index)
2139 #ifdef HAVE_VIDEOTOOLBOXDECODER
2140 CVBufferRef cvBufferRef = m_buffers[index].cvBufferRef;
2144 YUVPLANE &plane = m_buffers[index].fields[0][0];
2146 CVPixelBufferLockBaseAddress(cvBufferRef, kCVPixelBufferLock_ReadOnly);
2147 #if !TARGET_OS_IPHONE
2148 int rowbytes = CVPixelBufferGetBytesPerRow(cvBufferRef);
2150 int bufferWidth = CVPixelBufferGetWidth(cvBufferRef);
2151 int bufferHeight = CVPixelBufferGetHeight(cvBufferRef);
2152 unsigned char *bufferBase = (unsigned char *)CVPixelBufferGetBaseAddress(cvBufferRef);
2154 glEnable(m_textureTarget);
2157 glBindTexture(m_textureTarget, plane.id);
2158 #if !TARGET_OS_IPHONE
2159 #ifdef GL_UNPACK_ROW_LENGTH
2161 glPixelStorei( GL_UNPACK_ROW_LENGTH, rowbytes);
2163 #ifdef GL_TEXTURE_STORAGE_HINT_APPLE
2164 // Set storage hint. Can also use GL_STORAGE_SHARED_APPLE see docs.
2165 glTexParameteri(m_textureTarget, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
2169 // Using BGRA extension to pull in video frame data directly
2170 glTexSubImage2D(m_textureTarget, 0, 0, 0, bufferWidth, bufferHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bufferBase);
2172 #if !TARGET_OS_IPHONE
2173 #ifdef GL_UNPACK_ROW_LENGTH
2175 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0);
2178 glBindTexture(m_textureTarget, 0);
2180 glDisable(m_textureTarget);
2183 CVPixelBufferUnlockBaseAddress(cvBufferRef, kCVPixelBufferLock_ReadOnly);
2184 CVBufferRelease(m_buffers[index].cvBufferRef);
2185 m_buffers[index].cvBufferRef = NULL;
2187 plane.flipindex = m_buffers[index].flipindex;
2191 void CLinuxRendererGLES::DeleteCVRefTexture(int index)
2193 #ifdef HAVE_VIDEOTOOLBOXDECODER
2194 YUVPLANE &plane = m_buffers[index].fields[0][0];
2196 if (m_buffers[index].cvBufferRef)
2197 CVBufferRelease(m_buffers[index].cvBufferRef);
2198 m_buffers[index].cvBufferRef = NULL;
2200 if(plane.id && glIsTexture(plane.id))
2201 glDeleteTextures(1, &plane.id);
2205 bool CLinuxRendererGLES::CreateCVRefTexture(int index)
2207 #ifdef HAVE_VIDEOTOOLBOXDECODER
2208 YV12Image &im = m_buffers[index].image;
2209 YUVFIELDS &fields = m_buffers[index].fields;
2210 YUVPLANE &plane = fields[0][0];
2212 DeleteCVRefTexture(index);
2214 memset(&im , 0, sizeof(im));
2215 memset(&fields, 0, sizeof(fields));
2217 im.height = m_sourceHeight;
2218 im.width = m_sourceWidth;
2220 plane.texwidth = im.width;
2221 plane.texheight = im.height;
2223 if(m_renderMethod & RENDER_POT)
2225 plane.texwidth = NP2(plane.texwidth);
2226 plane.texheight = NP2(plane.texheight);
2228 glEnable(m_textureTarget);
2229 glGenTextures(1, &plane.id);
2232 glBindTexture(m_textureTarget, plane.id);
2233 #if !TARGET_OS_IPHONE
2234 #ifdef GL_UNPACK_ROW_LENGTH
2236 glPixelStorei(GL_UNPACK_ROW_LENGTH, m_sourceWidth);
2238 #ifdef GL_TEXTURE_STORAGE_HINT_APPLE
2239 // Set storage hint. Can also use GL_STORAGE_SHARED_APPLE see docs.
2240 glTexParameteri(m_textureTarget, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
2241 // Set client storage
2243 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2246 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2247 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2248 // This is necessary for non-power-of-two textures
2249 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2250 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2251 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
2252 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
2254 #if !TARGET_OS_IPHONE
2255 // turn off client storage so it doesn't get picked up for the next texture
2256 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2258 glBindTexture(m_textureTarget, 0);
2259 glDisable(m_textureTarget);
2264 //********************************************************************************************************
2265 // BYPASS creation, deletion, copying + clearing
2266 //********************************************************************************************************
2267 void CLinuxRendererGLES::UploadBYPASSTexture(int index)
2270 void CLinuxRendererGLES::DeleteBYPASSTexture(int index)
2273 bool CLinuxRendererGLES::CreateBYPASSTexture(int index)
2278 //********************************************************************************************************
2279 // EGLIMG creation, deletion, copying + clearing
2280 //********************************************************************************************************
2281 void CLinuxRendererGLES::UploadEGLIMGTexture(int index)
2283 #ifdef HAS_LIBSTAGEFRIGHT
2284 #ifdef DEBUG_VERBOSE
2285 unsigned int time = XbmcThreads::SystemClockMillis();
2288 if(m_buffers[index].eglimg != EGL_NO_IMAGE_KHR)
2290 YUVPLANE &plane = m_buffers[index].fields[0][0];
2292 glActiveTexture(GL_TEXTURE0);
2293 glBindTexture(m_textureTarget, plane.id);
2294 glEGLImageTargetTexture2DOES(m_textureTarget, (EGLImageKHR)m_buffers[index].eglimg);
2295 glBindTexture(m_textureTarget, 0);
2297 plane.flipindex = m_buffers[index].flipindex;
2300 #ifdef DEBUG_VERBOSE
2301 CLog::Log(LOGDEBUG, "UploadEGLIMGTexture %d: img:%p, tm:%d\n", index, m_buffers[index].eglimg, XbmcThreads::SystemClockMillis() - time);
2305 void CLinuxRendererGLES::DeleteEGLIMGTexture(int index)
2307 #ifdef HAS_LIBSTAGEFRIGHT
2308 YUVPLANE &plane = m_buffers[index].fields[0][0];
2310 if(plane.id && glIsTexture(plane.id))
2311 glDeleteTextures(1, &plane.id);
2315 bool CLinuxRendererGLES::CreateEGLIMGTexture(int index)
2317 #ifdef HAS_LIBSTAGEFRIGHT
2318 YV12Image &im = m_buffers[index].image;
2319 YUVFIELDS &fields = m_buffers[index].fields;
2320 YUVPLANE &plane = fields[0][0];
2322 DeleteEGLIMGTexture(index);
2324 memset(&im , 0, sizeof(im));
2325 memset(&fields, 0, sizeof(fields));
2327 im.height = m_sourceHeight;
2328 im.width = m_sourceWidth;
2330 plane.texwidth = im.width;
2331 plane.texheight = im.height;
2333 if(m_renderMethod & RENDER_POT)
2335 plane.texwidth = NP2(plane.texwidth);
2336 plane.texheight = NP2(plane.texheight);
2338 glEnable(m_textureTarget);
2339 glGenTextures(1, &plane.id);
2342 glBindTexture(m_textureTarget, plane.id);
2344 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2345 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2346 // This is necessary for non-power-of-two textures
2347 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2348 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2350 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2352 glDisable(m_textureTarget);
2357 //********************************************************************************************************
2358 // SurfaceTexture creation, deletion, copying + clearing
2359 //********************************************************************************************************
2360 void CLinuxRendererGLES::UploadSurfaceTexture(int index)
2362 #if defined(TARGET_ANDROID)
2363 #ifdef DEBUG_VERBOSE
2364 unsigned int time = XbmcThreads::SystemClockMillis();
2368 YUVBUFFER &buf = m_buffers[index];
2372 #ifdef DEBUG_VERBOSE
2373 mindex = buf.mediacodec->GetIndex();
2375 buf.fields[0][0].id = buf.mediacodec->GetTextureID();
2376 buf.mediacodec->UpdateTexImage();
2377 buf.mediacodec->GetTransformMatrix(m_textureMatrix);
2378 SAFE_RELEASE(buf.mediacodec);
2381 #ifdef DEBUG_VERBOSE
2382 CLog::Log(LOGDEBUG, "UploadSurfaceTexture %d: img: %d tm:%d", index, mindex, XbmcThreads::SystemClockMillis() - time);
2386 void CLinuxRendererGLES::DeleteSurfaceTexture(int index)
2388 #if defined(TARGET_ANDROID)
2389 SAFE_RELEASE(m_buffers[index].mediacodec);
2392 bool CLinuxRendererGLES::CreateSurfaceTexture(int index)
2397 void CLinuxRendererGLES::SetTextureFilter(GLenum method)
2399 for (int i = 0 ; i<m_NumYV12Buffers ; i++)
2401 YUVFIELDS &fields = m_buffers[i].fields;
2403 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
2405 glBindTexture(m_textureTarget, fields[f][0].id);
2406 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2407 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2410 if (!(m_renderMethod & RENDER_SW))
2412 glBindTexture(m_textureTarget, fields[f][1].id);
2413 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2414 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2417 glBindTexture(m_textureTarget, fields[f][2].id);
2418 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2419 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2426 bool CLinuxRendererGLES::Supports(ERENDERFEATURE feature)
2428 // Player controls render, let it dictate available render features
2429 if((m_renderMethod & RENDER_BYPASS))
2431 Features::iterator itr = std::find(m_renderFeatures.begin(),m_renderFeatures.end(), feature);
2432 return itr != m_renderFeatures.end();
2435 if(feature == RENDERFEATURE_BRIGHTNESS)
2438 if(feature == RENDERFEATURE_CONTRAST)
2441 if(feature == RENDERFEATURE_GAMMA)
2444 if(feature == RENDERFEATURE_NOISE)
2447 if(feature == RENDERFEATURE_SHARPNESS)
2450 if (feature == RENDERFEATURE_NONLINSTRETCH)
2453 if (feature == RENDERFEATURE_STRETCH ||
2454 feature == RENDERFEATURE_CROP ||
2455 feature == RENDERFEATURE_ZOOM ||
2456 feature == RENDERFEATURE_VERTICAL_SHIFT ||
2457 feature == RENDERFEATURE_PIXEL_RATIO ||
2458 feature == RENDERFEATURE_POSTPROCESS ||
2459 feature == RENDERFEATURE_ROTATION)
2466 bool CLinuxRendererGLES::SupportsMultiPassRendering()
2471 bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode)
2473 // Player controls render, let it dictate available deinterlace modes
2474 if((m_renderMethod & RENDER_BYPASS))
2476 Features::iterator itr = std::find(m_deinterlaceModes.begin(),m_deinterlaceModes.end(), mode);
2477 return itr != m_deinterlaceModes.end();
2480 if (mode == VS_DEINTERLACEMODE_OFF)
2483 if(m_renderMethod & RENDER_OMXEGL)
2486 if(m_renderMethod & RENDER_EGLIMG)
2489 if(m_renderMethod & RENDER_CVREF)
2492 if(mode == VS_DEINTERLACEMODE_AUTO
2493 || mode == VS_DEINTERLACEMODE_FORCE)
2499 bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method)
2501 // Player controls render, let it dictate available deinterlace methods
2502 if((m_renderMethod & RENDER_BYPASS))
2504 Features::iterator itr = std::find(m_deinterlaceMethods.begin(),m_deinterlaceMethods.end(), method);
2505 return itr != m_deinterlaceMethods.end();
2508 if(m_renderMethod & RENDER_OMXEGL)
2511 if(m_renderMethod & RENDER_EGLIMG)
2514 if(m_renderMethod & RENDER_MEDIACODEC)
2517 if(m_renderMethod & RENDER_CVREF)
2520 if(method == VS_INTERLACEMETHOD_AUTO)
2523 #if defined(__i386__) || defined(__x86_64__)
2524 if(method == VS_INTERLACEMETHOD_DEINTERLACE
2525 || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF
2526 || method == VS_INTERLACEMETHOD_SW_BLEND)
2528 if(method == VS_INTERLACEMETHOD_SW_BLEND)
2535 bool CLinuxRendererGLES::Supports(ESCALINGMETHOD method)
2537 // Player controls render, let it dictate available scaling methods
2538 if((m_renderMethod & RENDER_BYPASS))
2540 Features::iterator itr = std::find(m_scalingMethods.begin(),m_scalingMethods.end(), method);
2541 return itr != m_scalingMethods.end();
2544 if(method == VS_SCALINGMETHOD_NEAREST
2545 || method == VS_SCALINGMETHOD_LINEAR)
2551 EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod()
2553 // Player controls render, let it pick the auto-deinterlace method
2554 if((m_renderMethod & RENDER_BYPASS))
2556 if (!m_deinterlaceMethods.empty())
2557 return ((EINTERLACEMETHOD)m_deinterlaceMethods[0]);
2559 return VS_INTERLACEMETHOD_NONE;
2562 if(m_renderMethod & RENDER_OMXEGL)
2563 return VS_INTERLACEMETHOD_NONE;
2565 if(m_renderMethod & RENDER_EGLIMG)
2566 return VS_INTERLACEMETHOD_NONE;
2568 if(m_renderMethod & RENDER_CVREF)
2569 return VS_INTERLACEMETHOD_NONE;
2571 #if defined(__i386__) || defined(__x86_64__)
2572 return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
2574 return VS_INTERLACEMETHOD_SW_BLEND;
2578 unsigned int CLinuxRendererGLES::GetProcessorSize()
2580 if(m_format == RENDER_FMT_OMXEGL
2581 || m_format == RENDER_FMT_CVBREF
2582 || m_format == RENDER_FMT_EGLIMG
2583 || m_format == RENDER_FMT_MEDIACODEC)
2589 #ifdef HAVE_LIBOPENMAX
2590 void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index)
2592 YUVBUFFER &buf = m_buffers[index];
2593 buf.openMaxBuffer = picture->openMaxBuffer;
2596 #ifdef HAVE_VIDEOTOOLBOXDECODER
2597 void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
2599 YUVBUFFER &buf = m_buffers[index];
2600 if (buf.cvBufferRef)
2601 CVBufferRelease(buf.cvBufferRef);
2602 buf.cvBufferRef = cvBufferRef;
2603 // retain another reference, this way dvdplayer and renderer can issue releases.
2604 CVBufferRetain(buf.cvBufferRef);
2607 #ifdef HAS_LIBSTAGEFRIGHT
2608 void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKHR eglimg, int index)
2610 #ifdef DEBUG_VERBOSE
2611 unsigned int time = XbmcThreads::SystemClockMillis();
2614 YUVBUFFER &buf = m_buffers[index];
2615 if (buf.eglimg != EGL_NO_IMAGE_KHR)
2616 stf->ReleaseBuffer(buf.eglimg);
2617 stf->LockBuffer(eglimg);
2620 buf.eglimg = eglimg;
2622 #ifdef DEBUG_VERBOSE
2623 CLog::Log(LOGDEBUG, "AddProcessor %d: img:%p: tm:%d\n", index, eglimg, XbmcThreads::SystemClockMillis() - time);
2628 #if defined(TARGET_ANDROID)
2629 void CLinuxRendererGLES::AddProcessor(CDVDMediaCodecInfo *mediacodec, int index)
2631 #ifdef DEBUG_VERBOSE
2632 unsigned int time = XbmcThreads::SystemClockMillis();
2636 YUVBUFFER &buf = m_buffers[index];
2639 buf.mediacodec = mediacodec->Retain();
2640 #ifdef DEBUG_VERBOSE
2641 mindex = buf.mediacodec->GetIndex();
2643 // releaseOutputBuffer must be in same thread as
2644 // dequeueOutputBuffer. We are in DVDPlayerVideo
2645 // thread here, so we are safe.
2646 buf.mediacodec->ReleaseOutputBuffer(true);
2649 #ifdef DEBUG_VERBOSE
2650 CLog::Log(LOGDEBUG, "AddProcessor %d: img:%d tm:%d", index, mindex, XbmcThreads::SystemClockMillis() - time);