2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
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.
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.
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.
25 #include "surfacewin.h"
27 #include "dsallocator.h"
32 //This is stuff for rendering the OSD
41 external_driving=false;
43 filter_type=D3DTEXF_FORCE_DWORD;
44 lastrendertime=timeGetTime();
45 event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
46 d3dmutex = CreateMutex(NULL,FALSE,NULL);
52 if (initted) shutdown();
54 CloseHandle(d3dmutex);
59 if (!initted) return 0;
63 int OsdWin::init(void* device)
65 if (initted) return 0;
66 Video* video = Video::getInstance();
67 //First Create Direct 3D Object
68 d3d=Direct3DCreate9(D3D_SDK_VERSION);
71 Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 object!");
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!");
86 d3ddevice->GetRenderTarget(0,&d3drtsurf);
88 if (!InitVertexBuffer()) {
89 Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 vertex buf!");
92 /* We have to determine which kind of filtering is supported*/
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;
101 if (filter_type==D3DTEXF_LINEAR)
103 filter_type=D3DTEXF_POINT;
107 if ( ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT)!=0)
108 && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT)!=0)) {
109 if (filter_type==D3DTEXF_FORCE_DWORD)
111 filter_type=D3DTEXF_POINT;
114 if (filter_type==D3DTEXF_POINT) {
115 filter_type=D3DTEXF_NONE;
118 if (filter_type==D3DTEXF_FORCE_DWORD) {
119 filter_type=D3DTEXF_NONE;
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());
129 initted = 1; // must set this here or create surface won't work
134 DWORD OsdWin::getFilterCaps()
136 if (!initted) return NULL;
138 d3ddevice->GetDeviceCaps(&caps);
139 return caps.StretchRectFilterCaps;
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;
179 if (d3ddevice->CreateVertexBuffer(4*sizeof(OSDVERTEX),0,D3DFVF_OSDVERTEX,D3DPOOL_MANAGED,
180 &d3dvb,NULL)!=D3D_OK) {
184 if (d3dvb->Lock(0,sizeof(osdvertices),&pvertex,0)!=D3D_OK) {
187 memcpy(pvertex,osdvertices,sizeof(osdvertices));
192 int OsdWin::shutdown()
194 if (!initted) return 0;
196 d3drtsurf->Release();
197 d3ddevice->Release();
203 void OsdWin::screenShot(char* fileName)
205 screen->screenShot(fileName);
208 // This function is called from the WinMain function in order to get Screen updates
209 void OsdWin::Render()
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();
218 Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads
221 DWORD time1=timeGetTime();
222 if ((time1-lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing
223 InternalRendering(NULL);
224 lastrendertime=timeGetTime();
233 void OsdWin::RenderDS(LPDIRECT3DSURFACE9 present){
234 if (!initted) return;
235 if (external_driving) {
236 InternalRendering(present);
237 lastrendertime=timeGetTime();
242 void OsdWin::InternalRendering(LPDIRECT3DSURFACE9 present){
243 WaitForSingleObject(d3dmutex,INFINITE);
244 HRESULT losty=d3ddevice->TestCooperativeLevel();
245 if (losty==D3DERR_DEVICELOST) {
247 return; //Device Lost
249 if (losty==D3DERR_DEVICENOTRESET){
253 WaitForSingleObject(event,INFINITE);
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();
267 destrect.right=destrect.right/2;
268 destrect.bottom=destrect.bottom/2;
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);
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;
287 d3ddevice->StretchRect(present,&sourcerect,d3drtsurf ,&destrect,filter_type);
291 VideoWin* video =(VideoWin*) Video::getInstance();
293 if (!video->isVideoOn()) d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
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);
303 d3ddevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
304 d3ddevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);
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);
313 d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);
314 d3ddevice->EndScene();
315 //Show it to the user!
317 if (hres=d3ddevice->Present(NULL,NULL,NULL,NULL)==D3DERR_DEVICELOST){
319 if (!external_driving) DoLost();
323 ReleaseMutex(d3dmutex);
324 if (!external_driving) {
325 Sleep(4);//The User can wait for 4 milliseconds to see his changes
329 bool OsdWin::DoLost(){
330 Log::getInstance()->log("OSD", Log::WARN, "Direct3D Device Lost! Reobtaining...");
332 if (external_driving && dsallocator!=NULL) {
333 dsallocator->LostDevice(d3ddevice,d3d); //Propagate the information through DS
335 //First we free up all resources
336 Video* video = Video::getInstance();
337 ((SurfaceWin*)screen)->ReleaseSurface();
338 if (d3drtsurf) d3drtsurf->Release();
340 if (d3dvb) d3dvb->Release();
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){
351 d3ddevice->GetRenderTarget(0,&d3drtsurf);
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
361 screen->create(video->getScreenWidth(), video->getScreenHeight());
367 LPDIRECT3DDEVICE9 OsdWin::getD3dDev() {
368 WaitForSingleObject(event,INFINITE);//We will only return if we are initted
372 LPDIRECT3D9 OsdWin::getD3d() {
373 WaitForSingleObject(event,INFINITE);//We will only return if we are initted
377 void OsdWin::BeginPainting() {//We synchronize calls to d3d between different threads
378 WaitForSingleObject(d3dmutex,INFINITE);
381 void OsdWin::EndPainting() {
382 ReleaseMutex(d3dmutex);
385 void OsdWin::setExternalDriving(DsAllocator* dsall) {
387 external_driving=false;
391 WaitForSingleObject(event,INFINITE);//We will only return if we are initted
393 external_driving=true;
396 void OsdWin::Blank() {
397 WaitForSingleObject(event,INFINITE);
399 d3ddevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);