VirtualBox

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

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

crOpenGL: yet another adjustment to 3D notify mechanism

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