VirtualBox

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

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

crOpenGL: disable annoying logging

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 107.7 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "server.h"
8#include "cr_net.h"
9#include "cr_unpack.h"
10#include "cr_error.h"
11#include "cr_glstate.h"
12#include "cr_string.h"
13#include "cr_mem.h"
14#include "cr_hash.h"
15#include "cr_vreg.h"
16#include "cr_environment.h"
17#include "cr_pixeldata.h"
18#include "server_dispatch.h"
19#include "state/cr_texture.h"
20#include "render/renderspu.h"
21#include <signal.h>
22#include <stdlib.h>
23#define DEBUG_FP_EXCEPTIONS 0
24#if DEBUG_FP_EXCEPTIONS
25#include <fpu_control.h>
26#include <math.h>
27#endif
28#include <iprt/assert.h>
29#include <VBox/err.h>
30#include <VBox/log.h>
31
32#ifdef VBOXCR_LOGFPS
33#include <iprt/timer.h>
34#endif
35
36#ifdef VBOX_WITH_CRHGSMI
37# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
38uint8_t* g_pvVRamBase = NULL;
39uint32_t g_cbVRam = 0;
40HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion = NULL;
41PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion = NULL;
42#endif
43
44/**
45 * \mainpage CrServerLib
46 *
47 * \section CrServerLibIntroduction Introduction
48 *
49 * Chromium consists of all the top-level files in the cr
50 * directory. The core module basically takes care of API dispatch,
51 * and OpenGL state management.
52 */
53
54
55/**
56 * CRServer global data
57 */
58CRServer cr_server;
59
60int tearingdown = 0; /* can't be static */
61
62DECLINLINE(int32_t) crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
63{
64 CRClient *pClient = NULL;
65 int32_t i;
66
67 *ppClient = NULL;
68
69 for (i = 0; i < cr_server.numClients; i++)
70 {
71 if (cr_server.clients[i] && cr_server.clients[i]->conn
72 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
73 {
74 pClient = cr_server.clients[i];
75 break;
76 }
77 }
78 if (!pClient)
79 {
80 crWarning("client not found!");
81 return VERR_INVALID_PARAMETER;
82 }
83
84 if (!pClient->conn->vMajor)
85 {
86 crWarning("no major version specified for client!");
87 return VERR_NOT_SUPPORTED;
88 }
89
90 *ppClient = pClient;
91
92 return VINF_SUCCESS;
93}
94
95
96/**
97 * Return pointer to server's first SPU.
98 */
99SPU*
100crServerHeadSPU(void)
101{
102 return cr_server.head_spu;
103}
104
105
106
107static void DeleteBarrierCallback( void *data )
108{
109 CRServerBarrier *barrier = (CRServerBarrier *) data;
110 crFree(barrier->waiting);
111 crFree(barrier);
112}
113
114
115static void deleteContextInfoCallback( void *data )
116{
117 CRContextInfo *c = (CRContextInfo *) data;
118 crStateDestroyContext(c->pContext);
119 if (c->CreateInfo.pszDpyName)
120 crFree(c->CreateInfo.pszDpyName);
121 crFree(c);
122}
123
124static void deleteMuralInfoCallback( void *data )
125{
126 CRMuralInfo *m = (CRMuralInfo *) data;
127 if (m->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID) /* <- do not do term for default mural as it does not contain any info to be freed,
128 * and renderspu will destroy it up itself*/
129 {
130 crServerMuralTerm(m);
131 }
132 crFree(m);
133}
134
135static void crServerTearDown( void )
136{
137 GLint i;
138 CRClientNode *pNode, *pNext;
139
140 /* avoid a race condition */
141 if (tearingdown)
142 return;
143
144 tearingdown = 1;
145
146 crStateSetCurrent( NULL );
147
148 cr_server.curClient = NULL;
149 cr_server.run_queue = NULL;
150
151 crFree( cr_server.overlap_intens );
152 cr_server.overlap_intens = NULL;
153
154 /* needed to make sure window dummy mural not get created on mural destruction
155 * and generally this should be zeroed up */
156 cr_server.currentCtxInfo = NULL;
157 cr_server.currentWindow = -1;
158 cr_server.currentNativeWindow = 0;
159 cr_server.currentMural = NULL;
160
161 if (CrBltIsInitialized(&cr_server.Blitter))
162 {
163 CrBltTerm(&cr_server.Blitter);
164 }
165
166 /* sync our state with renderspu,
167 * do it before mural & context deletion to avoid deleting currently set murals/contexts*/
168 cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
169
170 /* Deallocate all semaphores */
171 crFreeHashtable(cr_server.semaphores, crFree);
172 cr_server.semaphores = NULL;
173
174 /* Deallocate all barriers */
175 crFreeHashtable(cr_server.barriers, DeleteBarrierCallback);
176 cr_server.barriers = NULL;
177
178 /* Free all context info */
179 crFreeHashtable(cr_server.contextTable, deleteContextInfoCallback);
180
181 /* Free vertex programs */
182 crFreeHashtable(cr_server.programTable, crFree);
183
184 /* Free dummy murals */
185 crFreeHashtable(cr_server.dummyMuralTable, deleteMuralInfoCallback);
186
187 /* Free murals */
188 crFreeHashtable(cr_server.muralTable, deleteMuralInfoCallback);
189
190 crServerDisplayTermAll();
191 CrDemTerm(&cr_server.PresentTexturepMap);
192 CrDemTeGlobalTerm();
193 memset(cr_server.DisplaysInitMap, 0, sizeof (cr_server.DisplaysInitMap));
194 memset(cr_server.aDispplays, 0, sizeof (cr_server.aDispplays));
195
196 for (i = 0; i < cr_server.numClients; i++) {
197 if (cr_server.clients[i]) {
198 CRConnection *conn = cr_server.clients[i]->conn;
199 crNetFreeConnection(conn);
200 crFree(cr_server.clients[i]);
201 }
202 }
203 cr_server.numClients = 0;
204
205 pNode = cr_server.pCleanupClient;
206 while (pNode)
207 {
208 pNext=pNode->next;
209 crFree(pNode->pClient);
210 crFree(pNode);
211 pNode=pNext;
212 }
213 cr_server.pCleanupClient = NULL;
214
215 if (crServerRpwIsInitialized(&cr_server.RpwWorker))
216 {
217 crServerRpwTerm(&cr_server.RpwWorker);
218 }
219
220#if 1
221 /* disable these two lines if trying to get stack traces with valgrind */
222 crSPUUnloadChain(cr_server.head_spu);
223 cr_server.head_spu = NULL;
224#endif
225
226 crStateDestroy();
227
228 crNetTearDown();
229
230 VBoxVrListClear(&cr_server.RootVr);
231
232 VBoxVrTerm();
233}
234
235static void crServerClose( unsigned int id )
236{
237 crError( "Client disconnected!" );
238 (void) id;
239}
240
241static void crServerCleanup( int sigio )
242{
243 crServerTearDown();
244
245 tearingdown = 0;
246}
247
248
249void
250crServerSetPort(int port)
251{
252 cr_server.tcpip_port = port;
253}
254
255
256
257static void
258crPrintHelp(void)
259{
260 printf("Usage: crserver [OPTIONS]\n");
261 printf("Options:\n");
262 printf(" -mothership URL Specifies URL for contacting the mothership.\n");
263 printf(" URL is of the form [protocol://]hostname[:port]\n");
264 printf(" -port N Specifies the port number this server will listen to.\n");
265 printf(" -help Prints this information.\n");
266}
267
268
269/**
270 * Do CRServer initializations. After this, we can begin servicing clients.
271 */
272void
273crServerInit(int argc, char *argv[])
274{
275 int i;
276 const char*env;
277 char *mothership = NULL;
278 CRMuralInfo *defaultMural;
279 int rc = VBoxVrInit();
280 if (!RT_SUCCESS(rc))
281 {
282 crWarning("VBoxVrInit failed, rc %d", rc);
283 return;
284 }
285
286 for (i = 1 ; i < argc ; i++)
287 {
288 if (!crStrcmp( argv[i], "-mothership" ))
289 {
290 if (i == argc - 1)
291 {
292 crError( "-mothership requires an argument" );
293 }
294 mothership = argv[i+1];
295 i++;
296 }
297 else if (!crStrcmp( argv[i], "-port" ))
298 {
299 /* This is the port on which we'll accept client connections */
300 if (i == argc - 1)
301 {
302 crError( "-port requires an argument" );
303 }
304 cr_server.tcpip_port = crStrToInt(argv[i+1]);
305 i++;
306 }
307 else if (!crStrcmp( argv[i], "-vncmode" ))
308 {
309 cr_server.vncMode = 1;
310 }
311 else if (!crStrcmp( argv[i], "-help" ))
312 {
313 crPrintHelp();
314 exit(0);
315 }
316 }
317
318 signal( SIGTERM, crServerCleanup );
319 signal( SIGINT, crServerCleanup );
320#ifndef WINDOWS
321 signal( SIGPIPE, SIG_IGN );
322#endif
323
324#if DEBUG_FP_EXCEPTIONS
325 {
326 fpu_control_t mask;
327 _FPU_GETCW(mask);
328 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
329 | _FPU_MASK_OM | _FPU_MASK_UM);
330 _FPU_SETCW(mask);
331 }
332#endif
333
334 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
335
336 if (cr_server.bUseMultipleContexts)
337 {
338 crInfo("Info: using multiple contexts!");
339 crDebug("Debug: using multiple contexts!");
340 }
341
342 env = crGetenv("CR_SERVER_CAPS");
343 if (env && env[0] != '\0')
344 {
345 cr_server.u32Caps = crServerVBoxParseNumerics(env, 0);
346 cr_server.u32Caps &= ~(CR_VBOX_CAP_TEX_PRESENT | CR_VBOX_CAP_NO_DWM_SUPPORT);
347 }
348 else
349 {
350 cr_server.u32Caps = CR_VBOX_CAP_TEX_PRESENT;
351 }
352
353 cr_server.firstCallCreateContext = GL_TRUE;
354 cr_server.firstCallMakeCurrent = GL_TRUE;
355 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
356
357 /*
358 * Create default mural info and hash table.
359 */
360 cr_server.muralTable = crAllocHashtable();
361 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
362 defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
363 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
364
365 cr_server.programTable = crAllocHashtable();
366
367 crNetInit(crServerRecv, crServerClose);
368 crStateInit();
369
370 crServerSetVBoxConfiguration();
371
372 crStateLimitsInit( &(cr_server.limits) );
373
374 /*
375 * Default context
376 */
377 cr_server.contextTable = crAllocHashtable();
378 cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
379
380 cr_server.dummyMuralTable = crAllocHashtable();
381
382 CrDemGlobalInit();
383
384 CrDemInit(&cr_server.PresentTexturepMap);
385 memset(cr_server.DisplaysInitMap, 0, sizeof (cr_server.DisplaysInitMap));
386 memset(cr_server.aDispplays, 0, sizeof (cr_server.aDispplays));
387
388 cr_server.fRootVrOn = GL_FALSE;
389 VBoxVrListInit(&cr_server.RootVr);
390 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
391
392 crMemset(&cr_server.RpwWorker, 0, sizeof (cr_server.RpwWorker));
393
394 env = crGetenv("CR_SERVER_BFB");
395 if (env)
396 {
397 cr_server.fBlitterMode = env[0] - '0';
398 }
399 else
400 {
401 cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED;
402 }
403 crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter));
404
405 crServerInitDispatch();
406 crServerInitTmpCtxDispatch();
407 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
408
409 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
410 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
411
412 cr_server.barriers = crAllocHashtable();
413 cr_server.semaphores = crAllocHashtable();
414}
415
416void crVBoxServerTearDown(void)
417{
418 crServerTearDown();
419}
420
421/**
422 * Do CRServer initializations. After this, we can begin servicing clients.
423 */
424GLboolean crVBoxServerInit(void)
425{
426 CRMuralInfo *defaultMural;
427 const char*env;
428 int rc = VBoxVrInit();
429 if (!RT_SUCCESS(rc))
430 {
431 crWarning("VBoxVrInit failed, rc %d", rc);
432 return GL_FALSE;
433 }
434
435#if DEBUG_FP_EXCEPTIONS
436 {
437 fpu_control_t mask;
438 _FPU_GETCW(mask);
439 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
440 | _FPU_MASK_OM | _FPU_MASK_UM);
441 _FPU_SETCW(mask);
442 }
443#endif
444
445 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
446
447 if (cr_server.bUseMultipleContexts)
448 {
449 crInfo("Info: using multiple contexts!");
450 crDebug("Debug: using multiple contexts!");
451 }
452
453 env = crGetenv("CR_SERVER_CAPS");
454 if (env && env[0] != '\0')
455 {
456 cr_server.u32Caps = crServerVBoxParseNumerics(env, 0);
457 cr_server.u32Caps &= ~(CR_VBOX_CAP_TEX_PRESENT | CR_VBOX_CAP_NO_DWM_SUPPORT);
458 }
459 else
460 {
461 cr_server.u32Caps = CR_VBOX_CAP_TEX_PRESENT;
462 }
463
464 crNetInit(crServerRecv, crServerClose);
465
466 cr_server.firstCallCreateContext = GL_TRUE;
467 cr_server.firstCallMakeCurrent = GL_TRUE;
468
469 cr_server.bIsInLoadingState = GL_FALSE;
470 cr_server.bIsInSavingState = GL_FALSE;
471 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
472
473 cr_server.pCleanupClient = NULL;
474
475 /*
476 * Create default mural info and hash table.
477 */
478 cr_server.muralTable = crAllocHashtable();
479 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
480 defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
481 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
482
483 cr_server.programTable = crAllocHashtable();
484
485 crStateInit();
486
487 crStateLimitsInit( &(cr_server.limits) );
488
489 cr_server.barriers = crAllocHashtable();
490 cr_server.semaphores = crAllocHashtable();
491
492 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
493 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
494
495 /*
496 * Default context
497 */
498 cr_server.contextTable = crAllocHashtable();
499
500 cr_server.dummyMuralTable = crAllocHashtable();
501
502 CrDemGlobalInit();
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 rc = crServerDisplaySaveState(pSSM);
1728 AssertRCReturn(rc, rc);
1729
1730 /* all context gl error states should have now be synced with chromium erro states,
1731 * reset the error if any */
1732 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1733 crWarning("crServer: glGetError %d after saving snapshot", err);
1734
1735 cr_server.bIsInSavingState = GL_FALSE;
1736
1737#ifdef DEBUG_misha
1738 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1739 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
1740#endif
1741
1742 return VINF_SUCCESS;
1743}
1744
1745static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1746{
1747 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1748 CRASSERT(pContextInfo);
1749 CRASSERT(pContextInfo->pContext);
1750 return pContextInfo->pContext;
1751}
1752
1753typedef struct CR_SERVER_LOADSTATE_READER
1754{
1755 PSSMHANDLE pSSM;
1756 uint32_t cbBuffer;
1757 uint32_t cbData;
1758 uint32_t offData;
1759 uint8_t *pu8Buffer;
1760} CR_SERVER_LOADSTATE_READER;
1761
1762static void crServerLsrInit(CR_SERVER_LOADSTATE_READER *pReader, PSSMHANDLE pSSM)
1763{
1764 memset(pReader, 0, sizeof (*pReader));
1765 pReader->pSSM = pSSM;
1766}
1767
1768static void crServerLsrTerm(CR_SERVER_LOADSTATE_READER *pReader)
1769{
1770 if (pReader->pu8Buffer)
1771 RTMemFree(pReader->pu8Buffer);
1772
1773 /* sanity */
1774 memset(pReader, 0, sizeof (*pReader));
1775}
1776
1777static int crServerLsrDataGetMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1778{
1779 int rc = VINF_SUCCESS;
1780 uint32_t cbRemaining = cbBuffer;
1781 if (pReader->cbData)
1782 {
1783 uint8_t cbData = RT_MIN(pReader->cbData, cbBuffer);
1784 memcpy(pvBuffer, pReader->pu8Buffer + pReader->offData, cbData);
1785 pReader->cbData -= cbData;
1786 pReader->offData += cbData;
1787
1788 cbRemaining -= cbData;
1789 pvBuffer = ((uint8_t*)pvBuffer) + cbData;
1790 }
1791
1792 if (cbRemaining)
1793 {
1794 rc = SSMR3GetMem(pReader->pSSM, pvBuffer, cbRemaining);
1795 AssertRC(rc);
1796 }
1797
1798 return rc;
1799}
1800
1801static int crServerLsrDataGetU32(CR_SERVER_LOADSTATE_READER *pReader, uint32_t *pu32)
1802{
1803 return crServerLsrDataGetMem(pReader, pu32, sizeof (*pu32));
1804}
1805
1806static int crServerLsrDataPutMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1807{
1808 if (!pReader->cbData && pReader->cbBuffer >= cbBuffer)
1809 {
1810 pReader->offData = 0;
1811 pReader->cbData = cbBuffer;
1812 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1813 }
1814 else if (pReader->offData >= cbBuffer)
1815 {
1816 pReader->offData -= cbBuffer;
1817 pReader->cbData += cbBuffer;
1818 memcpy(pReader->pu8Buffer + pReader->offData, pvBuffer, cbBuffer);
1819 }
1820 else
1821 {
1822 uint8_t *pu8Buffer = pReader->pu8Buffer;
1823
1824 pReader->pu8Buffer = (uint8_t*)RTMemAlloc(cbBuffer + pReader->cbData);
1825 if (!pReader->pu8Buffer)
1826 {
1827 crWarning("failed to allocate mem %d", cbBuffer + pReader->cbData);
1828 return VERR_NO_MEMORY;
1829 }
1830
1831 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1832 if (pu8Buffer)
1833 {
1834 memcpy(pReader->pu8Buffer + cbBuffer, pu8Buffer + pReader->offData, pReader->cbData);
1835 RTMemFree(pu8Buffer);
1836 }
1837 else
1838 {
1839 Assert(!pReader->cbData);
1840 }
1841 pReader->offData = 0;
1842 pReader->cbData += cbBuffer;
1843 }
1844
1845 return VINF_SUCCESS;
1846}
1847
1848/* data to be skipped */
1849
1850typedef struct CR_SERVER_BUGGY_MURAL_DATA_2
1851{
1852 void*ListHead_pNext;
1853 void*ListHead_pPrev;
1854 uint32_t cEntries;
1855} CR_SERVER_BUGGY_MURAL_DATA_2;
1856typedef struct CR_SERVER_BUGGY_MURAL_DATA_1
1857{
1858 /* VBOXVR_COMPOSITOR_ENTRY Ce; */
1859 void*Ce_Node_pNext;
1860 void*Ce_Node_pPrev;
1861 CR_SERVER_BUGGY_MURAL_DATA_2 Vr;
1862 /* VBOXVR_TEXTURE Tex; */
1863 uint32_t Tex_width;
1864 uint32_t Tex_height;
1865 uint32_t Tex_target;
1866 uint32_t Tex_hwid;
1867 /* RTPOINT Pos; */
1868 uint32_t Pos_x;
1869 uint32_t Pos_y;
1870 uint32_t fChanged;
1871 uint32_t cRects;
1872 void* paSrcRects;
1873 void* paDstRects;
1874} CR_SERVER_BUGGY_MURAL_DATA_1;
1875
1876typedef struct CR_SERVER_BUGGY_MURAL_DATA_4
1877{
1878 uint32_t u32Magic;
1879 int32_t cLockers;
1880 RTNATIVETHREAD NativeThreadOwner;
1881 int32_t cNestings;
1882 uint32_t fFlags;
1883 void* EventSem;
1884 R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec;
1885 RTHCPTR Alignment;
1886} CR_SERVER_BUGGY_MURAL_DATA_4;
1887
1888typedef struct CR_SERVER_BUGGY_MURAL_DATA_3
1889{
1890 void*Compositor_List_pNext;
1891 void*Compositor_List_pPrev;
1892 void*Compositor_pfnEntryRemoved;
1893 float StretchX;
1894 float StretchY;
1895 uint32_t cRects;
1896 uint32_t cRectsBuffer;
1897 void*paSrcRects;
1898 void*paDstRects;
1899 CR_SERVER_BUGGY_MURAL_DATA_4 CritSect;
1900} CR_SERVER_BUGGY_MURAL_DATA_3;
1901
1902typedef struct CR_SERVER_BUGGY_MURAL_DATA
1903{
1904 uint8_t fRootVrOn;
1905 CR_SERVER_BUGGY_MURAL_DATA_1 RootVrCEntry;
1906 CR_SERVER_BUGGY_MURAL_DATA_3 RootVrCompositor;
1907} CR_SERVER_BUGGY_MURAL_DATA;
1908
1909AssertCompile(sizeof (CR_SERVER_BUGGY_MURAL_DATA) < sizeof (CRClient));
1910
1911static int32_t crVBoxServerLoadMurals(CR_SERVER_LOADSTATE_READER *pReader, uint32_t version)
1912{
1913 unsigned long key;
1914 uint32_t ui, uiNumElems;
1915 bool fBuggyMuralData = false;
1916 /* Load windows */
1917 int32_t rc = crServerLsrDataGetU32(pReader, &uiNumElems);
1918 AssertRCReturn(rc, rc);
1919 for (ui=0; ui<uiNumElems; ++ui)
1920 {
1921 CRCreateInfo_t createInfo;
1922 char psz[200];
1923 GLint winID;
1924 unsigned long key;
1925
1926 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1927 AssertRCReturn(rc, rc);
1928 rc = crServerLsrDataGetMem(pReader, &createInfo, sizeof(createInfo));
1929 AssertRCReturn(rc, rc);
1930
1931 CRASSERT(!pReader->cbData);
1932
1933 if (createInfo.pszDpyName)
1934 {
1935 rc = SSMR3GetStrZEx(pReader->pSSM, psz, 200, NULL);
1936 AssertRCReturn(rc, rc);
1937 createInfo.pszDpyName = psz;
1938 }
1939
1940 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1941 CRASSERT((int64_t)winID == (int64_t)key);
1942 }
1943
1944 /* Load cr_server.muralTable */
1945 rc = SSMR3GetU32(pReader->pSSM, &uiNumElems);
1946 AssertRCReturn(rc, rc);
1947 for (ui=0; ui<uiNumElems; ++ui)
1948 {
1949 CRMuralInfo muralInfo;
1950 CRMuralInfo *pActualMural = NULL;
1951
1952 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1953 AssertRCReturn(rc, rc);
1954 rc = crServerLsrDataGetMem(pReader, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1955 AssertRCReturn(rc, rc);
1956
1957 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1958 muralInfo.bFbDraw = GL_TRUE;
1959
1960 if (!ui && version == SHCROGL_SSM_VERSION_WITH_BUGGY_MURAL_INFO)
1961 {
1962 /* Lookahead buffer used to determine whether the data erroneously stored root visible regions data */
1963 union
1964 {
1965 void * apv[1];
1966 CR_SERVER_BUGGY_MURAL_DATA Data;
1967 /* need to chak spuWindow, so taking the offset of filed following it*/
1968 uint8_t au8[RT_OFFSETOF(CRMuralInfo, screenId)];
1969 RTRECT aVisRects[sizeof (CR_SERVER_BUGGY_MURAL_DATA) / sizeof (RTRECT)];
1970 } LaBuf;
1971
1972 do {
1973 /* first value is bool (uint8_t) value followed by pointer-size-based alignment.
1974 * the mural memory is zero-initialized initially, so we can be sure the padding is zeroed */
1975 rc = crServerLsrDataGetMem(pReader, &LaBuf, sizeof (LaBuf));
1976 AssertRCReturn(rc, rc);
1977 if (LaBuf.apv[0] != NULL && LaBuf.apv[0] != ((void*)1))
1978 break;
1979
1980 /* check that the pointers are either valid or NULL */
1981 if(LaBuf.Data.RootVrCEntry.Ce_Node_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pNext))
1982 break;
1983 if(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev))
1984 break;
1985 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext))
1986 break;
1987 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev))
1988 break;
1989
1990 /* the entry can can be the only one within the (mural) compositor,
1991 * so its compositor entry node can either contain NULL pNext and pPrev,
1992 * or both of them pointing to compositor's list head */
1993 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext != LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1994 break;
1995
1996 /* can either both or none be NULL */
1997 if (!LaBuf.Data.RootVrCEntry.Ce_Node_pNext != !LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1998 break;
1999
2000 if (!LaBuf.Data.fRootVrOn)
2001 {
2002 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext || LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
2003 break;
2004
2005 /* either non-initialized (zeroed) or empty list */
2006 if (LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext != LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
2007 break;
2008
2009 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
2010 break;
2011 }
2012 else
2013 {
2014 /* the entry should be initialized */
2015 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext)
2016 break;
2017 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
2018 break;
2019
2020 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
2021 {
2022 /* entry should be in compositor list*/
2023 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev == NULL)
2024 break;
2025 CRASSERT(LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2026 }
2027 else
2028 {
2029 /* entry should NOT be in compositor list*/
2030 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev != NULL)
2031 break;
2032 CRASSERT(!LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2033 }
2034 }
2035
2036#if 0
2037 if (muralInfo.pVisibleRects)
2038 {
2039 int j;
2040 int cRects = RT_MIN(muralInfo.cVisibleRects, RT_ELEMENTS(LaBuf.aVisRects));
2041 CRASSERT(cRects);
2042 for (j = 0; j < cRects; ++j)
2043 {
2044 PRTRECT pRect = &LaBuf.aVisRects[j];
2045 if (pRect->xLeft >= pRect->xRight)
2046 break;
2047 if (pRect->yTop >= pRect->yBottom)
2048 break;
2049 if (pRect->xLeft < 0 || pRect->xRight < 0
2050 || pRect->yTop < 0 || pRect->yBottom < 0)
2051 break;
2052 if (pRect->xLeft > (GLint)muralInfo.width
2053 || pRect->xRight > (GLint)muralInfo.width)
2054 break;
2055 if (pRect->yTop > (GLint)muralInfo.height
2056 || pRect->yBottom > (GLint)muralInfo.height)
2057 break;
2058 }
2059
2060 if (j < cRects)
2061 {
2062 fBuggyMuralData = true;
2063 break;
2064 }
2065 }
2066
2067 if (muralInfo.pVisibleRects)
2068 {
2069 /* @todo: do we actually need any further checks here? */
2070 fBuggyMuralData = true;
2071 break;
2072 }
2073
2074 /* no visible regions*/
2075
2076 if (ui == uiNumElems - 1)
2077 {
2078 /* this is the last mural, next it goes idsPool, whose content can not match the above template again */
2079 fBuggyMuralData = true;
2080 break;
2081 }
2082
2083 /* next it goes a next mural info */
2084// if (!fExpectPtr)
2085// {
2086// CRMuralInfo *pNextSpuWindowInfoMural = (CRMuralInfo*)((void*)&LaBuf);
2087// if (!pNextSpuWindowInfoMural->spuWindow)
2088// fBuggyMuralData = true;
2089//
2090// break;
2091// }
2092#endif
2093 /* fExpectPtr == true, the valid pointer values should not match possible mural width/height/position */
2094 fBuggyMuralData = true;
2095 break;
2096
2097 } while (0);
2098
2099 rc = crServerLsrDataPutMem(pReader, &LaBuf, sizeof (LaBuf));
2100 AssertRCReturn(rc, rc);
2101 }
2102
2103 if (fBuggyMuralData)
2104 {
2105 CR_SERVER_BUGGY_MURAL_DATA Tmp;
2106 rc = crServerLsrDataGetMem(pReader, &Tmp, sizeof (Tmp));
2107 AssertRCReturn(rc, rc);
2108 }
2109
2110 if (muralInfo.pVisibleRects)
2111 {
2112 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
2113 if (!muralInfo.pVisibleRects)
2114 {
2115 return VERR_NO_MEMORY;
2116 }
2117
2118 rc = crServerLsrDataGetMem(pReader, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
2119 AssertRCReturn(rc, rc);
2120 }
2121
2122 pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);
2123 CRASSERT(pActualMural);
2124
2125 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
2126 {
2127 rc = crServerLsrDataGetMem(pReader, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
2128 CRASSERT(rc == VINF_SUCCESS);
2129 }
2130
2131 /* Restore windows geometry info */
2132 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
2133 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
2134 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
2135 if (muralInfo.bReceivedRects)
2136 {
2137 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
2138 }
2139 crServerDispatchWindowShow(key, muralInfo.bVisible);
2140
2141 if (muralInfo.pVisibleRects)
2142 {
2143 crFree(muralInfo.pVisibleRects);
2144 }
2145
2146 Assert(!pActualMural->fDataPresented);
2147
2148 if (version >= SHCROGL_SSM_VERSION_WITH_PRESENT_STATE)
2149 pActualMural->fDataPresented = muralInfo.fDataPresented;
2150 else
2151 pActualMural->fDataPresented = crServerVBoxCompositionPresentNeeded(pActualMural);
2152 }
2153
2154 CRASSERT(RT_SUCCESS(rc));
2155 return VINF_SUCCESS;
2156}
2157
2158static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
2159 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
2160{
2161 CRContext *pContext = pContextInfo->pContext;
2162 int32_t rc = VINF_SUCCESS;
2163 GLuint i;
2164 /* can apply the data right away */
2165 struct
2166 {
2167 CRFBData data;
2168 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
2169 } Data;
2170
2171 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
2172
2173 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
2174 {
2175 if (!pMural->width || !pMural->height)
2176 return VINF_SUCCESS;
2177
2178 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
2179 if (!RT_SUCCESS(rc))
2180 {
2181 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2182 return rc;
2183 }
2184 }
2185 else
2186 {
2187 GLint storedWidth, storedHeight;
2188
2189 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2190 {
2191 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
2192 CRASSERT(cr_server.currentMural == pMural);
2193 storedWidth = pMural->width;
2194 storedHeight = pMural->height;
2195 }
2196 else
2197 {
2198 storedWidth = pContext->buffer.storedWidth;
2199 storedHeight = pContext->buffer.storedHeight;
2200 }
2201
2202 if (!storedWidth || !storedHeight)
2203 return VINF_SUCCESS;
2204
2205 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
2206 if (!RT_SUCCESS(rc))
2207 {
2208 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2209 return rc;
2210 }
2211 }
2212
2213 CRASSERT(Data.data.cElements);
2214
2215 for (i = 0; i < Data.data.cElements; ++i)
2216 {
2217 CRFBDataElement * pEl = &Data.data.aElements[i];
2218 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
2219 AssertRCReturn(rc, rc);
2220 }
2221
2222 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2223 {
2224 CRBufferState *pBuf = &pContext->buffer;
2225 /* can apply the data right away */
2226 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2227 CRASSERT(cr_server.currentMural);
2228
2229 cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
2230 0,
2231 pContextInfo->SpuContext >= 0
2232 ? pContextInfo->SpuContext
2233 : cr_server.MainContextInfo.SpuContext);
2234 crStateApplyFBImage(pContext, &Data.data);
2235 CRASSERT(!pBuf->pFrontImg);
2236 CRASSERT(!pBuf->pBackImg);
2237 crVBoxServerFBImageDataTerm(&Data.data);
2238
2239 if ((pMural->fPresentMode & CR_SERVER_REDIR_F_FBO) && pMural->fDataPresented && crServerVBoxCompositionPresentNeeded(pMural))
2240 {
2241 crServerPresentFBO(pMural);
2242 }
2243
2244 CRASSERT(cr_server.currentMural);
2245 cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
2246 0,
2247 cr_server.currentCtxInfo->SpuContext >= 0
2248 ? cr_server.currentCtxInfo->SpuContext
2249 : cr_server.MainContextInfo.SpuContext);
2250 }
2251 else
2252 {
2253 CRBufferState *pBuf = &pContext->buffer;
2254 CRASSERT(!pBuf->pFrontImg);
2255 CRASSERT(!pBuf->pBackImg);
2256 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
2257
2258 if (Data.data.cElements)
2259 {
2260 CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
2261 if (!RT_SUCCESS(rc))
2262 {
2263 crVBoxServerFBImageDataTerm(&Data.data);
2264 crWarning("crAlloc failed");
2265 return VERR_NO_MEMORY;
2266 }
2267
2268 crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
2269 pBuf->pFrontImg = pLazyData;
2270 }
2271 }
2272
2273 CRASSERT(RT_SUCCESS(rc));
2274 return VINF_SUCCESS;
2275}
2276
2277DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
2278{
2279 int32_t rc, i;
2280 uint32_t ui, uiNumElems;
2281 unsigned long key;
2282 GLenum err;
2283 CR_SERVER_LOADSTATE_READER Reader;
2284
2285 if (!cr_server.bIsInLoadingState)
2286 {
2287 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
2288 cr_server.bIsInLoadingState = GL_TRUE;
2289
2290 /* Read number of clients */
2291 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
2292 AssertRCReturn(rc, rc);
2293 }
2294
2295 g_hackVBoxServerSaveLoadCallsLeft--;
2296
2297 /* Do nothing until we're being called last time */
2298 if (g_hackVBoxServerSaveLoadCallsLeft>0)
2299 {
2300 return VINF_SUCCESS;
2301 }
2302
2303 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
2304 {
2305 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2306 }
2307
2308 crServerLsrInit(&Reader, pSSM);
2309
2310#ifdef DEBUG_misha
2311#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
2312#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
2313
2314 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2315 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
2316#endif
2317
2318 /* Load and recreate rendering contexts */
2319 rc = SSMR3GetU32(pSSM, &uiNumElems);
2320 AssertRCReturn(rc, rc);
2321 for (ui=0; ui<uiNumElems; ++ui)
2322 {
2323 CRCreateInfo_t createInfo;
2324 char psz[200];
2325 GLint ctxID;
2326 CRContextInfo* pContextInfo;
2327 CRContext* pContext;
2328
2329 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2330 AssertRCReturn(rc, rc);
2331 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
2332 AssertRCReturn(rc, rc);
2333
2334 if (createInfo.pszDpyName)
2335 {
2336 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
2337 AssertRCReturn(rc, rc);
2338 createInfo.pszDpyName = psz;
2339 }
2340
2341 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
2342 CRASSERT((int64_t)ctxID == (int64_t)key);
2343
2344 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2345 CRASSERT(pContextInfo);
2346 CRASSERT(pContextInfo->pContext);
2347 pContext = pContextInfo->pContext;
2348 pContext->shared->id=-1;
2349 }
2350
2351 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2352 {
2353 CRASSERT(!Reader.pu8Buffer);
2354 /* we have a mural data here */
2355 rc = crVBoxServerLoadMurals(&Reader, version);
2356 AssertRCReturn(rc, rc);
2357 CRASSERT(!Reader.pu8Buffer);
2358 }
2359
2360 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
2361 {
2362 /* set the current client to allow doing crServerPerformMakeCurrent later */
2363 CRASSERT(cr_server.numClients);
2364 cr_server.curClient = cr_server.clients[0];
2365 }
2366
2367 rc = crStateLoadGlobals(pSSM, version);
2368 AssertRCReturn(rc, rc);
2369
2370 if (uiNumElems)
2371 {
2372 /* ensure we have main context set up as current */
2373 CRMuralInfo *pMural;
2374 CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
2375 CRASSERT(!cr_server.currentCtxInfo);
2376 CRASSERT(!cr_server.currentMural);
2377 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
2378 CRASSERT(pMural);
2379 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
2380 }
2381
2382 /* Restore context state data */
2383 for (ui=0; ui<uiNumElems; ++ui)
2384 {
2385 CRContextInfo* pContextInfo;
2386 CRContext *pContext;
2387 CRMuralInfo *pMural = NULL;
2388 int32_t winId = 0;
2389
2390 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2391 AssertRCReturn(rc, rc);
2392
2393 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2394 CRASSERT(pContextInfo);
2395 CRASSERT(pContextInfo->pContext);
2396 pContext = pContextInfo->pContext;
2397
2398 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2399 {
2400 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
2401 AssertRCReturn(rc, rc);
2402
2403 if (winId)
2404 {
2405 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
2406 CRASSERT(pMural);
2407 }
2408 else
2409 {
2410 /* null winId means a dummy mural, get it */
2411 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
2412 CRASSERT(pMural);
2413 }
2414 }
2415
2416 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
2417 AssertRCReturn(rc, rc);
2418
2419 /*Restore front/back buffer images*/
2420 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2421 AssertRCReturn(rc, rc);
2422 }
2423
2424 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2425 {
2426 CRContextInfo *pContextInfo;
2427 CRMuralInfo *pMural;
2428 GLint ctxId;
2429
2430 rc = SSMR3GetU32(pSSM, &uiNumElems);
2431 AssertRCReturn(rc, rc);
2432 for (ui=0; ui<uiNumElems; ++ui)
2433 {
2434 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
2435 CRMuralInfo *pInitialCurMural;
2436
2437 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2438 AssertRCReturn(rc, rc);
2439
2440 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
2441 AssertRCReturn(rc, rc);
2442
2443 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
2444 CRASSERT(pMural);
2445 if (ctxId)
2446 {
2447 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
2448 CRASSERT(pContextInfo);
2449 }
2450 else
2451 pContextInfo = &cr_server.MainContextInfo;
2452
2453 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
2454 pInitialCurMural = pContextInfo->currentMural;
2455
2456 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2457 AssertRCReturn(rc, rc);
2458
2459 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
2460 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
2461 pContextInfo->currentMural = pInitialCurMural;
2462 }
2463
2464 CRASSERT(!uiNumElems || cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2465
2466 cr_server.curClient = NULL;
2467 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
2468 }
2469 else
2470 {
2471 CRServerFreeIDsPool_t dummyIdsPool;
2472
2473 CRASSERT(!Reader.pu8Buffer);
2474
2475 /* we have a mural data here */
2476 rc = crVBoxServerLoadMurals(&Reader, version);
2477 AssertRCReturn(rc, rc);
2478
2479 /* not used any more, just read it out and ignore */
2480 rc = crServerLsrDataGetMem(&Reader, &dummyIdsPool, sizeof(dummyIdsPool));
2481 CRASSERT(rc == VINF_SUCCESS);
2482 }
2483
2484 /* Load clients info */
2485 for (i = 0; i < cr_server.numClients; i++)
2486 {
2487 if (cr_server.clients[i] && cr_server.clients[i]->conn)
2488 {
2489 CRClient *pClient = cr_server.clients[i];
2490 CRClient client;
2491 unsigned long ctxID=-1, winID=-1;
2492
2493 rc = crServerLsrDataGetU32(&Reader, &ui);
2494 AssertRCReturn(rc, rc);
2495 /* If this assert fires, then we should search correct client in the list first*/
2496 CRASSERT(ui == pClient->conn->u32ClientID);
2497
2498 if (version>=4)
2499 {
2500 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMajor);
2501 AssertRCReturn(rc, rc);
2502
2503 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMinor);
2504 AssertRCReturn(rc, rc);
2505 }
2506
2507 rc = crServerLsrDataGetMem(&Reader, &client, sizeof(client));
2508 CRASSERT(rc == VINF_SUCCESS);
2509
2510 client.conn = pClient->conn;
2511 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2512 * and fail to bind old textures.
2513 */
2514 /*client.number = pClient->number;*/
2515 *pClient = client;
2516
2517 pClient->currentContextNumber = -1;
2518 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2519 pClient->currentMural = NULL;
2520 pClient->currentWindow = -1;
2521
2522 cr_server.curClient = pClient;
2523
2524 if (client.currentCtxInfo && client.currentContextNumber > 0)
2525 {
2526 rc = crServerLsrDataGetMem(&Reader, &ctxID, sizeof(ctxID));
2527 AssertRCReturn(rc, rc);
2528 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2529 CRASSERT(client.currentCtxInfo);
2530 CRASSERT(client.currentCtxInfo->pContext);
2531 //pClient->currentCtx = client.currentCtx;
2532 //pClient->currentContextNumber = ctxID;
2533 }
2534
2535 if (client.currentMural && client.currentWindow > 0)
2536 {
2537 rc = crServerLsrDataGetMem(&Reader, &winID, sizeof(winID));
2538 AssertRCReturn(rc, rc);
2539 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2540 CRASSERT(client.currentMural);
2541 //pClient->currentMural = client.currentMural;
2542 //pClient->currentWindow = winID;
2543 }
2544
2545 CRASSERT(!Reader.cbData);
2546
2547 /* Restore client active context and window */
2548 crServerDispatchMakeCurrent(winID, 0, ctxID);
2549
2550 if (0)
2551 {
2552// CRContext *tmpCtx;
2553// CRCreateInfo_t *createInfo;
2554 GLfloat one[4] = { 1, 1, 1, 1 };
2555 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
2556
2557 crServerDispatchMakeCurrent(winID, 0, ctxID);
2558
2559 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
2560
2561 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
2562 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
2563 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
2564#ifdef CR_ARB_texture_cube_map
2565 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
2566#endif
2567#ifdef CR_NV_texture_rectangle
2568 //@todo this doesn't work as expected
2569 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
2570#endif
2571 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
2572 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
2573 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
2574
2575 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
2576 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
2577 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
2578
2579 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
2580 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
2581
2582 //crStateViewport( 0, 0, 600, 600 );
2583 //pClient->currentMural->viewportValidated = GL_FALSE;
2584 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
2585
2586 //crStateMatrixMode(GL_PROJECTION);
2587 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
2588
2589 //crStateLoadIdentity();
2590 //cr_server.head_spu->dispatch_table.LoadIdentity();
2591
2592 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2593 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2594
2595 //crStateMatrixMode(GL_MODELVIEW);
2596 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
2597 //crServerDispatchLoadIdentity();
2598 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2599 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2600 //crServerDispatchLoadIdentity();
2601
2602 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
2603 CRASSERT(createInfo);
2604 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
2605 CRASSERT(tmpCtx);
2606 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
2607 crStateDestroyContext(tmpCtx);*/
2608 }
2609 }
2610 }
2611
2612 //crServerDispatchMakeCurrent(-1, 0, -1);
2613
2614 cr_server.curClient = NULL;
2615
2616 if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_INFO)
2617 {
2618 rc = crServerDisplayLoadState(pSSM, version);
2619 AssertRCReturn(rc, rc);
2620 }
2621
2622 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2623 crWarning("crServer: glGetError %d after loading snapshot", err);
2624
2625 cr_server.bIsInLoadingState = GL_FALSE;
2626
2627#if 0
2628 crVBoxServerCheckConsistency();
2629#endif
2630
2631#ifdef DEBUG_misha
2632 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2633 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
2634#endif
2635
2636 CRASSERT(!Reader.cbData);
2637 crServerLsrTerm(&Reader);
2638
2639 return VINF_SUCCESS;
2640}
2641
2642#define SCREEN(i) (cr_server.screen[i])
2643#define MAPPED(screen) ((screen).winID != 0)
2644
2645extern DECLEXPORT(void) crServerVBoxSetNotifyEventCB(PFNCRSERVERNOTIFYEVENT pfnCb)
2646{
2647 cr_server.pfnNotifyEventCB = pfnCb;
2648}
2649
2650void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void*pvData)
2651{
2652 /* this is something unexpected, but just in case */
2653 if (idScreen >= cr_server.screenCount)
2654 {
2655 crWarning("invalid screen id %d", idScreen);
2656 return;
2657 }
2658
2659 cr_server.pfnNotifyEventCB(idScreen, uEvent, pvData);
2660}
2661
2662void crVBoxServerCheckVisibilityEvent(int32_t idScreen)
2663{
2664 if (cr_server.cDisableEvents)
2665 return;
2666
2667 if (idScreen < 0)
2668 {
2669 int32_t i = 0;
2670 for (; i < cr_server.screenCount; ++i)
2671 {
2672 crVBoxServerCheckVisibilityEvent(i);
2673 }
2674 return;
2675 }
2676
2677 CRASSERT(idScreen < cr_server.screenCount);
2678
2679 if (!cr_server.aWinVisibilityInfos[idScreen].fVisibleChanged
2680 && !cr_server.aWinVisibilityInfos[idScreen].cVisibleWindows == !cr_server.aWinVisibilityInfos[idScreen].fLastReportedVisible)
2681 return;
2682
2683 crVBoxServerNotifyEvent(idScreen, VBOX3D_NOTIFY_EVENT_TYPE_VISIBLE_3DDATA,
2684 cr_server.aWinVisibilityInfos[idScreen].cVisibleWindows ? (void*)1 : NULL);
2685
2686 cr_server.aWinVisibilityInfos[idScreen].fLastReportedVisible = cr_server.aWinVisibilityInfos[idScreen].cVisibleWindows ? 1 : 0;
2687 cr_server.aWinVisibilityInfos[idScreen].fVisibleChanged = 0;
2688}
2689
2690static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2691{
2692 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2693 int *sIndex = (int*) data2;
2694
2695 Assert(pMI->cDisabled);
2696
2697 if (pMI->screenId == *sIndex)
2698 {
2699 crServerWindowReparent(pMI);
2700 }
2701}
2702
2703static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
2704{
2705 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2706 (void) data2;
2707
2708 crServerCheckMuralGeometry(pMI);
2709}
2710
2711DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2712{
2713 int i;
2714
2715 if (sCount>CR_MAX_GUEST_MONITORS)
2716 return VERR_INVALID_PARAMETER;
2717
2718 /*Shouldn't happen yet, but to be safe in future*/
2719 for (i=0; i<cr_server.screenCount; ++i)
2720 {
2721 if (MAPPED(SCREEN(i)))
2722 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
2723 return VERR_NOT_IMPLEMENTED;
2724 }
2725
2726 cr_server.screenCount = sCount;
2727
2728 for (i=0; i<sCount; ++i)
2729 {
2730 SCREEN(i).winID = 0;
2731 }
2732
2733 return VINF_SUCCESS;
2734}
2735
2736DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2737{
2738 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2739
2740 if (sIndex<0 || sIndex>=cr_server.screenCount)
2741 return VERR_INVALID_PARAMETER;
2742
2743 if (MAPPED(SCREEN(sIndex)))
2744 {
2745 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
2746
2747 SCREEN(sIndex).winID = 0;
2748 renderspuSetWindowId(0);
2749
2750 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2751
2752 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2753
2754 if (pDisplay)
2755 CrDpReparent(pDisplay, &SCREEN(sIndex));
2756 }
2757
2758 renderspuSetWindowId(SCREEN(0).winID);
2759
2760 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2761
2762 return VINF_SUCCESS;
2763}
2764
2765DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2766{
2767 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2768
2769 if (sIndex<0 || sIndex>=cr_server.screenCount)
2770 return VERR_INVALID_PARAMETER;
2771
2772 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2773 {
2774 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2775 crVBoxServerUnmapScreen(sIndex);
2776 }
2777
2778 SCREEN(sIndex).winID = winID;
2779 SCREEN(sIndex).x = x;
2780 SCREEN(sIndex).y = y;
2781 SCREEN(sIndex).w = w;
2782 SCREEN(sIndex).h = h;
2783
2784 renderspuSetWindowId(SCREEN(sIndex).winID);
2785 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2786
2787 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2788 renderspuSetWindowId(SCREEN(0).winID);
2789
2790 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2791
2792#ifndef WINDOWS
2793 /*Restore FB content for clients, which have current window on a screen being remapped*/
2794 {
2795 GLint i;
2796
2797 for (i = 0; i < cr_server.numClients; i++)
2798 {
2799 cr_server.curClient = cr_server.clients[i];
2800 if (cr_server.curClient->currentCtxInfo
2801 && cr_server.curClient->currentCtxInfo->pContext
2802 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2803 && cr_server.curClient->currentMural
2804 && cr_server.curClient->currentMural->screenId == sIndex
2805 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2806 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2807 {
2808 int clientWindow = cr_server.curClient->currentWindow;
2809 int clientContext = cr_server.curClient->currentContextNumber;
2810 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2811
2812 if (clientWindow && clientWindow != cr_server.currentWindow)
2813 {
2814 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2815 }
2816
2817 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2818 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2819 }
2820 }
2821 cr_server.curClient = NULL;
2822 }
2823#endif
2824
2825 {
2826 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
2827 if (pDisplay)
2828 CrDpReparent(pDisplay, &SCREEN(sIndex));
2829 }
2830
2831 return VINF_SUCCESS;
2832}
2833
2834static int crVBoxServerUpdateMuralRootVisibleRegion(CRMuralInfo *pMI)
2835{
2836 GLboolean fForcePresent;
2837
2838 int rc = VINF_SUCCESS;
2839
2840 fForcePresent = crServerVBoxCompositionPresentNeeded(pMI);
2841
2842 crServerVBoxCompositionDisableEnter(pMI);
2843
2844 if (cr_server.fRootVrOn)
2845 {
2846 if (!pMI->fRootVrOn)
2847 {
2848 CrVrScrCompositorInit(&pMI->RootVrCompositor);
2849 }
2850
2851 rc = crServerMuralSynchRootVr(pMI);
2852 if (!RT_SUCCESS(rc))
2853 {
2854 crWarning("crServerMuralSynchRootVr failed, rc %d", rc);
2855 goto end;
2856 }
2857 }
2858 else
2859 {
2860 CrVrScrCompositorClear(&pMI->RootVrCompositor);
2861 }
2862
2863 pMI->fRootVrOn = cr_server.fRootVrOn;
2864
2865 crServerWindowVisibleRegion(pMI);
2866
2867end:
2868 crServerVBoxCompositionDisableLeave(pMI, fForcePresent);
2869
2870 return rc;
2871}
2872
2873static void crVBoxServerSetRootVisibleRegionCB(unsigned long key, void *data1, void *data2)
2874{
2875 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2876
2877 if (!pMI->CreateInfo.externalID)
2878 return;
2879 (void) data2;
2880
2881 crVBoxServerUpdateMuralRootVisibleRegion(pMI);
2882}
2883
2884DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects)
2885{
2886 int32_t rc = VINF_SUCCESS;
2887
2888 /* non-zero rects pointer indicate rects are present and switched on
2889 * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions,
2890 * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */
2891 if (pRects)
2892 {
2893 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
2894 rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL);
2895 if (!RT_SUCCESS(rc))
2896 {
2897 crWarning("VBoxVrListRectsSet failed! rc %d", rc);
2898 return rc;
2899 }
2900
2901 cr_server.fRootVrOn = GL_TRUE;
2902 }
2903 else
2904 {
2905 if (!cr_server.fRootVrOn)
2906 return VINF_SUCCESS;
2907
2908 VBoxVrListClear(&cr_server.RootVr);
2909
2910 cr_server.fRootVrOn = GL_FALSE;
2911 }
2912
2913 crHashtableWalk(cr_server.muralTable, crVBoxServerSetRootVisibleRegionCB, NULL);
2914
2915 return VINF_SUCCESS;
2916}
2917
2918DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2919{
2920 cr_server.pfnPresentFBO = pfnPresentFBO;
2921}
2922
2923int32_t crServerSetOffscreenRenderingMode(GLuint value)
2924{
2925 /* sanitize values */
2926 value = crServerRedirModeAdjust(value);
2927
2928 if (value == CR_SERVER_REDIR_F_NONE)
2929 {
2930 crWarning("crServerSetOffscreenRenderingMode: value undefined");
2931 }
2932
2933 if (cr_server.fPresentMode==value)
2934 {
2935 return VINF_SUCCESS;
2936 }
2937
2938 if ((value & CR_SERVER_REDIR_F_FBO) && !crServerSupportRedirMuralFBO())
2939 {
2940 crWarning("crServerSetOffscreenRenderingMode: FBO not supported");
2941 return VERR_NOT_SUPPORTED;
2942 }
2943
2944 cr_server.fPresentMode=value;
2945
2946 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2947
2948 return VINF_SUCCESS;
2949}
2950
2951DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2952{
2953 return crServerSetOffscreenRenderingMode(value ?
2954 cr_server.fPresentModeDefault | CR_SERVER_REDIR_F_FBO_RAM_VRDP | cr_server.fVramPresentModeDefault
2955 : cr_server.fPresentModeDefault);
2956}
2957
2958static void crVBoxServerOutputRedirectCB(unsigned long key, void *data1, void *data2)
2959{
2960 CRMuralInfo *mural = (CRMuralInfo*) data1;
2961
2962 if (!mural->CreateInfo.externalID)
2963 return;
2964
2965 if (cr_server.bUseOutputRedirect)
2966 crServerPresentOutputRedirect(mural);
2967 else
2968 crServerOutputRedirectCheckEnableDisable(mural);
2969}
2970
2971DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2972{
2973 /* No need for a synchronization as this is single threaded. */
2974 if (pCallbacks)
2975 {
2976 cr_server.outputRedirect = *pCallbacks;
2977 cr_server.bUseOutputRedirect = true;
2978 }
2979 else
2980 {
2981 cr_server.bUseOutputRedirect = false;
2982 }
2983
2984 /* dynamically intercept already existing output */
2985 crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
2986
2987 return VINF_SUCCESS;
2988}
2989
2990static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2)
2991{
2992 CRMuralInfo *mural = (CRMuralInfo*) data1;
2993 int *sIndex = (int*) data2;
2994
2995 if (mural->screenId != *sIndex)
2996 return;
2997
2998 crServerCheckMuralGeometry(mural);
2999}
3000
3001
3002DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
3003{
3004 CRScreenViewportInfo *pVieport;
3005 GLboolean fPosChanged, fSizeChanged;
3006
3007 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
3008
3009 if (sIndex<0 || sIndex>=cr_server.screenCount)
3010 {
3011 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
3012 return VERR_INVALID_PARAMETER;
3013 }
3014
3015 pVieport = &cr_server.screenVieport[sIndex];
3016 fPosChanged = (pVieport->x != x || pVieport->y != y);
3017 fSizeChanged = (pVieport->w != w || pVieport->h != h);
3018
3019 if (!fPosChanged && !fSizeChanged)
3020 {
3021 crDebug("crVBoxServerSetScreenViewport: no changes");
3022 return VINF_SUCCESS;
3023 }
3024
3025 if (fPosChanged)
3026 {
3027 pVieport->x = x;
3028 pVieport->y = y;
3029
3030 crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex);
3031 }
3032
3033 if (fSizeChanged)
3034 {
3035 pVieport->w = w;
3036 pVieport->h = h;
3037
3038 /* no need to do anything here actually */
3039 }
3040
3041 if (fPosChanged || fSizeChanged)
3042 {
3043 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
3044 if (pDisplay)
3045 CrDpResize(pDisplay, SCREEN(sIndex).x, SCREEN(sIndex).y, SCREEN(sIndex).w, SCREEN(sIndex).h);
3046 }
3047 return VINF_SUCCESS;
3048}
3049
3050
3051#ifdef VBOX_WITH_CRHGSMI
3052/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
3053 *
3054 * 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.
3055 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
3056 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
3057 * to block the lower-priority thread trying to complete the blocking command.
3058 * And removed extra memcpy done on blocked command arrival.
3059 *
3060 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
3061 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
3062 *
3063 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
3064 * */
3065int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
3066{
3067 int32_t rc;
3068 uint32_t cBuffers = pCmd->cBuffers;
3069 uint32_t cParams;
3070 uint32_t cbHdr;
3071 CRVBOXHGSMIHDR *pHdr;
3072 uint32_t u32Function;
3073 uint32_t u32ClientID;
3074 CRClient *pClient;
3075
3076 if (!g_pvVRamBase)
3077 {
3078 crWarning("g_pvVRamBase is not initialized");
3079 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
3080 return VINF_SUCCESS;
3081 }
3082
3083 if (!cBuffers)
3084 {
3085 crWarning("zero buffers passed in!");
3086 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3087 return VINF_SUCCESS;
3088 }
3089
3090 cParams = cBuffers-1;
3091
3092 cbHdr = pCmd->aBuffers[0].cbBuffer;
3093 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
3094 if (!pHdr)
3095 {
3096 crWarning("invalid header buffer!");
3097 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3098 return VINF_SUCCESS;
3099 }
3100
3101 if (cbHdr < sizeof (*pHdr))
3102 {
3103 crWarning("invalid header buffer size!");
3104 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3105 return VINF_SUCCESS;
3106 }
3107
3108 u32Function = pHdr->u32Function;
3109 u32ClientID = pHdr->u32ClientID;
3110
3111 switch (u32Function)
3112 {
3113 case SHCRGL_GUEST_FN_WRITE:
3114 {
3115 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
3116
3117 /* @todo: Verify */
3118 if (cParams == 1)
3119 {
3120 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
3121 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3122 /* Fetch parameters. */
3123 uint32_t cbBuffer = pBuf->cbBuffer;
3124 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3125
3126 if (cbHdr < sizeof (*pFnCmd))
3127 {
3128 crWarning("invalid write cmd buffer size!");
3129 rc = VERR_INVALID_PARAMETER;
3130 break;
3131 }
3132
3133 CRASSERT(cbBuffer);
3134 if (!pBuffer)
3135 {
3136 crWarning("invalid buffer data received from guest!");
3137 rc = VERR_INVALID_PARAMETER;
3138 break;
3139 }
3140
3141 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3142 if (RT_FAILURE(rc))
3143 {
3144 break;
3145 }
3146
3147 /* This should never fire unless we start to multithread */
3148 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3149 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3150
3151 pClient->conn->pBuffer = pBuffer;
3152 pClient->conn->cbBuffer = cbBuffer;
3153 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
3154 rc = crVBoxServerInternalClientWriteRead(pClient);
3155 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3156 return rc;
3157 }
3158 else
3159 {
3160 crWarning("invalid number of args");
3161 rc = VERR_INVALID_PARAMETER;
3162 break;
3163 }
3164 break;
3165 }
3166
3167 case SHCRGL_GUEST_FN_INJECT:
3168 {
3169 Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
3170
3171 /* @todo: Verify */
3172 if (cParams == 1)
3173 {
3174 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
3175 /* Fetch parameters. */
3176 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
3177 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3178 uint32_t cbBuffer = pBuf->cbBuffer;
3179 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3180
3181 if (cbHdr < sizeof (*pFnCmd))
3182 {
3183 crWarning("invalid inject cmd buffer size!");
3184 rc = VERR_INVALID_PARAMETER;
3185 break;
3186 }
3187
3188 CRASSERT(cbBuffer);
3189 if (!pBuffer)
3190 {
3191 crWarning("invalid buffer data received from guest!");
3192 rc = VERR_INVALID_PARAMETER;
3193 break;
3194 }
3195
3196 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3197 if (RT_FAILURE(rc))
3198 {
3199 break;
3200 }
3201
3202 /* This should never fire unless we start to multithread */
3203 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3204 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3205
3206 pClient->conn->pBuffer = pBuffer;
3207 pClient->conn->cbBuffer = cbBuffer;
3208 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
3209 rc = crVBoxServerInternalClientWriteRead(pClient);
3210 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3211 return rc;
3212 }
3213
3214 crWarning("invalid number of args");
3215 rc = VERR_INVALID_PARAMETER;
3216 break;
3217 }
3218
3219 case SHCRGL_GUEST_FN_READ:
3220 {
3221 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3222
3223 /* @todo: Verify */
3224 if (cParams == 1)
3225 {
3226 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3227 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3228 /* Fetch parameters. */
3229 uint32_t cbBuffer = pBuf->cbBuffer;
3230 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3231
3232 if (cbHdr < sizeof (*pFnCmd))
3233 {
3234 crWarning("invalid read cmd buffer size!");
3235 rc = VERR_INVALID_PARAMETER;
3236 break;
3237 }
3238
3239
3240 if (!pBuffer)
3241 {
3242 crWarning("invalid buffer data received from guest!");
3243 rc = VERR_INVALID_PARAMETER;
3244 break;
3245 }
3246
3247 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3248 if (RT_FAILURE(rc))
3249 {
3250 break;
3251 }
3252
3253 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3254
3255 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3256
3257 /* Return the required buffer size always */
3258 pFnCmd->cbBuffer = cbBuffer;
3259
3260 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3261
3262 /* the read command is never pended, complete it right away */
3263 pHdr->result = rc;
3264 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3265 return VINF_SUCCESS;
3266 }
3267
3268 crWarning("invalid number of args");
3269 rc = VERR_INVALID_PARAMETER;
3270 break;
3271 }
3272
3273 case SHCRGL_GUEST_FN_WRITE_READ:
3274 {
3275 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3276
3277 /* @todo: Verify */
3278 if (cParams == 2)
3279 {
3280 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3281 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3282 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3283
3284 /* Fetch parameters. */
3285 uint32_t cbBuffer = pBuf->cbBuffer;
3286 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3287
3288 uint32_t cbWriteback = pWbBuf->cbBuffer;
3289 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3290
3291 if (cbHdr < sizeof (*pFnCmd))
3292 {
3293 crWarning("invalid write_read cmd buffer size!");
3294 rc = VERR_INVALID_PARAMETER;
3295 break;
3296 }
3297
3298
3299 CRASSERT(cbBuffer);
3300 if (!pBuffer)
3301 {
3302 crWarning("invalid write buffer data received from guest!");
3303 rc = VERR_INVALID_PARAMETER;
3304 break;
3305 }
3306
3307 CRASSERT(cbWriteback);
3308 if (!pWriteback)
3309 {
3310 crWarning("invalid writeback buffer data received from guest!");
3311 rc = VERR_INVALID_PARAMETER;
3312 break;
3313 }
3314 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3315 if (RT_FAILURE(rc))
3316 {
3317 pHdr->result = rc;
3318 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3319 return rc;
3320 }
3321
3322 /* This should never fire unless we start to multithread */
3323 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3324 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3325
3326 pClient->conn->pBuffer = pBuffer;
3327 pClient->conn->cbBuffer = cbBuffer;
3328 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
3329 rc = crVBoxServerInternalClientWriteRead(pClient);
3330 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3331 return rc;
3332 }
3333
3334 crWarning("invalid number of args");
3335 rc = VERR_INVALID_PARAMETER;
3336 break;
3337 }
3338
3339 case SHCRGL_GUEST_FN_SET_VERSION:
3340 {
3341 crWarning("invalid function");
3342 rc = VERR_NOT_IMPLEMENTED;
3343 break;
3344 }
3345
3346 case SHCRGL_GUEST_FN_SET_PID:
3347 {
3348 crWarning("invalid function");
3349 rc = VERR_NOT_IMPLEMENTED;
3350 break;
3351 }
3352
3353 default:
3354 {
3355 crWarning("invalid function");
3356 rc = VERR_NOT_IMPLEMENTED;
3357 break;
3358 }
3359
3360 }
3361
3362 /* we can be on fail only here */
3363 CRASSERT(RT_FAILURE(rc));
3364 pHdr->result = rc;
3365 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3366 return rc;
3367}
3368
3369int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
3370{
3371 int rc = VINF_SUCCESS;
3372
3373 switch (pCtl->enmType)
3374 {
3375 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
3376 {
3377 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
3378 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
3379 g_cbVRam = pSetup->cbVRam;
3380 rc = VINF_SUCCESS;
3381 break;
3382 }
3383 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
3384 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
3385 rc = VINF_SUCCESS;
3386 break;
3387 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
3388 {
3389 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
3390 g_hCrHgsmiCompletion = pSetup->hCompletion;
3391 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
3392 rc = VINF_SUCCESS;
3393 break;
3394 }
3395 default:
3396 AssertMsgFailed(("invalid param %d", pCtl->enmType));
3397 rc = VERR_INVALID_PARAMETER;
3398 }
3399
3400 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
3401 * to complete them accordingly.
3402 * This approach allows using host->host and host->guest commands in the same way here
3403 * making the command completion to be the responsibility of the command originator.
3404 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
3405 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
3406 return rc;
3407}
3408#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