]> git.vomp.tv Git - vompclient-marten.git/blob - osdwin.cc
Buffering progress bar
[vompclient-marten.git] / osdwin.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21
22 #include "osdwin.h"
23 #include "mtd.h"
24 #include "videowin.h"
25 #include "surfacewin.h"
26
27 #include "dsallocator.h"
28 #include "message.h"
29 #include "command.h"
30
31
32 //This is stuff for rendering the OSD
33
34
35 OsdWin::OsdWin()
36 {
37   d3d=NULL;
38   d3ddevice=NULL;
39   d3dvb=NULL;
40   d3drtsurf=NULL;
41   external_driving=false;
42   dsallocator=NULL;
43   filter_type=D3DTEXF_FORCE_DWORD;
44   lastrendertime=timeGetTime();
45   event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
46   d3dmutex = CreateMutex(NULL,FALSE,NULL);
47   
48 }
49
50 OsdWin::~OsdWin()
51 {
52   if (initted) shutdown();
53   CloseHandle(event);
54   CloseHandle(d3dmutex);
55 }
56
57 int OsdWin::getFD()
58 {
59   if (!initted) return 0;
60   return fdOsd;
61 }
62
63 int OsdWin::init(void* device)
64 {
65   if (initted) return 0;
66    Video* video = Video::getInstance();
67   //First Create Direct 3D Object
68   d3d=Direct3DCreate9(D3D_SDK_VERSION);
69   if (!d3d) 
70   {
71     Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 object!");
72     return 0;
73   }
74   // then create the Device
75   D3DPRESENT_PARAMETERS d3dparas;
76   ZeroMemory(&d3dparas,sizeof(d3dparas));
77   d3dparas.BackBufferWidth=video->getScreenWidth();
78   d3dparas.BackBufferHeight=video->getScreenHeight();
79   d3dparas.Windowed=TRUE;
80   d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;
81   if (d3d->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,*((HWND*) device),
82           D3DCREATE_SOFTWARE_VERTEXPROCESSING |D3DCREATE_MULTITHREADED,&d3dparas,&d3ddevice)!=D3D_OK) {
83            Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 device!");
84        return 0;
85   }
86   d3ddevice->GetRenderTarget(0,&d3drtsurf);
87
88   if (!InitVertexBuffer()) {
89            Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 vertex buf!");
90                   return 0;
91   }
92   /* We have to determine which kind of filtering is supported*/
93   D3DCAPS9 caps;
94   d3ddevice->GetDeviceCaps(&caps);
95   if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR)!=0)
96           && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)!=0)) {
97           if (filter_type==D3DTEXF_FORCE_DWORD) {
98                         filter_type=D3DTEXF_LINEAR;
99           }
100   } else {
101       if (filter_type==D3DTEXF_LINEAR)
102       {
103           filter_type=D3DTEXF_POINT;
104       }
105   }
106   
107   if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT)!=0)
108           && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT)!=0)) {
109        if (filter_type==D3DTEXF_FORCE_DWORD) 
110        {
111                   filter_type=D3DTEXF_POINT;
112    }
113    } else {
114        if (filter_type==D3DTEXF_POINT) {
115            filter_type=D3DTEXF_NONE;
116    }
117    }
118    if (filter_type==D3DTEXF_FORCE_DWORD) {
119        filter_type=D3DTEXF_NONE;
120    }
121
122
123
124   //Now we will create the Screen
125   screen = new SurfaceWin(Surface::SCREEN);
126   SetEvent(event);//Now all devices are ready
127   screen->create(video->getScreenWidth(), video->getScreenHeight());
128   screen->display();
129   initted = 1; // must set this here or create surface won't work
130   
131   return 1;
132 }
133
134 DWORD OsdWin::getFilterCaps()
135 {
136     if (!initted) return NULL;
137     D3DCAPS9 caps;
138     d3ddevice->GetDeviceCaps(&caps);
139     return caps.StretchRectFilterCaps;
140 }
141
142 int OsdWin::InitVertexBuffer() {
143   Video* video = Video::getInstance();
144   FLOAT texx=((float)video->getScreenWidth())/1024.f;
145   FLOAT texy=((float)video->getScreenHeight())/1024.f;
146   D3DCOLOR osdcolor=D3DCOLOR_RGBA(255,255,255,255);
147   osdvertices[0].c=osdcolor;
148   osdvertices[0].x=0.f-0.5f;
149   osdvertices[0].y=0.f-0.5f;
150   osdvertices[0].z=0.5f;
151   osdvertices[0].rhw=1.f;
152   osdvertices[0].u=0.f;
153   osdvertices[0].v=0.f;
154   osdvertices[1].c=osdcolor;
155   osdvertices[1].x=((float)video->getScreenWidth())-0.5f;-0.5f;
156   osdvertices[1].y=0.f-0.5f;
157   osdvertices[1].z=0.5f;
158   osdvertices[1].u=texx;
159   osdvertices[1].v=0.f;
160   osdvertices[1].rhw=1.f;
161   osdvertices[2].c=osdcolor;
162   osdvertices[2].x=((float)video->getScreenWidth())-0.5f;
163   osdvertices[2].y=((float)video->getScreenHeight())-0.5f;
164   osdvertices[2].z=0.5f;
165   osdvertices[2].rhw=1.f;
166   osdvertices[2].u=texx;
167   osdvertices[2].v=texy;
168   osdvertices[3].c=osdcolor;
169   osdvertices[3].x=0.f-0.5f;
170   osdvertices[3].y=((float)video->getScreenHeight())-0.5f;
171   osdvertices[3].z=0.5f;
172   osdvertices[3].rhw=1.f;
173   osdvertices[3].u=0.f;
174   osdvertices[3].v=texy;
175   if (d3dvb) {
176           d3dvb->Release();
177           d3dvb=NULL;
178   }
179   if (d3ddevice->CreateVertexBuffer(4*sizeof(OSDVERTEX),0,D3DFVF_OSDVERTEX,D3DPOOL_MANAGED,
180           &d3dvb,NULL)!=D3D_OK) {
181           return 0;
182   }
183   void *pvertex=NULL;
184   if (d3dvb->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) {
185           return 0;
186   }
187   memcpy(pvertex,osdvertices,sizeof(osdvertices));
188   d3dvb->Unlock();
189   return 1;
190 }
191
192 int OsdWin::shutdown()
193 {
194   if (!initted) return 0;
195   initted = 0;
196   d3drtsurf->Release();
197   d3ddevice->Release();
198   d3d->Release();
199
200   return 1;
201 }
202
203 void OsdWin::screenShot(char* fileName)
204 {
205   screen->screenShot(fileName);
206 }
207
208 // This function is called from the WinMain function in order to get Screen updates
209 void OsdWin::Render()
210 {
211         if (!initted) return ;
212         if (external_driving) {
213         DWORD time1=timeGetTime(); //Updates the Menue
214                 if ((time1-lastrendertime)>200) {//5 fps for OSD updates are enough, avoids tearing
215                         InternalRendering(NULL);
216                         lastrendertime=timeGetTime();
217         } else {
218                 Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads
219         }
220         } else {
221                 DWORD time1=timeGetTime();
222                 if ((time1-lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing
223                         InternalRendering(NULL);
224                         lastrendertime=timeGetTime();
225                 } else {
226                         Sleep(5);
227                 
228                 }
229                 
230         }
231 }
232
233 void OsdWin::RenderDS(LPDIRECT3DSURFACE9 present){
234         if (!initted) return;
235         if (external_driving) {
236                 InternalRendering(present);
237         lastrendertime=timeGetTime();
238         }
239 }
240
241
242 void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){
243     WaitForSingleObject(d3dmutex,INFINITE);
244     HRESULT losty=d3ddevice->TestCooperativeLevel();
245     if (losty==D3DERR_DEVICELOST) {
246         Sleep(10);
247         return; //Device Lost
248     }
249     if (losty==D3DERR_DEVICENOTRESET){
250        DoLost();
251        return;
252     }
253         WaitForSingleObject(event,INFINITE);
254         
255    
256         BeginPainting();
257     d3ddevice->SetRenderTarget(0,d3drtsurf);//Stupid VMR manipulates the render target
258         if (external_driving) {
259                 //Copy video to Backbuffer
260                 if (present!=NULL ) {
261                         VideoWin* video =(VideoWin*) Video::getInstance();
262                         /*calculating destination rect */
263                         RECT destrect={0,0,video->getScreenWidth(),video->getScreenHeight()};
264                         UCHAR mode=video->getMode();
265                         switch (mode) {
266                         case Video::EIGHTH:
267                         destrect.right=destrect.right/2;
268                         destrect.bottom=destrect.bottom/2;
269                         case Video::QUARTER:
270                         destrect.right=destrect.right/2+video->getPosx()*2;
271                         destrect.bottom=destrect.bottom/2+video->getPosy()*2;
272                         destrect.left=video->getPosx()*2;
273                         destrect.top=video->getPosy()*2;
274                         d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
275                         break;
276                         };
277                         D3DSURFACE_DESC surf_desc;
278                         present->GetDesc(&surf_desc);//for chop sides
279                         RECT sourcerect= {0,0,surf_desc.Width,surf_desc.Height};
280                         if (video->getPseudoTVsize()==Video::ASPECT4X3 
281                                 && video->getMode()==Video::NORMAL 
282                                 && video->getAspectRatio()==Video::ASPECT16X9) {
283                                         unsigned int correction=((double) (surf_desc.Width))*4.*9./3./16.;
284                                         sourcerect.left=(surf_desc.Width-correction)/2;
285                                         sourcerect.right=sourcerect.left+correction;
286                         }
287                         d3ddevice->StretchRect(present,&sourcerect,d3drtsurf  ,&destrect,filter_type);
288
289                 }
290         } else {
291                 VideoWin* video =(VideoWin*) Video::getInstance();
292                 //Clear Background
293                 if (!video->isVideoOn()) d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
294         }
295         //Drawing the OSD
296         if (d3ddevice->BeginScene()==D3D_OK) {
297                 d3ddevice->SetStreamSource(0,d3dvb,0,sizeof(OSDVERTEX));
298                 d3ddevice->SetFVF(D3DFVF_OSDVERTEX);
299                 d3ddevice->SetTexture(0,((SurfaceWin*)screen)->getD3dtexture());
300                 //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
301                 d3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP,D3DTOP_MODULATE);
302
303         d3ddevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
304         d3ddevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
305
306
307                 d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
308                 d3ddevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
309                 d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
310                 d3ddevice->SetRenderState(D3DRS_LIGHTING,FALSE);
311
312
313                 d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);
314                 d3ddevice->EndScene();
315                 //Show it to the user!
316         HRESULT hres;
317                 if (hres=d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){
318                         EndPainting();
319                         if (!external_driving) DoLost();
320                 }
321                 EndPainting();
322         }
323         ReleaseMutex(d3dmutex);
324         if (!external_driving) {
325                 Sleep(4);//The User can wait for 4 milliseconds to see his changes
326         }
327 }
328
329 bool OsdWin::DoLost(){
330         Log::getInstance()->log("OSD", Log::WARN, "Direct3D Device Lost! Reobtaining...");
331         ResetEvent(event);
332         if (external_driving && dsallocator!=NULL) {
333                 dsallocator->LostDevice(d3ddevice,d3d); //Propagate the information through DS
334         }
335         //First we free up all resources
336         Video* video = Video::getInstance();
337         ((SurfaceWin*)screen)->ReleaseSurface();
338         if (d3drtsurf) d3drtsurf->Release();
339     d3drtsurf=NULL;
340         if (d3dvb) d3dvb->Release();
341         d3dvb=NULL;
342         D3DPRESENT_PARAMETERS d3dparas;
343         ZeroMemory(&d3dparas,sizeof(d3dparas));
344         d3dparas.BackBufferWidth=video->getScreenWidth();
345         d3dparas.BackBufferHeight=video->getScreenHeight();
346         d3dparas.Windowed=TRUE;
347         d3dparas.SwapEffect=D3DSWAPEFFECT_COPY;
348         if (d3ddevice->Reset(&d3dparas)!=D3D_OK){
349                 return false;
350         }
351     d3ddevice->GetRenderTarget(0,&d3drtsurf);
352         InitVertexBuffer();
353     //Redraw Views, Chris could you add a member function to BoxStack, so that
354         // I can cause it to completely redraw the Views?
355         // Otherwise the OSD would be distorted after Device Lost
356         // FIXME
357         
358         SetEvent(event);
359
360
361         screen->create(video->getScreenWidth(), video->getScreenHeight());
362         screen->display();
363         
364         return true;
365
366 }
367 LPDIRECT3DDEVICE9 OsdWin::getD3dDev() {
368         WaitForSingleObject(event,INFINITE);//We will only return if we are initted
369         return d3ddevice;
370 }
371
372 LPDIRECT3D9 OsdWin::getD3d() {
373         WaitForSingleObject(event,INFINITE);//We will only return if we are initted
374         return d3d;
375 }
376
377 void OsdWin::BeginPainting() {//We synchronize calls to d3d between different threads
378         WaitForSingleObject(d3dmutex,INFINITE);
379 }
380
381 void OsdWin::EndPainting() {
382         ReleaseMutex(d3dmutex);
383 }
384
385 void OsdWin::setExternalDriving(DsAllocator* dsall) {
386         if (dsall==NULL) {
387                 external_driving=false;
388                 dsallocator=NULL;
389                 return;
390         }
391         WaitForSingleObject(event,INFINITE);//We will only return if we are initted
392         dsallocator=dsall;
393         external_driving=true;
394 }
395
396 void OsdWin::Blank() {
397         WaitForSingleObject(event,INFINITE);
398         BeginPainting();
399         d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
400         EndPainting();
401 }