VirtualBox

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

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

crOpenGL: remove unnecessary check

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