VirtualBox

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

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

crOpenGL: more threading fixes

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