VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/OpenGL/VBoxOGL.cpp@ 3432

Last change on this file since 3432 was 3432, checked in by vboxsync, 18 years ago

Fixed issue with NULL parameter passing

File size: 13.7 KB
Line 
1/** @file
2 *
3 * VBoxDisp -- Windows Guest OpenGL ICD
4 *
5 * Copyright (C) 2006-2007 innotek GmbH
6 *
7 * This file is part of VirtualBox Open Source Edition (OSE), as
8 * available from http://www.virtualbox.org. This file is free software;
9 * you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License as published by the Free Software Foundation,
11 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
12 * distribution. VirtualBox OSE is distributed in the hope that it will
13 * be useful, but WITHOUT ANY WARRANTY of any kind.
14 *
15 * If you received this file as part of a commercial VirtualBox
16 * distribution, then only the terms of your commercial VirtualBox
17 * license agreement apply instead of the previous paragraph.
18 *
19 */
20#include "VBoxOGL.h"
21#include <VBox/version.h>
22#include <VBox/VBoxGuest.h>
23#include <stdarg.h>
24#include <stdio.h>
25
26#define VBOX_INIT_CALL(a, b, c) \
27 (a)->result = VINF_SUCCESS; \
28 (a)->u32ClientID = (c)->u32ClientID; \
29 (a)->u32Function = VBOXOGL_FN_##b; \
30 (a)->cParms = VBOXOGL_CPARMS_##b
31
32
33 HINSTANCE hDllVBoxOGL = 0;
34static DWORD dwOGLTlsIndex = TLS_OUT_OF_INDEXES;
35static VBOX_OGL_CTX vboxOGLCtx = {0};
36static char szOpenGLVersion[256] = "";
37static char szOpenGLExtensions[8192] = ""; /* this one can be rather long */
38
39
40/**
41 * Set the thread local OpenGL context
42 *
43 * @param pCtx thread local OpenGL context ptr
44 */
45void VBoxOGLSetThreadCtx(PVBOX_OGL_THREAD_CTX pCtx)
46{
47 BOOL ret;
48
49 ret = TlsSetValue(dwOGLTlsIndex, pCtx);
50 Assert(ret);
51}
52
53
54/**
55 * Return the thread local OpenGL context
56 *
57 * @return thread local OpenGL context ptr or NULL if failure
58 */
59PVBOX_OGL_THREAD_CTX VBoxOGLGetThreadCtx()
60{
61 PVBOX_OGL_THREAD_CTX pCtx;
62
63 pCtx = (PVBOX_OGL_THREAD_CTX)TlsGetValue(dwOGLTlsIndex);
64 if (!pCtx)
65 {
66 /* lazy init */
67 VBoxOGLThreadAttach();
68 pCtx = (PVBOX_OGL_THREAD_CTX)TlsGetValue(dwOGLTlsIndex);
69 }
70 Assert(pCtx);
71 return pCtx;
72}
73
74/**
75 * Initialize the OpenGL guest-host communication channel
76 *
77 * @return success or failure (boolean)
78 * @param hDllInst Dll instance handle
79 */
80BOOL VBoxOGLInit(HINSTANCE hDllInst)
81{
82 dwOGLTlsIndex = TlsAlloc();
83 if (dwOGLTlsIndex == TLS_OUT_OF_INDEXES)
84 {
85 DbgPrintf(("TlsAlloc failed with %d\n", GetLastError()));
86 return FALSE;
87 }
88 DbgPrintf(("VBoxOGLInit TLS index=%d\n", dwOGLTlsIndex));
89
90 /* open VBox guest driver */
91 vboxOGLCtx.hGuestDrv = CreateFile(VBOXGUEST_DEVICE_NAME,
92 GENERIC_READ | GENERIC_WRITE,
93 FILE_SHARE_READ | FILE_SHARE_WRITE,
94 NULL,
95 OPEN_EXISTING,
96 FILE_ATTRIBUTE_NORMAL,
97 NULL);
98 if (vboxOGLCtx.hGuestDrv == INVALID_HANDLE_VALUE)
99 {
100 DbgPrintf(("VBoxService: could not open VBox Guest Additions driver! rc = %d\n", GetLastError()));
101 return FALSE;
102 }
103
104 VBoxOGLThreadAttach();
105 hDllVBoxOGL = hDllInst;
106 return TRUE;
107}
108
109/**
110 * Destroy the OpenGL guest-host communication channel
111 *
112 * @return success or failure (boolean)
113 */
114BOOL VBoxOGLExit()
115{
116 DbgPrintf(("VBoxOGLExit\n"));
117 VBoxOGLThreadDetach();
118 CloseHandle(vboxOGLCtx.hGuestDrv);
119
120 hDllVBoxOGL = 0;
121 return TRUE;
122}
123
124
125/**
126 * Initialize new thread
127 *
128 * @return success or failure (boolean)
129 */
130BOOL VBoxOGLThreadAttach()
131{
132 PVBOX_OGL_THREAD_CTX pCtx;
133
134 DbgPrintf(("VBoxOGLThreadAttach id=%x\n", GetCurrentThreadId()));
135
136 pCtx = (PVBOX_OGL_THREAD_CTX)malloc(sizeof(*pCtx));
137 AssertReturn(pCtx, FALSE);
138 if (!pCtx)
139 return FALSE;
140
141 pCtx->pCmdBuffer = (uint8_t *)VirtualAlloc(NULL, VBOX_OGL_MAX_CMD_BUFFER, MEM_COMMIT, PAGE_READWRITE);
142 pCtx->pCmdBufferEnd = pCtx->pCmdBuffer + VBOX_OGL_MAX_CMD_BUFFER;
143 pCtx->pCurrentCmd = pCtx->pCmdBuffer;
144 pCtx->cCommands = 0;
145 Assert(pCtx->pCmdBuffer);
146 if (!pCtx->pCmdBuffer)
147 return FALSE;
148
149 VBoxOGLSetThreadCtx(pCtx);
150
151 VBoxGuestHGCMConnectInfo info;
152 memset (&info, 0, sizeof (info));
153
154 info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
155
156 strcpy (info.Loc.u.host.achName, "VBoxSharedOpenGL");
157
158 DWORD cbReturned;
159
160 if (DeviceIoControl(vboxOGLCtx.hGuestDrv,
161 IOCTL_VBOXGUEST_HGCM_CONNECT,
162 &info, sizeof (info),
163 &info, sizeof (info),
164 &cbReturned,
165 NULL))
166 {
167 if (info.result == VINF_SUCCESS)
168 {
169 pCtx->u32ClientID = info.u32ClientID;
170 DbgPrintf(("HGCM connect was successful: client id =%x\n", pCtx->u32ClientID));
171 }
172 }
173 else
174 {
175 DbgPrintf(("HGCM connect failed with rc=%x\n", GetLastError()));
176 return FALSE;
177 }
178
179 VBoxOGLglGetString parms;
180 memset(&parms, 0, sizeof(parms));
181
182 VBOX_INIT_CALL(&parms.hdr, GLGETSTRING, pCtx);
183
184 parms.name.type = VMMDevHGCMParmType_32bit;
185 parms.name.u.value32 = GL_VERSION;
186 parms.pString.type = VMMDevHGCMParmType_LinAddr;
187 parms.pString.u.Pointer.size = sizeof(szOpenGLVersion);
188 parms.pString.u.Pointer.u.linearAddr = (vmmDevHypPtr)szOpenGLVersion;
189
190 int rc = vboxHGCMCall(vboxOGLCtx.hGuestDrv, &parms, sizeof (parms));
191
192 if ( VBOX_FAILURE(rc)
193 || VBOX_FAILURE(parms.hdr.result))
194 {
195 DbgPrintf(("GL_VERSION failed with %x %x\n", rc, parms.hdr.result));
196 return FALSE;
197 }
198 DbgPrintf(("GL_VERSION=%s\n", szOpenGLVersion));
199
200 memset(&parms, 0, sizeof(parms));
201 VBOX_INIT_CALL(&parms.hdr, GLGETSTRING, pCtx);
202
203 parms.name.type = VMMDevHGCMParmType_32bit;
204 parms.name.u.value32 = GL_EXTENSIONS;
205 parms.pString.type = VMMDevHGCMParmType_LinAddr;
206 parms.pString.u.Pointer.size = sizeof(szOpenGLExtensions);
207 parms.pString.u.Pointer.u.linearAddr = (vmmDevHypPtr)szOpenGLExtensions;
208
209 rc = vboxHGCMCall(vboxOGLCtx.hGuestDrv, &parms, sizeof (parms));
210
211 if ( VBOX_FAILURE(rc)
212 || VBOX_FAILURE(parms.hdr.result))
213 {
214 DbgPrintf(("GL_EXTENSIONS failed with %x %x\n", rc, parms.hdr.result));
215 return FALSE;
216 }
217 DbgPrintf(("GL_EXTENSIONS=%s\n\n", szOpenGLExtensions));
218
219 return TRUE;
220}
221
222/**
223 * Clean up for terminating thread
224 *
225 * @return success or failure (boolean)
226 */
227BOOL VBoxOGLThreadDetach()
228{
229 PVBOX_OGL_THREAD_CTX pCtx;
230
231 DbgPrintf(("VBoxOGLThreadDetach id=%x\n", GetCurrentThreadId()));
232
233 pCtx = VBoxOGLGetThreadCtx();
234 if (pCtx && pCtx->u32ClientID)
235 {
236 VBoxGuestHGCMDisconnectInfo info;
237
238 memset (&info, 0, sizeof (info));
239
240 info.u32ClientID = pCtx->u32ClientID;
241
242 DWORD cbReturned;
243
244 BOOL bRet = DeviceIoControl(vboxOGLCtx.hGuestDrv,
245 IOCTL_VBOXGUEST_HGCM_DISCONNECT,
246 &info, sizeof (info),
247 &info, sizeof (info),
248 &cbReturned,
249 NULL);
250
251 if (!bRet)
252 {
253 DbgPrintf(("Disconnect failed with %x\n", GetLastError()));
254 }
255 }
256 if (pCtx)
257 {
258 if (pCtx->pCmdBuffer)
259 VirtualFree(pCtx->pCmdBuffer, 0, MEM_RELEASE);
260
261 free(pCtx);
262 VBoxOGLSetThreadCtx(NULL);
263 }
264
265 return TRUE;
266}
267
268
269
270/**
271 * Send an HGCM request
272 *
273 * @return VBox status code
274 * @param hDriver Driver handle
275 * @param pvData Data pointer
276 * @param cbData Data size
277 */
278int vboxHGCMCall(HANDLE hDriver, void *pvData, unsigned cbData)
279{
280 DWORD cbReturned;
281
282 if (DeviceIoControl (hDriver,
283 IOCTL_VBOXGUEST_HGCM_CALL,
284 pvData, cbData,
285 pvData, cbData,
286 &cbReturned,
287 NULL))
288 {
289 return VINF_SUCCESS;
290 }
291 DbgPrintf(("vboxCall failed with %x\n", GetLastError()));
292 return VERR_NOT_SUPPORTED;
293}
294
295#ifdef DEBUG
296/**
297 * Log to the debug output device
298 *
299 * @param pszFormat Format string
300 * @param ... Variable parameters
301 */
302void VBoxDbgLog(char *pszFormat, ...)
303{
304 va_list va;
305
306 va_start(va, pszFormat);
307 CHAR Buffer[10240];
308 if (strlen(pszFormat) < 512)
309 {
310 vsprintf (Buffer, pszFormat, va);
311
312 printf(Buffer);
313// OutputDebugStringA(Buffer);
314 }
315
316 va_end (va);
317}
318#endif
319
320
321GLenum APIENTRY glGetError (void)
322{
323 PVBOX_OGL_THREAD_CTX pCtx = VBoxOGLGetThreadCtx();
324
325 /** @todo if fetch error flag set -> flush buffer */
326 return pCtx->glLastError;
327}
328
329void APIENTRY glSetError(GLenum glNewError)
330{
331 PVBOX_OGL_THREAD_CTX pCtx = VBoxOGLGetThreadCtx();
332
333 pCtx->glLastError = glNewError;
334}
335
336/**
337 * Query OpenGL strings
338 *
339 * @returns OpenGL string pointer
340 * @param name string type
341 */
342const GLubyte * APIENTRY glGetString (GLenum name)
343{
344 DbgPrintf(("glGetString %x\n", name));
345 switch (name)
346 {
347 /* Note: We hide the host vendor and renderer to avoid exposing potential critical information (exploits) */
348 case GL_VENDOR:
349 return (const GLubyte *)VBOX_VENDOR;
350
351 case GL_RENDERER:
352 return (const GLubyte *)"VirtualBox OpenGL Renderer";
353
354 case GL_VERSION:
355 return (const GLubyte *)szOpenGLVersion;
356
357 case GL_EXTENSIONS:
358 return (const GLubyte *)szOpenGLExtensions;
359
360 default:
361 glLogError(GL_INVALID_ENUM);
362 return NULL;
363 }
364}
365
366/**
367 * Flush the OpenGL command queue and return the return val of the last command
368 *
369 * @returns return val of last command
370 */
371uint64_t VBoxOGLFlush()
372{
373 PVBOX_OGL_THREAD_CTX pCtx = VBoxOGLGetThreadCtx();
374 VBoxOGLglFlush parms;
375
376 AssertReturn(pCtx->pCurrentCmd > pCtx->pCmdBuffer, 0);
377
378 VBOX_INIT_CALL(&parms.hdr, GLFLUSH, pCtx);
379
380 parms.pCmdBuffer.type = VMMDevHGCMParmType_LinAddr;
381 parms.pCmdBuffer.u.Pointer.size = pCtx->pCurrentCmd - pCtx->pCmdBuffer;
382 parms.pCmdBuffer.u.Pointer.u.linearAddr = (vmmDevHypPtr)pCtx->pCmdBuffer;
383 parms.cCommands.type = VMMDevHGCMParmType_32bit;
384 parms.cCommands.u.value32 = pCtx->cCommands;
385 parms.retval.type = VMMDevHGCMParmType_64bit;
386 parms.retval.u.value64 = 0;
387 parms.lasterror.type = VMMDevHGCMParmType_32bit;
388 parms.lasterror.u.value32 = 0;
389
390 int rc = vboxHGCMCall(vboxOGLCtx.hGuestDrv, &parms, sizeof (parms));
391
392 /* reset command buffer */
393 pCtx->pCurrentCmd = pCtx->pCmdBuffer;
394 pCtx->cCommands = 0;
395
396 if ( VBOX_FAILURE(rc)
397 || VBOX_FAILURE(parms.hdr.result))
398 {
399 DbgPrintf(("GL_FLUSH failed with %x %x\n", rc, parms.hdr.result));
400 return 0;
401 }
402
403 glSetError(parms.lasterror.u.value32);
404#ifdef DEBUG
405 if (parms.lasterror.u.value32)
406 DbgPrintf(("Last command returned error %x\n", parms.lasterror.u.value32));
407#endif
408 return parms.retval.u.value64;
409}
410
411/**
412 * Flush the OpenGL command queue and return the return val of the last command
413 * The last command's final parameter is a pointer where its result is stored
414 *
415 * @returns return val of last command
416 * @param pLastParam Last parameter's address
417 * @param cbParam Last parameter's size
418 */
419uint64_t VBoxOGLFlushPtr(void *pLastParam, uint32_t cbParam)
420{
421 PVBOX_OGL_THREAD_CTX pCtx = VBoxOGLGetThreadCtx();
422 VBoxOGLglFlushPtr parms;
423
424 AssertReturn(pCtx->pCurrentCmd > pCtx->pCmdBuffer, 0);
425
426 VBOX_INIT_CALL(&parms.hdr, GLFLUSHPTR, pCtx);
427
428 parms.pCmdBuffer.type = VMMDevHGCMParmType_LinAddr;
429 parms.pCmdBuffer.u.Pointer.size = pCtx->pCurrentCmd - pCtx->pCmdBuffer;
430 parms.pCmdBuffer.u.Pointer.u.linearAddr = (vmmDevHypPtr)pCtx->pCmdBuffer;
431 parms.cCommands.type = VMMDevHGCMParmType_32bit;
432 parms.cCommands.u.value32 = pCtx->cCommands;
433 parms.retval.type = VMMDevHGCMParmType_64bit;
434 parms.retval.u.value64 = 0;
435 parms.lasterror.type = VMMDevHGCMParmType_32bit;
436 parms.lasterror.u.value32 = 0;
437 if (!cbParam || !pLastParam)
438 {
439 parms.pLastParam.type = VMMDevHGCMParmType_LinAddr;
440 parms.pLastParam.u.Pointer.size = cbParam;
441 parms.pLastParam.u.Pointer.u.linearAddr = (vmmDevHypPtr)pLastParam;
442 }
443 else
444 {
445 /* Placeholder as HGCM doesn't like NULL pointers */
446 Assert(!cbParam && !pLastParam);
447 parms.pLastParam.type = VMMDevHGCMParmType_32bit;
448 parms.pLastParam.u.value32 = 0;
449 }
450
451 int rc = vboxHGCMCall(vboxOGLCtx.hGuestDrv, &parms, sizeof (parms));
452
453 /* reset command buffer */
454 pCtx->pCurrentCmd = pCtx->pCmdBuffer;
455 pCtx->cCommands = 0;
456
457 if ( VBOX_FAILURE(rc)
458 || VBOX_FAILURE(parms.hdr.result))
459 {
460 DbgPrintf(("GL_FLUSH failed with %x %x\n", rc, parms.hdr.result));
461 return 0;
462 }
463
464 glSetError(parms.lasterror.u.value32);
465#ifdef DEBUG
466 if (parms.lasterror.u.value32)
467 DbgPrintf(("Last command returned error %x\n", parms.lasterror.u.value32));
468#endif
469 return parms.retval.u.value64;
470}
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