VirtualBox

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

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

3D: saving state: try to make code a little bit more readable/structurized.

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