VirtualBox

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

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

crOpenGL: video recording working

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 114.5 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 CreateInfo;
857 CreateInfo.pszDpyName = pMural->CreateInfo.pszDpyName;
858 CreateInfo.visualBits = pMural->CreateInfo.requestedVisualBits;
859 CreateInfo.externalID = pMural->CreateInfo.externalID;
860 crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
861}
862
863static void crVBoxServerSaveCreateInfoFromCtxInfoCB(unsigned long key, void *data1, void *data2)
864{
865 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
866 CRCreateInfo_t CreateInfo;
867 CreateInfo.pszDpyName = pContextInfo->CreateInfo.pszDpyName;
868 CreateInfo.visualBits = pContextInfo->CreateInfo.requestedVisualBits;
869 /* saved state contains internal id */
870 CreateInfo.externalID = pContextInfo->pContext->id;
871 crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
872}
873
874static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data2)
875{
876 CRTextureObj *pTexture = (CRTextureObj *) data1;
877 CRContext *pContext = (CRContext *) data2;
878
879 CRASSERT(pTexture && pContext);
880 crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
881}
882
883typedef struct CRVBOX_SAVE_STATE_GLOBAL
884{
885 /* context id -> mural association
886 * on context data save, each context will be made current with the corresponding mural from this table
887 * thus saving the mural front & back buffer data */
888 CRHashTable *contextMuralTable;
889 /* mural id -> context info
890 * for murals that do not have associated context in contextMuralTable
891 * we still need to save*/
892 CRHashTable *additionalMuralContextTable;
893
894 PSSMHANDLE pSSM;
895
896 int rc;
897} CRVBOX_SAVE_STATE_GLOBAL, *PCRVBOX_SAVE_STATE_GLOBAL;
898
899
900typedef struct CRVBOX_CTXWND_CTXWALKER_CB
901{
902 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
903 CRHashTable *usedMuralTable;
904 GLuint cAdditionalMurals;
905} CRVBOX_CTXWND_CTXWALKER_CB, *PCRVBOX_CTXWND_CTXWALKER_CB;
906
907static void crVBoxServerBuildAdditionalWindowContextMapCB(unsigned long key, void *data1, void *data2)
908{
909 CRMuralInfo * pMural = (CRMuralInfo *) data1;
910 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
911 CRContextInfo *pContextInfo = NULL;
912
913 if (!pMural->CreateInfo.externalID)
914 {
915 CRASSERT(!key);
916 return;
917 }
918
919 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
920 {
921 Assert(crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
922 return;
923 }
924
925 Assert(!crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
926
927 if (cr_server.MainContextInfo.CreateInfo.realVisualBits == pMural->CreateInfo.realVisualBits)
928 {
929 pContextInfo = &cr_server.MainContextInfo;
930 }
931 else
932 {
933 crWarning("different visual bits not implemented!");
934 pContextInfo = &cr_server.MainContextInfo;
935 }
936
937 crHashtableAdd(pData->pGlobal->additionalMuralContextTable, pMural->CreateInfo.externalID, pContextInfo);
938}
939
940
941typedef struct CRVBOX_CTXWND_WNDWALKER_CB
942{
943 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
944 CRHashTable *usedMuralTable;
945 CRContextInfo *pContextInfo;
946 CRMuralInfo * pMural;
947} CRVBOX_CTXWND_WNDWALKER_CB, *PCRVBOX_CTXWND_WNDWALKER_CB;
948
949static void crVBoxServerBuildContextWindowMapWindowWalkerCB(unsigned long key, void *data1, void *data2)
950{
951 CRMuralInfo * pMural = (CRMuralInfo *) data1;
952 PCRVBOX_CTXWND_WNDWALKER_CB pData = (PCRVBOX_CTXWND_WNDWALKER_CB)data2;
953
954 Assert(pData->pMural != pMural);
955 Assert(pData->pContextInfo);
956
957 if (pData->pMural)
958 return;
959
960 if (!pMural->CreateInfo.externalID)
961 {
962 CRASSERT(!key);
963 return;
964 }
965
966 if (!CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pData->pContextInfo->pContext))
967 return;
968
969 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
970 return;
971
972 CRASSERT(pMural->CreateInfo.realVisualBits == pData->pContextInfo->CreateInfo.realVisualBits);
973 pData->pMural = pMural;
974}
975
976static void crVBoxServerBuildContextUsedWindowMapCB(unsigned long key, void *data1, void *data2)
977{
978 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
979 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
980
981 if (!pContextInfo->currentMural)
982 return;
983
984 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pContextInfo->currentMural);
985 crHashtableAdd(pData->usedMuralTable, pContextInfo->currentMural->CreateInfo.externalID, pContextInfo->currentMural);
986}
987
988CRMuralInfo * crServerGetDummyMural(GLint visualBits)
989{
990 CRMuralInfo * pMural = (CRMuralInfo *)crHashtableSearch(cr_server.dummyMuralTable, visualBits);
991 if (!pMural)
992 {
993 GLint id;
994 pMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
995 if (!pMural)
996 {
997 crWarning("crCalloc failed!");
998 return NULL;
999 }
1000 id = crServerMuralInit(pMural, "", visualBits, 0);
1001 if (id < 0)
1002 {
1003 crWarning("crServerMuralInit failed!");
1004 crFree(pMural);
1005 return NULL;
1006 }
1007
1008 crHashtableAdd(cr_server.dummyMuralTable, visualBits, pMural);
1009 }
1010
1011 return pMural;
1012}
1013
1014static void crVBoxServerBuildContextUnusedWindowMapCB(unsigned long key, void *data1, void *data2)
1015{
1016 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
1017 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
1018 CRMuralInfo * pMural = NULL;
1019
1020 if (pContextInfo->currentMural)
1021 return;
1022
1023 Assert(crHashtableNumElements(pData->pGlobal->contextMuralTable) <= crHashtableNumElements(cr_server.muralTable) - 1);
1024 if (crHashtableNumElements(pData->pGlobal->contextMuralTable) < crHashtableNumElements(cr_server.muralTable) - 1)
1025 {
1026 CRVBOX_CTXWND_WNDWALKER_CB MuralData;
1027 MuralData.pGlobal = pData->pGlobal;
1028 MuralData.usedMuralTable = pData->usedMuralTable;
1029 MuralData.pContextInfo = pContextInfo;
1030 MuralData.pMural = NULL;
1031
1032 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildContextWindowMapWindowWalkerCB, &MuralData);
1033
1034 pMural = MuralData.pMural;
1035
1036 }
1037
1038 if (!pMural)
1039 {
1040 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
1041 if (!pMural)
1042 {
1043 crWarning("crServerGetDummyMural failed");
1044 return;
1045 }
1046 }
1047 else
1048 {
1049 crHashtableAdd(pData->usedMuralTable, pMural->CreateInfo.externalID, pMural);
1050 ++pData->cAdditionalMurals;
1051 }
1052
1053 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pMural);
1054}
1055
1056static void crVBoxServerBuildSaveStateGlobal(PCRVBOX_SAVE_STATE_GLOBAL pGlobal)
1057{
1058 CRVBOX_CTXWND_CTXWALKER_CB Data;
1059 GLuint cMurals;
1060 pGlobal->contextMuralTable = crAllocHashtable();
1061 pGlobal->additionalMuralContextTable = crAllocHashtable();
1062 /* 1. go through all contexts and match all having currentMural set */
1063 Data.pGlobal = pGlobal;
1064 Data.usedMuralTable = crAllocHashtable();
1065 Data.cAdditionalMurals = 0;
1066 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUsedWindowMapCB, &Data);
1067
1068 cMurals = crHashtableNumElements(pGlobal->contextMuralTable);
1069 CRASSERT(cMurals <= crHashtableNumElements(cr_server.contextTable));
1070 CRASSERT(cMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
1071 CRASSERT(cMurals == crHashtableNumElements(Data.usedMuralTable));
1072 if (cMurals < crHashtableNumElements(cr_server.contextTable))
1073 {
1074 Data.cAdditionalMurals = 0;
1075 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUnusedWindowMapCB, &Data);
1076 }
1077
1078 CRASSERT(crHashtableNumElements(pGlobal->contextMuralTable) == crHashtableNumElements(cr_server.contextTable));
1079 CRASSERT(cMurals + Data.cAdditionalMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
1080 if (cMurals + Data.cAdditionalMurals < crHashtableNumElements(cr_server.muralTable) - 1)
1081 {
1082 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildAdditionalWindowContextMapCB, &Data);
1083 CRASSERT(cMurals + Data.cAdditionalMurals + crHashtableNumElements(pGlobal->additionalMuralContextTable) == crHashtableNumElements(cr_server.muralTable) - 1);
1084 }
1085
1086 crFreeHashtable(Data.usedMuralTable, NULL);
1087}
1088
1089static void crVBoxServerFBImageDataTerm(CRFBData *pData)
1090{
1091 GLuint i;
1092 for (i = 0; i < pData->cElements; ++i)
1093 {
1094 CRFBDataElement * pEl = &pData->aElements[i];
1095 if (pEl->pvData)
1096 {
1097 crFree(pEl->pvData);
1098 /* sanity */
1099 pEl->pvData = NULL;
1100 }
1101 }
1102 pData->cElements = 0;
1103}
1104
1105static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, uint32_t version, GLuint overrideWidth, GLuint overrideHeight)
1106{
1107 CRContext *pContext;
1108 GLuint i;
1109 GLfloat *pF;
1110 CRFBDataElement *pEl;
1111 GLuint width;
1112 GLuint height;
1113
1114 crMemset(pData, 0, sizeof (*pData));
1115
1116 pContext = pCtxInfo->pContext;
1117
1118 /* the version should be always actual when we do reads,
1119 * i.e. it could differ on writes when snapshot is getting loaded */
1120 CRASSERT(fWrite || version == SHCROGL_SSM_VERSION);
1121
1122 width = overrideWidth ? overrideWidth : pMural->width;
1123 height = overrideHeight ? overrideHeight : pMural->height;
1124
1125 if (!width || !height)
1126 return VINF_SUCCESS;
1127
1128 if (pMural)
1129 {
1130 if (fWrite)
1131 {
1132 if (!pContext->framebufferobject.drawFB)
1133 pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurDrawBuffer);
1134 }
1135 else
1136 {
1137 if (!pContext->framebufferobject.readFB)
1138 pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurReadBuffer);
1139 }
1140 }
1141 pData->cElements = 0;
1142
1143 pEl = &pData->aElements[pData->cElements];
1144 pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1145 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT;
1146 pEl->posX = 0;
1147 pEl->posY = 0;
1148 pEl->width = width;
1149 pEl->height = height;
1150 pEl->enmFormat = GL_RGBA;
1151 pEl->enmType = GL_UNSIGNED_BYTE;
1152 pEl->cbData = width * height * 4;
1153 pEl->pvData = crCalloc(pEl->cbData);
1154 if (!pEl->pvData)
1155 {
1156 crVBoxServerFBImageDataTerm(pData);
1157 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1158 return VERR_NO_MEMORY;
1159 }
1160 ++pData->cElements;
1161
1162 /* there is a lot of code that assumes we have double buffering, just assert here to print a warning in the log
1163 * so that we know that something irregular is going on */
1164 CRASSERT(pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT);
1165 if ((pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT)
1166 || version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL /* <- older version had a typo which lead to back always being used,
1167 * no matter what the visual bits are */
1168 )
1169 {
1170 pEl = &pData->aElements[pData->cElements];
1171 pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0;
1172 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK;
1173 pEl->posX = 0;
1174 pEl->posY = 0;
1175 pEl->width = width;
1176 pEl->height = height;
1177 pEl->enmFormat = GL_RGBA;
1178 pEl->enmType = GL_UNSIGNED_BYTE;
1179 pEl->cbData = width * height * 4;
1180 pEl->pvData = crCalloc(pEl->cbData);
1181 if (!pEl->pvData)
1182 {
1183 crVBoxServerFBImageDataTerm(pData);
1184 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1185 return VERR_NO_MEMORY;
1186 }
1187 ++pData->cElements;
1188 }
1189
1190 if (version < SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1191 return VINF_SUCCESS;
1192
1193
1194 if (version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL)
1195 {
1196/* if (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT) */ /* <- older version had a typo which lead to back always being used,
1197 * no matter what the visual bits are */
1198 {
1199 AssertCompile(sizeof (GLfloat) == 4);
1200 pEl = &pData->aElements[pData->cElements];
1201 pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1202 pEl->enmBuffer = 0; /* we do not care */
1203 pEl->posX = 0;
1204 pEl->posY = 0;
1205 pEl->width = width;
1206 pEl->height = height;
1207 pEl->enmFormat = GL_DEPTH_COMPONENT;
1208 pEl->enmType = GL_FLOAT;
1209 pEl->cbData = width * height * 4;
1210 pEl->pvData = crCalloc(pEl->cbData);
1211 if (!pEl->pvData)
1212 {
1213 crVBoxServerFBImageDataTerm(pData);
1214 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1215 return VERR_NO_MEMORY;
1216 }
1217
1218 /* init to default depth value, just in case */
1219 pF = (GLfloat*)pEl->pvData;
1220 for (i = 0; i < width * height; ++i)
1221 {
1222 pF[i] = 1.;
1223 }
1224 ++pData->cElements;
1225 }
1226
1227 /* if (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT) */ /* <- older version had a typo which lead to back always being used,
1228 * no matter what the visual bits are */
1229 {
1230 AssertCompile(sizeof (GLuint) == 4);
1231 pEl = &pData->aElements[pData->cElements];
1232 pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1233 pEl->enmBuffer = 0; /* we do not care */
1234 pEl->posX = 0;
1235 pEl->posY = 0;
1236 pEl->width = width;
1237 pEl->height = height;
1238 pEl->enmFormat = GL_STENCIL_INDEX;
1239 pEl->enmType = GL_UNSIGNED_INT;
1240 pEl->cbData = width * height * 4;
1241 pEl->pvData = crCalloc(pEl->cbData);
1242 if (!pEl->pvData)
1243 {
1244 crVBoxServerFBImageDataTerm(pData);
1245 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1246 return VERR_NO_MEMORY;
1247 }
1248 ++pData->cElements;
1249 }
1250 return VINF_SUCCESS;
1251 }
1252
1253 if ((pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT)
1254 || (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT))
1255 {
1256 pEl = &pData->aElements[pData->cElements];
1257 pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1258 pEl->enmBuffer = 0; /* we do not care */
1259 pEl->posX = 0;
1260 pEl->posY = 0;
1261 pEl->width = width;
1262 pEl->height = height;
1263 pEl->enmFormat = GL_DEPTH_STENCIL;
1264 pEl->enmType = GL_UNSIGNED_INT_24_8;
1265 pEl->cbData = width * height * 4;
1266 pEl->pvData = crCalloc(pEl->cbData);
1267 if (!pEl->pvData)
1268 {
1269 crVBoxServerFBImageDataTerm(pData);
1270 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1271 return VERR_NO_MEMORY;
1272 }
1273 ++pData->cElements;
1274 }
1275 return VINF_SUCCESS;
1276}
1277
1278static int crVBoxServerFBImageDataInit(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite)
1279{
1280 return crVBoxServerFBImageDataInitEx(pData, pCtxInfo, pMural, fWrite, SHCROGL_SSM_VERSION, 0, 0);
1281}
1282
1283static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
1284{
1285 CRContextInfo *pCtxInfo;
1286 CRContext *pContext;
1287 CRMuralInfo *pMural;
1288 int32_t rc;
1289 GLuint i;
1290 struct
1291 {
1292 CRFBData data;
1293 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1294 } Data;
1295
1296 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1297
1298 pCtxInfo = cr_server.currentCtxInfo;
1299 pContext = pCtxInfo->pContext;
1300 pMural = pCtxInfo->currentMural;
1301
1302 rc = crVBoxServerFBImageDataInit(&Data.data, pCtxInfo, pMural, GL_FALSE);
1303 if (!RT_SUCCESS(rc))
1304 {
1305 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1306 return rc;
1307 }
1308
1309 rc = crStateAcquireFBImage(pContext, &Data.data);
1310 AssertRCReturn(rc, rc);
1311
1312 for (i = 0; i < Data.data.cElements; ++i)
1313 {
1314 CRFBDataElement * pEl = &Data.data.aElements[i];
1315 rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
1316 AssertRCReturn(rc, rc);
1317 }
1318
1319 crVBoxServerFBImageDataTerm(&Data.data);
1320
1321 return VINF_SUCCESS;
1322}
1323
1324#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
1325 if(!RT_SUCCESS((_rc))) { \
1326 AssertFailed(); \
1327 return; \
1328 } \
1329 } while (0)
1330
1331static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
1332{
1333 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1334 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1335 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1336 PSSMHANDLE pSSM = pData->pSSM;
1337 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1338 CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
1339
1340 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1341
1342 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1343
1344 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1345 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1346
1347 pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
1348 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1349
1350 crServerPerformMakeCurrent(pMural, pContextInfo);
1351
1352 pData->rc = crVBoxServerSaveFBImage(pSSM);
1353
1354 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1355 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1356 pContextInfo->currentMural = pInitialCurMural;
1357
1358 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1359}
1360
1361static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
1362{
1363 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1364 CRContext *pContext = pContextInfo->pContext;
1365 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1366 PSSMHANDLE pSSM = pData->pSSM;
1367 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
1368 CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
1369 const int32_t i32Dummy = 0;
1370
1371 AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
1372 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1373
1374 CRASSERT(pContext && pSSM);
1375 CRASSERT(pMural);
1376 CRASSERT(pMural->CreateInfo.externalID);
1377
1378 /* We could have skipped saving the key and use similar callback to load context states back,
1379 * but there's no guarantee we'd traverse hashtable in same order after loading.
1380 */
1381 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1382 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1383
1384#ifdef DEBUG_misha
1385 {
1386 unsigned long id;
1387 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
1388 crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
1389 else
1390 CRASSERT(id == key);
1391 }
1392#endif
1393
1394#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1395 if (pContextInfo->currentMural
1396 || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
1397 )
1398 {
1399 CRASSERT(pMural->CreateInfo.externalID);
1400 CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1401 pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
1402 }
1403 else
1404 {
1405 /* this is a dummy mural */
1406 CRASSERT(!pMural->width);
1407 CRASSERT(!pMural->height);
1408 CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1409 pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
1410 }
1411 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1412
1413 CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
1414 CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
1415 CRASSERT(cr_server.curClient);
1416
1417 crServerPerformMakeCurrent(pMural, pContextInfo);
1418#endif
1419
1420 pData->rc = crStateSaveContext(pContext, pSSM);
1421 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1422
1423 pData->rc = crVBoxServerSaveFBImage(pSSM);
1424 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1425
1426 /* restore the initial current mural */
1427 pContextInfo->currentMural = pContextCurrentMural;
1428}
1429
1430#if 0
1431typedef struct CR_SERVER_CHECK_BUFFERS
1432{
1433 CRBufferObject *obj;
1434 CRContext *ctx;
1435}CR_SERVER_CHECK_BUFFERS, *PCR_SERVER_CHECK_BUFFERS;
1436
1437static void crVBoxServerCheckConsistencyContextBuffersCB(unsigned long key, void *data1, void *data2)
1438{
1439 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1440 CRContext *ctx = pContextInfo->pContext;
1441 PCR_SERVER_CHECK_BUFFERS pBuffers = (PCR_SERVER_CHECK_BUFFERS)data2;
1442 CRBufferObject *obj = pBuffers->obj;
1443 CRBufferObjectState *b = &(ctx->bufferobject);
1444 int j, k;
1445
1446 if (obj == b->arrayBuffer)
1447 {
1448 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1449 pBuffers->ctx = ctx;
1450 }
1451 if (obj == b->elementsBuffer)
1452 {
1453 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1454 pBuffers->ctx = ctx;
1455 }
1456#ifdef CR_ARB_pixel_buffer_object
1457 if (obj == b->packBuffer)
1458 {
1459 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1460 pBuffers->ctx = ctx;
1461 }
1462 if (obj == b->unpackBuffer)
1463 {
1464 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1465 pBuffers->ctx = ctx;
1466 }
1467#endif
1468
1469#ifdef CR_ARB_vertex_buffer_object
1470 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1471 {
1472 CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array);
1473 if (obj == cp->buffer)
1474 {
1475 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1476 pBuffers->ctx = ctx;
1477 }
1478 }
1479
1480 for (k=0; k<ctx->client.vertexArrayStackDepth; ++k)
1481 {
1482 CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k];
1483 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1484 {
1485 CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray);
1486 if (obj == cp->buffer)
1487 {
1488 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1489 pBuffers->ctx = ctx;
1490 }
1491 }
1492 }
1493#endif
1494}
1495
1496static void crVBoxServerCheckConsistencyBuffersCB(unsigned long key, void *data1, void *data2)
1497{
1498 CRBufferObject *obj = (CRBufferObject *)data1;
1499 CR_SERVER_CHECK_BUFFERS Buffers = {0};
1500 Buffers.obj = obj;
1501 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckConsistencyContextBuffersCB, (void*)&Buffers);
1502}
1503
1504//static void crVBoxServerCheckConsistency2CB(unsigned long key, void *data1, void *data2)
1505//{
1506// CRContextInfo* pContextInfo1 = (CRContextInfo*)data1;
1507// CRContextInfo* pContextInfo2 = (CRContextInfo*)data2;
1508//
1509// CRASSERT(pContextInfo1->pContext);
1510// CRASSERT(pContextInfo2->pContext);
1511//
1512// if (pContextInfo1 == pContextInfo2)
1513// {
1514// CRASSERT(pContextInfo1->pContext == pContextInfo2->pContext);
1515// return;
1516// }
1517//
1518// CRASSERT(pContextInfo1->pContext != pContextInfo2->pContext);
1519// CRASSERT(pContextInfo1->pContext->shared);
1520// CRASSERT(pContextInfo2->pContext->shared);
1521// CRASSERT(pContextInfo1->pContext->shared == pContextInfo2->pContext->shared);
1522// if (pContextInfo1->pContext->shared != pContextInfo2->pContext->shared)
1523// return;
1524//
1525// crHashtableWalk(pContextInfo1->pContext->shared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, pContextInfo2);
1526//}
1527static void crVBoxServerCheckSharedCB(unsigned long key, void *data1, void *data2)
1528{
1529 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1530 void **ppShared = (void**)data2;
1531 if (!*ppShared)
1532 *ppShared = pContextInfo->pContext->shared;
1533 else
1534 Assert(pContextInfo->pContext->shared == *ppShared);
1535}
1536
1537static void crVBoxServerCheckConsistency()
1538{
1539 CRSharedState *pShared = NULL;
1540 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckSharedCB, (void*)&pShared);
1541 Assert(pShared);
1542 if (pShared)
1543 {
1544 crHashtableWalk(pShared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, NULL);
1545 }
1546}
1547#endif
1548
1549static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
1550
1551DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
1552{
1553 int32_t rc, i;
1554 uint32_t ui32;
1555 GLboolean b;
1556 unsigned long key;
1557 GLenum err;
1558#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1559 CRClient *curClient;
1560 CRMuralInfo *curMural = NULL;
1561 CRContextInfo *curCtxInfo = NULL;
1562#endif
1563 CRVBOX_SAVE_STATE_GLOBAL Data;
1564
1565 crMemset(&Data, 0, sizeof (Data));
1566
1567#if 0
1568 crVBoxServerCheckConsistency();
1569#endif
1570
1571 /* We shouldn't be called if there's no clients at all*/
1572 CRASSERT(cr_server.numClients>0);
1573
1574 /* @todo it's hack atm */
1575 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1576 * for every connected client (e.g. guest opengl application)
1577 */
1578 if (!cr_server.bIsInSavingState) /* It's first call */
1579 {
1580 cr_server.bIsInSavingState = GL_TRUE;
1581
1582 /* Store number of clients */
1583 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1584 AssertRCReturn(rc, rc);
1585
1586 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
1587 }
1588
1589 g_hackVBoxServerSaveLoadCallsLeft--;
1590
1591 /* Do nothing until we're being called last time */
1592 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1593 {
1594 return VINF_SUCCESS;
1595 }
1596
1597#ifdef DEBUG_misha
1598#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart"
1599#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop"
1600
1601 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1602 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START);
1603#endif
1604
1605 /* Save rendering contexts creation info */
1606 ui32 = crHashtableNumElements(cr_server.contextTable);
1607 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1608 AssertRCReturn(rc, rc);
1609 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1610
1611#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1612 curClient = cr_server.curClient;
1613 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1614 if (curClient)
1615 {
1616 curCtxInfo = cr_server.curClient->currentCtxInfo;
1617 curMural = cr_server.curClient->currentMural;
1618 }
1619 else if (cr_server.numClients)
1620 {
1621 cr_server.curClient = cr_server.clients[0];
1622 }
1623#endif
1624
1625 /* first save windows info */
1626 /* Save windows creation info */
1627 ui32 = crHashtableNumElements(cr_server.muralTable);
1628 /* There should be default mural always */
1629 CRASSERT(ui32>=1);
1630 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1631 AssertRCReturn(rc, rc);
1632 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1633
1634 /* Save cr_server.muralTable
1635 * @todo we don't need it all, just geometry info actually
1636 */
1637 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1638 AssertRCReturn(rc, rc);
1639 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1640
1641 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1642 crVBoxServerBuildSaveStateGlobal(&Data);
1643
1644 rc = crStateSaveGlobals(pSSM);
1645 AssertRCReturn(rc, rc);
1646
1647 Data.pSSM = pSSM;
1648 /* Save contexts state tracker data */
1649 /* @todo For now just some blind data dumps,
1650 * but I've a feeling those should be saved/restored in a very strict sequence to
1651 * allow diff_api to work correctly.
1652 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1653 */
1654 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1655 AssertRCReturn(Data.rc, Data.rc);
1656
1657 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1658 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1659 AssertRCReturn(rc, rc);
1660
1661 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1662 AssertRCReturn(Data.rc, Data.rc);
1663
1664#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1665 cr_server.curClient = curClient;
1666 /* Restore original win and ctx IDs*/
1667 if (curClient && curMural && curCtxInfo)
1668 {
1669 crServerPerformMakeCurrent(curMural, curCtxInfo);
1670 }
1671 else
1672 {
1673 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1674 }
1675#endif
1676
1677 /* Save clients info */
1678 for (i = 0; i < cr_server.numClients; i++)
1679 {
1680 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1681 {
1682 CRClient *pClient = cr_server.clients[i];
1683
1684 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1685 AssertRCReturn(rc, rc);
1686
1687 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1688 AssertRCReturn(rc, rc);
1689
1690 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1691 AssertRCReturn(rc, rc);
1692
1693 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1694 AssertRCReturn(rc, rc);
1695
1696 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber > 0)
1697 {
1698 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1699 CRASSERT(b);
1700 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1701 AssertRCReturn(rc, rc);
1702 }
1703
1704 if (pClient->currentMural && pClient->currentWindow > 0)
1705 {
1706 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1707 CRASSERT(b);
1708 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1709 AssertRCReturn(rc, rc);
1710 }
1711 }
1712 }
1713
1714 rc = CrPMgrSaveState(pSSM);
1715 AssertRCReturn(rc, rc);
1716
1717 /* all context gl error states should have now be synced with chromium erro states,
1718 * reset the error if any */
1719 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1720 crWarning("crServer: glGetError %d after saving snapshot", err);
1721
1722 cr_server.bIsInSavingState = GL_FALSE;
1723
1724#ifdef DEBUG_misha
1725 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1726 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
1727#endif
1728
1729 return VINF_SUCCESS;
1730}
1731
1732static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1733{
1734 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1735 CRASSERT(pContextInfo);
1736 CRASSERT(pContextInfo->pContext);
1737 return pContextInfo->pContext;
1738}
1739
1740typedef struct CR_SERVER_LOADSTATE_READER
1741{
1742 PSSMHANDLE pSSM;
1743 uint32_t cbBuffer;
1744 uint32_t cbData;
1745 uint32_t offData;
1746 uint8_t *pu8Buffer;
1747} CR_SERVER_LOADSTATE_READER;
1748
1749static void crServerLsrInit(CR_SERVER_LOADSTATE_READER *pReader, PSSMHANDLE pSSM)
1750{
1751 memset(pReader, 0, sizeof (*pReader));
1752 pReader->pSSM = pSSM;
1753}
1754
1755static void crServerLsrTerm(CR_SERVER_LOADSTATE_READER *pReader)
1756{
1757 if (pReader->pu8Buffer)
1758 RTMemFree(pReader->pu8Buffer);
1759
1760 /* sanity */
1761 memset(pReader, 0, sizeof (*pReader));
1762}
1763
1764static int crServerLsrDataGetMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1765{
1766 int rc = VINF_SUCCESS;
1767 uint32_t cbRemaining = cbBuffer;
1768 if (pReader->cbData)
1769 {
1770 uint8_t cbData = RT_MIN(pReader->cbData, cbBuffer);
1771 memcpy(pvBuffer, pReader->pu8Buffer + pReader->offData, cbData);
1772 pReader->cbData -= cbData;
1773 pReader->offData += cbData;
1774
1775 cbRemaining -= cbData;
1776 pvBuffer = ((uint8_t*)pvBuffer) + cbData;
1777 }
1778
1779 if (cbRemaining)
1780 {
1781 rc = SSMR3GetMem(pReader->pSSM, pvBuffer, cbRemaining);
1782 AssertRC(rc);
1783 }
1784
1785 return rc;
1786}
1787
1788static int crServerLsrDataGetU32(CR_SERVER_LOADSTATE_READER *pReader, uint32_t *pu32)
1789{
1790 return crServerLsrDataGetMem(pReader, pu32, sizeof (*pu32));
1791}
1792
1793static int crServerLsrDataPutMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
1794{
1795 if (!pReader->cbData && pReader->cbBuffer >= cbBuffer)
1796 {
1797 pReader->offData = 0;
1798 pReader->cbData = cbBuffer;
1799 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1800 }
1801 else if (pReader->offData >= cbBuffer)
1802 {
1803 pReader->offData -= cbBuffer;
1804 pReader->cbData += cbBuffer;
1805 memcpy(pReader->pu8Buffer + pReader->offData, pvBuffer, cbBuffer);
1806 }
1807 else
1808 {
1809 uint8_t *pu8Buffer = pReader->pu8Buffer;
1810
1811 pReader->pu8Buffer = (uint8_t*)RTMemAlloc(cbBuffer + pReader->cbData);
1812 if (!pReader->pu8Buffer)
1813 {
1814 crWarning("failed to allocate mem %d", cbBuffer + pReader->cbData);
1815 return VERR_NO_MEMORY;
1816 }
1817
1818 memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
1819 if (pu8Buffer)
1820 {
1821 memcpy(pReader->pu8Buffer + cbBuffer, pu8Buffer + pReader->offData, pReader->cbData);
1822 RTMemFree(pu8Buffer);
1823 }
1824 else
1825 {
1826 Assert(!pReader->cbData);
1827 }
1828 pReader->offData = 0;
1829 pReader->cbData += cbBuffer;
1830 }
1831
1832 return VINF_SUCCESS;
1833}
1834
1835/* data to be skipped */
1836
1837typedef struct CR_SERVER_BUGGY_MURAL_DATA_2
1838{
1839 void*ListHead_pNext;
1840 void*ListHead_pPrev;
1841 uint32_t cEntries;
1842} CR_SERVER_BUGGY_MURAL_DATA_2;
1843typedef struct CR_SERVER_BUGGY_MURAL_DATA_1
1844{
1845 /* VBOXVR_COMPOSITOR_ENTRY Ce; */
1846 void*Ce_Node_pNext;
1847 void*Ce_Node_pPrev;
1848 CR_SERVER_BUGGY_MURAL_DATA_2 Vr;
1849 /* VBOXVR_TEXTURE Tex; */
1850 uint32_t Tex_width;
1851 uint32_t Tex_height;
1852 uint32_t Tex_target;
1853 uint32_t Tex_hwid;
1854 /* RTPOINT Pos; */
1855 uint32_t Pos_x;
1856 uint32_t Pos_y;
1857 uint32_t fChanged;
1858 uint32_t cRects;
1859 void* paSrcRects;
1860 void* paDstRects;
1861} CR_SERVER_BUGGY_MURAL_DATA_1;
1862
1863typedef struct CR_SERVER_BUGGY_MURAL_DATA_4
1864{
1865 uint32_t u32Magic;
1866 int32_t cLockers;
1867 RTNATIVETHREAD NativeThreadOwner;
1868 int32_t cNestings;
1869 uint32_t fFlags;
1870 void* EventSem;
1871 R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec;
1872 RTHCPTR Alignment;
1873} CR_SERVER_BUGGY_MURAL_DATA_4;
1874
1875typedef struct CR_SERVER_BUGGY_MURAL_DATA_3
1876{
1877 void*Compositor_List_pNext;
1878 void*Compositor_List_pPrev;
1879 void*Compositor_pfnEntryRemoved;
1880 float StretchX;
1881 float StretchY;
1882 uint32_t cRects;
1883 uint32_t cRectsBuffer;
1884 void*paSrcRects;
1885 void*paDstRects;
1886 CR_SERVER_BUGGY_MURAL_DATA_4 CritSect;
1887} CR_SERVER_BUGGY_MURAL_DATA_3;
1888
1889typedef struct CR_SERVER_BUGGY_MURAL_DATA
1890{
1891 uint8_t fRootVrOn;
1892 CR_SERVER_BUGGY_MURAL_DATA_1 RootVrCEntry;
1893 CR_SERVER_BUGGY_MURAL_DATA_3 RootVrCompositor;
1894} CR_SERVER_BUGGY_MURAL_DATA;
1895
1896AssertCompile(sizeof (CR_SERVER_BUGGY_MURAL_DATA) < sizeof (CRClient));
1897
1898static int32_t crVBoxServerLoadMurals(CR_SERVER_LOADSTATE_READER *pReader, uint32_t version)
1899{
1900 unsigned long key;
1901 uint32_t ui, uiNumElems;
1902 bool fBuggyMuralData = false;
1903 /* Load windows */
1904 int32_t rc = crServerLsrDataGetU32(pReader, &uiNumElems);
1905 AssertRCReturn(rc, rc);
1906 for (ui=0; ui<uiNumElems; ++ui)
1907 {
1908 CRCreateInfo_t createInfo;
1909 char psz[200];
1910 GLint winID;
1911 unsigned long key;
1912
1913 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1914 AssertRCReturn(rc, rc);
1915 rc = crServerLsrDataGetMem(pReader, &createInfo, sizeof(createInfo));
1916 AssertRCReturn(rc, rc);
1917
1918 CRASSERT(!pReader->cbData);
1919
1920 if (createInfo.pszDpyName)
1921 {
1922 rc = SSMR3GetStrZEx(pReader->pSSM, psz, 200, NULL);
1923 AssertRCReturn(rc, rc);
1924 createInfo.pszDpyName = psz;
1925 }
1926
1927 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1928 CRASSERT((int64_t)winID == (int64_t)key);
1929 }
1930
1931 /* Load cr_server.muralTable */
1932 rc = SSMR3GetU32(pReader->pSSM, &uiNumElems);
1933 AssertRCReturn(rc, rc);
1934 for (ui=0; ui<uiNumElems; ++ui)
1935 {
1936 CRMuralInfo muralInfo;
1937 CRMuralInfo *pActualMural = NULL;
1938
1939 rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
1940 AssertRCReturn(rc, rc);
1941 rc = crServerLsrDataGetMem(pReader, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1942 AssertRCReturn(rc, rc);
1943
1944 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1945 muralInfo.bFbDraw = GL_TRUE;
1946
1947 if (!ui && version == SHCROGL_SSM_VERSION_WITH_BUGGY_MURAL_INFO)
1948 {
1949 /* Lookahead buffer used to determine whether the data erroneously stored root visible regions data */
1950 union
1951 {
1952 void * apv[1];
1953 CR_SERVER_BUGGY_MURAL_DATA Data;
1954 /* need to chak spuWindow, so taking the offset of filed following it*/
1955 uint8_t au8[RT_OFFSETOF(CRMuralInfo, screenId)];
1956 RTRECT aVisRects[sizeof (CR_SERVER_BUGGY_MURAL_DATA) / sizeof (RTRECT)];
1957 } LaBuf;
1958
1959 do {
1960 /* first value is bool (uint8_t) value followed by pointer-size-based alignment.
1961 * the mural memory is zero-initialized initially, so we can be sure the padding is zeroed */
1962 rc = crServerLsrDataGetMem(pReader, &LaBuf, sizeof (LaBuf));
1963 AssertRCReturn(rc, rc);
1964 if (LaBuf.apv[0] != NULL && LaBuf.apv[0] != ((void*)1))
1965 break;
1966
1967 /* check that the pointers are either valid or NULL */
1968 if(LaBuf.Data.RootVrCEntry.Ce_Node_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pNext))
1969 break;
1970 if(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev))
1971 break;
1972 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext))
1973 break;
1974 if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev))
1975 break;
1976
1977 /* the entry can can be the only one within the (mural) compositor,
1978 * so its compositor entry node can either contain NULL pNext and pPrev,
1979 * or both of them pointing to compositor's list head */
1980 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext != LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1981 break;
1982
1983 /* can either both or none be NULL */
1984 if (!LaBuf.Data.RootVrCEntry.Ce_Node_pNext != !LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1985 break;
1986
1987 if (!LaBuf.Data.fRootVrOn)
1988 {
1989 if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext || LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
1990 break;
1991
1992 /* either non-initialized (zeroed) or empty list */
1993 if (LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext != LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
1994 break;
1995
1996 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
1997 break;
1998 }
1999 else
2000 {
2001 /* the entry should be initialized */
2002 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext)
2003 break;
2004 if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
2005 break;
2006
2007 if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
2008 {
2009 /* entry should be in compositor list*/
2010 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev == NULL)
2011 break;
2012 CRASSERT(LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2013 }
2014 else
2015 {
2016 /* entry should NOT be in compositor list*/
2017 if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev != NULL)
2018 break;
2019 CRASSERT(!LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
2020 }
2021 }
2022
2023#if 0
2024 if (muralInfo.pVisibleRects)
2025 {
2026 int j;
2027 int cRects = RT_MIN(muralInfo.cVisibleRects, RT_ELEMENTS(LaBuf.aVisRects));
2028 CRASSERT(cRects);
2029 for (j = 0; j < cRects; ++j)
2030 {
2031 PRTRECT pRect = &LaBuf.aVisRects[j];
2032 if (pRect->xLeft >= pRect->xRight)
2033 break;
2034 if (pRect->yTop >= pRect->yBottom)
2035 break;
2036 if (pRect->xLeft < 0 || pRect->xRight < 0
2037 || pRect->yTop < 0 || pRect->yBottom < 0)
2038 break;
2039 if (pRect->xLeft > (GLint)muralInfo.width
2040 || pRect->xRight > (GLint)muralInfo.width)
2041 break;
2042 if (pRect->yTop > (GLint)muralInfo.height
2043 || pRect->yBottom > (GLint)muralInfo.height)
2044 break;
2045 }
2046
2047 if (j < cRects)
2048 {
2049 fBuggyMuralData = true;
2050 break;
2051 }
2052 }
2053
2054 if (muralInfo.pVisibleRects)
2055 {
2056 /* @todo: do we actually need any further checks here? */
2057 fBuggyMuralData = true;
2058 break;
2059 }
2060
2061 /* no visible regions*/
2062
2063 if (ui == uiNumElems - 1)
2064 {
2065 /* this is the last mural, next it goes idsPool, whose content can not match the above template again */
2066 fBuggyMuralData = true;
2067 break;
2068 }
2069
2070 /* next it goes a next mural info */
2071// if (!fExpectPtr)
2072// {
2073// CRMuralInfo *pNextSpuWindowInfoMural = (CRMuralInfo*)((void*)&LaBuf);
2074// if (!pNextSpuWindowInfoMural->spuWindow)
2075// fBuggyMuralData = true;
2076//
2077// break;
2078// }
2079#endif
2080 /* fExpectPtr == true, the valid pointer values should not match possible mural width/height/position */
2081 fBuggyMuralData = true;
2082 break;
2083
2084 } while (0);
2085
2086 rc = crServerLsrDataPutMem(pReader, &LaBuf, sizeof (LaBuf));
2087 AssertRCReturn(rc, rc);
2088 }
2089
2090 if (fBuggyMuralData)
2091 {
2092 CR_SERVER_BUGGY_MURAL_DATA Tmp;
2093 rc = crServerLsrDataGetMem(pReader, &Tmp, sizeof (Tmp));
2094 AssertRCReturn(rc, rc);
2095 }
2096
2097 if (muralInfo.pVisibleRects)
2098 {
2099 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
2100 if (!muralInfo.pVisibleRects)
2101 {
2102 return VERR_NO_MEMORY;
2103 }
2104
2105 rc = crServerLsrDataGetMem(pReader, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
2106 AssertRCReturn(rc, rc);
2107 }
2108
2109 pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);
2110 CRASSERT(pActualMural);
2111
2112 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
2113 {
2114 rc = crServerLsrDataGetMem(pReader, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
2115 CRASSERT(rc == VINF_SUCCESS);
2116 }
2117
2118 /* Restore windows geometry info */
2119 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
2120 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
2121 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
2122 if (muralInfo.bReceivedRects)
2123 {
2124 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
2125 }
2126 crServerDispatchWindowShow(key, muralInfo.bVisible);
2127
2128 if (muralInfo.pVisibleRects)
2129 {
2130 crFree(muralInfo.pVisibleRects);
2131 }
2132 }
2133
2134 CRASSERT(RT_SUCCESS(rc));
2135 return VINF_SUCCESS;
2136}
2137
2138static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
2139 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
2140{
2141 CRContext *pContext = pContextInfo->pContext;
2142 int32_t rc = VINF_SUCCESS;
2143 GLuint i;
2144 /* can apply the data right away */
2145 struct
2146 {
2147 CRFBData data;
2148 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
2149 } Data;
2150
2151 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
2152
2153 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
2154 {
2155 if (!pMural->width || !pMural->height)
2156 return VINF_SUCCESS;
2157
2158 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
2159 if (!RT_SUCCESS(rc))
2160 {
2161 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2162 return rc;
2163 }
2164 }
2165 else
2166 {
2167 GLint storedWidth, storedHeight;
2168
2169 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2170 {
2171 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
2172 CRASSERT(cr_server.currentMural == pMural);
2173 storedWidth = pMural->width;
2174 storedHeight = pMural->height;
2175 }
2176 else
2177 {
2178 storedWidth = pContext->buffer.storedWidth;
2179 storedHeight = pContext->buffer.storedHeight;
2180 }
2181
2182 if (!storedWidth || !storedHeight)
2183 return VINF_SUCCESS;
2184
2185 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
2186 if (!RT_SUCCESS(rc))
2187 {
2188 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
2189 return rc;
2190 }
2191 }
2192
2193 CRASSERT(Data.data.cElements);
2194
2195 for (i = 0; i < Data.data.cElements; ++i)
2196 {
2197 CRFBDataElement * pEl = &Data.data.aElements[i];
2198 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
2199 AssertRCReturn(rc, rc);
2200 }
2201
2202 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2203 {
2204 CRBufferState *pBuf = &pContext->buffer;
2205 /* can apply the data right away */
2206 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2207 CRASSERT(cr_server.currentMural);
2208
2209 cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
2210 0,
2211 pContextInfo->SpuContext >= 0
2212 ? pContextInfo->SpuContext
2213 : cr_server.MainContextInfo.SpuContext);
2214 crStateApplyFBImage(pContext, &Data.data);
2215 CRASSERT(!pBuf->pFrontImg);
2216 CRASSERT(!pBuf->pBackImg);
2217 crVBoxServerFBImageDataTerm(&Data.data);
2218
2219 crServerPresentFBO(pMural);
2220
2221 CRASSERT(cr_server.currentMural);
2222 cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
2223 0,
2224 cr_server.currentCtxInfo->SpuContext >= 0
2225 ? cr_server.currentCtxInfo->SpuContext
2226 : cr_server.MainContextInfo.SpuContext);
2227 }
2228 else
2229 {
2230 CRBufferState *pBuf = &pContext->buffer;
2231 CRASSERT(!pBuf->pFrontImg);
2232 CRASSERT(!pBuf->pBackImg);
2233 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
2234
2235 if (Data.data.cElements)
2236 {
2237 CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
2238 if (!RT_SUCCESS(rc))
2239 {
2240 crVBoxServerFBImageDataTerm(&Data.data);
2241 crWarning("crAlloc failed");
2242 return VERR_NO_MEMORY;
2243 }
2244
2245 crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
2246 pBuf->pFrontImg = pLazyData;
2247 }
2248 }
2249
2250 CRASSERT(RT_SUCCESS(rc));
2251 return VINF_SUCCESS;
2252}
2253
2254DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
2255{
2256 int32_t rc, i;
2257 uint32_t ui, uiNumElems;
2258 unsigned long key;
2259 GLenum err;
2260 CR_SERVER_LOADSTATE_READER Reader;
2261
2262 if (!cr_server.bIsInLoadingState)
2263 {
2264 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
2265 cr_server.bIsInLoadingState = GL_TRUE;
2266
2267 /* Read number of clients */
2268 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
2269 AssertRCReturn(rc, rc);
2270 }
2271
2272 g_hackVBoxServerSaveLoadCallsLeft--;
2273
2274 /* Do nothing until we're being called last time */
2275 if (g_hackVBoxServerSaveLoadCallsLeft>0)
2276 {
2277 return VINF_SUCCESS;
2278 }
2279
2280 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
2281 {
2282 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2283 }
2284
2285 crServerLsrInit(&Reader, pSSM);
2286
2287#ifdef DEBUG_misha
2288#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
2289#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
2290
2291 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2292 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
2293#endif
2294
2295 /* Load and recreate rendering contexts */
2296 rc = SSMR3GetU32(pSSM, &uiNumElems);
2297 AssertRCReturn(rc, rc);
2298 for (ui=0; ui<uiNumElems; ++ui)
2299 {
2300 CRCreateInfo_t createInfo;
2301 char psz[200];
2302 GLint ctxID;
2303 CRContextInfo* pContextInfo;
2304 CRContext* pContext;
2305
2306 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2307 AssertRCReturn(rc, rc);
2308 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
2309 AssertRCReturn(rc, rc);
2310
2311 if (createInfo.pszDpyName)
2312 {
2313 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
2314 AssertRCReturn(rc, rc);
2315 createInfo.pszDpyName = psz;
2316 }
2317
2318 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
2319 CRASSERT((int64_t)ctxID == (int64_t)key);
2320
2321 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2322 CRASSERT(pContextInfo);
2323 CRASSERT(pContextInfo->pContext);
2324 pContext = pContextInfo->pContext;
2325 pContext->shared->id=-1;
2326 }
2327
2328 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2329 {
2330 CRASSERT(!Reader.pu8Buffer);
2331 /* we have a mural data here */
2332 rc = crVBoxServerLoadMurals(&Reader, version);
2333 AssertRCReturn(rc, rc);
2334 CRASSERT(!Reader.pu8Buffer);
2335 }
2336
2337 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
2338 {
2339 /* set the current client to allow doing crServerPerformMakeCurrent later */
2340 CRASSERT(cr_server.numClients);
2341 cr_server.curClient = cr_server.clients[0];
2342 }
2343
2344 rc = crStateLoadGlobals(pSSM, version);
2345 AssertRCReturn(rc, rc);
2346
2347 if (uiNumElems)
2348 {
2349 /* ensure we have main context set up as current */
2350 CRMuralInfo *pMural;
2351 CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
2352 CRASSERT(!cr_server.currentCtxInfo);
2353 CRASSERT(!cr_server.currentMural);
2354 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
2355 CRASSERT(pMural);
2356 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
2357 }
2358
2359 /* Restore context state data */
2360 for (ui=0; ui<uiNumElems; ++ui)
2361 {
2362 CRContextInfo* pContextInfo;
2363 CRContext *pContext;
2364 CRMuralInfo *pMural = NULL;
2365 int32_t winId = 0;
2366
2367 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2368 AssertRCReturn(rc, rc);
2369
2370 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
2371 CRASSERT(pContextInfo);
2372 CRASSERT(pContextInfo->pContext);
2373 pContext = pContextInfo->pContext;
2374
2375 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2376 {
2377 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
2378 AssertRCReturn(rc, rc);
2379
2380 if (winId)
2381 {
2382 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
2383 CRASSERT(pMural);
2384 }
2385 else
2386 {
2387 /* null winId means a dummy mural, get it */
2388 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
2389 CRASSERT(pMural);
2390 }
2391 }
2392
2393 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
2394 AssertRCReturn(rc, rc);
2395
2396 /*Restore front/back buffer images*/
2397 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2398 AssertRCReturn(rc, rc);
2399 }
2400
2401 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
2402 {
2403 CRContextInfo *pContextInfo;
2404 CRMuralInfo *pMural;
2405 GLint ctxId;
2406
2407 rc = SSMR3GetU32(pSSM, &uiNumElems);
2408 AssertRCReturn(rc, rc);
2409 for (ui=0; ui<uiNumElems; ++ui)
2410 {
2411 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
2412 CRMuralInfo *pInitialCurMural;
2413
2414 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
2415 AssertRCReturn(rc, rc);
2416
2417 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
2418 AssertRCReturn(rc, rc);
2419
2420 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
2421 CRASSERT(pMural);
2422 if (ctxId)
2423 {
2424 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
2425 CRASSERT(pContextInfo);
2426 }
2427 else
2428 pContextInfo = &cr_server.MainContextInfo;
2429
2430 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
2431 pInitialCurMural = pContextInfo->currentMural;
2432
2433 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2434 AssertRCReturn(rc, rc);
2435
2436 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
2437 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
2438 pContextInfo->currentMural = pInitialCurMural;
2439 }
2440
2441 CRASSERT(!uiNumElems || cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2442
2443 cr_server.curClient = NULL;
2444 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
2445 }
2446 else
2447 {
2448 CRServerFreeIDsPool_t dummyIdsPool;
2449
2450 CRASSERT(!Reader.pu8Buffer);
2451
2452 /* we have a mural data here */
2453 rc = crVBoxServerLoadMurals(&Reader, version);
2454 AssertRCReturn(rc, rc);
2455
2456 /* not used any more, just read it out and ignore */
2457 rc = crServerLsrDataGetMem(&Reader, &dummyIdsPool, sizeof(dummyIdsPool));
2458 CRASSERT(rc == VINF_SUCCESS);
2459 }
2460
2461 /* Load clients info */
2462 for (i = 0; i < cr_server.numClients; i++)
2463 {
2464 if (cr_server.clients[i] && cr_server.clients[i]->conn)
2465 {
2466 CRClient *pClient = cr_server.clients[i];
2467 CRClient client;
2468 unsigned long ctxID=-1, winID=-1;
2469
2470 rc = crServerLsrDataGetU32(&Reader, &ui);
2471 AssertRCReturn(rc, rc);
2472 /* If this assert fires, then we should search correct client in the list first*/
2473 CRASSERT(ui == pClient->conn->u32ClientID);
2474
2475 if (version>=4)
2476 {
2477 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMajor);
2478 AssertRCReturn(rc, rc);
2479
2480 rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMinor);
2481 AssertRCReturn(rc, rc);
2482 }
2483
2484 rc = crServerLsrDataGetMem(&Reader, &client, sizeof(client));
2485 CRASSERT(rc == VINF_SUCCESS);
2486
2487 client.conn = pClient->conn;
2488 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2489 * and fail to bind old textures.
2490 */
2491 /*client.number = pClient->number;*/
2492 *pClient = client;
2493
2494 pClient->currentContextNumber = -1;
2495 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2496 pClient->currentMural = NULL;
2497 pClient->currentWindow = -1;
2498
2499 cr_server.curClient = pClient;
2500
2501 if (client.currentCtxInfo && client.currentContextNumber > 0)
2502 {
2503 rc = crServerLsrDataGetMem(&Reader, &ctxID, sizeof(ctxID));
2504 AssertRCReturn(rc, rc);
2505 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2506 CRASSERT(client.currentCtxInfo);
2507 CRASSERT(client.currentCtxInfo->pContext);
2508 //pClient->currentCtx = client.currentCtx;
2509 //pClient->currentContextNumber = ctxID;
2510 }
2511
2512 if (client.currentMural && client.currentWindow > 0)
2513 {
2514 rc = crServerLsrDataGetMem(&Reader, &winID, sizeof(winID));
2515 AssertRCReturn(rc, rc);
2516 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2517 CRASSERT(client.currentMural);
2518 //pClient->currentMural = client.currentMural;
2519 //pClient->currentWindow = winID;
2520 }
2521
2522 CRASSERT(!Reader.cbData);
2523
2524 /* Restore client active context and window */
2525 crServerDispatchMakeCurrent(winID, 0, ctxID);
2526
2527 if (0)
2528 {
2529// CRContext *tmpCtx;
2530// CRCreateInfo_t *createInfo;
2531 GLfloat one[4] = { 1, 1, 1, 1 };
2532 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
2533
2534 crServerDispatchMakeCurrent(winID, 0, ctxID);
2535
2536 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
2537
2538 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
2539 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
2540 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
2541#ifdef CR_ARB_texture_cube_map
2542 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
2543#endif
2544#ifdef CR_NV_texture_rectangle
2545 //@todo this doesn't work as expected
2546 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
2547#endif
2548 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
2549 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
2550 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
2551
2552 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
2553 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
2554 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
2555
2556 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
2557 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
2558
2559 //crStateViewport( 0, 0, 600, 600 );
2560 //pClient->currentMural->viewportValidated = GL_FALSE;
2561 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
2562
2563 //crStateMatrixMode(GL_PROJECTION);
2564 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
2565
2566 //crStateLoadIdentity();
2567 //cr_server.head_spu->dispatch_table.LoadIdentity();
2568
2569 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2570 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2571
2572 //crStateMatrixMode(GL_MODELVIEW);
2573 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
2574 //crServerDispatchLoadIdentity();
2575 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2576 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2577 //crServerDispatchLoadIdentity();
2578
2579 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
2580 CRASSERT(createInfo);
2581 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
2582 CRASSERT(tmpCtx);
2583 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
2584 crStateDestroyContext(tmpCtx);*/
2585 }
2586 }
2587 }
2588
2589 //crServerDispatchMakeCurrent(-1, 0, -1);
2590
2591 cr_server.curClient = NULL;
2592
2593 if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_INFO)
2594 {
2595 HCR_FRAMEBUFFER hFb;
2596
2597 rc = CrPMgrLoadState(pSSM, version);
2598 AssertRCReturn(rc, rc);
2599 }
2600
2601 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2602 crWarning("crServer: glGetError %d after loading snapshot", err);
2603
2604 cr_server.bIsInLoadingState = GL_FALSE;
2605
2606#if 0
2607 crVBoxServerCheckConsistency();
2608#endif
2609
2610#ifdef DEBUG_misha
2611 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2612 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
2613#endif
2614
2615 CRASSERT(!Reader.cbData);
2616 crServerLsrTerm(&Reader);
2617
2618 return VINF_SUCCESS;
2619}
2620
2621#define SCREEN(i) (cr_server.screen[i])
2622#define MAPPED(screen) ((screen).winID != 0)
2623
2624extern DECLEXPORT(void) crServerVBoxSetNotifyEventCB(PFNCRSERVERNOTIFYEVENT pfnCb)
2625{
2626 cr_server.pfnNotifyEventCB = pfnCb;
2627}
2628
2629void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void*pvData)
2630{
2631 /* this is something unexpected, but just in case */
2632 if (idScreen >= cr_server.screenCount)
2633 {
2634 crWarning("invalid screen id %d", idScreen);
2635 return;
2636 }
2637
2638 cr_server.pfnNotifyEventCB(idScreen, uEvent, pvData);
2639}
2640
2641void crServerWindowReparent(CRMuralInfo *pMural)
2642{
2643 pMural->fHasParentWindow = !!cr_server.screen[pMural->screenId].winID;
2644
2645 renderspuReparentWindow(pMural->spuWindow);
2646}
2647
2648static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2649{
2650 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2651 int *sIndex = (int*) data2;
2652
2653 if (pMI->screenId == *sIndex)
2654 {
2655 crServerWindowReparent(pMI);
2656 }
2657}
2658
2659DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2660{
2661 int i;
2662
2663 if (sCount>CR_MAX_GUEST_MONITORS)
2664 return VERR_INVALID_PARAMETER;
2665
2666 /*Shouldn't happen yet, but to be safe in future*/
2667 for (i=0; i<cr_server.screenCount; ++i)
2668 {
2669 if (MAPPED(SCREEN(i)))
2670 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
2671 return VERR_NOT_IMPLEMENTED;
2672 }
2673
2674 cr_server.screenCount = sCount;
2675
2676 for (i=0; i<sCount; ++i)
2677 {
2678 SCREEN(i).winID = 0;
2679 }
2680
2681 return VINF_SUCCESS;
2682}
2683
2684DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2685{
2686 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2687
2688 if (sIndex<0 || sIndex>=cr_server.screenCount)
2689 return VERR_INVALID_PARAMETER;
2690
2691 if (MAPPED(SCREEN(sIndex)))
2692 {
2693 SCREEN(sIndex).winID = 0;
2694 renderspuSetWindowId(0);
2695
2696 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2697
2698 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2699
2700 CrPMgrScreenChanged((uint32_t)sIndex);
2701 }
2702
2703 renderspuSetWindowId(SCREEN(0).winID);
2704
2705 return VINF_SUCCESS;
2706}
2707
2708DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2709{
2710 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2711
2712 if (sIndex<0 || sIndex>=cr_server.screenCount)
2713 return VERR_INVALID_PARAMETER;
2714
2715 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2716 {
2717 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2718 crVBoxServerUnmapScreen(sIndex);
2719 }
2720
2721 SCREEN(sIndex).winID = winID;
2722 SCREEN(sIndex).x = x;
2723 SCREEN(sIndex).y = y;
2724 SCREEN(sIndex).w = w;
2725 SCREEN(sIndex).h = h;
2726
2727 renderspuSetWindowId(SCREEN(sIndex).winID);
2728 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2729
2730 crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
2731 renderspuSetWindowId(SCREEN(0).winID);
2732
2733#ifndef WINDOWS
2734 /*Restore FB content for clients, which have current window on a screen being remapped*/
2735 {
2736 GLint i;
2737
2738 for (i = 0; i < cr_server.numClients; i++)
2739 {
2740 cr_server.curClient = cr_server.clients[i];
2741 if (cr_server.curClient->currentCtxInfo
2742 && cr_server.curClient->currentCtxInfo->pContext
2743 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2744 && cr_server.curClient->currentMural
2745 && cr_server.curClient->currentMural->screenId == sIndex
2746 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2747 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2748 {
2749 int clientWindow = cr_server.curClient->currentWindow;
2750 int clientContext = cr_server.curClient->currentContextNumber;
2751 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2752
2753 if (clientWindow && clientWindow != cr_server.currentWindow)
2754 {
2755 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2756 }
2757
2758 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2759 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2760 }
2761 }
2762 cr_server.curClient = NULL;
2763 }
2764#endif
2765
2766 CrPMgrScreenChanged((uint32_t)sIndex);
2767
2768 return VINF_SUCCESS;
2769}
2770
2771DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects)
2772{
2773 int32_t rc = VINF_SUCCESS;
2774 GLboolean fOldRootVrOn = cr_server.fRootVrOn;
2775
2776 /* non-zero rects pointer indicate rects are present and switched on
2777 * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions,
2778 * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */
2779 if (pRects)
2780 {
2781 crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
2782 rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL);
2783 if (!RT_SUCCESS(rc))
2784 {
2785 crWarning("VBoxVrListRectsSet failed! rc %d", rc);
2786 return rc;
2787 }
2788
2789 cr_server.fRootVrOn = GL_TRUE;
2790 }
2791 else
2792 {
2793 if (!cr_server.fRootVrOn)
2794 return VINF_SUCCESS;
2795
2796 VBoxVrListClear(&cr_server.RootVr);
2797
2798 cr_server.fRootVrOn = GL_FALSE;
2799 }
2800
2801 if (!fOldRootVrOn != !cr_server.fRootVrOn)
2802 {
2803 rc = CrPMgrModeRootVr(cr_server.fRootVrOn);
2804 if (!RT_SUCCESS(rc))
2805 {
2806 crWarning("CrPMgrModeRootVr failed rc %d", rc);
2807 return rc;
2808 }
2809 }
2810 else if (cr_server.fRootVrOn)
2811 {
2812 rc = CrPMgrRootVrUpdate();
2813 if (!RT_SUCCESS(rc))
2814 {
2815 crWarning("CrPMgrRootVrUpdate failed rc %d", rc);
2816 return rc;
2817 }
2818 }
2819
2820 return VINF_SUCCESS;
2821}
2822
2823DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2824{
2825 cr_server.pfnPresentFBO = pfnPresentFBO;
2826}
2827
2828DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2829{
2830 return CrPMgrModeVrdp(value);
2831}
2832
2833DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2834{
2835 /* No need for a synchronization as this is single threaded. */
2836 if (pCallbacks)
2837 {
2838 cr_server.outputRedirect = *pCallbacks;
2839 }
2840 else
2841 {
2842 memset (&cr_server.outputRedirect, 0, sizeof (cr_server.outputRedirect));
2843 }
2844
2845 return VINF_SUCCESS;
2846}
2847
2848DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2849{
2850 CRScreenViewportInfo *pViewport;
2851 RTRECT NewRect;
2852 int rc;
2853
2854 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2855
2856 if (sIndex<0 || sIndex>=cr_server.screenCount)
2857 {
2858 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2859 return VERR_INVALID_PARAMETER;
2860 }
2861
2862 NewRect.xLeft = x;
2863 NewRect.yTop = y;
2864 NewRect.xRight = x + w;
2865 NewRect.yBottom = y + h;
2866
2867 pViewport = &cr_server.screenVieport[sIndex];
2868 /*always do viewport updates no matter whether the rectangle actually changes,
2869 * this is needed to ensure window is adjusted properly on OSX */
2870 pViewport->Rect = NewRect;
2871 rc = CrPMgrViewportUpdate((uint32_t)sIndex);
2872 if (!RT_SUCCESS(rc))
2873 {
2874 crWarning("CrPMgrViewportUpdate failed %d", rc);
2875 return rc;
2876 }
2877
2878 return VINF_SUCCESS;
2879}
2880
2881
2882#ifdef VBOX_WITH_CRHGSMI
2883
2884static int32_t crVBoxServerCmdVbvaCrCmdProcess(struct VBOXCMDVBVA_CRCMD_CMD *pCmd)
2885{
2886 int32_t rc;
2887 uint32_t cBuffers = pCmd->cBuffers;
2888 uint32_t cParams;
2889 uint32_t cbHdr;
2890 CRVBOXHGSMIHDR *pHdr;
2891 uint32_t u32Function;
2892 uint32_t u32ClientID;
2893 CRClient *pClient;
2894
2895 if (!g_pvVRamBase)
2896 {
2897 crWarning("g_pvVRamBase is not initialized");
2898 return VERR_INVALID_STATE;
2899 }
2900
2901 if (!cBuffers)
2902 {
2903 crWarning("zero buffers passed in!");
2904 return VERR_INVALID_PARAMETER;
2905 }
2906
2907 cParams = cBuffers-1;
2908
2909 cbHdr = pCmd->aBuffers[0].cbBuffer;
2910 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2911 if (!pHdr)
2912 {
2913 crWarning("invalid header buffer!");
2914 return VERR_INVALID_PARAMETER;
2915 }
2916
2917 if (cbHdr < sizeof (*pHdr))
2918 {
2919 crWarning("invalid header buffer size!");
2920 return VERR_INVALID_PARAMETER;
2921 }
2922
2923 u32Function = pHdr->u32Function;
2924 u32ClientID = pHdr->u32ClientID;
2925
2926 switch (u32Function)
2927 {
2928 case SHCRGL_GUEST_FN_WRITE:
2929 {
2930 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2931
2932 /* @todo: Verify */
2933 if (cParams == 1)
2934 {
2935 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2936 VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
2937 /* Fetch parameters. */
2938 uint32_t cbBuffer = pBuf->cbBuffer;
2939 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2940
2941 if (cbHdr < sizeof (*pFnCmd))
2942 {
2943 crWarning("invalid write cmd buffer size!");
2944 rc = VERR_INVALID_PARAMETER;
2945 break;
2946 }
2947
2948 CRASSERT(cbBuffer);
2949 if (!pBuffer)
2950 {
2951 crWarning("invalid buffer data received from guest!");
2952 rc = VERR_INVALID_PARAMETER;
2953 break;
2954 }
2955
2956 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2957 if (RT_FAILURE(rc))
2958 {
2959 break;
2960 }
2961
2962 /* This should never fire unless we start to multithread */
2963 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2964 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2965
2966 pClient->conn->pBuffer = pBuffer;
2967 pClient->conn->cbBuffer = cbBuffer;
2968 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
2969 rc = crVBoxServerInternalClientWriteRead(pClient);
2970 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2971 return rc;
2972 }
2973 else
2974 {
2975 crWarning("invalid number of args");
2976 rc = VERR_INVALID_PARAMETER;
2977 break;
2978 }
2979 break;
2980 }
2981
2982 case SHCRGL_GUEST_FN_INJECT:
2983 {
2984 Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2985
2986 /* @todo: Verify */
2987 if (cParams == 1)
2988 {
2989 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2990 /* Fetch parameters. */
2991 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2992 VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
2993 uint32_t cbBuffer = pBuf->cbBuffer;
2994 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2995
2996 if (cbHdr < sizeof (*pFnCmd))
2997 {
2998 crWarning("invalid inject cmd buffer size!");
2999 rc = VERR_INVALID_PARAMETER;
3000 break;
3001 }
3002
3003 CRASSERT(cbBuffer);
3004 if (!pBuffer)
3005 {
3006 crWarning("invalid buffer data received from guest!");
3007 rc = VERR_INVALID_PARAMETER;
3008 break;
3009 }
3010
3011 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3012 if (RT_FAILURE(rc))
3013 {
3014 break;
3015 }
3016
3017 /* This should never fire unless we start to multithread */
3018 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3019 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3020
3021 pClient->conn->pBuffer = pBuffer;
3022 pClient->conn->cbBuffer = cbBuffer;
3023 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
3024 rc = crVBoxServerInternalClientWriteRead(pClient);
3025 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3026 return rc;
3027 }
3028
3029 crWarning("invalid number of args");
3030 rc = VERR_INVALID_PARAMETER;
3031 break;
3032 }
3033
3034 case SHCRGL_GUEST_FN_READ:
3035 {
3036 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3037
3038 /* @todo: Verify */
3039 if (cParams == 1)
3040 {
3041 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3042 VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3043 /* Fetch parameters. */
3044 uint32_t cbBuffer = pBuf->cbBuffer;
3045 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3046
3047 if (cbHdr < sizeof (*pFnCmd))
3048 {
3049 crWarning("invalid read cmd buffer size!");
3050 rc = VERR_INVALID_PARAMETER;
3051 break;
3052 }
3053
3054
3055 if (!pBuffer)
3056 {
3057 crWarning("invalid buffer data received from guest!");
3058 rc = VERR_INVALID_PARAMETER;
3059 break;
3060 }
3061
3062 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3063 if (RT_FAILURE(rc))
3064 {
3065 break;
3066 }
3067
3068 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3069
3070 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3071
3072 /* Return the required buffer size always */
3073 pFnCmd->cbBuffer = cbBuffer;
3074
3075 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3076
3077 /* the read command is never pended, complete it right away */
3078 pHdr->result = rc;
3079
3080 return VINF_SUCCESS;
3081 }
3082
3083 crWarning("invalid number of args");
3084 rc = VERR_INVALID_PARAMETER;
3085 break;
3086 }
3087
3088 case SHCRGL_GUEST_FN_WRITE_READ:
3089 {
3090 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3091
3092 /* @todo: Verify */
3093 if (cParams == 2)
3094 {
3095 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3096 VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
3097 VBOXCMDVBVA_CRCMD_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3098
3099 /* Fetch parameters. */
3100 uint32_t cbBuffer = pBuf->cbBuffer;
3101 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3102
3103 uint32_t cbWriteback = pWbBuf->cbBuffer;
3104 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3105
3106 if (cbHdr < sizeof (*pFnCmd))
3107 {
3108 crWarning("invalid write_read cmd buffer size!");
3109 rc = VERR_INVALID_PARAMETER;
3110 break;
3111 }
3112
3113
3114 CRASSERT(cbBuffer);
3115 if (!pBuffer)
3116 {
3117 crWarning("invalid write buffer data received from guest!");
3118 rc = VERR_INVALID_PARAMETER;
3119 break;
3120 }
3121
3122 CRASSERT(cbWriteback);
3123 if (!pWriteback)
3124 {
3125 crWarning("invalid writeback buffer data received from guest!");
3126 rc = VERR_INVALID_PARAMETER;
3127 break;
3128 }
3129 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3130 if (RT_FAILURE(rc))
3131 {
3132 pHdr->result = rc;
3133 return VINF_SUCCESS;
3134 }
3135
3136 /* This should never fire unless we start to multithread */
3137 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3138 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3139
3140 pClient->conn->pBuffer = pBuffer;
3141 pClient->conn->cbBuffer = cbBuffer;
3142 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, false);
3143 rc = crVBoxServerInternalClientWriteRead(pClient);
3144 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3145 return rc;
3146 }
3147
3148 crWarning("invalid number of args");
3149 rc = VERR_INVALID_PARAMETER;
3150 break;
3151 }
3152
3153 case SHCRGL_GUEST_FN_SET_VERSION:
3154 {
3155 crWarning("invalid function");
3156 rc = VERR_NOT_IMPLEMENTED;
3157 break;
3158 }
3159
3160 case SHCRGL_GUEST_FN_SET_PID:
3161 {
3162 crWarning("invalid function");
3163 rc = VERR_NOT_IMPLEMENTED;
3164 break;
3165 }
3166
3167 default:
3168 {
3169 crWarning("invalid function");
3170 rc = VERR_NOT_IMPLEMENTED;
3171 break;
3172 }
3173
3174 }
3175
3176 /* we can be on fail only here */
3177 CRASSERT(RT_FAILURE(rc));
3178 pHdr->result = rc;
3179
3180 return rc;
3181}
3182
3183static int32_t crVBoxServerCrCmdProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd)
3184{
3185 switch (pCmd->u8OpCode)
3186 {
3187 case VBOXCMDVBVA_OPTYPE_CRCMD:
3188 {
3189 VBOXCMDVBVA_CRCMD *pCrCmdDr = (VBOXCMDVBVA_CRCMD*)pCmd;
3190 VBOXCMDVBVA_CRCMD_CMD *pCrCmd = &pCrCmdDr->Cmd;
3191 int rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd);
3192 if (RT_SUCCESS(rc))
3193 {
3194 /* success */
3195 pCmd->i8Result = 0;
3196 }
3197 else
3198 {
3199 crWarning("crVBoxServerCmdVbvaCrCmdProcess failed, rc %d", rc);
3200 pCmd->i8Result = -1;
3201 }
3202 break;
3203 }
3204 case VBOXCMDVBVA_OPTYPE_BLT_OFFPRIMSZFMT_OR_ID:
3205 {
3206 crVBoxServerCrCmdBltProcess(pCmd, cbCmd);
3207 break;
3208 }
3209 default:
3210 WARN(("unsupported command"));
3211 pCmd->i8Result = -1;
3212 }
3213 return VINF_SUCCESS;
3214}
3215
3216int32_t crVBoxServerCrCmdNotifyCmds()
3217{
3218 PVBOXCMDVBVA_HDR pCmd = NULL;
3219 uint32_t cbCmd;
3220
3221 for (;;)
3222 {
3223 int rc = cr_server.CltInfo.pfnCmdGet(cr_server.CltInfo.hClient, &pCmd, &cbCmd);
3224 if (rc == VINF_EOF)
3225 return VINF_SUCCESS;
3226 if (!RT_SUCCESS(rc))
3227 return rc;
3228
3229 rc = crVBoxServerCrCmdProcess(pCmd, cbCmd);
3230 if (!RT_SUCCESS(rc))
3231 return rc;
3232 }
3233
3234 /* should not be here! */
3235 AssertFailed();
3236 return VERR_INTERNAL_ERROR;
3237}
3238
3239/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
3240 *
3241 * 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.
3242 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
3243 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
3244 * to block the lower-priority thread trying to complete the blocking command.
3245 * And removed extra memcpy done on blocked command arrival.
3246 *
3247 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
3248 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
3249 *
3250 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
3251 * */
3252
3253
3254int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
3255{
3256
3257 int32_t rc;
3258 uint32_t cBuffers = pCmd->cBuffers;
3259 uint32_t cParams;
3260 uint32_t cbHdr;
3261 CRVBOXHGSMIHDR *pHdr;
3262 uint32_t u32Function;
3263 uint32_t u32ClientID;
3264 CRClient *pClient;
3265
3266 if (!g_pvVRamBase)
3267 {
3268 crWarning("g_pvVRamBase is not initialized");
3269
3270 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
3271 return VINF_SUCCESS;
3272 }
3273
3274 if (!cBuffers)
3275 {
3276 crWarning("zero buffers passed in!");
3277
3278 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3279 return VINF_SUCCESS;
3280 }
3281
3282 cParams = cBuffers-1;
3283
3284 cbHdr = pCmd->aBuffers[0].cbBuffer;
3285 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
3286 if (!pHdr)
3287 {
3288 crWarning("invalid header buffer!");
3289
3290 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3291 return VINF_SUCCESS;
3292 }
3293
3294 if (cbHdr < sizeof (*pHdr))
3295 {
3296 crWarning("invalid header buffer size!");
3297
3298 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
3299 return VINF_SUCCESS;
3300 }
3301
3302 u32Function = pHdr->u32Function;
3303 u32ClientID = pHdr->u32ClientID;
3304
3305 switch (u32Function)
3306 {
3307 case SHCRGL_GUEST_FN_WRITE:
3308 {
3309 Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
3310
3311 /* @todo: Verify */
3312 if (cParams == 1)
3313 {
3314 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
3315 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3316 /* Fetch parameters. */
3317 uint32_t cbBuffer = pBuf->cbBuffer;
3318 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3319
3320 if (cbHdr < sizeof (*pFnCmd))
3321 {
3322 crWarning("invalid write cmd buffer size!");
3323 rc = VERR_INVALID_PARAMETER;
3324 break;
3325 }
3326
3327 CRASSERT(cbBuffer);
3328 if (!pBuffer)
3329 {
3330 crWarning("invalid buffer data received from guest!");
3331 rc = VERR_INVALID_PARAMETER;
3332 break;
3333 }
3334
3335 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3336 if (RT_FAILURE(rc))
3337 {
3338 break;
3339 }
3340
3341 /* This should never fire unless we start to multithread */
3342 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3343 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3344
3345 pClient->conn->pBuffer = pBuffer;
3346 pClient->conn->cbBuffer = cbBuffer;
3347 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3348 rc = crVBoxServerInternalClientWriteRead(pClient);
3349 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3350 return rc;
3351 }
3352 else
3353 {
3354 crWarning("invalid number of args");
3355 rc = VERR_INVALID_PARAMETER;
3356 break;
3357 }
3358 break;
3359 }
3360
3361 case SHCRGL_GUEST_FN_INJECT:
3362 {
3363 Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
3364
3365 /* @todo: Verify */
3366 if (cParams == 1)
3367 {
3368 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
3369 /* Fetch parameters. */
3370 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
3371 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3372 uint32_t cbBuffer = pBuf->cbBuffer;
3373 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3374
3375 if (cbHdr < sizeof (*pFnCmd))
3376 {
3377 crWarning("invalid inject cmd buffer size!");
3378 rc = VERR_INVALID_PARAMETER;
3379 break;
3380 }
3381
3382 CRASSERT(cbBuffer);
3383 if (!pBuffer)
3384 {
3385 crWarning("invalid buffer data received from guest!");
3386 rc = VERR_INVALID_PARAMETER;
3387 break;
3388 }
3389
3390 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
3391 if (RT_FAILURE(rc))
3392 {
3393 break;
3394 }
3395
3396 /* This should never fire unless we start to multithread */
3397 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3398 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3399
3400 pClient->conn->pBuffer = pBuffer;
3401 pClient->conn->cbBuffer = cbBuffer;
3402 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
3403 rc = crVBoxServerInternalClientWriteRead(pClient);
3404 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3405 return rc;
3406 }
3407
3408 crWarning("invalid number of args");
3409 rc = VERR_INVALID_PARAMETER;
3410 break;
3411 }
3412
3413 case SHCRGL_GUEST_FN_READ:
3414 {
3415 Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
3416
3417 /* @todo: Verify */
3418 if (cParams == 1)
3419 {
3420 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
3421 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3422 /* Fetch parameters. */
3423 uint32_t cbBuffer = pBuf->cbBuffer;
3424 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3425
3426 if (cbHdr < sizeof (*pFnCmd))
3427 {
3428 crWarning("invalid read cmd buffer size!");
3429 rc = VERR_INVALID_PARAMETER;
3430 break;
3431 }
3432
3433
3434 if (!pBuffer)
3435 {
3436 crWarning("invalid buffer data received from guest!");
3437 rc = VERR_INVALID_PARAMETER;
3438 break;
3439 }
3440
3441 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3442 if (RT_FAILURE(rc))
3443 {
3444 break;
3445 }
3446
3447 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3448
3449 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
3450
3451 /* Return the required buffer size always */
3452 pFnCmd->cbBuffer = cbBuffer;
3453
3454 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3455
3456 /* the read command is never pended, complete it right away */
3457 pHdr->result = rc;
3458
3459 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3460 return VINF_SUCCESS;
3461 }
3462
3463 crWarning("invalid number of args");
3464 rc = VERR_INVALID_PARAMETER;
3465 break;
3466 }
3467
3468 case SHCRGL_GUEST_FN_WRITE_READ:
3469 {
3470 Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
3471
3472 /* @todo: Verify */
3473 if (cParams == 2)
3474 {
3475 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
3476 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
3477 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
3478
3479 /* Fetch parameters. */
3480 uint32_t cbBuffer = pBuf->cbBuffer;
3481 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
3482
3483 uint32_t cbWriteback = pWbBuf->cbBuffer;
3484 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
3485
3486 if (cbHdr < sizeof (*pFnCmd))
3487 {
3488 crWarning("invalid write_read cmd buffer size!");
3489 rc = VERR_INVALID_PARAMETER;
3490 break;
3491 }
3492
3493
3494 CRASSERT(cbBuffer);
3495 if (!pBuffer)
3496 {
3497 crWarning("invalid write buffer data received from guest!");
3498 rc = VERR_INVALID_PARAMETER;
3499 break;
3500 }
3501
3502 CRASSERT(cbWriteback);
3503 if (!pWriteback)
3504 {
3505 crWarning("invalid writeback buffer data received from guest!");
3506 rc = VERR_INVALID_PARAMETER;
3507 break;
3508 }
3509 rc = crVBoxServerClientGet(u32ClientID, &pClient);
3510 if (RT_FAILURE(rc))
3511 {
3512 pHdr->result = rc;
3513 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3514 return rc;
3515 }
3516
3517 /* This should never fire unless we start to multithread */
3518 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
3519 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3520
3521 pClient->conn->pBuffer = pBuffer;
3522 pClient->conn->cbBuffer = cbBuffer;
3523 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, true);
3524 rc = crVBoxServerInternalClientWriteRead(pClient);
3525 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
3526 return rc;
3527 }
3528
3529 crWarning("invalid number of args");
3530 rc = VERR_INVALID_PARAMETER;
3531 break;
3532 }
3533
3534 case SHCRGL_GUEST_FN_SET_VERSION:
3535 {
3536 crWarning("invalid function");
3537 rc = VERR_NOT_IMPLEMENTED;
3538 break;
3539 }
3540
3541 case SHCRGL_GUEST_FN_SET_PID:
3542 {
3543 crWarning("invalid function");
3544 rc = VERR_NOT_IMPLEMENTED;
3545 break;
3546 }
3547
3548 default:
3549 {
3550 crWarning("invalid function");
3551 rc = VERR_NOT_IMPLEMENTED;
3552 break;
3553 }
3554
3555 }
3556
3557 /* we can be on fail only here */
3558 CRASSERT(RT_FAILURE(rc));
3559 pHdr->result = rc;
3560
3561 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
3562 return rc;
3563
3564}
3565
3566static DECLCALLBACK(bool) crVBoxServerHasData()
3567{
3568 HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
3569 for (;
3570 hFb;
3571 hFb = CrPMgrFbGetNextEnabled(hFb))
3572 {
3573 if (CrFbHas3DData(hFb))
3574 return true;
3575 }
3576
3577 return false;
3578}
3579
3580int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
3581{
3582 int rc = VINF_SUCCESS;
3583
3584 switch (pCtl->enmType)
3585 {
3586 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
3587 {
3588 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
3589 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
3590 g_cbVRam = pSetup->cbVRam;
3591 cr_server.CltInfo = *pSetup->pCrCmdClientInfo;
3592 rc = VINF_SUCCESS;
3593 break;
3594 }
3595 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
3596 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
3597 rc = VINF_SUCCESS;
3598 break;
3599 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB:
3600 {
3601 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB)pCtl;
3602 g_hCrHgsmiCompletion = pSetup->hCompletion;
3603 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
3604
3605 pSetup->MainInterface.pfnHasData = crVBoxServerHasData;
3606
3607 rc = VINF_SUCCESS;
3608 break;
3609 }
3610 default:
3611 AssertMsgFailed(("invalid param %d", pCtl->enmType));
3612 rc = VERR_INVALID_PARAMETER;
3613 }
3614
3615 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
3616 * to complete them accordingly.
3617 * This approach allows using host->host and host->guest commands in the same way here
3618 * making the command completion to be the responsibility of the command originator.
3619 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
3620 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
3621 return rc;
3622}
3623
3624#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