VirtualBox

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

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

Additions/3D: update to mesa-21.3.8. bugref:9845

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 18.5 KB
 
1/* $Id: VBoxGL.c 95262 2022-06-13 17:26:17Z 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(HDC hDC)
240{
241 RT_NOREF(hDC); /** @todo Use it? */
242 struct pipe_screen *screen = NULL;
243
244 if (gaDrvLoadSVGA(&g_drvfuncs))
245 {
246 WDDMGalliumDriverEnv const *pEnv = GaDrvEnvKmtCreate();
247 if (pEnv)
248 {
249 /// @todo pEnv to include destructor callback, to be called from winsys screen destructor?
250 screen = g_drvfuncs.pfnGaDrvScreenCreate(pEnv);
251 }
252 }
253
254 return screen;
255}
256
257static void
258wddm_present(struct pipe_screen *screen,
259 struct pipe_context *context,
260 struct pipe_resource *res,
261 HDC hDC)
262{
263 RT_NOREF(context);
264 struct stw_context *ctx = stw_current_context();
265 struct pipe_context *pipe = ctx->st->pipe;
266
267 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
268 if (pEnv)
269 {
270 /* Get context and kernel-mode handle of the resource. */
271 uint32_t u32Cid = g_drvfuncs.pfnGaDrvGetContextId(pipe);
272 D3DKMT_HANDLE hContext = GaDrvEnvKmtContextHandle(pEnv, u32Cid);
273
274 uint32_t u32SourceSid = g_drvfuncs.pfnGaDrvGetSurfaceId(screen, res);
275 D3DKMT_HANDLE hSource = GaDrvEnvKmtSurfaceHandle(pEnv, u32SourceSid);
276
277 HWND hwnd = WindowFromDC(hDC);
278
279 vboxKmtPresent(hContext, hwnd, hSource, res->width0, res->height0);
280 }
281}
282
283static boolean
284wddm_get_adapter_luid(struct pipe_screen *screen,
285 HDC hDC,
286 LUID *pAdapterLuid)
287{
288 RT_NOREF(hDC); /** @todo Use it? */
289 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
290 if (pEnv)
291 {
292 GaDrvEnvKmtAdapterLUID(pEnv, pAdapterLuid);
293 return true;
294 }
295
296 return false;
297}
298
299static struct stw_shared_surface *
300wddm_shared_surface_open(struct pipe_screen *screen,
301 HANDLE hSharedSurface)
302{
303 struct stw_shared_surface *surface = NULL;
304
305 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
306 if (pEnv)
307 {
308 surface = (struct stw_shared_surface *)malloc(sizeof(struct stw_shared_surface));
309 if (surface)
310 {
311 D3DKMT_HANDLE hAdapter = GaDrvEnvKmtAdapterHandle(pEnv);
312 D3DKMT_HANDLE hDevice = GaDrvEnvKmtDeviceHandle(pEnv);
313 NTSTATUS Status = vboxKmtOpenSharedSurface(hAdapter, hDevice, (D3DKMT_HANDLE)(uintptr_t)hSharedSurface, surface);
314 if (Status != STATUS_SUCCESS)
315 {
316 free(surface);
317 surface = NULL;
318 }
319 }
320 }
321 return surface;
322}
323
324static void
325wddm_shared_surface_close(struct pipe_screen *screen,
326 struct stw_shared_surface *surface)
327{
328 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
329 if (pEnv)
330 {
331 D3DKMT_HANDLE hDevice = GaDrvEnvKmtDeviceHandle(pEnv);
332 vboxKmtCloseSharedSurface(hDevice, surface);
333 }
334 free(surface);
335}
336
337static void
338wddm_compose(struct pipe_screen *screen,
339 struct pipe_resource *res,
340 struct stw_shared_surface *dest,
341 LPCRECT pRect,
342 ULONGLONG PresentHistoryToken)
343{
344 struct stw_context *ctx = stw_current_context();
345 struct pipe_context *pipe = ctx->st->pipe;
346
347 /* The ICD asked to present something, make sure that any outstanding commends are submitted. */
348 g_drvfuncs.pfnGaDrvContextFlush(pipe);
349
350 uint32_t u32SourceSid = g_drvfuncs.pfnGaDrvGetSurfaceId(screen, res);
351
352 /* Generate SVGA_3D_CMD_SURFACE_COPY command for these resources. */
353 struct
354 {
355 SVGA3dCmdHeader header;
356 SVGA3dCmdSurfaceCopy surfaceCopy;
357 SVGA3dCopyBox box;
358 } command;
359
360 command.header.id = SVGA_3D_CMD_SURFACE_COPY;
361 command.header.size = sizeof(command) - sizeof(SVGA3dCmdHeader);
362
363 command.surfaceCopy.src.sid = u32SourceSid;
364 command.surfaceCopy.src.face = 0;
365 command.surfaceCopy.src.mipmap = 0;
366 command.surfaceCopy.dest.sid = dest->u32Sid;
367 command.surfaceCopy.dest.face = 0;
368 command.surfaceCopy.dest.mipmap = 0;
369
370 command.box.x = pRect->left;
371 command.box.y = pRect->top;
372 command.box.z = 0;
373 command.box.w = pRect->right - pRect->left;
374 command.box.h = pRect->bottom - pRect->top;
375 command.box.d = 1;
376 command.box.srcx = 0;
377 command.box.srcy = 0;
378 command.box.srcz = 0;
379
380 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
381 if (pEnv)
382 {
383 uint32_t u32Cid = g_drvfuncs.pfnGaDrvGetContextId(pipe);
384 GaDrvEnvKmtRenderCompose(pEnv, u32Cid, &command, sizeof(command), PresentHistoryToken);
385 }
386}
387
388static unsigned
389wddm_get_pfd_flags(struct pipe_screen *screen)
390{
391 (void)screen;
392 return stw_pfd_gdi_support | stw_pfd_double_buffer;
393}
394
395static const char *
396wddm_get_name(void)
397{
398 return "VBoxGL";
399}
400
401static const struct stw_winsys stw_winsys = {
402 wddm_screen_create,
403 wddm_present,
404 wddm_get_adapter_luid,
405 wddm_shared_surface_open,
406 wddm_shared_surface_close,
407 wddm_compose,
408 wddm_get_pfd_flags,
409 NULL, /* create_framebuffer */
410 wddm_get_name,
411};
412
413#ifdef DEBUG
414typedef BOOL WINAPI FNGetModuleInformation(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb);
415typedef FNGetModuleInformation *PFNGetModuleInformation;
416
417static PFNGetModuleInformation g_pfnGetModuleInformation = NULL;
418static HMODULE g_hModPsapi = NULL;
419static PVOID g_VBoxWDbgVEHandler = NULL;
420
421static bool vboxVDbgIsAddressInModule(PVOID pv, const char *pszModuleName)
422{
423 HMODULE hMod = GetModuleHandleA(pszModuleName);
424 if (!hMod)
425 return false;
426
427 if (!g_pfnGetModuleInformation)
428 return false;
429
430 HANDLE hProcess = GetCurrentProcess();
431 MODULEINFO ModuleInfo = {0};
432 if (!g_pfnGetModuleInformation(hProcess, hMod, &ModuleInfo, sizeof(ModuleInfo)))
433 return false;
434
435 return (uintptr_t)ModuleInfo.lpBaseOfDll <= (uintptr_t)pv
436 && (uintptr_t)pv < (uintptr_t)ModuleInfo.lpBaseOfDll + ModuleInfo.SizeOfImage;
437}
438
439static bool vboxVDbgIsExceptionIgnored(PEXCEPTION_RECORD pExceptionRecord)
440{
441 /* Module (dll) names for GetModuleHandle.
442 * Exceptions originated from these modules will be ignored.
443 */
444 static const char *apszIgnoredModuleNames[] =
445 {
446 NULL
447 };
448
449 int i = 0;
450 while (apszIgnoredModuleNames[i])
451 {
452 if (vboxVDbgIsAddressInModule(pExceptionRecord->ExceptionAddress, apszIgnoredModuleNames[i]))
453 return true;
454
455 ++i;
456 }
457
458 return false;
459}
460
461static LONG WINAPI vboxVDbgVectoredHandler(struct _EXCEPTION_POINTERS *pExceptionInfo) RT_NOTHROW_DEF
462{
463 static volatile bool g_fAllowIgnore = true; /* Might be changed in kernel debugger. */
464
465 PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
466 /* PCONTEXT pContextRecord = pExceptionInfo->ContextRecord; */
467
468 switch (pExceptionRecord->ExceptionCode)
469 {
470 default:
471 break;
472 case EXCEPTION_BREAKPOINT:
473 case EXCEPTION_ACCESS_VIOLATION:
474 case EXCEPTION_STACK_OVERFLOW:
475 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
476 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
477 case EXCEPTION_FLT_INVALID_OPERATION:
478 case EXCEPTION_INT_DIVIDE_BY_ZERO:
479 case EXCEPTION_ILLEGAL_INSTRUCTION:
480 if (g_fAllowIgnore && vboxVDbgIsExceptionIgnored(pExceptionRecord))
481 break;
482 ASMBreakpoint();
483 break;
484 case 0x40010006: /* OutputDebugStringA? */
485 case 0x4001000a: /* OutputDebugStringW? */
486 break;
487 }
488 return EXCEPTION_CONTINUE_SEARCH;
489}
490
491static void vboxVDbgVEHandlerRegister(void)
492{
493 Assert(!g_VBoxWDbgVEHandler);
494 g_VBoxWDbgVEHandler = AddVectoredExceptionHandler(1, vboxVDbgVectoredHandler);
495 Assert(g_VBoxWDbgVEHandler);
496
497 g_hModPsapi = GetModuleHandleA("Psapi.dll"); /* Usually already loaded. */
498 if (g_hModPsapi)
499 g_pfnGetModuleInformation = (PFNGetModuleInformation)GetProcAddress(g_hModPsapi, "GetModuleInformation");
500}
501
502static void vboxVDbgVEHandlerUnregister(void)
503{
504 Assert(g_VBoxWDbgVEHandler);
505 ULONG uResult = RemoveVectoredExceptionHandler(g_VBoxWDbgVEHandler);
506 Assert(uResult); RT_NOREF(uResult);
507 g_VBoxWDbgVEHandler = NULL;
508
509 g_hModPsapi = NULL;
510 g_pfnGetModuleInformation = NULL;
511}
512#endif /* DEBUG */
513
514BOOL WINAPI DllMain(HINSTANCE hDLLInst,
515 DWORD fdwReason,
516 LPVOID lpvReserved)
517{
518 RT_NOREF2(hDLLInst, lpvReserved);
519
520 switch (fdwReason)
521 {
522 case DLL_PROCESS_ATTACH:
523#ifdef DEBUG
524 vboxVDbgVEHandlerRegister();
525#endif
526 D3DKMTLoad();
527 stw_init(&stw_winsys);
528 stw_init_thread();
529 break;
530
531 case DLL_PROCESS_DETACH:
532#ifdef DEBUG
533 vboxVDbgVEHandlerUnregister();
534#endif
535 break;
536
537 case DLL_THREAD_ATTACH:
538 stw_init_thread();
539 break;
540
541 case DLL_THREAD_DETACH:
542 stw_cleanup_thread();
543 break;
544
545 default:
546 if (lpvReserved == NULL)
547 {
548 // We're being unloaded from the process.
549 stw_cleanup_thread();
550 stw_cleanup();
551 }
552 else
553 {
554 // Process itself is terminating, and all threads and modules are
555 // being detached.
556 //
557 // The order threads (including llvmpipe rasterizer threads) are
558 // destroyed can not be relied up, so it's not safe to cleanup.
559 //
560 // However global destructors (e.g., LLVM's) will still be called, and
561 // if Microsoft OPENGL32.DLL's DllMain is called after us, it will
562 // still try to invoke DrvDeleteContext to destroys all outstanding,
563 // so set stw_dev to NULL to return immediately if that happens.
564 stw_dev = NULL;
565 }
566 break;
567 }
568
569 return TRUE;
570}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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