VirtualBox

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

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

crOpenGL/wddm: TexPresent fixes, irq handling fix

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