VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/state_tracker/state_init.c@ 41057

Last change on this file since 41057 was 41057, checked in by vboxsync, 13 years ago

crOpenGL: fix gl resource leaking (server part)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.2 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "state.h"
8#include "cr_mem.h"
9#include "cr_error.h"
10#include "cr_spu.h"
11
12#ifdef CHROMIUM_THREADSAFE
13static bool __isContextTLSInited = false;
14CRtsd __contextTSD;
15#else
16CRContext *__currentContext = NULL;
17#endif
18
19CRStateBits *__currentBits = NULL;
20GLboolean g_availableContexts[CR_MAX_CONTEXTS];
21
22static CRSharedState *gSharedState=NULL;
23
24static CRContext *defaultContext = NULL;
25
26static GLboolean g_bVBoxEnableDiffOnMakeCurrent = GL_TRUE;
27
28
29/**
30 * Allocate a new shared state object.
31 * Contains texture objects, display lists, etc.
32 */
33static CRSharedState *
34crStateAllocShared(void)
35{
36 CRSharedState *s = (CRSharedState *) crCalloc(sizeof(CRSharedState));
37 if (s) {
38 s->textureTable = crAllocHashtable();
39 s->dlistTable = crAllocHashtable();
40 s->buffersTable = crAllocHashtable();
41 s->fbTable = crAllocHashtable();
42 s->rbTable = crAllocHashtable();
43 s->refCount = 1; /* refcount is number of contexts using this state */
44 s->saveCount = 0;
45 }
46 return s;
47}
48
49
50
51/**
52 * Callback used for crFreeHashtable().
53 */
54static void
55DeleteTextureCallback(void *texObj)
56{
57#ifndef IN_GUEST
58 diff_api.DeleteTextures(1, &((CRTextureObj *)texObj)->hwid);
59#endif
60 crStateDeleteTextureObject((CRTextureObj *) texObj);
61}
62
63#ifndef IN_GUEST
64typedef struct CR_STATE_RELEASEOBJ
65{
66 CRContext *pCtx;
67 CRSharedState *s;
68} CR_STATE_RELEASEOBJ, *PCR_STATE_RELEASEOBJ;
69
70static void ReleaseTextureCallback(unsigned long key, void *data1, void *data2)
71{
72 PCR_STATE_RELEASEOBJ pData = (PCR_STATE_RELEASEOBJ)data2;
73 CRTextureObj *pObj = (CRTextureObj *)data1;
74 CR_STATE_SHAREDOBJ_USAGE_CLEAR(pObj, pData->pCtx);
75 if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pObj))
76 crHashtableDelete(pData->s->textureTable, key, DeleteTextureCallback);
77}
78
79static void ReleaseBufferObjectCallback(unsigned long key, void *data1, void *data2)
80{
81 PCR_STATE_RELEASEOBJ pData = (PCR_STATE_RELEASEOBJ)data2;
82 CRBufferObject *pObj = (CRBufferObject *)data1;
83 CR_STATE_SHAREDOBJ_USAGE_CLEAR(pObj, pData->pCtx);
84 if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pObj))
85 crHashtableDelete(pData->s->buffersTable, key, crStateFreeBufferObject);
86}
87
88static void ReleaseFBOCallback(unsigned long key, void *data1, void *data2)
89{
90 PCR_STATE_RELEASEOBJ pData = (PCR_STATE_RELEASEOBJ)data2;
91 CRFramebufferObject *pObj = (CRFramebufferObject *)data1;
92 CR_STATE_SHAREDOBJ_USAGE_CLEAR(pObj, pData->pCtx);
93 if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pObj))
94 crHashtableDelete(pData->s->fbTable, key, crStateFreeFBO);
95}
96
97static void ReleaseRBOCallback(unsigned long key, void *data1, void *data2)
98{
99 PCR_STATE_RELEASEOBJ pData = (PCR_STATE_RELEASEOBJ)data2;
100 CRRenderbufferObject *pObj = (CRRenderbufferObject *)data1;
101 CR_STATE_SHAREDOBJ_USAGE_CLEAR(pObj, pData->pCtx);
102 if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pObj))
103 crHashtableDelete(pData->s->rbTable, key, crStateFreeRBO);
104}
105#endif
106/**
107 * Decrement shared state's refcount and delete when it hits zero.
108 */
109DECLEXPORT(void)
110crStateFreeShared(CRContext *pContext, CRSharedState *s)
111{
112 s->refCount--;
113 if (s->refCount <= 0) {
114 if (s==gSharedState)
115 {
116 gSharedState = NULL;
117 }
118 crFreeHashtable(s->textureTable, DeleteTextureCallback);
119 crFreeHashtable(s->dlistTable, crFree); /* call crFree for each entry */
120 crFreeHashtable(s->buffersTable, crStateFreeBufferObject);
121 crFreeHashtable(s->fbTable, crStateFreeFBO);
122 crFreeHashtable(s->rbTable, crStateFreeRBO);
123 crFree(s);
124 }
125#ifndef IN_GUEST
126 else
127 {
128 /* evaluate usage bits*/
129 CR_STATE_RELEASEOBJ CbData;
130 CbData.pCtx = pContext;
131 CbData.s = s;
132 crHashtableWalk(s->textureTable, ReleaseTextureCallback, &CbData);
133 crHashtableWalk(s->buffersTable, ReleaseBufferObjectCallback , &CbData);
134 crHashtableWalk(s->fbTable, ReleaseFBOCallback, &CbData);
135 crHashtableWalk(s->rbTable, ReleaseRBOCallback, &CbData);
136 }
137#endif
138}
139
140DECLEXPORT(void) STATE_APIENTRY
141crStateShareContext(GLboolean value)
142{
143 CRContext *pCtx = GetCurrentContext();
144 CRASSERT(pCtx && pCtx->shared);
145
146 if (value)
147 {
148 if (pCtx->shared == gSharedState)
149 {
150 return;
151 }
152
153 crDebug("Context(%i) shared", pCtx->id);
154
155 if (!gSharedState)
156 {
157 gSharedState = pCtx->shared;
158 }
159 else
160 {
161 crStateFreeShared(pCtx, pCtx->shared);
162 pCtx->shared = gSharedState;
163 gSharedState->refCount++;
164 }
165 }
166 else
167 {
168 if (pCtx->shared != gSharedState)
169 {
170 return;
171 }
172
173 crDebug("Context(%i) unshared", pCtx->id);
174
175 if (gSharedState->refCount==1)
176 {
177 gSharedState = NULL;
178 }
179 else
180 {
181 pCtx->shared = crStateAllocShared();
182 pCtx->shared->id = pCtx->id;
183 crStateFreeShared(pCtx, gSharedState);
184 }
185 }
186}
187
188DECLEXPORT(GLboolean) STATE_APIENTRY
189crStateContextIsShared(CRContext *pCtx)
190{
191 return pCtx->shared==gSharedState;
192}
193
194DECLEXPORT(void) STATE_APIENTRY
195crStateSetSharedContext(CRContext *pCtx)
196{
197 if (gSharedState)
198 {
199 crWarning("crStateSetSharedContext: shared is being changed from %p to %p", gSharedState, pCtx->shared);
200 }
201
202 gSharedState = pCtx->shared;
203}
204
205#ifdef CHROMIUM_THREADSAFE
206static void
207crStateFreeContext(CRContext *ctx);
208static DECLCALLBACK(void) crStateContextDtor(void *pvCtx)
209{
210 crStateFreeContext((CRContext*)pvCtx);
211}
212#endif
213
214/*
215 * Helper for crStateCreateContext, below.
216 */
217static CRContext *
218crStateCreateContextId(int i, const CRLimitsState *limits,
219 GLint visBits, CRContext *shareCtx)
220{
221 CRContext *ctx = (CRContext *) crCalloc( sizeof( *ctx ) );
222 int j;
223 int node32 = i >> 5;
224 int node = i & 0x1f;
225
226 ctx->id = i;
227#ifdef CHROMIUM_THREADSAFE
228 VBoxTlsRefInit(ctx, crStateContextDtor);
229#endif
230 ctx->flush_func = NULL;
231 for (j=0;j<CR_MAX_BITARRAY;j++){
232 if (j == node32) {
233 ctx->bitid[j] = (1 << node);
234 } else {
235 ctx->bitid[j] = 0;
236 }
237 ctx->neg_bitid[j] = ~(ctx->bitid[j]);
238 }
239
240 if (shareCtx) {
241 CRASSERT(shareCtx->shared);
242 ctx->shared = shareCtx->shared;
243 ctx->shared->refCount ++;
244 }
245 else {
246 ctx->shared = crStateAllocShared();
247 ctx->shared->id = ctx->id;
248 }
249
250 /* use Chromium's OpenGL defaults */
251 crStateLimitsInit( &(ctx->limits) );
252 crStateExtensionsInit( &(ctx->limits), &(ctx->extensions) );
253
254 crStateBufferObjectInit( ctx ); /* must precede client state init! */
255 crStateClientInit( &(ctx->client) );
256
257 crStateBufferInit( ctx );
258 crStateCurrentInit( ctx );
259 crStateEvaluatorInit( ctx );
260 crStateFogInit( ctx );
261 crStateHintInit( ctx );
262 crStateLightingInit( ctx );
263 crStateLineInit( ctx );
264 crStateListsInit( ctx );
265 crStateMultisampleInit( ctx );
266 crStateOcclusionInit( ctx );
267 crStatePixelInit( ctx );
268 crStatePolygonInit( ctx );
269 crStatePointInit( ctx );
270 crStateProgramInit( ctx );
271 crStateRegCombinerInit( ctx );
272 crStateStencilInit( ctx );
273 crStateTextureInit( ctx );
274 crStateTransformInit( ctx );
275 crStateViewportInit ( ctx );
276 crStateFramebufferObjectInit(ctx);
277 crStateGLSLInit(ctx);
278
279 /* This has to come last. */
280 crStateAttribInit( &(ctx->attrib) );
281
282 ctx->renderMode = GL_RENDER;
283
284 /* Initialize values that depend on the visual mode */
285 if (visBits & CR_DOUBLE_BIT) {
286 ctx->limits.doubleBuffer = GL_TRUE;
287 }
288 if (visBits & CR_RGB_BIT) {
289 ctx->limits.redBits = 8;
290 ctx->limits.greenBits = 8;
291 ctx->limits.blueBits = 8;
292 if (visBits & CR_ALPHA_BIT) {
293 ctx->limits.alphaBits = 8;
294 }
295 }
296 else {
297 ctx->limits.indexBits = 8;
298 }
299 if (visBits & CR_DEPTH_BIT) {
300 ctx->limits.depthBits = 24;
301 }
302 if (visBits & CR_STENCIL_BIT) {
303 ctx->limits.stencilBits = 8;
304 }
305 if (visBits & CR_ACCUM_BIT) {
306 ctx->limits.accumRedBits = 16;
307 ctx->limits.accumGreenBits = 16;
308 ctx->limits.accumBlueBits = 16;
309 if (visBits & CR_ALPHA_BIT) {
310 ctx->limits.accumAlphaBits = 16;
311 }
312 }
313 if (visBits & CR_STEREO_BIT) {
314 ctx->limits.stereo = GL_TRUE;
315 }
316 if (visBits & CR_MULTISAMPLE_BIT) {
317 ctx->limits.sampleBuffers = 1;
318 ctx->limits.samples = 4;
319 ctx->multisample.enabled = GL_TRUE;
320 }
321
322 if (visBits & CR_OVERLAY_BIT) {
323 ctx->limits.level = 1;
324 }
325
326 return ctx;
327}
328
329/*@todo crStateAttribDestroy*/
330static void
331crStateFreeContext(CRContext *ctx)
332{
333 crStateClientDestroy( &(ctx->client) );
334 crStateLimitsDestroy( &(ctx->limits) );
335 crStateBufferObjectDestroy( ctx );
336 crStateEvaluatorDestroy( ctx );
337 crStateListsDestroy( ctx );
338 crStateLightingDestroy( ctx );
339 crStateOcclusionDestroy( ctx );
340 crStateProgramDestroy( ctx );
341 crStateTextureDestroy( ctx );
342 crStateTransformDestroy( ctx );
343 crStateFreeShared(ctx, ctx->shared);
344 crStateFramebufferObjectDestroy(ctx);
345 crStateGLSLDestroy(ctx);
346 if (ctx->buffer.pFrontImg) crFree(ctx->buffer.pFrontImg);
347 if (ctx->buffer.pBackImg) crFree(ctx->buffer.pBackImg);
348 crFree( ctx );
349}
350
351#ifdef CHROMIUM_THREADSAFE
352# ifndef RT_OS_WINDOWS
353static DECLCALLBACK(void) crStateThreadTlsDtor(void *pvValue)
354{
355 CRContext *pCtx = (CRContext*)pvValue;
356 VBoxTlsRefRelease(pCtx);
357}
358# endif
359#endif
360
361/*
362 * Allocate the state (dirty) bits data structures.
363 * This should be called before we create any contexts.
364 * We'll also create the default/NULL context at this time and make
365 * it the current context by default. This means that if someone
366 * tries to set GL state before calling MakeCurrent() they'll be
367 * modifying the default state object, and not segfaulting on a NULL
368 * pointer somewhere.
369 */
370void crStateInit(void)
371{
372 unsigned int i;
373
374 /* Purely initialize the context bits */
375 if (!__currentBits) {
376 __currentBits = (CRStateBits *) crCalloc( sizeof(CRStateBits) );
377 crStateClientInitBits( &(__currentBits->client) );
378 crStateLightingInitBits( &(__currentBits->lighting) );
379 } else
380 crWarning("State tracker is being re-initialized..\n");
381
382 for (i=0;i<CR_MAX_CONTEXTS;i++)
383 g_availableContexts[i] = 0;
384
385#ifdef CHROMIUM_THREADSAFE
386 if (!__isContextTLSInited)
387 {
388# ifndef RT_OS_WINDOWS
389 /* tls destructor is implemented for all platforms except windows*/
390 crInitTSDF(&__contextTSD, crStateThreadTlsDtor);
391# else
392 /* windows should do cleanup via DllMain THREAD_DETACH notification */
393 crInitTSD(&__contextTSD);
394# endif
395 __isContextTLSInited = 1;
396 }
397#endif
398
399 if (defaultContext) {
400 /* Free the default/NULL context.
401 * Ensures context bits are reset */
402#ifdef CHROMIUM_THREADSAFE
403 SetCurrentContext(NULL);
404 VBoxTlsRefRelease(defaultContext);
405#else
406 crStateFreeContext(defaultContext);
407 __currentContext = NULL;
408#endif
409 }
410
411 /* Reset diff_api */
412 crMemZero(&diff_api, sizeof(SPUDispatchTable));
413
414 /* Allocate the default/NULL context */
415 defaultContext = crStateCreateContextId(0, NULL, CR_RGB_BIT, NULL);
416 CRASSERT(g_availableContexts[0] == 0);
417 g_availableContexts[0] = 1; /* in use forever */
418
419#ifdef CHROMIUM_THREADSAFE
420 SetCurrentContext(defaultContext);
421#else
422 __currentContext = defaultContext;
423#endif
424}
425
426void crStateDestroy(void)
427{
428 if (__currentBits)
429 {
430 crStateClientDestroyBits(&(__currentBits->client));
431 crStateLightingDestroyBits(&(__currentBits->lighting));
432 crFree(__currentBits);
433 __currentBits = NULL;
434 }
435
436#ifdef CHROMIUM_THREADSAFE
437 crFreeTSD(&__contextTSD);
438 __isContextTLSInited = 0;
439#endif
440}
441
442/*
443 * Notes on context switching and the "default context".
444 *
445 * See the paper "Tracking Graphics State for Networked Rendering"
446 * by Ian Buck, Greg Humphries and Pat Hanrahan for background
447 * information about how the state tracker and context switching
448 * works.
449 *
450 * When we make a new context current, we call crStateSwitchContext()
451 * in order to transform the 'from' context into the 'to' context
452 * (i.e. the old context to the new context). The transformation
453 * is accomplished by calling GL functions through the 'diff_api'
454 * so that the downstream GL machine (represented by the __currentContext
455 * structure) is updated to reflect the new context state. Finally,
456 * we point __currentContext to the new context.
457 *
458 * A subtle problem we have to deal with is context destruction.
459 * This issue arose while testing with Glean. We found that when
460 * the currently bound context was getting destroyed that state
461 * tracking was incorrect when a subsequent new context was activated.
462 * In DestroyContext, the __hwcontext was being set to NULL and effectively
463 * going away. Later in MakeCurrent we had no idea what the state of the
464 * downstream GL machine was (since __hwcontext was gone). This meant
465 * we had nothing to 'diff' against and the downstream GL machine was
466 * in an unknown state.
467 *
468 * The solution to this problem is the "default/NULL" context. The
469 * default context is created the first time CreateContext is called
470 * and is never freed. Whenever we get a crStateMakeCurrent(NULL) call
471 * or destroy the currently bound context in crStateDestroyContext()
472 * we call crStateSwitchContext() to switch to the default context and
473 * then set the __currentContext pointer to point to the default context.
474 * This ensures that the dirty bits are updated and the diff_api functions
475 * are called to keep the downstream GL machine in a known state.
476 * Finally, the __hwcontext variable is no longer needed now.
477 *
478 * Yeah, this is kind of a mind-bender, but it really solves the problem
479 * pretty cleanly.
480 *
481 * -Brian
482 */
483
484
485CRContext *
486crStateCreateContext(const CRLimitsState *limits, GLint visBits, CRContext *share)
487{
488 int i;
489
490 /* Must have created the default context via crStateInit() first */
491 CRASSERT(defaultContext);
492
493 for (i = 1 ; i < CR_MAX_CONTEXTS ; i++)
494 {
495 if (!g_availableContexts[i])
496 {
497 g_availableContexts[i] = 1; /* it's no longer available */
498 return crStateCreateContextId( i, limits, visBits, share );
499 }
500 }
501 crError( "Out of available contexts in crStateCreateContexts (max %d)",
502 CR_MAX_CONTEXTS );
503 /* never get here */
504 return NULL;
505}
506
507CRContext *
508crStateCreateContextEx(const CRLimitsState *limits, GLint visBits, CRContext *share, GLint presetID)
509{
510 if (presetID>0)
511 {
512 CRASSERT(!g_availableContexts[presetID]);
513 g_availableContexts[presetID] = 1;
514 return crStateCreateContextId(presetID, limits, visBits, share);
515 }
516 else return crStateCreateContext(limits, visBits, share);
517}
518
519void crStateDestroyContext( CRContext *ctx )
520{
521 CRContext *current = GetCurrentContext();
522
523 if (current == ctx) {
524 /* destroying the current context - have to be careful here */
525 CRASSERT(defaultContext);
526 /* Check to see if the differencer exists first,
527 we may not have one, aka the packspu */
528 if (diff_api.AlphaFunc)
529 crStateSwitchContext(current, defaultContext);
530#ifdef CHROMIUM_THREADSAFE
531 SetCurrentContext(defaultContext);
532#else
533 __currentContext = defaultContext;
534#endif
535 /* ensure matrix state is also current */
536 crStateMatrixMode(defaultContext->transform.matrixMode);
537 }
538 g_availableContexts[ctx->id] = 0;
539
540#ifdef CHROMIUM_THREADSAFE
541 VBoxTlsRefRelease(ctx);
542#else
543 crStateFreeContext(ctx);
544#endif
545}
546
547GLboolean crStateEnableDiffOnMakeCurrent(GLboolean fEnable)
548{
549 GLboolean bOld = g_bVBoxEnableDiffOnMakeCurrent;
550 g_bVBoxEnableDiffOnMakeCurrent = fEnable;
551 return bOld;
552}
553
554void crStateMakeCurrent( CRContext *ctx )
555{
556 CRContext *current = GetCurrentContext();
557
558 if (ctx == NULL)
559 ctx = defaultContext;
560
561 if (current == ctx)
562 return; /* no-op */
563
564 CRASSERT(ctx);
565
566 if (g_bVBoxEnableDiffOnMakeCurrent && current) {
567 /* Check to see if the differencer exists first,
568 we may not have one, aka the packspu */
569 if (diff_api.AlphaFunc)
570 crStateSwitchContext( current, ctx );
571 }
572
573#ifdef CHROMIUM_THREADSAFE
574 SetCurrentContext(ctx);
575#else
576 __currentContext = ctx;
577#endif
578
579 /* ensure matrix state is also current */
580 crStateMatrixMode(ctx->transform.matrixMode);
581}
582
583
584/*
585 * As above, but don't call crStateSwitchContext().
586 */
587void crStateSetCurrent( CRContext *ctx )
588{
589 CRContext *current = GetCurrentContext();
590
591 if (ctx == NULL)
592 ctx = defaultContext;
593
594 if (current == ctx)
595 return; /* no-op */
596
597 CRASSERT(ctx);
598
599#ifdef CHROMIUM_THREADSAFE
600 SetCurrentContext(ctx);
601#else
602 __currentContext = ctx;
603#endif
604
605 /* ensure matrix state is also current */
606 crStateMatrixMode(ctx->transform.matrixMode);
607}
608
609
610CRContext *crStateGetCurrent(void)
611{
612 return GetCurrentContext();
613}
614
615
616void crStateUpdateColorBits(void)
617{
618 /* This is a hack to force updating the 'current' attribs */
619 CRStateBits *sb = GetCurrentBits();
620 FILLDIRTY(sb->current.dirty);
621 FILLDIRTY(sb->current.vertexAttrib[VERT_ATTRIB_COLOR0]);
622}
623
624
625void STATE_APIENTRY
626crStateChromiumParameteriCR( GLenum target, GLint value )
627{
628 /* This no-op function helps smooth code-gen */
629}
630
631void STATE_APIENTRY
632crStateChromiumParameterfCR( GLenum target, GLfloat value )
633{
634 /* This no-op function helps smooth code-gen */
635}
636
637void STATE_APIENTRY
638crStateChromiumParametervCR( GLenum target, GLenum type, GLsizei count, const GLvoid *values )
639{
640 /* This no-op function helps smooth code-gen */
641}
642
643void STATE_APIENTRY
644crStateGetChromiumParametervCR( GLenum target, GLuint index, GLenum type, GLsizei count, GLvoid *values )
645{
646 /* This no-op function helps smooth code-gen */
647}
648
649void STATE_APIENTRY
650crStateReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
651 GLenum format, GLenum type, GLvoid *pixels )
652{
653 /* This no-op function helps smooth code-gen */
654}
655
656void crStateVBoxDetachThread()
657{
658 /* release the context ref so that it can be freed */
659 SetCurrentContext(NULL);
660}
661
662
663void crStateVBoxAttachThread()
664{
665}
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