VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.cpp@ 78375

Last change on this file since 78375 was 78375, checked in by vboxsync, 6 years ago

Additions/common/crOpengl,GuestHost/OpenGL,HostServices/SharedOpenGL: Eliminate all global variables from the state tracker library (state_tracker) in preparation of the SPU DLL merging, bugref:9435

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

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