Merge pull request #4539 from Matricom/amcodec
[vuplus_xbmc] / xbmc / windowing / osx / WinSystemIOS.mm
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 #if defined(TARGET_DARWIN_IOS)
22 //hack around problem with xbmc's typedef int BOOL
23 // and obj-c's typedef unsigned char BOOL
24 #define BOOL XBMC_BOOL 
25 #include "system.h"
26 #undef BOOL
27
28 #ifdef HAS_EGL
29 #define BOOL XBMC_BOOL 
30 #include "WinSystemIOS.h"
31 #include "utils/log.h"
32 #include "filesystem/SpecialProtocol.h"
33 #include "settings/DisplaySettings.h"
34 #include "guilib/GraphicContext.h"
35 #include "guilib/Texture.h"
36 #include "utils/StringUtils.h"
37 #include "guilib/DispResource.h"
38 #include "threads/SingleLock.h"
39 #include <vector>
40 #undef BOOL
41
42 #import <Foundation/Foundation.h>
43 #import <OpenGLES/ES2/gl.h>
44 #import <OpenGLES/ES2/glext.h>
45 #if defined(TARGET_DARWIN_IOS_ATV2)
46 #import "atv2/XBMCController.h"
47 #else
48 #import "ios/XBMCController.h"
49 #endif
50 #import "osx/IOSScreenManager.h"
51 #include "osx/DarwinUtils.h"
52 #import <dlfcn.h>
53
54 CWinSystemIOS::CWinSystemIOS() : CWinSystemBase()
55 {
56   m_eWindowSystem = WINDOW_SYSTEM_IOS;
57
58   m_iVSyncErrors = 0;
59   m_bIsBackgrounded = false;
60 }
61
62 CWinSystemIOS::~CWinSystemIOS()
63 {
64 }
65
66 bool CWinSystemIOS::InitWindowSystem()
67 {
68         return CWinSystemBase::InitWindowSystem();
69 }
70
71 bool CWinSystemIOS::DestroyWindowSystem()
72 {
73   return true;
74 }
75
76 bool CWinSystemIOS::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
77 {
78   //NSLog(@"%s", __PRETTY_FUNCTION__);
79         
80   if(!SetFullScreen(fullScreen, res, false))
81     return false;
82
83   [g_xbmcController setFramebuffer];
84
85   m_bWindowCreated = true;
86
87   m_eglext  = " ";
88   m_eglext += (const char*) glGetString(GL_EXTENSIONS);
89   m_eglext += " ";
90
91   CLog::Log(LOGDEBUG, "EGL_EXTENSIONS:%s", m_eglext.c_str());
92   return true;
93 }
94
95 bool CWinSystemIOS::DestroyWindow()
96 {
97   return true;
98 }
99
100 bool CWinSystemIOS::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
101 {
102   //NSLog(@"%s", __PRETTY_FUNCTION__);
103         
104   if (m_nWidth != newWidth || m_nHeight != newHeight)
105   {
106     m_nWidth  = newWidth;
107     m_nHeight = newHeight;
108   }
109
110   CRenderSystemGLES::ResetRenderSystem(newWidth, newHeight, false, 0);
111
112   return true;
113 }
114
115 bool CWinSystemIOS::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
116 {
117   //NSLog(@"%s", __PRETTY_FUNCTION__);
118         
119   m_nWidth      = res.iWidth;
120   m_nHeight     = res.iHeight;
121   m_bFullScreen = fullScreen;
122
123   CLog::Log(LOGDEBUG, "About to switch to %i x %i on screen %i",m_nWidth, m_nHeight, res.iScreen);
124 #ifndef TARGET_DARWIN_IOS_ATV2
125   SwitchToVideoMode(res.iWidth, res.iHeight, res.fRefreshRate, res.iScreen);
126 #endif//TARGET_DARWIN_IOS_ATV2
127   CRenderSystemGLES::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate);
128   
129   return true;
130 }
131
132 UIScreenMode *getModeForResolution(int width, int height, unsigned int screenIdx)
133 {
134   if( screenIdx >= [[UIScreen screens] count])
135     return NULL;
136     
137   UIScreen *aScreen = [[UIScreen screens]objectAtIndex:screenIdx];
138   for ( UIScreenMode *mode in [aScreen availableModes] )
139   {
140     //for main screen also find modes where width and height are
141     //exchanged (because of the 90°degree rotated buildinscreens)
142     if((mode.size.width == width && mode.size.height == height) || 
143         (screenIdx == 0 && mode.size.width == height && mode.size.height == width))
144     {
145       CLog::Log(LOGDEBUG,"Found matching mode");
146       return mode;
147     }
148   }
149   CLog::Log(LOGERROR,"No matching mode found!");
150   return NULL;
151 }
152
153 bool CWinSystemIOS::SwitchToVideoMode(int width, int height, double refreshrate, int screenIdx)
154 {
155   bool ret = false;
156   // SwitchToVideoMode will not return until the display has actually switched over.
157   // This can take several seconds.
158   if( screenIdx >= GetNumScreens())
159     return false;
160   
161   //get the mode to pass to the controller
162   UIScreenMode *newMode = getModeForResolution(width, height, screenIdx);
163
164   if(newMode)
165   {
166     ret = [g_xbmcController changeScreen:screenIdx withMode:newMode];
167   }
168   return ret;
169 }
170
171 int CWinSystemIOS::GetNumScreens()
172 {
173   return [[UIScreen screens] count];
174 }
175
176 int CWinSystemIOS::GetCurrentScreen()
177 {
178   int idx = 0;
179   if ([[IOSScreenManager sharedInstance] isExternalScreen])
180   {
181     idx = 1;
182   }
183   return idx;
184 }
185
186 bool CWinSystemIOS::GetScreenResolution(int* w, int* h, double* fps, int screenIdx)
187 {
188   // Figure out the screen size. (default to main screen)
189   if(screenIdx >= GetNumScreens())
190     return false;
191   UIScreen *screen = [[UIScreen screens] objectAtIndex:screenIdx];
192   CGSize screenSize = [screen currentMode].size;
193   *w = screenSize.width;
194   *h = screenSize.height;
195   *fps = 0.0;
196   //if current mode is 0x0 (happens with external screens which arn't active)
197   //then use the preferred mode
198   if(*h == 0 || *w ==0)
199   {
200     UIScreenMode *firstMode = [screen preferredMode];
201     *w = firstMode.size.width;
202     *h = firstMode.size.height;
203   }
204   
205   //for mainscreen use the eagl bounds
206   //because mainscreen is build in
207   //in 90° rotated
208   if(screenIdx == 0)
209   {
210     *w = [g_xbmcController getScreenSize].width;
211     *h = [g_xbmcController getScreenSize].height;
212   }
213   CLog::Log(LOGDEBUG,"Current resolution Screen: %i with %i x %i",screenIdx, *w, *h);  
214   return true;
215 }
216
217 void CWinSystemIOS::UpdateResolutions()
218 {
219   // Add display resolution
220   int w, h;
221   double fps;
222   CWinSystemBase::UpdateResolutions();
223
224   //first screen goes into the current desktop mode
225   if(GetScreenResolution(&w, &h, &fps, 0))
226   {
227     UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, w, h, fps);
228   }
229
230 #ifndef TARGET_DARWIN_IOS_ATV2
231   //see resolution.h enum RESOLUTION for how the resolutions
232   //have to appear in the resolution info vector in CDisplaySettings
233   //add the desktop resolutions of the other screens
234   for(int i = 1; i < GetNumScreens(); i++)
235   {
236     RESOLUTION_INFO res;      
237     //get current resolution of screen i
238     if(GetScreenResolution(&w, &h, &fps, i))
239     {
240       UpdateDesktopResolution(res, i, w, h, fps);
241       CDisplaySettings::Get().AddResolutionInfo(res);
242     }
243   }
244   
245   //now just fill in the possible reolutions for the attached screens
246   //and push to the resolution info vector
247   FillInVideoModes();
248 #endif //TARGET_DARWIN_IOS_ATV2
249 }
250
251 void CWinSystemIOS::FillInVideoModes()
252 {
253   // Add full screen settings for additional monitors
254   int numDisplays = GetNumScreens();
255
256   for (int disp = 0; disp < numDisplays; disp++)
257   {
258     RESOLUTION_INFO res;
259     int w, h;
260     // atm we don't get refreshrate info from iOS
261     // but this may change in the future. In that case
262     // we will adapt this code for filling some
263     // usefull info into this local var :)
264     double refreshrate = 0.0;
265     //screen 0 is mainscreen - 1 has to be the external one...
266     UIScreen *aScreen = [[UIScreen screens]objectAtIndex:disp];
267     //found external screen
268     for ( UIScreenMode *mode in [aScreen availableModes] )
269     {
270       w = mode.size.width;
271       h = mode.size.height;
272       UpdateDesktopResolution(res, disp, w, h, refreshrate);
273       CLog::Log(LOGNOTICE, "Found possible resolution for display %d with %d x %d\n", disp, w, h);      
274
275       //overwrite the mode str because  UpdateDesktopResolution adds a
276       //"Full Screen". Since the current resolution is there twice
277       //this would lead to 2 identical resolution entrys in the guisettings.xml.
278       //That would cause problems with saving screen overscan calibration
279       //because the wrong entry is picked on load.
280       //So we just use UpdateDesktopResolutions for the current DESKTOP_RESOLUTIONS
281       //in UpdateResolutions. And on all othere resolutions make a unique
282       //mode str by doing it without appending "Full Screen".
283       //this is what linux does - though it feels that there shouldn't be
284       //the same resolution twice... - thats why i add a FIXME here.
285       res.strMode = StringUtils::Format("%dx%d @ %.2f", w, h, refreshrate);
286       g_graphicsContext.ResetOverscan(res);
287       CDisplaySettings::Get().AddResolutionInfo(res);
288     }
289   }
290 }
291
292 bool CWinSystemIOS::IsExtSupported(const char* extension)
293 {
294   if(strncmp(extension, "EGL_", 4) != 0)
295     return CRenderSystemGLES::IsExtSupported(extension);
296
297   CStdString name;
298
299   name  = " ";
300   name += extension;
301   name += " ";
302
303   return m_eglext.find(name) != string::npos;
304 }
305
306 bool CWinSystemIOS::BeginRender()
307 {
308   bool rtn;
309
310   [g_xbmcController setFramebuffer];
311
312   rtn = CRenderSystemGLES::BeginRender();
313   return rtn;
314 }
315
316 bool CWinSystemIOS::EndRender()
317 {
318   bool rtn;
319
320   rtn = CRenderSystemGLES::EndRender();
321   return rtn;
322 }
323
324 void CWinSystemIOS::Register(IDispResource *resource)
325 {
326   CSingleLock lock(m_resourceSection);
327   m_resources.push_back(resource);
328 }
329
330 void CWinSystemIOS::Unregister(IDispResource* resource)
331 {
332   CSingleLock lock(m_resourceSection);
333   std::vector<IDispResource*>::iterator i = find(m_resources.begin(), m_resources.end(), resource);
334   if (i != m_resources.end())
335     m_resources.erase(i);
336 }
337
338 void CWinSystemIOS::OnAppFocusChange(bool focus)
339 {
340   CSingleLock lock(m_resourceSection);
341   m_bIsBackgrounded = !focus;
342   CLog::Log(LOGDEBUG, "CWinSystemIOS::OnAppFocusChange: %d", focus ? 1 : 0);
343   for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
344     (*i)->OnAppFocusChange(focus);
345 }
346
347 void CWinSystemIOS::InitDisplayLink(void)
348 {
349 }
350 void CWinSystemIOS::DeinitDisplayLink(void)
351 {
352 }
353 double CWinSystemIOS::GetDisplayLinkFPS(void)
354 {
355   double fps;
356
357   fps = [g_xbmcController getDisplayLinkFPS];
358   return fps;
359 }
360
361 bool CWinSystemIOS::PresentRenderImpl(const CDirtyRegionList &dirty)
362 {
363   //glFlush;
364   [g_xbmcController presentFramebuffer];
365   return true;
366 }
367
368 void CWinSystemIOS::SetVSyncImpl(bool enable)
369 {
370   #if 0 
371     // set swapinterval if possible
372     void *eglSwapInterval;      
373     eglSwapInterval = dlsym( RTLD_DEFAULT, "eglSwapInterval" );
374     if ( eglSwapInterval )
375     {
376       ((void(*)(int))eglSwapInterval)( 1 ) ;
377     }
378   #endif
379   m_iVSyncMode = 10;
380 }
381
382 void CWinSystemIOS::ShowOSMouse(bool show)
383 {
384 }
385
386 bool CWinSystemIOS::HasCursor()
387 {
388   if( DarwinIsAppleTV2() )
389   {
390     return true;
391   }
392   else//apple touch devices
393   {
394     return false;
395   }
396 }
397
398 void CWinSystemIOS::NotifyAppActiveChange(bool bActivated)
399 {
400   if (bActivated && m_bWasFullScreenBeforeMinimize && !g_graphicsContext.IsFullScreenRoot())
401     g_graphicsContext.ToggleFullScreenRoot();
402 }
403
404 bool CWinSystemIOS::Minimize()
405 {
406   m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot();
407   if (m_bWasFullScreenBeforeMinimize)
408     g_graphicsContext.ToggleFullScreenRoot();
409
410   return true;
411 }
412
413 bool CWinSystemIOS::Restore()
414 {
415   return false;
416 }
417
418 bool CWinSystemIOS::Hide()
419 {
420   return true;
421 }
422
423 bool CWinSystemIOS::Show(bool raise)
424 {
425   return true;
426 }
427 #endif
428
429 #endif