VirtualBox

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

Last change on this file since 45527 was 45527, checked in by vboxsync, 12 years ago

crOpenGL: fix warnings

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

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