VirtualBox

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

最後變更 在這個檔案從56473是 56473,由 vboxsync 提交於 9 年 前

Host 3D: extend SPU structure with interface for save/restore internal SPU state; provide plug for Expando SPU saving state; drop unused and confusing stuff from DLM module.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 124.0 KB
 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "server.h"
8#include "cr_net.h"
9#include "cr_unpack.h"
10#include "cr_error.h"
11#include "cr_glstate.h"
12#include "cr_string.h"
13#include "cr_mem.h"
14#include "cr_hash.h"
15#include "cr_vreg.h"
16#include "cr_environment.h"
17#include "cr_pixeldata.h"
18
19#ifdef VBOX_WITH_CR_DISPLAY_LISTS
20# include "cr_dlm.h"
21#endif
22
23#include "server_dispatch.h"
24#include "state/cr_texture.h"
25#include "render/renderspu.h"
26#include <signal.h>
27#include <stdlib.h>
28#define DEBUG_FP_EXCEPTIONS 0
29#if DEBUG_FP_EXCEPTIONS
30#include <fpu_control.h>
31#include <math.h>
32#endif
33#include <iprt/assert.h>
34#include <VBox/err.h>
35#include <VBox/log.h>
36
37#ifdef VBOXCR_LOGFPS
38#include <iprt/timer.h>
39#endif
40
41#ifdef VBOX_WITH_CRHGSMI
42# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
43uint8_t* g_pvVRamBase = NULL;
44uint32_t g_cbVRam = 0;
45PPDMLED g_pLed = NULL;
46
47HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion = NULL;
48PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion = NULL;
49#endif
50
51/**
52 * \mainpage CrServerLib
53 *
54 * \section CrServerLibIntroduction Introduction
55 *
56 * Chromium consists of all the top-level files in the cr
57 * directory. The core module basically takes care of API dispatch,
58 * and OpenGL state management.
59 */
60
61
62/**
63 * CRServer global data
64 */
65CRServer cr_server;
66
67int tearingdown = 0; /* can't be static */
68
69static DECLCALLBACK(int8_t) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, const VBOXCMDVBVA_HDR *pCmd, uint32_t cbCmd);
70
71DECLINLINE(CRClient*) crVBoxServerClientById(uint32_t u32ClientID)
72{
73 int32_t i;
74
75 if (cr_server.fCrCmdEnabled)
76 return CrHTableGet(&cr_server.clientTable, u32ClientID);
77
78 for (i = 0; i < cr_server.numClients; i++)
79 {
80 if (cr_server.clients[i] && cr_server.clients[i]->conn
81 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
82 {
83 return cr_server.clients[i];
84 }
85 }
86
87 return NULL;
88}
89
90int32_t crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
91{
92 CRClient *pClient = NULL;
93
94 pClient = crVBoxServerClientById(u32ClientID);
95
96 if (!pClient)
97 {
98 WARN(("client not found!"));
99 *ppClient = NULL;
100 return VERR_INVALID_PARAMETER;
101 }
102
103 if (!pClient->conn->vMajor)
104 {
105 WARN(("no major version specified for client!"));
106 *ppClient = NULL;
107 return VERR_NOT_SUPPORTED;
108 }
109
110 *ppClient = pClient;
111
112 return VINF_SUCCESS;
113}
114
115
116/**
117 * Return pointer to server's first SPU.
118 */
119SPU*
120crServerHeadSPU(void)
121{
122 return cr_server.head_spu;
123}
124
125
126
127static void DeleteBarrierCallback( void *data )
128{
129 CRServerBarrier *barrier = (CRServerBarrier *) data;
130 crFree(barrier->waiting);
131 crFree(barrier);
132}
133
134
135static void deleteContextInfoCallback( void *data )
136{
137 CRContextInfo *c = (CRContextInfo *) data;
138 crStateDestroyContext(c->pContext);
139 if (c->CreateInfo.pszDpyName)
140 crFree(c->CreateInfo.pszDpyName);
141 crFree(c);
142}
143
144static void deleteMuralInfoCallback( void *data )
145{
146 CRMuralInfo *m = (CRMuralInfo *) data;
147 if (m->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID) /* <- do not do term for default mural as it does not contain any info to be freed,
148 * and renderspu will destroy it up itself*/
149 {
150 crServerMuralTerm(m);
151 }
152 crFree(m);
153}
154
155static int crVBoxServerCrCmdDisablePostProcess(VBOXCRCMDCTL_HGCMENABLE_DATA *pData);
156
157static void crServerTearDown( void )
158{
159 GLint i;
160 CRClientNode *pNode, *pNext;
161 GLboolean fOldEnableDiff;
162 GLboolean fContextsDeleted = GL_FALSE;
163
164 /* avoid a race condition */
165 if (tearingdown)
166 return;
167
168 tearingdown = 1;
169
170 if (cr_server.fCrCmdEnabled)
171 {
172 VBOXCRCMDCTL_HGCMENABLE_DATA EnableData;
173 /* crVBoxServerHgcmEnable will erase the DisableData, preserve it here */
174 VBOXCRCMDCTL_HGCMDISABLE_DATA DisableData = cr_server.DisableData;
175 int rc;
176
177 CRASSERT(DisableData.pfnNotifyTerm);
178 rc = DisableData.pfnNotifyTerm(DisableData.hNotifyTerm, &EnableData);
179 if (!RT_SUCCESS(rc))
180 {
181 WARN(("pfnNotifyTerm failed %d", rc));
182 return;
183 }
184
185 crVBoxServerCrCmdDisablePostProcess(&EnableData);
186 fContextsDeleted = GL_TRUE;
187
188 CRASSERT(DisableData.pfnNotifyTermDone);
189 DisableData.pfnNotifyTermDone(DisableData.hNotifyTerm);
190
191 Assert(!cr_server.fCrCmdEnabled);
192 }
193
194 crStateSetCurrent( NULL );
195
196 cr_server.curClient = NULL;
197 cr_server.run_queue = NULL;
198
199 crFree( cr_server.overlap_intens );
200 cr_server.overlap_intens = NULL;
201
202 /* needed to make sure window dummy mural not get created on mural destruction
203 * and generally this should be zeroed up */
204 cr_server.currentCtxInfo = NULL;
205 cr_server.currentWindow = -1;
206 cr_server.currentNativeWindow = 0;
207 cr_server.currentMural = NULL;
208
209 if (!fContextsDeleted)
210 {
211#ifndef VBOX_WITH_CR_DISPLAY_LISTS
212 /* sync our state with renderspu,
213 * do it before mural & context deletion to avoid deleting currently set murals/contexts*/
214 cr_server.head_spu->dispatch_table.MakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID);
215#endif
216 }
217
218 /* Deallocate all semaphores */
219 crFreeHashtable(cr_server.semaphores, crFree);
220 cr_server.semaphores = NULL;
221
222 /* Deallocate all barriers */
223 crFreeHashtable(cr_server.barriers, DeleteBarrierCallback);
224 cr_server.barriers = NULL;
225
226 /* 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 crVBoxAddFBDataElement(CRFBData *pData, GLint idFBO, GLenum enmBuffer, GLint width, GLint height, GLenum enmFormat, GLenum enmType)
1223{
1224 CRFBDataElement *pEl;
1225
1226 AssertCompile(sizeof (GLfloat) == 4);
1227 AssertCompile(sizeof (GLuint) == 4);
1228
1229 pEl = &pData->aElements[pData->cElements];
1230 pEl->idFBO = idFBO;
1231 pEl->enmBuffer = enmBuffer;
1232 pEl->posX = 0;
1233 pEl->posY = 0;
1234 pEl->width = width;
1235 pEl->height = height;
1236 pEl->enmFormat = enmFormat;
1237 pEl->enmType = enmType;
1238 pEl->cbData = width * height * 4;
1239
1240 pEl->pvData = crCalloc(pEl->cbData);
1241 if (!pEl->pvData)
1242 {
1243 crVBoxServerFBImageDataTerm(pData);
1244 crWarning(": crCalloc failed");
1245 return VERR_NO_MEMORY;
1246 }
1247
1248 ++pData->cElements;
1249
1250 return VINF_SUCCESS;
1251}
1252
1253/* Add framebuffer image elements arrording to SSM version. Please refer to cr_version.h
1254 * in order to distinguish between versions. */
1255static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, uint32_t version, GLuint overrideWidth, GLuint overrideHeight)
1256{
1257 CRContext *pContext;
1258 GLuint i;
1259 GLfloat *pF;
1260 GLuint width;
1261 GLuint height;
1262 int rc;
1263
1264 crMemset(pData, 0, sizeof (*pData));
1265
1266 pContext = pCtxInfo->pContext;
1267
1268 /* the version should be always actual when we do reads,
1269 * i.e. it could differ on writes when snapshot is getting loaded */
1270 CRASSERT(fWrite || version == SHCROGL_SSM_VERSION);
1271
1272 width = overrideWidth ? overrideWidth : pMural->width;
1273 height = overrideHeight ? overrideHeight : pMural->height;
1274
1275 if (!width || !height)
1276 return VINF_SUCCESS;
1277
1278 if (pMural)
1279 {
1280 if (fWrite)
1281 {
1282 if (!pContext->framebufferobject.drawFB)
1283 pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurDrawBuffer);
1284 }
1285 else
1286 {
1287 if (!pContext->framebufferobject.readFB)
1288 pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurReadBuffer);
1289 }
1290 }
1291
1292 pData->u32Version = version;
1293
1294 pData->cElements = 0;
1295
1296 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1297 pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT, width, height, GL_RGBA, GL_UNSIGNED_BYTE);
1298 AssertReturn(rc == VINF_SUCCESS, rc);
1299
1300 /* There is a lot of code that assumes we have double buffering, just assert here to print a warning in the log
1301 * so that we know that something irregular is going on. */
1302 CRASSERT(pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT);
1303
1304 if (( pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT)
1305 || version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL) /* <- Older version had a typo which lead to back always being used,
1306 * no matter what the visual bits are. */
1307 {
1308 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0,
1309 pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK, width, height, GL_RGBA, GL_UNSIGNED_BYTE);
1310 AssertReturn(rc == VINF_SUCCESS, rc);
1311 }
1312
1313 if (version < SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1314 return VINF_SUCCESS;
1315
1316 if (version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL)
1317 {
1318 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1319 pMural ? pMural->idDepthStencilRB : 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
1320 AssertReturn(rc == VINF_SUCCESS, rc);
1321
1322 /* Init to default depth value, just in case. "pData->cElements - 1" because we incremented counter in crVBoxAddFBDataElement(). */
1323 pF = (GLfloat*)pData->aElements[pData->cElements - 1].pvData;
1324 for (i = 0; i < width * height; ++i)
1325 pF[i] = 1.;
1326
1327 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1328 pMural ? pMural->idDepthStencilRB : 0, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_INT);
1329 AssertReturn(rc == VINF_SUCCESS, rc);
1330
1331 return VINF_SUCCESS;
1332 }
1333
1334 if (version < SHCROGL_SSM_VERSION_WITH_SEPARATE_DEPTH_STENCIL_BUFFERS)
1335 {
1336 /* Use GL_DEPTH_STENCIL only in case if both CR_STENCIL_BIT and CR_DEPTH_BIT specified. */
1337 if ( (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT)
1338 && (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT))
1339 {
1340 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0, 0,
1341 width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
1342 AssertReturn(rc == VINF_SUCCESS, rc);
1343 }
1344
1345 return VINF_SUCCESS;
1346 }
1347
1348 /* Current SSM verion (SHCROGL_SSM_VERSION_WITH_SEPARATE_DEPTH_STENCIL_BUFFERS). */
1349
1350 if (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT)
1351 {
1352 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1353 pMural ? pMural->idDepthStencilRB : 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
1354 AssertReturn(rc == VINF_SUCCESS, rc);
1355
1356 /* Init to default depth value, just in case. "pData->cElements - 1" because we incremented counter in crVBoxAddFBDataElement(). */
1357 pF = (GLfloat*)pData->aElements[pData->cElements - 1].pvData;
1358 for (i = 0; i < width * height; ++i)
1359 pF[i] = 1.;
1360 }
1361
1362 if (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT)
1363 {
1364 rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
1365 pMural ? pMural->idDepthStencilRB : 0, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_INT);
1366 AssertReturn(rc == VINF_SUCCESS, rc);
1367 }
1368
1369 return VINF_SUCCESS;
1370}
1371
1372static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
1373{
1374 CRContextInfo *pCtxInfo;
1375 CRContext *pContext;
1376 CRMuralInfo *pMural;
1377 int32_t rc;
1378 GLuint i;
1379 struct
1380 {
1381 CRFBData data;
1382 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1383 } Data;
1384
1385 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1386
1387 pCtxInfo = cr_server.currentCtxInfo;
1388 pContext = pCtxInfo->pContext;
1389 pMural = pCtxInfo->currentMural;
1390
1391 rc = crVBoxServerFBImageDataInitEx(&Data.data, pCtxInfo, pMural, GL_FALSE, SHCROGL_SSM_VERSION, 0, 0);
1392 if (!RT_SUCCESS(rc))
1393 {
1394 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1395 return rc;
1396 }
1397
1398 rc = crStateAcquireFBImage(pContext, &Data.data);
1399 AssertRCReturn(rc, rc);
1400
1401 for (i = 0; i < Data.data.cElements; ++i)
1402 {
1403 CRFBDataElement * pEl = &Data.data.aElements[i];
1404 rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
1405 AssertRCReturn(rc, rc);
1406 }
1407
1408 crVBoxServerFBImageDataTerm(&Data.data);
1409
1410 return VINF_SUCCESS;
1411}
1412
1413#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
1414 if(!RT_SUCCESS((_rc))) { \
1415 AssertFailed(); \
1416 return; \
1417 } \
1418 } while (0)
1419
1420static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
1421{
1422 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1423 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1424 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1425 PSSMHANDLE pSSM = pData->pSSM;
1426 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1427 CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
1428
1429 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1430
1431 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1432
1433 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1434 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1435
1436 pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
1437 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1438
1439 crServerPerformMakeCurrent(pMural, pContextInfo);
1440
1441 pData->rc = crVBoxServerSaveFBImage(pSSM);
1442
1443 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1444 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1445 pContextInfo->currentMural = pInitialCurMural;
1446
1447 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1448}
1449
1450static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
1451{
1452 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1453 CRContext *pContext = pContextInfo->pContext;
1454 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1455 PSSMHANDLE pSSM = pData->pSSM;
1456 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
1457 CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
1458 const int32_t i32Dummy = 0;
1459
1460 AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
1461 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1462
1463 CRASSERT(pContext && pSSM);
1464 CRASSERT(pMural);
1465 CRASSERT(pMural->CreateInfo.externalID);
1466
1467 /* We could have skipped saving the key and use similar callback to load context states back,
1468 * but there's no guarantee we'd traverse hashtable in same order after loading.
1469 */
1470 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1471 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1472
1473#ifdef DEBUG_misha
1474 {
1475 unsigned long id;
1476 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
1477 crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
1478 else
1479 CRASSERT(id == key);
1480 }
1481#endif
1482
1483#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1484 if (pContextInfo->currentMural
1485 || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
1486 )
1487 {
1488 CRASSERT(pMural->CreateInfo.externalID);
1489 CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1490 pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
1491 }
1492 else
1493 {
1494 /* this is a dummy mural */
1495 CRASSERT(!pMural->width);
1496 CRASSERT(!pMural->height);
1497 CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1498 pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
1499 }
1500 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1501
1502 CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
1503 CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
1504 CRASSERT(cr_server.curClient);
1505
1506 crServerPerformMakeCurrent(pMural, pContextInfo);
1507#endif
1508
1509 pData->rc = crStateSaveContext(pContext, pSSM);
1510 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1511
1512 pData->rc = crVBoxServerSaveFBImage(pSSM);
1513 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1514
1515 /* restore the initial current mural */
1516 pContextInfo->currentMural = pContextCurrentMural;
1517}
1518
1519static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
1520
1521static int32_t crVBoxServerSaveStatePerform(PSSMHANDLE pSSM)
1522{
1523 int32_t rc, i;
1524 uint32_t ui32;
1525 GLboolean b;
1526 unsigned long key;
1527 GLenum err;
1528#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1529 CRClient *curClient;
1530 CRMuralInfo *curMural = NULL;
1531 CRContextInfo *curCtxInfo = NULL;
1532#endif
1533 CRVBOX_SAVE_STATE_GLOBAL Data;
1534
1535 crMemset(&Data, 0, sizeof (Data));
1536
1537#if 0
1538 crVBoxServerCheckConsistency();
1539#endif
1540
1541 /* We shouldn't be called if there's no clients at all*/
1542 CRASSERT(cr_server.numClients > 0);
1543
1544 /* @todo it's hack atm */
1545 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1546 * for every connected client (e.g. guest opengl application)
1547 */
1548 if (!cr_server.bIsInSavingState) /* It's first call */
1549 {
1550 cr_server.bIsInSavingState = GL_TRUE;
1551
1552 /* Store number of clients */
1553 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1554 AssertRCReturn(rc, rc);
1555
1556 /* we get called only once for CrCmd case, so disable the hack */
1557 g_hackVBoxServerSaveLoadCallsLeft = cr_server.fCrCmdEnabled ? 1 : cr_server.numClients;
1558 }
1559
1560 g_hackVBoxServerSaveLoadCallsLeft--;
1561
1562 /* Do nothing until we're being called last time */
1563 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1564 {
1565 return VINF_SUCCESS;
1566 }
1567
1568#ifdef DEBUG_misha
1569#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart"
1570#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop"
1571
1572 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1573 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START);
1574#endif
1575
1576 /* Save rendering contexts creation info */
1577 ui32 = crHashtableNumElements(cr_server.contextTable);
1578 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1579 AssertRCReturn(rc, rc);
1580 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1581
1582#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1583 curClient = cr_server.curClient;
1584 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1585 if (curClient)
1586 {
1587 curCtxInfo = cr_server.curClient->currentCtxInfo;
1588 curMural = cr_server.curClient->currentMural;
1589 }
1590 else if (cr_server.numClients)
1591 {
1592 cr_server.curClient = cr_server.clients[0];
1593 }
1594#endif
1595
1596 /* first save windows info */
1597 /* Save windows creation info */
1598 ui32 = crHashtableNumElements(cr_server.muralTable);
1599 /* There should be default mural always */
1600 CRASSERT(ui32>=1);
1601 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1602 AssertRCReturn(rc, rc);
1603 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1604
1605 /* Save cr_server.muralTable
1606 * @todo we don't need it all, just geometry info actually
1607 */
1608 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1609 AssertRCReturn(rc, rc);
1610 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1611
1612 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1613 crVBoxServerBuildSaveStateGlobal(&Data);
1614
1615 rc = crStateSaveGlobals(pSSM);
1616 AssertRCReturn(rc, rc);
1617
1618 Data.pSSM = pSSM;
1619 /* Save contexts state tracker data */
1620 /* @todo For now just some blind data dumps,
1621 * but I've a feeling those should be saved/restored in a very strict sequence to
1622 * allow diff_api to work correctly.
1623 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1624 */
1625 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1626 AssertRCReturn(Data.rc, Data.rc);
1627
1628 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1629 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1630 AssertRCReturn(rc, rc);
1631
1632 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1633 AssertRCReturn(Data.rc, Data.rc);
1634
1635#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1636 cr_server.curClient = curClient;
1637 /* Restore original win and ctx IDs*/
1638 if (curClient && curMural && curCtxInfo)
1639 {
1640 crServerPerformMakeCurrent(curMural, curCtxInfo);
1641 }
1642 else
1643 {
1644 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1645 }
1646#endif
1647
1648 /* Save clients info */
1649 for (i = 0; i < cr_server.numClients; i++)
1650 {
1651 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1652 {
1653 CRClient *pClient = cr_server.clients[i];
1654
1655 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1656 AssertRCReturn(rc, rc);
1657
1658 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1659 AssertRCReturn(rc, rc);
1660
1661 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1662 AssertRCReturn(rc, rc);
1663
1664 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1665 AssertRCReturn(rc, rc);
1666
1667 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber > 0)
1668 {
1669 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1670 CRASSERT(b);
1671 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1672 AssertRCReturn(rc, rc);
1673 }
1674
1675 if (pClient->currentMural && pClient->currentWindow > 0)
1676 {
1677 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1678 CRASSERT(b);
1679 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1680 AssertRCReturn(rc, rc);
1681 }
1682 }
1683 }
1684
1685#ifdef VBOX_WITH_CR_DISPLAY_LISTS
1686 if (cr_server.head_spu->dispatch_table.spu_save_state)
1687 {
1688 rc = cr_server.head_spu->dispatch_table.spu_save_state("NULL");
1689 AssertRCReturn(rc, rc);
1690 }
1691 else
1692 crDebug("Do not save %s SPU state: no interface exported.", cr_server.head_spu->name);
1693#endif
1694
1695 rc = crServerPendSaveState(pSSM);
1696 AssertRCReturn(rc, rc);
1697
1698 rc = CrPMgrSaveState(pSSM);
1699 AssertRCReturn(rc, rc);
1700
1701 /* all context gl error states should have now be synced with chromium erro states,
1702 * reset the error if any */
1703 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1704 crWarning("crServer: glGetError %d after saving snapshot", err);
1705
1706 cr_server.bIsInSavingState = GL_FALSE;
1707
1708#ifdef DEBUG_misha
1709 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1710 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
1711#endif
1712
1713 return VINF_SUCCESS;
1714}
1715
1716DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
1717{
1718 if (cr_server.fCrCmdEnabled)
1719 {
1720 WARN(("we should not be called with cmd enabled!"));
1721 return VERR_INTERNAL_ERROR;
1722 }
1723
1724 return crVBoxServerSaveStatePerform(pSSM);
1725}
1726
1727static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1728{
1729 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1730 CRASSERT(pContextInfo);
1731 CRASSERT(pContextInfo->pContext);
1732 return pContextInfo->pContext;
1733}
1734
1735typedef struct CR_SERVER_LOADSTATE_READER
1736{
1737 PSSMHANDLE pSSM;
1738 uint32_t cbBuffer;
1739 uint32_t cbData;
1740 uint32_t offData;
1741 uint8_t *pu8Buffer;
1742} CR_SERVER_LOADSTATE_READER;
1743
1744static void crServerLsrInit(CR_SERVER_LOADSTATE_READER *pReader, PSSMHANDLE pSSM)
1745{
1746 memset(pReader, 0, sizeof (*pReader));
1747 pReader->pSSM = pSSM;
1748}
1749
1750static void crServerLsrTerm(CR_SERVER_LOADSTATE_READER *pReader)
1751{
1752 if (pReader->pu8Buffer)
1753 RTMemFree(pReader->pu8Buffer);
1754
1755 /* sanity */
1756 memset(pReader, 0, sizeof (*pReader));
1757}
1758
1759static int crServerLsrDataGetMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1760{
1761 int rc = VINF_SUCCESS;
1762 uint32_t cbRemaining = cbBuffer;
1763 if (pReader->cbData)
1764 {
1765 uint8_t cbData = RT_MIN(pReader->cbData, cbBuffer);
1766 memcpy(pvBuffer, pReader->pu8Buffer + pReader->offData, cbData);
1767 pReader->cbData -= cbData;
1768 pReader->offData += cbData;
1769
1770 cbRemaining -= cbData;
1771 pvBuffer = ((uint8_t*)pvBuffer) + cbData;
1772 }
1773
1774 if (cbRemaining)
1775 {
1776 rc = SSMR3GetMem(pReader->pSSM, pvBuffer, cbRemaining);
1777 AssertRC(rc);
1778 }
1779
1780 return rc;
1781}
1782
1783static int crServerLsrDataGetU32(CR_SERVER_LOADSTATE_READER *pReader, uint32_t *pu32)
1784{
1785 return crServerLsrDataGetMem(pReader, pu32, sizeof (*pu32));
1786}
1787
1788static int crServerLsrDataPutMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1789{
1790 if (!pReader->cbData && pReader->cbBuffer >= cbBuffer)
1791 {
1792 pReader->offData = 0;
1793 pReader->cbData = cbBuffer;
1794 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1795 }
1796 else if (pReader->offData >= cbBuffer)
1797 {
1798 pReader->offData -= cbBuffer;
1799 pReader->cbData += cbBuffer;
1800 memcpy(pReader->pu8Buffer + pReader->offData, pvBuffer, cbBuffer);
1801 }
1802 else
1803 {
1804 uint8_t *pu8Buffer = pReader->pu8Buffer;
1805
1806 pReader->pu8Buffer = (uint8_t*)RTMemAlloc(cbBuffer + pReader->cbData);
1807 if (!pReader->pu8Buffer)
1808 {
1809 crWarning("failed to allocate mem %d", cbBuffer + pReader->cbData);
1810 return VERR_NO_MEMORY;
1811 }
1812
1813 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1814 if (pu8Buffer)
1815 {
1816 memcpy(pReader->pu8Buffer + cbBuffer, pu8Buffer + pReader->offData, pReader->cbData);
1817 RTMemFree(pu8Buffer);
1818 }
1819 else
1820 {
1821 Assert(!pReader->cbData);
1822 }
1823 pReader->offData = 0;
1824 pReader->cbData += cbBuffer;
1825 }
1826
1827 return VINF_SUCCESS;
1828}
1829
1830/* data to be skipped */
1831
1832typedef struct CR_SERVER_BUGGY_MURAL_DATA_2
1833{
1834 void*ListHead_pNext;
1835 void*ListHead_pPrev;
1836 uint32_t cEntries;
1837} CR_SERVER_BUGGY_MURAL_DATA_2;
1838typedef struct CR_SERVER_BUGGY_MURAL_DATA_1
1839{
1840 /* VBOXVR_COMPOSITOR_ENTRY Ce; */
1841 void*Ce_Node_pNext;
1842 void*Ce_Node_pPrev;
1843 CR_SERVER_BUGGY_MURAL_DATA_2 Vr;
1844 /* VBOXVR_TEXTURE Tex; */
1845 uint32_t Tex_width;
1846 uint32_t Tex_height;
1847 uint32_t Tex_target;
1848 uint32_t Tex_hwid;
1849 /* RTPOINT Pos; */
1850 uint32_t Pos_x;
1851 uint32_t Pos_y;
1852 uint32_t fChanged;
1853 uint32_t cRects;
1854 void* paSrcRects;
1855 void* paDstRects;
1856} CR_SERVER_BUGGY_MURAL_DATA_1;
1857
1858typedef struct CR_SERVER_BUGGY_MURAL_DATA_4
1859{
1860 uint32_t u32Magic;
1861 int32_t cLockers;
1862 RTNATIVETHREAD NativeThreadOwner;
1863 int32_t cNestings;
1864 uint32_t fFlags;
1865 void* EventSem;
1866 R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec;
1867 RTHCPTR Alignment;
1868} CR_SERVER_BUGGY_MURAL_DATA_4;
1869
1870typedef struct CR_SERVER_BUGGY_MURAL_DATA_3
1871{
1872 void*Compositor_List_pNext;
1873 void*Compositor_List_pPrev;
1874 void*Compositor_pfnEntryRemoved;
1875 float StretchX;
1876 float StretchY;
1877 uint32_t cRects;
1878 uint32_t cRectsBuffer;
1879 void*paSrcRects;
1880 void*paDstRects;
1881 CR_SERVER_BUGGY_MURAL_DATA_4 CritSect;
1882} CR_SERVER_BUGGY_MURAL_DATA_3;
1883
1884typedef struct CR_SERVER_BUGGY_MURAL_DATA
1885{
1886 uint8_t fRootVrOn;
1887 CR_SERVER_BUGGY_MURAL_DATA_1 RootVrCEntry;
1888 CR_SERVER_BUGGY_MURAL_DATA_3 RootVrCompositor;
1889} CR_SERVER_BUGGY_MURAL_DATA;
1890
1891AssertCompile(sizeof (CR_SERVER_BUGGY_MURAL_DATA) < sizeof (CRClient));
1892
1893static int32_t crVBoxServerLoadMurals(CR_SERVER_LOADSTATE_READER *pReader, uint32_t version)
1894{
1895 unsigned long key;
1896 uint32_t ui, uiNumElems;
1897 bool fBuggyMuralData = false;
1898 /* Load windows */
1899 int32_t rc = crServerLsrDataGetU32(pReader, &uiNumElems);
1900 AssertRCReturn(rc, rc);
1901 for (ui=0; ui<uiNumElems; ++ui)
1902 {
1903 CRCreateInfo_t createInfo;
1904 char psz[200];
1905 GLint winID;
1906 unsigned long key;
1907
1908 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1909 AssertRCReturn(rc, rc);
1910 rc = crServerLsrDataGetMem(pReader, &createInfo, sizeof(createInfo));
1911 AssertRCReturn(rc, rc);
1912
1913 CRASSERT(!pReader->cbData);
1914
1915 if (createInfo.pszDpyName)
1916 {
1917 rc = SSMR3GetStrZEx(pReader->pSSM, psz, 200, NULL);
1918 AssertRCReturn(rc, rc);
1919 createInfo.pszDpyName = psz;
1920 }
1921
1922 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1923 CRASSERT((int64_t)winID == (int64_t)key);
1924 }
1925
1926 /* Load cr_server.muralTable */
1927 rc = SSMR3GetU32(pReader->pSSM, &uiNumElems);
1928 AssertRCReturn(rc, rc);
1929 for (ui=0; ui<uiNumElems; ++ui)
1930 {
1931 CRMuralInfo muralInfo;
1932 CRMuralInfo *pActualMural = NULL;
1933
1934 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1935 AssertRCReturn(rc, rc);
1936 rc = crServerLsrDataGetMem(pReader, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1937 AssertRCReturn(rc, rc);
1938
1939 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1940 muralInfo.bFbDraw = GL_TRUE;
1941
1942 if (!ui && version == SHCROGL_SSM_VERSION_WITH_BUGGY_MURAL_INFO)
1943 {
1944 /* Lookahead buffer used to determine whether the data erroneously stored root visible regions data */
1945 union
1946 {
1947 void * apv[1];
1948 CR_SERVER_BUGGY_MURAL_DATA Data;
1949 /* need to chak spuWindow, so taking the offset of filed following it*/
1950 uint8_t au8[RT_OFFSETOF(CRMuralInfo, screenId)];
1951 RTRECT aVisRects[sizeof (CR_SERVER_BUGGY_MURAL_DATA) / sizeof (RTRECT)];
1952 } LaBuf;
1953
1954 do {
1955 /* first value is bool (uint8_t) value followed by pointer-size-based alignment.
1956 * the mural memory is zero-initialized initially, so we can be sure the padding is zeroed */
1957 rc = crServerLsrDataGetMem(pReader, &LaBuf, sizeof (LaBuf));
1958 AssertRCReturn(rc, rc);
1959 if (LaBuf.apv[0] != NULL && LaBuf.apv[0] != ((void*)1))
1960 break;
1961
1962 /* check that the pointers are either valid or NULL */
1963 if(LaBuf.Data.RootVrCEntry.Ce_Node_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pNext))
1964 break;
1965 if(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev))
1966 break;
1967 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext))
1968 break;
1969 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev))
1970 break;
1971
1972 /* the entry can can be the only one within the (mural) compositor,
1973 * so its compositor entry node can either contain NULL pNext and pPrev,
1974 * or both of them pointing to compositor's list head */
1975 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext != LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1976 break;
1977
1978 /* can either both or none be NULL */
1979 if (!LaBuf.Data.RootVrCEntry.Ce_Node_pNext != !LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1980 break;
1981
1982 if (!LaBuf.Data.fRootVrOn)
1983 {
1984 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext || LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1985 break;
1986
1987 /* either non-initialized (zeroed) or empty list */
1988 if (LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext != LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
1989 break;
1990
1991 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
1992 break;
1993 }
1994 else
1995 {
1996 /* the entry should be initialized */
1997 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext)
1998 break;
1999 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
2000 break;
2001
2002 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
2003 {
2004 /* entry should be in compositor list*/
2005 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev == NULL)
2006 break;
2007 CRASSERT(LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2008 }
2009 else
2010 {
2011 /* entry should NOT be in compositor list*/
2012 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev != NULL)
2013 break;
2014 CRASSERT(!LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2015 }
2016 }
2017
2018 /* fExpectPtr == true, the valid pointer values should not match possible mural width/height/position */
2019 fBuggyMuralData = true;
2020 break;
2021
2022 } while (0);
2023
2024 rc = crServerLsrDataPutMem(pReader, &LaBuf, sizeof (LaBuf));
2025 AssertRCReturn(rc, rc);
2026 }
2027
2028 if (fBuggyMuralData)
2029 {
2030 CR_SERVER_BUGGY_MURAL_DATA Tmp;
2031 rc = crServerLsrDataGetMem(pReader, &Tmp, sizeof (Tmp));
2032 AssertRCReturn(rc, rc);
2033 }
2034
2035 if (muralInfo.pVisibleRects)
2036 {
2037 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
2038 if (!muralInfo.pVisibleRects)
2039 {
2040 return VERR_NO_MEMORY;
2041 }
2042
2043 rc = crServerLsrDataGetMem(pReader, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
2044 AssertRCReturn(rc, rc);
2045 }
2046
2047 pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);
2048 CRASSERT(pActualMural);
2049
2050 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
2051 {
2052 rc = crServerLsrDataGetMem(pReader, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
2053 CRASSERT(rc == VINF_SUCCESS);
2054 }
2055
2056 /* Restore windows geometry info */
2057 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
2058 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
2059 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
2060 if (muralInfo.bReceivedRects)
2061 {
2062 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
2063 }
2064 crServerDispatchWindowShow(key, muralInfo.bVisible);
2065
2066 if (muralInfo.pVisibleRects)
2067 {
2068 crFree(muralInfo.pVisibleRects);
2069 }
2070 }
2071
2072 CRASSERT(RT_SUCCESS(rc));
2073 return VINF_SUCCESS;
2074}
2075
2076static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
2077 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
2078{
2079 CRContext *pContext = pContextInfo->pContext;
2080 int32_t rc = VINF_SUCCESS;
2081 GLuint i;
2082 /* can apply the data right away */
2083 struct
2084 {
2085 CRFBData data;
2086 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
2087 } Data;
2088
2089 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
2090
2091 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
2092 {
2093 if (!pMural->width || !pMural->height)
2094 return VINF_SUCCESS;
2095
2096 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
2097 if (!RT_SUCCESS(rc))
2098 {
2099 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2100 return rc;
2101 }
2102 }
2103 else
2104 {
2105 GLint storedWidth, storedHeight;
2106
2107 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2108 {
2109 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
2110 CRASSERT(cr_server.currentMural == pMural);
2111 storedWidth = pMural->width;
2112 storedHeight = pMural->height;
2113 }
2114 else
2115 {
2116 storedWidth = pContext->buffer.storedWidth;
2117 storedHeight = pContext->buffer.storedHeight;
2118 }
2119
2120 if (!storedWidth || !storedHeight)
2121 return VINF_SUCCESS;
2122
2123 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
2124 if (!RT_SUCCESS(rc))
2125 {
2126 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2127 return rc;
2128 }
2129 }
2130
2131 CRASSERT(Data.data.cElements);
2132
2133 for (i = 0; i < Data.data.cElements; ++i)
2134 {
2135 CRFBDataElement * pEl = &Data.data.aElements[i];
2136 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
2137 AssertRCReturn(rc, rc);
2138 }
2139
2140 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2141 {
2142 CRBufferState *pBuf = &pContext->buffer;
2143 /* can apply the data right away */
2144 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2145 CRASSERT(cr_server.currentMural);
2146
2147 cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
2148 0,
2149 pContextInfo->SpuContext >= 0
2150 ? pContextInfo->SpuContext
2151 : cr_server.MainContextInfo.SpuContext);
2152 crStateApplyFBImage(pContext, &Data.data);
2153 CRASSERT(!pBuf->pFrontImg);
2154 CRASSERT(!pBuf->pBackImg);
2155 crVBoxServerFBImageDataTerm(&Data.data);
2156
2157 crServerPresentFBO(pMural);
2158
2159 CRASSERT(cr_server.currentMural);
2160 cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
2161 0,
2162 cr_server.currentCtxInfo->SpuContext >= 0
2163 ? cr_server.currentCtxInfo->SpuContext
2164 : cr_server.MainContextInfo.SpuContext);
2165 }
2166 else
2167 {
2168 CRBufferState *pBuf = &pContext->buffer;
2169 CRASSERT(!pBuf->pFrontImg);
2170 CRASSERT(!pBuf->pBackImg);
2171 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
2172
2173 if (Data.data.cElements)
2174 {
2175 CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
2176 if (!RT_SUCCESS(rc))
2177 {
2178 crVBoxServerFBImageDataTerm(&Data.data);
2179 crWarning("crAlloc failed");
2180 return VERR_NO_MEMORY;
2181 }
2182
2183 crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
2184 pBuf->pFrontImg = pLazyData;
2185 }
2186 }
2187
2188 CRASSERT(RT_SUCCESS(rc));
2189 return VINF_SUCCESS;
2190}
2191
2192static int32_t crVBoxServerLoadStatePerform(PSSMHANDLE pSSM, uint32_t version)
2193{
2194 int32_t rc, i;
2195 uint32_t ui, uiNumElems;
2196 unsigned long key;
2197 GLenum err;
2198 CR_SERVER_LOADSTATE_READER Reader;
2199
2200 if (!cr_server.bIsInLoadingState)
2201 {
2202 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
2203 cr_server.bIsInLoadingState = GL_TRUE;
2204
2205 /* Read number of clients */
2206 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
2207 AssertRCReturn(rc, rc);
2208
2209 Assert(g_hackVBoxServerSaveLoadCallsLeft);
2210 /* we get called only once for CrCmd */
2211 if (cr_server.fCrCmdEnabled)
2212 g_hackVBoxServerSaveLoadCallsLeft = 1;
2213 }
2214
2215 g_hackVBoxServerSaveLoadCallsLeft--;
2216
2217 /* Do nothing until we're being called last time */
2218 if (g_hackVBoxServerSaveLoadCallsLeft>0)
2219 {
2220 return VINF_SUCCESS;
2221 }
2222
2223 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
2224 {
2225 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2226 }
2227
2228 crServerLsrInit(&Reader, pSSM);
2229
2230#ifdef DEBUG_misha
2231#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
2232#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
2233
2234 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2235 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
2236#endif
2237
2238 /* Load and recreate rendering contexts */
2239 rc = SSMR3GetU32(pSSM, &uiNumElems);
2240 AssertRCReturn(rc, rc);
2241 for (ui=0; ui<uiNumElems; ++ui)
2242 {
2243 CRCreateInfo_t createInfo;
2244 char psz[200];
2245 GLint ctxID;
2246 CRContextInfo* pContextInfo;
2247 CRContext* pContext;
2248
2249 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2250 AssertRCReturn(rc, rc);
2251 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
2252 AssertRCReturn(rc, rc);
2253
2254 if (createInfo.pszDpyName)
2255 {
2256 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
2257 AssertRCReturn(rc, rc);
2258 createInfo.pszDpyName = psz;
2259 }
2260
2261 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
2262 CRASSERT((int64_t)ctxID == (int64_t)key);
2263
2264 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2265 CRASSERT(pContextInfo);
2266 CRASSERT(pContextInfo->pContext);
2267 pContext = pContextInfo->pContext;
2268 pContext->shared->id=-1;
2269 }
2270
2271 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2272 {
2273 CRASSERT(!Reader.pu8Buffer);
2274 /* we have a mural data here */
2275 rc = crVBoxServerLoadMurals(&Reader, version);
2276 AssertRCReturn(rc, rc);
2277 CRASSERT(!Reader.pu8Buffer);
2278 }
2279
2280 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
2281 {
2282 /* set the current client to allow doing crServerPerformMakeCurrent later */
2283 CRASSERT(cr_server.numClients);
2284 cr_server.curClient = cr_server.clients[0];
2285 }
2286
2287 rc = crStateLoadGlobals(pSSM, version);
2288 AssertRCReturn(rc, rc);
2289
2290 if (uiNumElems)
2291 {
2292 /* ensure we have main context set up as current */
2293 CRMuralInfo *pMural;
2294 CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
2295 CRASSERT(!cr_server.currentCtxInfo);
2296 CRASSERT(!cr_server.currentMural);
2297 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
2298 CRASSERT(pMural);
2299 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
2300 }
2301
2302 /* Restore context state data */
2303 for (ui=0; ui<uiNumElems; ++ui)
2304 {
2305 CRContextInfo* pContextInfo;
2306 CRContext *pContext;
2307 CRMuralInfo *pMural = NULL;
2308 int32_t winId = 0;
2309
2310 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2311 AssertRCReturn(rc, rc);
2312
2313 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2314 CRASSERT(pContextInfo);
2315 CRASSERT(pContextInfo->pContext);
2316 pContext = pContextInfo->pContext;
2317
2318 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2319 {
2320 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
2321 AssertRCReturn(rc, rc);
2322
2323 if (winId)
2324 {
2325 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
2326 CRASSERT(pMural);
2327 }
2328 else
2329 {
2330 /* null winId means a dummy mural, get it */
2331 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
2332 CRASSERT(pMural);
2333 }
2334 }
2335
2336 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
2337 AssertRCReturn(rc, rc);
2338
2339 /*Restore front/back buffer images*/
2340 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2341 AssertRCReturn(rc, rc);
2342 }
2343
2344 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2345 {
2346 CRContextInfo *pContextInfo;
2347 CRMuralInfo *pMural;
2348 GLint ctxId;
2349
2350 rc = SSMR3GetU32(pSSM, &uiNumElems);
2351 AssertRCReturn(rc, rc);
2352 for (ui=0; ui<uiNumElems; ++ui)
2353 {
2354 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
2355 CRMuralInfo *pInitialCurMural;
2356
2357 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2358 AssertRCReturn(rc, rc);
2359
2360 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
2361 AssertRCReturn(rc, rc);
2362
2363 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
2364 CRASSERT(pMural);
2365 if (ctxId)
2366 {
2367 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
2368 CRASSERT(pContextInfo);
2369 }
2370 else
2371 pContextInfo = &cr_server.MainContextInfo;
2372
2373 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
2374 pInitialCurMural = pContextInfo->currentMural;
2375
2376 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2377 AssertRCReturn(rc, rc);
2378
2379 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
2380 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
2381 pContextInfo->currentMural = pInitialCurMural;
2382 }
2383
2384 CRASSERT(!uiNumElems || cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2385
2386 cr_server.curClient = NULL;
2387 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
2388 }
2389 else
2390 {
2391 CRServerFreeIDsPool_t dummyIdsPool;
2392
2393 CRASSERT(!Reader.pu8Buffer);
2394
2395 /* we have a mural data here */
2396 rc = crVBoxServerLoadMurals(&Reader, version);
2397 AssertRCReturn(rc, rc);
2398
2399 /* not used any more, just read it out and ignore */
2400 rc = crServerLsrDataGetMem(&Reader, &dummyIdsPool, sizeof(dummyIdsPool));
2401 CRASSERT(rc == VINF_SUCCESS);
2402 }
2403
2404 /* Load clients info */
2405 for (i = 0; i < cr_server.numClients; i++)
2406 {
2407 if (cr_server.clients[i] && cr_server.clients[i]->conn)
2408 {
2409 CRClient *pClient = cr_server.clients[i];
2410 CRClient client;
2411 unsigned long ctxID=-1, winID=-1;
2412
2413 rc = crServerLsrDataGetU32(&Reader, &ui);
2414 AssertRCReturn(rc, rc);
2415 /* If this assert fires, then we should search correct client in the list first*/
2416 CRASSERT(ui == pClient->conn->u32ClientID);
2417
2418 if (version>=4)
2419 {
2420 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMajor);
2421 AssertRCReturn(rc, rc);
2422
2423 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMinor);
2424 AssertRCReturn(rc, rc);
2425 }
2426
2427 rc = crServerLsrDataGetMem(&Reader, &client, sizeof(client));
2428 CRASSERT(rc == VINF_SUCCESS);
2429
2430 client.conn = pClient->conn;
2431 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2432 * and fail to bind old textures.
2433 */
2434 /*client.number = pClient->number;*/
2435 *pClient = client;
2436
2437 pClient->currentContextNumber = -1;
2438 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2439 pClient->currentMural = NULL;
2440 pClient->currentWindow = -1;
2441
2442 cr_server.curClient = pClient;
2443
2444 if (client.currentCtxInfo && client.currentContextNumber > 0)
2445 {
2446 rc = crServerLsrDataGetMem(&Reader, &ctxID, sizeof(ctxID));
2447 AssertRCReturn(rc, rc);
2448 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2449 CRASSERT(client.currentCtxInfo);
2450 CRASSERT(client.currentCtxInfo->pContext);
2451 //pClient->currentCtx = client.currentCtx;
2452 //pClient->currentContextNumber = ctxID;
2453 }
2454
2455 if (client.currentMural && client.currentWindow > 0)
2456 {
2457 rc = crServerLsrDataGetMem(&Reader, &winID, sizeof(winID));
2458 AssertRCReturn(rc, rc);
2459 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2460 CRASSERT(client.currentMural);
2461 //pClient->currentMural = client.currentMural;
2462 //pClient->currentWindow = winID;
2463 }
2464
2465 CRASSERT(!Reader.cbData);
2466
2467 /* Restore client active context and window */
2468 crServerDispatchMakeCurrent(winID, 0, ctxID);
2469 }
2470 }
2471
2472 cr_server.curClient = NULL;
2473
2474 rc = crServerPendLoadState(pSSM, version);
2475 AssertRCReturn(rc, rc);
2476
2477 if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_INFO)
2478 {
2479 rc = CrPMgrLoadState(pSSM, version);
2480 AssertRCReturn(rc, rc);
2481 }
2482
2483 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2484 crWarning("crServer: glGetError %d after loading snapshot", err);
2485
2486 cr_server.bIsInLoadingState = GL_FALSE;
2487
2488#ifdef DEBUG_misha
2489 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2490 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
2491#endif
2492
2493 CRASSERT(!Reader.cbData);
2494 crServerLsrTerm(&Reader);
2495
2496 return VINF_SUCCESS;
2497}
2498
2499DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
2500{
2501 if (cr_server.fCrCmdEnabled)
2502 {
2503 WARN(("CrCmd enabled"));
2504 return VERR_INTERNAL_ERROR;
2505 }
2506
2507 return crVBoxServerLoadStatePerform(pSSM, version);
2508}
2509
2510#define SCREEN(i) (cr_server.screen[i])
2511#define MAPPED(screen) ((screen).winID != 0)
2512
2513extern DECLEXPORT(void) crServerVBoxSetNotifyEventCB(PFNCRSERVERNOTIFYEVENT pfnCb)
2514{
2515 cr_server.pfnNotifyEventCB = pfnCb;
2516}
2517
2518void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void* pvData, uint32_t cbData)
2519{
2520 /* this is something unexpected, but just in case */
2521 if (idScreen >= cr_server.screenCount)
2522 {
2523 crWarning("invalid screen id %d", idScreen);
2524 return;
2525 }
2526
2527 cr_server.pfnNotifyEventCB(idScreen, uEvent, pvData, cbData);
2528}
2529
2530void crServerWindowReparent(CRMuralInfo *pMural)
2531{
2532 pMural->fHasParentWindow = !!cr_server.screen[pMural->screenId].winID;
2533
2534 renderspuReparentWindow(pMural->spuWindow);
2535}
2536
2537DECLEXPORT(void) crServerSetUnscaledHiDPI(bool fEnable)
2538{
2539 renderspuSetUnscaledHiDPI(fEnable);
2540}
2541
2542static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2543{
2544 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2545 int *sIndex = (int*) data2;
2546
2547 if (pMI->screenId == *sIndex)
2548 {
2549 crServerWindowReparent(pMI);
2550 }
2551}
2552
2553DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2554{
2555 int i;
2556
2557 if (sCount>CR_MAX_GUEST_MONITORS)
2558 return VERR_INVALID_PARAMETER;
2559
2560 /*Shouldn't happen yet, but to be safe in future*/
2561 for (i=0; i<cr_server.screenCount; ++i)
2562 {
2563 if (MAPPED(SCREEN(i)))
2564 WARN(("Screen count is changing, but screen[%i] is still mapped", i));
2565 return VERR_NOT_IMPLEMENTED;
2566 }
2567
2568 cr_server.screenCount = sCount;
2569
2570 for (i=0; i<sCount; ++i)
2571 {
2572 SCREEN(i).winID = 0;
2573 }
2574
2575 return VINF_SUCCESS;
2576}
2577
2578DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2579{
2580 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2581
2582 if (sIndex<0 || sIndex>=cr_server.screenCount)
2583 return VERR_INVALID_PARAMETER;
2584
2585 if (MAPPED(SCREEN(sIndex)))
2586 {
2587 SCREEN(sIndex).winID = 0;
2588 renderspuSetWindowId(0);
2589
2590 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2591
2592 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2593
2594 CrPMgrScreenChanged((uint32_t)sIndex);
2595 }
2596
2597 renderspuSetWindowId(SCREEN(0).winID);
2598
2599 return VINF_SUCCESS;
2600}
2601
2602DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2603{
2604 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2605
2606 if (sIndex<0 || sIndex>=cr_server.screenCount)
2607 return VERR_INVALID_PARAMETER;
2608
2609 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2610 {
2611 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2612 crVBoxServerUnmapScreen(sIndex);
2613 }
2614
2615 SCREEN(sIndex).winID = winID;
2616 SCREEN(sIndex).x = x;
2617 SCREEN(sIndex).y = y;
2618 SCREEN(sIndex).w = w;
2619 SCREEN(sIndex).h = h;
2620
2621 renderspuSetWindowId(SCREEN(sIndex).winID);
2622 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2623
2624 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2625 renderspuSetWindowId(SCREEN(0).winID);
2626
2627#ifndef WINDOWS
2628 /*Restore FB content for clients, which have current window on a screen being remapped*/
2629 {
2630 GLint i;
2631
2632 for (i = 0; i < cr_server.numClients; i++)
2633 {
2634 cr_server.curClient = cr_server.clients[i];
2635 if (cr_server.curClient->currentCtxInfo
2636 && cr_server.curClient->currentCtxInfo->pContext
2637 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2638 && cr_server.curClient->currentMural
2639 && cr_server.curClient->currentMural->screenId == sIndex
2640 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2641 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2642 {
2643 int clientWindow = cr_server.curClient->currentWindow;
2644 int clientContext = cr_server.curClient->currentContextNumber;
2645 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2646
2647 if (clientWindow && clientWindow != cr_server.currentWindow)
2648 {
2649 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2650 }
2651
2652 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2653 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2654 }
2655 }
2656 cr_server.curClient = NULL;
2657 }
2658#endif
2659
2660 CrPMgrScreenChanged((uint32_t)sIndex);
2661
2662 return VINF_SUCCESS;
2663}
2664
2665DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects)
2666{
2667 int32_t rc = VINF_SUCCESS;
2668 GLboolean fOldRootVrOn = cr_server.fRootVrOn;
2669
2670 /* non-zero rects pointer indicate rects are present and switched on
2671 * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions,
2672 * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */
2673 if (pRects)
2674 {
2675 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
2676 rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL);
2677 if (!RT_SUCCESS(rc))
2678 {
2679 crWarning("VBoxVrListRectsSet failed! rc %d", rc);
2680 return rc;
2681 }
2682
2683 cr_server.fRootVrOn = GL_TRUE;
2684 }
2685 else
2686 {
2687 if (!cr_server.fRootVrOn)
2688 return VINF_SUCCESS;
2689
2690 VBoxVrListClear(&cr_server.RootVr);
2691
2692 cr_server.fRootVrOn = GL_FALSE;
2693 }
2694
2695 if (!fOldRootVrOn != !cr_server.fRootVrOn)
2696 {
2697 rc = CrPMgrModeRootVr(cr_server.fRootVrOn);
2698 if (!RT_SUCCESS(rc))
2699 {
2700 crWarning("CrPMgrModeRootVr failed rc %d", rc);
2701 return rc;
2702 }
2703 }
2704 else if (cr_server.fRootVrOn)
2705 {
2706 rc = CrPMgrRootVrUpdate();
2707 if (!RT_SUCCESS(rc))
2708 {
2709 crWarning("CrPMgrRootVrUpdate failed rc %d", rc);
2710 return rc;
2711 }
2712 }
2713
2714 return VINF_SUCCESS;
2715}
2716
2717DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2718{
2719 return CrPMgrModeVrdp(value);
2720}
2721
2722DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2723{
2724 /* No need for a synchronization as this is single threaded. */
2725 if (pCallbacks)
2726 {
2727 cr_server.outputRedirect = *pCallbacks;
2728 }
2729 else
2730 {
2731 memset (&cr_server.outputRedirect, 0, sizeof (cr_server.outputRedirect));
2732 }
2733
2734 return VINF_SUCCESS;
2735}
2736
2737DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2738{
2739 CRScreenViewportInfo *pViewport;
2740 RTRECT NewRect;
2741 int rc;
2742
2743 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2744
2745 if (sIndex<0 || sIndex>=cr_server.screenCount)
2746 {
2747 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2748 return VERR_INVALID_PARAMETER;
2749 }
2750
2751 NewRect.xLeft = x;
2752 NewRect.yTop = y;
2753 NewRect.xRight = x + w;
2754 NewRect.yBottom = y + h;
2755
2756 pViewport = &cr_server.screenVieport[sIndex];
2757 /*always do viewport updates no matter whether the rectangle actually changes,
2758 * this is needed to ensure window is adjusted properly on OSX */
2759 pViewport->Rect = NewRect;
2760 rc = CrPMgrViewportUpdate((uint32_t)sIndex);
2761 if (!RT_SUCCESS(rc))
2762 {
2763 crWarning("CrPMgrViewportUpdate failed %d", rc);
2764 return rc;
2765 }
2766
2767 return VINF_SUCCESS;
2768}
2769
2770static void crVBoxServerDeleteMuralCb(unsigned long key, void *data1, void *data2)
2771{
2772 CRHashTable *h = (CRHashTable*)data2;
2773 CRMuralInfo *m = (CRMuralInfo *) data1;
2774 if (m->spuWindow == CR_RENDER_DEFAULT_WINDOW_ID)
2775 return;
2776
2777 crHashtableDelete(h, key, NULL);
2778 crServerMuralTerm(m);
2779 crFree(m);
2780}
2781
2782static void crVBoxServerDefaultContextClear()
2783{
2784 HCR_FRAMEBUFFER hFb;
2785 int rc = CrPMgrDisable();
2786 if (RT_FAILURE(rc))
2787 {
2788 WARN(("CrPMgrDisable failed %d", rc));
2789 return;
2790 }
2791
2792 for (hFb = CrPMgrFbGetFirstEnabled(); hFb; hFb = CrPMgrFbGetNextEnabled(hFb))
2793 {
2794 int rc = CrFbUpdateBegin(hFb);
2795 if (RT_SUCCESS(rc))
2796 {
2797 CrFbRegionsClear(hFb);
2798 CrFbUpdateEnd(hFb);
2799 }
2800 else
2801 WARN(("CrFbUpdateBegin failed %d", rc));
2802 }
2803
2804 cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
2805 crStateCleanupCurrent();
2806
2807 /* note: we need to clean all contexts, since otherwise renderspu leanup won't work,
2808 * i.e. renderspu would need to clean up its own internal windows, it won't be able to do that if
2809 * some those windows is associated with any context. */
2810 if (cr_server.MainContextInfo.SpuContext)
2811 {
2812 cr_server.head_spu->dispatch_table.DestroyContext(cr_server.MainContextInfo.SpuContext);
2813 crStateDestroyContext(cr_server.MainContextInfo.pContext);
2814 if (cr_server.MainContextInfo.CreateInfo.pszDpyName)
2815 crFree(cr_server.MainContextInfo.CreateInfo.pszDpyName);
2816
2817 memset(&cr_server.MainContextInfo, 0, sizeof (cr_server.MainContextInfo));
2818 }
2819
2820 cr_server.firstCallCreateContext = GL_TRUE;
2821 cr_server.firstCallMakeCurrent = GL_TRUE;
2822 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
2823
2824 CRASSERT(!cr_server.curClient);
2825
2826 cr_server.currentCtxInfo = NULL;
2827 cr_server.currentWindow = 0;
2828 cr_server.currentNativeWindow = 0;
2829 cr_server.currentMural = NULL;
2830
2831 crStateDestroy();
2832// crStateCleanupCurrent();
2833
2834 if (CrBltIsInitialized(&cr_server.Blitter))
2835 {
2836 CrBltTerm(&cr_server.Blitter);
2837 Assert(!CrBltIsInitialized(&cr_server.Blitter));
2838 }
2839
2840 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerDeleteMuralCb, cr_server.dummyMuralTable);
2841
2842 cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_RENDERTHREAD_INFORM, 0);
2843}
2844
2845static void crVBoxServerDefaultContextSet()
2846{
2847 cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_RENDERTHREAD_INFORM, 1);
2848
2849 CRASSERT(!cr_server.MainContextInfo.SpuContext);
2850
2851// crStateSetCurrent(NULL);
2852 crStateInit();
2853 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
2854
2855 CrPMgrEnable();
2856}
2857
2858#ifdef VBOX_WITH_CRHGSMI
2859
2860static int32_t crVBoxServerCmdVbvaCrCmdProcess(const struct VBOXCMDVBVA_CRCMD_CMD *pCmd, uint32_t cbCmd)
2861{
2862 int32_t rc;
2863 uint32_t cBuffers = pCmd->cBuffers;
2864 uint32_t cParams;
2865 uint32_t cbHdr;
2866 CRVBOXHGSMIHDR *pHdr;
2867 uint32_t u32Function;
2868 uint32_t u32ClientID;
2869 CRClient *pClient;
2870
2871 if (!g_pvVRamBase)
2872 {
2873 WARN(("g_pvVRamBase is not initialized"));
2874 return VERR_INVALID_STATE;
2875 }
2876
2877 if (!cBuffers)
2878 {
2879 WARN(("zero buffers passed in!"));
2880 return VERR_INVALID_PARAMETER;
2881 }
2882
2883 cParams = cBuffers-1;
2884
2885 if (cbCmd < RT_OFFSETOF(VBOXCMDVBVA_CRCMD_CMD, aBuffers[cBuffers]))
2886 {
2887 WARN(("invalid buffer size"));
2888 return VERR_INVALID_PARAMETER;
2889 }
2890
2891 cbHdr = pCmd->aBuffers[0].cbBuffer;
2892 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2893 if (!pHdr)
2894 {
2895 WARN(("invalid header buffer!"));
2896 return VERR_INVALID_PARAMETER;
2897 }
2898
2899 if (cbHdr < sizeof (*pHdr))
2900 {
2901 WARN(("invalid header buffer size!"));
2902 return VERR_INVALID_PARAMETER;
2903 }
2904
2905 u32Function = pHdr->u32Function;
2906 u32ClientID = pHdr->u32ClientID;
2907
2908 switch (u32Function)
2909 {
2910 case SHCRGL_GUEST_FN_WRITE:
2911 {
2912 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2913
2914 /* @todo: Verify */
2915 if (cParams == 1)
2916 {
2917 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2918 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
2919 /* Fetch parameters. */
2920 uint32_t cbBuffer = pBuf->cbBuffer;
2921 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2922
2923 if (cbHdr < sizeof (*pFnCmd))
2924 {
2925 WARN(("invalid write cmd buffer size!"));
2926 rc = VERR_INVALID_PARAMETER;
2927 break;
2928 }
2929
2930 CRASSERT(cbBuffer);
2931 if (!pBuffer)
2932 {
2933 WARN(("invalid buffer data received from guest!"));
2934 rc = VERR_INVALID_PARAMETER;
2935 break;
2936 }
2937
2938 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2939 if (RT_FAILURE(rc))
2940 {
2941 WARN(("crVBoxServerClientGet failed %d", rc));
2942 break;
2943 }
2944
2945 /* This should never fire unless we start to multithread */
2946 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2947 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2948
2949 pClient->conn->pBuffer = pBuffer;
2950 pClient->conn->cbBuffer = cbBuffer;
2951 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
2952 crVBoxServerInternalClientWriteRead(pClient);
2953 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2954 return VINF_SUCCESS;
2955 }
2956
2957 WARN(("invalid number of args"));
2958 rc = VERR_INVALID_PARAMETER;
2959 break;
2960 }
2961
2962 case SHCRGL_GUEST_FN_INJECT:
2963 {
2964 WARN(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2965
2966 /* @todo: Verify */
2967 if (cParams == 1)
2968 {
2969 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2970 /* Fetch parameters. */
2971 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2972 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
2973 uint32_t cbBuffer = pBuf->cbBuffer;
2974 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2975
2976 if (cbHdr < sizeof (*pFnCmd))
2977 {
2978 WARN(("invalid inject cmd buffer size!"));
2979 rc = VERR_INVALID_PARAMETER;
2980 break;
2981 }
2982
2983 CRASSERT(cbBuffer);
2984 if (!pBuffer)
2985 {
2986 WARN(("invalid buffer data received from guest!"));
2987 rc = VERR_INVALID_PARAMETER;
2988 break;
2989 }
2990
2991 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
2992 if (RT_FAILURE(rc))
2993 {
2994 WARN(("crVBoxServerClientGet failed %d", rc));
2995 break;
2996 }
2997
2998 /* This should never fire unless we start to multithread */
2999 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3000 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3001
3002 pClient->conn->pBuffer = pBuffer;
3003 pClient->conn->cbBuffer = cbBuffer;
3004 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
3005 crVBoxServerInternalClientWriteRead(pClient);
3006 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3007 return VINF_SUCCESS;
3008 }
3009
3010 WARN(("invalid number of args"));
3011 rc = VERR_INVALID_PARAMETER;
3012 break;
3013 }
3014
3015 case SHCRGL_GUEST_FN_READ:
3016 {
3017 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3018
3019 /* @todo: Verify */
3020 if (cParams == 1)
3021 {
3022 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3023 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3024 /* Fetch parameters. */
3025 uint32_t cbBuffer = pBuf->cbBuffer;
3026 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3027
3028 if (cbHdr < sizeof (*pFnCmd))
3029 {
3030 WARN(("invalid read cmd buffer size!"));
3031 rc = VERR_INVALID_PARAMETER;
3032 break;
3033 }
3034
3035 if (!pBuffer)
3036 {
3037 WARN(("invalid buffer data received from guest!"));
3038 rc = VERR_INVALID_PARAMETER;
3039 break;
3040 }
3041
3042 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3043 if (RT_FAILURE(rc))
3044 {
3045 WARN(("crVBoxServerClientGet failed %d", rc));
3046 break;
3047 }
3048
3049 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3050
3051 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3052
3053 /* Return the required buffer size always */
3054 pFnCmd->cbBuffer = cbBuffer;
3055
3056 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3057
3058 /* the read command is never pended, complete it right away */
3059 if (RT_FAILURE(rc))
3060 {
3061 WARN(("crVBoxServerInternalClientRead failed %d", rc));
3062 break;
3063 }
3064
3065 break;
3066 }
3067
3068 crWarning("invalid number of args");
3069 rc = VERR_INVALID_PARAMETER;
3070 break;
3071 }
3072
3073 case SHCRGL_GUEST_FN_WRITE_READ:
3074 {
3075 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3076
3077 /* @todo: Verify */
3078 if (cParams == 2)
3079 {
3080 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3081 const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3082 const VBOXCMDVBVA_CRCMD_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3083
3084 /* Fetch parameters. */
3085 uint32_t cbBuffer = pBuf->cbBuffer;
3086 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3087
3088 uint32_t cbWriteback = pWbBuf->cbBuffer;
3089 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3090
3091 if (cbHdr < sizeof (*pFnCmd))
3092 {
3093 WARN(("invalid write_read cmd buffer size!"));
3094 rc = VERR_INVALID_PARAMETER;
3095 break;
3096 }
3097
3098 CRASSERT(cbBuffer);
3099 if (!pBuffer)
3100 {
3101 WARN(("invalid write buffer data received from guest!"));
3102 rc = VERR_INVALID_PARAMETER;
3103 break;
3104 }
3105
3106 CRASSERT(cbWriteback);
3107 if (!pWriteback)
3108 {
3109 WARN(("invalid writeback buffer data received from guest!"));
3110 rc = VERR_INVALID_PARAMETER;
3111 break;
3112 }
3113
3114 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3115 if (RT_FAILURE(rc))
3116 {
3117 WARN(("crVBoxServerClientGet failed %d", rc));
3118 break;
3119 }
3120
3121 /* This should never fire unless we start to multithread */
3122 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3123 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3124
3125 pClient->conn->pBuffer = pBuffer;
3126 pClient->conn->cbBuffer = cbBuffer;
3127 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, false);
3128 crVBoxServerInternalClientWriteRead(pClient);
3129 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3130 return VINF_SUCCESS;
3131 }
3132
3133 crWarning("invalid number of args");
3134 rc = VERR_INVALID_PARAMETER;
3135 break;
3136 }
3137
3138 case SHCRGL_GUEST_FN_SET_VERSION:
3139 {
3140 WARN(("SHCRGL_GUEST_FN_SET_VERSION: invalid function"));
3141 rc = VERR_NOT_IMPLEMENTED;
3142 break;
3143 }
3144
3145 case SHCRGL_GUEST_FN_SET_PID:
3146 {
3147 WARN(("SHCRGL_GUEST_FN_SET_PID: invalid function"));
3148 rc = VERR_NOT_IMPLEMENTED;
3149 break;
3150 }
3151
3152 default:
3153 {
3154 WARN(("invalid function, %d", u32Function));
3155 rc = VERR_NOT_IMPLEMENTED;
3156 break;
3157 }
3158
3159 }
3160
3161 pHdr->result = rc;
3162
3163 return VINF_SUCCESS;
3164}
3165
3166static DECLCALLBACK(int) crVBoxCrCmdEnable(HVBOXCRCMDSVR hSvr, VBOXCRCMD_SVRENABLE_INFO *pInfo)
3167{
3168 Assert(!cr_server.fCrCmdEnabled);
3169 Assert(!cr_server.numClients);
3170
3171 cr_server.CrCmdClientInfo = *pInfo;
3172
3173 crVBoxServerDefaultContextSet();
3174
3175 cr_server.fCrCmdEnabled = GL_TRUE;
3176
3177 crInfo("crCmd ENABLED");
3178
3179 return VINF_SUCCESS;
3180}
3181
3182static DECLCALLBACK(int) crVBoxCrCmdDisable(HVBOXCRCMDSVR hSvr)
3183{
3184 Assert(cr_server.fCrCmdEnabled);
3185
3186 crVBoxServerRemoveAllClients();
3187
3188 CrHTableEmpty(&cr_server.clientTable);
3189
3190 crVBoxServerDefaultContextClear();
3191
3192 memset(&cr_server.CrCmdClientInfo, 0, sizeof (cr_server.CrCmdClientInfo));
3193
3194 cr_server.fCrCmdEnabled = GL_FALSE;
3195
3196 crInfo("crCmd DISABLED");
3197
3198 return VINF_SUCCESS;
3199}
3200
3201static DECLCALLBACK(int) crVBoxCrCmdHostCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
3202{
3203 return crVBoxServerHostCtl((VBOXCRCMDCTL*)pCmd, cbCmd);
3204}
3205
3206static int crVBoxCrDisconnect(uint32_t u32Client)
3207{
3208 CRClient *pClient = (CRClient*)CrHTableRemove(&cr_server.clientTable, u32Client);
3209 if (!pClient)
3210 {
3211 WARN(("invalid client id"));
3212 return VERR_INVALID_PARAMETER;
3213 }
3214
3215 crVBoxServerRemoveClientObj(pClient);
3216
3217 return VINF_SUCCESS;
3218}
3219
3220static int crVBoxCrConnectEx(VBOXCMDVBVA_3DCTL_CONNECT *pConnect, uint32_t u32ClientId)
3221{
3222 CRClient *pClient;
3223 int rc;
3224
3225 if (u32ClientId == CRHTABLE_HANDLE_INVALID)
3226 {
3227 /* allocate client id */
3228 u32ClientId = CrHTablePut(&cr_server.clientTable, (void*)1);
3229 if (u32ClientId == CRHTABLE_HANDLE_INVALID)
3230 {
3231 WARN(("CrHTablePut failed"));
3232 return VERR_NO_MEMORY;
3233 }
3234 }
3235
3236 rc = crVBoxServerAddClientObj(u32ClientId, &pClient);
3237 if (RT_SUCCESS(rc))
3238 {
3239 rc = crVBoxServerClientObjSetVersion(pClient, pConnect->u32MajorVersion, pConnect->u32MinorVersion);
3240 if (RT_SUCCESS(rc))
3241 {
3242 rc = crVBoxServerClientObjSetPID(pClient, pConnect->u64Pid);
3243 if (RT_SUCCESS(rc))
3244 {
3245 rc = CrHTablePutToSlot(&cr_server.clientTable, u32ClientId, pClient);
3246 if (RT_SUCCESS(rc))
3247 {
3248 pConnect->Hdr.u32CmdClientId = u32ClientId;
3249 return VINF_SUCCESS;
3250 }
3251 else
3252 WARN(("CrHTablePutToSlot failed %d", rc));
3253 }
3254 else
3255 WARN(("crVBoxServerClientObjSetPID failed %d", rc));
3256 }
3257 else
3258 WARN(("crVBoxServerClientObjSetVersion failed %d", rc));
3259
3260 crVBoxServerRemoveClientObj(pClient);
3261 }
3262 else
3263 WARN(("crVBoxServerAddClientObj failed %d", rc));
3264
3265 CrHTableRemove(&cr_server.clientTable, u32ClientId);
3266
3267 return rc;
3268}
3269
3270static int crVBoxCrConnect(VBOXCMDVBVA_3DCTL_CONNECT *pConnect)
3271{
3272 return crVBoxCrConnectEx(pConnect, CRHTABLE_HANDLE_INVALID);
3273}
3274
3275static DECLCALLBACK(int) crVBoxCrCmdGuestCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
3276{
3277 VBOXCMDVBVA_3DCTL *pCtl = (VBOXCMDVBVA_3DCTL*)pCmd;
3278 if (cbCmd < sizeof (VBOXCMDVBVA_3DCTL))
3279 {
3280 WARN(("invalid buffer size"));
3281 return VERR_INVALID_PARAMETER;
3282 }
3283
3284 switch (pCtl->u32Type)
3285 {
3286 case VBOXCMDVBVA3DCTL_TYPE_CONNECT:
3287 {
3288 if (cbCmd != sizeof (VBOXCMDVBVA_3DCTL_CONNECT))
3289 {
3290 WARN(("invalid command size"));
3291 return VERR_INVALID_PARAMETER;
3292 }
3293
3294 return crVBoxCrConnect((VBOXCMDVBVA_3DCTL_CONNECT*)pCtl);
3295 }
3296 case VBOXCMDVBVA3DCTL_TYPE_DISCONNECT:
3297 {
3298 if (cbCmd != sizeof (VBOXCMDVBVA_3DCTL))
3299 {
3300 WARN(("invalid command size"));
3301 return VERR_INVALID_PARAMETER;
3302 }
3303
3304 return crVBoxCrDisconnect(pCtl->u32CmdClientId);
3305 }
3306 case VBOXCMDVBVA3DCTL_TYPE_CMD:
3307 {
3308 VBOXCMDVBVA_3DCTL_CMD *p3DCmd;
3309 if (cbCmd < sizeof (VBOXCMDVBVA_3DCTL_CMD))
3310 {
3311 WARN(("invalid size"));
3312 return VERR_INVALID_PARAMETER;
3313 }
3314
3315 p3DCmd = (VBOXCMDVBVA_3DCTL_CMD*)pCmd;
3316
3317 return crVBoxCrCmdCmd(NULL, &p3DCmd->Cmd, cbCmd - RT_OFFSETOF(VBOXCMDVBVA_3DCTL_CMD, Cmd));
3318 }
3319 default:
3320 WARN(("crVBoxCrCmdGuestCtl: invalid function %d", pCtl->u32Type));
3321 return VERR_INVALID_PARAMETER;
3322 }
3323}
3324
3325static DECLCALLBACK(int) crVBoxCrCmdResize(HVBOXCRCMDSVR hSvr, const struct VBVAINFOSCREEN *pScreen, const uint32_t *pTargetMap)
3326{
3327 CRASSERT(cr_server.fCrCmdEnabled);
3328 return CrPMgrResize(pScreen, NULL, pTargetMap);
3329}
3330
3331static const char* gszVBoxOGLSSMMagic = "***OpenGL state data***";
3332
3333static int crVBoxCrCmdSaveClients(PSSMHANDLE pSSM)
3334{
3335 int i;
3336 int rc = SSMR3PutU32(pSSM, cr_server.numClients);
3337 AssertRCReturn(rc, rc);
3338
3339 for (i = 0; i < cr_server.numClients; i++)
3340 {
3341 CRClient * pClient = cr_server.clients[i];
3342 Assert(pClient);
3343
3344 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
3345 AssertRCReturn(rc, rc);
3346 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
3347 AssertRCReturn(rc, rc);
3348 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
3349 AssertRCReturn(rc, rc);
3350 rc = SSMR3PutU64(pSSM, pClient->pid);
3351 AssertRCReturn(rc, rc);
3352 }
3353
3354 return VINF_SUCCESS;
3355}
3356
3357static int crVBoxCrCmdLoadClients(PSSMHANDLE pSSM, uint32_t u32Version)
3358{
3359 uint32_t i;
3360 uint32_t u32;
3361 VBOXCMDVBVA_3DCTL_CONNECT Connect;
3362 int rc = SSMR3GetU32(pSSM, &u32);
3363 AssertRCReturn(rc, rc);
3364
3365 for (i = 0; i < u32; i++)
3366 {
3367 uint32_t u32ClientID;
3368 Connect.Hdr.u32Type = VBOXCMDVBVA3DCTL_TYPE_CONNECT;
3369 Connect.Hdr.u32CmdClientId = 0;
3370
3371 rc = SSMR3GetU32(pSSM, &u32ClientID);
3372 AssertRCReturn(rc, rc);
3373 rc = SSMR3GetU32(pSSM, &Connect.u32MajorVersion);
3374 AssertRCReturn(rc, rc);
3375 rc = SSMR3GetU32(pSSM, &Connect.u32MinorVersion);
3376 AssertRCReturn(rc, rc);
3377 rc = SSMR3GetU64(pSSM, &Connect.u64Pid);
3378 AssertRCReturn(rc, rc);
3379
3380 rc = crVBoxCrConnectEx(&Connect, u32ClientID);
3381 AssertRCReturn(rc, rc);
3382 }
3383
3384 return VINF_SUCCESS;
3385}
3386
3387static DECLCALLBACK(int) crVBoxCrCmdSaveState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM)
3388{
3389 int rc = VINF_SUCCESS;
3390
3391 Assert(cr_server.fCrCmdEnabled);
3392
3393 /* Start*/
3394 rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
3395 AssertRCReturn(rc, rc);
3396
3397 if (!cr_server.numClients)
3398 {
3399 rc = SSMR3PutU32(pSSM, 0);
3400 AssertRCReturn(rc, rc);
3401
3402 rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
3403 AssertRCReturn(rc, rc);
3404
3405 return VINF_SUCCESS;
3406 }
3407
3408 rc = SSMR3PutU32(pSSM, 1);
3409 AssertRCReturn(rc, rc);
3410
3411 /* Version */
3412 rc = SSMR3PutU32(pSSM, (uint32_t) SHCROGL_SSM_VERSION);
3413 AssertRCReturn(rc, rc);
3414
3415 rc = crVBoxCrCmdSaveClients(pSSM);
3416 AssertRCReturn(rc, rc);
3417
3418 /* The state itself */
3419 rc = crVBoxServerSaveStatePerform(pSSM);
3420 AssertRCReturn(rc, rc);
3421
3422 /* Save svc buffers info */
3423 {
3424 rc = SSMR3PutU32(pSSM, 0);
3425 AssertRCReturn(rc, rc);
3426
3427 rc = SSMR3PutU32(pSSM, 0);
3428 AssertRCReturn(rc, rc);
3429 }
3430
3431 /* End */
3432 rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
3433 AssertRCReturn(rc, rc);
3434
3435 return VINF_SUCCESS;
3436}
3437
3438static DECLCALLBACK(int) crVBoxCrCmdLoadState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM, uint32_t u32Version)
3439{
3440 int rc = VINF_SUCCESS;
3441
3442 char psz[2000];
3443 uint32_t ui32;
3444
3445 Assert(cr_server.fCrCmdEnabled);
3446
3447 /* Start of data */
3448 rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL);
3449 AssertRCReturn(rc, rc);
3450 if (strcmp(gszVBoxOGLSSMMagic, psz))
3451 {
3452 WARN(("unexpected data"));
3453 return VERR_SSM_UNEXPECTED_DATA;
3454 }
3455
3456 /* num clients */
3457 rc = SSMR3GetU32(pSSM, &ui32);
3458 AssertRCReturn(rc, rc);
3459
3460 if (!ui32)
3461 {
3462 /* no clients, dummy stub */
3463 rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL);
3464 AssertRCReturn(rc, rc);
3465 if (strcmp(gszVBoxOGLSSMMagic, psz))
3466 {
3467 WARN(("unexpected data"));
3468 return VERR_SSM_UNEXPECTED_DATA;
3469 }
3470
3471 return VINF_SUCCESS;
3472 }
3473 if (ui32 != 1)
3474 {
3475 WARN(("invalid id"));
3476 return VERR_SSM_UNEXPECTED_DATA;
3477 }
3478
3479 /* Version */
3480 rc = SSMR3GetU32(pSSM, &ui32);
3481 AssertRCReturn(rc, rc);
3482
3483 if (ui32 < SHCROGL_SSM_VERSION_CRCMD)
3484 {
3485 WARN(("unexpected version"));
3486 return VERR_SSM_UNEXPECTED_DATA;
3487 }
3488
3489 rc = crVBoxCrCmdLoadClients(pSSM, u32Version);
3490 AssertRCReturn(rc, rc);
3491
3492 /* The state itself */
3493 rc = crVBoxServerLoadStatePerform(pSSM, ui32);
3494 AssertRCReturn(rc, rc);
3495
3496 /* Save svc buffers info */
3497 {
3498 rc = SSMR3GetU32(pSSM, &ui32);
3499 AssertRCReturn(rc, rc);
3500
3501 if (ui32)
3502 {
3503 WARN(("unexpected data1"));
3504 return VERR_SSM_UNEXPECTED_DATA;
3505 }
3506
3507 rc = SSMR3GetU32(pSSM, &ui32);
3508 AssertRCReturn(rc, rc);
3509
3510 if (ui32)
3511 {
3512 WARN(("unexpected data1"));
3513 return VERR_SSM_UNEXPECTED_DATA;
3514 }
3515 }
3516
3517 /* End */
3518 rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL);
3519 AssertRCReturn(rc, rc);
3520 if (strcmp(gszVBoxOGLSSMMagic, psz))
3521 {
3522 WARN(("unexpected data"));
3523 return VERR_SSM_UNEXPECTED_DATA;
3524 }
3525
3526 return VINF_SUCCESS;
3527}
3528
3529
3530static DECLCALLBACK(int8_t) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, const VBOXCMDVBVA_HDR *pCmd, uint32_t cbCmd)
3531{
3532 switch (pCmd->u8OpCode)
3533 {
3534 case VBOXCMDVBVA_OPTYPE_CRCMD:
3535 {
3536 const VBOXCMDVBVA_CRCMD *pCrCmdDr;
3537 const VBOXCMDVBVA_CRCMD_CMD *pCrCmd;
3538 int rc;
3539 pCrCmdDr = (const VBOXCMDVBVA_CRCMD*)pCmd;
3540 pCrCmd = &pCrCmdDr->Cmd;
3541 if (cbCmd < sizeof (VBOXCMDVBVA_CRCMD))
3542 {
3543 WARN(("invalid buffer size"));
3544 return -1;
3545 }
3546 rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd, cbCmd - RT_OFFSETOF(VBOXCMDVBVA_CRCMD, Cmd));
3547 if (RT_SUCCESS(rc))
3548 {
3549 /* success */
3550 return 0;
3551 }
3552
3553 WARN(("crVBoxServerCmdVbvaCrCmdProcess failed, rc %d", rc));
3554 return -1;
3555 }
3556 case VBOXCMDVBVA_OPTYPE_FLIP:
3557 {
3558 const VBOXCMDVBVA_FLIP *pFlip;
3559
3560 if (cbCmd < VBOXCMDVBVA_SIZEOF_FLIPSTRUCT_MIN)
3561 {
3562 WARN(("invalid buffer size (cbCmd(%u) < sizeof(VBOXCMDVBVA_FLIP)(%u))", cbCmd, sizeof(VBOXCMDVBVA_FLIP)));
3563 return -1;
3564 }
3565
3566 pFlip = (const VBOXCMDVBVA_FLIP*)pCmd;
3567 return crVBoxServerCrCmdFlipProcess(pFlip, cbCmd);
3568 }
3569 case VBOXCMDVBVA_OPTYPE_BLT:
3570 {
3571 if (cbCmd < sizeof (VBOXCMDVBVA_BLT_HDR))
3572 {
3573 WARN(("invalid buffer size"));
3574 return -1;
3575 }
3576
3577 return crVBoxServerCrCmdBltProcess((const VBOXCMDVBVA_BLT_HDR*)pCmd, cbCmd);
3578 }
3579 case VBOXCMDVBVA_OPTYPE_CLRFILL:
3580 {
3581 if (cbCmd < sizeof (VBOXCMDVBVA_CLRFILL_HDR))
3582 {
3583 WARN(("invalid buffer size"));
3584 return -1;
3585 }
3586
3587 return crVBoxServerCrCmdClrFillProcess((const VBOXCMDVBVA_CLRFILL_HDR*)pCmd, cbCmd);
3588 }
3589 default:
3590 WARN(("unsupported command"));
3591 return -1;
3592 }
3593
3594 WARN(("internal error"));
3595 return -1;
3596}
3597
3598/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
3599 *
3600 * 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.
3601 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
3602 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
3603 * to block the lower-priority thread trying to complete the blocking command.
3604 * And removed extra memcpy done on blocked command arrival.
3605 *
3606 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
3607 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
3608 *
3609 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
3610 * */
3611
3612
3613int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
3614{
3615
3616 int32_t rc;
3617 uint32_t cBuffers = pCmd->cBuffers;
3618 uint32_t cParams;
3619 uint32_t cbHdr;
3620 CRVBOXHGSMIHDR *pHdr;
3621 uint32_t u32Function;
3622 uint32_t u32ClientID;
3623 CRClient *pClient;
3624
3625 if (!g_pvVRamBase)
3626 {
3627 WARN(("g_pvVRamBase is not initialized"));
3628
3629 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
3630 return VINF_SUCCESS;
3631 }
3632
3633 if (!cBuffers)
3634 {
3635 WARN(("zero buffers passed in!"));
3636
3637 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3638 return VINF_SUCCESS;
3639 }
3640
3641 cParams = cBuffers-1;
3642
3643 cbHdr = pCmd->aBuffers[0].cbBuffer;
3644 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
3645 if (!pHdr)
3646 {
3647 WARN(("invalid header buffer!"));
3648
3649 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3650 return VINF_SUCCESS;
3651 }
3652
3653 if (cbHdr < sizeof (*pHdr))
3654 {
3655 WARN(("invalid header buffer size!"));
3656
3657 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3658 return VINF_SUCCESS;
3659 }
3660
3661 u32Function = pHdr->u32Function;
3662 u32ClientID = pHdr->u32ClientID;
3663
3664 switch (u32Function)
3665 {
3666 case SHCRGL_GUEST_FN_WRITE:
3667 {
3668 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
3669
3670 /* @todo: Verify */
3671 if (cParams == 1)
3672 {
3673 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
3674 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3675 /* Fetch parameters. */
3676 uint32_t cbBuffer = pBuf->cbBuffer;
3677 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3678
3679 if (cbHdr < sizeof (*pFnCmd))
3680 {
3681 crWarning("invalid write cmd buffer size!");
3682 rc = VERR_INVALID_PARAMETER;
3683 break;
3684 }
3685
3686 CRASSERT(cbBuffer);
3687 if (!pBuffer)
3688 {
3689 crWarning("invalid buffer data received from guest!");
3690 rc = VERR_INVALID_PARAMETER;
3691 break;
3692 }
3693
3694 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3695 if (RT_FAILURE(rc))
3696 {
3697 break;
3698 }
3699
3700 /* This should never fire unless we start to multithread */
3701 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3702 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3703
3704 pClient->conn->pBuffer = pBuffer;
3705 pClient->conn->cbBuffer = cbBuffer;
3706 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3707 crVBoxServerInternalClientWriteRead(pClient);
3708 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3709 return VINF_SUCCESS;
3710 }
3711 else
3712 {
3713 crWarning("invalid number of args");
3714 rc = VERR_INVALID_PARAMETER;
3715 break;
3716 }
3717 break;
3718 }
3719
3720 case SHCRGL_GUEST_FN_INJECT:
3721 {
3722 Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
3723
3724 /* @todo: Verify */
3725 if (cParams == 1)
3726 {
3727 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
3728 /* Fetch parameters. */
3729 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
3730 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3731 uint32_t cbBuffer = pBuf->cbBuffer;
3732 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3733
3734 if (cbHdr < sizeof (*pFnCmd))
3735 {
3736 crWarning("invalid inject cmd buffer size!");
3737 rc = VERR_INVALID_PARAMETER;
3738 break;
3739 }
3740
3741 CRASSERT(cbBuffer);
3742 if (!pBuffer)
3743 {
3744 crWarning("invalid buffer data received from guest!");
3745 rc = VERR_INVALID_PARAMETER;
3746 break;
3747 }
3748
3749 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3750 if (RT_FAILURE(rc))
3751 {
3752 break;
3753 }
3754
3755 /* This should never fire unless we start to multithread */
3756 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3757 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3758
3759 pClient->conn->pBuffer = pBuffer;
3760 pClient->conn->cbBuffer = cbBuffer;
3761 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3762 crVBoxServerInternalClientWriteRead(pClient);
3763 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3764 return VINF_SUCCESS;
3765 }
3766
3767 crWarning("invalid number of args");
3768 rc = VERR_INVALID_PARAMETER;
3769 break;
3770 }
3771
3772 case SHCRGL_GUEST_FN_READ:
3773 {
3774 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3775
3776 /* @todo: Verify */
3777 if (cParams == 1)
3778 {
3779 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3780 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3781 /* Fetch parameters. */
3782 uint32_t cbBuffer = pBuf->cbBuffer;
3783 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3784
3785 if (cbHdr < sizeof (*pFnCmd))
3786 {
3787 crWarning("invalid read cmd buffer size!");
3788 rc = VERR_INVALID_PARAMETER;
3789 break;
3790 }
3791
3792
3793 if (!pBuffer)
3794 {
3795 crWarning("invalid buffer data received from guest!");
3796 rc = VERR_INVALID_PARAMETER;
3797 break;
3798 }
3799
3800 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3801 if (RT_FAILURE(rc))
3802 {
3803 break;
3804 }
3805
3806 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3807
3808 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3809
3810 /* Return the required buffer size always */
3811 pFnCmd->cbBuffer = cbBuffer;
3812
3813 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3814
3815 /* the read command is never pended, complete it right away */
3816 pHdr->result = rc;
3817
3818 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3819 return VINF_SUCCESS;
3820 }
3821
3822 crWarning("invalid number of args");
3823 rc = VERR_INVALID_PARAMETER;
3824 break;
3825 }
3826
3827 case SHCRGL_GUEST_FN_WRITE_READ:
3828 {
3829 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3830
3831 /* @todo: Verify */
3832 if (cParams == 2)
3833 {
3834 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3835 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3836 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3837
3838 /* Fetch parameters. */
3839 uint32_t cbBuffer = pBuf->cbBuffer;
3840 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3841
3842 uint32_t cbWriteback = pWbBuf->cbBuffer;
3843 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3844
3845 if (cbHdr < sizeof (*pFnCmd))
3846 {
3847 crWarning("invalid write_read cmd buffer size!");
3848 rc = VERR_INVALID_PARAMETER;
3849 break;
3850 }
3851
3852
3853 CRASSERT(cbBuffer);
3854 if (!pBuffer)
3855 {
3856 crWarning("invalid write buffer data received from guest!");
3857 rc = VERR_INVALID_PARAMETER;
3858 break;
3859 }
3860
3861 CRASSERT(cbWriteback);
3862 if (!pWriteback)
3863 {
3864 crWarning("invalid writeback buffer data received from guest!");
3865 rc = VERR_INVALID_PARAMETER;
3866 break;
3867 }
3868 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3869 if (RT_FAILURE(rc))
3870 {
3871 pHdr->result = rc;
3872 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3873 return rc;
3874 }
3875
3876 /* This should never fire unless we start to multithread */
3877 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3878 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3879
3880 pClient->conn->pBuffer = pBuffer;
3881 pClient->conn->cbBuffer = cbBuffer;
3882 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, true);
3883 crVBoxServerInternalClientWriteRead(pClient);
3884 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3885 return VINF_SUCCESS;
3886 }
3887
3888 crWarning("invalid number of args");
3889 rc = VERR_INVALID_PARAMETER;
3890 break;
3891 }
3892
3893 case SHCRGL_GUEST_FN_SET_VERSION:
3894 {
3895 WARN(("crVBoxServerCrHgsmiCmd, SHCRGL_GUEST_FN_SET_VERSION: invalid function"));
3896 rc = VERR_NOT_IMPLEMENTED;
3897 break;
3898 }
3899
3900 case SHCRGL_GUEST_FN_SET_PID:
3901 {
3902 WARN(("crVBoxServerCrHgsmiCmd, SHCRGL_GUEST_FN_SET_PID: invalid function"));
3903 rc = VERR_NOT_IMPLEMENTED;
3904 break;
3905 }
3906
3907 default:
3908 {
3909 WARN(("crVBoxServerCrHgsmiCmd: invalid functionm %d", u32Function));
3910 rc = VERR_NOT_IMPLEMENTED;
3911 break;
3912 }
3913
3914 }
3915
3916 /* we can be on fail only here */
3917 CRASSERT(RT_FAILURE(rc));
3918 pHdr->result = rc;
3919
3920 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3921 return rc;
3922
3923}
3924
3925
3926static DECLCALLBACK(bool) crVBoxServerHasDataForScreen(uint32_t u32ScreenID)
3927{
3928 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabledForScreen(u32ScreenID);
3929 if (hFb)
3930 return CrFbHas3DData(hFb);
3931
3932 return false;
3933}
3934
3935
3936static DECLCALLBACK(bool) crVBoxServerHasData()
3937{
3938 HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
3939 for (;
3940 hFb;
3941 hFb = CrPMgrFbGetNextEnabled(hFb))
3942 {
3943 if (CrFbHas3DData(hFb))
3944 return true;
3945 }
3946
3947 return false;
3948}
3949
3950int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
3951{
3952 int rc = VINF_SUCCESS;
3953
3954 switch (pCtl->enmType)
3955 {
3956 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
3957 {
3958 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
3959 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
3960 g_cbVRam = pSetup->cbVRam;
3961
3962 g_pLed = pSetup->pLed;
3963
3964 cr_server.ClientInfo = pSetup->CrClientInfo;
3965
3966 pSetup->CrCmdServerInfo.hSvr = NULL;
3967 pSetup->CrCmdServerInfo.pfnEnable = crVBoxCrCmdEnable;
3968 pSetup->CrCmdServerInfo.pfnDisable = crVBoxCrCmdDisable;
3969 pSetup->CrCmdServerInfo.pfnCmd = crVBoxCrCmdCmd;
3970 pSetup->CrCmdServerInfo.pfnHostCtl = crVBoxCrCmdHostCtl;
3971 pSetup->CrCmdServerInfo.pfnGuestCtl = crVBoxCrCmdGuestCtl;
3972 pSetup->CrCmdServerInfo.pfnResize = crVBoxCrCmdResize;
3973 pSetup->CrCmdServerInfo.pfnSaveState = crVBoxCrCmdSaveState;
3974 pSetup->CrCmdServerInfo.pfnLoadState = crVBoxCrCmdLoadState;
3975 rc = VINF_SUCCESS;
3976 break;
3977 }
3978 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
3979 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
3980 rc = VINF_SUCCESS;
3981 break;
3982 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB:
3983 {
3984 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB)pCtl;
3985 g_hCrHgsmiCompletion = pSetup->hCompletion;
3986 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
3987
3988 pSetup->MainInterface.pfnHasData = crVBoxServerHasData;
3989 pSetup->MainInterface.pfnHasDataForScreen = crVBoxServerHasDataForScreen;
3990
3991 rc = VINF_SUCCESS;
3992 break;
3993 }
3994 default:
3995 AssertMsgFailed(("invalid param %d", pCtl->enmType));
3996 rc = VERR_INVALID_PARAMETER;
3997 }
3998
3999 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
4000 * to complete them accordingly.
4001 * This approach allows using host->host and host->guest commands in the same way here
4002 * making the command completion to be the responsibility of the command originator.
4003 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
4004 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
4005 return rc;
4006}
4007
4008static int crVBoxServerCrCmdDisablePostProcess(VBOXCRCMDCTL_HGCMENABLE_DATA *pData)
4009{
4010 int rc = VINF_SUCCESS;
4011 uint8_t* pCtl;
4012 uint32_t cbCtl;
4013 HVBOXCRCMDCTL_REMAINING_HOST_COMMAND hRHCmd = pData->hRHCmd;
4014 PFNVBOXCRCMDCTL_REMAINING_HOST_COMMAND pfnRHCmd = pData->pfnRHCmd;
4015
4016 Assert(!cr_server.fCrCmdEnabled);
4017
4018 if (cr_server.numClients)
4019 {
4020 WARN(("cr_server.numClients(%d) is not NULL", cr_server.numClients));
4021 return VERR_INVALID_STATE;
4022 }
4023
4024 for (pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc); pCtl; pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc))
4025 {
4026 rc = crVBoxCrCmdHostCtl(NULL, pCtl, cbCtl);
4027 }
4028
4029 memset(&cr_server.DisableData, 0, sizeof (cr_server.DisableData));
4030
4031 return VINF_SUCCESS;
4032}
4033
4034int32_t crVBoxServerHgcmEnable(VBOXCRCMDCTL_HGCMENABLE_DATA *pData)
4035{
4036 int rc = crVBoxServerCrCmdDisablePostProcess(pData);
4037 if (RT_FAILURE(rc))
4038 {
4039 WARN(("crVBoxServerCrCmdDisablePostProcess failed %d", rc));
4040 return rc;
4041 }
4042
4043 crVBoxServerDefaultContextSet();
4044
4045 return VINF_SUCCESS;
4046}
4047
4048int32_t crVBoxServerHgcmDisable(VBOXCRCMDCTL_HGCMDISABLE_DATA *pData)
4049{
4050 Assert(!cr_server.fCrCmdEnabled);
4051
4052 Assert(!cr_server.numClients);
4053
4054 crVBoxServerRemoveAllClients();
4055
4056 CRASSERT(!cr_server.numClients);
4057
4058 crVBoxServerDefaultContextClear();
4059
4060 cr_server.DisableData = *pData;
4061
4062 return VINF_SUCCESS;
4063}
4064
4065#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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