VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c@ 44390

Last change on this file since 44390 was 44390, checked in by vboxsync, 12 years ago

crOpenGL: more context cleanup fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.8 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 "cr_spu.h"
8#include "chromium.h"
9#include "cr_error.h"
10#include "cr_net.h"
11#include "cr_rand.h"
12#include "server_dispatch.h"
13#include "server.h"
14#include "cr_mem.h"
15#include "cr_string.h"
16
17GLint SERVER_DISPATCH_APIENTRY
18crServerDispatchCreateContext(const char *dpyName, GLint visualBits, GLint shareCtx)
19{
20 return crServerDispatchCreateContextEx(dpyName, visualBits, shareCtx, -1, -1);
21}
22
23GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLint shareCtx, GLint preloadCtxID, int32_t internalID)
24{
25 GLint retVal = -1;
26 CRContext *newCtx;
27 CRContextInfo *pContextInfo;
28 GLboolean fFirst = GL_FALSE;
29
30 if (shareCtx > 0) {
31 crWarning("CRServer: context sharing not implemented.");
32 shareCtx = 0;
33 }
34
35 pContextInfo = (CRContextInfo *) crAlloc(sizeof (CRContextInfo));
36 if (!pContextInfo)
37 {
38 crWarning("failed to alloc context info!");
39 return -1;
40 }
41
42 pContextInfo->currentMural = NULL;
43
44 pContextInfo->CreateInfo.visualBits = visualBits;
45
46 /* Since the Cr server serialized all incoming clients/contexts into
47 * one outgoing GL stream, we only need to create one context for the
48 * head SPU. We'll only have to make it current once too, below.
49 */
50 if (cr_server.firstCallCreateContext) {
51 cr_server.MainContextInfo.CreateInfo.visualBits = visualBits;
52 cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table.
53 CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.visualBits, shareCtx);
54 if (cr_server.MainContextInfo.SpuContext < 0) {
55 crWarning("crServerDispatchCreateContext() failed.");
56 crFree(pContextInfo);
57 return -1;
58 }
59 cr_server.MainContextInfo.pContext = crStateCreateContext(&cr_server.limits, visualBits, NULL);
60 CRASSERT(cr_server.MainContextInfo.pContext);
61 cr_server.firstCallCreateContext = GL_FALSE;
62 fFirst = GL_TRUE;
63 }
64 else {
65 /* second or third or ... context */
66 if (!cr_server.bUseMultipleContexts && ((visualBits & cr_server.MainContextInfo.CreateInfo.visualBits) != visualBits)) {
67 int oldSpuContext;
68
69 /* the new context needs new visual attributes */
70 cr_server.MainContextInfo.CreateInfo.visualBits |= visualBits;
71 crDebug("crServerDispatchCreateContext requires new visual (0x%x).",
72 cr_server.MainContextInfo.CreateInfo.visualBits);
73
74 /* Here, we used to just destroy the old rendering context.
75 * Unfortunately, this had the side effect of destroying
76 * all display lists and textures that had been loaded on
77 * the old context as well.
78 *
79 * Now, first try to create a new context, with a suitable
80 * visual, sharing display lists and textures with the
81 * old context. Then destroy the old context.
82 */
83
84 /* create new rendering context with suitable visual */
85 oldSpuContext = cr_server.MainContextInfo.SpuContext;
86 cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table.
87 CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.visualBits, cr_server.MainContextInfo.SpuContext);
88 /* destroy old rendering context */
89 cr_server.head_spu->dispatch_table.DestroyContext(oldSpuContext);
90 if (cr_server.MainContextInfo.SpuContext < 0) {
91 crWarning("crServerDispatchCreateContext() failed.");
92 crFree(pContextInfo);
93 return -1;
94 }
95 }
96 }
97
98 if (cr_server.bUseMultipleContexts) {
99 pContextInfo->SpuContext = cr_server.head_spu->dispatch_table.
100 CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.visualBits, cr_server.MainContextInfo.SpuContext);
101 if (pContextInfo->SpuContext < 0) {
102 crWarning("crServerDispatchCreateContext() failed.");
103 crStateEnableDiffOnMakeCurrent(GL_TRUE);
104 cr_server.bUseMultipleContexts = GL_FALSE;
105 if (!fFirst)
106 crError("creating shared context failed, while it is expected to work!");
107 }
108 else if (fFirst)
109 {
110 crStateEnableDiffOnMakeCurrent(GL_FALSE);
111 }
112 }
113 else
114 {
115 pContextInfo->SpuContext = -1;
116 }
117
118 /* Now create a new state-tracker context and initialize the
119 * dispatch function pointers.
120 */
121 newCtx = crStateCreateContextEx(&cr_server.limits, visualBits, NULL, internalID);
122 if (newCtx) {
123 crStateSetCurrentPointers( newCtx, &(cr_server.current) );
124 crStateResetCurrentPointers(&(cr_server.current));
125 retVal = preloadCtxID<0 ? (GLint)crHashtableAllocKeys( cr_server.contextTable, 1 ) : preloadCtxID;
126
127 pContextInfo->pContext = newCtx;
128 pContextInfo->CreateInfo.visualBits = visualBits;
129 pContextInfo->CreateInfo.externalID = retVal;
130 pContextInfo->CreateInfo.pszDpyName = dpyName ? crStrdup(dpyName) : NULL;
131 crHashtableAdd(cr_server.contextTable, retVal, pContextInfo);
132 }
133
134 if (retVal != -1 && !cr_server.bIsInLoadingState) {
135 int pos;
136 for (pos = 0; pos < CR_MAX_CONTEXTS; pos++) {
137 if (cr_server.curClient->contextList[pos] == 0) {
138 cr_server.curClient->contextList[pos] = retVal;
139 break;
140 }
141 }
142 }
143
144 crServerReturnValue( &retVal, sizeof(retVal) );
145
146 return retVal;
147}
148
149static int crServerRemoveClientContext(CRClient *pClient, GLint ctx)
150{
151 int pos;
152
153 for (pos = 0; pos < CR_MAX_CONTEXTS; ++pos)
154 {
155 if (pClient->contextList[pos] == ctx)
156 {
157 pClient->contextList[pos] = 0;
158 return true;
159 }
160 }
161
162 return false;
163}
164
165static void crServerCleanupMuralCtxUsageCB(unsigned long key, void *data1, void *data2)
166{
167 CRMuralInfo *mural = (CRMuralInfo *) data1;
168 CRContext *ctx = (CRContext *) data2;
169
170 CR_STATE_SHAREDOBJ_USAGE_CLEAR(mural, ctx);
171}
172
173void SERVER_DISPATCH_APIENTRY
174crServerDispatchDestroyContext( GLint ctx )
175{
176 CRContextInfo *crCtxInfo;
177 CRContext *crCtx;
178 int32_t client;
179 CRClientNode *pNode;
180 int found=false;
181
182 crCtxInfo = (CRContextInfo *) crHashtableSearch(cr_server.contextTable, ctx);
183 if (!crCtxInfo) {
184 crWarning("CRServer: DestroyContext invalid context %d", ctx);
185 return;
186 }
187 crCtx = crCtxInfo->pContext;
188 CRASSERT(crCtx);
189
190 crDebug("CRServer: DestroyContext context %d", ctx);
191
192 if (cr_server.currentCtxInfo == crCtxInfo)
193 {
194 CRMuralInfo *dummyMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
195 crServerPerformMakeCurrent(dummyMural, &cr_server.MainContextInfo);
196 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
197 }
198
199 crHashtableWalk(cr_server.muralTable, crServerCleanupMuralCtxUsageCB, crCtx);
200 crCtxInfo->currentMural = NULL;
201 crHashtableDelete(cr_server.contextTable, ctx, NULL);
202 crStateDestroyContext( crCtx );
203
204 if (crCtxInfo->CreateInfo.pszDpyName)
205 crFree(crCtxInfo->CreateInfo.pszDpyName);
206
207 if (crCtxInfo->SpuContext >= 0)
208 cr_server.head_spu->dispatch_table.DestroyContext(crCtxInfo->SpuContext);
209
210 crFree(crCtxInfo);
211
212 if (cr_server.curClient)
213 {
214 /* If we delete our current context, default back to the null context */
215 if (cr_server.curClient->currentCtxInfo == crCtxInfo) {
216 cr_server.curClient->currentContextNumber = -1;
217 cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
218 }
219
220 found = crServerRemoveClientContext(cr_server.curClient, ctx);
221
222 /*Some application call destroy context not in a thread where it was created...have do deal with it.*/
223 if (!found)
224 {
225 for (client=0; client<cr_server.numClients; ++client)
226 {
227 if (cr_server.clients[client]==cr_server.curClient)
228 continue;
229
230 found = crServerRemoveClientContext(cr_server.clients[client], ctx);
231
232 if (found) break;
233 }
234 }
235
236 if (!found)
237 {
238 pNode=cr_server.pCleanupClient;
239
240 while (pNode && !found)
241 {
242 found = crServerRemoveClientContext(pNode->pClient, ctx);
243 pNode = pNode->next;
244 }
245 }
246
247 CRASSERT(found);
248 }
249
250 /*Make sure this context isn't active in other clients*/
251 for (client=0; client<cr_server.numClients; ++client)
252 {
253 if (cr_server.clients[client]->currentCtxInfo == crCtxInfo)
254 {
255 cr_server.clients[client]->currentContextNumber = -1;
256 cr_server.clients[client]->currentCtxInfo = &cr_server.MainContextInfo;
257 }
258 }
259
260 pNode=cr_server.pCleanupClient;
261 while (pNode)
262 {
263 if (pNode->pClient->currentCtxInfo == crCtxInfo)
264 {
265 pNode->pClient->currentContextNumber = -1;
266 pNode->pClient->currentCtxInfo = &cr_server.MainContextInfo;
267 }
268 pNode = pNode->next;
269 }
270
271 CRASSERT(cr_server.currentCtxInfo != crCtxInfo);
272}
273
274void crServerPerformMakeCurrent( CRMuralInfo *mural, CRContextInfo *ctxInfo )
275{
276 CRMuralInfo *oldMural;
277 CRContext *ctx, *oldCtx = NULL;
278 GLuint idDrawFBO, idReadFBO;
279 GLint context = ctxInfo->CreateInfo.externalID;
280 GLint window = mural->CreateInfo.externalID;
281
282 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
283
284 ctx = ctxInfo->pContext;
285 CRASSERT(ctx);
286
287 oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow);
288
289 /* Ubuntu 11.04 hosts misbehave if context window switch is
290 * done with non-default framebuffer object settings.
291 * crStateSwitchPrepare & crStateSwitchPostprocess are supposed to work around this problem
292 * crStateSwitchPrepare restores the FBO state to its default values before the context window switch,
293 * while crStateSwitchPostprocess restores it back to the original values */
294 oldCtx = crStateGetCurrent();
295 if (oldMural && oldMural->fUseFBO && crServerSupportRedirMuralFBO())
296 {
297 idDrawFBO = oldMural->aidFBOs[oldMural->iCurDrawBuffer];
298 idReadFBO = oldMural->aidFBOs[oldMural->iCurReadBuffer];
299 }
300 else
301 {
302 idDrawFBO = 0;
303 idReadFBO = 0;
304 }
305 crStateSwitchPrepare(cr_server.bUseMultipleContexts ? NULL : ctx, oldCtx, idDrawFBO, idReadFBO);
306
307 /*
308 crDebug("**** %s client %d curCtx=%d curWin=%d", __func__,
309 cr_server.curClient->number, ctxPos, window);
310 */
311 cr_server.curClient->currentContextNumber = context;
312 cr_server.curClient->currentCtxInfo = ctxInfo;
313 cr_server.curClient->currentMural = mural;
314 cr_server.curClient->currentWindow = window;
315
316 CRASSERT(cr_server.curClient->currentCtxInfo);
317 CRASSERT(cr_server.curClient->currentCtxInfo->pContext);
318
319 /* This is a hack to force updating the 'current' attribs */
320 crStateUpdateColorBits();
321
322 if (ctx)
323 crStateSetCurrentPointers( ctx, &(cr_server.current) );
324
325 /* check if being made current for first time, update viewport */
326#if 0
327 if (ctx) {
328 /* initialize the viewport */
329 if (ctx->viewport.viewportW == 0) {
330 ctx->viewport.viewportW = mural->width;
331 ctx->viewport.viewportH = mural->height;
332 ctx->viewport.scissorW = mural->width;
333 ctx->viewport.scissorH = mural->height;
334 }
335 }
336#endif
337
338 /*
339 crDebug("**** %s currentWindow %d newWindow %d", __func__,
340 cr_server.currentWindow, window);
341 */
342
343 if (1/*cr_server.firstCallMakeCurrent ||
344 cr_server.currentWindow != window ||
345 cr_server.currentNativeWindow != nativeWindow*/) {
346 /* Since the cr server serialized all incoming contexts/clients into
347 * one output stream of GL commands, we only need to call the head
348 * SPU's MakeCurrent() function once.
349 * BUT, if we're rendering to multiple windows, we do have to issue
350 * MakeCurrent() calls sometimes. The same GL context will always be
351 * used though.
352 */
353 cr_server.head_spu->dispatch_table.MakeCurrent( mural->spuWindow,
354 0,
355 ctxInfo->SpuContext >= 0
356 ? ctxInfo->SpuContext
357 : cr_server.MainContextInfo.SpuContext);
358
359 CR_STATE_SHAREDOBJ_USAGE_SET(mural, ctx);
360 if (cr_server.currentCtxInfo)
361 cr_server.currentCtxInfo->currentMural = NULL;
362 ctxInfo->currentMural = mural;
363
364 cr_server.firstCallMakeCurrent = GL_FALSE;
365 cr_server.currentCtxInfo = ctxInfo;
366 cr_server.currentWindow = window;
367 cr_server.currentNativeWindow = 0;
368 cr_server.currentMural = mural;
369 }
370
371 /* This used to be earlier, after crStateUpdateColorBits() call */
372 crStateMakeCurrent( ctx );
373
374 if (mural && mural->fUseFBO && crServerSupportRedirMuralFBO())
375 {
376 GLuint id = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer);
377 if (id != mural->iCurDrawBuffer)
378 {
379 crWarning("DBO draw buffer changed on make current");
380 mural->iCurDrawBuffer = id;
381 }
382
383 id = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer);
384 if (id != mural->iCurReadBuffer)
385 {
386 crWarning("DBO read buffer changed on make current");
387 mural->iCurReadBuffer = id;
388 }
389
390 idDrawFBO = mural->aidFBOs[mural->iCurDrawBuffer];
391 idReadFBO = mural->aidFBOs[mural->iCurReadBuffer];
392 }
393 else
394 {
395 idDrawFBO = 0;
396 idReadFBO = 0;
397 }
398 crStateSwitchPostprocess(ctx, cr_server.bUseMultipleContexts ? NULL : oldCtx, idDrawFBO, idReadFBO);
399
400 if (!ctx->framebufferobject.drawFB
401 && (ctx->buffer.drawBuffer == GL_FRONT || ctx->buffer.drawBuffer == GL_FRONT_LEFT))
402 cr_server.curClient->currentMural->bFbDraw = GL_TRUE;
403
404 if (!mural->fUseFBO)
405 {
406 ctx->buffer.width = mural->width;
407 ctx->buffer.height = mural->height;
408 }
409 else
410 {
411 ctx->buffer.width = 0;
412 ctx->buffer.height = 0;
413 }
414}
415
416
417void SERVER_DISPATCH_APIENTRY
418crServerDispatchMakeCurrent( GLint window, GLint nativeWindow, GLint context )
419{
420 CRMuralInfo *mural;
421 CRContextInfo *ctxInfo = NULL;
422
423 if (context >= 0 && window >= 0) {
424 mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
425 if (!mural)
426 {
427 crWarning("CRServer: invalid window %d passed to crServerDispatchMakeCurrent()", window);
428 return;
429 }
430
431 /* Update the state tracker's current context */
432 ctxInfo = (CRContextInfo *) crHashtableSearch(cr_server.contextTable, context);
433 if (!ctxInfo) {
434 crWarning("CRserver: NULL context in MakeCurrent %d", context);
435 return;
436 }
437 }
438 else {
439#if 0
440 oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow);
441 if (oldMural && oldMural->bUseFBO && crServerSupportRedirMuralFBO())
442 {
443 if (!crStateGetCurrent()->framebufferobject.drawFB)
444 {
445 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
446 }
447 if (!crStateGetCurrent()->framebufferobject.readFB)
448 {
449 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0);
450 }
451 }
452
453 ctxInfo = &cr_server.MainContextInfo;
454 window = -1;
455 mural = NULL;
456#endif
457 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
458 return;
459 }
460
461 crServerPerformMakeCurrent( mural, ctxInfo );
462}
463
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette