VirtualBox

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

最後變更 在這個檔案從45248是 45248,由 vboxsync 提交於 12 年 前

crOpenGL/VRDP: always show 3D window unles in Headles mode

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 93.4 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 "cr_vreg.h"
16#include "cr_environment.h"
17#include "cr_pixeldata.h"
18#include "server_dispatch.h"
19#include "state/cr_texture.h"
20#include "render/renderspu.h"
21#include <signal.h>
22#include <stdlib.h>
23#define DEBUG_FP_EXCEPTIONS 0
24#if DEBUG_FP_EXCEPTIONS
25#include <fpu_control.h>
26#include <math.h>
27#endif
28#include <iprt/assert.h>
29#include <VBox/err.h>
30
31#ifdef VBOXCR_LOGFPS
32#include <iprt/timer.h>
33#endif
34
35#ifdef VBOX_WITH_CRHGSMI
36# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
37uint8_t* g_pvVRamBase = NULL;
38uint32_t g_cbVRam = 0;
39HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion = NULL;
40PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion = NULL;
41#endif
42
43/**
44 * \mainpage CrServerLib
45 *
46 * \section CrServerLibIntroduction Introduction
47 *
48 * Chromium consists of all the top-level files in the cr
49 * directory. The core module basically takes care of API dispatch,
50 * and OpenGL state management.
51 */
52
53
54/**
55 * CRServer global data
56 */
57CRServer cr_server;
58
59int tearingdown = 0; /* can't be static */
60
61DECLINLINE(int32_t) crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
62{
63 CRClient *pClient = NULL;
64 int32_t i;
65
66 *ppClient = NULL;
67
68 for (i = 0; i < cr_server.numClients; i++)
69 {
70 if (cr_server.clients[i] && cr_server.clients[i]->conn
71 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
72 {
73 pClient = cr_server.clients[i];
74 break;
75 }
76 }
77 if (!pClient)
78 {
79 crWarning("client not found!");
80 return VERR_INVALID_PARAMETER;
81 }
82
83 if (!pClient->conn->vMajor)
84 {
85 crWarning("no major version specified for client!");
86 return VERR_NOT_SUPPORTED;
87 }
88
89 *ppClient = pClient;
90
91 return VINF_SUCCESS;
92}
93
94
95/**
96 * Return pointer to server's first SPU.
97 */
98SPU*
99crServerHeadSPU(void)
100{
101 return cr_server.head_spu;
102}
103
104
105
106static void DeleteBarrierCallback( void *data )
107{
108 CRServerBarrier *barrier = (CRServerBarrier *) data;
109 crFree(barrier->waiting);
110 crFree(barrier);
111}
112
113
114static void deleteContextInfoCallback( void *data )
115{
116 CRContextInfo *c = (CRContextInfo *) data;
117 crStateDestroyContext(c->pContext);
118 if (c->CreateInfo.pszDpyName)
119 crFree(c->CreateInfo.pszDpyName);
120 crFree(c);
121}
122
123static void deleteMuralInfoCallback( void *data )
124{
125 CRMuralInfo *m = (CRMuralInfo *) data;
126 if (m->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID) /* <- do not do term for default mural as it does not contain any info to be freed,
127 * and renderspu will destroy it up itself*/
128 {
129 crServerMuralTerm(m);
130 }
131 crFree(m);
132}
133
134static void crServerTearDown( void )
135{
136 GLint i;
137 CRClientNode *pNode, *pNext;
138
139 /* avoid a race condition */
140 if (tearingdown)
141 return;
142
143 tearingdown = 1;
144
145 crStateSetCurrent( NULL );
146
147 cr_server.curClient = NULL;
148 cr_server.run_queue = NULL;
149
150 crFree( cr_server.overlap_intens );
151 cr_server.overlap_intens = NULL;
152
153 /* needed to make sure window dummy mural not get created on mural destruction
154 * and generally this should be zeroed up */
155 cr_server.currentCtxInfo = NULL;
156 cr_server.currentWindow = 0;
157 cr_server.currentNativeWindow = 0;
158 cr_server.currentMural = NULL;
159
160 if (CrBltIsInitialized(&cr_server.Blitter))
161 {
162 CrBltTerm(&cr_server.Blitter);
163 }
164
165 /* sync our state with renderspu,
166 * do it before mural & context deletion to avoid deleting currently set murals/contexts*/
167 cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
168
169 /* Deallocate all semaphores */
170 crFreeHashtable(cr_server.semaphores, crFree);
171 cr_server.semaphores = NULL;
172
173 /* Deallocate all barriers */
174 crFreeHashtable(cr_server.barriers, DeleteBarrierCallback);
175 cr_server.barriers = NULL;
176
177 /* Free all context info */
178 crFreeHashtable(cr_server.contextTable, deleteContextInfoCallback);
179
180 /* Free vertex programs */
181 crFreeHashtable(cr_server.programTable, crFree);
182
183 /* Free dummy murals */
184 crFreeHashtable(cr_server.dummyMuralTable, deleteMuralInfoCallback);
185
186 /* Free murals */
187 crFreeHashtable(cr_server.muralTable, deleteMuralInfoCallback);
188
189 for (i = 0; i < cr_server.numClients; i++) {
190 if (cr_server.clients[i]) {
191 CRConnection *conn = cr_server.clients[i]->conn;
192 crNetFreeConnection(conn);
193 crFree(cr_server.clients[i]);
194 }
195 }
196 cr_server.numClients = 0;
197
198 pNode = cr_server.pCleanupClient;
199 while (pNode)
200 {
201 pNext=pNode->next;
202 crFree(pNode->pClient);
203 crFree(pNode);
204 pNode=pNext;
205 }
206 cr_server.pCleanupClient = NULL;
207
208#if 1
209 /* disable these two lines if trying to get stack traces with valgrind */
210 crSPUUnloadChain(cr_server.head_spu);
211 cr_server.head_spu = NULL;
212#endif
213
214 crStateDestroy();
215
216 crNetTearDown();
217
218 VBoxVrListClear(&cr_server.RootVr);
219
220 VBoxVrTerm();
221}
222
223static void crServerClose( unsigned int id )
224{
225 crError( "Client disconnected!" );
226 (void) id;
227}
228
229static void crServerCleanup( int sigio )
230{
231 crServerTearDown();
232
233 tearingdown = 0;
234}
235
236
237void
238crServerSetPort(int port)
239{
240 cr_server.tcpip_port = port;
241}
242
243
244
245static void
246crPrintHelp(void)
247{
248 printf("Usage: crserver [OPTIONS]\n");
249 printf("Options:\n");
250 printf(" -mothership URL Specifies URL for contacting the mothership.\n");
251 printf(" URL is of the form [protocol://]hostname[:port]\n");
252 printf(" -port N Specifies the port number this server will listen to.\n");
253 printf(" -help Prints this information.\n");
254}
255
256
257/**
258 * Do CRServer initializations. After this, we can begin servicing clients.
259 */
260void
261crServerInit(int argc, char *argv[])
262{
263 int i;
264 const char*env;
265 char *mothership = NULL;
266 CRMuralInfo *defaultMural;
267 int rc = VBoxVrInit();
268 if (!RT_SUCCESS(rc))
269 {
270 crWarning("VBoxVrInit failed, rc %d", rc);
271 return;
272 }
273
274 for (i = 1 ; i < argc ; i++)
275 {
276 if (!crStrcmp( argv[i], "-mothership" ))
277 {
278 if (i == argc - 1)
279 {
280 crError( "-mothership requires an argument" );
281 }
282 mothership = argv[i+1];
283 i++;
284 }
285 else if (!crStrcmp( argv[i], "-port" ))
286 {
287 /* This is the port on which we'll accept client connections */
288 if (i == argc - 1)
289 {
290 crError( "-port requires an argument" );
291 }
292 cr_server.tcpip_port = crStrToInt(argv[i+1]);
293 i++;
294 }
295 else if (!crStrcmp( argv[i], "-vncmode" ))
296 {
297 cr_server.vncMode = 1;
298 }
299 else if (!crStrcmp( argv[i], "-help" ))
300 {
301 crPrintHelp();
302 exit(0);
303 }
304 }
305
306 signal( SIGTERM, crServerCleanup );
307 signal( SIGINT, crServerCleanup );
308#ifndef WINDOWS
309 signal( SIGPIPE, SIG_IGN );
310#endif
311
312#if DEBUG_FP_EXCEPTIONS
313 {
314 fpu_control_t mask;
315 _FPU_GETCW(mask);
316 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
317 | _FPU_MASK_OM | _FPU_MASK_UM);
318 _FPU_SETCW(mask);
319 }
320#endif
321
322 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
323
324 if (cr_server.bUseMultipleContexts)
325 {
326 crInfo("Info: using multiple contexts!");
327 crDebug("Debug: using multiple contexts!");
328 }
329
330 cr_server.firstCallCreateContext = GL_TRUE;
331 cr_server.firstCallMakeCurrent = GL_TRUE;
332 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
333
334 /*
335 * Create default mural info and hash table.
336 */
337 cr_server.muralTable = crAllocHashtable();
338 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
339 defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
340 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
341
342 cr_server.programTable = crAllocHashtable();
343
344 crNetInit(crServerRecv, crServerClose);
345 crStateInit();
346
347 crServerSetVBoxConfiguration();
348
349 crStateLimitsInit( &(cr_server.limits) );
350
351 /*
352 * Default context
353 */
354 cr_server.contextTable = crAllocHashtable();
355 cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
356
357 cr_server.dummyMuralTable = crAllocHashtable();
358
359 cr_server.fRootVrOn = GL_FALSE;
360 VBoxVrListInit(&cr_server.RootVr);
361 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
362
363 env = crGetenv("CR_SERVER_BFB");
364 if (env)
365 {
366 cr_server.fBlitterMode = env[0] - '0';
367 }
368 else
369 {
370 cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED;
371 }
372 crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter));
373
374 crServerInitDispatch();
375 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
376
377 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
378 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
379
380 cr_server.barriers = crAllocHashtable();
381 cr_server.semaphores = crAllocHashtable();
382}
383
384void crVBoxServerTearDown(void)
385{
386 crServerTearDown();
387}
388
389/**
390 * Do CRServer initializations. After this, we can begin servicing clients.
391 */
392GLboolean crVBoxServerInit(void)
393{
394 CRMuralInfo *defaultMural;
395 const char*env;
396 int rc = VBoxVrInit();
397 if (!RT_SUCCESS(rc))
398 {
399 crWarning("VBoxVrInit failed, rc %d", rc);
400 return GL_FALSE;
401 }
402
403#if DEBUG_FP_EXCEPTIONS
404 {
405 fpu_control_t mask;
406 _FPU_GETCW(mask);
407 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
408 | _FPU_MASK_OM | _FPU_MASK_UM);
409 _FPU_SETCW(mask);
410 }
411#endif
412
413 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
414
415 if (cr_server.bUseMultipleContexts)
416 {
417 crInfo("Info: using multiple contexts!");
418 crDebug("Debug: using multiple contexts!");
419 }
420
421 crNetInit(crServerRecv, crServerClose);
422
423 cr_server.firstCallCreateContext = GL_TRUE;
424 cr_server.firstCallMakeCurrent = GL_TRUE;
425
426 cr_server.bIsInLoadingState = GL_FALSE;
427 cr_server.bIsInSavingState = GL_FALSE;
428 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
429
430 cr_server.pCleanupClient = NULL;
431
432 /*
433 * Create default mural info and hash table.
434 */
435 cr_server.muralTable = crAllocHashtable();
436 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
437 defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
438 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
439
440 cr_server.programTable = crAllocHashtable();
441
442 crStateInit();
443
444 crStateLimitsInit( &(cr_server.limits) );
445
446 cr_server.barriers = crAllocHashtable();
447 cr_server.semaphores = crAllocHashtable();
448
449 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
450 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
451
452 /*
453 * Default context
454 */
455 cr_server.contextTable = crAllocHashtable();
456
457 cr_server.dummyMuralTable = crAllocHashtable();
458
459 cr_server.fRootVrOn = GL_FALSE;
460 VBoxVrListInit(&cr_server.RootVr);
461 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
462
463 env = crGetenv("CR_SERVER_BFB");
464 if (env)
465 {
466 cr_server.fBlitterMode = env[0] - '0';
467 }
468 else
469 {
470 cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED;
471 }
472 crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter));
473
474 crServerSetVBoxConfigurationHGCM();
475
476 if (!cr_server.head_spu)
477 return GL_FALSE;
478
479 crServerInitDispatch();
480 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
481
482 /*Check for PBO support*/
483 if (crStateGetCurrent()->extensions.ARB_pixel_buffer_object)
484 {
485 cr_server.bUsePBOForReadback=GL_TRUE;
486 }
487
488 return GL_TRUE;
489}
490
491int32_t crVBoxServerAddClient(uint32_t u32ClientID)
492{
493 CRClient *newClient;
494
495 if (cr_server.numClients>=CR_MAX_CLIENTS)
496 {
497 return VERR_MAX_THRDS_REACHED;
498 }
499
500 newClient = (CRClient *) crCalloc(sizeof(CRClient));
501 crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
502
503 newClient->spu_id = 0;
504 newClient->currentCtxInfo = &cr_server.MainContextInfo;
505 newClient->currentContextNumber = -1;
506 newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
507 cr_server.tcpip_port,
508 cr_server.mtu, 0);
509 newClient->conn->u32ClientID = u32ClientID;
510
511 cr_server.clients[cr_server.numClients++] = newClient;
512
513 crServerAddToRunQueue(newClient);
514
515 return VINF_SUCCESS;
516}
517
518void crVBoxServerRemoveClient(uint32_t u32ClientID)
519{
520 CRClient *pClient=NULL;
521 int32_t i;
522
523 crDebug("crServer: RemoveClient u32ClientID=%d", u32ClientID);
524
525 for (i = 0; i < cr_server.numClients; i++)
526 {
527 if (cr_server.clients[i] && cr_server.clients[i]->conn
528 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
529 {
530 pClient = cr_server.clients[i];
531 break;
532 }
533 }
534 //if (!pClient) return VERR_INVALID_PARAMETER;
535 if (!pClient)
536 {
537 crWarning("Invalid client id %u passed to crVBoxServerRemoveClient", u32ClientID);
538 return;
539 }
540
541#ifdef VBOX_WITH_CRHGSMI
542 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
543#endif
544
545 /* Disconnect the client */
546 pClient->conn->Disconnect(pClient->conn);
547
548 /* Let server clear client from the queue */
549 crServerDeleteClient(pClient);
550}
551
552static int32_t crVBoxServerInternalClientWriteRead(CRClient *pClient)
553{
554#ifdef VBOXCR_LOGFPS
555 uint64_t tstart, tend;
556#endif
557
558 /*crDebug("=>crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
559
560
561#ifdef VBOXCR_LOGFPS
562 tstart = RTTimeNanoTS();
563#endif
564
565 /* This should be setup already */
566 CRASSERT(pClient->conn->pBuffer);
567 CRASSERT(pClient->conn->cbBuffer);
568#ifdef VBOX_WITH_CRHGSMI
569 CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&pClient->conn->CmdData);
570#endif
571
572 if (
573#ifdef VBOX_WITH_CRHGSMI
574 !CRVBOXHGSMI_CMDDATA_IS_SET(&pClient->conn->CmdData) &&
575#endif
576 cr_server.run_queue->client != pClient
577 && crServerClientInBeginEnd(cr_server.run_queue->client))
578 {
579 crDebug("crServer: client %d blocked, allow_redir_ptr = 0", pClient->conn->u32ClientID);
580 pClient->conn->allow_redir_ptr = 0;
581 }
582 else
583 {
584 pClient->conn->allow_redir_ptr = 1;
585 }
586
587 crNetRecv();
588 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
589 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
590
591 crServerServiceClients();
592
593#if 0
594 if (pClient->currentMural) {
595 crStateViewport( 0, 0, 500, 500 );
596 pClient->currentMural->viewportValidated = GL_FALSE;
597 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 500, 500 );
598 crStateViewport( 0, 0, 600, 600 );
599 pClient->currentMural->viewportValidated = GL_FALSE;
600 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
601
602 crStateMatrixMode(GL_PROJECTION);
603 cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
604 crServerDispatchLoadIdentity();
605 crStateFrustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
606 cr_server.head_spu->dispatch_table.Frustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
607 crServerDispatchLoadIdentity();
608 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
609 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
610
611 crStateMatrixMode(GL_MODELVIEW);
612 cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
613 crServerDispatchLoadIdentity();
614 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
615 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
616 crServerDispatchLoadIdentity();
617 }
618#endif
619
620 crStateResetCurrentPointers(&cr_server.current);
621
622#ifndef VBOX_WITH_CRHGSMI
623 CRASSERT(!pClient->conn->allow_redir_ptr || crNetNumMessages(pClient->conn)==0);
624#endif
625
626#ifdef VBOXCR_LOGFPS
627 tend = RTTimeNanoTS();
628 pClient->timeUsed += tend-tstart;
629#endif
630 /*crDebug("<=crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
631
632 return VINF_SUCCESS;
633}
634
635
636int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer)
637{
638 CRClient *pClient=NULL;
639 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
640
641 if (RT_FAILURE(rc))
642 return rc;
643
644
645 CRASSERT(pBuffer);
646
647 /* This should never fire unless we start to multithread */
648 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
649
650 pClient->conn->pBuffer = pBuffer;
651 pClient->conn->cbBuffer = cbBuffer;
652#ifdef VBOX_WITH_CRHGSMI
653 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
654#endif
655
656 return crVBoxServerInternalClientWriteRead(pClient);
657}
658
659int32_t crVBoxServerInternalClientRead(CRClient *pClient, uint8_t *pBuffer, uint32_t *pcbBuffer)
660{
661 if (pClient->conn->cbHostBuffer > *pcbBuffer)
662 {
663 crDebug("crServer: [%lx] ClientRead u32ClientID=%d FAIL, host buffer too small %d of %d",
664 crThreadID(), pClient->conn->u32ClientID, *pcbBuffer, pClient->conn->cbHostBuffer);
665
666 /* Return the size of needed buffer */
667 *pcbBuffer = pClient->conn->cbHostBuffer;
668
669 return VERR_BUFFER_OVERFLOW;
670 }
671
672 *pcbBuffer = pClient->conn->cbHostBuffer;
673
674 if (*pcbBuffer)
675 {
676 CRASSERT(pClient->conn->pHostBuffer);
677
678 crMemcpy(pBuffer, pClient->conn->pHostBuffer, *pcbBuffer);
679 pClient->conn->cbHostBuffer = 0;
680 }
681
682 return VINF_SUCCESS;
683}
684
685int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t *pcbBuffer)
686{
687 CRClient *pClient=NULL;
688 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
689
690 if (RT_FAILURE(rc))
691 return rc;
692
693#ifdef VBOX_WITH_CRHGSMI
694 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
695#endif
696
697 return crVBoxServerInternalClientRead(pClient, pBuffer, pcbBuffer);
698}
699
700int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor)
701{
702 CRClient *pClient=NULL;
703 int32_t i;
704
705 for (i = 0; i < cr_server.numClients; i++)
706 {
707 if (cr_server.clients[i] && cr_server.clients[i]->conn
708 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
709 {
710 pClient = cr_server.clients[i];
711 break;
712 }
713 }
714 if (!pClient) return VERR_INVALID_PARAMETER;
715
716 pClient->conn->vMajor = vMajor;
717 pClient->conn->vMinor = vMinor;
718
719 if (vMajor != CR_PROTOCOL_VERSION_MAJOR
720 || vMinor != CR_PROTOCOL_VERSION_MINOR)
721 {
722 return VERR_NOT_SUPPORTED;
723 }
724 else return VINF_SUCCESS;
725}
726
727int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid)
728{
729 CRClient *pClient=NULL;
730 int32_t i;
731
732 for (i = 0; i < cr_server.numClients; i++)
733 {
734 if (cr_server.clients[i] && cr_server.clients[i]->conn
735 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
736 {
737 pClient = cr_server.clients[i];
738 break;
739 }
740 }
741 if (!pClient) return VERR_INVALID_PARAMETER;
742
743 pClient->pid = pid;
744
745 return VINF_SUCCESS;
746}
747
748int
749CRServerMain(int argc, char *argv[])
750{
751 crServerInit(argc, argv);
752
753 crServerSerializeRemoteStreams();
754
755 crServerTearDown();
756
757 tearingdown = 0;
758
759 return 0;
760}
761
762static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2)
763{
764 CRMuralInfo *pMI = (CRMuralInfo*) data1;
765 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
766 int32_t rc;
767
768 CRASSERT(pMI && pSSM);
769
770 /* Don't store default mural */
771 if (!key) return;
772
773 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
774 CRASSERT(rc == VINF_SUCCESS);
775
776 rc = SSMR3PutMem(pSSM, pMI, RT_OFFSETOF(CRMuralInfo, CreateInfo));
777 CRASSERT(rc == VINF_SUCCESS);
778
779 if (pMI->pVisibleRects)
780 {
781 rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects);
782 }
783
784 rc = SSMR3PutMem(pSSM, pMI->ctxUsage, sizeof (pMI->ctxUsage));
785 CRASSERT(rc == VINF_SUCCESS);
786}
787
788/* @todo add hashtable walker with result info and intermediate abort */
789static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *data2)
790{
791 CRCreateInfo_t *pCreateInfo = (CRCreateInfo_t *)data1;
792 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
793 int32_t rc;
794
795 CRASSERT(pCreateInfo && pSSM);
796
797 /* Don't store default mural create info */
798 if (!key) return;
799
800 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
801 CRASSERT(rc == VINF_SUCCESS);
802
803 rc = SSMR3PutMem(pSSM, pCreateInfo, sizeof(*pCreateInfo));
804 CRASSERT(rc == VINF_SUCCESS);
805
806 if (pCreateInfo->pszDpyName)
807 {
808 rc = SSMR3PutStrZ(pSSM, pCreateInfo->pszDpyName);
809 CRASSERT(rc == VINF_SUCCESS);
810 }
811}
812
813static void crVBoxServerSaveCreateInfoFromMuralInfoCB(unsigned long key, void *data1, void *data2)
814{
815 CRMuralInfo *pMural = (CRMuralInfo *)data1;
816 CRCreateInfo_t *pCreateInfo = &pMural->CreateInfo;
817 crVBoxServerSaveCreateInfoCB(key, pCreateInfo, data2);
818}
819
820static void crVBoxServerSaveCreateInfoFromCtxInfoCB(unsigned long key, void *data1, void *data2)
821{
822 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
823 CRCreateInfo_t CreateInfo = pContextInfo->CreateInfo;
824 /* saved state contains internal id */
825 CreateInfo.externalID = pContextInfo->pContext->id;
826 crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
827}
828
829static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data2)
830{
831 CRTextureObj *pTexture = (CRTextureObj *) data1;
832 CRContext *pContext = (CRContext *) data2;
833
834 CRASSERT(pTexture && pContext);
835 crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
836}
837
838typedef struct CRVBOX_SAVE_STATE_GLOBAL
839{
840 /* context id -> mural association
841 * on context data save, each context will be made current with the corresponding mural from this table
842 * thus saving the mural front & back buffer data */
843 CRHashTable *contextMuralTable;
844 /* mural id -> context info
845 * for murals that do not have associated context in contextMuralTable
846 * we still need to save*/
847 CRHashTable *additionalMuralContextTable;
848
849 PSSMHANDLE pSSM;
850
851 int rc;
852} CRVBOX_SAVE_STATE_GLOBAL, *PCRVBOX_SAVE_STATE_GLOBAL;
853
854
855typedef struct CRVBOX_CTXWND_CTXWALKER_CB
856{
857 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
858 CRHashTable *usedMuralTable;
859 GLuint cAdditionalMurals;
860} CRVBOX_CTXWND_CTXWALKER_CB, *PCRVBOX_CTXWND_CTXWALKER_CB;
861
862static void crVBoxServerBuildAdditionalWindowContextMapCB(unsigned long key, void *data1, void *data2)
863{
864 CRMuralInfo * pMural = (CRMuralInfo *) data1;
865 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
866 CRContextInfo *pContextInfo = NULL;
867
868 if (!pMural->CreateInfo.externalID)
869 {
870 CRASSERT(!key);
871 return;
872 }
873
874 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
875 {
876 Assert(crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
877 return;
878 }
879
880 Assert(!crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
881
882 if (cr_server.MainContextInfo.CreateInfo.visualBits == pMural->CreateInfo.visualBits)
883 {
884 pContextInfo = &cr_server.MainContextInfo;
885 }
886 else
887 {
888 crWarning("different visual bits not implemented!");
889 pContextInfo = &cr_server.MainContextInfo;
890 }
891
892 crHashtableAdd(pData->pGlobal->additionalMuralContextTable, pMural->CreateInfo.externalID, pContextInfo);
893}
894
895
896typedef struct CRVBOX_CTXWND_WNDWALKER_CB
897{
898 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
899 CRHashTable *usedMuralTable;
900 CRContextInfo *pContextInfo;
901 CRMuralInfo * pMural;
902} CRVBOX_CTXWND_WNDWALKER_CB, *PCRVBOX_CTXWND_WNDWALKER_CB;
903
904static void crVBoxServerBuildContextWindowMapWindowWalkerCB(unsigned long key, void *data1, void *data2)
905{
906 CRMuralInfo * pMural = (CRMuralInfo *) data1;
907 PCRVBOX_CTXWND_WNDWALKER_CB pData = (PCRVBOX_CTXWND_WNDWALKER_CB)data2;
908
909 Assert(pData->pMural != pMural);
910 Assert(pData->pContextInfo);
911
912 if (pData->pMural)
913 return;
914
915 if (!pMural->CreateInfo.externalID)
916 {
917 CRASSERT(!key);
918 return;
919 }
920
921 if (!CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pData->pContextInfo->pContext))
922 return;
923
924 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
925 return;
926
927 CRASSERT(pMural->CreateInfo.visualBits == pData->pContextInfo->CreateInfo.visualBits);
928 pData->pMural = pMural;
929}
930
931static void crVBoxServerBuildContextUsedWindowMapCB(unsigned long key, void *data1, void *data2)
932{
933 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
934 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
935
936 if (!pContextInfo->currentMural)
937 return;
938
939 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pContextInfo->currentMural);
940 crHashtableAdd(pData->usedMuralTable, pContextInfo->currentMural->CreateInfo.externalID, pContextInfo->currentMural);
941}
942
943CRMuralInfo * crServerGetDummyMural(GLint visualBits)
944{
945 CRMuralInfo * pMural = (CRMuralInfo *)crHashtableSearch(cr_server.dummyMuralTable, visualBits);
946 if (!pMural)
947 {
948 GLint id;
949 pMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
950 if (!pMural)
951 {
952 crWarning("crCalloc failed!");
953 return NULL;
954 }
955 id = crServerMuralInit(pMural, "", visualBits, -1);
956 if (id < 0)
957 {
958 crWarning("crServerMuralInit failed!");
959 crFree(pMural);
960 return NULL;
961 }
962
963 crHashtableAdd(cr_server.dummyMuralTable, visualBits, pMural);
964 }
965
966 return pMural;
967}
968
969static void crVBoxServerBuildContextUnusedWindowMapCB(unsigned long key, void *data1, void *data2)
970{
971 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
972 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
973 CRMuralInfo * pMural = NULL;
974
975 if (pContextInfo->currentMural)
976 return;
977
978 Assert(crHashtableNumElements(pData->pGlobal->contextMuralTable) <= crHashtableNumElements(cr_server.muralTable) - 1);
979 if (crHashtableNumElements(pData->pGlobal->contextMuralTable) < crHashtableNumElements(cr_server.muralTable) - 1)
980 {
981 CRVBOX_CTXWND_WNDWALKER_CB MuralData;
982 MuralData.pGlobal = pData->pGlobal;
983 MuralData.usedMuralTable = pData->usedMuralTable;
984 MuralData.pContextInfo = pContextInfo;
985 MuralData.pMural = NULL;
986
987 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildContextWindowMapWindowWalkerCB, &MuralData);
988
989 pMural = MuralData.pMural;
990
991 }
992
993 if (!pMural)
994 {
995 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
996 if (!pMural)
997 {
998 crWarning("crServerGetDummyMural failed");
999 return;
1000 }
1001 }
1002 else
1003 {
1004 crHashtableAdd(pData->usedMuralTable, pMural->CreateInfo.externalID, pMural);
1005 ++pData->cAdditionalMurals;
1006 }
1007
1008 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pMural);
1009}
1010
1011static void crVBoxServerBuildSaveStateGlobal(PCRVBOX_SAVE_STATE_GLOBAL pGlobal)
1012{
1013 CRVBOX_CTXWND_CTXWALKER_CB Data;
1014 GLuint cMurals;
1015 pGlobal->contextMuralTable = crAllocHashtable();
1016 pGlobal->additionalMuralContextTable = crAllocHashtable();
1017 /* 1. go through all contexts and match all having currentMural set */
1018 Data.pGlobal = pGlobal;
1019 Data.usedMuralTable = crAllocHashtable();
1020 Data.cAdditionalMurals = 0;
1021 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUsedWindowMapCB, &Data);
1022
1023 cMurals = crHashtableNumElements(pGlobal->contextMuralTable);
1024 CRASSERT(cMurals <= crHashtableNumElements(cr_server.contextTable));
1025 CRASSERT(cMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
1026 CRASSERT(cMurals == crHashtableNumElements(Data.usedMuralTable));
1027 if (cMurals < crHashtableNumElements(cr_server.contextTable))
1028 {
1029 Data.cAdditionalMurals = 0;
1030 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUnusedWindowMapCB, &Data);
1031 }
1032
1033 CRASSERT(crHashtableNumElements(pGlobal->contextMuralTable) == crHashtableNumElements(cr_server.contextTable));
1034 CRASSERT(cMurals + Data.cAdditionalMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
1035 if (cMurals + Data.cAdditionalMurals < crHashtableNumElements(cr_server.muralTable) - 1)
1036 {
1037 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildAdditionalWindowContextMapCB, &Data);
1038 CRASSERT(cMurals + Data.cAdditionalMurals + crHashtableNumElements(pGlobal->additionalMuralContextTable) == crHashtableNumElements(cr_server.muralTable) - 1);
1039 }
1040
1041 crFreeHashtable(Data.usedMuralTable, NULL);
1042}
1043
1044static void crVBoxServerFBImageDataTerm(CRFBData *pData)
1045{
1046 GLuint i;
1047 for (i = 0; i < pData->cElements; ++i)
1048 {
1049 CRFBDataElement * pEl = &pData->aElements[i];
1050 if (pEl->pvData)
1051 {
1052 crFree(pEl->pvData);
1053 /* sanity */
1054 pEl->pvData = NULL;
1055 }
1056 }
1057 pData->cElements = 0;
1058}
1059
1060static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, uint32_t version, GLuint overrideWidth, GLuint overrideHeight)
1061{
1062 CRContext *pContext;
1063 GLuint i;
1064 GLfloat *pF;
1065 CRFBDataElement *pEl;
1066 GLuint width;
1067 GLuint height;
1068
1069 crMemset(pData, 0, sizeof (*pData));
1070
1071 pContext = pCtxInfo->pContext;
1072
1073 /* the version should be always actual when we do reads,
1074 * i.e. it could differ on writes when snapshot is getting loaded */
1075 CRASSERT(fWrite || version == SHCROGL_SSM_VERSION);
1076
1077 width = overrideWidth ? overrideWidth : pMural->width;
1078 height = overrideHeight ? overrideHeight : pMural->height;
1079
1080 if (!width || !height)
1081 return VINF_SUCCESS;
1082
1083 pData->idFBO = (pMural->fPresentMode & CR_SERVER_REDIR_F_FBO) ? pMural->aidColorTexs[fWrite ? pMural->iCurDrawBuffer : pMural->iCurReadBuffer] : 0;
1084 pData->cElements = 0;
1085
1086 pEl = &pData->aElements[pData->cElements];
1087 pEl->idFBO = (pMural->fPresentMode & CR_SERVER_REDIR_F_FBO) ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1088 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT;
1089 pEl->posX = 0;
1090 pEl->posY = 0;
1091 pEl->width = width;
1092 pEl->height = height;
1093 pEl->enmFormat = GL_RGBA;
1094 pEl->enmType = GL_UNSIGNED_BYTE;
1095 pEl->cbData = width * height * 4;
1096 pEl->pvData = crCalloc(pEl->cbData);
1097 if (!pEl->pvData)
1098 {
1099 crVBoxServerFBImageDataTerm(pData);
1100 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1101 return VERR_NO_MEMORY;
1102 }
1103 ++pData->cElements;
1104
1105 /* there is a lot of code that assumes we have double buffering, just assert here to print a warning in the log
1106 * so that we know that something irregular is going on */
1107 CRASSERT(pCtxInfo->CreateInfo.visualBits & CR_DOUBLE_BIT);
1108 if ((pCtxInfo->CreateInfo.visualBits & CR_DOUBLE_BIT)
1109 || version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL /* <- older version had a typo which lead to back always being used,
1110 * no matter what the visual bits are */
1111 )
1112 {
1113 pEl = &pData->aElements[pData->cElements];
1114 pEl->idFBO = (pMural->fPresentMode & CR_SERVER_REDIR_F_FBO) ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0;
1115 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK;
1116 pEl->posX = 0;
1117 pEl->posY = 0;
1118 pEl->width = width;
1119 pEl->height = height;
1120 pEl->enmFormat = GL_RGBA;
1121 pEl->enmType = GL_UNSIGNED_BYTE;
1122 pEl->cbData = width * height * 4;
1123 pEl->pvData = crCalloc(pEl->cbData);
1124 if (!pEl->pvData)
1125 {
1126 crVBoxServerFBImageDataTerm(pData);
1127 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1128 return VERR_NO_MEMORY;
1129 }
1130 ++pData->cElements;
1131 }
1132
1133 if (version < SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1134 return VINF_SUCCESS;
1135
1136
1137 if (version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL)
1138 {
1139/* if (pCtxInfo->CreateInfo.visualBits & CR_DEPTH_BIT) */ /* <- older version had a typo which lead to back always being used,
1140 * no matter what the visual bits are */
1141 {
1142 AssertCompile(sizeof (GLfloat) == 4);
1143 pEl = &pData->aElements[pData->cElements];
1144 pEl->idFBO = (pMural->fPresentMode & CR_SERVER_REDIR_F_FBO) ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1145 pEl->enmBuffer = 0; /* we do not care */
1146 pEl->posX = 0;
1147 pEl->posY = 0;
1148 pEl->width = width;
1149 pEl->height = height;
1150 pEl->enmFormat = GL_DEPTH_COMPONENT;
1151 pEl->enmType = GL_FLOAT;
1152 pEl->cbData = width * height * 4;
1153 pEl->pvData = crCalloc(pEl->cbData);
1154 if (!pEl->pvData)
1155 {
1156 crVBoxServerFBImageDataTerm(pData);
1157 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1158 return VERR_NO_MEMORY;
1159 }
1160
1161 /* init to default depth value, just in case */
1162 pF = (GLfloat*)pEl->pvData;
1163 for (i = 0; i < width * height; ++i)
1164 {
1165 pF[i] = 1.;
1166 }
1167 ++pData->cElements;
1168 }
1169
1170 /* if (pCtxInfo->CreateInfo.visualBits & CR_STENCIL_BIT) */ /* <- older version had a typo which lead to back always being used,
1171 * no matter what the visual bits are */
1172 {
1173 AssertCompile(sizeof (GLuint) == 4);
1174 pEl = &pData->aElements[pData->cElements];
1175 pEl->idFBO = (pMural->fPresentMode & CR_SERVER_REDIR_F_FBO) ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1176 pEl->enmBuffer = 0; /* we do not care */
1177 pEl->posX = 0;
1178 pEl->posY = 0;
1179 pEl->width = width;
1180 pEl->height = height;
1181 pEl->enmFormat = GL_STENCIL_INDEX;
1182 pEl->enmType = GL_UNSIGNED_INT;
1183 pEl->cbData = width * height * 4;
1184 pEl->pvData = crCalloc(pEl->cbData);
1185 if (!pEl->pvData)
1186 {
1187 crVBoxServerFBImageDataTerm(pData);
1188 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1189 return VERR_NO_MEMORY;
1190 }
1191 ++pData->cElements;
1192 }
1193 return VINF_SUCCESS;
1194 }
1195
1196 if ((pCtxInfo->CreateInfo.visualBits & CR_STENCIL_BIT)
1197 || (pCtxInfo->CreateInfo.visualBits & CR_DEPTH_BIT))
1198 {
1199 pEl = &pData->aElements[pData->cElements];
1200 pEl->idFBO = (pMural->fPresentMode & CR_SERVER_REDIR_F_FBO) ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1201 pEl->enmBuffer = 0; /* we do not care */
1202 pEl->posX = 0;
1203 pEl->posY = 0;
1204 pEl->width = width;
1205 pEl->height = height;
1206 pEl->enmFormat = GL_DEPTH_STENCIL;
1207 pEl->enmType = GL_UNSIGNED_INT_24_8;
1208 pEl->cbData = width * height * 4;
1209 pEl->pvData = crCalloc(pEl->cbData);
1210 if (!pEl->pvData)
1211 {
1212 crVBoxServerFBImageDataTerm(pData);
1213 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1214 return VERR_NO_MEMORY;
1215 }
1216 ++pData->cElements;
1217 }
1218 return VINF_SUCCESS;
1219}
1220
1221static int crVBoxServerFBImageDataInit(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite)
1222{
1223 return crVBoxServerFBImageDataInitEx(pData, pCtxInfo, pMural, fWrite, SHCROGL_SSM_VERSION, 0, 0);
1224}
1225
1226static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
1227{
1228 CRContextInfo *pCtxInfo;
1229 CRContext *pContext;
1230 CRMuralInfo *pMural;
1231 int32_t rc;
1232 GLuint i;
1233 struct
1234 {
1235 CRFBData data;
1236 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1237 } Data;
1238
1239 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1240
1241 pCtxInfo = cr_server.currentCtxInfo;
1242 pContext = pCtxInfo->pContext;
1243 pMural = pCtxInfo->currentMural;
1244
1245 rc = crVBoxServerFBImageDataInit(&Data.data, pCtxInfo, pMural, GL_FALSE);
1246 if (!RT_SUCCESS(rc))
1247 {
1248 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1249 return rc;
1250 }
1251
1252 rc = crStateAcquireFBImage(pContext, &Data.data);
1253 AssertRCReturn(rc, rc);
1254
1255 for (i = 0; i < Data.data.cElements; ++i)
1256 {
1257 CRFBDataElement * pEl = &Data.data.aElements[i];
1258 rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
1259 AssertRCReturn(rc, rc);
1260 }
1261
1262 crVBoxServerFBImageDataTerm(&Data.data);
1263
1264 return VINF_SUCCESS;
1265}
1266
1267#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
1268 if(!RT_SUCCESS((_rc))) { \
1269 AssertFailed(); \
1270 return; \
1271 } \
1272 } while (0)
1273
1274static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
1275{
1276 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1277 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1278 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1279 PSSMHANDLE pSSM = pData->pSSM;
1280 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1281 CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
1282
1283 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1284
1285 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1286
1287 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1288 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1289
1290 pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
1291 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1292
1293 crServerPerformMakeCurrent(pMural, pContextInfo);
1294
1295 pData->rc = crVBoxServerSaveFBImage(pSSM);
1296
1297 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1298 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1299 pContextInfo->currentMural = pInitialCurMural;
1300
1301 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1302}
1303
1304static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
1305{
1306 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1307 CRContext *pContext = pContextInfo->pContext;
1308 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1309 PSSMHANDLE pSSM = pData->pSSM;
1310 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
1311 CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
1312 const int32_t i32Dummy = 0;
1313
1314 AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
1315 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1316
1317 CRASSERT(pContext && pSSM);
1318 CRASSERT(pMural);
1319 CRASSERT(pMural->CreateInfo.externalID);
1320
1321 /* We could have skipped saving the key and use similar callback to load context states back,
1322 * but there's no guarantee we'd traverse hashtable in same order after loading.
1323 */
1324 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1325 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1326
1327#ifdef DEBUG_misha
1328 {
1329 unsigned long id;
1330 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
1331 crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
1332 else
1333 CRASSERT(id == key);
1334 }
1335#endif
1336
1337#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1338 if (pContextInfo->currentMural
1339 || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
1340 )
1341 {
1342 CRASSERT(pMural->CreateInfo.externalID);
1343 CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1344 pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
1345 }
1346 else
1347 {
1348 /* this is a dummy mural */
1349 CRASSERT(!pMural->width);
1350 CRASSERT(!pMural->height);
1351 CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1352 pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
1353 }
1354 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1355
1356 CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
1357 CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
1358 CRASSERT(cr_server.curClient);
1359
1360 crServerPerformMakeCurrent(pMural, pContextInfo);
1361#endif
1362
1363 pData->rc = crStateSaveContext(pContext, pSSM);
1364 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1365
1366 pData->rc = crVBoxServerSaveFBImage(pSSM);
1367 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1368
1369 /* restore the initial current mural */
1370 pContextInfo->currentMural = pContextCurrentMural;
1371}
1372
1373#if 0
1374typedef struct CR_SERVER_CHECK_BUFFERS
1375{
1376 CRBufferObject *obj;
1377 CRContext *ctx;
1378}CR_SERVER_CHECK_BUFFERS, *PCR_SERVER_CHECK_BUFFERS;
1379
1380static void crVBoxServerCheckConsistencyContextBuffersCB(unsigned long key, void *data1, void *data2)
1381{
1382 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1383 CRContext *ctx = pContextInfo->pContext;
1384 PCR_SERVER_CHECK_BUFFERS pBuffers = (PCR_SERVER_CHECK_BUFFERS)data2;
1385 CRBufferObject *obj = pBuffers->obj;
1386 CRBufferObjectState *b = &(ctx->bufferobject);
1387 int j, k;
1388
1389 if (obj == b->arrayBuffer)
1390 {
1391 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1392 pBuffers->ctx = ctx;
1393 }
1394 if (obj == b->elementsBuffer)
1395 {
1396 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1397 pBuffers->ctx = ctx;
1398 }
1399#ifdef CR_ARB_pixel_buffer_object
1400 if (obj == b->packBuffer)
1401 {
1402 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1403 pBuffers->ctx = ctx;
1404 }
1405 if (obj == b->unpackBuffer)
1406 {
1407 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1408 pBuffers->ctx = ctx;
1409 }
1410#endif
1411
1412#ifdef CR_ARB_vertex_buffer_object
1413 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1414 {
1415 CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array);
1416 if (obj == cp->buffer)
1417 {
1418 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1419 pBuffers->ctx = ctx;
1420 }
1421 }
1422
1423 for (k=0; k<ctx->client.vertexArrayStackDepth; ++k)
1424 {
1425 CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k];
1426 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1427 {
1428 CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray);
1429 if (obj == cp->buffer)
1430 {
1431 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1432 pBuffers->ctx = ctx;
1433 }
1434 }
1435 }
1436#endif
1437}
1438
1439static void crVBoxServerCheckConsistencyBuffersCB(unsigned long key, void *data1, void *data2)
1440{
1441 CRBufferObject *obj = (CRBufferObject *)data1;
1442 CR_SERVER_CHECK_BUFFERS Buffers = {0};
1443 Buffers.obj = obj;
1444 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckConsistencyContextBuffersCB, (void*)&Buffers);
1445}
1446
1447//static void crVBoxServerCheckConsistency2CB(unsigned long key, void *data1, void *data2)
1448//{
1449// CRContextInfo* pContextInfo1 = (CRContextInfo*)data1;
1450// CRContextInfo* pContextInfo2 = (CRContextInfo*)data2;
1451//
1452// CRASSERT(pContextInfo1->pContext);
1453// CRASSERT(pContextInfo2->pContext);
1454//
1455// if (pContextInfo1 == pContextInfo2)
1456// {
1457// CRASSERT(pContextInfo1->pContext == pContextInfo2->pContext);
1458// return;
1459// }
1460//
1461// CRASSERT(pContextInfo1->pContext != pContextInfo2->pContext);
1462// CRASSERT(pContextInfo1->pContext->shared);
1463// CRASSERT(pContextInfo2->pContext->shared);
1464// CRASSERT(pContextInfo1->pContext->shared == pContextInfo2->pContext->shared);
1465// if (pContextInfo1->pContext->shared != pContextInfo2->pContext->shared)
1466// return;
1467//
1468// crHashtableWalk(pContextInfo1->pContext->shared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, pContextInfo2);
1469//}
1470static void crVBoxServerCheckSharedCB(unsigned long key, void *data1, void *data2)
1471{
1472 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1473 void **ppShared = (void**)data2;
1474 if (!*ppShared)
1475 *ppShared = pContextInfo->pContext->shared;
1476 else
1477 Assert(pContextInfo->pContext->shared == *ppShared);
1478}
1479
1480static void crVBoxServerCheckConsistency()
1481{
1482 CRSharedState *pShared = NULL;
1483 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckSharedCB, (void*)&pShared);
1484 Assert(pShared);
1485 if (pShared)
1486 {
1487 crHashtableWalk(pShared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, NULL);
1488 }
1489}
1490#endif
1491
1492static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
1493
1494DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
1495{
1496 int32_t rc, i;
1497 uint32_t ui32;
1498 GLboolean b;
1499 unsigned long key;
1500 GLenum err;
1501#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1502 CRClient *curClient;
1503 CRMuralInfo *curMural = NULL;
1504 CRContextInfo *curCtxInfo = NULL;
1505#endif
1506 CRVBOX_SAVE_STATE_GLOBAL Data;
1507
1508 crMemset(&Data, 0, sizeof (Data));
1509
1510#if 0
1511 crVBoxServerCheckConsistency();
1512#endif
1513
1514 /* We shouldn't be called if there's no clients at all*/
1515 CRASSERT(cr_server.numClients>0);
1516
1517 /* @todo it's hack atm */
1518 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1519 * for every connected client (e.g. guest opengl application)
1520 */
1521 if (!cr_server.bIsInSavingState) /* It's first call */
1522 {
1523 cr_server.bIsInSavingState = GL_TRUE;
1524
1525 /* Store number of clients */
1526 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1527 AssertRCReturn(rc, rc);
1528
1529 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
1530 }
1531
1532 g_hackVBoxServerSaveLoadCallsLeft--;
1533
1534 /* Do nothing until we're being called last time */
1535 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1536 {
1537 return VINF_SUCCESS;
1538 }
1539
1540#ifdef DEBUG_misha
1541#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart"
1542#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop"
1543
1544 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1545 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START);
1546#endif
1547
1548 /* Save rendering contexts creation info */
1549 ui32 = crHashtableNumElements(cr_server.contextTable);
1550 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1551 AssertRCReturn(rc, rc);
1552 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1553
1554#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1555 curClient = cr_server.curClient;
1556 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1557 if (curClient)
1558 {
1559 curCtxInfo = cr_server.curClient->currentCtxInfo;
1560 curMural = cr_server.curClient->currentMural;
1561 }
1562 else if (cr_server.numClients)
1563 {
1564 cr_server.curClient = cr_server.clients[0];
1565 }
1566#endif
1567
1568 /* first save windows info */
1569 /* Save windows creation info */
1570 ui32 = crHashtableNumElements(cr_server.muralTable);
1571 /* There should be default mural always */
1572 CRASSERT(ui32>=1);
1573 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1574 AssertRCReturn(rc, rc);
1575 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1576
1577 /* Save cr_server.muralTable
1578 * @todo we don't need it all, just geometry info actually
1579 */
1580 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1581 AssertRCReturn(rc, rc);
1582 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1583
1584 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1585 crVBoxServerBuildSaveStateGlobal(&Data);
1586
1587 rc = crStateSaveGlobals(pSSM);
1588 AssertRCReturn(rc, rc);
1589
1590 Data.pSSM = pSSM;
1591 /* Save contexts state tracker data */
1592 /* @todo For now just some blind data dumps,
1593 * but I've a feeling those should be saved/restored in a very strict sequence to
1594 * allow diff_api to work correctly.
1595 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1596 */
1597 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1598 AssertRCReturn(Data.rc, Data.rc);
1599
1600 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1601 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1602 AssertRCReturn(rc, rc);
1603
1604 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1605 AssertRCReturn(Data.rc, Data.rc);
1606
1607#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1608 cr_server.curClient = curClient;
1609 /* Restore original win and ctx IDs*/
1610 if (curClient && curMural && curCtxInfo)
1611 {
1612 crServerPerformMakeCurrent(curMural, curCtxInfo);
1613 }
1614 else
1615 {
1616 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1617 }
1618#endif
1619
1620 /* Save clients info */
1621 for (i = 0; i < cr_server.numClients; i++)
1622 {
1623 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1624 {
1625 CRClient *pClient = cr_server.clients[i];
1626
1627 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1628 AssertRCReturn(rc, rc);
1629
1630 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1631 AssertRCReturn(rc, rc);
1632
1633 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1634 AssertRCReturn(rc, rc);
1635
1636 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1637 AssertRCReturn(rc, rc);
1638
1639 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0)
1640 {
1641 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1642 CRASSERT(b);
1643 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1644 AssertRCReturn(rc, rc);
1645 }
1646
1647 if (pClient->currentMural && pClient->currentWindow>=0)
1648 {
1649 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1650 CRASSERT(b);
1651 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1652 AssertRCReturn(rc, rc);
1653 }
1654 }
1655 }
1656
1657 /* all context gl error states should have now be synced with chromium erro states,
1658 * reset the error if any */
1659 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1660 crWarning("crServer: glGetError %d after saving snapshot", err);
1661
1662 cr_server.bIsInSavingState = GL_FALSE;
1663
1664#ifdef DEBUG_misha
1665 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1666 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
1667#endif
1668
1669 return VINF_SUCCESS;
1670}
1671
1672static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1673{
1674 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1675 CRASSERT(pContextInfo);
1676 CRASSERT(pContextInfo->pContext);
1677 return pContextInfo->pContext;
1678}
1679
1680static int32_t crVBoxServerLoadMurals(PSSMHANDLE pSSM, uint32_t version)
1681{
1682 unsigned long key;
1683 uint32_t ui, uiNumElems;
1684 /* Load windows */
1685 int32_t rc = SSMR3GetU32(pSSM, &uiNumElems);
1686 AssertRCReturn(rc, rc);
1687 for (ui=0; ui<uiNumElems; ++ui)
1688 {
1689 CRCreateInfo_t createInfo;
1690 char psz[200];
1691 GLint winID;
1692 unsigned long key;
1693
1694 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1695 AssertRCReturn(rc, rc);
1696 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1697 AssertRCReturn(rc, rc);
1698
1699 if (createInfo.pszDpyName)
1700 {
1701 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1702 AssertRCReturn(rc, rc);
1703 createInfo.pszDpyName = psz;
1704 }
1705
1706 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1707 CRASSERT((int64_t)winID == (int64_t)key);
1708 }
1709
1710 /* Load cr_server.muralTable */
1711 rc = SSMR3GetU32(pSSM, &uiNumElems);
1712 AssertRCReturn(rc, rc);
1713 for (ui=0; ui<uiNumElems; ++ui)
1714 {
1715 CRMuralInfo muralInfo;
1716 CRMuralInfo *pActualMural = NULL;
1717
1718 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1719 AssertRCReturn(rc, rc);
1720 rc = SSMR3GetMem(pSSM, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1721 AssertRCReturn(rc, rc);
1722
1723 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1724 muralInfo.bFbDraw = GL_TRUE;
1725
1726 if (muralInfo.pVisibleRects)
1727 {
1728 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
1729 if (!muralInfo.pVisibleRects)
1730 {
1731 return VERR_NO_MEMORY;
1732 }
1733
1734 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
1735 AssertRCReturn(rc, rc);
1736 }
1737
1738 pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);;
1739 CRASSERT(pActualMural);
1740
1741 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
1742 {
1743 rc = SSMR3GetMem(pSSM, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
1744 CRASSERT(rc == VINF_SUCCESS);
1745 }
1746
1747 /* Restore windows geometry info */
1748 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
1749 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
1750 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
1751 if (muralInfo.bReceivedRects)
1752 {
1753 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
1754 }
1755 crServerDispatchWindowShow(key, muralInfo.bVisible);
1756
1757 if (muralInfo.pVisibleRects)
1758 {
1759 crFree(muralInfo.pVisibleRects);
1760 }
1761
1762 Assert(!pActualMural->fDataPresented);
1763
1764 if (version >= SHCROGL_SSM_VERSION_WITH_PRESENT_STATE)
1765 pActualMural->fDataPresented = muralInfo.fDataPresented;
1766 else
1767 pActualMural->fDataPresented = crServerVBoxCompositionPresentNeeded(pActualMural);
1768 }
1769
1770 CRASSERT(RT_SUCCESS(rc));
1771 return VINF_SUCCESS;
1772}
1773
1774static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
1775 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
1776{
1777 CRContext *pContext = pContextInfo->pContext;
1778 int32_t rc = VINF_SUCCESS;
1779 GLuint i;
1780 /* can apply the data right away */
1781 struct
1782 {
1783 CRFBData data;
1784 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1785 } Data;
1786
1787 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1788
1789 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1790 {
1791 if (!pMural->width || !pMural->height)
1792 return VINF_SUCCESS;
1793
1794 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
1795 if (!RT_SUCCESS(rc))
1796 {
1797 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1798 return rc;
1799 }
1800 }
1801 else
1802 {
1803 GLint storedWidth, storedHeight;
1804
1805 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1806 {
1807 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1808 CRASSERT(cr_server.currentMural = pMural);
1809 storedWidth = pMural->width;
1810 storedHeight = pMural->height;
1811 }
1812 else
1813 {
1814 storedWidth = pContext->buffer.storedWidth;
1815 storedHeight = pContext->buffer.storedHeight;
1816 }
1817
1818 if (!storedWidth || !storedHeight)
1819 return VINF_SUCCESS;
1820
1821 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
1822 if (!RT_SUCCESS(rc))
1823 {
1824 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1825 return rc;
1826 }
1827 }
1828
1829 CRASSERT(Data.data.cElements);
1830
1831 for (i = 0; i < Data.data.cElements; ++i)
1832 {
1833 CRFBDataElement * pEl = &Data.data.aElements[i];
1834 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
1835 AssertRCReturn(rc, rc);
1836 }
1837
1838 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1839 {
1840 CRBufferState *pBuf = &pContext->buffer;
1841 /* can apply the data right away */
1842 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
1843 CRASSERT(cr_server.currentMural);
1844
1845 cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
1846 0,
1847 pContextInfo->SpuContext >= 0
1848 ? pContextInfo->SpuContext
1849 : cr_server.MainContextInfo.SpuContext);
1850 crStateApplyFBImage(pContext, &Data.data);
1851 CRASSERT(!pBuf->pFrontImg);
1852 CRASSERT(!pBuf->pBackImg);
1853 crVBoxServerFBImageDataTerm(&Data.data);
1854
1855 if ((pMural->fPresentMode & CR_SERVER_REDIR_F_FBO) && pMural->fDataPresented && crServerVBoxCompositionPresentNeeded(pMural))
1856 {
1857 crServerPresentFBO(pMural);
1858 }
1859
1860 CRASSERT(cr_server.currentMural);
1861 cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
1862 0,
1863 cr_server.currentCtxInfo->SpuContext >= 0
1864 ? cr_server.currentCtxInfo->SpuContext
1865 : cr_server.MainContextInfo.SpuContext);
1866 }
1867 else
1868 {
1869 CRBufferState *pBuf = &pContext->buffer;
1870 CRASSERT(!pBuf->pFrontImg);
1871 CRASSERT(!pBuf->pBackImg);
1872 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
1873
1874 if (Data.data.cElements)
1875 {
1876 CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1877 if (!RT_SUCCESS(rc))
1878 {
1879 crVBoxServerFBImageDataTerm(&Data.data);
1880 crWarning("crAlloc failed");
1881 return VERR_NO_MEMORY;
1882 }
1883
1884 crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1885 pBuf->pFrontImg = pLazyData;
1886 }
1887 }
1888
1889 CRASSERT(RT_SUCCESS(rc));
1890 return VINF_SUCCESS;
1891}
1892
1893DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
1894{
1895 int32_t rc, i;
1896 uint32_t ui, uiNumElems;
1897 unsigned long key;
1898 GLenum err;
1899
1900 if (!cr_server.bIsInLoadingState)
1901 {
1902 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
1903 cr_server.bIsInLoadingState = GL_TRUE;
1904
1905 /* Read number of clients */
1906 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
1907 AssertRCReturn(rc, rc);
1908 }
1909
1910 g_hackVBoxServerSaveLoadCallsLeft--;
1911
1912 /* Do nothing until we're being called last time */
1913 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1914 {
1915 return VINF_SUCCESS;
1916 }
1917
1918 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
1919 {
1920 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1921 }
1922
1923#ifdef DEBUG_misha
1924#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
1925#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
1926
1927 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1928 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
1929#endif
1930
1931 /* Load and recreate rendering contexts */
1932 rc = SSMR3GetU32(pSSM, &uiNumElems);
1933 AssertRCReturn(rc, rc);
1934 for (ui=0; ui<uiNumElems; ++ui)
1935 {
1936 CRCreateInfo_t createInfo;
1937 char psz[200];
1938 GLint ctxID;
1939 CRContextInfo* pContextInfo;
1940 CRContext* pContext;
1941
1942 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1943 AssertRCReturn(rc, rc);
1944 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1945 AssertRCReturn(rc, rc);
1946
1947 if (createInfo.pszDpyName)
1948 {
1949 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1950 AssertRCReturn(rc, rc);
1951 createInfo.pszDpyName = psz;
1952 }
1953
1954 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
1955 CRASSERT((int64_t)ctxID == (int64_t)key);
1956
1957 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1958 CRASSERT(pContextInfo);
1959 CRASSERT(pContextInfo->pContext);
1960 pContext = pContextInfo->pContext;
1961 pContext->shared->id=-1;
1962 }
1963
1964 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1965 {
1966 /* we have a mural data here */
1967 rc = crVBoxServerLoadMurals(pSSM, version);
1968 AssertRCReturn(rc, rc);
1969 }
1970
1971 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
1972 {
1973 /* set the current client to allow doing crServerPerformMakeCurrent later */
1974 CRASSERT(cr_server.numClients);
1975 cr_server.curClient = cr_server.clients[0];
1976 }
1977
1978 rc = crStateLoadGlobals(pSSM, version);
1979 AssertRCReturn(rc, rc);
1980
1981 if (uiNumElems)
1982 {
1983 /* ensure we have main context set up as current */
1984 CRMuralInfo *pMural;
1985 CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
1986 CRASSERT(!cr_server.currentCtxInfo);
1987 CRASSERT(!cr_server.currentMural);
1988 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
1989 CRASSERT(pMural);
1990 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
1991 }
1992
1993 /* Restore context state data */
1994 for (ui=0; ui<uiNumElems; ++ui)
1995 {
1996 CRContextInfo* pContextInfo;
1997 CRContext *pContext;
1998 CRMuralInfo *pMural = NULL;
1999 int32_t winId = 0;
2000
2001 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2002 AssertRCReturn(rc, rc);
2003
2004 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2005 CRASSERT(pContextInfo);
2006 CRASSERT(pContextInfo->pContext);
2007 pContext = pContextInfo->pContext;
2008
2009 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2010 {
2011 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
2012 AssertRCReturn(rc, rc);
2013
2014 if (winId)
2015 {
2016 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
2017 CRASSERT(pMural);
2018 }
2019 else
2020 {
2021 /* null winId means a dummy mural, get it */
2022 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
2023 CRASSERT(pMural);
2024 }
2025 }
2026
2027 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
2028 AssertRCReturn(rc, rc);
2029
2030 /*Restore front/back buffer images*/
2031 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2032 AssertRCReturn(rc, rc);
2033 }
2034
2035 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2036 {
2037 CRContextInfo *pContextInfo;
2038 CRMuralInfo *pMural;
2039 GLint ctxId;
2040
2041 rc = SSMR3GetU32(pSSM, &uiNumElems);
2042 AssertRCReturn(rc, rc);
2043 for (ui=0; ui<uiNumElems; ++ui)
2044 {
2045 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
2046 CRMuralInfo *pInitialCurMural;
2047
2048 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2049 AssertRCReturn(rc, rc);
2050
2051 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
2052 AssertRCReturn(rc, rc);
2053
2054 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
2055 CRASSERT(pMural);
2056 if (ctxId)
2057 {
2058 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
2059 CRASSERT(pContextInfo);
2060 }
2061 else
2062 pContextInfo = &cr_server.MainContextInfo;
2063
2064 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
2065 pInitialCurMural = pContextInfo->currentMural;
2066
2067 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2068 AssertRCReturn(rc, rc);
2069
2070 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
2071 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
2072 pContextInfo->currentMural = pInitialCurMural;
2073 }
2074
2075 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2076
2077 cr_server.curClient = NULL;
2078 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
2079 }
2080 else
2081 {
2082 CRServerFreeIDsPool_t dummyIdsPool;
2083
2084 /* we have a mural data here */
2085 rc = crVBoxServerLoadMurals(pSSM, version);
2086 AssertRCReturn(rc, rc);
2087
2088 /* not used any more, just read it out and ignore */
2089 rc = SSMR3GetMem(pSSM, &dummyIdsPool, sizeof(dummyIdsPool));
2090 CRASSERT(rc == VINF_SUCCESS);
2091 }
2092
2093 /* Load clients info */
2094 for (i = 0; i < cr_server.numClients; i++)
2095 {
2096 if (cr_server.clients[i] && cr_server.clients[i]->conn)
2097 {
2098 CRClient *pClient = cr_server.clients[i];
2099 CRClient client;
2100 unsigned long ctxID=-1, winID=-1;
2101
2102 rc = SSMR3GetU32(pSSM, &ui);
2103 AssertRCReturn(rc, rc);
2104 /* If this assert fires, then we should search correct client in the list first*/
2105 CRASSERT(ui == pClient->conn->u32ClientID);
2106
2107 if (version>=4)
2108 {
2109 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
2110 AssertRCReturn(rc, rc);
2111
2112 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
2113 AssertRCReturn(rc, rc);
2114 }
2115
2116 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
2117 CRASSERT(rc == VINF_SUCCESS);
2118
2119 client.conn = pClient->conn;
2120 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2121 * and fail to bind old textures.
2122 */
2123 /*client.number = pClient->number;*/
2124 *pClient = client;
2125
2126 pClient->currentContextNumber = -1;
2127 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2128 pClient->currentMural = NULL;
2129 pClient->currentWindow = -1;
2130
2131 cr_server.curClient = pClient;
2132
2133 if (client.currentCtxInfo && client.currentContextNumber>=0)
2134 {
2135 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
2136 AssertRCReturn(rc, rc);
2137 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2138 CRASSERT(client.currentCtxInfo);
2139 CRASSERT(client.currentCtxInfo->pContext);
2140 //pClient->currentCtx = client.currentCtx;
2141 //pClient->currentContextNumber = ctxID;
2142 }
2143
2144 if (client.currentMural && client.currentWindow>=0)
2145 {
2146 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
2147 AssertRCReturn(rc, rc);
2148 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2149 CRASSERT(client.currentMural);
2150 //pClient->currentMural = client.currentMural;
2151 //pClient->currentWindow = winID;
2152 }
2153
2154 /* Restore client active context and window */
2155 crServerDispatchMakeCurrent(winID, 0, ctxID);
2156
2157 if (0)
2158 {
2159// CRContext *tmpCtx;
2160// CRCreateInfo_t *createInfo;
2161 GLfloat one[4] = { 1, 1, 1, 1 };
2162 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
2163
2164 crServerDispatchMakeCurrent(winID, 0, ctxID);
2165
2166 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
2167
2168 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
2169 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
2170 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
2171#ifdef CR_ARB_texture_cube_map
2172 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
2173#endif
2174#ifdef CR_NV_texture_rectangle
2175 //@todo this doesn't work as expected
2176 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
2177#endif
2178 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
2179 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
2180 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
2181
2182 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
2183 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
2184 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
2185
2186 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
2187 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
2188
2189 //crStateViewport( 0, 0, 600, 600 );
2190 //pClient->currentMural->viewportValidated = GL_FALSE;
2191 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
2192
2193 //crStateMatrixMode(GL_PROJECTION);
2194 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
2195
2196 //crStateLoadIdentity();
2197 //cr_server.head_spu->dispatch_table.LoadIdentity();
2198
2199 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2200 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2201
2202 //crStateMatrixMode(GL_MODELVIEW);
2203 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
2204 //crServerDispatchLoadIdentity();
2205 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2206 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2207 //crServerDispatchLoadIdentity();
2208
2209 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
2210 CRASSERT(createInfo);
2211 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
2212 CRASSERT(tmpCtx);
2213 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
2214 crStateDestroyContext(tmpCtx);*/
2215 }
2216 }
2217 }
2218
2219 //crServerDispatchMakeCurrent(-1, 0, -1);
2220
2221 cr_server.curClient = NULL;
2222
2223 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2224 crWarning("crServer: glGetError %d after loading snapshot", err);
2225
2226 cr_server.bIsInLoadingState = GL_FALSE;
2227
2228#if 0
2229 crVBoxServerCheckConsistency();
2230#endif
2231
2232#ifdef DEBUG_misha
2233 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2234 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
2235#endif
2236
2237 return VINF_SUCCESS;
2238}
2239
2240#define SCREEN(i) (cr_server.screen[i])
2241#define MAPPED(screen) ((screen).winID != 0)
2242
2243static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2244{
2245 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2246 int *sIndex = (int*) data2;
2247
2248 Assert(pMI->cDisabled);
2249
2250 if (pMI->screenId == *sIndex)
2251 {
2252 crServerVBoxCompositionDisableEnter(pMI);
2253
2254 renderspuReparentWindow(pMI->spuWindow);
2255
2256 crServerVBoxCompositionDisableLeave(pMI, GL_FALSE);
2257 }
2258}
2259
2260static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
2261{
2262 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2263 (void) data2;
2264
2265 crServerCheckMuralGeometry(pMI);
2266}
2267
2268DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2269{
2270 int i;
2271
2272 if (sCount>CR_MAX_GUEST_MONITORS)
2273 return VERR_INVALID_PARAMETER;
2274
2275 /*Shouldn't happen yet, but to be safe in future*/
2276 for (i=0; i<cr_server.screenCount; ++i)
2277 {
2278 if (MAPPED(SCREEN(i)))
2279 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
2280 return VERR_NOT_IMPLEMENTED;
2281 }
2282
2283 cr_server.screenCount = sCount;
2284
2285 for (i=0; i<sCount; ++i)
2286 {
2287 SCREEN(i).winID = 0;
2288 }
2289
2290 return VINF_SUCCESS;
2291}
2292
2293DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2294{
2295 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2296
2297 if (sIndex<0 || sIndex>=cr_server.screenCount)
2298 return VERR_INVALID_PARAMETER;
2299
2300 if (MAPPED(SCREEN(sIndex)))
2301 {
2302 SCREEN(sIndex).winID = 0;
2303 renderspuSetWindowId(0);
2304
2305 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2306
2307 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2308 }
2309
2310 renderspuSetWindowId(SCREEN(0).winID);
2311
2312 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2313
2314 return VINF_SUCCESS;
2315}
2316
2317DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2318{
2319 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2320
2321 if (sIndex<0 || sIndex>=cr_server.screenCount)
2322 return VERR_INVALID_PARAMETER;
2323
2324 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2325 {
2326 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2327 crVBoxServerUnmapScreen(sIndex);
2328 }
2329
2330 SCREEN(sIndex).winID = winID;
2331 SCREEN(sIndex).x = x;
2332 SCREEN(sIndex).y = y;
2333 SCREEN(sIndex).w = w;
2334 SCREEN(sIndex).h = h;
2335
2336 renderspuSetWindowId(SCREEN(sIndex).winID);
2337 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2338
2339 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2340 renderspuSetWindowId(SCREEN(0).winID);
2341
2342 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2343
2344#ifndef WINDOWS
2345 /*Restore FB content for clients, which have current window on a screen being remapped*/
2346 {
2347 GLint i;
2348
2349 for (i = 0; i < cr_server.numClients; i++)
2350 {
2351 cr_server.curClient = cr_server.clients[i];
2352 if (cr_server.curClient->currentCtxInfo
2353 && cr_server.curClient->currentCtxInfo->pContext
2354 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2355 && cr_server.curClient->currentMural
2356 && cr_server.curClient->currentMural->screenId == sIndex
2357 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2358 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2359 {
2360 int clientWindow = cr_server.curClient->currentWindow;
2361 int clientContext = cr_server.curClient->currentContextNumber;
2362 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2363
2364 if (clientWindow && clientWindow != cr_server.currentWindow)
2365 {
2366 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2367 }
2368
2369 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2370 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2371 }
2372 }
2373 cr_server.curClient = NULL;
2374 }
2375#endif
2376
2377 {
2378 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
2379 if (pDisplay)
2380 CrDpResize(pDisplay, w, h, w, h);
2381 }
2382
2383 return VINF_SUCCESS;
2384}
2385
2386static int crVBoxServerUpdateMuralRootVisibleRegion(CRMuralInfo *pMI)
2387{
2388 GLboolean fForcePresent;
2389 uint32_t cRects;
2390 const RTRECT *pRects;
2391 int rc;
2392
2393 fForcePresent = crServerVBoxCompositionPresentNeeded(pMI);
2394
2395 crServerVBoxCompositionDisableEnter(pMI);
2396
2397 if (cr_server.fRootVrOn)
2398 {
2399 if (!pMI->fRootVrOn)
2400 {
2401 VBOXVR_TEXTURE Tex = {0};
2402
2403 rc = CrVrScrCompositorInit(&pMI->RootVrCompositor);
2404 if (!RT_SUCCESS(rc))
2405 {
2406 crWarning("CrVrScrCompositorInit failed, rc %d", rc);
2407 goto end;
2408 }
2409
2410
2411 Tex.width = pMI->width;
2412 Tex.height = pMI->height;
2413 Tex.target = GL_TEXTURE_2D;
2414 Tex.hwid = 0;
2415 CrVrScrCompositorEntryInit(&pMI->RootVrCEntry, &Tex);
2416 }
2417
2418 rc = crServerMuralSynchRootVr(pMI, &cRects, &pRects);
2419 if (!RT_SUCCESS(rc))
2420 {
2421 crWarning("crServerMuralSynchRootVr failed, rc %d", rc);
2422 goto end;
2423 }
2424
2425 if (!pMI->fRootVrOn)
2426 CrVrScrCompositorEntryTexUpdate(&pMI->RootVrCEntry, CrVrScrCompositorEntryTexGet(&pMI->CEntry));
2427 }
2428 else
2429 {
2430 CrVrScrCompositorTerm(&pMI->RootVrCompositor);
2431 rc = CrVrScrCompositorEntryRegionsGet(&pMI->Compositor, &pMI->CEntry, &cRects, NULL, &pRects);
2432 if (!RT_SUCCESS(rc))
2433 {
2434 crWarning("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc);
2435 goto end;
2436 }
2437
2438 /* CEntry should always be in sync */
2439// CrVrScrCompositorEntryTexUpdate(&pMI->CEntry, CrVrScrCompositorEntryTexGet(&pMI->RootVrCEntry));
2440 }
2441
2442 cr_server.head_spu->dispatch_table.WindowVisibleRegion(pMI->spuWindow, cRects, pRects);
2443
2444 pMI->fRootVrOn = cr_server.fRootVrOn;
2445
2446end:
2447 crServerVBoxCompositionDisableLeave(pMI, fForcePresent);
2448
2449 return rc;
2450}
2451
2452static void crVBoxServerSetRootVisibleRegionCB(unsigned long key, void *data1, void *data2)
2453{
2454 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2455
2456 if (!pMI->CreateInfo.externalID)
2457 return;
2458 (void) data2;
2459
2460 crVBoxServerUpdateMuralRootVisibleRegion(pMI);
2461}
2462
2463DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects)
2464{
2465 int32_t rc = VINF_SUCCESS;
2466
2467 /* non-zero rects pointer indicate rects are present and switched on
2468 * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions,
2469 * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */
2470 if (pRects)
2471 {
2472 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
2473 rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL);
2474 if (!RT_SUCCESS(rc))
2475 {
2476 crWarning("VBoxVrListRectsSet failed! rc %d", rc);
2477 return rc;
2478 }
2479
2480 cr_server.fRootVrOn = GL_TRUE;
2481 }
2482 else
2483 {
2484 if (!cr_server.fRootVrOn)
2485 return VINF_SUCCESS;
2486
2487 VBoxVrListClear(&cr_server.RootVr);
2488
2489 cr_server.fRootVrOn = GL_FALSE;
2490 }
2491
2492 crHashtableWalk(cr_server.muralTable, crVBoxServerSetRootVisibleRegionCB, NULL);
2493
2494 return VINF_SUCCESS;
2495}
2496
2497DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2498{
2499 cr_server.pfnPresentFBO = pfnPresentFBO;
2500}
2501
2502int32_t crServerSetOffscreenRenderingMode(GLuint value)
2503{
2504 /* sanitize values */
2505 value = crServerRedirModeAdjust(value);
2506
2507 if (value == CR_SERVER_REDIR_F_NONE)
2508 {
2509 crWarning("crServerSetOffscreenRenderingMode: value undefined");
2510 }
2511
2512 if (cr_server.fPresentMode==value)
2513 {
2514 return VINF_SUCCESS;
2515 }
2516
2517 if ((value & CR_SERVER_REDIR_F_FBO) && !crServerSupportRedirMuralFBO())
2518 {
2519 crWarning("crServerSetOffscreenRenderingMode: FBO not supported");
2520 return VERR_NOT_SUPPORTED;
2521 }
2522
2523 cr_server.fPresentMode=value;
2524
2525 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2526
2527 return VINF_SUCCESS;
2528}
2529
2530DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2531{
2532 return crServerSetOffscreenRenderingMode(value ?
2533 cr_server.fPresentModeDefault | CR_SERVER_REDIR_F_FBO_RAM_VRDP
2534 : cr_server.fPresentModeDefault);
2535}
2536
2537DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2538{
2539 /* No need for a synchronization as this is single threaded. */
2540 if (pCallbacks)
2541 {
2542 cr_server.outputRedirect = *pCallbacks;
2543 cr_server.bUseOutputRedirect = true;
2544 }
2545 else
2546 {
2547 cr_server.bUseOutputRedirect = false;
2548 }
2549
2550 // @todo dynamically intercept already existing output:
2551 // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
2552
2553 return VINF_SUCCESS;
2554}
2555
2556static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2)
2557{
2558 CRMuralInfo *mural = (CRMuralInfo*) data1;
2559 int *sIndex = (int*) data2;
2560
2561 if (mural->screenId != *sIndex)
2562 return;
2563
2564 crServerCheckMuralGeometry(mural);
2565}
2566
2567
2568DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2569{
2570 CRScreenViewportInfo *pVieport;
2571 GLboolean fPosChanged, fSizeChanged;
2572
2573 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2574
2575 if (sIndex<0 || sIndex>=cr_server.screenCount)
2576 {
2577 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2578 return VERR_INVALID_PARAMETER;
2579 }
2580
2581 pVieport = &cr_server.screenVieport[sIndex];
2582 fPosChanged = (pVieport->x != x || pVieport->y != y);
2583 fSizeChanged = (pVieport->w != w || pVieport->h != h);
2584
2585 if (!fPosChanged && !fSizeChanged)
2586 {
2587 crDebug("crVBoxServerSetScreenViewport: no changes");
2588 return VINF_SUCCESS;
2589 }
2590
2591 if (fPosChanged)
2592 {
2593 pVieport->x = x;
2594 pVieport->y = y;
2595
2596 crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex);
2597 }
2598
2599 if (fSizeChanged)
2600 {
2601 pVieport->w = w;
2602 pVieport->h = h;
2603
2604 /* no need to do anything here actually */
2605 }
2606 return VINF_SUCCESS;
2607}
2608
2609
2610#ifdef VBOX_WITH_CRHGSMI
2611/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
2612 *
2613 * For now we need the notion of CrHgdmi commands in the crserver_lib to be able to complete it asynchronously once it is really processed.
2614 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
2615 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
2616 * to block the lower-priority thread trying to complete the blocking command.
2617 * And removed extra memcpy done on blocked command arrival.
2618 *
2619 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
2620 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
2621 *
2622 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
2623 * */
2624int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
2625{
2626 int32_t rc;
2627 uint32_t cBuffers = pCmd->cBuffers;
2628 uint32_t cParams;
2629 uint32_t cbHdr;
2630 CRVBOXHGSMIHDR *pHdr;
2631 uint32_t u32Function;
2632 uint32_t u32ClientID;
2633 CRClient *pClient;
2634
2635 if (!g_pvVRamBase)
2636 {
2637 crWarning("g_pvVRamBase is not initialized");
2638 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
2639 return VINF_SUCCESS;
2640 }
2641
2642 if (!cBuffers)
2643 {
2644 crWarning("zero buffers passed in!");
2645 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2646 return VINF_SUCCESS;
2647 }
2648
2649 cParams = cBuffers-1;
2650
2651 cbHdr = pCmd->aBuffers[0].cbBuffer;
2652 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2653 if (!pHdr)
2654 {
2655 crWarning("invalid header buffer!");
2656 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2657 return VINF_SUCCESS;
2658 }
2659
2660 if (cbHdr < sizeof (*pHdr))
2661 {
2662 crWarning("invalid header buffer size!");
2663 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2664 return VINF_SUCCESS;
2665 }
2666
2667 u32Function = pHdr->u32Function;
2668 u32ClientID = pHdr->u32ClientID;
2669
2670 switch (u32Function)
2671 {
2672 case SHCRGL_GUEST_FN_WRITE:
2673 {
2674 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2675
2676 /* @todo: Verify */
2677 if (cParams == 1)
2678 {
2679 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2680 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2681 /* Fetch parameters. */
2682 uint32_t cbBuffer = pBuf->cbBuffer;
2683 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2684
2685 if (cbHdr < sizeof (*pFnCmd))
2686 {
2687 crWarning("invalid write cmd buffer size!");
2688 rc = VERR_INVALID_PARAMETER;
2689 break;
2690 }
2691
2692 CRASSERT(cbBuffer);
2693 if (!pBuffer)
2694 {
2695 crWarning("invalid buffer data received from guest!");
2696 rc = VERR_INVALID_PARAMETER;
2697 break;
2698 }
2699
2700 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2701 if (RT_FAILURE(rc))
2702 {
2703 break;
2704 }
2705
2706 /* This should never fire unless we start to multithread */
2707 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2708 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2709
2710 pClient->conn->pBuffer = pBuffer;
2711 pClient->conn->cbBuffer = cbBuffer;
2712 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2713 rc = crVBoxServerInternalClientWriteRead(pClient);
2714 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2715 return rc;
2716 }
2717 else
2718 {
2719 crWarning("invalid number of args");
2720 rc = VERR_INVALID_PARAMETER;
2721 break;
2722 }
2723 break;
2724 }
2725
2726 case SHCRGL_GUEST_FN_INJECT:
2727 {
2728 crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2729
2730 /* @todo: Verify */
2731 if (cParams == 1)
2732 {
2733 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2734 /* Fetch parameters. */
2735 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2736 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2737 uint32_t cbBuffer = pBuf->cbBuffer;
2738 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2739
2740 if (cbHdr < sizeof (*pFnCmd))
2741 {
2742 crWarning("invalid inject cmd buffer size!");
2743 rc = VERR_INVALID_PARAMETER;
2744 break;
2745 }
2746
2747 CRASSERT(cbBuffer);
2748 if (!pBuffer)
2749 {
2750 crWarning("invalid buffer data received from guest!");
2751 rc = VERR_INVALID_PARAMETER;
2752 break;
2753 }
2754
2755 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
2756 if (RT_FAILURE(rc))
2757 {
2758 break;
2759 }
2760
2761 /* This should never fire unless we start to multithread */
2762 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2763 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2764
2765 pClient->conn->pBuffer = pBuffer;
2766 pClient->conn->cbBuffer = cbBuffer;
2767 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2768 rc = crVBoxServerInternalClientWriteRead(pClient);
2769 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2770 return rc;
2771 }
2772
2773 crWarning("invalid number of args");
2774 rc = VERR_INVALID_PARAMETER;
2775 break;
2776 }
2777
2778 case SHCRGL_GUEST_FN_READ:
2779 {
2780 crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n"));
2781
2782 /* @todo: Verify */
2783 if (cParams == 1)
2784 {
2785 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
2786 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2787 /* Fetch parameters. */
2788 uint32_t cbBuffer = pBuf->cbBuffer;
2789 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2790
2791 if (cbHdr < sizeof (*pFnCmd))
2792 {
2793 crWarning("invalid read cmd buffer size!");
2794 rc = VERR_INVALID_PARAMETER;
2795 break;
2796 }
2797
2798
2799 if (!pBuffer)
2800 {
2801 crWarning("invalid buffer data received from guest!");
2802 rc = VERR_INVALID_PARAMETER;
2803 break;
2804 }
2805
2806 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2807 if (RT_FAILURE(rc))
2808 {
2809 break;
2810 }
2811
2812 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2813
2814 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
2815
2816 /* Return the required buffer size always */
2817 pFnCmd->cbBuffer = cbBuffer;
2818
2819 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2820
2821 /* the read command is never pended, complete it right away */
2822 pHdr->result = rc;
2823 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2824 return VINF_SUCCESS;
2825 }
2826
2827 crWarning("invalid number of args");
2828 rc = VERR_INVALID_PARAMETER;
2829 break;
2830 }
2831
2832 case SHCRGL_GUEST_FN_WRITE_READ:
2833 {
2834 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
2835
2836 /* @todo: Verify */
2837 if (cParams == 2)
2838 {
2839 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
2840 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2841 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
2842
2843 /* Fetch parameters. */
2844 uint32_t cbBuffer = pBuf->cbBuffer;
2845 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2846
2847 uint32_t cbWriteback = pWbBuf->cbBuffer;
2848 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
2849
2850 if (cbHdr < sizeof (*pFnCmd))
2851 {
2852 crWarning("invalid write_read cmd buffer size!");
2853 rc = VERR_INVALID_PARAMETER;
2854 break;
2855 }
2856
2857
2858 CRASSERT(cbBuffer);
2859 if (!pBuffer)
2860 {
2861 crWarning("invalid write buffer data received from guest!");
2862 rc = VERR_INVALID_PARAMETER;
2863 break;
2864 }
2865
2866 CRASSERT(cbWriteback);
2867 if (!pWriteback)
2868 {
2869 crWarning("invalid writeback buffer data received from guest!");
2870 rc = VERR_INVALID_PARAMETER;
2871 break;
2872 }
2873 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2874 if (RT_FAILURE(rc))
2875 {
2876 pHdr->result = rc;
2877 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2878 return rc;
2879 }
2880
2881 /* This should never fire unless we start to multithread */
2882 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2883 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2884
2885 pClient->conn->pBuffer = pBuffer;
2886 pClient->conn->cbBuffer = cbBuffer;
2887 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
2888 rc = crVBoxServerInternalClientWriteRead(pClient);
2889 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2890 return rc;
2891 }
2892
2893 crWarning("invalid number of args");
2894 rc = VERR_INVALID_PARAMETER;
2895 break;
2896 }
2897
2898 case SHCRGL_GUEST_FN_SET_VERSION:
2899 {
2900 crWarning("invalid function");
2901 rc = VERR_NOT_IMPLEMENTED;
2902 break;
2903 }
2904
2905 case SHCRGL_GUEST_FN_SET_PID:
2906 {
2907 crWarning("invalid function");
2908 rc = VERR_NOT_IMPLEMENTED;
2909 break;
2910 }
2911
2912 default:
2913 {
2914 crWarning("invalid function");
2915 rc = VERR_NOT_IMPLEMENTED;
2916 break;
2917 }
2918
2919 }
2920
2921 /* we can be on fail only here */
2922 CRASSERT(RT_FAILURE(rc));
2923 pHdr->result = rc;
2924 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2925 return rc;
2926}
2927
2928int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
2929{
2930 int rc = VINF_SUCCESS;
2931
2932 switch (pCtl->enmType)
2933 {
2934 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
2935 {
2936 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
2937 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
2938 g_cbVRam = pSetup->cbVRam;
2939 rc = VINF_SUCCESS;
2940 break;
2941 }
2942 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
2943 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
2944 rc = VINF_SUCCESS;
2945 break;
2946 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
2947 {
2948 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
2949 g_hCrHgsmiCompletion = pSetup->hCompletion;
2950 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
2951 rc = VINF_SUCCESS;
2952 break;
2953 }
2954 default:
2955 AssertMsgFailed(("invalid param %d", pCtl->enmType));
2956 rc = VERR_INVALID_PARAMETER;
2957 }
2958
2959 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
2960 * to complete them accordingly.
2961 * This approach allows using host->host and host->guest commands in the same way here
2962 * making the command completion to be the responsibility of the command originator.
2963 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
2964 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
2965 return rc;
2966}
2967#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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