VirtualBox

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

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

crOpenGL: fix default mural refs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 88.2 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 != CR_RENDER_DEFAULT_WINDOW_ID) /* <- 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 defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
332 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
333
334 cr_server.programTable = crAllocHashtable();
335
336 crNetInit(crServerRecv, crServerClose);
337 crStateInit();
338
339 crServerSetVBoxConfiguration();
340
341 crStateLimitsInit( &(cr_server.limits) );
342
343 /*
344 * Default context
345 */
346 cr_server.contextTable = crAllocHashtable();
347 cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
348
349 cr_server.dummyMuralTable = crAllocHashtable();
350
351 crServerInitDispatch();
352 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
353
354 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
355 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
356
357 cr_server.barriers = crAllocHashtable();
358 cr_server.semaphores = crAllocHashtable();
359}
360
361void crVBoxServerTearDown(void)
362{
363 crServerTearDown();
364}
365
366/**
367 * Do CRServer initializations. After this, we can begin servicing clients.
368 */
369GLboolean crVBoxServerInit(void)
370{
371 CRMuralInfo *defaultMural;
372
373 int rc = VBoxVrInit();
374 if (!RT_SUCCESS(rc))
375 {
376 crWarning("VBoxVrInit failed, rc %d", rc);
377 return GL_FALSE;
378 }
379
380#if DEBUG_FP_EXCEPTIONS
381 {
382 fpu_control_t mask;
383 _FPU_GETCW(mask);
384 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
385 | _FPU_MASK_OM | _FPU_MASK_UM);
386 _FPU_SETCW(mask);
387 }
388#endif
389
390 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
391
392 if (cr_server.bUseMultipleContexts)
393 {
394 crInfo("Info: using multiple contexts!");
395 crDebug("Debug: using multiple contexts!");
396 }
397
398 crNetInit(crServerRecv, crServerClose);
399
400 cr_server.firstCallCreateContext = GL_TRUE;
401 cr_server.firstCallMakeCurrent = GL_TRUE;
402
403 cr_server.bIsInLoadingState = GL_FALSE;
404 cr_server.bIsInSavingState = GL_FALSE;
405 cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
406
407 cr_server.pCleanupClient = NULL;
408
409 /*
410 * Create default mural info and hash table.
411 */
412 cr_server.muralTable = crAllocHashtable();
413 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
414 defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
415 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
416
417 cr_server.programTable = crAllocHashtable();
418
419 crStateInit();
420
421 crStateLimitsInit( &(cr_server.limits) );
422
423 cr_server.barriers = crAllocHashtable();
424 cr_server.semaphores = crAllocHashtable();
425
426 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
427 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
428
429 /*
430 * Default context
431 */
432 cr_server.contextTable = crAllocHashtable();
433
434 cr_server.dummyMuralTable = crAllocHashtable();
435
436 crServerSetVBoxConfigurationHGCM();
437
438 if (!cr_server.head_spu)
439 return GL_FALSE;
440
441 crServerInitDispatch();
442 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
443
444 /*Check for PBO support*/
445 if (crStateGetCurrent()->extensions.ARB_pixel_buffer_object)
446 {
447 cr_server.bUsePBOForReadback=GL_TRUE;
448 }
449
450 return GL_TRUE;
451}
452
453int32_t crVBoxServerAddClient(uint32_t u32ClientID)
454{
455 CRClient *newClient;
456
457 if (cr_server.numClients>=CR_MAX_CLIENTS)
458 {
459 return VERR_MAX_THRDS_REACHED;
460 }
461
462 newClient = (CRClient *) crCalloc(sizeof(CRClient));
463 crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
464
465 newClient->spu_id = 0;
466 newClient->currentCtxInfo = &cr_server.MainContextInfo;
467 newClient->currentContextNumber = -1;
468 newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
469 cr_server.tcpip_port,
470 cr_server.mtu, 0);
471 newClient->conn->u32ClientID = u32ClientID;
472
473 cr_server.clients[cr_server.numClients++] = newClient;
474
475 crServerAddToRunQueue(newClient);
476
477 return VINF_SUCCESS;
478}
479
480void crVBoxServerRemoveClient(uint32_t u32ClientID)
481{
482 CRClient *pClient=NULL;
483 int32_t i;
484
485 crDebug("crServer: RemoveClient u32ClientID=%d", u32ClientID);
486
487 for (i = 0; i < cr_server.numClients; i++)
488 {
489 if (cr_server.clients[i] && cr_server.clients[i]->conn
490 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
491 {
492 pClient = cr_server.clients[i];
493 break;
494 }
495 }
496 //if (!pClient) return VERR_INVALID_PARAMETER;
497 if (!pClient)
498 {
499 crWarning("Invalid client id %u passed to crVBoxServerRemoveClient", u32ClientID);
500 return;
501 }
502
503#ifdef VBOX_WITH_CRHGSMI
504 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
505#endif
506
507 /* Disconnect the client */
508 pClient->conn->Disconnect(pClient->conn);
509
510 /* Let server clear client from the queue */
511 crServerDeleteClient(pClient);
512}
513
514static int32_t crVBoxServerInternalClientWriteRead(CRClient *pClient)
515{
516#ifdef VBOXCR_LOGFPS
517 uint64_t tstart, tend;
518#endif
519
520 /*crDebug("=>crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
521
522
523#ifdef VBOXCR_LOGFPS
524 tstart = RTTimeNanoTS();
525#endif
526
527 /* This should be setup already */
528 CRASSERT(pClient->conn->pBuffer);
529 CRASSERT(pClient->conn->cbBuffer);
530#ifdef VBOX_WITH_CRHGSMI
531 CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&pClient->conn->CmdData);
532#endif
533
534 if (
535#ifdef VBOX_WITH_CRHGSMI
536 !CRVBOXHGSMI_CMDDATA_IS_SET(&pClient->conn->CmdData) &&
537#endif
538 cr_server.run_queue->client != pClient
539 && crServerClientInBeginEnd(cr_server.run_queue->client))
540 {
541 crDebug("crServer: client %d blocked, allow_redir_ptr = 0", pClient->conn->u32ClientID);
542 pClient->conn->allow_redir_ptr = 0;
543 }
544 else
545 {
546 pClient->conn->allow_redir_ptr = 1;
547 }
548
549 crNetRecv();
550 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
551 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
552
553 crServerServiceClients();
554
555#if 0
556 if (pClient->currentMural) {
557 crStateViewport( 0, 0, 500, 500 );
558 pClient->currentMural->viewportValidated = GL_FALSE;
559 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 500, 500 );
560 crStateViewport( 0, 0, 600, 600 );
561 pClient->currentMural->viewportValidated = GL_FALSE;
562 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
563
564 crStateMatrixMode(GL_PROJECTION);
565 cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
566 crServerDispatchLoadIdentity();
567 crStateFrustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
568 cr_server.head_spu->dispatch_table.Frustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
569 crServerDispatchLoadIdentity();
570 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
571 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
572
573 crStateMatrixMode(GL_MODELVIEW);
574 cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
575 crServerDispatchLoadIdentity();
576 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
577 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
578 crServerDispatchLoadIdentity();
579 }
580#endif
581
582 crStateResetCurrentPointers(&cr_server.current);
583
584#ifndef VBOX_WITH_CRHGSMI
585 CRASSERT(!pClient->conn->allow_redir_ptr || crNetNumMessages(pClient->conn)==0);
586#endif
587
588#ifdef VBOXCR_LOGFPS
589 tend = RTTimeNanoTS();
590 pClient->timeUsed += tend-tstart;
591#endif
592 /*crDebug("<=crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
593
594 return VINF_SUCCESS;
595}
596
597
598int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer)
599{
600 CRClient *pClient=NULL;
601 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
602
603 if (RT_FAILURE(rc))
604 return rc;
605
606
607 CRASSERT(pBuffer);
608
609 /* This should never fire unless we start to multithread */
610 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
611
612 pClient->conn->pBuffer = pBuffer;
613 pClient->conn->cbBuffer = cbBuffer;
614#ifdef VBOX_WITH_CRHGSMI
615 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
616#endif
617
618 return crVBoxServerInternalClientWriteRead(pClient);
619}
620
621int32_t crVBoxServerInternalClientRead(CRClient *pClient, uint8_t *pBuffer, uint32_t *pcbBuffer)
622{
623 if (pClient->conn->cbHostBuffer > *pcbBuffer)
624 {
625 crDebug("crServer: [%lx] ClientRead u32ClientID=%d FAIL, host buffer too small %d of %d",
626 crThreadID(), pClient->conn->u32ClientID, *pcbBuffer, pClient->conn->cbHostBuffer);
627
628 /* Return the size of needed buffer */
629 *pcbBuffer = pClient->conn->cbHostBuffer;
630
631 return VERR_BUFFER_OVERFLOW;
632 }
633
634 *pcbBuffer = pClient->conn->cbHostBuffer;
635
636 if (*pcbBuffer)
637 {
638 CRASSERT(pClient->conn->pHostBuffer);
639
640 crMemcpy(pBuffer, pClient->conn->pHostBuffer, *pcbBuffer);
641 pClient->conn->cbHostBuffer = 0;
642 }
643
644 return VINF_SUCCESS;
645}
646
647int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t *pcbBuffer)
648{
649 CRClient *pClient=NULL;
650 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
651
652 if (RT_FAILURE(rc))
653 return rc;
654
655#ifdef VBOX_WITH_CRHGSMI
656 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
657#endif
658
659 return crVBoxServerInternalClientRead(pClient, pBuffer, pcbBuffer);
660}
661
662int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor)
663{
664 CRClient *pClient=NULL;
665 int32_t i;
666
667 for (i = 0; i < cr_server.numClients; i++)
668 {
669 if (cr_server.clients[i] && cr_server.clients[i]->conn
670 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
671 {
672 pClient = cr_server.clients[i];
673 break;
674 }
675 }
676 if (!pClient) return VERR_INVALID_PARAMETER;
677
678 pClient->conn->vMajor = vMajor;
679 pClient->conn->vMinor = vMinor;
680
681 if (vMajor != CR_PROTOCOL_VERSION_MAJOR
682 || vMinor != CR_PROTOCOL_VERSION_MINOR)
683 {
684 return VERR_NOT_SUPPORTED;
685 }
686 else return VINF_SUCCESS;
687}
688
689int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid)
690{
691 CRClient *pClient=NULL;
692 int32_t i;
693
694 for (i = 0; i < cr_server.numClients; i++)
695 {
696 if (cr_server.clients[i] && cr_server.clients[i]->conn
697 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
698 {
699 pClient = cr_server.clients[i];
700 break;
701 }
702 }
703 if (!pClient) return VERR_INVALID_PARAMETER;
704
705 pClient->pid = pid;
706
707 return VINF_SUCCESS;
708}
709
710int
711CRServerMain(int argc, char *argv[])
712{
713 crServerInit(argc, argv);
714
715 crServerSerializeRemoteStreams();
716
717 crServerTearDown();
718
719 tearingdown = 0;
720
721 return 0;
722}
723
724static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2)
725{
726 CRMuralInfo *pMI = (CRMuralInfo*) data1;
727 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
728 int32_t rc;
729
730 CRASSERT(pMI && pSSM);
731
732 /* Don't store default mural */
733 if (!key) return;
734
735 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
736 CRASSERT(rc == VINF_SUCCESS);
737
738 rc = SSMR3PutMem(pSSM, pMI, RT_OFFSETOF(CRMuralInfo, CreateInfo));
739 CRASSERT(rc == VINF_SUCCESS);
740
741 if (pMI->pVisibleRects)
742 {
743 rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects);
744 }
745
746 rc = SSMR3PutMem(pSSM, pMI->ctxUsage, sizeof (pMI->ctxUsage));
747 CRASSERT(rc == VINF_SUCCESS);
748}
749
750/* @todo add hashtable walker with result info and intermediate abort */
751static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *data2)
752{
753 CRCreateInfo_t *pCreateInfo = (CRCreateInfo_t *)data1;
754 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
755 int32_t rc;
756
757 CRASSERT(pCreateInfo && pSSM);
758
759 /* Don't store default mural create info */
760 if (!key) return;
761
762 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
763 CRASSERT(rc == VINF_SUCCESS);
764
765 rc = SSMR3PutMem(pSSM, pCreateInfo, sizeof(*pCreateInfo));
766 CRASSERT(rc == VINF_SUCCESS);
767
768 if (pCreateInfo->pszDpyName)
769 {
770 rc = SSMR3PutStrZ(pSSM, pCreateInfo->pszDpyName);
771 CRASSERT(rc == VINF_SUCCESS);
772 }
773}
774
775static void crVBoxServerSaveCreateInfoFromMuralInfoCB(unsigned long key, void *data1, void *data2)
776{
777 CRMuralInfo *pMural = (CRMuralInfo *)data1;
778 CRCreateInfo_t *pCreateInfo = &pMural->CreateInfo;
779 crVBoxServerSaveCreateInfoCB(key, pCreateInfo, data2);
780}
781
782static void crVBoxServerSaveCreateInfoFromCtxInfoCB(unsigned long key, void *data1, void *data2)
783{
784 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
785 CRCreateInfo_t CreateInfo = pContextInfo->CreateInfo;
786 /* saved state contains internal id */
787 CreateInfo.externalID = pContextInfo->pContext->id;
788 crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
789}
790
791static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data2)
792{
793 CRTextureObj *pTexture = (CRTextureObj *) data1;
794 CRContext *pContext = (CRContext *) data2;
795
796 CRASSERT(pTexture && pContext);
797 crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
798}
799
800typedef struct CRVBOX_SAVE_STATE_GLOBAL
801{
802 /* context id -> mural association
803 * on context data save, each context will be made current with the corresponding mural from this table
804 * thus saving the mural front & back buffer data */
805 CRHashTable *contextMuralTable;
806 /* mural id -> context info
807 * for murals that do not have associated context in contextMuralTable
808 * we still need to save*/
809 CRHashTable *additionalMuralContextTable;
810
811 PSSMHANDLE pSSM;
812
813 int rc;
814} CRVBOX_SAVE_STATE_GLOBAL, *PCRVBOX_SAVE_STATE_GLOBAL;
815
816
817typedef struct CRVBOX_CTXWND_CTXWALKER_CB
818{
819 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
820 CRHashTable *usedMuralTable;
821 GLuint cAdditionalMurals;
822} CRVBOX_CTXWND_CTXWALKER_CB, *PCRVBOX_CTXWND_CTXWALKER_CB;
823
824static void crVBoxServerBuildAdditionalWindowContextMapCB(unsigned long key, void *data1, void *data2)
825{
826 CRMuralInfo * pMural = (CRMuralInfo *) data1;
827 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
828 CRContextInfo *pContextInfo = NULL;
829
830 if (!pMural->CreateInfo.externalID)
831 {
832 CRASSERT(!key);
833 return;
834 }
835
836 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
837 {
838 Assert(crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
839 return;
840 }
841
842 Assert(!crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
843
844 if (cr_server.MainContextInfo.CreateInfo.visualBits == pMural->CreateInfo.visualBits)
845 {
846 pContextInfo = &cr_server.MainContextInfo;
847 }
848 else
849 {
850 crWarning("different visual bits not implemented!");
851 pContextInfo = &cr_server.MainContextInfo;
852 }
853
854 crHashtableAdd(pData->pGlobal->additionalMuralContextTable, pMural->CreateInfo.externalID, pContextInfo);
855}
856
857
858typedef struct CRVBOX_CTXWND_WNDWALKER_CB
859{
860 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
861 CRHashTable *usedMuralTable;
862 CRContextInfo *pContextInfo;
863 CRMuralInfo * pMural;
864} CRVBOX_CTXWND_WNDWALKER_CB, *PCRVBOX_CTXWND_WNDWALKER_CB;
865
866static void crVBoxServerBuildContextWindowMapWindowWalkerCB(unsigned long key, void *data1, void *data2)
867{
868 CRMuralInfo * pMural = (CRMuralInfo *) data1;
869 PCRVBOX_CTXWND_WNDWALKER_CB pData = (PCRVBOX_CTXWND_WNDWALKER_CB)data2;
870
871 Assert(pData->pMural != pMural);
872 Assert(pData->pContextInfo);
873
874 if (pData->pMural)
875 return;
876
877 if (!pMural->CreateInfo.externalID)
878 {
879 CRASSERT(!key);
880 return;
881 }
882
883 if (!CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pData->pContextInfo->pContext))
884 return;
885
886 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
887 return;
888
889 CRASSERT(pMural->CreateInfo.visualBits == pData->pContextInfo->CreateInfo.visualBits);
890 pData->pMural = pMural;
891}
892
893static void crVBoxServerBuildContextUsedWindowMapCB(unsigned long key, void *data1, void *data2)
894{
895 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
896 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
897
898 if (!pContextInfo->currentMural)
899 return;
900
901 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pContextInfo->currentMural);
902 crHashtableAdd(pData->usedMuralTable, pContextInfo->currentMural->CreateInfo.externalID, pContextInfo->currentMural);
903}
904
905CRMuralInfo * crServerGetDummyMural(GLint visualBits)
906{
907 CRMuralInfo * pMural = (CRMuralInfo *)crHashtableSearch(cr_server.dummyMuralTable, visualBits);
908 if (!pMural)
909 {
910 GLint id;
911 pMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
912 if (!pMural)
913 {
914 crWarning("crCalloc failed!");
915 return NULL;
916 }
917 id = crServerMuralInit(pMural, "", visualBits, -1);
918 if (id < 0)
919 {
920 crWarning("crServerMuralInit failed!");
921 crFree(pMural);
922 return NULL;
923 }
924
925 crHashtableAdd(cr_server.dummyMuralTable, visualBits, pMural);
926 }
927
928 return pMural;
929}
930
931static void crVBoxServerBuildContextUnusedWindowMapCB(unsigned long key, void *data1, void *data2)
932{
933 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
934 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
935 CRMuralInfo * pMural = NULL;
936
937 if (pContextInfo->currentMural)
938 return;
939
940 Assert(crHashtableNumElements(pData->pGlobal->contextMuralTable) <= crHashtableNumElements(cr_server.muralTable) - 1);
941 if (crHashtableNumElements(pData->pGlobal->contextMuralTable) < crHashtableNumElements(cr_server.muralTable) - 1)
942 {
943 CRVBOX_CTXWND_WNDWALKER_CB MuralData;
944 MuralData.pGlobal = pData->pGlobal;
945 MuralData.usedMuralTable = pData->usedMuralTable;
946 MuralData.pContextInfo = pContextInfo;
947 MuralData.pMural = NULL;
948
949 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildContextWindowMapWindowWalkerCB, &MuralData);
950
951 pMural = MuralData.pMural;
952
953 }
954
955 if (!pMural)
956 {
957 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
958 if (!pMural)
959 {
960 crWarning("crServerGetDummyMural failed");
961 return;
962 }
963 }
964 else
965 {
966 crHashtableAdd(pData->usedMuralTable, pMural->CreateInfo.externalID, pMural);
967 ++pData->cAdditionalMurals;
968 }
969
970 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pMural);
971}
972
973static void crVBoxServerBuildSaveStateGlobal(PCRVBOX_SAVE_STATE_GLOBAL pGlobal)
974{
975 CRVBOX_CTXWND_CTXWALKER_CB Data;
976 GLuint cMurals;
977 pGlobal->contextMuralTable = crAllocHashtable();
978 pGlobal->additionalMuralContextTable = crAllocHashtable();
979 /* 1. go through all contexts and match all having currentMural set */
980 Data.pGlobal = pGlobal;
981 Data.usedMuralTable = crAllocHashtable();
982 Data.cAdditionalMurals = 0;
983 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUsedWindowMapCB, &Data);
984
985 cMurals = crHashtableNumElements(pGlobal->contextMuralTable);
986 CRASSERT(cMurals <= crHashtableNumElements(cr_server.contextTable));
987 CRASSERT(cMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
988 CRASSERT(cMurals == crHashtableNumElements(Data.usedMuralTable));
989 if (cMurals < crHashtableNumElements(cr_server.contextTable))
990 {
991 Data.cAdditionalMurals = 0;
992 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUnusedWindowMapCB, &Data);
993 }
994
995 CRASSERT(crHashtableNumElements(pGlobal->contextMuralTable) == crHashtableNumElements(cr_server.contextTable));
996 CRASSERT(cMurals + Data.cAdditionalMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
997 if (cMurals + Data.cAdditionalMurals < crHashtableNumElements(cr_server.muralTable) - 1)
998 {
999 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildAdditionalWindowContextMapCB, &Data);
1000 CRASSERT(cMurals + Data.cAdditionalMurals + crHashtableNumElements(pGlobal->additionalMuralContextTable) == crHashtableNumElements(cr_server.muralTable) - 1);
1001 }
1002
1003 crFreeHashtable(Data.usedMuralTable, NULL);
1004}
1005
1006static void crVBoxServerFBImageDataTerm(CRFBData *pData)
1007{
1008 GLuint i;
1009 for (i = 0; i < pData->cElements; ++i)
1010 {
1011 CRFBDataElement * pEl = &pData->aElements[i];
1012 if (pEl->pvData)
1013 {
1014 crFree(pEl->pvData);
1015 /* sanity */
1016 pEl->pvData = NULL;
1017 }
1018 }
1019 pData->cElements = 0;
1020}
1021
1022static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, uint32_t version, GLuint overrideWidth, GLuint overrideHeight)
1023{
1024 CRContext *pContext;
1025 GLuint i;
1026 GLfloat *pF;
1027 CRFBDataElement *pEl;
1028 GLuint width;
1029 GLuint height;
1030
1031 crMemset(pData, 0, sizeof (*pData));
1032
1033 pContext = pCtxInfo->pContext;
1034
1035 /* the version should be always actual when we do reads,
1036 * i.e. it could differ on writes when snapshot is getting loaded */
1037 CRASSERT(fWrite || version == SHCROGL_SSM_VERSION);
1038
1039 width = overrideWidth ? overrideWidth : pMural->width;
1040 height = overrideHeight ? overrideHeight : pMural->height;
1041
1042 if (!width || !height)
1043 return VINF_SUCCESS;
1044
1045 pData->idFBO = pMural->fUseFBO ? pMural->aidColorTexs[fWrite ? pMural->iCurDrawBuffer : pMural->iCurReadBuffer] : 0;
1046 pData->cElements = 0;
1047
1048 pEl = &pData->aElements[pData->cElements];
1049 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1050 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT;
1051 pEl->posX = 0;
1052 pEl->posY = 0;
1053 pEl->width = width;
1054 pEl->height = height;
1055 pEl->enmFormat = GL_RGBA;
1056 pEl->enmType = GL_UNSIGNED_BYTE;
1057 pEl->cbData = width * height * 4;
1058 pEl->pvData = crCalloc(pEl->cbData);
1059 if (!pEl->pvData)
1060 {
1061 crVBoxServerFBImageDataTerm(pData);
1062 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1063 return VERR_NO_MEMORY;
1064 }
1065 ++pData->cElements;
1066
1067 /* there is a lot of code that assumes we have double buffering, just assert here to print a warning in the log
1068 * so that we know that something irregular is going on */
1069 CRASSERT(pCtxInfo->CreateInfo.visualBits & CR_DOUBLE_BIT);
1070 if ((pCtxInfo->CreateInfo.visualBits & CR_DOUBLE_BIT)
1071 || version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL /* <- older version had a typo which lead to back always being used,
1072 * no matter what the visual bits are */
1073 )
1074 {
1075 pEl = &pData->aElements[pData->cElements];
1076 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0;
1077 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK;
1078 pEl->posX = 0;
1079 pEl->posY = 0;
1080 pEl->width = width;
1081 pEl->height = height;
1082 pEl->enmFormat = GL_RGBA;
1083 pEl->enmType = GL_UNSIGNED_BYTE;
1084 pEl->cbData = width * height * 4;
1085 pEl->pvData = crCalloc(pEl->cbData);
1086 if (!pEl->pvData)
1087 {
1088 crVBoxServerFBImageDataTerm(pData);
1089 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1090 return VERR_NO_MEMORY;
1091 }
1092 ++pData->cElements;
1093 }
1094
1095 if (version < SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1096 return VINF_SUCCESS;
1097
1098
1099 if (version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL)
1100 {
1101/* if (pCtxInfo->CreateInfo.visualBits & CR_DEPTH_BIT) */ /* <- older version had a typo which lead to back always being used,
1102 * no matter what the visual bits are */
1103 {
1104 AssertCompile(sizeof (GLfloat) == 4);
1105 pEl = &pData->aElements[pData->cElements];
1106 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1107 pEl->enmBuffer = 0; /* we do not care */
1108 pEl->posX = 0;
1109 pEl->posY = 0;
1110 pEl->width = width;
1111 pEl->height = height;
1112 pEl->enmFormat = GL_DEPTH_COMPONENT;
1113 pEl->enmType = GL_FLOAT;
1114 pEl->cbData = width * height * 4;
1115 pEl->pvData = crCalloc(pEl->cbData);
1116 if (!pEl->pvData)
1117 {
1118 crVBoxServerFBImageDataTerm(pData);
1119 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1120 return VERR_NO_MEMORY;
1121 }
1122
1123 /* init to default depth value, just in case */
1124 pF = (GLfloat*)pEl->pvData;
1125 for (i = 0; i < width * height; ++i)
1126 {
1127 pF[i] = 1.;
1128 }
1129 ++pData->cElements;
1130 }
1131
1132 /* if (pCtxInfo->CreateInfo.visualBits & CR_STENCIL_BIT) */ /* <- older version had a typo which lead to back always being used,
1133 * no matter what the visual bits are */
1134 {
1135 AssertCompile(sizeof (GLuint) == 4);
1136 pEl = &pData->aElements[pData->cElements];
1137 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1138 pEl->enmBuffer = 0; /* we do not care */
1139 pEl->posX = 0;
1140 pEl->posY = 0;
1141 pEl->width = width;
1142 pEl->height = height;
1143 pEl->enmFormat = GL_STENCIL_INDEX;
1144 pEl->enmType = GL_UNSIGNED_INT;
1145 pEl->cbData = width * height * 4;
1146 pEl->pvData = crCalloc(pEl->cbData);
1147 if (!pEl->pvData)
1148 {
1149 crVBoxServerFBImageDataTerm(pData);
1150 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1151 return VERR_NO_MEMORY;
1152 }
1153 ++pData->cElements;
1154 }
1155 return VINF_SUCCESS;
1156 }
1157
1158 if ((pCtxInfo->CreateInfo.visualBits & CR_STENCIL_BIT)
1159 || (pCtxInfo->CreateInfo.visualBits & CR_DEPTH_BIT))
1160 {
1161 pEl = &pData->aElements[pData->cElements];
1162 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1163 pEl->enmBuffer = 0; /* we do not care */
1164 pEl->posX = 0;
1165 pEl->posY = 0;
1166 pEl->width = width;
1167 pEl->height = height;
1168 pEl->enmFormat = GL_DEPTH_STENCIL;
1169 pEl->enmType = GL_UNSIGNED_INT_24_8;
1170 pEl->cbData = width * height * 4;
1171 pEl->pvData = crCalloc(pEl->cbData);
1172 if (!pEl->pvData)
1173 {
1174 crVBoxServerFBImageDataTerm(pData);
1175 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1176 return VERR_NO_MEMORY;
1177 }
1178 ++pData->cElements;
1179 }
1180 return VINF_SUCCESS;
1181}
1182
1183static int crVBoxServerFBImageDataInit(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite)
1184{
1185 return crVBoxServerFBImageDataInitEx(pData, pCtxInfo, pMural, fWrite, SHCROGL_SSM_VERSION, 0, 0);
1186}
1187
1188static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
1189{
1190 CRContextInfo *pCtxInfo;
1191 CRContext *pContext;
1192 CRMuralInfo *pMural;
1193 int32_t rc;
1194 GLuint i;
1195 struct
1196 {
1197 CRFBData data;
1198 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1199 } Data;
1200
1201 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1202
1203 pCtxInfo = cr_server.currentCtxInfo;
1204 pContext = pCtxInfo->pContext;
1205 pMural = pCtxInfo->currentMural;
1206
1207 rc = crVBoxServerFBImageDataInit(&Data.data, pCtxInfo, pMural, GL_FALSE);
1208 if (!RT_SUCCESS(rc))
1209 {
1210 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1211 return rc;
1212 }
1213
1214 rc = crStateAcquireFBImage(pContext, &Data.data);
1215 AssertRCReturn(rc, rc);
1216
1217 for (i = 0; i < Data.data.cElements; ++i)
1218 {
1219 CRFBDataElement * pEl = &Data.data.aElements[i];
1220 rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
1221 AssertRCReturn(rc, rc);
1222 }
1223
1224 crVBoxServerFBImageDataTerm(&Data.data);
1225
1226 return VINF_SUCCESS;
1227}
1228
1229#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
1230 if(!RT_SUCCESS((_rc))) { \
1231 AssertFailed(); \
1232 return; \
1233 } \
1234 } while (0)
1235
1236static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
1237{
1238 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1239 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1240 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1241 PSSMHANDLE pSSM = pData->pSSM;
1242 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1243 CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
1244
1245 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1246
1247 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1248
1249 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1250 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1251
1252 pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
1253 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1254
1255 crServerPerformMakeCurrent(pMural, pContextInfo);
1256
1257 pData->rc = crVBoxServerSaveFBImage(pSSM);
1258
1259 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1260 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1261 pContextInfo->currentMural = pInitialCurMural;
1262
1263 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1264}
1265
1266static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
1267{
1268 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1269 CRContext *pContext = pContextInfo->pContext;
1270 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1271 PSSMHANDLE pSSM = pData->pSSM;
1272 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
1273 CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
1274 const int32_t i32Dummy = 0;
1275
1276 AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
1277 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1278
1279 CRASSERT(pContext && pSSM);
1280 CRASSERT(pMural);
1281 CRASSERT(pMural->CreateInfo.externalID);
1282
1283 /* We could have skipped saving the key and use similar callback to load context states back,
1284 * but there's no guarantee we'd traverse hashtable in same order after loading.
1285 */
1286 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1287 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1288
1289#ifdef DEBUG_misha
1290 {
1291 unsigned long id;
1292 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
1293 crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
1294 else
1295 CRASSERT(id == key);
1296 }
1297#endif
1298
1299#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1300 if (pContextInfo->currentMural
1301 || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
1302 )
1303 {
1304 CRASSERT(pMural->CreateInfo.externalID);
1305 CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1306 pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
1307 }
1308 else
1309 {
1310 /* this is a dummy mural */
1311 CRASSERT(!pMural->width);
1312 CRASSERT(!pMural->height);
1313 CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1314 pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
1315 }
1316 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1317
1318 CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
1319 CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
1320 CRASSERT(cr_server.curClient);
1321
1322 crServerPerformMakeCurrent(pMural, pContextInfo);
1323#endif
1324
1325 pData->rc = crStateSaveContext(pContext, pSSM);
1326 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1327
1328 pData->rc = crVBoxServerSaveFBImage(pSSM);
1329 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1330
1331 /* restore the initial current mural */
1332 pContextInfo->currentMural = pContextCurrentMural;
1333}
1334
1335#if 0
1336typedef struct CR_SERVER_CHECK_BUFFERS
1337{
1338 CRBufferObject *obj;
1339 CRContext *ctx;
1340}CR_SERVER_CHECK_BUFFERS, *PCR_SERVER_CHECK_BUFFERS;
1341
1342static void crVBoxServerCheckConsistencyContextBuffersCB(unsigned long key, void *data1, void *data2)
1343{
1344 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1345 CRContext *ctx = pContextInfo->pContext;
1346 PCR_SERVER_CHECK_BUFFERS pBuffers = (PCR_SERVER_CHECK_BUFFERS)data2;
1347 CRBufferObject *obj = pBuffers->obj;
1348 CRBufferObjectState *b = &(ctx->bufferobject);
1349 int j, k;
1350
1351 if (obj == b->arrayBuffer)
1352 {
1353 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1354 pBuffers->ctx = ctx;
1355 }
1356 if (obj == b->elementsBuffer)
1357 {
1358 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1359 pBuffers->ctx = ctx;
1360 }
1361#ifdef CR_ARB_pixel_buffer_object
1362 if (obj == b->packBuffer)
1363 {
1364 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1365 pBuffers->ctx = ctx;
1366 }
1367 if (obj == b->unpackBuffer)
1368 {
1369 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1370 pBuffers->ctx = ctx;
1371 }
1372#endif
1373
1374#ifdef CR_ARB_vertex_buffer_object
1375 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1376 {
1377 CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array);
1378 if (obj == cp->buffer)
1379 {
1380 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1381 pBuffers->ctx = ctx;
1382 }
1383 }
1384
1385 for (k=0; k<ctx->client.vertexArrayStackDepth; ++k)
1386 {
1387 CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k];
1388 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1389 {
1390 CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray);
1391 if (obj == cp->buffer)
1392 {
1393 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1394 pBuffers->ctx = ctx;
1395 }
1396 }
1397 }
1398#endif
1399}
1400
1401static void crVBoxServerCheckConsistencyBuffersCB(unsigned long key, void *data1, void *data2)
1402{
1403 CRBufferObject *obj = (CRBufferObject *)data1;
1404 CR_SERVER_CHECK_BUFFERS Buffers = {0};
1405 Buffers.obj = obj;
1406 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckConsistencyContextBuffersCB, (void*)&Buffers);
1407}
1408
1409//static void crVBoxServerCheckConsistency2CB(unsigned long key, void *data1, void *data2)
1410//{
1411// CRContextInfo* pContextInfo1 = (CRContextInfo*)data1;
1412// CRContextInfo* pContextInfo2 = (CRContextInfo*)data2;
1413//
1414// CRASSERT(pContextInfo1->pContext);
1415// CRASSERT(pContextInfo2->pContext);
1416//
1417// if (pContextInfo1 == pContextInfo2)
1418// {
1419// CRASSERT(pContextInfo1->pContext == pContextInfo2->pContext);
1420// return;
1421// }
1422//
1423// CRASSERT(pContextInfo1->pContext != pContextInfo2->pContext);
1424// CRASSERT(pContextInfo1->pContext->shared);
1425// CRASSERT(pContextInfo2->pContext->shared);
1426// CRASSERT(pContextInfo1->pContext->shared == pContextInfo2->pContext->shared);
1427// if (pContextInfo1->pContext->shared != pContextInfo2->pContext->shared)
1428// return;
1429//
1430// crHashtableWalk(pContextInfo1->pContext->shared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, pContextInfo2);
1431//}
1432static void crVBoxServerCheckSharedCB(unsigned long key, void *data1, void *data2)
1433{
1434 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1435 void **ppShared = (void**)data2;
1436 if (!*ppShared)
1437 *ppShared = pContextInfo->pContext->shared;
1438 else
1439 Assert(pContextInfo->pContext->shared == *ppShared);
1440}
1441
1442static void crVBoxServerCheckConsistency()
1443{
1444 CRSharedState *pShared = NULL;
1445 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckSharedCB, (void*)&pShared);
1446 Assert(pShared);
1447 if (pShared)
1448 {
1449 crHashtableWalk(pShared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, NULL);
1450 }
1451}
1452#endif
1453
1454static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
1455
1456DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
1457{
1458 int32_t rc, i;
1459 uint32_t ui32;
1460 GLboolean b;
1461 unsigned long key;
1462 GLenum err;
1463#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1464 CRClient *curClient;
1465 CRMuralInfo *curMural = NULL;
1466 CRContextInfo *curCtxInfo = NULL;
1467#endif
1468 CRVBOX_SAVE_STATE_GLOBAL Data;
1469
1470 crMemset(&Data, 0, sizeof (Data));
1471
1472#if 0
1473 crVBoxServerCheckConsistency();
1474#endif
1475
1476 /* We shouldn't be called if there's no clients at all*/
1477 CRASSERT(cr_server.numClients>0);
1478
1479 /* @todo it's hack atm */
1480 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1481 * for every connected client (e.g. guest opengl application)
1482 */
1483 if (!cr_server.bIsInSavingState) /* It's first call */
1484 {
1485 cr_server.bIsInSavingState = GL_TRUE;
1486
1487 /* Store number of clients */
1488 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1489 AssertRCReturn(rc, rc);
1490
1491 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
1492 }
1493
1494 g_hackVBoxServerSaveLoadCallsLeft--;
1495
1496 /* Do nothing until we're being called last time */
1497 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1498 {
1499 return VINF_SUCCESS;
1500 }
1501
1502#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart"
1503#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop"
1504
1505 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1506 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START);
1507
1508 /* Save rendering contexts creation info */
1509 ui32 = crHashtableNumElements(cr_server.contextTable);
1510 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1511 AssertRCReturn(rc, rc);
1512 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1513
1514#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1515 curClient = cr_server.curClient;
1516 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1517 if (curClient)
1518 {
1519 curCtxInfo = cr_server.curClient->currentCtxInfo;
1520 curMural = cr_server.curClient->currentMural;
1521 }
1522 else if (cr_server.numClients)
1523 {
1524 cr_server.curClient = cr_server.clients[0];
1525 }
1526#endif
1527
1528 /* first save windows info */
1529 /* Save windows creation info */
1530 ui32 = crHashtableNumElements(cr_server.muralTable);
1531 /* There should be default mural always */
1532 CRASSERT(ui32>=1);
1533 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1534 AssertRCReturn(rc, rc);
1535 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1536
1537 /* Save cr_server.muralTable
1538 * @todo we don't need it all, just geometry info actually
1539 */
1540 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1541 AssertRCReturn(rc, rc);
1542 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1543
1544 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1545 crVBoxServerBuildSaveStateGlobal(&Data);
1546
1547 rc = crStateSaveGlobals(pSSM);
1548 AssertRCReturn(rc, rc);
1549
1550 Data.pSSM = pSSM;
1551 /* Save contexts state tracker data */
1552 /* @todo For now just some blind data dumps,
1553 * but I've a feeling those should be saved/restored in a very strict sequence to
1554 * allow diff_api to work correctly.
1555 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1556 */
1557 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1558 AssertRCReturn(Data.rc, Data.rc);
1559
1560 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1561 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1562 AssertRCReturn(rc, rc);
1563
1564 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1565 AssertRCReturn(Data.rc, Data.rc);
1566
1567#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1568 cr_server.curClient = curClient;
1569 /* Restore original win and ctx IDs*/
1570 if (curClient && curMural && curCtxInfo)
1571 {
1572 crServerPerformMakeCurrent(curMural, curCtxInfo);
1573 }
1574 else
1575 {
1576 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1577 }
1578#endif
1579
1580 /* Save clients info */
1581 for (i = 0; i < cr_server.numClients; i++)
1582 {
1583 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1584 {
1585 CRClient *pClient = cr_server.clients[i];
1586
1587 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1588 AssertRCReturn(rc, rc);
1589
1590 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1591 AssertRCReturn(rc, rc);
1592
1593 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1594 AssertRCReturn(rc, rc);
1595
1596 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1597 AssertRCReturn(rc, rc);
1598
1599 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0)
1600 {
1601 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1602 CRASSERT(b);
1603 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1604 AssertRCReturn(rc, rc);
1605 }
1606
1607 if (pClient->currentMural && pClient->currentWindow>=0)
1608 {
1609 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1610 CRASSERT(b);
1611 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1612 AssertRCReturn(rc, rc);
1613 }
1614 }
1615 }
1616
1617 /* all context gl error states should have now be synced with chromium erro states,
1618 * reset the error if any */
1619 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1620 crWarning("crServer: glGetError %d after saving snapshot", err);
1621
1622 cr_server.bIsInSavingState = GL_FALSE;
1623
1624 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1625 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
1626
1627 return VINF_SUCCESS;
1628}
1629
1630static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1631{
1632 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1633 CRASSERT(pContextInfo);
1634 CRASSERT(pContextInfo->pContext);
1635 return pContextInfo->pContext;
1636}
1637
1638static int32_t crVBoxServerLoadMurals(PSSMHANDLE pSSM, uint32_t version)
1639{
1640 unsigned long key;
1641 uint32_t ui, uiNumElems;
1642 /* Load windows */
1643 int32_t rc = SSMR3GetU32(pSSM, &uiNumElems);
1644 AssertRCReturn(rc, rc);
1645 for (ui=0; ui<uiNumElems; ++ui)
1646 {
1647 CRCreateInfo_t createInfo;
1648 char psz[200];
1649 GLint winID;
1650 unsigned long key;
1651
1652 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1653 AssertRCReturn(rc, rc);
1654 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1655 AssertRCReturn(rc, rc);
1656
1657 if (createInfo.pszDpyName)
1658 {
1659 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1660 AssertRCReturn(rc, rc);
1661 createInfo.pszDpyName = psz;
1662 }
1663
1664 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1665 CRASSERT((int64_t)winID == (int64_t)key);
1666 }
1667
1668 /* Load cr_server.muralTable */
1669 rc = SSMR3GetU32(pSSM, &uiNumElems);
1670 AssertRCReturn(rc, rc);
1671 for (ui=0; ui<uiNumElems; ++ui)
1672 {
1673 CRMuralInfo muralInfo;
1674
1675 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1676 AssertRCReturn(rc, rc);
1677 rc = SSMR3GetMem(pSSM, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1678 AssertRCReturn(rc, rc);
1679
1680 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1681 muralInfo.bFbDraw = GL_TRUE;
1682
1683 if (muralInfo.pVisibleRects)
1684 {
1685 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
1686 if (!muralInfo.pVisibleRects)
1687 {
1688 return VERR_NO_MEMORY;
1689 }
1690
1691 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
1692 AssertRCReturn(rc, rc);
1693 }
1694
1695 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
1696 {
1697 CRMuralInfo *pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);;
1698 CRASSERT(pActualMural);
1699 rc = SSMR3GetMem(pSSM, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
1700 CRASSERT(rc == VINF_SUCCESS);
1701 }
1702
1703 /* Restore windows geometry info */
1704 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
1705 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
1706 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
1707 if (muralInfo.bReceivedRects)
1708 {
1709 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
1710 }
1711 crServerDispatchWindowShow(key, muralInfo.bVisible);
1712
1713 if (muralInfo.pVisibleRects)
1714 {
1715 crFree(muralInfo.pVisibleRects);
1716 }
1717 }
1718
1719 CRASSERT(RT_SUCCESS(rc));
1720 return VINF_SUCCESS;
1721}
1722
1723static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
1724 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
1725{
1726 CRContext *pContext = pContextInfo->pContext;
1727 int32_t rc = VINF_SUCCESS;
1728 GLuint i;
1729 /* can apply the data right away */
1730 struct
1731 {
1732 CRFBData data;
1733 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1734 } Data;
1735
1736 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1737
1738 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1739 {
1740 if (!pMural->width || !pMural->height)
1741 return VINF_SUCCESS;
1742
1743 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
1744 if (!RT_SUCCESS(rc))
1745 {
1746 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1747 return rc;
1748 }
1749 }
1750 else
1751 {
1752 GLint storedWidth, storedHeight;
1753
1754 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1755 {
1756 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1757 CRASSERT(cr_server.currentMural = pMural);
1758 storedWidth = pMural->width;
1759 storedHeight = pMural->height;
1760 }
1761 else
1762 {
1763 storedWidth = pContext->buffer.storedWidth;
1764 storedHeight = pContext->buffer.storedHeight;
1765 }
1766
1767 if (!storedWidth || !storedHeight)
1768 return VINF_SUCCESS;
1769
1770 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
1771 if (!RT_SUCCESS(rc))
1772 {
1773 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1774 return rc;
1775 }
1776 }
1777
1778 CRASSERT(Data.data.cElements);
1779
1780 for (i = 0; i < Data.data.cElements; ++i)
1781 {
1782 CRFBDataElement * pEl = &Data.data.aElements[i];
1783 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
1784 AssertRCReturn(rc, rc);
1785 }
1786
1787 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1788 {
1789 CRBufferState *pBuf = &pContext->buffer;
1790 /* can apply the data right away */
1791 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
1792 CRASSERT(cr_server.currentMural);
1793
1794 cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
1795 0,
1796 pContextInfo->SpuContext >= 0
1797 ? pContextInfo->SpuContext
1798 : cr_server.MainContextInfo.SpuContext);
1799 crStateApplyFBImage(pContext, &Data.data);
1800 CRASSERT(!pBuf->pFrontImg);
1801 CRASSERT(!pBuf->pBackImg);
1802 crVBoxServerFBImageDataTerm(&Data.data);
1803
1804 if (pMural->fUseFBO && pMural->bVisible)
1805 {
1806 crServerPresentFBO(pMural);
1807 }
1808
1809 CRASSERT(cr_server.currentMural);
1810 cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
1811 0,
1812 cr_server.currentCtxInfo->SpuContext >= 0
1813 ? cr_server.currentCtxInfo->SpuContext
1814 : cr_server.MainContextInfo.SpuContext);
1815 }
1816 else
1817 {
1818 CRBufferState *pBuf = &pContext->buffer;
1819 CRASSERT(!pBuf->pFrontImg);
1820 CRASSERT(!pBuf->pBackImg);
1821 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
1822
1823 if (Data.data.cElements)
1824 {
1825 CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1826 if (!RT_SUCCESS(rc))
1827 {
1828 crVBoxServerFBImageDataTerm(&Data.data);
1829 crWarning("crAlloc failed");
1830 return VERR_NO_MEMORY;
1831 }
1832
1833 crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1834 pBuf->pFrontImg = pLazyData;
1835 }
1836 }
1837
1838 CRASSERT(RT_SUCCESS(rc));
1839 return VINF_SUCCESS;
1840}
1841
1842DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
1843{
1844 int32_t rc, i;
1845 uint32_t ui, uiNumElems;
1846 unsigned long key;
1847 GLenum err;
1848
1849 if (!cr_server.bIsInLoadingState)
1850 {
1851 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
1852 cr_server.bIsInLoadingState = GL_TRUE;
1853
1854 /* Read number of clients */
1855 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
1856 AssertRCReturn(rc, rc);
1857 }
1858
1859 g_hackVBoxServerSaveLoadCallsLeft--;
1860
1861 /* Do nothing until we're being called last time */
1862 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1863 {
1864 return VINF_SUCCESS;
1865 }
1866
1867 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
1868 {
1869 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1870 }
1871
1872#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
1873#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
1874
1875 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1876 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
1877
1878 /* Load and recreate rendering contexts */
1879 rc = SSMR3GetU32(pSSM, &uiNumElems);
1880 AssertRCReturn(rc, rc);
1881 for (ui=0; ui<uiNumElems; ++ui)
1882 {
1883 CRCreateInfo_t createInfo;
1884 char psz[200];
1885 GLint ctxID;
1886 CRContextInfo* pContextInfo;
1887 CRContext* pContext;
1888
1889 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1890 AssertRCReturn(rc, rc);
1891 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1892 AssertRCReturn(rc, rc);
1893
1894 if (createInfo.pszDpyName)
1895 {
1896 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1897 AssertRCReturn(rc, rc);
1898 createInfo.pszDpyName = psz;
1899 }
1900
1901 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
1902 CRASSERT((int64_t)ctxID == (int64_t)key);
1903
1904 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1905 CRASSERT(pContextInfo);
1906 CRASSERT(pContextInfo->pContext);
1907 pContext = pContextInfo->pContext;
1908 pContext->shared->id=-1;
1909 }
1910
1911 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1912 {
1913 /* we have a mural data here */
1914 rc = crVBoxServerLoadMurals(pSSM, version);
1915 AssertRCReturn(rc, rc);
1916 }
1917
1918 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
1919 {
1920 /* set the current client to allow doing crServerPerformMakeCurrent later */
1921 CRASSERT(cr_server.numClients);
1922 cr_server.curClient = cr_server.clients[0];
1923 }
1924
1925 rc = crStateLoadGlobals(pSSM, version);
1926 AssertRCReturn(rc, rc);
1927
1928 if (uiNumElems)
1929 {
1930 /* ensure we have main context set up as current */
1931 CRMuralInfo *pMural;
1932 CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
1933 CRASSERT(!cr_server.currentCtxInfo);
1934 CRASSERT(!cr_server.currentMural);
1935 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
1936 CRASSERT(pMural);
1937 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
1938 }
1939
1940 /* Restore context state data */
1941 for (ui=0; ui<uiNumElems; ++ui)
1942 {
1943 CRContextInfo* pContextInfo;
1944 CRContext *pContext;
1945 CRMuralInfo *pMural = NULL;
1946 int32_t winId = 0;
1947
1948 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1949 AssertRCReturn(rc, rc);
1950
1951 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1952 CRASSERT(pContextInfo);
1953 CRASSERT(pContextInfo->pContext);
1954 pContext = pContextInfo->pContext;
1955
1956 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1957 {
1958 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
1959 AssertRCReturn(rc, rc);
1960
1961 if (winId)
1962 {
1963 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
1964 CRASSERT(pMural);
1965 }
1966 else
1967 {
1968 /* null winId means a dummy mural, get it */
1969 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
1970 CRASSERT(pMural);
1971 }
1972 }
1973
1974 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
1975 AssertRCReturn(rc, rc);
1976
1977 /*Restore front/back buffer images*/
1978 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1979 AssertRCReturn(rc, rc);
1980 }
1981
1982 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1983 {
1984 CRContextInfo *pContextInfo;
1985 CRMuralInfo *pMural;
1986 GLint ctxId;
1987
1988 rc = SSMR3GetU32(pSSM, &uiNumElems);
1989 AssertRCReturn(rc, rc);
1990 for (ui=0; ui<uiNumElems; ++ui)
1991 {
1992 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1993 CRMuralInfo *pInitialCurMural;
1994
1995 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1996 AssertRCReturn(rc, rc);
1997
1998 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
1999 AssertRCReturn(rc, rc);
2000
2001 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
2002 CRASSERT(pMural);
2003 if (ctxId)
2004 {
2005 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
2006 CRASSERT(pContextInfo);
2007 }
2008 else
2009 pContextInfo = &cr_server.MainContextInfo;
2010
2011 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
2012 pInitialCurMural = pContextInfo->currentMural;
2013
2014 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2015 AssertRCReturn(rc, rc);
2016
2017 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
2018 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
2019 pContextInfo->currentMural = pInitialCurMural;
2020 }
2021
2022 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2023
2024 cr_server.curClient = NULL;
2025 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
2026 }
2027 else
2028 {
2029 CRServerFreeIDsPool_t dummyIdsPool;
2030
2031 /* we have a mural data here */
2032 rc = crVBoxServerLoadMurals(pSSM, version);
2033 AssertRCReturn(rc, rc);
2034
2035 /* not used any more, just read it out and ignore */
2036 rc = SSMR3GetMem(pSSM, &dummyIdsPool, sizeof(dummyIdsPool));
2037 CRASSERT(rc == VINF_SUCCESS);
2038 }
2039
2040 /* Load clients info */
2041 for (i = 0; i < cr_server.numClients; i++)
2042 {
2043 if (cr_server.clients[i] && cr_server.clients[i]->conn)
2044 {
2045 CRClient *pClient = cr_server.clients[i];
2046 CRClient client;
2047 unsigned long ctxID=-1, winID=-1;
2048
2049 rc = SSMR3GetU32(pSSM, &ui);
2050 AssertRCReturn(rc, rc);
2051 /* If this assert fires, then we should search correct client in the list first*/
2052 CRASSERT(ui == pClient->conn->u32ClientID);
2053
2054 if (version>=4)
2055 {
2056 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
2057 AssertRCReturn(rc, rc);
2058
2059 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
2060 AssertRCReturn(rc, rc);
2061 }
2062
2063 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
2064 CRASSERT(rc == VINF_SUCCESS);
2065
2066 client.conn = pClient->conn;
2067 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2068 * and fail to bind old textures.
2069 */
2070 /*client.number = pClient->number;*/
2071 *pClient = client;
2072
2073 pClient->currentContextNumber = -1;
2074 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2075 pClient->currentMural = NULL;
2076 pClient->currentWindow = -1;
2077
2078 cr_server.curClient = pClient;
2079
2080 if (client.currentCtxInfo && client.currentContextNumber>=0)
2081 {
2082 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
2083 AssertRCReturn(rc, rc);
2084 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2085 CRASSERT(client.currentCtxInfo);
2086 CRASSERT(client.currentCtxInfo->pContext);
2087 //pClient->currentCtx = client.currentCtx;
2088 //pClient->currentContextNumber = ctxID;
2089 }
2090
2091 if (client.currentMural && client.currentWindow>=0)
2092 {
2093 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
2094 AssertRCReturn(rc, rc);
2095 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2096 CRASSERT(client.currentMural);
2097 //pClient->currentMural = client.currentMural;
2098 //pClient->currentWindow = winID;
2099 }
2100
2101 /* Restore client active context and window */
2102 crServerDispatchMakeCurrent(winID, 0, ctxID);
2103
2104 if (0)
2105 {
2106// CRContext *tmpCtx;
2107// CRCreateInfo_t *createInfo;
2108 GLfloat one[4] = { 1, 1, 1, 1 };
2109 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
2110
2111 crServerDispatchMakeCurrent(winID, 0, ctxID);
2112
2113 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
2114
2115 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
2116 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
2117 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
2118#ifdef CR_ARB_texture_cube_map
2119 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
2120#endif
2121#ifdef CR_NV_texture_rectangle
2122 //@todo this doesn't work as expected
2123 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
2124#endif
2125 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
2126 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
2127 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
2128
2129 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
2130 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
2131 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
2132
2133 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
2134 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
2135
2136 //crStateViewport( 0, 0, 600, 600 );
2137 //pClient->currentMural->viewportValidated = GL_FALSE;
2138 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
2139
2140 //crStateMatrixMode(GL_PROJECTION);
2141 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
2142
2143 //crStateLoadIdentity();
2144 //cr_server.head_spu->dispatch_table.LoadIdentity();
2145
2146 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2147 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2148
2149 //crStateMatrixMode(GL_MODELVIEW);
2150 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
2151 //crServerDispatchLoadIdentity();
2152 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2153 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2154 //crServerDispatchLoadIdentity();
2155
2156 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
2157 CRASSERT(createInfo);
2158 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
2159 CRASSERT(tmpCtx);
2160 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
2161 crStateDestroyContext(tmpCtx);*/
2162 }
2163 }
2164 }
2165
2166 //crServerDispatchMakeCurrent(-1, 0, -1);
2167
2168 cr_server.curClient = NULL;
2169
2170 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2171 crWarning("crServer: glGetError %d after loading snapshot", err);
2172
2173 cr_server.bIsInLoadingState = GL_FALSE;
2174
2175#if 0
2176 crVBoxServerCheckConsistency();
2177#endif
2178
2179 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2180 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
2181
2182
2183 return VINF_SUCCESS;
2184}
2185
2186#define SCREEN(i) (cr_server.screen[i])
2187#define MAPPED(screen) ((screen).winID != 0)
2188
2189static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2190{
2191 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2192 int *sIndex = (int*) data2;
2193
2194 if (pMI->screenId == *sIndex)
2195 {
2196 renderspuReparentWindow(pMI->spuWindow);
2197 }
2198}
2199
2200static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
2201{
2202 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2203 (void) data2;
2204
2205 crServerCheckMuralGeometry(pMI);
2206}
2207
2208DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2209{
2210 int i;
2211
2212 if (sCount>CR_MAX_GUEST_MONITORS)
2213 return VERR_INVALID_PARAMETER;
2214
2215 /*Shouldn't happen yet, but to be safe in future*/
2216 for (i=0; i<cr_server.screenCount; ++i)
2217 {
2218 if (MAPPED(SCREEN(i)))
2219 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
2220 return VERR_NOT_IMPLEMENTED;
2221 }
2222
2223 cr_server.screenCount = sCount;
2224
2225 for (i=0; i<sCount; ++i)
2226 {
2227 SCREEN(i).winID = 0;
2228 }
2229
2230 return VINF_SUCCESS;
2231}
2232
2233DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2234{
2235 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2236
2237 if (sIndex<0 || sIndex>=cr_server.screenCount)
2238 return VERR_INVALID_PARAMETER;
2239
2240 if (MAPPED(SCREEN(sIndex)))
2241 {
2242 SCREEN(sIndex).winID = 0;
2243 renderspuSetWindowId(0);
2244
2245 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2246 }
2247
2248 renderspuSetWindowId(SCREEN(0).winID);
2249 return VINF_SUCCESS;
2250}
2251
2252DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2253{
2254 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2255
2256 if (sIndex<0 || sIndex>=cr_server.screenCount)
2257 return VERR_INVALID_PARAMETER;
2258
2259 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2260 {
2261 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2262 crVBoxServerUnmapScreen(sIndex);
2263 }
2264
2265 SCREEN(sIndex).winID = winID;
2266 SCREEN(sIndex).x = x;
2267 SCREEN(sIndex).y = y;
2268 SCREEN(sIndex).w = w;
2269 SCREEN(sIndex).h = h;
2270
2271 renderspuSetWindowId(SCREEN(sIndex).winID);
2272 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2273 renderspuSetWindowId(SCREEN(0).winID);
2274
2275 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2276
2277#ifndef WINDOWS
2278 /*Restore FB content for clients, which have current window on a screen being remapped*/
2279 {
2280 GLint i;
2281
2282 for (i = 0; i < cr_server.numClients; i++)
2283 {
2284 cr_server.curClient = cr_server.clients[i];
2285 if (cr_server.curClient->currentCtxInfo
2286 && cr_server.curClient->currentCtxInfo->pContext
2287 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2288 && cr_server.curClient->currentMural
2289 && cr_server.curClient->currentMural->screenId == sIndex
2290 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2291 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2292 {
2293 int clientWindow = cr_server.curClient->currentWindow;
2294 int clientContext = cr_server.curClient->currentContextNumber;
2295 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2296
2297 if (clientWindow && clientWindow != cr_server.currentWindow)
2298 {
2299 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2300 }
2301
2302 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2303 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2304 }
2305 }
2306 cr_server.curClient = NULL;
2307 }
2308#endif
2309
2310 {
2311 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
2312 if (pDisplay)
2313 CrDpResize(pDisplay, w, h, w, h);
2314 }
2315
2316 return VINF_SUCCESS;
2317}
2318
2319DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
2320{
2321 renderspuSetRootVisibleRegion(cRects, pRects);
2322
2323 return VINF_SUCCESS;
2324}
2325
2326DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2327{
2328 cr_server.pfnPresentFBO = pfnPresentFBO;
2329}
2330
2331int32_t crServerSetOffscreenRenderingMode(GLubyte value)
2332{
2333 if (cr_server.bForceOffscreenRendering==value)
2334 {
2335 return VINF_SUCCESS;
2336 }
2337
2338 if (value > CR_SERVER_REDIR_MAXVAL)
2339 {
2340 crWarning("crServerSetOffscreenRenderingMode: invalid arg: %d", value);
2341 return VERR_INVALID_PARAMETER;
2342 }
2343
2344 if (value && !crServerSupportRedirMuralFBO())
2345 {
2346 return VERR_NOT_SUPPORTED;
2347 }
2348
2349 cr_server.bForceOffscreenRendering=value;
2350
2351 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2352
2353 return VINF_SUCCESS;
2354}
2355
2356DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2357{
2358 return crServerSetOffscreenRenderingMode(value ? CR_SERVER_REDIR_FBO_RAM : cr_server.bOffscreenRenderingDefault);
2359}
2360
2361DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2362{
2363 /* No need for a synchronization as this is single threaded. */
2364 if (pCallbacks)
2365 {
2366 cr_server.outputRedirect = *pCallbacks;
2367 cr_server.bUseOutputRedirect = true;
2368 }
2369 else
2370 {
2371 cr_server.bUseOutputRedirect = false;
2372 }
2373
2374 // @todo dynamically intercept already existing output:
2375 // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
2376
2377 return VINF_SUCCESS;
2378}
2379
2380static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2)
2381{
2382 CRMuralInfo *mural = (CRMuralInfo*) data1;
2383 int *sIndex = (int*) data2;
2384
2385 if (mural->screenId != *sIndex)
2386 return;
2387
2388 crServerCheckMuralGeometry(mural);
2389}
2390
2391
2392DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2393{
2394 CRScreenViewportInfo *pVieport;
2395 GLboolean fPosChanged, fSizeChanged;
2396
2397 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2398
2399 if (sIndex<0 || sIndex>=cr_server.screenCount)
2400 {
2401 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2402 return VERR_INVALID_PARAMETER;
2403 }
2404
2405 pVieport = &cr_server.screenVieport[sIndex];
2406 fPosChanged = (pVieport->x != x || pVieport->y != y);
2407 fSizeChanged = (pVieport->w != w || pVieport->h != h);
2408
2409 if (!fPosChanged && !fSizeChanged)
2410 {
2411 crDebug("crVBoxServerSetScreenViewport: no changes");
2412 return VINF_SUCCESS;
2413 }
2414
2415 if (fPosChanged)
2416 {
2417 pVieport->x = x;
2418 pVieport->y = y;
2419
2420 crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex);
2421 }
2422
2423 if (fSizeChanged)
2424 {
2425 pVieport->w = w;
2426 pVieport->h = h;
2427
2428 /* no need to do anything here actually */
2429 }
2430 return VINF_SUCCESS;
2431}
2432
2433
2434#ifdef VBOX_WITH_CRHGSMI
2435/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
2436 *
2437 * 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.
2438 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
2439 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
2440 * to block the lower-priority thread trying to complete the blocking command.
2441 * And removed extra memcpy done on blocked command arrival.
2442 *
2443 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
2444 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
2445 *
2446 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
2447 * */
2448int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
2449{
2450 int32_t rc;
2451 uint32_t cBuffers = pCmd->cBuffers;
2452 uint32_t cParams;
2453 uint32_t cbHdr;
2454 CRVBOXHGSMIHDR *pHdr;
2455 uint32_t u32Function;
2456 uint32_t u32ClientID;
2457 CRClient *pClient;
2458
2459 if (!g_pvVRamBase)
2460 {
2461 crWarning("g_pvVRamBase is not initialized");
2462 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
2463 return VINF_SUCCESS;
2464 }
2465
2466 if (!cBuffers)
2467 {
2468 crWarning("zero buffers passed in!");
2469 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2470 return VINF_SUCCESS;
2471 }
2472
2473 cParams = cBuffers-1;
2474
2475 cbHdr = pCmd->aBuffers[0].cbBuffer;
2476 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2477 if (!pHdr)
2478 {
2479 crWarning("invalid header buffer!");
2480 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2481 return VINF_SUCCESS;
2482 }
2483
2484 if (cbHdr < sizeof (*pHdr))
2485 {
2486 crWarning("invalid header buffer size!");
2487 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2488 return VINF_SUCCESS;
2489 }
2490
2491 u32Function = pHdr->u32Function;
2492 u32ClientID = pHdr->u32ClientID;
2493
2494 switch (u32Function)
2495 {
2496 case SHCRGL_GUEST_FN_WRITE:
2497 {
2498 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2499
2500 /* @todo: Verify */
2501 if (cParams == 1)
2502 {
2503 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2504 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2505 /* Fetch parameters. */
2506 uint32_t cbBuffer = pBuf->cbBuffer;
2507 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2508
2509 if (cbHdr < sizeof (*pFnCmd))
2510 {
2511 crWarning("invalid write cmd buffer size!");
2512 rc = VERR_INVALID_PARAMETER;
2513 break;
2514 }
2515
2516 CRASSERT(cbBuffer);
2517 if (!pBuffer)
2518 {
2519 crWarning("invalid buffer data received from guest!");
2520 rc = VERR_INVALID_PARAMETER;
2521 break;
2522 }
2523
2524 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2525 if (RT_FAILURE(rc))
2526 {
2527 break;
2528 }
2529
2530 /* This should never fire unless we start to multithread */
2531 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2532 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2533
2534 pClient->conn->pBuffer = pBuffer;
2535 pClient->conn->cbBuffer = cbBuffer;
2536 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2537 rc = crVBoxServerInternalClientWriteRead(pClient);
2538 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2539 return rc;
2540 }
2541 else
2542 {
2543 crWarning("invalid number of args");
2544 rc = VERR_INVALID_PARAMETER;
2545 break;
2546 }
2547 break;
2548 }
2549
2550 case SHCRGL_GUEST_FN_INJECT:
2551 {
2552 crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2553
2554 /* @todo: Verify */
2555 if (cParams == 1)
2556 {
2557 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2558 /* Fetch parameters. */
2559 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2560 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2561 uint32_t cbBuffer = pBuf->cbBuffer;
2562 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2563
2564 if (cbHdr < sizeof (*pFnCmd))
2565 {
2566 crWarning("invalid inject cmd buffer size!");
2567 rc = VERR_INVALID_PARAMETER;
2568 break;
2569 }
2570
2571 CRASSERT(cbBuffer);
2572 if (!pBuffer)
2573 {
2574 crWarning("invalid buffer data received from guest!");
2575 rc = VERR_INVALID_PARAMETER;
2576 break;
2577 }
2578
2579 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
2580 if (RT_FAILURE(rc))
2581 {
2582 break;
2583 }
2584
2585 /* This should never fire unless we start to multithread */
2586 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2587 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2588
2589 pClient->conn->pBuffer = pBuffer;
2590 pClient->conn->cbBuffer = cbBuffer;
2591 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2592 rc = crVBoxServerInternalClientWriteRead(pClient);
2593 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2594 return rc;
2595 }
2596
2597 crWarning("invalid number of args");
2598 rc = VERR_INVALID_PARAMETER;
2599 break;
2600 }
2601
2602 case SHCRGL_GUEST_FN_READ:
2603 {
2604 crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n"));
2605
2606 /* @todo: Verify */
2607 if (cParams == 1)
2608 {
2609 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
2610 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2611 /* Fetch parameters. */
2612 uint32_t cbBuffer = pBuf->cbBuffer;
2613 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2614
2615 if (cbHdr < sizeof (*pFnCmd))
2616 {
2617 crWarning("invalid read cmd buffer size!");
2618 rc = VERR_INVALID_PARAMETER;
2619 break;
2620 }
2621
2622
2623 if (!pBuffer)
2624 {
2625 crWarning("invalid buffer data received from guest!");
2626 rc = VERR_INVALID_PARAMETER;
2627 break;
2628 }
2629
2630 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2631 if (RT_FAILURE(rc))
2632 {
2633 break;
2634 }
2635
2636 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2637
2638 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
2639
2640 /* Return the required buffer size always */
2641 pFnCmd->cbBuffer = cbBuffer;
2642
2643 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2644
2645 /* the read command is never pended, complete it right away */
2646 pHdr->result = rc;
2647 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2648 return VINF_SUCCESS;
2649 }
2650
2651 crWarning("invalid number of args");
2652 rc = VERR_INVALID_PARAMETER;
2653 break;
2654 }
2655
2656 case SHCRGL_GUEST_FN_WRITE_READ:
2657 {
2658 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
2659
2660 /* @todo: Verify */
2661 if (cParams == 2)
2662 {
2663 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
2664 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2665 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
2666
2667 /* Fetch parameters. */
2668 uint32_t cbBuffer = pBuf->cbBuffer;
2669 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2670
2671 uint32_t cbWriteback = pWbBuf->cbBuffer;
2672 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
2673
2674 if (cbHdr < sizeof (*pFnCmd))
2675 {
2676 crWarning("invalid write_read cmd buffer size!");
2677 rc = VERR_INVALID_PARAMETER;
2678 break;
2679 }
2680
2681
2682 CRASSERT(cbBuffer);
2683 if (!pBuffer)
2684 {
2685 crWarning("invalid write buffer data received from guest!");
2686 rc = VERR_INVALID_PARAMETER;
2687 break;
2688 }
2689
2690 CRASSERT(cbWriteback);
2691 if (!pWriteback)
2692 {
2693 crWarning("invalid writeback buffer data received from guest!");
2694 rc = VERR_INVALID_PARAMETER;
2695 break;
2696 }
2697 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2698 if (RT_FAILURE(rc))
2699 {
2700 pHdr->result = rc;
2701 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2702 return rc;
2703 }
2704
2705 /* This should never fire unless we start to multithread */
2706 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2707 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2708
2709 pClient->conn->pBuffer = pBuffer;
2710 pClient->conn->cbBuffer = cbBuffer;
2711 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
2712 rc = crVBoxServerInternalClientWriteRead(pClient);
2713 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2714 return rc;
2715 }
2716
2717 crWarning("invalid number of args");
2718 rc = VERR_INVALID_PARAMETER;
2719 break;
2720 }
2721
2722 case SHCRGL_GUEST_FN_SET_VERSION:
2723 {
2724 crWarning("invalid function");
2725 rc = VERR_NOT_IMPLEMENTED;
2726 break;
2727 }
2728
2729 case SHCRGL_GUEST_FN_SET_PID:
2730 {
2731 crWarning("invalid function");
2732 rc = VERR_NOT_IMPLEMENTED;
2733 break;
2734 }
2735
2736 default:
2737 {
2738 crWarning("invalid function");
2739 rc = VERR_NOT_IMPLEMENTED;
2740 break;
2741 }
2742
2743 }
2744
2745 /* we can be on fail only here */
2746 CRASSERT(RT_FAILURE(rc));
2747 pHdr->result = rc;
2748 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2749 return rc;
2750}
2751
2752int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
2753{
2754 int rc = VINF_SUCCESS;
2755
2756 switch (pCtl->enmType)
2757 {
2758 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
2759 {
2760 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
2761 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
2762 g_cbVRam = pSetup->cbVRam;
2763 rc = VINF_SUCCESS;
2764 break;
2765 }
2766 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
2767 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
2768 rc = VINF_SUCCESS;
2769 break;
2770 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
2771 {
2772 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
2773 g_hCrHgsmiCompletion = pSetup->hCompletion;
2774 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
2775 rc = VINF_SUCCESS;
2776 break;
2777 }
2778 default:
2779 AssertMsgFailed(("invalid param %d", pCtl->enmType));
2780 rc = VERR_INVALID_PARAMETER;
2781 }
2782
2783 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
2784 * to complete them accordingly.
2785 * This approach allows using host->host and host->guest commands in the same way here
2786 * making the command completion to be the responsibility of the command originator.
2787 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
2788 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
2789 return rc;
2790}
2791#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