]> git.vomp.tv Git - vompclient.git/blob - windowsosd.cc
Rewrite timers class using std::thread/mutex/cond/chrono
[vompclient.git] / windowsosd.cc
1 /*
2         Copyright 2014 Marten Richter
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 "windowsosd.h"
23 #include "dsallocator.h"
24 #include "video.h"
25 #include "videowin.h"
26 #include "log.h"
27 #include "colour.h"
28
29
30 typedef HRESULT(__stdcall *FCT_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager);
31 typedef HRESULT(__stdcall *FCT_MFCreateVideoSampleFromSurface)(IUnknown* pUnkSurface, IMFSample** ppSample);
32
33 FCT_DXVA2CreateDirect3DDeviceManager9 ptrDXVA2CreateDirect3DDeviceManager9 = NULL;
34 FCT_MFCreateVideoSampleFromSurface ptrMFCreateVideoSampleFromSurface = NULL;
35
36
37 WindowsOsd::WindowsOsd()
38 {
39         d3d = NULL;
40         d3ddevice = NULL;
41         d3drtsurf = NULL;
42
43         evrsupported = true;
44         filter_type = D3DTEXF_FORCE_DWORD;
45         evrstate = EVR_pres_off;
46
47         swappy = NULL;
48         swapsurf = NULL;
49         window = NULL;
50
51         external_driving = false;
52         dsallocator = NULL;
53
54         lastrendertime = timeGetTime();
55         event = CreateEvent(NULL,/*FALSE*/TRUE, FALSE, NULL);
56         d3dmutex = CreateMutex(NULL, FALSE, NULL);
57
58         /*EVR stuff*/
59         dxvadevicehandle = NULL;
60         HMODULE hlib = NULL;
61         hlib = LoadLibrary("dxva2.dll");
62         if (!hlib) {
63                 evrsupported = false;
64                 return;
65         }
66         ptrDXVA2CreateDirect3DDeviceManager9 = (FCT_DXVA2CreateDirect3DDeviceManager9)GetProcAddress(hlib, "DXVA2CreateDirect3DDeviceManager9");
67         if (!ptrDXVA2CreateDirect3DDeviceManager9){
68                 evrsupported = false;
69                 return;
70         }
71
72         hlib = LoadLibrary("evr.dll");
73         if (!hlib) {
74                 evrsupported = false;
75                 return;
76         }
77
78         ptrMFCreateVideoSampleFromSurface = (FCT_MFCreateVideoSampleFromSurface)GetProcAddress(hlib, "MFCreateVideoSampleFromSurface");
79         if (!ptrMFCreateVideoSampleFromSurface){
80                 evrsupported = false;
81                 return;
82         }
83
84 }
85
86 WindowsOsd::~WindowsOsd()
87 {
88         CloseHandle(event);
89         CloseHandle(d3dmutex);
90 }
91
92
93 void WindowsOsd::LockDevice()
94 {
95         if (!evrsupported) return;
96         if (!dxvadevicehandle)
97         {
98                 d3ddevman->OpenDeviceHandle(&dxvadevicehandle);
99         }
100         IDirect3DDevice9 *temp;
101         d3ddevman->LockDevice(dxvadevicehandle, &temp, TRUE);
102
103 }
104
105 void WindowsOsd::UnlockDevice()
106 {
107         if (!evrsupported) return;
108         if (!isInitialized()) return;
109         d3ddevman->UnlockDevice(dxvadevicehandle, TRUE);
110         if (dxvadevicehandle)
111         {
112                 d3ddevman->CloseDeviceHandle(dxvadevicehandle);
113                 dxvadevicehandle = NULL;
114         }
115
116 }
117
118 int WindowsOsd::createDirect3D9Objects()
119 {
120         Video* video = Video::getInstance();
121         //First Create Direct 3D Object
122 #ifdef WINDOWS_LEGACY
123         d3d = Direct3DCreate9(D3D_SDK_VERSION);
124         if (!d3d)
125         {
126                 Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 object!");
127                 return 0;
128         }
129 #else
130         HRESULT err = Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d);
131         if (err != S_OK)
132         {
133                 Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9Ex object! %d",err);
134                 return 0;
135         }
136 #endif
137         
138         // then create the Device
139         D3DPRESENT_PARAMETERS d3dparas;
140         ZeroMemory(&d3dparas, sizeof(d3dparas));
141         d3dparas.BackBufferWidth = BACKBUFFER_WIDTH;
142         d3dparas.BackBufferHeight = BACKBUFFER_HEIGHT;
143         d3dparas.Windowed = TRUE;
144         d3dparas.SwapEffect = D3DSWAPEFFECT_COPY;
145 #ifdef WINDOWS_LEGACY
146         if (d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
147                 D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, &d3dparas, &d3ddevice) != D3D_OK) {
148                 Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 device!");
149                 return 0;
150         }
151 #else
152         if (d3d->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
153                 D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, &d3dparas, NULL, &d3ddevice) != D3D_OK) {
154                 Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 device!");
155                 return 0;
156         }
157 #endif
158         d3ddevice->GetRenderTarget(0, &d3drtsurf);
159
160         /*
161         if (!InitVertexBuffer()) {
162         Log::getInstance()->log("OSD", Log::WARN, "Could not create Direct3D9 vertex buf!");
163         return 0;
164         }*/
165         /* We have to determine which kind of filtering is supported*/
166         D3DCAPS9 caps;
167         d3ddevice->GetDeviceCaps(&caps);
168         if (((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) != 0)
169                 && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR) != 0)) {
170                 if (filter_type == D3DTEXF_FORCE_DWORD) {
171                         filter_type = D3DTEXF_LINEAR;
172                 }
173         }
174         else {
175                 if (filter_type == D3DTEXF_LINEAR)
176                 {
177                         filter_type = D3DTEXF_POINT;
178                 }
179         }
180
181         if (((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MINFPOINT) != 0)
182                 && ((caps.StretchRectFilterCaps & D3DPTFILTERCAPS_MAGFPOINT) != 0)) {
183                 if (filter_type == D3DTEXF_FORCE_DWORD)
184                 {
185                         filter_type = D3DTEXF_POINT;
186                 }
187         }
188         else {
189                 if (filter_type == D3DTEXF_POINT) {
190                         filter_type = D3DTEXF_NONE;
191                 }
192         }
193         if (filter_type == D3DTEXF_FORCE_DWORD) {
194                 filter_type = D3DTEXF_NONE;
195         }
196
197         if (evrsupported)
198         {
199                 if (ptrDXVA2CreateDirect3DDeviceManager9(&dxvatoken, &d3ddevman) != S_OK) evrsupported = false;
200                 else {
201                         d3ddevman->ResetDevice(d3ddevice, dxvatoken);
202                 }
203         }
204         SetEvent(event);//Now all devices are ready
205         return 1;
206 }
207
208 void WindowsOsd::startRenderLoop()
209 {
210         threadStart();
211 }
212
213 void WindowsOsd::stopRenderLoop()
214 {
215         threadStop();
216 }
217
218 void WindowsOsd::shutdownDirect3D9Objects()
219 {
220         threadStop();
221         evrsupported = 0;
222         if (d3ddevman) d3ddevman->Release();
223         d3drtsurf->Release();
224         d3ddevice->Release();
225         d3d->Release();
226         if (swapsurf) swapsurf->Release();
227         if (swappy) swappy->Release();
228 }
229
230 #if WIN32
231 // FIXME win pragma
232 #pragma warning(disable : 4703)
233 #endif
234
235 void WindowsOsd::threadMethod()
236 {
237         while (true)
238         {
239                 DWORD waittime = 10;
240                 if (isInitialized()){
241                         if (evrstate == EVR_pres_off || evrstate == EVR_pres_pause)
242                         {
243                                 Render();
244                         }
245                         else if (evrstate == EVR_pres_started)
246                         {
247                                 LPDIRECT3DSURFACE9 surf;
248                                 if (dsallocator) dsallocator->GetNextSurface(&surf, &waittime);
249                                 if (surf == NULL)
250                                 {
251                                         Render();
252                                 }
253                                 else
254                                 {
255                                         RenderDS(surf);
256                                         surf->Release();
257                                         if (dsallocator) dsallocator->DiscardSurfaceandgetWait(&waittime);
258                                 }
259                         }
260                 }
261                 threadCheckExit();
262                 if (waittime != 0) Sleep(min(10, waittime));
263                 //Sleep(1);
264         }
265 }
266
267 void WindowsOsd::setExternalDriving(DsAllocator* dsall, DWORD width, DWORD height) {
268
269         if (swappy)
270         {
271                 BeginPainting();
272                 d3ddevice->StretchRect(swapsurf, NULL, d3drtsurf, NULL, filter_type);
273                 LPDIRECT3DSWAPCHAIN9 temp = swappy;
274                 LPDIRECT3DSURFACE9 tempsurf = swapsurf;
275                 swappy = NULL;
276                 swapsurf = NULL;
277                 EndPainting();
278                 tempsurf->Release();
279                 temp->Release();
280         }
281
282         if (dsall == NULL) {
283                 external_driving = false;
284                 dsallocator = NULL;
285                 return;
286         }
287         WaitForSingleObject(event, INFINITE);//We will only return if we are initted
288         BeginPainting();
289
290         if (width>BACKBUFFER_WIDTH || height>BACKBUFFER_HEIGHT)
291         {
292                 D3DPRESENT_PARAMETERS d3dparas;
293                 ZeroMemory(&d3dparas, sizeof(d3dparas));
294                 d3dparas.BackBufferWidth = width;
295                 d3dparas.BackBufferHeight = height;
296                 d3dparas.Windowed = TRUE;
297                 d3dparas.SwapEffect = D3DSWAPEFFECT_COPY;
298                 if (d3ddevice->CreateAdditionalSwapChain(&d3dparas, &swappy) != D3D_OK){
299                         Log::getInstance()->log("OSD", Log::WARN, "Could not create Swap Chain!");
300                         //return 0;
301                 }
302                 else {
303                         swappy->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &swapsurf);
304                 }
305                 Log::getInstance()->log("OSD", Log::INFO, "Create Additional Swap Chain %d %d!", width, height);
306         }
307
308         dsallocator = dsall;
309         external_driving = true;
310
311         EndPainting();
312 }
313
314 // This function is called from the WinMain function in order to get Screen updates
315 void WindowsOsd::Render()
316 {
317         if (!isInitialized()) return;
318         if (external_driving) {
319                 DWORD time1 = timeGetTime(); //Updates the Menue
320                 if ((time1 - lastrendertime)>200) {//5 fps for OSD updates are enough, avoids tearing
321                         updateOsd();
322                         InternalRendering(NULL);
323                         lastosdrendertime = lastrendertime = timeGetTime();
324                 }
325                 else {
326                         //Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads
327                 }
328         }
329         else {
330                 DWORD time1 = timeGetTime();
331                 if ((time1 - lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing
332                         updateOsd();
333                         InternalRendering(NULL);
334                         lastosdrendertime = lastrendertime = timeGetTime();
335                 }
336                 else {
337                         //Sleep(5);
338
339                 }
340
341         }
342 }
343
344 void WindowsOsd::RenderDS(LPDIRECT3DSURFACE9 present){
345         if (!isInitialized()) return;
346         if (external_driving) {
347                 InternalRendering(present);
348                 lastrendertime = timeGetTime();
349         }
350         if ((lastrendertime - lastosdrendertime) > 50) {
351                 updateOsd();
352                 lastosdrendertime =  timeGetTime();
353         }
354 }
355
356
357 void WindowsOsd::BeginPainting() {//We synchronize calls to d3d between different threads
358         WaitForSingleObject(d3dmutex, INFINITE);
359         LockDevice();
360 }
361
362 void WindowsOsd::EndPainting() {
363         UnlockDevice();
364         ReleaseMutex(d3dmutex);
365 }
366
367 DWORD WindowsOsd::getFilterCaps()
368 {
369         if (!isInitialized()) return NULL;
370         D3DCAPS9 caps;
371         d3ddevice->GetDeviceCaps(&caps);
372         return caps.StretchRectFilterCaps;
373 }
374
375 LPDIRECT3DDEVICE9 WindowsOsd::getD3dDev() {
376         WaitForSingleObject(event, INFINITE);//We will only return if we are initted
377         return d3ddevice;
378 }
379
380 LPDIRECT3D9 WindowsOsd::getD3d() {
381         WaitForSingleObject(event, INFINITE);//We will only return if we are initted
382         return d3d;
383 }
384
385
386 void WindowsOsd::Blank() {
387         WaitForSingleObject(event, INFINITE);
388         BeginPainting();
389         d3ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
390         EndPainting();
391 }
392
393 void WindowsOsd::InternalRendering(LPDIRECT3DSURFACE9 present){
394         BeginPainting();
395         HRESULT losty = d3ddevice->TestCooperativeLevel();
396         if (losty == D3DERR_DEVICELOST) {
397                 //Sleep(10);
398                 EndPainting();
399                 return; //Device Lost
400         }
401         if (losty == D3DERR_DEVICENOTRESET){
402                 EndPainting();
403                 DoLost();
404                 return;
405         }
406         WaitForSingleObject(event, INFINITE);
407
408         LPDIRECT3DSURFACE9 targetsurf;
409         if (swappy)
410         {
411                 targetsurf = swapsurf;
412                 d3ddevice->SetRenderTarget(0, swapsurf);//Stupid VMR manipulates the render target
413         }
414         else
415         {
416                 targetsurf = d3drtsurf;
417                 d3ddevice->SetRenderTarget(0, d3drtsurf);//Stupid VMR manipulates the render target
418         }
419         D3DSURFACE_DESC targetdesc;
420         targetsurf->GetDesc(&targetdesc);
421
422         d3ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
423         LPDIRECT3DVERTEXBUFFER9 vb2 = NULL;
424         vb2 = InitBackgroundVertexBuffer(targetdesc.Width, targetdesc.Height);
425         if (d3ddevice->BeginScene() == D3D_OK) {
426                 d3ddevice->SetStreamSource(0, vb2, 0, sizeof(OSDVERTEX));
427                 d3ddevice->SetFVF(D3DFVF_OSDVERTEX);
428                 d3ddevice->SetTexture(0, NULL);
429
430                 d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
431                 d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
432                 d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
433                 d3ddevice->SetRenderState(D3DRS_LIGHTING, FALSE);
434
435                 d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
436                 d3ddevice->EndScene();
437         }
438
439         vb2->Release();
440
441         if (external_driving) {
442                 //Copy video to Backbuffer
443                 if (present != NULL) {
444                         VideoWin* video = (VideoWin*)Video::getInstance();
445                         /*calculating destination rect */
446                         RECT destrect = { 0, 0,/*video->getScreenWidth()*/ targetdesc.Width,
447                                 /*video->getScreenHeight()*/targetdesc.Height };
448                         const VideoDisplay &vd = video->getVideoDisplay();
449                         int addx, addy;
450                         addx = addy = 0;
451
452                         switch (vd.mode) {
453                         case Eighth:
454                                 destrect.right = destrect.right / 2;
455                                 destrect.bottom = destrect.bottom / 2;
456                         case Quarter:
457                                 destrect.right = destrect.right / 2;
458                                 destrect.bottom = destrect.bottom / 2;
459                                 break;
460                         case Window:
461                                 float imageaspect = 720.f / 576.f;
462                                 float boxaspect = ((float)vd.width) / ((float)vd.height);
463                                 float videoaspect = ((float)targetdesc.Width) / ((float)targetdesc.Height);
464                                 if (imageaspect > boxaspect) {
465                                         destrect.right = (int)(((float)destrect.right) * ((float)vd.width) / 720.f);
466                                         destrect.bottom = (int)(((float)destrect.right) / videoaspect);
467                                         addy += (((float)vd.height) - ((float)vd.width) / imageaspect)*0.5f / 576.f
468                                                 *((float)targetdesc.Height);
469                                 }
470                                 else {
471                                         destrect.bottom = (int)(((float)destrect.bottom) * ((float)vd.height) / 576.f);
472                                         destrect.right = (int)(((float)destrect.bottom)*videoaspect);
473                                         addx += (((float)vd.width) - ((float)vd.height) * imageaspect)*0.5f / 720.f
474                                                 *((float)targetdesc.Width);
475                                 }
476
477
478                                 break;
479                         };
480                         switch (vd.mode) {
481                         case Quarter:
482                         case Eighth:
483                         case Window:
484                                 destrect.left = (int)(((float)vd.x*targetdesc.Width) / 720.f) + addx;
485                                 destrect.top = (int)(((float)vd.y*targetdesc.Height) / 576.f) + addy;
486                                 destrect.right += destrect.left;
487                                 destrect.bottom += destrect.top;
488                                 break;
489                         }
490
491
492                         D3DSURFACE_DESC surf_desc;
493                         present->GetDesc(&surf_desc);//for chop sides
494                         RECT sourcerect = { 0, 0, surf_desc.Width, surf_desc.Height };
495                         if (video->getPseudoTVsize() == Video::ASPECT4X3
496                                 && video->getMode() == Video::NORMAL
497                                 && video->getAspectRatio() == Video::ASPECT16X9) {
498                                 unsigned int correction = ((double)(surf_desc.Width))*4.*9. / 3. / 16.;
499                                 sourcerect.left = (surf_desc.Width - correction) / 2;
500                                 sourcerect.right = sourcerect.left + correction;
501                         }
502                         d3ddevice->StretchRect(present, &sourcerect, targetsurf, &destrect, filter_type);
503
504                 }
505         }
506         
507         LPDIRECT3DVERTEXBUFFER9 vb1 = NULL;
508         vb1 = InitVertexBuffer(targetdesc.Width, targetdesc.Height);
509
510
511         //Drawing the OSD
512         if (d3ddevice->BeginScene() == D3D_OK) {
513                 d3ddevice->SetStreamSource(0, vb1, 0, sizeof(OSDVERTEX));
514                 d3ddevice->SetFVF(D3DFVF_OSDVERTEX);
515                 d3ddevice->SetTexture(0, NULL);
516                 LPDIRECT3DTEXTURE9 osdtex = getNextOsdTexture();
517                 d3ddevice->SetTexture(0, osdtex);
518                 //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
519                 d3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
520
521                 d3ddevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
522                 d3ddevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
523
524
525                 d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
526                 d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
527                 d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
528                 d3ddevice->SetRenderState(D3DRS_LIGHTING, FALSE);
529
530
531                 d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
532                 d3ddevice->EndScene();
533                 //Show it to the user!
534                 HRESULT hres;
535                 if (swappy)
536                 {
537                         if (hres = swappy->Present(NULL, NULL, NULL, NULL, 0) == D3DERR_DEVICELOST){
538                                 //EndPainting();
539                                 if (!external_driving) DoLost();
540                         }
541                 }
542                 else
543                 {
544                         if (hres = d3ddevice->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST){
545                                 //EndPainting();
546                                 if (!external_driving) DoLost();
547                         }
548                 }
549
550         }
551
552         vb1->Release();
553         EndPainting();
554
555
556         //      if (!external_driving) {
557         //              Sleep(4);//The User can wait for 4 milliseconds to see his changes
558         //      }
559 }
560
561 bool WindowsOsd::DoLost(){
562         Log::getInstance()->log("OSD", Log::WARN, "Direct3D Device Lost! Reobtaining...");
563         ResetEvent(event);
564         if (external_driving && dsallocator != NULL) {
565                 dsallocator->LostDevice(d3ddevice, d3d); //Propagate the information through DS
566         }
567         //First we free up all resources
568         Video* video = Video::getInstance();
569         lostDestroyObjects();
570         if (d3drtsurf) d3drtsurf->Release();
571         d3drtsurf = NULL;
572         D3DPRESENT_PARAMETERS d3dparas;
573         ZeroMemory(&d3dparas, sizeof(d3dparas));
574         d3dparas.BackBufferWidth = BACKBUFFER_WIDTH;
575         d3dparas.BackBufferHeight = BACKBUFFER_HEIGHT;
576         d3dparas.Windowed = TRUE;
577         d3dparas.SwapEffect = D3DSWAPEFFECT_COPY;
578
579         if (swapsurf) { swapsurf->Release(); swapsurf = NULL; };
580         if (swappy) { swappy->Release(); swappy = NULL; };
581
582         if (d3ddevice->Reset(&d3dparas) != D3D_OK){
583                 return false;
584         }
585         d3ddevice->GetRenderTarget(0, &d3drtsurf);
586         if (d3ddevman) d3ddevman->ResetDevice(d3ddevice, dxvatoken);
587         //InitVertexBuffer();
588         //Redraw Views, Chris could you add a member function to BoxStack, so that
589         // I can cause it to completely redraw the Views?
590         // Otherwise the OSD would be distorted after Device Lost
591         // FIXME
592
593         SetEvent(event);
594
595         lostRecreateObjects();
596
597
598         return true;
599
600 }
601
602 LPDIRECT3DVERTEXBUFFER9  WindowsOsd::InitVertexBuffer(DWORD width, DWORD height)
603 {
604         LPDIRECT3DVERTEXBUFFER9 ret = NULL;
605         FLOAT texx;
606         FLOAT texy;
607         getTextureCoordinates(&texx, &texy);
608
609         D3DCOLOR osdcolor = D3DCOLOR_RGBA(255, 255, 255, 255);
610         OSDVERTEX osdvertices[4];
611         osdvertices[0].c = osdcolor;
612         osdvertices[0].x = 0.f - 0.5f;
613         osdvertices[0].y = 0.f - 0.5f;
614         osdvertices[0].z = 0.5f;
615         osdvertices[0].rhw = 1.f;
616         osdvertices[0].u = 0.f;
617         osdvertices[0].v = 0.f;
618         osdvertices[1].c = osdcolor;
619         osdvertices[1].x = ((float)width) - 0.5f;
620         osdvertices[1].y = 0.f - 0.5f;
621         osdvertices[1].z = 0.5f;
622         osdvertices[1].u = texx;
623         osdvertices[1].v = 0.f;
624         osdvertices[1].rhw = 1.f;
625         osdvertices[2].c = osdcolor;
626         osdvertices[2].x = ((float)width) - 0.5f;
627         osdvertices[2].y = ((float)height) - 0.5f;
628         osdvertices[2].z = 0.5f;
629         osdvertices[2].rhw = 1.f;
630         osdvertices[2].u = texx;
631         osdvertices[2].v = texy;
632         osdvertices[3].c = osdcolor;
633         osdvertices[3].x = 0.f - 0.5f;
634         osdvertices[3].y = ((float)height) - 0.5f;
635         osdvertices[3].z = 0.5f;
636         osdvertices[3].rhw = 1.f;
637         osdvertices[3].u = 0.f;
638         osdvertices[3].v = texy;
639
640         if (d3ddevice->CreateVertexBuffer(4 * sizeof(OSDVERTEX), 0, D3DFVF_OSDVERTEX, D3DPOOL_DEFAULT,
641                 &ret, NULL) != D3D_OK) {
642                 return NULL;
643         }
644         void *pvertex = NULL;
645         if (ret->Lock(0, sizeof(osdvertices), &pvertex, 0) != D3D_OK) {
646                 return NULL;
647         }
648         memcpy(pvertex, osdvertices, sizeof(osdvertices));
649         ret->Unlock();
650         return ret;
651 }
652
653 LPDIRECT3DVERTEXBUFFER9  WindowsOsd::InitBackgroundVertexBuffer(DWORD width, DWORD height)
654 {
655         LPDIRECT3DVERTEXBUFFER9 ret = NULL;
656         FLOAT texx;
657         FLOAT texy;
658         getTextureCoordinates(&texx, &texy);
659
660         DrawStyle bg = DrawStyle::WALLPAPER;
661         if (bg.ft != DrawStyle::GradientLinear) {
662                 bg.grad_col[0] = bg;
663         }
664         
665
666         OSDVERTEX osdvertices[4];
667         osdvertices[0].c = D3DCOLOR_RGBA(bg.red,bg.green,bg.blue,0xff);
668         osdvertices[0].x = 0.f - 0.5f;
669         osdvertices[0].y = 0.f - 0.5f;
670         osdvertices[0].z = 0.5f;
671         osdvertices[0].rhw = 1.f;
672         osdvertices[0].u = 0.f;
673         osdvertices[0].v = 0.f;
674         osdvertices[1].c = D3DCOLOR_RGBA(bg.red, bg.green, bg.blue, 0xff);
675         osdvertices[1].x = ((float)width) - 0.5f;
676         osdvertices[1].y = 0.f - 0.5f;
677         osdvertices[1].z = 0.5f;
678         osdvertices[1].u = texx;
679         osdvertices[1].v = 0.f;
680         osdvertices[1].rhw = 1.f;
681         osdvertices[2].c = D3DCOLOR_RGBA(bg.grad_col[0].red, bg.grad_col[0].green,
682                 bg.grad_col[0].blue, 0xff);
683         osdvertices[2].x = ((float)width) - 0.5f;
684         osdvertices[2].y = ((float)height) - 0.5f;
685         osdvertices[2].z = 0.5f;
686         osdvertices[2].rhw = 1.f;
687         osdvertices[2].u = texx;
688         osdvertices[2].v = texy;
689         osdvertices[3].c = D3DCOLOR_RGBA(bg.grad_col[0].red, bg.grad_col[0].green,
690                 bg.grad_col[0].blue, 0xff);
691         osdvertices[3].x = 0.f - 0.5f;
692         osdvertices[3].y = ((float)height) - 0.5f;
693         osdvertices[3].z = 0.5f;
694         osdvertices[3].rhw = 1.f;
695         osdvertices[3].u = 0.f;
696         osdvertices[3].v = texy;
697
698         if (d3ddevice->CreateVertexBuffer(4 * sizeof(OSDVERTEX), 0, D3DFVF_OSDVERTEX, D3DPOOL_DEFAULT,
699                 &ret, NULL) != D3D_OK) {
700                 return NULL;
701         }
702         void *pvertex = NULL;
703         if (ret->Lock(0, sizeof(osdvertices), &pvertex, 0) != D3D_OK) {
704                 return NULL;
705         }
706         memcpy(pvertex, osdvertices, sizeof(osdvertices));
707         ret->Unlock();
708         return ret;
709 }