VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c@ 33540

最後變更 在這個檔案從33540是 33540,由 vboxsync 提交於 14 年 前

*: spelling fixes, thanks Timeless!

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 34.8 KB
 
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 "server.h"
8#include "cr_net.h"
9#include "cr_unpack.h"
10#include "cr_error.h"
11#include "cr_glstate.h"
12#include "cr_string.h"
13#include "cr_mem.h"
14#include "cr_hash.h"
15#include "server_dispatch.h"
16#include "state/cr_texture.h"
17#include "render/renderspu.h"
18#include <signal.h>
19#include <stdlib.h>
20#define DEBUG_FP_EXCEPTIONS 0
21#if DEBUG_FP_EXCEPTIONS
22#include <fpu_control.h>
23#include <math.h>
24#endif
25#include <iprt/assert.h>
26#include <VBox/err.h>
27
28#ifdef VBOXCR_LOGFPS
29#include <iprt/timer.h>
30#endif
31
32/**
33 * \mainpage CrServerLib
34 *
35 * \section CrServerLibIntroduction Introduction
36 *
37 * Chromium consists of all the top-level files in the cr
38 * directory. The core module basically takes care of API dispatch,
39 * and OpenGL state management.
40 */
41
42
43/**
44 * CRServer global data
45 */
46CRServer cr_server;
47
48int tearingdown = 0; /* can't be static */
49
50
51/**
52 * Return pointer to server's first SPU.
53 */
54SPU*
55crServerHeadSPU(void)
56{
57 return cr_server.head_spu;
58}
59
60
61
62static void DeleteBarrierCallback( void *data )
63{
64 CRServerBarrier *barrier = (CRServerBarrier *) data;
65 crFree(barrier->waiting);
66 crFree(barrier);
67}
68
69
70static void deleteContextCallback( void *data )
71{
72 CRContext *c = (CRContext *) data;
73 crStateDestroyContext(c);
74}
75
76
77static void crServerTearDown( void )
78{
79 GLint i;
80
81 /* avoid a race condition */
82 if (tearingdown)
83 return;
84
85 tearingdown = 1;
86
87 crStateSetCurrent( NULL );
88
89 cr_server.curClient = NULL;
90 cr_server.run_queue = NULL;
91
92 crFree( cr_server.overlap_intens );
93 cr_server.overlap_intens = NULL;
94
95 /* Deallocate all semaphores */
96 crFreeHashtable(cr_server.semaphores, crFree);
97 cr_server.semaphores = NULL;
98
99 /* Deallocate all barriers */
100 crFreeHashtable(cr_server.barriers, DeleteBarrierCallback);
101 cr_server.barriers = NULL;
102
103 /* Free all context info */
104 crFreeHashtable(cr_server.contextTable, deleteContextCallback);
105
106 /* Free context/window creation info */
107 crFreeHashtable(cr_server.pContextCreateInfoTable, crServerCreateInfoDeleteCB);
108 crFreeHashtable(cr_server.pWindowCreateInfoTable, crServerCreateInfoDeleteCB);
109
110 /* Free vertex programs */
111 crFreeHashtable(cr_server.programTable, crFree);
112
113 for (i = 0; i < cr_server.numClients; i++) {
114 if (cr_server.clients[i]) {
115 CRConnection *conn = cr_server.clients[i]->conn;
116 crNetFreeConnection(conn);
117 crFree(cr_server.clients[i]);
118 }
119 }
120 cr_server.numClients = 0;
121
122#if 1
123 /* disable these two lines if trying to get stack traces with valgrind */
124 crSPUUnloadChain(cr_server.head_spu);
125 cr_server.head_spu = NULL;
126#endif
127
128 crStateDestroy();
129
130 crNetTearDown();
131}
132
133static void crServerClose( unsigned int id )
134{
135 crError( "Client disconnected!" );
136 (void) id;
137}
138
139static void crServerCleanup( int sigio )
140{
141 crServerTearDown();
142
143 tearingdown = 0;
144}
145
146
147void
148crServerSetPort(int port)
149{
150 cr_server.tcpip_port = port;
151}
152
153
154
155static void
156crPrintHelp(void)
157{
158 printf("Usage: crserver [OPTIONS]\n");
159 printf("Options:\n");
160 printf(" -mothership URL Specifies URL for contacting the mothership.\n");
161 printf(" URL is of the form [protocol://]hostname[:port]\n");
162 printf(" -port N Specifies the port number this server will listen to.\n");
163 printf(" -help Prints this information.\n");
164}
165
166
167/**
168 * Do CRServer initializations. After this, we can begin servicing clients.
169 */
170void
171crServerInit(int argc, char *argv[])
172{
173 int i;
174 char *mothership = NULL;
175 CRMuralInfo *defaultMural;
176
177 for (i = 1 ; i < argc ; i++)
178 {
179 if (!crStrcmp( argv[i], "-mothership" ))
180 {
181 if (i == argc - 1)
182 {
183 crError( "-mothership requires an argument" );
184 }
185 mothership = argv[i+1];
186 i++;
187 }
188 else if (!crStrcmp( argv[i], "-port" ))
189 {
190 /* This is the port on which we'll accept client connections */
191 if (i == argc - 1)
192 {
193 crError( "-port requires an argument" );
194 }
195 cr_server.tcpip_port = crStrToInt(argv[i+1]);
196 i++;
197 }
198 else if (!crStrcmp( argv[i], "-vncmode" ))
199 {
200 cr_server.vncMode = 1;
201 }
202 else if (!crStrcmp( argv[i], "-help" ))
203 {
204 crPrintHelp();
205 exit(0);
206 }
207 }
208
209 signal( SIGTERM, crServerCleanup );
210 signal( SIGINT, crServerCleanup );
211#ifndef WINDOWS
212 signal( SIGPIPE, SIG_IGN );
213#endif
214
215#if DEBUG_FP_EXCEPTIONS
216 {
217 fpu_control_t mask;
218 _FPU_GETCW(mask);
219 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
220 | _FPU_MASK_OM | _FPU_MASK_UM);
221 _FPU_SETCW(mask);
222 }
223#endif
224
225 cr_server.firstCallCreateContext = GL_TRUE;
226 cr_server.firstCallMakeCurrent = GL_TRUE;
227
228 /*
229 * Create default mural info and hash table.
230 */
231 cr_server.muralTable = crAllocHashtable();
232 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
233 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
234
235 cr_server.programTable = crAllocHashtable();
236
237 crNetInit(crServerRecv, crServerClose);
238 crStateInit();
239
240 crServerSetVBoxConfiguration();
241
242 crStateLimitsInit( &(cr_server.limits) );
243
244 /*
245 * Default context
246 */
247 cr_server.contextTable = crAllocHashtable();
248 cr_server.DummyContext = crStateCreateContext( &cr_server.limits,
249 CR_RGB_BIT | CR_DEPTH_BIT, NULL );
250 cr_server.curClient->currentCtx = cr_server.DummyContext;
251
252 crServerInitDispatch();
253 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
254
255 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
256 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
257
258 cr_server.barriers = crAllocHashtable();
259 cr_server.semaphores = crAllocHashtable();
260}
261
262void crVBoxServerTearDown(void)
263{
264 crServerTearDown();
265}
266
267/**
268 * Do CRServer initializations. After this, we can begin servicing clients.
269 */
270GLboolean crVBoxServerInit(void)
271{
272 CRMuralInfo *defaultMural;
273
274#if DEBUG_FP_EXCEPTIONS
275 {
276 fpu_control_t mask;
277 _FPU_GETCW(mask);
278 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
279 | _FPU_MASK_OM | _FPU_MASK_UM);
280 _FPU_SETCW(mask);
281 }
282#endif
283
284 crNetInit(crServerRecv, crServerClose);
285
286 cr_server.firstCallCreateContext = GL_TRUE;
287 cr_server.firstCallMakeCurrent = GL_TRUE;
288
289 cr_server.bIsInLoadingState = GL_FALSE;
290 cr_server.bIsInSavingState = GL_FALSE;
291
292 /*
293 * Create default mural info and hash table.
294 */
295 cr_server.muralTable = crAllocHashtable();
296 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
297 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
298
299 cr_server.programTable = crAllocHashtable();
300
301 crStateInit();
302
303 crStateLimitsInit( &(cr_server.limits) );
304
305 cr_server.barriers = crAllocHashtable();
306 cr_server.semaphores = crAllocHashtable();
307
308 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
309 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
310
311 /*
312 * Default context
313 */
314 cr_server.contextTable = crAllocHashtable();
315 cr_server.DummyContext = crStateCreateContext( &cr_server.limits,
316 CR_RGB_BIT | CR_DEPTH_BIT, NULL );
317 cr_server.pContextCreateInfoTable = crAllocHashtable();
318 cr_server.pWindowCreateInfoTable = crAllocHashtable();
319
320 crServerSetVBoxConfigurationHGCM();
321
322 if (!cr_server.head_spu)
323 return GL_FALSE;
324
325 crServerInitDispatch();
326 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
327
328 return GL_TRUE;
329}
330
331int32_t crVBoxServerAddClient(uint32_t u32ClientID)
332{
333 CRClient *newClient;
334
335 if (cr_server.numClients>=CR_MAX_CLIENTS)
336 {
337 return VERR_MAX_THRDS_REACHED;
338 }
339
340 newClient = (CRClient *) crCalloc(sizeof(CRClient));
341 crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
342
343 newClient->spu_id = 0;
344 newClient->currentCtx = cr_server.DummyContext;
345 newClient->currentContextNumber = -1;
346 newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
347 cr_server.tcpip_port,
348 cr_server.mtu, 0);
349 newClient->conn->u32ClientID = u32ClientID;
350
351 cr_server.clients[cr_server.numClients++] = newClient;
352
353 crServerAddToRunQueue(newClient);
354
355 return VINF_SUCCESS;
356}
357
358void crVBoxServerRemoveClient(uint32_t u32ClientID)
359{
360 CRClient *pClient;
361 int32_t i;
362
363 crDebug("crServer: RemoveClient u32ClientID=%d", u32ClientID);
364
365 for (i = 0; i < cr_server.numClients; i++)
366 {
367 if (cr_server.clients[i] && cr_server.clients[i]->conn
368 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
369 {
370 break;
371 }
372 }
373 pClient = cr_server.clients[i];
374 CRASSERT(pClient);
375
376 /* Disconnect the client */
377 pClient->conn->Disconnect(pClient->conn);
378
379 /* Let server clear client from the queue */
380 crServerDeleteClient(pClient);
381}
382
383int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer)
384{
385 CRClient *pClient = NULL;
386 int32_t i;
387#ifdef VBOXCR_LOGFPS
388 uint64_t tstart, tend;
389#endif
390
391 /*crDebug("=>crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
392
393 for (i = 0; i < cr_server.numClients; i++)
394 {
395 if (cr_server.clients[i] && cr_server.clients[i]->conn
396 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
397 {
398 pClient = cr_server.clients[i];
399 break;
400 }
401 }
402 if (!pClient) return VERR_INVALID_PARAMETER;
403
404 if (!pClient->conn->vMajor) return VERR_NOT_SUPPORTED;
405
406#ifdef VBOXCR_LOGFPS
407 tstart = RTTimeNanoTS();
408#endif
409
410 CRASSERT(pBuffer);
411
412 /* This should never fire unless we start to multithread */
413 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
414
415 /* Check if there's a blocker in queue and it's not this client */
416 if (cr_server.run_queue->client != pClient
417 && crServerClientInBeginEnd(cr_server.run_queue->client))
418 {
419 crDebug("crServer: client %d blocked, allow_redir_ptr = 0", u32ClientID);
420 pClient->conn->allow_redir_ptr = 0;
421 }
422 else
423 {
424 pClient->conn->allow_redir_ptr = 1;
425 }
426
427 pClient->conn->pBuffer = pBuffer;
428 pClient->conn->cbBuffer = cbBuffer;
429
430 crNetRecv();
431 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
432
433 crServerServiceClients();
434
435#if 0
436 if (pClient->currentMural) {
437 crStateViewport( 0, 0, 500, 500 );
438 pClient->currentMural->viewportValidated = GL_FALSE;
439 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 500, 500 );
440 crStateViewport( 0, 0, 600, 600 );
441 pClient->currentMural->viewportValidated = GL_FALSE;
442 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
443
444 crStateMatrixMode(GL_PROJECTION);
445 cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
446 crServerDispatchLoadIdentity();
447 crStateFrustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
448 cr_server.head_spu->dispatch_table.Frustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
449 crServerDispatchLoadIdentity();
450 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
451 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
452
453 crStateMatrixMode(GL_MODELVIEW);
454 cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
455 crServerDispatchLoadIdentity();
456 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
457 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
458 crServerDispatchLoadIdentity();
459 }
460#endif
461
462 crStateResetCurrentPointers(&cr_server.current);
463
464 CRASSERT(!pClient->conn->allow_redir_ptr || crNetNumMessages(pClient->conn)==0);
465
466#ifdef VBOXCR_LOGFPS
467 tend = RTTimeNanoTS();
468 pClient->timeUsed += tend-tstart;
469#endif
470 /*crDebug("<=crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
471
472 return VINF_SUCCESS;
473}
474
475int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t *pcbBuffer)
476{
477 CRClient *pClient;
478 int32_t i;
479
480 //crDebug("crServer: [%x] ClientRead u32ClientID=%d", crThreadID(), u32ClientID);
481
482 for (i = 0; i < cr_server.numClients; i++)
483 {
484 if (cr_server.clients[i] && cr_server.clients[i]->conn
485 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
486 {
487 break;
488 }
489 }
490 pClient = cr_server.clients[i];
491 CRASSERT(pClient);
492
493 if (!pClient->conn->vMajor) return VERR_NOT_SUPPORTED;
494
495 if (pClient->conn->cbHostBuffer > *pcbBuffer)
496 {
497 crDebug("crServer: [%lx] ClientRead u32ClientID=%d FAIL, host buffer too small %d of %d",
498 crThreadID(), u32ClientID, *pcbBuffer, pClient->conn->cbHostBuffer);
499
500 /* Return the size of needed buffer */
501 *pcbBuffer = pClient->conn->cbHostBuffer;
502
503 return VERR_BUFFER_OVERFLOW;
504 }
505
506 *pcbBuffer = pClient->conn->cbHostBuffer;
507
508 if (*pcbBuffer)
509 {
510 CRASSERT(pClient->conn->pHostBuffer);
511
512 crMemcpy(pBuffer, pClient->conn->pHostBuffer, *pcbBuffer);
513 pClient->conn->cbHostBuffer = 0;
514 }
515
516 return VINF_SUCCESS;
517}
518
519int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor)
520{
521 CRClient *pClient;
522 int32_t i;
523
524 for (i = 0; i < cr_server.numClients; i++)
525 {
526 if (cr_server.clients[i] && cr_server.clients[i]->conn
527 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
528 {
529 break;
530 }
531 }
532 pClient = cr_server.clients[i];
533 CRASSERT(pClient);
534
535 pClient->conn->vMajor = vMajor;
536 pClient->conn->vMinor = vMinor;
537
538 if (vMajor != CR_PROTOCOL_VERSION_MAJOR
539 || vMinor != CR_PROTOCOL_VERSION_MINOR)
540 {
541 return VERR_NOT_SUPPORTED;
542 }
543 else return VINF_SUCCESS;
544}
545
546int
547CRServerMain(int argc, char *argv[])
548{
549 crServerInit(argc, argv);
550
551 crServerSerializeRemoteStreams();
552
553 crServerTearDown();
554
555 tearingdown = 0;
556
557 return 0;
558}
559
560static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2)
561{
562 CRMuralInfo *pMI = (CRMuralInfo*) data1;
563 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
564 int32_t rc;
565
566 CRASSERT(pMI && pSSM);
567
568 /* Don't store default mural */
569 if (!key) return;
570
571 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
572 CRASSERT(rc == VINF_SUCCESS);
573
574 rc = SSMR3PutMem(pSSM, pMI, sizeof(*pMI));
575 CRASSERT(rc == VINF_SUCCESS);
576
577 if (pMI->pVisibleRects)
578 {
579 rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects);
580 }
581}
582
583/* @todo add hashtable walker with result info and intermediate abort */
584static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *data2)
585{
586 CRCreateInfo_t *pCreateInfo = (CRCreateInfo_t *) data1;
587 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
588 int32_t rc;
589
590 CRASSERT(pCreateInfo && pSSM);
591
592 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
593 CRASSERT(rc == VINF_SUCCESS);
594
595 rc = SSMR3PutMem(pSSM, pCreateInfo, sizeof(*pCreateInfo));
596 CRASSERT(rc == VINF_SUCCESS);
597
598 if (pCreateInfo->pszDpyName)
599 {
600 rc = SSMR3PutStrZ(pSSM, pCreateInfo->pszDpyName);
601 CRASSERT(rc == VINF_SUCCESS);
602 }
603}
604
605static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data2)
606{
607 CRTextureObj *pTexture = (CRTextureObj *) data1;
608 CRContext *pContext = (CRContext *) data2;
609
610 CRASSERT(pTexture && pContext);
611 crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
612}
613
614static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
615{
616 CRContext *pContext = (CRContext *) data1;
617 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
618 int32_t rc;
619
620 CRASSERT(pContext && pSSM);
621
622 /* We could have skipped saving the key and use similar callback to load context states back,
623 * but there's no guarantee we'd traverse hashtable in same order after loading.
624 */
625 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
626 CRASSERT(rc == VINF_SUCCESS);
627
628#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
629 if (cr_server.curClient)
630 {
631 unsigned long id;
632 if (!crHashtableGetDataKey(cr_server.contextTable, pContext, &id))
633 {
634 crWarning("No client id for server ctx %d", pContext->id);
635 }
636 else
637 {
638 crServerDispatchMakeCurrent(cr_server.curClient->currentWindow, 0, id);
639 }
640 }
641#endif
642
643 rc = crStateSaveContext(pContext, pSSM);
644 CRASSERT(rc == VINF_SUCCESS);
645}
646
647static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
648
649DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
650{
651 int32_t rc, i;
652 uint32_t ui32;
653 GLboolean b;
654 unsigned long key;
655#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
656 unsigned long ctxID=-1, winID=-1;
657#endif
658
659 /* We shouldn't be called if there's no clients at all*/
660 CRASSERT(cr_server.numClients>0);
661
662 /* @todo it's hack atm */
663 /* We want to be called only once to save server state but atm we're being called from svcSaveState
664 * for every connected client (e.g. guest opengl application)
665 */
666 if (!cr_server.bIsInSavingState) /* It's first call */
667 {
668 cr_server.bIsInSavingState = GL_TRUE;
669
670 /* Store number of clients */
671 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
672 AssertRCReturn(rc, rc);
673
674 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
675 }
676
677 g_hackVBoxServerSaveLoadCallsLeft--;
678
679 /* Do nothing until we're being called last time */
680 if (g_hackVBoxServerSaveLoadCallsLeft>0)
681 {
682 return VINF_SUCCESS;
683 }
684
685 /* Save rendering contexts creation info */
686 ui32 = crHashtableNumElements(cr_server.pContextCreateInfoTable);
687 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
688 AssertRCReturn(rc, rc);
689 crHashtableWalk(cr_server.pContextCreateInfoTable, crVBoxServerSaveCreateInfoCB, pSSM);
690
691#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
692 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
693 if (cr_server.curClient)
694 {
695 ctxID = cr_server.curClient->currentContextNumber;
696 winID = cr_server.curClient->currentWindow;
697 }
698#endif
699
700 /* Save contexts state tracker data */
701 /* @todo For now just some blind data dumps,
702 * but I've a feeling those should be saved/restored in a very strict sequence to
703 * allow diff_api to work correctly.
704 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
705 */
706 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, pSSM);
707
708#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
709 /* Restore original win and ctx IDs*/
710 if (cr_server.curClient)
711 {
712 crServerDispatchMakeCurrent(winID, 0, ctxID);
713 }
714#endif
715
716 /* Save windows creation info */
717 ui32 = crHashtableNumElements(cr_server.pWindowCreateInfoTable);
718 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
719 AssertRCReturn(rc, rc);
720 crHashtableWalk(cr_server.pWindowCreateInfoTable, crVBoxServerSaveCreateInfoCB, pSSM);
721
722 /* Save cr_server.muralTable
723 * @todo we don't need it all, just geometry info actually
724 * @todo store visible regions as well
725 */
726 ui32 = crHashtableNumElements(cr_server.muralTable);
727 /* There should be default mural always */
728 CRASSERT(ui32>=1);
729 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
730 AssertRCReturn(rc, rc);
731 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
732
733 /* Save starting free context and window IDs */
734 rc = SSMR3PutMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool));
735 AssertRCReturn(rc, rc);
736
737 /* Save clients info */
738 for (i = 0; i < cr_server.numClients; i++)
739 {
740 if (cr_server.clients[i] && cr_server.clients[i]->conn)
741 {
742 CRClient *pClient = cr_server.clients[i];
743
744 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
745 AssertRCReturn(rc, rc);
746
747 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
748 AssertRCReturn(rc, rc);
749
750 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
751 AssertRCReturn(rc, rc);
752
753 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
754 AssertRCReturn(rc, rc);
755
756 if (pClient->currentCtx && pClient->currentContextNumber>=0)
757 {
758 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtx, &key);
759 CRASSERT(b);
760 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
761 AssertRCReturn(rc, rc);
762 }
763
764 if (pClient->currentMural && pClient->currentWindow>=0)
765 {
766 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
767 CRASSERT(b);
768 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
769 AssertRCReturn(rc, rc);
770 }
771 }
772 }
773
774 cr_server.bIsInSavingState = GL_FALSE;
775
776 return VINF_SUCCESS;
777}
778
779DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
780{
781 int32_t rc, i;
782 uint32_t ui, uiNumElems;
783 unsigned long key;
784
785 if (!cr_server.bIsInLoadingState)
786 {
787 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
788 cr_server.bIsInLoadingState = GL_TRUE;
789
790 /* Read number of clients */
791 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
792 AssertRCReturn(rc, rc);
793 }
794
795 g_hackVBoxServerSaveLoadCallsLeft--;
796
797 /* Do nothing until we're being called last time */
798 if (g_hackVBoxServerSaveLoadCallsLeft>0)
799 {
800 return VINF_SUCCESS;
801 }
802
803 if (version!=SHCROGL_SSM_VERSION)
804 {
805 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
806 }
807
808 /* Load and recreate rendering contexts */
809 rc = SSMR3GetU32(pSSM, &uiNumElems);
810 AssertRCReturn(rc, rc);
811 for (ui=0; ui<uiNumElems; ++ui)
812 {
813 CRCreateInfo_t createInfo;
814 char psz[200];
815 GLint ctxID;
816 CRContext* pContext;
817
818 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
819 AssertRCReturn(rc, rc);
820 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
821 AssertRCReturn(rc, rc);
822
823 if (createInfo.pszDpyName)
824 {
825 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
826 AssertRCReturn(rc, rc);
827 createInfo.pszDpyName = psz;
828 }
829
830 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.internalID);
831 CRASSERT((int64_t)ctxID == (int64_t)key);
832
833 pContext = (CRContext*) crHashtableSearch(cr_server.contextTable, key);
834 CRASSERT(pContext);
835 pContext->shared->id=-1;
836 }
837
838 /* Restore context state data */
839 for (ui=0; ui<uiNumElems; ++ui)
840 {
841 CRContext *pContext;
842
843 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
844 AssertRCReturn(rc, rc);
845
846 pContext = (CRContext*) crHashtableSearch(cr_server.contextTable, key);
847 CRASSERT(pContext);
848
849 rc = crStateLoadContext(pContext, cr_server.contextTable, pSSM);
850 AssertRCReturn(rc, rc);
851 }
852
853 /* Load windows */
854 rc = SSMR3GetU32(pSSM, &uiNumElems);
855 AssertRCReturn(rc, rc);
856 for (ui=0; ui<uiNumElems; ++ui)
857 {
858 CRCreateInfo_t createInfo;
859 char psz[200];
860 GLint winID;
861 unsigned long key;
862
863 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
864 AssertRCReturn(rc, rc);
865 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
866 AssertRCReturn(rc, rc);
867
868 if (createInfo.pszDpyName)
869 {
870 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
871 AssertRCReturn(rc, rc);
872 createInfo.pszDpyName = psz;
873 }
874
875 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
876 CRASSERT((int64_t)winID == (int64_t)key);
877 }
878
879 /* Load cr_server.muralTable */
880 rc = SSMR3GetU32(pSSM, &uiNumElems);
881 AssertRCReturn(rc, rc);
882 for (ui=0; ui<uiNumElems; ++ui)
883 {
884 CRMuralInfo muralInfo;
885
886 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
887 AssertRCReturn(rc, rc);
888 rc = SSMR3GetMem(pSSM, &muralInfo, sizeof(muralInfo));
889 AssertRCReturn(rc, rc);
890
891 if (muralInfo.pVisibleRects)
892 {
893 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
894 if (!muralInfo.pVisibleRects)
895 {
896 return VERR_NO_MEMORY;
897 }
898
899 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
900 AssertRCReturn(rc, rc);
901 }
902
903 /* Restore windows geometry info */
904 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
905 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
906 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
907 if (muralInfo.cVisibleRects)
908 {
909 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
910 }
911 crServerDispatchWindowShow(key, muralInfo.bVisible);
912
913 if (muralInfo.pVisibleRects)
914 {
915 crFree(muralInfo.pVisibleRects);
916 }
917 }
918
919 /* Load starting free context and window IDs */
920 rc = SSMR3GetMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool));
921 CRASSERT(rc == VINF_SUCCESS);
922
923 /* Load clients info */
924 for (i = 0; i < cr_server.numClients; i++)
925 {
926 if (cr_server.clients[i] && cr_server.clients[i]->conn)
927 {
928 CRClient *pClient = cr_server.clients[i];
929 CRClient client;
930 unsigned long ctxID=-1, winID=-1;
931
932 rc = SSMR3GetU32(pSSM, &ui);
933 AssertRCReturn(rc, rc);
934 /* If this assert fires, then we should search correct client in the list first*/
935 CRASSERT(ui == pClient->conn->u32ClientID);
936
937 if (version>=4)
938 {
939 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
940 AssertRCReturn(rc, rc);
941
942 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
943 AssertRCReturn(rc, rc);
944 }
945
946 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
947 CRASSERT(rc == VINF_SUCCESS);
948
949 client.conn = pClient->conn;
950 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
951 * and fail to bind old textures.
952 */
953 /*client.number = pClient->number;*/
954 *pClient = client;
955
956 pClient->currentContextNumber = -1;
957 pClient->currentCtx = cr_server.DummyContext;
958 pClient->currentMural = NULL;
959 pClient->currentWindow = -1;
960
961 cr_server.curClient = pClient;
962
963 if (client.currentCtx && client.currentContextNumber>=0)
964 {
965 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
966 AssertRCReturn(rc, rc);
967 client.currentCtx = (CRContext*) crHashtableSearch(cr_server.contextTable, ctxID);
968 CRASSERT(client.currentCtx);
969 //pClient->currentCtx = client.currentCtx;
970 //pClient->currentContextNumber = ctxID;
971 }
972
973 if (client.currentMural && client.currentWindow>=0)
974 {
975 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
976 AssertRCReturn(rc, rc);
977 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
978 CRASSERT(client.currentMural);
979 //pClient->currentMural = client.currentMural;
980 //pClient->currentWindow = winID;
981 }
982
983 /* Restore client active context and window */
984 crServerDispatchMakeCurrent(winID, 0, ctxID);
985
986 if (0)
987 {
988 CRContext *tmpCtx;
989 CRCreateInfo_t *createInfo;
990 GLfloat one[4] = { 1, 1, 1, 1 };
991 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
992
993 crServerDispatchMakeCurrent(winID, 0, ctxID);
994
995 crHashtableWalk(client.currentCtx->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtx);
996
997 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.base1D, GL_TRUE);
998 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.base2D, GL_TRUE);
999 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.base3D, GL_TRUE);
1000#ifdef CR_ARB_texture_cube_map
1001 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.baseCubeMap, GL_TRUE);
1002#endif
1003#ifdef CR_NV_texture_rectangle
1004 //@todo this doesn't work as expected
1005 //crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.baseRect, GL_TRUE);
1006#endif
1007 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
1008 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
1009 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
1010
1011 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
1012 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
1013 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
1014
1015 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
1016 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
1017
1018 //crStateViewport( 0, 0, 600, 600 );
1019 //pClient->currentMural->viewportValidated = GL_FALSE;
1020 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
1021
1022 //crStateMatrixMode(GL_PROJECTION);
1023 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
1024
1025 //crStateLoadIdentity();
1026 //cr_server.head_spu->dispatch_table.LoadIdentity();
1027
1028 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1029 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1030
1031 //crStateMatrixMode(GL_MODELVIEW);
1032 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
1033 //crServerDispatchLoadIdentity();
1034 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1035 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1036 //crServerDispatchLoadIdentity();
1037
1038 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
1039 CRASSERT(createInfo);
1040 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
1041 CRASSERT(tmpCtx);
1042 crStateDiffContext(tmpCtx, client.currentCtx);
1043 crStateDestroyContext(tmpCtx);*/
1044 }
1045 }
1046 }
1047
1048 //crServerDispatchMakeCurrent(-1, 0, -1);
1049
1050 cr_server.curClient = NULL;
1051
1052 {
1053 GLenum err = crServerDispatchGetError();
1054
1055 if (err != GL_NO_ERROR)
1056 {
1057 crWarning("crServer: glGetError %d after loading snapshot", err);
1058 }
1059 }
1060
1061 cr_server.bIsInLoadingState = GL_FALSE;
1062
1063 return VINF_SUCCESS;
1064}
1065
1066#define SCREEN(i) (cr_server.screen[i])
1067#define MAPPED(screen) ((screen).winID != 0)
1068
1069static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
1070{
1071 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1072 int *sIndex = (int*) data2;
1073
1074 if (pMI->screenId == *sIndex)
1075 {
1076 renderspuReparentWindow(pMI->spuWindow);
1077 }
1078}
1079
1080static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
1081{
1082 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1083 (void) data2;
1084
1085 crServerCheckMuralGeometry(pMI);
1086}
1087
1088DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
1089{
1090 int i;
1091
1092 if (sCount>CR_MAX_GUEST_MONITORS)
1093 return VERR_INVALID_PARAMETER;
1094
1095 /*Shouldn't happen yet, but to be safe in future*/
1096 for (i=0; i<cr_server.screenCount; ++i)
1097 {
1098 if (MAPPED(SCREEN(i)))
1099 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
1100 return VERR_NOT_IMPLEMENTED;
1101 }
1102
1103 cr_server.screenCount = sCount;
1104
1105 for (i=0; i<sCount; ++i)
1106 {
1107 SCREEN(i).winID = 0;
1108 }
1109
1110 return VINF_SUCCESS;
1111}
1112
1113DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
1114{
1115 if (sIndex<0 || sIndex>=cr_server.screenCount)
1116 return VERR_INVALID_PARAMETER;
1117
1118 if (MAPPED(SCREEN(sIndex)))
1119 {
1120 SCREEN(sIndex).winID = 0;
1121 renderspuSetWindowId(0);
1122
1123 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
1124 }
1125
1126 renderspuSetWindowId(SCREEN(0).winID);
1127 return VINF_SUCCESS;
1128}
1129
1130DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
1131{
1132 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u]", sIndex, x, y, w, h);
1133
1134 if (sIndex<0 || sIndex>=cr_server.screenCount)
1135 return VERR_INVALID_PARAMETER;
1136
1137 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
1138 {
1139 crDebug("Mapped screen[%i] is being remapped.", sIndex);
1140 crVBoxServerUnmapScreen(sIndex);
1141 }
1142
1143 SCREEN(sIndex).winID = winID;
1144 SCREEN(sIndex).x = x;
1145 SCREEN(sIndex).y = y;
1146 SCREEN(sIndex).w = w;
1147 SCREEN(sIndex).h = h;
1148
1149 renderspuSetWindowId(SCREEN(sIndex).winID);
1150 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
1151 renderspuSetWindowId(SCREEN(0).winID);
1152
1153 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
1154
1155#ifndef WINDOWS
1156 /*Restore FB content for clients, which have current window on a screen being remapped*/
1157 {
1158 GLint i;
1159
1160 for (i = 0; i < cr_server.numClients; i++)
1161 {
1162 cr_server.curClient = cr_server.clients[i];
1163 if (cr_server.curClient->currentCtx
1164 && cr_server.curClient->currentCtx->pImage
1165 && cr_server.curClient->currentMural
1166 && cr_server.curClient->currentMural->screenId == sIndex
1167 && cr_server.curClient->currentCtx->viewport.viewportH == h
1168 && cr_server.curClient->currentCtx->viewport.viewportW == w)
1169 {
1170 int clientWindow = cr_server.curClient->currentWindow;
1171 int clientContext = cr_server.curClient->currentContextNumber;
1172
1173 if (clientWindow && clientWindow != cr_server.currentWindow)
1174 {
1175 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
1176 }
1177
1178 crStateApplyFBImage(cr_server.curClient->currentCtx);
1179 }
1180 }
1181 cr_server.curClient = NULL;
1182 }
1183#endif
1184
1185 return VINF_SUCCESS;
1186}
1187
1188DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
1189{
1190 renderspuSetRootVisibleRegion(cRects, pRects);
1191
1192 return VINF_SUCCESS;
1193}
1194
1195DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
1196{
1197 cr_server.pfnPresentFBO = pfnPresentFBO;
1198}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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