[ARM] Added neccessary GLES, EGL and other arm related files
[xbmc:xbmc-antiquated.git] / trunk / xbmc / RenderSystemGLES.cpp
1 /*
2 *      Copyright (C) 2005-2008 Team XBMC
3 *      http://www.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, write to
17 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 *  http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22
23 #include "system.h"
24
25 #if HAS_GLES == 2
26
27 #include "GraphicContext.h"
28 #include "AdvancedSettings.h"
29 #include "RenderSystemGLES.h"
30 #include "MatrixGLES.h"
31 #include "utils/log.h"
32 #include "utils/TimeUtils.h"
33 #include "utils/SystemInfo.h"
34
35
36 CRenderSystemGLES::CRenderSystemGLES() : CRenderSystemBase()
37 {
38   m_enumRenderingSystem = RENDERING_SYSTEM_OPENGLES;
39 }
40
41 CRenderSystemGLES::~CRenderSystemGLES()
42 {
43   DestroyRenderSystem();
44   CLog::Log(LOGDEBUG, "GUI Shader - Destroying Shader : %p", m_pGUIshader);
45   m_pGUIshader->Free();
46   delete m_pGUIshader;
47   m_pGUIshader = NULL;
48 }
49
50 bool CRenderSystemGLES::InitRenderSystem()
51 {
52   m_bVSync = false;
53   m_iVSyncMode = 0;
54   m_iSwapStamp = 0;
55   m_iSwapTime = 0;
56   m_iSwapRate = 0;
57   m_bVsyncInit = false;
58   m_maxTextureSize = 2048;
59   m_renderCaps = 0;
60   // Get the GL version number 
61   m_RenderVersionMajor = 0;
62   m_RenderVersionMinor = 0;
63
64   const char* ver = (const char*)glGetString(GL_VERSION);
65   if (ver != 0)
66   {
67     sscanf(ver, "%d.%d", &m_RenderVersionMajor, &m_RenderVersionMinor);
68     if (!m_RenderVersionMajor)
69       sscanf(ver, "%*s %*s %d.%d", &m_RenderVersionMajor, &m_RenderVersionMinor);
70     m_RenderVersion = ver;
71   }
72   
73   // Get our driver vendor and renderer
74   m_RenderVendor = (const char*) glGetString(GL_VENDOR);
75   m_RenderRenderer = (const char*) glGetString(GL_RENDERER);
76   
77   if (IsExtSupported("GL_TEXTURE_NPOT"))
78   {
79     m_renderCaps |= RENDER_CAPS_NPOT;
80   }
81
82   m_RenderExtensions  = " ";
83   m_RenderExtensions += (const char*) glGetString(GL_EXTENSIONS);
84   m_RenderExtensions += " ";
85
86   LogGraphicsInfo();
87   
88   m_bRenderCreated = true;
89   
90   InitialiseGUIShader();
91
92   return true;
93 }
94
95 bool CRenderSystemGLES::ResetRenderSystem(int width, int height, bool fullScreen, float refreshRate)
96 {
97   m_width = width;
98   m_height = height;
99   
100   glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
101   
102   CalculateMaxTexturesize();
103   
104   glViewport(0, 0, width, height);
105   glScissor(0, 0, width, height);
106
107   glEnable(GL_TEXTURE_2D); 
108   glEnable(GL_SCISSOR_TEST); 
109
110   g_matrices.MatrixMode(MM_PROJECTION);
111   g_matrices.LoadIdentity();
112
113   g_matrices.Ortho(0.0f, width-1, height-1, 0.0f, -1.0f, 1.0f);
114
115   g_matrices.MatrixMode(MM_MODELVIEW);
116   g_matrices.LoadIdentity();
117   
118   glBlendFunc(GL_SRC_ALPHA, GL_ONE);
119   glEnable(GL_BLEND);          // Turn Blending On
120   glDisable(GL_DEPTH_TEST);  
121     
122   return true;
123 }
124
125 bool CRenderSystemGLES::DestroyRenderSystem()
126 {
127   m_bRenderCreated = false;
128
129   return true;
130 }
131
132 bool CRenderSystemGLES::BeginRender()
133 {
134   if (!m_bRenderCreated)
135     return false;
136
137   return true;
138 }
139
140 bool CRenderSystemGLES::EndRender()
141 {
142   if (!m_bRenderCreated)
143     return false;
144
145   return true;
146 }
147
148 bool CRenderSystemGLES::ClearBuffers(color_t color)
149 {
150   if (!m_bRenderCreated)
151     return false;
152
153   return true;
154 }
155
156 bool CRenderSystemGLES::ClearBuffers(float r, float g, float b, float a)
157 {
158   if (!m_bRenderCreated)
159     return false;
160   
161   glClearColor(r, g, b, a);
162
163   GLbitfield flags = GL_COLOR_BUFFER_BIT;
164   glClear(flags);
165
166   return true;
167 }
168
169 bool CRenderSystemGLES::IsExtSupported(const char* extension)
170 {
171   if (extension == "GL_EXT_framebuffer_object")
172   {
173     // GLES has FBO as a core element, not an extension!
174     return true;
175   }
176   else
177   {
178     if (extension == "GL_TEXTURE_NPOT")
179     {
180       // GLES can have different methods to detect this one.
181       // Check define first, then do extension string search if not defined.
182 #ifdef GL_IMG_texture_npot
183       return true;
184 #endif
185     }
186
187     CStdString name;
188     name  = " ";
189     name += extension;
190     name += " ";
191
192     return m_RenderExtensions.find(name) != std::string::npos;
193   }
194 }
195
196 static int64_t abs(int64_t a)
197 {
198   if(a < 0)
199     return -a;
200   return a;
201 }
202
203 bool CRenderSystemGLES::PresentRender()
204 {
205   if (!m_bRenderCreated)
206     return false;
207
208   if (m_iVSyncMode != 0 && m_iSwapRate != 0) 
209   {
210     int64_t curr, diff, freq;
211     curr = CurrentHostCounter();
212     freq = CurrentHostFrequency();
213
214     if(m_iSwapStamp == 0)
215       m_iSwapStamp = curr;
216
217     /* calculate our next swap timestamp */
218     diff = curr - m_iSwapStamp;
219     diff = m_iSwapRate - diff % m_iSwapRate;
220     m_iSwapStamp = curr + diff;
221
222     /* sleep as close as we can before, assume 1ms precision of sleep *
223      * this should always awake so that we are guaranteed the given   *
224      * m_iSwapTime to do our swap                                     */
225     diff = (diff - m_iSwapTime) * 1000 / freq;
226     if (diff > 0)
227       Sleep((DWORD)diff);
228   }
229   
230   bool result = PresentRenderImpl();
231   
232   if (m_iVSyncMode && m_iSwapRate != 0)
233   {
234     int64_t curr, diff;
235     curr = CurrentHostCounter();
236
237     diff = curr - m_iSwapStamp;
238     m_iSwapStamp = curr;
239
240     if (abs(diff - m_iSwapRate) < abs(diff))
241       CLog::Log(LOGDEBUG, "%s - missed requested swap",__FUNCTION__);
242   }
243   
244   return result;
245 }
246
247 void CRenderSystemGLES::SetVSync(bool enable)
248 {
249   if (m_bVSync==enable && m_bVsyncInit == true)
250     return;
251
252   if (!m_bRenderCreated)
253     return;
254   
255   if (enable)
256     CLog::Log(LOGINFO, "GL: Enabling VSYNC");
257   else
258     CLog::Log(LOGINFO, "GL: Disabling VSYNC");
259
260   m_iVSyncMode   = 0;
261   m_iVSyncErrors = 0;
262   m_iSwapRate    = 0;
263   m_bVSync       = enable;
264   m_bVsyncInit   = true;
265
266   SetVSyncImpl(enable);
267   
268   if (!enable)
269     return;
270
271   if (g_advancedSettings.m_ForcedSwapTime != 0.0)
272   {
273     /* some hardware busy wait on swap/glfinish, so we must manually sleep to avoid 100% cpu */
274     double rate = g_graphicsContext.GetFPS();
275     if (rate <= 0.0 || rate > 1000.0)
276     {
277       CLog::Log(LOGWARNING, "Unable to determine a valid horizontal refresh rate, vsync workaround disabled %.2g", rate);
278       m_iSwapRate = 0;
279     }
280     else
281     {
282       int64_t freq;
283       freq = CurrentHostFrequency();
284       m_iSwapRate   = (int64_t)((double)freq / rate);
285       m_iSwapTime   = (int64_t)(0.001 * g_advancedSettings.m_ForcedSwapTime * freq);
286       m_iSwapStamp  = 0;
287       CLog::Log(LOGINFO, "GL: Using artificial vsync sleep with rate %f", rate);
288       if(!m_iVSyncMode)
289         m_iVSyncMode = 1;
290     }
291   }
292     
293   if (!m_iVSyncMode)
294     CLog::Log(LOGERROR, "GL: Vertical Blank Syncing unsupported");
295   else
296     CLog::Log(LOGINFO, "GL: Selected vsync mode %d", m_iVSyncMode);  
297 }
298
299 void CRenderSystemGLES::CaptureStateBlock()
300 {
301   if (!m_bRenderCreated)
302     return;
303
304   g_matrices.MatrixMode(MM_PROJECTION);
305   g_matrices.PushMatrix();
306   g_matrices.MatrixMode(MM_TEXTURE);
307   g_matrices.PushMatrix();
308   g_matrices.MatrixMode(MM_MODELVIEW);
309   g_matrices.PushMatrix();
310   glDisable(GL_SCISSOR_TEST); // fixes FBO corruption on Macs
311   glActiveTexture(GL_TEXTURE0);
312   glDisable(GL_TEXTURE_2D);
313 //TODO - NOTE: Only for Screensavers & Visualisations
314 //  glColor3f(1.0, 1.0, 1.0);
315 }
316
317 void CRenderSystemGLES::ApplyStateBlock()
318 {
319   if (!m_bRenderCreated)
320     return;
321
322   g_matrices.MatrixMode(MM_PROJECTION);
323   g_matrices.PopMatrix();
324   g_matrices.MatrixMode(MM_TEXTURE);
325   g_matrices.PopMatrix();
326   g_matrices.MatrixMode(MM_MODELVIEW);
327   g_matrices.PopMatrix();
328   glActiveTexture(GL_TEXTURE0);
329   glEnable(GL_TEXTURE_2D);
330   glEnable(GL_BLEND);
331   glEnable(GL_SCISSOR_TEST);  
332 }
333
334 void CRenderSystemGLES::SetCameraPosition(const CPoint &camera, int screenWidth, int screenHeight)
335
336   if (!m_bRenderCreated)
337     return;
338   
339   g_graphicsContext.BeginPaint();
340   
341   CPoint offset = camera - CPoint(screenWidth*0.5f, screenHeight*0.5f);
342   
343   GLint viewport[4];
344   glGetIntegerv(GL_VIEWPORT, viewport);
345
346   float w = (float)viewport[2]*0.5f;
347   float h = (float)viewport[3]*0.5f;
348
349   g_matrices.MatrixMode(MM_MODELVIEW);
350   g_matrices.LoadIdentity();
351   g_matrices.Translatef(-(viewport[0] + w + offset.x), +(viewport[1] + h + offset.y), 0);
352   g_matrices.LookAt(0.0, 0.0, -2.0*h, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0);
353   g_matrices.MatrixMode(MM_PROJECTION);
354   g_matrices.LoadIdentity();
355   g_matrices.Frustum( (-w - offset.x)*0.5f, (w - offset.x)*0.5f, (-h + offset.y)*0.5f, (h + offset.y)*0.5f, h, 100*h);
356   g_matrices.MatrixMode(MM_MODELVIEW);
357
358   g_graphicsContext.EndPaint();
359 }
360
361 bool CRenderSystemGLES::TestRender()
362 {
363   static float theta = 0.0;
364
365   //RESOLUTION_INFO resInfo = g_settings.m_ResInfo[g_guiSettings.m_LookAndFeelResolution];
366   //glViewport(0, 0, resInfo.iWidth, resInfo.iHeight);
367
368   g_matrices.PushMatrix();
369   g_matrices.Rotatef( theta, 0.0f, 0.0f, 1.0f );
370
371   EnableGUIShader(SM_DEFAULT);
372
373   GLfloat col[3][4];
374   GLfloat ver[3][2];
375   GLint   posLoc = GUIShaderGetPos();
376   GLint   colLoc = GUIShaderGetCol();
377
378   glVertexAttribPointer(posLoc,  2, GL_FLOAT, 0, 0, ver);
379   glVertexAttribPointer(colLoc,  4, GL_FLOAT, 0, 0, col);
380
381   glEnableVertexAttribArray(posLoc);
382   glEnableVertexAttribArray(colLoc);
383
384   // Setup Colour values
385   col[0][0] = col[0][3] = col[1][1] = col[1][3] = col[2][2] = col[2][3] = 1.0f;
386   col[0][1] = col[0][2] = col[1][0] = col[1][2] = col[2][0] = col[2][1] = 0.0f;
387
388   // Setup vertex position values
389   ver[0][0] =  0.0f;
390   ver[0][1] =  1.0f;
391   ver[1][0] =  0.87f;
392   ver[1][1] = -0.5f;
393   ver[2][0] = -0.87f;
394   ver[2][1] = -0.5f;
395
396   glDrawArrays(GL_TRIANGLES, 0, 3);
397
398   glDisableVertexAttribArray(posLoc);
399   glDisableVertexAttribArray(colLoc);
400
401   DisableGUIShader();
402
403   g_matrices.PopMatrix();
404
405   theta += 1.0f;
406
407   return true;
408 }
409
410 void CRenderSystemGLES::ApplyHardwareTransform(const TransformMatrix &finalMatrix)
411
412   if (!m_bRenderCreated)
413     return;
414
415   g_matrices.MatrixMode(MM_MODELVIEW);
416   g_matrices.PushMatrix();
417   GLfloat matrix[4][4];
418
419   for(int i=0;i<3;i++)
420     for(int j=0;j<4;j++)
421       matrix[j][i] = finalMatrix.m[i][j];
422
423   matrix[0][3] = 0.0f;
424   matrix[1][3] = 0.0f;
425   matrix[2][3] = 0.0f;
426   matrix[3][3] = 1.0f;
427
428   g_matrices.MultMatrixf(&matrix[0][0]);
429 }
430
431 void CRenderSystemGLES::RestoreHardwareTransform()
432 {
433   if (!m_bRenderCreated)
434     return;
435
436   g_matrices.MatrixMode(MM_MODELVIEW);
437   g_matrices.PopMatrix();
438 }
439
440 void CRenderSystemGLES::CalculateMaxTexturesize()
441 {
442   // GLES cannot do PROXY textures to determine maximum size,
443   CLog::Log(LOGINFO, "GL: Maximum texture width: %u", m_maxTextureSize);
444 }
445
446 void CRenderSystemGLES::GetViewPort(CRect& viewPort)
447 {
448   if (!m_bRenderCreated)
449     return;
450   
451   GLint glvp[4];
452   glGetIntegerv(GL_SCISSOR_BOX, glvp);
453   
454   viewPort.x1 = glvp[0];
455   viewPort.y1 = m_height - glvp[1] - glvp[3];
456   viewPort.x2 = glvp[0] + glvp[2];
457   viewPort.y2 = viewPort.y1 + glvp[3];
458 }
459
460 void CRenderSystemGLES::SetViewPort(CRect& viewPort)
461 {
462   if (!m_bRenderCreated)
463     return;
464   
465   glScissor((GLint) viewPort.x1, (GLint) (m_height - viewPort.y1 - viewPort.Height()), (GLsizei) viewPort.Width(), (GLsizei) viewPort.Height());
466   glViewport((GLint) viewPort.x1, (GLint) (m_height - viewPort.y1 - viewPort.Height()), (GLsizei) viewPort.Width(), (GLsizei) viewPort.Height());
467 }
468
469 void CRenderSystemGLES::InitialiseGUIShader()
470 {
471   if (!m_pGUIshader)
472   {
473     // Setup the OpenGL ES2.0 shader program for use
474     m_pGUIshader = new CGUIShader();
475     if (!m_pGUIshader->CompileAndLink())
476     {
477       m_pGUIshader->Free();
478       delete m_pGUIshader;
479       m_pGUIshader = NULL;
480       CLog::Log(LOGERROR, "GUI Shader - Initialise failed");
481     }
482     else
483     {
484       CLog::Log(LOGDEBUG, "GUI Shader - Initialise successful : %p", m_pGUIshader);
485     }
486   }
487   else
488   {
489     CLog::Log(LOGDEBUG, "GUI Shader - Tried to Initialise again. Was this intentional?");
490   }
491 }
492
493 void CRenderSystemGLES::EnableGUIShader(ESHADERMETHOD method)
494 {
495   if (m_pGUIshader)
496   {
497     m_pGUIshader->Setup(method);
498     m_pGUIshader->Enable();
499   }
500 }
501
502 void CRenderSystemGLES::DisableGUIShader()
503 {
504   if (m_pGUIshader)
505     m_pGUIshader->Disable();
506 }
507
508 GLint CRenderSystemGLES::GUIShaderGetPos()
509 {
510   if (m_pGUIshader)
511     return m_pGUIshader->GetPosLoc();
512
513   return -1;
514 }
515
516 GLint CRenderSystemGLES::GUIShaderGetCol()
517 {
518   if (m_pGUIshader)
519     return m_pGUIshader->GetColLoc();
520
521   return -1;
522 }
523
524 GLint CRenderSystemGLES::GUIShaderGetCoord0()
525 {
526   if (m_pGUIshader)
527     return m_pGUIshader->GetCord0Loc();
528
529   return -1;
530 }
531
532 GLint CRenderSystemGLES::GUIShaderGetCoord1()
533 {
534   if (m_pGUIshader)
535     return m_pGUIshader->GetCord1Loc();
536
537   return -1;
538 }
539
540 #endif