VirtualBox

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

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

crOpenGL: properly cleanup host opengl parts (#2954, #6443)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.1 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;
381 int32_t i;
382
383 //crDebug("crServer: [%x] ClientWrite u32ClientID=%d", crThreadID(), 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 break;
391 }
392 }
393 pClient = cr_server.clients[i];
394 CRASSERT(pClient);
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 return VINF_SUCCESS;
455}
456
457int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t *pcbBuffer)
458{
459 CRClient *pClient;
460 int32_t i;
461
462 //crDebug("crServer: [%x] ClientRead u32ClientID=%d", crThreadID(), u32ClientID);
463
464 for (i = 0; i < cr_server.numClients; i++)
465 {
466 if (cr_server.clients[i] && cr_server.clients[i]->conn
467 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
468 {
469 break;
470 }
471 }
472 pClient = cr_server.clients[i];
473 CRASSERT(pClient);
474
475 if (!pClient->conn->vMajor) return VERR_NOT_SUPPORTED;
476
477 if (pClient->conn->cbHostBuffer > *pcbBuffer)
478 {
479 crDebug("crServer: [%lx] ClientRead u32ClientID=%d FAIL, host buffer too small %d of %d",
480 crThreadID(), u32ClientID, *pcbBuffer, pClient->conn->cbHostBuffer);
481
482 /* Return the size of needed buffer */
483 *pcbBuffer = pClient->conn->cbHostBuffer;
484
485 return VERR_BUFFER_OVERFLOW;
486 }
487
488 *pcbBuffer = pClient->conn->cbHostBuffer;
489
490 if (*pcbBuffer)
491 {
492 CRASSERT(pClient->conn->pHostBuffer);
493
494 crMemcpy(pBuffer, pClient->conn->pHostBuffer, *pcbBuffer);
495 pClient->conn->cbHostBuffer = 0;
496 }
497
498 return VINF_SUCCESS;
499}
500
501int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor)
502{
503 CRClient *pClient;
504 int32_t i;
505
506 for (i = 0; i < cr_server.numClients; i++)
507 {
508 if (cr_server.clients[i] && cr_server.clients[i]->conn
509 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
510 {
511 break;
512 }
513 }
514 pClient = cr_server.clients[i];
515 CRASSERT(pClient);
516
517 pClient->conn->vMajor = vMajor;
518 pClient->conn->vMinor = vMinor;
519
520 if (vMajor != CR_PROTOCOL_VERSION_MAJOR
521 || vMinor != CR_PROTOCOL_VERSION_MINOR)
522 {
523 return VERR_NOT_SUPPORTED;
524 }
525 else return VINF_SUCCESS;
526}
527
528int
529CRServerMain(int argc, char *argv[])
530{
531 crServerInit(argc, argv);
532
533 crServerSerializeRemoteStreams();
534
535 crServerTearDown();
536
537 tearingdown = 0;
538
539 return 0;
540}
541
542static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2)
543{
544 CRMuralInfo *pMI = (CRMuralInfo*) data1;
545 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
546 int32_t rc;
547
548 CRASSERT(pMI && pSSM);
549
550 /* Don't store default mural */
551 if (!key) return;
552
553 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
554 CRASSERT(rc == VINF_SUCCESS);
555
556 rc = SSMR3PutMem(pSSM, pMI, sizeof(*pMI));
557 CRASSERT(rc == VINF_SUCCESS);
558
559 if (pMI->pVisibleRects)
560 {
561 rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects);
562 }
563}
564
565/* @todo add hashtable walker with result info and intermediate abort */
566static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *data2)
567{
568 CRCreateInfo_t *pCreateInfo = (CRCreateInfo_t *) data1;
569 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
570 int32_t rc;
571
572 CRASSERT(pCreateInfo && pSSM);
573
574 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
575 CRASSERT(rc == VINF_SUCCESS);
576
577 rc = SSMR3PutMem(pSSM, pCreateInfo, sizeof(*pCreateInfo));
578 CRASSERT(rc == VINF_SUCCESS);
579
580 if (pCreateInfo->pszDpyName)
581 {
582 rc = SSMR3PutStrZ(pSSM, pCreateInfo->pszDpyName);
583 CRASSERT(rc == VINF_SUCCESS);
584 }
585}
586
587static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data2)
588{
589 CRTextureObj *pTexture = (CRTextureObj *) data1;
590 CRContext *pContext = (CRContext *) data2;
591
592 CRASSERT(pTexture && pContext);
593 crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
594}
595
596static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
597{
598 CRContext *pContext = (CRContext *) data1;
599 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
600 int32_t rc;
601
602 CRASSERT(pContext && pSSM);
603
604 /* We could have skipped saving the key and use similar callback to load context states back,
605 * but there's no guarantee we'd traverse hashtable in same order after loading.
606 */
607 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
608 CRASSERT(rc == VINF_SUCCESS);
609
610#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
611 if (cr_server.curClient)
612 {
613 unsigned long id;
614 if (!crHashtableGetDataKey(cr_server.contextTable, pContext, &id))
615 {
616 crWarning("No client id for server ctx %d", pContext->id);
617 }
618 else
619 {
620 crServerDispatchMakeCurrent(cr_server.curClient->currentWindow, 0, id);
621 }
622 }
623#endif
624
625 rc = crStateSaveContext(pContext, pSSM);
626 CRASSERT(rc == VINF_SUCCESS);
627}
628
629static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
630
631DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
632{
633 int32_t rc, i;
634 uint32_t ui32;
635 GLboolean b;
636 unsigned long key;
637#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
638 unsigned long ctxID=-1, winID=-1;
639#endif
640
641 /* We shouldn't be called if there's no clients at all*/
642 CRASSERT(cr_server.numClients>0);
643
644 /* @todo it's hack atm */
645 /* We want to be called only once to save server state but atm we're being called from svcSaveState
646 * for every connected client (e.g. guest opengl application)
647 */
648 if (!cr_server.bIsInSavingState) /* It's first call */
649 {
650 cr_server.bIsInSavingState = GL_TRUE;
651
652 /* Store number of clients */
653 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
654 AssertRCReturn(rc, rc);
655
656 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
657 }
658
659 g_hackVBoxServerSaveLoadCallsLeft--;
660
661 /* Do nothing untill we're being called last time */
662 if (g_hackVBoxServerSaveLoadCallsLeft>0)
663 {
664 return VINF_SUCCESS;
665 }
666
667 /* Save rendering contexts creation info */
668 ui32 = crHashtableNumElements(cr_server.pContextCreateInfoTable);
669 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
670 AssertRCReturn(rc, rc);
671 crHashtableWalk(cr_server.pContextCreateInfoTable, crVBoxServerSaveCreateInfoCB, pSSM);
672
673#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
674 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
675 if (cr_server.curClient)
676 {
677 ctxID = cr_server.curClient->currentContextNumber;
678 winID = cr_server.curClient->currentWindow;
679 }
680#endif
681
682 /* Save contexts state tracker data */
683 /* @todo For now just some blind data dumps,
684 * but I've a feeling those should be saved/restored in a very strict sequence to
685 * allow diff_api to work correctly.
686 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
687 */
688 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, pSSM);
689
690#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
691 /* Restore original win and ctx IDs*/
692 if (cr_server.curClient)
693 {
694 crServerDispatchMakeCurrent(winID, 0, ctxID);
695 }
696#endif
697
698 /* Save windows creation info */
699 ui32 = crHashtableNumElements(cr_server.pWindowCreateInfoTable);
700 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
701 AssertRCReturn(rc, rc);
702 crHashtableWalk(cr_server.pWindowCreateInfoTable, crVBoxServerSaveCreateInfoCB, pSSM);
703
704 /* Save cr_server.muralTable
705 * @todo we don't need it all, just geometry info actually
706 * @todo store visible regions as well
707 */
708 ui32 = crHashtableNumElements(cr_server.muralTable);
709 /* There should be default mural always */
710 CRASSERT(ui32>=1);
711 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
712 AssertRCReturn(rc, rc);
713 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
714
715 /* Save starting free context and window IDs */
716 rc = SSMR3PutMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool));
717 AssertRCReturn(rc, rc);
718
719 /* Save clients info */
720 for (i = 0; i < cr_server.numClients; i++)
721 {
722 if (cr_server.clients[i] && cr_server.clients[i]->conn)
723 {
724 CRClient *pClient = cr_server.clients[i];
725
726 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
727 AssertRCReturn(rc, rc);
728
729 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
730 AssertRCReturn(rc, rc);
731
732 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
733 AssertRCReturn(rc, rc);
734
735 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
736 AssertRCReturn(rc, rc);
737
738 if (pClient->currentCtx && pClient->currentContextNumber>=0)
739 {
740 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtx, &key);
741 CRASSERT(b);
742 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
743 AssertRCReturn(rc, rc);
744 }
745
746 if (pClient->currentMural && pClient->currentWindow>=0)
747 {
748 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
749 CRASSERT(b);
750 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
751 AssertRCReturn(rc, rc);
752 }
753 }
754 }
755
756 cr_server.bIsInSavingState = GL_FALSE;
757
758 return VINF_SUCCESS;
759}
760
761DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
762{
763 int32_t rc, i;
764 uint32_t ui, uiNumElems;
765 unsigned long key;
766
767 if (!cr_server.bIsInLoadingState)
768 {
769 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
770 cr_server.bIsInLoadingState = GL_TRUE;
771
772 /* Read number of clients */
773 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
774 AssertRCReturn(rc, rc);
775 }
776
777 g_hackVBoxServerSaveLoadCallsLeft--;
778
779 /* Do nothing untill we're being called last time */
780 if (g_hackVBoxServerSaveLoadCallsLeft>0)
781 {
782 return VINF_SUCCESS;
783 }
784
785 /* Load and recreate rendering contexts */
786 rc = SSMR3GetU32(pSSM, &uiNumElems);
787 AssertRCReturn(rc, rc);
788 for (ui=0; ui<uiNumElems; ++ui)
789 {
790 CRCreateInfo_t createInfo;
791 char psz[200];
792 GLint ctxID;
793
794 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
795 AssertRCReturn(rc, rc);
796 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
797 AssertRCReturn(rc, rc);
798
799 if (createInfo.pszDpyName)
800 {
801 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
802 AssertRCReturn(rc, rc);
803 createInfo.pszDpyName = psz;
804 }
805
806 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.internalID);
807 CRASSERT((int64_t)ctxID == (int64_t)key);
808 }
809
810 /* Restore context state data */
811 for (ui=0; ui<uiNumElems; ++ui)
812 {
813 CRContext *pContext;
814
815 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
816 AssertRCReturn(rc, rc);
817
818 pContext = (CRContext*) crHashtableSearch(cr_server.contextTable, key);
819 CRASSERT(pContext);
820
821 rc = crStateLoadContext(pContext, pSSM);
822 AssertRCReturn(rc, rc);
823 }
824
825 /* Load windows */
826 rc = SSMR3GetU32(pSSM, &uiNumElems);
827 AssertRCReturn(rc, rc);
828 for (ui=0; ui<uiNumElems; ++ui)
829 {
830 CRCreateInfo_t createInfo;
831 char psz[200];
832 GLint winID;
833 unsigned long key;
834
835 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
836 AssertRCReturn(rc, rc);
837 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
838 AssertRCReturn(rc, rc);
839
840 if (createInfo.pszDpyName)
841 {
842 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
843 AssertRCReturn(rc, rc);
844 createInfo.pszDpyName = psz;
845 }
846
847 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
848 CRASSERT((int64_t)winID == (int64_t)key);
849 }
850
851 /* Load cr_server.muralTable */
852 rc = SSMR3GetU32(pSSM, &uiNumElems);
853 AssertRCReturn(rc, rc);
854 for (ui=0; ui<uiNumElems; ++ui)
855 {
856 CRMuralInfo muralInfo;
857
858 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
859 AssertRCReturn(rc, rc);
860 rc = SSMR3GetMem(pSSM, &muralInfo, sizeof(muralInfo));
861 AssertRCReturn(rc, rc);
862
863 if (muralInfo.pVisibleRects)
864 {
865 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
866 if (!muralInfo.pVisibleRects)
867 {
868 return VERR_NO_MEMORY;
869 }
870
871 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
872 AssertRCReturn(rc, rc);
873 }
874
875 /* Restore windows geometry info */
876 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
877 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
878 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
879 if (muralInfo.cVisibleRects)
880 {
881 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
882 }
883 crServerDispatchWindowShow(key, muralInfo.bVisible);
884
885 if (muralInfo.pVisibleRects)
886 {
887 crFree(muralInfo.pVisibleRects);
888 }
889 }
890
891 /* Load starting free context and window IDs */
892 rc = SSMR3GetMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool));
893 CRASSERT(rc == VINF_SUCCESS);
894
895 /* Load clients info */
896 for (i = 0; i < cr_server.numClients; i++)
897 {
898 if (cr_server.clients[i] && cr_server.clients[i]->conn)
899 {
900 CRClient *pClient = cr_server.clients[i];
901 CRClient client;
902 unsigned long ctxID=-1, winID=-1;
903
904 rc = SSMR3GetU32(pSSM, &ui);
905 AssertRCReturn(rc, rc);
906 /* If this assert fires, then we should search correct client in the list first*/
907 CRASSERT(ui == pClient->conn->u32ClientID);
908
909 if (version>=4)
910 {
911 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
912 AssertRCReturn(rc, rc);
913
914 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
915 AssertRCReturn(rc, rc);
916 }
917
918 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
919 CRASSERT(rc == VINF_SUCCESS);
920
921 client.conn = pClient->conn;
922 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
923 * and fail to bind old textures.
924 */
925 /*client.number = pClient->number;*/
926 *pClient = client;
927
928 pClient->currentContextNumber = -1;
929 pClient->currentCtx = cr_server.DummyContext;
930 pClient->currentMural = NULL;
931 pClient->currentWindow = -1;
932
933 cr_server.curClient = pClient;
934
935 if (client.currentCtx && client.currentContextNumber>=0)
936 {
937 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
938 AssertRCReturn(rc, rc);
939 client.currentCtx = (CRContext*) crHashtableSearch(cr_server.contextTable, ctxID);
940 CRASSERT(client.currentCtx);
941 //pClient->currentCtx = client.currentCtx;
942 //pClient->currentContextNumber = ctxID;
943 }
944
945 if (client.currentMural && client.currentWindow>=0)
946 {
947 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
948 AssertRCReturn(rc, rc);
949 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
950 CRASSERT(client.currentMural);
951 //pClient->currentMural = client.currentMural;
952 //pClient->currentWindow = winID;
953 }
954
955 /* Restore client active context and window */
956 crServerDispatchMakeCurrent(winID, 0, ctxID);
957
958 if (0)
959 {
960 CRContext *tmpCtx;
961 CRCreateInfo_t *createInfo;
962 GLfloat one[4] = { 1, 1, 1, 1 };
963 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
964
965 crServerDispatchMakeCurrent(winID, 0, ctxID);
966
967 crHashtableWalk(client.currentCtx->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtx);
968
969 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.base1D, GL_TRUE);
970 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.base2D, GL_TRUE);
971 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.base3D, GL_TRUE);
972#ifdef CR_ARB_texture_cube_map
973 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.baseCubeMap, GL_TRUE);
974#endif
975#ifdef CR_NV_texture_rectangle
976 //@todo this doesn't work as expected
977 //crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.baseRect, GL_TRUE);
978#endif
979 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
980 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
981 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
982
983 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
984 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
985 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
986
987 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
988 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
989
990 //crStateViewport( 0, 0, 600, 600 );
991 //pClient->currentMural->viewportValidated = GL_FALSE;
992 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
993
994 //crStateMatrixMode(GL_PROJECTION);
995 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
996
997 //crStateLoadIdentity();
998 //cr_server.head_spu->dispatch_table.LoadIdentity();
999
1000 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1001 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1002
1003 //crStateMatrixMode(GL_MODELVIEW);
1004 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
1005 //crServerDispatchLoadIdentity();
1006 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1007 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1008 //crServerDispatchLoadIdentity();
1009
1010 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
1011 CRASSERT(createInfo);
1012 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
1013 CRASSERT(tmpCtx);
1014 crStateDiffContext(tmpCtx, client.currentCtx);
1015 crStateDestroyContext(tmpCtx);*/
1016 }
1017 }
1018 }
1019
1020 //crServerDispatchMakeCurrent(-1, 0, -1);
1021
1022 cr_server.curClient = NULL;
1023
1024 {
1025 GLenum err = crServerDispatchGetError();
1026
1027 if (err != GL_NO_ERROR)
1028 {
1029 crWarning("crServer: glGetError %d after loading snapshot", err);
1030 }
1031 }
1032
1033 cr_server.bIsInLoadingState = GL_FALSE;
1034
1035 return VINF_SUCCESS;
1036}
1037
1038#define SCREEN(i) (cr_server.screen[i])
1039#define MAPPED(screen) ((screen).winID != 0)
1040
1041static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
1042{
1043 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1044 int *sIndex = (int*) data2;
1045
1046 if (pMI->screenId == *sIndex)
1047 {
1048 renderspuReparentWindow(pMI->spuWindow);
1049 }
1050}
1051
1052static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
1053{
1054 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1055 (void) data2;
1056
1057 crServerCheckMuralGeometry(pMI);
1058}
1059
1060DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
1061{
1062 int i;
1063
1064 if (sCount>CR_MAX_GUEST_MONITORS)
1065 return VERR_INVALID_PARAMETER;
1066
1067 /*Shouldn't happen yet, but to be safe in future*/
1068 for (i=0; i<cr_server.screenCount; ++i)
1069 {
1070 if (MAPPED(SCREEN(i)))
1071 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
1072 return VERR_NOT_IMPLEMENTED;
1073 }
1074
1075 cr_server.screenCount = sCount;
1076
1077 for (i=0; i<sCount; ++i)
1078 {
1079 SCREEN(i).winID = 0;
1080 }
1081
1082 return VINF_SUCCESS;
1083}
1084
1085DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
1086{
1087 if (sIndex<0 || sIndex>=cr_server.screenCount)
1088 return VERR_INVALID_PARAMETER;
1089
1090 if (MAPPED(SCREEN(sIndex)))
1091 {
1092 SCREEN(sIndex).winID = 0;
1093 renderspuSetWindowId(0);
1094
1095 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
1096 }
1097
1098 renderspuSetWindowId(SCREEN(0).winID);
1099 return VINF_SUCCESS;
1100}
1101
1102DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
1103{
1104 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u]", sIndex, x, y, w, h);
1105
1106 if (sIndex<0 || sIndex>=cr_server.screenCount)
1107 return VERR_INVALID_PARAMETER;
1108
1109 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
1110 {
1111 crDebug("Mapped screen[%i] is being remapped.", sIndex);
1112 crVBoxServerUnmapScreen(sIndex);
1113 }
1114
1115 SCREEN(sIndex).winID = winID;
1116 SCREEN(sIndex).x = x;
1117 SCREEN(sIndex).y = y;
1118 SCREEN(sIndex).w = w;
1119 SCREEN(sIndex).h = h;
1120
1121 renderspuSetWindowId(SCREEN(sIndex).winID);
1122 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
1123 renderspuSetWindowId(SCREEN(0).winID);
1124
1125 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
1126
1127#ifndef WINDOWS
1128 /*Restore FB content for clients, which have current window on a screen being remapped*/
1129 {
1130 GLint i;
1131
1132 for (i = 0; i < cr_server.numClients; i++)
1133 {
1134 cr_server.curClient = cr_server.clients[i];
1135 if (cr_server.curClient->currentCtx
1136 && cr_server.curClient->currentCtx->pImage
1137 && cr_server.curClient->currentMural
1138 && cr_server.curClient->currentMural->screenId == sIndex
1139 && cr_server.curClient->currentCtx->viewport.viewportH == h
1140 && cr_server.curClient->currentCtx->viewport.viewportW == w)
1141 {
1142 int clientWindow = cr_server.curClient->currentWindow;
1143 int clientContext = cr_server.curClient->currentContextNumber;
1144
1145 if (clientWindow && clientWindow != cr_server.currentWindow)
1146 {
1147 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
1148 }
1149
1150 crStateApplyFBImage(cr_server.curClient->currentCtx);
1151 }
1152 }
1153 cr_server.curClient = NULL;
1154 }
1155#endif
1156
1157 return VINF_SUCCESS;
1158}
1159
1160DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
1161{
1162 renderspuSetRootVisibleRegion(cRects, pRects);
1163
1164 return VINF_SUCCESS;
1165}
1166
1167DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
1168{
1169 cr_server.pfnPresentFBO = pfnPresentFBO;
1170}
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