VirtualBox

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

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

crOpenGL: wddm friendly windows info tracking + more consistent updates (disabled except windows yet)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.2 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: 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 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 /*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
796 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
797 AssertRCReturn(rc, rc);
798 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
799 AssertRCReturn(rc, rc);
800
801 if (createInfo.pszDpyName)
802 {
803 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
804 AssertRCReturn(rc, rc);
805 createInfo.pszDpyName = psz;
806 }
807
808 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.internalID);
809 CRASSERT((int64_t)ctxID == (int64_t)key);
810 }
811
812 /* Restore context state data */
813 for (ui=0; ui<uiNumElems; ++ui)
814 {
815 CRContext *pContext;
816
817 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
818 AssertRCReturn(rc, rc);
819
820 pContext = (CRContext*) crHashtableSearch(cr_server.contextTable, key);
821 CRASSERT(pContext);
822
823 rc = crStateLoadContext(pContext, pSSM);
824 AssertRCReturn(rc, rc);
825 }
826
827 /* Load windows */
828 rc = SSMR3GetU32(pSSM, &uiNumElems);
829 AssertRCReturn(rc, rc);
830 for (ui=0; ui<uiNumElems; ++ui)
831 {
832 CRCreateInfo_t createInfo;
833 char psz[200];
834 GLint winID;
835 unsigned long key;
836
837 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
838 AssertRCReturn(rc, rc);
839 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
840 AssertRCReturn(rc, rc);
841
842 if (createInfo.pszDpyName)
843 {
844 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
845 AssertRCReturn(rc, rc);
846 createInfo.pszDpyName = psz;
847 }
848
849 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
850 CRASSERT((int64_t)winID == (int64_t)key);
851 }
852
853 /* Load cr_server.muralTable */
854 rc = SSMR3GetU32(pSSM, &uiNumElems);
855 AssertRCReturn(rc, rc);
856 for (ui=0; ui<uiNumElems; ++ui)
857 {
858 CRMuralInfo muralInfo;
859
860 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
861 AssertRCReturn(rc, rc);
862 rc = SSMR3GetMem(pSSM, &muralInfo, sizeof(muralInfo));
863 AssertRCReturn(rc, rc);
864
865 if (muralInfo.pVisibleRects)
866 {
867 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
868 if (!muralInfo.pVisibleRects)
869 {
870 return VERR_NO_MEMORY;
871 }
872
873 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
874 AssertRCReturn(rc, rc);
875 }
876
877 /* Restore windows geometry info */
878 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
879 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
880 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
881 if (muralInfo.cVisibleRects)
882 {
883 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
884 }
885 crServerDispatchWindowShow(key, muralInfo.bVisible);
886
887 if (muralInfo.pVisibleRects)
888 {
889 crFree(muralInfo.pVisibleRects);
890 }
891 }
892
893 /* Load starting free context and window IDs */
894 rc = SSMR3GetMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool));
895 CRASSERT(rc == VINF_SUCCESS);
896
897 /* Load clients info */
898 for (i = 0; i < cr_server.numClients; i++)
899 {
900 if (cr_server.clients[i] && cr_server.clients[i]->conn)
901 {
902 CRClient *pClient = cr_server.clients[i];
903 CRClient client;
904 unsigned long ctxID=-1, winID=-1;
905
906 rc = SSMR3GetU32(pSSM, &ui);
907 AssertRCReturn(rc, rc);
908 /* If this assert fires, then we should search correct client in the list first*/
909 CRASSERT(ui == pClient->conn->u32ClientID);
910
911 if (version>=4)
912 {
913 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
914 AssertRCReturn(rc, rc);
915
916 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
917 AssertRCReturn(rc, rc);
918 }
919
920 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
921 CRASSERT(rc == VINF_SUCCESS);
922
923 client.conn = pClient->conn;
924 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
925 * and fail to bind old textures.
926 */
927 /*client.number = pClient->number;*/
928 *pClient = client;
929
930 pClient->currentContextNumber = -1;
931 pClient->currentCtx = cr_server.DummyContext;
932 pClient->currentMural = NULL;
933 pClient->currentWindow = -1;
934
935 cr_server.curClient = pClient;
936
937 if (client.currentCtx && client.currentContextNumber>=0)
938 {
939 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
940 AssertRCReturn(rc, rc);
941 client.currentCtx = (CRContext*) crHashtableSearch(cr_server.contextTable, ctxID);
942 CRASSERT(client.currentCtx);
943 //pClient->currentCtx = client.currentCtx;
944 //pClient->currentContextNumber = ctxID;
945 }
946
947 if (client.currentMural && client.currentWindow>=0)
948 {
949 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
950 AssertRCReturn(rc, rc);
951 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
952 CRASSERT(client.currentMural);
953 //pClient->currentMural = client.currentMural;
954 //pClient->currentWindow = winID;
955 }
956
957 /* Restore client active context and window */
958 crServerDispatchMakeCurrent(winID, 0, ctxID);
959
960 if (0)
961 {
962 CRContext *tmpCtx;
963 CRCreateInfo_t *createInfo;
964 GLfloat one[4] = { 1, 1, 1, 1 };
965 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
966
967 crServerDispatchMakeCurrent(winID, 0, ctxID);
968
969 crHashtableWalk(client.currentCtx->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtx);
970
971 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.base1D, GL_TRUE);
972 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.base2D, GL_TRUE);
973 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.base3D, GL_TRUE);
974#ifdef CR_ARB_texture_cube_map
975 crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.baseCubeMap, GL_TRUE);
976#endif
977#ifdef CR_NV_texture_rectangle
978 //@todo this doesn't work as expected
979 //crStateTextureObjectDiff(client.currentCtx, NULL, NULL, &client.currentCtx->texture.baseRect, GL_TRUE);
980#endif
981 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
982 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
983 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
984
985 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
986 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
987 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
988
989 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
990 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
991
992 //crStateViewport( 0, 0, 600, 600 );
993 //pClient->currentMural->viewportValidated = GL_FALSE;
994 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
995
996 //crStateMatrixMode(GL_PROJECTION);
997 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
998
999 //crStateLoadIdentity();
1000 //cr_server.head_spu->dispatch_table.LoadIdentity();
1001
1002 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1003 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1004
1005 //crStateMatrixMode(GL_MODELVIEW);
1006 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
1007 //crServerDispatchLoadIdentity();
1008 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1009 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1010 //crServerDispatchLoadIdentity();
1011
1012 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
1013 CRASSERT(createInfo);
1014 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
1015 CRASSERT(tmpCtx);
1016 crStateDiffContext(tmpCtx, client.currentCtx);
1017 crStateDestroyContext(tmpCtx);*/
1018 }
1019 }
1020 }
1021
1022 //crServerDispatchMakeCurrent(-1, 0, -1);
1023
1024 cr_server.curClient = NULL;
1025
1026 {
1027 GLenum err = crServerDispatchGetError();
1028
1029 if (err != GL_NO_ERROR)
1030 {
1031 crWarning("crServer: glGetError %d after loading snapshot", err);
1032 }
1033 }
1034
1035 cr_server.bIsInLoadingState = GL_FALSE;
1036
1037 return VINF_SUCCESS;
1038}
1039
1040#define SCREEN(i) (cr_server.screen[i])
1041#define MAPPED(screen) ((screen).winID != 0)
1042
1043static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
1044{
1045 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1046 int *sIndex = (int*) data2;
1047
1048 if (pMI->screenId == *sIndex)
1049 {
1050 renderspuReparentWindow(pMI->spuWindow);
1051 }
1052}
1053
1054static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
1055{
1056 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1057 (void) data2;
1058
1059 crServerCheckMuralGeometry(pMI);
1060}
1061
1062DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
1063{
1064 int i;
1065
1066 if (sCount>CR_MAX_GUEST_MONITORS)
1067 return VERR_INVALID_PARAMETER;
1068
1069 /*Shouldn't happen yet, but to be safe in future*/
1070 for (i=0; i<cr_server.screenCount; ++i)
1071 {
1072 if (MAPPED(SCREEN(i)))
1073 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
1074 return VERR_NOT_IMPLEMENTED;
1075 }
1076
1077 cr_server.screenCount = sCount;
1078
1079 for (i=0; i<sCount; ++i)
1080 {
1081 SCREEN(i).winID = 0;
1082 }
1083
1084 return VINF_SUCCESS;
1085}
1086
1087DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
1088{
1089 if (sIndex<0 || sIndex>=cr_server.screenCount)
1090 return VERR_INVALID_PARAMETER;
1091
1092 if (MAPPED(SCREEN(sIndex)))
1093 {
1094 SCREEN(sIndex).winID = 0;
1095 renderspuSetWindowId(0);
1096
1097 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
1098 }
1099
1100 renderspuSetWindowId(SCREEN(0).winID);
1101 return VINF_SUCCESS;
1102}
1103
1104DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
1105{
1106 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u]", sIndex, x, y, w, h);
1107
1108 if (sIndex<0 || sIndex>=cr_server.screenCount)
1109 return VERR_INVALID_PARAMETER;
1110
1111 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
1112 {
1113 crDebug("Mapped screen[%i] is being remapped.", sIndex);
1114 crVBoxServerUnmapScreen(sIndex);
1115 }
1116
1117 SCREEN(sIndex).winID = winID;
1118 SCREEN(sIndex).x = x;
1119 SCREEN(sIndex).y = y;
1120 SCREEN(sIndex).w = w;
1121 SCREEN(sIndex).h = h;
1122
1123 renderspuSetWindowId(SCREEN(sIndex).winID);
1124 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
1125 renderspuSetWindowId(SCREEN(0).winID);
1126
1127 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
1128
1129#ifndef WINDOWS
1130 /*Restore FB content for clients, which have current window on a screen being remapped*/
1131 {
1132 GLint i;
1133
1134 for (i = 0; i < cr_server.numClients; i++)
1135 {
1136 cr_server.curClient = cr_server.clients[i];
1137 if (cr_server.curClient->currentCtx
1138 && cr_server.curClient->currentCtx->pImage
1139 && cr_server.curClient->currentMural
1140 && cr_server.curClient->currentMural->screenId == sIndex
1141 && cr_server.curClient->currentCtx->viewport.viewportH == h
1142 && cr_server.curClient->currentCtx->viewport.viewportW == w)
1143 {
1144 int clientWindow = cr_server.curClient->currentWindow;
1145 int clientContext = cr_server.curClient->currentContextNumber;
1146
1147 if (clientWindow && clientWindow != cr_server.currentWindow)
1148 {
1149 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
1150 }
1151
1152 crStateApplyFBImage(cr_server.curClient->currentCtx);
1153 }
1154 }
1155 cr_server.curClient = NULL;
1156 }
1157#endif
1158
1159 return VINF_SUCCESS;
1160}
1161
1162DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
1163{
1164 renderspuSetRootVisibleRegion(cRects, pRects);
1165
1166 return VINF_SUCCESS;
1167}
1168
1169DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
1170{
1171 cr_server.pfnPresentFBO = pfnPresentFBO;
1172}
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