VirtualBox

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

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

crOpenGL: saved state: save depth and stencil buffer data (still needs more testing)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 84.8 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 = 0;
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 crFreeHashtable(Data.usedMuralTable, NULL);
996}
997
998static void crVBoxServerFBImageDataTerm(CRFBData *pData)
999{
1000 GLuint i;
1001 for (i = 0; i < pData->cElements; ++i)
1002 {
1003 CRFBDataElement * pEl = &pData->aElements[i];
1004 if (pEl->pvData)
1005 {
1006 crFree(pEl->pvData);
1007 /* sanity */
1008 pEl->pvData = NULL;
1009 }
1010 }
1011 pData->cElements = 0;
1012}
1013
1014static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, GLboolean fForceBackFrontOnly, GLuint overrideWidth, GLuint overrideHeight)
1015{
1016 CRContext *pContext;
1017 GLuint i;
1018 GLfloat *pF;
1019 CRFBDataElement *pEl;
1020 GLuint width;
1021 GLuint height;
1022
1023 CRASSERT(pCtxInfo->currentMural);
1024
1025 crMemset(pData, 0, sizeof (*pData));
1026
1027 pContext = pCtxInfo->pContext;
1028
1029 width = overrideWidth ? overrideWidth : pMural->width;
1030 height = overrideHeight ? overrideHeight : pMural->height;
1031
1032 if (!width || !height)
1033 return VINF_SUCCESS;
1034
1035 pData->idFBO = pMural->fUseFBO ? pMural->aidColorTexs[fWrite ? pMural->iCurDrawBuffer : pMural->iCurReadBuffer] : 0;
1036 pData->cElements = 0;
1037
1038 pEl = &pData->aElements[pData->cElements];
1039 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1040 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT;
1041 pEl->posX = 0;
1042 pEl->posY = 0;
1043 pEl->width = width;
1044 pEl->height = height;
1045 pEl->enmFormat = GL_RGBA;
1046 pEl->enmType = GL_UNSIGNED_BYTE;
1047 pEl->cbData = width * height * 4;
1048 pEl->pvData = crCalloc(pEl->cbData);
1049 if (!pEl->pvData)
1050 {
1051 crVBoxServerFBImageDataTerm(pData);
1052 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1053 return VERR_NO_MEMORY;
1054 }
1055 ++pData->cElements;
1056
1057 /* there is a lot of code that assumes we have double buffering, just assert here to print a warning in the log
1058 * so that we know that something irregular is going on */
1059 CRASSERT(pCtxInfo->CreateInfo.visualBits && CR_DOUBLE_BIT);
1060 if ((pCtxInfo->CreateInfo.visualBits && CR_DOUBLE_BIT) || fForceBackFrontOnly)
1061 {
1062 pEl = &pData->aElements[pData->cElements];
1063 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0;
1064 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK;
1065 pEl->posX = 0;
1066 pEl->posY = 0;
1067 pEl->width = width;
1068 pEl->height = height;
1069 pEl->enmFormat = GL_RGBA;
1070 pEl->enmType = GL_UNSIGNED_BYTE;
1071 pEl->cbData = width * height * 4;
1072 pEl->pvData = crCalloc(pEl->cbData);
1073 if (!pEl->pvData)
1074 {
1075 crVBoxServerFBImageDataTerm(pData);
1076 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1077 return VERR_NO_MEMORY;
1078 }
1079 ++pData->cElements;
1080 }
1081
1082 if (!fForceBackFrontOnly)
1083 {
1084 if (pCtxInfo->CreateInfo.visualBits && CR_DEPTH_BIT)
1085 {
1086 AssertCompile(sizeof (GLfloat) == 4);
1087 pEl = &pData->aElements[pData->cElements];
1088 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1089 pEl->enmBuffer = 0; /* we do not care */
1090 pEl->posX = 0;
1091 pEl->posY = 0;
1092 pEl->width = width;
1093 pEl->height = height;
1094 pEl->enmFormat = GL_DEPTH_COMPONENT;
1095 pEl->enmType = GL_FLOAT;
1096 pEl->cbData = width * height * 4;
1097 pEl->pvData = crCalloc(pEl->cbData);
1098 if (!pEl->pvData)
1099 {
1100 crVBoxServerFBImageDataTerm(pData);
1101 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1102 return VERR_NO_MEMORY;
1103 }
1104
1105 /* init to default depth value, just in case */
1106 pF = (GLfloat*)pEl->pvData;
1107 for (i = 0; i < width * height; ++i)
1108 {
1109 pF[i] = 1.;
1110 }
1111 ++pData->cElements;
1112 }
1113
1114 if (pCtxInfo->CreateInfo.visualBits && CR_STENCIL_BIT)
1115 {
1116 AssertCompile(sizeof (GLuint) == 4);
1117 pEl = &pData->aElements[pData->cElements];
1118 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1119 pEl->enmBuffer = 0; /* we do not care */
1120 pEl->posX = 0;
1121 pEl->posY = 0;
1122 pEl->width = width;
1123 pEl->height = height;
1124 pEl->enmFormat = GL_STENCIL_INDEX;
1125 pEl->enmType = GL_UNSIGNED_INT;
1126 pEl->cbData = width * height * 4;
1127 pEl->pvData = crCalloc(pEl->cbData);
1128 if (!pEl->pvData)
1129 {
1130 crVBoxServerFBImageDataTerm(pData);
1131 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1132 return VERR_NO_MEMORY;
1133 }
1134 ++pData->cElements;
1135 }
1136 }
1137 return VINF_SUCCESS;
1138}
1139
1140static int crVBoxServerFBImageDataInit(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite)
1141{
1142 return crVBoxServerFBImageDataInitEx(pData, pCtxInfo, pMural, fWrite, GL_FALSE, 0, 0);
1143}
1144
1145static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
1146{
1147 CRContextInfo *pCtxInfo;
1148 CRContext *pContext;
1149 CRMuralInfo *pMural;
1150 int32_t rc;
1151 GLuint i;
1152 struct
1153 {
1154 CRFBData data;
1155 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1156 } Data;
1157
1158 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1159
1160 pCtxInfo = cr_server.currentCtxInfo;
1161 pContext = pCtxInfo->pContext;
1162 pMural = pCtxInfo->currentMural;
1163
1164 rc = crVBoxServerFBImageDataInit(&Data.data, pCtxInfo, pMural, GL_FALSE);
1165 if (!RT_SUCCESS(rc))
1166 {
1167 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1168 return rc;
1169 }
1170
1171 rc = crStateAcquireFBImage(pContext, &Data.data);
1172 AssertRCReturn(rc, rc);
1173
1174 for (i = 0; i < Data.data.cElements; ++i)
1175 {
1176 CRFBDataElement * pEl = &Data.data.aElements[i];
1177 rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
1178 AssertRCReturn(rc, rc);
1179 }
1180
1181 crVBoxServerFBImageDataTerm(&Data.data);
1182
1183 return VINF_SUCCESS;
1184}
1185
1186#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
1187 if(!RT_SUCCESS((_rc))) { \
1188 AssertFailed(); \
1189 return; \
1190 } \
1191 } while (0)
1192
1193static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
1194{
1195 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1196 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1197 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1198 PSSMHANDLE pSSM = pData->pSSM;
1199 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1200 CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
1201
1202 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1203
1204 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1205
1206 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1207 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1208
1209 pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
1210 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1211
1212 crServerPerformMakeCurrent(pMural, pContextInfo);
1213
1214 pData->rc = crVBoxServerSaveFBImage(pSSM);
1215
1216 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1217 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1218 pContextInfo->currentMural = pInitialCurMural;
1219
1220 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1221}
1222
1223static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
1224{
1225 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1226 CRContext *pContext = pContextInfo->pContext;
1227 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1228 PSSMHANDLE pSSM = pData->pSSM;
1229 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
1230 CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
1231 const int32_t i32Dummy = 0;
1232
1233 AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
1234 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1235
1236 CRASSERT(pContext && pSSM);
1237 CRASSERT(pMural);
1238 CRASSERT(pMural->CreateInfo.externalID);
1239
1240 /* We could have skipped saving the key and use similar callback to load context states back,
1241 * but there's no guarantee we'd traverse hashtable in same order after loading.
1242 */
1243 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1244 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1245
1246#ifdef DEBUG_misha
1247 {
1248 unsigned long id;
1249 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
1250 crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
1251 else
1252 CRASSERT(id == key);
1253 }
1254#endif
1255
1256#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1257 if (pContextInfo->currentMural
1258 || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
1259 )
1260 {
1261 CRASSERT(pMural->CreateInfo.externalID);
1262 CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1263 pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
1264 }
1265 else
1266 {
1267 /* this is a dummy mural */
1268 CRASSERT(!pMural->width);
1269 CRASSERT(!pMural->height);
1270 CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1271 pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
1272 }
1273 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1274
1275 CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
1276 CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
1277 CRASSERT(cr_server.curClient);
1278
1279 crServerPerformMakeCurrent(pMural, pContextInfo);
1280#endif
1281
1282 pData->rc = crStateSaveContext(pContext, pSSM);
1283 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1284
1285 pData->rc = crVBoxServerSaveFBImage(pSSM);
1286 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1287
1288 /* restore the initial current mural */
1289 pContextInfo->currentMural = pContextCurrentMural;
1290}
1291
1292#if 0
1293typedef struct CR_SERVER_CHECK_BUFFERS
1294{
1295 CRBufferObject *obj;
1296 CRContext *ctx;
1297}CR_SERVER_CHECK_BUFFERS, *PCR_SERVER_CHECK_BUFFERS;
1298
1299static void crVBoxServerCheckConsistencyContextBuffersCB(unsigned long key, void *data1, void *data2)
1300{
1301 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1302 CRContext *ctx = pContextInfo->pContext;
1303 PCR_SERVER_CHECK_BUFFERS pBuffers = (PCR_SERVER_CHECK_BUFFERS)data2;
1304 CRBufferObject *obj = pBuffers->obj;
1305 CRBufferObjectState *b = &(ctx->bufferobject);
1306 int j, k;
1307
1308 if (obj == b->arrayBuffer)
1309 {
1310 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1311 pBuffers->ctx = ctx;
1312 }
1313 if (obj == b->elementsBuffer)
1314 {
1315 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1316 pBuffers->ctx = ctx;
1317 }
1318#ifdef CR_ARB_pixel_buffer_object
1319 if (obj == b->packBuffer)
1320 {
1321 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1322 pBuffers->ctx = ctx;
1323 }
1324 if (obj == b->unpackBuffer)
1325 {
1326 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1327 pBuffers->ctx = ctx;
1328 }
1329#endif
1330
1331#ifdef CR_ARB_vertex_buffer_object
1332 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1333 {
1334 CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array);
1335 if (obj == cp->buffer)
1336 {
1337 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1338 pBuffers->ctx = ctx;
1339 }
1340 }
1341
1342 for (k=0; k<ctx->client.vertexArrayStackDepth; ++k)
1343 {
1344 CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k];
1345 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1346 {
1347 CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray);
1348 if (obj == cp->buffer)
1349 {
1350 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1351 pBuffers->ctx = ctx;
1352 }
1353 }
1354 }
1355#endif
1356}
1357
1358static void crVBoxServerCheckConsistencyBuffersCB(unsigned long key, void *data1, void *data2)
1359{
1360 CRBufferObject *obj = (CRBufferObject *)data1;
1361 CR_SERVER_CHECK_BUFFERS Buffers = {0};
1362 Buffers.obj = obj;
1363 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckConsistencyContextBuffersCB, (void*)&Buffers);
1364}
1365
1366//static void crVBoxServerCheckConsistency2CB(unsigned long key, void *data1, void *data2)
1367//{
1368// CRContextInfo* pContextInfo1 = (CRContextInfo*)data1;
1369// CRContextInfo* pContextInfo2 = (CRContextInfo*)data2;
1370//
1371// CRASSERT(pContextInfo1->pContext);
1372// CRASSERT(pContextInfo2->pContext);
1373//
1374// if (pContextInfo1 == pContextInfo2)
1375// {
1376// CRASSERT(pContextInfo1->pContext == pContextInfo2->pContext);
1377// return;
1378// }
1379//
1380// CRASSERT(pContextInfo1->pContext != pContextInfo2->pContext);
1381// CRASSERT(pContextInfo1->pContext->shared);
1382// CRASSERT(pContextInfo2->pContext->shared);
1383// CRASSERT(pContextInfo1->pContext->shared == pContextInfo2->pContext->shared);
1384// if (pContextInfo1->pContext->shared != pContextInfo2->pContext->shared)
1385// return;
1386//
1387// crHashtableWalk(pContextInfo1->pContext->shared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, pContextInfo2);
1388//}
1389static void crVBoxServerCheckSharedCB(unsigned long key, void *data1, void *data2)
1390{
1391 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1392 void **ppShared = (void**)data2;
1393 if (!*ppShared)
1394 *ppShared = pContextInfo->pContext->shared;
1395 else
1396 Assert(pContextInfo->pContext->shared == *ppShared);
1397}
1398
1399static void crVBoxServerCheckConsistency()
1400{
1401 CRSharedState *pShared = NULL;
1402 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckSharedCB, (void*)&pShared);
1403 Assert(pShared);
1404 if (pShared)
1405 {
1406 crHashtableWalk(pShared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, NULL);
1407 }
1408}
1409#endif
1410
1411static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
1412
1413DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
1414{
1415 int32_t rc, i;
1416 uint32_t ui32;
1417 GLboolean b;
1418 unsigned long key;
1419 GLenum err;
1420#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1421 CRClient *curClient;
1422 CRMuralInfo *curMural = NULL;
1423 CRContextInfo *curCtxInfo = NULL;
1424#endif
1425 CRVBOX_SAVE_STATE_GLOBAL Data;
1426
1427 crMemset(&Data, 0, sizeof (Data));
1428
1429#if 0
1430 crVBoxServerCheckConsistency();
1431#endif
1432
1433 /* We shouldn't be called if there's no clients at all*/
1434 CRASSERT(cr_server.numClients>0);
1435
1436 /* @todo it's hack atm */
1437 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1438 * for every connected client (e.g. guest opengl application)
1439 */
1440 if (!cr_server.bIsInSavingState) /* It's first call */
1441 {
1442 cr_server.bIsInSavingState = GL_TRUE;
1443
1444 /* Store number of clients */
1445 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1446 AssertRCReturn(rc, rc);
1447
1448 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
1449 }
1450
1451 g_hackVBoxServerSaveLoadCallsLeft--;
1452
1453 /* Do nothing until we're being called last time */
1454 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1455 {
1456 return VINF_SUCCESS;
1457 }
1458
1459 /* Save rendering contexts creation info */
1460 ui32 = crHashtableNumElements(cr_server.contextTable);
1461 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1462 AssertRCReturn(rc, rc);
1463 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1464
1465#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1466 curClient = cr_server.curClient;
1467 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1468 if (curClient)
1469 {
1470 curCtxInfo = cr_server.curClient->currentCtxInfo;
1471 curMural = cr_server.curClient->currentMural;
1472 }
1473 else if (cr_server.numClients)
1474 {
1475 cr_server.curClient = cr_server.clients[0];
1476 }
1477#endif
1478
1479 /* first save windows info */
1480 /* Save windows creation info */
1481 ui32 = crHashtableNumElements(cr_server.muralTable);
1482 /* There should be default mural always */
1483 CRASSERT(ui32>=1);
1484 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1485 AssertRCReturn(rc, rc);
1486 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1487
1488 /* Save cr_server.muralTable
1489 * @todo we don't need it all, just geometry info actually
1490 */
1491 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1492 AssertRCReturn(rc, rc);
1493 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1494
1495 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1496 crVBoxServerBuildSaveStateGlobal(&Data);
1497
1498 rc = crStateSaveGlobals(pSSM);
1499 AssertRCReturn(rc, rc);
1500
1501 Data.pSSM = pSSM;
1502 /* Save contexts state tracker data */
1503 /* @todo For now just some blind data dumps,
1504 * but I've a feeling those should be saved/restored in a very strict sequence to
1505 * allow diff_api to work correctly.
1506 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1507 */
1508 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1509 AssertRCReturn(Data.rc, Data.rc);
1510
1511 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1512 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1513 AssertRCReturn(rc, rc);
1514
1515 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1516 AssertRCReturn(Data.rc, Data.rc);
1517
1518#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1519 cr_server.curClient = curClient;
1520 /* Restore original win and ctx IDs*/
1521 if (curClient && curMural && curCtxInfo)
1522 {
1523 crServerPerformMakeCurrent(curMural, curCtxInfo);
1524 }
1525 else
1526 {
1527 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1528 }
1529#endif
1530
1531 /* Save clients info */
1532 for (i = 0; i < cr_server.numClients; i++)
1533 {
1534 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1535 {
1536 CRClient *pClient = cr_server.clients[i];
1537
1538 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1539 AssertRCReturn(rc, rc);
1540
1541 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1542 AssertRCReturn(rc, rc);
1543
1544 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1545 AssertRCReturn(rc, rc);
1546
1547 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1548 AssertRCReturn(rc, rc);
1549
1550 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0)
1551 {
1552 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1553 CRASSERT(b);
1554 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1555 AssertRCReturn(rc, rc);
1556 }
1557
1558 if (pClient->currentMural && pClient->currentWindow>=0)
1559 {
1560 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1561 CRASSERT(b);
1562 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1563 AssertRCReturn(rc, rc);
1564 }
1565 }
1566 }
1567
1568 /* all context gl error states should have now be synced with chromium erro states,
1569 * reset the error if any */
1570 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1571 crWarning("crServer: glGetError %d after saving snapshot", err);
1572
1573 cr_server.bIsInSavingState = GL_FALSE;
1574
1575 return VINF_SUCCESS;
1576}
1577
1578static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1579{
1580 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1581 CRASSERT(pContextInfo);
1582 CRASSERT(pContextInfo->pContext);
1583 return pContextInfo->pContext;
1584}
1585
1586static int32_t crVBoxServerLoadMurals(PSSMHANDLE pSSM, uint32_t version)
1587{
1588 unsigned long key;
1589 uint32_t ui, uiNumElems;
1590 /* Load windows */
1591 int32_t rc = SSMR3GetU32(pSSM, &uiNumElems);
1592 AssertRCReturn(rc, rc);
1593 for (ui=0; ui<uiNumElems; ++ui)
1594 {
1595 CRCreateInfo_t createInfo;
1596 char psz[200];
1597 GLint winID;
1598 unsigned long key;
1599
1600 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1601 AssertRCReturn(rc, rc);
1602 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1603 AssertRCReturn(rc, rc);
1604
1605 if (createInfo.pszDpyName)
1606 {
1607 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1608 AssertRCReturn(rc, rc);
1609 createInfo.pszDpyName = psz;
1610 }
1611
1612 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1613 CRASSERT((int64_t)winID == (int64_t)key);
1614 }
1615
1616 /* Load cr_server.muralTable */
1617 rc = SSMR3GetU32(pSSM, &uiNumElems);
1618 AssertRCReturn(rc, rc);
1619 for (ui=0; ui<uiNumElems; ++ui)
1620 {
1621 CRMuralInfo muralInfo;
1622
1623 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1624 AssertRCReturn(rc, rc);
1625 rc = SSMR3GetMem(pSSM, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1626 AssertRCReturn(rc, rc);
1627
1628 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1629 muralInfo.bFbDraw = GL_TRUE;
1630
1631 if (muralInfo.pVisibleRects)
1632 {
1633 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
1634 if (!muralInfo.pVisibleRects)
1635 {
1636 return VERR_NO_MEMORY;
1637 }
1638
1639 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
1640 AssertRCReturn(rc, rc);
1641 }
1642
1643 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
1644 {
1645 CRMuralInfo *pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);;
1646 CRASSERT(pActualMural);
1647 rc = SSMR3GetMem(pSSM, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
1648 CRASSERT(rc == VINF_SUCCESS);
1649 }
1650
1651 /* Restore windows geometry info */
1652 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
1653 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
1654 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
1655 if (muralInfo.bReceivedRects)
1656 {
1657 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
1658 }
1659 crServerDispatchWindowShow(key, muralInfo.bVisible);
1660
1661 if (muralInfo.pVisibleRects)
1662 {
1663 crFree(muralInfo.pVisibleRects);
1664 }
1665 }
1666
1667 CRASSERT(RT_SUCCESS(rc));
1668 return VINF_SUCCESS;
1669}
1670
1671static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
1672 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
1673{
1674 CRContext *pContext = pContextInfo->pContext;
1675 int32_t rc = VINF_SUCCESS;
1676 GLuint i;
1677 /* can apply the data right away */
1678 struct
1679 {
1680 CRFBData data;
1681 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1682 } Data;
1683
1684 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1685
1686 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1687 {
1688 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1689 CRASSERT(cr_server.currentMural = pMural);
1690
1691 if (!pMural->width || !pMural->height)
1692 return VINF_SUCCESS;
1693
1694 rc = crVBoxServerFBImageDataInit(&Data.data, pContextInfo, pMural, GL_TRUE);
1695 if (!RT_SUCCESS(rc))
1696 {
1697 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1698 return rc;
1699 }
1700 }
1701 else
1702 {
1703 GLint storedWidth, storedHeight;
1704
1705 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1706 {
1707 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1708 CRASSERT(cr_server.currentMural = pMural);
1709 storedWidth = pMural->width;
1710 storedHeight = pMural->height;
1711 }
1712 else
1713 {
1714 storedWidth = pContext->buffer.storedWidth;
1715 storedHeight = pContext->buffer.storedHeight;
1716 }
1717
1718 if (!storedWidth || !storedHeight)
1719 return VINF_SUCCESS;
1720
1721 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, GL_TRUE, storedWidth, storedHeight);
1722 if (!RT_SUCCESS(rc))
1723 {
1724 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1725 return rc;
1726 }
1727 }
1728
1729 CRASSERT(Data.data.cElements);
1730
1731 for (i = 0; i < Data.data.cElements; ++i)
1732 {
1733 CRFBDataElement * pEl = &Data.data.aElements[i];
1734 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
1735 AssertRCReturn(rc, rc);
1736 }
1737
1738 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1739 {
1740 CRBufferState *pBuf = &pContext->buffer;
1741 /* can apply the data right away */
1742 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1743 CRASSERT(cr_server.currentMural = pMural);
1744
1745 crStateApplyFBImage(pContext, &Data.data);
1746 AssertRCReturn(rc, rc);
1747 CRASSERT(!pBuf->pFrontImg);
1748 CRASSERT(!pBuf->pBackImg);
1749 crVBoxServerFBImageDataTerm(&Data.data);
1750
1751 if (pMural->fUseFBO && pMural->bVisible)
1752 {
1753 crServerPresentFBO(pMural);
1754 }
1755 }
1756 else
1757 {
1758 CRBufferState *pBuf = &pContext->buffer;
1759 CRASSERT(!pBuf->pFrontImg);
1760 CRASSERT(!pBuf->pBackImg);
1761 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
1762
1763 if (Data.data.cElements)
1764 {
1765 CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1766 if (!RT_SUCCESS(rc))
1767 {
1768 crVBoxServerFBImageDataTerm(&Data.data);
1769 crWarning("crAlloc failed");
1770 return VERR_NO_MEMORY;
1771 }
1772
1773 crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1774 pBuf->pFrontImg = pLazyData;
1775 }
1776 }
1777
1778 CRASSERT(RT_SUCCESS(rc));
1779 return VINF_SUCCESS;
1780}
1781
1782DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
1783{
1784 int32_t rc, i;
1785 uint32_t ui, uiNumElems;
1786 unsigned long key;
1787 GLenum err;
1788
1789 if (!cr_server.bIsInLoadingState)
1790 {
1791 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
1792 cr_server.bIsInLoadingState = GL_TRUE;
1793
1794 /* Read number of clients */
1795 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
1796 AssertRCReturn(rc, rc);
1797 }
1798
1799 g_hackVBoxServerSaveLoadCallsLeft--;
1800
1801 /* Do nothing until we're being called last time */
1802 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1803 {
1804 return VINF_SUCCESS;
1805 }
1806
1807 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
1808 {
1809 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1810 }
1811
1812 /* Load and recreate rendering contexts */
1813 rc = SSMR3GetU32(pSSM, &uiNumElems);
1814 AssertRCReturn(rc, rc);
1815 for (ui=0; ui<uiNumElems; ++ui)
1816 {
1817 CRCreateInfo_t createInfo;
1818 char psz[200];
1819 GLint ctxID;
1820 CRContextInfo* pContextInfo;
1821 CRContext* pContext;
1822
1823 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1824 AssertRCReturn(rc, rc);
1825 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1826 AssertRCReturn(rc, rc);
1827
1828 if (createInfo.pszDpyName)
1829 {
1830 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1831 AssertRCReturn(rc, rc);
1832 createInfo.pszDpyName = psz;
1833 }
1834
1835 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
1836 CRASSERT((int64_t)ctxID == (int64_t)key);
1837
1838 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1839 CRASSERT(pContextInfo);
1840 CRASSERT(pContextInfo->pContext);
1841 pContext = pContextInfo->pContext;
1842 pContext->shared->id=-1;
1843 }
1844
1845 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1846 {
1847 /* we have a mural data here */
1848 rc = crVBoxServerLoadMurals(pSSM, version);
1849 AssertRCReturn(rc, rc);
1850 }
1851
1852 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
1853 {
1854 /* set the current client to allow doing crServerPerformMakeCurrent later */
1855 CRASSERT(cr_server.numClients);
1856 cr_server.curClient = cr_server.clients[0];
1857 }
1858
1859 rc = crStateLoadGlobals(pSSM, version);
1860 AssertRCReturn(rc, rc);
1861
1862 /* Restore context state data */
1863 for (ui=0; ui<uiNumElems; ++ui)
1864 {
1865 CRContextInfo* pContextInfo;
1866 CRContext *pContext;
1867 CRMuralInfo *pMural = NULL;
1868 int32_t winId = 0;
1869
1870 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1871 AssertRCReturn(rc, rc);
1872
1873 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1874 CRASSERT(pContextInfo);
1875 CRASSERT(pContextInfo->pContext);
1876 pContext = pContextInfo->pContext;
1877
1878 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1879 {
1880 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
1881 AssertRCReturn(rc, rc);
1882
1883 if (winId)
1884 {
1885 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
1886 CRASSERT(pMural);
1887 }
1888 else
1889 {
1890 /* null winId means a dummy mural, get it */
1891 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
1892 CRASSERT(pMural);
1893 }
1894
1895 crServerPerformMakeCurrent(pMural, pContextInfo);
1896 }
1897
1898 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
1899 AssertRCReturn(rc, rc);
1900
1901 /*Restore front/back buffer images*/
1902 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1903 AssertRCReturn(rc, rc);
1904 }
1905
1906 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1907 {
1908 CRContextInfo *pContextInfo;
1909 CRMuralInfo *pMural;
1910 GLint ctxId;
1911
1912 rc = SSMR3GetU32(pSSM, &uiNumElems);
1913 AssertRCReturn(rc, rc);
1914 for (ui=0; ui<uiNumElems; ++ui)
1915 {
1916 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1917 CRMuralInfo *pInitialCurMural;
1918
1919 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1920 AssertRCReturn(rc, rc);
1921
1922 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
1923 AssertRCReturn(rc, rc);
1924
1925 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1926 CRASSERT(pMural);
1927 if (ctxId)
1928 {
1929 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
1930 CRASSERT(pContextInfo);
1931 }
1932 else
1933 pContextInfo = &cr_server.MainContextInfo;
1934
1935 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1936 pInitialCurMural = pContextInfo->currentMural;
1937
1938 crServerPerformMakeCurrent(pMural, pContextInfo);
1939
1940 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1941 AssertRCReturn(rc, rc);
1942
1943 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1944 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1945 pContextInfo->currentMural = pInitialCurMural;
1946 }
1947
1948 if (cr_server.currentCtxInfo != &cr_server.MainContextInfo)
1949 {
1950 /* most ogl data gets loaded to hw on chromium 3D state switch, i.e. inside crStateMakeCurrent -> crStateSwitchContext
1951 * to force the crStateSwitchContext being called later, we need to set the current context to our dummy one */
1952 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
1953 CRASSERT(pMural);
1954 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
1955 }
1956
1957 cr_server.curClient = NULL;
1958 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1959 }
1960 else
1961 {
1962 CRServerFreeIDsPool_t dummyIdsPool;
1963
1964 /* we have a mural data here */
1965 rc = crVBoxServerLoadMurals(pSSM, version);
1966 AssertRCReturn(rc, rc);
1967
1968 /* not used any more, just read it out and ignore */
1969 rc = SSMR3GetMem(pSSM, &dummyIdsPool, sizeof(dummyIdsPool));
1970 CRASSERT(rc == VINF_SUCCESS);
1971 }
1972
1973 /* Load clients info */
1974 for (i = 0; i < cr_server.numClients; i++)
1975 {
1976 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1977 {
1978 CRClient *pClient = cr_server.clients[i];
1979 CRClient client;
1980 unsigned long ctxID=-1, winID=-1;
1981
1982 rc = SSMR3GetU32(pSSM, &ui);
1983 AssertRCReturn(rc, rc);
1984 /* If this assert fires, then we should search correct client in the list first*/
1985 CRASSERT(ui == pClient->conn->u32ClientID);
1986
1987 if (version>=4)
1988 {
1989 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
1990 AssertRCReturn(rc, rc);
1991
1992 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
1993 AssertRCReturn(rc, rc);
1994 }
1995
1996 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
1997 CRASSERT(rc == VINF_SUCCESS);
1998
1999 client.conn = pClient->conn;
2000 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2001 * and fail to bind old textures.
2002 */
2003 /*client.number = pClient->number;*/
2004 *pClient = client;
2005
2006 pClient->currentContextNumber = -1;
2007 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2008 pClient->currentMural = NULL;
2009 pClient->currentWindow = -1;
2010
2011 cr_server.curClient = pClient;
2012
2013 if (client.currentCtxInfo && client.currentContextNumber>=0)
2014 {
2015 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
2016 AssertRCReturn(rc, rc);
2017 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2018 CRASSERT(client.currentCtxInfo);
2019 CRASSERT(client.currentCtxInfo->pContext);
2020 //pClient->currentCtx = client.currentCtx;
2021 //pClient->currentContextNumber = ctxID;
2022 }
2023
2024 if (client.currentMural && client.currentWindow>=0)
2025 {
2026 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
2027 AssertRCReturn(rc, rc);
2028 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2029 CRASSERT(client.currentMural);
2030 //pClient->currentMural = client.currentMural;
2031 //pClient->currentWindow = winID;
2032 }
2033
2034 /* Restore client active context and window */
2035 crServerDispatchMakeCurrent(winID, 0, ctxID);
2036
2037 if (0)
2038 {
2039// CRContext *tmpCtx;
2040// CRCreateInfo_t *createInfo;
2041 GLfloat one[4] = { 1, 1, 1, 1 };
2042 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
2043
2044 crServerDispatchMakeCurrent(winID, 0, ctxID);
2045
2046 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
2047
2048 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
2049 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
2050 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
2051#ifdef CR_ARB_texture_cube_map
2052 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
2053#endif
2054#ifdef CR_NV_texture_rectangle
2055 //@todo this doesn't work as expected
2056 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
2057#endif
2058 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
2059 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
2060 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
2061
2062 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
2063 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
2064 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
2065
2066 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
2067 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
2068
2069 //crStateViewport( 0, 0, 600, 600 );
2070 //pClient->currentMural->viewportValidated = GL_FALSE;
2071 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
2072
2073 //crStateMatrixMode(GL_PROJECTION);
2074 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
2075
2076 //crStateLoadIdentity();
2077 //cr_server.head_spu->dispatch_table.LoadIdentity();
2078
2079 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2080 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2081
2082 //crStateMatrixMode(GL_MODELVIEW);
2083 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
2084 //crServerDispatchLoadIdentity();
2085 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2086 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2087 //crServerDispatchLoadIdentity();
2088
2089 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
2090 CRASSERT(createInfo);
2091 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
2092 CRASSERT(tmpCtx);
2093 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
2094 crStateDestroyContext(tmpCtx);*/
2095 }
2096 }
2097 }
2098
2099 //crServerDispatchMakeCurrent(-1, 0, -1);
2100
2101 cr_server.curClient = NULL;
2102
2103 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2104 crWarning("crServer: glGetError %d after loading snapshot", err);
2105
2106 cr_server.bIsInLoadingState = GL_FALSE;
2107
2108#if 0
2109 crVBoxServerCheckConsistency();
2110#endif
2111
2112 return VINF_SUCCESS;
2113}
2114
2115#define SCREEN(i) (cr_server.screen[i])
2116#define MAPPED(screen) ((screen).winID != 0)
2117
2118static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2119{
2120 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2121 int *sIndex = (int*) data2;
2122
2123 if (pMI->screenId == *sIndex)
2124 {
2125 renderspuReparentWindow(pMI->spuWindow);
2126 }
2127}
2128
2129static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
2130{
2131 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2132 (void) data2;
2133
2134 crServerCheckMuralGeometry(pMI);
2135}
2136
2137DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2138{
2139 int i;
2140
2141 if (sCount>CR_MAX_GUEST_MONITORS)
2142 return VERR_INVALID_PARAMETER;
2143
2144 /*Shouldn't happen yet, but to be safe in future*/
2145 for (i=0; i<cr_server.screenCount; ++i)
2146 {
2147 if (MAPPED(SCREEN(i)))
2148 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
2149 return VERR_NOT_IMPLEMENTED;
2150 }
2151
2152 cr_server.screenCount = sCount;
2153
2154 for (i=0; i<sCount; ++i)
2155 {
2156 SCREEN(i).winID = 0;
2157 }
2158
2159 return VINF_SUCCESS;
2160}
2161
2162DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2163{
2164 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2165
2166 if (sIndex<0 || sIndex>=cr_server.screenCount)
2167 return VERR_INVALID_PARAMETER;
2168
2169 if (MAPPED(SCREEN(sIndex)))
2170 {
2171 SCREEN(sIndex).winID = 0;
2172 renderspuSetWindowId(0);
2173
2174 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2175 }
2176
2177 renderspuSetWindowId(SCREEN(0).winID);
2178 return VINF_SUCCESS;
2179}
2180
2181DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2182{
2183 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2184
2185 if (sIndex<0 || sIndex>=cr_server.screenCount)
2186 return VERR_INVALID_PARAMETER;
2187
2188 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2189 {
2190 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2191 crVBoxServerUnmapScreen(sIndex);
2192 }
2193
2194 SCREEN(sIndex).winID = winID;
2195 SCREEN(sIndex).x = x;
2196 SCREEN(sIndex).y = y;
2197 SCREEN(sIndex).w = w;
2198 SCREEN(sIndex).h = h;
2199
2200 renderspuSetWindowId(SCREEN(sIndex).winID);
2201 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2202 renderspuSetWindowId(SCREEN(0).winID);
2203
2204 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2205
2206#ifndef WINDOWS
2207 /*Restore FB content for clients, which have current window on a screen being remapped*/
2208 {
2209 GLint i;
2210
2211 for (i = 0; i < cr_server.numClients; i++)
2212 {
2213 cr_server.curClient = cr_server.clients[i];
2214 if (cr_server.curClient->currentCtxInfo
2215 && cr_server.curClient->currentCtxInfo->pContext
2216 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2217 && cr_server.curClient->currentMural
2218 && cr_server.curClient->currentMural->screenId == sIndex
2219 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2220 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2221 {
2222 int clientWindow = cr_server.curClient->currentWindow;
2223 int clientContext = cr_server.curClient->currentContextNumber;
2224 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2225
2226 if (clientWindow && clientWindow != cr_server.currentWindow)
2227 {
2228 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2229 }
2230
2231 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2232 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2233 }
2234 }
2235 cr_server.curClient = NULL;
2236 }
2237#endif
2238
2239 {
2240 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
2241 if (pDisplay)
2242 CrDpResize(pDisplay, w, h, w, h);
2243 }
2244
2245 return VINF_SUCCESS;
2246}
2247
2248DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
2249{
2250 renderspuSetRootVisibleRegion(cRects, pRects);
2251
2252 return VINF_SUCCESS;
2253}
2254
2255DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2256{
2257 cr_server.pfnPresentFBO = pfnPresentFBO;
2258}
2259
2260int32_t crServerSetOffscreenRenderingMode(GLubyte value)
2261{
2262 if (cr_server.bForceOffscreenRendering==value)
2263 {
2264 return VINF_SUCCESS;
2265 }
2266
2267 if (value > CR_SERVER_REDIR_MAXVAL)
2268 {
2269 crWarning("crServerSetOffscreenRenderingMode: invalid arg: %d", value);
2270 return VERR_INVALID_PARAMETER;
2271 }
2272
2273 if (value && !crServerSupportRedirMuralFBO())
2274 {
2275 return VERR_NOT_SUPPORTED;
2276 }
2277
2278 cr_server.bForceOffscreenRendering=value;
2279
2280 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2281
2282 return VINF_SUCCESS;
2283}
2284
2285DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2286{
2287 return crServerSetOffscreenRenderingMode(value ? CR_SERVER_REDIR_FBO_RAM : cr_server.bOffscreenRenderingDefault);
2288}
2289
2290DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2291{
2292 /* No need for a synchronization as this is single threaded. */
2293 if (pCallbacks)
2294 {
2295 cr_server.outputRedirect = *pCallbacks;
2296 cr_server.bUseOutputRedirect = true;
2297 }
2298 else
2299 {
2300 cr_server.bUseOutputRedirect = false;
2301 }
2302
2303 // @todo dynamically intercept already existing output:
2304 // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
2305
2306 return VINF_SUCCESS;
2307}
2308
2309static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2)
2310{
2311 CRMuralInfo *mural = (CRMuralInfo*) data1;
2312 int *sIndex = (int*) data2;
2313
2314 if (mural->screenId != *sIndex)
2315 return;
2316
2317 crServerCheckMuralGeometry(mural);
2318}
2319
2320
2321DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2322{
2323 CRScreenViewportInfo *pVieport;
2324 GLboolean fPosChanged, fSizeChanged;
2325
2326 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2327
2328 if (sIndex<0 || sIndex>=cr_server.screenCount)
2329 {
2330 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2331 return VERR_INVALID_PARAMETER;
2332 }
2333
2334 pVieport = &cr_server.screenVieport[sIndex];
2335 fPosChanged = (pVieport->x != x || pVieport->y != y);
2336 fSizeChanged = (pVieport->w != w || pVieport->h != h);
2337
2338 if (!fPosChanged && !fSizeChanged)
2339 {
2340 crDebug("crVBoxServerSetScreenViewport: no changes");
2341 return VINF_SUCCESS;
2342 }
2343
2344 if (fPosChanged)
2345 {
2346 pVieport->x = x;
2347 pVieport->y = y;
2348
2349 crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex);
2350 }
2351
2352 if (fSizeChanged)
2353 {
2354 pVieport->w = w;
2355 pVieport->h = h;
2356
2357 /* no need to do anything here actually */
2358 }
2359 return VINF_SUCCESS;
2360}
2361
2362
2363#ifdef VBOX_WITH_CRHGSMI
2364/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
2365 *
2366 * 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.
2367 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
2368 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
2369 * to block the lower-priority thread trying to complete the blocking command.
2370 * And removed extra memcpy done on blocked command arrival.
2371 *
2372 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
2373 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
2374 *
2375 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
2376 * */
2377int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
2378{
2379 int32_t rc;
2380 uint32_t cBuffers = pCmd->cBuffers;
2381 uint32_t cParams;
2382 uint32_t cbHdr;
2383 CRVBOXHGSMIHDR *pHdr;
2384 uint32_t u32Function;
2385 uint32_t u32ClientID;
2386 CRClient *pClient;
2387
2388 if (!g_pvVRamBase)
2389 {
2390 crWarning("g_pvVRamBase is not initialized");
2391 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
2392 return VINF_SUCCESS;
2393 }
2394
2395 if (!cBuffers)
2396 {
2397 crWarning("zero buffers passed in!");
2398 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2399 return VINF_SUCCESS;
2400 }
2401
2402 cParams = cBuffers-1;
2403
2404 cbHdr = pCmd->aBuffers[0].cbBuffer;
2405 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2406 if (!pHdr)
2407 {
2408 crWarning("invalid header buffer!");
2409 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2410 return VINF_SUCCESS;
2411 }
2412
2413 if (cbHdr < sizeof (*pHdr))
2414 {
2415 crWarning("invalid header buffer size!");
2416 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2417 return VINF_SUCCESS;
2418 }
2419
2420 u32Function = pHdr->u32Function;
2421 u32ClientID = pHdr->u32ClientID;
2422
2423 switch (u32Function)
2424 {
2425 case SHCRGL_GUEST_FN_WRITE:
2426 {
2427 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2428
2429 /* @todo: Verify */
2430 if (cParams == 1)
2431 {
2432 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2433 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2434 /* Fetch parameters. */
2435 uint32_t cbBuffer = pBuf->cbBuffer;
2436 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2437
2438 if (cbHdr < sizeof (*pFnCmd))
2439 {
2440 crWarning("invalid write cmd buffer size!");
2441 rc = VERR_INVALID_PARAMETER;
2442 break;
2443 }
2444
2445 CRASSERT(cbBuffer);
2446 if (!pBuffer)
2447 {
2448 crWarning("invalid buffer data received from guest!");
2449 rc = VERR_INVALID_PARAMETER;
2450 break;
2451 }
2452
2453 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2454 if (RT_FAILURE(rc))
2455 {
2456 break;
2457 }
2458
2459 /* This should never fire unless we start to multithread */
2460 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2461 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2462
2463 pClient->conn->pBuffer = pBuffer;
2464 pClient->conn->cbBuffer = cbBuffer;
2465 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2466 rc = crVBoxServerInternalClientWriteRead(pClient);
2467 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2468 return rc;
2469 }
2470 else
2471 {
2472 crWarning("invalid number of args");
2473 rc = VERR_INVALID_PARAMETER;
2474 break;
2475 }
2476 break;
2477 }
2478
2479 case SHCRGL_GUEST_FN_INJECT:
2480 {
2481 crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2482
2483 /* @todo: Verify */
2484 if (cParams == 1)
2485 {
2486 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2487 /* Fetch parameters. */
2488 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2489 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2490 uint32_t cbBuffer = pBuf->cbBuffer;
2491 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2492
2493 if (cbHdr < sizeof (*pFnCmd))
2494 {
2495 crWarning("invalid inject cmd buffer size!");
2496 rc = VERR_INVALID_PARAMETER;
2497 break;
2498 }
2499
2500 CRASSERT(cbBuffer);
2501 if (!pBuffer)
2502 {
2503 crWarning("invalid buffer data received from guest!");
2504 rc = VERR_INVALID_PARAMETER;
2505 break;
2506 }
2507
2508 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
2509 if (RT_FAILURE(rc))
2510 {
2511 break;
2512 }
2513
2514 /* This should never fire unless we start to multithread */
2515 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2516 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2517
2518 pClient->conn->pBuffer = pBuffer;
2519 pClient->conn->cbBuffer = cbBuffer;
2520 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2521 rc = crVBoxServerInternalClientWriteRead(pClient);
2522 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2523 return rc;
2524 }
2525
2526 crWarning("invalid number of args");
2527 rc = VERR_INVALID_PARAMETER;
2528 break;
2529 }
2530
2531 case SHCRGL_GUEST_FN_READ:
2532 {
2533 crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n"));
2534
2535 /* @todo: Verify */
2536 if (cParams == 1)
2537 {
2538 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
2539 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2540 /* Fetch parameters. */
2541 uint32_t cbBuffer = pBuf->cbBuffer;
2542 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2543
2544 if (cbHdr < sizeof (*pFnCmd))
2545 {
2546 crWarning("invalid read cmd buffer size!");
2547 rc = VERR_INVALID_PARAMETER;
2548 break;
2549 }
2550
2551
2552 if (!pBuffer)
2553 {
2554 crWarning("invalid buffer data received from guest!");
2555 rc = VERR_INVALID_PARAMETER;
2556 break;
2557 }
2558
2559 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2560 if (RT_FAILURE(rc))
2561 {
2562 break;
2563 }
2564
2565 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2566
2567 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
2568
2569 /* Return the required buffer size always */
2570 pFnCmd->cbBuffer = cbBuffer;
2571
2572 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2573
2574 /* the read command is never pended, complete it right away */
2575 pHdr->result = rc;
2576 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2577 return VINF_SUCCESS;
2578 }
2579
2580 crWarning("invalid number of args");
2581 rc = VERR_INVALID_PARAMETER;
2582 break;
2583 }
2584
2585 case SHCRGL_GUEST_FN_WRITE_READ:
2586 {
2587 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
2588
2589 /* @todo: Verify */
2590 if (cParams == 2)
2591 {
2592 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
2593 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2594 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
2595
2596 /* Fetch parameters. */
2597 uint32_t cbBuffer = pBuf->cbBuffer;
2598 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2599
2600 uint32_t cbWriteback = pWbBuf->cbBuffer;
2601 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
2602
2603 if (cbHdr < sizeof (*pFnCmd))
2604 {
2605 crWarning("invalid write_read cmd buffer size!");
2606 rc = VERR_INVALID_PARAMETER;
2607 break;
2608 }
2609
2610
2611 CRASSERT(cbBuffer);
2612 if (!pBuffer)
2613 {
2614 crWarning("invalid write buffer data received from guest!");
2615 rc = VERR_INVALID_PARAMETER;
2616 break;
2617 }
2618
2619 CRASSERT(cbWriteback);
2620 if (!pWriteback)
2621 {
2622 crWarning("invalid writeback buffer data received from guest!");
2623 rc = VERR_INVALID_PARAMETER;
2624 break;
2625 }
2626 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2627 if (RT_FAILURE(rc))
2628 {
2629 pHdr->result = rc;
2630 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2631 return rc;
2632 }
2633
2634 /* This should never fire unless we start to multithread */
2635 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2636 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2637
2638 pClient->conn->pBuffer = pBuffer;
2639 pClient->conn->cbBuffer = cbBuffer;
2640 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
2641 rc = crVBoxServerInternalClientWriteRead(pClient);
2642 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2643 return rc;
2644 }
2645
2646 crWarning("invalid number of args");
2647 rc = VERR_INVALID_PARAMETER;
2648 break;
2649 }
2650
2651 case SHCRGL_GUEST_FN_SET_VERSION:
2652 {
2653 crWarning("invalid function");
2654 rc = VERR_NOT_IMPLEMENTED;
2655 break;
2656 }
2657
2658 case SHCRGL_GUEST_FN_SET_PID:
2659 {
2660 crWarning("invalid function");
2661 rc = VERR_NOT_IMPLEMENTED;
2662 break;
2663 }
2664
2665 default:
2666 {
2667 crWarning("invalid function");
2668 rc = VERR_NOT_IMPLEMENTED;
2669 break;
2670 }
2671
2672 }
2673
2674 /* we can be on fail only here */
2675 CRASSERT(RT_FAILURE(rc));
2676 pHdr->result = rc;
2677 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2678 return rc;
2679}
2680
2681int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
2682{
2683 int rc = VINF_SUCCESS;
2684
2685 switch (pCtl->enmType)
2686 {
2687 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
2688 {
2689 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
2690 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
2691 g_cbVRam = pSetup->cbVRam;
2692 rc = VINF_SUCCESS;
2693 break;
2694 }
2695 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
2696 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
2697 rc = VINF_SUCCESS;
2698 break;
2699 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
2700 {
2701 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
2702 g_hCrHgsmiCompletion = pSetup->hCompletion;
2703 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
2704 rc = VINF_SUCCESS;
2705 break;
2706 }
2707 default:
2708 AssertMsgFailed(("invalid param %d", pCtl->enmType));
2709 rc = VERR_INVALID_PARAMETER;
2710 }
2711
2712 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
2713 * to complete them accordingly.
2714 * This approach allows using host->host and host->guest commands in the same way here
2715 * making the command completion to be the responsibility of the command originator.
2716 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
2717 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
2718 return rc;
2719}
2720#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