VirtualBox

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

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

VRDP+3D: 3D rendering speedup: avoid unnecessary host GPU->guest VRAM->VRDP data transfers

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