VirtualBox

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

最後變更 在這個檔案從55769是 55766,由 vboxsync 提交於 10 年 前

3D: save state: fix accedental SEGFAULT.

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

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