VirtualBox

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

Last change on this file since 44444 was 44392, checked in by vboxsync, 12 years ago

crOpenGL: typo burn fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 78.6 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_environment.h"
16#include "cr_pixeldata.h"
17#include "server_dispatch.h"
18#include "state/cr_texture.h"
19#include "render/renderspu.h"
20#include <signal.h>
21#include <stdlib.h>
22#define DEBUG_FP_EXCEPTIONS 0
23#if DEBUG_FP_EXCEPTIONS
24#include <fpu_control.h>
25#include <math.h>
26#endif
27#include <iprt/assert.h>
28#include <VBox/err.h>
29
30#ifdef VBOXCR_LOGFPS
31#include <iprt/timer.h>
32#endif
33
34#ifdef VBOX_WITH_CRHGSMI
35# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
36uint8_t* g_pvVRamBase = NULL;
37uint32_t g_cbVRam = 0;
38HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion = NULL;
39PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion = NULL;
40#endif
41
42/**
43 * \mainpage CrServerLib
44 *
45 * \section CrServerLibIntroduction Introduction
46 *
47 * Chromium consists of all the top-level files in the cr
48 * directory. The core module basically takes care of API dispatch,
49 * and OpenGL state management.
50 */
51
52
53/**
54 * CRServer global data
55 */
56CRServer cr_server;
57
58int tearingdown = 0; /* can't be static */
59
60DECLINLINE(int32_t) crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
61{
62 CRClient *pClient = NULL;
63 int32_t i;
64
65 *ppClient = NULL;
66
67 for (i = 0; i < cr_server.numClients; i++)
68 {
69 if (cr_server.clients[i] && cr_server.clients[i]->conn
70 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
71 {
72 pClient = cr_server.clients[i];
73 break;
74 }
75 }
76 if (!pClient)
77 {
78 crWarning("client not found!");
79 return VERR_INVALID_PARAMETER;
80 }
81
82 if (!pClient->conn->vMajor)
83 {
84 crWarning("no major version specified for client!");
85 return VERR_NOT_SUPPORTED;
86 }
87
88 *ppClient = pClient;
89
90 return VINF_SUCCESS;
91}
92
93
94/**
95 * Return pointer to server's first SPU.
96 */
97SPU*
98crServerHeadSPU(void)
99{
100 return cr_server.head_spu;
101}
102
103
104
105static void DeleteBarrierCallback( void *data )
106{
107 CRServerBarrier *barrier = (CRServerBarrier *) data;
108 crFree(barrier->waiting);
109 crFree(barrier);
110}
111
112
113static void deleteContextInfoCallback( void *data )
114{
115 CRContextInfo *c = (CRContextInfo *) data;
116 crStateDestroyContext(c->pContext);
117 if (c->CreateInfo.pszDpyName)
118 crFree(c->CreateInfo.pszDpyName);
119 crFree(c);
120}
121
122static void deleteMuralInfoCallback( void *data )
123{
124 CRMuralInfo *m = (CRMuralInfo *) data;
125 if (m->spuWindow) /* <- do not do term for default mural as it does not contain any info to be freed,
126 * and renderspu will destroy it up itself*/
127 {
128 crServerMuralTerm(m);
129 }
130 crFree(m);
131}
132
133static void crServerTearDown( void )
134{
135 GLint i;
136 CRClientNode *pNode, *pNext;
137
138 /* avoid a race condition */
139 if (tearingdown)
140 return;
141
142 tearingdown = 1;
143
144 crStateSetCurrent( NULL );
145
146 cr_server.curClient = NULL;
147 cr_server.run_queue = NULL;
148
149 crFree( cr_server.overlap_intens );
150 cr_server.overlap_intens = NULL;
151
152 /* Deallocate all semaphores */
153 crFreeHashtable(cr_server.semaphores, crFree);
154 cr_server.semaphores = NULL;
155
156 /* Deallocate all barriers */
157 crFreeHashtable(cr_server.barriers, DeleteBarrierCallback);
158 cr_server.barriers = NULL;
159
160 /* Free all context info */
161 crFreeHashtable(cr_server.contextTable, deleteContextInfoCallback);
162
163 /* Free vertex programs */
164 crFreeHashtable(cr_server.programTable, crFree);
165
166 /* Free dummy murals */
167 crFreeHashtable(cr_server.dummyMuralTable, deleteMuralInfoCallback);
168
169 /* Free murals */
170 crFreeHashtable(cr_server.muralTable, deleteMuralInfoCallback);
171
172 for (i = 0; i < cr_server.numClients; i++) {
173 if (cr_server.clients[i]) {
174 CRConnection *conn = cr_server.clients[i]->conn;
175 crNetFreeConnection(conn);
176 crFree(cr_server.clients[i]);
177 }
178 }
179 cr_server.numClients = 0;
180
181 pNode = cr_server.pCleanupClient;
182 while (pNode)
183 {
184 pNext=pNode->next;
185 crFree(pNode->pClient);
186 crFree(pNode);
187 pNode=pNext;
188 }
189 cr_server.pCleanupClient = NULL;
190
191#if 1
192 /* disable these two lines if trying to get stack traces with valgrind */
193 crSPUUnloadChain(cr_server.head_spu);
194 cr_server.head_spu = NULL;
195#endif
196
197 crStateDestroy();
198
199 crNetTearDown();
200}
201
202static void crServerClose( unsigned int id )
203{
204 crError( "Client disconnected!" );
205 (void) id;
206}
207
208static void crServerCleanup( int sigio )
209{
210 crServerTearDown();
211
212 tearingdown = 0;
213}
214
215
216void
217crServerSetPort(int port)
218{
219 cr_server.tcpip_port = port;
220}
221
222
223
224static void
225crPrintHelp(void)
226{
227 printf("Usage: crserver [OPTIONS]\n");
228 printf("Options:\n");
229 printf(" -mothership URL Specifies URL for contacting the mothership.\n");
230 printf(" URL is of the form [protocol://]hostname[:port]\n");
231 printf(" -port N Specifies the port number this server will listen to.\n");
232 printf(" -help Prints this information.\n");
233}
234
235
236/**
237 * Do CRServer initializations. After this, we can begin servicing clients.
238 */
239void
240crServerInit(int argc, char *argv[])
241{
242 int i;
243 char *mothership = NULL;
244 CRMuralInfo *defaultMural;
245
246 for (i = 1 ; i < argc ; i++)
247 {
248 if (!crStrcmp( argv[i], "-mothership" ))
249 {
250 if (i == argc - 1)
251 {
252 crError( "-mothership requires an argument" );
253 }
254 mothership = argv[i+1];
255 i++;
256 }
257 else if (!crStrcmp( argv[i], "-port" ))
258 {
259 /* This is the port on which we'll accept client connections */
260 if (i == argc - 1)
261 {
262 crError( "-port requires an argument" );
263 }
264 cr_server.tcpip_port = crStrToInt(argv[i+1]);
265 i++;
266 }
267 else if (!crStrcmp( argv[i], "-vncmode" ))
268 {
269 cr_server.vncMode = 1;
270 }
271 else if (!crStrcmp( argv[i], "-help" ))
272 {
273 crPrintHelp();
274 exit(0);
275 }
276 }
277
278 signal( SIGTERM, crServerCleanup );
279 signal( SIGINT, crServerCleanup );
280#ifndef WINDOWS
281 signal( SIGPIPE, SIG_IGN );
282#endif
283
284#if DEBUG_FP_EXCEPTIONS
285 {
286 fpu_control_t mask;
287 _FPU_GETCW(mask);
288 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
289 | _FPU_MASK_OM | _FPU_MASK_UM);
290 _FPU_SETCW(mask);
291 }
292#endif
293
294 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
295
296 if (cr_server.bUseMultipleContexts)
297 {
298 crInfo("Info: using multiple contexts!");
299 crDebug("Debug: using multiple contexts!");
300 }
301
302 cr_server.firstCallCreateContext = GL_TRUE;
303 cr_server.firstCallMakeCurrent = GL_TRUE;
304 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
305
306 /*
307 * Create default mural info and hash table.
308 */
309 cr_server.muralTable = crAllocHashtable();
310 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
311 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
312
313 cr_server.programTable = crAllocHashtable();
314
315 crNetInit(crServerRecv, crServerClose);
316 crStateInit();
317
318 crServerSetVBoxConfiguration();
319
320 crStateLimitsInit( &(cr_server.limits) );
321
322 /*
323 * Default context
324 */
325 cr_server.contextTable = crAllocHashtable();
326 cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
327
328 cr_server.dummyMuralTable = crAllocHashtable();
329
330 crServerInitDispatch();
331 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
332
333 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
334 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
335
336 cr_server.barriers = crAllocHashtable();
337 cr_server.semaphores = crAllocHashtable();
338}
339
340void crVBoxServerTearDown(void)
341{
342 crServerTearDown();
343}
344
345/**
346 * Do CRServer initializations. After this, we can begin servicing clients.
347 */
348GLboolean crVBoxServerInit(void)
349{
350 CRMuralInfo *defaultMural;
351
352#if DEBUG_FP_EXCEPTIONS
353 {
354 fpu_control_t mask;
355 _FPU_GETCW(mask);
356 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
357 | _FPU_MASK_OM | _FPU_MASK_UM);
358 _FPU_SETCW(mask);
359 }
360#endif
361
362 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
363
364 if (cr_server.bUseMultipleContexts)
365 {
366 crInfo("Info: using multiple contexts!");
367 crDebug("Debug: using multiple contexts!");
368 }
369
370 crNetInit(crServerRecv, crServerClose);
371
372 cr_server.firstCallCreateContext = GL_TRUE;
373 cr_server.firstCallMakeCurrent = GL_TRUE;
374
375 cr_server.bIsInLoadingState = GL_FALSE;
376 cr_server.bIsInSavingState = GL_FALSE;
377 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
378
379 cr_server.pCleanupClient = NULL;
380
381 /*
382 * Create default mural info and hash table.
383 */
384 cr_server.muralTable = crAllocHashtable();
385 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
386 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
387
388 cr_server.programTable = crAllocHashtable();
389
390 crStateInit();
391
392 crStateLimitsInit( &(cr_server.limits) );
393
394 cr_server.barriers = crAllocHashtable();
395 cr_server.semaphores = crAllocHashtable();
396
397 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
398 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
399
400 /*
401 * Default context
402 */
403 cr_server.contextTable = crAllocHashtable();
404
405 cr_server.dummyMuralTable = crAllocHashtable();
406
407 crServerSetVBoxConfigurationHGCM();
408
409 if (!cr_server.head_spu)
410 return GL_FALSE;
411
412 crServerInitDispatch();
413 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
414
415 /*Check for PBO support*/
416 if (crStateGetCurrent()->extensions.ARB_pixel_buffer_object)
417 {
418 cr_server.bUsePBOForReadback=GL_TRUE;
419 }
420
421 return GL_TRUE;
422}
423
424int32_t crVBoxServerAddClient(uint32_t u32ClientID)
425{
426 CRClient *newClient;
427
428 if (cr_server.numClients>=CR_MAX_CLIENTS)
429 {
430 return VERR_MAX_THRDS_REACHED;
431 }
432
433 newClient = (CRClient *) crCalloc(sizeof(CRClient));
434 crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
435
436 newClient->spu_id = 0;
437 newClient->currentCtxInfo = &cr_server.MainContextInfo;
438 newClient->currentContextNumber = -1;
439 newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
440 cr_server.tcpip_port,
441 cr_server.mtu, 0);
442 newClient->conn->u32ClientID = u32ClientID;
443
444 cr_server.clients[cr_server.numClients++] = newClient;
445
446 crServerAddToRunQueue(newClient);
447
448 return VINF_SUCCESS;
449}
450
451void crVBoxServerRemoveClient(uint32_t u32ClientID)
452{
453 CRClient *pClient=NULL;
454 int32_t i;
455
456 crDebug("crServer: RemoveClient u32ClientID=%d", u32ClientID);
457
458 for (i = 0; i < cr_server.numClients; i++)
459 {
460 if (cr_server.clients[i] && cr_server.clients[i]->conn
461 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
462 {
463 pClient = cr_server.clients[i];
464 break;
465 }
466 }
467 //if (!pClient) return VERR_INVALID_PARAMETER;
468 if (!pClient)
469 {
470 crWarning("Invalid client id %u passed to crVBoxServerRemoveClient", u32ClientID);
471 return;
472 }
473
474#ifdef VBOX_WITH_CRHGSMI
475 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
476#endif
477
478 /* Disconnect the client */
479 pClient->conn->Disconnect(pClient->conn);
480
481 /* Let server clear client from the queue */
482 crServerDeleteClient(pClient);
483}
484
485static int32_t crVBoxServerInternalClientWriteRead(CRClient *pClient)
486{
487#ifdef VBOXCR_LOGFPS
488 uint64_t tstart, tend;
489#endif
490
491 /*crDebug("=>crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
492
493
494#ifdef VBOXCR_LOGFPS
495 tstart = RTTimeNanoTS();
496#endif
497
498 /* This should be setup already */
499 CRASSERT(pClient->conn->pBuffer);
500 CRASSERT(pClient->conn->cbBuffer);
501#ifdef VBOX_WITH_CRHGSMI
502 CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&pClient->conn->CmdData);
503#endif
504
505 if (
506#ifdef VBOX_WITH_CRHGSMI
507 !CRVBOXHGSMI_CMDDATA_IS_SET(&pClient->conn->CmdData) &&
508#endif
509 cr_server.run_queue->client != pClient
510 && crServerClientInBeginEnd(cr_server.run_queue->client))
511 {
512 crDebug("crServer: client %d blocked, allow_redir_ptr = 0", pClient->conn->u32ClientID);
513 pClient->conn->allow_redir_ptr = 0;
514 }
515 else
516 {
517 pClient->conn->allow_redir_ptr = 1;
518 }
519
520 crNetRecv();
521 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
522 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
523
524 crServerServiceClients();
525
526#if 0
527 if (pClient->currentMural) {
528 crStateViewport( 0, 0, 500, 500 );
529 pClient->currentMural->viewportValidated = GL_FALSE;
530 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 500, 500 );
531 crStateViewport( 0, 0, 600, 600 );
532 pClient->currentMural->viewportValidated = GL_FALSE;
533 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
534
535 crStateMatrixMode(GL_PROJECTION);
536 cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
537 crServerDispatchLoadIdentity();
538 crStateFrustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
539 cr_server.head_spu->dispatch_table.Frustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
540 crServerDispatchLoadIdentity();
541 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
542 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
543
544 crStateMatrixMode(GL_MODELVIEW);
545 cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
546 crServerDispatchLoadIdentity();
547 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
548 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
549 crServerDispatchLoadIdentity();
550 }
551#endif
552
553 crStateResetCurrentPointers(&cr_server.current);
554
555#ifndef VBOX_WITH_CRHGSMI
556 CRASSERT(!pClient->conn->allow_redir_ptr || crNetNumMessages(pClient->conn)==0);
557#endif
558
559#ifdef VBOXCR_LOGFPS
560 tend = RTTimeNanoTS();
561 pClient->timeUsed += tend-tstart;
562#endif
563 /*crDebug("<=crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
564
565 return VINF_SUCCESS;
566}
567
568
569int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer)
570{
571 CRClient *pClient=NULL;
572 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
573
574 if (RT_FAILURE(rc))
575 return rc;
576
577
578 CRASSERT(pBuffer);
579
580 /* This should never fire unless we start to multithread */
581 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
582
583 pClient->conn->pBuffer = pBuffer;
584 pClient->conn->cbBuffer = cbBuffer;
585#ifdef VBOX_WITH_CRHGSMI
586 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
587#endif
588
589 return crVBoxServerInternalClientWriteRead(pClient);
590}
591
592int32_t crVBoxServerInternalClientRead(CRClient *pClient, uint8_t *pBuffer, uint32_t *pcbBuffer)
593{
594 if (pClient->conn->cbHostBuffer > *pcbBuffer)
595 {
596 crDebug("crServer: [%lx] ClientRead u32ClientID=%d FAIL, host buffer too small %d of %d",
597 crThreadID(), pClient->conn->u32ClientID, *pcbBuffer, pClient->conn->cbHostBuffer);
598
599 /* Return the size of needed buffer */
600 *pcbBuffer = pClient->conn->cbHostBuffer;
601
602 return VERR_BUFFER_OVERFLOW;
603 }
604
605 *pcbBuffer = pClient->conn->cbHostBuffer;
606
607 if (*pcbBuffer)
608 {
609 CRASSERT(pClient->conn->pHostBuffer);
610
611 crMemcpy(pBuffer, pClient->conn->pHostBuffer, *pcbBuffer);
612 pClient->conn->cbHostBuffer = 0;
613 }
614
615 return VINF_SUCCESS;
616}
617
618int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t *pcbBuffer)
619{
620 CRClient *pClient=NULL;
621 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
622
623 if (RT_FAILURE(rc))
624 return rc;
625
626#ifdef VBOX_WITH_CRHGSMI
627 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
628#endif
629
630 return crVBoxServerInternalClientRead(pClient, pBuffer, pcbBuffer);
631}
632
633int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor)
634{
635 CRClient *pClient=NULL;
636 int32_t i;
637
638 for (i = 0; i < cr_server.numClients; i++)
639 {
640 if (cr_server.clients[i] && cr_server.clients[i]->conn
641 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
642 {
643 pClient = cr_server.clients[i];
644 break;
645 }
646 }
647 if (!pClient) return VERR_INVALID_PARAMETER;
648
649 pClient->conn->vMajor = vMajor;
650 pClient->conn->vMinor = vMinor;
651
652 if (vMajor != CR_PROTOCOL_VERSION_MAJOR
653 || vMinor != CR_PROTOCOL_VERSION_MINOR)
654 {
655 return VERR_NOT_SUPPORTED;
656 }
657 else return VINF_SUCCESS;
658}
659
660int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid)
661{
662 CRClient *pClient=NULL;
663 int32_t i;
664
665 for (i = 0; i < cr_server.numClients; i++)
666 {
667 if (cr_server.clients[i] && cr_server.clients[i]->conn
668 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
669 {
670 pClient = cr_server.clients[i];
671 break;
672 }
673 }
674 if (!pClient) return VERR_INVALID_PARAMETER;
675
676 pClient->pid = pid;
677
678 return VINF_SUCCESS;
679}
680
681int
682CRServerMain(int argc, char *argv[])
683{
684 crServerInit(argc, argv);
685
686 crServerSerializeRemoteStreams();
687
688 crServerTearDown();
689
690 tearingdown = 0;
691
692 return 0;
693}
694
695static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2)
696{
697 CRMuralInfo *pMI = (CRMuralInfo*) data1;
698 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
699 int32_t rc;
700
701 CRASSERT(pMI && pSSM);
702
703 /* Don't store default mural */
704 if (!key) return;
705
706 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
707 CRASSERT(rc == VINF_SUCCESS);
708
709 rc = SSMR3PutMem(pSSM, pMI, RT_OFFSETOF(CRMuralInfo, CreateInfo));
710 CRASSERT(rc == VINF_SUCCESS);
711
712 if (pMI->pVisibleRects)
713 {
714 rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects);
715 }
716
717 rc = SSMR3PutMem(pSSM, pMI->ctxUsage, sizeof (pMI->ctxUsage));
718 CRASSERT(rc == VINF_SUCCESS);
719}
720
721/* @todo add hashtable walker with result info and intermediate abort */
722static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *data2)
723{
724 CRCreateInfo_t *pCreateInfo = (CRCreateInfo_t *)data1;
725 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
726 int32_t rc;
727
728 CRASSERT(pCreateInfo && pSSM);
729
730 /* Don't store default mural create info */
731 if (!key) return;
732
733 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
734 CRASSERT(rc == VINF_SUCCESS);
735
736 rc = SSMR3PutMem(pSSM, pCreateInfo, sizeof(*pCreateInfo));
737 CRASSERT(rc == VINF_SUCCESS);
738
739 if (pCreateInfo->pszDpyName)
740 {
741 rc = SSMR3PutStrZ(pSSM, pCreateInfo->pszDpyName);
742 CRASSERT(rc == VINF_SUCCESS);
743 }
744}
745
746static void crVBoxServerSaveCreateInfoFromMuralInfoCB(unsigned long key, void *data1, void *data2)
747{
748 CRMuralInfo *pMural = (CRMuralInfo *)data1;
749 CRCreateInfo_t *pCreateInfo = &pMural->CreateInfo;
750 crVBoxServerSaveCreateInfoCB(key, pCreateInfo, data2);
751}
752
753static void crVBoxServerSaveCreateInfoFromCtxInfoCB(unsigned long key, void *data1, void *data2)
754{
755 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
756 CRCreateInfo_t CreateInfo = pContextInfo->CreateInfo;
757 /* saved state contains internal id */
758 CreateInfo.externalID = pContextInfo->pContext->id;
759 crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
760}
761
762static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data2)
763{
764 CRTextureObj *pTexture = (CRTextureObj *) data1;
765 CRContext *pContext = (CRContext *) data2;
766
767 CRASSERT(pTexture && pContext);
768 crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
769}
770
771typedef struct CRVBOX_SAVE_STATE_GLOBAL
772{
773 /* context id -> mural association
774 * on context data save, each context will be made current with the corresponding mural from this table
775 * thus saving the mural front & back buffer data */
776 CRHashTable *contextMuralTable;
777 /* mural id -> context info
778 * for murals that do not have associated context in contextMuralTable
779 * we still need to save*/
780 CRHashTable *additionalMuralContextTable;
781
782 PSSMHANDLE pSSM;
783
784 int rc;
785} CRVBOX_SAVE_STATE_GLOBAL, *PCRVBOX_SAVE_STATE_GLOBAL;
786
787
788typedef struct CRVBOX_CTXWND_CTXWALKER_CB
789{
790 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
791 CRHashTable *usedMuralTable;
792 GLuint cAdditionalMurals;
793} CRVBOX_CTXWND_CTXWALKER_CB, *PCRVBOX_CTXWND_CTXWALKER_CB;
794
795static void crVBoxServerBuildAdditionalWindowContextMapCB(unsigned long key, void *data1, void *data2)
796{
797 CRMuralInfo * pMural = (CRMuralInfo *) data1;
798 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
799 CRContextInfo *pContextInfo = NULL;
800
801 if (!pMural->CreateInfo.externalID)
802 return;
803
804 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
805 {
806 Assert(crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
807 return;
808 }
809
810 Assert(!crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
811
812 if (cr_server.MainContextInfo.CreateInfo.visualBits == pMural->CreateInfo.visualBits)
813 {
814 pContextInfo = &cr_server.MainContextInfo;
815 }
816 else
817 {
818 crWarning("different visual bits not implemented!");
819 pContextInfo = &cr_server.MainContextInfo;
820 }
821
822 crHashtableAdd(pData->pGlobal->additionalMuralContextTable, pMural->CreateInfo.externalID, pContextInfo);
823}
824
825
826typedef struct CRVBOX_CTXWND_WNDWALKER_CB
827{
828 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
829 CRHashTable *usedMuralTable;
830 CRContextInfo *pContextInfo;
831 CRMuralInfo * pMural;
832} CRVBOX_CTXWND_WNDWALKER_CB, *PCRVBOX_CTXWND_WNDWALKER_CB;
833
834static void crVBoxServerBuildContextWindowMapWindowWalkerCB(unsigned long key, void *data1, void *data2)
835{
836 CRMuralInfo * pMural = (CRMuralInfo *) data1;
837 PCRVBOX_CTXWND_WNDWALKER_CB pData = (PCRVBOX_CTXWND_WNDWALKER_CB)data2;
838
839 Assert(pData->pMural != pMural);
840 Assert(pData->pContextInfo);
841
842 if (pData->pMural)
843 return;
844
845 if (!pMural->CreateInfo.externalID)
846 return;
847
848 if (!CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pData->pContextInfo->pContext))
849 return;
850
851 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
852 return;
853
854 CRASSERT(pMural->CreateInfo.visualBits == pData->pContextInfo->CreateInfo.visualBits);
855 pData->pMural = pMural;
856}
857
858static void crVBoxServerBuildContextUsedWindowMapCB(unsigned long key, void *data1, void *data2)
859{
860 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
861 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
862
863 if (!pContextInfo->currentMural)
864 return;
865
866 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pContextInfo->currentMural);
867 crHashtableAdd(pData->usedMuralTable, pContextInfo->currentMural->CreateInfo.externalID, pContextInfo->currentMural);
868}
869
870CRMuralInfo * crServerGetDummyMural(GLint visualBits)
871{
872 CRMuralInfo * pMural = (CRMuralInfo *)crHashtableSearch(cr_server.dummyMuralTable, visualBits);
873 if (!pMural)
874 {
875 GLint id;
876 pMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
877 if (!pMural)
878 {
879 crWarning("crCalloc failed!");
880 return NULL;
881 }
882 id = crServerMuralInit(pMural, "", visualBits, -1);
883 if (id < 0)
884 {
885 crWarning("crServerMuralInit failed!");
886 crFree(pMural);
887 return NULL;
888 }
889
890 crHashtableAdd(cr_server.dummyMuralTable, visualBits, pMural);
891 }
892
893 return pMural;
894}
895
896static void crVBoxServerBuildContextUnusedWindowMapCB(unsigned long key, void *data1, void *data2)
897{
898 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
899 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
900 CRMuralInfo * pMural = NULL;
901
902 if (pContextInfo->currentMural)
903 return;
904
905 Assert(crHashtableNumElements(pData->pGlobal->contextMuralTable) <= crHashtableNumElements(cr_server.muralTable) - 1);
906 if (crHashtableNumElements(pData->pGlobal->contextMuralTable) < crHashtableNumElements(cr_server.muralTable) - 1)
907 {
908 CRVBOX_CTXWND_WNDWALKER_CB MuralData;
909 MuralData.pGlobal = pData->pGlobal;
910 MuralData.usedMuralTable = pData->usedMuralTable;
911 MuralData.pContextInfo = pContextInfo;
912 MuralData.pMural = NULL;
913
914 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildContextWindowMapWindowWalkerCB, &MuralData);
915
916 pMural = MuralData.pMural;
917
918 }
919
920 if (!pMural)
921 {
922 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
923 if (!pMural)
924 {
925 crWarning("crServerGetDummyMural failed");
926 return;
927 }
928 }
929 else
930 {
931 crHashtableAdd(pData->usedMuralTable, pMural->CreateInfo.externalID, pMural);
932 ++pData->cAdditionalMurals;
933 }
934
935 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pMural);
936}
937
938static void crVBoxServerBuildSaveStateGlobal(PCRVBOX_SAVE_STATE_GLOBAL pGlobal)
939{
940 CRVBOX_CTXWND_CTXWALKER_CB Data;
941 GLuint cMurals;
942 pGlobal->contextMuralTable = crAllocHashtable();
943 pGlobal->additionalMuralContextTable = crAllocHashtable();
944 /* 1. go through all contexts and match all having currentMural set */
945 Data.pGlobal = pGlobal;
946 Data.usedMuralTable = crAllocHashtable();
947 Data.cAdditionalMurals = 0;
948 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUsedWindowMapCB, &Data);
949
950 cMurals = crHashtableNumElements(pGlobal->contextMuralTable);
951 CRASSERT(cMurals <= crHashtableNumElements(cr_server.contextTable));
952 CRASSERT(cMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
953 CRASSERT(cMurals == crHashtableNumElements(Data.usedMuralTable));
954 if (cMurals < crHashtableNumElements(cr_server.contextTable))
955 {
956 Data.cAdditionalMurals = 0;
957 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUnusedWindowMapCB, &Data);
958 }
959
960 CRASSERT(crHashtableNumElements(pGlobal->contextMuralTable) == crHashtableNumElements(cr_server.contextTable));
961 CRASSERT(cMurals + Data.cAdditionalMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
962 if (cMurals + Data.cAdditionalMurals < crHashtableNumElements(cr_server.muralTable) - 1)
963 {
964 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildAdditionalWindowContextMapCB, &Data);
965 CRASSERT(cMurals + Data.cAdditionalMurals + crHashtableNumElements(pGlobal->additionalMuralContextTable) == crHashtableNumElements(cr_server.muralTable) - 1);
966 }
967}
968
969static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
970{
971 int32_t rc;
972 CRContext *pContext;
973 CRMuralInfo *pMural;
974 GLint cbData;
975
976 CRASSERT(cr_server.currentCtxInfo);
977 CRASSERT(cr_server.currentCtxInfo->currentMural);
978
979 pContext = cr_server.currentCtxInfo->pContext;
980 pMural = cr_server.currentCtxInfo->currentMural;
981 /* do crStateAcquireFBImage no matter whether offscreen drawing is used or not
982 * in the former case this would just free pContext->buffer.pFrontImg and pContext->buffer.pFrontImg
983 */
984 rc = crStateAcquireFBImage(pContext);
985 AssertRCReturn(rc, rc);
986
987 if (!pMural->width || !pMural->height)
988 return VINF_SUCCESS;
989
990
991 cbData = crPixelSize(GL_RGBA, GL_UNSIGNED_BYTE) * pMural->width * pMural->height;
992
993 if (!pMural->fUseFBO)
994 {
995 CRASSERT(pMural->width == pContext->buffer.storedWidth);
996 CRASSERT(pMural->width == pContext->buffer.width);
997 CRASSERT(pMural->height == pContext->buffer.storedHeight);
998 CRASSERT(pMural->height == pContext->buffer.height);
999
1000 rc = SSMR3PutMem(pSSM, pContext->buffer.pFrontImg, cbData);
1001 AssertRCReturn(rc, rc);
1002 rc = SSMR3PutMem(pSSM, pContext->buffer.pBackImg, cbData);
1003 AssertRCReturn(rc, rc);
1004
1005 crStateFreeFBImage(pContext);
1006 }
1007 else
1008 {
1009 CR_BLITTER_TEXTURE Tex;
1010 void *pvData;
1011 GLuint idPBO = cr_server.bUsePBOForReadback ? pMural->idPBO : 0;
1012
1013 if (idPBO)
1014 {
1015 CRASSERT(pMural->fboWidth == pMural->width);
1016 CRASSERT(pMural->fboHeight == pMural->height);
1017 }
1018
1019 Tex.width = pMural->width;
1020 Tex.height = pMural->height;
1021 Tex.target = GL_TEXTURE_2D;
1022 Tex.hwid = pMural->aidColorTexs[CR_SERVER_FBO_FB_IDX(pMural)];
1023
1024 CRASSERT(Tex.hwid);
1025
1026 pvData = CrHlpGetTexImage(pContext, &Tex, idPBO);
1027 if (!pvData)
1028 {
1029 crWarning("CrHlpGetTexImage failed for frontbuffer");
1030 return VERR_NO_MEMORY;
1031 }
1032
1033 rc = SSMR3PutMem(pSSM, pvData, cbData);
1034
1035 CrHlpFreeTexImage(pContext, idPBO, pvData);
1036
1037 AssertRCReturn(rc, rc);
1038
1039 Tex.hwid = pMural->aidColorTexs[CR_SERVER_FBO_BB_IDX(pMural)];
1040
1041 CRASSERT(Tex.hwid);
1042
1043 pvData = CrHlpGetTexImage(pContext, &Tex, idPBO);
1044 if (!pvData)
1045 {
1046 crWarning("CrHlpGetTexImage failed for backbuffer");
1047 return VERR_NO_MEMORY;
1048 }
1049
1050 rc = SSMR3PutMem(pSSM, pvData, cbData);
1051
1052 CrHlpFreeTexImage(pContext, idPBO, pvData);
1053
1054 AssertRCReturn(rc, rc);
1055 }
1056
1057 return VINF_SUCCESS;
1058}
1059
1060#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
1061 if(!RT_SUCCESS((_rc))) { \
1062 AssertFailed(); \
1063 return; \
1064 } \
1065 } while (0)
1066
1067static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
1068{
1069 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1070 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1071 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1072 PSSMHANDLE pSSM = pData->pSSM;
1073 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1074 CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
1075
1076 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1077
1078 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1079
1080 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1081 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1082
1083 pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
1084 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1085
1086 crServerPerformMakeCurrent(pMural, pContextInfo);
1087
1088 pData->rc = crVBoxServerSaveFBImage(pSSM);
1089
1090 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1091 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1092 pContextInfo->currentMural = pInitialCurMural;
1093
1094 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1095}
1096
1097static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
1098{
1099 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1100 CRContext *pContext = pContextInfo->pContext;
1101 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1102 PSSMHANDLE pSSM = pData->pSSM;
1103 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
1104 CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
1105 const int32_t i32Dummy = 0;
1106
1107 AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
1108 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1109
1110 CRASSERT(pContext && pSSM);
1111 CRASSERT(pMural);
1112
1113 /* We could have skipped saving the key and use similar callback to load context states back,
1114 * but there's no guarantee we'd traverse hashtable in same order after loading.
1115 */
1116 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1117 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1118
1119#ifdef DEBUG_misha
1120 {
1121 unsigned long id;
1122 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
1123 crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
1124 else
1125 CRASSERT(id == key);
1126 }
1127#endif
1128
1129#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1130 if (pContextInfo->currentMural || crHashtableSearch(cr_server.muralTable, key))
1131 {
1132 CRASSERT(pMural->CreateInfo.externalID);
1133 pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
1134 }
1135 else
1136 {
1137 CRASSERT(!pMural->width);
1138 CRASSERT(!pMural->height);
1139 CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, key));
1140 pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
1141 }
1142 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1143
1144 CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
1145 CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
1146 CRASSERT(cr_server.curClient);
1147
1148 crServerPerformMakeCurrent(pMural, pContextInfo);
1149#endif
1150
1151 pData->rc = crStateSaveContext(pContext, pSSM);
1152 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1153
1154 pData->rc = crVBoxServerSaveFBImage(pSSM);
1155 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1156
1157 /* restore the initial current mural */
1158 pContextInfo->currentMural = pContextCurrentMural;
1159}
1160
1161#if 0
1162typedef struct CR_SERVER_CHECK_BUFFERS
1163{
1164 CRBufferObject *obj;
1165 CRContext *ctx;
1166}CR_SERVER_CHECK_BUFFERS, *PCR_SERVER_CHECK_BUFFERS;
1167
1168static void crVBoxServerCheckConsistencyContextBuffersCB(unsigned long key, void *data1, void *data2)
1169{
1170 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1171 CRContext *ctx = pContextInfo->pContext;
1172 PCR_SERVER_CHECK_BUFFERS pBuffers = (PCR_SERVER_CHECK_BUFFERS)data2;
1173 CRBufferObject *obj = pBuffers->obj;
1174 CRBufferObjectState *b = &(ctx->bufferobject);
1175 int j, k;
1176
1177 if (obj == b->arrayBuffer)
1178 {
1179 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1180 pBuffers->ctx = ctx;
1181 }
1182 if (obj == b->elementsBuffer)
1183 {
1184 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1185 pBuffers->ctx = ctx;
1186 }
1187#ifdef CR_ARB_pixel_buffer_object
1188 if (obj == b->packBuffer)
1189 {
1190 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1191 pBuffers->ctx = ctx;
1192 }
1193 if (obj == b->unpackBuffer)
1194 {
1195 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1196 pBuffers->ctx = ctx;
1197 }
1198#endif
1199
1200#ifdef CR_ARB_vertex_buffer_object
1201 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1202 {
1203 CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array);
1204 if (obj == cp->buffer)
1205 {
1206 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1207 pBuffers->ctx = ctx;
1208 }
1209 }
1210
1211 for (k=0; k<ctx->client.vertexArrayStackDepth; ++k)
1212 {
1213 CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k];
1214 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1215 {
1216 CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray);
1217 if (obj == cp->buffer)
1218 {
1219 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1220 pBuffers->ctx = ctx;
1221 }
1222 }
1223 }
1224#endif
1225}
1226
1227static void crVBoxServerCheckConsistencyBuffersCB(unsigned long key, void *data1, void *data2)
1228{
1229 CRBufferObject *obj = (CRBufferObject *)data1;
1230 CR_SERVER_CHECK_BUFFERS Buffers = {0};
1231 Buffers.obj = obj;
1232 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckConsistencyContextBuffersCB, (void*)&Buffers);
1233}
1234
1235//static void crVBoxServerCheckConsistency2CB(unsigned long key, void *data1, void *data2)
1236//{
1237// CRContextInfo* pContextInfo1 = (CRContextInfo*)data1;
1238// CRContextInfo* pContextInfo2 = (CRContextInfo*)data2;
1239//
1240// CRASSERT(pContextInfo1->pContext);
1241// CRASSERT(pContextInfo2->pContext);
1242//
1243// if (pContextInfo1 == pContextInfo2)
1244// {
1245// CRASSERT(pContextInfo1->pContext == pContextInfo2->pContext);
1246// return;
1247// }
1248//
1249// CRASSERT(pContextInfo1->pContext != pContextInfo2->pContext);
1250// CRASSERT(pContextInfo1->pContext->shared);
1251// CRASSERT(pContextInfo2->pContext->shared);
1252// CRASSERT(pContextInfo1->pContext->shared == pContextInfo2->pContext->shared);
1253// if (pContextInfo1->pContext->shared != pContextInfo2->pContext->shared)
1254// return;
1255//
1256// crHashtableWalk(pContextInfo1->pContext->shared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, pContextInfo2);
1257//}
1258static void crVBoxServerCheckSharedCB(unsigned long key, void *data1, void *data2)
1259{
1260 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1261 void **ppShared = (void**)data2;
1262 if (!*ppShared)
1263 *ppShared = pContextInfo->pContext->shared;
1264 else
1265 Assert(pContextInfo->pContext->shared == *ppShared);
1266}
1267
1268static void crVBoxServerCheckConsistency()
1269{
1270 CRSharedState *pShared = NULL;
1271 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckSharedCB, (void*)&pShared);
1272 Assert(pShared);
1273 if (pShared)
1274 {
1275 crHashtableWalk(pShared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, NULL);
1276 }
1277}
1278#endif
1279
1280static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
1281
1282DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
1283{
1284 int32_t rc, i;
1285 uint32_t ui32;
1286 GLboolean b;
1287 unsigned long key;
1288 GLenum err;
1289#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1290 CRClient *curClient;
1291 CRMuralInfo *curMural = NULL;
1292 CRContextInfo *curCtxInfo = NULL;
1293#endif
1294 CRVBOX_SAVE_STATE_GLOBAL Data;
1295
1296 crMemset(&Data, 0, sizeof (Data));
1297
1298#if 0
1299 crVBoxServerCheckConsistency();
1300#endif
1301
1302 /* We shouldn't be called if there's no clients at all*/
1303 CRASSERT(cr_server.numClients>0);
1304
1305 /* @todo it's hack atm */
1306 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1307 * for every connected client (e.g. guest opengl application)
1308 */
1309 if (!cr_server.bIsInSavingState) /* It's first call */
1310 {
1311 cr_server.bIsInSavingState = GL_TRUE;
1312
1313 /* Store number of clients */
1314 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1315 AssertRCReturn(rc, rc);
1316
1317 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
1318 }
1319
1320 g_hackVBoxServerSaveLoadCallsLeft--;
1321
1322 /* Do nothing until we're being called last time */
1323 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1324 {
1325 return VINF_SUCCESS;
1326 }
1327
1328 /* Save rendering contexts creation info */
1329 ui32 = crHashtableNumElements(cr_server.contextTable);
1330 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1331 AssertRCReturn(rc, rc);
1332 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1333
1334#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1335 curClient = cr_server.curClient;
1336 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1337 if (curClient)
1338 {
1339 curCtxInfo = cr_server.curClient->currentCtxInfo;
1340 curMural = cr_server.curClient->currentMural;
1341 }
1342 else if (cr_server.numClients)
1343 {
1344 cr_server.curClient = cr_server.clients[0];
1345 }
1346#endif
1347
1348 /* first save windows info */
1349 /* Save windows creation info */
1350 ui32 = crHashtableNumElements(cr_server.muralTable);
1351 /* There should be default mural always */
1352 CRASSERT(ui32>=1);
1353 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1354 AssertRCReturn(rc, rc);
1355 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1356
1357 /* Save cr_server.muralTable
1358 * @todo we don't need it all, just geometry info actually
1359 */
1360 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1361 AssertRCReturn(rc, rc);
1362 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1363
1364 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1365 crVBoxServerBuildSaveStateGlobal(&Data);
1366
1367 rc = crStateSaveGlobals(pSSM);
1368 AssertRCReturn(rc, rc);
1369
1370 Data.pSSM = pSSM;
1371 /* Save contexts state tracker data */
1372 /* @todo For now just some blind data dumps,
1373 * but I've a feeling those should be saved/restored in a very strict sequence to
1374 * allow diff_api to work correctly.
1375 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1376 */
1377 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1378 AssertRCReturn(Data.rc, Data.rc);
1379
1380 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1381 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1382 AssertRCReturn(rc, rc);
1383
1384 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1385 AssertRCReturn(Data.rc, Data.rc);
1386
1387#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1388 cr_server.curClient = curClient;
1389 /* Restore original win and ctx IDs*/
1390 if (curClient && curMural && curCtxInfo)
1391 {
1392 crServerPerformMakeCurrent(curMural, curCtxInfo);
1393 }
1394 else
1395 {
1396 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1397 }
1398#endif
1399
1400 /* Save clients info */
1401 for (i = 0; i < cr_server.numClients; i++)
1402 {
1403 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1404 {
1405 CRClient *pClient = cr_server.clients[i];
1406
1407 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1408 AssertRCReturn(rc, rc);
1409
1410 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1411 AssertRCReturn(rc, rc);
1412
1413 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1414 AssertRCReturn(rc, rc);
1415
1416 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1417 AssertRCReturn(rc, rc);
1418
1419 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0)
1420 {
1421 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1422 CRASSERT(b);
1423 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1424 AssertRCReturn(rc, rc);
1425 }
1426
1427 if (pClient->currentMural && pClient->currentWindow>=0)
1428 {
1429 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1430 CRASSERT(b);
1431 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1432 AssertRCReturn(rc, rc);
1433 }
1434 }
1435 }
1436
1437 /* all context gl error states should have now be synced with chromium erro states,
1438 * reset the error if any */
1439 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1440 crWarning("crServer: glGetError %d after saving snapshot", err);
1441
1442 cr_server.bIsInSavingState = GL_FALSE;
1443
1444 return VINF_SUCCESS;
1445}
1446
1447static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1448{
1449 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1450 CRASSERT(pContextInfo);
1451 CRASSERT(pContextInfo->pContext);
1452 return pContextInfo->pContext;
1453}
1454
1455static int32_t crVBoxServerLoadMurals(PSSMHANDLE pSSM, uint32_t version)
1456{
1457 unsigned long key;
1458 uint32_t ui, uiNumElems;
1459 /* Load windows */
1460 int32_t rc = SSMR3GetU32(pSSM, &uiNumElems);
1461 AssertRCReturn(rc, rc);
1462 for (ui=0; ui<uiNumElems; ++ui)
1463 {
1464 CRCreateInfo_t createInfo;
1465 char psz[200];
1466 GLint winID;
1467 unsigned long key;
1468
1469 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1470 AssertRCReturn(rc, rc);
1471 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1472 AssertRCReturn(rc, rc);
1473
1474 if (createInfo.pszDpyName)
1475 {
1476 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1477 AssertRCReturn(rc, rc);
1478 createInfo.pszDpyName = psz;
1479 }
1480
1481 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1482 CRASSERT((int64_t)winID == (int64_t)key);
1483 }
1484
1485 /* Load cr_server.muralTable */
1486 rc = SSMR3GetU32(pSSM, &uiNumElems);
1487 AssertRCReturn(rc, rc);
1488 for (ui=0; ui<uiNumElems; ++ui)
1489 {
1490 CRMuralInfo muralInfo;
1491
1492 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1493 AssertRCReturn(rc, rc);
1494 rc = SSMR3GetMem(pSSM, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1495 AssertRCReturn(rc, rc);
1496
1497 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1498 muralInfo.bFbDraw = GL_TRUE;
1499
1500 if (muralInfo.pVisibleRects)
1501 {
1502 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
1503 if (!muralInfo.pVisibleRects)
1504 {
1505 return VERR_NO_MEMORY;
1506 }
1507
1508 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
1509 AssertRCReturn(rc, rc);
1510 }
1511
1512 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
1513 {
1514 CRMuralInfo *pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);;
1515 CRASSERT(pActualMural);
1516 rc = SSMR3GetMem(pSSM, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
1517 CRASSERT(rc == VINF_SUCCESS);
1518 }
1519
1520 /* Restore windows geometry info */
1521 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
1522 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
1523 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
1524 if (muralInfo.bReceivedRects)
1525 {
1526 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
1527 }
1528 crServerDispatchWindowShow(key, muralInfo.bVisible);
1529
1530 if (muralInfo.pVisibleRects)
1531 {
1532 crFree(muralInfo.pVisibleRects);
1533 }
1534 }
1535
1536 CRASSERT(RT_SUCCESS(rc));
1537 return VINF_SUCCESS;
1538}
1539
1540static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
1541 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
1542{
1543 CRContext *pContext = pContextInfo->pContext;
1544 GLint storedWidth, storedHeight;
1545 int32_t rc = VINF_SUCCESS;
1546
1547 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1548 {
1549 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1550 CRASSERT(cr_server.currentMural = pMural);
1551 storedWidth = pMural->width;
1552 storedHeight = pMural->height;
1553 CRASSERT(pContext->buffer.storedWidth == storedWidth);
1554 CRASSERT(pContext->buffer.storedHeight == storedHeight);
1555 }
1556 else
1557 {
1558 storedWidth = pContext->buffer.storedWidth;
1559 storedHeight = pContext->buffer.storedHeight;
1560 }
1561
1562 if (storedWidth && storedHeight)
1563 {
1564 CRBufferState *pBuf = &pContext->buffer;
1565 GLint cbData;
1566 void *pData;
1567
1568 cbData = crPixelSize(GL_RGBA, GL_UNSIGNED_BYTE) * storedWidth * storedHeight;
1569
1570 pData = crAlloc(cbData);
1571 if (!pData)
1572 {
1573 crWarning("crAlloc failed trying to allocate %d of fb data", cbData);
1574 pBuf->pFrontImg = NULL;
1575 pBuf->pBackImg = NULL;
1576 return VERR_NO_MEMORY;
1577 }
1578
1579 rc = SSMR3GetMem(pSSM, pData, cbData);
1580 AssertRCReturn(rc, rc);
1581
1582 pBuf->pFrontImg = pData;
1583
1584 pData = crAlloc(cbData);
1585 if (!pData)
1586 {
1587 crWarning("crAlloc failed trying to allocate %d of bb data", cbData);
1588 pBuf->pBackImg = NULL;
1589 return VERR_NO_MEMORY;
1590 }
1591
1592 rc = SSMR3GetMem(pSSM, pData, cbData);
1593 AssertRCReturn(rc, rc);
1594
1595 pBuf->pBackImg = pData;
1596
1597 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1598 {
1599 /* can apply the data right away */
1600 crStateApplyFBImage(pContext);
1601 CRASSERT(!pBuf->pFrontImg);
1602 CRASSERT(!pBuf->pBackImg);
1603 }
1604 }
1605
1606 CRASSERT(RT_SUCCESS(rc));
1607 return VINF_SUCCESS;
1608}
1609
1610DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
1611{
1612 int32_t rc, i;
1613 uint32_t ui, uiNumElems;
1614 unsigned long key;
1615 GLenum err;
1616
1617 if (!cr_server.bIsInLoadingState)
1618 {
1619 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
1620 cr_server.bIsInLoadingState = GL_TRUE;
1621
1622 /* Read number of clients */
1623 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
1624 AssertRCReturn(rc, rc);
1625 }
1626
1627 g_hackVBoxServerSaveLoadCallsLeft--;
1628
1629 /* Do nothing until we're being called last time */
1630 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1631 {
1632 return VINF_SUCCESS;
1633 }
1634
1635 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
1636 {
1637 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1638 }
1639
1640 /* Load and recreate rendering contexts */
1641 rc = SSMR3GetU32(pSSM, &uiNumElems);
1642 AssertRCReturn(rc, rc);
1643 for (ui=0; ui<uiNumElems; ++ui)
1644 {
1645 CRCreateInfo_t createInfo;
1646 char psz[200];
1647 GLint ctxID;
1648 CRContextInfo* pContextInfo;
1649 CRContext* pContext;
1650
1651 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1652 AssertRCReturn(rc, rc);
1653 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1654 AssertRCReturn(rc, rc);
1655
1656 if (createInfo.pszDpyName)
1657 {
1658 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1659 AssertRCReturn(rc, rc);
1660 createInfo.pszDpyName = psz;
1661 }
1662
1663 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
1664 CRASSERT((int64_t)ctxID == (int64_t)key);
1665
1666 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1667 CRASSERT(pContextInfo);
1668 CRASSERT(pContextInfo->pContext);
1669 pContext = pContextInfo->pContext;
1670 pContext->shared->id=-1;
1671 }
1672
1673 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1674 {
1675 /* we have a mural data here */
1676 rc = crVBoxServerLoadMurals(pSSM, version);
1677 AssertRCReturn(rc, rc);
1678 }
1679
1680 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
1681 {
1682 /* set the current client to allow doing crServerPerformMakeCurrent later */
1683 CRASSERT(cr_server.numClients);
1684 cr_server.curClient = cr_server.clients[0];
1685 }
1686
1687 rc = crStateLoadGlobals(pSSM, version);
1688 AssertRCReturn(rc, rc);
1689
1690 /* Restore context state data */
1691 for (ui=0; ui<uiNumElems; ++ui)
1692 {
1693 CRContextInfo* pContextInfo;
1694 CRContext *pContext;
1695 CRMuralInfo *pMural = NULL;
1696 int32_t winId = 0;
1697
1698 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1699 AssertRCReturn(rc, rc);
1700
1701 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1702 CRASSERT(pContextInfo);
1703 CRASSERT(pContextInfo->pContext);
1704 pContext = pContextInfo->pContext;
1705
1706 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1707 {
1708 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
1709 AssertRCReturn(rc, rc);
1710
1711 if (winId)
1712 {
1713 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
1714 CRASSERT(pMural);
1715 }
1716 else
1717 {
1718 /* null winId means a dummy mural, get it */
1719 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
1720 CRASSERT(pMural);
1721 }
1722
1723 crServerPerformMakeCurrent(pMural, pContextInfo);
1724 }
1725
1726 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
1727 AssertRCReturn(rc, rc);
1728
1729 /*Restore front/back buffer images*/
1730 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1731 AssertRCReturn(rc, rc);
1732 }
1733
1734 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1735 {
1736 CRContextInfo *pContextInfo;
1737 CRMuralInfo *pMural;
1738 GLint ctxId;
1739
1740 rc = SSMR3GetU32(pSSM, &uiNumElems);
1741 AssertRCReturn(rc, rc);
1742 for (ui=0; ui<uiNumElems; ++ui)
1743 {
1744 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1745 CRMuralInfo *pInitialCurMural;
1746
1747 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1748 AssertRCReturn(rc, rc);
1749
1750 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
1751 AssertRCReturn(rc, rc);
1752
1753 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1754 CRASSERT(pMural);
1755 if (ctxId)
1756 {
1757 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
1758 CRASSERT(pContextInfo);
1759 }
1760 else
1761 pContextInfo = &cr_server.MainContextInfo;
1762
1763 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1764 pInitialCurMural = pContextInfo->currentMural;
1765
1766 crServerPerformMakeCurrent(pMural, pContextInfo);
1767
1768 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1769 AssertRCReturn(rc, rc);
1770
1771 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1772 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1773 pContextInfo->currentMural = pInitialCurMural;
1774 }
1775
1776 if (cr_server.currentCtxInfo != &cr_server.MainContextInfo)
1777 {
1778 /* most ogl data gets loaded to hw on chromium 3D state switch, i.e. inside crStateMakeCurrent -> crStateSwitchContext
1779 * to force the crStateSwitchContext being called later, we need to set the current context to our dummy one */
1780 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
1781 CRASSERT(pMural);
1782 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
1783 }
1784
1785 cr_server.curClient = NULL;
1786 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1787 }
1788 else
1789 {
1790 CRServerFreeIDsPool_t dummyIdsPool;
1791
1792 /* we have a mural data here */
1793 rc = crVBoxServerLoadMurals(pSSM, version);
1794 AssertRCReturn(rc, rc);
1795
1796 /* not used any more, just read it out and ignore */
1797 rc = SSMR3GetMem(pSSM, &dummyIdsPool, sizeof(dummyIdsPool));
1798 CRASSERT(rc == VINF_SUCCESS);
1799 }
1800
1801 /* Load clients info */
1802 for (i = 0; i < cr_server.numClients; i++)
1803 {
1804 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1805 {
1806 CRClient *pClient = cr_server.clients[i];
1807 CRClient client;
1808 unsigned long ctxID=-1, winID=-1;
1809
1810 rc = SSMR3GetU32(pSSM, &ui);
1811 AssertRCReturn(rc, rc);
1812 /* If this assert fires, then we should search correct client in the list first*/
1813 CRASSERT(ui == pClient->conn->u32ClientID);
1814
1815 if (version>=4)
1816 {
1817 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
1818 AssertRCReturn(rc, rc);
1819
1820 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
1821 AssertRCReturn(rc, rc);
1822 }
1823
1824 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
1825 CRASSERT(rc == VINF_SUCCESS);
1826
1827 client.conn = pClient->conn;
1828 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
1829 * and fail to bind old textures.
1830 */
1831 /*client.number = pClient->number;*/
1832 *pClient = client;
1833
1834 pClient->currentContextNumber = -1;
1835 pClient->currentCtxInfo = &cr_server.MainContextInfo;
1836 pClient->currentMural = NULL;
1837 pClient->currentWindow = -1;
1838
1839 cr_server.curClient = pClient;
1840
1841 if (client.currentCtxInfo && client.currentContextNumber>=0)
1842 {
1843 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
1844 AssertRCReturn(rc, rc);
1845 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
1846 CRASSERT(client.currentCtxInfo);
1847 CRASSERT(client.currentCtxInfo->pContext);
1848 //pClient->currentCtx = client.currentCtx;
1849 //pClient->currentContextNumber = ctxID;
1850 }
1851
1852 if (client.currentMural && client.currentWindow>=0)
1853 {
1854 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
1855 AssertRCReturn(rc, rc);
1856 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
1857 CRASSERT(client.currentMural);
1858 //pClient->currentMural = client.currentMural;
1859 //pClient->currentWindow = winID;
1860 }
1861
1862 /* Restore client active context and window */
1863 crServerDispatchMakeCurrent(winID, 0, ctxID);
1864
1865 if (0)
1866 {
1867// CRContext *tmpCtx;
1868// CRCreateInfo_t *createInfo;
1869 GLfloat one[4] = { 1, 1, 1, 1 };
1870 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
1871
1872 crServerDispatchMakeCurrent(winID, 0, ctxID);
1873
1874 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
1875
1876 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
1877 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
1878 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
1879#ifdef CR_ARB_texture_cube_map
1880 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
1881#endif
1882#ifdef CR_NV_texture_rectangle
1883 //@todo this doesn't work as expected
1884 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
1885#endif
1886 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
1887 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
1888 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
1889
1890 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
1891 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
1892 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
1893
1894 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
1895 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
1896
1897 //crStateViewport( 0, 0, 600, 600 );
1898 //pClient->currentMural->viewportValidated = GL_FALSE;
1899 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
1900
1901 //crStateMatrixMode(GL_PROJECTION);
1902 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
1903
1904 //crStateLoadIdentity();
1905 //cr_server.head_spu->dispatch_table.LoadIdentity();
1906
1907 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1908 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1909
1910 //crStateMatrixMode(GL_MODELVIEW);
1911 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
1912 //crServerDispatchLoadIdentity();
1913 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1914 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1915 //crServerDispatchLoadIdentity();
1916
1917 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
1918 CRASSERT(createInfo);
1919 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
1920 CRASSERT(tmpCtx);
1921 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
1922 crStateDestroyContext(tmpCtx);*/
1923 }
1924 }
1925 }
1926
1927 //crServerDispatchMakeCurrent(-1, 0, -1);
1928
1929 cr_server.curClient = NULL;
1930
1931 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1932 crWarning("crServer: glGetError %d after loading snapshot", err);
1933
1934 cr_server.bIsInLoadingState = GL_FALSE;
1935
1936#if 0
1937 crVBoxServerCheckConsistency();
1938#endif
1939
1940 return VINF_SUCCESS;
1941}
1942
1943#define SCREEN(i) (cr_server.screen[i])
1944#define MAPPED(screen) ((screen).winID != 0)
1945
1946static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
1947{
1948 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1949 int *sIndex = (int*) data2;
1950
1951 if (pMI->screenId == *sIndex)
1952 {
1953 renderspuReparentWindow(pMI->spuWindow);
1954 }
1955}
1956
1957static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
1958{
1959 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1960 (void) data2;
1961
1962 crServerCheckMuralGeometry(pMI);
1963}
1964
1965DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
1966{
1967 int i;
1968
1969 if (sCount>CR_MAX_GUEST_MONITORS)
1970 return VERR_INVALID_PARAMETER;
1971
1972 /*Shouldn't happen yet, but to be safe in future*/
1973 for (i=0; i<cr_server.screenCount; ++i)
1974 {
1975 if (MAPPED(SCREEN(i)))
1976 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
1977 return VERR_NOT_IMPLEMENTED;
1978 }
1979
1980 cr_server.screenCount = sCount;
1981
1982 for (i=0; i<sCount; ++i)
1983 {
1984 SCREEN(i).winID = 0;
1985 }
1986
1987 return VINF_SUCCESS;
1988}
1989
1990DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
1991{
1992 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
1993
1994 if (sIndex<0 || sIndex>=cr_server.screenCount)
1995 return VERR_INVALID_PARAMETER;
1996
1997 if (MAPPED(SCREEN(sIndex)))
1998 {
1999 SCREEN(sIndex).winID = 0;
2000 renderspuSetWindowId(0);
2001
2002 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2003 }
2004
2005 renderspuSetWindowId(SCREEN(0).winID);
2006 return VINF_SUCCESS;
2007}
2008
2009DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2010{
2011 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2012
2013 if (sIndex<0 || sIndex>=cr_server.screenCount)
2014 return VERR_INVALID_PARAMETER;
2015
2016 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2017 {
2018 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2019 crVBoxServerUnmapScreen(sIndex);
2020 }
2021
2022 SCREEN(sIndex).winID = winID;
2023 SCREEN(sIndex).x = x;
2024 SCREEN(sIndex).y = y;
2025 SCREEN(sIndex).w = w;
2026 SCREEN(sIndex).h = h;
2027
2028 renderspuSetWindowId(SCREEN(sIndex).winID);
2029 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2030 renderspuSetWindowId(SCREEN(0).winID);
2031
2032 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2033
2034#ifndef WINDOWS
2035 /*Restore FB content for clients, which have current window on a screen being remapped*/
2036 {
2037 GLint i;
2038
2039 for (i = 0; i < cr_server.numClients; i++)
2040 {
2041 cr_server.curClient = cr_server.clients[i];
2042 if (cr_server.curClient->currentCtxInfo
2043 && cr_server.curClient->currentCtxInfo->pContext
2044 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg || cr_server.curClient->currentCtxInfo->pContext->buffer.pBackImg)
2045 && cr_server.curClient->currentMural
2046 && cr_server.curClient->currentMural->screenId == sIndex
2047 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2048 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2049 {
2050 int clientWindow = cr_server.curClient->currentWindow;
2051 int clientContext = cr_server.curClient->currentContextNumber;
2052
2053 if (clientWindow && clientWindow != cr_server.currentWindow)
2054 {
2055 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2056 }
2057
2058 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext);
2059 }
2060 }
2061 cr_server.curClient = NULL;
2062 }
2063#endif
2064
2065 {
2066 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
2067 if (pDisplay)
2068 CrDpResize(pDisplay, w, h, w, h);
2069 }
2070
2071 return VINF_SUCCESS;
2072}
2073
2074DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
2075{
2076 renderspuSetRootVisibleRegion(cRects, pRects);
2077
2078 return VINF_SUCCESS;
2079}
2080
2081DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2082{
2083 cr_server.pfnPresentFBO = pfnPresentFBO;
2084}
2085
2086int32_t crServerSetOffscreenRenderingMode(GLubyte value)
2087{
2088 if (cr_server.bForceOffscreenRendering==value)
2089 {
2090 return VINF_SUCCESS;
2091 }
2092
2093 if (value > CR_SERVER_REDIR_MAXVAL)
2094 {
2095 crWarning("crServerSetOffscreenRenderingMode: invalid arg: %d", value);
2096 return VERR_INVALID_PARAMETER;
2097 }
2098
2099 if (value && !crServerSupportRedirMuralFBO())
2100 {
2101 return VERR_NOT_SUPPORTED;
2102 }
2103
2104 cr_server.bForceOffscreenRendering=value;
2105
2106 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2107
2108 return VINF_SUCCESS;
2109}
2110
2111DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2112{
2113 return crServerSetOffscreenRenderingMode(value ? CR_SERVER_REDIR_FBO_RAM : cr_server.bOffscreenRenderingDefault);
2114}
2115
2116DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2117{
2118 /* No need for a synchronization as this is single threaded. */
2119 if (pCallbacks)
2120 {
2121 cr_server.outputRedirect = *pCallbacks;
2122 cr_server.bUseOutputRedirect = true;
2123 }
2124 else
2125 {
2126 cr_server.bUseOutputRedirect = false;
2127 }
2128
2129 // @todo dynamically intercept already existing output:
2130 // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
2131
2132 return VINF_SUCCESS;
2133}
2134
2135static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2)
2136{
2137 CRMuralInfo *mural = (CRMuralInfo*) data1;
2138 int *sIndex = (int*) data2;
2139
2140 if (mural->screenId != *sIndex)
2141 return;
2142
2143 crServerCheckMuralGeometry(mural);
2144}
2145
2146
2147DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2148{
2149 CRScreenViewportInfo *pVieport;
2150 GLboolean fPosChanged, fSizeChanged;
2151
2152 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2153
2154 if (sIndex<0 || sIndex>=cr_server.screenCount)
2155 {
2156 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2157 return VERR_INVALID_PARAMETER;
2158 }
2159
2160 pVieport = &cr_server.screenVieport[sIndex];
2161 fPosChanged = (pVieport->x != x || pVieport->y != y);
2162 fSizeChanged = (pVieport->w != w || pVieport->h != h);
2163
2164 if (!fPosChanged && !fSizeChanged)
2165 {
2166 crDebug("crVBoxServerSetScreenViewport: no changes");
2167 return VINF_SUCCESS;
2168 }
2169
2170 if (fPosChanged)
2171 {
2172 pVieport->x = x;
2173 pVieport->y = y;
2174
2175 crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex);
2176 }
2177
2178 if (fSizeChanged)
2179 {
2180 pVieport->w = w;
2181 pVieport->h = h;
2182
2183 /* no need to do anything here actually */
2184 }
2185 return VINF_SUCCESS;
2186}
2187
2188
2189#ifdef VBOX_WITH_CRHGSMI
2190/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
2191 *
2192 * 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.
2193 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
2194 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
2195 * to block the lower-priority thread trying to complete the blocking command.
2196 * And removed extra memcpy done on blocked command arrival.
2197 *
2198 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
2199 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
2200 *
2201 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
2202 * */
2203int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
2204{
2205 int32_t rc;
2206 uint32_t cBuffers = pCmd->cBuffers;
2207 uint32_t cParams;
2208 uint32_t cbHdr;
2209 CRVBOXHGSMIHDR *pHdr;
2210 uint32_t u32Function;
2211 uint32_t u32ClientID;
2212 CRClient *pClient;
2213
2214 if (!g_pvVRamBase)
2215 {
2216 crWarning("g_pvVRamBase is not initialized");
2217 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
2218 return VINF_SUCCESS;
2219 }
2220
2221 if (!cBuffers)
2222 {
2223 crWarning("zero buffers passed in!");
2224 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2225 return VINF_SUCCESS;
2226 }
2227
2228 cParams = cBuffers-1;
2229
2230 cbHdr = pCmd->aBuffers[0].cbBuffer;
2231 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2232 if (!pHdr)
2233 {
2234 crWarning("invalid header buffer!");
2235 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2236 return VINF_SUCCESS;
2237 }
2238
2239 if (cbHdr < sizeof (*pHdr))
2240 {
2241 crWarning("invalid header buffer size!");
2242 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2243 return VINF_SUCCESS;
2244 }
2245
2246 u32Function = pHdr->u32Function;
2247 u32ClientID = pHdr->u32ClientID;
2248
2249 switch (u32Function)
2250 {
2251 case SHCRGL_GUEST_FN_WRITE:
2252 {
2253 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2254
2255 /* @todo: Verify */
2256 if (cParams == 1)
2257 {
2258 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2259 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2260 /* Fetch parameters. */
2261 uint32_t cbBuffer = pBuf->cbBuffer;
2262 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2263
2264 if (cbHdr < sizeof (*pFnCmd))
2265 {
2266 crWarning("invalid write cmd buffer size!");
2267 rc = VERR_INVALID_PARAMETER;
2268 break;
2269 }
2270
2271 CRASSERT(cbBuffer);
2272 if (!pBuffer)
2273 {
2274 crWarning("invalid buffer data received from guest!");
2275 rc = VERR_INVALID_PARAMETER;
2276 break;
2277 }
2278
2279 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2280 if (RT_FAILURE(rc))
2281 {
2282 break;
2283 }
2284
2285 /* This should never fire unless we start to multithread */
2286 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2287 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2288
2289 pClient->conn->pBuffer = pBuffer;
2290 pClient->conn->cbBuffer = cbBuffer;
2291 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2292 rc = crVBoxServerInternalClientWriteRead(pClient);
2293 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2294 return rc;
2295 }
2296 else
2297 {
2298 crWarning("invalid number of args");
2299 rc = VERR_INVALID_PARAMETER;
2300 break;
2301 }
2302 break;
2303 }
2304
2305 case SHCRGL_GUEST_FN_INJECT:
2306 {
2307 crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2308
2309 /* @todo: Verify */
2310 if (cParams == 1)
2311 {
2312 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2313 /* Fetch parameters. */
2314 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2315 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2316 uint32_t cbBuffer = pBuf->cbBuffer;
2317 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2318
2319 if (cbHdr < sizeof (*pFnCmd))
2320 {
2321 crWarning("invalid inject cmd buffer size!");
2322 rc = VERR_INVALID_PARAMETER;
2323 break;
2324 }
2325
2326 CRASSERT(cbBuffer);
2327 if (!pBuffer)
2328 {
2329 crWarning("invalid buffer data received from guest!");
2330 rc = VERR_INVALID_PARAMETER;
2331 break;
2332 }
2333
2334 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
2335 if (RT_FAILURE(rc))
2336 {
2337 break;
2338 }
2339
2340 /* This should never fire unless we start to multithread */
2341 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2342 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2343
2344 pClient->conn->pBuffer = pBuffer;
2345 pClient->conn->cbBuffer = cbBuffer;
2346 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2347 rc = crVBoxServerInternalClientWriteRead(pClient);
2348 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2349 return rc;
2350 }
2351
2352 crWarning("invalid number of args");
2353 rc = VERR_INVALID_PARAMETER;
2354 break;
2355 }
2356
2357 case SHCRGL_GUEST_FN_READ:
2358 {
2359 crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n"));
2360
2361 /* @todo: Verify */
2362 if (cParams == 1)
2363 {
2364 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
2365 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2366 /* Fetch parameters. */
2367 uint32_t cbBuffer = pBuf->cbBuffer;
2368 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2369
2370 if (cbHdr < sizeof (*pFnCmd))
2371 {
2372 crWarning("invalid read cmd buffer size!");
2373 rc = VERR_INVALID_PARAMETER;
2374 break;
2375 }
2376
2377
2378 if (!pBuffer)
2379 {
2380 crWarning("invalid buffer data received from guest!");
2381 rc = VERR_INVALID_PARAMETER;
2382 break;
2383 }
2384
2385 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2386 if (RT_FAILURE(rc))
2387 {
2388 break;
2389 }
2390
2391 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2392
2393 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
2394
2395 /* Return the required buffer size always */
2396 pFnCmd->cbBuffer = cbBuffer;
2397
2398 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2399
2400 /* the read command is never pended, complete it right away */
2401 pHdr->result = rc;
2402 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2403 return VINF_SUCCESS;
2404 }
2405
2406 crWarning("invalid number of args");
2407 rc = VERR_INVALID_PARAMETER;
2408 break;
2409 }
2410
2411 case SHCRGL_GUEST_FN_WRITE_READ:
2412 {
2413 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
2414
2415 /* @todo: Verify */
2416 if (cParams == 2)
2417 {
2418 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
2419 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2420 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
2421
2422 /* Fetch parameters. */
2423 uint32_t cbBuffer = pBuf->cbBuffer;
2424 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2425
2426 uint32_t cbWriteback = pWbBuf->cbBuffer;
2427 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
2428
2429 if (cbHdr < sizeof (*pFnCmd))
2430 {
2431 crWarning("invalid write_read cmd buffer size!");
2432 rc = VERR_INVALID_PARAMETER;
2433 break;
2434 }
2435
2436
2437 CRASSERT(cbBuffer);
2438 if (!pBuffer)
2439 {
2440 crWarning("invalid write buffer data received from guest!");
2441 rc = VERR_INVALID_PARAMETER;
2442 break;
2443 }
2444
2445 CRASSERT(cbWriteback);
2446 if (!pWriteback)
2447 {
2448 crWarning("invalid writeback buffer data received from guest!");
2449 rc = VERR_INVALID_PARAMETER;
2450 break;
2451 }
2452 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2453 if (RT_FAILURE(rc))
2454 {
2455 pHdr->result = rc;
2456 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2457 return rc;
2458 }
2459
2460 /* This should never fire unless we start to multithread */
2461 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2462 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2463
2464 pClient->conn->pBuffer = pBuffer;
2465 pClient->conn->cbBuffer = cbBuffer;
2466 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
2467 rc = crVBoxServerInternalClientWriteRead(pClient);
2468 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2469 return rc;
2470 }
2471
2472 crWarning("invalid number of args");
2473 rc = VERR_INVALID_PARAMETER;
2474 break;
2475 }
2476
2477 case SHCRGL_GUEST_FN_SET_VERSION:
2478 {
2479 crWarning("invalid function");
2480 rc = VERR_NOT_IMPLEMENTED;
2481 break;
2482 }
2483
2484 case SHCRGL_GUEST_FN_SET_PID:
2485 {
2486 crWarning("invalid function");
2487 rc = VERR_NOT_IMPLEMENTED;
2488 break;
2489 }
2490
2491 default:
2492 {
2493 crWarning("invalid function");
2494 rc = VERR_NOT_IMPLEMENTED;
2495 break;
2496 }
2497
2498 }
2499
2500 /* we can be on fail only here */
2501 CRASSERT(RT_FAILURE(rc));
2502 pHdr->result = rc;
2503 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2504 return rc;
2505}
2506
2507int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
2508{
2509 int rc = VINF_SUCCESS;
2510
2511 switch (pCtl->enmType)
2512 {
2513 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
2514 {
2515 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
2516 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
2517 g_cbVRam = pSetup->cbVRam;
2518 rc = VINF_SUCCESS;
2519 break;
2520 }
2521 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
2522 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
2523 rc = VINF_SUCCESS;
2524 break;
2525 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
2526 {
2527 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
2528 g_hCrHgsmiCompletion = pSetup->hCompletion;
2529 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
2530 rc = VINF_SUCCESS;
2531 break;
2532 }
2533 default:
2534 AssertMsgFailed(("invalid param %d", pCtl->enmType));
2535 rc = VERR_INVALID_PARAMETER;
2536 }
2537
2538 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
2539 * to complete them accordingly.
2540 * This approach allows using host->host and host->guest commands in the same way here
2541 * making the command completion to be the responsibility of the command originator.
2542 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
2543 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
2544 return rc;
2545}
2546#endif
Note: See TracBrowser for help on using the repository browser.

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