VirtualBox

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

Last change on this file since 51094 was 51094, checked in by vboxsync, 11 years ago

crOpenGL/CrCmd: unload fixes

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

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