updated: No longer need to cast to a float.
[xbmc:xbmc-antiquated.git] / XBMC / xbmc / ApplicationRenderer.cpp
1 /*\r
2  *      Copyright (C) 2005-2007 Team XboxMediaCenter\r
3  *      http://www.xboxmediacenter.com\r
4  *\r
5  *  This Program is free software; you can redistribute it and/or modify\r
6  *  it under the terms of the GNU General Public License as published by\r
7  *  the Free Software Foundation; either version 2, or (at your option)\r
8  *  any later version.\r
9  *\r
10  *  This Program is distributed in the hope that it will be useful,\r
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
13  *  GNU General Public License for more details.\r
14  *\r
15  *  You should have received a copy of the GNU General Public License\r
16  *  along with GNU Make; see the file COPYING.  If not, write to\r
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\r
18  *  http://www.gnu.org/copyleft/gpl.html\r
19  *\r
20  */\r
21 \r
22 #include "stdafx.h"\r
23 #include "ApplicationRenderer.h"\r
24 #include "utils/GUIInfoManager.h"\r
25 #include "../guilib/guiImage.h"\r
26 \r
27 CApplicationRenderer g_ApplicationRenderer;\r
28 \r
29 CApplicationRenderer::CApplicationRenderer(void)\r
30 {\r
31 }\r
32 \r
33 CApplicationRenderer::~CApplicationRenderer()\r
34 {\r
35   Stop();\r
36 }\r
37 \r
38 void CApplicationRenderer::OnStartup()\r
39 {\r
40   m_time = timeGetTime();\r
41   m_enabled = true;\r
42   m_busyShown = false;\r
43   m_explicitbusy = 0;\r
44   m_busycount = 0;\r
45   m_prevbusycount = 0;\r
46 #ifndef HAS_SDL
47   m_lpSurface = NULL;\r
48 #endif
49   m_pWindow = NULL;\r
50   m_Resolution = g_graphicsContext.GetVideoResolution();\r
51 }\r
52 \r
53 void CApplicationRenderer::OnExit()\r
54 {\r
55   m_busycount = m_prevbusycount = m_explicitbusy = 0;\r
56   m_busyShown = false;\r
57   if (m_pWindow) m_pWindow->Close(true);\r
58   m_pWindow = NULL;\r
59 #ifndef HAS_SDL
60   SAFE_RELEASE(m_lpSurface);\r
61 #endif
62 }\r
63 \r
64 void CApplicationRenderer::Process()\r
65 {\r
66 #ifndef HAS_SDL
67   int iWidth = 0;\r
68   int iHeight = 0;\r
69   int iLeft = 0;\r
70   int iTop = 0;\r
71   LPDIRECT3DSURFACE8 lpSurfaceBack = NULL;\r
72   LPDIRECT3DSURFACE8 lpSurfaceFront = NULL;\r
73   while (!m_bStop)\r
74   {\r
75     if (!m_enabled || g_graphicsContext.IsFullScreenVideo())\r
76     {\r
77       Sleep(50);\r
78       continue;\r
79     }\r
80 \r
81     if (!m_pWindow || iWidth == 0 || iHeight == 0 || m_Resolution != g_graphicsContext.GetVideoResolution())\r
82     {\r
83       m_pWindow = (CGUIDialogBusy*)m_gWindowManager.GetWindow(WINDOW_DIALOG_BUSY);\r
84       if (m_pWindow)\r
85       {\r
86         m_pWindow->Initialize();//need to load the window to determine size.\r
87         if (m_pWindow->GetID() == WINDOW_INVALID)\r
88         {\r
89           //busywindow couldn't be loaded so stop this thread.\r
90           m_pWindow = NULL;\r
91           m_bStop = true;\r
92           break;\r
93         }\r
94 \r
95         SAFE_RELEASE(m_lpSurface);\r
96         FRECT rect = m_pWindow->GetScaledBounds();\r
97         m_pWindow->ClearAll(); //unload\r
98 \r
99         iLeft = (int)floor(rect.left);\r
100         iTop =  (int)floor(rect.top);\r
101         iWidth = (int)ceil(rect.right - rect.left);\r
102         iHeight = (int)ceil(rect.bottom - rect.top);\r
103         m_Resolution = g_graphicsContext.GetVideoResolution();\r
104       }\r
105     }\r
106 \r
107     float t0 = (1000.0f/g_graphicsContext.GetFPS());\r
108     float t1 = m_time + t0; //time when we expect a new render\r
109     float t2 = (float)timeGetTime();\r
110     if (t1 < t2) //we're late rendering\r
111     {\r
112       try\r
113       {\r
114         if (timeGetTime() >= (m_time + g_advancedSettings.m_busyDialogDelay))\r
115         {\r
116           CSingleLock lockg (g_graphicsContext);\r
117           if (m_prevbusycount != m_busycount)\r
118           {\r
119             Sleep(1);\r
120             continue;\r
121           }\r
122           if (!m_pWindow || iWidth == 0 || iHeight == 0)\r
123           {\r
124             Sleep(1000);\r
125             continue;\r
126           }\r
127           if (m_Resolution != g_graphicsContext.GetVideoResolution())\r
128           {\r
129             continue;\r
130           }\r
131           if (m_busycount > 0) m_busycount--;\r
132           //no busy indicator if a progress dialog is showing\r
133           if ((m_gWindowManager.HasModalDialog() && (m_gWindowManager.GetTopMostModalDialogID() != WINDOW_VIDEO_INFO) && (m_gWindowManager.GetTopMostModalDialogID() != WINDOW_MUSIC_INFO)) || (m_gWindowManager.GetTopMostModalDialogID() == WINDOW_DIALOG_PROGRESS))\r
134           {\r
135             //TODO: render progress dialog here instead of in dialog::Progress\r
136             m_time = timeGetTime();\r
137             lockg.Leave();\r
138             Sleep(1);\r
139             continue;\r
140           }\r
141           if (m_lpSurface == NULL)\r
142           {\r
143             D3DSURFACE_DESC desc;\r
144 #ifdef HAS_XBOX_D3D\r
145             if (SUCCEEDED(g_graphicsContext.Get3DDevice()->GetBackBuffer( -1, D3DBACKBUFFER_TYPE_MONO, &lpSurfaceFront)))\r
146             {\r
147               lpSurfaceFront->GetDesc( &desc );\r
148             }\r
149             else\r
150 #else\r
151             g_application.RenderNoPresent();\r
152             HRESULT result = g_graphicsContext.Get3DDevice()->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &lpSurfaceFront);\r
153             if (SUCCEEDED(result))\r
154             {\r
155               lpSurfaceFront->GetDesc( &desc );\r
156               iLeft = 0;\r
157               iTop = 0;\r
158               iWidth = desc.Width;\r
159               iHeight = desc.Height;\r
160             }\r
161             else\r
162 #endif\r
163             {\r
164               lockg.Leave();\r
165               Sleep(1000);\r
166               continue;\r
167             }\r
168             if (!SUCCEEDED(g_graphicsContext.Get3DDevice()->CreateImageSurface(iWidth, iHeight, desc.Format, &m_lpSurface)))\r
169             {\r
170               SAFE_RELEASE(lpSurfaceFront);\r
171               lockg.Leave();\r
172               Sleep(1000);\r
173               continue;\r
174             }\r
175             //copy part underneeth busy dialog\r
176             const RECT rc = { iLeft, iTop, iLeft + iWidth, iTop + iHeight  };\r
177             const RECT rcDest = { 0, 0, iWidth, iHeight  };\r
178             if (!CopySurface(lpSurfaceFront, &rc, m_lpSurface, &rcDest))\r
179             {\r
180                 SAFE_RELEASE(lpSurfaceFront);\r
181                 SAFE_RELEASE(m_lpSurface);\r
182                 lockg.Leave();\r
183                 Sleep(1000);\r
184                 continue;\r
185             }\r
186 \r
187             //copy front buffer to backbuffer(s) to avoid jumping\r
188             bool bBufferCopied = true;\r
189             for (int i = 0; i < g_graphicsContext.GetBackbufferCount(); i++)\r
190             {\r
191               if (!SUCCEEDED(g_graphicsContext.Get3DDevice()->GetBackBuffer( i, D3DBACKBUFFER_TYPE_MONO, &lpSurfaceBack)))\r
192               {\r
193                 bBufferCopied = false;\r
194                 break;\r
195               }\r
196               if (!CopySurface(lpSurfaceFront, NULL, lpSurfaceBack, NULL))\r
197               {\r
198                 bBufferCopied = false;\r
199                 break;\r
200               }\r
201               SAFE_RELEASE(lpSurfaceBack);\r
202             }\r
203             if (!bBufferCopied)\r
204             {\r
205               SAFE_RELEASE(lpSurfaceFront);\r
206               SAFE_RELEASE(lpSurfaceBack);\r
207               SAFE_RELEASE(m_lpSurface);\r
208               lockg.Leave();\r
209               Sleep(1000);\r
210               continue;\r
211             }\r
212             SAFE_RELEASE(lpSurfaceFront);\r
213           }\r
214           if (!SUCCEEDED(g_graphicsContext.Get3DDevice()->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &lpSurfaceBack)))\r
215           {\r
216               lockg.Leave();\r
217               Sleep(1000);\r
218               continue;\r
219           }\r
220           g_graphicsContext.Get3DDevice()->BeginScene();\r
221           //copy dialog background to backbuffer\r
222           const RECT rc = { 0, 0, iWidth, iHeight };\r
223           const RECT rcDest = { iLeft, iTop, iLeft + iWidth, iTop + iHeight };\r
224           const D3DRECT rc2 = { iLeft, iTop, iLeft + iWidth, iTop + iHeight };\r
225 #ifdef HAS_XBOX_D3D\r
226           g_graphicsContext.Get3DDevice()->Clear(1, &rc2, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0x00010001, 1.0f, 0L);\r
227 #else\r
228           g_graphicsContext.Get3DDevice()->Clear(1, &rc2, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00010001, 1.0f, 0L);\r
229 #endif\r
230           if (!CopySurface(m_lpSurface, &rc, lpSurfaceBack, &rcDest))\r
231           {\r
232               SAFE_RELEASE(lpSurfaceBack);\r
233               g_graphicsContext.Get3DDevice()->EndScene();\r
234               lockg.Leave();\r
235               Sleep(1000);\r
236               continue;\r
237           }\r
238           SAFE_RELEASE(lpSurfaceBack);\r
239           if (!m_busyShown)\r
240           {\r
241             m_pWindow->Show();\r
242             m_busyShown = true;\r
243           }\r
244           m_pWindow->Render();\r
245 \r
246           g_graphicsContext.Get3DDevice()->EndScene();\r
247           //D3DSWAPEFFECT_DISCARD is used so we can't just present the busy rect but can only present the entire screen.\r
248           g_graphicsContext.Get3DDevice()->Present( NULL, NULL, NULL, NULL );\r
249         }\r
250         m_busycount++;\r
251         m_prevbusycount = m_busycount;\r
252       }\r
253       catch (...)\r
254       {\r
255         CLog::Log(LOGERROR, __FUNCTION__" - Exception caught when  busy rendering");\r
256         SAFE_RELEASE(lpSurfaceFront);\r
257         SAFE_RELEASE(lpSurfaceBack);\r
258         SAFE_RELEASE(m_lpSurface);\r
259       }\r
260     }\r
261     Sleep(1);\r
262   }\r
263 #endif
264 }\r
265 \r
266 #ifndef HAS_SDL
267 bool CApplicationRenderer::CopySurface(LPDIRECT3DSURFACE8 pSurfaceSource, const RECT* rcSource, LPDIRECT3DSURFACE8 pSurfaceDest, const RECT* rcDest)\r
268 {\r
269   if (m_Resolution == HDTV_1080i)\r
270   {\r
271     //CopRects doesn't work at all in 1080i, D3DXLoadSurfaceFromSurface does but is ridiculously slow...\r
272     return SUCCEEDED(D3DXLoadSurfaceFromSurface(pSurfaceDest, NULL, rcDest, pSurfaceSource, NULL, rcSource, D3DX_FILTER_NONE, 0));\r
273   }\r
274   else\r
275   {\r
276     if (rcDest)\r
277     {\r
278       const POINT ptDest = { rcDest->left, rcDest->top };\r
279       return SUCCEEDED(g_graphicsContext.Get3DDevice()->CopyRects(pSurfaceSource, rcSource, rcSource?1:0, pSurfaceDest, &ptDest));\r
280     }\r
281     else\r
282     {\r
283       const POINT ptDest = { 0, 0 };\r
284       return SUCCEEDED(g_graphicsContext.Get3DDevice()->CopyRects(pSurfaceSource, rcSource, rcSource?1:0, pSurfaceDest, &ptDest));\r
285     }\r
286   }\r
287 }\r
288 #endif
289 \r
290 void CApplicationRenderer::UpdateBusyCount()\r
291 {\r
292   if (m_busycount == 0)\r
293   {\r
294     m_prevbusycount = 0;\r
295   }\r
296   else\r
297   {\r
298     m_busycount--;\r
299     m_prevbusycount = m_busycount;\r
300     if (m_pWindow && m_busyShown)\r
301     {\r
302       m_busyShown = false;\r
303       m_pWindow->Close();\r
304     }\r
305   }\r
306 }\r
307 \r
308 void CApplicationRenderer::Render(bool bFullscreen)\r
309 {\r
310   CSingleLock lockg (g_graphicsContext);\r
311   Disable();\r
312   UpdateBusyCount();\r
313 #ifndef HAS_SDL
314   SAFE_RELEASE(m_lpSurface);\r
315 #endif
316   if (bFullscreen)\r
317   {\r
318     g_application.DoRenderFullScreen();\r
319   }\r
320   else\r
321   {\r
322     g_application.DoRender();\r
323   }\r
324   m_time = timeGetTime();\r
325   Enable();\r
326 }\r
327 \r
328 void CApplicationRenderer::Enable()\r
329 {\r
330   m_enabled = true;\r
331 }\r
332 \r
333 void CApplicationRenderer::Disable()\r
334 {\r
335   m_enabled = false;\r
336 }\r
337 \r
338 bool CApplicationRenderer::Start()\r
339 {\r
340   if (g_advancedSettings.m_busyDialogDelay <= 0) return false; //delay of 0 is considered disabled.\r
341   Create();\r
342   return true;\r
343 }\r
344 \r
345 void CApplicationRenderer::Stop()\r
346 {\r
347   StopThread();\r
348 }\r
349 \r
350 bool CApplicationRenderer::IsBusy() const\r
351 {\r
352   return ((m_explicitbusy > 0) || m_busyShown);\r
353 }\r
354 \r
355 void CApplicationRenderer::SetBusy(bool bBusy)\r
356 {\r
357   if (g_advancedSettings.m_busyDialogDelay <= 0) return; //never show it if disabled.\r
358   bBusy?m_explicitbusy++:m_explicitbusy--;\r
359   if (m_explicitbusy < 0) m_explicitbusy = 0;\r
360   if (m_pWindow) \r
361   {\r
362     if (m_explicitbusy > 0)\r
363       m_pWindow->Show();\r
364     else \r
365       m_pWindow->Close();\r
366   }\r
367 }\r