VirtualBox

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

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

crOpenGL: 1. osx: do everything we can do in the main thread 2. bugfixes

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