VirtualBox

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

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

crOpenGL: resize bugfixes

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

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