VirtualBox

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

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

crOpenGL: crcmd enhancements & fixes; osx deadlock fix; temporary disabled crcmd for testing

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