VirtualBox

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

Last change on this file since 63939 was 62782, checked in by vboxsync, 8 years ago

HostServices,GuestHost: warnings

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette