droid:
[vuplus_xbmc] / xbmc / cores / VideoRenderers / LinuxRendererGLES.cpp
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 //#define DEBUG_VERBOSE 1
22
23 #include "system.h"
24 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
25   #include "config.h"
26 #endif
27
28 #if HAS_GLES == 2
29 #include "system_gl.h"
30
31 #include <locale.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"
54
55 #if defined(__ARM_NEON__)
56 #include "yuv2rgb.neon.h"
57 #include "utils/CPUInfo.h"
58 #endif
59 #ifdef HAVE_VIDEOTOOLBOXDECODER
60 #include "DVDCodecs/Video/DVDVideoCodecVideoToolBox.h"
61 #include <CoreVideo/CoreVideo.h>
62 #endif
63 #ifdef TARGET_DARWIN_IOS
64 #include "osx/DarwinUtils.h"
65 #endif
66 #if defined(HAS_LIBSTAGEFRIGHT)
67 #include <EGL/egl.h>
68 #include <EGL/eglext.h>
69 #include "windowing/egl/EGLWrapper.h"
70 #include "android/activity/XBMCApp.h"
71 #include "DVDCodecs/Video/StageFrightVideo.h"
72
73 // EGL extension functions
74 static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
75 static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
76 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
77 #endif
78
79 #if defined(TARGET_ANDROID)
80 #include "DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h"
81 #endif
82
83 using namespace Shaders;
84
85 CLinuxRendererGLES::YUVBUFFER::YUVBUFFER()
86 {
87   memset(&fields, 0, sizeof(fields));
88   memset(&image , 0, sizeof(image));
89   flipindex = 0;
90 #ifdef HAVE_LIBOPENMAX
91   openMaxBuffer = NULL;
92 #endif
93 #ifdef HAVE_VIDEOTOOLBOXDECODER
94   cvBufferRef = NULL;
95 #endif
96 #ifdef HAS_LIBSTAGEFRIGHT
97   stf = NULL;
98   eglimg = EGL_NO_IMAGE_KHR;
99 #endif
100 #if defined(TARGET_ANDROID)
101   mediacodec = NULL;
102 #endif
103 }
104
105 CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER()
106 {
107 }
108
109 CLinuxRendererGLES::CLinuxRendererGLES()
110 {
111   m_textureTarget = GL_TEXTURE_2D;
112
113   m_renderMethod = RENDER_GLSL;
114   m_oldRenderMethod = m_renderMethod;
115   m_renderQuality = RQ_SINGLEPASS;
116   m_iFlags = 0;
117   m_format = RENDER_FMT_NONE;
118
119   m_iYV12RenderBuffer = 0;
120   m_flipindex = 0;
121   m_currentField = FIELD_FULL;
122   m_reloadShaders = 0;
123   m_pYUVShader = NULL;
124   m_pVideoFilterShader = NULL;
125   m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
126   m_scalingMethodGui = (ESCALINGMETHOD)-1;
127
128   // default texture handlers to YUV
129   m_textureUpload = &CLinuxRendererGLES::UploadYV12Texture;
130   m_textureCreate = &CLinuxRendererGLES::CreateYV12Texture;
131   m_textureDelete = &CLinuxRendererGLES::DeleteYV12Texture;
132
133   m_rgbBuffer = NULL;
134   m_rgbBufferSize = 0;
135
136   m_dllSwScale = new DllSwScale;
137   m_sw_context = NULL;
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;
145
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");
153 #endif
154 }
155
156 CLinuxRendererGLES::~CLinuxRendererGLES()
157 {
158   UnInit();
159
160   if (m_rgbBuffer != NULL) {
161     delete [] m_rgbBuffer;
162     m_rgbBuffer = NULL;
163   }
164
165   if (m_pYUVShader)
166   {
167     m_pYUVShader->Free();
168     delete m_pYUVShader;
169     m_pYUVShader = NULL;
170   }
171
172   delete m_dllSwScale;
173 }
174
175 bool CLinuxRendererGLES::ValidateRenderTarget()
176 {
177   if (!m_bValidated)
178   {
179     CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D");
180
181     // function pointer for texture might change in
182     // call to LoadShaders
183     glFinish();
184     for (int i = 0 ; i < NUM_BUFFERS ; i++)
185       (this->*m_textureDelete)(i);
186
187      // create the yuv textures
188     LoadShaders();
189
190     for (int i = 0 ; i < m_NumYV12Buffers ; i++)
191       (this->*m_textureCreate)(i);
192
193     m_bValidated = true;
194     return true;
195   }
196   return false;
197 }
198
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)
200 {
201   m_sourceWidth = width;
202   m_sourceHeight = height;
203   m_renderOrientation = orientation;
204
205   // Save the flags.
206   m_iFlags = flags;
207   m_format = format;
208
209   // Calculate the input frame aspect ratio.
210   CalculateFrameAspectRatio(d_width, d_height);
211   ChooseBestResolution(fps);
212   SetViewMode(CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode);
213   ManageDisplay();
214
215   m_bConfigured = true;
216   m_bImageReady = false;
217   m_scalingMethodGui = (ESCALINGMETHOD)-1;
218
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;
222
223   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
224     m_buffers[i].image.flags = 0;
225
226   m_iLastRenderBuffer = -1;
227
228   m_RenderUpdateCallBackFn = NULL;
229   m_RenderUpdateCallBackCtx = NULL;
230   if ((m_format == RENDER_FMT_BYPASS) && g_application.GetCurrentPlayer())
231   {
232     m_renderFeatures.clear();
233     m_scalingMethods.clear();
234     m_deinterlaceModes.clear();
235     m_deinterlaceMethods.clear();
236
237     if (m_RenderFeaturesCallBackFn)
238     {
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;
243     }
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);
248   }
249
250   return true;
251 }
252
253 int CLinuxRendererGLES::NextYV12Texture()
254 {
255   return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
256 }
257
258 int CLinuxRendererGLES::GetImage(YV12Image *image, int source, bool readonly)
259 {
260   if (!image) return -1;
261   if (!m_bValidated) return -1;
262
263   /* take next available buffer */
264   if( source == AUTOSOURCE )
265    source = NextYV12Texture();
266
267   if ( m_renderMethod & RENDER_OMXEGL )
268   {
269     return source;
270   }
271 #ifdef HAS_LIBSTAGEFRIGHT
272   if ( m_renderMethod & RENDER_EGLIMG )
273   {
274     return source;
275   }
276
277 #endif
278   if ( m_renderMethod & RENDER_MEDIACODEC )
279   {
280     return source;
281   }
282
283 #ifdef HAVE_VIDEOTOOLBOXDECODER
284   if (m_renderMethod & RENDER_CVREF )
285   {
286     return source;
287   }
288 #endif
289
290   YV12Image &im = m_buffers[source].image;
291
292   if ((im.flags&(~IMAGE_FLAG_READY)) != 0)
293   {
294      CLog::Log(LOGDEBUG, "CLinuxRenderer::GetImage - request image but none to give");
295      return -1;
296   }
297
298   if( readonly )
299     im.flags |= IMAGE_FLAG_READING;
300   else
301     im.flags |= IMAGE_FLAG_WRITING;
302
303   // copy the image - should be operator of YV12Image
304   for (int p=0;p<MAX_PLANES;p++)
305   {
306     image->plane[p]  = im.plane[p];
307     image->stride[p] = im.stride[p];
308   }
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;
314   image->bpp      = 1;
315
316   return source;
317 }
318
319 void CLinuxRendererGLES::ReleaseImage(int source, bool preserve)
320 {
321   YV12Image &im = m_buffers[source].image;
322
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 */
326
327   if( preserve )
328     im.flags |= IMAGE_FLAG_RESERVED;
329
330   m_bImageReady = true;
331 }
332
333 void CLinuxRendererGLES::CalculateTextureSourceRects(int source, int num_planes)
334 {
335   YUVBUFFER& buf    =  m_buffers[source];
336   YV12Image* im     = &buf.image;
337   YUVFIELDS& fields =  buf.fields;
338
339   // calculate the source rectangle
340   for(int field = 0; field < 3; field++)
341   {
342     for(int plane = 0; plane < num_planes; plane++)
343     {
344       YUVPLANE& p = fields[field][plane];
345
346       p.rect = m_sourceRect;
347       p.width  = im->width;
348       p.height = im->height;
349
350       if(field != FIELD_FULL)
351       {
352         /* correct for field offsets and chroma offsets */
353         float offset_y = 0.5;
354         if(plane != 0)
355           offset_y += 0.5;
356         if(field == FIELD_BOT)
357           offset_y *= -1;
358
359         p.rect.y1 += offset_y;
360         p.rect.y2 += offset_y;
361
362         /* half the height if this is a field */
363         p.height  *= 0.5f;
364         p.rect.y1 *= 0.5f;
365         p.rect.y2 *= 0.5f;
366       }
367
368       if(plane != 0)
369       {
370         p.width   /= 1 << im->cshift_x;
371         p.height  /= 1 << im->cshift_y;
372
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;
377       }
378
379       if (m_textureTarget == GL_TEXTURE_2D)
380       {
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;
387       }
388     }
389   }
390 }
391
392 void CLinuxRendererGLES::LoadPlane( YUVPLANE& plane, int type, unsigned flipindex
393                                 , unsigned width, unsigned height
394                                 , unsigned int stride, void* data )
395 {
396   if(plane.flipindex == flipindex)
397     return;
398
399   const GLvoid *pixelData = data;
400
401   int bps = glFormatElementByteCount(type);
402
403   glBindTexture(m_textureTarget, plane.id);
404
405   // OpenGL ES does not support strided texture input.
406   if(stride != width * bps)
407   {
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);
411   } else {
412     glTexSubImage2D(m_textureTarget, 0, 0, 0, width, height, type, GL_UNSIGNED_BYTE, pixelData);
413   }
414
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));
421
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));
427
428   glBindTexture(m_textureTarget, 0);
429
430   plane.flipindex = flipindex;
431 }
432
433 void CLinuxRendererGLES::Reset()
434 {
435   for(int i=0; i<m_NumYV12Buffers; i++)
436   {
437     /* reset all image flags, this will cleanup textures later */
438     m_buffers[i].image.flags = 0;
439   }
440 }
441
442 void CLinuxRendererGLES::Flush()
443 {
444   if (!m_bValidated)
445     return;
446
447   glFinish();
448
449   for (int i = 0 ; i < m_NumYV12Buffers ; i++)
450     (this->*m_textureDelete)(i);
451
452   glFinish();
453   m_bValidated = false;
454   m_fbo.Cleanup();
455   m_iYV12RenderBuffer = 0;
456 }
457
458 void CLinuxRendererGLES::Update()
459 {
460   if (!m_bConfigured) return;
461   ManageDisplay();
462 }
463
464 void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
465 {
466   if (!m_bConfigured) return;
467
468   // if its first pass, just init textures and return
469   if (ValidateRenderTarget())
470     return;
471
472   if (m_renderMethod & RENDER_BYPASS)
473   {
474     ManageDisplay();
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);
479
480     CRect old = g_graphicsContext.GetScissors();
481
482     g_graphicsContext.BeginPaint();
483     g_graphicsContext.SetScissors(m_destRect);
484
485     glEnable(GL_BLEND);
486     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
487     glClearColor(0, 0, 0, 0);
488     glClear(GL_COLOR_BUFFER_BIT);
489
490     g_graphicsContext.SetScissors(old);
491     g_graphicsContext.EndPaint();
492     return;
493   }
494
495   // this needs to be checked after texture validation
496   if (!m_bImageReady) return;
497
498   int index = m_iYV12RenderBuffer;
499   YUVBUFFER& buf =  m_buffers[index];
500
501   if (m_format != RENDER_FMT_OMXEGL && m_format != RENDER_FMT_EGLIMG && m_format != RENDER_FMT_MEDIACODEC)
502   {
503     if (!buf.fields[FIELD_FULL][0].id) return;
504   }
505   if (buf.image.flags==0)
506     return;
507
508   ManageDisplay();
509
510   g_graphicsContext.BeginPaint();
511
512   m_iLastRenderBuffer = index;
513
514   if (clear)
515   {
516     glClearColor(m_clearColour, m_clearColour, m_clearColour, 0);
517     glClear(GL_COLOR_BUFFER_BIT);
518     glClearColor(0,0,0,0);
519   }
520
521   if (alpha<255)
522   {
523     glEnable(GL_BLEND);
524     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
525     if (m_pYUVShader)
526       m_pYUVShader->SetAlpha(alpha / 255.0f);
527   }
528   else
529   {
530     glDisable(GL_BLEND);
531     if (m_pYUVShader)
532       m_pYUVShader->SetAlpha(1.0f);
533   }
534
535   if ((flags & RENDER_FLAG_TOP) && (flags & RENDER_FLAG_BOT))
536     CLog::Log(LOGERROR, "GLES: Cannot render stipple!");
537   else
538     Render(flags, index);
539
540   VerifyGLState();
541   glEnable(GL_BLEND);
542
543   g_graphicsContext.EndPaint();
544 }
545
546 void CLinuxRendererGLES::FlipPage(int source)
547 {
548   if( source >= 0 && source < m_NumYV12Buffers )
549     m_iYV12RenderBuffer = source;
550   else
551     m_iYV12RenderBuffer = NextYV12Texture();
552
553   m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
554
555   return;
556 }
557
558 unsigned int CLinuxRendererGLES::PreInit()
559 {
560   CSingleLock lock(g_graphicsContext);
561   m_bConfigured = false;
562   m_bValidated = false;
563   UnInit();
564   m_resolution = CDisplaySettings::Get().GetCurrentResolution();
565   if ( m_resolution == RES_WINDOW )
566     m_resolution = RES_DESKTOP;
567
568   m_iYV12RenderBuffer = 0;
569   m_NumYV12Buffers = 2;
570
571   m_formats.push_back(RENDER_FMT_YUV420P);
572   m_formats.push_back(RENDER_FMT_BYPASS);
573 #if defined(HAVE_LIBOPENMAX)
574   m_formats.push_back(RENDER_FMT_OMXEGL);
575 #endif
576 #ifdef HAVE_VIDEOTOOLBOXDECODER
577   m_formats.push_back(RENDER_FMT_CVBREF);
578 #endif
579 #ifdef HAS_LIBSTAGEFRIGHT
580   m_formats.push_back(RENDER_FMT_EGLIMG);
581 #endif
582 #if defined(TARGET_ANDROID)
583   m_formats.push_back(RENDER_FMT_MEDIACODEC);
584 #endif
585
586   // setup the background colour
587   m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
588
589   if (!m_dllSwScale->Load())
590     CLog::Log(LOGERROR,"CLinuxRendererGL::PreInit - failed to load rescale libraries!");
591
592   return true;
593 }
594
595 void CLinuxRendererGLES::UpdateVideoFilter()
596 {
597   if (m_scalingMethodGui == CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod)
598     return;
599   m_scalingMethodGui = CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod;
600   m_scalingMethod    = m_scalingMethodGui;
601
602   if(!Supports(m_scalingMethod))
603   {
604     CLog::Log(LOGWARNING, "CLinuxRendererGLES::UpdateVideoFilter - choosen scaling method %d, is not supported by renderer", (int)m_scalingMethod);
605     m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
606   }
607
608   if (m_pVideoFilterShader)
609   {
610     m_pVideoFilterShader->Free();
611     delete m_pVideoFilterShader;
612     m_pVideoFilterShader = NULL;
613   }
614   m_fbo.Cleanup();
615
616   VerifyGLState();
617
618   switch (m_scalingMethod)
619   {
620   case VS_SCALINGMETHOD_NEAREST:
621     SetTextureFilter(GL_NEAREST);
622     m_renderQuality = RQ_SINGLEPASS;
623     return;
624
625   case VS_SCALINGMETHOD_LINEAR:
626     SetTextureFilter(GL_LINEAR);
627     m_renderQuality = RQ_SINGLEPASS;
628     return;
629
630   case VS_SCALINGMETHOD_CUBIC:
631     CLog::Log(LOGERROR, "GLES: CUBIC not supported!");
632     break;
633
634   case VS_SCALINGMETHOD_LANCZOS2:
635   case VS_SCALINGMETHOD_LANCZOS3:
636   case VS_SCALINGMETHOD_SINC8:
637   case VS_SCALINGMETHOD_NEDI:
638     CLog::Log(LOGERROR, "GL: TODO: This scaler has not yet been implemented");
639     break;
640
641   default:
642     break;
643   }
644
645   CGUIDialogKaiToast::QueueNotification("Video Renderering", "Failed to init video filters/scalers, falling back to bilinear scaling");
646   CLog::Log(LOGERROR, "GL: Falling back to bilinear due to failure to init scaler");
647   if (m_pVideoFilterShader)
648   {
649     m_pVideoFilterShader->Free();
650     delete m_pVideoFilterShader;
651     m_pVideoFilterShader = NULL;
652   }
653   m_fbo.Cleanup();
654
655   SetTextureFilter(GL_LINEAR);
656   m_renderQuality = RQ_SINGLEPASS;
657 }
658
659 void CLinuxRendererGLES::LoadShaders(int field)
660 {
661 #ifdef TARGET_DARWIN_IOS
662   float ios_version = GetIOSVersion();
663 #endif
664   int requestedMethod = CSettings::Get().GetInt("videoplayer.rendermethod");
665   CLog::Log(LOGDEBUG, "GL: Requested render method: %d", requestedMethod);
666
667   if (m_pYUVShader)
668   {
669     m_pYUVShader->Free();
670     delete m_pYUVShader;
671     m_pYUVShader = NULL;
672   }
673
674   switch(requestedMethod)
675   {
676     case RENDER_METHOD_AUTO:
677     case RENDER_METHOD_GLSL:
678       if (m_format == RENDER_FMT_OMXEGL)
679       {
680         CLog::Log(LOGNOTICE, "GL: Using OMXEGL RGBA render method");
681         m_renderMethod = RENDER_OMXEGL;
682         break;
683       }
684       else if (m_format == RENDER_FMT_EGLIMG)
685       {
686         CLog::Log(LOGNOTICE, "GL: Using EGL Image render method");
687         m_renderMethod = RENDER_EGLIMG;
688         break;
689       }
690       else if (m_format == RENDER_FMT_MEDIACODEC)
691       {
692         CLog::Log(LOGNOTICE, "GL: Using MediaCodec render method");
693         m_renderMethod = RENDER_MEDIACODEC;
694         break;
695       }
696       else if (m_format == RENDER_FMT_BYPASS)
697       {
698         CLog::Log(LOGNOTICE, "GL: Using BYPASS render method");
699         m_renderMethod = RENDER_BYPASS;
700         break;
701       }
702       else if (m_format == RENDER_FMT_CVBREF)
703       {
704         CLog::Log(LOGNOTICE, "GL: Using CoreVideoRef RGBA render method");
705         m_renderMethod = RENDER_CVREF;
706         break;
707       }
708       #if defined(TARGET_DARWIN_IOS)
709       else if (ios_version < 5.0 && m_format == RENDER_FMT_YUV420P)
710       {
711         CLog::Log(LOGNOTICE, "GL: Using software color conversion/RGBA render method");
712         m_renderMethod = RENDER_SW;
713         break;
714       }
715       #endif
716       // Try GLSL shaders if supported and user requested auto or GLSL.
717       if (glCreateProgram)
718       {
719         // create regular progressive scan shader
720         m_pYUVShader = new YUV2RGBProgressiveShader(false, m_iFlags, m_format);
721         CLog::Log(LOGNOTICE, "GL: Selecting Single Pass YUV 2 RGB shader");
722
723         if (m_pYUVShader && m_pYUVShader->CompileAndLink())
724         {
725           m_renderMethod = RENDER_GLSL;
726           UpdateVideoFilter();
727           break;
728         }
729         else if (m_pYUVShader)
730         {
731           m_pYUVShader->Free();
732           delete m_pYUVShader;
733           m_pYUVShader = NULL;
734           CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB GLSL shader");
735           // drop through and try SW
736         }
737       }
738     case RENDER_METHOD_SOFTWARE:
739     default:
740       {
741         // Use software YUV 2 RGB conversion if user requested it or GLSL failed
742         m_renderMethod = RENDER_SW ;
743         CLog::Log(LOGNOTICE, "GL: Using software color conversion/RGBA rendering");
744       }
745   }
746
747   // determine whether GPU supports NPOT textures
748   if (!g_Windowing.IsExtSupported("GL_TEXTURE_NPOT"))
749   {
750     CLog::Log(LOGNOTICE, "GL: GL_ARB_texture_rectangle not supported and OpenGL version is not 2.x");
751     CLog::Log(LOGNOTICE, "GL: Reverting to POT textures");
752     m_renderMethod |= RENDER_POT;
753   }
754   else
755     CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
756
757   // Now that we now the render method, setup texture function handlers
758   if (m_format == RENDER_FMT_CVBREF)
759   {
760     m_textureUpload = &CLinuxRendererGLES::UploadCVRefTexture;
761     m_textureCreate = &CLinuxRendererGLES::CreateCVRefTexture;
762     m_textureDelete = &CLinuxRendererGLES::DeleteCVRefTexture;
763   }
764   else if (m_format == RENDER_FMT_BYPASS)
765   {
766     m_textureUpload = &CLinuxRendererGLES::UploadBYPASSTexture;
767     m_textureCreate = &CLinuxRendererGLES::CreateBYPASSTexture;
768     m_textureDelete = &CLinuxRendererGLES::DeleteBYPASSTexture;
769   }
770   else if (m_format == RENDER_FMT_EGLIMG)
771   {
772     m_textureUpload = &CLinuxRendererGLES::UploadEGLIMGTexture;
773     m_textureCreate = &CLinuxRendererGLES::CreateEGLIMGTexture;
774     m_textureDelete = &CLinuxRendererGLES::DeleteEGLIMGTexture;
775   }
776   else if (m_format == RENDER_FMT_MEDIACODEC)
777   {
778     m_textureUpload = &CLinuxRendererGLES::UploadSurfaceTexture;
779     m_textureCreate = &CLinuxRendererGLES::CreateSurfaceTexture;
780     m_textureDelete = &CLinuxRendererGLES::DeleteSurfaceTexture;
781   }
782
783   else
784   {
785     // default to YV12 texture handlers
786     m_textureUpload = &CLinuxRendererGLES::UploadYV12Texture;
787     m_textureCreate = &CLinuxRendererGLES::CreateYV12Texture;
788     m_textureDelete = &CLinuxRendererGLES::DeleteYV12Texture;
789   }
790
791   if (m_oldRenderMethod != m_renderMethod)
792   {
793     CLog::Log(LOGDEBUG, "CLinuxRendererGLES: Reorder drawpoints due to method change from %i to %i", m_oldRenderMethod, m_renderMethod);
794     ReorderDrawPoints();
795     m_oldRenderMethod = m_renderMethod;
796   }
797 }
798
799 void CLinuxRendererGLES::UnInit()
800 {
801   CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
802   CSingleLock lock(g_graphicsContext);
803
804   if (m_rgbBuffer != NULL)
805   {
806     delete [] m_rgbBuffer;
807     m_rgbBuffer = NULL;
808   }
809   m_rgbBufferSize = 0;
810
811   // YV12 textures
812   for (int i = 0; i < NUM_BUFFERS; ++i)
813     (this->*m_textureDelete)(i);
814
815   if (m_dllSwScale && m_sw_context)
816   {
817     m_dllSwScale->sws_freeContext(m_sw_context);
818     m_sw_context = NULL;
819   }
820
821   // cleanup framebuffer object if it was in use
822   m_fbo.Cleanup();
823   m_bValidated = false;
824   m_bImageReady = false;
825   m_bConfigured = false;
826   m_RenderUpdateCallBackFn = NULL;
827   m_RenderUpdateCallBackCtx = NULL;
828   m_RenderFeaturesCallBackFn = NULL;
829   m_RenderFeaturesCallBackCtx = NULL;
830 }
831
832 inline void CLinuxRendererGLES::ReorderDrawPoints()
833 {
834
835   CBaseRenderer::ReorderDrawPoints();//call base impl. for rotating the points
836
837   //corevideo and EGL are flipped in y
838   if(m_renderMethod & RENDER_CVREF)
839   {
840     CPoint tmp;
841     tmp = m_rotatedDestCoords[0];
842     m_rotatedDestCoords[0] = m_rotatedDestCoords[3];
843     m_rotatedDestCoords[3] = tmp;
844     tmp = m_rotatedDestCoords[1];
845     m_rotatedDestCoords[1] = m_rotatedDestCoords[2];
846     m_rotatedDestCoords[2] = tmp;
847   }
848 }
849
850 void CLinuxRendererGLES::ReleaseBuffer(int idx)
851 {
852 #ifdef HAVE_VIDEOTOOLBOXDECODER
853   YUVBUFFER &buf = m_buffers[idx];
854
855   if (buf.cvBufferRef)
856     CVBufferRelease(buf.cvBufferRef);
857   buf.cvBufferRef = NULL;
858 #endif
859 #if defined(TARGET_ANDROID)
860   YUVBUFFER &buf = m_buffers[idx];
861
862   SAFE_RELEASE(buf.mediacodec);
863 #endif
864 }
865
866 void CLinuxRendererGLES::Render(DWORD flags, int index)
867 {
868   // If rendered directly by the hardware
869   if (m_renderMethod & RENDER_BYPASS)
870     return;
871
872   // obtain current field, if interlaced
873   if( flags & RENDER_FLAG_TOP)
874     m_currentField = FIELD_TOP;
875
876   else if (flags & RENDER_FLAG_BOT)
877     m_currentField = FIELD_BOT;
878
879   else
880     m_currentField = FIELD_FULL;
881
882   (this->*m_textureUpload)(index);
883
884   if (m_renderMethod & RENDER_GLSL)
885   {
886     UpdateVideoFilter();
887     switch(m_renderQuality)
888     {
889     case RQ_LOW:
890     case RQ_SINGLEPASS:
891       RenderSinglePass(index, m_currentField);
892       VerifyGLState();
893       break;
894
895     case RQ_MULTIPASS:
896       RenderMultiPass(index, m_currentField);
897       VerifyGLState();
898       break;
899
900     case RQ_SOFTWARE:
901       RenderSoftware(index, m_currentField);
902       VerifyGLState();
903       break;
904     }
905   }
906   else if (m_renderMethod & RENDER_OMXEGL)
907   {
908     RenderOpenMax(index, m_currentField);
909     VerifyGLState();
910   }
911   else if (m_renderMethod & RENDER_EGLIMG)
912   {
913     RenderEglImage(index, m_currentField);
914     VerifyGLState();
915   }
916   else if (m_renderMethod & RENDER_CVREF)
917   {
918     RenderCoreVideoRef(index, m_currentField);
919     VerifyGLState();
920   }
921   else if (m_renderMethod & RENDER_MEDIACODEC)
922   {
923     RenderSurfaceTexture(index, m_currentField);
924   }
925   else
926   {
927     RenderSoftware(index, m_currentField);
928     VerifyGLState();
929   }
930 }
931
932 void CLinuxRendererGLES::RenderSinglePass(int index, int field)
933 {
934   YV12Image &im     = m_buffers[index].image;
935   YUVFIELDS &fields = m_buffers[index].fields;
936   YUVPLANES &planes = fields[field];
937
938   if (m_reloadShaders)
939   {
940     m_reloadShaders = 0;
941     LoadShaders(field);
942   }
943
944   glDisable(GL_DEPTH_TEST);
945
946   // Y
947   glActiveTexture(GL_TEXTURE0);
948   glEnable(m_textureTarget);
949   glBindTexture(m_textureTarget, planes[0].id);
950
951   // U
952   glActiveTexture(GL_TEXTURE1);
953   glEnable(m_textureTarget);
954   glBindTexture(m_textureTarget, planes[1].id);
955
956   // V
957   glActiveTexture(GL_TEXTURE2);
958   glEnable(m_textureTarget);
959   glBindTexture(m_textureTarget, planes[2].id);
960
961   glActiveTexture(GL_TEXTURE0);
962   VerifyGLState();
963
964   m_pYUVShader->SetBlack(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * 0.01f - 0.5f);
965   m_pYUVShader->SetContrast(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast * 0.02f);
966   m_pYUVShader->SetWidth(im.width);
967   m_pYUVShader->SetHeight(im.height);
968   if     (field == FIELD_TOP)
969     m_pYUVShader->SetField(1);
970   else if(field == FIELD_BOT)
971     m_pYUVShader->SetField(0);
972
973   m_pYUVShader->SetMatrices(g_matrices.GetMatrix(MM_PROJECTION), g_matrices.GetMatrix(MM_MODELVIEW));
974   m_pYUVShader->Enable();
975
976   GLubyte idx[4] = {0, 1, 3, 2};        //determines order of triangle strip
977   GLfloat m_vert[4][3];
978   GLfloat m_tex[3][4][2];
979
980   GLint vertLoc = m_pYUVShader->GetVertexLoc();
981   GLint Yloc    = m_pYUVShader->GetYcoordLoc();
982   GLint Uloc    = m_pYUVShader->GetUcoordLoc();
983   GLint Vloc    = m_pYUVShader->GetVcoordLoc();
984
985   glVertexAttribPointer(vertLoc, 3, GL_FLOAT, 0, 0, m_vert);
986   glVertexAttribPointer(Yloc, 2, GL_FLOAT, 0, 0, m_tex[0]);
987   glVertexAttribPointer(Uloc, 2, GL_FLOAT, 0, 0, m_tex[1]);
988   glVertexAttribPointer(Vloc, 2, GL_FLOAT, 0, 0, m_tex[2]);
989
990   glEnableVertexAttribArray(vertLoc);
991   glEnableVertexAttribArray(Yloc);
992   glEnableVertexAttribArray(Uloc);
993   glEnableVertexAttribArray(Vloc);
994
995   // Setup vertex position values
996   for(int i = 0; i < 4; i++)
997   {
998     m_vert[i][0] = m_rotatedDestCoords[i].x;
999     m_vert[i][1] = m_rotatedDestCoords[i].y;
1000     m_vert[i][2] = 0.0f;// set z to 0
1001   }
1002
1003   // Setup texture coordinates
1004   for (int i=0; i<3; i++)
1005   {
1006     m_tex[i][0][0] = m_tex[i][3][0] = planes[i].rect.x1;
1007     m_tex[i][0][1] = m_tex[i][1][1] = planes[i].rect.y1;
1008     m_tex[i][1][0] = m_tex[i][2][0] = planes[i].rect.x2;
1009     m_tex[i][2][1] = m_tex[i][3][1] = planes[i].rect.y2;
1010   }
1011
1012   glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1013
1014   VerifyGLState();
1015
1016   m_pYUVShader->Disable();
1017   VerifyGLState();
1018
1019   glDisableVertexAttribArray(vertLoc);
1020   glDisableVertexAttribArray(Yloc);
1021   glDisableVertexAttribArray(Uloc);
1022   glDisableVertexAttribArray(Vloc);
1023
1024   glActiveTexture(GL_TEXTURE1);
1025   glDisable(m_textureTarget);
1026
1027   glActiveTexture(GL_TEXTURE2);
1028   glDisable(m_textureTarget);
1029
1030   glActiveTexture(GL_TEXTURE0);
1031   glDisable(m_textureTarget);
1032
1033   g_matrices.MatrixMode(MM_MODELVIEW);
1034
1035   VerifyGLState();
1036 }
1037
1038 void CLinuxRendererGLES::RenderMultiPass(int index, int field)
1039 {
1040   // TODO: Multipass rendering does not currently work! FIX!
1041   CLog::Log(LOGERROR, "GLES: MULTIPASS rendering was called! But it doesnt work!!!");
1042   return;
1043
1044   YV12Image &im     = m_buffers[index].image;
1045   YUVPLANES &planes = m_buffers[index].fields[field];
1046
1047   if (m_reloadShaders)
1048   {
1049     m_reloadShaders = 0;
1050     LoadShaders(m_currentField);
1051   }
1052
1053   glDisable(GL_DEPTH_TEST);
1054
1055   // Y
1056   glEnable(m_textureTarget);
1057   glActiveTexture(GL_TEXTURE0);
1058   glBindTexture(m_textureTarget, planes[0].id);
1059   VerifyGLState();
1060
1061   // U
1062   glActiveTexture(GL_TEXTURE1);
1063   glEnable(m_textureTarget);
1064   glBindTexture(m_textureTarget, planes[1].id);
1065   VerifyGLState();
1066
1067   // V
1068   glActiveTexture(GL_TEXTURE2);
1069   glEnable(m_textureTarget);
1070   glBindTexture(m_textureTarget, planes[2].id);
1071   VerifyGLState();
1072
1073   glActiveTexture(GL_TEXTURE0);
1074   VerifyGLState();
1075
1076   // make sure the yuv shader is loaded and ready to go
1077   if (!m_pYUVShader || (!m_pYUVShader->OK()))
1078   {
1079     CLog::Log(LOGERROR, "GL: YUV shader not active, cannot do multipass render");
1080     return;
1081   }
1082
1083   m_fbo.BeginRender();
1084   VerifyGLState();
1085
1086   m_pYUVShader->SetBlack(CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness * 0.01f - 0.5f);
1087   m_pYUVShader->SetContrast(CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast * 0.02f);
1088   m_pYUVShader->SetWidth(im.width);
1089   m_pYUVShader->SetHeight(im.height);
1090   if     (field == FIELD_TOP)
1091     m_pYUVShader->SetField(1);
1092   else if(field == FIELD_BOT)
1093     m_pYUVShader->SetField(0);
1094
1095   VerifyGLState();
1096 //TODO
1097 //  glPushAttrib(GL_VIEWPORT_BIT);
1098 //  glPushAttrib(GL_SCISSOR_BIT);
1099   g_matrices.MatrixMode(MM_MODELVIEW);
1100   g_matrices.PushMatrix();
1101   g_matrices.LoadIdentity();
1102   VerifyGLState();
1103
1104   g_matrices.MatrixMode(MM_PROJECTION);
1105   g_matrices.PushMatrix();
1106   g_matrices.LoadIdentity();
1107   VerifyGLState();
1108   g_matrices.Ortho2D(0, m_sourceWidth, 0, m_sourceHeight);
1109   glViewport(0, 0, m_sourceWidth, m_sourceHeight);
1110   glScissor(0, 0, m_sourceWidth, m_sourceHeight);
1111   g_matrices.MatrixMode(MM_MODELVIEW);
1112   VerifyGLState();
1113
1114
1115   if (!m_pYUVShader->Enable())
1116   {
1117     CLog::Log(LOGERROR, "GL: Error enabling YUV shader");
1118   }
1119
1120 // 1st Pass to video frame size
1121 //TODO
1122 //  float imgwidth  = planes[0].rect.x2 - planes[0].rect.x1;
1123 //  float imgheight = planes[0].rect.y2 - planes[0].rect.y1;
1124 //  if (m_textureTarget == GL_TEXTURE_2D)
1125 //  {
1126 //    imgwidth  *= planes[0].texwidth;
1127 //    imgheight *= planes[0].texheight;
1128 //  }
1129 //  
1130 //  glBegin(GL_QUADS);
1131 //
1132 //  glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
1133 //  glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y1);
1134 //  glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y1);
1135 //  glVertex2f(0.0f    , 0.0f);
1136 //
1137 //  glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y1);
1138 //  glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y1);
1139 //  glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y1);
1140 //  glVertex2f(imgwidth, 0.0f);
1141 //
1142 //  glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y2);
1143 //  glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y2);
1144 //  glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y2);
1145 //  glVertex2f(imgwidth, imgheight);
1146 //
1147 //  glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y2);
1148 //  glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y2);
1149 //  glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y2);
1150 //  glVertex2f(0.0f    , imgheight);
1151 //
1152 //  glEnd();
1153 //  VerifyGLState();
1154
1155   m_pYUVShader->Disable();
1156
1157   g_matrices.MatrixMode(MM_MODELVIEW);
1158   g_matrices.PopMatrix(); // pop modelview
1159   g_matrices.MatrixMode(MM_PROJECTION);
1160   g_matrices.PopMatrix(); // pop projection
1161 //TODO
1162 //  glPopAttrib(); // pop scissor
1163 //  glPopAttrib(); // pop viewport
1164   g_matrices.MatrixMode(MM_MODELVIEW);
1165   VerifyGLState();
1166
1167   m_fbo.EndRender();
1168
1169   glActiveTexture(GL_TEXTURE1);
1170   glDisable(m_textureTarget);
1171   glActiveTexture(GL_TEXTURE2);
1172   glDisable(m_textureTarget);
1173   glActiveTexture(GL_TEXTURE0);
1174   glDisable(m_textureTarget);
1175
1176   glEnable(GL_TEXTURE_2D);
1177   glBindTexture(GL_TEXTURE_2D, m_fbo.Texture());
1178   VerifyGLState();
1179
1180   // Use regular normalized texture coordinates
1181
1182   // 2nd Pass to screen size with optional video filter
1183
1184   if (m_pVideoFilterShader)
1185   {
1186     m_fbo.SetFiltering(GL_TEXTURE_2D, GL_NEAREST);
1187     m_pVideoFilterShader->SetSourceTexture(0);
1188     m_pVideoFilterShader->SetWidth(m_sourceWidth);
1189     m_pVideoFilterShader->SetHeight(m_sourceHeight);
1190     m_pVideoFilterShader->Enable();
1191   }
1192   else
1193     m_fbo.SetFiltering(GL_TEXTURE_2D, GL_LINEAR);
1194
1195   VerifyGLState();
1196
1197 //TODO
1198 //  imgwidth  /= m_sourceWidth;
1199 //  imgheight /= m_sourceHeight;
1200 //
1201 //  glBegin(GL_QUADS);
1202 //
1203 //  glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f    , 0.0f);
1204 //  glVertex4f(m_destRect.x1, m_destRect.y1, 0, 1.0f );
1205 //
1206 //  glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, 0.0f);
1207 //  glVertex4f(m_destRect.x2, m_destRect.y1, 0, 1.0f);
1208 //
1209 //  glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, imgheight);
1210 //  glVertex4f(m_destRect.x2, m_destRect.y2, 0, 1.0f);
1211 //
1212 //  glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f    , imgheight);
1213 //  glVertex4f(m_destRect.x1, m_destRect.y2, 0, 1.0f);
1214 //
1215 //  glEnd();
1216
1217   VerifyGLState();
1218
1219   if (m_pVideoFilterShader)
1220     m_pVideoFilterShader->Disable();
1221
1222   VerifyGLState();
1223
1224   glDisable(m_textureTarget);
1225   VerifyGLState();
1226 }
1227
1228 void CLinuxRendererGLES::RenderSoftware(int index, int field)
1229 {
1230   YUVPLANES &planes = m_buffers[index].fields[field];
1231
1232   glDisable(GL_DEPTH_TEST);
1233
1234   // Y
1235   glEnable(m_textureTarget);
1236   glActiveTexture(GL_TEXTURE0);
1237   glBindTexture(m_textureTarget, planes[0].id);
1238
1239   g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1240
1241   GLubyte idx[4] = {0, 1, 3, 2};        //determines order of triangle strip
1242   GLfloat ver[4][4];
1243   GLfloat tex[4][2];
1244   GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1245
1246   GLint   posLoc = g_Windowing.GUIShaderGetPos();
1247   GLint   texLoc = g_Windowing.GUIShaderGetCoord0();
1248   GLint   colLoc = g_Windowing.GUIShaderGetCol();
1249
1250   glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1251   glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1252   glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1253
1254   glEnableVertexAttribArray(posLoc);
1255   glEnableVertexAttribArray(texLoc);
1256   glEnableVertexAttribArray(colLoc);
1257
1258   // Set vertex coordinates
1259   for(int i = 0; i < 4; i++)
1260   {
1261     ver[i][0] = m_rotatedDestCoords[i].x;
1262     ver[i][1] = m_rotatedDestCoords[i].y;
1263     ver[i][2] = 0.0f;// set z to 0
1264     ver[i][3] = 1.0f;
1265   }
1266
1267   // Set texture coordinates
1268   tex[0][0] = tex[3][0] = planes[0].rect.x1;
1269   tex[0][1] = tex[1][1] = planes[0].rect.y1;
1270   tex[1][0] = tex[2][0] = planes[0].rect.x2;
1271   tex[2][1] = tex[3][1] = planes[0].rect.y2;
1272
1273   glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1274
1275   glDisableVertexAttribArray(posLoc);
1276   glDisableVertexAttribArray(texLoc);
1277   glDisableVertexAttribArray(colLoc);
1278
1279   g_Windowing.DisableGUIShader();
1280
1281   VerifyGLState();
1282
1283   glDisable(m_textureTarget);
1284   VerifyGLState();
1285 }
1286
1287 void CLinuxRendererGLES::RenderOpenMax(int index, int field)
1288 {
1289 #if defined(HAVE_LIBOPENMAX)
1290   GLuint textureId = m_buffers[index].openMaxBuffer->texture_id;
1291
1292   glDisable(GL_DEPTH_TEST);
1293
1294   // Y
1295   glEnable(m_textureTarget);
1296   glActiveTexture(GL_TEXTURE0);
1297   glBindTexture(m_textureTarget, textureId);
1298
1299   g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1300
1301   GLubyte idx[4] = {0, 1, 3, 2};        //determines order of triangle strip
1302   GLfloat ver[4][4];
1303   GLfloat tex[4][2];
1304   GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1305
1306   GLint   posLoc = g_Windowing.GUIShaderGetPos();
1307   GLint   texLoc = g_Windowing.GUIShaderGetCoord0();
1308   GLint   colLoc = g_Windowing.GUIShaderGetCol();
1309
1310   glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1311   glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1312   glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1313
1314   glEnableVertexAttribArray(posLoc);
1315   glEnableVertexAttribArray(texLoc);
1316   glEnableVertexAttribArray(colLoc);
1317
1318   // Set vertex coordinates
1319   for(int i = 0; i < 4; i++)
1320   {
1321     ver[i][0] = m_rotatedDestCoords[i].x;
1322     ver[i][1] = m_rotatedDestCoords[i].y;
1323     ver[i][2] = 0.0f;// set z to 0
1324     ver[i][3] = 1.0f;
1325   }
1326
1327   // Set texture coordinates
1328   tex[0][0] = tex[3][0] = 0;
1329   tex[0][1] = tex[1][1] = 0;
1330   tex[1][0] = tex[2][0] = 1;
1331   tex[2][1] = tex[3][1] = 1;
1332
1333   glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1334
1335   glDisableVertexAttribArray(posLoc);
1336   glDisableVertexAttribArray(texLoc);
1337   glDisableVertexAttribArray(colLoc);
1338
1339   g_Windowing.DisableGUIShader();
1340
1341   VerifyGLState();
1342
1343   glDisable(m_textureTarget);
1344   VerifyGLState();
1345 #endif
1346 }
1347
1348 void CLinuxRendererGLES::RenderEglImage(int index, int field)
1349 {
1350 #if defined(HAS_LIBSTAGEFRIGHT)
1351 #ifdef DEBUG_VERBOSE
1352   unsigned int time = XbmcThreads::SystemClockMillis();
1353 #endif
1354
1355   YUVPLANE &plane = m_buffers[index].fields[field][0];
1356
1357   glDisable(GL_DEPTH_TEST);
1358
1359   glActiveTexture(GL_TEXTURE0);
1360   glBindTexture(m_textureTarget, plane.id);
1361
1362   g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1363
1364   GLubyte idx[4] = {0, 1, 3, 2};        //determines order of triangle strip
1365   GLfloat ver[4][4];
1366   GLfloat tex[4][2];
1367   GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1368
1369   GLint   posLoc = g_Windowing.GUIShaderGetPos();
1370   GLint   texLoc = g_Windowing.GUIShaderGetCoord0();
1371   GLint   colLoc = g_Windowing.GUIShaderGetCol();
1372
1373   glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1374   glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1375   glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1376
1377   glEnableVertexAttribArray(posLoc);
1378   glEnableVertexAttribArray(texLoc);
1379   glEnableVertexAttribArray(colLoc);
1380
1381   // Set vertex coordinates
1382   for(int i = 0; i < 4; i++)
1383   {
1384     ver[i][0] = m_rotatedDestCoords[i].x;
1385     ver[i][1] = m_rotatedDestCoords[i].y;
1386     ver[i][2] = 0.0f;// set z to 0
1387     ver[i][3] = 1.0f;
1388   }
1389
1390   // Set texture coordinates (is flipped in y)
1391   tex[0][0] = tex[3][0] = 0;
1392   tex[0][1] = tex[1][1] = 1;
1393   tex[1][0] = tex[2][0] = 1;
1394   tex[2][1] = tex[3][1] = 0;
1395
1396   glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1397
1398   glDisableVertexAttribArray(posLoc);
1399   glDisableVertexAttribArray(texLoc);
1400   glDisableVertexAttribArray(colLoc);
1401
1402   g_Windowing.DisableGUIShader();
1403   VerifyGLState();
1404
1405   glBindTexture(m_textureTarget, 0);
1406   VerifyGLState();
1407
1408 #ifdef DEBUG_VERBOSE
1409   CLog::Log(LOGDEBUG, "RenderEglImage %d: tm:%d\n", index, XbmcThreads::SystemClockMillis() - time);
1410 #endif
1411 #endif
1412 }
1413
1414 void CLinuxRendererGLES::RenderSurfaceTexture(int index, int field)
1415 {
1416 #if defined(TARGET_ANDROID)
1417   #ifdef DEBUG_VERBOSE
1418     unsigned int time = XbmcThreads::SystemClockMillis();
1419   #endif
1420
1421   YUVPLANE &plane = m_buffers[index].fields[0][0];
1422
1423   glDisable(GL_DEPTH_TEST);
1424
1425   glActiveTexture(GL_TEXTURE0);
1426   glBindTexture(GL_TEXTURE_EXTERNAL_OES, plane.id);
1427
1428   g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA_OES);
1429
1430   glUniformMatrix4fv(g_Windowing.GUIShaderGetCoord0Matrix(), 1, GL_FALSE, m_textureMatrix);
1431
1432   GLubyte idx[4] = {0, 1, 3, 2};        //determines order of triangle strip
1433   GLfloat ver[4][4];
1434   GLfloat tex[4][4];
1435
1436   GLint   posLoc = g_Windowing.GUIShaderGetPos();
1437   GLint   texLoc = g_Windowing.GUIShaderGetCoord0();
1438
1439
1440   glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1441   glVertexAttribPointer(texLoc, 4, GL_FLOAT, 0, 0, tex);
1442
1443   glEnableVertexAttribArray(posLoc);
1444   glEnableVertexAttribArray(texLoc);
1445
1446   // Set vertex coordinates
1447   for(int i = 0; i < 4; i++)
1448   {
1449     ver[i][0] = m_rotatedDestCoords[i].x;
1450     ver[i][1] = m_rotatedDestCoords[i].y;
1451     ver[i][2] = 0.0f;        // set z to 0
1452     ver[i][3] = 1.0f;
1453   }
1454
1455   // Set texture coordinates (MediaCodec is flipped in y)
1456   tex[0][0] = tex[3][0] = 0.0f;
1457   tex[0][1] = tex[1][1] = 1.0f;
1458   tex[1][0] = tex[2][0] = 1.0f;
1459   tex[2][1] = tex[3][1] = 0.0f;
1460
1461   for(int i = 0; i < 4; i++)
1462   {
1463     tex[i][2] = 0.0f;
1464     tex[i][3] = 1.0f;
1465   }
1466
1467   glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1468
1469   glDisableVertexAttribArray(posLoc);
1470   glDisableVertexAttribArray(texLoc);
1471
1472   const float identity[16] = {
1473       1.0f, 0.0f, 0.0f, 0.0f,
1474       0.0f, 1.0f, 0.0f, 0.0f,
1475       0.0f, 0.0f, 1.0f, 0.0f,
1476       0.0f, 0.0f, 0.0f, 1.0f
1477   };
1478   glUniformMatrix4fv(g_Windowing.GUIShaderGetCoord0Matrix(),  1, GL_FALSE, identity);
1479
1480   g_Windowing.DisableGUIShader();
1481   VerifyGLState();
1482
1483   glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
1484   VerifyGLState();
1485
1486   #ifdef DEBUG_VERBOSE
1487     CLog::Log(LOGDEBUG, "RenderMediaCodecImage %d: tm:%d", index, XbmcThreads::SystemClockMillis() - time);
1488   #endif
1489 #endif
1490 }
1491
1492 void CLinuxRendererGLES::RenderCoreVideoRef(int index, int field)
1493 {
1494 #ifdef HAVE_VIDEOTOOLBOXDECODER
1495   YUVPLANE &plane = m_buffers[index].fields[field][0];
1496
1497   glDisable(GL_DEPTH_TEST);
1498
1499   glEnable(m_textureTarget);
1500   glActiveTexture(GL_TEXTURE0);
1501   glBindTexture(m_textureTarget, plane.id);
1502
1503   g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
1504
1505   GLubyte idx[4] = {0, 1, 3, 2};        //determines order of triangle strip
1506   GLfloat ver[4][4];
1507   GLfloat tex[4][2];
1508   GLfloat col[3] = {1.0f, 1.0f, 1.0f};
1509
1510   GLint   posLoc = g_Windowing.GUIShaderGetPos();
1511   GLint   texLoc = g_Windowing.GUIShaderGetCoord0();
1512   GLint   colLoc = g_Windowing.GUIShaderGetCol();
1513
1514   glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1515   glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1516   glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
1517
1518   glEnableVertexAttribArray(posLoc);
1519   glEnableVertexAttribArray(texLoc);
1520   glEnableVertexAttribArray(colLoc);
1521
1522   // Set vertex coordinates
1523   for(int i = 0; i < 4; i++)
1524   {
1525     ver[i][0] = m_rotatedDestCoords[i].x;
1526     ver[i][1] = m_rotatedDestCoords[i].y;
1527     ver[i][2] = 0.0f;// set z to 0
1528     ver[i][3] = 1.0f;
1529   }
1530
1531   // Set texture coordinates (corevideo is flipped in y)
1532   tex[0][0] = tex[3][0] = 0;
1533   tex[0][1] = tex[1][1] = 1;
1534   tex[1][0] = tex[2][0] = 1;
1535   tex[2][1] = tex[3][1] = 0;
1536
1537   glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1538
1539   glDisableVertexAttribArray(posLoc);
1540   glDisableVertexAttribArray(texLoc);
1541   glDisableVertexAttribArray(colLoc);
1542
1543   g_Windowing.DisableGUIShader();
1544   VerifyGLState();
1545
1546   glDisable(m_textureTarget);
1547   VerifyGLState();
1548 #endif
1549 }
1550
1551 bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture)
1552 {
1553   if (!m_bValidated)
1554     return false;
1555
1556   // If rendered directly by the hardware
1557   if (m_renderMethod & RENDER_BYPASS)
1558   {
1559     capture->BeginRender();
1560     capture->EndRender();
1561     return true;
1562   }
1563
1564   // save current video rect
1565   CRect saveSize = m_destRect;
1566   saveRotatedCoords();//backup current m_rotatedDestCoords
1567
1568   // new video rect is thumbnail size
1569   m_destRect.SetRect(0, 0, (float)capture->GetWidth(), (float)capture->GetHeight());
1570   MarkDirty();
1571   syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords
1572   // clear framebuffer and invert Y axis to get non-inverted image
1573   glDisable(GL_BLEND);
1574
1575   g_matrices.MatrixMode(MM_MODELVIEW);
1576   g_matrices.PushMatrix();
1577   // fixme - we know that cvref  & eglimg are already flipped in y direction
1578   // but somehow this also effects the rendercapture here
1579   // therefore we have to skip the flip here or we get upside down
1580   // images
1581   if (m_renderMethod != RENDER_CVREF)
1582   {
1583     g_matrices.Translatef(0.0f, capture->GetHeight(), 0.0f);
1584     g_matrices.Scalef(1.0f, -1.0f, 1.0f);
1585   }
1586
1587   capture->BeginRender();
1588
1589   Render(RENDER_FLAG_NOOSD, m_iYV12RenderBuffer);
1590   // read pixels
1591   glReadPixels(0, g_graphicsContext.GetHeight() - capture->GetHeight(), capture->GetWidth(), capture->GetHeight(),
1592                GL_RGBA, GL_UNSIGNED_BYTE, capture->GetRenderBuffer());
1593
1594   // OpenGLES returns in RGBA order but CRenderCapture needs BGRA order
1595   // XOR Swap RGBA -> BGRA
1596   unsigned char* pixels = (unsigned char*)capture->GetRenderBuffer();
1597   for (unsigned int i = 0; i < capture->GetWidth() * capture->GetHeight(); i++, pixels+=4)
1598   {
1599     std::swap(pixels[0], pixels[2]);
1600   }
1601
1602   capture->EndRender();
1603
1604   // revert model view matrix
1605   g_matrices.MatrixMode(MM_MODELVIEW);
1606   g_matrices.PopMatrix();
1607
1608   // restore original video rect
1609   m_destRect = saveSize;
1610   restoreRotatedCoords();//restores the previous state of the rotated dest coords
1611
1612   return true;
1613 }
1614
1615 //********************************************************************************************************
1616 // YV12 Texture creation, deletion, copying + clearing
1617 //********************************************************************************************************
1618 void CLinuxRendererGLES::UploadYV12Texture(int source)
1619 {
1620   YUVBUFFER& buf    =  m_buffers[source];
1621   YV12Image* im     = &buf.image;
1622   YUVFIELDS& fields =  buf.fields;
1623
1624
1625 #if defined(HAVE_LIBOPENMAX)
1626   if (!(im->flags&IMAGE_FLAG_READY) || m_buffers[source].openMaxBuffer)
1627 #else
1628   if (!(im->flags&IMAGE_FLAG_READY))
1629 #endif
1630   {
1631     return;
1632   }
1633
1634   // if we don't have a shader, fallback to SW YUV2RGB for now
1635   if (m_renderMethod & RENDER_SW)
1636   {
1637     if(m_rgbBufferSize < m_sourceWidth * m_sourceHeight * 4)
1638     {
1639       delete [] m_rgbBuffer;
1640       m_rgbBufferSize = m_sourceWidth*m_sourceHeight*4;
1641       m_rgbBuffer = new BYTE[m_rgbBufferSize];
1642     }
1643
1644 #if defined(__ARM_NEON__)
1645     if (g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_NEON)
1646     {
1647       yuv420_2_rgb8888_neon(m_rgbBuffer, im->plane[0], im->plane[2], im->plane[1],
1648         m_sourceWidth, m_sourceHeight, im->stride[0], im->stride[1], m_sourceWidth * 4);
1649     }
1650     else
1651 #endif
1652     {
1653       m_sw_context = m_dllSwScale->sws_getCachedContext(m_sw_context,
1654         im->width, im->height, PIX_FMT_YUV420P,
1655         im->width, im->height, PIX_FMT_RGBA,
1656         SWS_FAST_BILINEAR, NULL, NULL, NULL);
1657
1658       uint8_t *src[]  = { im->plane[0], im->plane[1], im->plane[2], 0 };
1659       int srcStride[] = { im->stride[0], im->stride[1], im->stride[2], 0 };
1660       uint8_t *dst[]  = { m_rgbBuffer, 0, 0, 0 };
1661       int dstStride[] = { m_sourceWidth*4, 0, 0, 0 };
1662       m_dllSwScale->sws_scale(m_sw_context, src, srcStride, 0, im->height, dst, dstStride);
1663     }
1664   }
1665
1666   bool deinterlacing;
1667   if (m_currentField == FIELD_FULL)
1668     deinterlacing = false;
1669   else
1670     deinterlacing = true;
1671
1672   glEnable(m_textureTarget);
1673   VerifyGLState();
1674
1675   if (m_renderMethod & RENDER_SW)
1676   {
1677     // Load RGB image
1678     if (deinterlacing)
1679     {
1680       LoadPlane( fields[FIELD_TOP][0] , GL_RGBA, buf.flipindex
1681                , im->width, im->height >> 1
1682                , m_sourceWidth*8, m_rgbBuffer );
1683
1684       LoadPlane( fields[FIELD_BOT][0], GL_RGBA, buf.flipindex
1685                , im->width, im->height >> 1
1686                , m_sourceWidth*8, m_rgbBuffer + m_sourceWidth*4);
1687     }
1688     else
1689     {
1690       LoadPlane( fields[FIELD_FULL][0], GL_RGBA, buf.flipindex
1691                , im->width, im->height
1692                , m_sourceWidth*4, m_rgbBuffer );
1693     }
1694   }
1695   else
1696   {
1697     glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1698
1699     if (deinterlacing)
1700     {
1701       // Load Y fields
1702       LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex
1703                , im->width, im->height >> 1
1704                , im->stride[0]*2, im->plane[0] );
1705
1706       LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex
1707                , im->width, im->height >> 1
1708                , im->stride[0]*2, im->plane[0] + im->stride[0]) ;
1709     }
1710     else
1711     {
1712       // Load Y plane
1713       LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
1714                , im->width, im->height
1715                , im->stride[0], im->plane[0] );
1716     }
1717   }
1718
1719   VerifyGLState();
1720
1721   if (!(m_renderMethod & RENDER_SW))
1722   {
1723     glPixelStorei(GL_UNPACK_ALIGNMENT,1);
1724
1725     if (deinterlacing)
1726     {
1727       // Load Even U & V Fields
1728       LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE, buf.flipindex
1729                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1730                , im->stride[1]*2, im->plane[1] );
1731
1732       LoadPlane( fields[FIELD_TOP][2], GL_LUMINANCE, buf.flipindex
1733                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1734                , im->stride[2]*2, im->plane[2] );
1735
1736       // Load Odd U & V Fields
1737       LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE, buf.flipindex
1738                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1739                , im->stride[1]*2, im->plane[1] + im->stride[1] );
1740
1741       LoadPlane( fields[FIELD_BOT][2], GL_LUMINANCE, buf.flipindex
1742                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
1743                , im->stride[2]*2, im->plane[2] + im->stride[2] );
1744
1745     }
1746     else
1747     {
1748       LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, buf.flipindex
1749                , im->width >> im->cshift_x, im->height >> im->cshift_y
1750                , im->stride[1], im->plane[1] );
1751
1752       LoadPlane( fields[FIELD_FULL][2], GL_LUMINANCE, buf.flipindex
1753                , im->width >> im->cshift_x, im->height >> im->cshift_y
1754                , im->stride[2], im->plane[2] );
1755     }
1756   }
1757   CalculateTextureSourceRects(source, 3);
1758
1759   glDisable(m_textureTarget);
1760 }
1761
1762 void CLinuxRendererGLES::DeleteYV12Texture(int index)
1763 {
1764   YV12Image &im     = m_buffers[index].image;
1765   YUVFIELDS &fields = m_buffers[index].fields;
1766
1767   if( fields[FIELD_FULL][0].id == 0 ) return;
1768
1769   /* finish up all textures, and delete them */
1770   g_graphicsContext.BeginPaint();  //FIXME
1771   for(int f = 0;f<MAX_FIELDS;f++)
1772   {
1773     for(int p = 0;p<MAX_PLANES;p++)
1774     {
1775       if( fields[f][p].id )
1776       {
1777         if (glIsTexture(fields[f][p].id))
1778           glDeleteTextures(1, &fields[f][p].id);
1779         fields[f][p].id = 0;
1780       }
1781     }
1782   }
1783   g_graphicsContext.EndPaint();
1784
1785   for(int p = 0;p<MAX_PLANES;p++)
1786   {
1787     if (im.plane[p])
1788     {
1789       delete[] im.plane[p];
1790       im.plane[p] = NULL;
1791     }
1792   }
1793 }
1794
1795 bool CLinuxRendererGLES::CreateYV12Texture(int index)
1796 {
1797   /* since we also want the field textures, pitch must be texture aligned */
1798   YV12Image &im     = m_buffers[index].image;
1799   YUVFIELDS &fields = m_buffers[index].fields;
1800
1801   DeleteYV12Texture(index);
1802
1803   im.height = m_sourceHeight;
1804   im.width  = m_sourceWidth;
1805   im.cshift_x = 1;
1806   im.cshift_y = 1;
1807
1808   im.stride[0] = im.width;
1809   im.stride[1] = im.width >> im.cshift_x;
1810   im.stride[2] = im.width >> im.cshift_x;
1811
1812   im.planesize[0] = im.stride[0] * im.height;
1813   im.planesize[1] = im.stride[1] * ( im.height >> im.cshift_y );
1814   im.planesize[2] = im.stride[2] * ( im.height >> im.cshift_y );
1815
1816   for (int i = 0; i < 3; i++)
1817     im.plane[i] = new BYTE[im.planesize[i]];
1818
1819   glEnable(m_textureTarget);
1820   for(int f = 0;f<MAX_FIELDS;f++)
1821   {
1822     for(int p = 0;p<MAX_PLANES;p++)
1823     {
1824       if (!glIsTexture(fields[f][p].id))
1825       {
1826         glGenTextures(1, &fields[f][p].id);
1827         VerifyGLState();
1828       }
1829     }
1830   }
1831
1832   // YUV
1833   for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
1834   {
1835     int fieldshift = (f==FIELD_FULL) ? 0 : 1;
1836     YUVPLANES &planes = fields[f];
1837
1838     planes[0].texwidth  = im.width;
1839     planes[0].texheight = im.height >> fieldshift;
1840
1841     if (m_renderMethod & RENDER_SW)
1842     {
1843       planes[1].texwidth  = 0;
1844       planes[1].texheight = 0;
1845       planes[2].texwidth  = 0;
1846       planes[2].texheight = 0;
1847     }
1848     else
1849     {
1850       planes[1].texwidth  = planes[0].texwidth  >> im.cshift_x;
1851       planes[1].texheight = planes[0].texheight >> im.cshift_y;
1852       planes[2].texwidth  = planes[0].texwidth  >> im.cshift_x;
1853       planes[2].texheight = planes[0].texheight >> im.cshift_y;
1854     }
1855
1856     if(m_renderMethod & RENDER_POT)
1857     {
1858       for(int p = 0; p < 3; p++)
1859       {
1860         planes[p].texwidth  = NP2(planes[p].texwidth);
1861         planes[p].texheight = NP2(planes[p].texheight);
1862       }
1863     }
1864
1865     for(int p = 0; p < 3; p++)
1866     {
1867       YUVPLANE &plane = planes[p];
1868       if (plane.texwidth * plane.texheight == 0)
1869         continue;
1870
1871       glBindTexture(m_textureTarget, plane.id);
1872       if (m_renderMethod & RENDER_SW)
1873       {
1874         if(m_renderMethod & RENDER_POT)
1875           CLog::Log(LOGDEBUG, "GL: Creating RGB POT texture of size %d x %d",  plane.texwidth, plane.texheight);
1876         else
1877           CLog::Log(LOGDEBUG,  "GL: Creating RGB NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
1878
1879         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1880         glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1881       }
1882       else
1883       {
1884         if(m_renderMethod & RENDER_POT)
1885           CLog::Log(LOGDEBUG, "GL: Creating YUV POT texture of size %d x %d",  plane.texwidth, plane.texheight);
1886         else
1887           CLog::Log(LOGDEBUG,  "GL: Creating YUV NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
1888
1889         glTexImage2D(m_textureTarget, 0, GL_LUMINANCE, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
1890       }
1891
1892       glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1893       glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1894       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1895       glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1896       VerifyGLState();
1897     }
1898   }
1899   glDisable(m_textureTarget);
1900   return true;
1901 }
1902
1903 //********************************************************************************************************
1904 // CoreVideoRef Texture creation, deletion, copying + clearing
1905 //********************************************************************************************************
1906 void CLinuxRendererGLES::UploadCVRefTexture(int index)
1907 {
1908 #ifdef HAVE_VIDEOTOOLBOXDECODER
1909   CVBufferRef cvBufferRef = m_buffers[index].cvBufferRef;
1910
1911   if (cvBufferRef)
1912   {
1913     YUVPLANE &plane = m_buffers[index].fields[0][0];
1914
1915     CVPixelBufferLockBaseAddress(cvBufferRef, kCVPixelBufferLock_ReadOnly);
1916     #if !TARGET_OS_IPHONE
1917       int rowbytes = CVPixelBufferGetBytesPerRow(cvBufferRef);
1918     #endif
1919     int bufferWidth = CVPixelBufferGetWidth(cvBufferRef);
1920     int bufferHeight = CVPixelBufferGetHeight(cvBufferRef);
1921     unsigned char *bufferBase = (unsigned char *)CVPixelBufferGetBaseAddress(cvBufferRef);
1922
1923     glEnable(m_textureTarget);
1924     VerifyGLState();
1925
1926     glBindTexture(m_textureTarget, plane.id);
1927     #if !TARGET_OS_IPHONE
1928       #ifdef GL_UNPACK_ROW_LENGTH
1929         // Set row pixels
1930         glPixelStorei( GL_UNPACK_ROW_LENGTH, rowbytes);
1931       #endif
1932       #ifdef GL_TEXTURE_STORAGE_HINT_APPLE
1933         // Set storage hint. Can also use GL_STORAGE_SHARED_APPLE see docs.
1934         glTexParameteri(m_textureTarget, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
1935       #endif
1936     #endif
1937
1938     // Using BGRA extension to pull in video frame data directly
1939     glTexSubImage2D(m_textureTarget, 0, 0, 0, bufferWidth, bufferHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bufferBase);
1940
1941     #if !TARGET_OS_IPHONE
1942       #ifdef GL_UNPACK_ROW_LENGTH
1943         // Unset row pixels
1944         glPixelStorei( GL_UNPACK_ROW_LENGTH, 0);
1945       #endif
1946     #endif
1947     glBindTexture(m_textureTarget, 0);
1948
1949     glDisable(m_textureTarget);
1950     VerifyGLState();
1951
1952     CVPixelBufferUnlockBaseAddress(cvBufferRef, kCVPixelBufferLock_ReadOnly);
1953     CVBufferRelease(m_buffers[index].cvBufferRef);
1954     m_buffers[index].cvBufferRef = NULL;
1955
1956     plane.flipindex = m_buffers[index].flipindex;
1957   }
1958 #endif
1959 }
1960 void CLinuxRendererGLES::DeleteCVRefTexture(int index)
1961 {
1962 #ifdef HAVE_VIDEOTOOLBOXDECODER
1963   YUVPLANE &plane = m_buffers[index].fields[0][0];
1964
1965   if (m_buffers[index].cvBufferRef)
1966     CVBufferRelease(m_buffers[index].cvBufferRef);
1967   m_buffers[index].cvBufferRef = NULL;
1968
1969   if(plane.id && glIsTexture(plane.id))
1970     glDeleteTextures(1, &plane.id);
1971   plane.id = 0;
1972 #endif
1973 }
1974 bool CLinuxRendererGLES::CreateCVRefTexture(int index)
1975 {
1976 #ifdef HAVE_VIDEOTOOLBOXDECODER
1977   YV12Image &im     = m_buffers[index].image;
1978   YUVFIELDS &fields = m_buffers[index].fields;
1979   YUVPLANE  &plane  = fields[0][0];
1980
1981   DeleteCVRefTexture(index);
1982
1983   memset(&im    , 0, sizeof(im));
1984   memset(&fields, 0, sizeof(fields));
1985
1986   im.height = m_sourceHeight;
1987   im.width  = m_sourceWidth;
1988
1989   plane.texwidth  = im.width;
1990   plane.texheight = im.height;
1991
1992   if(m_renderMethod & RENDER_POT)
1993   {
1994     plane.texwidth  = NP2(plane.texwidth);
1995     plane.texheight = NP2(plane.texheight);
1996   }
1997   glEnable(m_textureTarget);
1998   glGenTextures(1, &plane.id);
1999   VerifyGLState();
2000
2001   glBindTexture(m_textureTarget, plane.id);
2002   #if !TARGET_OS_IPHONE
2003     #ifdef GL_UNPACK_ROW_LENGTH
2004       // Set row pixels
2005       glPixelStorei(GL_UNPACK_ROW_LENGTH, m_sourceWidth);
2006     #endif
2007     #ifdef GL_TEXTURE_STORAGE_HINT_APPLE
2008       // Set storage hint. Can also use GL_STORAGE_SHARED_APPLE see docs.
2009       glTexParameteri(m_textureTarget, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
2010       // Set client storage
2011     #endif
2012     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2013   #endif
2014
2015   glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2016   glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2017         // This is necessary for non-power-of-two textures
2018   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2019   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2020   glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
2021   glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
2022
2023   #if !TARGET_OS_IPHONE
2024     // turn off client storage so it doesn't get picked up for the next texture
2025     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2026   #endif
2027   glBindTexture(m_textureTarget, 0);
2028   glDisable(m_textureTarget);
2029 #endif
2030   return true;
2031 }
2032
2033 //********************************************************************************************************
2034 // BYPASS creation, deletion, copying + clearing
2035 //********************************************************************************************************
2036 void CLinuxRendererGLES::UploadBYPASSTexture(int index)
2037 {
2038 }
2039 void CLinuxRendererGLES::DeleteBYPASSTexture(int index)
2040 {
2041 }
2042 bool CLinuxRendererGLES::CreateBYPASSTexture(int index)
2043 {
2044   return true;
2045 }
2046
2047 //********************************************************************************************************
2048 // EGLIMG creation, deletion, copying + clearing
2049 //********************************************************************************************************
2050 void CLinuxRendererGLES::UploadEGLIMGTexture(int index)
2051 {
2052 #ifdef HAS_LIBSTAGEFRIGHT
2053 #ifdef DEBUG_VERBOSE
2054   unsigned int time = XbmcThreads::SystemClockMillis();
2055 #endif
2056
2057   if(m_buffers[index].eglimg != EGL_NO_IMAGE_KHR)
2058   {
2059     YUVPLANE &plane = m_buffers[index].fields[0][0];
2060
2061     glActiveTexture(GL_TEXTURE0);
2062     glBindTexture(m_textureTarget, plane.id);
2063     glEGLImageTargetTexture2DOES(m_textureTarget, (EGLImageKHR)m_buffers[index].eglimg);
2064     glBindTexture(m_textureTarget, 0);
2065
2066     plane.flipindex = m_buffers[index].flipindex;
2067   }
2068
2069 #ifdef DEBUG_VERBOSE
2070   CLog::Log(LOGDEBUG, "UploadEGLIMGTexture %d: img:%p, tm:%d\n", index, m_buffers[index].eglimg, XbmcThreads::SystemClockMillis() - time);
2071 #endif
2072 #endif
2073 }
2074 void CLinuxRendererGLES::DeleteEGLIMGTexture(int index)
2075 {
2076 #ifdef HAS_LIBSTAGEFRIGHT
2077   YUVPLANE &plane = m_buffers[index].fields[0][0];
2078
2079   if(plane.id && glIsTexture(plane.id))
2080     glDeleteTextures(1, &plane.id);
2081   plane.id = 0;
2082 #endif
2083 }
2084 bool CLinuxRendererGLES::CreateEGLIMGTexture(int index)
2085 {
2086 #ifdef HAS_LIBSTAGEFRIGHT
2087   YV12Image &im     = m_buffers[index].image;
2088   YUVFIELDS &fields = m_buffers[index].fields;
2089   YUVPLANE  &plane  = fields[0][0];
2090
2091   DeleteEGLIMGTexture(index);
2092
2093   memset(&im    , 0, sizeof(im));
2094   memset(&fields, 0, sizeof(fields));
2095
2096   im.height = m_sourceHeight;
2097   im.width  = m_sourceWidth;
2098
2099   plane.texwidth  = im.width;
2100   plane.texheight = im.height;
2101
2102   if(m_renderMethod & RENDER_POT)
2103   {
2104     plane.texwidth  = NP2(plane.texwidth);
2105     plane.texheight = NP2(plane.texheight);
2106   }
2107   glEnable(m_textureTarget);
2108   glGenTextures(1, &plane.id);
2109   VerifyGLState();
2110
2111   glBindTexture(m_textureTarget, plane.id);
2112
2113   glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2114   glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2115         // This is necessary for non-power-of-two textures
2116   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2117   glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2118
2119   glTexImage2D(m_textureTarget, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2120
2121   glDisable(m_textureTarget);
2122 #endif
2123   return true;
2124 }
2125
2126 //********************************************************************************************************
2127 // SurfaceTexture creation, deletion, copying + clearing
2128 //********************************************************************************************************
2129 void CLinuxRendererGLES::UploadSurfaceTexture(int index)
2130 {
2131 #if defined(TARGET_ANDROID)
2132 #ifdef DEBUG_VERBOSE
2133   unsigned int time = XbmcThreads::SystemClockMillis();
2134 #endif
2135
2136   int mindex = -1;
2137   YUVBUFFER &buf = m_buffers[index];
2138
2139   if (buf.mediacodec)
2140   {
2141     mindex = buf.mediacodec->GetIndex();
2142     buf.fields[0][0].id = buf.mediacodec->GetTextureID();
2143     buf.mediacodec->UpdateTexImage();
2144     buf.mediacodec->GetTransformMatrix(m_textureMatrix);
2145     SAFE_RELEASE(buf.mediacodec);
2146   }
2147
2148 #ifdef DEBUG_VERBOSE
2149   CLog::Log(LOGDEBUG, "UploadSurfaceTexture %d: img: %d tm:%d", index, mindex, XbmcThreads::SystemClockMillis() - time);
2150 #endif
2151 #endif
2152 }
2153 void CLinuxRendererGLES::DeleteSurfaceTexture(int index)
2154 {
2155 #if defined(TARGET_ANDROID)
2156   SAFE_RELEASE(m_buffers[index].mediacodec);
2157 #endif
2158 }
2159 bool CLinuxRendererGLES::CreateSurfaceTexture(int index)
2160 {
2161   return true;
2162 }
2163
2164 void CLinuxRendererGLES::SetTextureFilter(GLenum method)
2165 {
2166   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
2167   {
2168     YUVFIELDS &fields = m_buffers[i].fields;
2169
2170     for (int f = FIELD_FULL; f<=FIELD_BOT ; f++)
2171     {
2172       glBindTexture(m_textureTarget, fields[f][0].id);
2173       glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2174       glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2175       VerifyGLState();
2176
2177       if (!(m_renderMethod & RENDER_SW))
2178       {
2179         glBindTexture(m_textureTarget, fields[f][1].id);
2180         glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2181         glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2182         VerifyGLState();
2183
2184         glBindTexture(m_textureTarget, fields[f][2].id);
2185         glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, method);
2186         glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, method);
2187         VerifyGLState();
2188       }
2189     }
2190   }
2191 }
2192
2193 bool CLinuxRendererGLES::Supports(ERENDERFEATURE feature)
2194 {
2195   // Player controls render, let it dictate available render features
2196   if((m_renderMethod & RENDER_BYPASS))
2197   {
2198     Features::iterator itr = std::find(m_renderFeatures.begin(),m_renderFeatures.end(), feature);
2199     return itr != m_renderFeatures.end();
2200   }
2201
2202   if(feature == RENDERFEATURE_BRIGHTNESS)
2203     return false;
2204
2205   if(feature == RENDERFEATURE_CONTRAST)
2206     return false;
2207
2208   if(feature == RENDERFEATURE_GAMMA)
2209     return false;
2210
2211   if(feature == RENDERFEATURE_NOISE)
2212     return false;
2213
2214   if(feature == RENDERFEATURE_SHARPNESS)
2215     return false;
2216
2217   if (feature == RENDERFEATURE_NONLINSTRETCH)
2218     return false;
2219
2220   if (feature == RENDERFEATURE_STRETCH         ||
2221       feature == RENDERFEATURE_CROP            ||
2222       feature == RENDERFEATURE_ZOOM            ||
2223       feature == RENDERFEATURE_VERTICAL_SHIFT  ||
2224       feature == RENDERFEATURE_PIXEL_RATIO     ||
2225       feature == RENDERFEATURE_POSTPROCESS     ||
2226       feature == RENDERFEATURE_ROTATION)
2227     return true;
2228
2229
2230   return false;
2231 }
2232
2233 bool CLinuxRendererGLES::SupportsMultiPassRendering()
2234 {
2235   return false;
2236 }
2237
2238 bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode)
2239 {
2240   // Player controls render, let it dictate available deinterlace modes
2241   if((m_renderMethod & RENDER_BYPASS))
2242   {
2243     Features::iterator itr = std::find(m_deinterlaceModes.begin(),m_deinterlaceModes.end(), mode);
2244     return itr != m_deinterlaceModes.end();
2245   }
2246
2247   if (mode == VS_DEINTERLACEMODE_OFF)
2248     return true;
2249
2250   if(m_renderMethod & RENDER_OMXEGL)
2251     return false;
2252
2253   if(m_renderMethod & RENDER_EGLIMG)
2254     return false;
2255
2256   if(m_renderMethod & RENDER_CVREF)
2257     return false;
2258
2259   if(mode == VS_DEINTERLACEMODE_AUTO
2260   || mode == VS_DEINTERLACEMODE_FORCE)
2261     return true;
2262
2263   return false;
2264 }
2265
2266 bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method)
2267 {
2268   // Player controls render, let it dictate available deinterlace methods
2269   if((m_renderMethod & RENDER_BYPASS))
2270   {
2271     Features::iterator itr = std::find(m_deinterlaceMethods.begin(),m_deinterlaceMethods.end(), method);
2272     return itr != m_deinterlaceMethods.end();
2273   }
2274
2275   if(m_renderMethod & RENDER_OMXEGL)
2276     return false;
2277
2278   if(m_renderMethod & RENDER_EGLIMG)
2279     return false;
2280
2281   if(m_renderMethod & RENDER_MEDIACODEC)
2282     return false;
2283
2284   if(m_renderMethod & RENDER_CVREF)
2285     return false;
2286
2287   if(method == VS_INTERLACEMETHOD_AUTO)
2288     return true;
2289
2290 #if defined(__i386__) || defined(__x86_64__)
2291   if(method == VS_INTERLACEMETHOD_DEINTERLACE
2292   || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF
2293   || method == VS_INTERLACEMETHOD_SW_BLEND)
2294 #else
2295   if(method == VS_INTERLACEMETHOD_SW_BLEND)
2296 #endif
2297     return true;
2298
2299   return false;
2300 }
2301
2302 bool CLinuxRendererGLES::Supports(ESCALINGMETHOD method)
2303 {
2304   // Player controls render, let it dictate available scaling methods
2305   if((m_renderMethod & RENDER_BYPASS))
2306   {
2307     Features::iterator itr = std::find(m_scalingMethods.begin(),m_scalingMethods.end(), method);
2308     return itr != m_scalingMethods.end();
2309   }
2310
2311   if(method == VS_SCALINGMETHOD_NEAREST
2312   || method == VS_SCALINGMETHOD_LINEAR)
2313     return true;
2314
2315   return false;
2316 }
2317
2318 EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod()
2319 {
2320   // Player controls render, let it pick the auto-deinterlace method
2321   if((m_renderMethod & RENDER_BYPASS))
2322   {
2323     if (!m_deinterlaceMethods.empty())
2324       return ((EINTERLACEMETHOD)m_deinterlaceMethods[0]);
2325     else
2326       return VS_INTERLACEMETHOD_NONE;
2327   }
2328
2329   if(m_renderMethod & RENDER_OMXEGL)
2330     return VS_INTERLACEMETHOD_NONE;
2331
2332   if(m_renderMethod & RENDER_EGLIMG)
2333     return VS_INTERLACEMETHOD_NONE;
2334
2335   if(m_renderMethod & RENDER_CVREF)
2336     return VS_INTERLACEMETHOD_NONE;
2337
2338 #if defined(__i386__) || defined(__x86_64__)
2339   return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
2340 #else
2341   return VS_INTERLACEMETHOD_SW_BLEND;
2342 #endif
2343 }
2344
2345 unsigned int CLinuxRendererGLES::GetProcessorSize()
2346 {
2347   if(m_format == RENDER_FMT_OMXEGL
2348   || m_format == RENDER_FMT_CVBREF
2349   || m_format == RENDER_FMT_EGLIMG
2350   || m_format == RENDER_FMT_MEDIACODEC)
2351     return 1;
2352   else
2353     return 0;
2354 }
2355
2356 #ifdef HAVE_LIBOPENMAX
2357 void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index)
2358 {
2359   YUVBUFFER &buf = m_buffers[index];
2360   buf.openMaxBuffer = picture->openMaxBuffer;
2361 }
2362 #endif
2363 #ifdef HAVE_VIDEOTOOLBOXDECODER
2364 void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index)
2365 {
2366   YUVBUFFER &buf = m_buffers[index];
2367   if (buf.cvBufferRef)
2368     CVBufferRelease(buf.cvBufferRef);
2369   buf.cvBufferRef = cvBufferRef;
2370   // retain another reference, this way dvdplayer and renderer can issue releases.
2371   CVBufferRetain(buf.cvBufferRef);
2372 }
2373 #endif
2374 #ifdef HAS_LIBSTAGEFRIGHT
2375 void CLinuxRendererGLES::AddProcessor(CStageFrightVideo* stf, EGLImageKHR eglimg, int index)
2376 {
2377 #ifdef DEBUG_VERBOSE
2378   unsigned int time = XbmcThreads::SystemClockMillis();
2379 #endif
2380
2381   YUVBUFFER &buf = m_buffers[index];
2382   if (buf.eglimg != EGL_NO_IMAGE_KHR)
2383     stf->ReleaseBuffer(buf.eglimg);
2384   stf->LockBuffer(eglimg);
2385
2386   buf.stf = stf;
2387   buf.eglimg = eglimg;
2388
2389 #ifdef DEBUG_VERBOSE
2390   CLog::Log(LOGDEBUG, "AddProcessor %d: img:%p: tm:%d\n", index, eglimg, XbmcThreads::SystemClockMillis() - time);
2391 #endif
2392 }
2393 #endif
2394
2395 #if defined(TARGET_ANDROID)
2396 void CLinuxRendererGLES::AddProcessor(CDVDMediaCodecInfo *mediacodec, int index)
2397 {
2398 #ifdef DEBUG_VERBOSE
2399   unsigned int time = XbmcThreads::SystemClockMillis();
2400 #endif
2401
2402   int mindex = -1;
2403   YUVBUFFER &buf = m_buffers[index];
2404   if (mediacodec)
2405   {
2406     buf.mediacodec = mediacodec->Retain();
2407     mindex = buf.mediacodec->GetIndex();
2408     // releaseOutputBuffer must be in same thread as
2409     // dequeueOutputBuffer. We are in DVDPlayerVideo
2410     // thread here, so we are safe.
2411     buf.mediacodec->ReleaseOutputBuffer(true);
2412   }
2413
2414 #ifdef DEBUG_VERBOSE
2415   CLog::Log(LOGDEBUG, "AddProcessor %d: img:%d tm:%d", index, mindex, XbmcThreads::SystemClockMillis() - time);
2416 #endif
2417 }
2418 #endif
2419
2420 #endif
2421