VirtualBox

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

Last change on this file since 50913 was 50913, checked in by vboxsync, 11 years ago

wddm/graphics: new command submission working for 2D, more testing needed

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

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