VirtualBox

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

Last change on this file since 53400 was 53400, checked in by vboxsync, 10 years ago

Restore 3D state: fix SEGFAULT on X11 host (Linux): bind to corresponding (frame-, render-) buffer before put data into it (tested on X11 only).

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

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