VirtualBox

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

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

crOpenGl: more stencil/depth saved state fixes

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