VirtualBox

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

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

Config.kmk,GuestHost\OpenGL,HostServices\SharedOpenGL: Fix a bunch of compiler warnings and enable them again

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