VirtualBox

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

Last change on this file since 53169 was 53166, checked in by vboxsync, 11 years ago

Host 3D: Chronium Server: drop unused code.

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