VirtualBox

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

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

DevVGA/crOpenGL: bugfixes, logging

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