VirtualBox

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

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

crOpenGL: proper support for GL_NONE,AUX,etc. for offscreen rendering

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