VirtualBox

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

Last change on this file since 76787 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 126.3 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
19#ifdef VBOX_WITH_CR_DISPLAY_LISTS
20# include "cr_dlm.h"
21#endif
22
23#include "server_dispatch.h"
24#include "state/cr_texture.h"
25#include "render/renderspu.h"
26#include <signal.h>
27#include <stdlib.h>
28#define DEBUG_FP_EXCEPTIONS 0
29#if DEBUG_FP_EXCEPTIONS
30#include <fpu_control.h>
31#include <math.h>
32#endif
33#include <iprt/assert.h>
34#include <VBox/err.h>
35#include <VBox/log.h>
36#include <VBox/AssertGuest.h>
37
38#ifdef VBOXCR_LOGFPS
39#include <iprt/timer.h>
40#endif
41
42#ifdef VBOX_WITH_CRHGSMI
43# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
44uint8_t* g_pvVRamBase = NULL;
45uint32_t g_cbVRam = 0;
46PPDMLED g_pLed = NULL;
47
48HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion = NULL;
49PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion = NULL;
50#endif
51
52/**
53 * \mainpage CrServerLib
54 *
55 * \section CrServerLibIntroduction Introduction
56 *
57 * Chromium consists of all the top-level files in the cr
58 * directory. The core module basically takes care of API dispatch,
59 * and OpenGL state management.
60 */
61
62
63/**
64 * CRServer global data
65 */
66CRServer cr_server;
67
68int tearingdown = 0; /* can't be static */
69
70static DECLCALLBACK(int8_t) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr,
71 const VBOXCMDVBVA_HDR RT_UNTRUSTED_VOLATILE_GUEST *pCmd, uint32_t cbCmd);
72
73DECLINLINE(CRClient*) crVBoxServerClientById(uint32_t u32ClientID)
74{
75 int32_t i;
76
77 if (cr_server.fCrCmdEnabled)
78 return CrHTableGet(&cr_server.clientTable, u32ClientID);
79
80 for (i = 0; i < cr_server.numClients; i++)
81 {
82 if (cr_server.clients[i] && cr_server.clients[i]->conn
83 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
84 {
85 return cr_server.clients[i];
86 }
87 }
88
89 return NULL;
90}
91
92int32_t crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
93{
94 CRClient *pClient = NULL;
95
96 pClient = crVBoxServerClientById(u32ClientID);
97
98 if (!pClient)
99 {
100 WARN(("client not found!"));
101 *ppClient = NULL;
102 return VERR_INVALID_PARAMETER;
103 }
104
105 if (!pClient->conn->vMajor)
106 {
107 WARN(("no major version specified for client!"));
108 *ppClient = NULL;
109 return VERR_NOT_SUPPORTED;
110 }
111
112 *ppClient = pClient;
113
114 return VINF_SUCCESS;
115}
116
117
118/**
119 * Return pointer to server's first SPU.
120 */
121SPU*
122crServerHeadSPU(void)
123{
124 return cr_server.head_spu;
125}
126
127
128
129static void DeleteBarrierCallback( void *data )
130{
131 CRServerBarrier *barrier = (CRServerBarrier *) data;
132 crFree(barrier->waiting);
133 crFree(barrier);
134}
135
136
137static void deleteContextInfoCallback( void *data )
138{
139 CRContextInfo *c = (CRContextInfo *) data;
140 crStateDestroyContext(c->pContext);
141 if (c->CreateInfo.pszDpyName)
142 crFree(c->CreateInfo.pszDpyName);
143 crFree(c);
144}
145
146static void deleteMuralInfoCallback( void *data )
147{
148 CRMuralInfo *m = (CRMuralInfo *) data;
149 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,
150 * and renderspu will destroy it up itself*/
151 {
152 crServerMuralTerm(m);
153 }
154 crFree(m);
155}
156
157static int crVBoxServerCrCmdDisablePostProcess(VBOXCRCMDCTL_HGCMENABLE_DATA *pData);
158
159static void crServerTearDown( void )
160{
161 GLint i;
162 CRClientNode *pNode, *pNext;
163 GLboolean fOldEnableDiff;
164 GLboolean fContextsDeleted = GL_FALSE;
165
166 /* avoid a race condition */
167 if (tearingdown)
168 return;
169
170 tearingdown = 1;
171
172 if (cr_server.fCrCmdEnabled)
173 {
174 VBOXCRCMDCTL_HGCMENABLE_DATA EnableData;
175 /* crVBoxServerHgcmEnable will erase the DisableData, preserve it here */
176 VBOXCRCMDCTL_HGCMDISABLE_DATA DisableData = cr_server.DisableData;
177 int rc;
178
179 CRASSERT(DisableData.pfnNotifyTerm);
180 rc = DisableData.pfnNotifyTerm(DisableData.hNotifyTerm, &EnableData);
181 if (!RT_SUCCESS(rc))
182 {
183 WARN(("pfnNotifyTerm failed %d", rc));
184 return;
185 }
186
187 crVBoxServerCrCmdDisablePostProcess(&EnableData);
188 fContextsDeleted = GL_TRUE;
189
190 CRASSERT(DisableData.pfnNotifyTermDone);
191 DisableData.pfnNotifyTermDone(DisableData.hNotifyTerm);
192
193 Assert(!cr_server.fCrCmdEnabled);
194 }
195
196 crStateSetCurrent( NULL );
197
198 cr_server.curClient = NULL;
199 cr_server.run_queue = NULL;
200
201 crFree( cr_server.overlap_intens );
202 cr_server.overlap_intens = NULL;
203
204 /* needed to make sure window dummy mural not get created on mural destruction
205 * and generally this should be zeroed up */
206 cr_server.currentCtxInfo = NULL;
207 cr_server.currentWindow = -1;
208 cr_server.currentNativeWindow = 0;
209 cr_server.currentMural = NULL;
210
211 if (!fContextsDeleted)
212 {
213#ifndef VBOX_WITH_CR_DISPLAY_LISTS
214 /* sync our state with renderspu,
215 * do it before mural & context deletion to avoid deleting currently set murals/contexts*/
216 cr_server.head_spu->dispatch_table.MakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID);
217#endif
218 }
219
220 /* Deallocate all semaphores */
221 crFreeHashtable(cr_server.semaphores, crFree);
222 cr_server.semaphores = NULL;
223
224 /* Deallocate all barriers */
225 crFreeHashtable(cr_server.barriers, DeleteBarrierCallback);
226 cr_server.barriers = NULL;
227
228#if 0 /** @todo @bugref{8662} -- can trigger SEGFAULTs during savestate */
229 /* Free all context info */
230 crFreeHashtable(cr_server.contextTable, deleteContextInfoCallback);
231#endif
232
233 /* synchronize with reality */
234 if (!fContextsDeleted)
235 {
236 fOldEnableDiff = crStateEnableDiffOnMakeCurrent(GL_FALSE);
237 if(cr_server.MainContextInfo.pContext)
238 crStateMakeCurrent(cr_server.MainContextInfo.pContext);
239 crStateEnableDiffOnMakeCurrent(fOldEnableDiff);
240 }
241
242 /* Free vertex programs */
243 crFreeHashtable(cr_server.programTable, crFree);
244
245 /* Free murals */
246 crFreeHashtable(cr_server.muralTable, deleteMuralInfoCallback);
247
248 CrPMgrTerm();
249
250 if (CrBltIsInitialized(&cr_server.Blitter))
251 {
252 CrBltTerm(&cr_server.Blitter);
253 }
254
255 /* Free dummy murals */
256 crFreeHashtable(cr_server.dummyMuralTable, deleteMuralInfoCallback);
257
258 for (i = 0; i < cr_server.numClients; i++) {
259 if (cr_server.clients[i]) {
260 CRConnection *conn = cr_server.clients[i]->conn;
261 crNetFreeConnection(conn);
262 crFree(cr_server.clients[i]);
263 }
264 }
265 cr_server.numClients = 0;
266
267 pNode = cr_server.pCleanupClient;
268 while (pNode)
269 {
270 pNext=pNode->next;
271 crFree(pNode->pClient);
272 crFree(pNode);
273 pNode=pNext;
274 }
275 cr_server.pCleanupClient = NULL;
276
277 if (crServerRpwIsInitialized(&cr_server.RpwWorker))
278 {
279 crServerRpwTerm(&cr_server.RpwWorker);
280 }
281
282#if 1
283 /* disable these two lines if trying to get stack traces with valgrind */
284 crSPUUnloadChain(cr_server.head_spu);
285 cr_server.head_spu = NULL;
286#endif
287
288 crStateDestroy();
289
290 crNetTearDown();
291
292 VBoxVrListClear(&cr_server.RootVr);
293
294 VBoxVrTerm();
295
296 RTSemEventDestroy(cr_server.hCalloutCompletionEvent);
297}
298
299static void crServerClose( unsigned int id )
300{
301 crError( "Client disconnected!" );
302 (void) id;
303}
304
305static void crServerCleanup( int sigio )
306{
307 crServerTearDown();
308
309 tearingdown = 0;
310}
311
312
313void
314crServerSetPort(int port)
315{
316 cr_server.tcpip_port = port;
317}
318
319
320
321static void
322crPrintHelp(void)
323{
324 printf("Usage: crserver [OPTIONS]\n");
325 printf("Options:\n");
326 printf(" -mothership URL Specifies URL for contacting the mothership.\n");
327 printf(" URL is of the form [protocol://]hostname[:port]\n");
328 printf(" -port N Specifies the port number this server will listen to.\n");
329 printf(" -help Prints this information.\n");
330}
331
332
333/**
334 * Do CRServer initializations. After this, we can begin servicing clients.
335 */
336void
337crServerInit(int argc, char *argv[])
338{
339 int i;
340 const char*env;
341 char *mothership = NULL;
342 CRMuralInfo *defaultMural;
343 int rc = VBoxVrInit();
344 if (!RT_SUCCESS(rc))
345 {
346 crWarning("VBoxVrInit failed, rc %d", rc);
347 return;
348 }
349
350 for (i = 1 ; i < argc ; i++)
351 {
352 if (!crStrcmp( argv[i], "-mothership" ))
353 {
354 if (i == argc - 1)
355 {
356 crError( "-mothership requires an argument" );
357 }
358 mothership = argv[i+1];
359 i++;
360 }
361 else if (!crStrcmp( argv[i], "-port" ))
362 {
363 /* This is the port on which we'll accept client connections */
364 if (i == argc - 1)
365 {
366 crError( "-port requires an argument" );
367 }
368 cr_server.tcpip_port = crStrToInt(argv[i+1]);
369 i++;
370 }
371 else if (!crStrcmp( argv[i], "-vncmode" ))
372 {
373 cr_server.vncMode = 1;
374 }
375 else if (!crStrcmp( argv[i], "-help" ))
376 {
377 crPrintHelp();
378 exit(0);
379 }
380 }
381
382 signal( SIGTERM, crServerCleanup );
383 signal( SIGINT, crServerCleanup );
384#ifndef WINDOWS
385 signal( SIGPIPE, SIG_IGN );
386#endif
387
388#if DEBUG_FP_EXCEPTIONS
389 {
390 fpu_control_t mask;
391 _FPU_GETCW(mask);
392 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
393 | _FPU_MASK_OM | _FPU_MASK_UM);
394 _FPU_SETCW(mask);
395 }
396#endif
397
398 cr_server.fCrCmdEnabled = GL_FALSE;
399 cr_server.fProcessingPendedCommands = GL_FALSE;
400 CrHTableCreate(&cr_server.clientTable, CR_MAX_CLIENTS);
401
402 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
403
404 if (cr_server.bUseMultipleContexts)
405 {
406 crInfo("Info: using multiple contexts!");
407 crDebug("Debug: using multiple contexts!");
408 }
409
410 cr_server.firstCallCreateContext = GL_TRUE;
411 cr_server.firstCallMakeCurrent = GL_TRUE;
412 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
413
414 /*
415 * Create default mural info and hash table.
416 */
417 cr_server.muralTable = crAllocHashtable();
418 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
419 defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
420 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
421
422 cr_server.programTable = crAllocHashtable();
423
424 crNetInit(crServerRecv, crServerClose);
425 crStateInit();
426
427 crServerSetVBoxConfiguration();
428
429 crStateLimitsInit( &(cr_server.limits) );
430
431 /*
432 * Default context
433 */
434 cr_server.contextTable = crAllocHashtable();
435 cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
436
437 cr_server.dummyMuralTable = crAllocHashtable();
438
439 CrPMgrInit();
440
441 cr_server.fRootVrOn = GL_FALSE;
442 VBoxVrListInit(&cr_server.RootVr);
443 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
444
445 crMemset(&cr_server.RpwWorker, 0, sizeof (cr_server.RpwWorker));
446
447 env = crGetenv("CR_SERVER_BFB");
448 if (env)
449 {
450 cr_server.fBlitterMode = env[0] - '0';
451 }
452 else
453 {
454 cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED;
455 }
456 crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter));
457
458 crServerInitDispatch();
459 crServerInitTmpCtxDispatch();
460 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
461
462#ifdef VBOX_WITH_CRSERVER_DUMPER
463 crMemset(&cr_server.Recorder, 0, sizeof (cr_server.Recorder));
464 crMemset(&cr_server.RecorderBlitter, 0, sizeof (cr_server.RecorderBlitter));
465 crMemset(&cr_server.DbgPrintDumper, 0, sizeof (cr_server.DbgPrintDumper));
466 crMemset(&cr_server.HtmlDumper, 0, sizeof (cr_server.HtmlDumper));
467 cr_server.pDumper = NULL;
468#endif
469
470 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
471 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
472
473 cr_server.barriers = crAllocHashtable();
474 cr_server.semaphores = crAllocHashtable();
475}
476
477void crVBoxServerTearDown(void)
478{
479 crServerTearDown();
480}
481
482/**
483 * Do CRServer initializations. After this, we can begin servicing clients.
484 */
485GLboolean crVBoxServerInit(void)
486{
487 CRMuralInfo *defaultMural;
488 const char*env;
489 int rc = VBoxVrInit();
490 if (!RT_SUCCESS(rc))
491 {
492 crWarning("VBoxVrInit failed, rc %d", rc);
493 return GL_FALSE;
494 }
495
496#if DEBUG_FP_EXCEPTIONS
497 {
498 fpu_control_t mask;
499 _FPU_GETCW(mask);
500 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
501 | _FPU_MASK_OM | _FPU_MASK_UM);
502 _FPU_SETCW(mask);
503 }
504#endif
505
506 cr_server.fCrCmdEnabled = GL_FALSE;
507 cr_server.fProcessingPendedCommands = GL_FALSE;
508 CrHTableCreate(&cr_server.clientTable, CR_MAX_CLIENTS);
509
510 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
511
512 if (cr_server.bUseMultipleContexts)
513 {
514 crInfo("Info: using multiple contexts!");
515 crDebug("Debug: using multiple contexts!");
516 }
517
518 crNetInit(crServerRecv, crServerClose);
519
520 cr_server.firstCallCreateContext = GL_TRUE;
521 cr_server.firstCallMakeCurrent = GL_TRUE;
522
523 cr_server.bIsInLoadingState = GL_FALSE;
524 cr_server.bIsInSavingState = GL_FALSE;
525 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
526
527 cr_server.pCleanupClient = NULL;
528
529 rc = RTSemEventCreate(&cr_server.hCalloutCompletionEvent);
530 if (!RT_SUCCESS(rc))
531 {
532 WARN(("RTSemEventCreate failed %d", rc));
533 return GL_FALSE;
534 }
535
536 /*
537 * Create default mural info and hash table.
538 */
539 cr_server.muralTable = crAllocHashtable();
540 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
541 defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
542 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
543
544 cr_server.programTable = crAllocHashtable();
545
546 crStateInit();
547
548 crStateLimitsInit( &(cr_server.limits) );
549
550 cr_server.barriers = crAllocHashtable();
551 cr_server.semaphores = crAllocHashtable();
552
553 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
554 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
555
556 /*
557 * Default context
558 */
559 cr_server.contextTable = crAllocHashtable();
560
561 cr_server.dummyMuralTable = crAllocHashtable();
562
563 CrPMgrInit();
564
565 cr_server.fRootVrOn = GL_FALSE;
566 VBoxVrListInit(&cr_server.RootVr);
567 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
568
569 crMemset(&cr_server.RpwWorker, 0, sizeof (cr_server.RpwWorker));
570
571 env = crGetenv("CR_SERVER_BFB");
572 if (env)
573 {
574 cr_server.fBlitterMode = env[0] - '0';
575 }
576 else
577 {
578 cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED;
579 }
580 crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter));
581
582 crServerSetVBoxConfigurationHGCM();
583
584 if (!cr_server.head_spu)
585 {
586 crStateDestroy();
587 return GL_FALSE;
588 }
589
590 crServerInitDispatch();
591 crServerInitTmpCtxDispatch();
592 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
593
594#ifdef VBOX_WITH_CRSERVER_DUMPER
595 crMemset(&cr_server.Recorder, 0, sizeof (cr_server.Recorder));
596 crMemset(&cr_server.RecorderBlitter, 0, sizeof (cr_server.RecorderBlitter));
597 crMemset(&cr_server.DbgPrintDumper, 0, sizeof (cr_server.DbgPrintDumper));
598 crMemset(&cr_server.HtmlDumper, 0, sizeof (cr_server.HtmlDumper));
599 cr_server.pDumper = NULL;
600#endif
601
602 /*Check for PBO support*/
603 if (crStateGetCurrent()->extensions.ARB_pixel_buffer_object)
604 {
605 cr_server.bUsePBOForReadback=GL_TRUE;
606 }
607
608 return GL_TRUE;
609}
610
611static int32_t crVBoxServerAddClientObj(uint32_t u32ClientID, CRClient **ppNewClient)
612{
613 CRClient *newClient;
614
615 if (cr_server.numClients>=CR_MAX_CLIENTS)
616 {
617 if (ppNewClient)
618 *ppNewClient = NULL;
619 return VERR_MAX_THRDS_REACHED;
620 }
621
622 newClient = (CRClient *) crCalloc(sizeof(CRClient));
623 crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
624
625 newClient->spu_id = 0;
626 newClient->currentCtxInfo = &cr_server.MainContextInfo;
627 newClient->currentContextNumber = -1;
628 newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
629 cr_server.tcpip_port,
630 cr_server.mtu, 0);
631 newClient->conn->u32ClientID = u32ClientID;
632
633 cr_server.clients[cr_server.numClients++] = newClient;
634
635 crServerAddToRunQueue(newClient);
636
637 if (ppNewClient)
638 *ppNewClient = newClient;
639
640 return VINF_SUCCESS;
641}
642
643int32_t crVBoxServerAddClient(uint32_t u32ClientID)
644{
645 CRClient *newClient;
646
647 if (cr_server.numClients>=CR_MAX_CLIENTS)
648 {
649 return VERR_MAX_THRDS_REACHED;
650 }
651
652 newClient = (CRClient *) crCalloc(sizeof(CRClient));
653 crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
654
655 newClient->spu_id = 0;
656 newClient->currentCtxInfo = &cr_server.MainContextInfo;
657 newClient->currentContextNumber = -1;
658 newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
659 cr_server.tcpip_port,
660 cr_server.mtu, 0);
661 newClient->conn->u32ClientID = u32ClientID;
662
663 cr_server.clients[cr_server.numClients++] = newClient;
664
665 crServerAddToRunQueue(newClient);
666
667 return VINF_SUCCESS;
668}
669
670static void crVBoxServerRemoveClientObj(CRClient *pClient)
671{
672#ifdef VBOX_WITH_CRHGSMI
673 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
674#endif
675
676 /* Disconnect the client */
677 pClient->conn->Disconnect(pClient->conn);
678
679 /* Let server clear client from the queue */
680 crServerDeleteClient(pClient);
681}
682
683static void crVBoxServerRemoveAllClients()
684{
685 int32_t i;
686 for (i = cr_server.numClients - 1; i >= 0; --i)
687 {
688 Assert(cr_server.clients[i]);
689 crVBoxServerRemoveClientObj(cr_server.clients[i]);
690 }
691}
692
693void crVBoxServerRemoveClient(uint32_t u32ClientID)
694{
695 CRClient *pClient=NULL;
696 int32_t i;
697
698 crDebug("crServer: RemoveClient u32ClientID=%d", u32ClientID);
699
700 for (i = 0; i < cr_server.numClients; i++)
701 {
702 if (cr_server.clients[i] && cr_server.clients[i]->conn
703 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
704 {
705 pClient = cr_server.clients[i];
706 break;
707 }
708 }
709 //if (!pClient) return VERR_INVALID_PARAMETER;
710 if (!pClient)
711 {
712 WARN(("Invalid client id %u passed to crVBoxServerRemoveClient", u32ClientID));
713 return;
714 }
715
716 crVBoxServerRemoveClientObj(pClient);
717}
718
719static void crVBoxServerInternalClientWriteRead(CRClient *pClient)
720{
721#ifdef VBOXCR_LOGFPS
722 uint64_t tstart, tend;
723#endif
724
725 /*crDebug("=>crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
726
727
728#ifdef VBOXCR_LOGFPS
729 tstart = RTTimeNanoTS();
730#endif
731
732 /* This should be setup already */
733 CRASSERT(pClient->conn->pBuffer);
734 CRASSERT(pClient->conn->cbBuffer);
735#ifdef VBOX_WITH_CRHGSMI
736 CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&pClient->conn->CmdData);
737#endif
738
739 if (
740#ifdef VBOX_WITH_CRHGSMI
741 !CRVBOXHGSMI_CMDDATA_IS_SET(&pClient->conn->CmdData) &&
742#endif
743 cr_server.run_queue->client != pClient
744 && crServerClientInBeginEnd(cr_server.run_queue->client))
745 {
746 crDebug("crServer: client %d blocked, allow_redir_ptr = 0", pClient->conn->u32ClientID);
747 pClient->conn->allow_redir_ptr = 0;
748 }
749 else
750 {
751 pClient->conn->allow_redir_ptr = 1;
752 }
753
754 crNetRecv();
755 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
756 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
757
758 crServerServiceClients();
759 crStateResetCurrentPointers(&cr_server.current);
760
761#ifndef VBOX_WITH_CRHGSMI
762 CRASSERT(!pClient->conn->allow_redir_ptr || crNetNumMessages(pClient->conn)==0);
763#endif
764
765#ifdef VBOXCR_LOGFPS
766 tend = RTTimeNanoTS();
767 pClient->timeUsed += tend-tstart;
768#endif
769 /*crDebug("<=crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
770}
771
772
773int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer)
774{
775 CRClient *pClient=NULL;
776 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
777
778 if (RT_FAILURE(rc))
779 return rc;
780
781 CRASSERT(pBuffer);
782
783 /* This should never fire unless we start to multithread */
784 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
785
786 pClient->conn->pBuffer = pBuffer;
787 pClient->conn->cbBuffer = cbBuffer;
788#ifdef VBOX_WITH_CRHGSMI
789 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
790#endif
791
792 crVBoxServerInternalClientWriteRead(pClient);
793
794 return VINF_SUCCESS;
795}
796
797int32_t crVBoxServerInternalClientRead(CRClient *pClient, uint8_t *pBuffer, uint32_t *pcbBuffer)
798{
799 if (pClient->conn->cbHostBuffer > *pcbBuffer)
800 {
801 crDebug("crServer: [%lx] ClientRead u32ClientID=%d FAIL, host buffer too small %d of %d",
802 crThreadID(), pClient->conn->u32ClientID, *pcbBuffer, pClient->conn->cbHostBuffer);
803
804 /* Return the size of needed buffer */
805 *pcbBuffer = pClient->conn->cbHostBuffer;
806
807 return VERR_BUFFER_OVERFLOW;
808 }
809
810 *pcbBuffer = pClient->conn->cbHostBuffer;
811
812 if (*pcbBuffer)
813 {
814 CRASSERT(pClient->conn->pHostBuffer);
815
816 crMemcpy(pBuffer, pClient->conn->pHostBuffer, *pcbBuffer);
817 pClient->conn->cbHostBuffer = 0;
818 }
819
820 return VINF_SUCCESS;
821}
822
823int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t *pcbBuffer)
824{
825 CRClient *pClient=NULL;
826 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
827
828 if (RT_FAILURE(rc))
829 return rc;
830
831#ifdef VBOX_WITH_CRHGSMI
832 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
833#endif
834
835 return crVBoxServerInternalClientRead(pClient, pBuffer, pcbBuffer);
836}
837
838extern DECLEXPORT(int32_t) crVBoxServerClientGetCapsLegacy(uint32_t u32ClientID, uint32_t *pu32Caps)
839{
840 uint32_t u32Caps = cr_server.u32Caps;
841 u32Caps &= ~CR_VBOX_CAP_CMDVBVA;
842 *pu32Caps = u32Caps;
843 return VINF_SUCCESS;
844}
845
846extern DECLEXPORT(int32_t) crVBoxServerClientGetCapsNew(uint32_t u32ClientID, CR_CAPS_INFO *pInfo)
847{
848 pInfo->u32Caps = cr_server.u32Caps;
849 pInfo->u32CmdVbvaVersion = CR_CMDVBVA_VERSION;
850 return VINF_SUCCESS;
851}
852
853static int32_t crVBoxServerClientObjSetVersion(CRClient *pClient, uint32_t vMajor, uint32_t vMinor)
854{
855 pClient->conn->vMajor = vMajor;
856 pClient->conn->vMinor = vMinor;
857
858 if (vMajor != CR_PROTOCOL_VERSION_MAJOR
859 || vMinor != CR_PROTOCOL_VERSION_MINOR)
860 return VERR_NOT_SUPPORTED;
861 return VINF_SUCCESS;
862}
863
864int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor)
865{
866 CRClient *pClient=NULL;
867 int32_t i;
868
869 for (i = 0; i < cr_server.numClients; i++)
870 {
871 if (cr_server.clients[i] && cr_server.clients[i]->conn
872 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
873 {
874 pClient = cr_server.clients[i];
875 break;
876 }
877 }
878 if (!pClient) return VERR_INVALID_PARAMETER;
879
880 return crVBoxServerClientObjSetVersion(pClient, vMajor, vMinor);
881}
882
883static int32_t crVBoxServerClientObjSetPID(CRClient *pClient, uint64_t pid)
884{
885 pClient->pid = pid;
886
887 return VINF_SUCCESS;
888}
889
890int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid)
891{
892 CRClient *pClient=NULL;
893 int32_t i;
894
895 for (i = 0; i < cr_server.numClients; i++)
896 {
897 if (cr_server.clients[i] && cr_server.clients[i]->conn
898 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
899 {
900 pClient = cr_server.clients[i];
901 break;
902 }
903 }
904 if (!pClient) return VERR_INVALID_PARAMETER;
905
906 return crVBoxServerClientObjSetPID(pClient, pid);
907}
908
909int
910CRServerMain(int argc, char *argv[])
911{
912 crServerInit(argc, argv);
913
914 crServerSerializeRemoteStreams();
915
916 crServerTearDown();
917
918 tearingdown = 0;
919
920 return 0;
921}
922
923static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2)
924{
925 CRMuralInfo *pMI = (CRMuralInfo*) data1;
926 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
927 int32_t rc;
928
929 CRASSERT(pMI && pSSM);
930
931 /* Don't store default mural */
932 if (!key) return;
933
934 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
935 CRASSERT(rc == VINF_SUCCESS);
936
937 rc = SSMR3PutMem(pSSM, pMI, RT_UOFFSETOF(CRMuralInfo, CreateInfo));
938 CRASSERT(rc == VINF_SUCCESS);
939
940 if (pMI->pVisibleRects)
941 {
942 rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects);
943 }
944
945 rc = SSMR3PutMem(pSSM, pMI->ctxUsage, sizeof (pMI->ctxUsage));
946 CRASSERT(rc == VINF_SUCCESS);
947}
948
949/** @todo add hashtable walker with result info and intermediate abort */
950static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *data2)
951{
952 CRCreateInfo_t *pCreateInfo = (CRCreateInfo_t *)data1;
953 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
954 int32_t rc;
955
956 CRASSERT(pCreateInfo && pSSM);
957
958 /* Don't store default mural create info */
959 if (!key) return;
960
961 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
962 CRASSERT(rc == VINF_SUCCESS);
963
964 rc = SSMR3PutMem(pSSM, pCreateInfo, sizeof(*pCreateInfo));
965 CRASSERT(rc == VINF_SUCCESS);
966
967 if (pCreateInfo->pszDpyName)
968 {
969 rc = SSMR3PutStrZ(pSSM, pCreateInfo->pszDpyName);
970 CRASSERT(rc == VINF_SUCCESS);
971 }
972}
973
974static void crVBoxServerSaveCreateInfoFromMuralInfoCB(unsigned long key, void *data1, void *data2)
975{
976 CRMuralInfo *pMural = (CRMuralInfo *)data1;
977 CRCreateInfo_t CreateInfo;
978 CreateInfo.pszDpyName = pMural->CreateInfo.pszDpyName;
979 CreateInfo.visualBits = pMural->CreateInfo.requestedVisualBits;
980 CreateInfo.externalID = pMural->CreateInfo.externalID;
981 crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
982}
983
984static void crVBoxServerSaveCreateInfoFromCtxInfoCB(unsigned long key, void *data1, void *data2)
985{
986 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
987 CRCreateInfo_t CreateInfo;
988 CreateInfo.pszDpyName = pContextInfo->CreateInfo.pszDpyName;
989 CreateInfo.visualBits = pContextInfo->CreateInfo.requestedVisualBits;
990 /* saved state contains internal id */
991 CreateInfo.externalID = pContextInfo->pContext->id;
992 crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
993}
994
995static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data2)
996{
997 CRTextureObj *pTexture = (CRTextureObj *) data1;
998 CRContext *pContext = (CRContext *) data2;
999
1000 CRASSERT(pTexture && pContext);
1001 crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
1002}
1003
1004typedef struct CRVBOX_SAVE_STATE_GLOBAL
1005{
1006 /* context id -> mural association
1007 * on context data save, each context will be made current with the corresponding mural from this table
1008 * thus saving the mural front & back buffer data */
1009 CRHashTable *contextMuralTable;
1010 /* mural id -> context info
1011 * for murals that do not have associated context in contextMuralTable
1012 * we still need to save*/
1013 CRHashTable *additionalMuralContextTable;
1014
1015 PSSMHANDLE pSSM;
1016
1017 int rc;
1018} CRVBOX_SAVE_STATE_GLOBAL, *PCRVBOX_SAVE_STATE_GLOBAL;
1019
1020
1021typedef struct CRVBOX_CTXWND_CTXWALKER_CB
1022{
1023 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
1024 CRHashTable *usedMuralTable;
1025 GLuint cAdditionalMurals;
1026} CRVBOX_CTXWND_CTXWALKER_CB, *PCRVBOX_CTXWND_CTXWALKER_CB;
1027
1028static void crVBoxServerBuildAdditionalWindowContextMapCB(unsigned long key, void *data1, void *data2)
1029{
1030 CRMuralInfo * pMural = (CRMuralInfo *) data1;
1031 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
1032 CRContextInfo *pContextInfo = NULL;
1033
1034 if (!pMural->CreateInfo.externalID)
1035 {
1036 CRASSERT(!key);
1037 return;
1038 }
1039
1040 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
1041 {
1042 Assert(crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
1043 return;
1044 }
1045
1046 Assert(!crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
1047
1048 if (cr_server.MainContextInfo.CreateInfo.realVisualBits == pMural->CreateInfo.realVisualBits)
1049 {
1050 pContextInfo = &cr_server.MainContextInfo;
1051 }
1052 else
1053 {
1054 crWarning("different visual bits not implemented!");
1055 pContextInfo = &cr_server.MainContextInfo;
1056 }
1057
1058 crHashtableAdd(pData->pGlobal->additionalMuralContextTable, pMural->CreateInfo.externalID, pContextInfo);
1059}
1060
1061
1062typedef struct CRVBOX_CTXWND_WNDWALKER_CB
1063{
1064 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
1065 CRHashTable *usedMuralTable;
1066 CRContextInfo *pContextInfo;
1067 CRMuralInfo * pMural;
1068} CRVBOX_CTXWND_WNDWALKER_CB, *PCRVBOX_CTXWND_WNDWALKER_CB;
1069
1070static void crVBoxServerBuildContextWindowMapWindowWalkerCB(unsigned long key, void *data1, void *data2)
1071{
1072 CRMuralInfo * pMural = (CRMuralInfo *) data1;
1073 PCRVBOX_CTXWND_WNDWALKER_CB pData = (PCRVBOX_CTXWND_WNDWALKER_CB)data2;
1074
1075 Assert(pData->pMural != pMural);
1076 Assert(pData->pContextInfo);
1077
1078 if (pData->pMural)
1079 return;
1080
1081 if (!pMural->CreateInfo.externalID)
1082 {
1083 CRASSERT(!key);
1084 return;
1085 }
1086
1087 if (!CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pData->pContextInfo->pContext))
1088 return;
1089
1090 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
1091 return;
1092
1093 CRASSERT(pMural->CreateInfo.realVisualBits == pData->pContextInfo->CreateInfo.realVisualBits);
1094 pData->pMural = pMural;
1095}
1096
1097static void crVBoxServerBuildContextUsedWindowMapCB(unsigned long key, void *data1, void *data2)
1098{
1099 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
1100 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
1101
1102 if (!pContextInfo->currentMural)
1103 return;
1104
1105 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pContextInfo->currentMural);
1106 crHashtableAdd(pData->usedMuralTable, pContextInfo->currentMural->CreateInfo.externalID, pContextInfo->currentMural);
1107}
1108
1109CRMuralInfo * crServerGetDummyMural(GLint visualBits)
1110{
1111 CRMuralInfo * pMural = (CRMuralInfo *)crHashtableSearch(cr_server.dummyMuralTable, visualBits);
1112 if (!pMural)
1113 {
1114 GLint id;
1115 pMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
1116 if (!pMural)
1117 {
1118 crWarning("crCalloc failed!");
1119 return NULL;
1120 }
1121 id = crServerMuralInit(pMural, GL_FALSE, visualBits, 0);
1122 if (id < 0)
1123 {
1124 crWarning("crServerMuralInit failed!");
1125 crFree(pMural);
1126 return NULL;
1127 }
1128
1129 crHashtableAdd(cr_server.dummyMuralTable, visualBits, pMural);
1130 }
1131
1132 return pMural;
1133}
1134
1135static void crVBoxServerBuildContextUnusedWindowMapCB(unsigned long key, void *data1, void *data2)
1136{
1137 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
1138 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
1139 CRMuralInfo * pMural = NULL;
1140
1141 if (pContextInfo->currentMural)
1142 return;
1143
1144 Assert(crHashtableNumElements(pData->pGlobal->contextMuralTable) <= crHashtableNumElements(cr_server.muralTable) - 1);
1145 if (crHashtableNumElements(pData->pGlobal->contextMuralTable) < crHashtableNumElements(cr_server.muralTable) - 1)
1146 {
1147 CRVBOX_CTXWND_WNDWALKER_CB MuralData;
1148 MuralData.pGlobal = pData->pGlobal;
1149 MuralData.usedMuralTable = pData->usedMuralTable;
1150 MuralData.pContextInfo = pContextInfo;
1151 MuralData.pMural = NULL;
1152
1153 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildContextWindowMapWindowWalkerCB, &MuralData);
1154
1155 pMural = MuralData.pMural;
1156
1157 }
1158
1159 if (!pMural)
1160 {
1161 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
1162 if (!pMural)
1163 {
1164 crWarning("crServerGetDummyMural failed");
1165 return;
1166 }
1167 }
1168 else
1169 {
1170 crHashtableAdd(pData->usedMuralTable, pMural->CreateInfo.externalID, pMural);
1171 ++pData->cAdditionalMurals;
1172 }
1173
1174 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pMural);
1175}
1176
1177static void crVBoxServerBuildSaveStateGlobal(PCRVBOX_SAVE_STATE_GLOBAL pGlobal)
1178{
1179 CRVBOX_CTXWND_CTXWALKER_CB Data;
1180 GLuint cMurals;
1181 pGlobal->contextMuralTable = crAllocHashtable();
1182 pGlobal->additionalMuralContextTable = crAllocHashtable();
1183 /* 1. go through all contexts and match all having currentMural set */
1184 Data.pGlobal = pGlobal;
1185 Data.usedMuralTable = crAllocHashtable();
1186 Data.cAdditionalMurals = 0;
1187 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUsedWindowMapCB, &Data);
1188
1189 cMurals = crHashtableNumElements(pGlobal->contextMuralTable);
1190 CRASSERT(cMurals <= crHashtableNumElements(cr_server.contextTable));
1191 CRASSERT(cMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
1192 CRASSERT(cMurals == crHashtableNumElements(Data.usedMuralTable));
1193 if (cMurals < crHashtableNumElements(cr_server.contextTable))
1194 {
1195 Data.cAdditionalMurals = 0;
1196 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUnusedWindowMapCB, &Data);
1197 }
1198
1199 CRASSERT(crHashtableNumElements(pGlobal->contextMuralTable) == crHashtableNumElements(cr_server.contextTable));
1200 CRASSERT(cMurals + Data.cAdditionalMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
1201 if (cMurals + Data.cAdditionalMurals < crHashtableNumElements(cr_server.muralTable) - 1)
1202 {
1203 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildAdditionalWindowContextMapCB, &Data);
1204 CRASSERT(cMurals + Data.cAdditionalMurals + crHashtableNumElements(pGlobal->additionalMuralContextTable) == crHashtableNumElements(cr_server.muralTable) - 1);
1205 }
1206
1207 crFreeHashtable(Data.usedMuralTable, NULL);
1208}
1209
1210static void crVBoxServerFBImageDataTerm(CRFBData *pData)
1211{
1212 GLuint i;
1213 for (i = 0; i < pData->cElements; ++i)
1214 {
1215 CRFBDataElement * pEl = &pData->aElements[i];
1216 if (pEl->pvData)
1217 {
1218 crFree(pEl->pvData);
1219 /* sanity */
1220 pEl->pvData = NULL;
1221 }
1222 }
1223 pData->cElements = 0;
1224}
1225
1226static int crVBoxAddFBDataElement(CRFBData *pData, GLint idFBO, GLenum enmBuffer, GLint width, GLint height, GLenum enmFormat, GLenum enmType)
1227{
1228 CRFBDataElement *pEl;
1229
1230 AssertCompile(sizeof (GLfloat) == 4);
1231 AssertCompile(sizeof (GLuint) == 4);
1232
1233 pEl = &pData->aElements[pData->cElements];
1234 pEl->idFBO = idFBO;
1235 pEl->enmBuffer = enmBuffer;
1236 pEl->posX = 0;
1237 pEl->posY = 0;
1238 pEl->width = width;
1239 pEl->height = height;
1240 pEl->enmFormat = enmFormat;
1241 pEl->enmType = enmType;
1242 pEl->cbData = width * height * 4;
1243
1244 pEl->pvData = crCalloc(pEl->cbData);
1245 if (!pEl->pvData)
1246 {
1247 crVBoxServerFBImageDataTerm(pData);
1248 crWarning(": crCalloc failed");
1249 return VERR_NO_MEMORY;
1250 }
1251
1252 ++pData->cElements;
1253
1254 return VINF_SUCCESS;
1255}
1256
1257/* Add framebuffer image elements arrording to SSM version. Please refer to cr_version.h
1258 * in order to distinguish between versions. */
1259static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, uint32_t version, GLuint overrideWidth, GLuint overrideHeight)
1260{
1261 CRContext *pContext;
1262 GLuint i;
1263 GLfloat *pF;
1264 GLuint width;
1265 GLuint height;
1266 int rc;
1267
1268 crMemset(pData, 0, sizeof (*pData));
1269
1270 pContext = pCtxInfo->pContext;
1271
1272 /* the version should be always actual when we do reads,
1273 * i.e. it could differ on writes when snapshot is getting loaded */
1274 CRASSERT(fWrite || version == SHCROGL_SSM_VERSION);
1275
1276 width = overrideWidth ? overrideWidth : pMural->width;
1277 height = overrideHeight ? overrideHeight : pMural->height;
1278
1279 if (!width || !height)
1280 return VINF_SUCCESS;
1281
1282 if (pMural)
1283 {
1284 if (fWrite)
1285 {
1286 if (!pContext->framebufferobject.drawFB)
1287 pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurDrawBuffer);
1288 }
1289 else
1290 {
1291 if (!pContext->framebufferobject.readFB)
1292 pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurReadBuffer);
1293 }
1294 }
1295
1296 pData->u32Version = version;
1297
1298 pData->cElements = 0;
1299
1300 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1301 pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT, width, height, GL_RGBA, GL_UNSIGNED_BYTE);
1302 AssertReturn(rc == VINF_SUCCESS, rc);
1303
1304 /* There is a lot of code that assumes we have double buffering, just assert here to print a warning in the log
1305 * so that we know that something irregular is going on. */
1306 CRASSERT(pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT);
1307
1308 if (( pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT)
1309 || version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL) /* <- Older version had a typo which lead to back always being used,
1310 * no matter what the visual bits are. */
1311 {
1312 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0,
1313 pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK, width, height, GL_RGBA, GL_UNSIGNED_BYTE);
1314 AssertReturn(rc == VINF_SUCCESS, rc);
1315 }
1316
1317 if (version < SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1318 return VINF_SUCCESS;
1319
1320 if (version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL)
1321 {
1322 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1323 pMural ? pMural->idDepthStencilRB : 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
1324 AssertReturn(rc == VINF_SUCCESS, rc);
1325
1326 /* Init to default depth value, just in case. "pData->cElements - 1" because we incremented counter in crVBoxAddFBDataElement(). */
1327 pF = (GLfloat*)pData->aElements[pData->cElements - 1].pvData;
1328 for (i = 0; i < width * height; ++i)
1329 pF[i] = 1.;
1330
1331 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1332 pMural ? pMural->idDepthStencilRB : 0, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_INT);
1333 AssertReturn(rc == VINF_SUCCESS, rc);
1334
1335 return VINF_SUCCESS;
1336 }
1337
1338 if (version < SHCROGL_SSM_VERSION_WITH_SEPARATE_DEPTH_STENCIL_BUFFERS)
1339 {
1340 /* Use GL_DEPTH_STENCIL only in case if both CR_STENCIL_BIT and CR_DEPTH_BIT specified. */
1341 if ( (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT)
1342 && (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT))
1343 {
1344 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0, 0,
1345 width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
1346 AssertReturn(rc == VINF_SUCCESS, rc);
1347 }
1348
1349 return VINF_SUCCESS;
1350 }
1351
1352 /* Current SSM verion (SHCROGL_SSM_VERSION_WITH_SEPARATE_DEPTH_STENCIL_BUFFERS). */
1353
1354 if (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT)
1355 {
1356 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1357 pMural ? pMural->idDepthStencilRB : 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
1358 AssertReturn(rc == VINF_SUCCESS, rc);
1359
1360 /* Init to default depth value, just in case. "pData->cElements - 1" because we incremented counter in crVBoxAddFBDataElement(). */
1361 pF = (GLfloat*)pData->aElements[pData->cElements - 1].pvData;
1362 for (i = 0; i < width * height; ++i)
1363 pF[i] = 1.;
1364 }
1365
1366 if (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT)
1367 {
1368 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1369 pMural ? pMural->idDepthStencilRB : 0, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_INT);
1370 AssertReturn(rc == VINF_SUCCESS, rc);
1371 }
1372
1373 return VINF_SUCCESS;
1374}
1375
1376static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
1377{
1378 CRContextInfo *pCtxInfo;
1379 CRContext *pContext;
1380 CRMuralInfo *pMural;
1381 int32_t rc;
1382 GLuint i;
1383 struct
1384 {
1385 CRFBData data;
1386 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1387 } Data;
1388
1389 Assert(sizeof (Data) >= RT_UOFFSETOF(CRFBData, aElements[4]));
1390
1391 pCtxInfo = cr_server.currentCtxInfo;
1392 pContext = pCtxInfo->pContext;
1393 pMural = pCtxInfo->currentMural;
1394
1395 rc = crVBoxServerFBImageDataInitEx(&Data.data, pCtxInfo, pMural, GL_FALSE, SHCROGL_SSM_VERSION, 0, 0);
1396 if (!RT_SUCCESS(rc))
1397 {
1398 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1399 return rc;
1400 }
1401
1402 rc = crStateAcquireFBImage(pContext, &Data.data);
1403 AssertRCReturn(rc, rc);
1404
1405 for (i = 0; i < Data.data.cElements; ++i)
1406 {
1407 CRFBDataElement * pEl = &Data.data.aElements[i];
1408 rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
1409 AssertRCReturn(rc, rc);
1410 }
1411
1412 crVBoxServerFBImageDataTerm(&Data.data);
1413
1414 return VINF_SUCCESS;
1415}
1416
1417#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
1418 if(!RT_SUCCESS((_rc))) { \
1419 AssertFailed(); \
1420 return; \
1421 } \
1422 } while (0)
1423
1424static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
1425{
1426 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1427 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1428 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1429 PSSMHANDLE pSSM = pData->pSSM;
1430 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1431 CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
1432
1433 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1434
1435 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1436
1437 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1438 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1439
1440 pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
1441 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1442
1443 crServerPerformMakeCurrent(pMural, pContextInfo);
1444
1445 pData->rc = crVBoxServerSaveFBImage(pSSM);
1446
1447 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1448 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1449 pContextInfo->currentMural = pInitialCurMural;
1450
1451 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1452}
1453
1454static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
1455{
1456 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1457 CRContext *pContext = pContextInfo->pContext;
1458 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1459 PSSMHANDLE pSSM = pData->pSSM;
1460 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
1461 CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
1462 const int32_t i32Dummy = 0;
1463
1464 AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
1465 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1466
1467 CRASSERT(pContext && pSSM);
1468 CRASSERT(pMural);
1469 CRASSERT(pMural->CreateInfo.externalID);
1470
1471 /* We could have skipped saving the key and use similar callback to load context states back,
1472 * but there's no guarantee we'd traverse hashtable in same order after loading.
1473 */
1474 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1475 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1476
1477#ifdef DEBUG_misha
1478 {
1479 unsigned long id;
1480 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
1481 crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
1482 else
1483 CRASSERT(id == key);
1484 }
1485#endif
1486
1487#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1488 if (pContextInfo->currentMural
1489 || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
1490 )
1491 {
1492 CRASSERT(pMural->CreateInfo.externalID);
1493 CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1494 pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
1495 }
1496 else
1497 {
1498 /* this is a dummy mural */
1499 CRASSERT(!pMural->width);
1500 CRASSERT(!pMural->height);
1501 CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1502 pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
1503 }
1504 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1505
1506 CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
1507 CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
1508 CRASSERT(cr_server.curClient);
1509
1510 crServerPerformMakeCurrent(pMural, pContextInfo);
1511#endif
1512
1513 pData->rc = crStateSaveContext(pContext, pSSM);
1514 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1515
1516 pData->rc = crVBoxServerSaveFBImage(pSSM);
1517 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1518
1519 /* restore the initial current mural */
1520 pContextInfo->currentMural = pContextCurrentMural;
1521}
1522
1523static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
1524
1525static int32_t crVBoxServerSaveStatePerform(PSSMHANDLE pSSM)
1526{
1527 int32_t rc, i;
1528 uint32_t ui32;
1529 GLboolean b;
1530 unsigned long key;
1531 GLenum err;
1532#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1533 CRClient *curClient;
1534 CRMuralInfo *curMural = NULL;
1535 CRContextInfo *curCtxInfo = NULL;
1536#endif
1537 CRVBOX_SAVE_STATE_GLOBAL Data;
1538
1539 crMemset(&Data, 0, sizeof (Data));
1540
1541#if 0
1542 crVBoxServerCheckConsistency();
1543#endif
1544
1545 /* We shouldn't be called if there's no clients at all*/
1546 CRASSERT(cr_server.numClients > 0);
1547
1548 /** @todo it's hack atm */
1549 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1550 * for every connected client (e.g. guest opengl application)
1551 */
1552 if (!cr_server.bIsInSavingState) /* It's first call */
1553 {
1554 cr_server.bIsInSavingState = GL_TRUE;
1555
1556 /* Store number of clients */
1557 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1558 AssertRCReturn(rc, rc);
1559
1560 /* we get called only once for CrCmd case, so disable the hack */
1561 g_hackVBoxServerSaveLoadCallsLeft = cr_server.fCrCmdEnabled ? 1 : cr_server.numClients;
1562 }
1563
1564 g_hackVBoxServerSaveLoadCallsLeft--;
1565
1566 /* Do nothing until we're being called last time */
1567 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1568 {
1569 return VINF_SUCCESS;
1570 }
1571
1572#ifdef DEBUG_misha
1573#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart"
1574#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop"
1575
1576 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1577 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START);
1578#endif
1579
1580 /* Save rendering contexts creation info */
1581 ui32 = crHashtableNumElements(cr_server.contextTable);
1582 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1583 AssertRCReturn(rc, rc);
1584 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1585
1586#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1587 curClient = cr_server.curClient;
1588 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1589 if (curClient)
1590 {
1591 curCtxInfo = cr_server.curClient->currentCtxInfo;
1592 curMural = cr_server.curClient->currentMural;
1593 }
1594 else if (cr_server.numClients)
1595 {
1596 cr_server.curClient = cr_server.clients[0];
1597 }
1598#endif
1599
1600 /* first save windows info */
1601 /* Save windows creation info */
1602 ui32 = crHashtableNumElements(cr_server.muralTable);
1603 /* There should be default mural always */
1604 CRASSERT(ui32>=1);
1605 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1606 AssertRCReturn(rc, rc);
1607 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1608
1609 /* Save cr_server.muralTable
1610 * @todo we don't need it all, just geometry info actually
1611 */
1612 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1613 AssertRCReturn(rc, rc);
1614 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1615
1616 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1617 crVBoxServerBuildSaveStateGlobal(&Data);
1618
1619 rc = crStateSaveGlobals(pSSM);
1620 AssertRCReturn(rc, rc);
1621
1622 Data.pSSM = pSSM;
1623 /* Save contexts state tracker data */
1624 /** @todo For now just some blind data dumps,
1625 * but I've a feeling those should be saved/restored in a very strict sequence to
1626 * allow diff_api to work correctly.
1627 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1628 */
1629 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1630 AssertRCReturn(Data.rc, Data.rc);
1631
1632 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1633 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1634 AssertRCReturn(rc, rc);
1635
1636 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1637 AssertRCReturn(Data.rc, Data.rc);
1638
1639#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1640 cr_server.curClient = curClient;
1641 /* Restore original win and ctx IDs*/
1642 if (curClient && curMural && curCtxInfo)
1643 {
1644 crServerPerformMakeCurrent(curMural, curCtxInfo);
1645 }
1646 else
1647 {
1648 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1649 }
1650#endif
1651
1652 /* Save clients info */
1653 for (i = 0; i < cr_server.numClients; i++)
1654 {
1655 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1656 {
1657 CRClient *pClient = cr_server.clients[i];
1658
1659 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1660 AssertRCReturn(rc, rc);
1661
1662 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1663 AssertRCReturn(rc, rc);
1664
1665 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1666 AssertRCReturn(rc, rc);
1667
1668 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1669 AssertRCReturn(rc, rc);
1670
1671 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber > 0)
1672 {
1673 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1674 CRASSERT(b);
1675 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1676 AssertRCReturn(rc, rc);
1677 }
1678
1679 if (pClient->currentMural && pClient->currentWindow > 0)
1680 {
1681 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1682 CRASSERT(b);
1683 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1684 AssertRCReturn(rc, rc);
1685 }
1686 }
1687 }
1688
1689 rc = crServerPendSaveState(pSSM);
1690 AssertRCReturn(rc, rc);
1691
1692 rc = CrPMgrSaveState(pSSM);
1693 AssertRCReturn(rc, rc);
1694
1695#ifdef VBOX_WITH_CR_DISPLAY_LISTS
1696 if (cr_server.head_spu->dispatch_table.spu_save_state)
1697 {
1698 rc = cr_server.head_spu->dispatch_table.spu_save_state((void *)pSSM);
1699 AssertRCReturn(rc, rc);
1700 }
1701 else
1702 crDebug("Do not save %s SPU state: no interface exported.", cr_server.head_spu->name);
1703#endif
1704
1705 /* all context gl error states should have now be synced with chromium erro states,
1706 * reset the error if any */
1707 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1708 crWarning("crServer: glGetError %d after saving snapshot", err);
1709
1710 cr_server.bIsInSavingState = GL_FALSE;
1711
1712#ifdef DEBUG_misha
1713 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1714 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
1715#endif
1716
1717 return VINF_SUCCESS;
1718}
1719
1720DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
1721{
1722 if (cr_server.fCrCmdEnabled)
1723 {
1724 WARN(("we should not be called with cmd enabled!"));
1725 return VERR_INTERNAL_ERROR;
1726 }
1727
1728 return crVBoxServerSaveStatePerform(pSSM);
1729}
1730
1731static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1732{
1733 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1734 CRASSERT(pContextInfo);
1735 CRASSERT(pContextInfo->pContext);
1736 return pContextInfo->pContext;
1737}
1738
1739typedef struct CR_SERVER_LOADSTATE_READER
1740{
1741 PSSMHANDLE pSSM;
1742 uint32_t cbBuffer;
1743 uint32_t cbData;
1744 uint32_t offData;
1745 uint8_t *pu8Buffer;
1746} CR_SERVER_LOADSTATE_READER;
1747
1748static void crServerLsrInit(CR_SERVER_LOADSTATE_READER *pReader, PSSMHANDLE pSSM)
1749{
1750 memset(pReader, 0, sizeof (*pReader));
1751 pReader->pSSM = pSSM;
1752}
1753
1754static void crServerLsrTerm(CR_SERVER_LOADSTATE_READER *pReader)
1755{
1756 if (pReader->pu8Buffer)
1757 RTMemFree(pReader->pu8Buffer);
1758
1759 /* sanity */
1760 memset(pReader, 0, sizeof (*pReader));
1761}
1762
1763static int crServerLsrDataGetMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1764{
1765 int rc = VINF_SUCCESS;
1766 uint32_t cbRemaining = cbBuffer;
1767 if (pReader->cbData)
1768 {
1769 uint8_t cbData = RT_MIN(pReader->cbData, cbBuffer);
1770 memcpy(pvBuffer, pReader->pu8Buffer + pReader->offData, cbData);
1771 pReader->cbData -= cbData;
1772 pReader->offData += cbData;
1773
1774 cbRemaining -= cbData;
1775 pvBuffer = ((uint8_t*)pvBuffer) + cbData;
1776 }
1777
1778 if (cbRemaining)
1779 {
1780 rc = SSMR3GetMem(pReader->pSSM, pvBuffer, cbRemaining);
1781 AssertRC(rc);
1782 }
1783
1784 return rc;
1785}
1786
1787static int crServerLsrDataGetU32(CR_SERVER_LOADSTATE_READER *pReader, uint32_t *pu32)
1788{
1789 return crServerLsrDataGetMem(pReader, pu32, sizeof (*pu32));
1790}
1791
1792static int crServerLsrDataPutMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1793{
1794 if (!pReader->cbData && pReader->cbBuffer >= cbBuffer)
1795 {
1796 pReader->offData = 0;
1797 pReader->cbData = cbBuffer;
1798 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1799 }
1800 else if (pReader->offData >= cbBuffer)
1801 {
1802 pReader->offData -= cbBuffer;
1803 pReader->cbData += cbBuffer;
1804 memcpy(pReader->pu8Buffer + pReader->offData, pvBuffer, cbBuffer);
1805 }
1806 else
1807 {
1808 uint8_t *pu8Buffer = pReader->pu8Buffer;
1809
1810 pReader->pu8Buffer = (uint8_t*)RTMemAlloc(cbBuffer + pReader->cbData);
1811 if (!pReader->pu8Buffer)
1812 {
1813 crWarning("failed to allocate mem %d", cbBuffer + pReader->cbData);
1814 return VERR_NO_MEMORY;
1815 }
1816
1817 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1818 if (pu8Buffer)
1819 {
1820 memcpy(pReader->pu8Buffer + cbBuffer, pu8Buffer + pReader->offData, pReader->cbData);
1821 RTMemFree(pu8Buffer);
1822 }
1823 else
1824 {
1825 Assert(!pReader->cbData);
1826 }
1827 pReader->offData = 0;
1828 pReader->cbData += cbBuffer;
1829 }
1830
1831 return VINF_SUCCESS;
1832}
1833
1834/* data to be skipped */
1835
1836typedef struct CR_SERVER_BUGGY_MURAL_DATA_2
1837{
1838 void*ListHead_pNext;
1839 void*ListHead_pPrev;
1840 uint32_t cEntries;
1841} CR_SERVER_BUGGY_MURAL_DATA_2;
1842typedef struct CR_SERVER_BUGGY_MURAL_DATA_1
1843{
1844 /* VBOXVR_COMPOSITOR_ENTRY Ce; */
1845 void*Ce_Node_pNext;
1846 void*Ce_Node_pPrev;
1847 CR_SERVER_BUGGY_MURAL_DATA_2 Vr;
1848 /* VBOXVR_TEXTURE Tex; */
1849 uint32_t Tex_width;
1850 uint32_t Tex_height;
1851 uint32_t Tex_target;
1852 uint32_t Tex_hwid;
1853 /* RTPOINT Pos; */
1854 uint32_t Pos_x;
1855 uint32_t Pos_y;
1856 uint32_t fChanged;
1857 uint32_t cRects;
1858 void* paSrcRects;
1859 void* paDstRects;
1860} CR_SERVER_BUGGY_MURAL_DATA_1;
1861
1862typedef struct CR_SERVER_BUGGY_MURAL_DATA_4
1863{
1864 uint32_t u32Magic;
1865 int32_t cLockers;
1866 RTNATIVETHREAD NativeThreadOwner;
1867 int32_t cNestings;
1868 uint32_t fFlags;
1869 void* EventSem;
1870 R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec;
1871 RTHCPTR Alignment;
1872} CR_SERVER_BUGGY_MURAL_DATA_4;
1873
1874typedef struct CR_SERVER_BUGGY_MURAL_DATA_3
1875{
1876 void*Compositor_List_pNext;
1877 void*Compositor_List_pPrev;
1878 void*Compositor_pfnEntryRemoved;
1879 float StretchX;
1880 float StretchY;
1881 uint32_t cRects;
1882 uint32_t cRectsBuffer;
1883 void*paSrcRects;
1884 void*paDstRects;
1885 CR_SERVER_BUGGY_MURAL_DATA_4 CritSect;
1886} CR_SERVER_BUGGY_MURAL_DATA_3;
1887
1888typedef struct CR_SERVER_BUGGY_MURAL_DATA
1889{
1890 uint8_t fRootVrOn;
1891 CR_SERVER_BUGGY_MURAL_DATA_1 RootVrCEntry;
1892 CR_SERVER_BUGGY_MURAL_DATA_3 RootVrCompositor;
1893} CR_SERVER_BUGGY_MURAL_DATA;
1894
1895AssertCompile(sizeof (CR_SERVER_BUGGY_MURAL_DATA) < sizeof (CRClient));
1896
1897static int32_t crVBoxServerLoadMurals(CR_SERVER_LOADSTATE_READER *pReader, uint32_t version)
1898{
1899 unsigned long key;
1900 uint32_t ui, uiNumElems;
1901 bool fBuggyMuralData = false;
1902 /* Load windows */
1903 int32_t rc = crServerLsrDataGetU32(pReader, &uiNumElems);
1904 AssertLogRelRCReturn(rc, rc);
1905 for (ui=0; ui<uiNumElems; ++ui)
1906 {
1907 CRCreateInfo_t createInfo;
1908 char psz[200];
1909 GLint winID;
1910 unsigned long key;
1911
1912 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1913 AssertLogRelRCReturn(rc, rc);
1914 rc = crServerLsrDataGetMem(pReader, &createInfo, sizeof(createInfo));
1915 AssertLogRelRCReturn(rc, rc);
1916
1917 CRASSERT(!pReader->cbData);
1918
1919 if (createInfo.pszDpyName)
1920 {
1921 rc = SSMR3GetStrZEx(pReader->pSSM, psz, 200, NULL);
1922 AssertLogRelRCReturn(rc, rc);
1923 createInfo.pszDpyName = psz;
1924 }
1925
1926 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1927 CRASSERT((int64_t)winID == (int64_t)key);
1928 }
1929
1930 /* Load cr_server.muralTable */
1931 rc = SSMR3GetU32(pReader->pSSM, &uiNumElems);
1932 AssertLogRelRCReturn(rc, rc);
1933 for (ui=0; ui<uiNumElems; ++ui)
1934 {
1935 CRMuralInfo muralInfo;
1936 CRMuralInfo *pActualMural = NULL;
1937
1938 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1939 AssertLogRelRCReturn(rc, rc);
1940 rc = crServerLsrDataGetMem(pReader, &muralInfo, RT_UOFFSETOF(CRMuralInfo, CreateInfo));
1941 AssertLogRelRCReturn(rc, rc);
1942
1943 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1944 muralInfo.bFbDraw = GL_TRUE;
1945
1946 if (!ui && version == SHCROGL_SSM_VERSION_WITH_BUGGY_MURAL_INFO)
1947 {
1948 /* Lookahead buffer used to determine whether the data erroneously stored root visible regions data */
1949 union
1950 {
1951 void * apv[1];
1952 CR_SERVER_BUGGY_MURAL_DATA Data;
1953 /* need to chak spuWindow, so taking the offset of filed following it*/
1954 uint8_t au8[RT_UOFFSETOF(CRMuralInfo, screenId)];
1955 RTRECT aVisRects[sizeof (CR_SERVER_BUGGY_MURAL_DATA) / sizeof (RTRECT)];
1956 } LaBuf;
1957
1958 do {
1959 /* first value is bool (uint8_t) value followed by pointer-size-based alignment.
1960 * the mural memory is zero-initialized initially, so we can be sure the padding is zeroed */
1961 rc = crServerLsrDataGetMem(pReader, &LaBuf, sizeof (LaBuf));
1962 AssertLogRelRCReturn(rc, rc);
1963 if (LaBuf.apv[0] != NULL && LaBuf.apv[0] != ((void *)(uintptr_t)1))
1964 break;
1965
1966 /* check that the pointers are either valid or NULL */
1967 if(LaBuf.Data.RootVrCEntry.Ce_Node_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pNext))
1968 break;
1969 if(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev))
1970 break;
1971 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext))
1972 break;
1973 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev))
1974 break;
1975
1976 /* the entry can can be the only one within the (mural) compositor,
1977 * so its compositor entry node can either contain NULL pNext and pPrev,
1978 * or both of them pointing to compositor's list head */
1979 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext != LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1980 break;
1981
1982 /* can either both or none be NULL */
1983 if (!LaBuf.Data.RootVrCEntry.Ce_Node_pNext != !LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1984 break;
1985
1986 if (!LaBuf.Data.fRootVrOn)
1987 {
1988 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext || LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1989 break;
1990
1991 /* either non-initialized (zeroed) or empty list */
1992 if (LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext != LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
1993 break;
1994
1995 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
1996 break;
1997 }
1998 else
1999 {
2000 /* the entry should be initialized */
2001 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext)
2002 break;
2003 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
2004 break;
2005
2006 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
2007 {
2008 /* entry should be in compositor list*/
2009 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev == NULL)
2010 break;
2011 CRASSERT(LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2012 }
2013 else
2014 {
2015 /* entry should NOT be in compositor list*/
2016 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev != NULL)
2017 break;
2018 CRASSERT(!LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2019 }
2020 }
2021
2022 /* fExpectPtr == true, the valid pointer values should not match possible mural width/height/position */
2023 fBuggyMuralData = true;
2024 break;
2025
2026 } while (0);
2027
2028 rc = crServerLsrDataPutMem(pReader, &LaBuf, sizeof (LaBuf));
2029 AssertLogRelRCReturn(rc, rc);
2030 }
2031
2032 if (fBuggyMuralData)
2033 {
2034 CR_SERVER_BUGGY_MURAL_DATA Tmp;
2035 rc = crServerLsrDataGetMem(pReader, &Tmp, sizeof (Tmp));
2036 AssertLogRelRCReturn(rc, rc);
2037 }
2038
2039 if (muralInfo.pVisibleRects)
2040 {
2041 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
2042 if (!muralInfo.pVisibleRects)
2043 {
2044 return VERR_NO_MEMORY;
2045 }
2046
2047 rc = crServerLsrDataGetMem(pReader, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
2048 AssertLogRelRCReturn(rc, rc);
2049 }
2050
2051 pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);
2052 CRASSERT(pActualMural);
2053
2054 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
2055 {
2056 rc = crServerLsrDataGetMem(pReader, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
2057 CRASSERT(rc == VINF_SUCCESS);
2058 }
2059
2060 /* Restore windows geometry info */
2061 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
2062 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
2063 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
2064 if (muralInfo.bReceivedRects)
2065 {
2066 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
2067 }
2068 crServerDispatchWindowShow(key, muralInfo.bVisible);
2069
2070 if (muralInfo.pVisibleRects)
2071 {
2072 crFree(muralInfo.pVisibleRects);
2073 }
2074 }
2075
2076 CRASSERT(RT_SUCCESS(rc));
2077 return VINF_SUCCESS;
2078}
2079
2080static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
2081 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
2082{
2083 CRContext *pContext = pContextInfo->pContext;
2084 int32_t rc = VINF_SUCCESS;
2085 GLuint i;
2086 /* can apply the data right away */
2087 struct
2088 {
2089 CRFBData data;
2090 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
2091 } Data;
2092
2093 Assert(sizeof (Data) >= RT_UOFFSETOF(CRFBData, aElements[4]));
2094
2095 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
2096 {
2097 if (!pMural->width || !pMural->height)
2098 return VINF_SUCCESS;
2099
2100 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
2101 if (!RT_SUCCESS(rc))
2102 {
2103 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2104 return rc;
2105 }
2106 }
2107 else
2108 {
2109 GLint storedWidth, storedHeight;
2110
2111 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2112 {
2113 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
2114 CRASSERT(cr_server.currentMural == pMural);
2115 storedWidth = pMural->width;
2116 storedHeight = pMural->height;
2117 }
2118 else
2119 {
2120 storedWidth = pContext->buffer.storedWidth;
2121 storedHeight = pContext->buffer.storedHeight;
2122 }
2123
2124 if (!storedWidth || !storedHeight)
2125 return VINF_SUCCESS;
2126
2127 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
2128 if (!RT_SUCCESS(rc))
2129 {
2130 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2131 return rc;
2132 }
2133 }
2134
2135 CRASSERT(Data.data.cElements);
2136
2137 for (i = 0; i < Data.data.cElements; ++i)
2138 {
2139 CRFBDataElement * pEl = &Data.data.aElements[i];
2140 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
2141 AssertLogRelRCReturn(rc, rc);
2142 }
2143
2144 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2145 {
2146 CRBufferState *pBuf = &pContext->buffer;
2147 /* can apply the data right away */
2148 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2149 CRASSERT(cr_server.currentMural);
2150
2151 cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
2152 0,
2153 pContextInfo->SpuContext >= 0
2154 ? pContextInfo->SpuContext
2155 : cr_server.MainContextInfo.SpuContext);
2156 crStateApplyFBImage(pContext, &Data.data);
2157 CRASSERT(!pBuf->pFrontImg);
2158 CRASSERT(!pBuf->pBackImg);
2159 crVBoxServerFBImageDataTerm(&Data.data);
2160
2161 crServerPresentFBO(pMural);
2162
2163 CRASSERT(cr_server.currentMural);
2164 cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
2165 0,
2166 cr_server.currentCtxInfo->SpuContext >= 0
2167 ? cr_server.currentCtxInfo->SpuContext
2168 : cr_server.MainContextInfo.SpuContext);
2169 }
2170 else
2171 {
2172 CRBufferState *pBuf = &pContext->buffer;
2173 CRASSERT(!pBuf->pFrontImg);
2174 CRASSERT(!pBuf->pBackImg);
2175 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
2176
2177 if (Data.data.cElements)
2178 {
2179 CRFBData *pLazyData = crAlloc(RT_UOFFSETOF_DYN(CRFBData, aElements[Data.data.cElements]));
2180 if (!RT_SUCCESS(rc))
2181 {
2182 crVBoxServerFBImageDataTerm(&Data.data);
2183 crWarning("crAlloc failed");
2184 return VERR_NO_MEMORY;
2185 }
2186
2187 crMemcpy(pLazyData, &Data.data, RT_UOFFSETOF_DYN(CRFBData, aElements[Data.data.cElements]));
2188 pBuf->pFrontImg = pLazyData;
2189 }
2190 }
2191
2192 CRASSERT(RT_SUCCESS(rc));
2193 return VINF_SUCCESS;
2194}
2195
2196static int32_t crVBoxServerLoadStatePerform(PSSMHANDLE pSSM, uint32_t version)
2197{
2198 int32_t rc, i;
2199 uint32_t ui, uiNumElems;
2200 unsigned long key;
2201 GLenum err;
2202 CR_SERVER_LOADSTATE_READER Reader;
2203
2204 if (!cr_server.bIsInLoadingState)
2205 {
2206 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
2207 cr_server.bIsInLoadingState = GL_TRUE;
2208
2209 /* Read number of clients */
2210 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
2211 AssertLogRelRCReturn(rc, rc);
2212
2213 Assert(g_hackVBoxServerSaveLoadCallsLeft);
2214 /* we get called only once for CrCmd */
2215 if (cr_server.fCrCmdEnabled)
2216 g_hackVBoxServerSaveLoadCallsLeft = 1;
2217 }
2218
2219 g_hackVBoxServerSaveLoadCallsLeft--;
2220
2221 /* Do nothing until we're being called last time */
2222 if (g_hackVBoxServerSaveLoadCallsLeft>0)
2223 {
2224 return VINF_SUCCESS;
2225 }
2226
2227 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
2228 {
2229 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2230 }
2231
2232 crServerLsrInit(&Reader, pSSM);
2233
2234#ifdef DEBUG_misha
2235#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
2236#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
2237
2238 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2239 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
2240#endif
2241
2242 /* Load and recreate rendering contexts */
2243 rc = SSMR3GetU32(pSSM, &uiNumElems);
2244 AssertLogRelRCReturn(rc, rc);
2245 for (ui = 0; ui < uiNumElems; ++ui)
2246 {
2247 CRCreateInfo_t createInfo;
2248 char psz[200];
2249 GLint ctxID;
2250 CRContextInfo* pContextInfo;
2251 CRContext* pContext;
2252
2253 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2254 AssertLogRelRCReturn(rc, rc);
2255 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
2256 AssertLogRelRCReturn(rc, rc);
2257
2258 if (createInfo.pszDpyName)
2259 {
2260 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
2261 AssertLogRelRCReturn(rc, rc);
2262 createInfo.pszDpyName = psz;
2263 }
2264
2265 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
2266 CRASSERT((int64_t)ctxID == (int64_t)key);
2267
2268 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2269 CRASSERT(pContextInfo);
2270 CRASSERT(pContextInfo->pContext);
2271 pContext = pContextInfo->pContext;
2272 pContext->shared->id=-1;
2273 }
2274
2275 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2276 {
2277 CRASSERT(!Reader.pu8Buffer);
2278 /* we have a mural data here */
2279 rc = crVBoxServerLoadMurals(&Reader, version);
2280 AssertLogRelRCReturn(rc, rc);
2281 CRASSERT(!Reader.pu8Buffer);
2282 }
2283
2284 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
2285 {
2286 /* set the current client to allow doing crServerPerformMakeCurrent later */
2287 CRASSERT(cr_server.numClients);
2288 cr_server.curClient = cr_server.clients[0];
2289 }
2290
2291 rc = crStateLoadGlobals(pSSM, version);
2292 AssertLogRelRCReturn(rc, rc);
2293
2294 if (uiNumElems)
2295 {
2296 /* ensure we have main context set up as current */
2297 CRMuralInfo *pMural;
2298 CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
2299 CRASSERT(!cr_server.currentCtxInfo);
2300 CRASSERT(!cr_server.currentMural);
2301 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
2302 CRASSERT(pMural);
2303 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
2304 }
2305
2306 /* Restore context state data */
2307 for (ui=0; ui<uiNumElems; ++ui)
2308 {
2309 CRContextInfo* pContextInfo;
2310 CRContext *pContext;
2311 CRMuralInfo *pMural = NULL;
2312 int32_t winId = 0;
2313
2314 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2315 AssertLogRelRCReturn(rc, rc);
2316
2317 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2318 CRASSERT(pContextInfo);
2319 CRASSERT(pContextInfo->pContext);
2320 pContext = pContextInfo->pContext;
2321
2322 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2323 {
2324 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
2325 AssertLogRelRCReturn(rc, rc);
2326
2327 if (winId)
2328 {
2329 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
2330 CRASSERT(pMural);
2331 }
2332 else
2333 {
2334 /* null winId means a dummy mural, get it */
2335 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
2336 CRASSERT(pMural);
2337 }
2338 }
2339
2340 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
2341 AssertLogRelRCReturn(rc, rc);
2342
2343 /*Restore front/back buffer images*/
2344 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2345 AssertLogRelRCReturn(rc, rc);
2346 }
2347
2348 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2349 {
2350 CRContextInfo *pContextInfo;
2351 CRMuralInfo *pMural;
2352 GLint ctxId;
2353
2354 rc = SSMR3GetU32(pSSM, &uiNumElems);
2355 AssertLogRelRCReturn(rc, rc);
2356 for (ui=0; ui<uiNumElems; ++ui)
2357 {
2358 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
2359 CRMuralInfo *pInitialCurMural;
2360
2361 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2362 AssertLogRelRCReturn(rc, rc);
2363
2364 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
2365 AssertLogRelRCReturn(rc, rc);
2366
2367 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
2368 CRASSERT(pMural);
2369 if (ctxId)
2370 {
2371 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
2372 CRASSERT(pContextInfo);
2373 }
2374 else
2375 pContextInfo = &cr_server.MainContextInfo;
2376
2377 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
2378 pInitialCurMural = pContextInfo->currentMural;
2379
2380 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2381 AssertLogRelRCReturn(rc, rc);
2382
2383 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
2384 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
2385 pContextInfo->currentMural = pInitialCurMural;
2386 }
2387
2388 CRASSERT(!uiNumElems || cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2389
2390 cr_server.curClient = NULL;
2391 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
2392 }
2393 else
2394 {
2395 CRServerFreeIDsPool_t dummyIdsPool;
2396
2397 CRASSERT(!Reader.pu8Buffer);
2398
2399 /* we have a mural data here */
2400 rc = crVBoxServerLoadMurals(&Reader, version);
2401 AssertLogRelRCReturn(rc, rc);
2402
2403 /* not used any more, just read it out and ignore */
2404 rc = crServerLsrDataGetMem(&Reader, &dummyIdsPool, sizeof(dummyIdsPool));
2405 CRASSERT(rc == VINF_SUCCESS);
2406 }
2407
2408 /* Load clients info */
2409 for (i = 0; i < cr_server.numClients; i++)
2410 {
2411 if (cr_server.clients[i] && cr_server.clients[i]->conn)
2412 {
2413 CRClient *pClient = cr_server.clients[i];
2414 CRClient client;
2415 unsigned long ctxID=-1, winID=-1;
2416
2417 rc = crServerLsrDataGetU32(&Reader, &ui);
2418 AssertLogRelRCReturn(rc, rc);
2419 /* If this assert fires, then we should search correct client in the list first*/
2420 CRASSERT(ui == pClient->conn->u32ClientID);
2421
2422 if (version>=4)
2423 {
2424 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMajor);
2425 AssertLogRelRCReturn(rc, rc);
2426
2427 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMinor);
2428 AssertLogRelRCReturn(rc, rc);
2429 }
2430
2431 rc = crServerLsrDataGetMem(&Reader, &client, sizeof(client));
2432 CRASSERT(rc == VINF_SUCCESS);
2433
2434 client.conn = pClient->conn;
2435 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2436 * and fail to bind old textures.
2437 */
2438 /*client.number = pClient->number;*/
2439 *pClient = client;
2440
2441 pClient->currentContextNumber = -1;
2442 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2443 pClient->currentMural = NULL;
2444 pClient->currentWindow = -1;
2445
2446 cr_server.curClient = pClient;
2447
2448 if (client.currentCtxInfo && client.currentContextNumber > 0)
2449 {
2450 rc = crServerLsrDataGetMem(&Reader, &ctxID, sizeof(ctxID));
2451 AssertLogRelRCReturn(rc, rc);
2452 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2453 CRASSERT(client.currentCtxInfo);
2454 CRASSERT(client.currentCtxInfo->pContext);
2455 //pClient->currentCtx = client.currentCtx;
2456 //pClient->currentContextNumber = ctxID;
2457 }
2458
2459 if (client.currentMural && client.currentWindow > 0)
2460 {
2461 rc = crServerLsrDataGetMem(&Reader, &winID, sizeof(winID));
2462 AssertLogRelRCReturn(rc, rc);
2463 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2464 CRASSERT(client.currentMural);
2465 //pClient->currentMural = client.currentMural;
2466 //pClient->currentWindow = winID;
2467 }
2468
2469 CRASSERT(!Reader.cbData);
2470
2471 /* Restore client active context and window */
2472 crServerDispatchMakeCurrent(winID, 0, ctxID);
2473 }
2474 }
2475
2476 cr_server.curClient = NULL;
2477
2478 rc = crServerPendLoadState(pSSM, version);
2479 AssertLogRelRCReturn(rc, rc);
2480
2481 if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_INFO)
2482 {
2483 rc = CrPMgrLoadState(pSSM, version);
2484 AssertLogRelRCReturn(rc, rc);
2485 }
2486
2487#ifdef VBOX_WITH_CR_DISPLAY_LISTS
2488 if (version >= SHCROGL_SSM_VERSION_WITH_DISPLAY_LISTS)
2489 {
2490 if (cr_server.head_spu->dispatch_table.spu_load_state)
2491 {
2492 rc = cr_server.head_spu->dispatch_table.spu_load_state((void *)pSSM);
2493 AssertLogRelRCReturn(rc, rc);
2494 }
2495 else
2496 crDebug("Do not load %s SPU state: no interface exported.", cr_server.head_spu->name);
2497 }
2498#endif
2499
2500 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2501 crWarning("crServer: glGetError %d after loading snapshot", err);
2502
2503 cr_server.bIsInLoadingState = GL_FALSE;
2504
2505#ifdef DEBUG_misha
2506 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2507 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
2508#endif
2509
2510 CRASSERT(!Reader.cbData);
2511 crServerLsrTerm(&Reader);
2512
2513 return VINF_SUCCESS;
2514}
2515
2516DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
2517{
2518 if (cr_server.fCrCmdEnabled)
2519 {
2520 WARN(("CrCmd enabled"));
2521 return VERR_INTERNAL_ERROR;
2522 }
2523
2524 return crVBoxServerLoadStatePerform(pSSM, version);
2525}
2526
2527#define SCREEN(i) (cr_server.screen[i])
2528#define MAPPED(screen) ((screen).winID != 0)
2529
2530extern DECLEXPORT(void) crServerVBoxSetNotifyEventCB(PFNCRSERVERNOTIFYEVENT pfnCb)
2531{
2532 cr_server.pfnNotifyEventCB = pfnCb;
2533}
2534
2535void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void* pvData, uint32_t cbData)
2536{
2537 /* this is something unexpected, but just in case */
2538 if (idScreen >= cr_server.screenCount)
2539 {
2540 crWarning("invalid screen id %d", idScreen);
2541 return;
2542 }
2543
2544 cr_server.pfnNotifyEventCB(idScreen, uEvent, pvData, cbData);
2545}
2546
2547void crServerWindowReparent(CRMuralInfo *pMural)
2548{
2549 pMural->fHasParentWindow = !!cr_server.screen[pMural->screenId].winID;
2550
2551 renderspuReparentWindow(pMural->spuWindow);
2552}
2553
2554DECLEXPORT(void) crServerSetUnscaledHiDPI(bool fEnable)
2555{
2556 renderspuSetUnscaledHiDPI(fEnable);
2557}
2558
2559static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2560{
2561 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2562 int *sIndex = (int*) data2;
2563
2564 if (pMI->screenId == *sIndex)
2565 {
2566 crServerWindowReparent(pMI);
2567 }
2568}
2569
2570DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2571{
2572 int i;
2573
2574 if (sCount > CR_MAX_GUEST_MONITORS)
2575 return VERR_INVALID_PARAMETER;
2576
2577 /*Shouldn't happen yet, but to be safe in future*/
2578 for (i = 0; i < cr_server.screenCount; /*++i - unreachable code*/)
2579 {
2580 if (MAPPED(SCREEN(i)))
2581 WARN(("Screen count is changing, but screen[%i] is still mapped", i));
2582 return VERR_NOT_IMPLEMENTED;
2583 }
2584
2585 cr_server.screenCount = sCount;
2586
2587 for (i=0; i<sCount; ++i)
2588 {
2589 SCREEN(i).winID = 0;
2590 }
2591
2592 return VINF_SUCCESS;
2593}
2594
2595DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2596{
2597 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2598
2599 if (sIndex<0 || sIndex>=cr_server.screenCount)
2600 return VERR_INVALID_PARAMETER;
2601
2602 if (MAPPED(SCREEN(sIndex)))
2603 {
2604 SCREEN(sIndex).winID = 0;
2605 renderspuSetWindowId(0);
2606
2607 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2608
2609 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2610
2611 CrPMgrScreenChanged((uint32_t)sIndex);
2612 }
2613
2614 renderspuSetWindowId(SCREEN(0).winID);
2615
2616 return VINF_SUCCESS;
2617}
2618
2619DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2620{
2621 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2622
2623 if (sIndex<0 || sIndex>=cr_server.screenCount)
2624 return VERR_INVALID_PARAMETER;
2625
2626 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2627 {
2628 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2629 crVBoxServerUnmapScreen(sIndex);
2630 }
2631
2632 SCREEN(sIndex).winID = winID;
2633 SCREEN(sIndex).x = x;
2634 SCREEN(sIndex).y = y;
2635 SCREEN(sIndex).w = w;
2636 SCREEN(sIndex).h = h;
2637
2638 renderspuSetWindowId(SCREEN(sIndex).winID);
2639 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2640
2641 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2642 renderspuSetWindowId(SCREEN(0).winID);
2643
2644#ifndef WINDOWS
2645 /*Restore FB content for clients, which have current window on a screen being remapped*/
2646 {
2647 GLint i;
2648
2649 for (i = 0; i < cr_server.numClients; i++)
2650 {
2651 cr_server.curClient = cr_server.clients[i];
2652 if (cr_server.curClient->currentCtxInfo
2653 && cr_server.curClient->currentCtxInfo->pContext
2654 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2655 && cr_server.curClient->currentMural
2656 && cr_server.curClient->currentMural->screenId == sIndex
2657 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2658 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2659 {
2660 int clientWindow = cr_server.curClient->currentWindow;
2661 int clientContext = cr_server.curClient->currentContextNumber;
2662 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2663
2664 if (clientWindow && clientWindow != cr_server.currentWindow)
2665 {
2666 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2667 }
2668
2669 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2670 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2671 }
2672 }
2673 cr_server.curClient = NULL;
2674 }
2675#endif
2676
2677 CrPMgrScreenChanged((uint32_t)sIndex);
2678
2679 return VINF_SUCCESS;
2680}
2681
2682DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects)
2683{
2684 int32_t rc = VINF_SUCCESS;
2685 GLboolean fOldRootVrOn = cr_server.fRootVrOn;
2686
2687 /* non-zero rects pointer indicate rects are present and switched on
2688 * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions,
2689 * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */
2690 if (pRects)
2691 {
2692 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
2693 rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL);
2694 if (!RT_SUCCESS(rc))
2695 {
2696 crWarning("VBoxVrListRectsSet failed! rc %d", rc);
2697 return rc;
2698 }
2699
2700 cr_server.fRootVrOn = GL_TRUE;
2701 }
2702 else
2703 {
2704 if (!cr_server.fRootVrOn)
2705 return VINF_SUCCESS;
2706
2707 VBoxVrListClear(&cr_server.RootVr);
2708
2709 cr_server.fRootVrOn = GL_FALSE;
2710 }
2711
2712 if (!fOldRootVrOn != !cr_server.fRootVrOn)
2713 {
2714 rc = CrPMgrModeRootVr(cr_server.fRootVrOn);
2715 if (!RT_SUCCESS(rc))
2716 {
2717 crWarning("CrPMgrModeRootVr failed rc %d", rc);
2718 return rc;
2719 }
2720 }
2721 else if (cr_server.fRootVrOn)
2722 {
2723 rc = CrPMgrRootVrUpdate();
2724 if (!RT_SUCCESS(rc))
2725 {
2726 crWarning("CrPMgrRootVrUpdate failed rc %d", rc);
2727 return rc;
2728 }
2729 }
2730
2731 return VINF_SUCCESS;
2732}
2733
2734DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2735{
2736 return CrPMgrModeVrdp(value);
2737}
2738
2739DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2740{
2741 /* No need for a synchronization as this is single threaded. */
2742 if (pCallbacks)
2743 {
2744 cr_server.outputRedirect = *pCallbacks;
2745 }
2746 else
2747 {
2748 memset (&cr_server.outputRedirect, 0, sizeof (cr_server.outputRedirect));
2749 }
2750
2751 return VINF_SUCCESS;
2752}
2753
2754DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2755{
2756 CRScreenViewportInfo *pViewport;
2757 RTRECT NewRect;
2758 int rc;
2759
2760 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2761
2762 if (sIndex<0 || sIndex>=cr_server.screenCount)
2763 {
2764 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2765 return VERR_INVALID_PARAMETER;
2766 }
2767
2768 NewRect.xLeft = x;
2769 NewRect.yTop = y;
2770 NewRect.xRight = x + w;
2771 NewRect.yBottom = y + h;
2772
2773 pViewport = &cr_server.screenVieport[sIndex];
2774 /*always do viewport updates no matter whether the rectangle actually changes,
2775 * this is needed to ensure window is adjusted properly on OSX */
2776 pViewport->Rect = NewRect;
2777 rc = CrPMgrViewportUpdate((uint32_t)sIndex);
2778 if (!RT_SUCCESS(rc))
2779 {
2780 crWarning("CrPMgrViewportUpdate failed %d", rc);
2781 return rc;
2782 }
2783
2784 return VINF_SUCCESS;
2785}
2786
2787static void crVBoxServerDeleteMuralCb(unsigned long key, void *data1, void *data2)
2788{
2789 CRHashTable *h = (CRHashTable*)data2;
2790 CRMuralInfo *m = (CRMuralInfo *) data1;
2791 if (m->spuWindow == CR_RENDER_DEFAULT_WINDOW_ID)
2792 return;
2793
2794 crHashtableDelete(h, key, NULL);
2795 crServerMuralTerm(m);
2796 crFree(m);
2797}
2798
2799static void crVBoxServerDefaultContextClear()
2800{
2801 HCR_FRAMEBUFFER hFb;
2802 int rc = CrPMgrDisable();
2803 if (RT_FAILURE(rc))
2804 {
2805 WARN(("CrPMgrDisable failed %d", rc));
2806 return;
2807 }
2808
2809 for (hFb = CrPMgrFbGetFirstEnabled(); hFb; hFb = CrPMgrFbGetNextEnabled(hFb))
2810 {
2811 int rc = CrFbUpdateBegin(hFb);
2812 if (RT_SUCCESS(rc))
2813 {
2814 CrFbRegionsClear(hFb);
2815 CrFbUpdateEnd(hFb);
2816 }
2817 else
2818 WARN(("CrFbUpdateBegin failed %d", rc));
2819 }
2820
2821 cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
2822 crStateCleanupCurrent();
2823
2824 /* note: we need to clean all contexts, since otherwise renderspu leanup won't work,
2825 * i.e. renderspu would need to clean up its own internal windows, it won't be able to do that if
2826 * some those windows is associated with any context. */
2827 if (cr_server.MainContextInfo.SpuContext)
2828 {
2829 cr_server.head_spu->dispatch_table.DestroyContext(cr_server.MainContextInfo.SpuContext);
2830 crStateDestroyContext(cr_server.MainContextInfo.pContext);
2831 if (cr_server.MainContextInfo.CreateInfo.pszDpyName)
2832 crFree(cr_server.MainContextInfo.CreateInfo.pszDpyName);
2833
2834 memset(&cr_server.MainContextInfo, 0, sizeof (cr_server.MainContextInfo));
2835 }
2836
2837 cr_server.firstCallCreateContext = GL_TRUE;
2838 cr_server.firstCallMakeCurrent = GL_TRUE;
2839 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
2840
2841 CRASSERT(!cr_server.curClient);
2842
2843 cr_server.currentCtxInfo = NULL;
2844 cr_server.currentWindow = 0;
2845 cr_server.currentNativeWindow = 0;
2846 cr_server.currentMural = NULL;
2847
2848 crStateDestroy();
2849// crStateCleanupCurrent();
2850
2851 if (CrBltIsInitialized(&cr_server.Blitter))
2852 {
2853 CrBltTerm(&cr_server.Blitter);
2854 Assert(!CrBltIsInitialized(&cr_server.Blitter));
2855 }
2856
2857 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerDeleteMuralCb, cr_server.dummyMuralTable);
2858
2859 cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_RENDERTHREAD_INFORM, 0);
2860}
2861
2862static void crVBoxServerDefaultContextSet()
2863{
2864 cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_RENDERTHREAD_INFORM, 1);
2865
2866 CRASSERT(!cr_server.MainContextInfo.SpuContext);
2867
2868// crStateSetCurrent(NULL);
2869 crStateInit();
2870 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
2871
2872 CrPMgrEnable();
2873}
2874
2875#ifdef VBOX_WITH_CRHGSMI
2876
2877/** @todo RT_UNTRUSTED_VOLATILE_GUEST */
2878static int32_t crVBoxServerCmdVbvaCrCmdProcess(VBOXCMDVBVA_CRCMD_CMD const RT_UNTRUSTED_VOLATILE_GUEST *pCmdTodo, uint32_t cbCmd)
2879{
2880 VBOXCMDVBVA_CRCMD_CMD const *pCmd = (VBOXCMDVBVA_CRCMD_CMD const *)pCmdTodo;
2881 int32_t rc;
2882 uint32_t cBuffers = pCmd->cBuffers;
2883 uint32_t cParams;
2884 uint32_t cbHdr;
2885 CRVBOXHGSMIHDR *pHdr;
2886 uint32_t u32Function;
2887 uint32_t u32ClientID;
2888 CRClient *pClient;
2889
2890 if (!g_pvVRamBase)
2891 {
2892 WARN(("g_pvVRamBase is not initialized"));
2893 return VERR_INVALID_STATE;
2894 }
2895
2896 if (!cBuffers)
2897 {
2898 WARN(("zero buffers passed in!"));
2899 return VERR_INVALID_PARAMETER;
2900 }
2901
2902 cParams = cBuffers-1;
2903
2904 if (cbCmd < RT_UOFFSETOF_DYN(VBOXCMDVBVA_CRCMD_CMD, aBuffers[cBuffers]))
2905 {
2906 WARN(("invalid buffer size"));
2907 return VERR_INVALID_PARAMETER;
2908 }
2909
2910 cbHdr = pCmd->aBuffers[0].cbBuffer;
2911 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2912 if (!pHdr)
2913 {
2914 WARN(("invalid header buffer!"));
2915 return VERR_INVALID_PARAMETER;
2916 }
2917
2918 if (cbHdr < sizeof (*pHdr))
2919 {
2920 WARN(("invalid header buffer size!"));
2921 return VERR_INVALID_PARAMETER;
2922 }
2923
2924 u32Function = pHdr->u32Function;
2925 u32ClientID = pHdr->u32ClientID;
2926
2927 switch (u32Function)
2928 {
2929 case SHCRGL_GUEST_FN_WRITE:
2930 {
2931 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2932
2933 /** @todo Verify */
2934 if (cParams == 1)
2935 {
2936 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2937 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
2938 /* Fetch parameters. */
2939 uint32_t cbBuffer = pBuf->cbBuffer;
2940 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2941
2942 if (cbHdr < sizeof (*pFnCmd))
2943 {
2944 WARN(("invalid write cmd buffer size!"));
2945 rc = VERR_INVALID_PARAMETER;
2946 break;
2947 }
2948
2949 CRASSERT(cbBuffer);
2950 if (!pBuffer)
2951 {
2952 WARN(("invalid buffer data received from guest!"));
2953 rc = VERR_INVALID_PARAMETER;
2954 break;
2955 }
2956
2957 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2958 if (RT_FAILURE(rc))
2959 {
2960 WARN(("crVBoxServerClientGet failed %d", rc));
2961 break;
2962 }
2963
2964 /* This should never fire unless we start to multithread */
2965 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2966 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2967
2968 pClient->conn->pBuffer = pBuffer;
2969 pClient->conn->cbBuffer = cbBuffer;
2970 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
2971 crVBoxServerInternalClientWriteRead(pClient);
2972 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2973 return VINF_SUCCESS;
2974 }
2975
2976 WARN(("invalid number of args"));
2977 rc = VERR_INVALID_PARAMETER;
2978 break;
2979 }
2980
2981 case SHCRGL_GUEST_FN_INJECT:
2982 {
2983 WARN(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2984
2985 /** @todo Verify */
2986 if (cParams == 1)
2987 {
2988 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2989 /* Fetch parameters. */
2990 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2991 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
2992 uint32_t cbBuffer = pBuf->cbBuffer;
2993 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2994
2995 if (cbHdr < sizeof (*pFnCmd))
2996 {
2997 WARN(("invalid inject cmd buffer size!"));
2998 rc = VERR_INVALID_PARAMETER;
2999 break;
3000 }
3001
3002 CRASSERT(cbBuffer);
3003 if (!pBuffer)
3004 {
3005 WARN(("invalid buffer data received from guest!"));
3006 rc = VERR_INVALID_PARAMETER;
3007 break;
3008 }
3009
3010 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3011 if (RT_FAILURE(rc))
3012 {
3013 WARN(("crVBoxServerClientGet failed %d", rc));
3014 break;
3015 }
3016
3017 /* This should never fire unless we start to multithread */
3018 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3019 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3020
3021 pClient->conn->pBuffer = pBuffer;
3022 pClient->conn->cbBuffer = cbBuffer;
3023 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
3024 crVBoxServerInternalClientWriteRead(pClient);
3025 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3026 return VINF_SUCCESS;
3027 }
3028
3029 WARN(("invalid number of args"));
3030 rc = VERR_INVALID_PARAMETER;
3031 break;
3032 }
3033
3034 case SHCRGL_GUEST_FN_READ:
3035 {
3036 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3037
3038 /** @todo Verify */
3039 if (cParams == 1)
3040 {
3041 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3042 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3043 /* Fetch parameters. */
3044 uint32_t cbBuffer = pBuf->cbBuffer;
3045 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3046
3047 if (cbHdr < sizeof (*pFnCmd))
3048 {
3049 WARN(("invalid read cmd buffer size!"));
3050 rc = VERR_INVALID_PARAMETER;
3051 break;
3052 }
3053
3054 if (!pBuffer)
3055 {
3056 WARN(("invalid buffer data received from guest!"));
3057 rc = VERR_INVALID_PARAMETER;
3058 break;
3059 }
3060
3061 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3062 if (RT_FAILURE(rc))
3063 {
3064 WARN(("crVBoxServerClientGet failed %d", rc));
3065 break;
3066 }
3067
3068 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3069
3070 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3071
3072 /* Return the required buffer size always */
3073 pFnCmd->cbBuffer = cbBuffer;
3074
3075 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3076
3077 /* the read command is never pended, complete it right away */
3078 if (RT_FAILURE(rc))
3079 {
3080 WARN(("crVBoxServerInternalClientRead failed %d", rc));
3081 break;
3082 }
3083
3084 break;
3085 }
3086
3087 crWarning("invalid number of args");
3088 rc = VERR_INVALID_PARAMETER;
3089 break;
3090 }
3091
3092 case SHCRGL_GUEST_FN_WRITE_READ:
3093 {
3094 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3095
3096 /** @todo Verify */
3097 if (cParams == 2)
3098 {
3099 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3100 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3101 const VBOXCMDVBVA_CRCMD_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3102
3103 /* Fetch parameters. */
3104 uint32_t cbBuffer = pBuf->cbBuffer;
3105 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3106
3107 uint32_t cbWriteback = pWbBuf->cbBuffer;
3108 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3109
3110 if (cbHdr < sizeof (*pFnCmd))
3111 {
3112 WARN(("invalid write_read cmd buffer size!"));
3113 rc = VERR_INVALID_PARAMETER;
3114 break;
3115 }
3116
3117 CRASSERT(cbBuffer);
3118 if (!pBuffer)
3119 {
3120 WARN(("invalid write buffer data received from guest!"));
3121 rc = VERR_INVALID_PARAMETER;
3122 break;
3123 }
3124
3125 CRASSERT(cbWriteback);
3126 if (!pWriteback)
3127 {
3128 WARN(("invalid writeback buffer data received from guest!"));
3129 rc = VERR_INVALID_PARAMETER;
3130 break;
3131 }
3132
3133 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3134 if (RT_FAILURE(rc))
3135 {
3136 WARN(("crVBoxServerClientGet failed %d", rc));
3137 break;
3138 }
3139
3140 /* This should never fire unless we start to multithread */
3141 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3142 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3143
3144 pClient->conn->pBuffer = pBuffer;
3145 pClient->conn->cbBuffer = cbBuffer;
3146 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, false);
3147 crVBoxServerInternalClientWriteRead(pClient);
3148 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3149 return VINF_SUCCESS;
3150 }
3151
3152 crWarning("invalid number of args");
3153 rc = VERR_INVALID_PARAMETER;
3154 break;
3155 }
3156
3157 case SHCRGL_GUEST_FN_SET_VERSION:
3158 {
3159 WARN(("SHCRGL_GUEST_FN_SET_VERSION: invalid function"));
3160 rc = VERR_NOT_IMPLEMENTED;
3161 break;
3162 }
3163
3164 case SHCRGL_GUEST_FN_SET_PID:
3165 {
3166 WARN(("SHCRGL_GUEST_FN_SET_PID: invalid function"));
3167 rc = VERR_NOT_IMPLEMENTED;
3168 break;
3169 }
3170
3171 default:
3172 {
3173 WARN(("invalid function, %d", u32Function));
3174 rc = VERR_NOT_IMPLEMENTED;
3175 break;
3176 }
3177
3178 }
3179
3180 pHdr->result = rc;
3181
3182 return VINF_SUCCESS;
3183}
3184
3185static DECLCALLBACK(int) crVBoxCrCmdEnable(HVBOXCRCMDSVR hSvr, VBOXCRCMD_SVRENABLE_INFO *pInfo)
3186{
3187 Assert(!cr_server.fCrCmdEnabled);
3188 Assert(!cr_server.numClients);
3189
3190 cr_server.CrCmdClientInfo = *pInfo;
3191
3192 crVBoxServerDefaultContextSet();
3193
3194 cr_server.fCrCmdEnabled = GL_TRUE;
3195
3196 crInfo("crCmd ENABLED");
3197
3198 return VINF_SUCCESS;
3199}
3200
3201static DECLCALLBACK(int) crVBoxCrCmdDisable(HVBOXCRCMDSVR hSvr)
3202{
3203 Assert(cr_server.fCrCmdEnabled);
3204
3205 crVBoxServerRemoveAllClients();
3206
3207 CrHTableEmpty(&cr_server.clientTable);
3208
3209 crVBoxServerDefaultContextClear();
3210
3211 memset(&cr_server.CrCmdClientInfo, 0, sizeof (cr_server.CrCmdClientInfo));
3212
3213 cr_server.fCrCmdEnabled = GL_FALSE;
3214
3215 crInfo("crCmd DISABLED");
3216
3217 return VINF_SUCCESS;
3218}
3219
3220static DECLCALLBACK(int) crVBoxCrCmdHostCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
3221{
3222 return crVBoxServerHostCtl((VBOXCRCMDCTL*)pCmd, cbCmd);
3223}
3224
3225static int crVBoxCrDisconnect(uint32_t u32Client)
3226{
3227 CRClient *pClient = (CRClient*)CrHTableRemove(&cr_server.clientTable, u32Client);
3228 if (!pClient)
3229 {
3230 WARN(("invalid client id"));
3231 return VERR_INVALID_PARAMETER;
3232 }
3233
3234 crVBoxServerRemoveClientObj(pClient);
3235
3236 return VINF_SUCCESS;
3237}
3238
3239static int crVBoxCrConnectEx(VBOXCMDVBVA_3DCTL_CONNECT RT_UNTRUSTED_VOLATILE_GUEST *pConnect, uint32_t u32ClientId)
3240{
3241 CRClient *pClient;
3242 int rc;
3243 uint32_t const uMajorVersion = pConnect->u32MajorVersion;
3244 uint32_t const uMinorVersion = pConnect->u32MinorVersion;
3245 uint64_t const uPid = pConnect->u64Pid;
3246 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
3247
3248 if (u32ClientId == CRHTABLE_HANDLE_INVALID)
3249 {
3250 /* allocate client id */
3251 u32ClientId = CrHTablePut(&cr_server.clientTable, (void *)(uintptr_t)1);
3252 if (u32ClientId == CRHTABLE_HANDLE_INVALID)
3253 {
3254 WARN(("CrHTablePut failed"));
3255 return VERR_NO_MEMORY;
3256 }
3257 }
3258
3259 rc = crVBoxServerAddClientObj(u32ClientId, &pClient);
3260 if (RT_SUCCESS(rc))
3261 {
3262 rc = crVBoxServerClientObjSetVersion(pClient, uMajorVersion, uMinorVersion);
3263 if (RT_SUCCESS(rc))
3264 {
3265 rc = crVBoxServerClientObjSetPID(pClient, uPid);
3266 if (RT_SUCCESS(rc))
3267 {
3268 rc = CrHTablePutToSlot(&cr_server.clientTable, u32ClientId, pClient);
3269 if (RT_SUCCESS(rc))
3270 {
3271 pConnect->Hdr.u32CmdClientId = u32ClientId;
3272 return VINF_SUCCESS;
3273 }
3274 WARN(("CrHTablePutToSlot failed %d", rc));
3275 }
3276 else
3277 WARN(("crVBoxServerClientObjSetPID failed %d", rc));
3278 }
3279 else
3280 WARN(("crVBoxServerClientObjSetVersion failed %d", rc));
3281
3282 crVBoxServerRemoveClientObj(pClient);
3283 }
3284 else
3285 WARN(("crVBoxServerAddClientObj failed %d", rc));
3286
3287 CrHTableRemove(&cr_server.clientTable, u32ClientId);
3288
3289 return rc;
3290}
3291
3292static int crVBoxCrConnect(VBOXCMDVBVA_3DCTL_CONNECT RT_UNTRUSTED_VOLATILE_GUEST *pConnect)
3293{
3294 return crVBoxCrConnectEx(pConnect, CRHTABLE_HANDLE_INVALID);
3295}
3296
3297/**
3298 * @interface_method_impl{VBOXCRCMD_SVRINFO,pfnGuestCtl}
3299 */
3300static DECLCALLBACK(int) crVBoxCrCmdGuestCtl(HVBOXCRCMDSVR hSvr, uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pbCmd, uint32_t cbCmd)
3301{
3302 /*
3303 * Toplevel input validation.
3304 */
3305 ASSERT_GUEST_LOGREL_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_3DCTL), VERR_INVALID_PARAMETER);
3306 {
3307 VBOXCMDVBVA_3DCTL RT_UNTRUSTED_VOLATILE_GUEST *pCtl = (VBOXCMDVBVA_3DCTL RT_UNTRUSTED_VOLATILE_GUEST*)pbCmd;
3308 const uint32_t uType = pCtl->u32Type;
3309 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
3310
3311 ASSERT_GUEST_LOGREL_RETURN( uType == VBOXCMDVBVA3DCTL_TYPE_CMD
3312 || uType == VBOXCMDVBVA3DCTL_TYPE_CONNECT
3313 || uType == VBOXCMDVBVA3DCTL_TYPE_DISCONNECT
3314 , VERR_INVALID_PARAMETER);
3315 RT_UNTRUSTED_VALIDATED_FENCE();
3316
3317 /*
3318 * Call worker abd process the request.
3319 */
3320 switch (uType)
3321 {
3322 case VBOXCMDVBVA3DCTL_TYPE_CMD:
3323 ASSERT_GUEST_LOGREL_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_3DCTL_CMD), VERR_INVALID_PARAMETER);
3324 {
3325 VBOXCMDVBVA_3DCTL_CMD RT_UNTRUSTED_VOLATILE_GUEST *p3DCmd
3326 = (VBOXCMDVBVA_3DCTL_CMD RT_UNTRUSTED_VOLATILE_GUEST *)pbCmd;
3327 return crVBoxCrCmdCmd(NULL, &p3DCmd->Cmd, cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_3DCTL_CMD, Cmd));
3328 }
3329
3330 case VBOXCMDVBVA3DCTL_TYPE_CONNECT:
3331 ASSERT_GUEST_LOGREL_RETURN(cbCmd == sizeof(VBOXCMDVBVA_3DCTL_CONNECT), VERR_INVALID_PARAMETER);
3332 return crVBoxCrConnect((VBOXCMDVBVA_3DCTL_CONNECT RT_UNTRUSTED_VOLATILE_GUEST *)pCtl);
3333
3334 case VBOXCMDVBVA3DCTL_TYPE_DISCONNECT:
3335 ASSERT_GUEST_LOGREL_RETURN(cbCmd == sizeof(VBOXCMDVBVA_3DCTL), VERR_INVALID_PARAMETER);
3336 {
3337 uint32_t idClient = pCtl->u32CmdClientId;
3338 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
3339 return crVBoxCrDisconnect(idClient);
3340 }
3341
3342 default:
3343 AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);
3344 }
3345 }
3346}
3347
3348static DECLCALLBACK(int) crVBoxCrCmdResize(HVBOXCRCMDSVR hSvr, const struct VBVAINFOSCREEN *pScreen, const uint32_t *pTargetMap)
3349{
3350 CRASSERT(cr_server.fCrCmdEnabled);
3351 return CrPMgrResize(pScreen, NULL, pTargetMap);
3352}
3353
3354static const char* gszVBoxOGLSSMMagic = "***OpenGL state data***";
3355
3356static int crVBoxCrCmdSaveClients(PSSMHANDLE pSSM)
3357{
3358 int i;
3359 int rc = SSMR3PutU32(pSSM, cr_server.numClients);
3360 AssertRCReturn(rc, rc);
3361
3362 for (i = 0; i < cr_server.numClients; i++)
3363 {
3364 CRClient * pClient = cr_server.clients[i];
3365 Assert(pClient);
3366
3367 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
3368 AssertRCReturn(rc, rc);
3369 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
3370 AssertRCReturn(rc, rc);
3371 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
3372 AssertRCReturn(rc, rc);
3373 rc = SSMR3PutU64(pSSM, pClient->pid);
3374 AssertRCReturn(rc, rc);
3375 }
3376
3377 return VINF_SUCCESS;
3378}
3379
3380static int crVBoxCrCmdLoadClients(PSSMHANDLE pSSM, uint32_t u32Version)
3381{
3382 uint32_t i;
3383 uint32_t u32;
3384 VBOXCMDVBVA_3DCTL_CONNECT Connect;
3385 int rc = SSMR3GetU32(pSSM, &u32);
3386 AssertLogRelRCReturn(rc, rc);
3387
3388 for (i = 0; i < u32; i++)
3389 {
3390 uint32_t u32ClientID;
3391 Connect.Hdr.u32Type = VBOXCMDVBVA3DCTL_TYPE_CONNECT;
3392 Connect.Hdr.u32CmdClientId = 0;
3393
3394 rc = SSMR3GetU32(pSSM, &u32ClientID);
3395 AssertLogRelRCReturn(rc, rc);
3396 rc = SSMR3GetU32(pSSM, &Connect.u32MajorVersion);
3397 AssertLogRelRCReturn(rc, rc);
3398 rc = SSMR3GetU32(pSSM, &Connect.u32MinorVersion);
3399 AssertLogRelRCReturn(rc, rc);
3400 rc = SSMR3GetU64(pSSM, &Connect.u64Pid);
3401 AssertLogRelRCReturn(rc, rc);
3402
3403 rc = crVBoxCrConnectEx(&Connect, u32ClientID);
3404 AssertLogRelRCReturn(rc, rc);
3405 }
3406
3407 return VINF_SUCCESS;
3408}
3409
3410static DECLCALLBACK(int) crVBoxCrCmdSaveState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM)
3411{
3412 int rc = VINF_SUCCESS;
3413
3414 Assert(cr_server.fCrCmdEnabled);
3415
3416 /* Start*/
3417 rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
3418 AssertRCReturn(rc, rc);
3419
3420 if (!cr_server.numClients)
3421 {
3422 rc = SSMR3PutU32(pSSM, 0);
3423 AssertRCReturn(rc, rc);
3424
3425 rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
3426 AssertRCReturn(rc, rc);
3427
3428 return VINF_SUCCESS;
3429 }
3430
3431 rc = SSMR3PutU32(pSSM, 1);
3432 AssertRCReturn(rc, rc);
3433
3434 /* Version */
3435 rc = SSMR3PutU32(pSSM, (uint32_t) SHCROGL_SSM_VERSION);
3436 AssertRCReturn(rc, rc);
3437
3438 rc = crVBoxCrCmdSaveClients(pSSM);
3439 AssertRCReturn(rc, rc);
3440
3441 /* The state itself */
3442 rc = crVBoxServerSaveStatePerform(pSSM);
3443 AssertRCReturn(rc, rc);
3444
3445 /* Save svc buffers info */
3446 {
3447 rc = SSMR3PutU32(pSSM, 0);
3448 AssertRCReturn(rc, rc);
3449
3450 rc = SSMR3PutU32(pSSM, 0);
3451 AssertRCReturn(rc, rc);
3452 }
3453
3454 /* End */
3455 rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
3456 AssertRCReturn(rc, rc);
3457
3458 return VINF_SUCCESS;
3459}
3460
3461static DECLCALLBACK(int) crVBoxCrCmdLoadState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM, uint32_t u32Version)
3462{
3463 int rc = VINF_SUCCESS;
3464
3465 char szBuf[2000];
3466 uint32_t ui32;
3467
3468 Assert(cr_server.fCrCmdEnabled);
3469
3470 /* Start of data */
3471 rc = SSMR3GetStrZEx(pSSM, szBuf, sizeof(szBuf), NULL);
3472 AssertLogRelRCReturn(rc, rc);
3473 AssertLogRelMsgReturn(!strcmp(gszVBoxOGLSSMMagic, szBuf), ("Unexpected data1: '%s'\n", szBuf), VERR_SSM_UNEXPECTED_DATA);
3474
3475 /* num clients */
3476 rc = SSMR3GetU32(pSSM, &ui32);
3477 AssertLogRelRCReturn(rc, rc);
3478
3479 if (!ui32)
3480 {
3481 /* no clients, dummy stub */
3482 rc = SSMR3GetStrZEx(pSSM, szBuf, sizeof(szBuf), NULL);
3483 AssertLogRelRCReturn(rc, rc);
3484 AssertLogRelMsgReturn(!strcmp(gszVBoxOGLSSMMagic, szBuf), ("Unexpected data2: '%s'\n", szBuf), VERR_SSM_UNEXPECTED_DATA);
3485
3486 return VINF_SUCCESS;
3487 }
3488 AssertLogRelMsgReturn(ui32 == 1, ("Invalid client count: %#x\n", ui32), VERR_SSM_UNEXPECTED_DATA);
3489
3490 /* Version */
3491 rc = SSMR3GetU32(pSSM, &ui32);
3492 AssertLogRelRCReturn(rc, rc);
3493 AssertLogRelMsgReturn(ui32 >= SHCROGL_SSM_VERSION_CRCMD, ("Unexpected version: %#x\n", ui32), VERR_SSM_UNEXPECTED_DATA);
3494
3495 rc = crVBoxCrCmdLoadClients(pSSM, u32Version);
3496 AssertLogRelRCReturn(rc, rc);
3497
3498 /* The state itself */
3499 rc = crVBoxServerLoadStatePerform(pSSM, ui32);
3500 AssertLogRelRCReturn(rc, rc);
3501
3502 /* Save svc buffers info */
3503 {
3504 rc = SSMR3GetU32(pSSM, &ui32);
3505 AssertLogRelRCReturn(rc, rc);
3506 AssertLogRelMsgReturn(ui32 == 0, ("Unexpected data3: %#x\n", ui32), VERR_SSM_UNEXPECTED_DATA);
3507
3508 rc = SSMR3GetU32(pSSM, &ui32);
3509 AssertLogRelRCReturn(rc, rc);
3510 AssertLogRelMsgReturn(ui32 == 0, ("Unexpected data4: %#x\n", ui32), VERR_SSM_UNEXPECTED_DATA);
3511 }
3512
3513 /* End */
3514 rc = SSMR3GetStrZEx(pSSM, szBuf, sizeof(szBuf), NULL);
3515 AssertLogRelRCReturn(rc, rc);
3516 AssertLogRelMsgReturn(!strcmp(gszVBoxOGLSSMMagic, szBuf), ("Unexpected data5: '%s'\n", szBuf), VERR_SSM_UNEXPECTED_DATA);
3517
3518 return VINF_SUCCESS;
3519}
3520
3521
3522/**
3523 * @interface_method_impl{VBOXCRCMD_SVRINFO,pfnCmd}
3524 */
3525static DECLCALLBACK(int8_t) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr,
3526 const VBOXCMDVBVA_HDR RT_UNTRUSTED_VOLATILE_GUEST *pCmd, uint32_t cbCmd)
3527{
3528 uint8_t bOpcode = pCmd->u8OpCode;
3529 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
3530 ASSERT_GUEST_LOGREL_MSG_RETURN( bOpcode == VBOXCMDVBVA_OPTYPE_CRCMD
3531 || bOpcode == VBOXCMDVBVA_OPTYPE_FLIP
3532 || bOpcode == VBOXCMDVBVA_OPTYPE_BLT
3533 || bOpcode == VBOXCMDVBVA_OPTYPE_CLRFILL,
3534 ("%#x\n", bOpcode), -1);
3535 RT_UNTRUSTED_VALIDATED_FENCE();
3536
3537 switch (bOpcode)
3538 {
3539 case VBOXCMDVBVA_OPTYPE_CRCMD:
3540 ASSERT_GUEST_LOGREL_MSG_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_CRCMD), ("cbCmd=%u\n", cbCmd), -1);
3541 {
3542 VBOXCMDVBVA_CRCMD const RT_UNTRUSTED_VOLATILE_GUEST *pCrCmdDr
3543 = (VBOXCMDVBVA_CRCMD const RT_UNTRUSTED_VOLATILE_GUEST *)pCmd;
3544 VBOXCMDVBVA_CRCMD_CMD const RT_UNTRUSTED_VOLATILE_GUEST *pCrCmd = &pCrCmdDr->Cmd;
3545 int rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd, cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_CRCMD, Cmd));
3546 ASSERT_GUEST_LOGREL_RC_RETURN(rc, -1);
3547 return 0;
3548 }
3549
3550 case VBOXCMDVBVA_OPTYPE_FLIP:
3551 ASSERT_GUEST_LOGREL_MSG_RETURN(cbCmd >= VBOXCMDVBVA_SIZEOF_FLIPSTRUCT_MIN, ("cbCmd=%u\n", cbCmd), -1);
3552 {
3553 VBOXCMDVBVA_FLIP const RT_UNTRUSTED_VOLATILE_GUEST *pFlip
3554 = (VBOXCMDVBVA_FLIP const RT_UNTRUSTED_VOLATILE_GUEST *)pCmd;
3555 return crVBoxServerCrCmdFlipProcess(pFlip, cbCmd);
3556 }
3557
3558 case VBOXCMDVBVA_OPTYPE_BLT:
3559 ASSERT_GUEST_LOGREL_MSG_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_BLT_HDR), ("cbCmd=%u\n", cbCmd), -1);
3560 return crVBoxServerCrCmdBltProcess((VBOXCMDVBVA_BLT_HDR const RT_UNTRUSTED_VOLATILE_GUEST *)pCmd, cbCmd);
3561
3562 case VBOXCMDVBVA_OPTYPE_CLRFILL:
3563 ASSERT_GUEST_LOGREL_MSG_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_CLRFILL_HDR), ("cbCmd=%u\n", cbCmd), -1);
3564 return crVBoxServerCrCmdClrFillProcess((VBOXCMDVBVA_CLRFILL_HDR const RT_UNTRUSTED_VOLATILE_GUEST *)pCmd, cbCmd);
3565
3566 default:
3567 AssertFailedReturn(-1);
3568 }
3569 /* not reached */
3570}
3571
3572/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
3573 *
3574 * 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.
3575 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
3576 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
3577 * to block the lower-priority thread trying to complete the blocking command.
3578 * And removed extra memcpy done on blocked command arrival.
3579 *
3580 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
3581 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
3582 *
3583 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
3584 * */
3585
3586
3587int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
3588{
3589
3590 int32_t rc;
3591 uint32_t cBuffers = pCmd->cBuffers;
3592 uint32_t cParams;
3593 uint32_t cbHdr;
3594 CRVBOXHGSMIHDR *pHdr;
3595 uint32_t u32Function;
3596 uint32_t u32ClientID;
3597 CRClient *pClient;
3598
3599 if (!g_pvVRamBase)
3600 {
3601 WARN(("g_pvVRamBase is not initialized"));
3602
3603 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
3604 return VINF_SUCCESS;
3605 }
3606
3607 if (!cBuffers)
3608 {
3609 WARN(("zero buffers passed in!"));
3610
3611 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3612 return VINF_SUCCESS;
3613 }
3614
3615 cParams = cBuffers-1;
3616
3617 cbHdr = pCmd->aBuffers[0].cbBuffer;
3618 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
3619 if (!pHdr)
3620 {
3621 WARN(("invalid header buffer!"));
3622
3623 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3624 return VINF_SUCCESS;
3625 }
3626
3627 if (cbHdr < sizeof (*pHdr))
3628 {
3629 WARN(("invalid header buffer size!"));
3630
3631 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3632 return VINF_SUCCESS;
3633 }
3634
3635 u32Function = pHdr->u32Function;
3636 u32ClientID = pHdr->u32ClientID;
3637
3638 switch (u32Function)
3639 {
3640 case SHCRGL_GUEST_FN_WRITE:
3641 {
3642 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
3643
3644 /** @todo Verify */
3645 if (cParams == 1)
3646 {
3647 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
3648 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3649 /* Fetch parameters. */
3650 uint32_t cbBuffer = pBuf->cbBuffer;
3651 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3652
3653 if (cbHdr < sizeof (*pFnCmd))
3654 {
3655 crWarning("invalid write cmd buffer size!");
3656 rc = VERR_INVALID_PARAMETER;
3657 break;
3658 }
3659
3660 CRASSERT(cbBuffer);
3661 if (!pBuffer)
3662 {
3663 crWarning("invalid buffer data received from guest!");
3664 rc = VERR_INVALID_PARAMETER;
3665 break;
3666 }
3667
3668 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3669 if (RT_FAILURE(rc))
3670 {
3671 break;
3672 }
3673
3674 /* This should never fire unless we start to multithread */
3675 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3676 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3677
3678 pClient->conn->pBuffer = pBuffer;
3679 pClient->conn->cbBuffer = cbBuffer;
3680 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3681 crVBoxServerInternalClientWriteRead(pClient);
3682 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3683 return VINF_SUCCESS;
3684 }
3685 else
3686 {
3687 crWarning("invalid number of args");
3688 rc = VERR_INVALID_PARAMETER;
3689 break;
3690 }
3691 break;
3692 }
3693
3694 case SHCRGL_GUEST_FN_INJECT:
3695 {
3696 Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
3697
3698 /** @todo Verify */
3699 if (cParams == 1)
3700 {
3701 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
3702 /* Fetch parameters. */
3703 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
3704 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3705 uint32_t cbBuffer = pBuf->cbBuffer;
3706 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3707
3708 if (cbHdr < sizeof (*pFnCmd))
3709 {
3710 crWarning("invalid inject cmd buffer size!");
3711 rc = VERR_INVALID_PARAMETER;
3712 break;
3713 }
3714
3715 CRASSERT(cbBuffer);
3716 if (!pBuffer)
3717 {
3718 crWarning("invalid buffer data received from guest!");
3719 rc = VERR_INVALID_PARAMETER;
3720 break;
3721 }
3722
3723 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3724 if (RT_FAILURE(rc))
3725 {
3726 break;
3727 }
3728
3729 /* This should never fire unless we start to multithread */
3730 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3731 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3732
3733 pClient->conn->pBuffer = pBuffer;
3734 pClient->conn->cbBuffer = cbBuffer;
3735 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3736 crVBoxServerInternalClientWriteRead(pClient);
3737 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3738 return VINF_SUCCESS;
3739 }
3740
3741 crWarning("invalid number of args");
3742 rc = VERR_INVALID_PARAMETER;
3743 break;
3744 }
3745
3746 case SHCRGL_GUEST_FN_READ:
3747 {
3748 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3749
3750 /** @todo Verify */
3751 if (cParams == 1)
3752 {
3753 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3754 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3755 /* Fetch parameters. */
3756 uint32_t cbBuffer = pBuf->cbBuffer;
3757 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3758
3759 if (cbHdr < sizeof (*pFnCmd))
3760 {
3761 crWarning("invalid read cmd buffer size!");
3762 rc = VERR_INVALID_PARAMETER;
3763 break;
3764 }
3765
3766
3767 if (!pBuffer)
3768 {
3769 crWarning("invalid buffer data received from guest!");
3770 rc = VERR_INVALID_PARAMETER;
3771 break;
3772 }
3773
3774 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3775 if (RT_FAILURE(rc))
3776 {
3777 break;
3778 }
3779
3780 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3781
3782 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3783
3784 /* Return the required buffer size always */
3785 pFnCmd->cbBuffer = cbBuffer;
3786
3787 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3788
3789 /* the read command is never pended, complete it right away */
3790 pHdr->result = rc;
3791
3792 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3793 return VINF_SUCCESS;
3794 }
3795
3796 crWarning("invalid number of args");
3797 rc = VERR_INVALID_PARAMETER;
3798 break;
3799 }
3800
3801 case SHCRGL_GUEST_FN_WRITE_READ:
3802 {
3803 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3804
3805 /** @todo Verify */
3806 if (cParams == 2)
3807 {
3808 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3809 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3810 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3811
3812 /* Fetch parameters. */
3813 uint32_t cbBuffer = pBuf->cbBuffer;
3814 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3815
3816 uint32_t cbWriteback = pWbBuf->cbBuffer;
3817 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3818
3819 if (cbHdr < sizeof (*pFnCmd))
3820 {
3821 crWarning("invalid write_read cmd buffer size!");
3822 rc = VERR_INVALID_PARAMETER;
3823 break;
3824 }
3825
3826
3827 CRASSERT(cbBuffer);
3828 if (!pBuffer)
3829 {
3830 crWarning("invalid write buffer data received from guest!");
3831 rc = VERR_INVALID_PARAMETER;
3832 break;
3833 }
3834
3835 CRASSERT(cbWriteback);
3836 if (!pWriteback)
3837 {
3838 crWarning("invalid writeback buffer data received from guest!");
3839 rc = VERR_INVALID_PARAMETER;
3840 break;
3841 }
3842 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3843 if (RT_FAILURE(rc))
3844 {
3845 pHdr->result = rc;
3846 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3847 return rc;
3848 }
3849
3850 /* This should never fire unless we start to multithread */
3851 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3852 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3853
3854 pClient->conn->pBuffer = pBuffer;
3855 pClient->conn->cbBuffer = cbBuffer;
3856 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, true);
3857 crVBoxServerInternalClientWriteRead(pClient);
3858 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3859 return VINF_SUCCESS;
3860 }
3861
3862 crWarning("invalid number of args");
3863 rc = VERR_INVALID_PARAMETER;
3864 break;
3865 }
3866
3867 case SHCRGL_GUEST_FN_SET_VERSION:
3868 {
3869 WARN(("crVBoxServerCrHgsmiCmd, SHCRGL_GUEST_FN_SET_VERSION: invalid function"));
3870 rc = VERR_NOT_IMPLEMENTED;
3871 break;
3872 }
3873
3874 case SHCRGL_GUEST_FN_SET_PID:
3875 {
3876 WARN(("crVBoxServerCrHgsmiCmd, SHCRGL_GUEST_FN_SET_PID: invalid function"));
3877 rc = VERR_NOT_IMPLEMENTED;
3878 break;
3879 }
3880
3881 default:
3882 {
3883 WARN(("crVBoxServerCrHgsmiCmd: invalid functionm %d", u32Function));
3884 rc = VERR_NOT_IMPLEMENTED;
3885 break;
3886 }
3887
3888 }
3889
3890 /* we can be on fail only here */
3891 CRASSERT(RT_FAILURE(rc));
3892 pHdr->result = rc;
3893
3894 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3895 return rc;
3896
3897}
3898
3899
3900static DECLCALLBACK(bool) crVBoxServerHasDataForScreen(uint32_t u32ScreenID)
3901{
3902 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabledForScreen(u32ScreenID);
3903 if (hFb)
3904 return CrFbHas3DData(hFb);
3905
3906 return false;
3907}
3908
3909
3910static DECLCALLBACK(bool) crVBoxServerHasData(void)
3911{
3912 HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
3913 for (;
3914 hFb;
3915 hFb = CrPMgrFbGetNextEnabled(hFb))
3916 {
3917 if (CrFbHas3DData(hFb))
3918 return true;
3919 }
3920
3921 return false;
3922}
3923
3924int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
3925{
3926 int rc = VINF_SUCCESS;
3927
3928 switch (pCtl->enmType)
3929 {
3930 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
3931 {
3932 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
3933 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
3934 g_cbVRam = pSetup->cbVRam;
3935
3936 g_pLed = pSetup->pLed;
3937
3938 cr_server.ClientInfo = pSetup->CrClientInfo;
3939
3940 pSetup->CrCmdServerInfo.hSvr = NULL;
3941 pSetup->CrCmdServerInfo.pfnEnable = crVBoxCrCmdEnable;
3942 pSetup->CrCmdServerInfo.pfnDisable = crVBoxCrCmdDisable;
3943 pSetup->CrCmdServerInfo.pfnCmd = crVBoxCrCmdCmd;
3944 pSetup->CrCmdServerInfo.pfnHostCtl = crVBoxCrCmdHostCtl;
3945 pSetup->CrCmdServerInfo.pfnGuestCtl = crVBoxCrCmdGuestCtl;
3946 pSetup->CrCmdServerInfo.pfnResize = crVBoxCrCmdResize;
3947 pSetup->CrCmdServerInfo.pfnSaveState = crVBoxCrCmdSaveState;
3948 pSetup->CrCmdServerInfo.pfnLoadState = crVBoxCrCmdLoadState;
3949 rc = VINF_SUCCESS;
3950 break;
3951 }
3952 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
3953 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
3954 rc = VINF_SUCCESS;
3955 break;
3956 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB:
3957 {
3958 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB)pCtl;
3959 g_hCrHgsmiCompletion = pSetup->hCompletion;
3960 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
3961
3962 pSetup->MainInterface.pfnHasData = crVBoxServerHasData;
3963 pSetup->MainInterface.pfnHasDataForScreen = crVBoxServerHasDataForScreen;
3964
3965 rc = VINF_SUCCESS;
3966 break;
3967 }
3968 default:
3969 AssertMsgFailed(("invalid param %d", pCtl->enmType));
3970 rc = VERR_INVALID_PARAMETER;
3971 }
3972
3973 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
3974 * to complete them accordingly.
3975 * This approach allows using host->host and host->guest commands in the same way here
3976 * making the command completion to be the responsibility of the command originator.
3977 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
3978 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
3979 return rc;
3980}
3981
3982static int crVBoxServerCrCmdDisablePostProcess(VBOXCRCMDCTL_HGCMENABLE_DATA *pData)
3983{
3984 int rc = VINF_SUCCESS;
3985 uint8_t* pCtl;
3986 uint32_t cbCtl;
3987 HVBOXCRCMDCTL_REMAINING_HOST_COMMAND hRHCmd = pData->hRHCmd;
3988 PFNVBOXCRCMDCTL_REMAINING_HOST_COMMAND pfnRHCmd = pData->pfnRHCmd;
3989
3990 Assert(!cr_server.fCrCmdEnabled);
3991
3992 if (cr_server.numClients)
3993 {
3994 WARN(("cr_server.numClients(%d) is not NULL", cr_server.numClients));
3995 return VERR_INVALID_STATE;
3996 }
3997
3998 for (pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc); pCtl; pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc))
3999 {
4000 rc = crVBoxCrCmdHostCtl(NULL, pCtl, cbCtl);
4001 }
4002
4003 memset(&cr_server.DisableData, 0, sizeof (cr_server.DisableData));
4004
4005 return VINF_SUCCESS;
4006}
4007
4008int32_t crVBoxServerHgcmEnable(VBOXCRCMDCTL_HGCMENABLE_DATA *pData)
4009{
4010 int rc = crVBoxServerCrCmdDisablePostProcess(pData);
4011 if (RT_FAILURE(rc))
4012 {
4013 WARN(("crVBoxServerCrCmdDisablePostProcess failed %d", rc));
4014 return rc;
4015 }
4016
4017 crVBoxServerDefaultContextSet();
4018
4019 return VINF_SUCCESS;
4020}
4021
4022int32_t crVBoxServerHgcmDisable(VBOXCRCMDCTL_HGCMDISABLE_DATA *pData)
4023{
4024 Assert(!cr_server.fCrCmdEnabled);
4025
4026 Assert(!cr_server.numClients);
4027
4028 crVBoxServerRemoveAllClients();
4029
4030 CRASSERT(!cr_server.numClients);
4031
4032 crVBoxServerDefaultContextClear();
4033
4034 cr_server.DisableData = *pData;
4035
4036 return VINF_SUCCESS;
4037}
4038
4039#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