VirtualBox

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

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

crOpenGL: proper support of GetErr being called from display list, better error handling

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