VirtualBox

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

Last change on this file since 10093 was 8387, checked in by vboxsync, 17 years ago

eol

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