VirtualBox

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

Last change on this file since 46783 was 46783, checked in by vboxsync, 12 years ago

wddm/crOpenGL: more TexPresent impl

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

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