VirtualBox

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

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

crOpenGL: seamles mode support impl; bugfizes & cleanup

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