VirtualBox

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

Last change on this file since 33223 was 32940, checked in by vboxsync, 14 years ago

crOpenGL: another perf counter

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