VirtualBox

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

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

DevVGA/crOpenGL: create worker thread when needed only; saved state; bugfixes (to be continued)

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

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