VirtualBox

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

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

crOpenGL: presentation infrastructure rework (still work in progress)

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