[ARM] Added neccessary GLES, EGL and other arm related files
[xbmc:xbmc-antiquated.git] / trunk / xbmc / cores / VideoRenderers / LinuxRendererGLES.cpp
1 /*
2 * XBMC Media Center
3 * Linux OpenGL Renderer
4 * Copyright (c) 2007 Frodo/jcmarshall/vulkanr/d4rk
5 *
6 * Based on XBoxRenderer by Frodo/jcmarshall
7 * Portions Copyright (c) by the authors of ffmpeg / xvid /mplayer
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 #include "system.h"
24 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
25   #include "config.h"
26 #endif
27
28 #if HAS_GLES == 2
29 #include <locale.h>
30 #include "MatrixGLES.h"
31 #include "LinuxRendererGLES.h"
32 #include "Application.h"
33 #include "MathUtils.h"
34 #include "Settings.h"
35 #include "AdvancedSettings.h"
36 #include "GUISettings.h"
37 #include "FrameBufferObject.h"
38 #include "VideoShaders/YUV2RGBShader.h"
39 #include "VideoShaders/VideoFilterShader.h"
40 #include "WindowingFactory.h"
41 #include "Texture.h"
42
43 using namespace Shaders;
44
45 CLinuxRendererGLES::CLinuxRendererGLES()
46 {
47   for (int i = 0; i < NUM_BUFFERS; i++)
48     m_eventTexturesDone[i] = CreateEvent(NULL,FALSE,TRUE,NULL);
49
50   m_renderMethod = RENDER_GLSL;
51   m_renderQuality = RQ_SINGLEPASS;
52   m_iFlags = 0;
53
54   m_iYV12RenderBuffer = 0;
55   m_flipindex = 0;
56   m_currentField = FIELD_FULL;
57   m_reloadShaders = 0;
58   m_pYUVShader = NULL;
59   m_pVideoFilterShader = NULL;
60   m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
61   m_scalingMethodGui = (ESCALINGMETHOD)-1;
62   m_upscalingWidth = 0;
63   m_upscalingHeight = 0;
64   memset(&m_imScaled, 0, sizeof(m_imScaled));
65   m_isSoftwareUpscaling = false;
66
67   memset(m_buffers, 0, sizeof(m_buffers));
68
69   m_rgbBuffer = NULL;
70   m_rgbBufferSize = 0;
71 }
72
73 CLinuxRendererGLES::~CLinuxRendererGLES()
74 {
75   UnInit();
76   for (int i = 0; i < NUM_BUFFERS; i++)
77     CloseHandle(m_eventTexturesDone[i]);
78
79   if (m_rgbBuffer != NULL) {
80     delete [] m_rgbBuffer;
81     m_rgbBuffer = NULL;
82   }
83   for (int i=0; i<3; i++)
84   {
85     if (m_imScaled.plane[i])
86     {
87       delete [] m_imScaled.plane[i];
88       m_imScaled.plane[i] = 0;
89     }
90   }
91
92   if (m_pYUVShader)
93   {
94     m_pYUVShader->Free();
95     delete m_pYUVShader;
96     m_pYUVShader = NULL;
97   }
98 }
99
100 void CLinuxRendererGLES::ManageTextures()
101 {
102   m_NumYV12Buffers = 2;
103   //m_iYV12RenderBuffer = 0;
104   return;
105 }
106
107 bool CLinuxRendererGLES::ValidateRenderTarget()
108 {
109   if (!m_bValidated)
110   {
111     CLog::Log(LOGNOTICE,"Using GL_TEXTURE_2D");
112
113      // create the yuv textures    
114     LoadShaders();
115     for (int i = 0 ; i < m_NumYV12Buffers ; i++)
116     {
117       CreateYV12Texture(i);
118     }
119     m_bValidated = true;
120     return true;
121   }
122   return false;  
123 }
124
125 bool CLinuxRendererGLES::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags)
126 {
127   m_sourceWidth = width;
128   m_sourceHeight = height;
129
130   // Save the flags.
131   m_iFlags = flags;
132
133   // Calculate the input frame aspect ratio.
134   CalculateFrameAspectRatio(d_width, d_height);
135   ChooseBestResolution(fps);
136   SetViewMode(g_settings.m_currentVideoSettings.m_ViewMode);
137   ManageDisplay();
138
139   ChooseUpscalingMethod();
140
141   m_bConfigured = true;
142   m_bImageReady = false;
143   m_scalingMethodGui = (ESCALINGMETHOD)-1;
144
145   // Ensure that textures are recreated and rendering starts only after the 1st 
146   // frame is loaded after every call to Configure().
147   m_bValidated = false;
148
149   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
150     m_buffers[i].image.flags = 0;
151
152   m_iLastRenderBuffer = -1;
153   return true;
154 }
155
156 void CLinuxRendererGLES::ChooseUpscalingMethod()
157 {
158   m_upscalingWidth  = m_destRect.Width();
159   m_upscalingHeight = m_destRect.Height();
160
161   int upscale = g_advancedSettings.m_videoHighQualityScaling;
162   
163   // See if we're a candiate for upscaling.
164   bool candidateForUpscaling = false;
165   if (upscale != SOFTWARE_UPSCALING_DISABLED && (int)m_sourceWidth < m_upscalingWidth && (int)m_sourceHeight < m_upscalingHeight)
166   {
167     CLog::Log(LOGWARNING, "Upscale: possible given resolution increase.");
168     candidateForUpscaling = true;
169   }
170
171   // Turn if off if we're told to upscale HD content and we're not always on.
172   if (upscale == SOFTWARE_UPSCALING_SD_CONTENT && (m_sourceHeight >= 720 || m_sourceWidth >= 1280))
173   {
174     CLog::Log(LOGWARNING, "Upscale: Disabled due to HD source.");
175     candidateForUpscaling = false;
176   }
177
178   if (candidateForUpscaling)
179   {
180     ESCALINGMETHOD ret = (ESCALINGMETHOD)g_advancedSettings.m_videoHighQualityScalingMethod;
181
182     // Make sure to override the default setting for the video
183     g_settings.m_currentVideoSettings.m_ScalingMethod = ret;
184
185     // Initialize software upscaling.
186     if (g_advancedSettings.m_videoHighQualityScalingMethod < 10) //non-hardware
187     {
188       InitializeSoftwareUpscaling();
189       CLog::Log(LOGWARNING, "Upscale: selected algorithm %d", ret);
190     }
191   }
192 }
193
194 void CLinuxRendererGLES::InitializeSoftwareUpscaling()
195 {
196   // Allocate a new destination image.
197   m_imScaled.cshift_x = m_imScaled.cshift_y = 1;
198
199   // Free the old planes if they exist.
200   for (int i=0; i<3; i++)
201   {
202     if (m_imScaled.plane[i])
203     {
204       delete [] m_imScaled.plane[i];
205       m_imScaled.plane[i] = 0;
206     }
207   }
208
209   m_imScaled.stride[0] = ALIGN((m_upscalingWidth)   , 16);
210   m_imScaled.stride[1] = ALIGN((m_upscalingWidth>>1), 16);
211   m_imScaled.stride[2] = ALIGN((m_upscalingWidth>>1), 16);
212   m_imScaled.plane[0] = new BYTE[m_imScaled.stride[0] * ALIGN((m_upscalingHeight)   , 16)];
213   m_imScaled.plane[1] = new BYTE[m_imScaled.stride[1] * ALIGN((m_upscalingHeight>>1), 16)];
214   m_imScaled.plane[2] = new BYTE[m_imScaled.stride[2] * ALIGN((m_upscalingHeight>>1), 16)];
215   m_imScaled.width = m_upscalingWidth;
216   m_imScaled.height = m_upscalingHeight;
217   m_imScaled.flags = 0;
218 }
219
220 bool CLinuxRendererGLES::IsSoftwareUpscaling()
221 {
222   // See if we should be performing software upscaling on this frame.
223   if (m_scalingMethod < VS_SCALINGMETHOD_BICUBIC_SOFTWARE ||
224        (m_currentField != FIELD_FULL && 
225         g_settings.m_currentVideoSettings.m_InterlaceMethod!=VS_INTERLACEMETHOD_NONE && 
226         g_settings.m_currentVideoSettings.m_InterlaceMethod!=VS_INTERLACEMETHOD_DEINTERLACE))
227   {
228     return false;
229   }
230
231   return true;
232 }
233
234 int CLinuxRendererGLES::NextYV12Texture()
235 {
236   return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers;
237 }
238
239 int CLinuxRendererGLES::GetImage(YV12Image *image, int source, bool readonly)
240 {
241   if (!image) return -1;
242   if (!m_bValidated) return -1;
243
244   /* take next available buffer */
245   if( source == AUTOSOURCE )
246     source = NextYV12Texture();
247
248   YV12Image &im = m_buffers[source].image;
249   if (!im.plane[0])
250   {
251      CLog::Log(LOGDEBUG, "CLinuxRenderer::GetImage - image planes not allocated");
252      return -1;
253   }
254
255   if ((im.flags&(~IMAGE_FLAG_READY)) != 0)
256   {
257      CLog::Log(LOGDEBUG, "CLinuxRenderer::GetImage - request image but none to give");
258      return -1;
259   }
260
261   if( readonly )
262     im.flags |= IMAGE_FLAG_READING;
263   else
264   {
265     if( WaitForSingleObject(m_eventTexturesDone[source], 500) == WAIT_TIMEOUT )
266       CLog::Log(LOGWARNING, "%s - Timeout waiting for texture %d", __FUNCTION__, source);
267
268     im.flags |= IMAGE_FLAG_WRITING;
269   }
270
271   // copy the image - should be operator of YV12Image
272   for (int p=0;p<MAX_PLANES;p++)
273   {
274     image->plane[p]  = im.plane[p];
275     image->stride[p] = im.stride[p];
276   }
277   image->width    = im.width;
278   image->height   = im.height;
279   image->flags    = im.flags;
280   image->cshift_x = im.cshift_x;
281   image->cshift_y = im.cshift_y;
282
283   return source;
284
285   return -1;
286 }
287
288 void CLinuxRendererGLES::ReleaseImage(int source, bool preserve)
289 {
290   YV12Image &im = m_buffers[source].image;
291
292   if( im.flags & IMAGE_FLAG_WRITING )
293     SetEvent(m_eventTexturesDone[source]);
294
295   im.flags &= ~IMAGE_FLAG_INUSE;
296   im.flags |= IMAGE_FLAG_READY;
297   /* if image should be preserved reserve it so it's not auto seleceted */
298
299   if( preserve )
300     im.flags |= IMAGE_FLAG_RESERVED;
301
302   m_bImageReady = true;
303 }
304
305 void CLinuxRendererGLES::LoadPlane( YUVPLANE& plane, int type, unsigned flipindex
306                                 , unsigned width, unsigned height
307                                 , int stride, void* data )
308 {
309   if(plane.flipindex == flipindex)
310     return;
311
312   glBindTexture(GL_TEXTURE_2D, plane.id);
313   glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, type, GL_UNSIGNED_BYTE, data);
314
315   /* check if we need to load any border pixels */
316   if(height < plane.texheight)
317     glTexSubImage2D( GL_TEXTURE_2D, 0
318                    , 0, height, width, 1
319                    , type, GL_UNSIGNED_BYTE
320                    , (unsigned char*)data + stride * (height-1));
321
322   if(width  < plane.texwidth)
323     glTexSubImage2D( GL_TEXTURE_2D, 0
324                    , width, 0, 1, height
325                    , type, GL_UNSIGNED_BYTE
326                    , (unsigned char*)data + stride - 1);
327
328   glBindTexture(GL_TEXTURE_2D, 0);
329
330   plane.flipindex = flipindex;
331 }
332
333 void CLinuxRendererGLES::LoadTextures(int source)
334 {
335   YUVBUFFER& buf    =  m_buffers[source];
336   YV12Image* im     = &buf.image;
337   YUVFIELDS& fields =  buf.fields;
338
339   if (!(im->flags&IMAGE_FLAG_READY))
340   {
341     SetEvent(m_eventTexturesDone[source]);
342     return;
343   }
344
345   // See if we need to recreate textures.
346   if (m_isSoftwareUpscaling != IsSoftwareUpscaling())
347   {
348     for (int i = 0 ; i < m_NumYV12Buffers ; i++)
349       CreateYV12Texture(i);
350
351     im->flags = IMAGE_FLAG_READY;
352   }
353
354   // if we don't have a shader, fallback to SW YUV2RGB for now
355   if (m_renderMethod & RENDER_SW)
356   {
357     if(m_rgbBufferSize < m_sourceWidth * m_sourceHeight * 4)
358     {
359       delete [] m_rgbBuffer;
360       m_rgbBufferSize = m_sourceWidth*m_sourceHeight*4;
361       m_rgbBuffer = new BYTE[m_rgbBufferSize];
362     }
363
364     struct SwsContext *context = m_dllSwScale.sws_getContext(im->width, im->height, PIX_FMT_YUV420P,
365                                                              im->width, im->height, PIX_FMT_BGRA,
366                                                              SWS_FAST_BILINEAR, NULL, NULL, NULL);
367     uint8_t *src[] = { im->plane[0], im->plane[1], im->plane[2], 0 };
368     int     srcStride[] = { im->stride[0], im->stride[1], im->stride[2], 0 };
369     uint8_t *dst[] = { m_rgbBuffer, 0, 0, 0 };
370     int     dstStride[] = { m_sourceWidth*4, 0, 0, 0 };
371     m_dllSwScale.sws_scale(context, src, srcStride, 0, im->height, dst, dstStride);
372     m_dllSwScale.sws_freeContext(context);
373     SetEvent(m_eventTexturesDone[source]);
374   }
375   else if (IsSoftwareUpscaling()) // FIXME: s/w upscaling + RENDER_SW => broken
376   {
377     // Perform the scaling.
378     uint8_t* src[] =       { im->plane[0],  im->plane[1],  im->plane[2], 0 };
379     int      srcStride[] = { im->stride[0], im->stride[1], im->stride[2], 0 };
380     uint8_t* dst[] =       { m_imScaled.plane[0],  m_imScaled.plane[1],  m_imScaled.plane[2], 0 };
381     int      dstStride[] = { m_imScaled.stride[0], m_imScaled.stride[1], m_imScaled.stride[2], 0 };
382     int      algorithm   = 0;
383
384     switch (m_scalingMethod)
385     {
386     case VS_SCALINGMETHOD_BICUBIC_SOFTWARE: algorithm = SWS_BICUBIC; break;
387     case VS_SCALINGMETHOD_LANCZOS_SOFTWARE: algorithm = SWS_LANCZOS; break;
388     case VS_SCALINGMETHOD_SINC_SOFTWARE:    algorithm = SWS_SINC;    break;
389     default: break;
390     }
391
392     struct SwsContext *ctx = m_dllSwScale.sws_getContext(im->width, im->height, PIX_FMT_YUV420P,
393                                                          m_upscalingWidth, m_upscalingHeight, PIX_FMT_YUV420P,
394                                                          algorithm, NULL, NULL, NULL);
395     m_dllSwScale.sws_scale(ctx, src, srcStride, 0, im->height, dst, dstStride);
396     m_dllSwScale.sws_freeContext(ctx);
397
398     im = &m_imScaled;
399     im->flags = IMAGE_FLAG_READY;
400   }
401
402   bool deinterlacing;
403   if (m_currentField == FIELD_FULL)
404     deinterlacing = false;
405   else
406     deinterlacing = true;
407
408   glEnable(GL_TEXTURE_2D);
409   VerifyGLState();
410
411   if (m_renderMethod & RENDER_SW)
412   {
413     // Load RGB image
414     if (deinterlacing)
415     {
416       LoadPlane( fields[FIELD_ODD][0] , GL_RGBA, buf.flipindex
417                , im->width, im->height >> 1
418                , m_sourceWidth*2, m_rgbBuffer );
419
420       LoadPlane( fields[FIELD_EVEN][0], GL_RGBA, buf.flipindex
421                , im->width, im->height >> 1
422                , m_sourceWidth*2, m_rgbBuffer + m_sourceWidth*4);      
423     }
424     else
425     {
426       LoadPlane( fields[FIELD_FULL][0], GL_RGBA, buf.flipindex
427                , im->width, im->height
428                , m_sourceWidth, m_rgbBuffer );
429     }
430   }
431   else
432   {
433     glPixelStorei(GL_UNPACK_ALIGNMENT,1);
434
435     if (deinterlacing)
436     {
437       // Load Y fields
438       LoadPlane( fields[FIELD_ODD][0] , GL_LUMINANCE, buf.flipindex
439                , im->width, im->height >> 1
440                , im->stride[0]*2, im->plane[0] );
441
442       LoadPlane( fields[FIELD_EVEN][0], GL_LUMINANCE, buf.flipindex
443                , im->width, im->height >> 1
444                , im->stride[0]*2, im->plane[0] + im->stride[0]) ;     
445     }
446     else
447     {
448       // Load Y plane
449       LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
450                , im->width, im->height
451                , im->stride[0], im->plane[0] );
452     }
453   }
454
455   VerifyGLState();
456
457   if (!(m_renderMethod & RENDER_SW))
458   {
459     glPixelStorei(GL_UNPACK_ALIGNMENT,1);
460
461     if (deinterlacing)
462     {
463       // Load Even U & V Fields
464       LoadPlane( fields[FIELD_ODD][1], GL_LUMINANCE, buf.flipindex
465                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
466                , im->stride[1]*2, im->plane[1] );
467
468       LoadPlane( fields[FIELD_ODD][2], GL_LUMINANCE, buf.flipindex
469                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
470                , im->stride[2]*2, im->plane[2] );
471       
472       // Load Odd U & V Fields
473       LoadPlane( fields[FIELD_EVEN][1], GL_LUMINANCE, buf.flipindex
474                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
475                , im->stride[1]*2, im->plane[1] + im->stride[1] );
476
477       LoadPlane( fields[FIELD_EVEN][2], GL_LUMINANCE, buf.flipindex
478                , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
479                , im->stride[2]*2, im->plane[2] + im->stride[2] );
480       
481     }
482     else
483     {
484       LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, buf.flipindex
485                , im->width >> im->cshift_x, im->height >> im->cshift_y
486                , im->stride[1], im->plane[1] );
487
488       LoadPlane( fields[FIELD_FULL][2], GL_LUMINANCE, buf.flipindex
489                , im->width >> im->cshift_x, im->height >> im->cshift_y
490                , im->stride[2], im->plane[2] );
491     }
492   }
493   SetEvent(m_eventTexturesDone[source]);
494
495   // calculate the source rectangle
496   for(int field = 0; field < 3; field++)
497   {
498     for(int plane = 0; plane < 3; plane++)
499     {
500       YUVPLANE& p = fields[field][plane];
501
502       /* software upscaling is precropped */
503       if(IsSoftwareUpscaling())
504         p.rect.SetRect(0, 0, im->width, im->height);
505       else      
506         p.rect = m_sourceRect;
507
508       p.width  = im->width;
509       p.height = im->height;
510
511       if(field != FIELD_FULL)
512       {
513         /* correct for field offsets and chroma offsets */
514         float offset_y = 0.5;
515         if(plane != 0)
516           offset_y += 0.5;
517         if(field == FIELD_EVEN)
518           offset_y *= -1;
519
520         p.rect.y1 += offset_y;
521         p.rect.y2 += offset_y;
522
523         /* half the height if this is a field */
524         p.height  *= 0.5f;
525         p.rect.y1 *= 0.5f; 
526         p.rect.y2 *= 0.5f;
527       }
528
529       if(plane != 0)
530       {
531         p.width   /= 1 << im->cshift_x;
532         p.height  /= 1 << im->cshift_y;
533
534         p.rect.x1 /= 1 << im->cshift_x;
535         p.rect.x2 /= 1 << im->cshift_x;
536         p.rect.y1 /= 1 << im->cshift_y;
537         p.rect.y2 /= 1 << im->cshift_y;
538       }
539
540       p.height  /= p.texheight;
541       p.rect.y1 /= p.texheight;
542       p.rect.y2 /= p.texheight;
543       p.width   /= p.texwidth;
544       p.rect.x1 /= p.texwidth;
545       p.rect.x2 /= p.texwidth;
546     }
547   }
548
549   glDisable(GL_TEXTURE_2D);
550 }
551
552 void CLinuxRendererGLES::Reset()
553 {
554   for(int i=0; i<m_NumYV12Buffers; i++)
555   {
556     /* reset all image flags, this will cleanup textures later */
557     m_buffers[i].image.flags = 0;
558     /* reset texture locks, a bit ugly, could result in tearing */
559     SetEvent(m_eventTexturesDone[i]);
560   }
561 }
562
563 void CLinuxRendererGLES::Update(bool bPauseDrawing)
564 {
565   if (!m_bConfigured) return;
566   ManageDisplay();
567   ManageTextures();
568 }
569
570 void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha)
571 {
572   if (!m_bConfigured) return;
573
574   // if its first pass, just init textures and return
575   if (ValidateRenderTarget())
576     return;
577
578   // this needs to be checked after texture validation
579   if (!m_bImageReady) return;
580
581   int index = m_iYV12RenderBuffer;
582   YUVBUFFER& buf =  m_buffers[index];
583
584   if (!buf.fields[FIELD_FULL][0].id) return ;
585
586   if (buf.image.flags==0)
587     return;
588
589   ManageDisplay();
590   ManageTextures();
591
592   g_graphicsContext.BeginPaint();
593
594   if( WaitForSingleObject(m_eventTexturesDone[index], 500) == WAIT_TIMEOUT )
595   {
596     CLog::Log(LOGWARNING, "%s - Timeout waiting for texture %d", __FUNCTION__, index);
597
598     // render the previous frame if this one isn't ready yet
599     if (m_iLastRenderBuffer > -1)
600     {
601       m_iYV12RenderBuffer = m_iLastRenderBuffer;
602       index = m_iYV12RenderBuffer;
603     }
604   }
605   else
606     m_iLastRenderBuffer = index;
607
608   if (clear)
609   {
610     glClearColor(m_clearColour, m_clearColour, m_clearColour, 0);
611     glClear(GL_COLOR_BUFFER_BIT);
612     glClearColor(0,0,0,0);
613   }
614
615   if (alpha<255)
616   {
617     glEnable(GL_BLEND);
618     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
619     m_pYUVShader->SetAlpha(alpha / 255.0f);
620   }
621   else
622   {
623     glDisable(GL_BLEND);
624     m_pYUVShader->SetAlpha(1.0f);
625   }
626
627   if ((flags & RENDER_FLAG_ODD) && (flags & RENDER_FLAG_EVEN))
628     CLog::Log(LOGERROR, "GLES: Cannot render stipple!");
629   else
630     Render(flags, index);
631
632   VerifyGLState();
633   glEnable(GL_BLEND);
634   glFlush();
635
636   g_graphicsContext.EndPaint();
637 }
638
639 void CLinuxRendererGLES::FlipPage(int source)
640 {
641   if( source >= 0 && source < m_NumYV12Buffers )
642     m_iYV12RenderBuffer = source;
643   else
644     m_iYV12RenderBuffer = NextYV12Texture();
645
646   m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex;
647
648   return;
649 }
650
651
652 unsigned int CLinuxRendererGLES::DrawSlice(unsigned char *src[], int stride[], int w, int h, int x, int y)
653 {
654   BYTE *s;
655   BYTE *d;
656   int i, p;
657
658   int index = NextYV12Texture();
659   if( index < 0 )
660     return -1;
661
662   YV12Image &im = m_buffers[index].image;
663   // copy Y
664   p = 0;
665   d = (BYTE*)im.plane[p] + im.stride[p] * y + x;
666   s = src[p];
667   for (i = 0;i < h;i++)
668   {
669     memcpy(d, s, w);
670     s += stride[p];
671     d += im.stride[p];
672   }
673
674   w >>= im.cshift_x; h >>= im.cshift_y;
675   x >>= im.cshift_x; y >>= im.cshift_y;
676
677   // copy U
678   p = 1;
679   d = (BYTE*)im.plane[p] + im.stride[p] * y + x;
680   s = src[p];
681   for (i = 0;i < h;i++)
682   {
683     memcpy(d, s, w);
684     s += stride[p];
685     d += im.stride[p];
686   }
687
688   // copy V
689   p = 2;
690   d = (BYTE*)im.plane[p] + im.stride[p] * y + x;
691   s = src[p];
692   for (i = 0;i < h;i++)
693   {
694     memcpy(d, s, w);
695     s += stride[p];
696     d += im.stride[p];
697   }
698
699   SetEvent(m_eventTexturesDone[index]);
700   return 0;
701 }
702
703 unsigned int CLinuxRendererGLES::PreInit()
704 {
705   CSingleLock lock(g_graphicsContext);
706   m_bConfigured = false;
707   m_bValidated = false;
708   UnInit();
709   m_resolution = RES_PAL_4x3;
710
711   m_iYV12RenderBuffer = 0;
712   m_NumYV12Buffers = 2;
713
714   // setup the background colour
715   m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
716
717   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwScale.Load())
718     CLog::Log(LOGERROR,"CLinuxRendererGL::PreInit - failed to load rescale libraries!");
719
720   #if (! defined USE_EXTERNAL_FFMPEG)
721     m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
722   #elif (defined HAVE_LIBSWSCALE_RGB2RGB_H) || (defined HAVE_FFMPEG_RGB2RGB_H)
723     m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);
724   #endif
725
726   return true;
727 }
728
729 void CLinuxRendererGLES::UpdateVideoFilter()
730 {
731   if (m_scalingMethodGui == g_settings.m_currentVideoSettings.m_ScalingMethod)
732     return;
733   m_scalingMethodGui = g_settings.m_currentVideoSettings.m_ScalingMethod;
734   m_scalingMethod    = m_scalingMethodGui;
735
736   if(!Supports(m_scalingMethod))
737   {
738     CLog::Log(LOGWARNING, "CLinuxRendererGLES::UpdateVideoFilter - choosen scaling method %d, is not supported by renderer", (int)m_scalingMethod);
739     m_scalingMethod = VS_SCALINGMETHOD_LINEAR;
740   }
741
742   if (m_pVideoFilterShader)
743   {
744     m_pVideoFilterShader->Free();
745     delete m_pVideoFilterShader;
746     m_pVideoFilterShader = NULL;
747   }
748   m_fbo.Cleanup();
749
750   VerifyGLState();
751
752   switch (m_scalingMethod)
753   {
754   case VS_SCALINGMETHOD_NEAREST:
755     SetTextureFilter(GL_NEAREST);
756     m_renderQuality = RQ_SINGLEPASS;
757     return;
758
759   case VS_SCALINGMETHOD_LINEAR:
760     SetTextureFilter(GL_LINEAR);
761     m_renderQuality = RQ_SINGLEPASS;
762     return;
763
764   case VS_SCALINGMETHOD_CUBIC:
765     CLog::Log(LOGERROR, "GLES: CUBIC not supported!");
766     break;
767
768   case VS_SCALINGMETHOD_LANCZOS2:
769   case VS_SCALINGMETHOD_LANCZOS3:
770   case VS_SCALINGMETHOD_SINC8:
771   case VS_SCALINGMETHOD_NEDI:
772     CLog::Log(LOGERROR, "GL: TODO: This scaler has not yet been implemented");
773     break;
774
775   case VS_SCALINGMETHOD_BICUBIC_SOFTWARE:
776   case VS_SCALINGMETHOD_LANCZOS_SOFTWARE:
777   case VS_SCALINGMETHOD_SINC_SOFTWARE:
778     InitializeSoftwareUpscaling();
779     m_renderQuality = RQ_SINGLEPASS;
780     return;
781
782   default:
783     break;
784   }
785
786   g_application.m_guiDialogKaiToast.QueueNotification("Video Renderering", "Failed to init video filters/scalers, falling back to bilinear scaling");
787   CLog::Log(LOGERROR, "GL: Falling back to bilinear due to failure to init scaler");
788   if (m_pVideoFilterShader)
789   {
790     m_pVideoFilterShader->Free();
791     delete m_pVideoFilterShader;
792     m_pVideoFilterShader = NULL;
793   }
794   m_fbo.Cleanup();
795
796   SetTextureFilter(GL_LINEAR);
797   m_renderQuality = RQ_SINGLEPASS;
798 }
799
800 void CLinuxRendererGLES::LoadShaders(int field)
801 {
802   int requestedMethod = g_guiSettings.GetInt("videoplayer.rendermethod");
803   CLog::Log(LOGDEBUG, "GL: Requested render method: %d", requestedMethod);
804   bool err = false;
805
806   /*
807     Try GLSL shaders if they're supported and if the user has
808     requested for it. (settings -> video -> player -> rendermethod)
809    */
810   if (glCreateProgram // TODO: proper check
811       && (requestedMethod==RENDER_METHOD_AUTO || requestedMethod==RENDER_METHOD_GLSL))
812   {
813     if (m_pYUVShader)
814     {
815       m_pYUVShader->Free();
816       delete m_pYUVShader;
817       m_pYUVShader = NULL;
818     }
819
820     // create regular progressive scan shader
821     m_pYUVShader = new YUV2RGBProgressiveShader(false, m_iFlags);
822     CLog::Log(LOGNOTICE, "GL: Selecting Single Pass YUV 2 RGB shader");
823
824     if (m_pYUVShader && m_pYUVShader->CompileAndLink())
825     {
826       m_renderMethod = RENDER_GLSL;
827       UpdateVideoFilter();
828     }
829     else
830     {
831       m_pYUVShader->Free();
832       delete m_pYUVShader;
833       m_pYUVShader = NULL;
834       err = true;
835       CLog::Log(LOGERROR, "GL: Error enabling YUV2RGB GLSL shader");
836     }
837   }
838
839   /*
840     Fall back to software YUV 2 RGB conversion if
841       1) user requested it
842       2) or GLSL and/or ARB shaders failed
843    */
844   else
845   {
846     m_renderMethod = RENDER_SW ;
847     CLog::Log(LOGNOTICE, "GL: Shaders support not present, falling back to SW mode");
848   }
849
850   if (err==true)
851   {
852     CLog::Log(LOGERROR, "GL: Falling back to Software YUV2RGB");
853     m_renderMethod = RENDER_SW;
854   }
855
856   // determine whether GPU supports NPOT textures
857   if (!g_Windowing.IsExtSupported("GL_TEXTURE_NPOT"))
858   {
859     CLog::Log(LOGNOTICE, "GL: GL_ARB_texture_rectangle not supported and OpenGL version is not 2.x");
860     CLog::Log(LOGNOTICE, "GL: Reverting to POT textures");
861     m_renderMethod |= RENDER_POT;
862   }
863   else
864     CLog::Log(LOGNOTICE, "GL: NPOT texture support detected");
865 }
866
867 void CLinuxRendererGLES::UnInit()
868 {
869   CLog::Log(LOGDEBUG, "LinuxRendererGL: Cleaning up GL resources");
870   CSingleLock lock(g_graphicsContext);
871
872   if (m_rgbBuffer != NULL)
873   {
874     delete [] m_rgbBuffer;
875     m_rgbBuffer = NULL;
876   }
877   m_rgbBufferSize = 0;
878
879   // YV12 textures
880   for (int i = 0; i < NUM_BUFFERS; ++i)
881     DeleteYV12Texture(i);
882
883   // cleanup framebuffer object if it was in use
884   m_fbo.Cleanup();
885   m_bValidated = false;
886   m_bImageReady = false;
887   m_bConfigured = false;
888 }
889
890 void CLinuxRendererGLES::Render(DWORD flags, int renderBuffer)
891 {
892   // obtain current field, if interlaced
893   if( flags & RENDER_FLAG_ODD)
894     m_currentField = FIELD_ODD;
895
896   else if (flags & RENDER_FLAG_EVEN)
897     m_currentField = FIELD_EVEN;
898
899   else if (flags & RENDER_FLAG_LAST)
900   {
901     switch(m_currentField)
902     {
903     case FIELD_ODD:
904       flags = RENDER_FLAG_ODD;
905       break;
906
907     case FIELD_EVEN:
908       flags = RENDER_FLAG_EVEN;
909       break;
910     }
911   }
912   else
913     m_currentField = FIELD_FULL;
914
915   LoadTextures(renderBuffer);
916
917   if (m_renderMethod & RENDER_GLSL)
918   {
919     UpdateVideoFilter();
920     switch(m_renderQuality)
921     {
922     case RQ_LOW:
923     case RQ_SINGLEPASS:
924       RenderSinglePass(renderBuffer, m_currentField);
925       VerifyGLState();
926       break;
927
928     case RQ_MULTIPASS:
929       RenderMultiPass(renderBuffer, m_currentField);
930       VerifyGLState();
931       break;
932
933     case RQ_SOFTWARE:
934       RenderSoftware(renderBuffer, m_currentField);
935       VerifyGLState();
936       break;
937     }
938   }
939   else
940   {
941     RenderSoftware(renderBuffer, m_currentField);
942     VerifyGLState();
943   }
944 }
945
946 void CLinuxRendererGLES::RenderSinglePass(int index, int field)
947 {
948   YV12Image &im     = m_buffers[index].image;
949   YUVFIELDS &fields = m_buffers[index].fields;
950   YUVPLANES &planes = fields[field];
951
952   // set scissors if we are not in fullscreen video
953   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
954     g_graphicsContext.ClipToViewWindow();
955
956   if (m_reloadShaders)
957   {
958     m_reloadShaders = 0;
959     LoadShaders(field);
960   }
961
962   glDisable(GL_DEPTH_TEST);
963
964   // Y
965   glActiveTexture(GL_TEXTURE0);
966   glEnable(GL_TEXTURE_2D);
967   glBindTexture(GL_TEXTURE_2D, planes[0].id);
968
969   // U
970   glActiveTexture(GL_TEXTURE1);
971   glEnable(GL_TEXTURE_2D);
972   glBindTexture(GL_TEXTURE_2D, planes[1].id);
973
974   // V
975   glActiveTexture(GL_TEXTURE2);
976   glEnable(GL_TEXTURE_2D);
977   glBindTexture(GL_TEXTURE_2D, planes[2].id);
978
979   glActiveTexture(GL_TEXTURE0);
980   VerifyGLState();
981
982   m_pYUVShader->SetBlack(g_settings.m_currentVideoSettings.m_Brightness * 0.01f - 0.5f);
983   m_pYUVShader->SetContrast(g_settings.m_currentVideoSettings.m_Contrast * 0.02f);
984   m_pYUVShader->SetWidth(im.width);
985   m_pYUVShader->SetHeight(im.height);
986   if     (field == FIELD_ODD)
987     m_pYUVShader->SetField(1);
988   else if(field == FIELD_EVEN)
989     m_pYUVShader->SetField(0);
990
991   m_pYUVShader->SetMatrices(g_matrices.GetMatrix(MM_PROJECTION), g_matrices.GetMatrix(MM_MODELVIEW));
992   m_pYUVShader->Enable();
993
994   GLubyte idx[4] = {0, 1, 3, 2};        //determines order of triangle strip
995   GLfloat m_vert[4][3];
996   GLfloat m_tex[3][4][2];
997
998   GLint vertLoc = m_pYUVShader->GetVertexLoc();
999   GLint Yloc    = m_pYUVShader->GetYcoordLoc();
1000   GLint Uloc    = m_pYUVShader->GetUcoordLoc();
1001   GLint Vloc    = m_pYUVShader->GetVcoordLoc();
1002
1003   glVertexAttribPointer(vertLoc, 3, GL_FLOAT, 0, 0, m_vert);
1004   glVertexAttribPointer(Yloc, 2, GL_FLOAT, 0, 0, m_tex[0]);
1005   glVertexAttribPointer(Uloc, 2, GL_FLOAT, 0, 0, m_tex[1]);
1006   glVertexAttribPointer(Vloc, 2, GL_FLOAT, 0, 0, m_tex[2]);
1007
1008   glEnableVertexAttribArray(vertLoc);
1009   glEnableVertexAttribArray(Yloc);
1010   glEnableVertexAttribArray(Uloc);
1011   glEnableVertexAttribArray(Vloc);
1012
1013   // Setup vertex position values
1014   m_vert[0][0] = m_vert[3][0] = m_destRect.x1;
1015   m_vert[0][1] = m_vert[1][1] = m_destRect.y1;
1016   m_vert[1][0] = m_vert[2][0] = m_destRect.x2;
1017   m_vert[2][1] = m_vert[3][1] = m_destRect.y2;
1018   m_vert[0][2] = m_vert[1][2] = m_vert[2][2] = m_vert[3][2] = 0.0f;
1019
1020   // Setup texture coordinates
1021   for (int i=0; i<3; i++)
1022   {
1023     m_tex[i][0][0] = m_tex[i][3][0] = planes[i].rect.x1;
1024     m_tex[i][0][1] = m_tex[i][1][1] = planes[i].rect.y1;
1025     m_tex[i][1][0] = m_tex[i][2][0] = planes[i].rect.x2;
1026     m_tex[i][2][1] = m_tex[i][3][1] = planes[i].rect.y2;
1027   }
1028
1029   glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1030
1031   VerifyGLState();
1032
1033   m_pYUVShader->Disable();
1034   VerifyGLState();
1035
1036   glDisableVertexAttribArray(vertLoc);
1037   glDisableVertexAttribArray(Yloc);
1038   glDisableVertexAttribArray(Uloc);
1039   glDisableVertexAttribArray(Vloc);
1040
1041   glActiveTexture(GL_TEXTURE1);
1042   glDisable(GL_TEXTURE_2D);
1043
1044   glActiveTexture(GL_TEXTURE2);
1045   glDisable(GL_TEXTURE_2D);
1046
1047   glActiveTexture(GL_TEXTURE0);
1048   glDisable(GL_TEXTURE_2D);
1049
1050   g_matrices.MatrixMode(MM_MODELVIEW);
1051
1052   VerifyGLState();
1053 }
1054
1055 void CLinuxRendererGLES::RenderMultiPass(int index, int field)
1056 {
1057   // TODO: Multipass rendering does not currently work! FIX!
1058   CLog::Log(LOGERROR, "GLES: MULTIPASS rendering was called! But it doesnt work!!!");
1059   return;
1060
1061   YV12Image &im     = m_buffers[index].image;
1062   YUVPLANES &planes = m_buffers[index].fields[field];
1063
1064   // set scissors if we are not in fullscreen video
1065   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1066     g_graphicsContext.ClipToViewWindow();
1067
1068   if (m_reloadShaders)
1069   {
1070     m_reloadShaders = 0;
1071     LoadShaders(m_currentField);
1072   }
1073
1074   glDisable(GL_DEPTH_TEST);
1075
1076   // Y
1077   glEnable(GL_TEXTURE_2D);
1078   glActiveTexture(GL_TEXTURE0);
1079   glBindTexture(GL_TEXTURE_2D, planes[0].id);
1080   VerifyGLState();
1081
1082   // U
1083   glActiveTexture(GL_TEXTURE1);
1084   glEnable(GL_TEXTURE_2D);
1085   glBindTexture(GL_TEXTURE_2D, planes[1].id);
1086   VerifyGLState();
1087
1088   // V
1089   glActiveTexture(GL_TEXTURE2);
1090   glEnable(GL_TEXTURE_2D);
1091   glBindTexture(GL_TEXTURE_2D, planes[2].id);
1092   VerifyGLState();
1093
1094   glActiveTexture(GL_TEXTURE0);
1095   VerifyGLState();
1096
1097   // make sure the yuv shader is loaded and ready to go
1098   if (!m_pYUVShader || (!m_pYUVShader->OK()))
1099   {
1100     CLog::Log(LOGERROR, "GL: YUV shader not active, cannot do multipass render");
1101     return;
1102   }
1103
1104   m_fbo.BeginRender();
1105   VerifyGLState();
1106
1107   m_pYUVShader->SetBlack(g_settings.m_currentVideoSettings.m_Brightness * 0.01f - 0.5f);
1108   m_pYUVShader->SetContrast(g_settings.m_currentVideoSettings.m_Contrast * 0.02f);
1109   m_pYUVShader->SetWidth(im.width);
1110   m_pYUVShader->SetHeight(im.height);
1111   if     (field == FIELD_ODD)
1112     m_pYUVShader->SetField(1);
1113   else if(field == FIELD_EVEN)
1114     m_pYUVShader->SetField(0);
1115
1116   VerifyGLState();
1117 //TODO
1118 //  glPushAttrib(GL_VIEWPORT_BIT);
1119 //  glPushAttrib(GL_SCISSOR_BIT);
1120   g_matrices.MatrixMode(MM_MODELVIEW);
1121   g_matrices.PushMatrix();
1122   g_matrices.LoadIdentity();
1123   VerifyGLState();
1124
1125   g_matrices.MatrixMode(MM_PROJECTION);
1126   g_matrices.PushMatrix();
1127   g_matrices.LoadIdentity();
1128   VerifyGLState();
1129   g_matrices.Ortho2D(0, m_sourceWidth, 0, m_sourceHeight);
1130   glViewport(0, 0, m_sourceWidth, m_sourceHeight);
1131   glScissor(0, 0, m_sourceWidth, m_sourceHeight);
1132   g_matrices.MatrixMode(MM_MODELVIEW);
1133   VerifyGLState();
1134
1135
1136   if (!m_pYUVShader->Enable())
1137   {
1138     CLog::Log(LOGERROR, "GL: Error enabling YUV shader");
1139   }
1140
1141   float imgwidth  = planes[0].rect.x2 - planes[0].rect.x1;
1142   float imgheight = planes[0].rect.y2 - planes[0].rect.y1;
1143   imgwidth  *= planes[0].texwidth;
1144   imgheight *= planes[0].texheight;
1145
1146   // 1st Pass to video frame size
1147 //TODO
1148 //  glBegin(GL_QUADS);
1149 //
1150 //  glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
1151 //  glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y1);
1152 //  glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y1);
1153 //  glVertex2f(0.0f    , 0.0f);
1154 //
1155 //  glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y1);
1156 //  glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y1);
1157 //  glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y1);
1158 //  glVertex2f(imgwidth, 0.0f);
1159 //
1160 //  glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x2, planes[0].rect.y2);
1161 //  glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x2, planes[1].rect.y2);
1162 //  glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x2, planes[2].rect.y2);
1163 //  glVertex2f(imgwidth, imgheight);
1164 //
1165 //  glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y2);
1166 //  glMultiTexCoord2fARB(GL_TEXTURE1, planes[1].rect.x1, planes[1].rect.y2);
1167 //  glMultiTexCoord2fARB(GL_TEXTURE2, planes[2].rect.x1, planes[2].rect.y2);
1168 //  glVertex2f(0.0f    , imgheight);
1169 //
1170 //  glEnd();
1171 //  VerifyGLState();
1172
1173   m_pYUVShader->Disable();
1174
1175   g_matrices.MatrixMode(MM_MODELVIEW);
1176   g_matrices.PopMatrix(); // pop modelview
1177   g_matrices.MatrixMode(MM_PROJECTION);
1178   g_matrices.PopMatrix(); // pop projection
1179 //TODO
1180 //  glPopAttrib(); // pop scissor
1181 //  glPopAttrib(); // pop viewport
1182   g_matrices.MatrixMode(MM_MODELVIEW);
1183   VerifyGLState();
1184
1185   m_fbo.EndRender();
1186
1187   glActiveTexture(GL_TEXTURE1);
1188   glDisable(GL_TEXTURE_2D);
1189   glActiveTexture(GL_TEXTURE2);
1190   glDisable(GL_TEXTURE_2D);
1191   glActiveTexture(GL_TEXTURE0);
1192   glDisable(GL_TEXTURE_2D);
1193
1194   glEnable(GL_TEXTURE_2D);
1195   glBindTexture(GL_TEXTURE_2D, m_fbo.Texture());
1196   VerifyGLState();
1197
1198   // Use regular normalized texture coordinates
1199
1200   // 2nd Pass to screen size with optional video filter
1201
1202   if (m_pVideoFilterShader)
1203   {
1204     m_fbo.SetFiltering(GL_TEXTURE_2D, GL_NEAREST);
1205     m_pVideoFilterShader->SetSourceTexture(0);
1206     m_pVideoFilterShader->SetWidth(m_sourceWidth);
1207     m_pVideoFilterShader->SetHeight(m_sourceHeight);
1208     m_pVideoFilterShader->Enable();
1209   }
1210   else
1211     m_fbo.SetFiltering(GL_TEXTURE_2D, GL_LINEAR);
1212
1213   VerifyGLState();
1214
1215   imgwidth  /= m_sourceWidth;
1216   imgheight /= m_sourceHeight;
1217
1218 //TODO
1219 //  glBegin(GL_QUADS);
1220 //
1221 //  glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f    , 0.0f);
1222 //  glVertex4f(m_destRect.x1, m_destRect.y1, 0, 1.0f );
1223 //
1224 //  glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, 0.0f);
1225 //  glVertex4f(m_destRect.x2, m_destRect.y1, 0, 1.0f);
1226 //
1227 //  glMultiTexCoord2fARB(GL_TEXTURE0, imgwidth, imgheight);
1228 //  glVertex4f(m_destRect.x2, m_destRect.y2, 0, 1.0f);
1229 //
1230 //  glMultiTexCoord2fARB(GL_TEXTURE0, 0.0f    , imgheight);
1231 //  glVertex4f(m_destRect.x1, m_destRect.y2, 0, 1.0f);
1232 //
1233 //  glEnd();
1234
1235   VerifyGLState();
1236
1237   if (m_pVideoFilterShader)
1238     m_pVideoFilterShader->Disable();
1239
1240   VerifyGLState();
1241
1242   glDisable(GL_TEXTURE_2D);
1243   VerifyGLState();
1244 }
1245
1246 void CLinuxRendererGLES::RenderSoftware(int index, int field)
1247 {
1248   YUVPLANES &planes = m_buffers[index].fields[field];
1249
1250   // set scissors if we are not in fullscreen video
1251   if ( !(g_graphicsContext.IsFullScreenVideo() || g_graphicsContext.IsCalibrating() ))
1252     g_graphicsContext.ClipToViewWindow();
1253
1254   glDisable(GL_DEPTH_TEST);
1255
1256   // Y
1257   glEnable(GL_TEXTURE_2D);
1258   glActiveTexture(GL_TEXTURE0);
1259   glBindTexture(GL_TEXTURE_2D, planes[0].id);
1260
1261   g_Windowing.EnableGUIShader(SM_TEXTURE);
1262
1263   GLubyte idx[4] = {0, 1, 3, 2};        //determines order of triangle strip
1264   GLfloat ver[4][4];
1265   GLfloat tex[4][2];
1266   GLint   posLoc = g_Windowing.GUIShaderGetPos();
1267   GLint   texLoc = g_Windowing.GUIShaderGetCoord0();
1268
1269   glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
1270   glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
1271
1272   glEnableVertexAttribArray(posLoc);
1273   glEnableVertexAttribArray(texLoc);
1274
1275   // Set vertex coordinates
1276   ver[0][0] = ver[3][0] = m_destRect.x1;
1277   ver[0][1] = ver[1][1] = m_destRect.y1;
1278   ver[1][0] = ver[2][0] = m_destRect.x2;
1279   ver[2][1] = ver[3][1] = m_destRect.y2;
1280   ver[0][2] = ver[1][2] = ver[2][2] = ver[3][2] = 0.0f;
1281   ver[0][3] = ver[1][3] = ver[2][3] = ver[3][3] = 1.0f;
1282
1283   // Set texture coordinates
1284   tex[0][0] = tex[3][0] = planes[0].rect.x1;
1285   tex[0][1] = tex[1][1] = planes[0].rect.y1;
1286   tex[1][0] = tex[2][0] = planes[0].rect.x2;
1287   tex[2][1] = tex[3][1] = planes[0].rect.y2;
1288
1289   glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
1290
1291   glDisableVertexAttribArray(posLoc);
1292   glDisableVertexAttribArray(texLoc);
1293
1294   g_Windowing.DisableGUIShader();
1295
1296   VerifyGLState();
1297
1298   glDisable(GL_TEXTURE_2D);
1299   VerifyGLState();
1300 }
1301
1302 void CLinuxRendererGLES::CreateThumbnail(CBaseTexture* texture, unsigned int width, unsigned int height)
1303 {
1304   // get our screen rect
1305   const CRect& rv = g_graphicsContext.GetViewWindow();
1306
1307   // save current video rect
1308   CRect saveSize = m_destRect;
1309
1310   // new video rect is thumbnail size
1311   m_destRect.SetRect(0, 0, (float)width, (float)height);
1312
1313   // clear framebuffer and invert Y axis to get non-inverted image
1314   glClearColor(0, 0, 0, 1);
1315   glClear(GL_COLOR_BUFFER_BIT);
1316   glClearColor(0, 0, 0, 0);
1317   glDisable(GL_BLEND);
1318   g_matrices.MatrixMode(MM_MODELVIEW);
1319   g_matrices.PushMatrix();
1320   g_matrices.Translatef(0, height, 0);
1321   g_matrices.Scalef(1.0, -1.0f, 1.0f);
1322
1323   Render(RENDER_FLAG_NOOSD, m_iYV12RenderBuffer);
1324
1325   // read pixels
1326   glReadPixels(0, rv.y2-height, width, height, GL_RGBA, GL_UNSIGNED_BYTE, texture->GetPixels());
1327
1328   // revert model view matrix
1329   g_matrices.MatrixMode(MM_MODELVIEW);
1330   g_matrices.PopMatrix();
1331
1332   // restore original video rect
1333   m_destRect = saveSize;
1334 }
1335
1336 //********************************************************************************************************
1337 // YV12 Texture creation, deletion, copying + clearing
1338 //********************************************************************************************************
1339 void CLinuxRendererGLES::DeleteYV12Texture(int index)
1340 {
1341   YV12Image &im     = m_buffers[index].image;
1342   YUVFIELDS &fields = m_buffers[index].fields;
1343
1344   if( fields[FIELD_FULL][0].id == 0 ) return;
1345
1346   CLog::Log(LOGDEBUG, "Deleted YV12 texture %i", index);
1347   /* finish up all textures, and delete them */
1348   g_graphicsContext.BeginPaint();  //FIXME
1349   for(int f = 0;f<MAX_FIELDS;f++)
1350   {
1351     for(int p = 0;p<MAX_PLANES;p++)
1352     {
1353       if( fields[f][p].id )
1354       {
1355         if (glIsTexture(fields[f][p].id))
1356         {
1357           glDeleteTextures(1, &fields[f][p].id);
1358           CLog::Log(LOGDEBUG, "GL: Deleting texture field %d plane %d", f+1, p+1);
1359         }
1360         fields[f][p].id = 0;
1361       }
1362     }
1363   }
1364   g_graphicsContext.EndPaint();
1365
1366   for(int p = 0;p<MAX_PLANES;p++)
1367   {
1368     if (im.plane[p])
1369     {
1370       delete[] im.plane[p];
1371       im.plane[p] = NULL;
1372     }
1373   }
1374 }
1375
1376 void CLinuxRendererGLES::ClearYV12Texture(int index)
1377 {
1378   //YV12Image &im = m_image[index];
1379
1380   //memset(im.plane[0], 0,   im.stride[0] * im.height);
1381   //memset(im.plane[1], 128, im.stride[1] * im.height>>im.cshift_y );
1382   //memset(im.plane[2], 128, im.stride[2] * im.height>>im.cshift_y );
1383   //SetEvent(m_eventTexturesDone[index]);
1384 }
1385
1386 bool CLinuxRendererGLES::CreateYV12Texture(int index, bool clear)
1387 {
1388   // Remember if we're software upscaling.
1389   m_isSoftwareUpscaling = IsSoftwareUpscaling();
1390
1391   /* since we also want the field textures, pitch must be texture aligned */
1392   unsigned p;
1393
1394   YV12Image &im     = m_buffers[index].image;
1395   YUVFIELDS &fields = m_buffers[index].fields;
1396
1397   if (clear)
1398   {
1399     DeleteYV12Texture(index);
1400
1401     im.height = m_sourceHeight;
1402     im.width  = m_sourceWidth;
1403     im.cshift_x = 1;
1404     im.cshift_y = 1;
1405
1406     im.stride[0] = im.width;
1407     im.stride[1] = im.width >> im.cshift_x;
1408     im.stride[2] = im.width >> im.cshift_x;
1409
1410     im.planesize[0] = im.stride[0] * im.height;
1411     im.planesize[1] = im.stride[1] * ( im.height >> im.cshift_y );
1412     im.planesize[2] = im.stride[2] * ( im.height >> im.cshift_y );
1413
1414     for (int i = 0; i < 3; i++)
1415       im.plane[i] = new BYTE[im.planesize[i]];
1416   }
1417
1418   glEnable(GL_TEXTURE_2D);
1419   for(int f = 0;f<MAX_FIELDS;f++)
1420   {
1421     for(p = 0;p<MAX_PLANES;p++)
1422     {
1423       if (!glIsTexture(fields[f][p].id))
1424       {
1425         glGenTextures(1, &fields[f][p].id);
1426         VerifyGLState();
1427       }
1428     }
1429   }
1430
1431   // YUV
1432   for (int f = FIELD_FULL; f<=FIELD_EVEN ; f++)
1433   {
1434     int fieldshift = (f==FIELD_FULL) ? 0 : 1;
1435     YUVPLANES &planes = fields[f];
1436
1437     if(m_isSoftwareUpscaling)
1438     {
1439       planes[0].texwidth  = m_upscalingWidth;
1440       planes[0].texheight = m_upscalingHeight >> fieldshift;
1441     }
1442     else
1443     {
1444       planes[0].texwidth  = im.width;
1445       planes[0].texheight = im.height >> fieldshift;
1446     }
1447
1448     if (m_renderMethod & RENDER_SW)
1449     {
1450       planes[1].texwidth  = 0;
1451       planes[1].texheight = 0;
1452       planes[2].texwidth  = 0;
1453       planes[2].texheight = 0;
1454     }
1455     else
1456     {
1457       planes[1].texwidth  = planes[0].texwidth  >> im.cshift_x;
1458       planes[1].texheight = planes[0].texheight >> im.cshift_y;
1459       planes[2].texwidth  = planes[0].texwidth  >> im.cshift_x;
1460       planes[2].texheight = planes[0].texheight >> im.cshift_y;
1461     }
1462
1463     if(m_renderMethod & RENDER_POT)
1464     {
1465       for(int p = 0; p < 3; p++)
1466       {
1467         planes[p].texwidth  = NP2(planes[p].texwidth);
1468         planes[p].texheight = NP2(planes[p].texheight);
1469       }
1470     }
1471
1472     for(int p = 0; p < 3; p++)
1473     {
1474       YUVPLANE &plane = planes[p];
1475       if (plane.texwidth * plane.texheight == 0)
1476         continue;
1477
1478       glBindTexture(GL_TEXTURE_2D, plane.id);
1479       if (m_renderMethod & RENDER_SW)
1480       {
1481         if(m_renderMethod & RENDER_POT)
1482           CLog::Log(LOGNOTICE, "GL: Creating RGB POT texture of size %d x %d",  plane.texwidth, plane.texheight);
1483         else
1484           CLog::Log(LOGDEBUG,  "GL: Creating RGB NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
1485
1486         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
1487       } 
1488       else
1489       {
1490         if(m_renderMethod & RENDER_POT)
1491           CLog::Log(LOGNOTICE, "GL: Creating YUV POT texture of size %d x %d",  plane.texwidth, plane.texheight);
1492         else
1493           CLog::Log(LOGDEBUG,  "GL: Creating YUV NPOT texture of size %d x %d", plane.texwidth, plane.texheight);
1494
1495         glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, plane.texwidth, plane.texheight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
1496       }
1497
1498       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1499       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1500       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1501       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1502       VerifyGLState();
1503     }
1504   }
1505   glDisable(GL_TEXTURE_2D);
1506   SetEvent(m_eventTexturesDone[index]);
1507   return true;
1508 }
1509
1510 void CLinuxRendererGLES::SetTextureFilter(GLenum method)
1511 {
1512   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
1513   {
1514     YUVFIELDS &fields = m_buffers[i].fields;
1515
1516     for (int f = FIELD_FULL; f<=FIELD_EVEN ; f++)
1517     {
1518       glBindTexture(GL_TEXTURE_2D, fields[f][0].id);
1519       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, method);
1520       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, method);
1521       VerifyGLState();
1522
1523       if (!(m_renderMethod & RENDER_SW))
1524       {
1525         glBindTexture(GL_TEXTURE_2D, fields[f][1].id);
1526         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, method);
1527         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, method);
1528         VerifyGLState();
1529
1530         glBindTexture(GL_TEXTURE_2D, fields[f][2].id);
1531         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, method);
1532         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, method);
1533         VerifyGLState();
1534       }
1535     }
1536   }
1537 }
1538
1539 bool CLinuxRendererGLES::SupportsBrightness()
1540 {
1541   return false;
1542 }
1543
1544 bool CLinuxRendererGLES::SupportsContrast()
1545 {
1546   return false;
1547 }
1548
1549 bool CLinuxRendererGLES::SupportsGamma()
1550 {
1551   return false;
1552 }
1553
1554 bool CLinuxRendererGLES::SupportsMultiPassRendering()
1555 {
1556   return false;
1557 }
1558
1559 bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method)
1560 {
1561   return false;
1562 }
1563
1564 bool CLinuxRendererGLES::Supports(ESCALINGMETHOD method)
1565 {
1566   if(method == VS_SCALINGMETHOD_NEAREST
1567   || method == VS_SCALINGMETHOD_LINEAR)
1568     return true;
1569
1570   if (g_advancedSettings.m_videoHighQualityScaling != SOFTWARE_UPSCALING_DISABLED)
1571   {
1572     if(method == VS_SCALINGMETHOD_BICUBIC_SOFTWARE
1573     || method == VS_SCALINGMETHOD_LANCZOS_SOFTWARE
1574     || method == VS_SCALINGMETHOD_SINC_SOFTWARE)
1575       return true;
1576   }
1577
1578   return false;
1579 }
1580
1581 #endif