VirtualBox

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

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

crOpenGL: new command submission continued

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

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