VirtualBox

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

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

crOpenGL: notify VISIBLE_3DDATA event on remap

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

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