VirtualBox

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

Last change on this file since 32625 was 32420, checked in by vboxsync, 14 years ago

crOpenGL: some mutter/meego related fixes

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