]> git.vomp.tv Git - vompclient.git/blob - windowsosd.cc
Fix text corruption in channel number display on live tv
[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
268 void WindowsOsd::threadPostStopCleanup()
269 {
270         //Doing nothing
271         //goo;
272 }
273
274 void WindowsOsd::setExternalDriving(DsAllocator* dsall, DWORD width, DWORD height) {
275
276         if (swappy)
277         {
278                 BeginPainting();
279                 d3ddevice->StretchRect(swapsurf, NULL, d3drtsurf, NULL, filter_type);
280                 LPDIRECT3DSWAPCHAIN9 temp = swappy;
281                 LPDIRECT3DSURFACE9 tempsurf = swapsurf;
282                 swappy = NULL;
283                 swapsurf = NULL;
284                 EndPainting();
285                 tempsurf->Release();
286                 temp->Release();
287         }
288
289         if (dsall == NULL) {
290                 external_driving = false;
291                 dsallocator = NULL;
292                 return;
293         }
294         WaitForSingleObject(event, INFINITE);//We will only return if we are initted
295         BeginPainting();
296
297         if (width>BACKBUFFER_WIDTH || height>BACKBUFFER_HEIGHT)
298         {
299                 D3DPRESENT_PARAMETERS d3dparas;
300                 ZeroMemory(&d3dparas, sizeof(d3dparas));
301                 d3dparas.BackBufferWidth = width;
302                 d3dparas.BackBufferHeight = height;
303                 d3dparas.Windowed = TRUE;
304                 d3dparas.SwapEffect = D3DSWAPEFFECT_COPY;
305                 if (d3ddevice->CreateAdditionalSwapChain(&d3dparas, &swappy) != D3D_OK){
306                         Log::getInstance()->log("OSD", Log::WARN, "Could not create Swap Chain!");
307                         //return 0;
308                 }
309                 else {
310                         swappy->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &swapsurf);
311                 }
312                 Log::getInstance()->log("OSD", Log::INFO, "Create Additional Swap Chain %d %d!", width, height);
313         }
314
315         dsallocator = dsall;
316         external_driving = true;
317
318         EndPainting();
319 }
320
321 // This function is called from the WinMain function in order to get Screen updates
322 void WindowsOsd::Render()
323 {
324         if (!isInitialized()) return;
325         if (external_driving) {
326                 DWORD time1 = timeGetTime(); //Updates the Menue
327                 if ((time1 - lastrendertime)>200) {//5 fps for OSD updates are enough, avoids tearing
328                         updateOsd();
329                         InternalRendering(NULL);
330                         lastosdrendertime = lastrendertime = timeGetTime();
331                 }
332                 else {
333                         //Sleep(5); //Sleep for 5 ms, in order to avoid blocking the other threads
334                 }
335         }
336         else {
337                 DWORD time1 = timeGetTime();
338                 if ((time1 - lastrendertime)>50) {//10 fps for OSD updates are enough, avoids tearing
339                         updateOsd();
340                         InternalRendering(NULL);
341                         lastosdrendertime = lastrendertime = timeGetTime();
342                 }
343                 else {
344                         //Sleep(5);
345
346                 }
347
348         }
349 }
350
351 void WindowsOsd::RenderDS(LPDIRECT3DSURFACE9 present){
352         if (!isInitialized()) return;
353         if (external_driving) {
354                 InternalRendering(present);
355                 lastrendertime = timeGetTime();
356         }
357         if ((lastrendertime - lastosdrendertime) > 50) {
358                 updateOsd();
359                 lastosdrendertime =  timeGetTime();
360         }
361 }
362
363
364 void WindowsOsd::BeginPainting() {//We synchronize calls to d3d between different threads
365         WaitForSingleObject(d3dmutex, INFINITE);
366         LockDevice();
367 }
368
369 void WindowsOsd::EndPainting() {
370         UnlockDevice();
371         ReleaseMutex(d3dmutex);
372 }
373
374 DWORD WindowsOsd::getFilterCaps()
375 {
376         if (!isInitialized()) return NULL;
377         D3DCAPS9 caps;
378         d3ddevice->GetDeviceCaps(&caps);
379         return caps.StretchRectFilterCaps;
380 }
381
382 LPDIRECT3DDEVICE9 WindowsOsd::getD3dDev() {
383         WaitForSingleObject(event, INFINITE);//We will only return if we are initted
384         return d3ddevice;
385 }
386
387 LPDIRECT3D9 WindowsOsd::getD3d() {
388         WaitForSingleObject(event, INFINITE);//We will only return if we are initted
389         return d3d;
390 }
391
392
393 void WindowsOsd::Blank() {
394         WaitForSingleObject(event, INFINITE);
395         BeginPainting();
396         d3ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
397         EndPainting();
398 }
399
400 void WindowsOsd::InternalRendering(LPDIRECT3DSURFACE9 present){
401         BeginPainting();
402         HRESULT losty = d3ddevice->TestCooperativeLevel();
403         if (losty == D3DERR_DEVICELOST) {
404                 //Sleep(10);
405                 EndPainting();
406                 return; //Device Lost
407         }
408         if (losty == D3DERR_DEVICENOTRESET){
409                 EndPainting();
410                 DoLost();
411                 return;
412         }
413         WaitForSingleObject(event, INFINITE);
414
415         LPDIRECT3DSURFACE9 targetsurf;
416         if (swappy)
417         {
418                 targetsurf = swapsurf;
419                 d3ddevice->SetRenderTarget(0, swapsurf);//Stupid VMR manipulates the render target
420         }
421         else
422         {
423                 targetsurf = d3drtsurf;
424                 d3ddevice->SetRenderTarget(0, d3drtsurf);//Stupid VMR manipulates the render target
425         }
426         D3DSURFACE_DESC targetdesc;
427         targetsurf->GetDesc(&targetdesc);
428
429         d3ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
430         LPDIRECT3DVERTEXBUFFER9 vb2 = NULL;
431         vb2 = InitBackgroundVertexBuffer(targetdesc.Width, targetdesc.Height);
432         if (d3ddevice->BeginScene() == D3D_OK) {
433                 d3ddevice->SetStreamSource(0, vb2, 0, sizeof(OSDVERTEX));
434                 d3ddevice->SetFVF(D3DFVF_OSDVERTEX);
435                 d3ddevice->SetTexture(0, NULL);
436
437                 d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
438                 d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
439                 d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
440                 d3ddevice->SetRenderState(D3DRS_LIGHTING, FALSE);
441
442                 d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
443                 d3ddevice->EndScene();
444         }
445
446         vb2->Release();
447
448         if (external_driving) {
449                 //Copy video to Backbuffer
450                 if (present != NULL) {
451                         VideoWin* video = (VideoWin*)Video::getInstance();
452                         /*calculating destination rect */
453                         RECT destrect = { 0, 0,/*video->getScreenWidth()*/ targetdesc.Width,
454                                 /*video->getScreenHeight()*/targetdesc.Height };
455                         const VideoDisplay &vd = video->getVideoDisplay();
456                         int addx, addy;
457                         addx = addy = 0;
458
459                         switch (vd.mode) {
460                         case Eighth:
461                                 destrect.right = destrect.right / 2;
462                                 destrect.bottom = destrect.bottom / 2;
463                         case Quarter:
464                                 destrect.right = destrect.right / 2;
465                                 destrect.bottom = destrect.bottom / 2;
466                                 break;
467                         case Window:
468                                 float imageaspect = 720.f / 576.f;
469                                 float boxaspect = ((float)vd.width) / ((float)vd.height);
470                                 float videoaspect = ((float)targetdesc.Width) / ((float)targetdesc.Height);
471                                 if (imageaspect > boxaspect) {
472                                         destrect.right = (int)(((float)destrect.right) * ((float)vd.width) / 720.f);
473                                         destrect.bottom = (int)(((float)destrect.right) / videoaspect);
474                                         addy += (((float)vd.height) - ((float)vd.width) / imageaspect)*0.5f / 576.f
475                                                 *((float)targetdesc.Height);
476                                 }
477                                 else {
478                                         destrect.bottom = (int)(((float)destrect.bottom) * ((float)vd.height) / 576.f);
479                                         destrect.right = (int)(((float)destrect.bottom)*videoaspect);
480                                         addx += (((float)vd.width) - ((float)vd.height) * imageaspect)*0.5f / 720.f
481                                                 *((float)targetdesc.Width);
482                                 }
483
484
485                                 break;
486                         };
487                         switch (vd.mode) {
488                         case Quarter:
489                         case Eighth:
490                         case Window:
491                                 destrect.left = (int)(((float)vd.x*targetdesc.Width) / 720.f) + addx;
492                                 destrect.top = (int)(((float)vd.y*targetdesc.Height) / 576.f) + addy;
493                                 destrect.right += destrect.left;
494                                 destrect.bottom += destrect.top;
495                                 break;
496                         }
497
498
499                         D3DSURFACE_DESC surf_desc;
500                         present->GetDesc(&surf_desc);//for chop sides
501                         RECT sourcerect = { 0, 0, surf_desc.Width, surf_desc.Height };
502                         if (video->getPseudoTVsize() == Video::ASPECT4X3
503                                 && video->getMode() == Video::NORMAL
504                                 && video->getAspectRatio() == Video::ASPECT16X9) {
505                                 unsigned int correction = ((double)(surf_desc.Width))*4.*9. / 3. / 16.;
506                                 sourcerect.left = (surf_desc.Width - correction) / 2;
507                                 sourcerect.right = sourcerect.left + correction;
508                         }
509                         d3ddevice->StretchRect(present, &sourcerect, targetsurf, &destrect, filter_type);
510
511                 }
512         }
513         
514         LPDIRECT3DVERTEXBUFFER9 vb1 = NULL;
515         vb1 = InitVertexBuffer(targetdesc.Width, targetdesc.Height);
516
517
518         //Drawing the OSD
519         if (d3ddevice->BeginScene() == D3D_OK) {
520                 d3ddevice->SetStreamSource(0, vb1, 0, sizeof(OSDVERTEX));
521                 d3ddevice->SetFVF(D3DFVF_OSDVERTEX);
522                 d3ddevice->SetTexture(0, NULL);
523                 LPDIRECT3DTEXTURE9 osdtex = getNextOsdTexture();
524                 d3ddevice->SetTexture(0, osdtex);
525                 //d3ddevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE);
526                 d3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
527
528                 d3ddevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
529                 d3ddevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
530
531
532                 d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
533                 d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
534                 d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
535                 d3ddevice->SetRenderState(D3DRS_LIGHTING, FALSE);
536
537
538                 d3ddevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
539                 d3ddevice->EndScene();
540                 //Show it to the user!
541                 HRESULT hres;
542                 if (swappy)
543                 {
544                         if (hres = swappy->Present(NULL, NULL, NULL, NULL, 0) == D3DERR_DEVICELOST){
545                                 //EndPainting();
546                                 if (!external_driving) DoLost();
547                         }
548                 }
549                 else
550                 {
551                         if (hres = d3ddevice->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST){
552                                 //EndPainting();
553                                 if (!external_driving) DoLost();
554                         }
555                 }
556
557         }
558
559         vb1->Release();
560         EndPainting();
561
562
563         //      if (!external_driving) {
564         //              Sleep(4);//The User can wait for 4 milliseconds to see his changes
565         //      }
566 }
567
568 bool WindowsOsd::DoLost(){
569         Log::getInstance()->log("OSD", Log::WARN, "Direct3D Device Lost! Reobtaining...");
570         ResetEvent(event);
571         if (external_driving && dsallocator != NULL) {
572                 dsallocator->LostDevice(d3ddevice, d3d); //Propagate the information through DS
573         }
574         //First we free up all resources
575         Video* video = Video::getInstance();
576         lostDestroyObjects();
577         if (d3drtsurf) d3drtsurf->Release();
578         d3drtsurf = NULL;
579         D3DPRESENT_PARAMETERS d3dparas;
580         ZeroMemory(&d3dparas, sizeof(d3dparas));
581         d3dparas.BackBufferWidth = BACKBUFFER_WIDTH;
582         d3dparas.BackBufferHeight = BACKBUFFER_HEIGHT;
583         d3dparas.Windowed = TRUE;
584         d3dparas.SwapEffect = D3DSWAPEFFECT_COPY;
585
586         if (swapsurf) { swapsurf->Release(); swapsurf = NULL; };
587         if (swappy) { swappy->Release(); swappy = NULL; };
588
589         if (d3ddevice->Reset(&d3dparas) != D3D_OK){
590                 return false;
591         }
592         d3ddevice->GetRenderTarget(0, &d3drtsurf);
593         if (d3ddevman) d3ddevman->ResetDevice(d3ddevice, dxvatoken);
594         //InitVertexBuffer();
595         //Redraw Views, Chris could you add a member function to BoxStack, so that
596         // I can cause it to completely redraw the Views?
597         // Otherwise the OSD would be distorted after Device Lost
598         // FIXME
599
600         SetEvent(event);
601
602         lostRecreateObjects();
603
604
605         return true;
606
607 }
608
609 LPDIRECT3DVERTEXBUFFER9  WindowsOsd::InitVertexBuffer(DWORD width, DWORD height)
610 {
611         LPDIRECT3DVERTEXBUFFER9 ret = NULL;
612         FLOAT texx;
613         FLOAT texy;
614         getTextureCoordinates(&texx, &texy);
615
616         D3DCOLOR osdcolor = D3DCOLOR_RGBA(255, 255, 255, 255);
617         OSDVERTEX osdvertices[4];
618         osdvertices[0].c = osdcolor;
619         osdvertices[0].x = 0.f - 0.5f;
620         osdvertices[0].y = 0.f - 0.5f;
621         osdvertices[0].z = 0.5f;
622         osdvertices[0].rhw = 1.f;
623         osdvertices[0].u = 0.f;
624         osdvertices[0].v = 0.f;
625         osdvertices[1].c = osdcolor;
626         osdvertices[1].x = ((float)width) - 0.5f;
627         osdvertices[1].y = 0.f - 0.5f;
628         osdvertices[1].z = 0.5f;
629         osdvertices[1].u = texx;
630         osdvertices[1].v = 0.f;
631         osdvertices[1].rhw = 1.f;
632         osdvertices[2].c = osdcolor;
633         osdvertices[2].x = ((float)width) - 0.5f;
634         osdvertices[2].y = ((float)height) - 0.5f;
635         osdvertices[2].z = 0.5f;
636         osdvertices[2].rhw = 1.f;
637         osdvertices[2].u = texx;
638         osdvertices[2].v = texy;
639         osdvertices[3].c = osdcolor;
640         osdvertices[3].x = 0.f - 0.5f;
641         osdvertices[3].y = ((float)height) - 0.5f;
642         osdvertices[3].z = 0.5f;
643         osdvertices[3].rhw = 1.f;
644         osdvertices[3].u = 0.f;
645         osdvertices[3].v = texy;
646
647         if (d3ddevice->CreateVertexBuffer(4 * sizeof(OSDVERTEX), 0, D3DFVF_OSDVERTEX, D3DPOOL_DEFAULT,
648                 &ret, NULL) != D3D_OK) {
649                 return NULL;
650         }
651         void *pvertex = NULL;
652         if (ret->Lock(0, sizeof(osdvertices), &pvertex, 0) != D3D_OK) {
653                 return NULL;
654         }
655         memcpy(pvertex, osdvertices, sizeof(osdvertices));
656         ret->Unlock();
657         return ret;
658 }
659
660 LPDIRECT3DVERTEXBUFFER9  WindowsOsd::InitBackgroundVertexBuffer(DWORD width, DWORD height)
661 {
662         LPDIRECT3DVERTEXBUFFER9 ret = NULL;
663         FLOAT texx;
664         FLOAT texy;
665         getTextureCoordinates(&texx, &texy);
666
667         DrawStyle bg = DrawStyle::WALLPAPER;
668         if (bg.ft != DrawStyle::GradientLinear) {
669                 bg.grad_col[0] = bg;
670         }
671         
672
673         OSDVERTEX osdvertices[4];
674         osdvertices[0].c = D3DCOLOR_RGBA(bg.red,bg.green,bg.blue,0xff);
675         osdvertices[0].x = 0.f - 0.5f;
676         osdvertices[0].y = 0.f - 0.5f;
677         osdvertices[0].z = 0.5f;
678         osdvertices[0].rhw = 1.f;
679         osdvertices[0].u = 0.f;
680         osdvertices[0].v = 0.f;
681         osdvertices[1].c = D3DCOLOR_RGBA(bg.red, bg.green, bg.blue, 0xff);
682         osdvertices[1].x = ((float)width) - 0.5f;
683         osdvertices[1].y = 0.f - 0.5f;
684         osdvertices[1].z = 0.5f;
685         osdvertices[1].u = texx;
686         osdvertices[1].v = 0.f;
687         osdvertices[1].rhw = 1.f;
688         osdvertices[2].c = D3DCOLOR_RGBA(bg.grad_col[0].red, bg.grad_col[0].green,
689                 bg.grad_col[0].blue, 0xff);
690         osdvertices[2].x = ((float)width) - 0.5f;
691         osdvertices[2].y = ((float)height) - 0.5f;
692         osdvertices[2].z = 0.5f;
693         osdvertices[2].rhw = 1.f;
694         osdvertices[2].u = texx;
695         osdvertices[2].v = texy;
696         osdvertices[3].c = D3DCOLOR_RGBA(bg.grad_col[0].red, bg.grad_col[0].green,
697                 bg.grad_col[0].blue, 0xff);
698         osdvertices[3].x = 0.f - 0.5f;
699         osdvertices[3].y = ((float)height) - 0.5f;
700         osdvertices[3].z = 0.5f;
701         osdvertices[3].rhw = 1.f;
702         osdvertices[3].u = 0.f;
703         osdvertices[3].v = texy;
704
705         if (d3ddevice->CreateVertexBuffer(4 * sizeof(OSDVERTEX), 0, D3DFVF_OSDVERTEX, D3DPOOL_DEFAULT,
706                 &ret, NULL) != D3D_OK) {
707                 return NULL;
708         }
709         void *pvertex = NULL;
710         if (ret->Lock(0, sizeof(osdvertices), &pvertex, 0) != D3D_OK) {
711                 return NULL;
712         }
713         memcpy(pvertex, osdvertices, sizeof(osdvertices));
714         ret->Unlock();
715         return ret;
716 }