[cstdstring] demise Format, replacing with StringUtils::Format
[vuplus_xbmc] / xbmc / windowing / egl / EGLNativeTypeRaspberryPI.cpp
1 /*
2  *      Copyright (C) 2011-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 #include "system.h"
21
22 #include <EGL/egl.h>
23 #include "EGLNativeTypeRaspberryPI.h"
24 #include "utils/log.h"
25 #include "guilib/gui3d.h"
26 #include "linux/DllBCM.h"
27 #include "utils/StringUtils.h"
28
29 #ifndef __VIDEOCORE4__
30 #define __VIDEOCORE4__
31 #endif
32
33 #define __VCCOREVER__ 0x04000000
34
35 #define IS_WIDESCREEN(m) ( m == 3 || m == 7 || m == 9 || \
36     m == 11 || m == 13 || m == 15 || m == 18 || m == 22 || \
37     m == 24 || m == 26 || m == 28 || m == 30 || m == 36 || \
38     m == 38 || m == 43 || m == 45 || m == 49 || m == 51 || \
39     m == 53 || m == 55 || m == 57 || m == 59)
40
41 #define MAKEFLAGS(group, mode, interlace) \
42   ( ( (mode)<<24 ) | ( (group)<<16 ) | \
43    ( (interlace) != 0 ? D3DPRESENTFLAG_INTERLACED : D3DPRESENTFLAG_PROGRESSIVE) | \
44    ( ((group) == HDMI_RES_GROUP_CEA && IS_WIDESCREEN(mode) ) ? D3DPRESENTFLAG_WIDESCREEN : 0) )
45
46 #define GETFLAGS_GROUP(f)       ( (HDMI_RES_GROUP_T)( ((f) >> 16) & 0xff ))
47 #define GETFLAGS_MODE(f)        ( ( (f) >>24 ) & 0xff )
48
49 //#ifndef DEBUG_PRINT
50 //#define DEBUG_PRINT 1
51 //#endif
52
53 #if defined(DEBUG_PRINT)
54 # define DLOG(fmt, args...) printf(fmt, ##args)
55 #else
56 # define DLOG(fmt, args...)
57 #endif
58
59
60 CEGLNativeTypeRaspberryPI::CEGLNativeTypeRaspberryPI()
61 {
62 #if defined(TARGET_RASPBERRY_PI)
63   m_DllBcmHost    = NULL;
64   m_nativeWindow  = NULL;
65 #endif
66 }
67
68 CEGLNativeTypeRaspberryPI::~CEGLNativeTypeRaspberryPI()
69 {
70 #if defined(TARGET_RASPBERRY_PI)
71   delete m_DllBcmHost;
72   if(m_nativeWindow)
73     free(m_nativeWindow);
74 #endif
75
76
77 bool CEGLNativeTypeRaspberryPI::CheckCompatibility()
78 {
79 #if defined(TARGET_RASPBERRY_PI)
80   DLOG("CEGLNativeTypeRaspberryPI::CheckCompatibility\n");
81   return true;
82 #else
83   return false;
84 #endif
85 }
86
87 void CEGLNativeTypeRaspberryPI::Initialize()
88 {
89 #if defined(TARGET_RASPBERRY_PI)
90   m_DllBcmHost              = NULL;
91   m_dispman_element         = DISPMANX_NO_HANDLE;
92   m_dispman_display         = DISPMANX_NO_HANDLE;
93
94   m_width                   = 1280;
95   m_height                  = 720;
96   m_initDesktopRes          = true;
97
98   m_DllBcmHost = new DllBcmHost;
99   m_DllBcmHost->Load();
100 #endif
101 }
102
103 void CEGLNativeTypeRaspberryPI::Destroy()
104 {
105 #if defined(TARGET_RASPBERRY_PI)
106   if(m_DllBcmHost && m_DllBcmHost->IsLoaded())
107     m_DllBcmHost->Unload();
108   delete m_DllBcmHost;
109   m_DllBcmHost = NULL;
110 #endif
111 }
112
113 bool CEGLNativeTypeRaspberryPI::CreateNativeDisplay()
114 {
115   m_nativeDisplay = EGL_DEFAULT_DISPLAY;
116   return true;
117 }
118
119 bool CEGLNativeTypeRaspberryPI::CreateNativeWindow()
120 {
121 #if defined(TARGET_RASPBERRY_PI)
122   if(!m_nativeWindow)
123     m_nativeWindow = (EGLNativeWindowType) calloc(1,sizeof( EGL_DISPMANX_WINDOW_T));
124   DLOG("CEGLNativeTypeRaspberryPI::CEGLNativeTypeRaspberryPI\n");
125   return true;
126 #else
127   return false;
128 #endif
129 }
130
131 bool CEGLNativeTypeRaspberryPI::GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const
132 {
133   if (!nativeDisplay)
134     return false;
135   *nativeDisplay = (XBNativeDisplayType*) &m_nativeDisplay;
136   return true;
137 }
138
139 bool CEGLNativeTypeRaspberryPI::GetNativeWindow(XBNativeDisplayType **nativeWindow) const
140 {
141   DLOG("CEGLNativeTypeRaspberryPI::GetNativeWindow\n");
142   if (!nativeWindow)
143     return false;
144   *nativeWindow = (XBNativeWindowType*) &m_nativeWindow;
145   return true;
146 }  
147
148 bool CEGLNativeTypeRaspberryPI::DestroyNativeDisplay()
149 {
150   DLOG("CEGLNativeTypeRaspberryPI::DestroyNativeDisplay\n");
151   return true;
152 }
153
154 bool CEGLNativeTypeRaspberryPI::DestroyNativeWindow()
155 {
156 #if defined(TARGET_RASPBERRY_PI)
157   DestroyDispmaxWindow();
158   free(m_nativeWindow);
159   m_nativeWindow = NULL;
160   DLOG("CEGLNativeTypeRaspberryPI::DestroyNativeWindow\n");
161   return true;
162 #else
163   return false;
164 #endif  
165 }
166
167 bool CEGLNativeTypeRaspberryPI::GetNativeResolution(RESOLUTION_INFO *res) const
168 {
169 #if defined(TARGET_RASPBERRY_PI)
170   *res = m_desktopRes;
171
172   DLOG("CEGLNativeTypeRaspberryPI::GetNativeResolution %s\n", res->strMode.c_str());
173   return true;
174 #else
175   return false;
176 #endif
177 }
178
179 #if defined(TARGET_RASPBERRY_PI)
180 int CEGLNativeTypeRaspberryPI::FindMatchingResolution(const RESOLUTION_INFO &res, const std::vector<RESOLUTION_INFO> &resolutions)
181 {
182   for (int i = 0; i < (int)resolutions.size(); i++)
183   {
184     if(resolutions[i].iScreenWidth == res.iScreenWidth && resolutions[i].iScreenHeight == res.iScreenHeight && resolutions[i].fRefreshRate == res.fRefreshRate &&
185       (resolutions[i].dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB)) == (res.dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB)))
186     {
187        return i;
188     }
189   }
190   return -1;
191 }
192 #endif
193
194 #if defined(TARGET_RASPBERRY_PI)
195 int CEGLNativeTypeRaspberryPI::AddUniqueResolution(const RESOLUTION_INFO &res, std::vector<RESOLUTION_INFO> &resolutions)
196 {
197   int i = FindMatchingResolution(res, resolutions);
198   if (i>=0)
199   {  // don't replace a progressive resolution with an interlaced one of same resolution
200      if (!(res.dwFlags & D3DPRESENTFLAG_INTERLACED))
201        resolutions[i] = res;
202   }
203   else
204   {
205      resolutions.push_back(res);
206   }
207   return i;
208 }
209 #endif
210
211 bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
212 {
213 #if defined(TARGET_RASPBERRY_PI)
214   if(!m_DllBcmHost || !m_nativeWindow)
215     return false;
216
217   DestroyDispmaxWindow();
218
219   if(!m_fixedMode && GETFLAGS_GROUP(res.dwFlags) && GETFLAGS_MODE(res.dwFlags))
220   {
221     sem_init(&m_tv_synced, 0, 0);
222     m_DllBcmHost->vc_tv_register_callback(CallbackTvServiceCallback, this);
223
224     if (res.dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB))
225     {
226       /* inform TV of any 3D settings. Note this property just applies to next hdmi mode change, so no need to call for 2D modes */
227       HDMI_PROPERTY_PARAM_T property;
228       property.property = HDMI_PROPERTY_3D_STRUCTURE;
229       if (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
230         property.param1 = HDMI_3D_FORMAT_SBS_HALF;
231       else if (res.dwFlags & D3DPRESENTFLAG_MODE3DTB)
232         property.param1 = HDMI_3D_FORMAT_TB_HALF;
233       else
234         property.param1 = HDMI_3D_FORMAT_NONE;
235       property.param2 = 0;
236       vc_tv_hdmi_set_property(&property);
237     }
238     int success = m_DllBcmHost->vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags));
239
240     if (success == 0)
241     {
242       CLog::Log(LOGDEBUG, "EGL set HDMI mode (%d,%d)=%d%s%s\n",
243                           GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), success,
244                           (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ? " SBS":"",
245                           (res.dwFlags & D3DPRESENTFLAG_MODE3DTB) ? " TB":"");
246
247       sem_wait(&m_tv_synced);
248     }
249     else
250     {
251       CLog::Log(LOGERROR, "EGL failed to set HDMI mode (%d,%d)=%d%s%s\n",
252                           GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), success,
253                           (res.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ? " SBS":"",
254                           (res.dwFlags & D3DPRESENTFLAG_MODE3DTB) ? " TB":"");
255     }
256     m_DllBcmHost->vc_tv_unregister_callback(CallbackTvServiceCallback);
257     sem_destroy(&m_tv_synced);
258
259     m_desktopRes = res;
260   }
261
262   m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0);
263
264   m_width   = res.iWidth;
265   m_height  = res.iHeight;
266
267   VC_RECT_T dst_rect;
268   VC_RECT_T src_rect;
269
270   dst_rect.x      = 0;
271   dst_rect.y      = 0;
272   dst_rect.width  = res.iScreenWidth;
273   dst_rect.height = res.iScreenHeight;
274
275   src_rect.x      = 0;
276   src_rect.y      = 0;
277   src_rect.width  = m_width << 16;
278   src_rect.height = m_height << 16;
279
280   VC_DISPMANX_ALPHA_T alpha;
281   memset(&alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T));
282   alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE;
283
284   DISPMANX_CLAMP_T clamp;
285   memset(&clamp, 0x0, sizeof(DISPMANX_CLAMP_T));
286
287   DISPMANX_TRANSFORM_T transform = DISPMANX_NO_ROTATE;
288   DISPMANX_UPDATE_HANDLE_T dispman_update = m_DllBcmHost->vc_dispmanx_update_start(0);
289
290   CLog::Log(LOGDEBUG, "EGL set resolution %dx%d -> %dx%d @ %.2f fps (%d,%d) flags:%x aspect:%.2f\n",
291       m_width, m_height, dst_rect.width, dst_rect.height, res.fRefreshRate, GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags), (int)res.dwFlags, res.fPixelRatio);
292
293   m_dispman_element = m_DllBcmHost->vc_dispmanx_element_add(dispman_update,
294     m_dispman_display,
295     1,                              // layer
296     &dst_rect,
297     (DISPMANX_RESOURCE_HANDLE_T)0,  // src
298     &src_rect,
299     DISPMANX_PROTECTION_NONE,
300     &alpha,                         //alphe
301     &clamp,                         //clamp
302     transform);                     // transform
303
304   assert(m_dispman_element != DISPMANX_NO_HANDLE);
305   assert(m_dispman_element != (unsigned)DISPMANX_INVALID);
306
307   memset(m_nativeWindow, 0, sizeof(EGL_DISPMANX_WINDOW_T));
308
309   EGL_DISPMANX_WINDOW_T *nativeWindow = (EGL_DISPMANX_WINDOW_T *)m_nativeWindow;
310
311   nativeWindow->element = m_dispman_element;
312   nativeWindow->width   = m_width;
313   nativeWindow->height  = m_height;
314
315   m_DllBcmHost->vc_dispmanx_display_set_background(dispman_update, m_dispman_display, 0x00, 0x00, 0x00);
316   m_DllBcmHost->vc_dispmanx_update_submit_sync(dispman_update);
317
318   DLOG("CEGLNativeTypeRaspberryPI::SetNativeResolution\n");
319
320   return true;
321 #else
322   return false;
323 #endif
324 }
325
326 #if defined(TARGET_RASPBERRY_PI)
327 static float get_display_aspect_ratio(HDMI_ASPECT_T aspect)
328 {
329   float display_aspect;
330   switch (aspect) {
331     case HDMI_ASPECT_4_3:   display_aspect = 4.0/3.0;   break;
332     case HDMI_ASPECT_14_9:  display_aspect = 14.0/9.0;  break;
333     case HDMI_ASPECT_16_9:  display_aspect = 16.0/9.0;  break;
334     case HDMI_ASPECT_5_4:   display_aspect = 5.0/4.0;   break;
335     case HDMI_ASPECT_16_10: display_aspect = 16.0/10.0; break;
336     case HDMI_ASPECT_15_9:  display_aspect = 15.0/9.0;  break;
337     case HDMI_ASPECT_64_27: display_aspect = 64.0/27.0; break;
338     default:                display_aspect = 16.0/9.0;  break;
339   }
340   return display_aspect;
341 }
342
343 static float get_display_aspect_ratio(SDTV_ASPECT_T aspect)
344 {
345   float display_aspect;
346   switch (aspect) {
347     case SDTV_ASPECT_4_3:  display_aspect = 4.0/3.0;  break;
348     case SDTV_ASPECT_14_9: display_aspect = 14.0/9.0; break;
349     case SDTV_ASPECT_16_9: display_aspect = 16.0/9.0; break;
350     default:               display_aspect = 4.0/3.0;  break;
351   }
352   return display_aspect;
353 }
354 #endif
355
356 bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
357 {
358 #if defined(TARGET_RASPBERRY_PI)
359   resolutions.clear();
360
361   if(!m_DllBcmHost)
362     return false;
363
364   m_fixedMode               = false;
365
366   /* read initial desktop resolution before probe resolutions.
367    * probing will replace the desktop resolution when it finds the same one.
368    * we raplace it because probing will generate more detailed 
369    * resolution flags we don't get with vc_tv_get_state.
370    */
371
372   if(m_initDesktopRes)
373   {
374     TV_DISPLAY_STATE_T tv_state;
375
376     // get current display settings state
377     memset(&tv_state, 0, sizeof(TV_DISPLAY_STATE_T));
378     m_DllBcmHost->vc_tv_get_display_state(&tv_state);
379
380     if ((tv_state.state & ( VC_HDMI_HDMI | VC_HDMI_DVI )) != 0) // hdtv
381     {
382       m_desktopRes.iScreen      = 0;
383       m_desktopRes.bFullScreen  = true;
384       m_desktopRes.iWidth       = tv_state.display.hdmi.width;
385       m_desktopRes.iHeight      = tv_state.display.hdmi.height;
386       m_desktopRes.iScreenWidth = tv_state.display.hdmi.width;
387       m_desktopRes.iScreenHeight= tv_state.display.hdmi.height;
388       m_desktopRes.dwFlags      = MAKEFLAGS(tv_state.display.hdmi.group, tv_state.display.hdmi.mode, tv_state.display.hdmi.scan_mode);
389       m_desktopRes.fPixelRatio  = get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
390       // Also add 3D flags
391       if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_SBS_HALF)
392       {
393         m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
394         m_desktopRes.fPixelRatio *= 2.0;
395       }
396       else if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_TB_HALF)
397       {
398         m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
399         m_desktopRes.fPixelRatio *= 0.5;
400       }
401       m_desktopRes.fRefreshRate = (float)tv_state.display.hdmi.frame_rate;
402     }
403     else // sdtv
404     {
405       m_desktopRes.iScreen      = 0;
406       m_desktopRes.bFullScreen  = true;
407       m_desktopRes.iWidth       = tv_state.display.sdtv.width;
408       m_desktopRes.iHeight      = tv_state.display.sdtv.height;
409       m_desktopRes.iScreenWidth = tv_state.display.sdtv.width;
410       m_desktopRes.iScreenHeight= tv_state.display.sdtv.height;
411       m_desktopRes.dwFlags      = D3DPRESENTFLAG_INTERLACED;
412       m_desktopRes.fRefreshRate = (float)tv_state.display.sdtv.frame_rate;
413       m_desktopRes.fPixelRatio  = get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
414     }
415
416     m_desktopRes.strMode = StringUtils::Format("%dx%d", m_desktopRes.iScreenWidth, m_desktopRes.iScreenHeight);
417
418     if((int)m_desktopRes.fRefreshRate > 1)
419     {
420       m_desktopRes.strMode = StringUtils::Format("%dx%d @ %.2f%s - Full Screen", m_desktopRes.iScreenWidth, m_desktopRes.iScreenHeight, m_desktopRes.fRefreshRate,
421         m_desktopRes.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
422     }
423     m_initDesktopRes = false;
424
425     int gui_width  = m_desktopRes.iWidth;
426     int gui_height = m_desktopRes.iHeight;
427
428     ClampToGUIDisplayLimits(gui_width, gui_height);
429
430     m_desktopRes.iWidth = gui_width;
431     m_desktopRes.iHeight = gui_height;
432
433     m_desktopRes.iSubtitles   = (int)(0.965 * m_desktopRes.iHeight);
434
435     CLog::Log(LOGDEBUG, "EGL initial desktop resolution %s (%.2f)\n", m_desktopRes.strMode.c_str(), m_desktopRes.fPixelRatio);
436   }
437
438   GetSupportedModes(HDMI_RES_GROUP_CEA, resolutions);
439   GetSupportedModes(HDMI_RES_GROUP_DMT, resolutions);
440
441   if(resolutions.size() == 0)
442   {
443     RESOLUTION_INFO res;
444     CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);
445
446     AddUniqueResolution(m_desktopRes, resolutions);
447   }
448
449   if(resolutions.size() < 2)
450     m_fixedMode = true;
451
452   DLOG("CEGLNativeTypeRaspberryPI::ProbeResolutions\n");
453   return true;
454 #else
455   return false;
456 #endif
457 }
458
459 bool CEGLNativeTypeRaspberryPI::GetPreferredResolution(RESOLUTION_INFO *res) const
460 {
461   DLOG("CEGLNativeTypeRaspberryPI::GetPreferredResolution\n");
462   return false;
463 }
464
465 bool CEGLNativeTypeRaspberryPI::ShowWindow(bool show)
466 {
467   DLOG("CEGLNativeTypeRaspberryPI::ShowWindow\n");
468   return false;
469 }
470
471 #if defined(TARGET_RASPBERRY_PI)
472 void CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow()
473 {
474   if(!m_DllBcmHost)
475     return;
476
477   DISPMANX_UPDATE_HANDLE_T dispman_update = m_DllBcmHost->vc_dispmanx_update_start(0);
478
479   if (m_dispman_element != DISPMANX_NO_HANDLE)
480   {
481     m_DllBcmHost->vc_dispmanx_element_remove(dispman_update, m_dispman_element);
482     m_dispman_element = DISPMANX_NO_HANDLE;
483   }
484   m_DllBcmHost->vc_dispmanx_update_submit_sync(dispman_update);
485
486   if (m_dispman_display != DISPMANX_NO_HANDLE)
487   {
488     m_DllBcmHost->vc_dispmanx_display_close(m_dispman_display);
489     m_dispman_display = DISPMANX_NO_HANDLE;
490   }
491   DLOG("CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow\n");
492 }
493
494 void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::vector<RESOLUTION_INFO> &resolutions)
495 {
496   if(!m_DllBcmHost)
497     return;
498
499   //Supported HDMI CEA/DMT resolutions, preferred resolution will be returned
500   int32_t num_modes = 0;
501   HDMI_RES_GROUP_T prefer_group;
502   uint32_t prefer_mode;
503   int i;
504   TV_SUPPORTED_MODE_NEW_T *supported_modes = NULL;
505   // query the number of modes first
506   int max_supported_modes = m_DllBcmHost->vc_tv_hdmi_get_supported_modes_new(group, NULL, 0, &prefer_group, &prefer_mode);
507
508   if (max_supported_modes > 0)
509     supported_modes = new TV_SUPPORTED_MODE_NEW_T[max_supported_modes];
510
511   if (supported_modes)
512   {
513     num_modes = m_DllBcmHost->vc_tv_hdmi_get_supported_modes_new(group,
514         supported_modes, max_supported_modes, &prefer_group, &prefer_mode);
515
516     CLog::Log(LOGDEBUG, "EGL get supported modes (%d) = %d, prefer_group=%x, prefer_mode=%x\n",
517         group, num_modes, prefer_group, prefer_mode);
518   }
519
520   if (num_modes > 0 && prefer_group != HDMI_RES_GROUP_INVALID)
521   {
522     TV_SUPPORTED_MODE_NEW_T *tv = supported_modes;
523     for (i=0; i < num_modes; i++, tv++)
524     {
525       RESOLUTION_INFO res;
526
527       res.iScreen       = 0;
528       res.bFullScreen   = true;
529       res.dwFlags       = MAKEFLAGS(group, tv->code, tv->scan_mode);
530       res.fRefreshRate  = (float)tv->frame_rate;
531       res.iWidth        = tv->width;
532       res.iHeight       = tv->height;
533       res.iScreenWidth  = tv->width;
534       res.iScreenHeight = tv->height;
535       res.fPixelRatio   = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res.iScreenWidth / (float)res.iScreenHeight);
536
537       int gui_width  = res.iWidth;
538       int gui_height = res.iHeight;
539
540       ClampToGUIDisplayLimits(gui_width, gui_height);
541
542       res.iWidth = gui_width;
543       res.iHeight = gui_height;
544
545       res.strMode = StringUtils::Format("%dx%d @ %.2f%s - Full Screen", res.iScreenWidth, res.iScreenHeight, res.fRefreshRate,
546         res.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
547
548       CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f) %s%s:%x\n", i, res.strMode.c_str(), res.fPixelRatio,
549           tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
550
551       res.iSubtitles    = (int)(0.965 * res.iHeight);
552
553       AddUniqueResolution(res, resolutions);
554
555       // Also add 3D versions of modes
556       if (tv->struct_3d_mask & HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_HORIZONTAL)
557       {
558         RESOLUTION_INFO res2 = res;
559         res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
560         res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
561         res2.fPixelRatio   *= 2.0f;
562         res2.strMode = StringUtils::Format("%dx%d @ %.2f%s - Full Screen", res2.iScreenWidth, res2.iScreenHeight, res2.fRefreshRate,
563             res2.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
564         CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f) SBS\n", i, res2.strMode.c_str(), res2.fPixelRatio);
565
566         res2.iSubtitles    = (int)(0.965 * res2.iHeight);
567
568         AddUniqueResolution(res2, resolutions);
569       }
570       if (tv->struct_3d_mask & HDMI_3D_STRUCT_TOP_AND_BOTTOM)
571       {
572         RESOLUTION_INFO res2 = res;
573         res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
574         res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
575         res2.fPixelRatio   *= 0.5f;
576         res2.strMode = StringUtils::Format("%dx%d @ %.2f%s - Full Screen", res2.iScreenWidth, res2.iScreenHeight, res2.fRefreshRate,
577             res2.dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
578         CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f) TAB\n", i, res2.strMode.c_str(), res2.fPixelRatio);
579
580         res2.iSubtitles    = (int)(0.965 * res2.iHeight);
581
582         AddUniqueResolution(res2, resolutions);
583       }
584     }
585   }
586   if (supported_modes)
587     delete [] supported_modes;
588 }
589
590 void CEGLNativeTypeRaspberryPI::TvServiceCallback(uint32_t reason, uint32_t param1, uint32_t param2)
591 {
592   CLog::Log(LOGDEBUG, "EGL tv_service_callback (%d,%d,%d)\n", reason, param1, param2);
593   switch(reason)
594   {
595   case VC_HDMI_UNPLUGGED:
596     break;
597   case VC_HDMI_STANDBY:
598     break;
599   case VC_SDTV_NTSC:
600   case VC_SDTV_PAL:
601   case VC_HDMI_HDMI:
602   case VC_HDMI_DVI:
603     //Signal we are ready now
604     sem_post(&m_tv_synced);
605     break;
606   default:
607      break;
608   }
609 }
610
611 void CEGLNativeTypeRaspberryPI::CallbackTvServiceCallback(void *userdata, uint32_t reason, uint32_t param1, uint32_t param2)
612 {
613    CEGLNativeTypeRaspberryPI *callback = static_cast<CEGLNativeTypeRaspberryPI*>(userdata);
614    callback->TvServiceCallback(reason, param1, param2);
615 }
616
617 bool CEGLNativeTypeRaspberryPI::ClampToGUIDisplayLimits(int &width, int &height)
618 {
619   const int max_width = 1280, max_height = 720;
620   float ar = (float)width/(float)height;
621   // bigger than maximum, so need to clamp
622   if (width > max_width || height > max_height) {
623     // wider than max, so clamp width first
624     if (ar > (float)max_width/(float)max_height)
625     {
626       width = max_width;
627       height = (float)max_width / ar + 0.5f;
628     // taller than max, so clamp height first
629     } else {
630       height = max_height;
631       width = (float)max_height * ar + 0.5f;
632     }
633     return true;
634   }
635
636   return false;
637 }
638
639 #endif
640