VirtualBox

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

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

3D for VRDP: initial commit (xTracker 5565).

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