VirtualBox

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

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

crOpenGL: misc bugfixes & cleanups

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette