VirtualBox

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

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

crOpenGL: Fedora 18 saved state working, multiple saved state fixes, debugging stuff

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