VirtualBox

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

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

Some build fixes

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

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