VirtualBox

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

Last change on this file since 55762 was 55762, checked in by vboxsync, 10 years ago

Host 3D: DLM: dump local stuff (preparing for saving Display Lists).

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

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