VirtualBox

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

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

crOpenGL: bugfixes, debugging, dumping draw commands to html

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

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