VirtualBox

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

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

crOpenGL: crOpenGL: 1. workaround point sprite driver bugs; 2. workaround multi-string shader source driver bug; 3. proper GLhandle for OSX; 4. extended dumping; 5. misc fixes

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette