VirtualBox

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

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

crOpenGL: fix destroyed context refference in TLS

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