VirtualBox

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

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

Host 3D: Chromium server: add Expando SPU and DLM module in order to record and save OpenGL Display Lists (currently disabled).

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