VirtualBox

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

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

3D: saving state: fix broken in r100180 SSM versioning.

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