VirtualBox

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

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

crOpenGL: pdm led, some fixes to follow

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

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