VirtualBox

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

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

Host 3D: fix SEGFAULT on old X11 i915 driver on 3D state restore: use DEPTH_STENCIL attachment only in case if both DEPTH and STENCIL were specified.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 124.1 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "server.h"
8#include "cr_net.h"
9#include "cr_unpack.h"
10#include "cr_error.h"
11#include "cr_glstate.h"
12#include "cr_string.h"
13#include "cr_mem.h"
14#include "cr_hash.h"
15#include "cr_vreg.h"
16#include "cr_environment.h"
17#include "cr_pixeldata.h"
18#include "server_dispatch.h"
19#include "state/cr_texture.h"
20#include "render/renderspu.h"
21#include <signal.h>
22#include <stdlib.h>
23#define DEBUG_FP_EXCEPTIONS 0
24#if DEBUG_FP_EXCEPTIONS
25#include <fpu_control.h>
26#include <math.h>
27#endif
28#include <iprt/assert.h>
29#include <VBox/err.h>
30#include <VBox/log.h>
31
32#ifdef VBOXCR_LOGFPS
33#include <iprt/timer.h>
34#endif
35
36#ifdef VBOX_WITH_CRHGSMI
37# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
38uint8_t* g_pvVRamBase = NULL;
39uint32_t g_cbVRam = 0;
40PPDMLED g_pLed = NULL;
41
42HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion = NULL;
43PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion = NULL;
44#endif
45
46/**
47 * \mainpage CrServerLib
48 *
49 * \section CrServerLibIntroduction Introduction
50 *
51 * Chromium consists of all the top-level files in the cr
52 * directory. The core module basically takes care of API dispatch,
53 * and OpenGL state management.
54 */
55
56
57/**
58 * CRServer global data
59 */
60CRServer cr_server;
61
62int tearingdown = 0; /* can't be static */
63
64static DECLCALLBACK(int8_t) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, const VBOXCMDVBVA_HDR *pCmd, uint32_t cbCmd);
65
66DECLINLINE(CRClient*) crVBoxServerClientById(uint32_t u32ClientID)
67{
68 int32_t i;
69
70 if (cr_server.fCrCmdEnabled)
71 return CrHTableGet(&cr_server.clientTable, u32ClientID);
72
73 for (i = 0; i < cr_server.numClients; i++)
74 {
75 if (cr_server.clients[i] && cr_server.clients[i]->conn
76 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
77 {
78 return cr_server.clients[i];
79 }
80 }
81
82 return NULL;
83}
84
85int32_t crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
86{
87 CRClient *pClient = NULL;
88
89 pClient = crVBoxServerClientById(u32ClientID);
90
91 if (!pClient)
92 {
93 WARN(("client not found!"));
94 *ppClient = NULL;
95 return VERR_INVALID_PARAMETER;
96 }
97
98 if (!pClient->conn->vMajor)
99 {
100 WARN(("no major version specified for client!"));
101 *ppClient = NULL;
102 return VERR_NOT_SUPPORTED;
103 }
104
105 *ppClient = pClient;
106
107 return VINF_SUCCESS;
108}
109
110
111/**
112 * Return pointer to server's first SPU.
113 */
114SPU*
115crServerHeadSPU(void)
116{
117 return cr_server.head_spu;
118}
119
120
121
122static void DeleteBarrierCallback( void *data )
123{
124 CRServerBarrier *barrier = (CRServerBarrier *) data;
125 crFree(barrier->waiting);
126 crFree(barrier);
127}
128
129
130static void deleteContextInfoCallback( void *data )
131{
132 CRContextInfo *c = (CRContextInfo *) data;
133 crStateDestroyContext(c->pContext);
134 if (c->CreateInfo.pszDpyName)
135 crFree(c->CreateInfo.pszDpyName);
136 crFree(c);
137}
138
139static void deleteMuralInfoCallback( void *data )
140{
141 CRMuralInfo *m = (CRMuralInfo *) data;
142 if (m->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID) /* <- do not do term for default mural as it does not contain any info to be freed,
143 * and renderspu will destroy it up itself*/
144 {
145 crServerMuralTerm(m);
146 }
147 crFree(m);
148}
149
150static int crVBoxServerCrCmdDisablePostProcess(VBOXCRCMDCTL_HGCMENABLE_DATA *pData);
151
152static void crServerTearDown( void )
153{
154 GLint i;
155 CRClientNode *pNode, *pNext;
156 GLboolean fOldEnableDiff;
157 GLboolean fContextsDeleted = GL_FALSE;
158
159 /* avoid a race condition */
160 if (tearingdown)
161 return;
162
163 tearingdown = 1;
164
165 if (cr_server.fCrCmdEnabled)
166 {
167 VBOXCRCMDCTL_HGCMENABLE_DATA EnableData;
168 /* crVBoxServerHgcmEnable will erase the DisableData, preserve it here */
169 VBOXCRCMDCTL_HGCMDISABLE_DATA DisableData = cr_server.DisableData;
170 int rc;
171
172 CRASSERT(DisableData.pfnNotifyTerm);
173 rc = DisableData.pfnNotifyTerm(DisableData.hNotifyTerm, &EnableData);
174 if (!RT_SUCCESS(rc))
175 {
176 WARN(("pfnNotifyTerm failed %d", rc));
177 return;
178 }
179
180 crVBoxServerCrCmdDisablePostProcess(&EnableData);
181 fContextsDeleted = GL_TRUE;
182
183 CRASSERT(DisableData.pfnNotifyTermDone);
184 DisableData.pfnNotifyTermDone(DisableData.hNotifyTerm);
185
186 Assert(!cr_server.fCrCmdEnabled);
187 }
188
189 crStateSetCurrent( NULL );
190
191 cr_server.curClient = NULL;
192 cr_server.run_queue = NULL;
193
194 crFree( cr_server.overlap_intens );
195 cr_server.overlap_intens = NULL;
196
197 /* needed to make sure window dummy mural not get created on mural destruction
198 * and generally this should be zeroed up */
199 cr_server.currentCtxInfo = NULL;
200 cr_server.currentWindow = -1;
201 cr_server.currentNativeWindow = 0;
202 cr_server.currentMural = NULL;
203
204 if (!fContextsDeleted)
205 {
206#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 /* Use GL_DEPTH_STENCIL only in case if both CR_STENCIL_BIT and CR_DEPTH_BIT specified. */
1366 if ( (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT)
1367 && (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT))
1368 {
1369 pEl = &pData->aElements[pData->cElements];
1370 pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1371 pEl->enmBuffer = 0; /* we do not care */
1372 pEl->posX = 0;
1373 pEl->posY = 0;
1374 pEl->width = width;
1375 pEl->height = height;
1376 pEl->enmFormat = GL_DEPTH_STENCIL;
1377 pEl->enmType = GL_UNSIGNED_INT_24_8;
1378 pEl->cbData = width * height * 4;
1379 pEl->pvData = crCalloc(pEl->cbData);
1380 if (!pEl->pvData)
1381 {
1382 crVBoxServerFBImageDataTerm(pData);
1383 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1384 return VERR_NO_MEMORY;
1385 }
1386 ++pData->cElements;
1387 }
1388 return VINF_SUCCESS;
1389}
1390
1391static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
1392{
1393 CRContextInfo *pCtxInfo;
1394 CRContext *pContext;
1395 CRMuralInfo *pMural;
1396 int32_t rc;
1397 GLuint i;
1398 struct
1399 {
1400 CRFBData data;
1401 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1402 } Data;
1403
1404 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1405
1406 pCtxInfo = cr_server.currentCtxInfo;
1407 pContext = pCtxInfo->pContext;
1408 pMural = pCtxInfo->currentMural;
1409
1410 rc = crVBoxServerFBImageDataInitEx(&Data.data, pCtxInfo, pMural, GL_FALSE, SHCROGL_SSM_VERSION, 0, 0);
1411 if (!RT_SUCCESS(rc))
1412 {
1413 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1414 return rc;
1415 }
1416
1417 rc = crStateAcquireFBImage(pContext, &Data.data);
1418 AssertRCReturn(rc, rc);
1419
1420 for (i = 0; i < Data.data.cElements; ++i)
1421 {
1422 CRFBDataElement * pEl = &Data.data.aElements[i];
1423 rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
1424 AssertRCReturn(rc, rc);
1425 }
1426
1427 crVBoxServerFBImageDataTerm(&Data.data);
1428
1429 return VINF_SUCCESS;
1430}
1431
1432#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
1433 if(!RT_SUCCESS((_rc))) { \
1434 AssertFailed(); \
1435 return; \
1436 } \
1437 } while (0)
1438
1439static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
1440{
1441 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1442 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1443 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1444 PSSMHANDLE pSSM = pData->pSSM;
1445 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1446 CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
1447
1448 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1449
1450 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1451
1452 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1453 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1454
1455 pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
1456 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1457
1458 crServerPerformMakeCurrent(pMural, pContextInfo);
1459
1460 pData->rc = crVBoxServerSaveFBImage(pSSM);
1461
1462 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1463 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1464 pContextInfo->currentMural = pInitialCurMural;
1465
1466 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1467}
1468
1469static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
1470{
1471 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1472 CRContext *pContext = pContextInfo->pContext;
1473 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1474 PSSMHANDLE pSSM = pData->pSSM;
1475 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
1476 CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
1477 const int32_t i32Dummy = 0;
1478
1479 AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
1480 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1481
1482 CRASSERT(pContext && pSSM);
1483 CRASSERT(pMural);
1484 CRASSERT(pMural->CreateInfo.externalID);
1485
1486 /* We could have skipped saving the key and use similar callback to load context states back,
1487 * but there's no guarantee we'd traverse hashtable in same order after loading.
1488 */
1489 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1490 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1491
1492#ifdef DEBUG_misha
1493 {
1494 unsigned long id;
1495 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
1496 crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
1497 else
1498 CRASSERT(id == key);
1499 }
1500#endif
1501
1502#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1503 if (pContextInfo->currentMural
1504 || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
1505 )
1506 {
1507 CRASSERT(pMural->CreateInfo.externalID);
1508 CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1509 pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
1510 }
1511 else
1512 {
1513 /* this is a dummy mural */
1514 CRASSERT(!pMural->width);
1515 CRASSERT(!pMural->height);
1516 CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1517 pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
1518 }
1519 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1520
1521 CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
1522 CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
1523 CRASSERT(cr_server.curClient);
1524
1525 crServerPerformMakeCurrent(pMural, pContextInfo);
1526#endif
1527
1528 pData->rc = crStateSaveContext(pContext, pSSM);
1529 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1530
1531 pData->rc = crVBoxServerSaveFBImage(pSSM);
1532 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1533
1534 /* restore the initial current mural */
1535 pContextInfo->currentMural = pContextCurrentMural;
1536}
1537
1538static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
1539
1540static int32_t crVBoxServerSaveStatePerform(PSSMHANDLE pSSM)
1541{
1542 int32_t rc, i;
1543 uint32_t ui32;
1544 GLboolean b;
1545 unsigned long key;
1546 GLenum err;
1547#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1548 CRClient *curClient;
1549 CRMuralInfo *curMural = NULL;
1550 CRContextInfo *curCtxInfo = NULL;
1551#endif
1552 CRVBOX_SAVE_STATE_GLOBAL Data;
1553
1554 crMemset(&Data, 0, sizeof (Data));
1555
1556#if 0
1557 crVBoxServerCheckConsistency();
1558#endif
1559
1560 /* We shouldn't be called if there's no clients at all*/
1561 CRASSERT(cr_server.numClients > 0);
1562
1563 /* @todo it's hack atm */
1564 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1565 * for every connected client (e.g. guest opengl application)
1566 */
1567 if (!cr_server.bIsInSavingState) /* It's first call */
1568 {
1569 cr_server.bIsInSavingState = GL_TRUE;
1570
1571 /* Store number of clients */
1572 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1573 AssertRCReturn(rc, rc);
1574
1575 /* we get called only once for CrCmd case, so disable the hack */
1576 g_hackVBoxServerSaveLoadCallsLeft = cr_server.fCrCmdEnabled ? 1 : cr_server.numClients;
1577 }
1578
1579 g_hackVBoxServerSaveLoadCallsLeft--;
1580
1581 /* Do nothing until we're being called last time */
1582 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1583 {
1584 return VINF_SUCCESS;
1585 }
1586
1587#ifdef DEBUG_misha
1588#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart"
1589#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop"
1590
1591 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1592 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START);
1593#endif
1594
1595 /* Save rendering contexts creation info */
1596 ui32 = crHashtableNumElements(cr_server.contextTable);
1597 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1598 AssertRCReturn(rc, rc);
1599 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1600
1601#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1602 curClient = cr_server.curClient;
1603 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1604 if (curClient)
1605 {
1606 curCtxInfo = cr_server.curClient->currentCtxInfo;
1607 curMural = cr_server.curClient->currentMural;
1608 }
1609 else if (cr_server.numClients)
1610 {
1611 cr_server.curClient = cr_server.clients[0];
1612 }
1613#endif
1614
1615 /* first save windows info */
1616 /* Save windows creation info */
1617 ui32 = crHashtableNumElements(cr_server.muralTable);
1618 /* There should be default mural always */
1619 CRASSERT(ui32>=1);
1620 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1621 AssertRCReturn(rc, rc);
1622 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1623
1624 /* Save cr_server.muralTable
1625 * @todo we don't need it all, just geometry info actually
1626 */
1627 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1628 AssertRCReturn(rc, rc);
1629 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1630
1631 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1632 crVBoxServerBuildSaveStateGlobal(&Data);
1633
1634 rc = crStateSaveGlobals(pSSM);
1635 AssertRCReturn(rc, rc);
1636
1637 Data.pSSM = pSSM;
1638 /* Save contexts state tracker data */
1639 /* @todo For now just some blind data dumps,
1640 * but I've a feeling those should be saved/restored in a very strict sequence to
1641 * allow diff_api to work correctly.
1642 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1643 */
1644 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1645 AssertRCReturn(Data.rc, Data.rc);
1646
1647 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1648 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1649 AssertRCReturn(rc, rc);
1650
1651 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1652 AssertRCReturn(Data.rc, Data.rc);
1653
1654#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1655 cr_server.curClient = curClient;
1656 /* Restore original win and ctx IDs*/
1657 if (curClient && curMural && curCtxInfo)
1658 {
1659 crServerPerformMakeCurrent(curMural, curCtxInfo);
1660 }
1661 else
1662 {
1663 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1664 }
1665#endif
1666
1667 /* Save clients info */
1668 for (i = 0; i < cr_server.numClients; i++)
1669 {
1670 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1671 {
1672 CRClient *pClient = cr_server.clients[i];
1673
1674 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1675 AssertRCReturn(rc, rc);
1676
1677 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1678 AssertRCReturn(rc, rc);
1679
1680 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1681 AssertRCReturn(rc, rc);
1682
1683 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1684 AssertRCReturn(rc, rc);
1685
1686 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber > 0)
1687 {
1688 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1689 CRASSERT(b);
1690 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1691 AssertRCReturn(rc, rc);
1692 }
1693
1694 if (pClient->currentMural && pClient->currentWindow > 0)
1695 {
1696 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1697 CRASSERT(b);
1698 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1699 AssertRCReturn(rc, rc);
1700 }
1701 }
1702 }
1703
1704 rc = crServerPendSaveState(pSSM);
1705 AssertRCReturn(rc, rc);
1706
1707 rc = CrPMgrSaveState(pSSM);
1708 AssertRCReturn(rc, rc);
1709
1710 /* all context gl error states should have now be synced with chromium erro states,
1711 * reset the error if any */
1712 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1713 crWarning("crServer: glGetError %d after saving snapshot", err);
1714
1715 cr_server.bIsInSavingState = GL_FALSE;
1716
1717#ifdef DEBUG_misha
1718 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1719 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
1720#endif
1721
1722 return VINF_SUCCESS;
1723}
1724
1725DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
1726{
1727 if (cr_server.fCrCmdEnabled)
1728 {
1729 WARN(("we should not be called with cmd enabled!"));
1730 return VERR_INTERNAL_ERROR;
1731 }
1732
1733 return crVBoxServerSaveStatePerform(pSSM);
1734}
1735
1736static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1737{
1738 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1739 CRASSERT(pContextInfo);
1740 CRASSERT(pContextInfo->pContext);
1741 return pContextInfo->pContext;
1742}
1743
1744typedef struct CR_SERVER_LOADSTATE_READER
1745{
1746 PSSMHANDLE pSSM;
1747 uint32_t cbBuffer;
1748 uint32_t cbData;
1749 uint32_t offData;
1750 uint8_t *pu8Buffer;
1751} CR_SERVER_LOADSTATE_READER;
1752
1753static void crServerLsrInit(CR_SERVER_LOADSTATE_READER *pReader, PSSMHANDLE pSSM)
1754{
1755 memset(pReader, 0, sizeof (*pReader));
1756 pReader->pSSM = pSSM;
1757}
1758
1759static void crServerLsrTerm(CR_SERVER_LOADSTATE_READER *pReader)
1760{
1761 if (pReader->pu8Buffer)
1762 RTMemFree(pReader->pu8Buffer);
1763
1764 /* sanity */
1765 memset(pReader, 0, sizeof (*pReader));
1766}
1767
1768static int crServerLsrDataGetMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1769{
1770 int rc = VINF_SUCCESS;
1771 uint32_t cbRemaining = cbBuffer;
1772 if (pReader->cbData)
1773 {
1774 uint8_t cbData = RT_MIN(pReader->cbData, cbBuffer);
1775 memcpy(pvBuffer, pReader->pu8Buffer + pReader->offData, cbData);
1776 pReader->cbData -= cbData;
1777 pReader->offData += cbData;
1778
1779 cbRemaining -= cbData;
1780 pvBuffer = ((uint8_t*)pvBuffer) + cbData;
1781 }
1782
1783 if (cbRemaining)
1784 {
1785 rc = SSMR3GetMem(pReader->pSSM, pvBuffer, cbRemaining);
1786 AssertRC(rc);
1787 }
1788
1789 return rc;
1790}
1791
1792static int crServerLsrDataGetU32(CR_SERVER_LOADSTATE_READER *pReader, uint32_t *pu32)
1793{
1794 return crServerLsrDataGetMem(pReader, pu32, sizeof (*pu32));
1795}
1796
1797static int crServerLsrDataPutMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1798{
1799 if (!pReader->cbData && pReader->cbBuffer >= cbBuffer)
1800 {
1801 pReader->offData = 0;
1802 pReader->cbData = cbBuffer;
1803 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1804 }
1805 else if (pReader->offData >= cbBuffer)
1806 {
1807 pReader->offData -= cbBuffer;
1808 pReader->cbData += cbBuffer;
1809 memcpy(pReader->pu8Buffer + pReader->offData, pvBuffer, cbBuffer);
1810 }
1811 else
1812 {
1813 uint8_t *pu8Buffer = pReader->pu8Buffer;
1814
1815 pReader->pu8Buffer = (uint8_t*)RTMemAlloc(cbBuffer + pReader->cbData);
1816 if (!pReader->pu8Buffer)
1817 {
1818 crWarning("failed to allocate mem %d", cbBuffer + pReader->cbData);
1819 return VERR_NO_MEMORY;
1820 }
1821
1822 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1823 if (pu8Buffer)
1824 {
1825 memcpy(pReader->pu8Buffer + cbBuffer, pu8Buffer + pReader->offData, pReader->cbData);
1826 RTMemFree(pu8Buffer);
1827 }
1828 else
1829 {
1830 Assert(!pReader->cbData);
1831 }
1832 pReader->offData = 0;
1833 pReader->cbData += cbBuffer;
1834 }
1835
1836 return VINF_SUCCESS;
1837}
1838
1839/* data to be skipped */
1840
1841typedef struct CR_SERVER_BUGGY_MURAL_DATA_2
1842{
1843 void*ListHead_pNext;
1844 void*ListHead_pPrev;
1845 uint32_t cEntries;
1846} CR_SERVER_BUGGY_MURAL_DATA_2;
1847typedef struct CR_SERVER_BUGGY_MURAL_DATA_1
1848{
1849 /* VBOXVR_COMPOSITOR_ENTRY Ce; */
1850 void*Ce_Node_pNext;
1851 void*Ce_Node_pPrev;
1852 CR_SERVER_BUGGY_MURAL_DATA_2 Vr;
1853 /* VBOXVR_TEXTURE Tex; */
1854 uint32_t Tex_width;
1855 uint32_t Tex_height;
1856 uint32_t Tex_target;
1857 uint32_t Tex_hwid;
1858 /* RTPOINT Pos; */
1859 uint32_t Pos_x;
1860 uint32_t Pos_y;
1861 uint32_t fChanged;
1862 uint32_t cRects;
1863 void* paSrcRects;
1864 void* paDstRects;
1865} CR_SERVER_BUGGY_MURAL_DATA_1;
1866
1867typedef struct CR_SERVER_BUGGY_MURAL_DATA_4
1868{
1869 uint32_t u32Magic;
1870 int32_t cLockers;
1871 RTNATIVETHREAD NativeThreadOwner;
1872 int32_t cNestings;
1873 uint32_t fFlags;
1874 void* EventSem;
1875 R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec;
1876 RTHCPTR Alignment;
1877} CR_SERVER_BUGGY_MURAL_DATA_4;
1878
1879typedef struct CR_SERVER_BUGGY_MURAL_DATA_3
1880{
1881 void*Compositor_List_pNext;
1882 void*Compositor_List_pPrev;
1883 void*Compositor_pfnEntryRemoved;
1884 float StretchX;
1885 float StretchY;
1886 uint32_t cRects;
1887 uint32_t cRectsBuffer;
1888 void*paSrcRects;
1889 void*paDstRects;
1890 CR_SERVER_BUGGY_MURAL_DATA_4 CritSect;
1891} CR_SERVER_BUGGY_MURAL_DATA_3;
1892
1893typedef struct CR_SERVER_BUGGY_MURAL_DATA
1894{
1895 uint8_t fRootVrOn;
1896 CR_SERVER_BUGGY_MURAL_DATA_1 RootVrCEntry;
1897 CR_SERVER_BUGGY_MURAL_DATA_3 RootVrCompositor;
1898} CR_SERVER_BUGGY_MURAL_DATA;
1899
1900AssertCompile(sizeof (CR_SERVER_BUGGY_MURAL_DATA) < sizeof (CRClient));
1901
1902static int32_t crVBoxServerLoadMurals(CR_SERVER_LOADSTATE_READER *pReader, uint32_t version)
1903{
1904 unsigned long key;
1905 uint32_t ui, uiNumElems;
1906 bool fBuggyMuralData = false;
1907 /* Load windows */
1908 int32_t rc = crServerLsrDataGetU32(pReader, &uiNumElems);
1909 AssertRCReturn(rc, rc);
1910 for (ui=0; ui<uiNumElems; ++ui)
1911 {
1912 CRCreateInfo_t createInfo;
1913 char psz[200];
1914 GLint winID;
1915 unsigned long key;
1916
1917 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1918 AssertRCReturn(rc, rc);
1919 rc = crServerLsrDataGetMem(pReader, &createInfo, sizeof(createInfo));
1920 AssertRCReturn(rc, rc);
1921
1922 CRASSERT(!pReader->cbData);
1923
1924 if (createInfo.pszDpyName)
1925 {
1926 rc = SSMR3GetStrZEx(pReader->pSSM, psz, 200, NULL);
1927 AssertRCReturn(rc, rc);
1928 createInfo.pszDpyName = psz;
1929 }
1930
1931 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1932 CRASSERT((int64_t)winID == (int64_t)key);
1933 }
1934
1935 /* Load cr_server.muralTable */
1936 rc = SSMR3GetU32(pReader->pSSM, &uiNumElems);
1937 AssertRCReturn(rc, rc);
1938 for (ui=0; ui<uiNumElems; ++ui)
1939 {
1940 CRMuralInfo muralInfo;
1941 CRMuralInfo *pActualMural = NULL;
1942
1943 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1944 AssertRCReturn(rc, rc);
1945 rc = crServerLsrDataGetMem(pReader, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1946 AssertRCReturn(rc, rc);
1947
1948 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1949 muralInfo.bFbDraw = GL_TRUE;
1950
1951 if (!ui && version == SHCROGL_SSM_VERSION_WITH_BUGGY_MURAL_INFO)
1952 {
1953 /* Lookahead buffer used to determine whether the data erroneously stored root visible regions data */
1954 union
1955 {
1956 void * apv[1];
1957 CR_SERVER_BUGGY_MURAL_DATA Data;
1958 /* need to chak spuWindow, so taking the offset of filed following it*/
1959 uint8_t au8[RT_OFFSETOF(CRMuralInfo, screenId)];
1960 RTRECT aVisRects[sizeof (CR_SERVER_BUGGY_MURAL_DATA) / sizeof (RTRECT)];
1961 } LaBuf;
1962
1963 do {
1964 /* first value is bool (uint8_t) value followed by pointer-size-based alignment.
1965 * the mural memory is zero-initialized initially, so we can be sure the padding is zeroed */
1966 rc = crServerLsrDataGetMem(pReader, &LaBuf, sizeof (LaBuf));
1967 AssertRCReturn(rc, rc);
1968 if (LaBuf.apv[0] != NULL && LaBuf.apv[0] != ((void*)1))
1969 break;
1970
1971 /* check that the pointers are either valid or NULL */
1972 if(LaBuf.Data.RootVrCEntry.Ce_Node_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pNext))
1973 break;
1974 if(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev))
1975 break;
1976 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext))
1977 break;
1978 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev))
1979 break;
1980
1981 /* the entry can can be the only one within the (mural) compositor,
1982 * so its compositor entry node can either contain NULL pNext and pPrev,
1983 * or both of them pointing to compositor's list head */
1984 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext != LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1985 break;
1986
1987 /* can either both or none be NULL */
1988 if (!LaBuf.Data.RootVrCEntry.Ce_Node_pNext != !LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1989 break;
1990
1991 if (!LaBuf.Data.fRootVrOn)
1992 {
1993 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext || LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1994 break;
1995
1996 /* either non-initialized (zeroed) or empty list */
1997 if (LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext != LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
1998 break;
1999
2000 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
2001 break;
2002 }
2003 else
2004 {
2005 /* the entry should be initialized */
2006 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext)
2007 break;
2008 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
2009 break;
2010
2011 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
2012 {
2013 /* entry should be in compositor list*/
2014 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev == NULL)
2015 break;
2016 CRASSERT(LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2017 }
2018 else
2019 {
2020 /* entry should NOT be in compositor list*/
2021 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev != NULL)
2022 break;
2023 CRASSERT(!LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2024 }
2025 }
2026
2027 /* fExpectPtr == true, the valid pointer values should not match possible mural width/height/position */
2028 fBuggyMuralData = true;
2029 break;
2030
2031 } while (0);
2032
2033 rc = crServerLsrDataPutMem(pReader, &LaBuf, sizeof (LaBuf));
2034 AssertRCReturn(rc, rc);
2035 }
2036
2037 if (fBuggyMuralData)
2038 {
2039 CR_SERVER_BUGGY_MURAL_DATA Tmp;
2040 rc = crServerLsrDataGetMem(pReader, &Tmp, sizeof (Tmp));
2041 AssertRCReturn(rc, rc);
2042 }
2043
2044 if (muralInfo.pVisibleRects)
2045 {
2046 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
2047 if (!muralInfo.pVisibleRects)
2048 {
2049 return VERR_NO_MEMORY;
2050 }
2051
2052 rc = crServerLsrDataGetMem(pReader, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
2053 AssertRCReturn(rc, rc);
2054 }
2055
2056 pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);
2057 CRASSERT(pActualMural);
2058
2059 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
2060 {
2061 rc = crServerLsrDataGetMem(pReader, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
2062 CRASSERT(rc == VINF_SUCCESS);
2063 }
2064
2065 /* Restore windows geometry info */
2066 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
2067 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
2068 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
2069 if (muralInfo.bReceivedRects)
2070 {
2071 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
2072 }
2073 crServerDispatchWindowShow(key, muralInfo.bVisible);
2074
2075 if (muralInfo.pVisibleRects)
2076 {
2077 crFree(muralInfo.pVisibleRects);
2078 }
2079 }
2080
2081 CRASSERT(RT_SUCCESS(rc));
2082 return VINF_SUCCESS;
2083}
2084
2085static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
2086 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
2087{
2088 CRContext *pContext = pContextInfo->pContext;
2089 int32_t rc = VINF_SUCCESS;
2090 GLuint i;
2091 /* can apply the data right away */
2092 struct
2093 {
2094 CRFBData data;
2095 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
2096 } Data;
2097
2098 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
2099
2100 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
2101 {
2102 if (!pMural->width || !pMural->height)
2103 return VINF_SUCCESS;
2104
2105 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
2106 if (!RT_SUCCESS(rc))
2107 {
2108 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2109 return rc;
2110 }
2111 }
2112 else
2113 {
2114 GLint storedWidth, storedHeight;
2115
2116 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2117 {
2118 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
2119 CRASSERT(cr_server.currentMural == pMural);
2120 storedWidth = pMural->width;
2121 storedHeight = pMural->height;
2122 }
2123 else
2124 {
2125 storedWidth = pContext->buffer.storedWidth;
2126 storedHeight = pContext->buffer.storedHeight;
2127 }
2128
2129 if (!storedWidth || !storedHeight)
2130 return VINF_SUCCESS;
2131
2132 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
2133 if (!RT_SUCCESS(rc))
2134 {
2135 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2136 return rc;
2137 }
2138 }
2139
2140 CRASSERT(Data.data.cElements);
2141
2142 for (i = 0; i < Data.data.cElements; ++i)
2143 {
2144 CRFBDataElement * pEl = &Data.data.aElements[i];
2145 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
2146 AssertRCReturn(rc, rc);
2147 }
2148
2149 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2150 {
2151 CRBufferState *pBuf = &pContext->buffer;
2152 /* can apply the data right away */
2153 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2154 CRASSERT(cr_server.currentMural);
2155
2156 cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
2157 0,
2158 pContextInfo->SpuContext >= 0
2159 ? pContextInfo->SpuContext
2160 : cr_server.MainContextInfo.SpuContext);
2161 crStateApplyFBImage(pContext, &Data.data);
2162 CRASSERT(!pBuf->pFrontImg);
2163 CRASSERT(!pBuf->pBackImg);
2164 crVBoxServerFBImageDataTerm(&Data.data);
2165
2166 crServerPresentFBO(pMural);
2167
2168 CRASSERT(cr_server.currentMural);
2169 cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
2170 0,
2171 cr_server.currentCtxInfo->SpuContext >= 0
2172 ? cr_server.currentCtxInfo->SpuContext
2173 : cr_server.MainContextInfo.SpuContext);
2174 }
2175 else
2176 {
2177 CRBufferState *pBuf = &pContext->buffer;
2178 CRASSERT(!pBuf->pFrontImg);
2179 CRASSERT(!pBuf->pBackImg);
2180 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
2181
2182 if (Data.data.cElements)
2183 {
2184 CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
2185 if (!RT_SUCCESS(rc))
2186 {
2187 crVBoxServerFBImageDataTerm(&Data.data);
2188 crWarning("crAlloc failed");
2189 return VERR_NO_MEMORY;
2190 }
2191
2192 crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
2193 pBuf->pFrontImg = pLazyData;
2194 }
2195 }
2196
2197 CRASSERT(RT_SUCCESS(rc));
2198 return VINF_SUCCESS;
2199}
2200
2201static int32_t crVBoxServerLoadStatePerform(PSSMHANDLE pSSM, uint32_t version)
2202{
2203 int32_t rc, i;
2204 uint32_t ui, uiNumElems;
2205 unsigned long key;
2206 GLenum err;
2207 CR_SERVER_LOADSTATE_READER Reader;
2208
2209 if (!cr_server.bIsInLoadingState)
2210 {
2211 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
2212 cr_server.bIsInLoadingState = GL_TRUE;
2213
2214 /* Read number of clients */
2215 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
2216 AssertRCReturn(rc, rc);
2217
2218 Assert(g_hackVBoxServerSaveLoadCallsLeft);
2219 /* we get called only once for CrCmd */
2220 if (cr_server.fCrCmdEnabled)
2221 g_hackVBoxServerSaveLoadCallsLeft = 1;
2222 }
2223
2224 g_hackVBoxServerSaveLoadCallsLeft--;
2225
2226 /* Do nothing until we're being called last time */
2227 if (g_hackVBoxServerSaveLoadCallsLeft>0)
2228 {
2229 return VINF_SUCCESS;
2230 }
2231
2232 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
2233 {
2234 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2235 }
2236
2237 crServerLsrInit(&Reader, pSSM);
2238
2239#ifdef DEBUG_misha
2240#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
2241#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
2242
2243 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2244 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
2245#endif
2246
2247 /* Load and recreate rendering contexts */
2248 rc = SSMR3GetU32(pSSM, &uiNumElems);
2249 AssertRCReturn(rc, rc);
2250 for (ui=0; ui<uiNumElems; ++ui)
2251 {
2252 CRCreateInfo_t createInfo;
2253 char psz[200];
2254 GLint ctxID;
2255 CRContextInfo* pContextInfo;
2256 CRContext* pContext;
2257
2258 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2259 AssertRCReturn(rc, rc);
2260 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
2261 AssertRCReturn(rc, rc);
2262
2263 if (createInfo.pszDpyName)
2264 {
2265 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
2266 AssertRCReturn(rc, rc);
2267 createInfo.pszDpyName = psz;
2268 }
2269
2270 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
2271 CRASSERT((int64_t)ctxID == (int64_t)key);
2272
2273 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2274 CRASSERT(pContextInfo);
2275 CRASSERT(pContextInfo->pContext);
2276 pContext = pContextInfo->pContext;
2277 pContext->shared->id=-1;
2278 }
2279
2280 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2281 {
2282 CRASSERT(!Reader.pu8Buffer);
2283 /* we have a mural data here */
2284 rc = crVBoxServerLoadMurals(&Reader, version);
2285 AssertRCReturn(rc, rc);
2286 CRASSERT(!Reader.pu8Buffer);
2287 }
2288
2289 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
2290 {
2291 /* set the current client to allow doing crServerPerformMakeCurrent later */
2292 CRASSERT(cr_server.numClients);
2293 cr_server.curClient = cr_server.clients[0];
2294 }
2295
2296 rc = crStateLoadGlobals(pSSM, version);
2297 AssertRCReturn(rc, rc);
2298
2299 if (uiNumElems)
2300 {
2301 /* ensure we have main context set up as current */
2302 CRMuralInfo *pMural;
2303 CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
2304 CRASSERT(!cr_server.currentCtxInfo);
2305 CRASSERT(!cr_server.currentMural);
2306 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
2307 CRASSERT(pMural);
2308 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
2309 }
2310
2311 /* Restore context state data */
2312 for (ui=0; ui<uiNumElems; ++ui)
2313 {
2314 CRContextInfo* pContextInfo;
2315 CRContext *pContext;
2316 CRMuralInfo *pMural = NULL;
2317 int32_t winId = 0;
2318
2319 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2320 AssertRCReturn(rc, rc);
2321
2322 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2323 CRASSERT(pContextInfo);
2324 CRASSERT(pContextInfo->pContext);
2325 pContext = pContextInfo->pContext;
2326
2327 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2328 {
2329 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
2330 AssertRCReturn(rc, rc);
2331
2332 if (winId)
2333 {
2334 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
2335 CRASSERT(pMural);
2336 }
2337 else
2338 {
2339 /* null winId means a dummy mural, get it */
2340 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
2341 CRASSERT(pMural);
2342 }
2343 }
2344
2345 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
2346 AssertRCReturn(rc, rc);
2347
2348 /*Restore front/back buffer images*/
2349 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2350 AssertRCReturn(rc, rc);
2351 }
2352
2353 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2354 {
2355 CRContextInfo *pContextInfo;
2356 CRMuralInfo *pMural;
2357 GLint ctxId;
2358
2359 rc = SSMR3GetU32(pSSM, &uiNumElems);
2360 AssertRCReturn(rc, rc);
2361 for (ui=0; ui<uiNumElems; ++ui)
2362 {
2363 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
2364 CRMuralInfo *pInitialCurMural;
2365
2366 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2367 AssertRCReturn(rc, rc);
2368
2369 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
2370 AssertRCReturn(rc, rc);
2371
2372 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
2373 CRASSERT(pMural);
2374 if (ctxId)
2375 {
2376 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
2377 CRASSERT(pContextInfo);
2378 }
2379 else
2380 pContextInfo = &cr_server.MainContextInfo;
2381
2382 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
2383 pInitialCurMural = pContextInfo->currentMural;
2384
2385 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2386 AssertRCReturn(rc, rc);
2387
2388 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
2389 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
2390 pContextInfo->currentMural = pInitialCurMural;
2391 }
2392
2393 CRASSERT(!uiNumElems || cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2394
2395 cr_server.curClient = NULL;
2396 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
2397 }
2398 else
2399 {
2400 CRServerFreeIDsPool_t dummyIdsPool;
2401
2402 CRASSERT(!Reader.pu8Buffer);
2403
2404 /* we have a mural data here */
2405 rc = crVBoxServerLoadMurals(&Reader, version);
2406 AssertRCReturn(rc, rc);
2407
2408 /* not used any more, just read it out and ignore */
2409 rc = crServerLsrDataGetMem(&Reader, &dummyIdsPool, sizeof(dummyIdsPool));
2410 CRASSERT(rc == VINF_SUCCESS);
2411 }
2412
2413 /* Load clients info */
2414 for (i = 0; i < cr_server.numClients; i++)
2415 {
2416 if (cr_server.clients[i] && cr_server.clients[i]->conn)
2417 {
2418 CRClient *pClient = cr_server.clients[i];
2419 CRClient client;
2420 unsigned long ctxID=-1, winID=-1;
2421
2422 rc = crServerLsrDataGetU32(&Reader, &ui);
2423 AssertRCReturn(rc, rc);
2424 /* If this assert fires, then we should search correct client in the list first*/
2425 CRASSERT(ui == pClient->conn->u32ClientID);
2426
2427 if (version>=4)
2428 {
2429 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMajor);
2430 AssertRCReturn(rc, rc);
2431
2432 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMinor);
2433 AssertRCReturn(rc, rc);
2434 }
2435
2436 rc = crServerLsrDataGetMem(&Reader, &client, sizeof(client));
2437 CRASSERT(rc == VINF_SUCCESS);
2438
2439 client.conn = pClient->conn;
2440 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2441 * and fail to bind old textures.
2442 */
2443 /*client.number = pClient->number;*/
2444 *pClient = client;
2445
2446 pClient->currentContextNumber = -1;
2447 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2448 pClient->currentMural = NULL;
2449 pClient->currentWindow = -1;
2450
2451 cr_server.curClient = pClient;
2452
2453 if (client.currentCtxInfo && client.currentContextNumber > 0)
2454 {
2455 rc = crServerLsrDataGetMem(&Reader, &ctxID, sizeof(ctxID));
2456 AssertRCReturn(rc, rc);
2457 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2458 CRASSERT(client.currentCtxInfo);
2459 CRASSERT(client.currentCtxInfo->pContext);
2460 //pClient->currentCtx = client.currentCtx;
2461 //pClient->currentContextNumber = ctxID;
2462 }
2463
2464 if (client.currentMural && client.currentWindow > 0)
2465 {
2466 rc = crServerLsrDataGetMem(&Reader, &winID, sizeof(winID));
2467 AssertRCReturn(rc, rc);
2468 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2469 CRASSERT(client.currentMural);
2470 //pClient->currentMural = client.currentMural;
2471 //pClient->currentWindow = winID;
2472 }
2473
2474 CRASSERT(!Reader.cbData);
2475
2476 /* Restore client active context and window */
2477 crServerDispatchMakeCurrent(winID, 0, ctxID);
2478 }
2479 }
2480
2481 cr_server.curClient = NULL;
2482
2483 rc = crServerPendLoadState(pSSM, version);
2484 AssertRCReturn(rc, rc);
2485
2486 if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_INFO)
2487 {
2488 rc = CrPMgrLoadState(pSSM, version);
2489 AssertRCReturn(rc, rc);
2490 }
2491
2492 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2493 crWarning("crServer: glGetError %d after loading snapshot", err);
2494
2495 cr_server.bIsInLoadingState = GL_FALSE;
2496
2497#ifdef DEBUG_misha
2498 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2499 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
2500#endif
2501
2502 CRASSERT(!Reader.cbData);
2503 crServerLsrTerm(&Reader);
2504
2505 return VINF_SUCCESS;
2506}
2507
2508DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
2509{
2510 if (cr_server.fCrCmdEnabled)
2511 {
2512 WARN(("CrCmd enabled"));
2513 return VERR_INTERNAL_ERROR;
2514 }
2515
2516 return crVBoxServerLoadStatePerform(pSSM, version);
2517}
2518
2519#define SCREEN(i) (cr_server.screen[i])
2520#define MAPPED(screen) ((screen).winID != 0)
2521
2522extern DECLEXPORT(void) crServerVBoxSetNotifyEventCB(PFNCRSERVERNOTIFYEVENT pfnCb)
2523{
2524 cr_server.pfnNotifyEventCB = pfnCb;
2525}
2526
2527void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void* pvData, uint32_t cbData)
2528{
2529 /* this is something unexpected, but just in case */
2530 if (idScreen >= cr_server.screenCount)
2531 {
2532 crWarning("invalid screen id %d", idScreen);
2533 return;
2534 }
2535
2536 cr_server.pfnNotifyEventCB(idScreen, uEvent, pvData, cbData);
2537}
2538
2539void crServerWindowReparent(CRMuralInfo *pMural)
2540{
2541 pMural->fHasParentWindow = !!cr_server.screen[pMural->screenId].winID;
2542
2543 renderspuReparentWindow(pMural->spuWindow);
2544}
2545
2546DECLEXPORT(void) crServerSetUnscaledHiDPI(bool fEnable)
2547{
2548 renderspuSetUnscaledHiDPI(fEnable);
2549}
2550
2551static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2552{
2553 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2554 int *sIndex = (int*) data2;
2555
2556 if (pMI->screenId == *sIndex)
2557 {
2558 crServerWindowReparent(pMI);
2559 }
2560}
2561
2562DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2563{
2564 int i;
2565
2566 if (sCount>CR_MAX_GUEST_MONITORS)
2567 return VERR_INVALID_PARAMETER;
2568
2569 /*Shouldn't happen yet, but to be safe in future*/
2570 for (i=0; i<cr_server.screenCount; ++i)
2571 {
2572 if (MAPPED(SCREEN(i)))
2573 WARN(("Screen count is changing, but screen[%i] is still mapped", i));
2574 return VERR_NOT_IMPLEMENTED;
2575 }
2576
2577 cr_server.screenCount = sCount;
2578
2579 for (i=0; i<sCount; ++i)
2580 {
2581 SCREEN(i).winID = 0;
2582 }
2583
2584 return VINF_SUCCESS;
2585}
2586
2587DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2588{
2589 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2590
2591 if (sIndex<0 || sIndex>=cr_server.screenCount)
2592 return VERR_INVALID_PARAMETER;
2593
2594 if (MAPPED(SCREEN(sIndex)))
2595 {
2596 SCREEN(sIndex).winID = 0;
2597 renderspuSetWindowId(0);
2598
2599 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2600
2601 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2602
2603 CrPMgrScreenChanged((uint32_t)sIndex);
2604 }
2605
2606 renderspuSetWindowId(SCREEN(0).winID);
2607
2608 return VINF_SUCCESS;
2609}
2610
2611DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2612{
2613 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2614
2615 if (sIndex<0 || sIndex>=cr_server.screenCount)
2616 return VERR_INVALID_PARAMETER;
2617
2618 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2619 {
2620 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2621 crVBoxServerUnmapScreen(sIndex);
2622 }
2623
2624 SCREEN(sIndex).winID = winID;
2625 SCREEN(sIndex).x = x;
2626 SCREEN(sIndex).y = y;
2627 SCREEN(sIndex).w = w;
2628 SCREEN(sIndex).h = h;
2629
2630 renderspuSetWindowId(SCREEN(sIndex).winID);
2631 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2632
2633 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2634 renderspuSetWindowId(SCREEN(0).winID);
2635
2636#ifndef WINDOWS
2637 /*Restore FB content for clients, which have current window on a screen being remapped*/
2638 {
2639 GLint i;
2640
2641 for (i = 0; i < cr_server.numClients; i++)
2642 {
2643 cr_server.curClient = cr_server.clients[i];
2644 if (cr_server.curClient->currentCtxInfo
2645 && cr_server.curClient->currentCtxInfo->pContext
2646 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2647 && cr_server.curClient->currentMural
2648 && cr_server.curClient->currentMural->screenId == sIndex
2649 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2650 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2651 {
2652 int clientWindow = cr_server.curClient->currentWindow;
2653 int clientContext = cr_server.curClient->currentContextNumber;
2654 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2655
2656 if (clientWindow && clientWindow != cr_server.currentWindow)
2657 {
2658 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2659 }
2660
2661 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2662 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2663 }
2664 }
2665 cr_server.curClient = NULL;
2666 }
2667#endif
2668
2669 CrPMgrScreenChanged((uint32_t)sIndex);
2670
2671 return VINF_SUCCESS;
2672}
2673
2674DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects)
2675{
2676 int32_t rc = VINF_SUCCESS;
2677 GLboolean fOldRootVrOn = cr_server.fRootVrOn;
2678
2679 /* non-zero rects pointer indicate rects are present and switched on
2680 * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions,
2681 * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */
2682 if (pRects)
2683 {
2684 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
2685 rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL);
2686 if (!RT_SUCCESS(rc))
2687 {
2688 crWarning("VBoxVrListRectsSet failed! rc %d", rc);
2689 return rc;
2690 }
2691
2692 cr_server.fRootVrOn = GL_TRUE;
2693 }
2694 else
2695 {
2696 if (!cr_server.fRootVrOn)
2697 return VINF_SUCCESS;
2698
2699 VBoxVrListClear(&cr_server.RootVr);
2700
2701 cr_server.fRootVrOn = GL_FALSE;
2702 }
2703
2704 if (!fOldRootVrOn != !cr_server.fRootVrOn)
2705 {
2706 rc = CrPMgrModeRootVr(cr_server.fRootVrOn);
2707 if (!RT_SUCCESS(rc))
2708 {
2709 crWarning("CrPMgrModeRootVr failed rc %d", rc);
2710 return rc;
2711 }
2712 }
2713 else if (cr_server.fRootVrOn)
2714 {
2715 rc = CrPMgrRootVrUpdate();
2716 if (!RT_SUCCESS(rc))
2717 {
2718 crWarning("CrPMgrRootVrUpdate failed rc %d", rc);
2719 return rc;
2720 }
2721 }
2722
2723 return VINF_SUCCESS;
2724}
2725
2726DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2727{
2728 return CrPMgrModeVrdp(value);
2729}
2730
2731DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2732{
2733 /* No need for a synchronization as this is single threaded. */
2734 if (pCallbacks)
2735 {
2736 cr_server.outputRedirect = *pCallbacks;
2737 }
2738 else
2739 {
2740 memset (&cr_server.outputRedirect, 0, sizeof (cr_server.outputRedirect));
2741 }
2742
2743 return VINF_SUCCESS;
2744}
2745
2746DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2747{
2748 CRScreenViewportInfo *pViewport;
2749 RTRECT NewRect;
2750 int rc;
2751
2752 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2753
2754 if (sIndex<0 || sIndex>=cr_server.screenCount)
2755 {
2756 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2757 return VERR_INVALID_PARAMETER;
2758 }
2759
2760 NewRect.xLeft = x;
2761 NewRect.yTop = y;
2762 NewRect.xRight = x + w;
2763 NewRect.yBottom = y + h;
2764
2765 pViewport = &cr_server.screenVieport[sIndex];
2766 /*always do viewport updates no matter whether the rectangle actually changes,
2767 * this is needed to ensure window is adjusted properly on OSX */
2768 pViewport->Rect = NewRect;
2769 rc = CrPMgrViewportUpdate((uint32_t)sIndex);
2770 if (!RT_SUCCESS(rc))
2771 {
2772 crWarning("CrPMgrViewportUpdate failed %d", rc);
2773 return rc;
2774 }
2775
2776 return VINF_SUCCESS;
2777}
2778
2779static void crVBoxServerDeleteMuralCb(unsigned long key, void *data1, void *data2)
2780{
2781 CRHashTable *h = (CRHashTable*)data2;
2782 CRMuralInfo *m = (CRMuralInfo *) data1;
2783 if (m->spuWindow == CR_RENDER_DEFAULT_WINDOW_ID)
2784 return;
2785
2786 crHashtableDelete(h, key, NULL);
2787 crServerMuralTerm(m);
2788 crFree(m);
2789}
2790
2791static void crVBoxServerDefaultContextClear()
2792{
2793 HCR_FRAMEBUFFER hFb;
2794 int rc = CrPMgrDisable();
2795 if (RT_FAILURE(rc))
2796 {
2797 WARN(("CrPMgrDisable failed %d", rc));
2798 return;
2799 }
2800
2801 for (hFb = CrPMgrFbGetFirstEnabled(); hFb; hFb = CrPMgrFbGetNextEnabled(hFb))
2802 {
2803 int rc = CrFbUpdateBegin(hFb);
2804 if (RT_SUCCESS(rc))
2805 {
2806 CrFbRegionsClear(hFb);
2807 CrFbUpdateEnd(hFb);
2808 }
2809 else
2810 WARN(("CrFbUpdateBegin failed %d", rc));
2811 }
2812
2813 cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
2814 crStateCleanupCurrent();
2815
2816 /* note: we need to clean all contexts, since otherwise renderspu leanup won't work,
2817 * i.e. renderspu would need to clean up its own internal windows, it won't be able to do that if
2818 * some those windows is associated with any context. */
2819 if (cr_server.MainContextInfo.SpuContext)
2820 {
2821 cr_server.head_spu->dispatch_table.DestroyContext(cr_server.MainContextInfo.SpuContext);
2822 crStateDestroyContext(cr_server.MainContextInfo.pContext);
2823 if (cr_server.MainContextInfo.CreateInfo.pszDpyName)
2824 crFree(cr_server.MainContextInfo.CreateInfo.pszDpyName);
2825
2826 memset(&cr_server.MainContextInfo, 0, sizeof (cr_server.MainContextInfo));
2827 }
2828
2829 cr_server.firstCallCreateContext = GL_TRUE;
2830 cr_server.firstCallMakeCurrent = GL_TRUE;
2831 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
2832
2833 CRASSERT(!cr_server.curClient);
2834
2835 cr_server.currentCtxInfo = NULL;
2836 cr_server.currentWindow = 0;
2837 cr_server.currentNativeWindow = 0;
2838 cr_server.currentMural = NULL;
2839
2840 crStateDestroy();
2841// crStateCleanupCurrent();
2842
2843 if (CrBltIsInitialized(&cr_server.Blitter))
2844 {
2845 CrBltTerm(&cr_server.Blitter);
2846 Assert(!CrBltIsInitialized(&cr_server.Blitter));
2847 }
2848
2849 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerDeleteMuralCb, cr_server.dummyMuralTable);
2850
2851 cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_RENDERTHREAD_INFORM, 0);
2852}
2853
2854static void crVBoxServerDefaultContextSet()
2855{
2856 cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_RENDERTHREAD_INFORM, 1);
2857
2858 CRASSERT(!cr_server.MainContextInfo.SpuContext);
2859
2860// crStateSetCurrent(NULL);
2861 crStateInit();
2862 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
2863
2864 CrPMgrEnable();
2865}
2866
2867#ifdef VBOX_WITH_CRHGSMI
2868
2869static int32_t crVBoxServerCmdVbvaCrCmdProcess(const struct VBOXCMDVBVA_CRCMD_CMD *pCmd, uint32_t cbCmd)
2870{
2871 int32_t rc;
2872 uint32_t cBuffers = pCmd->cBuffers;
2873 uint32_t cParams;
2874 uint32_t cbHdr;
2875 CRVBOXHGSMIHDR *pHdr;
2876 uint32_t u32Function;
2877 uint32_t u32ClientID;
2878 CRClient *pClient;
2879
2880 if (!g_pvVRamBase)
2881 {
2882 WARN(("g_pvVRamBase is not initialized"));
2883 return VERR_INVALID_STATE;
2884 }
2885
2886 if (!cBuffers)
2887 {
2888 WARN(("zero buffers passed in!"));
2889 return VERR_INVALID_PARAMETER;
2890 }
2891
2892 cParams = cBuffers-1;
2893
2894 if (cbCmd < RT_OFFSETOF(VBOXCMDVBVA_CRCMD_CMD, aBuffers[cBuffers]))
2895 {
2896 WARN(("invalid buffer size"));
2897 return VERR_INVALID_PARAMETER;
2898 }
2899
2900 cbHdr = pCmd->aBuffers[0].cbBuffer;
2901 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2902 if (!pHdr)
2903 {
2904 WARN(("invalid header buffer!"));
2905 return VERR_INVALID_PARAMETER;
2906 }
2907
2908 if (cbHdr < sizeof (*pHdr))
2909 {
2910 WARN(("invalid header buffer size!"));
2911 return VERR_INVALID_PARAMETER;
2912 }
2913
2914 u32Function = pHdr->u32Function;
2915 u32ClientID = pHdr->u32ClientID;
2916
2917 switch (u32Function)
2918 {
2919 case SHCRGL_GUEST_FN_WRITE:
2920 {
2921 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2922
2923 /* @todo: Verify */
2924 if (cParams == 1)
2925 {
2926 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2927 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
2928 /* Fetch parameters. */
2929 uint32_t cbBuffer = pBuf->cbBuffer;
2930 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2931
2932 if (cbHdr < sizeof (*pFnCmd))
2933 {
2934 WARN(("invalid write cmd buffer size!"));
2935 rc = VERR_INVALID_PARAMETER;
2936 break;
2937 }
2938
2939 CRASSERT(cbBuffer);
2940 if (!pBuffer)
2941 {
2942 WARN(("invalid buffer data received from guest!"));
2943 rc = VERR_INVALID_PARAMETER;
2944 break;
2945 }
2946
2947 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2948 if (RT_FAILURE(rc))
2949 {
2950 WARN(("crVBoxServerClientGet failed %d", rc));
2951 break;
2952 }
2953
2954 /* This should never fire unless we start to multithread */
2955 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2956 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2957
2958 pClient->conn->pBuffer = pBuffer;
2959 pClient->conn->cbBuffer = cbBuffer;
2960 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
2961 crVBoxServerInternalClientWriteRead(pClient);
2962 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2963 return VINF_SUCCESS;
2964 }
2965
2966 WARN(("invalid number of args"));
2967 rc = VERR_INVALID_PARAMETER;
2968 break;
2969 }
2970
2971 case SHCRGL_GUEST_FN_INJECT:
2972 {
2973 WARN(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2974
2975 /* @todo: Verify */
2976 if (cParams == 1)
2977 {
2978 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2979 /* Fetch parameters. */
2980 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2981 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
2982 uint32_t cbBuffer = pBuf->cbBuffer;
2983 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2984
2985 if (cbHdr < sizeof (*pFnCmd))
2986 {
2987 WARN(("invalid inject cmd buffer size!"));
2988 rc = VERR_INVALID_PARAMETER;
2989 break;
2990 }
2991
2992 CRASSERT(cbBuffer);
2993 if (!pBuffer)
2994 {
2995 WARN(("invalid buffer data received from guest!"));
2996 rc = VERR_INVALID_PARAMETER;
2997 break;
2998 }
2999
3000 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3001 if (RT_FAILURE(rc))
3002 {
3003 WARN(("crVBoxServerClientGet failed %d", rc));
3004 break;
3005 }
3006
3007 /* This should never fire unless we start to multithread */
3008 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3009 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3010
3011 pClient->conn->pBuffer = pBuffer;
3012 pClient->conn->cbBuffer = cbBuffer;
3013 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
3014 crVBoxServerInternalClientWriteRead(pClient);
3015 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3016 return VINF_SUCCESS;
3017 }
3018
3019 WARN(("invalid number of args"));
3020 rc = VERR_INVALID_PARAMETER;
3021 break;
3022 }
3023
3024 case SHCRGL_GUEST_FN_READ:
3025 {
3026 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3027
3028 /* @todo: Verify */
3029 if (cParams == 1)
3030 {
3031 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3032 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3033 /* Fetch parameters. */
3034 uint32_t cbBuffer = pBuf->cbBuffer;
3035 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3036
3037 if (cbHdr < sizeof (*pFnCmd))
3038 {
3039 WARN(("invalid read cmd buffer size!"));
3040 rc = VERR_INVALID_PARAMETER;
3041 break;
3042 }
3043
3044 if (!pBuffer)
3045 {
3046 WARN(("invalid buffer data received from guest!"));
3047 rc = VERR_INVALID_PARAMETER;
3048 break;
3049 }
3050
3051 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3052 if (RT_FAILURE(rc))
3053 {
3054 WARN(("crVBoxServerClientGet failed %d", rc));
3055 break;
3056 }
3057
3058 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3059
3060 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3061
3062 /* Return the required buffer size always */
3063 pFnCmd->cbBuffer = cbBuffer;
3064
3065 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3066
3067 /* the read command is never pended, complete it right away */
3068 if (RT_FAILURE(rc))
3069 {
3070 WARN(("crVBoxServerInternalClientRead failed %d", rc));
3071 break;
3072 }
3073
3074 break;
3075 }
3076
3077 crWarning("invalid number of args");
3078 rc = VERR_INVALID_PARAMETER;
3079 break;
3080 }
3081
3082 case SHCRGL_GUEST_FN_WRITE_READ:
3083 {
3084 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3085
3086 /* @todo: Verify */
3087 if (cParams == 2)
3088 {
3089 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3090 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3091 const VBOXCMDVBVA_CRCMD_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3092
3093 /* Fetch parameters. */
3094 uint32_t cbBuffer = pBuf->cbBuffer;
3095 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3096
3097 uint32_t cbWriteback = pWbBuf->cbBuffer;
3098 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3099
3100 if (cbHdr < sizeof (*pFnCmd))
3101 {
3102 WARN(("invalid write_read cmd buffer size!"));
3103 rc = VERR_INVALID_PARAMETER;
3104 break;
3105 }
3106
3107 CRASSERT(cbBuffer);
3108 if (!pBuffer)
3109 {
3110 WARN(("invalid write buffer data received from guest!"));
3111 rc = VERR_INVALID_PARAMETER;
3112 break;
3113 }
3114
3115 CRASSERT(cbWriteback);
3116 if (!pWriteback)
3117 {
3118 WARN(("invalid writeback buffer data received from guest!"));
3119 rc = VERR_INVALID_PARAMETER;
3120 break;
3121 }
3122
3123 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3124 if (RT_FAILURE(rc))
3125 {
3126 WARN(("crVBoxServerClientGet failed %d", rc));
3127 break;
3128 }
3129
3130 /* This should never fire unless we start to multithread */
3131 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3132 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3133
3134 pClient->conn->pBuffer = pBuffer;
3135 pClient->conn->cbBuffer = cbBuffer;
3136 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, false);
3137 crVBoxServerInternalClientWriteRead(pClient);
3138 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3139 return VINF_SUCCESS;
3140 }
3141
3142 crWarning("invalid number of args");
3143 rc = VERR_INVALID_PARAMETER;
3144 break;
3145 }
3146
3147 case SHCRGL_GUEST_FN_SET_VERSION:
3148 {
3149 WARN(("SHCRGL_GUEST_FN_SET_VERSION: invalid function"));
3150 rc = VERR_NOT_IMPLEMENTED;
3151 break;
3152 }
3153
3154 case SHCRGL_GUEST_FN_SET_PID:
3155 {
3156 WARN(("SHCRGL_GUEST_FN_SET_PID: invalid function"));
3157 rc = VERR_NOT_IMPLEMENTED;
3158 break;
3159 }
3160
3161 default:
3162 {
3163 WARN(("invalid function, %d", u32Function));
3164 rc = VERR_NOT_IMPLEMENTED;
3165 break;
3166 }
3167
3168 }
3169
3170 pHdr->result = rc;
3171
3172 return VINF_SUCCESS;
3173}
3174
3175static DECLCALLBACK(int) crVBoxCrCmdEnable(HVBOXCRCMDSVR hSvr, VBOXCRCMD_SVRENABLE_INFO *pInfo)
3176{
3177 Assert(!cr_server.fCrCmdEnabled);
3178 Assert(!cr_server.numClients);
3179
3180 cr_server.CrCmdClientInfo = *pInfo;
3181
3182 crVBoxServerDefaultContextSet();
3183
3184 cr_server.fCrCmdEnabled = GL_TRUE;
3185
3186 crInfo("crCmd ENABLED");
3187
3188 return VINF_SUCCESS;
3189}
3190
3191static DECLCALLBACK(int) crVBoxCrCmdDisable(HVBOXCRCMDSVR hSvr)
3192{
3193 Assert(cr_server.fCrCmdEnabled);
3194
3195 crVBoxServerRemoveAllClients();
3196
3197 CrHTableEmpty(&cr_server.clientTable);
3198
3199 crVBoxServerDefaultContextClear();
3200
3201 memset(&cr_server.CrCmdClientInfo, 0, sizeof (cr_server.CrCmdClientInfo));
3202
3203 cr_server.fCrCmdEnabled = GL_FALSE;
3204
3205 crInfo("crCmd DISABLED");
3206
3207 return VINF_SUCCESS;
3208}
3209
3210static DECLCALLBACK(int) crVBoxCrCmdHostCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
3211{
3212 return crVBoxServerHostCtl((VBOXCRCMDCTL*)pCmd, cbCmd);
3213}
3214
3215static int crVBoxCrDisconnect(uint32_t u32Client)
3216{
3217 CRClient *pClient = (CRClient*)CrHTableRemove(&cr_server.clientTable, u32Client);
3218 if (!pClient)
3219 {
3220 WARN(("invalid client id"));
3221 return VERR_INVALID_PARAMETER;
3222 }
3223
3224 crVBoxServerRemoveClientObj(pClient);
3225
3226 return VINF_SUCCESS;
3227}
3228
3229static int crVBoxCrConnectEx(VBOXCMDVBVA_3DCTL_CONNECT *pConnect, uint32_t u32ClientId)
3230{
3231 CRClient *pClient;
3232 int rc;
3233
3234 if (u32ClientId == CRHTABLE_HANDLE_INVALID)
3235 {
3236 /* allocate client id */
3237 u32ClientId = CrHTablePut(&cr_server.clientTable, (void*)1);
3238 if (u32ClientId == CRHTABLE_HANDLE_INVALID)
3239 {
3240 WARN(("CrHTablePut failed"));
3241 return VERR_NO_MEMORY;
3242 }
3243 }
3244
3245 rc = crVBoxServerAddClientObj(u32ClientId, &pClient);
3246 if (RT_SUCCESS(rc))
3247 {
3248 rc = crVBoxServerClientObjSetVersion(pClient, pConnect->u32MajorVersion, pConnect->u32MinorVersion);
3249 if (RT_SUCCESS(rc))
3250 {
3251 rc = crVBoxServerClientObjSetPID(pClient, pConnect->u64Pid);
3252 if (RT_SUCCESS(rc))
3253 {
3254 rc = CrHTablePutToSlot(&cr_server.clientTable, u32ClientId, pClient);
3255 if (RT_SUCCESS(rc))
3256 {
3257 pConnect->Hdr.u32CmdClientId = u32ClientId;
3258 return VINF_SUCCESS;
3259 }
3260 else
3261 WARN(("CrHTablePutToSlot failed %d", rc));
3262 }
3263 else
3264 WARN(("crVBoxServerClientObjSetPID failed %d", rc));
3265 }
3266 else
3267 WARN(("crVBoxServerClientObjSetVersion failed %d", rc));
3268
3269 crVBoxServerRemoveClientObj(pClient);
3270 }
3271 else
3272 WARN(("crVBoxServerAddClientObj failed %d", rc));
3273
3274 CrHTableRemove(&cr_server.clientTable, u32ClientId);
3275
3276 return rc;
3277}
3278
3279static int crVBoxCrConnect(VBOXCMDVBVA_3DCTL_CONNECT *pConnect)
3280{
3281 return crVBoxCrConnectEx(pConnect, CRHTABLE_HANDLE_INVALID);
3282}
3283
3284static DECLCALLBACK(int) crVBoxCrCmdGuestCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
3285{
3286 VBOXCMDVBVA_3DCTL *pCtl = (VBOXCMDVBVA_3DCTL*)pCmd;
3287 if (cbCmd < sizeof (VBOXCMDVBVA_3DCTL))
3288 {
3289 WARN(("invalid buffer size"));
3290 return VERR_INVALID_PARAMETER;
3291 }
3292
3293 switch (pCtl->u32Type)
3294 {
3295 case VBOXCMDVBVA3DCTL_TYPE_CONNECT:
3296 {
3297 if (cbCmd != sizeof (VBOXCMDVBVA_3DCTL_CONNECT))
3298 {
3299 WARN(("invalid command size"));
3300 return VERR_INVALID_PARAMETER;
3301 }
3302
3303 return crVBoxCrConnect((VBOXCMDVBVA_3DCTL_CONNECT*)pCtl);
3304 }
3305 case VBOXCMDVBVA3DCTL_TYPE_DISCONNECT:
3306 {
3307 if (cbCmd != sizeof (VBOXCMDVBVA_3DCTL))
3308 {
3309 WARN(("invalid command size"));
3310 return VERR_INVALID_PARAMETER;
3311 }
3312
3313 return crVBoxCrDisconnect(pCtl->u32CmdClientId);
3314 }
3315 case VBOXCMDVBVA3DCTL_TYPE_CMD:
3316 {
3317 VBOXCMDVBVA_3DCTL_CMD *p3DCmd;
3318 if (cbCmd < sizeof (VBOXCMDVBVA_3DCTL_CMD))
3319 {
3320 WARN(("invalid size"));
3321 return VERR_INVALID_PARAMETER;
3322 }
3323
3324 p3DCmd = (VBOXCMDVBVA_3DCTL_CMD*)pCmd;
3325
3326 return crVBoxCrCmdCmd(NULL, &p3DCmd->Cmd, cbCmd - RT_OFFSETOF(VBOXCMDVBVA_3DCTL_CMD, Cmd));
3327 }
3328 default:
3329 WARN(("crVBoxCrCmdGuestCtl: invalid function %d", pCtl->u32Type));
3330 return VERR_INVALID_PARAMETER;
3331 }
3332}
3333
3334static DECLCALLBACK(int) crVBoxCrCmdResize(HVBOXCRCMDSVR hSvr, const struct VBVAINFOSCREEN *pScreen, const uint32_t *pTargetMap)
3335{
3336 CRASSERT(cr_server.fCrCmdEnabled);
3337 return CrPMgrResize(pScreen, NULL, pTargetMap);
3338}
3339
3340static const char* gszVBoxOGLSSMMagic = "***OpenGL state data***";
3341
3342static int crVBoxCrCmdSaveClients(PSSMHANDLE pSSM)
3343{
3344 int i;
3345 int rc = SSMR3PutU32(pSSM, cr_server.numClients);
3346 AssertRCReturn(rc, rc);
3347
3348 for (i = 0; i < cr_server.numClients; i++)
3349 {
3350 CRClient * pClient = cr_server.clients[i];
3351 Assert(pClient);
3352
3353 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
3354 AssertRCReturn(rc, rc);
3355 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
3356 AssertRCReturn(rc, rc);
3357 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
3358 AssertRCReturn(rc, rc);
3359 rc = SSMR3PutU64(pSSM, pClient->pid);
3360 AssertRCReturn(rc, rc);
3361 }
3362
3363 return VINF_SUCCESS;
3364}
3365
3366static int crVBoxCrCmdLoadClients(PSSMHANDLE pSSM, uint32_t u32Version)
3367{
3368 uint32_t i;
3369 uint32_t u32;
3370 VBOXCMDVBVA_3DCTL_CONNECT Connect;
3371 int rc = SSMR3GetU32(pSSM, &u32);
3372 AssertRCReturn(rc, rc);
3373
3374 for (i = 0; i < u32; i++)
3375 {
3376 uint32_t u32ClientID;
3377 Connect.Hdr.u32Type = VBOXCMDVBVA3DCTL_TYPE_CONNECT;
3378 Connect.Hdr.u32CmdClientId = 0;
3379
3380 rc = SSMR3GetU32(pSSM, &u32ClientID);
3381 AssertRCReturn(rc, rc);
3382 rc = SSMR3GetU32(pSSM, &Connect.u32MajorVersion);
3383 AssertRCReturn(rc, rc);
3384 rc = SSMR3GetU32(pSSM, &Connect.u32MinorVersion);
3385 AssertRCReturn(rc, rc);
3386 rc = SSMR3GetU64(pSSM, &Connect.u64Pid);
3387 AssertRCReturn(rc, rc);
3388
3389 rc = crVBoxCrConnectEx(&Connect, u32ClientID);
3390 AssertRCReturn(rc, rc);
3391 }
3392
3393 return VINF_SUCCESS;
3394}
3395
3396static DECLCALLBACK(int) crVBoxCrCmdSaveState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM)
3397{
3398 int rc = VINF_SUCCESS;
3399
3400 Assert(cr_server.fCrCmdEnabled);
3401
3402 /* Start*/
3403 rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
3404 AssertRCReturn(rc, rc);
3405
3406 if (!cr_server.numClients)
3407 {
3408 rc = SSMR3PutU32(pSSM, 0);
3409 AssertRCReturn(rc, rc);
3410
3411 rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
3412 AssertRCReturn(rc, rc);
3413
3414 return VINF_SUCCESS;
3415 }
3416
3417 rc = SSMR3PutU32(pSSM, 1);
3418 AssertRCReturn(rc, rc);
3419
3420 /* Version */
3421 rc = SSMR3PutU32(pSSM, (uint32_t) SHCROGL_SSM_VERSION);
3422 AssertRCReturn(rc, rc);
3423
3424 rc = crVBoxCrCmdSaveClients(pSSM);
3425 AssertRCReturn(rc, rc);
3426
3427 /* The state itself */
3428 rc = crVBoxServerSaveStatePerform(pSSM);
3429 AssertRCReturn(rc, rc);
3430
3431 /* Save svc buffers info */
3432 {
3433 rc = SSMR3PutU32(pSSM, 0);
3434 AssertRCReturn(rc, rc);
3435
3436 rc = SSMR3PutU32(pSSM, 0);
3437 AssertRCReturn(rc, rc);
3438 }
3439
3440 /* End */
3441 rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
3442 AssertRCReturn(rc, rc);
3443
3444 return VINF_SUCCESS;
3445}
3446
3447static DECLCALLBACK(int) crVBoxCrCmdLoadState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM, uint32_t u32Version)
3448{
3449 int rc = VINF_SUCCESS;
3450
3451 char psz[2000];
3452 uint32_t ui32;
3453
3454 Assert(cr_server.fCrCmdEnabled);
3455
3456 /* Start of data */
3457 rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL);
3458 AssertRCReturn(rc, rc);
3459 if (strcmp(gszVBoxOGLSSMMagic, psz))
3460 {
3461 WARN(("unexpected data"));
3462 return VERR_SSM_UNEXPECTED_DATA;
3463 }
3464
3465 /* num clients */
3466 rc = SSMR3GetU32(pSSM, &ui32);
3467 AssertRCReturn(rc, rc);
3468
3469 if (!ui32)
3470 {
3471 /* no clients, dummy stub */
3472 rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL);
3473 AssertRCReturn(rc, rc);
3474 if (strcmp(gszVBoxOGLSSMMagic, psz))
3475 {
3476 WARN(("unexpected data"));
3477 return VERR_SSM_UNEXPECTED_DATA;
3478 }
3479
3480 return VINF_SUCCESS;
3481 }
3482 if (ui32 != 1)
3483 {
3484 WARN(("invalid id"));
3485 return VERR_SSM_UNEXPECTED_DATA;
3486 }
3487
3488 /* Version */
3489 rc = SSMR3GetU32(pSSM, &ui32);
3490 AssertRCReturn(rc, rc);
3491
3492 if (ui32 < SHCROGL_SSM_VERSION_CRCMD)
3493 {
3494 WARN(("unexpected version"));
3495 return VERR_SSM_UNEXPECTED_DATA;
3496 }
3497
3498 rc = crVBoxCrCmdLoadClients(pSSM, u32Version);
3499 AssertRCReturn(rc, rc);
3500
3501 /* The state itself */
3502 rc = crVBoxServerLoadStatePerform(pSSM, ui32);
3503 AssertRCReturn(rc, rc);
3504
3505 /* Save svc buffers info */
3506 {
3507 rc = SSMR3GetU32(pSSM, &ui32);
3508 AssertRCReturn(rc, rc);
3509
3510 if (ui32)
3511 {
3512 WARN(("unexpected data1"));
3513 return VERR_SSM_UNEXPECTED_DATA;
3514 }
3515
3516 rc = SSMR3GetU32(pSSM, &ui32);
3517 AssertRCReturn(rc, rc);
3518
3519 if (ui32)
3520 {
3521 WARN(("unexpected data1"));
3522 return VERR_SSM_UNEXPECTED_DATA;
3523 }
3524 }
3525
3526 /* End */
3527 rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL);
3528 AssertRCReturn(rc, rc);
3529 if (strcmp(gszVBoxOGLSSMMagic, psz))
3530 {
3531 WARN(("unexpected data"));
3532 return VERR_SSM_UNEXPECTED_DATA;
3533 }
3534
3535 return VINF_SUCCESS;
3536}
3537
3538
3539static DECLCALLBACK(int8_t) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, const VBOXCMDVBVA_HDR *pCmd, uint32_t cbCmd)
3540{
3541 switch (pCmd->u8OpCode)
3542 {
3543 case VBOXCMDVBVA_OPTYPE_CRCMD:
3544 {
3545 const VBOXCMDVBVA_CRCMD *pCrCmdDr;
3546 const VBOXCMDVBVA_CRCMD_CMD *pCrCmd;
3547 int rc;
3548 pCrCmdDr = (const VBOXCMDVBVA_CRCMD*)pCmd;
3549 pCrCmd = &pCrCmdDr->Cmd;
3550 if (cbCmd < sizeof (VBOXCMDVBVA_CRCMD))
3551 {
3552 WARN(("invalid buffer size"));
3553 return -1;
3554 }
3555 rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd, cbCmd - RT_OFFSETOF(VBOXCMDVBVA_CRCMD, Cmd));
3556 if (RT_SUCCESS(rc))
3557 {
3558 /* success */
3559 return 0;
3560 }
3561
3562 WARN(("crVBoxServerCmdVbvaCrCmdProcess failed, rc %d", rc));
3563 return -1;
3564 }
3565 case VBOXCMDVBVA_OPTYPE_FLIP:
3566 {
3567 const VBOXCMDVBVA_FLIP *pFlip;
3568
3569 if (cbCmd < sizeof (VBOXCMDVBVA_FLIP))
3570 {
3571 WARN(("invalid buffer size"));
3572 return -1;
3573 }
3574
3575 pFlip = (const VBOXCMDVBVA_FLIP*)pCmd;
3576 return crVBoxServerCrCmdFlipProcess(pFlip);
3577 }
3578 case VBOXCMDVBVA_OPTYPE_BLT:
3579 {
3580 if (cbCmd < sizeof (VBOXCMDVBVA_BLT_HDR))
3581 {
3582 WARN(("invalid buffer size"));
3583 return -1;
3584 }
3585
3586 return crVBoxServerCrCmdBltProcess((const VBOXCMDVBVA_BLT_HDR*)pCmd, cbCmd);
3587 }
3588 case VBOXCMDVBVA_OPTYPE_CLRFILL:
3589 {
3590 if (cbCmd < sizeof (VBOXCMDVBVA_CLRFILL_HDR))
3591 {
3592 WARN(("invalid buffer size"));
3593 return -1;
3594 }
3595
3596 return crVBoxServerCrCmdClrFillProcess((const VBOXCMDVBVA_CLRFILL_HDR*)pCmd, cbCmd);
3597 }
3598 default:
3599 WARN(("unsupported command"));
3600 return -1;
3601 }
3602
3603 WARN(("internal error"));
3604 return -1;
3605}
3606
3607/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
3608 *
3609 * 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.
3610 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
3611 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
3612 * to block the lower-priority thread trying to complete the blocking command.
3613 * And removed extra memcpy done on blocked command arrival.
3614 *
3615 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
3616 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
3617 *
3618 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
3619 * */
3620
3621
3622int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
3623{
3624
3625 int32_t rc;
3626 uint32_t cBuffers = pCmd->cBuffers;
3627 uint32_t cParams;
3628 uint32_t cbHdr;
3629 CRVBOXHGSMIHDR *pHdr;
3630 uint32_t u32Function;
3631 uint32_t u32ClientID;
3632 CRClient *pClient;
3633
3634 if (!g_pvVRamBase)
3635 {
3636 WARN(("g_pvVRamBase is not initialized"));
3637
3638 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
3639 return VINF_SUCCESS;
3640 }
3641
3642 if (!cBuffers)
3643 {
3644 WARN(("zero buffers passed in!"));
3645
3646 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3647 return VINF_SUCCESS;
3648 }
3649
3650 cParams = cBuffers-1;
3651
3652 cbHdr = pCmd->aBuffers[0].cbBuffer;
3653 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
3654 if (!pHdr)
3655 {
3656 WARN(("invalid header buffer!"));
3657
3658 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3659 return VINF_SUCCESS;
3660 }
3661
3662 if (cbHdr < sizeof (*pHdr))
3663 {
3664 WARN(("invalid header buffer size!"));
3665
3666 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3667 return VINF_SUCCESS;
3668 }
3669
3670 u32Function = pHdr->u32Function;
3671 u32ClientID = pHdr->u32ClientID;
3672
3673 switch (u32Function)
3674 {
3675 case SHCRGL_GUEST_FN_WRITE:
3676 {
3677 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
3678
3679 /* @todo: Verify */
3680 if (cParams == 1)
3681 {
3682 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
3683 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3684 /* Fetch parameters. */
3685 uint32_t cbBuffer = pBuf->cbBuffer;
3686 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3687
3688 if (cbHdr < sizeof (*pFnCmd))
3689 {
3690 crWarning("invalid write cmd buffer size!");
3691 rc = VERR_INVALID_PARAMETER;
3692 break;
3693 }
3694
3695 CRASSERT(cbBuffer);
3696 if (!pBuffer)
3697 {
3698 crWarning("invalid buffer data received from guest!");
3699 rc = VERR_INVALID_PARAMETER;
3700 break;
3701 }
3702
3703 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3704 if (RT_FAILURE(rc))
3705 {
3706 break;
3707 }
3708
3709 /* This should never fire unless we start to multithread */
3710 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3711 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3712
3713 pClient->conn->pBuffer = pBuffer;
3714 pClient->conn->cbBuffer = cbBuffer;
3715 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3716 crVBoxServerInternalClientWriteRead(pClient);
3717 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3718 return VINF_SUCCESS;
3719 }
3720 else
3721 {
3722 crWarning("invalid number of args");
3723 rc = VERR_INVALID_PARAMETER;
3724 break;
3725 }
3726 break;
3727 }
3728
3729 case SHCRGL_GUEST_FN_INJECT:
3730 {
3731 Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
3732
3733 /* @todo: Verify */
3734 if (cParams == 1)
3735 {
3736 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
3737 /* Fetch parameters. */
3738 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
3739 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3740 uint32_t cbBuffer = pBuf->cbBuffer;
3741 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3742
3743 if (cbHdr < sizeof (*pFnCmd))
3744 {
3745 crWarning("invalid inject cmd buffer size!");
3746 rc = VERR_INVALID_PARAMETER;
3747 break;
3748 }
3749
3750 CRASSERT(cbBuffer);
3751 if (!pBuffer)
3752 {
3753 crWarning("invalid buffer data received from guest!");
3754 rc = VERR_INVALID_PARAMETER;
3755 break;
3756 }
3757
3758 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3759 if (RT_FAILURE(rc))
3760 {
3761 break;
3762 }
3763
3764 /* This should never fire unless we start to multithread */
3765 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3766 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3767
3768 pClient->conn->pBuffer = pBuffer;
3769 pClient->conn->cbBuffer = cbBuffer;
3770 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3771 crVBoxServerInternalClientWriteRead(pClient);
3772 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3773 return VINF_SUCCESS;
3774 }
3775
3776 crWarning("invalid number of args");
3777 rc = VERR_INVALID_PARAMETER;
3778 break;
3779 }
3780
3781 case SHCRGL_GUEST_FN_READ:
3782 {
3783 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3784
3785 /* @todo: Verify */
3786 if (cParams == 1)
3787 {
3788 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3789 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3790 /* Fetch parameters. */
3791 uint32_t cbBuffer = pBuf->cbBuffer;
3792 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3793
3794 if (cbHdr < sizeof (*pFnCmd))
3795 {
3796 crWarning("invalid read cmd buffer size!");
3797 rc = VERR_INVALID_PARAMETER;
3798 break;
3799 }
3800
3801
3802 if (!pBuffer)
3803 {
3804 crWarning("invalid buffer data received from guest!");
3805 rc = VERR_INVALID_PARAMETER;
3806 break;
3807 }
3808
3809 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3810 if (RT_FAILURE(rc))
3811 {
3812 break;
3813 }
3814
3815 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3816
3817 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3818
3819 /* Return the required buffer size always */
3820 pFnCmd->cbBuffer = cbBuffer;
3821
3822 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3823
3824 /* the read command is never pended, complete it right away */
3825 pHdr->result = rc;
3826
3827 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3828 return VINF_SUCCESS;
3829 }
3830
3831 crWarning("invalid number of args");
3832 rc = VERR_INVALID_PARAMETER;
3833 break;
3834 }
3835
3836 case SHCRGL_GUEST_FN_WRITE_READ:
3837 {
3838 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3839
3840 /* @todo: Verify */
3841 if (cParams == 2)
3842 {
3843 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3844 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3845 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3846
3847 /* Fetch parameters. */
3848 uint32_t cbBuffer = pBuf->cbBuffer;
3849 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3850
3851 uint32_t cbWriteback = pWbBuf->cbBuffer;
3852 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3853
3854 if (cbHdr < sizeof (*pFnCmd))
3855 {
3856 crWarning("invalid write_read cmd buffer size!");
3857 rc = VERR_INVALID_PARAMETER;
3858 break;
3859 }
3860
3861
3862 CRASSERT(cbBuffer);
3863 if (!pBuffer)
3864 {
3865 crWarning("invalid write buffer data received from guest!");
3866 rc = VERR_INVALID_PARAMETER;
3867 break;
3868 }
3869
3870 CRASSERT(cbWriteback);
3871 if (!pWriteback)
3872 {
3873 crWarning("invalid writeback buffer data received from guest!");
3874 rc = VERR_INVALID_PARAMETER;
3875 break;
3876 }
3877 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3878 if (RT_FAILURE(rc))
3879 {
3880 pHdr->result = rc;
3881 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3882 return rc;
3883 }
3884
3885 /* This should never fire unless we start to multithread */
3886 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3887 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3888
3889 pClient->conn->pBuffer = pBuffer;
3890 pClient->conn->cbBuffer = cbBuffer;
3891 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, true);
3892 crVBoxServerInternalClientWriteRead(pClient);
3893 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3894 return VINF_SUCCESS;
3895 }
3896
3897 crWarning("invalid number of args");
3898 rc = VERR_INVALID_PARAMETER;
3899 break;
3900 }
3901
3902 case SHCRGL_GUEST_FN_SET_VERSION:
3903 {
3904 WARN(("crVBoxServerCrHgsmiCmd, SHCRGL_GUEST_FN_SET_VERSION: invalid function"));
3905 rc = VERR_NOT_IMPLEMENTED;
3906 break;
3907 }
3908
3909 case SHCRGL_GUEST_FN_SET_PID:
3910 {
3911 WARN(("crVBoxServerCrHgsmiCmd, SHCRGL_GUEST_FN_SET_PID: invalid function"));
3912 rc = VERR_NOT_IMPLEMENTED;
3913 break;
3914 }
3915
3916 default:
3917 {
3918 WARN(("crVBoxServerCrHgsmiCmd: invalid functionm %d", u32Function));
3919 rc = VERR_NOT_IMPLEMENTED;
3920 break;
3921 }
3922
3923 }
3924
3925 /* we can be on fail only here */
3926 CRASSERT(RT_FAILURE(rc));
3927 pHdr->result = rc;
3928
3929 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3930 return rc;
3931
3932}
3933
3934
3935static DECLCALLBACK(bool) crVBoxServerHasDataForScreen(uint32_t u32ScreenID)
3936{
3937 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabledForScreen(u32ScreenID);
3938 if (hFb)
3939 return CrFbHas3DData(hFb);
3940
3941 return false;
3942}
3943
3944
3945static DECLCALLBACK(bool) crVBoxServerHasData()
3946{
3947 HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
3948 for (;
3949 hFb;
3950 hFb = CrPMgrFbGetNextEnabled(hFb))
3951 {
3952 if (CrFbHas3DData(hFb))
3953 return true;
3954 }
3955
3956 return false;
3957}
3958
3959int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
3960{
3961 int rc = VINF_SUCCESS;
3962
3963 switch (pCtl->enmType)
3964 {
3965 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
3966 {
3967 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
3968 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
3969 g_cbVRam = pSetup->cbVRam;
3970
3971 g_pLed = pSetup->pLed;
3972
3973 cr_server.ClientInfo = pSetup->CrClientInfo;
3974
3975 pSetup->CrCmdServerInfo.hSvr = NULL;
3976 pSetup->CrCmdServerInfo.pfnEnable = crVBoxCrCmdEnable;
3977 pSetup->CrCmdServerInfo.pfnDisable = crVBoxCrCmdDisable;
3978 pSetup->CrCmdServerInfo.pfnCmd = crVBoxCrCmdCmd;
3979 pSetup->CrCmdServerInfo.pfnHostCtl = crVBoxCrCmdHostCtl;
3980 pSetup->CrCmdServerInfo.pfnGuestCtl = crVBoxCrCmdGuestCtl;
3981 pSetup->CrCmdServerInfo.pfnResize = crVBoxCrCmdResize;
3982 pSetup->CrCmdServerInfo.pfnSaveState = crVBoxCrCmdSaveState;
3983 pSetup->CrCmdServerInfo.pfnLoadState = crVBoxCrCmdLoadState;
3984 rc = VINF_SUCCESS;
3985 break;
3986 }
3987 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
3988 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
3989 rc = VINF_SUCCESS;
3990 break;
3991 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB:
3992 {
3993 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB)pCtl;
3994 g_hCrHgsmiCompletion = pSetup->hCompletion;
3995 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
3996
3997 pSetup->MainInterface.pfnHasData = crVBoxServerHasData;
3998 pSetup->MainInterface.pfnHasDataForScreen = crVBoxServerHasDataForScreen;
3999
4000 rc = VINF_SUCCESS;
4001 break;
4002 }
4003 default:
4004 AssertMsgFailed(("invalid param %d", pCtl->enmType));
4005 rc = VERR_INVALID_PARAMETER;
4006 }
4007
4008 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
4009 * to complete them accordingly.
4010 * This approach allows using host->host and host->guest commands in the same way here
4011 * making the command completion to be the responsibility of the command originator.
4012 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
4013 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
4014 return rc;
4015}
4016
4017static int crVBoxServerCrCmdDisablePostProcess(VBOXCRCMDCTL_HGCMENABLE_DATA *pData)
4018{
4019 int rc = VINF_SUCCESS;
4020 uint8_t* pCtl;
4021 uint32_t cbCtl;
4022 HVBOXCRCMDCTL_REMAINING_HOST_COMMAND hRHCmd = pData->hRHCmd;
4023 PFNVBOXCRCMDCTL_REMAINING_HOST_COMMAND pfnRHCmd = pData->pfnRHCmd;
4024
4025 Assert(!cr_server.fCrCmdEnabled);
4026
4027 if (cr_server.numClients)
4028 {
4029 WARN(("cr_server.numClients(%d) is not NULL", cr_server.numClients));
4030 return VERR_INVALID_STATE;
4031 }
4032
4033 for (pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc); pCtl; pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc))
4034 {
4035 rc = crVBoxCrCmdHostCtl(NULL, pCtl, cbCtl);
4036 }
4037
4038 memset(&cr_server.DisableData, 0, sizeof (cr_server.DisableData));
4039
4040 return VINF_SUCCESS;
4041}
4042
4043int32_t crVBoxServerHgcmEnable(VBOXCRCMDCTL_HGCMENABLE_DATA *pData)
4044{
4045 int rc = crVBoxServerCrCmdDisablePostProcess(pData);
4046 if (RT_FAILURE(rc))
4047 {
4048 WARN(("crVBoxServerCrCmdDisablePostProcess failed %d", rc));
4049 return rc;
4050 }
4051
4052 crVBoxServerDefaultContextSet();
4053
4054 return VINF_SUCCESS;
4055}
4056
4057int32_t crVBoxServerHgcmDisable(VBOXCRCMDCTL_HGCMDISABLE_DATA *pData)
4058{
4059 Assert(!cr_server.fCrCmdEnabled);
4060
4061 Assert(!cr_server.numClients);
4062
4063 crVBoxServerRemoveAllClients();
4064
4065 CRASSERT(!cr_server.numClients);
4066
4067 crVBoxServerDefaultContextClear();
4068
4069 cr_server.DisableData = *pData;
4070
4071 return VINF_SUCCESS;
4072}
4073
4074#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