VirtualBox

source: vbox/trunk/src/VBox/Additions/3D/win/VBoxGL/VBoxGL.c@ 95234

最後變更 在這個檔案從95234是 95234,由 vboxsync 提交於 3 年 前

WDDM: allow gallium based d3d9 and opengl drivers to work with VGPU10. bugref:9845

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 18.0 KB
 
1/* $Id: VBoxGL.c 95234 2022-06-08 16:31:28Z vboxsync $ */
2/** @file
3 * VirtualBox Windows Guest Mesa3D - OpenGL driver.
4 */
5
6/*
7 * Copyright (C) 2018-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "GaDrvEnvKMT.h"
19
20#include "stw_winsys.h"
21#include "stw_device.h"
22#include "stw_context.h"
23
24#include "pipe/p_state.h"
25#include "svga3d_reg.h"
26
27#include <iprt/asm.h>
28
29#include <common/wddm/VBoxMPIf.h>
30
31#include <Psapi.h>
32
33static const char *g_pszSvgaDll =
34#ifdef VBOX_WOW64
35 "VBoxSVGA-x86.dll"
36#else
37 "VBoxSVGA.dll"
38#endif
39;
40
41static struct GaDrvFunctions
42{
43 PFNGaDrvScreenCreate pfnGaDrvScreenCreate;
44 PFNGaDrvScreenDestroy pfnGaDrvScreenDestroy;
45 PFNGaDrvGetWDDMEnv pfnGaDrvGetWDDMEnv;
46 PFNGaDrvGetContextId pfnGaDrvGetContextId;
47 PFNGaDrvGetSurfaceId pfnGaDrvGetSurfaceId;
48 PFNGaDrvContextFlush pfnGaDrvContextFlush;
49} g_drvfuncs;
50
51
52static HMODULE gaDrvLoadSVGA(struct GaDrvFunctions *pDrvFuncs)
53{
54 struct VBOXWDDMDLLPROC aDrvProcs[] =
55 {
56 { "GaDrvScreenCreate", (FARPROC *)&pDrvFuncs->pfnGaDrvScreenCreate },
57 { "GaDrvScreenDestroy", (FARPROC *)&pDrvFuncs->pfnGaDrvScreenDestroy },
58 { "GaDrvGetWDDMEnv", (FARPROC *)&pDrvFuncs->pfnGaDrvGetWDDMEnv },
59 { "GaDrvGetContextId", (FARPROC *)&pDrvFuncs->pfnGaDrvGetContextId },
60 { "GaDrvGetSurfaceId", (FARPROC *)&pDrvFuncs->pfnGaDrvGetSurfaceId },
61 { "GaDrvContextFlush", (FARPROC *)&pDrvFuncs->pfnGaDrvContextFlush },
62 { NULL, NULL }
63 };
64
65 HMODULE hmod = VBoxWddmLoadSystemDll(g_pszSvgaDll);
66 if (hmod)
67 {
68 VBoxWddmLoadAdresses(hmod, aDrvProcs);
69 }
70 return hmod;
71}
72
73struct stw_shared_surface
74{
75 D3DKMT_HANDLE hResource;
76 D3DKMT_HANDLE hSurface;
77 uint32_t u32Sid;
78};
79
80static NTSTATUS vboxKmtPresent(D3DKMT_HANDLE hContext, HWND hwnd, D3DKMT_HANDLE hSource, LONG lWidth, LONG lHeight)
81{
82 RECT r;
83 r.left = 0;
84 r.top = 0;
85 r.right = lWidth;
86 r.bottom = lHeight;
87
88 D3DKMT_PRESENT PresentData;
89 memset(&PresentData, 0, sizeof(PresentData));
90 PresentData.hContext = hContext;
91 PresentData.hWindow = hwnd;
92 PresentData.hSource = hSource;
93 PresentData.hDestination = 0;
94 PresentData.Flags.Blt = 1;
95 PresentData.Flags.SrcRectValid = 1;
96 PresentData.Flags.DstRectValid = 1;
97 PresentData.SrcRect = r;
98 PresentData.SubRectCnt = 1;
99 PresentData.pSrcSubRects = &r;
100 PresentData.DstRect = r;
101
102 D3DKMTFUNCTIONS const *d3dkmt = D3DKMTFunctions();
103 NTSTATUS Status = d3dkmt->pfnD3DKMTPresent(&PresentData);
104 return Status;
105}
106
107NTSTATUS vboxKmtOpenSharedSurface(D3DKMT_HANDLE hAdapter, D3DKMT_HANDLE hDevice, D3DKMT_HANDLE hSharedSurface, struct stw_shared_surface *pSurf)
108{
109 D3DKMTFUNCTIONS const *d3dkmt = D3DKMTFunctions();
110
111 D3DKMT_QUERYRESOURCEINFO QueryResourceInfoData;
112 memset(&QueryResourceInfoData, 0, sizeof(QueryResourceInfoData));
113 QueryResourceInfoData.hDevice = hDevice;
114 QueryResourceInfoData.hGlobalShare = hSharedSurface;
115
116 NTSTATUS Status = d3dkmt->pfnD3DKMTQueryResourceInfo(&QueryResourceInfoData);
117 if (Status == STATUS_SUCCESS)
118 {
119 D3DDDI_OPENALLOCATIONINFO OpenAllocationInfoData;
120 memset(&OpenAllocationInfoData, 0, sizeof(OpenAllocationInfoData));
121
122 D3DKMT_OPENRESOURCE OpenResourceData;
123 memset(&OpenResourceData, 0, sizeof(OpenResourceData));
124 OpenResourceData.hDevice = hDevice;
125 OpenResourceData.hGlobalShare = hSharedSurface;
126 OpenResourceData.NumAllocations = 1;
127 OpenResourceData.pOpenAllocationInfo = &OpenAllocationInfoData;
128 if (QueryResourceInfoData.PrivateRuntimeDataSize)
129 {
130 OpenResourceData.pPrivateRuntimeData = malloc(QueryResourceInfoData.PrivateRuntimeDataSize);
131 if (OpenResourceData.pPrivateRuntimeData == NULL)
132 {
133 Status = STATUS_NOT_SUPPORTED;
134 }
135 OpenResourceData.PrivateRuntimeDataSize = QueryResourceInfoData.PrivateRuntimeDataSize;
136 }
137 if (QueryResourceInfoData.ResourcePrivateDriverDataSize)
138 {
139 OpenResourceData.pResourcePrivateDriverData = malloc(QueryResourceInfoData.ResourcePrivateDriverDataSize);
140 if (OpenResourceData.pResourcePrivateDriverData == NULL)
141 {
142 Status = STATUS_NOT_SUPPORTED;
143 }
144 OpenResourceData.ResourcePrivateDriverDataSize = QueryResourceInfoData.ResourcePrivateDriverDataSize;
145 }
146 if (QueryResourceInfoData.TotalPrivateDriverDataSize)
147 {
148 OpenResourceData.pTotalPrivateDriverDataBuffer = malloc(QueryResourceInfoData.TotalPrivateDriverDataSize);
149 if (OpenResourceData.pTotalPrivateDriverDataBuffer == NULL)
150 {
151 Status = STATUS_NOT_SUPPORTED;
152 }
153 OpenResourceData.TotalPrivateDriverDataBufferSize = QueryResourceInfoData.TotalPrivateDriverDataSize;
154 }
155
156 if (Status == STATUS_SUCCESS)
157 {
158 Status = d3dkmt->pfnD3DKMTOpenResource(&OpenResourceData);
159 if (Status == STATUS_SUCCESS)
160 {
161 if (OpenAllocationInfoData.PrivateDriverDataSize == sizeof(VBOXWDDM_ALLOCINFO))
162 {
163 VBOXWDDM_ALLOCINFO *pVBoxAllocInfo = (VBOXWDDM_ALLOCINFO *)OpenAllocationInfoData.pPrivateDriverData;
164 pSurf->hResource = OpenResourceData.hResource;
165 pSurf->hSurface = OpenAllocationInfoData.hAllocation;
166 pSurf->u32Sid = pVBoxAllocInfo->hostID;
167 }
168 else if (OpenAllocationInfoData.PrivateDriverDataSize == sizeof(VBOXDXALLOCATIONDESC))
169 {
170 //VBOXDXALLOCATIONDESC *pAllocDesc = (VBOXDXALLOCATIONDESC *)OpenAllocationInfoData.PrivateDriverDataSize;
171 pSurf->hResource = OpenResourceData.hResource;
172 pSurf->hSurface = OpenAllocationInfoData.hAllocation;
173
174 VBOXDISPIFESCAPE_SVGAGETSID data;
175 memset(&data, 0, sizeof(data));
176 data.EscapeHdr.escapeCode = VBOXESC_SVGAGETSID;
177 data.hAllocation = OpenAllocationInfoData.hAllocation;
178 // data.u32Sid = 0;
179
180 D3DKMT_ESCAPE EscapeData;
181 memset(&EscapeData, 0, sizeof(EscapeData));
182 EscapeData.hAdapter = hAdapter;
183 EscapeData.hDevice = hDevice;
184 EscapeData.Type = D3DKMT_ESCAPE_DRIVERPRIVATE;
185 // EscapeData.Flags.HardwareAccess = 0;
186 EscapeData.pPrivateDriverData = &data;
187 EscapeData.PrivateDriverDataSize = sizeof(data);
188 // EscapeData.hContext = 0;
189 Status = d3dkmt->pfnD3DKMTEscape(&EscapeData);
190 if (Status == STATUS_SUCCESS)
191 pSurf->u32Sid = data.u32Sid;
192 else
193 Assert(0);
194 }
195 else
196 Assert(0);
197 }
198 }
199
200 if (OpenResourceData.pPrivateRuntimeData != NULL)
201 {
202 free(OpenResourceData.pPrivateRuntimeData);
203 }
204 if (OpenResourceData.pResourcePrivateDriverData != NULL)
205 {
206 free(OpenResourceData.pResourcePrivateDriverData);
207 }
208 if (OpenResourceData.pTotalPrivateDriverDataBuffer != NULL)
209 {
210 free(OpenResourceData.pTotalPrivateDriverDataBuffer);
211 }
212 }
213
214 return Status;
215}
216
217NTSTATUS vboxKmtCloseSharedSurface(D3DKMT_HANDLE hDevice, struct stw_shared_surface *pSurf)
218{
219 D3DKMTFUNCTIONS const *d3dkmt = D3DKMTFunctions();
220
221 D3DKMT_DESTROYALLOCATION DestroyAllocationData;
222 memset(&DestroyAllocationData, 0, sizeof(DestroyAllocationData));
223 DestroyAllocationData.hDevice = hDevice;
224 DestroyAllocationData.hResource = pSurf->hResource;
225 /* "If the OpenGL ICD sets the handle in the hResource member to a non-NULL value,
226 * the ICD must set phAllocationList to NULL." and
227 * "the AllocationCount member is ignored by the OpenGL runtime."
228 */
229 // DestroyAllocationData.phAllocationList = NULL;
230 // DestroyAllocationData.AllocationCount = 0;
231
232 NTSTATUS Status = d3dkmt->pfnD3DKMTDestroyAllocation(&DestroyAllocationData);
233 Assert(Status == STATUS_SUCCESS);
234 return Status;
235}
236
237
238static struct pipe_screen *
239wddm_screen_create(void)
240{
241 struct pipe_screen *screen = NULL;
242
243 if (gaDrvLoadSVGA(&g_drvfuncs))
244 {
245 WDDMGalliumDriverEnv const *pEnv = GaDrvEnvKmtCreate();
246 if (pEnv)
247 {
248 /// @todo pEnv to include destructor callback, to be called from winsys screen destructor?
249 screen = g_drvfuncs.pfnGaDrvScreenCreate(pEnv);
250 }
251 }
252
253 return screen;
254}
255
256static void
257wddm_present(struct pipe_screen *screen,
258 struct pipe_resource *res,
259 HDC hDC)
260{
261 struct stw_context *ctx = stw_current_context();
262 struct pipe_context *pipe = ctx->st->pipe;
263
264 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
265 if (pEnv)
266 {
267 /* Get context and kernel-mode handle of the resource. */
268 uint32_t u32Cid = g_drvfuncs.pfnGaDrvGetContextId(pipe);
269 D3DKMT_HANDLE hContext = GaDrvEnvKmtContextHandle(pEnv, u32Cid);
270
271 uint32_t u32SourceSid = g_drvfuncs.pfnGaDrvGetSurfaceId(screen, res);
272 D3DKMT_HANDLE hSource = GaDrvEnvKmtSurfaceHandle(pEnv, u32SourceSid);
273
274 HWND hwnd = WindowFromDC(hDC);
275
276 vboxKmtPresent(hContext, hwnd, hSource, res->width0, res->height0);
277 }
278}
279
280static boolean
281wddm_get_adapter_luid(struct pipe_screen *screen,
282 LUID *pAdapterLuid)
283{
284 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
285 if (pEnv)
286 {
287 GaDrvEnvKmtAdapterLUID(pEnv, pAdapterLuid);
288 return true;
289 }
290
291 return false;
292}
293
294static struct stw_shared_surface *
295wddm_shared_surface_open(struct pipe_screen *screen,
296 HANDLE hSharedSurface)
297{
298 struct stw_shared_surface *surface = NULL;
299
300 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
301 if (pEnv)
302 {
303 surface = (struct stw_shared_surface *)malloc(sizeof(struct stw_shared_surface));
304 if (surface)
305 {
306 D3DKMT_HANDLE hAdapter = GaDrvEnvKmtAdapterHandle(pEnv);
307 D3DKMT_HANDLE hDevice = GaDrvEnvKmtDeviceHandle(pEnv);
308 NTSTATUS Status = vboxKmtOpenSharedSurface(hAdapter, hDevice, (D3DKMT_HANDLE)(uintptr_t)hSharedSurface, surface);
309 if (Status != STATUS_SUCCESS)
310 {
311 free(surface);
312 surface = NULL;
313 }
314 }
315 }
316 return surface;
317}
318
319static void
320wddm_shared_surface_close(struct pipe_screen *screen,
321 struct stw_shared_surface *surface)
322{
323 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
324 if (pEnv)
325 {
326 D3DKMT_HANDLE hDevice = GaDrvEnvKmtDeviceHandle(pEnv);
327 vboxKmtCloseSharedSurface(hDevice, surface);
328 }
329 free(surface);
330}
331
332static void
333wddm_compose(struct pipe_screen *screen,
334 struct pipe_resource *res,
335 struct stw_shared_surface *dest,
336 LPCRECT pRect,
337 ULONGLONG PresentHistoryToken)
338{
339 struct stw_context *ctx = stw_current_context();
340 struct pipe_context *pipe = ctx->st->pipe;
341
342 /* The ICD asked to present something, make sure that any outstanding commends are submitted. */
343 g_drvfuncs.pfnGaDrvContextFlush(pipe);
344
345 uint32_t u32SourceSid = g_drvfuncs.pfnGaDrvGetSurfaceId(screen, res);
346
347 /* Generate SVGA_3D_CMD_SURFACE_COPY command for these resources. */
348 struct
349 {
350 SVGA3dCmdHeader header;
351 SVGA3dCmdSurfaceCopy surfaceCopy;
352 SVGA3dCopyBox box;
353 } command;
354
355 command.header.id = SVGA_3D_CMD_SURFACE_COPY;
356 command.header.size = sizeof(command) - sizeof(SVGA3dCmdHeader);
357
358 command.surfaceCopy.src.sid = u32SourceSid;
359 command.surfaceCopy.src.face = 0;
360 command.surfaceCopy.src.mipmap = 0;
361 command.surfaceCopy.dest.sid = dest->u32Sid;
362 command.surfaceCopy.dest.face = 0;
363 command.surfaceCopy.dest.mipmap = 0;
364
365 command.box.x = pRect->left;
366 command.box.y = pRect->top;
367 command.box.z = 0;
368 command.box.w = pRect->right - pRect->left;
369 command.box.h = pRect->bottom - pRect->top;
370 command.box.d = 1;
371 command.box.srcx = 0;
372 command.box.srcy = 0;
373 command.box.srcz = 0;
374
375 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
376 if (pEnv)
377 {
378 uint32_t u32Cid = g_drvfuncs.pfnGaDrvGetContextId(pipe);
379 GaDrvEnvKmtRenderCompose(pEnv, u32Cid, &command, sizeof(command), PresentHistoryToken);
380 }
381}
382
383static const struct stw_winsys stw_winsys = {
384 wddm_screen_create,
385 wddm_present,
386 wddm_get_adapter_luid,
387 wddm_shared_surface_open,
388 wddm_shared_surface_close,
389 wddm_compose
390};
391
392#ifdef DEBUG
393typedef BOOL WINAPI FNGetModuleInformation(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb);
394typedef FNGetModuleInformation *PFNGetModuleInformation;
395
396static PFNGetModuleInformation g_pfnGetModuleInformation = NULL;
397static HMODULE g_hModPsapi = NULL;
398static PVOID g_VBoxWDbgVEHandler = NULL;
399
400static bool vboxVDbgIsAddressInModule(PVOID pv, const char *pszModuleName)
401{
402 HMODULE hMod = GetModuleHandleA(pszModuleName);
403 if (!hMod)
404 return false;
405
406 if (!g_pfnGetModuleInformation)
407 return false;
408
409 HANDLE hProcess = GetCurrentProcess();
410 MODULEINFO ModuleInfo = {0};
411 if (!g_pfnGetModuleInformation(hProcess, hMod, &ModuleInfo, sizeof(ModuleInfo)))
412 return false;
413
414 return (uintptr_t)ModuleInfo.lpBaseOfDll <= (uintptr_t)pv
415 && (uintptr_t)pv < (uintptr_t)ModuleInfo.lpBaseOfDll + ModuleInfo.SizeOfImage;
416}
417
418static bool vboxVDbgIsExceptionIgnored(PEXCEPTION_RECORD pExceptionRecord)
419{
420 /* Module (dll) names for GetModuleHandle.
421 * Exceptions originated from these modules will be ignored.
422 */
423 static const char *apszIgnoredModuleNames[] =
424 {
425 NULL
426 };
427
428 int i = 0;
429 while (apszIgnoredModuleNames[i])
430 {
431 if (vboxVDbgIsAddressInModule(pExceptionRecord->ExceptionAddress, apszIgnoredModuleNames[i]))
432 return true;
433
434 ++i;
435 }
436
437 return false;
438}
439
440static LONG WINAPI vboxVDbgVectoredHandler(struct _EXCEPTION_POINTERS *pExceptionInfo) RT_NOTHROW_DEF
441{
442 static volatile bool g_fAllowIgnore = true; /* Might be changed in kernel debugger. */
443
444 PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
445 /* PCONTEXT pContextRecord = pExceptionInfo->ContextRecord; */
446
447 switch (pExceptionRecord->ExceptionCode)
448 {
449 default:
450 break;
451 case EXCEPTION_BREAKPOINT:
452 case EXCEPTION_ACCESS_VIOLATION:
453 case EXCEPTION_STACK_OVERFLOW:
454 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
455 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
456 case EXCEPTION_FLT_INVALID_OPERATION:
457 case EXCEPTION_INT_DIVIDE_BY_ZERO:
458 case EXCEPTION_ILLEGAL_INSTRUCTION:
459 if (g_fAllowIgnore && vboxVDbgIsExceptionIgnored(pExceptionRecord))
460 break;
461 ASMBreakpoint();
462 break;
463 case 0x40010006: /* OutputDebugStringA? */
464 case 0x4001000a: /* OutputDebugStringW? */
465 break;
466 }
467 return EXCEPTION_CONTINUE_SEARCH;
468}
469
470static void vboxVDbgVEHandlerRegister(void)
471{
472 Assert(!g_VBoxWDbgVEHandler);
473 g_VBoxWDbgVEHandler = AddVectoredExceptionHandler(1, vboxVDbgVectoredHandler);
474 Assert(g_VBoxWDbgVEHandler);
475
476 g_hModPsapi = GetModuleHandleA("Psapi.dll"); /* Usually already loaded. */
477 if (g_hModPsapi)
478 g_pfnGetModuleInformation = (PFNGetModuleInformation)GetProcAddress(g_hModPsapi, "GetModuleInformation");
479}
480
481static void vboxVDbgVEHandlerUnregister(void)
482{
483 Assert(g_VBoxWDbgVEHandler);
484 ULONG uResult = RemoveVectoredExceptionHandler(g_VBoxWDbgVEHandler);
485 Assert(uResult); RT_NOREF(uResult);
486 g_VBoxWDbgVEHandler = NULL;
487
488 g_hModPsapi = NULL;
489 g_pfnGetModuleInformation = NULL;
490}
491#endif /* DEBUG */
492
493BOOL WINAPI DllMain(HINSTANCE hDLLInst,
494 DWORD fdwReason,
495 LPVOID lpvReserved)
496{
497 RT_NOREF2(hDLLInst, lpvReserved);
498
499 switch (fdwReason)
500 {
501 case DLL_PROCESS_ATTACH:
502#ifdef DEBUG
503 vboxVDbgVEHandlerRegister();
504#endif
505 D3DKMTLoad();
506 stw_init(&stw_winsys);
507 stw_init_thread();
508 break;
509
510 case DLL_PROCESS_DETACH:
511#ifdef DEBUG
512 vboxVDbgVEHandlerUnregister();
513#endif
514 break;
515
516 case DLL_THREAD_ATTACH:
517 stw_init_thread();
518 break;
519
520 case DLL_THREAD_DETACH:
521 stw_cleanup_thread();
522 break;
523
524 default:
525 if (lpvReserved == NULL)
526 {
527 // We're being unloaded from the process.
528 stw_cleanup_thread();
529 stw_cleanup();
530 }
531 else
532 {
533 // Process itself is terminating, and all threads and modules are
534 // being detached.
535 //
536 // The order threads (including llvmpipe rasterizer threads) are
537 // destroyed can not be relied up, so it's not safe to cleanup.
538 //
539 // However global destructors (e.g., LLVM's) will still be called, and
540 // if Microsoft OPENGL32.DLL's DllMain is called after us, it will
541 // still try to invoke DrvDeleteContext to destroys all outstanding,
542 // so set stw_dev to NULL to return immediately if that happens.
543 stw_dev = NULL;
544 }
545 break;
546 }
547
548 return TRUE;
549}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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