VirtualBox

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

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

Host 3D unscaled HiDPI output: privide notifyHiDPIOutputPolicyChange() IDisplay interface to GUI in ouder to notify 3D about corresponding user option value change.

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