VirtualBox

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

Last change on this file since 28197 was 27889, checked in by vboxsync, 15 years ago

crOpenGL: more code for multiscreen support

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