VirtualBox

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

最後變更 在這個檔案從69301是 66838,由 vboxsync 提交於 8 年 前

sharedogl/server_main: integers must first be cast thru uintptr_t before casting to pointers.

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

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