VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/vboxext.c@ 41014

Last change on this file since 41014 was 39602, checked in by vboxsync, 13 years ago

wine/XPDM: 1. Additional swapchain creation fixes 2. De-libwine'ize wined3d 3. Single context per swapchain 4. wine & crOgl current context sync fixes 5. Proper Get/ReleaseDC handling

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 KB
Line 
1/* $Id: vboxext.c 39602 2011-12-14 11:12:17Z vboxsync $ */
2/** @file
3 *
4 * VBox extension to Wine D3D
5 *
6 * Copyright (C) 2011 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16#include "config.h"
17#include "wine/port.h"
18#include "wined3d_private.h"
19#include "vboxext.h"
20
21WINE_DEFAULT_DEBUG_CHANNEL(d3d_vbox);
22
23typedef DECLCALLBACK(void) FNVBOXEXTWORKERCB(void *pvUser);
24typedef FNVBOXEXTWORKERCB *PFNVBOXEXTWORKERCB;
25
26HRESULT VBoxExtDwSubmitProcSync(PFNVBOXEXTWORKERCB pfnCb, void *pvCb);
27HRESULT VBoxExtDwSubmitProcAsync(PFNVBOXEXTWORKERCB pfnCb, void *pvCb);
28
29/*******************************/
30#ifdef VBOX_WITH_WDDM
31# if defined(VBOX_WDDM_WOW64)
32# define VBOXEXT_WINE_MODULE_NAME "wined3dwddm-x86.dll"
33# else
34# define VBOXEXT_WINE_MODULE_NAME "wined3dwddm.dll"
35# endif
36#else
37/* both 32bit and 64bit versions of xpdm wine libs are named identically */
38# define VBOXEXT_WINE_MODULE_NAME "wined3d.dll"
39#endif
40
41typedef struct VBOXEXT_WORKER
42{
43 CRITICAL_SECTION CritSect;
44
45 HANDLE hEvent;
46
47 HANDLE hThread;
48 DWORD idThread;
49 /* wine does not seem to guarantie the dll is not unloaded in case FreeLibrary is used
50 * while d3d object is not terminated, keep an extra reference to ensure we're not unloaded
51 * while we are active */
52 HMODULE hSelf;
53} VBOXEXT_WORKER, *PVBOXEXT_WORKER;
54
55
56
57HRESULT VBoxExtWorkerCreate(PVBOXEXT_WORKER pWorker);
58HRESULT VBoxExtWorkerDestroy(PVBOXEXT_WORKER pWorker);
59HRESULT VBoxExtWorkerSubmitProc(PVBOXEXT_WORKER pWorker, PFNVBOXEXTWORKERCB pfnCb, void *pvCb);
60
61
62/*******************************/
63typedef struct VBOXEXT_GLOBAL
64{
65 VBOXEXT_WORKER Worker;
66} VBOXEXT_GLOBAL, *PVBOXEXT_GLOBAL;
67
68static VBOXEXT_GLOBAL g_VBoxExtGlobal;
69
70#define WM_VBOXEXT_CALLPROC (WM_APP+1)
71#define WM_VBOXEXT_INIT_QUIT (WM_APP+2)
72
73typedef struct VBOXEXT_CALLPROC
74{
75 PFNVBOXEXTWORKERCB pfnCb;
76 void *pvCb;
77} VBOXEXT_CALLPROC, *PVBOXEXT_CALLPROC;
78
79static DWORD WINAPI vboxExtWorkerThread(void *pvUser)
80{
81 PVBOXEXT_WORKER pWorker = (PVBOXEXT_WORKER)pvUser;
82 MSG Msg;
83
84 PeekMessage(&Msg,
85 NULL /* HWND hWnd */,
86 WM_USER /* UINT wMsgFilterMin */,
87 WM_USER /* UINT wMsgFilterMax */,
88 PM_NOREMOVE);
89 SetEvent(pWorker->hEvent);
90
91 do
92 {
93 BOOL bResult = GetMessage(&Msg,
94 0 /*HWND hWnd*/,
95 0 /*UINT wMsgFilterMin*/,
96 0 /*UINT wMsgFilterMax*/
97 );
98
99 if(!bResult) /* WM_QUIT was posted */
100 break;
101
102 Assert(bResult != -1);
103 if(bResult == -1) /* error occurred */
104 break;
105
106 switch (Msg.message)
107 {
108 case WM_VBOXEXT_CALLPROC:
109 {
110 VBOXEXT_CALLPROC* pData = (VBOXEXT_CALLPROC*)Msg.lParam;
111 pData->pfnCb(pData->pvCb);
112 SetEvent(pWorker->hEvent);
113 break;
114 }
115 case WM_VBOXEXT_INIT_QUIT:
116 case WM_CLOSE:
117 {
118 PostQuitMessage(0);
119 break;
120 }
121 default:
122 TranslateMessage(&Msg);
123 DispatchMessage(&Msg);
124 }
125 } while (1);
126 return 0;
127}
128
129HRESULT VBoxExtWorkerCreate(PVBOXEXT_WORKER pWorker)
130{
131 if(!GetModuleHandleEx(0, VBOXEXT_WINE_MODULE_NAME, &pWorker->hSelf))
132 {
133 DWORD dwEr = GetLastError();
134 ERR("GetModuleHandleEx failed, %d", dwEr);
135 return E_FAIL;
136 }
137
138 InitializeCriticalSection(&pWorker->CritSect);
139 pWorker->hEvent = CreateEvent(NULL, /* LPSECURITY_ATTRIBUTES lpEventAttributes */
140 FALSE, /* BOOL bManualReset */
141 FALSE, /* BOOL bInitialState */
142 NULL /* LPCTSTR lpName */
143 );
144 if (pWorker->hEvent)
145 {
146 pWorker->hThread = CreateThread(
147 NULL /* LPSECURITY_ATTRIBUTES lpThreadAttributes */,
148 0 /* SIZE_T dwStackSize */,
149 vboxExtWorkerThread,
150 pWorker,
151 0 /* DWORD dwCreationFlags */,
152 &pWorker->idThread);
153 if (pWorker->hThread)
154 {
155 DWORD dwResult = WaitForSingleObject(pWorker->hEvent, INFINITE);
156 if (WAIT_OBJECT_0 == dwResult)
157 return S_OK;
158 ERR("WaitForSingleObject returned %d\n", dwResult);
159 }
160 else
161 {
162 DWORD winErr = GetLastError();
163 ERR("CreateThread failed, winErr = (%d)", winErr);
164 }
165
166 DeleteCriticalSection(&pWorker->CritSect);
167 }
168 else
169 {
170 DWORD winErr = GetLastError();
171 ERR("CreateEvent failed, winErr = (%d)", winErr);
172 }
173
174 FreeLibrary(pWorker->hSelf);
175
176 return E_FAIL;
177}
178
179HRESULT VBoxExtWorkerDestroy(PVBOXEXT_WORKER pWorker)
180{
181 BOOL bResult = PostThreadMessage(pWorker->idThread, WM_VBOXEXT_INIT_QUIT, 0, 0);
182 DWORD dwErr;
183 if (!bResult)
184 {
185 DWORD winErr = GetLastError();
186 ERR("PostThreadMessage failed, winErr = (%d)", winErr);
187 return E_FAIL;
188 }
189
190 dwErr = WaitForSingleObject(pWorker->hThread, INFINITE);
191 if (dwErr != WAIT_OBJECT_0)
192 {
193 ERR("WaitForSingleObject returned (%d)", dwErr);
194 return E_FAIL;
195 }
196
197 CloseHandle(pWorker->hEvent);
198 DeleteCriticalSection(&pWorker->CritSect);
199
200 FreeLibrary(pWorker->hSelf);
201
202 CloseHandle(pWorker->hThread);
203
204 return S_OK;
205}
206
207static HRESULT vboxExtWorkerSubmit(VBOXEXT_WORKER *pWorker, UINT Msg, LPARAM lParam, BOOL fSync)
208{
209 HRESULT hr = E_FAIL;
210 BOOL bResult;
211 /* need to serialize since vboxExtWorkerThread is using one pWorker->hEvent
212 * to signal job completion */
213 EnterCriticalSection(&pWorker->CritSect);
214 bResult = PostThreadMessage(pWorker->idThread, Msg, 0, lParam);
215 if (bResult)
216 {
217 if (fSync)
218 {
219 DWORD dwErr = WaitForSingleObject(pWorker->hEvent, INFINITE);
220 if (dwErr == WAIT_OBJECT_0)
221 {
222 hr = S_OK;
223 }
224 else
225 {
226 ERR("WaitForSingleObject returned (%d)", dwErr);
227 }
228 }
229 else
230 hr = S_OK;
231 }
232 else
233 {
234 DWORD winErr = GetLastError();
235 ERR("PostThreadMessage failed, winErr = (%d)", winErr);
236 return E_FAIL;
237 }
238 LeaveCriticalSection(&pWorker->CritSect);
239 return hr;
240}
241
242HRESULT VBoxExtWorkerSubmitProcSync(PVBOXEXT_WORKER pWorker, PFNVBOXEXTWORKERCB pfnCb, void *pvCb)
243{
244 VBOXEXT_CALLPROC Ctx;
245 Ctx.pfnCb = pfnCb;
246 Ctx.pvCb = pvCb;
247 return vboxExtWorkerSubmit(pWorker, WM_VBOXEXT_CALLPROC, (LPARAM)&Ctx, TRUE);
248}
249
250static DECLCALLBACK(void) vboxExtWorkerSubmitProcAsyncWorker(void *pvUser)
251{
252 PVBOXEXT_CALLPROC pCallInfo = (PVBOXEXT_CALLPROC)pvUser;
253 pCallInfo[1].pfnCb(pCallInfo[1].pvCb);
254 HeapFree(GetProcessHeap(), 0, pCallInfo);
255}
256
257HRESULT VBoxExtWorkerSubmitProcAsync(PVBOXEXT_WORKER pWorker, PFNVBOXEXTWORKERCB pfnCb, void *pvCb)
258{
259 HRESULT hr;
260 PVBOXEXT_CALLPROC pCallInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof (VBOXEXT_CALLPROC) * 2);
261 if (!pCallInfo)
262 {
263 ERR("HeapAlloc failed\n");
264 return E_OUTOFMEMORY;
265 }
266 pCallInfo[0].pfnCb = vboxExtWorkerSubmitProcAsyncWorker;
267 pCallInfo[0].pvCb = pCallInfo;
268 pCallInfo[1].pfnCb = pfnCb;
269 pCallInfo[1].pvCb = pvCb;
270 hr = vboxExtWorkerSubmit(pWorker, WM_VBOXEXT_CALLPROC, (LPARAM)pCallInfo, FALSE);
271 if (FAILED(hr))
272 {
273 ERR("vboxExtWorkerSubmit failed, hr 0x%x\n", hr);
274 HeapFree(GetProcessHeap(), 0, pCallInfo);
275 return hr;
276 }
277 return S_OK;
278}
279
280
281static HRESULT vboxExtInit()
282{
283 HRESULT hr = S_OK;
284 memset(&g_VBoxExtGlobal, 0, sizeof (g_VBoxExtGlobal));
285 hr = VBoxExtWorkerCreate(&g_VBoxExtGlobal.Worker);
286 return hr;
287}
288
289static HRESULT vboxExtTerm()
290{
291 HRESULT hr = VBoxExtWorkerDestroy(&g_VBoxExtGlobal.Worker);
292 return hr;
293}
294
295/* wine serializes all calls to us, so no need for any synchronization here */
296static DWORD g_cVBoxExtInits = 0;
297
298static DWORD vboxExtAddRef()
299{
300 return ++g_cVBoxExtInits;
301}
302
303static DWORD vboxExtRelease()
304{
305 DWORD cVBoxExtInits = --g_cVBoxExtInits;
306 Assert(cVBoxExtInits < UINT32_MAX/2);
307 return cVBoxExtInits;
308}
309
310static DWORD vboxExtGetRef()
311{
312 return g_cVBoxExtInits;
313}
314
315HRESULT VBoxExtCheckInit()
316{
317 HRESULT hr = S_OK;
318 if (!vboxExtGetRef())
319 {
320 hr = vboxExtInit();
321 if (FAILED(hr))
322 {
323 ERR("vboxExtInit failed, hr (0x%x)", hr);
324 return hr;
325 }
326 }
327 vboxExtAddRef();
328 return S_OK;
329}
330
331HRESULT VBoxExtCheckTerm()
332{
333 HRESULT hr = S_OK;
334 if (vboxExtGetRef() == 1)
335 {
336 hr = vboxExtTerm();
337 if (FAILED(hr))
338 {
339 ERR("vboxExtTerm failed, hr (0x%x)", hr);
340 return hr;
341 }
342 }
343 vboxExtRelease();
344 return S_OK;
345}
346
347HRESULT VBoxExtDwSubmitProcSync(PFNVBOXEXTWORKERCB pfnCb, void *pvCb)
348{
349 return VBoxExtWorkerSubmitProcSync(&g_VBoxExtGlobal.Worker, pfnCb, pvCb);
350}
351
352HRESULT VBoxExtDwSubmitProcAsync(PFNVBOXEXTWORKERCB pfnCb, void *pvCb)
353{
354 return VBoxExtWorkerSubmitProcAsync(&g_VBoxExtGlobal.Worker, pfnCb, pvCb);
355}
356
357#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
358# ifndef VBOX_WITH_WDDM
359typedef struct VBOXEXT_GETDC_CB
360{
361 HWND hWnd;
362 HDC hDC;
363} VBOXEXT_GETDC_CB, *PVBOXEXT_GETDC_CB;
364
365static DECLCALLBACK(void) vboxExtGetDCWorker(void *pvUser)
366{
367 PVBOXEXT_GETDC_CB pData = (PVBOXEXT_GETDC_CB)pvUser;
368 pData->hDC = GetDC(pData->hWnd);
369}
370
371typedef struct VBOXEXT_RELEASEDC_CB
372{
373 HWND hWnd;
374 HDC hDC;
375 int ret;
376} VBOXEXT_RELEASEDC_CB, *PVBOXEXT_RELEASEDC_CB;
377
378static DECLCALLBACK(void) vboxExtReleaseDCWorker(void *pvUser)
379{
380 PVBOXEXT_RELEASEDC_CB pData = (PVBOXEXT_RELEASEDC_CB)pvUser;
381 pData->ret = ReleaseDC(pData->hWnd, pData->hDC);
382}
383
384HDC VBoxExtGetDC(HWND hWnd)
385{
386 HRESULT hr;
387 VBOXEXT_GETDC_CB Data = {0};
388 Data.hWnd = hWnd;
389 Data.hDC = NULL;
390
391 hr = VBoxExtDwSubmitProcSync(vboxExtGetDCWorker, &Data);
392 if (FAILED(hr))
393 {
394 ERR("VBoxExtDwSubmitProcSync feiled, hr (0x%x)\n", hr);
395 return NULL;
396 }
397
398 return Data.hDC;
399}
400
401int VBoxExtReleaseDC(HWND hWnd, HDC hDC)
402{
403 HRESULT hr;
404 VBOXEXT_RELEASEDC_CB Data = {0};
405 Data.hWnd = hWnd;
406 Data.hDC = hDC;
407 Data.ret = 0;
408
409 hr = VBoxExtDwSubmitProcSync(vboxExtReleaseDCWorker, &Data);
410 if (FAILED(hr))
411 {
412 ERR("VBoxExtDwSubmitProcSync feiled, hr (0x%x)\n", hr);
413 return -1;
414 }
415
416 return Data.ret;
417}
418# endif /* #ifndef VBOX_WITH_WDDM */
419
420static DECLCALLBACK(void) vboxExtReleaseContextWorker(void *pvUser)
421{
422 struct wined3d_context *context = (struct wined3d_context *)pvUser;
423 wined3d_mutex_lock();
424 VBoxTlsRefRelease(context);
425 wined3d_mutex_unlock();
426}
427
428void VBoxExtReleaseContextAsync(struct wined3d_context *context)
429{
430 HRESULT hr;
431
432 hr = VBoxExtDwSubmitProcAsync(vboxExtReleaseContextWorker, context);
433 if (FAILED(hr))
434 {
435 ERR("VBoxExtDwSubmitProcAsync feiled, hr (0x%x)\n", hr);
436 return;
437 }
438}
439
440#endif /* #if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT) */
441
442/* window creation API */
443static LRESULT CALLBACK vboxExtWndProc(HWND hwnd,
444 UINT uMsg,
445 WPARAM wParam,
446 LPARAM lParam
447)
448{
449 switch(uMsg)
450 {
451 case WM_CLOSE:
452 TRACE("got WM_CLOSE for hwnd(0x%x)", hwnd);
453 return 0;
454 case WM_DESTROY:
455 TRACE("got WM_DESTROY for hwnd(0x%x)", hwnd);
456 return 0;
457 case WM_NCHITTEST:
458 TRACE("got WM_NCHITTEST for hwnd(0x%x)\n", hwnd);
459 return HTNOWHERE;
460 }
461
462 return DefWindowProc(hwnd, uMsg, wParam, lParam);
463}
464
465#define VBOXEXTWND_NAME "VboxDispD3DWineWnd"
466
467HRESULT vboxExtWndDoCreate(DWORD w, DWORD h, HWND *phWnd, HDC *phDC)
468{
469 HRESULT hr = S_OK;
470 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
471 /* Register the Window Class. */
472 WNDCLASS wc;
473 if (!GetClassInfo(hInstance, VBOXEXTWND_NAME, &wc))
474 {
475 wc.style = 0;//CS_OWNDC;
476 wc.lpfnWndProc = vboxExtWndProc;
477 wc.cbClsExtra = 0;
478 wc.cbWndExtra = 0;
479 wc.hInstance = hInstance;
480 wc.hIcon = NULL;
481 wc.hCursor = NULL;
482 wc.hbrBackground = NULL;
483 wc.lpszMenuName = NULL;
484 wc.lpszClassName = VBOXEXTWND_NAME;
485 if (!RegisterClass(&wc))
486 {
487 DWORD winErr = GetLastError();
488 ERR("RegisterClass failed, winErr(%d)\n", winErr);
489 hr = E_FAIL;
490 }
491 }
492
493 if (hr == S_OK)
494 {
495 HWND hWnd = CreateWindowEx (WS_EX_TOOLWINDOW,
496 VBOXEXTWND_NAME, VBOXEXTWND_NAME,
497 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
498 0, 0,
499 w, h,
500 NULL, //GetDesktopWindow() /* hWndParent */,
501 NULL /* hMenu */,
502 hInstance,
503 NULL /* lpParam */);
504 Assert(hWnd);
505 if (hWnd)
506 {
507 *phWnd = hWnd;
508 *phDC = GetDC(hWnd);
509 /* make sure we keep inited until the window is active */
510 vboxExtAddRef();
511 }
512 else
513 {
514 DWORD winErr = GetLastError();
515 ERR("CreateWindowEx failed, winErr(%d)\n", winErr);
516 hr = E_FAIL;
517 }
518 }
519
520 return hr;
521}
522
523static HRESULT vboxExtWndDoDestroy(HWND hWnd, HDC hDC)
524{
525 BOOL bResult;
526 DWORD winErr;
527 ReleaseDC(hWnd, hDC);
528 bResult = DestroyWindow(hWnd);
529 Assert(bResult);
530 if (bResult)
531 {
532 /* release the reference we previously acquired on window creation */
533 vboxExtRelease();
534 return S_OK;
535 }
536
537 winErr = GetLastError();
538 ERR("DestroyWindow failed, winErr(%d) for hWnd(0x%x)\n", winErr, hWnd);
539
540 return E_FAIL;
541}
542
543typedef struct VBOXEXTWND_CREATE_INFO
544{
545 int hr;
546 HWND hWnd;
547 HDC hDC;
548 DWORD width;
549 DWORD height;
550} VBOXEXTWND_CREATE_INFO;
551
552typedef struct VBOXEXTWND_DESTROY_INFO
553{
554 int hr;
555 HWND hWnd;
556 HDC hDC;
557} VBOXEXTWND_DESTROY_INFO;
558
559DECLCALLBACK(void) vboxExtWndDestroyWorker(void *pvUser)
560{
561 VBOXEXTWND_DESTROY_INFO *pInfo = (VBOXEXTWND_DESTROY_INFO*)pvUser;
562 pInfo->hr = vboxExtWndDoDestroy(pInfo->hWnd, pInfo->hDC);
563 Assert(pInfo->hr == S_OK);
564}
565
566DECLCALLBACK(void) vboxExtWndCreateWorker(void *pvUser)
567{
568 VBOXEXTWND_CREATE_INFO *pInfo = (VBOXEXTWND_CREATE_INFO*)pvUser;
569 pInfo->hr = vboxExtWndDoCreate(pInfo->width, pInfo->height, &pInfo->hWnd, &pInfo->hDC);
570 Assert(pInfo->hr == S_OK);
571}
572
573HRESULT VBoxExtWndDestroy(HWND hWnd, HDC hDC)
574{
575 HRESULT hr;
576 VBOXEXTWND_DESTROY_INFO Info;
577 Info.hr = E_FAIL;
578 Info.hWnd = hWnd;
579 Info.hDC = hDC;
580 hr = VBoxExtDwSubmitProcSync(vboxExtWndDestroyWorker, &Info);
581 Assert(hr == S_OK);
582 if (hr == S_OK)
583 {
584 Assert(Info.hr == S_OK);
585 return Info.hr;
586 }
587 return hr;
588}
589
590HRESULT VBoxExtWndCreate(DWORD width, DWORD height, HWND *phWnd, HDC *phDC)
591{
592 HRESULT hr;
593 VBOXEXTWND_CREATE_INFO Info;
594 Info.hr = E_FAIL;
595 Info.width = width;
596 Info.height = height;
597 hr = VBoxExtDwSubmitProcSync(vboxExtWndCreateWorker, &Info);
598 Assert(hr == S_OK);
599 if (hr == S_OK)
600 {
601 Assert(Info.hr == S_OK);
602 if (Info.hr == S_OK)
603 {
604 *phWnd = Info.hWnd;
605 *phDC = Info.hDC;
606 }
607 return Info.hr;
608 }
609 return hr;
610}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette