VirtualBox

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

最後變更 在這個檔案從34382是 33988,由 vboxsync 提交於 14 年 前

crOpenGL/wddm: more multithreading fixes, vista expirience index works now

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette