VirtualBox

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

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

crOpenGL: presentation infrastructure rework (still work in progress)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 114.9 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 crVBoxServerCheckVisibilityEvent(int32_t idScreen)
2637{
2638 if (cr_server.cDisableEvents)
2639 return;
2640
2641 if (idScreen < 0)
2642 {
2643 int32_t i = 0;
2644 for (; i < cr_server.screenCount; ++i)
2645 {
2646 crVBoxServerCheckVisibilityEvent(i);
2647 }
2648 return;
2649 }
2650
2651 CRASSERT(idScreen < cr_server.screenCount);
2652
2653 if (!cr_server.aWinVisibilityInfos[idScreen].fVisibleChanged
2654 && !cr_server.aWinVisibilityInfos[idScreen].cVisibleWindows == !cr_server.aWinVisibilityInfos[idScreen].fLastReportedVisible)
2655 return;
2656
2657 crVBoxServerNotifyEvent(idScreen, VBOX3D_NOTIFY_EVENT_TYPE_VISIBLE_3DDATA,
2658 cr_server.aWinVisibilityInfos[idScreen].cVisibleWindows ? (void*)1 : NULL);
2659
2660 cr_server.aWinVisibilityInfos[idScreen].fLastReportedVisible = cr_server.aWinVisibilityInfos[idScreen].cVisibleWindows ? 1 : 0;
2661 cr_server.aWinVisibilityInfos[idScreen].fVisibleChanged = 0;
2662}
2663
2664void crServerWindowReparent(CRMuralInfo *pMural)
2665{
2666 pMural->fHasParentWindow = !!cr_server.screen[pMural->screenId].winID;
2667
2668 renderspuReparentWindow(pMural->spuWindow);
2669}
2670
2671static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2672{
2673 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2674 int *sIndex = (int*) data2;
2675
2676 if (pMI->screenId == *sIndex)
2677 {
2678 crServerWindowReparent(pMI);
2679 }
2680}
2681
2682DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2683{
2684 int i;
2685
2686 if (sCount>CR_MAX_GUEST_MONITORS)
2687 return VERR_INVALID_PARAMETER;
2688
2689 /*Shouldn't happen yet, but to be safe in future*/
2690 for (i=0; i<cr_server.screenCount; ++i)
2691 {
2692 if (MAPPED(SCREEN(i)))
2693 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
2694 return VERR_NOT_IMPLEMENTED;
2695 }
2696
2697 cr_server.screenCount = sCount;
2698
2699 for (i=0; i<sCount; ++i)
2700 {
2701 SCREEN(i).winID = 0;
2702 }
2703
2704 return VINF_SUCCESS;
2705}
2706
2707DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2708{
2709 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2710
2711 if (sIndex<0 || sIndex>=cr_server.screenCount)
2712 return VERR_INVALID_PARAMETER;
2713
2714 if (MAPPED(SCREEN(sIndex)))
2715 {
2716 SCREEN(sIndex).winID = 0;
2717 renderspuSetWindowId(0);
2718
2719 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2720
2721 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2722
2723 CrPMgrScreenChanged((uint32_t)sIndex);
2724 }
2725
2726 renderspuSetWindowId(SCREEN(0).winID);
2727
2728/* crVBoxServerNotifyEvent(sIndex, VBOX3D_NOTIFY_EVENT_TYPE_VISIBLE_3DDATA, NULL); */
2729
2730 return VINF_SUCCESS;
2731}
2732
2733DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2734{
2735 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2736
2737 if (sIndex<0 || sIndex>=cr_server.screenCount)
2738 return VERR_INVALID_PARAMETER;
2739
2740 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2741 {
2742 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2743 crVBoxServerUnmapScreen(sIndex);
2744 }
2745
2746 SCREEN(sIndex).winID = winID;
2747 SCREEN(sIndex).x = x;
2748 SCREEN(sIndex).y = y;
2749 SCREEN(sIndex).w = w;
2750 SCREEN(sIndex).h = h;
2751
2752 renderspuSetWindowId(SCREEN(sIndex).winID);
2753 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2754
2755 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2756 renderspuSetWindowId(SCREEN(0).winID);
2757
2758#ifndef WINDOWS
2759 /*Restore FB content for clients, which have current window on a screen being remapped*/
2760 {
2761 GLint i;
2762
2763 for (i = 0; i < cr_server.numClients; i++)
2764 {
2765 cr_server.curClient = cr_server.clients[i];
2766 if (cr_server.curClient->currentCtxInfo
2767 && cr_server.curClient->currentCtxInfo->pContext
2768 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2769 && cr_server.curClient->currentMural
2770 && cr_server.curClient->currentMural->screenId == sIndex
2771 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2772 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2773 {
2774 int clientWindow = cr_server.curClient->currentWindow;
2775 int clientContext = cr_server.curClient->currentContextNumber;
2776 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2777
2778 if (clientWindow && clientWindow != cr_server.currentWindow)
2779 {
2780 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2781 }
2782
2783 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2784 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2785 }
2786 }
2787 cr_server.curClient = NULL;
2788 }
2789#endif
2790
2791 CrPMgrScreenChanged((uint32_t)sIndex);
2792
2793 crVBoxServerNotifyEvent(sIndex, VBOX3D_NOTIFY_EVENT_TYPE_VISIBLE_3DDATA,
2794 cr_server.aWinVisibilityInfos[sIndex].cVisibleWindows ? (void*)1 : NULL);
2795
2796 return VINF_SUCCESS;
2797}
2798
2799DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects)
2800{
2801 int32_t rc = VINF_SUCCESS;
2802 GLboolean fOldRootVrOn = cr_server.fRootVrOn;
2803
2804 /* non-zero rects pointer indicate rects are present and switched on
2805 * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions,
2806 * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */
2807 if (pRects)
2808 {
2809 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
2810 rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL);
2811 if (!RT_SUCCESS(rc))
2812 {
2813 crWarning("VBoxVrListRectsSet failed! rc %d", rc);
2814 return rc;
2815 }
2816
2817 cr_server.fRootVrOn = GL_TRUE;
2818 }
2819 else
2820 {
2821 if (!cr_server.fRootVrOn)
2822 return VINF_SUCCESS;
2823
2824 VBoxVrListClear(&cr_server.RootVr);
2825
2826 cr_server.fRootVrOn = GL_FALSE;
2827 }
2828
2829 if (!fOldRootVrOn != !cr_server.fRootVrOn)
2830 {
2831 rc = CrPMgrModeRootVr(cr_server.fRootVrOn);
2832 if (!RT_SUCCESS(rc))
2833 {
2834 crWarning("CrPMgrModeRootVr failed rc %d", rc);
2835 return rc;
2836 }
2837 }
2838 else if (cr_server.fRootVrOn)
2839 {
2840 rc = CrPMgrRootVrUpdate();
2841 if (!RT_SUCCESS(rc))
2842 {
2843 crWarning("CrPMgrRootVrUpdate failed rc %d", rc);
2844 return rc;
2845 }
2846 }
2847
2848 return VINF_SUCCESS;
2849}
2850
2851DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2852{
2853 cr_server.pfnPresentFBO = pfnPresentFBO;
2854}
2855
2856DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2857{
2858 return CrPMgrModeVrdp(value);
2859}
2860
2861DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2862{
2863 /* No need for a synchronization as this is single threaded. */
2864 if (pCallbacks)
2865 {
2866 cr_server.outputRedirect = *pCallbacks;
2867 }
2868 else
2869 {
2870 memset (&cr_server.outputRedirect, 0, sizeof (cr_server.outputRedirect));
2871 }
2872
2873 return VINF_SUCCESS;
2874}
2875
2876DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2877{
2878 CRScreenViewportInfo *pViewport;
2879 RTRECT NewRect;
2880 GLboolean fChanged;
2881 int rc;
2882
2883 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2884
2885 if (sIndex<0 || sIndex>=cr_server.screenCount)
2886 {
2887 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2888 return VERR_INVALID_PARAMETER;
2889 }
2890
2891 NewRect.xLeft = x;
2892 NewRect.yTop = y;
2893 NewRect.xRight = x + w;
2894 NewRect.yBottom = y + h;
2895
2896 pViewport = &cr_server.screenVieport[sIndex];
2897
2898 fChanged = !!memcmp(&NewRect, &pViewport->Rect, sizeof (NewRect));
2899 if (!fChanged)
2900 {
2901 crDebug("crVBoxServerSetScreenViewport: no changes");
2902 return VINF_SUCCESS;
2903 }
2904
2905 pViewport->Rect = NewRect;
2906 rc = CrPMgrViewportUpdate((uint32_t)sIndex);
2907 if (!RT_SUCCESS(rc))
2908 {
2909 crWarning("CrPMgrViewportUpdate failed %d", rc);
2910 return rc;
2911 }
2912
2913 return VINF_SUCCESS;
2914}
2915
2916
2917#ifdef VBOX_WITH_CRHGSMI
2918/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
2919 *
2920 * 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.
2921 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
2922 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
2923 * to block the lower-priority thread trying to complete the blocking command.
2924 * And removed extra memcpy done on blocked command arrival.
2925 *
2926 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
2927 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
2928 *
2929 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
2930 * */
2931static int32_t crVBoxServerCmdVbvaCrCmdProcess(struct VBOXCMDVBVA_CRCMD_CMD *pCmd)
2932{
2933 int32_t rc;
2934 uint32_t cBuffers = pCmd->cBuffers;
2935 uint32_t cParams;
2936 uint32_t cbHdr;
2937 CRVBOXHGSMIHDR *pHdr;
2938 uint32_t u32Function;
2939 uint32_t u32ClientID;
2940 CRClient *pClient;
2941
2942 if (!g_pvVRamBase)
2943 {
2944 crWarning("g_pvVRamBase is not initialized");
2945 return VERR_INVALID_STATE;
2946 }
2947
2948 if (!cBuffers)
2949 {
2950 crWarning("zero buffers passed in!");
2951 return VERR_INVALID_PARAMETER;
2952 }
2953
2954 cParams = cBuffers-1;
2955
2956 cbHdr = pCmd->aBuffers[0].cbBuffer;
2957 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2958 if (!pHdr)
2959 {
2960 crWarning("invalid header buffer!");
2961 return VERR_INVALID_PARAMETER;
2962 }
2963
2964 if (cbHdr < sizeof (*pHdr))
2965 {
2966 crWarning("invalid header buffer size!");
2967 return VERR_INVALID_PARAMETER;
2968 }
2969
2970 u32Function = pHdr->u32Function;
2971 u32ClientID = pHdr->u32ClientID;
2972
2973 switch (u32Function)
2974 {
2975 case SHCRGL_GUEST_FN_WRITE:
2976 {
2977 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2978
2979 /* @todo: Verify */
2980 if (cParams == 1)
2981 {
2982 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2983 VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
2984 /* Fetch parameters. */
2985 uint32_t cbBuffer = pBuf->cbBuffer;
2986 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2987
2988 if (cbHdr < sizeof (*pFnCmd))
2989 {
2990 crWarning("invalid write cmd buffer size!");
2991 rc = VERR_INVALID_PARAMETER;
2992 break;
2993 }
2994
2995 CRASSERT(cbBuffer);
2996 if (!pBuffer)
2997 {
2998 crWarning("invalid buffer data received from guest!");
2999 rc = VERR_INVALID_PARAMETER;
3000 break;
3001 }
3002
3003 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3004 if (RT_FAILURE(rc))
3005 {
3006 break;
3007 }
3008
3009 /* This should never fire unless we start to multithread */
3010 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3011 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3012
3013 pClient->conn->pBuffer = pBuffer;
3014 pClient->conn->cbBuffer = cbBuffer;
3015 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
3016 rc = crVBoxServerInternalClientWriteRead(pClient);
3017 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3018 return rc;
3019 }
3020 else
3021 {
3022 crWarning("invalid number of args");
3023 rc = VERR_INVALID_PARAMETER;
3024 break;
3025 }
3026 break;
3027 }
3028
3029 case SHCRGL_GUEST_FN_INJECT:
3030 {
3031 Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
3032
3033 /* @todo: Verify */
3034 if (cParams == 1)
3035 {
3036 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
3037 /* Fetch parameters. */
3038 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
3039 VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3040 uint32_t cbBuffer = pBuf->cbBuffer;
3041 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3042
3043 if (cbHdr < sizeof (*pFnCmd))
3044 {
3045 crWarning("invalid inject cmd buffer size!");
3046 rc = VERR_INVALID_PARAMETER;
3047 break;
3048 }
3049
3050 CRASSERT(cbBuffer);
3051 if (!pBuffer)
3052 {
3053 crWarning("invalid buffer data received from guest!");
3054 rc = VERR_INVALID_PARAMETER;
3055 break;
3056 }
3057
3058 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3059 if (RT_FAILURE(rc))
3060 {
3061 break;
3062 }
3063
3064 /* This should never fire unless we start to multithread */
3065 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3066 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3067
3068 pClient->conn->pBuffer = pBuffer;
3069 pClient->conn->cbBuffer = cbBuffer;
3070 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
3071 rc = crVBoxServerInternalClientWriteRead(pClient);
3072 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3073 return rc;
3074 }
3075
3076 crWarning("invalid number of args");
3077 rc = VERR_INVALID_PARAMETER;
3078 break;
3079 }
3080
3081 case SHCRGL_GUEST_FN_READ:
3082 {
3083 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3084
3085 /* @todo: Verify */
3086 if (cParams == 1)
3087 {
3088 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3089 VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3090 /* Fetch parameters. */
3091 uint32_t cbBuffer = pBuf->cbBuffer;
3092 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3093
3094 if (cbHdr < sizeof (*pFnCmd))
3095 {
3096 crWarning("invalid read cmd buffer size!");
3097 rc = VERR_INVALID_PARAMETER;
3098 break;
3099 }
3100
3101
3102 if (!pBuffer)
3103 {
3104 crWarning("invalid buffer data received from guest!");
3105 rc = VERR_INVALID_PARAMETER;
3106 break;
3107 }
3108
3109 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3110 if (RT_FAILURE(rc))
3111 {
3112 break;
3113 }
3114
3115 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3116
3117 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3118
3119 /* Return the required buffer size always */
3120 pFnCmd->cbBuffer = cbBuffer;
3121
3122 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3123
3124 /* the read command is never pended, complete it right away */
3125 pHdr->result = rc;
3126
3127 return VINF_SUCCESS;
3128 }
3129
3130 crWarning("invalid number of args");
3131 rc = VERR_INVALID_PARAMETER;
3132 break;
3133 }
3134
3135 case SHCRGL_GUEST_FN_WRITE_READ:
3136 {
3137 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3138
3139 /* @todo: Verify */
3140 if (cParams == 2)
3141 {
3142 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3143 VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3144 VBOXCMDVBVA_CRCMD_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3145
3146 /* Fetch parameters. */
3147 uint32_t cbBuffer = pBuf->cbBuffer;
3148 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3149
3150 uint32_t cbWriteback = pWbBuf->cbBuffer;
3151 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3152
3153 if (cbHdr < sizeof (*pFnCmd))
3154 {
3155 crWarning("invalid write_read cmd buffer size!");
3156 rc = VERR_INVALID_PARAMETER;
3157 break;
3158 }
3159
3160
3161 CRASSERT(cbBuffer);
3162 if (!pBuffer)
3163 {
3164 crWarning("invalid write buffer data received from guest!");
3165 rc = VERR_INVALID_PARAMETER;
3166 break;
3167 }
3168
3169 CRASSERT(cbWriteback);
3170 if (!pWriteback)
3171 {
3172 crWarning("invalid writeback buffer data received from guest!");
3173 rc = VERR_INVALID_PARAMETER;
3174 break;
3175 }
3176 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3177 if (RT_FAILURE(rc))
3178 {
3179 pHdr->result = rc;
3180 return VINF_SUCCESS;
3181 }
3182
3183 /* This should never fire unless we start to multithread */
3184 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3185 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3186
3187 pClient->conn->pBuffer = pBuffer;
3188 pClient->conn->cbBuffer = cbBuffer;
3189 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, false);
3190 rc = crVBoxServerInternalClientWriteRead(pClient);
3191 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3192 return rc;
3193 }
3194
3195 crWarning("invalid number of args");
3196 rc = VERR_INVALID_PARAMETER;
3197 break;
3198 }
3199
3200 case SHCRGL_GUEST_FN_SET_VERSION:
3201 {
3202 crWarning("invalid function");
3203 rc = VERR_NOT_IMPLEMENTED;
3204 break;
3205 }
3206
3207 case SHCRGL_GUEST_FN_SET_PID:
3208 {
3209 crWarning("invalid function");
3210 rc = VERR_NOT_IMPLEMENTED;
3211 break;
3212 }
3213
3214 default:
3215 {
3216 crWarning("invalid function");
3217 rc = VERR_NOT_IMPLEMENTED;
3218 break;
3219 }
3220
3221 }
3222
3223 /* we can be on fail only here */
3224 CRASSERT(RT_FAILURE(rc));
3225 pHdr->result = rc;
3226
3227 return rc;
3228}
3229
3230int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
3231{
3232
3233 int32_t rc;
3234 uint32_t cBuffers = pCmd->cBuffers;
3235 uint32_t cParams;
3236 uint32_t cbHdr;
3237 CRVBOXHGSMIHDR *pHdr;
3238 uint32_t u32Function;
3239 uint32_t u32ClientID;
3240 CRClient *pClient;
3241
3242 if (!g_pvVRamBase)
3243 {
3244 crWarning("g_pvVRamBase is not initialized");
3245
3246 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
3247 return VINF_SUCCESS;
3248 }
3249
3250 if (!cBuffers)
3251 {
3252 crWarning("zero buffers passed in!");
3253
3254 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3255 return VINF_SUCCESS;
3256 }
3257
3258 cParams = cBuffers-1;
3259
3260 cbHdr = pCmd->aBuffers[0].cbBuffer;
3261 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
3262 if (!pHdr)
3263 {
3264 crWarning("invalid header buffer!");
3265
3266 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3267 return VINF_SUCCESS;
3268 }
3269
3270 if (cbHdr < sizeof (*pHdr))
3271 {
3272 crWarning("invalid header buffer size!");
3273
3274 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3275 return VINF_SUCCESS;
3276 }
3277
3278 u32Function = pHdr->u32Function;
3279 u32ClientID = pHdr->u32ClientID;
3280
3281 switch (u32Function)
3282 {
3283 case SHCRGL_GUEST_FN_WRITE:
3284 {
3285 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
3286
3287 /* @todo: Verify */
3288 if (cParams == 1)
3289 {
3290 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
3291 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3292 /* Fetch parameters. */
3293 uint32_t cbBuffer = pBuf->cbBuffer;
3294 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3295
3296 if (cbHdr < sizeof (*pFnCmd))
3297 {
3298 crWarning("invalid write cmd buffer size!");
3299 rc = VERR_INVALID_PARAMETER;
3300 break;
3301 }
3302
3303 CRASSERT(cbBuffer);
3304 if (!pBuffer)
3305 {
3306 crWarning("invalid buffer data received from guest!");
3307 rc = VERR_INVALID_PARAMETER;
3308 break;
3309 }
3310
3311 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3312 if (RT_FAILURE(rc))
3313 {
3314 break;
3315 }
3316
3317 /* This should never fire unless we start to multithread */
3318 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3319 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3320
3321 pClient->conn->pBuffer = pBuffer;
3322 pClient->conn->cbBuffer = cbBuffer;
3323 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3324 rc = crVBoxServerInternalClientWriteRead(pClient);
3325 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3326 return rc;
3327 }
3328 else
3329 {
3330 crWarning("invalid number of args");
3331 rc = VERR_INVALID_PARAMETER;
3332 break;
3333 }
3334 break;
3335 }
3336
3337 case SHCRGL_GUEST_FN_INJECT:
3338 {
3339 Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
3340
3341 /* @todo: Verify */
3342 if (cParams == 1)
3343 {
3344 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
3345 /* Fetch parameters. */
3346 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
3347 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3348 uint32_t cbBuffer = pBuf->cbBuffer;
3349 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3350
3351 if (cbHdr < sizeof (*pFnCmd))
3352 {
3353 crWarning("invalid inject cmd buffer size!");
3354 rc = VERR_INVALID_PARAMETER;
3355 break;
3356 }
3357
3358 CRASSERT(cbBuffer);
3359 if (!pBuffer)
3360 {
3361 crWarning("invalid buffer data received from guest!");
3362 rc = VERR_INVALID_PARAMETER;
3363 break;
3364 }
3365
3366 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3367 if (RT_FAILURE(rc))
3368 {
3369 break;
3370 }
3371
3372 /* This should never fire unless we start to multithread */
3373 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3374 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3375
3376 pClient->conn->pBuffer = pBuffer;
3377 pClient->conn->cbBuffer = cbBuffer;
3378 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3379 rc = crVBoxServerInternalClientWriteRead(pClient);
3380 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3381 return rc;
3382 }
3383
3384 crWarning("invalid number of args");
3385 rc = VERR_INVALID_PARAMETER;
3386 break;
3387 }
3388
3389 case SHCRGL_GUEST_FN_READ:
3390 {
3391 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3392
3393 /* @todo: Verify */
3394 if (cParams == 1)
3395 {
3396 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3397 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3398 /* Fetch parameters. */
3399 uint32_t cbBuffer = pBuf->cbBuffer;
3400 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3401
3402 if (cbHdr < sizeof (*pFnCmd))
3403 {
3404 crWarning("invalid read cmd buffer size!");
3405 rc = VERR_INVALID_PARAMETER;
3406 break;
3407 }
3408
3409
3410 if (!pBuffer)
3411 {
3412 crWarning("invalid buffer data received from guest!");
3413 rc = VERR_INVALID_PARAMETER;
3414 break;
3415 }
3416
3417 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3418 if (RT_FAILURE(rc))
3419 {
3420 break;
3421 }
3422
3423 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3424
3425 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3426
3427 /* Return the required buffer size always */
3428 pFnCmd->cbBuffer = cbBuffer;
3429
3430 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3431
3432 /* the read command is never pended, complete it right away */
3433 pHdr->result = rc;
3434
3435 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3436 return VINF_SUCCESS;
3437 }
3438
3439 crWarning("invalid number of args");
3440 rc = VERR_INVALID_PARAMETER;
3441 break;
3442 }
3443
3444 case SHCRGL_GUEST_FN_WRITE_READ:
3445 {
3446 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3447
3448 /* @todo: Verify */
3449 if (cParams == 2)
3450 {
3451 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3452 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3453 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3454
3455 /* Fetch parameters. */
3456 uint32_t cbBuffer = pBuf->cbBuffer;
3457 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3458
3459 uint32_t cbWriteback = pWbBuf->cbBuffer;
3460 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3461
3462 if (cbHdr < sizeof (*pFnCmd))
3463 {
3464 crWarning("invalid write_read cmd buffer size!");
3465 rc = VERR_INVALID_PARAMETER;
3466 break;
3467 }
3468
3469
3470 CRASSERT(cbBuffer);
3471 if (!pBuffer)
3472 {
3473 crWarning("invalid write buffer data received from guest!");
3474 rc = VERR_INVALID_PARAMETER;
3475 break;
3476 }
3477
3478 CRASSERT(cbWriteback);
3479 if (!pWriteback)
3480 {
3481 crWarning("invalid writeback buffer data received from guest!");
3482 rc = VERR_INVALID_PARAMETER;
3483 break;
3484 }
3485 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3486 if (RT_FAILURE(rc))
3487 {
3488 pHdr->result = rc;
3489 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3490 return rc;
3491 }
3492
3493 /* This should never fire unless we start to multithread */
3494 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3495 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3496
3497 pClient->conn->pBuffer = pBuffer;
3498 pClient->conn->cbBuffer = cbBuffer;
3499 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, true);
3500 rc = crVBoxServerInternalClientWriteRead(pClient);
3501 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3502 return rc;
3503 }
3504
3505 crWarning("invalid number of args");
3506 rc = VERR_INVALID_PARAMETER;
3507 break;
3508 }
3509
3510 case SHCRGL_GUEST_FN_SET_VERSION:
3511 {
3512 crWarning("invalid function");
3513 rc = VERR_NOT_IMPLEMENTED;
3514 break;
3515 }
3516
3517 case SHCRGL_GUEST_FN_SET_PID:
3518 {
3519 crWarning("invalid function");
3520 rc = VERR_NOT_IMPLEMENTED;
3521 break;
3522 }
3523
3524 default:
3525 {
3526 crWarning("invalid function");
3527 rc = VERR_NOT_IMPLEMENTED;
3528 break;
3529 }
3530
3531 }
3532
3533 /* we can be on fail only here */
3534 CRASSERT(RT_FAILURE(rc));
3535 pHdr->result = rc;
3536
3537 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3538 return rc;
3539
3540}
3541
3542int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
3543{
3544 int rc = VINF_SUCCESS;
3545
3546 switch (pCtl->enmType)
3547 {
3548 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
3549 {
3550 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
3551 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
3552 g_cbVRam = pSetup->cbVRam;
3553 cr_server.CltInfo = *pSetup->pCrCmdClientInfo;
3554 rc = VINF_SUCCESS;
3555 break;
3556 }
3557 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
3558 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
3559 rc = VINF_SUCCESS;
3560 break;
3561 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
3562 {
3563 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
3564 g_hCrHgsmiCompletion = pSetup->hCompletion;
3565 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
3566 rc = VINF_SUCCESS;
3567 break;
3568 }
3569 default:
3570 AssertMsgFailed(("invalid param %d", pCtl->enmType));
3571 rc = VERR_INVALID_PARAMETER;
3572 }
3573
3574 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
3575 * to complete them accordingly.
3576 * This approach allows using host->host and host->guest commands in the same way here
3577 * making the command completion to be the responsibility of the command originator.
3578 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
3579 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
3580 return rc;
3581}
3582
3583static int32_t crVBoxServerCrCmdProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd)
3584{
3585 switch (pCmd->u8OpCode)
3586 {
3587 case VBOXCMDVBVA_OPTYPE_CRCMD:
3588 {
3589 VBOXCMDVBVA_CRCMD *pCrCmdDr = (VBOXCMDVBVA_CRCMD*)pCmd;
3590 VBOXCMDVBVA_CRCMD_CMD *pCrCmd = &pCrCmdDr->Cmd;
3591 int rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd);
3592 if (RT_SUCCESS(rc))
3593 {
3594 /* success */
3595 pCmd->i8Result = 0;
3596 }
3597 else
3598 {
3599 crWarning("crVBoxServerCmdVbvaCrCmdProcess failed, rc %d", rc);
3600 pCmd->i8Result = -1;
3601 }
3602 break;
3603 }
3604 default:
3605 crWarning("unsupported command");
3606 pCmd->i8Result = -1;
3607 }
3608 return VINF_SUCCESS;
3609}
3610
3611int32_t crVBoxServerCrCmdNotifyCmds()
3612{
3613 PVBOXCMDVBVA_HDR pCmd = NULL;
3614 uint32_t cbCmd;
3615
3616 for (;;)
3617 {
3618 int rc = cr_server.CltInfo.pfnCmdGet(cr_server.CltInfo.hClient, &pCmd, &cbCmd);
3619 if (rc == VINF_EOF)
3620 return VINF_SUCCESS;
3621 if (!RT_SUCCESS(rc))
3622 return rc;
3623
3624 rc = crVBoxServerCrCmdProcess(pCmd, cbCmd);
3625 if (!RT_SUCCESS(rc))
3626 return rc;
3627 }
3628
3629 /* should not be here! */
3630 AssertFailed();
3631 return VERR_INTERNAL_ERROR;
3632}
3633#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