VirtualBox

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

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

crOpenGL: keep zero external ID for default mural

  • 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, CR_RENDER_DEFAULT_WINDOW_ID, 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, CR_RENDER_DEFAULT_WINDOW_ID, 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 return;
832
833 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
834 {
835 Assert(crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
836 return;
837 }
838
839 Assert(!crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
840
841 if (cr_server.MainContextInfo.CreateInfo.visualBits == pMural->CreateInfo.visualBits)
842 {
843 pContextInfo = &cr_server.MainContextInfo;
844 }
845 else
846 {
847 crWarning("different visual bits not implemented!");
848 pContextInfo = &cr_server.MainContextInfo;
849 }
850
851 crHashtableAdd(pData->pGlobal->additionalMuralContextTable, pMural->CreateInfo.externalID, pContextInfo);
852}
853
854
855typedef struct CRVBOX_CTXWND_WNDWALKER_CB
856{
857 PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
858 CRHashTable *usedMuralTable;
859 CRContextInfo *pContextInfo;
860 CRMuralInfo * pMural;
861} CRVBOX_CTXWND_WNDWALKER_CB, *PCRVBOX_CTXWND_WNDWALKER_CB;
862
863static void crVBoxServerBuildContextWindowMapWindowWalkerCB(unsigned long key, void *data1, void *data2)
864{
865 CRMuralInfo * pMural = (CRMuralInfo *) data1;
866 PCRVBOX_CTXWND_WNDWALKER_CB pData = (PCRVBOX_CTXWND_WNDWALKER_CB)data2;
867
868 Assert(pData->pMural != pMural);
869 Assert(pData->pContextInfo);
870
871 if (pData->pMural)
872 return;
873
874 if (!pMural->CreateInfo.externalID)
875 return;
876
877 if (!CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pData->pContextInfo->pContext))
878 return;
879
880 if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
881 return;
882
883 CRASSERT(pMural->CreateInfo.visualBits == pData->pContextInfo->CreateInfo.visualBits);
884 pData->pMural = pMural;
885}
886
887static void crVBoxServerBuildContextUsedWindowMapCB(unsigned long key, void *data1, void *data2)
888{
889 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
890 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
891
892 if (!pContextInfo->currentMural)
893 return;
894
895 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pContextInfo->currentMural);
896 crHashtableAdd(pData->usedMuralTable, pContextInfo->currentMural->CreateInfo.externalID, pContextInfo->currentMural);
897}
898
899CRMuralInfo * crServerGetDummyMural(GLint visualBits)
900{
901 CRMuralInfo * pMural = (CRMuralInfo *)crHashtableSearch(cr_server.dummyMuralTable, visualBits);
902 if (!pMural)
903 {
904 GLint id;
905 pMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
906 if (!pMural)
907 {
908 crWarning("crCalloc failed!");
909 return NULL;
910 }
911 id = crServerMuralInit(pMural, "", visualBits, -1);
912 if (id < 0)
913 {
914 crWarning("crServerMuralInit failed!");
915 crFree(pMural);
916 return NULL;
917 }
918
919 crHashtableAdd(cr_server.dummyMuralTable, visualBits, pMural);
920 }
921
922 return pMural;
923}
924
925static void crVBoxServerBuildContextUnusedWindowMapCB(unsigned long key, void *data1, void *data2)
926{
927 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
928 PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
929 CRMuralInfo * pMural = NULL;
930
931 if (pContextInfo->currentMural)
932 return;
933
934 Assert(crHashtableNumElements(pData->pGlobal->contextMuralTable) <= crHashtableNumElements(cr_server.muralTable) - 1);
935 if (crHashtableNumElements(pData->pGlobal->contextMuralTable) < crHashtableNumElements(cr_server.muralTable) - 1)
936 {
937 CRVBOX_CTXWND_WNDWALKER_CB MuralData;
938 MuralData.pGlobal = pData->pGlobal;
939 MuralData.usedMuralTable = pData->usedMuralTable;
940 MuralData.pContextInfo = pContextInfo;
941 MuralData.pMural = NULL;
942
943 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildContextWindowMapWindowWalkerCB, &MuralData);
944
945 pMural = MuralData.pMural;
946
947 }
948
949 if (!pMural)
950 {
951 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
952 if (!pMural)
953 {
954 crWarning("crServerGetDummyMural failed");
955 return;
956 }
957 }
958 else
959 {
960 crHashtableAdd(pData->usedMuralTable, pMural->CreateInfo.externalID, pMural);
961 ++pData->cAdditionalMurals;
962 }
963
964 crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pMural);
965}
966
967static void crVBoxServerBuildSaveStateGlobal(PCRVBOX_SAVE_STATE_GLOBAL pGlobal)
968{
969 CRVBOX_CTXWND_CTXWALKER_CB Data;
970 GLuint cMurals;
971 pGlobal->contextMuralTable = crAllocHashtable();
972 pGlobal->additionalMuralContextTable = crAllocHashtable();
973 /* 1. go through all contexts and match all having currentMural set */
974 Data.pGlobal = pGlobal;
975 Data.usedMuralTable = crAllocHashtable();
976 Data.cAdditionalMurals = 0;
977 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUsedWindowMapCB, &Data);
978
979 cMurals = crHashtableNumElements(pGlobal->contextMuralTable);
980 CRASSERT(cMurals <= crHashtableNumElements(cr_server.contextTable));
981 CRASSERT(cMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
982 CRASSERT(cMurals == crHashtableNumElements(Data.usedMuralTable));
983 if (cMurals < crHashtableNumElements(cr_server.contextTable))
984 {
985 Data.cAdditionalMurals = 0;
986 crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUnusedWindowMapCB, &Data);
987 }
988
989 CRASSERT(crHashtableNumElements(pGlobal->contextMuralTable) == crHashtableNumElements(cr_server.contextTable));
990 CRASSERT(cMurals + Data.cAdditionalMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
991 if (cMurals + Data.cAdditionalMurals < crHashtableNumElements(cr_server.muralTable) - 1)
992 {
993 crHashtableWalk(cr_server.muralTable, crVBoxServerBuildAdditionalWindowContextMapCB, &Data);
994 CRASSERT(cMurals + Data.cAdditionalMurals + crHashtableNumElements(pGlobal->additionalMuralContextTable) == crHashtableNumElements(cr_server.muralTable) - 1);
995 }
996
997 crFreeHashtable(Data.usedMuralTable, NULL);
998}
999
1000static void crVBoxServerFBImageDataTerm(CRFBData *pData)
1001{
1002 GLuint i;
1003 for (i = 0; i < pData->cElements; ++i)
1004 {
1005 CRFBDataElement * pEl = &pData->aElements[i];
1006 if (pEl->pvData)
1007 {
1008 crFree(pEl->pvData);
1009 /* sanity */
1010 pEl->pvData = NULL;
1011 }
1012 }
1013 pData->cElements = 0;
1014}
1015
1016static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, uint32_t version, GLuint overrideWidth, GLuint overrideHeight)
1017{
1018 CRContext *pContext;
1019 GLuint i;
1020 GLfloat *pF;
1021 CRFBDataElement *pEl;
1022 GLuint width;
1023 GLuint height;
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#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart"
1497#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop"
1498
1499 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1500 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START);
1501
1502 /* Save rendering contexts creation info */
1503 ui32 = crHashtableNumElements(cr_server.contextTable);
1504 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1505 AssertRCReturn(rc, rc);
1506 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1507
1508#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1509 curClient = cr_server.curClient;
1510 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1511 if (curClient)
1512 {
1513 curCtxInfo = cr_server.curClient->currentCtxInfo;
1514 curMural = cr_server.curClient->currentMural;
1515 }
1516 else if (cr_server.numClients)
1517 {
1518 cr_server.curClient = cr_server.clients[0];
1519 }
1520#endif
1521
1522 /* first save windows info */
1523 /* Save windows creation info */
1524 ui32 = crHashtableNumElements(cr_server.muralTable);
1525 /* There should be default mural always */
1526 CRASSERT(ui32>=1);
1527 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1528 AssertRCReturn(rc, rc);
1529 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1530
1531 /* Save cr_server.muralTable
1532 * @todo we don't need it all, just geometry info actually
1533 */
1534 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1535 AssertRCReturn(rc, rc);
1536 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1537
1538 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1539 crVBoxServerBuildSaveStateGlobal(&Data);
1540
1541 rc = crStateSaveGlobals(pSSM);
1542 AssertRCReturn(rc, rc);
1543
1544 Data.pSSM = pSSM;
1545 /* Save contexts state tracker data */
1546 /* @todo For now just some blind data dumps,
1547 * but I've a feeling those should be saved/restored in a very strict sequence to
1548 * allow diff_api to work correctly.
1549 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1550 */
1551 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1552 AssertRCReturn(Data.rc, Data.rc);
1553
1554 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1555 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1556 AssertRCReturn(rc, rc);
1557
1558 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1559 AssertRCReturn(Data.rc, Data.rc);
1560
1561#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1562 cr_server.curClient = curClient;
1563 /* Restore original win and ctx IDs*/
1564 if (curClient && curMural && curCtxInfo)
1565 {
1566 crServerPerformMakeCurrent(curMural, curCtxInfo);
1567 }
1568 else
1569 {
1570 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1571 }
1572#endif
1573
1574 /* Save clients info */
1575 for (i = 0; i < cr_server.numClients; i++)
1576 {
1577 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1578 {
1579 CRClient *pClient = cr_server.clients[i];
1580
1581 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1582 AssertRCReturn(rc, rc);
1583
1584 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1585 AssertRCReturn(rc, rc);
1586
1587 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1588 AssertRCReturn(rc, rc);
1589
1590 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1591 AssertRCReturn(rc, rc);
1592
1593 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0)
1594 {
1595 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1596 CRASSERT(b);
1597 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1598 AssertRCReturn(rc, rc);
1599 }
1600
1601 if (pClient->currentMural && pClient->currentWindow>=0)
1602 {
1603 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1604 CRASSERT(b);
1605 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1606 AssertRCReturn(rc, rc);
1607 }
1608 }
1609 }
1610
1611 /* all context gl error states should have now be synced with chromium erro states,
1612 * reset the error if any */
1613 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1614 crWarning("crServer: glGetError %d after saving snapshot", err);
1615
1616 cr_server.bIsInSavingState = GL_FALSE;
1617
1618 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1619 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
1620
1621 return VINF_SUCCESS;
1622}
1623
1624static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1625{
1626 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1627 CRASSERT(pContextInfo);
1628 CRASSERT(pContextInfo->pContext);
1629 return pContextInfo->pContext;
1630}
1631
1632static int32_t crVBoxServerLoadMurals(PSSMHANDLE pSSM, uint32_t version)
1633{
1634 unsigned long key;
1635 uint32_t ui, uiNumElems;
1636 /* Load windows */
1637 int32_t rc = SSMR3GetU32(pSSM, &uiNumElems);
1638 AssertRCReturn(rc, rc);
1639 for (ui=0; ui<uiNumElems; ++ui)
1640 {
1641 CRCreateInfo_t createInfo;
1642 char psz[200];
1643 GLint winID;
1644 unsigned long key;
1645
1646 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1647 AssertRCReturn(rc, rc);
1648 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1649 AssertRCReturn(rc, rc);
1650
1651 if (createInfo.pszDpyName)
1652 {
1653 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1654 AssertRCReturn(rc, rc);
1655 createInfo.pszDpyName = psz;
1656 }
1657
1658 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1659 CRASSERT((int64_t)winID == (int64_t)key);
1660 }
1661
1662 /* Load cr_server.muralTable */
1663 rc = SSMR3GetU32(pSSM, &uiNumElems);
1664 AssertRCReturn(rc, rc);
1665 for (ui=0; ui<uiNumElems; ++ui)
1666 {
1667 CRMuralInfo muralInfo;
1668
1669 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1670 AssertRCReturn(rc, rc);
1671 rc = SSMR3GetMem(pSSM, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1672 AssertRCReturn(rc, rc);
1673
1674 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1675 muralInfo.bFbDraw = GL_TRUE;
1676
1677 if (muralInfo.pVisibleRects)
1678 {
1679 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
1680 if (!muralInfo.pVisibleRects)
1681 {
1682 return VERR_NO_MEMORY;
1683 }
1684
1685 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
1686 AssertRCReturn(rc, rc);
1687 }
1688
1689 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
1690 {
1691 CRMuralInfo *pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);;
1692 CRASSERT(pActualMural);
1693 rc = SSMR3GetMem(pSSM, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
1694 CRASSERT(rc == VINF_SUCCESS);
1695 }
1696
1697 /* Restore windows geometry info */
1698 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
1699 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
1700 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
1701 if (muralInfo.bReceivedRects)
1702 {
1703 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
1704 }
1705 crServerDispatchWindowShow(key, muralInfo.bVisible);
1706
1707 if (muralInfo.pVisibleRects)
1708 {
1709 crFree(muralInfo.pVisibleRects);
1710 }
1711 }
1712
1713 CRASSERT(RT_SUCCESS(rc));
1714 return VINF_SUCCESS;
1715}
1716
1717static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
1718 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
1719{
1720 CRContext *pContext = pContextInfo->pContext;
1721 int32_t rc = VINF_SUCCESS;
1722 GLuint i;
1723 /* can apply the data right away */
1724 struct
1725 {
1726 CRFBData data;
1727 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1728 } Data;
1729
1730 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1731
1732 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1733 {
1734 if (!pMural->width || !pMural->height)
1735 return VINF_SUCCESS;
1736
1737 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
1738 if (!RT_SUCCESS(rc))
1739 {
1740 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1741 return rc;
1742 }
1743 }
1744 else
1745 {
1746 GLint storedWidth, storedHeight;
1747
1748 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1749 {
1750 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1751 CRASSERT(cr_server.currentMural = pMural);
1752 storedWidth = pMural->width;
1753 storedHeight = pMural->height;
1754 }
1755 else
1756 {
1757 storedWidth = pContext->buffer.storedWidth;
1758 storedHeight = pContext->buffer.storedHeight;
1759 }
1760
1761 if (!storedWidth || !storedHeight)
1762 return VINF_SUCCESS;
1763
1764 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
1765 if (!RT_SUCCESS(rc))
1766 {
1767 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1768 return rc;
1769 }
1770 }
1771
1772 CRASSERT(Data.data.cElements);
1773
1774 for (i = 0; i < Data.data.cElements; ++i)
1775 {
1776 CRFBDataElement * pEl = &Data.data.aElements[i];
1777 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
1778 AssertRCReturn(rc, rc);
1779 }
1780
1781 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1782 {
1783 CRBufferState *pBuf = &pContext->buffer;
1784 /* can apply the data right away */
1785 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
1786 CRASSERT(cr_server.currentMural);
1787
1788 cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
1789 0,
1790 pContextInfo->SpuContext >= 0
1791 ? pContextInfo->SpuContext
1792 : cr_server.MainContextInfo.SpuContext);
1793 crStateApplyFBImage(pContext, &Data.data);
1794 CRASSERT(!pBuf->pFrontImg);
1795 CRASSERT(!pBuf->pBackImg);
1796 crVBoxServerFBImageDataTerm(&Data.data);
1797
1798 if (pMural->fUseFBO && pMural->bVisible)
1799 {
1800 crServerPresentFBO(pMural);
1801 }
1802
1803 CRASSERT(cr_server.currentMural);
1804 cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
1805 0,
1806 cr_server.currentCtxInfo->SpuContext >= 0
1807 ? cr_server.currentCtxInfo->SpuContext
1808 : cr_server.MainContextInfo.SpuContext);
1809 }
1810 else
1811 {
1812 CRBufferState *pBuf = &pContext->buffer;
1813 CRASSERT(!pBuf->pFrontImg);
1814 CRASSERT(!pBuf->pBackImg);
1815 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
1816
1817 if (Data.data.cElements)
1818 {
1819 CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1820 if (!RT_SUCCESS(rc))
1821 {
1822 crVBoxServerFBImageDataTerm(&Data.data);
1823 crWarning("crAlloc failed");
1824 return VERR_NO_MEMORY;
1825 }
1826
1827 crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1828 pBuf->pFrontImg = pLazyData;
1829 }
1830 }
1831
1832 CRASSERT(RT_SUCCESS(rc));
1833 return VINF_SUCCESS;
1834}
1835
1836DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
1837{
1838 int32_t rc, i;
1839 uint32_t ui, uiNumElems;
1840 unsigned long key;
1841 GLenum err;
1842
1843 if (!cr_server.bIsInLoadingState)
1844 {
1845 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
1846 cr_server.bIsInLoadingState = GL_TRUE;
1847
1848 /* Read number of clients */
1849 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
1850 AssertRCReturn(rc, rc);
1851 }
1852
1853 g_hackVBoxServerSaveLoadCallsLeft--;
1854
1855 /* Do nothing until we're being called last time */
1856 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1857 {
1858 return VINF_SUCCESS;
1859 }
1860
1861 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
1862 {
1863 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1864 }
1865
1866#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
1867#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
1868
1869 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
1870 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
1871
1872 /* Load and recreate rendering contexts */
1873 rc = SSMR3GetU32(pSSM, &uiNumElems);
1874 AssertRCReturn(rc, rc);
1875 for (ui=0; ui<uiNumElems; ++ui)
1876 {
1877 CRCreateInfo_t createInfo;
1878 char psz[200];
1879 GLint ctxID;
1880 CRContextInfo* pContextInfo;
1881 CRContext* pContext;
1882
1883 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1884 AssertRCReturn(rc, rc);
1885 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1886 AssertRCReturn(rc, rc);
1887
1888 if (createInfo.pszDpyName)
1889 {
1890 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1891 AssertRCReturn(rc, rc);
1892 createInfo.pszDpyName = psz;
1893 }
1894
1895 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
1896 CRASSERT((int64_t)ctxID == (int64_t)key);
1897
1898 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1899 CRASSERT(pContextInfo);
1900 CRASSERT(pContextInfo->pContext);
1901 pContext = pContextInfo->pContext;
1902 pContext->shared->id=-1;
1903 }
1904
1905 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1906 {
1907 /* we have a mural data here */
1908 rc = crVBoxServerLoadMurals(pSSM, version);
1909 AssertRCReturn(rc, rc);
1910 }
1911
1912 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
1913 {
1914 /* set the current client to allow doing crServerPerformMakeCurrent later */
1915 CRASSERT(cr_server.numClients);
1916 cr_server.curClient = cr_server.clients[0];
1917 }
1918
1919 rc = crStateLoadGlobals(pSSM, version);
1920 AssertRCReturn(rc, rc);
1921
1922 if (uiNumElems)
1923 {
1924 /* ensure we have main context set up as current */
1925 CRMuralInfo *pMural;
1926 CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
1927 CRASSERT(!cr_server.currentCtxInfo);
1928 CRASSERT(!cr_server.currentMural);
1929 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
1930 CRASSERT(pMural);
1931 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
1932 }
1933
1934 /* Restore context state data */
1935 for (ui=0; ui<uiNumElems; ++ui)
1936 {
1937 CRContextInfo* pContextInfo;
1938 CRContext *pContext;
1939 CRMuralInfo *pMural = NULL;
1940 int32_t winId = 0;
1941
1942 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1943 AssertRCReturn(rc, rc);
1944
1945 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1946 CRASSERT(pContextInfo);
1947 CRASSERT(pContextInfo->pContext);
1948 pContext = pContextInfo->pContext;
1949
1950 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1951 {
1952 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
1953 AssertRCReturn(rc, rc);
1954
1955 if (winId)
1956 {
1957 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
1958 CRASSERT(pMural);
1959 }
1960 else
1961 {
1962 /* null winId means a dummy mural, get it */
1963 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
1964 CRASSERT(pMural);
1965 }
1966 }
1967
1968 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
1969 AssertRCReturn(rc, rc);
1970
1971 /*Restore front/back buffer images*/
1972 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1973 AssertRCReturn(rc, rc);
1974 }
1975
1976 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1977 {
1978 CRContextInfo *pContextInfo;
1979 CRMuralInfo *pMural;
1980 GLint ctxId;
1981
1982 rc = SSMR3GetU32(pSSM, &uiNumElems);
1983 AssertRCReturn(rc, rc);
1984 for (ui=0; ui<uiNumElems; ++ui)
1985 {
1986 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1987 CRMuralInfo *pInitialCurMural;
1988
1989 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1990 AssertRCReturn(rc, rc);
1991
1992 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
1993 AssertRCReturn(rc, rc);
1994
1995 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1996 CRASSERT(pMural);
1997 if (ctxId)
1998 {
1999 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
2000 CRASSERT(pContextInfo);
2001 }
2002 else
2003 pContextInfo = &cr_server.MainContextInfo;
2004
2005 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
2006 pInitialCurMural = pContextInfo->currentMural;
2007
2008 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
2009 AssertRCReturn(rc, rc);
2010
2011 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
2012 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
2013 pContextInfo->currentMural = pInitialCurMural;
2014 }
2015
2016 CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
2017
2018 cr_server.curClient = NULL;
2019 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
2020 }
2021 else
2022 {
2023 CRServerFreeIDsPool_t dummyIdsPool;
2024
2025 /* we have a mural data here */
2026 rc = crVBoxServerLoadMurals(pSSM, version);
2027 AssertRCReturn(rc, rc);
2028
2029 /* not used any more, just read it out and ignore */
2030 rc = SSMR3GetMem(pSSM, &dummyIdsPool, sizeof(dummyIdsPool));
2031 CRASSERT(rc == VINF_SUCCESS);
2032 }
2033
2034 /* Load clients info */
2035 for (i = 0; i < cr_server.numClients; i++)
2036 {
2037 if (cr_server.clients[i] && cr_server.clients[i]->conn)
2038 {
2039 CRClient *pClient = cr_server.clients[i];
2040 CRClient client;
2041 unsigned long ctxID=-1, winID=-1;
2042
2043 rc = SSMR3GetU32(pSSM, &ui);
2044 AssertRCReturn(rc, rc);
2045 /* If this assert fires, then we should search correct client in the list first*/
2046 CRASSERT(ui == pClient->conn->u32ClientID);
2047
2048 if (version>=4)
2049 {
2050 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
2051 AssertRCReturn(rc, rc);
2052
2053 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
2054 AssertRCReturn(rc, rc);
2055 }
2056
2057 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
2058 CRASSERT(rc == VINF_SUCCESS);
2059
2060 client.conn = pClient->conn;
2061 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2062 * and fail to bind old textures.
2063 */
2064 /*client.number = pClient->number;*/
2065 *pClient = client;
2066
2067 pClient->currentContextNumber = -1;
2068 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2069 pClient->currentMural = NULL;
2070 pClient->currentWindow = -1;
2071
2072 cr_server.curClient = pClient;
2073
2074 if (client.currentCtxInfo && client.currentContextNumber>=0)
2075 {
2076 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
2077 AssertRCReturn(rc, rc);
2078 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2079 CRASSERT(client.currentCtxInfo);
2080 CRASSERT(client.currentCtxInfo->pContext);
2081 //pClient->currentCtx = client.currentCtx;
2082 //pClient->currentContextNumber = ctxID;
2083 }
2084
2085 if (client.currentMural && client.currentWindow>=0)
2086 {
2087 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
2088 AssertRCReturn(rc, rc);
2089 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2090 CRASSERT(client.currentMural);
2091 //pClient->currentMural = client.currentMural;
2092 //pClient->currentWindow = winID;
2093 }
2094
2095 /* Restore client active context and window */
2096 crServerDispatchMakeCurrent(winID, 0, ctxID);
2097
2098 if (0)
2099 {
2100// CRContext *tmpCtx;
2101// CRCreateInfo_t *createInfo;
2102 GLfloat one[4] = { 1, 1, 1, 1 };
2103 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
2104
2105 crServerDispatchMakeCurrent(winID, 0, ctxID);
2106
2107 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
2108
2109 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
2110 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
2111 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
2112#ifdef CR_ARB_texture_cube_map
2113 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
2114#endif
2115#ifdef CR_NV_texture_rectangle
2116 //@todo this doesn't work as expected
2117 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
2118#endif
2119 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
2120 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
2121 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
2122
2123 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
2124 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
2125 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
2126
2127 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
2128 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
2129
2130 //crStateViewport( 0, 0, 600, 600 );
2131 //pClient->currentMural->viewportValidated = GL_FALSE;
2132 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
2133
2134 //crStateMatrixMode(GL_PROJECTION);
2135 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
2136
2137 //crStateLoadIdentity();
2138 //cr_server.head_spu->dispatch_table.LoadIdentity();
2139
2140 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2141 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2142
2143 //crStateMatrixMode(GL_MODELVIEW);
2144 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
2145 //crServerDispatchLoadIdentity();
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 //crServerDispatchLoadIdentity();
2149
2150 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
2151 CRASSERT(createInfo);
2152 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
2153 CRASSERT(tmpCtx);
2154 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
2155 crStateDestroyContext(tmpCtx);*/
2156 }
2157 }
2158 }
2159
2160 //crServerDispatchMakeCurrent(-1, 0, -1);
2161
2162 cr_server.curClient = NULL;
2163
2164 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2165 crWarning("crServer: glGetError %d after loading snapshot", err);
2166
2167 cr_server.bIsInLoadingState = GL_FALSE;
2168
2169#if 0
2170 crVBoxServerCheckConsistency();
2171#endif
2172
2173 if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
2174 cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
2175
2176
2177 return VINF_SUCCESS;
2178}
2179
2180#define SCREEN(i) (cr_server.screen[i])
2181#define MAPPED(screen) ((screen).winID != 0)
2182
2183static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2184{
2185 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2186 int *sIndex = (int*) data2;
2187
2188 if (pMI->screenId == *sIndex)
2189 {
2190 renderspuReparentWindow(pMI->spuWindow);
2191 }
2192}
2193
2194static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
2195{
2196 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2197 (void) data2;
2198
2199 crServerCheckMuralGeometry(pMI);
2200}
2201
2202DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2203{
2204 int i;
2205
2206 if (sCount>CR_MAX_GUEST_MONITORS)
2207 return VERR_INVALID_PARAMETER;
2208
2209 /*Shouldn't happen yet, but to be safe in future*/
2210 for (i=0; i<cr_server.screenCount; ++i)
2211 {
2212 if (MAPPED(SCREEN(i)))
2213 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
2214 return VERR_NOT_IMPLEMENTED;
2215 }
2216
2217 cr_server.screenCount = sCount;
2218
2219 for (i=0; i<sCount; ++i)
2220 {
2221 SCREEN(i).winID = 0;
2222 }
2223
2224 return VINF_SUCCESS;
2225}
2226
2227DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2228{
2229 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2230
2231 if (sIndex<0 || sIndex>=cr_server.screenCount)
2232 return VERR_INVALID_PARAMETER;
2233
2234 if (MAPPED(SCREEN(sIndex)))
2235 {
2236 SCREEN(sIndex).winID = 0;
2237 renderspuSetWindowId(0);
2238
2239 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2240 }
2241
2242 renderspuSetWindowId(SCREEN(0).winID);
2243 return VINF_SUCCESS;
2244}
2245
2246DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2247{
2248 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2249
2250 if (sIndex<0 || sIndex>=cr_server.screenCount)
2251 return VERR_INVALID_PARAMETER;
2252
2253 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2254 {
2255 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2256 crVBoxServerUnmapScreen(sIndex);
2257 }
2258
2259 SCREEN(sIndex).winID = winID;
2260 SCREEN(sIndex).x = x;
2261 SCREEN(sIndex).y = y;
2262 SCREEN(sIndex).w = w;
2263 SCREEN(sIndex).h = h;
2264
2265 renderspuSetWindowId(SCREEN(sIndex).winID);
2266 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2267 renderspuSetWindowId(SCREEN(0).winID);
2268
2269 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2270
2271#ifndef WINDOWS
2272 /*Restore FB content for clients, which have current window on a screen being remapped*/
2273 {
2274 GLint i;
2275
2276 for (i = 0; i < cr_server.numClients; i++)
2277 {
2278 cr_server.curClient = cr_server.clients[i];
2279 if (cr_server.curClient->currentCtxInfo
2280 && cr_server.curClient->currentCtxInfo->pContext
2281 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2282 && cr_server.curClient->currentMural
2283 && cr_server.curClient->currentMural->screenId == sIndex
2284 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2285 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2286 {
2287 int clientWindow = cr_server.curClient->currentWindow;
2288 int clientContext = cr_server.curClient->currentContextNumber;
2289 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2290
2291 if (clientWindow && clientWindow != cr_server.currentWindow)
2292 {
2293 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2294 }
2295
2296 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2297 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2298 }
2299 }
2300 cr_server.curClient = NULL;
2301 }
2302#endif
2303
2304 {
2305 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
2306 if (pDisplay)
2307 CrDpResize(pDisplay, w, h, w, h);
2308 }
2309
2310 return VINF_SUCCESS;
2311}
2312
2313DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
2314{
2315 renderspuSetRootVisibleRegion(cRects, pRects);
2316
2317 return VINF_SUCCESS;
2318}
2319
2320DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2321{
2322 cr_server.pfnPresentFBO = pfnPresentFBO;
2323}
2324
2325int32_t crServerSetOffscreenRenderingMode(GLubyte value)
2326{
2327 if (cr_server.bForceOffscreenRendering==value)
2328 {
2329 return VINF_SUCCESS;
2330 }
2331
2332 if (value > CR_SERVER_REDIR_MAXVAL)
2333 {
2334 crWarning("crServerSetOffscreenRenderingMode: invalid arg: %d", value);
2335 return VERR_INVALID_PARAMETER;
2336 }
2337
2338 if (value && !crServerSupportRedirMuralFBO())
2339 {
2340 return VERR_NOT_SUPPORTED;
2341 }
2342
2343 cr_server.bForceOffscreenRendering=value;
2344
2345 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2346
2347 return VINF_SUCCESS;
2348}
2349
2350DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2351{
2352 return crServerSetOffscreenRenderingMode(value ? CR_SERVER_REDIR_FBO_RAM : cr_server.bOffscreenRenderingDefault);
2353}
2354
2355DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2356{
2357 /* No need for a synchronization as this is single threaded. */
2358 if (pCallbacks)
2359 {
2360 cr_server.outputRedirect = *pCallbacks;
2361 cr_server.bUseOutputRedirect = true;
2362 }
2363 else
2364 {
2365 cr_server.bUseOutputRedirect = false;
2366 }
2367
2368 // @todo dynamically intercept already existing output:
2369 // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
2370
2371 return VINF_SUCCESS;
2372}
2373
2374static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2)
2375{
2376 CRMuralInfo *mural = (CRMuralInfo*) data1;
2377 int *sIndex = (int*) data2;
2378
2379 if (mural->screenId != *sIndex)
2380 return;
2381
2382 crServerCheckMuralGeometry(mural);
2383}
2384
2385
2386DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2387{
2388 CRScreenViewportInfo *pVieport;
2389 GLboolean fPosChanged, fSizeChanged;
2390
2391 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2392
2393 if (sIndex<0 || sIndex>=cr_server.screenCount)
2394 {
2395 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2396 return VERR_INVALID_PARAMETER;
2397 }
2398
2399 pVieport = &cr_server.screenVieport[sIndex];
2400 fPosChanged = (pVieport->x != x || pVieport->y != y);
2401 fSizeChanged = (pVieport->w != w || pVieport->h != h);
2402
2403 if (!fPosChanged && !fSizeChanged)
2404 {
2405 crDebug("crVBoxServerSetScreenViewport: no changes");
2406 return VINF_SUCCESS;
2407 }
2408
2409 if (fPosChanged)
2410 {
2411 pVieport->x = x;
2412 pVieport->y = y;
2413
2414 crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex);
2415 }
2416
2417 if (fSizeChanged)
2418 {
2419 pVieport->w = w;
2420 pVieport->h = h;
2421
2422 /* no need to do anything here actually */
2423 }
2424 return VINF_SUCCESS;
2425}
2426
2427
2428#ifdef VBOX_WITH_CRHGSMI
2429/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
2430 *
2431 * 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.
2432 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
2433 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
2434 * to block the lower-priority thread trying to complete the blocking command.
2435 * And removed extra memcpy done on blocked command arrival.
2436 *
2437 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
2438 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
2439 *
2440 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
2441 * */
2442int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
2443{
2444 int32_t rc;
2445 uint32_t cBuffers = pCmd->cBuffers;
2446 uint32_t cParams;
2447 uint32_t cbHdr;
2448 CRVBOXHGSMIHDR *pHdr;
2449 uint32_t u32Function;
2450 uint32_t u32ClientID;
2451 CRClient *pClient;
2452
2453 if (!g_pvVRamBase)
2454 {
2455 crWarning("g_pvVRamBase is not initialized");
2456 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
2457 return VINF_SUCCESS;
2458 }
2459
2460 if (!cBuffers)
2461 {
2462 crWarning("zero buffers passed in!");
2463 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2464 return VINF_SUCCESS;
2465 }
2466
2467 cParams = cBuffers-1;
2468
2469 cbHdr = pCmd->aBuffers[0].cbBuffer;
2470 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2471 if (!pHdr)
2472 {
2473 crWarning("invalid header buffer!");
2474 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2475 return VINF_SUCCESS;
2476 }
2477
2478 if (cbHdr < sizeof (*pHdr))
2479 {
2480 crWarning("invalid header buffer size!");
2481 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2482 return VINF_SUCCESS;
2483 }
2484
2485 u32Function = pHdr->u32Function;
2486 u32ClientID = pHdr->u32ClientID;
2487
2488 switch (u32Function)
2489 {
2490 case SHCRGL_GUEST_FN_WRITE:
2491 {
2492 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2493
2494 /* @todo: Verify */
2495 if (cParams == 1)
2496 {
2497 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2498 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2499 /* Fetch parameters. */
2500 uint32_t cbBuffer = pBuf->cbBuffer;
2501 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2502
2503 if (cbHdr < sizeof (*pFnCmd))
2504 {
2505 crWarning("invalid write cmd buffer size!");
2506 rc = VERR_INVALID_PARAMETER;
2507 break;
2508 }
2509
2510 CRASSERT(cbBuffer);
2511 if (!pBuffer)
2512 {
2513 crWarning("invalid buffer data received from guest!");
2514 rc = VERR_INVALID_PARAMETER;
2515 break;
2516 }
2517
2518 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2519 if (RT_FAILURE(rc))
2520 {
2521 break;
2522 }
2523
2524 /* This should never fire unless we start to multithread */
2525 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2526 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2527
2528 pClient->conn->pBuffer = pBuffer;
2529 pClient->conn->cbBuffer = cbBuffer;
2530 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2531 rc = crVBoxServerInternalClientWriteRead(pClient);
2532 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2533 return rc;
2534 }
2535 else
2536 {
2537 crWarning("invalid number of args");
2538 rc = VERR_INVALID_PARAMETER;
2539 break;
2540 }
2541 break;
2542 }
2543
2544 case SHCRGL_GUEST_FN_INJECT:
2545 {
2546 crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2547
2548 /* @todo: Verify */
2549 if (cParams == 1)
2550 {
2551 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2552 /* Fetch parameters. */
2553 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2554 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2555 uint32_t cbBuffer = pBuf->cbBuffer;
2556 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2557
2558 if (cbHdr < sizeof (*pFnCmd))
2559 {
2560 crWarning("invalid inject cmd buffer size!");
2561 rc = VERR_INVALID_PARAMETER;
2562 break;
2563 }
2564
2565 CRASSERT(cbBuffer);
2566 if (!pBuffer)
2567 {
2568 crWarning("invalid buffer data received from guest!");
2569 rc = VERR_INVALID_PARAMETER;
2570 break;
2571 }
2572
2573 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
2574 if (RT_FAILURE(rc))
2575 {
2576 break;
2577 }
2578
2579 /* This should never fire unless we start to multithread */
2580 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2581 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2582
2583 pClient->conn->pBuffer = pBuffer;
2584 pClient->conn->cbBuffer = cbBuffer;
2585 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2586 rc = crVBoxServerInternalClientWriteRead(pClient);
2587 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2588 return rc;
2589 }
2590
2591 crWarning("invalid number of args");
2592 rc = VERR_INVALID_PARAMETER;
2593 break;
2594 }
2595
2596 case SHCRGL_GUEST_FN_READ:
2597 {
2598 crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n"));
2599
2600 /* @todo: Verify */
2601 if (cParams == 1)
2602 {
2603 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
2604 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2605 /* Fetch parameters. */
2606 uint32_t cbBuffer = pBuf->cbBuffer;
2607 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2608
2609 if (cbHdr < sizeof (*pFnCmd))
2610 {
2611 crWarning("invalid read cmd buffer size!");
2612 rc = VERR_INVALID_PARAMETER;
2613 break;
2614 }
2615
2616
2617 if (!pBuffer)
2618 {
2619 crWarning("invalid buffer data received from guest!");
2620 rc = VERR_INVALID_PARAMETER;
2621 break;
2622 }
2623
2624 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2625 if (RT_FAILURE(rc))
2626 {
2627 break;
2628 }
2629
2630 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2631
2632 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
2633
2634 /* Return the required buffer size always */
2635 pFnCmd->cbBuffer = cbBuffer;
2636
2637 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2638
2639 /* the read command is never pended, complete it right away */
2640 pHdr->result = rc;
2641 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2642 return VINF_SUCCESS;
2643 }
2644
2645 crWarning("invalid number of args");
2646 rc = VERR_INVALID_PARAMETER;
2647 break;
2648 }
2649
2650 case SHCRGL_GUEST_FN_WRITE_READ:
2651 {
2652 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
2653
2654 /* @todo: Verify */
2655 if (cParams == 2)
2656 {
2657 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
2658 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2659 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
2660
2661 /* Fetch parameters. */
2662 uint32_t cbBuffer = pBuf->cbBuffer;
2663 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2664
2665 uint32_t cbWriteback = pWbBuf->cbBuffer;
2666 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
2667
2668 if (cbHdr < sizeof (*pFnCmd))
2669 {
2670 crWarning("invalid write_read cmd buffer size!");
2671 rc = VERR_INVALID_PARAMETER;
2672 break;
2673 }
2674
2675
2676 CRASSERT(cbBuffer);
2677 if (!pBuffer)
2678 {
2679 crWarning("invalid write buffer data received from guest!");
2680 rc = VERR_INVALID_PARAMETER;
2681 break;
2682 }
2683
2684 CRASSERT(cbWriteback);
2685 if (!pWriteback)
2686 {
2687 crWarning("invalid writeback buffer data received from guest!");
2688 rc = VERR_INVALID_PARAMETER;
2689 break;
2690 }
2691 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2692 if (RT_FAILURE(rc))
2693 {
2694 pHdr->result = rc;
2695 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2696 return rc;
2697 }
2698
2699 /* This should never fire unless we start to multithread */
2700 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2701 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2702
2703 pClient->conn->pBuffer = pBuffer;
2704 pClient->conn->cbBuffer = cbBuffer;
2705 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
2706 rc = crVBoxServerInternalClientWriteRead(pClient);
2707 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2708 return rc;
2709 }
2710
2711 crWarning("invalid number of args");
2712 rc = VERR_INVALID_PARAMETER;
2713 break;
2714 }
2715
2716 case SHCRGL_GUEST_FN_SET_VERSION:
2717 {
2718 crWarning("invalid function");
2719 rc = VERR_NOT_IMPLEMENTED;
2720 break;
2721 }
2722
2723 case SHCRGL_GUEST_FN_SET_PID:
2724 {
2725 crWarning("invalid function");
2726 rc = VERR_NOT_IMPLEMENTED;
2727 break;
2728 }
2729
2730 default:
2731 {
2732 crWarning("invalid function");
2733 rc = VERR_NOT_IMPLEMENTED;
2734 break;
2735 }
2736
2737 }
2738
2739 /* we can be on fail only here */
2740 CRASSERT(RT_FAILURE(rc));
2741 pHdr->result = rc;
2742 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2743 return rc;
2744}
2745
2746int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
2747{
2748 int rc = VINF_SUCCESS;
2749
2750 switch (pCtl->enmType)
2751 {
2752 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
2753 {
2754 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
2755 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
2756 g_cbVRam = pSetup->cbVRam;
2757 rc = VINF_SUCCESS;
2758 break;
2759 }
2760 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
2761 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
2762 rc = VINF_SUCCESS;
2763 break;
2764 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
2765 {
2766 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
2767 g_hCrHgsmiCompletion = pSetup->hCompletion;
2768 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
2769 rc = VINF_SUCCESS;
2770 break;
2771 }
2772 default:
2773 AssertMsgFailed(("invalid param %d", pCtl->enmType));
2774 rc = VERR_INVALID_PARAMETER;
2775 }
2776
2777 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
2778 * to complete them accordingly.
2779 * This approach allows using host->host and host->guest commands in the same way here
2780 * making the command completion to be the responsibility of the command originator.
2781 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
2782 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
2783 return rc;
2784}
2785#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