VirtualBox

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

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

crOpenGL: fix server cleanup

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