VirtualBox

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

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

crOpenGL: work around Ubuntu 11.04 FBO issues

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.2 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 CRCreateInfo_t *pCreateInfo;
28
29 if (shareCtx > 0) {
30 crWarning("CRServer: context sharing not implemented.");
31 shareCtx = 0;
32 }
33
34 /* Since the Cr server serialized all incoming clients/contexts into
35 * one outgoing GL stream, we only need to create one context for the
36 * head SPU. We'll only have to make it current once too, below.
37 */
38 if (cr_server.firstCallCreateContext) {
39 cr_server.SpuContextVisBits = visualBits;
40 cr_server.SpuContext = cr_server.head_spu->dispatch_table.
41 CreateContext(dpyName, cr_server.SpuContextVisBits, shareCtx);
42 if (cr_server.SpuContext < 0) {
43 crWarning("crServerDispatchCreateContext() failed.");
44 return -1;
45 }
46 cr_server.firstCallCreateContext = GL_FALSE;
47 }
48 else {
49 /* second or third or ... context */
50 if ((visualBits & cr_server.SpuContextVisBits) != visualBits) {
51 int oldSpuContext;
52
53 /* the new context needs new visual attributes */
54 cr_server.SpuContextVisBits |= visualBits;
55 crDebug("crServerDispatchCreateContext requires new visual (0x%x).",
56 cr_server.SpuContextVisBits);
57
58 /* Here, we used to just destroy the old rendering context.
59 * Unfortunately, this had the side effect of destroying
60 * all display lists and textures that had been loaded on
61 * the old context as well.
62 *
63 * Now, first try to create a new context, with a suitable
64 * visual, sharing display lists and textures with the
65 * old context. Then destroy the old context.
66 */
67
68 /* create new rendering context with suitable visual */
69 oldSpuContext = cr_server.SpuContext;
70 cr_server.SpuContext = cr_server.head_spu->dispatch_table.
71 CreateContext(dpyName, cr_server.SpuContextVisBits, cr_server.SpuContext);
72 /* destroy old rendering context */
73 cr_server.head_spu->dispatch_table.DestroyContext(oldSpuContext);
74 if (cr_server.SpuContext < 0) {
75 crWarning("crServerDispatchCreateContext() failed.");
76 return -1;
77 }
78 }
79 }
80
81 /* Now create a new state-tracker context and initialize the
82 * dispatch function pointers.
83 */
84 newCtx = crStateCreateContextEx(&cr_server.limits, visualBits, NULL, internalID);
85 if (newCtx) {
86 crStateSetCurrentPointers( newCtx, &(cr_server.current) );
87 crStateResetCurrentPointers(&(cr_server.current));
88 retVal = preloadCtxID<0 ? crServerGenerateID(&cr_server.idsPool.freeContextID) : preloadCtxID;
89 crHashtableAdd(cr_server.contextTable, retVal, newCtx);
90
91 pCreateInfo = (CRCreateInfo_t *) crAlloc(sizeof(CRCreateInfo_t));
92 pCreateInfo->pszDpyName = dpyName ? crStrdup(dpyName) : NULL;
93 pCreateInfo->visualBits = visualBits;
94 pCreateInfo->internalID = newCtx->id;
95 crHashtableAdd(cr_server.pContextCreateInfoTable, retVal, pCreateInfo);
96 }
97
98 if (retVal != -1 && !cr_server.bIsInLoadingState) {
99 int pos;
100 for (pos = 0; pos < CR_MAX_CONTEXTS; pos++) {
101 if (cr_server.curClient->contextList[pos] == 0) {
102 cr_server.curClient->contextList[pos] = retVal;
103 break;
104 }
105 }
106 }
107
108 {
109 /* As we're using only one host context to serve all client contexts, newly created context will still
110 * hold last error value from any previous failed opengl call. Proper solution would be to redirect any
111 * client glGetError calls to our state tracker, but right now it's missing quite a lot of checks and doesn't
112 * reflect host driver/gpu specific issues. Thus we just reset last opengl error at context creation.
113 */
114 GLint err;
115
116 err = cr_server.head_spu->dispatch_table.GetError();
117 if (err!=GL_NO_ERROR)
118 {
119#ifdef DEBUG_misha
120 crDebug("Cleared gl error %#x on context creation", err);
121#else
122 crWarning("Cleared gl error %#x on context creation", err);
123#endif
124 }
125 }
126
127 crServerReturnValue( &retVal, sizeof(retVal) );
128
129 return retVal;
130}
131
132static int crServerRemoveClientContext(CRClient *pClient, GLint ctx)
133{
134 int pos;
135
136 for (pos = 0; pos < CR_MAX_CONTEXTS; ++pos)
137 {
138 if (pClient->contextList[pos] == ctx)
139 {
140 pClient->contextList[pos] = 0;
141 return true;
142 }
143 }
144
145 return false;
146}
147
148void SERVER_DISPATCH_APIENTRY
149crServerDispatchDestroyContext( GLint ctx )
150{
151 CRContext *crCtx;
152 int32_t client;
153 CRClientNode *pNode;
154 int found=false;
155
156 crCtx = (CRContext *) crHashtableSearch(cr_server.contextTable, ctx);
157 if (!crCtx) {
158 crWarning("CRServer: DestroyContext invalid context %d", ctx);
159 return;
160 }
161
162 crDebug("CRServer: DestroyContext context %d", ctx);
163
164 crHashtableDelete(cr_server.contextTable, ctx, NULL);
165 crStateDestroyContext( crCtx );
166 crHashtableDelete(cr_server.pContextCreateInfoTable, ctx, crServerCreateInfoDeleteCB);
167
168 if (cr_server.curClient)
169 {
170 /* If we delete our current context, default back to the null context */
171 if (cr_server.curClient->currentCtx == crCtx) {
172 cr_server.curClient->currentContextNumber = -1;
173 cr_server.curClient->currentCtx = cr_server.DummyContext;
174 }
175
176 found = crServerRemoveClientContext(cr_server.curClient, ctx);
177
178 /*Some application call destroy context not in a thread where it was created...have do deal with it.*/
179 if (!found)
180 {
181 for (client=0; client<cr_server.numClients; ++client)
182 {
183 if (cr_server.clients[client]==cr_server.curClient)
184 continue;
185
186 found = crServerRemoveClientContext(cr_server.clients[client], ctx);
187
188 if (found) break;
189 }
190 }
191
192 if (!found)
193 {
194 pNode=cr_server.pCleanupClient;
195
196 while (pNode && !found)
197 {
198 found = crServerRemoveClientContext(pNode->pClient, ctx);
199 pNode = pNode->next;
200 }
201 }
202
203 CRASSERT(found);
204 }
205
206 /*Make sure this context isn't active in other clients*/
207 for (client=0; client<cr_server.numClients; ++client)
208 {
209 if (cr_server.clients[client]->currentCtx == crCtx)
210 {
211 cr_server.clients[client]->currentContextNumber = -1;
212 cr_server.clients[client]->currentCtx = cr_server.DummyContext;
213 }
214 }
215
216 pNode=cr_server.pCleanupClient;
217 while (pNode)
218 {
219 if (pNode->pClient->currentCtx == crCtx)
220 {
221 pNode->pClient->currentContextNumber = -1;
222 pNode->pClient->currentCtx = cr_server.DummyContext;
223 }
224 pNode = pNode->next;
225 }
226}
227
228
229void SERVER_DISPATCH_APIENTRY
230crServerDispatchMakeCurrent( GLint window, GLint nativeWindow, GLint context )
231{
232 CRMuralInfo *mural, *oldMural;
233 CRContext *ctx, *oldCtx;
234
235 if (context >= 0 && window >= 0) {
236 mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
237 if (!mural)
238 {
239 crWarning("CRServer: invalid window %d passed to crServerDispatchMakeCurrent()", window);
240 return;
241 }
242
243 /* Update the state tracker's current context */
244 ctx = (CRContext *) crHashtableSearch(cr_server.contextTable, context);
245 if (!ctx) {
246 crWarning("CRserver: NULL context in MakeCurrent %d", context);
247 return;
248 }
249 }
250 else {
251 oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow);
252 if (oldMural && oldMural->bUseFBO && crServerSupportRedirMuralFBO())
253 {
254 if (!crStateGetCurrent()->framebufferobject.drawFB)
255 {
256 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
257 }
258 if (!crStateGetCurrent()->framebufferobject.readFB)
259 {
260 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0);
261 }
262 }
263
264 ctx = cr_server.DummyContext;
265 window = -1;
266 mural = NULL;
267 return;
268 }
269
270 /* Ubuntu 11.04 hosts misbehave if context window switch is
271 * done with non-default framebuffer object settings.
272 * crStateSwichPrepare & crStateSwichPostprocess are supposed to work around this problem
273 * crStateSwichPrepare restores the FBO state to its default values before the context window switch,
274 * while crStateSwichPostprocess restores it back to the original values */
275 oldCtx = crStateSwichPrepare(ctx);
276
277 /*
278 crDebug("**** %s client %d curCtx=%d curWin=%d", __func__,
279 cr_server.curClient->number, ctxPos, window);
280 */
281 cr_server.curClient->currentContextNumber = context;
282 cr_server.curClient->currentCtx = ctx;
283 cr_server.curClient->currentMural = mural;
284 cr_server.curClient->currentWindow = window;
285
286 CRASSERT(cr_server.curClient->currentCtx);
287
288 /* This is a hack to force updating the 'current' attribs */
289 crStateUpdateColorBits();
290
291 if (ctx)
292 crStateSetCurrentPointers( ctx, &(cr_server.current) );
293
294 /* check if being made current for first time, update viewport */
295#if 0
296 if (ctx) {
297 /* initialize the viewport */
298 if (ctx->viewport.viewportW == 0) {
299 ctx->viewport.viewportW = mural->width;
300 ctx->viewport.viewportH = mural->height;
301 ctx->viewport.scissorW = mural->width;
302 ctx->viewport.scissorH = mural->height;
303 }
304 }
305#endif
306
307 /*
308 crDebug("**** %s currentWindow %d newWindow %d", __func__,
309 cr_server.currentWindow, window);
310 */
311
312 oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow);
313
314 if (1/*cr_server.firstCallMakeCurrent ||
315 cr_server.currentWindow != window ||
316 cr_server.currentNativeWindow != nativeWindow*/) {
317 /* Since the cr server serialized all incoming contexts/clients into
318 * one output stream of GL commands, we only need to call the head
319 * SPU's MakeCurrent() function once.
320 * BUT, if we're rendering to multiple windows, we do have to issue
321 * MakeCurrent() calls sometimes. The same GL context will always be
322 * used though.
323 */
324 cr_server.head_spu->dispatch_table.MakeCurrent( mural->spuWindow,
325 nativeWindow,
326 cr_server.SpuContext );
327 cr_server.firstCallMakeCurrent = GL_FALSE;
328 cr_server.currentWindow = window;
329 cr_server.currentNativeWindow = nativeWindow;
330 }
331
332 /* This used to be earlier, after crStateUpdateColorBits() call */
333 crStateMakeCurrent( ctx );
334
335 crStateSwichPostprocess(oldCtx);
336
337 if (oldMural != mural && crServerSupportRedirMuralFBO())
338 {
339 if (!crStateGetCurrent()->framebufferobject.drawFB)
340 {
341 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, mural->bUseFBO ? mural->idFBO:0);
342 }
343 if (!crStateGetCurrent()->framebufferobject.readFB)
344 {
345 cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, mural->bUseFBO ? mural->idFBO:0);
346 }
347 }
348
349 if (!mural->bUseFBO)
350 {
351 ctx->buffer.width = mural->width;
352 ctx->buffer.height = mural->height;
353 }
354 else
355 {
356 ctx->buffer.width = 0;
357 ctx->buffer.height = 0;
358 }
359}
360
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