VirtualBox

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

Last change on this file since 44390 was 44290, checked in by vboxsync, 12 years ago

crOpenGL: saved state fixes & improvements

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 78.5 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "server.h"
8#include "cr_net.h"
9#include "cr_unpack.h"
10#include "cr_error.h"
11#include "cr_glstate.h"
12#include "cr_string.h"
13#include "cr_mem.h"
14#include "cr_hash.h"
15#include "cr_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 = {0};
1295
1296#if 0
1297 crVBoxServerCheckConsistency();
1298#endif
1299
1300 /* We shouldn't be called if there's no clients at all*/
1301 CRASSERT(cr_server.numClients>0);
1302
1303 /* @todo it's hack atm */
1304 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1305 * for every connected client (e.g. guest opengl application)
1306 */
1307 if (!cr_server.bIsInSavingState) /* It's first call */
1308 {
1309 cr_server.bIsInSavingState = GL_TRUE;
1310
1311 /* Store number of clients */
1312 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1313 AssertRCReturn(rc, rc);
1314
1315 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
1316 }
1317
1318 g_hackVBoxServerSaveLoadCallsLeft--;
1319
1320 /* Do nothing until we're being called last time */
1321 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1322 {
1323 return VINF_SUCCESS;
1324 }
1325
1326 /* Save rendering contexts creation info */
1327 ui32 = crHashtableNumElements(cr_server.contextTable);
1328 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1329 AssertRCReturn(rc, rc);
1330 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1331
1332#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1333 curClient = cr_server.curClient;
1334 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1335 if (curClient)
1336 {
1337 curCtxInfo = cr_server.curClient->currentCtxInfo;
1338 curMural = cr_server.curClient->currentMural;
1339 }
1340 else if (cr_server.numClients)
1341 {
1342 cr_server.curClient = cr_server.clients[0];
1343 }
1344#endif
1345
1346 /* first save windows info */
1347 /* Save windows creation info */
1348 ui32 = crHashtableNumElements(cr_server.muralTable);
1349 /* There should be default mural always */
1350 CRASSERT(ui32>=1);
1351 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1352 AssertRCReturn(rc, rc);
1353 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1354
1355 /* Save cr_server.muralTable
1356 * @todo we don't need it all, just geometry info actually
1357 */
1358 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1359 AssertRCReturn(rc, rc);
1360 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1361
1362 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1363 crVBoxServerBuildSaveStateGlobal(&Data);
1364
1365 rc = crStateSaveGlobals(pSSM);
1366 AssertRCReturn(rc, rc);
1367
1368 Data.pSSM = pSSM;
1369 /* Save contexts state tracker data */
1370 /* @todo For now just some blind data dumps,
1371 * but I've a feeling those should be saved/restored in a very strict sequence to
1372 * allow diff_api to work correctly.
1373 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1374 */
1375 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1376 AssertRCReturn(Data.rc, Data.rc);
1377
1378 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1379 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1380 AssertRCReturn(rc, rc);
1381
1382 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1383 AssertRCReturn(Data.rc, Data.rc);
1384
1385#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1386 cr_server.curClient = curClient;
1387 /* Restore original win and ctx IDs*/
1388 if (curClient && curMural && curCtxInfo)
1389 {
1390 crServerPerformMakeCurrent(curMural, curCtxInfo);
1391 }
1392 else
1393 {
1394 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1395 }
1396#endif
1397
1398 /* Save clients info */
1399 for (i = 0; i < cr_server.numClients; i++)
1400 {
1401 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1402 {
1403 CRClient *pClient = cr_server.clients[i];
1404
1405 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1406 AssertRCReturn(rc, rc);
1407
1408 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1409 AssertRCReturn(rc, rc);
1410
1411 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1412 AssertRCReturn(rc, rc);
1413
1414 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1415 AssertRCReturn(rc, rc);
1416
1417 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0)
1418 {
1419 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1420 CRASSERT(b);
1421 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1422 AssertRCReturn(rc, rc);
1423 }
1424
1425 if (pClient->currentMural && pClient->currentWindow>=0)
1426 {
1427 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1428 CRASSERT(b);
1429 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1430 AssertRCReturn(rc, rc);
1431 }
1432 }
1433 }
1434
1435 /* all context gl error states should have now be synced with chromium erro states,
1436 * reset the error if any */
1437 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1438 crWarning("crServer: glGetError %d after saving snapshot", err);
1439
1440 cr_server.bIsInSavingState = GL_FALSE;
1441
1442 return VINF_SUCCESS;
1443}
1444
1445static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1446{
1447 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1448 CRASSERT(pContextInfo);
1449 CRASSERT(pContextInfo->pContext);
1450 return pContextInfo->pContext;
1451}
1452
1453static int32_t crVBoxServerLoadMurals(PSSMHANDLE pSSM, uint32_t version)
1454{
1455 unsigned long key;
1456 uint32_t ui, uiNumElems;
1457 /* Load windows */
1458 int32_t rc = SSMR3GetU32(pSSM, &uiNumElems);
1459 AssertRCReturn(rc, rc);
1460 for (ui=0; ui<uiNumElems; ++ui)
1461 {
1462 CRCreateInfo_t createInfo;
1463 char psz[200];
1464 GLint winID;
1465 unsigned long key;
1466
1467 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1468 AssertRCReturn(rc, rc);
1469 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1470 AssertRCReturn(rc, rc);
1471
1472 if (createInfo.pszDpyName)
1473 {
1474 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1475 AssertRCReturn(rc, rc);
1476 createInfo.pszDpyName = psz;
1477 }
1478
1479 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1480 CRASSERT((int64_t)winID == (int64_t)key);
1481 }
1482
1483 /* Load cr_server.muralTable */
1484 rc = SSMR3GetU32(pSSM, &uiNumElems);
1485 AssertRCReturn(rc, rc);
1486 for (ui=0; ui<uiNumElems; ++ui)
1487 {
1488 CRMuralInfo muralInfo;
1489
1490 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1491 AssertRCReturn(rc, rc);
1492 rc = SSMR3GetMem(pSSM, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1493 AssertRCReturn(rc, rc);
1494
1495 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1496 muralInfo.bFbDraw = GL_TRUE;
1497
1498 if (muralInfo.pVisibleRects)
1499 {
1500 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
1501 if (!muralInfo.pVisibleRects)
1502 {
1503 return VERR_NO_MEMORY;
1504 }
1505
1506 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
1507 AssertRCReturn(rc, rc);
1508 }
1509
1510 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
1511 {
1512 CRMuralInfo *pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);;
1513 CRASSERT(pActualMural);
1514 rc = SSMR3GetMem(pSSM, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
1515 CRASSERT(rc == VINF_SUCCESS);
1516 }
1517
1518 /* Restore windows geometry info */
1519 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
1520 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
1521 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
1522 if (muralInfo.bReceivedRects)
1523 {
1524 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
1525 }
1526 crServerDispatchWindowShow(key, muralInfo.bVisible);
1527
1528 if (muralInfo.pVisibleRects)
1529 {
1530 crFree(muralInfo.pVisibleRects);
1531 }
1532 }
1533
1534 CRASSERT(RT_SUCCESS(rc));
1535 return VINF_SUCCESS;
1536}
1537
1538static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
1539 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
1540{
1541 CRContext *pContext = pContextInfo->pContext;
1542 GLint storedWidth, storedHeight;
1543 int32_t rc = VINF_SUCCESS;
1544
1545 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1546 {
1547 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1548 CRASSERT(cr_server.currentMural = pMural);
1549 storedWidth = pMural->width;
1550 storedHeight = pMural->height;
1551 CRASSERT(pContext->buffer.storedWidth == storedWidth);
1552 CRASSERT(pContext->buffer.storedHeight == storedHeight);
1553 }
1554 else
1555 {
1556 storedWidth = pContext->buffer.storedWidth;
1557 storedHeight = pContext->buffer.storedHeight;
1558 }
1559
1560 if (storedWidth && storedHeight)
1561 {
1562 CRBufferState *pBuf = &pContext->buffer;
1563 GLint cbData;
1564 void *pData;
1565
1566 cbData = crPixelSize(GL_RGBA, GL_UNSIGNED_BYTE) * storedWidth * storedHeight;
1567
1568 pData = crAlloc(cbData);
1569 if (!pData)
1570 {
1571 crWarning("crAlloc failed trying to allocate %d of fb data", cbData);
1572 pBuf->pFrontImg = NULL;
1573 pBuf->pBackImg = NULL;
1574 return VERR_NO_MEMORY;
1575 }
1576
1577 rc = SSMR3GetMem(pSSM, pData, cbData);
1578 AssertRCReturn(rc, rc);
1579
1580 pBuf->pFrontImg = pData;
1581
1582 pData = crAlloc(cbData);
1583 if (!pData)
1584 {
1585 crWarning("crAlloc failed trying to allocate %d of bb data", cbData);
1586 pBuf->pBackImg = NULL;
1587 return VERR_NO_MEMORY;
1588 }
1589
1590 rc = SSMR3GetMem(pSSM, pData, cbData);
1591 AssertRCReturn(rc, rc);
1592
1593 pBuf->pBackImg = pData;
1594
1595 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1596 {
1597 /* can apply the data right away */
1598 crStateApplyFBImage(pContext);
1599 CRASSERT(!pBuf->pFrontImg);
1600 CRASSERT(!pBuf->pBackImg);
1601 }
1602 }
1603
1604 CRASSERT(RT_SUCCESS(rc));
1605 return VINF_SUCCESS;
1606}
1607
1608DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
1609{
1610 int32_t rc, i;
1611 uint32_t ui, uiNumElems;
1612 unsigned long key;
1613 GLenum err;
1614
1615 if (!cr_server.bIsInLoadingState)
1616 {
1617 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
1618 cr_server.bIsInLoadingState = GL_TRUE;
1619
1620 /* Read number of clients */
1621 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
1622 AssertRCReturn(rc, rc);
1623 }
1624
1625 g_hackVBoxServerSaveLoadCallsLeft--;
1626
1627 /* Do nothing until we're being called last time */
1628 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1629 {
1630 return VINF_SUCCESS;
1631 }
1632
1633 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
1634 {
1635 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1636 }
1637
1638 /* Load and recreate rendering contexts */
1639 rc = SSMR3GetU32(pSSM, &uiNumElems);
1640 AssertRCReturn(rc, rc);
1641 for (ui=0; ui<uiNumElems; ++ui)
1642 {
1643 CRCreateInfo_t createInfo;
1644 char psz[200];
1645 GLint ctxID;
1646 CRContextInfo* pContextInfo;
1647 CRContext* pContext;
1648
1649 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1650 AssertRCReturn(rc, rc);
1651 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1652 AssertRCReturn(rc, rc);
1653
1654 if (createInfo.pszDpyName)
1655 {
1656 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1657 AssertRCReturn(rc, rc);
1658 createInfo.pszDpyName = psz;
1659 }
1660
1661 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
1662 CRASSERT((int64_t)ctxID == (int64_t)key);
1663
1664 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1665 CRASSERT(pContextInfo);
1666 CRASSERT(pContextInfo->pContext);
1667 pContext = pContextInfo->pContext;
1668 pContext->shared->id=-1;
1669 }
1670
1671 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1672 {
1673 /* we have a mural data here */
1674 rc = crVBoxServerLoadMurals(pSSM, version);
1675 AssertRCReturn(rc, rc);
1676 }
1677
1678 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
1679 {
1680 /* set the current client to allow doing crServerPerformMakeCurrent later */
1681 CRASSERT(cr_server.numClients);
1682 cr_server.curClient = cr_server.clients[0];
1683 }
1684
1685 rc = crStateLoadGlobals(pSSM, version);
1686 AssertRCReturn(rc, rc);
1687
1688 /* Restore context state data */
1689 for (ui=0; ui<uiNumElems; ++ui)
1690 {
1691 CRContextInfo* pContextInfo;
1692 CRContext *pContext;
1693 CRMuralInfo *pMural = NULL;
1694 int32_t winId = 0;
1695
1696 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1697 AssertRCReturn(rc, rc);
1698
1699 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1700 CRASSERT(pContextInfo);
1701 CRASSERT(pContextInfo->pContext);
1702 pContext = pContextInfo->pContext;
1703
1704 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1705 {
1706 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
1707 AssertRCReturn(rc, rc);
1708
1709 if (winId)
1710 {
1711 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
1712 CRASSERT(pMural);
1713 }
1714 else
1715 {
1716 /* null winId means a dummy mural, get it */
1717 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
1718 CRASSERT(pMural);
1719 }
1720
1721 crServerPerformMakeCurrent(pMural, pContextInfo);
1722 }
1723
1724 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
1725 AssertRCReturn(rc, rc);
1726
1727 /*Restore front/back buffer images*/
1728 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1729 AssertRCReturn(rc, rc);
1730 }
1731
1732 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1733 {
1734 CRContextInfo *pContextInfo;
1735 CRMuralInfo *pMural;
1736 GLint ctxId;
1737
1738 rc = SSMR3GetU32(pSSM, &uiNumElems);
1739 AssertRCReturn(rc, rc);
1740 for (ui=0; ui<uiNumElems; ++ui)
1741 {
1742 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1743 CRMuralInfo *pInitialCurMural;
1744
1745 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1746 AssertRCReturn(rc, rc);
1747
1748 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
1749 AssertRCReturn(rc, rc);
1750
1751 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1752 CRASSERT(pMural);
1753 if (ctxId)
1754 {
1755 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
1756 CRASSERT(pContextInfo);
1757 }
1758 else
1759 pContextInfo = &cr_server.MainContextInfo;
1760
1761 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1762 pInitialCurMural = pContextInfo->currentMural;
1763
1764 crServerPerformMakeCurrent(pMural, pContextInfo);
1765
1766 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1767 AssertRCReturn(rc, rc);
1768
1769 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1770 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1771 pContextInfo->currentMural = pInitialCurMural;
1772 }
1773
1774 if (cr_server.currentCtxInfo != &cr_server.MainContextInfo)
1775 {
1776 /* most ogl data gets loaded to hw on chromium 3D state switch, i.e. inside crStateMakeCurrent -> crStateSwitchContext
1777 * to force the crStateSwitchContext being called later, we need to set the current context to our dummy one */
1778 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
1779 CRASSERT(pMural);
1780 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
1781 }
1782
1783 cr_server.curClient = NULL;
1784 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1785 }
1786 else
1787 {
1788 CRServerFreeIDsPool_t dummyIdsPool;
1789
1790 /* we have a mural data here */
1791 rc = crVBoxServerLoadMurals(pSSM, version);
1792 AssertRCReturn(rc, rc);
1793
1794 /* not used any more, just read it out and ignore */
1795 rc = SSMR3GetMem(pSSM, &dummyIdsPool, sizeof(dummyIdsPool));
1796 CRASSERT(rc == VINF_SUCCESS);
1797 }
1798
1799 /* Load clients info */
1800 for (i = 0; i < cr_server.numClients; i++)
1801 {
1802 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1803 {
1804 CRClient *pClient = cr_server.clients[i];
1805 CRClient client;
1806 unsigned long ctxID=-1, winID=-1;
1807
1808 rc = SSMR3GetU32(pSSM, &ui);
1809 AssertRCReturn(rc, rc);
1810 /* If this assert fires, then we should search correct client in the list first*/
1811 CRASSERT(ui == pClient->conn->u32ClientID);
1812
1813 if (version>=4)
1814 {
1815 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
1816 AssertRCReturn(rc, rc);
1817
1818 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
1819 AssertRCReturn(rc, rc);
1820 }
1821
1822 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
1823 CRASSERT(rc == VINF_SUCCESS);
1824
1825 client.conn = pClient->conn;
1826 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
1827 * and fail to bind old textures.
1828 */
1829 /*client.number = pClient->number;*/
1830 *pClient = client;
1831
1832 pClient->currentContextNumber = -1;
1833 pClient->currentCtxInfo = &cr_server.MainContextInfo;
1834 pClient->currentMural = NULL;
1835 pClient->currentWindow = -1;
1836
1837 cr_server.curClient = pClient;
1838
1839 if (client.currentCtxInfo && client.currentContextNumber>=0)
1840 {
1841 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
1842 AssertRCReturn(rc, rc);
1843 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
1844 CRASSERT(client.currentCtxInfo);
1845 CRASSERT(client.currentCtxInfo->pContext);
1846 //pClient->currentCtx = client.currentCtx;
1847 //pClient->currentContextNumber = ctxID;
1848 }
1849
1850 if (client.currentMural && client.currentWindow>=0)
1851 {
1852 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
1853 AssertRCReturn(rc, rc);
1854 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
1855 CRASSERT(client.currentMural);
1856 //pClient->currentMural = client.currentMural;
1857 //pClient->currentWindow = winID;
1858 }
1859
1860 /* Restore client active context and window */
1861 crServerDispatchMakeCurrent(winID, 0, ctxID);
1862
1863 if (0)
1864 {
1865// CRContext *tmpCtx;
1866// CRCreateInfo_t *createInfo;
1867 GLfloat one[4] = { 1, 1, 1, 1 };
1868 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
1869
1870 crServerDispatchMakeCurrent(winID, 0, ctxID);
1871
1872 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
1873
1874 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
1875 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
1876 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
1877#ifdef CR_ARB_texture_cube_map
1878 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
1879#endif
1880#ifdef CR_NV_texture_rectangle
1881 //@todo this doesn't work as expected
1882 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
1883#endif
1884 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
1885 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
1886 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
1887
1888 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
1889 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
1890 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
1891
1892 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
1893 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
1894
1895 //crStateViewport( 0, 0, 600, 600 );
1896 //pClient->currentMural->viewportValidated = GL_FALSE;
1897 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
1898
1899 //crStateMatrixMode(GL_PROJECTION);
1900 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
1901
1902 //crStateLoadIdentity();
1903 //cr_server.head_spu->dispatch_table.LoadIdentity();
1904
1905 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1906 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1907
1908 //crStateMatrixMode(GL_MODELVIEW);
1909 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
1910 //crServerDispatchLoadIdentity();
1911 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1912 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1913 //crServerDispatchLoadIdentity();
1914
1915 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
1916 CRASSERT(createInfo);
1917 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
1918 CRASSERT(tmpCtx);
1919 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
1920 crStateDestroyContext(tmpCtx);*/
1921 }
1922 }
1923 }
1924
1925 //crServerDispatchMakeCurrent(-1, 0, -1);
1926
1927 cr_server.curClient = NULL;
1928
1929 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1930 crWarning("crServer: glGetError %d after loading snapshot", err);
1931
1932 cr_server.bIsInLoadingState = GL_FALSE;
1933
1934#if 0
1935 crVBoxServerCheckConsistency();
1936#endif
1937
1938 return VINF_SUCCESS;
1939}
1940
1941#define SCREEN(i) (cr_server.screen[i])
1942#define MAPPED(screen) ((screen).winID != 0)
1943
1944static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
1945{
1946 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1947 int *sIndex = (int*) data2;
1948
1949 if (pMI->screenId == *sIndex)
1950 {
1951 renderspuReparentWindow(pMI->spuWindow);
1952 }
1953}
1954
1955static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
1956{
1957 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1958 (void) data2;
1959
1960 crServerCheckMuralGeometry(pMI);
1961}
1962
1963DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
1964{
1965 int i;
1966
1967 if (sCount>CR_MAX_GUEST_MONITORS)
1968 return VERR_INVALID_PARAMETER;
1969
1970 /*Shouldn't happen yet, but to be safe in future*/
1971 for (i=0; i<cr_server.screenCount; ++i)
1972 {
1973 if (MAPPED(SCREEN(i)))
1974 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
1975 return VERR_NOT_IMPLEMENTED;
1976 }
1977
1978 cr_server.screenCount = sCount;
1979
1980 for (i=0; i<sCount; ++i)
1981 {
1982 SCREEN(i).winID = 0;
1983 }
1984
1985 return VINF_SUCCESS;
1986}
1987
1988DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
1989{
1990 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
1991
1992 if (sIndex<0 || sIndex>=cr_server.screenCount)
1993 return VERR_INVALID_PARAMETER;
1994
1995 if (MAPPED(SCREEN(sIndex)))
1996 {
1997 SCREEN(sIndex).winID = 0;
1998 renderspuSetWindowId(0);
1999
2000 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2001 }
2002
2003 renderspuSetWindowId(SCREEN(0).winID);
2004 return VINF_SUCCESS;
2005}
2006
2007DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2008{
2009 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2010
2011 if (sIndex<0 || sIndex>=cr_server.screenCount)
2012 return VERR_INVALID_PARAMETER;
2013
2014 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2015 {
2016 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2017 crVBoxServerUnmapScreen(sIndex);
2018 }
2019
2020 SCREEN(sIndex).winID = winID;
2021 SCREEN(sIndex).x = x;
2022 SCREEN(sIndex).y = y;
2023 SCREEN(sIndex).w = w;
2024 SCREEN(sIndex).h = h;
2025
2026 renderspuSetWindowId(SCREEN(sIndex).winID);
2027 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2028 renderspuSetWindowId(SCREEN(0).winID);
2029
2030 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2031
2032#ifndef WINDOWS
2033 /*Restore FB content for clients, which have current window on a screen being remapped*/
2034 {
2035 GLint i;
2036
2037 for (i = 0; i < cr_server.numClients; i++)
2038 {
2039 cr_server.curClient = cr_server.clients[i];
2040 if (cr_server.curClient->currentCtxInfo
2041 && cr_server.curClient->currentCtxInfo->pContext
2042 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg || cr_server.curClient->currentCtxInfo->pContext->buffer.pBackImg)
2043 && cr_server.curClient->currentMural
2044 && cr_server.curClient->currentMural->screenId == sIndex
2045 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2046 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2047 {
2048 int clientWindow = cr_server.curClient->currentWindow;
2049 int clientContext = cr_server.curClient->currentContextNumber;
2050
2051 if (clientWindow && clientWindow != cr_server.currentWindow)
2052 {
2053 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2054 }
2055
2056 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext);
2057 }
2058 }
2059 cr_server.curClient = NULL;
2060 }
2061#endif
2062
2063 {
2064 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
2065 if (pDisplay)
2066 CrDpResize(pDisplay, w, h, w, h);
2067 }
2068
2069 return VINF_SUCCESS;
2070}
2071
2072DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
2073{
2074 renderspuSetRootVisibleRegion(cRects, pRects);
2075
2076 return VINF_SUCCESS;
2077}
2078
2079DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2080{
2081 cr_server.pfnPresentFBO = pfnPresentFBO;
2082}
2083
2084int32_t crServerSetOffscreenRenderingMode(GLubyte value)
2085{
2086 if (cr_server.bForceOffscreenRendering==value)
2087 {
2088 return VINF_SUCCESS;
2089 }
2090
2091 if (value > CR_SERVER_REDIR_MAXVAL)
2092 {
2093 crWarning("crServerSetOffscreenRenderingMode: invalid arg: %d", value);
2094 return VERR_INVALID_PARAMETER;
2095 }
2096
2097 if (value && !crServerSupportRedirMuralFBO())
2098 {
2099 return VERR_NOT_SUPPORTED;
2100 }
2101
2102 cr_server.bForceOffscreenRendering=value;
2103
2104 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2105
2106 return VINF_SUCCESS;
2107}
2108
2109DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2110{
2111 return crServerSetOffscreenRenderingMode(value ? CR_SERVER_REDIR_FBO_RAM : cr_server.bOffscreenRenderingDefault);
2112}
2113
2114DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2115{
2116 /* No need for a synchronization as this is single threaded. */
2117 if (pCallbacks)
2118 {
2119 cr_server.outputRedirect = *pCallbacks;
2120 cr_server.bUseOutputRedirect = true;
2121 }
2122 else
2123 {
2124 cr_server.bUseOutputRedirect = false;
2125 }
2126
2127 // @todo dynamically intercept already existing output:
2128 // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
2129
2130 return VINF_SUCCESS;
2131}
2132
2133static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2)
2134{
2135 CRMuralInfo *mural = (CRMuralInfo*) data1;
2136 int *sIndex = (int*) data2;
2137
2138 if (mural->screenId != *sIndex)
2139 return;
2140
2141 crServerCheckMuralGeometry(mural);
2142}
2143
2144
2145DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2146{
2147 CRScreenViewportInfo *pVieport;
2148 GLboolean fPosChanged, fSizeChanged;
2149
2150 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2151
2152 if (sIndex<0 || sIndex>=cr_server.screenCount)
2153 {
2154 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2155 return VERR_INVALID_PARAMETER;
2156 }
2157
2158 pVieport = &cr_server.screenVieport[sIndex];
2159 fPosChanged = (pVieport->x != x || pVieport->y != y);
2160 fSizeChanged = (pVieport->w != w || pVieport->h != h);
2161
2162 if (!fPosChanged && !fSizeChanged)
2163 {
2164 crDebug("crVBoxServerSetScreenViewport: no changes");
2165 return VINF_SUCCESS;
2166 }
2167
2168 if (fPosChanged)
2169 {
2170 pVieport->x = x;
2171 pVieport->y = y;
2172
2173 crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex);
2174 }
2175
2176 if (fSizeChanged)
2177 {
2178 pVieport->w = w;
2179 pVieport->h = h;
2180
2181 /* no need to do anything here actually */
2182 }
2183 return VINF_SUCCESS;
2184}
2185
2186
2187#ifdef VBOX_WITH_CRHGSMI
2188/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
2189 *
2190 * 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.
2191 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
2192 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
2193 * to block the lower-priority thread trying to complete the blocking command.
2194 * And removed extra memcpy done on blocked command arrival.
2195 *
2196 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
2197 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
2198 *
2199 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
2200 * */
2201int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
2202{
2203 int32_t rc;
2204 uint32_t cBuffers = pCmd->cBuffers;
2205 uint32_t cParams;
2206 uint32_t cbHdr;
2207 CRVBOXHGSMIHDR *pHdr;
2208 uint32_t u32Function;
2209 uint32_t u32ClientID;
2210 CRClient *pClient;
2211
2212 if (!g_pvVRamBase)
2213 {
2214 crWarning("g_pvVRamBase is not initialized");
2215 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
2216 return VINF_SUCCESS;
2217 }
2218
2219 if (!cBuffers)
2220 {
2221 crWarning("zero buffers passed in!");
2222 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2223 return VINF_SUCCESS;
2224 }
2225
2226 cParams = cBuffers-1;
2227
2228 cbHdr = pCmd->aBuffers[0].cbBuffer;
2229 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2230 if (!pHdr)
2231 {
2232 crWarning("invalid header buffer!");
2233 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2234 return VINF_SUCCESS;
2235 }
2236
2237 if (cbHdr < sizeof (*pHdr))
2238 {
2239 crWarning("invalid header buffer size!");
2240 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2241 return VINF_SUCCESS;
2242 }
2243
2244 u32Function = pHdr->u32Function;
2245 u32ClientID = pHdr->u32ClientID;
2246
2247 switch (u32Function)
2248 {
2249 case SHCRGL_GUEST_FN_WRITE:
2250 {
2251 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2252
2253 /* @todo: Verify */
2254 if (cParams == 1)
2255 {
2256 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2257 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2258 /* Fetch parameters. */
2259 uint32_t cbBuffer = pBuf->cbBuffer;
2260 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2261
2262 if (cbHdr < sizeof (*pFnCmd))
2263 {
2264 crWarning("invalid write cmd buffer size!");
2265 rc = VERR_INVALID_PARAMETER;
2266 break;
2267 }
2268
2269 CRASSERT(cbBuffer);
2270 if (!pBuffer)
2271 {
2272 crWarning("invalid buffer data received from guest!");
2273 rc = VERR_INVALID_PARAMETER;
2274 break;
2275 }
2276
2277 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2278 if (RT_FAILURE(rc))
2279 {
2280 break;
2281 }
2282
2283 /* This should never fire unless we start to multithread */
2284 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2285 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2286
2287 pClient->conn->pBuffer = pBuffer;
2288 pClient->conn->cbBuffer = cbBuffer;
2289 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2290 rc = crVBoxServerInternalClientWriteRead(pClient);
2291 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2292 return rc;
2293 }
2294 else
2295 {
2296 crWarning("invalid number of args");
2297 rc = VERR_INVALID_PARAMETER;
2298 break;
2299 }
2300 break;
2301 }
2302
2303 case SHCRGL_GUEST_FN_INJECT:
2304 {
2305 crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2306
2307 /* @todo: Verify */
2308 if (cParams == 1)
2309 {
2310 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2311 /* Fetch parameters. */
2312 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2313 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2314 uint32_t cbBuffer = pBuf->cbBuffer;
2315 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2316
2317 if (cbHdr < sizeof (*pFnCmd))
2318 {
2319 crWarning("invalid inject cmd buffer size!");
2320 rc = VERR_INVALID_PARAMETER;
2321 break;
2322 }
2323
2324 CRASSERT(cbBuffer);
2325 if (!pBuffer)
2326 {
2327 crWarning("invalid buffer data received from guest!");
2328 rc = VERR_INVALID_PARAMETER;
2329 break;
2330 }
2331
2332 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
2333 if (RT_FAILURE(rc))
2334 {
2335 break;
2336 }
2337
2338 /* This should never fire unless we start to multithread */
2339 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2340 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2341
2342 pClient->conn->pBuffer = pBuffer;
2343 pClient->conn->cbBuffer = cbBuffer;
2344 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2345 rc = crVBoxServerInternalClientWriteRead(pClient);
2346 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2347 return rc;
2348 }
2349
2350 crWarning("invalid number of args");
2351 rc = VERR_INVALID_PARAMETER;
2352 break;
2353 }
2354
2355 case SHCRGL_GUEST_FN_READ:
2356 {
2357 crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n"));
2358
2359 /* @todo: Verify */
2360 if (cParams == 1)
2361 {
2362 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
2363 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2364 /* Fetch parameters. */
2365 uint32_t cbBuffer = pBuf->cbBuffer;
2366 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2367
2368 if (cbHdr < sizeof (*pFnCmd))
2369 {
2370 crWarning("invalid read cmd buffer size!");
2371 rc = VERR_INVALID_PARAMETER;
2372 break;
2373 }
2374
2375
2376 if (!pBuffer)
2377 {
2378 crWarning("invalid buffer data received from guest!");
2379 rc = VERR_INVALID_PARAMETER;
2380 break;
2381 }
2382
2383 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2384 if (RT_FAILURE(rc))
2385 {
2386 break;
2387 }
2388
2389 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2390
2391 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
2392
2393 /* Return the required buffer size always */
2394 pFnCmd->cbBuffer = cbBuffer;
2395
2396 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2397
2398 /* the read command is never pended, complete it right away */
2399 pHdr->result = rc;
2400 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2401 return VINF_SUCCESS;
2402 }
2403
2404 crWarning("invalid number of args");
2405 rc = VERR_INVALID_PARAMETER;
2406 break;
2407 }
2408
2409 case SHCRGL_GUEST_FN_WRITE_READ:
2410 {
2411 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
2412
2413 /* @todo: Verify */
2414 if (cParams == 2)
2415 {
2416 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
2417 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2418 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
2419
2420 /* Fetch parameters. */
2421 uint32_t cbBuffer = pBuf->cbBuffer;
2422 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2423
2424 uint32_t cbWriteback = pWbBuf->cbBuffer;
2425 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
2426
2427 if (cbHdr < sizeof (*pFnCmd))
2428 {
2429 crWarning("invalid write_read cmd buffer size!");
2430 rc = VERR_INVALID_PARAMETER;
2431 break;
2432 }
2433
2434
2435 CRASSERT(cbBuffer);
2436 if (!pBuffer)
2437 {
2438 crWarning("invalid write buffer data received from guest!");
2439 rc = VERR_INVALID_PARAMETER;
2440 break;
2441 }
2442
2443 CRASSERT(cbWriteback);
2444 if (!pWriteback)
2445 {
2446 crWarning("invalid writeback buffer data received from guest!");
2447 rc = VERR_INVALID_PARAMETER;
2448 break;
2449 }
2450 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2451 if (RT_FAILURE(rc))
2452 {
2453 pHdr->result = rc;
2454 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2455 return rc;
2456 }
2457
2458 /* This should never fire unless we start to multithread */
2459 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2460 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2461
2462 pClient->conn->pBuffer = pBuffer;
2463 pClient->conn->cbBuffer = cbBuffer;
2464 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
2465 rc = crVBoxServerInternalClientWriteRead(pClient);
2466 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2467 return rc;
2468 }
2469
2470 crWarning("invalid number of args");
2471 rc = VERR_INVALID_PARAMETER;
2472 break;
2473 }
2474
2475 case SHCRGL_GUEST_FN_SET_VERSION:
2476 {
2477 crWarning("invalid function");
2478 rc = VERR_NOT_IMPLEMENTED;
2479 break;
2480 }
2481
2482 case SHCRGL_GUEST_FN_SET_PID:
2483 {
2484 crWarning("invalid function");
2485 rc = VERR_NOT_IMPLEMENTED;
2486 break;
2487 }
2488
2489 default:
2490 {
2491 crWarning("invalid function");
2492 rc = VERR_NOT_IMPLEMENTED;
2493 break;
2494 }
2495
2496 }
2497
2498 /* we can be on fail only here */
2499 CRASSERT(RT_FAILURE(rc));
2500 pHdr->result = rc;
2501 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2502 return rc;
2503}
2504
2505int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
2506{
2507 int rc = VINF_SUCCESS;
2508
2509 switch (pCtl->enmType)
2510 {
2511 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
2512 {
2513 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
2514 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
2515 g_cbVRam = pSetup->cbVRam;
2516 rc = VINF_SUCCESS;
2517 break;
2518 }
2519 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
2520 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
2521 rc = VINF_SUCCESS;
2522 break;
2523 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
2524 {
2525 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
2526 g_hCrHgsmiCompletion = pSetup->hCompletion;
2527 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
2528 rc = VINF_SUCCESS;
2529 break;
2530 }
2531 default:
2532 AssertMsgFailed(("invalid param %d", pCtl->enmType));
2533 rc = VERR_INVALID_PARAMETER;
2534 }
2535
2536 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
2537 * to complete them accordingly.
2538 * This approach allows using host->host and host->guest commands in the same way here
2539 * making the command completion to be the responsibility of the command originator.
2540 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
2541 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
2542 return rc;
2543}
2544#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