VirtualBox

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

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

crOpenGL: 3d data visibility notifications, bugfixes

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