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 "guilib/Texture.h"
46 #include "lib/DllSwScale.h"
47 #include "../dvdplayer/DVDCodecs/Video/OpenMaxVideo.h"
48 #include "threads/SingleLock.h"
49 #include "RenderCapture.h"
50 #include "RenderFormats.h"
51 #include "xbmc/Application.h"
52 #include "cores/IPlayer.h"
54 #if defined(__ARM_NEON__)
55 #include "yuv2rgb.neon.h"
56 #include "utils/CPUInfo.h"
58 #ifdef HAVE_VIDEOTOOLBOXDECODER
59 #include "DVDCodecs/Video/DVDVideoCodecVideoToolBox.h"
60 #include <CoreVideo/CoreVideo.h>
62 #ifdef TARGET_DARWIN_IOS
63 #include "osx/DarwinUtils.h"
65 #if defined(HAS_LIBSTAGEFRIGHT)
67 #include <EGL/eglext.h>
68 #include "windowing/egl/EGLWrapper.h"
69 #include "android/activity/XBMCApp.h"
70 #include "DVDCodecs/Video/DVDVideoCodecStageFright.h"
72 // EGL extension functions
73 static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
74 static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
75 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
78 #if defined(TARGET_ANDROID)
79 #include "DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h"
82 using namespace Shaders;
84 CLinuxRendererGLES::YUVBUFFER::YUVBUFFER()
86 memset(&fields, 0, sizeof(fields));
87 memset(&image , 0, sizeof(image));
89 #ifdef HAVE_LIBOPENMAX
92 #ifdef HAVE_VIDEOTOOLBOXDECODER
95 #ifdef HAS_LIBSTAGEFRIGHT
97 eglimg = EGL_NO_IMAGE_KHR;
99 #if defined(TARGET_ANDROID)
104 CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER()
108 CLinuxRendererGLES::CLinuxRendererGLES()
110 m_textureTarget = GL_TEXTURE_2D;
112 m_renderMethod = RENDER_GLSL;
113 m_oldRenderMethod = m_renderMethod;
114 m_renderQuality = RQ_SINGLEPASS;
116 m_format = RENDER_FMT_NONE;
118 m_iYV12RenderBuffer = 0;
120 m_currentField = FIELD_FULL;
123 m_pVideoFilterShader = NULL;
124 m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
125 m_scalingMethodGui = (ESCALINGMETHOD)-1;
127 // default texture handlers to YUV
128 m_textureUpload = &CLinuxRendererGLES::UploadYV12Texture;
129 m_textureCreate = &CLinuxRendererGLES::CreateYV12Texture;
130 m_textureDelete = &CLinuxRendererGLES::DeleteYV12Texture;
135 m_dllSwScale = new DllSwScale;
137 m_NumYV12Buffers = 0;
138 m_iLastRenderBuffer = 0;
139 m_bConfigured = false;
140 m_bValidated = false;
141 m_bImageReady = false;
142 m_StrictBinding = false;
143 m_clearColour = 0.0f;
145 #ifdef HAS_LIBSTAGEFRIGHT
146 if (!eglCreateImageKHR)
147 eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglCreateImageKHR");
148 if (!eglDestroyImageKHR)
149 eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglDestroyImageKHR");
150 if (!glEGLImageTargetTexture2DOES)
151 glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) CEGLWrapper::GetProcAddress("glEGLImageTargetTexture2DOES");
155 CLinuxRendererGLES::~CLinuxRendererGLES()
159 if (m_rgbBuffer != NULL) {
160 delete [] m_rgbBuffer;
166 m_pYUVShader->Free();
174 bool CLinuxRendererGLES::ValidateRenderTarget()
178 CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D");
180 // function pointer for texture might change in
181 // call to LoadShaders
183 for (int i = 0 ; i < NUM_BUFFERS ; i++)
184 (this->*m_textureDelete)(i);
186 // create the yuv textures
189 for (int i = 0 ; i < m_NumYV12Buffers ; i++)
190 (this->*m_textureCreate)(i);
198 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)
200 m_sourceWidth = width;
201 m_sourceHeight = height;
202 m_renderOrientation = orientation;
208 // Calculate the input frame aspect ratio.
209 CalculateFrameAspectRatio(d_width, d_height);
210 ChooseBestResolution(fps);
211 SetViewMode(CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode);
214 m_bConfigured = true;
215 m_bImageReady = false;
216 m_scalingMethodGui = (ESCALINGMETHOD)-1;
218 // Ensure that textures are recreated and rendering starts only after the 1st
219 // frame is loaded after every call to Configure().
220 m_bValidated = false;
222 for (int i = 0 ; i<m_NumYV12Buffers ; i++)
223 m_buffers[i].image.flags = 0;
225 m_iLastRenderBuffer = -1;
227 m_RenderUpdateCallBackFn = NULL;
228 m_RenderUpdateCallBackCtx = NULL;
229 if ((m_format == RENDER_FMT_BYPASS) && g_application.GetCurrentPlayer())
231 m_renderFeatures.clear();
232 m_scalingMethods.clear();
233 m_deinterlaceModes.clear();
234 m_deinterlaceMethods.clear();
236 if (m_RenderFeaturesCallBackFn)
238 (*m_RenderFeaturesCallBackFn)(m_RenderFeaturesCallBackCtx, m_renderFeatures);
239 // after setting up m_renderFeatures, we are done with the callback
240 m_RenderFeaturesCallBackFn = NULL;
241 m_RenderFeaturesCallBackCtx = NULL;
243 g_application.m_pPlayer->GetRenderFeatures(m_renderFeatures);
244 g_application.m_pPlayer->GetDeinterlaceMethods(m_deinterlaceMethods);
245 g_application.m_pPlayer->GetDeinterlaceModes(m_deinterlaceModes);
246 g_application.m_pPlayer->GetScalingMethods(m_scalingMethods);
252 int CLinuxRendererGLES::NextYV12Texture()
254 return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
257 int CLinuxRendererGLES::GetImage(YV12Image *image, int source, bool readonly)
259 if (!image) return -1;
260 if (!m_bValidated) return -1;
262 /* take next available buffer */
263 if( source == AUTOSOURCE )
264 source = NextYV12Texture();
266 if ( m_renderMethod & RENDER_OMXEGL )
270 #ifdef HAS_LIBSTAGEFRIGHT
271 if ( m_renderMethod & RENDER_EGLIMG )
277 if ( m_renderMethod & RENDER_MEDIACODEC )
282 #ifdef HAVE_VIDEOTOOLBOXDECODER
283 if (m_renderMethod & RENDER_CVREF )
289 YV12Image &im = m_buffers[source].image;
291 if ((im.flags&(~IMAGE_FLAG_READY)) != 0)
293 CLog::Log(LOGDEBUG, "CLinuxRenderer::GetImage - request image but none to give");
298 im.flags |= IMAGE_FLAG_READING;
300 im.flags |= IMAGE_FLAG_WRITING;
302 // copy the image - should be operator of YV12Image
303 for (int p=0;p<MAX_PLANES;p++)
305 image->plane[p] = im.plane[p];
306 image->stride[p] = im.stride[p];
308 image->width = im.width;
309 image->height = im.height;
310 image->flags = im.flags;
311 image->cshift_x = im.cshift_x;
312 image->cshift_y = im.cshift_y;
318 void CLinuxRendererGLES::ReleaseImage(int source, bool preserve)
320 YV12Image &im = m_buffers[source].image;
322 im.flags &= ~IMAGE_FLAG_INUSE;
323 im.flags |= IMAGE_FLAG_READY;
324 /* if image should be preserved reserve it so it's not auto seleceted */
327 im.flags |= IMAGE_FLAG_RESERVED;
329 m_bImageReady = true;
332 void CLinuxRendererGLES::CalculateTextureSourceRects(int source, int num_planes)
334 YUVBUFFER& buf = m_buffers[source];
335 YV12Image* im = &buf.image;
336 YUVFIELDS& fields = buf.fields;
338 // calculate the source rectangle
339 for(int field = 0; field < 3; field++)
341 for(int plane = 0; plane < num_planes; plane++)
343 YUVPLANE& p = fields[field][plane];
345 p.rect = m_sourceRect;
347 p.height = im->height;
349 if(field != FIELD_FULL)
351 /* correct for field offsets and chroma offsets */
352 float offset_y = 0.5;
355 if(field == FIELD_BOT)
358 p.rect.y1 += offset_y;
359 p.rect.y2 += offset_y;
361 /* half the height if this is a field */
369 p.width /= 1 << im->cshift_x;
370 p.height /= 1 << im->cshift_y;
372 p.rect.x1 /= 1 << im->cshift_x;
373 p.rect.x2 /= 1 << im->cshift_x;
374 p.rect.y1 /= 1 << im->cshift_y;
375 p.rect.y2 /= 1 << im->cshift_y;
378 // protect against division by zero
379 if (p.texheight == 0 || p.texwidth == 0 ||
380 p.pixpertex_x == 0 || p.pixpertex_y == 0)
385 p.height /= p.pixpertex_y;
386 p.rect.y1 /= p.pixpertex_y;
387 p.rect.y2 /= p.pixpertex_y;
388 p.width /= p.pixpertex_x;
389 p.rect.x1 /= p.pixpertex_x;
390 p.rect.x2 /= p.pixpertex_x;
392 if (m_textureTarget == GL_TEXTURE_2D)
394 p.height /= p.texheight;
395 p.rect.y1 /= p.texheight;
396 p.rect.y2 /= p.texheight;
397 p.width /= p.texwidth;
398 p.rect.x1 /= p.texwidth;
399 p.rect.x2 /= p.texwidth;
405 void CLinuxRendererGLES::LoadPlane( YUVPLANE& plane, int type, unsigned flipindex
406 , unsigned width, unsigned height
407 , unsigned int stride, int bpp, void* data )
409 if(plane.flipindex == flipindex)
412 const GLvoid *pixelData = data;
414 int bps = bpp * glFormatElementByteCount(type);
418 datatype = GL_UNSIGNED_SHORT;
420 datatype = GL_UNSIGNED_BYTE;
422 glBindTexture(m_textureTarget, plane.id);
424 // OpenGL ES does not support strided texture input.
425 if(stride != width * bps)
427 unsigned char* src = (unsigned char*)data;
428 for (unsigned int y = 0; y < height;++y, src += stride)
429 glTexSubImage2D(m_textureTarget, 0, 0, y, width, 1, type, datatype, src);
431 glTexSubImage2D(m_textureTarget, 0, 0, 0, width, height, type, datatype, pixelData);
434 /* check if we need to load any border pixels */
435 if(height < plane.texheight)
436 glTexSubImage2D( m_textureTarget, 0
437 , 0, height, width, 1
439 , (unsigned char*)pixelData + stride * (height-1));
441 if(width < plane.texwidth)
442 glTexSubImage2D( m_textureTarget, 0
443 , width, 0, 1, height
445 , (unsigned char*)pixelData + bps * (width-1));
447 glBindTexture(m_textureTarget, 0);
449 plane.flipindex = flipindex;
452 void CLinuxRendererGLES::Reset()
454 for(int i=0; i<m_NumYV12Buffers; i++)
456 /* reset all image flags, this will cleanup textures later */
457 m_buffers[i].image.flags = 0;
461 void CLinuxRendererGLES::Flush()
468 for (int i = 0 ; i < m_NumYV12Buffers ; i++)
469 (this->*m_textureDelete)(i);
472 m_bValidated = false;
474 m_iYV12RenderBuffer = 0;
477 void CLinuxRendererGLES::Update()
479 if (!m_bConfigured) return;
483 void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
485 if (!m_bConfigured) return;
487 // if its first pass, just init textures and return
488 if (ValidateRenderTarget())
491 if (m_renderMethod & RENDER_BYPASS)
494 // if running bypass, then the player might need the src/dst rects
495 // for sizing video playback on a layer other than the gles layer.
496 if (m_RenderUpdateCallBackFn)
497 (*m_RenderUpdateCallBackFn)(m_RenderUpdateCallBackCtx, m_sourceRect, m_destRect);
499 CRect old = g_graphicsContext.GetScissors();
501 g_graphicsContext.BeginPaint();
502 g_graphicsContext.SetScissors(m_destRect);
505 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
506 glClearColor(0, 0, 0, 0);
507 glClear(GL_COLOR_BUFFER_BIT);
509 g_graphicsContext.SetScissors(old);
510 g_graphicsContext.EndPaint();
514 // this needs to be checked after texture validation
515 if (!m_bImageReady) return;
517 int index = m_iYV12RenderBuffer;
518 YUVBUFFER& buf = m_buffers[index];
520 if (m_format != RENDER_FMT_OMXEGL && m_format != RENDER_FMT_EGLIMG && m_format != RENDER_FMT_MEDIACODEC)
522 if (!buf.fields[FIELD_FULL][0].id) return;
524 if (buf.image.flags==0)
529 g_graphicsContext.BeginPaint();
531 m_iLastRenderBuffer = index;
535 glClearColor(m_clearColour, m_clearColour, m_clearColour, 0);
536 glClear(GL_COLOR_BUFFER_BIT);
537 glClearColor(0,0,0,0);
543 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
545 m_pYUVShader->SetAlpha(alpha / 255.0f);
551 m_pYUVShader->SetAlpha(1.0f);
554 if ((flags & RENDER_FLAG_TOP) && (flags & RENDER_FLAG_BOT))
555 CLog::Log(LOGERROR, "GLES: Cannot render stipple!");
557 Render(flags, index);
562 g_graphicsContext.EndPaint();
565 void CLinuxRendererGLES::FlipPage(int source)
567 if( source >= 0 && source < m_NumYV12Buffers )
568 m_iYV12RenderBuffer = source;
570 m_iYV12RenderBuffer = NextYV12Texture();
572 m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
577 unsigned int CLinuxRendererGLES::PreInit()
579 CSingleLock lock(g_graphicsContext);
580 m_bConfigured = false;
581 m_bValidated = false;
583 m_resolution = CDisplaySettings::Get().GetCurrentResolution();
584 if ( m_resolution == RES_WINDOW )
585 m_resolution = RES_DESKTOP;
587 m_iYV12RenderBuffer = 0;
588 m_NumYV12Buffers = 2;
591 m_formats.push_back(RENDER_FMT_YUV420P);
592 m_formats.push_back(RENDER_FMT_NV12);
593 m_formats.push_back(RENDER_FMT_BYPASS);
594 #if defined(HAVE_LIBOPENMAX)
595 m_formats.push_back(RENDER_FMT_OMXEGL);
597 #ifdef HAVE_VIDEOTOOLBOXDECODER
598 m_formats.push_back(RENDER_FMT_CVBREF);
600 #ifdef HAS_LIBSTAGEFRIGHT
601 m_formats.push_back(RENDER_FMT_EGLIMG);
603 #if defined(TARGET_ANDROID)
604 m_formats.push_back(RENDER_FMT_MEDIACODEC);
607 // setup the background colour
608 m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
610 if (!m_dllSwScale->Load())
611 CLog::Log(LOGERROR,"CLinuxRendererGL::PreInit - failed to load rescale libraries!");
616 void CLinuxRendererGLES::UpdateVideoFilter()
618 if (m_scalingMethodGui == CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod)
620 m_scalingMethodGui = CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod;
621 m_scalingMethod = m_scalingMethodGui;
623 if(!Supports(m_scalingMethod))
625 CLog::Log(LOGWARNING, "CLinuxRendererGLES::UpdateVideoFilter - choosen scaling method %d, is not supported by renderer", (int)m_scalingMethod);
626 m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
629 if (m_pVideoFilterShader)
631 m_pVideoFilterShader->Free();
632 delete m_pVideoFilterShader;
633 m_pVideoFilterShader = NULL;
639 switch (m_scalingMethod)
641 case VS_SCALINGMETHOD_NEAREST:
642 SetTextureFilter(GL_NEAREST);
643 m_renderQuality = RQ_SINGLEPASS;
646 case VS_SCALINGMETHOD_LINEAR:
647 SetTextureFilter(GL_LINEAR);
648 m_renderQuality = RQ_SINGLEPASS;
651 case VS_SCALINGMETHOD_CUBIC:
652 CLog::Log(LOGERROR, "GLES: CUBIC not supported!");
655 case VS_SCALINGMETHOD_LANCZOS2:
656 case VS_SCALINGMETHOD_LANCZOS3:
657 case VS_SCALINGMETHOD_SINC8:
658 case VS_SCALINGMETHOD_NEDI:
659 CLog::Log(LOGERROR, "GL: TODO: This scaler has not yet been implemented");
666 CLog::Log(LOGERROR, "GL: Falling back to bilinear due to failure to init scaler");
667 if (m_pVideoFilterShader)
669 m_pVideoFilterShader->Free();
670 delete m_pVideoFilterShader;
671 m_pVideoFilterShader = NULL;
675 SetTextureFilter(GL_LINEAR);
676 m_renderQuality = RQ_SINGLEPASS;
679 void CLinuxRendererGLES::LoadShaders(int field)
681 #ifdef TARGET_DARWIN_IOS
682 float ios_version = GetIOSVersion();
684 int requestedMethod = CSettings::Get().GetInt("videoplayer.rendermethod");
685 CLog::Log(LOGDEBUG, "GL: Requested render method: %d", requestedMethod);
689 m_pYUVShader->Free();
694 switch(requestedMethod)
696 case RENDER_METHOD_AUTO:
697 case RENDER_METHOD_GLSL:
698 if (m_format == RENDER_FMT_OMXEGL)
700 CLog::Log(LOGNOTICE, "GL: Using OMXEGL RGBA render method");
701 m_renderMethod = RENDER_OMXEGL;
704 else if (m_format == RENDER_FMT_EGLIMG)
706 CLog::Log(LOGNOTICE, "GL: Using EGL Image render method");
707 m_renderMethod = RENDER_EGLIMG;
710 else if (m_format == RENDER_FMT_MEDIACODEC)
712 CLog::Log(LOGNOTICE, "GL: Using MediaCodec render method");
713 m_renderMethod = RENDER_MEDIACODEC;
716 else if (m_format == RENDER_FMT_BYPASS)
718 CLog::Log(LOGNOTICE, "GL: Using BYPASS render method");
719 m_renderMethod = RENDER_BYPASS;
722 else if (m_format == RENDER_FMT_CVBREF)
724 CLog::Log(LOGNOTICE, "GL: Using CoreVideoRef RGBA render method");
725 m_renderMethod = RENDER_CVREF;
728 #if defined(TARGET_DARWIN_IOS)
729 else if (ios_version < 5.0 && m_format == RENDER_FMT_YUV420P)
731 CLog::Log(LOGNOTICE, "GL: Using software color conversion/RGBA render method");
732 m_renderMethod = RENDER_SW;
736 // Try GLSL shaders if supported and user requested auto or GLSL.
739 // create regular progressive scan shader
740 m_pYUVShader = new YUV2RGBProgressiveShader(false, m_iFlags, m_format);
741 CLog::Log(LOGNOTICE, "GL: Selecting Single Pass YUV 2 RGB shader");
743 if (m_pYUVShader && m_pYUVShader->CompileAndLink())
745 m_renderMethod = RENDER_GLSL;
749 else if (m_pYUVShader)
751 m_pYUVShader->Free();
754 CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB GLSL shader");
755 // drop through and try SW
758 case RENDER_METHOD_SOFTWARE:
761 // Use software YUV 2 RGB conversion if user requested it or GLSL failed
762 m_renderMethod = RENDER_SW ;
763 CLog::Log(LOGNOTICE, "GL: Using software color conversion/RGBA rendering");
767 // determine whether GPU supports NPOT textures
768 if (!g_Windowing.IsExtSupported("GL_TEXTURE_NPOT"))
770 CLog::Log(LOGNOTICE, "GL: GL_ARB_texture_rectangle not supported and OpenGL version is not 2.x");
771 CLog::Log(LOGNOTICE, "GL: Reverting to POT textures");
772 m_renderMethod |= RENDER_POT;
775 CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
777 // Now that we now the render method, setup texture function handlers
778 if (m_format == RENDER_FMT_CVBREF)
780 m_textureUpload = &CLinuxRendererGLES::UploadCVRefTexture;
781 m_textureCreate = &CLinuxRendererGLES::CreateCVRefTexture;
782 m_textureDelete = &CLinuxRendererGLES::DeleteCVRefTexture;
784 else if (m_format == RENDER_FMT_BYPASS)
786 m_textureUpload = &CLinuxRendererGLES::UploadBYPASSTexture;
787 m_textureCreate = &CLinuxRendererGLES::CreateBYPASSTexture;
788 m_textureDelete = &CLinuxRendererGLES::DeleteBYPASSTexture;
790 else if (m_format == RENDER_FMT_EGLIMG)
792 m_textureUpload = &CLinuxRendererGLES::UploadEGLIMGTexture;
793 m_textureCreate = &CLinuxRendererGLES::CreateEGLIMGTexture;
794 m_textureDelete = &CLinuxRendererGLES::DeleteEGLIMGTexture;
796 else if (m_format == RENDER_FMT_MEDIACODEC)
798 m_textureUpload = &CLinuxRendererGLES::UploadSurfaceTexture;
799 m_textureCreate = &CLinuxRendererGLES::CreateSurfaceTexture;
800 m_textureDelete = &CLinuxRendererGLES::DeleteSurfaceTexture;
802 else if (m_format == RENDER_FMT_NV12)
804 m_textureUpload = &CLinuxRendererGLES::UploadNV12Texture;
805 m_textureCreate = &CLinuxRendererGLES::CreateNV12Texture;
806 m_textureDelete = &CLinuxRendererGLES::DeleteNV12Texture;
810 // default to YV12 texture handlers
811 m_textureUpload = &CLinuxRendererGLES::UploadYV12Texture;
812 m_textureCreate = &CLinuxRendererGLES::CreateYV12Texture;
813 m_textureDelete = &CLinuxRendererGLES::DeleteYV12Texture;
816 if (m_oldRenderMethod != m_renderMethod)
818 CLog::Log(LOGDEBUG, "CLinuxRendererGLES: Reorder drawpoints due to method change from %i to %i", m_oldRenderMethod, m_renderMethod);
820 m_oldRenderMethod = m_renderMethod;
824 void CLinuxRendererGLES::UnInit()
826 CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
827 CSingleLock lock(g_graphicsContext);
829 if (m_rgbBuffer != NULL)
831 delete [] m_rgbBuffer;
837 for (int i = 0; i < NUM_BUFFERS; ++i)
838 (this->*m_textureDelete)(i);
840 if (m_dllSwScale && m_sw_context)
842 m_dllSwScale->sws_freeContext(m_sw_context);
846 // cleanup framebuffer object if it was in use
848 m_bValidated = false;
849 m_bImageReady = false;
850 m_bConfigured = false;
851 m_RenderUpdateCallBackFn = NULL;
852 m_RenderUpdateCallBackCtx = NULL;
853 m_RenderFeaturesCallBackFn = NULL;
854 m_RenderFeaturesCallBackCtx = NULL;
857 inline void CLinuxRendererGLES::ReorderDrawPoints()
860 CBaseRenderer::ReorderDrawPoints();//call base impl. for rotating the points
862 //corevideo and EGL are flipped in y
863 if(m_renderMethod & RENDER_CVREF)
866 tmp = m_rotatedDestCoords[0];
867 m_rotatedDestCoords[0] = m_rotatedDestCoords[3];
868 m_rotatedDestCoords[3] = tmp;
869 tmp = m_rotatedDestCoords[1];
870 m_rotatedDestCoords[1] = m_rotatedDestCoords[2];
871 m_rotatedDestCoords[2] = tmp;
875 void CLinuxRendererGLES::ReleaseBuffer(int idx)
877 YUVBUFFER &buf = m_buffers[idx];
878 #ifdef HAVE_VIDEOTOOLBOXDECODER
879 if (m_renderMethod & RENDER_CVREF )
882 CVBufferRelease(buf.cvBufferRef);
883 buf.cvBufferRef = NULL;
886 #if defined(TARGET_ANDROID)
887 if ( m_renderMethod & RENDER_MEDIACODEC )
891 // The media buffer has been queued to the SurfaceView but we didn't render it
892 // We have to do to the updateTexImage or it will get stuck
893 buf.mediacodec->UpdateTexImage();
894 SAFE_RELEASE(buf.mediacodec);
900 void CLinuxRendererGLES::Render(DWORD flags, int index)
902 // If rendered directly by the hardware
903 if (m_renderMethod & RENDER_BYPASS)
906 // obtain current field, if interlaced
907 if( flags & RENDER_FLAG_TOP)
908 m_currentField = FIELD_TOP;
910 else if (flags & RENDER_FLAG_BOT)
911 m_currentField = FIELD_BOT;
914 m_currentField = FIELD_FULL;
916 (this->*m_textureUpload)(index);
918 if (m_renderMethod & RENDER_GLSL)
921 switch(m_renderQuality)
925 RenderSinglePass(index, m_currentField);
930 RenderMultiPass(index, m_currentField);
935 RenderSoftware(index, m_currentField);
940 else if (m_renderMethod & RENDER_OMXEGL)
942 RenderOpenMax(index, m_currentField);
945 else if (m_renderMethod & RENDER_EGLIMG)
947 RenderEglImage(index, m_currentField);
950 else if (m_renderMethod & RENDER_CVREF)
952 RenderCoreVideoRef(index, m_currentField);
955 else if (m_renderMethod & RENDER_MEDIACODEC)
957 RenderSurfaceTexture(index, m_currentField);
961 RenderSoftware(index, m_currentField);
966 void CLinuxRendererGLES::RenderSinglePass(int index, int field)
968 YV12Image &im = m_buffers[index].image;
969 YUVFIELDS &fields = m_buffers[index].fields;
970 YUVPLANES &planes = fields[field];
978 glDisable(GL_DEPTH_TEST);
981 glActiveTexture(GL_TEXTURE0);
982 glEnable(m_textureTarget);
983 glBindTexture(m_textureTarget, planes[0].id);
986 glActiveTexture(GL_TEXTURE1);
987 glEnable(m_textureTarget);
988 glBindTexture(m_textureTarget, planes[1].id);
991 glActiveTexture(GL_TEXTURE2);
992 glEnable(m_textureTarget);
993 glBindTexture(m_textureTarget, planes[2].id);
995 glActiveTexture(GL_TEXTURE0);
998 m_pYUVShader->SetBlack(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * 0.01f - 0.5f);
999 m_pYUVShader->SetContrast(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast * 0.02f);
1000 m_pYUVShader->SetWidth(im.width);
1001 m_pYUVShader->SetHeight(im.height);
1002 if (field == FIELD_TOP)
1003 m_pYUVShader->SetField(1);
1004 else if(field == FIELD_BOT)
1005 m_pYUVShader->SetField(0);
1007 m_pYUVShader->SetMatrices(g_matrices.GetMatrix(MM_PROJECTION), g_matrices.GetMatrix(MM_MODELVIEW));
1008 m_pYUVShader->Enable();
1010 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1011 GLfloat m_vert[4][3];
1012 GLfloat m_tex[3][4][2];
1014 GLint vertLoc = m_pYUVShader->GetVertexLoc();
1015 GLint Yloc = m_pYUVShader->GetYcoordLoc();
1016 GLint Uloc = m_pYUVShader->GetUcoordLoc();
1017 GLint Vloc = m_pYUVShader->GetVcoordLoc();
1019 glVertexAttribPointer(vertLoc, 3, GL_FLOAT, 0, 0, m_vert);
1020 glVertexAttribPointer(Yloc, 2, GL_FLOAT, 0, 0, m_tex[0]);
1021 glVertexAttribPointer(Uloc, 2, GL_FLOAT, 0, 0, m_tex[1]);
1022 glVertexAttribPointer(Vloc, 2, GL_FLOAT, 0, 0, m_tex[2]);
1024 glEnableVertexAttribArray(vertLoc);
1025 glEnableVertexAttribArray(Yloc);
1026 glEnableVertexAttribArray(Uloc);
1027 glEnableVertexAttribArray(Vloc);
1029 // Setup vertex position values
1030 for(int i = 0; i < 4; i++)
1032 m_vert[i][0] = m_rotatedDestCoords[i].x;
1033 m_vert[i][1] = m_rotatedDestCoords[i].y;
1034 m_vert[i][2] = 0.0f;// set z to 0
1037 // Setup texture coordinates
1038 for (int i=0; i<3; i++)
1040 m_tex[i][0][0] = m_tex[i][3][0] = planes[i].rect.x1;
1041 m_tex[i][0][1] = m_tex[i][1][1] = planes[i].rect.y1;
1042 m_tex[i][1][0] = m_tex[i][2][0] = planes[i].rect.x2;
1043 m_tex[i][2][1] = m_tex[i][3][1] = planes[i].rect.y2;
1046 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1050 m_pYUVShader->Disable();
1053 glDisableVertexAttribArray(vertLoc);
1054 glDisableVertexAttribArray(Yloc);
1055 glDisableVertexAttribArray(Uloc);
1056 glDisableVertexAttribArray(Vloc);
1058 glActiveTexture(GL_TEXTURE1);
1059 glDisable(m_textureTarget);
1061 glActiveTexture(GL_TEXTURE2);
1062 glDisable(m_textureTarget);
1064 glActiveTexture(GL_TEXTURE0);
1065 glDisable(m_textureTarget);
1067 g_matrices.MatrixMode(MM_MODELVIEW);
1072 void CLinuxRendererGLES::RenderMultiPass(int index, int field)
1074 // TODO: Multipass rendering does not currently work! FIX!
1075 CLog::Log(LOGERROR, "GLES: MULTIPASS rendering was called! But it doesnt work!!!");
1078 YV12Image &im = m_buffers[index].image;
1079 YUVPLANES &planes = m_buffers[index].fields[field];
1081 if (m_reloadShaders)
1083 m_reloadShaders = 0;
1084 LoadShaders(m_currentField);
1087 glDisable(GL_DEPTH_TEST);
1090 glEnable(m_textureTarget);
1091 glActiveTexture(GL_TEXTURE0);
1092 glBindTexture(m_textureTarget, planes[0].id);
1096 glActiveTexture(GL_TEXTURE1);
1097 glEnable(m_textureTarget);
1098 glBindTexture(m_textureTarget, planes[1].id);
1102 glActiveTexture(GL_TEXTURE2);
1103 glEnable(m_textureTarget);
1104 glBindTexture(m_textureTarget, planes[2].id);
1107 glActiveTexture(GL_TEXTURE0);
1110 // make sure the yuv shader is loaded and ready to go
1111 if (!m_pYUVShader || (!m_pYUVShader->OK()))
1113 CLog::Log(LOGERROR, "GL: YUV shader not active, cannot do multipass render");
1117 m_fbo.BeginRender();
1120 m_pYUVShader->SetBlack(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * 0.01f - 0.5f);
1121 m_pYUVShader->SetContrast(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast * 0.02f);
1122 m_pYUVShader->SetWidth(im.width);
1123 m_pYUVShader->SetHeight(im.height);
1124 if (field == FIELD_TOP)
1125 m_pYUVShader->SetField(1);
1126 else if(field == FIELD_BOT)
1127 m_pYUVShader->SetField(0);
1131 // glPushAttrib(GL_VIEWPORT_BIT);
1132 // glPushAttrib(GL_SCISSOR_BIT);
1133 g_matrices.MatrixMode(MM_MODELVIEW);
1134 g_matrices.PushMatrix();
1135 g_matrices.LoadIdentity();
1138 g_matrices.MatrixMode(MM_PROJECTION);
1139 g_matrices.PushMatrix();
1140 g_matrices.LoadIdentity();
1142 g_matrices.Ortho2D(0, m_sourceWidth, 0, m_sourceHeight);
1143 CRect viewport(0, 0, m_sourceWidth, m_sourceHeight);
1144 g_Windowing.SetViewPort(viewport);
1145 g_matrices.MatrixMode(MM_MODELVIEW);
1149 if (!m_pYUVShader->Enable())
1151 CLog::Log(LOGERROR, "GL: Error enabling YUV shader");
1154 // 1st Pass to video frame size
1156 // float imgwidth = planes[0].rect.x2 - planes[0].rect.x1;
1157 // float imgheight = planes[0].rect.y2 - planes[0].rect.y1;
1158 // if (m_textureTarget == GL_TEXTURE_2D)
1160 // imgwidth *= planes[0].pixpertex_x;
1161 // imgheight *= planes[0].pixpertex_y;
1164 // glBegin(GL_QUADS);
1166 // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
1167 // glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y1);
1168 // glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y1);
1169 // glVertex2f(0.0f , 0.0f);
1171 // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y1);
1172 // glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y1);
1173 // glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y1);
1174 // glVertex2f(imgwidth, 0.0f);
1176 // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y2);
1177 // glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y2);
1178 // glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y2);
1179 // glVertex2f(imgwidth, imgheight);
1181 // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y2);
1182 // glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y2);
1183 // glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y2);
1184 // glVertex2f(0.0f , imgheight);
1189 m_pYUVShader->Disable();
1191 g_matrices.MatrixMode(MM_MODELVIEW);
1192 g_matrices.PopMatrix(); // pop modelview
1193 g_matrices.MatrixMode(MM_PROJECTION);
1194 g_matrices.PopMatrix(); // pop projection
1196 // glPopAttrib(); // pop scissor
1197 // glPopAttrib(); // pop viewport
1198 g_matrices.MatrixMode(MM_MODELVIEW);
1203 glActiveTexture(GL_TEXTURE1);
1204 glDisable(m_textureTarget);
1205 glActiveTexture(GL_TEXTURE2);
1206 glDisable(m_textureTarget);
1207 glActiveTexture(GL_TEXTURE0);
1208 glDisable(m_textureTarget);
1210 glEnable(GL_TEXTURE_2D);
1211 glBindTexture(GL_TEXTURE_2D, m_fbo.Texture());
1214 // Use regular normalized texture coordinates
1216 // 2nd Pass to screen size with optional video filter
1218 if (m_pVideoFilterShader)
1220 m_fbo.SetFiltering(GL_TEXTURE_2D, GL_NEAREST);
1221 m_pVideoFilterShader->SetSourceTexture(0);
1222 m_pVideoFilterShader->SetWidth(m_sourceWidth);
1223 m_pVideoFilterShader->SetHeight(m_sourceHeight);
1224 m_pVideoFilterShader->Enable();
1227 m_fbo.SetFiltering(GL_TEXTURE_2D, GL_LINEAR);
1232 // imgwidth /= m_sourceWidth;
1233 // imgheight /= m_sourceHeight;
1235 // glBegin(GL_QUADS);
1237 // glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f , 0.0f);
1238 // glVertex4f(m_destRect.x1, m_destRect.y1, 0, 1.0f );
1240 // glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, 0.0f);
1241 // glVertex4f(m_destRect.x2, m_destRect.y1, 0, 1.0f);
1243 // glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, imgheight);
1244 // glVertex4f(m_destRect.x2, m_destRect.y2, 0, 1.0f);
1246 // glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f , imgheight);
1247 // glVertex4f(m_destRect.x1, m_destRect.y2, 0, 1.0f);
1253 if (m_pVideoFilterShader)
1254 m_pVideoFilterShader->Disable();
1258 glDisable(m_textureTarget);
1262 void CLinuxRendererGLES::RenderSoftware(int index, int field)
1264 YUVPLANES &planes = m_buffers[index].fields[field];
1266 glDisable(GL_DEPTH_TEST);
1269 glEnable(m_textureTarget);
1270 glActiveTexture(GL_TEXTURE0);
1271 glBindTexture(m_textureTarget, planes[0].id);
1273 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1275 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1278 GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1280 GLint posLoc = g_Windowing.GUIShaderGetPos();
1281 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1282 GLint colLoc = g_Windowing.GUIShaderGetCol();
1284 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1285 glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1286 glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1288 glEnableVertexAttribArray(posLoc);
1289 glEnableVertexAttribArray(texLoc);
1290 glEnableVertexAttribArray(colLoc);
1292 // Set vertex coordinates
1293 for(int i = 0; i < 4; i++)
1295 ver[i][0] = m_rotatedDestCoords[i].x;
1296 ver[i][1] = m_rotatedDestCoords[i].y;
1297 ver[i][2] = 0.0f;// set z to 0
1301 // Set texture coordinates
1302 tex[0][0] = tex[3][0] = planes[0].rect.x1;
1303 tex[0][1] = tex[1][1] = planes[0].rect.y1;
1304 tex[1][0] = tex[2][0] = planes[0].rect.x2;
1305 tex[2][1] = tex[3][1] = planes[0].rect.y2;
1307 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1309 glDisableVertexAttribArray(posLoc);
1310 glDisableVertexAttribArray(texLoc);
1311 glDisableVertexAttribArray(colLoc);
1313 g_Windowing.DisableGUIShader();
1317 glDisable(m_textureTarget);
1321 void CLinuxRendererGLES::RenderOpenMax(int index, int field)
1323 #if defined(HAVE_LIBOPENMAX)
1324 GLuint textureId = m_buffers[index].openMaxBuffer->texture_id;
1326 glDisable(GL_DEPTH_TEST);
1329 glEnable(m_textureTarget);
1330 glActiveTexture(GL_TEXTURE0);
1331 glBindTexture(m_textureTarget, textureId);
1333 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1335 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1338 GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1340 GLint posLoc = g_Windowing.GUIShaderGetPos();
1341 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1342 GLint colLoc = g_Windowing.GUIShaderGetCol();
1344 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1345 glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1346 glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1348 glEnableVertexAttribArray(posLoc);
1349 glEnableVertexAttribArray(texLoc);
1350 glEnableVertexAttribArray(colLoc);
1352 // Set vertex coordinates
1353 for(int i = 0; i < 4; i++)
1355 ver[i][0] = m_rotatedDestCoords[i].x;
1356 ver[i][1] = m_rotatedDestCoords[i].y;
1357 ver[i][2] = 0.0f;// set z to 0
1361 // Set texture coordinates
1362 tex[0][0] = tex[3][0] = 0;
1363 tex[0][1] = tex[1][1] = 0;
1364 tex[1][0] = tex[2][0] = 1;
1365 tex[2][1] = tex[3][1] = 1;
1367 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1369 glDisableVertexAttribArray(posLoc);
1370 glDisableVertexAttribArray(texLoc);
1371 glDisableVertexAttribArray(colLoc);
1373 g_Windowing.DisableGUIShader();
1377 glDisable(m_textureTarget);
1382 void CLinuxRendererGLES::RenderEglImage(int index, int field)
1384 #if defined(HAS_LIBSTAGEFRIGHT)
1385 #ifdef DEBUG_VERBOSE
1386 unsigned int time = XbmcThreads::SystemClockMillis();
1389 YUVPLANE &plane = m_buffers[index].fields[field][0];
1391 glDisable(GL_DEPTH_TEST);
1393 glActiveTexture(GL_TEXTURE0);
1394 glBindTexture(m_textureTarget, plane.id);
1396 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1398 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1401 GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1403 GLint posLoc = g_Windowing.GUIShaderGetPos();
1404 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1405 GLint colLoc = g_Windowing.GUIShaderGetCol();
1407 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1408 glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1409 glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1411 glEnableVertexAttribArray(posLoc);
1412 glEnableVertexAttribArray(texLoc);
1413 glEnableVertexAttribArray(colLoc);
1415 // Set vertex coordinates
1416 for(int i = 0; i < 4; i++)
1418 ver[i][0] = m_rotatedDestCoords[i].x;
1419 ver[i][1] = m_rotatedDestCoords[i].y;
1420 ver[i][2] = 0.0f;// set z to 0
1424 // Set texture coordinates (is flipped in y)
1425 tex[0][0] = tex[3][0] = plane.rect.x1;
1426 tex[0][1] = tex[1][1] = plane.rect.y2;
1427 tex[1][0] = tex[2][0] = plane.rect.x2;
1428 tex[2][1] = tex[3][1] = plane.rect.y1;
1430 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1432 glDisableVertexAttribArray(posLoc);
1433 glDisableVertexAttribArray(texLoc);
1434 glDisableVertexAttribArray(colLoc);
1436 g_Windowing.DisableGUIShader();
1439 glBindTexture(m_textureTarget, 0);
1442 #ifdef DEBUG_VERBOSE
1443 CLog::Log(LOGDEBUG, "RenderEglImage %d: tm:%d\n", index, XbmcThreads::SystemClockMillis() - time);
1448 void CLinuxRendererGLES::RenderSurfaceTexture(int index, int field)
1450 #if defined(TARGET_ANDROID)
1451 #ifdef DEBUG_VERBOSE
1452 unsigned int time = XbmcThreads::SystemClockMillis();
1455 YUVPLANE &plane = m_buffers[index].fields[0][0];
1457 glDisable(GL_DEPTH_TEST);
1459 glActiveTexture(GL_TEXTURE0);
1460 glBindTexture(GL_TEXTURE_EXTERNAL_OES, plane.id);
1462 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA_OES);
1464 glUniformMatrix4fv(g_Windowing.GUIShaderGetCoord0Matrix(), 1, GL_FALSE, m_textureMatrix);
1466 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1470 GLint posLoc = g_Windowing.GUIShaderGetPos();
1471 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1474 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1475 glVertexAttribPointer(texLoc, 4, GL_FLOAT, 0, 0, tex);
1477 glEnableVertexAttribArray(posLoc);
1478 glEnableVertexAttribArray(texLoc);
1480 // Set vertex coordinates
1481 for(int i = 0; i < 4; i++)
1483 ver[i][0] = m_rotatedDestCoords[i].x;
1484 ver[i][1] = m_rotatedDestCoords[i].y;
1485 ver[i][2] = 0.0f; // set z to 0
1489 // Set texture coordinates (MediaCodec is flipped in y)
1490 tex[0][0] = tex[3][0] = plane.rect.x1;
1491 tex[0][1] = tex[1][1] = plane.rect.y2;
1492 tex[1][0] = tex[2][0] = plane.rect.x2;
1493 tex[2][1] = tex[3][1] = plane.rect.y1;
1495 for(int i = 0; i < 4; i++)
1501 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1503 glDisableVertexAttribArray(posLoc);
1504 glDisableVertexAttribArray(texLoc);
1506 const float identity[16] = {
1507 1.0f, 0.0f, 0.0f, 0.0f,
1508 0.0f, 1.0f, 0.0f, 0.0f,
1509 0.0f, 0.0f, 1.0f, 0.0f,
1510 0.0f, 0.0f, 0.0f, 1.0f
1512 glUniformMatrix4fv(g_Windowing.GUIShaderGetCoord0Matrix(), 1, GL_FALSE, identity);
1514 g_Windowing.DisableGUIShader();
1517 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
1520 #ifdef DEBUG_VERBOSE
1521 CLog::Log(LOGDEBUG, "RenderMediaCodecImage %d: tm:%d", index, XbmcThreads::SystemClockMillis() - time);
1526 void CLinuxRendererGLES::RenderCoreVideoRef(int index, int field)
1528 #ifdef HAVE_VIDEOTOOLBOXDECODER
1529 YUVPLANE &plane = m_buffers[index].fields[field][0];
1531 glDisable(GL_DEPTH_TEST);
1533 glEnable(m_textureTarget);
1534 glActiveTexture(GL_TEXTURE0);
1535 glBindTexture(m_textureTarget, plane.id);
1537 g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1539 GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
1542 GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1544 GLint posLoc = g_Windowing.GUIShaderGetPos();
1545 GLint texLoc = g_Windowing.GUIShaderGetCoord0();
1546 GLint colLoc = g_Windowing.GUIShaderGetCol();
1548 glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1549 glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1550 glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1552 glEnableVertexAttribArray(posLoc);
1553 glEnableVertexAttribArray(texLoc);
1554 glEnableVertexAttribArray(colLoc);
1556 // Set vertex coordinates
1557 for(int i = 0; i < 4; i++)
1559 ver[i][0] = m_rotatedDestCoords[i].x;
1560 ver[i][1] = m_rotatedDestCoords[i].y;
1561 ver[i][2] = 0.0f;// set z to 0
1565 // Set texture coordinates (corevideo is flipped in y)
1566 tex[0][0] = tex[3][0] = plane.rect.x1;
1567 tex[0][1] = tex[1][1] = plane.rect.y2;
1568 tex[1][0] = tex[2][0] = plane.rect.x2;
1569 tex[2][1] = tex[3][1] = plane.rect.y1;
1571 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1573 glDisableVertexAttribArray(posLoc);
1574 glDisableVertexAttribArray(texLoc);
1575 glDisableVertexAttribArray(colLoc);
1577 g_Windowing.DisableGUIShader();
1580 glDisable(m_textureTarget);
1585 bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture)
1590 // If rendered directly by the hardware
1591 if (m_renderMethod & RENDER_BYPASS)
1593 capture->BeginRender();
1594 capture->EndRender();
1598 // save current video rect
1599 CRect saveSize = m_destRect;
1600 saveRotatedCoords();//backup current m_rotatedDestCoords
1602 // new video rect is thumbnail size
1603 m_destRect.SetRect(0, 0, (float)capture->GetWidth(), (float)capture->GetHeight());
1605 syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords
1606 // clear framebuffer and invert Y axis to get non-inverted image
1607 glDisable(GL_BLEND);
1609 g_matrices.MatrixMode(MM_MODELVIEW);
1610 g_matrices.PushMatrix();
1611 // fixme - we know that cvref & eglimg are already flipped in y direction
1612 // but somehow this also effects the rendercapture here
1613 // therefore we have to skip the flip here or we get upside down
1615 if (m_renderMethod != RENDER_CVREF)
1617 g_matrices.Translatef(0.0f, capture->GetHeight(), 0.0f);
1618 g_matrices.Scalef(1.0f, -1.0f, 1.0f);
1621 capture->BeginRender();
1623 Render(RENDER_FLAG_NOOSD, m_iYV12RenderBuffer);
1625 glReadPixels(0, g_graphicsContext.GetHeight() - capture->GetHeight(), capture->GetWidth(), capture->GetHeight(),
1626 GL_RGBA, GL_UNSIGNED_BYTE, capture->GetRenderBuffer());
1628 // OpenGLES returns in RGBA order but CRenderCapture needs BGRA order
1629 // XOR Swap RGBA -> BGRA
1630 unsigned char* pixels = (unsigned char*)capture->GetRenderBuffer();
1631 for (unsigned int i = 0; i < capture->GetWidth() * capture->GetHeight(); i++, pixels+=4)
1633 std::swap(pixels[0], pixels[2]);
1636 capture->EndRender();
1638 // revert model view matrix
1639 g_matrices.MatrixMode(MM_MODELVIEW);
1640 g_matrices.PopMatrix();
1642 // restore original video rect
1643 m_destRect = saveSize;
1644 restoreRotatedCoords();//restores the previous state of the rotated dest coords
1649 //********************************************************************************************************
1650 // YV12 Texture creation, deletion, copying + clearing
1651 //********************************************************************************************************
1652 void CLinuxRendererGLES::UploadYV12Texture(int source)
1654 YUVBUFFER& buf = m_buffers[source];
1655 YV12Image* im = &buf.image;
1656 YUVFIELDS& fields = buf.fields;
1659 #if defined(HAVE_LIBOPENMAX)
1660 if (!(im->flags&IMAGE_FLAG_READY) || m_buffers[source].openMaxBuffer)
1662 if (!(im->flags&IMAGE_FLAG_READY))
1668 // if we don't have a shader, fallback to SW YUV2RGB for now
1669 if (m_renderMethod & RENDER_SW)
1671 if(m_rgbBufferSize < m_sourceWidth * m_sourceHeight * 4)
1673 delete [] m_rgbBuffer;
1674 m_rgbBufferSize = m_sourceWidth*m_sourceHeight*4;
1675 m_rgbBuffer = new BYTE[m_rgbBufferSize];
1678 #if defined(__ARM_NEON__)
1679 if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON)
1681 yuv420_2_rgb8888_neon(m_rgbBuffer, im->plane[0], im->plane[2], im->plane[1],
1682 m_sourceWidth, m_sourceHeight, im->stride[0], im->stride[1], m_sourceWidth * 4);
1687 m_sw_context = m_dllSwScale->sws_getCachedContext(m_sw_context,
1688 im->width, im->height, PIX_FMT_YUV420P,
1689 im->width, im->height, PIX_FMT_RGBA,
1690 SWS_FAST_BILINEAR, NULL, NULL, NULL);
1692 uint8_t *src[] = { im->plane[0], im->plane[1], im->plane[2], 0 };
1693 int srcStride[] = { im->stride[0], im->stride[1], im->stride[2], 0 };
1694 uint8_t *dst[] = { m_rgbBuffer, 0, 0, 0 };
1695 int dstStride[] = { m_sourceWidth*4, 0, 0, 0 };
1696 m_dllSwScale->sws_scale(m_sw_context, src, srcStride, 0, im->height, dst, dstStride);
1701 if (m_currentField == FIELD_FULL)
1702 deinterlacing = false;
1704 deinterlacing = true;
1706 glEnable(m_textureTarget);
1709 if (m_renderMethod & RENDER_SW)
1714 LoadPlane( fields[FIELD_TOP][0] , GL_RGBA, buf.flipindex
1715 , im->width, im->height >> 1
1716 , m_sourceWidth*8, im->bpp, m_rgbBuffer );
1718 LoadPlane( fields[FIELD_BOT][0], GL_RGBA, buf.flipindex
1719 , im->width, im->height >> 1
1720 , m_sourceWidth*8, im->bpp, m_rgbBuffer + m_sourceWidth*4);
1724 LoadPlane( fields[FIELD_FULL][0], GL_RGBA, buf.flipindex
1725 , im->width, im->height
1726 , m_sourceWidth*4, im->bpp, m_rgbBuffer );
1731 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1735 // Load Even Y Field
1736 LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex
1737 , im->width, im->height >> 1
1738 , im->stride[0]*2, im->bpp, im->plane[0] );
1740 // Load Odd Y fields
1741 LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex
1742 , im->width, im->height >> 1
1743 , im->stride[0]*2, im->bpp, im->plane[0] + im->stride[0]) ;
1745 // Load Even U & V Fields
1746 LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE, buf.flipindex
1747 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1748 , im->stride[1]*2, im->bpp, im->plane[1] );
1750 LoadPlane( fields[FIELD_TOP][2], GL_ALPHA, buf.flipindex
1751 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1752 , im->stride[2]*2, im->bpp, im->plane[2] );
1754 // Load Odd U & V Fields
1755 LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE, buf.flipindex
1756 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1757 , im->stride[1]*2, im->bpp, im->plane[1] + im->stride[1] );
1759 LoadPlane( fields[FIELD_BOT][2], GL_ALPHA, buf.flipindex
1760 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1761 , im->stride[2]*2, im->bpp, im->plane[2] + im->stride[2] );
1766 LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
1767 , im->width, im->height
1768 , im->stride[0], im->bpp, im->plane[0] );
1771 LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, buf.flipindex
1772 , im->width >> im->cshift_x, im->height >> im->cshift_y
1773 , im->stride[1], im->bpp, im->plane[1] );
1776 LoadPlane( fields[FIELD_FULL][2], GL_ALPHA, buf.flipindex
1777 , im->width >> im->cshift_x, im->height >> im->cshift_y
1778 , im->stride[2], im->bpp, im->plane[2] );
1784 CalculateTextureSourceRects(source, 3);
1786 glDisable(m_textureTarget);
1789 void CLinuxRendererGLES::DeleteYV12Texture(int index)
1791 YV12Image &im = m_buffers[index].image;
1792 YUVFIELDS &fields = m_buffers[index].fields;
1794 if( fields[FIELD_FULL][0].id == 0 ) return;
1796 /* finish up all textures, and delete them */
1797 g_graphicsContext.BeginPaint(); //FIXME
1798 for(int f = 0;f<MAX_FIELDS;f++)
1800 for(int p = 0;p<MAX_PLANES;p++)
1802 if( fields[f][p].id )
1804 if (glIsTexture(fields[f][p].id))
1805 glDeleteTextures(1, &fields[f][p].id);
1806 fields[f][p].id = 0;
1810 g_graphicsContext.EndPaint();
1812 for(int p = 0;p<MAX_PLANES;p++)
1816 delete[] im.plane[p];
1822 static GLint GetInternalFormat(GLint format, int bpp)
1829 case GL_ALPHA: return GL_ALPHA16;
1831 #ifdef GL_LUMINANCE16
1832 case GL_LUMINANCE: return GL_LUMINANCE16;
1834 default: return format;
1841 bool CLinuxRendererGLES::CreateYV12Texture(int index)
1843 /* since we also want the field textures, pitch must be texture aligned */
1844 YV12Image &im = m_buffers[index].image;
1845 YUVFIELDS &fields = m_buffers[index].fields;
1847 DeleteYV12Texture(index);
1849 im.height = m_sourceHeight;
1850 im.width = m_sourceWidth;
1855 if(m_format == RENDER_FMT_YUV420P16
1856 || m_format == RENDER_FMT_YUV420P10)
1861 im.stride[0] = im.bpp * im.width;
1862 im.stride[1] = im.bpp * ( im.width >> im.cshift_x );
1863 im.stride[2] = im.bpp * ( im.width >> im.cshift_x );
1865 im.planesize[0] = im.stride[0] * im.height;
1866 im.planesize[1] = im.stride[1] * ( im.height >> im.cshift_y );
1867 im.planesize[2] = im.stride[2] * ( im.height >> im.cshift_y );
1869 for (int i = 0; i < 3; i++)
1870 im.plane[i] = new BYTE[im.planesize[i]];
1872 glEnable(m_textureTarget);
1873 for(int f = 0;f<MAX_FIELDS;f++)
1875 for(int p = 0;p<MAX_PLANES;p++)
1877 if (!glIsTexture(fields[f][p].id))
1879 glGenTextures(1, &fields[f][p].id);
1886 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
1888 int fieldshift = (f==FIELD_FULL) ? 0 : 1;
1889 YUVPLANES &planes = fields[f];
1891 planes[0].texwidth = im.width;
1892 planes[0].texheight = im.height >> fieldshift;
1894 if (m_renderMethod & RENDER_SW)
1896 planes[1].texwidth = 0;
1897 planes[1].texheight = 0;
1898 planes[2].texwidth = 0;
1899 planes[2].texheight = 0;
1903 planes[1].texwidth = planes[0].texwidth >> im.cshift_x;
1904 planes[1].texheight = planes[0].texheight >> im.cshift_y;
1905 planes[2].texwidth = planes[0].texwidth >> im.cshift_x;
1906 planes[2].texheight = planes[0].texheight >> im.cshift_y;
1909 for (int p = 0; p < 3; p++)
1911 planes[p].pixpertex_x = 1;
1912 planes[p].pixpertex_y = 1;
1915 if(m_renderMethod & RENDER_POT)
1917 for(int p = 0; p < 3; p++)
1919 planes[p].texwidth = NP2(planes[p].texwidth);
1920 planes[p].texheight = NP2(planes[p].texheight);
1924 for(int p = 0; p < 3; p++)
1926 YUVPLANE &plane = planes[p];
1927 if (plane.texwidth * plane.texheight == 0)
1930 glBindTexture(m_textureTarget, plane.id);
1931 if (m_renderMethod & RENDER_SW)
1933 if(m_renderMethod & RENDER_POT)
1934 CLog::Log(LOGDEBUG, "GL: Creating RGB POT texture of size %d x %d", plane.texwidth, plane.texheight);
1936 CLog::Log(LOGDEBUG, "GL: Creating RGB NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
1938 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1939 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1944 GLint internalformat;
1945 if (p == 2) //V plane needs an alpha texture
1948 format = GL_LUMINANCE;
1949 internalformat = GetInternalFormat(format, im.bpp);
1951 if(m_renderMethod & RENDER_POT)
1952 CLog::Log(LOGDEBUG, "GL: Creating YUV POT texture of size %d x %d", plane.texwidth, plane.texheight);
1954 CLog::Log(LOGDEBUG, "GL: Creating YUV NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
1956 glTexImage2D(m_textureTarget, 0, internalformat, plane.texwidth, plane.texheight, 0, format, GL_UNSIGNED_BYTE, NULL);
1959 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1960 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1961 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1962 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1966 glDisable(m_textureTarget);
1970 //********************************************************************************************************
1971 // NV12 Texture loading, creation and deletion
1972 //********************************************************************************************************
1973 void CLinuxRendererGLES::UploadNV12Texture(int source)
1975 YUVBUFFER& buf = m_buffers[source];
1976 YV12Image* im = &buf.image;
1977 YUVFIELDS& fields = buf.fields;
1979 if (!(im->flags & IMAGE_FLAG_READY))
1982 if (m_currentField == FIELD_FULL)
1983 deinterlacing = false;
1985 deinterlacing = true;
1987 glEnable(m_textureTarget);
1990 glPixelStorei(GL_UNPACK_ALIGNMENT, im->bpp);
1995 LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex
1996 , im->width, im->height >> 1
1997 , im->stride[0]*2, im->bpp, im->plane[0] );
1999 // Load Even Y field
2000 LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex
2001 , im->width, im->height >> 1
2002 , im->stride[0]*2, im->bpp, im->plane[0] + im->stride[0]) ;
2004 // Load Odd UV Fields
2005 LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE_ALPHA, buf.flipindex
2006 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
2007 , im->stride[1]*2, im->bpp, im->plane[1] );
2009 // Load Even UV Fields
2010 LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE_ALPHA, buf.flipindex
2011 , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
2012 , im->stride[1]*2, im->bpp, im->plane[1] + im->stride[1] );
2018 LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
2019 , im->width, im->height
2020 , im->stride[0], im->bpp, im->plane[0] );
2023 LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE_ALPHA, buf.flipindex
2024 , im->width >> im->cshift_x, im->height >> im->cshift_y
2025 , im->stride[1], im->bpp, im->plane[1] );
2030 CalculateTextureSourceRects(source, 3);
2032 glDisable(m_textureTarget);
2036 bool CLinuxRendererGLES::CreateNV12Texture(int index)
2038 // since we also want the field textures, pitch must be texture aligned
2039 YV12Image &im = m_buffers[index].image;
2040 YUVFIELDS &fields = m_buffers[index].fields;
2042 // Delete any old texture
2043 DeleteNV12Texture(index);
2045 im.height = m_sourceHeight;
2046 im.width = m_sourceWidth;
2051 im.stride[0] = im.width;
2052 im.stride[1] = im.width;
2060 im.planesize[0] = im.stride[0] * im.height;
2062 im.planesize[1] = im.stride[1] * im.height / 2;
2063 // third plane is not used
2064 im.planesize[2] = 0;
2066 for (int i = 0; i < 2; i++)
2067 im.plane[i] = new BYTE[im.planesize[i]];
2069 glEnable(m_textureTarget);
2070 for(int f = 0;f<MAX_FIELDS;f++)
2072 for(int p = 0;p<2;p++)
2074 if (!glIsTexture(fields[f][p].id))
2076 glGenTextures(1, &fields[f][p].id);
2080 fields[f][2].id = fields[f][1].id;
2084 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
2086 int fieldshift = (f==FIELD_FULL) ? 0 : 1;
2087 YUVPLANES &planes = fields[f];
2089 planes[0].texwidth = im.width;
2090 planes[0].texheight = im.height >> fieldshift;
2092 if (m_renderMethod & RENDER_SW)
2094 planes[1].texwidth = 0;
2095 planes[1].texheight = 0;
2096 planes[2].texwidth = 0;
2097 planes[2].texheight = 0;
2101 planes[1].texwidth = planes[0].texwidth >> im.cshift_x;
2102 planes[1].texheight = planes[0].texheight >> im.cshift_y;
2103 planes[2].texwidth = planes[1].texwidth;
2104 planes[2].texheight = planes[1].texheight;
2107 for (int p = 0; p < 3; p++)
2109 planes[p].pixpertex_x = 1;
2110 planes[p].pixpertex_y = 1;
2113 if(m_renderMethod & RENDER_POT)
2115 for(int p = 0; p < 3; p++)
2117 planes[p].texwidth = NP2(planes[p].texwidth);
2118 planes[p].texheight = NP2(planes[p].texheight);
2122 for(int p = 0; p < 2; p++)
2124 YUVPLANE &plane = planes[p];
2125 if (plane.texwidth * plane.texheight == 0)
2128 glBindTexture(m_textureTarget, plane.id);
2129 if (m_renderMethod & RENDER_SW)
2131 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2136 glTexImage2D(m_textureTarget, 0, GL_LUMINANCE_ALPHA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
2138 glTexImage2D(m_textureTarget, 0, GL_LUMINANCE, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
2141 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2142 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2143 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2144 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2148 glDisable(m_textureTarget);
2152 void CLinuxRendererGLES::DeleteNV12Texture(int index)
2154 YV12Image &im = m_buffers[index].image;
2155 YUVFIELDS &fields = m_buffers[index].fields;
2157 if( fields[FIELD_FULL][0].id == 0 ) return;
2159 // finish up all textures, and delete them
2160 g_graphicsContext.BeginPaint(); //FIXME
2161 for(int f = 0;f<MAX_FIELDS;f++)
2163 for(int p = 0;p<2;p++)
2165 if( fields[f][p].id )
2167 if (glIsTexture(fields[f][p].id))
2169 glDeleteTextures(1, &fields[f][p].id);
2171 fields[f][p].id = 0;
2174 fields[f][2].id = 0;
2176 g_graphicsContext.EndPaint();
2178 for(int p = 0;p<2;p++)
2182 delete[] im.plane[p];
2188 //********************************************************************************************************
2189 // CoreVideoRef Texture creation, deletion, copying + clearing
2190 //********************************************************************************************************
2191 void CLinuxRendererGLES::UploadCVRefTexture(int index)
2193 #ifdef HAVE_VIDEOTOOLBOXDECODER
2194 CVBufferRef cvBufferRef = m_buffers[index].cvBufferRef;
2198 YUVPLANE &plane = m_buffers[index].fields[0][0];
2200 CVPixelBufferLockBaseAddress(cvBufferRef, kCVPixelBufferLock_ReadOnly);
2201 #if !TARGET_OS_IPHONE
2202 int rowbytes = CVPixelBufferGetBytesPerRow(cvBufferRef);
2204 int bufferWidth = CVPixelBufferGetWidth(cvBufferRef);
2205 int bufferHeight = CVPixelBufferGetHeight(cvBufferRef);
2206 unsigned char *bufferBase = (unsigned char *)CVPixelBufferGetBaseAddress(cvBufferRef);
2208 glEnable(m_textureTarget);
2211 glBindTexture(m_textureTarget, plane.id);
2212 #if !TARGET_OS_IPHONE
2213 #ifdef GL_UNPACK_ROW_LENGTH
2215 glPixelStorei( GL_UNPACK_ROW_LENGTH, rowbytes);
2217 #ifdef GL_TEXTURE_STORAGE_HINT_APPLE
2218 // Set storage hint. Can also use GL_STORAGE_SHARED_APPLE see docs.
2219 glTexParameteri(m_textureTarget, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
2223 // Using BGRA extension to pull in video frame data directly
2224 glTexSubImage2D(m_textureTarget, 0, 0, 0, bufferWidth, bufferHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bufferBase);
2226 #if !TARGET_OS_IPHONE
2227 #ifdef GL_UNPACK_ROW_LENGTH
2229 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0);
2232 glBindTexture(m_textureTarget, 0);
2234 glDisable(m_textureTarget);
2237 CVPixelBufferUnlockBaseAddress(cvBufferRef, kCVPixelBufferLock_ReadOnly);
2238 CVBufferRelease(m_buffers[index].cvBufferRef);
2239 m_buffers[index].cvBufferRef = NULL;
2241 plane.flipindex = m_buffers[index].flipindex;
2244 CalculateTextureSourceRects(index, 1);
2247 void CLinuxRendererGLES::DeleteCVRefTexture(int index)
2249 #ifdef HAVE_VIDEOTOOLBOXDECODER
2250 YUVPLANE &plane = m_buffers[index].fields[0][0];
2252 if (m_buffers[index].cvBufferRef)
2253 CVBufferRelease(m_buffers[index].cvBufferRef);
2254 m_buffers[index].cvBufferRef = NULL;
2256 if(plane.id && glIsTexture(plane.id))
2257 glDeleteTextures(1, &plane.id);
2261 bool CLinuxRendererGLES::CreateCVRefTexture(int index)
2263 #ifdef HAVE_VIDEOTOOLBOXDECODER
2264 YV12Image &im = m_buffers[index].image;
2265 YUVFIELDS &fields = m_buffers[index].fields;
2266 YUVPLANE &plane = fields[0][0];
2268 DeleteCVRefTexture(index);
2270 memset(&im , 0, sizeof(im));
2271 memset(&fields, 0, sizeof(fields));
2273 im.height = m_sourceHeight;
2274 im.width = m_sourceWidth;
2276 plane.texwidth = im.width;
2277 plane.texheight = im.height;
2278 plane.pixpertex_x = 1;
2279 plane.pixpertex_y = 1;
2281 if(m_renderMethod & RENDER_POT)
2283 plane.texwidth = NP2(plane.texwidth);
2284 plane.texheight = NP2(plane.texheight);
2286 glEnable(m_textureTarget);
2287 glGenTextures(1, &plane.id);
2290 glBindTexture(m_textureTarget, plane.id);
2291 #if !TARGET_OS_IPHONE
2292 #ifdef GL_UNPACK_ROW_LENGTH
2294 glPixelStorei(GL_UNPACK_ROW_LENGTH, m_sourceWidth);
2296 #ifdef GL_TEXTURE_STORAGE_HINT_APPLE
2297 // Set storage hint. Can also use GL_STORAGE_SHARED_APPLE see docs.
2298 glTexParameteri(m_textureTarget, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
2299 // Set client storage
2301 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2304 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2305 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2306 // This is necessary for non-power-of-two textures
2307 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2308 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2309 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
2310 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
2312 #if !TARGET_OS_IPHONE
2313 // turn off client storage so it doesn't get picked up for the next texture
2314 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2316 glBindTexture(m_textureTarget, 0);
2317 glDisable(m_textureTarget);
2322 //********************************************************************************************************
2323 // BYPASS creation, deletion, copying + clearing
2324 //********************************************************************************************************
2325 void CLinuxRendererGLES::UploadBYPASSTexture(int index)
2328 void CLinuxRendererGLES::DeleteBYPASSTexture(int index)
2331 bool CLinuxRendererGLES::CreateBYPASSTexture(int index)
2336 //********************************************************************************************************
2337 // EGLIMG creation, deletion, copying + clearing
2338 //********************************************************************************************************
2339 void CLinuxRendererGLES::UploadEGLIMGTexture(int index)
2341 #ifdef HAS_LIBSTAGEFRIGHT
2342 #ifdef DEBUG_VERBOSE
2343 unsigned int time = XbmcThreads::SystemClockMillis();
2346 if(m_buffers[index].eglimg != EGL_NO_IMAGE_KHR)
2348 YUVPLANE &plane = m_buffers[index].fields[0][0];
2350 glActiveTexture(GL_TEXTURE0);
2351 glBindTexture(m_textureTarget, plane.id);
2352 glEGLImageTargetTexture2DOES(m_textureTarget, (EGLImageKHR)m_buffers[index].eglimg);
2353 glBindTexture(m_textureTarget, 0);
2355 plane.flipindex = m_buffers[index].flipindex;
2358 CalculateTextureSourceRects(index, 1);
2360 #ifdef DEBUG_VERBOSE
2361 CLog::Log(LOGDEBUG, "UploadEGLIMGTexture %d: img:%p, tm:%d\n", index, m_buffers[index].eglimg, XbmcThreads::SystemClockMillis() - time);
2365 void CLinuxRendererGLES::DeleteEGLIMGTexture(int index)
2367 #ifdef HAS_LIBSTAGEFRIGHT
2368 YUVBUFFER &buf = m_buffers[index];
2369 YUVPLANE &plane = buf.fields[0][0];
2371 if(plane.id && glIsTexture(plane.id))
2372 glDeleteTextures(1, &plane.id);
2376 buf.eglimg = EGL_NO_IMAGE_KHR;
2379 bool CLinuxRendererGLES::CreateEGLIMGTexture(int index)
2381 #ifdef HAS_LIBSTAGEFRIGHT
2382 YV12Image &im = m_buffers[index].image;
2383 YUVFIELDS &fields = m_buffers[index].fields;
2384 YUVPLANE &plane = fields[0][0];
2386 DeleteEGLIMGTexture(index);
2388 memset(&im , 0, sizeof(im));
2389 memset(&fields, 0, sizeof(fields));
2391 im.height = m_sourceHeight;
2392 im.width = m_sourceWidth;
2394 plane.texwidth = im.width;
2395 plane.texheight = im.height;
2396 plane.pixpertex_x = 1;
2397 plane.pixpertex_y = 1;
2399 if(m_renderMethod & RENDER_POT)
2401 plane.texwidth = NP2(plane.texwidth);
2402 plane.texheight = NP2(plane.texheight);
2404 glEnable(m_textureTarget);
2405 glGenTextures(1, &plane.id);
2408 glBindTexture(m_textureTarget, plane.id);
2410 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2411 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2412 // This is necessary for non-power-of-two textures
2413 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2414 glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2416 glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2418 glDisable(m_textureTarget);
2423 //********************************************************************************************************
2424 // SurfaceTexture creation, deletion, copying + clearing
2425 //********************************************************************************************************
2426 void CLinuxRendererGLES::UploadSurfaceTexture(int index)
2428 #if defined(TARGET_ANDROID)
2429 #ifdef DEBUG_VERBOSE
2430 unsigned int time = XbmcThreads::SystemClockMillis();
2434 YUVBUFFER &buf = m_buffers[index];
2438 #ifdef DEBUG_VERBOSE
2439 mindex = buf.mediacodec->GetIndex();
2441 buf.fields[0][0].id = buf.mediacodec->GetTextureID();
2442 buf.mediacodec->UpdateTexImage();
2443 buf.mediacodec->GetTransformMatrix(m_textureMatrix);
2444 SAFE_RELEASE(buf.mediacodec);
2447 CalculateTextureSourceRects(index, 1);
2449 #ifdef DEBUG_VERBOSE
2450 CLog::Log(LOGDEBUG, "UploadSurfaceTexture %d: img: %d tm:%d", index, mindex, XbmcThreads::SystemClockMillis() - time);
2454 void CLinuxRendererGLES::DeleteSurfaceTexture(int index)
2456 #if defined(TARGET_ANDROID)
2457 SAFE_RELEASE(m_buffers[index].mediacodec);
2460 bool CLinuxRendererGLES::CreateSurfaceTexture(int index)
2462 YV12Image &im = m_buffers[index].image;
2463 YUVFIELDS &fields = m_buffers[index].fields;
2464 YUVPLANE &plane = fields[0][0];
2466 memset(&im , 0, sizeof(im));
2467 memset(&fields, 0, sizeof(fields));
2469 im.height = m_sourceHeight;
2470 im.width = m_sourceWidth;
2472 plane.texwidth = im.width;
2473 plane.texheight = im.height;
2474 plane.pixpertex_x = 1;
2475 plane.pixpertex_y = 1;
2477 if(m_renderMethod & RENDER_POT)
2479 plane.texwidth = NP2(plane.texwidth);
2480 plane.texheight = NP2(plane.texheight);
2486 void CLinuxRendererGLES::SetTextureFilter(GLenum method)
2488 for (int i = 0 ; i<m_NumYV12Buffers ; i++)
2490 YUVFIELDS &fields = m_buffers[i].fields;
2492 for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
2494 glBindTexture(m_textureTarget, fields[f][0].id);
2495 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2496 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2499 if (!(m_renderMethod & RENDER_SW))
2501 glBindTexture(m_textureTarget, fields[f][1].id);
2502 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2503 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2506 glBindTexture(m_textureTarget, fields[f][2].id);
2507 glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2508 glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2515 bool CLinuxRendererGLES::Supports(ERENDERFEATURE feature)
2517 // Player controls render, let it dictate available render features
2518 if((m_renderMethod & RENDER_BYPASS))
2520 Features::iterator itr = std::find(m_renderFeatures.begin(),m_renderFeatures.end(), feature);
2521 return itr != m_renderFeatures.end();
2524 if(feature == RENDERFEATURE_BRIGHTNESS)
2527 if(feature == RENDERFEATURE_CONTRAST)
2530 if(feature == RENDERFEATURE_GAMMA)
2533 if(feature == RENDERFEATURE_NOISE)
2536 if(feature == RENDERFEATURE_SHARPNESS)
2539 if (feature == RENDERFEATURE_NONLINSTRETCH)
2542 if (feature == RENDERFEATURE_STRETCH ||
2543 feature == RENDERFEATURE_CROP ||
2544 feature == RENDERFEATURE_ZOOM ||
2545 feature == RENDERFEATURE_VERTICAL_SHIFT ||
2546 feature == RENDERFEATURE_PIXEL_RATIO ||
2547 feature == RENDERFEATURE_POSTPROCESS ||
2548 feature == RENDERFEATURE_ROTATION)
2555 bool CLinuxRendererGLES::SupportsMultiPassRendering()
2560 bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode)
2562 // Player controls render, let it dictate available deinterlace modes
2563 if((m_renderMethod & RENDER_BYPASS))
2565 Features::iterator itr = std::find(m_deinterlaceModes.begin(),m_deinterlaceModes.end(), mode);
2566 return itr != m_deinterlaceModes.end();
2569 if (mode == VS_DEINTERLACEMODE_OFF)
2572 if(m_renderMethod & RENDER_OMXEGL)
2575 if(m_renderMethod & RENDER_EGLIMG)
2578 if(m_renderMethod & RENDER_CVREF)
2581 if(mode == VS_DEINTERLACEMODE_AUTO
2582 || mode == VS_DEINTERLACEMODE_FORCE)
2588 bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method)
2590 // Player controls render, let it dictate available deinterlace methods
2591 if((m_renderMethod & RENDER_BYPASS))
2593 Features::iterator itr = std::find(m_deinterlaceMethods.begin(),m_deinterlaceMethods.end(), method);
2594 return itr != m_deinterlaceMethods.end();
2597 if(m_renderMethod & RENDER_OMXEGL)
2600 if(m_renderMethod & RENDER_EGLIMG)
2603 if(m_renderMethod & RENDER_MEDIACODEC)
2606 if(m_renderMethod & RENDER_CVREF)
2609 if(method == VS_INTERLACEMETHOD_AUTO)
2612 #if defined(__i386__) || defined(__x86_64__)
2613 if(method == VS_INTERLACEMETHOD_DEINTERLACE
2614 || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF
2615 || method == VS_INTERLACEMETHOD_SW_BLEND)
2617 if(method == VS_INTERLACEMETHOD_SW_BLEND)
2624 bool CLinuxRendererGLES::Supports(ESCALINGMETHOD method)
2626 // Player controls render, let it dictate available scaling methods
2627 if((m_renderMethod & RENDER_BYPASS))
2629 Features::iterator itr = std::find(m_scalingMethods.begin(),m_scalingMethods.end(), method);
2630 return itr != m_scalingMethods.end();
2633 if(method == VS_SCALINGMETHOD_NEAREST
2634 || method == VS_SCALINGMETHOD_LINEAR)
2640 EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod()
2642 // Player controls render, let it pick the auto-deinterlace method
2643 if((m_renderMethod & RENDER_BYPASS))
2645 if (!m_deinterlaceMethods.empty())
2646 return ((EINTERLACEMETHOD)m_deinterlaceMethods[0]);
2648 return VS_INTERLACEMETHOD_NONE;
2651 if(m_renderMethod & RENDER_OMXEGL)
2652 return VS_INTERLACEMETHOD_NONE;
2654 if(m_renderMethod & RENDER_EGLIMG)
2655 return VS_INTERLACEMETHOD_NONE;
2657 if(m_renderMethod & RENDER_CVREF)
2658 return VS_INTERLACEMETHOD_NONE;
2660 #if defined(__i386__) || defined(__x86_64__)
2661 return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
2663 return VS_INTERLACEMETHOD_SW_BLEND;
2667 unsigned int CLinuxRendererGLES::GetProcessorSize()
2669 if(m_format == RENDER_FMT_OMXEGL
2670 || m_format == RENDER_FMT_CVBREF
2671 || m_format == RENDER_FMT_EGLIMG
2672 || m_format == RENDER_FMT_MEDIACODEC)
2678 #ifdef HAVE_LIBOPENMAX
2679 void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index)
2681 YUVBUFFER &buf = m_buffers[index];
2682 buf.openMaxBuffer = picture->openMaxBuffer;
2685 #ifdef HAVE_VIDEOTOOLBOXDECODER
2686 void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
2688 YUVBUFFER &buf = m_buffers[index];
2689 if (buf.cvBufferRef)
2690 CVBufferRelease(buf.cvBufferRef);
2691 buf.cvBufferRef = cvBufferRef;
2692 // retain another reference, this way dvdplayer and renderer can issue releases.
2693 CVBufferRetain(buf.cvBufferRef);
2696 #ifdef HAS_LIBSTAGEFRIGHT
2697 void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKHR eglimg, int index)
2699 #ifdef DEBUG_VERBOSE
2700 unsigned int time = XbmcThreads::SystemClockMillis();
2703 YUVBUFFER &buf = m_buffers[index];
2704 if (buf.eglimg != EGL_NO_IMAGE_KHR)
2705 stf->ReleaseBuffer(buf.eglimg);
2706 stf->LockBuffer(eglimg);
2709 buf.eglimg = eglimg;
2711 #ifdef DEBUG_VERBOSE
2712 CLog::Log(LOGDEBUG, "AddProcessor %d: img:%p: tm:%d\n", index, eglimg, XbmcThreads::SystemClockMillis() - time);
2717 #if defined(TARGET_ANDROID)
2718 void CLinuxRendererGLES::AddProcessor(CDVDMediaCodecInfo *mediacodec, int index)
2720 #ifdef DEBUG_VERBOSE
2721 unsigned int time = XbmcThreads::SystemClockMillis();
2725 YUVBUFFER &buf = m_buffers[index];
2728 buf.mediacodec = mediacodec->Retain();
2729 #ifdef DEBUG_VERBOSE
2730 mindex = buf.mediacodec->GetIndex();
2732 // releaseOutputBuffer must be in same thread as
2733 // dequeueOutputBuffer. We are in DVDPlayerVideo
2734 // thread here, so we are safe.
2735 buf.mediacodec->ReleaseOutputBuffer(true);
2738 #ifdef DEBUG_VERBOSE
2739 CLog::Log(LOGDEBUG, "AddProcessor %d: img:%d tm:%d", index, mindex, XbmcThreads::SystemClockMillis() - time);