VirtualBox

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

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

crOpenGL: do not create invisible windows (fix OSX deadlock)

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

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