VirtualBox

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

Last change on this file since 76734 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.1 KB
Line 
1/* $Id: VBoxGL.c 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VirtualBox Windows Guest Mesa3D - OpenGL driver.
4 */
5
6/*
7 * Copyright (C) 2018-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.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
31static const char *g_pszSvgaDll =
32#ifdef VBOX_WOW64
33 "VBoxSVGA-x86.dll"
34#else
35 "VBoxSVGA.dll"
36#endif
37;
38
39static struct GaDrvFunctions
40{
41 PFNGaDrvScreenCreate pfnGaDrvScreenCreate;
42 PFNGaDrvScreenDestroy pfnGaDrvScreenDestroy;
43 PFNGaDrvGetWDDMEnv pfnGaDrvGetWDDMEnv;
44 PFNGaDrvGetContextId pfnGaDrvGetContextId;
45 PFNGaDrvGetSurfaceId pfnGaDrvGetSurfaceId;
46 PFNGaDrvContextFlush pfnGaDrvContextFlush;
47} g_drvfuncs;
48
49
50static HMODULE gaDrvLoadSVGA(struct GaDrvFunctions *pDrvFuncs)
51{
52 struct VBOXWDDMDLLPROC aDrvProcs[] =
53 {
54 { "GaDrvScreenCreate", (FARPROC *)&pDrvFuncs->pfnGaDrvScreenCreate },
55 { "GaDrvScreenDestroy", (FARPROC *)&pDrvFuncs->pfnGaDrvScreenDestroy },
56 { "GaDrvGetWDDMEnv", (FARPROC *)&pDrvFuncs->pfnGaDrvGetWDDMEnv },
57 { "GaDrvGetContextId", (FARPROC *)&pDrvFuncs->pfnGaDrvGetContextId },
58 { "GaDrvGetSurfaceId", (FARPROC *)&pDrvFuncs->pfnGaDrvGetSurfaceId },
59 { "GaDrvContextFlush", (FARPROC *)&pDrvFuncs->pfnGaDrvContextFlush },
60 { NULL, NULL }
61 };
62
63 HMODULE hmod = VBoxWddmLoadSystemDll(g_pszSvgaDll);
64 if (hmod)
65 {
66 VBoxWddmLoadAdresses(hmod, aDrvProcs);
67 }
68 return hmod;
69}
70
71struct stw_shared_surface
72{
73 D3DKMT_HANDLE hResource;
74 D3DKMT_HANDLE hSurface;
75 uint32_t u32Sid;
76};
77
78static NTSTATUS vboxKmtPresent(D3DKMT_HANDLE hContext, HWND hwnd, D3DKMT_HANDLE hSource, LONG lWidth, LONG lHeight)
79{
80 RECT r;
81 r.left = 0;
82 r.top = 0;
83 r.right = lWidth;
84 r.bottom = lHeight;
85
86 D3DKMT_PRESENT PresentData;
87 memset(&PresentData, 0, sizeof(PresentData));
88 PresentData.hContext = hContext;
89 PresentData.hWindow = hwnd;
90 PresentData.hSource = hSource;
91 PresentData.hDestination = 0;
92 PresentData.Flags.Blt = 1;
93 PresentData.Flags.SrcRectValid = 1;
94 PresentData.Flags.DstRectValid = 1;
95 PresentData.SrcRect = r;
96 PresentData.SubRectCnt = 1;
97 PresentData.pSrcSubRects = &r;
98 PresentData.DstRect = r;
99
100 D3DKMTFUNCTIONS const *d3dkmt = D3DKMTFunctions();
101 NTSTATUS Status = d3dkmt->pfnD3DKMTPresent(&PresentData);
102 return Status;
103}
104
105NTSTATUS vboxKmtOpenSharedSurface(D3DKMT_HANDLE hDevice, D3DKMT_HANDLE hSharedSurface, struct stw_shared_surface *pSurf)
106{
107 D3DKMTFUNCTIONS const *d3dkmt = D3DKMTFunctions();
108
109 D3DKMT_QUERYRESOURCEINFO QueryResourceInfoData;
110 memset(&QueryResourceInfoData, 0, sizeof(QueryResourceInfoData));
111 QueryResourceInfoData.hDevice = hDevice;
112 QueryResourceInfoData.hGlobalShare = hSharedSurface;
113
114 NTSTATUS Status = d3dkmt->pfnD3DKMTQueryResourceInfo(&QueryResourceInfoData);
115 if (Status == STATUS_SUCCESS)
116 {
117 D3DDDI_OPENALLOCATIONINFO OpenAllocationInfoData;
118 memset(&OpenAllocationInfoData, 0, sizeof(OpenAllocationInfoData));
119
120 D3DKMT_OPENRESOURCE OpenResourceData;
121 memset(&OpenResourceData, 0, sizeof(OpenResourceData));
122 OpenResourceData.hDevice = hDevice;
123 OpenResourceData.hGlobalShare = hSharedSurface;
124 OpenResourceData.NumAllocations = 1;
125 OpenResourceData.pOpenAllocationInfo = &OpenAllocationInfoData;
126 if (QueryResourceInfoData.PrivateRuntimeDataSize)
127 {
128 OpenResourceData.pPrivateRuntimeData = malloc(QueryResourceInfoData.PrivateRuntimeDataSize);
129 if (OpenResourceData.pPrivateRuntimeData == NULL)
130 {
131 Status = STATUS_NOT_SUPPORTED;
132 }
133 OpenResourceData.PrivateRuntimeDataSize = QueryResourceInfoData.PrivateRuntimeDataSize;
134 }
135 if (QueryResourceInfoData.ResourcePrivateDriverDataSize)
136 {
137 OpenResourceData.pResourcePrivateDriverData = malloc(QueryResourceInfoData.ResourcePrivateDriverDataSize);
138 if (OpenResourceData.pResourcePrivateDriverData == NULL)
139 {
140 Status = STATUS_NOT_SUPPORTED;
141 }
142 OpenResourceData.ResourcePrivateDriverDataSize = QueryResourceInfoData.ResourcePrivateDriverDataSize;
143 }
144 if (QueryResourceInfoData.TotalPrivateDriverDataSize)
145 {
146 OpenResourceData.pTotalPrivateDriverDataBuffer = malloc(QueryResourceInfoData.TotalPrivateDriverDataSize);
147 if (OpenResourceData.pTotalPrivateDriverDataBuffer == NULL)
148 {
149 Status = STATUS_NOT_SUPPORTED;
150 }
151 OpenResourceData.TotalPrivateDriverDataBufferSize = QueryResourceInfoData.TotalPrivateDriverDataSize;
152 }
153
154 if (Status == STATUS_SUCCESS)
155 {
156 Status = d3dkmt->pfnD3DKMTOpenResource(&OpenResourceData);
157 if (Status == STATUS_SUCCESS)
158 {
159 Assert(OpenAllocationInfoData.PrivateDriverDataSize == sizeof(VBOXWDDM_ALLOCINFO));
160 VBOXWDDM_ALLOCINFO *pVBoxAllocInfo = (VBOXWDDM_ALLOCINFO *)OpenAllocationInfoData.pPrivateDriverData;
161 pSurf->hResource = OpenResourceData.hResource;
162 pSurf->hSurface = OpenAllocationInfoData.hAllocation;
163 pSurf->u32Sid = pVBoxAllocInfo->hostID;
164 }
165 }
166
167 if (OpenResourceData.pPrivateRuntimeData != NULL)
168 {
169 free(OpenResourceData.pPrivateRuntimeData);
170 }
171 if (OpenResourceData.pResourcePrivateDriverData != NULL)
172 {
173 free(OpenResourceData.pResourcePrivateDriverData);
174 }
175 if (OpenResourceData.pTotalPrivateDriverDataBuffer != NULL)
176 {
177 free(OpenResourceData.pTotalPrivateDriverDataBuffer);
178 }
179 }
180
181 return Status;
182}
183
184NTSTATUS vboxKmtCloseSharedSurface(D3DKMT_HANDLE hDevice, struct stw_shared_surface *pSurf)
185{
186 D3DKMTFUNCTIONS const *d3dkmt = D3DKMTFunctions();
187
188 D3DKMT_DESTROYALLOCATION DestroyAllocationData;
189 memset(&DestroyAllocationData, 0, sizeof(DestroyAllocationData));
190 DestroyAllocationData.hDevice = hDevice;
191 DestroyAllocationData.hResource = pSurf->hResource;
192 /* "If the OpenGL ICD sets the handle in the hResource member to a non-NULL value,
193 * the ICD must set phAllocationList to NULL." and
194 * "the AllocationCount member is ignored by the OpenGL runtime."
195 */
196 // DestroyAllocationData.phAllocationList = NULL;
197 // DestroyAllocationData.AllocationCount = 0;
198
199 NTSTATUS Status = d3dkmt->pfnD3DKMTDestroyAllocation(&DestroyAllocationData);
200 Assert(Status == STATUS_SUCCESS);
201 return Status;
202}
203
204
205static struct pipe_screen *
206wddm_screen_create(void)
207{
208 struct pipe_screen *screen = NULL;
209
210 if (gaDrvLoadSVGA(&g_drvfuncs))
211 {
212 WDDMGalliumDriverEnv const *pEnv = GaDrvEnvKmtCreate();
213 if (pEnv)
214 {
215 /// @todo pEnv to include destructor callback, to be called from winsys screen destructor?
216 screen = g_drvfuncs.pfnGaDrvScreenCreate(pEnv);
217 }
218 }
219
220 return screen;
221}
222
223static void
224wddm_present(struct pipe_screen *screen,
225 struct pipe_resource *res,
226 HDC hDC)
227{
228 struct stw_context *ctx = stw_current_context();
229 struct pipe_context *pipe = ctx->st->pipe;
230
231 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
232 if (pEnv)
233 {
234 /* Get context and kernel-mode handle of the resource. */
235 uint32_t u32Cid = g_drvfuncs.pfnGaDrvGetContextId(pipe);
236 D3DKMT_HANDLE hContext = GaDrvEnvKmtContextHandle(pEnv, u32Cid);
237
238 uint32_t u32SourceSid = g_drvfuncs.pfnGaDrvGetSurfaceId(screen, res);
239 D3DKMT_HANDLE hSource = GaDrvEnvKmtSurfaceHandle(pEnv, u32SourceSid);
240
241 HWND hwnd = WindowFromDC(hDC);
242
243 vboxKmtPresent(hContext, hwnd, hSource, res->width0, res->height0);
244 }
245}
246
247static boolean
248wddm_get_adapter_luid(struct pipe_screen *screen,
249 LUID *pAdapterLuid)
250{
251 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
252 if (pEnv)
253 {
254 GaDrvEnvKmtAdapterLUID(pEnv, pAdapterLuid);
255 return true;
256 }
257
258 return false;
259}
260
261static struct stw_shared_surface *
262wddm_shared_surface_open(struct pipe_screen *screen,
263 HANDLE hSharedSurface)
264{
265 struct stw_shared_surface *surface = NULL;
266
267 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
268 if (pEnv)
269 {
270 surface = (struct stw_shared_surface *)malloc(sizeof(struct stw_shared_surface));
271 if (surface)
272 {
273 D3DKMT_HANDLE hDevice = GaDrvEnvKmtDeviceHandle(pEnv);
274 NTSTATUS Status = vboxKmtOpenSharedSurface(hDevice, (D3DKMT_HANDLE)hSharedSurface, surface);
275 if (Status != STATUS_SUCCESS)
276 {
277 free(surface);
278 surface = NULL;
279 }
280 }
281 }
282 return surface;
283}
284
285static void
286wddm_shared_surface_close(struct pipe_screen *screen,
287 struct stw_shared_surface *surface)
288{
289 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
290 if (pEnv)
291 {
292 D3DKMT_HANDLE hDevice = GaDrvEnvKmtDeviceHandle(pEnv);
293 vboxKmtCloseSharedSurface(hDevice, surface);
294 }
295 free(surface);
296}
297
298static void
299wddm_compose(struct pipe_screen *screen,
300 struct pipe_resource *res,
301 struct stw_shared_surface *dest,
302 LPCRECT pRect,
303 ULONGLONG PresentHistoryToken)
304{
305 struct stw_context *ctx = stw_current_context();
306 struct pipe_context *pipe = ctx->st->pipe;
307
308 /* The ICD asked to present something, make sure that any outstanding commends are submitted. */
309 g_drvfuncs.pfnGaDrvContextFlush(pipe);
310
311 uint32_t u32SourceSid = g_drvfuncs.pfnGaDrvGetSurfaceId(screen, res);
312
313 /* Generate SVGA_3D_CMD_SURFACE_COPY command for these resources. */
314 struct
315 {
316 SVGA3dCmdHeader header;
317 SVGA3dCmdSurfaceCopy surfaceCopy;
318 SVGA3dCopyBox box;
319 } command;
320
321 command.header.id = SVGA_3D_CMD_SURFACE_COPY;
322 command.header.size = sizeof(command) - sizeof(SVGA3dCmdHeader);
323
324 command.surfaceCopy.src.sid = u32SourceSid;
325 command.surfaceCopy.src.face = 0;
326 command.surfaceCopy.src.mipmap = 0;
327 command.surfaceCopy.dest.sid = dest->u32Sid;
328 command.surfaceCopy.dest.face = 0;
329 command.surfaceCopy.dest.mipmap = 0;
330
331 command.box.x = pRect->left;
332 command.box.y = pRect->top;
333 command.box.z = 0;
334 command.box.w = pRect->right - pRect->left;
335 command.box.h = pRect->bottom - pRect->top;
336 command.box.d = 1;
337 command.box.srcx = 0;
338 command.box.srcy = 0;
339 command.box.srcz = 0;
340
341 const WDDMGalliumDriverEnv *pEnv = g_drvfuncs.pfnGaDrvGetWDDMEnv(screen);
342 if (pEnv)
343 {
344 uint32_t u32Cid = g_drvfuncs.pfnGaDrvGetContextId(pipe);
345 GaDrvEnvKmtRenderCompose(pEnv, u32Cid, &command, sizeof(command), PresentHistoryToken);
346 }
347}
348
349static const struct stw_winsys stw_winsys = {
350 wddm_screen_create,
351 wddm_present,
352 wddm_get_adapter_luid,
353 wddm_shared_surface_open,
354 wddm_shared_surface_close,
355 wddm_compose
356};
357
358BOOL WINAPI DllMain(HINSTANCE hDLLInst,
359 DWORD fdwReason,
360 LPVOID lpvReserved)
361{
362 RT_NOREF2(hDLLInst, lpvReserved);
363
364 switch (fdwReason)
365 {
366 case DLL_PROCESS_ATTACH:
367 D3DKMTLoad();
368 stw_init(&stw_winsys);
369 stw_init_thread();
370 break;
371
372 case DLL_PROCESS_DETACH:
373 break;
374
375 case DLL_THREAD_ATTACH:
376 stw_init_thread();
377 break;
378
379 case DLL_THREAD_DETACH:
380 stw_cleanup_thread();
381 break;
382
383 default:
384 if (lpvReserved == NULL)
385 {
386 // We're being unloaded from the process.
387 stw_cleanup_thread();
388 stw_cleanup();
389 }
390 else
391 {
392 // Process itself is terminating, and all threads and modules are
393 // being detached.
394 //
395 // The order threads (including llvmpipe rasterizer threads) are
396 // destroyed can not be relied up, so it's not safe to cleanup.
397 //
398 // However global destructors (e.g., LLVM's) will still be called, and
399 // if Microsoft OPENGL32.DLL's DllMain is called after us, it will
400 // still try to invoke DrvDeleteContext to destroys all outstanding,
401 // so set stw_dev to NULL to return immediately if that happens.
402 stw_dev = NULL;
403 }
404 break;
405 }
406
407 return TRUE;
408}
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