VirtualBox

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

Last change on this file since 48079 was 48079, checked in by vboxsync, 11 years ago

crOpenGL: proper default shared context support

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