VirtualBox

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

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

crOpenGL: more new command submission fixes

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

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