VirtualBox

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

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

3D: WDDM: consider sub-regions on FLIP operation.

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