VirtualBox

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

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

crOpenGL: fix dealing with default mural

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 86.6 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 CRASSERT(pCtxInfo->currentMural);
1028
1029 crMemset(pData, 0, sizeof (*pData));
1030
1031 pContext = pCtxInfo->pContext;
1032
1033 /* the version should be always actual when we do reads,
1034 * i.e. it could differ on writes when snapshot is getting loaded */
1035 CRASSERT(fWrite || version == SHCROGL_SSM_VERSION);
1036
1037 width = overrideWidth ? overrideWidth : pMural->width;
1038 height = overrideHeight ? overrideHeight : pMural->height;
1039
1040 if (!width || !height)
1041 return VINF_SUCCESS;
1042
1043 pData->idFBO = pMural->fUseFBO ? pMural->aidColorTexs[fWrite ? pMural->iCurDrawBuffer : pMural->iCurReadBuffer] : 0;
1044 pData->cElements = 0;
1045
1046 pEl = &pData->aElements[pData->cElements];
1047 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1048 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT;
1049 pEl->posX = 0;
1050 pEl->posY = 0;
1051 pEl->width = width;
1052 pEl->height = height;
1053 pEl->enmFormat = GL_RGBA;
1054 pEl->enmType = GL_UNSIGNED_BYTE;
1055 pEl->cbData = width * height * 4;
1056 pEl->pvData = crCalloc(pEl->cbData);
1057 if (!pEl->pvData)
1058 {
1059 crVBoxServerFBImageDataTerm(pData);
1060 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1061 return VERR_NO_MEMORY;
1062 }
1063 ++pData->cElements;
1064
1065 /* there is a lot of code that assumes we have double buffering, just assert here to print a warning in the log
1066 * so that we know that something irregular is going on */
1067 CRASSERT(pCtxInfo->CreateInfo.visualBits & CR_DOUBLE_BIT);
1068 if ((pCtxInfo->CreateInfo.visualBits & CR_DOUBLE_BIT)
1069 || version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL /* <- older version had a typo which lead to back always being used,
1070 * no matter what the visual bits are */
1071 )
1072 {
1073 pEl = &pData->aElements[pData->cElements];
1074 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0;
1075 pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK;
1076 pEl->posX = 0;
1077 pEl->posY = 0;
1078 pEl->width = width;
1079 pEl->height = height;
1080 pEl->enmFormat = GL_RGBA;
1081 pEl->enmType = GL_UNSIGNED_BYTE;
1082 pEl->cbData = width * height * 4;
1083 pEl->pvData = crCalloc(pEl->cbData);
1084 if (!pEl->pvData)
1085 {
1086 crVBoxServerFBImageDataTerm(pData);
1087 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1088 return VERR_NO_MEMORY;
1089 }
1090 ++pData->cElements;
1091 }
1092
1093 if (version < SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1094 return VINF_SUCCESS;
1095
1096
1097 if (version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL)
1098 {
1099/* if (pCtxInfo->CreateInfo.visualBits & CR_DEPTH_BIT) */ /* <- older version had a typo which lead to back always being used,
1100 * no matter what the visual bits are */
1101 {
1102 AssertCompile(sizeof (GLfloat) == 4);
1103 pEl = &pData->aElements[pData->cElements];
1104 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1105 pEl->enmBuffer = 0; /* we do not care */
1106 pEl->posX = 0;
1107 pEl->posY = 0;
1108 pEl->width = width;
1109 pEl->height = height;
1110 pEl->enmFormat = GL_DEPTH_COMPONENT;
1111 pEl->enmType = GL_FLOAT;
1112 pEl->cbData = width * height * 4;
1113 pEl->pvData = crCalloc(pEl->cbData);
1114 if (!pEl->pvData)
1115 {
1116 crVBoxServerFBImageDataTerm(pData);
1117 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1118 return VERR_NO_MEMORY;
1119 }
1120
1121 /* init to default depth value, just in case */
1122 pF = (GLfloat*)pEl->pvData;
1123 for (i = 0; i < width * height; ++i)
1124 {
1125 pF[i] = 1.;
1126 }
1127 ++pData->cElements;
1128 }
1129
1130 /* if (pCtxInfo->CreateInfo.visualBits & CR_STENCIL_BIT) */ /* <- older version had a typo which lead to back always being used,
1131 * no matter what the visual bits are */
1132 {
1133 AssertCompile(sizeof (GLuint) == 4);
1134 pEl = &pData->aElements[pData->cElements];
1135 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1136 pEl->enmBuffer = 0; /* we do not care */
1137 pEl->posX = 0;
1138 pEl->posY = 0;
1139 pEl->width = width;
1140 pEl->height = height;
1141 pEl->enmFormat = GL_STENCIL_INDEX;
1142 pEl->enmType = GL_UNSIGNED_INT;
1143 pEl->cbData = width * height * 4;
1144 pEl->pvData = crCalloc(pEl->cbData);
1145 if (!pEl->pvData)
1146 {
1147 crVBoxServerFBImageDataTerm(pData);
1148 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1149 return VERR_NO_MEMORY;
1150 }
1151 ++pData->cElements;
1152 }
1153 return VINF_SUCCESS;
1154 }
1155
1156 if ((pCtxInfo->CreateInfo.visualBits & CR_STENCIL_BIT)
1157 || (pCtxInfo->CreateInfo.visualBits & CR_DEPTH_BIT))
1158 {
1159 pEl = &pData->aElements[pData->cElements];
1160 pEl->idFBO = pMural->fUseFBO ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0;
1161 pEl->enmBuffer = 0; /* we do not care */
1162 pEl->posX = 0;
1163 pEl->posY = 0;
1164 pEl->width = width;
1165 pEl->height = height;
1166 pEl->enmFormat = GL_DEPTH_STENCIL;
1167 pEl->enmType = GL_UNSIGNED_INT_24_8;
1168 pEl->cbData = width * height * 4;
1169 pEl->pvData = crCalloc(pEl->cbData);
1170 if (!pEl->pvData)
1171 {
1172 crVBoxServerFBImageDataTerm(pData);
1173 crWarning("crVBoxServerFBImageDataInit: crCalloc failed");
1174 return VERR_NO_MEMORY;
1175 }
1176 ++pData->cElements;
1177 }
1178 return VINF_SUCCESS;
1179}
1180
1181static int crVBoxServerFBImageDataInit(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite)
1182{
1183 return crVBoxServerFBImageDataInitEx(pData, pCtxInfo, pMural, fWrite, SHCROGL_SSM_VERSION, 0, 0);
1184}
1185
1186static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
1187{
1188 CRContextInfo *pCtxInfo;
1189 CRContext *pContext;
1190 CRMuralInfo *pMural;
1191 int32_t rc;
1192 GLuint i;
1193 struct
1194 {
1195 CRFBData data;
1196 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1197 } Data;
1198
1199 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1200
1201 pCtxInfo = cr_server.currentCtxInfo;
1202 pContext = pCtxInfo->pContext;
1203 pMural = pCtxInfo->currentMural;
1204
1205 rc = crVBoxServerFBImageDataInit(&Data.data, pCtxInfo, pMural, GL_FALSE);
1206 if (!RT_SUCCESS(rc))
1207 {
1208 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1209 return rc;
1210 }
1211
1212 rc = crStateAcquireFBImage(pContext, &Data.data);
1213 AssertRCReturn(rc, rc);
1214
1215 for (i = 0; i < Data.data.cElements; ++i)
1216 {
1217 CRFBDataElement * pEl = &Data.data.aElements[i];
1218 rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
1219 AssertRCReturn(rc, rc);
1220 }
1221
1222 crVBoxServerFBImageDataTerm(&Data.data);
1223
1224 return VINF_SUCCESS;
1225}
1226
1227#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
1228 if(!RT_SUCCESS((_rc))) { \
1229 AssertFailed(); \
1230 return; \
1231 } \
1232 } while (0)
1233
1234static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
1235{
1236 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1237 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1238 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1239 PSSMHANDLE pSSM = pData->pSSM;
1240 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1241 CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
1242
1243 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1244
1245 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1246
1247 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1248 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1249
1250 pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
1251 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1252
1253 crServerPerformMakeCurrent(pMural, pContextInfo);
1254
1255 pData->rc = crVBoxServerSaveFBImage(pSSM);
1256
1257 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1258 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1259 pContextInfo->currentMural = pInitialCurMural;
1260
1261 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1262}
1263
1264static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
1265{
1266 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
1267 CRContext *pContext = pContextInfo->pContext;
1268 PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
1269 PSSMHANDLE pSSM = pData->pSSM;
1270 CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
1271 CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
1272 const int32_t i32Dummy = 0;
1273
1274 AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
1275 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1276
1277 CRASSERT(pContext && pSSM);
1278 CRASSERT(pMural);
1279 CRASSERT(pMural->CreateInfo.externalID);
1280
1281 /* We could have skipped saving the key and use similar callback to load context states back,
1282 * but there's no guarantee we'd traverse hashtable in same order after loading.
1283 */
1284 pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1285 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1286
1287#ifdef DEBUG_misha
1288 {
1289 unsigned long id;
1290 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
1291 crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
1292 else
1293 CRASSERT(id == key);
1294 }
1295#endif
1296
1297#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1298 if (pContextInfo->currentMural
1299 || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
1300 )
1301 {
1302 CRASSERT(pMural->CreateInfo.externalID);
1303 CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1304 pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
1305 }
1306 else
1307 {
1308 /* this is a dummy mural */
1309 CRASSERT(!pMural->width);
1310 CRASSERT(!pMural->height);
1311 CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
1312 pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
1313 }
1314 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1315
1316 CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
1317 CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
1318 CRASSERT(cr_server.curClient);
1319
1320 crServerPerformMakeCurrent(pMural, pContextInfo);
1321#endif
1322
1323 pData->rc = crStateSaveContext(pContext, pSSM);
1324 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1325
1326 pData->rc = crVBoxServerSaveFBImage(pSSM);
1327 CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
1328
1329 /* restore the initial current mural */
1330 pContextInfo->currentMural = pContextCurrentMural;
1331}
1332
1333#if 0
1334typedef struct CR_SERVER_CHECK_BUFFERS
1335{
1336 CRBufferObject *obj;
1337 CRContext *ctx;
1338}CR_SERVER_CHECK_BUFFERS, *PCR_SERVER_CHECK_BUFFERS;
1339
1340static void crVBoxServerCheckConsistencyContextBuffersCB(unsigned long key, void *data1, void *data2)
1341{
1342 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1343 CRContext *ctx = pContextInfo->pContext;
1344 PCR_SERVER_CHECK_BUFFERS pBuffers = (PCR_SERVER_CHECK_BUFFERS)data2;
1345 CRBufferObject *obj = pBuffers->obj;
1346 CRBufferObjectState *b = &(ctx->bufferobject);
1347 int j, k;
1348
1349 if (obj == b->arrayBuffer)
1350 {
1351 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1352 pBuffers->ctx = ctx;
1353 }
1354 if (obj == b->elementsBuffer)
1355 {
1356 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1357 pBuffers->ctx = ctx;
1358 }
1359#ifdef CR_ARB_pixel_buffer_object
1360 if (obj == b->packBuffer)
1361 {
1362 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1363 pBuffers->ctx = ctx;
1364 }
1365 if (obj == b->unpackBuffer)
1366 {
1367 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1368 pBuffers->ctx = ctx;
1369 }
1370#endif
1371
1372#ifdef CR_ARB_vertex_buffer_object
1373 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1374 {
1375 CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array);
1376 if (obj == cp->buffer)
1377 {
1378 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1379 pBuffers->ctx = ctx;
1380 }
1381 }
1382
1383 for (k=0; k<ctx->client.vertexArrayStackDepth; ++k)
1384 {
1385 CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k];
1386 for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
1387 {
1388 CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray);
1389 if (obj == cp->buffer)
1390 {
1391 Assert(!pBuffers->ctx || pBuffers->ctx == ctx);
1392 pBuffers->ctx = ctx;
1393 }
1394 }
1395 }
1396#endif
1397}
1398
1399static void crVBoxServerCheckConsistencyBuffersCB(unsigned long key, void *data1, void *data2)
1400{
1401 CRBufferObject *obj = (CRBufferObject *)data1;
1402 CR_SERVER_CHECK_BUFFERS Buffers = {0};
1403 Buffers.obj = obj;
1404 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckConsistencyContextBuffersCB, (void*)&Buffers);
1405}
1406
1407//static void crVBoxServerCheckConsistency2CB(unsigned long key, void *data1, void *data2)
1408//{
1409// CRContextInfo* pContextInfo1 = (CRContextInfo*)data1;
1410// CRContextInfo* pContextInfo2 = (CRContextInfo*)data2;
1411//
1412// CRASSERT(pContextInfo1->pContext);
1413// CRASSERT(pContextInfo2->pContext);
1414//
1415// if (pContextInfo1 == pContextInfo2)
1416// {
1417// CRASSERT(pContextInfo1->pContext == pContextInfo2->pContext);
1418// return;
1419// }
1420//
1421// CRASSERT(pContextInfo1->pContext != pContextInfo2->pContext);
1422// CRASSERT(pContextInfo1->pContext->shared);
1423// CRASSERT(pContextInfo2->pContext->shared);
1424// CRASSERT(pContextInfo1->pContext->shared == pContextInfo2->pContext->shared);
1425// if (pContextInfo1->pContext->shared != pContextInfo2->pContext->shared)
1426// return;
1427//
1428// crHashtableWalk(pContextInfo1->pContext->shared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, pContextInfo2);
1429//}
1430static void crVBoxServerCheckSharedCB(unsigned long key, void *data1, void *data2)
1431{
1432 CRContextInfo* pContextInfo = (CRContextInfo*)data1;
1433 void **ppShared = (void**)data2;
1434 if (!*ppShared)
1435 *ppShared = pContextInfo->pContext->shared;
1436 else
1437 Assert(pContextInfo->pContext->shared == *ppShared);
1438}
1439
1440static void crVBoxServerCheckConsistency()
1441{
1442 CRSharedState *pShared = NULL;
1443 crHashtableWalk(cr_server.contextTable, crVBoxServerCheckSharedCB, (void*)&pShared);
1444 Assert(pShared);
1445 if (pShared)
1446 {
1447 crHashtableWalk(pShared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, NULL);
1448 }
1449}
1450#endif
1451
1452static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
1453
1454DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
1455{
1456 int32_t rc, i;
1457 uint32_t ui32;
1458 GLboolean b;
1459 unsigned long key;
1460 GLenum err;
1461#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1462 CRClient *curClient;
1463 CRMuralInfo *curMural = NULL;
1464 CRContextInfo *curCtxInfo = NULL;
1465#endif
1466 CRVBOX_SAVE_STATE_GLOBAL Data;
1467
1468 crMemset(&Data, 0, sizeof (Data));
1469
1470#if 0
1471 crVBoxServerCheckConsistency();
1472#endif
1473
1474 /* We shouldn't be called if there's no clients at all*/
1475 CRASSERT(cr_server.numClients>0);
1476
1477 /* @todo it's hack atm */
1478 /* We want to be called only once to save server state but atm we're being called from svcSaveState
1479 * for every connected client (e.g. guest opengl application)
1480 */
1481 if (!cr_server.bIsInSavingState) /* It's first call */
1482 {
1483 cr_server.bIsInSavingState = GL_TRUE;
1484
1485 /* Store number of clients */
1486 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
1487 AssertRCReturn(rc, rc);
1488
1489 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
1490 }
1491
1492 g_hackVBoxServerSaveLoadCallsLeft--;
1493
1494 /* Do nothing until we're being called last time */
1495 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1496 {
1497 return VINF_SUCCESS;
1498 }
1499
1500 /* Save rendering contexts creation info */
1501 ui32 = crHashtableNumElements(cr_server.contextTable);
1502 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1503 AssertRCReturn(rc, rc);
1504 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
1505
1506#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1507 curClient = cr_server.curClient;
1508 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
1509 if (curClient)
1510 {
1511 curCtxInfo = cr_server.curClient->currentCtxInfo;
1512 curMural = cr_server.curClient->currentMural;
1513 }
1514 else if (cr_server.numClients)
1515 {
1516 cr_server.curClient = cr_server.clients[0];
1517 }
1518#endif
1519
1520 /* first save windows info */
1521 /* Save windows creation info */
1522 ui32 = crHashtableNumElements(cr_server.muralTable);
1523 /* There should be default mural always */
1524 CRASSERT(ui32>=1);
1525 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1526 AssertRCReturn(rc, rc);
1527 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
1528
1529 /* Save cr_server.muralTable
1530 * @todo we don't need it all, just geometry info actually
1531 */
1532 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
1533 AssertRCReturn(rc, rc);
1534 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
1535
1536 /* we need to save front & backbuffer data for each mural first create a context -> mural association */
1537 crVBoxServerBuildSaveStateGlobal(&Data);
1538
1539 rc = crStateSaveGlobals(pSSM);
1540 AssertRCReturn(rc, rc);
1541
1542 Data.pSSM = pSSM;
1543 /* Save contexts state tracker data */
1544 /* @todo For now just some blind data dumps,
1545 * but I've a feeling those should be saved/restored in a very strict sequence to
1546 * allow diff_api to work correctly.
1547 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
1548 */
1549 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
1550 AssertRCReturn(Data.rc, Data.rc);
1551
1552 ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
1553 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
1554 AssertRCReturn(rc, rc);
1555
1556 crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
1557 AssertRCReturn(Data.rc, Data.rc);
1558
1559#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
1560 cr_server.curClient = curClient;
1561 /* Restore original win and ctx IDs*/
1562 if (curClient && curMural && curCtxInfo)
1563 {
1564 crServerPerformMakeCurrent(curMural, curCtxInfo);
1565 }
1566 else
1567 {
1568 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
1569 }
1570#endif
1571
1572 /* Save clients info */
1573 for (i = 0; i < cr_server.numClients; i++)
1574 {
1575 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1576 {
1577 CRClient *pClient = cr_server.clients[i];
1578
1579 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
1580 AssertRCReturn(rc, rc);
1581
1582 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
1583 AssertRCReturn(rc, rc);
1584
1585 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
1586 AssertRCReturn(rc, rc);
1587
1588 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
1589 AssertRCReturn(rc, rc);
1590
1591 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0)
1592 {
1593 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
1594 CRASSERT(b);
1595 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1596 AssertRCReturn(rc, rc);
1597 }
1598
1599 if (pClient->currentMural && pClient->currentWindow>=0)
1600 {
1601 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
1602 CRASSERT(b);
1603 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
1604 AssertRCReturn(rc, rc);
1605 }
1606 }
1607 }
1608
1609 /* all context gl error states should have now be synced with chromium erro states,
1610 * reset the error if any */
1611 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
1612 crWarning("crServer: glGetError %d after saving snapshot", err);
1613
1614 cr_server.bIsInSavingState = GL_FALSE;
1615
1616 return VINF_SUCCESS;
1617}
1618
1619static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
1620{
1621 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
1622 CRASSERT(pContextInfo);
1623 CRASSERT(pContextInfo->pContext);
1624 return pContextInfo->pContext;
1625}
1626
1627static int32_t crVBoxServerLoadMurals(PSSMHANDLE pSSM, uint32_t version)
1628{
1629 unsigned long key;
1630 uint32_t ui, uiNumElems;
1631 /* Load windows */
1632 int32_t rc = SSMR3GetU32(pSSM, &uiNumElems);
1633 AssertRCReturn(rc, rc);
1634 for (ui=0; ui<uiNumElems; ++ui)
1635 {
1636 CRCreateInfo_t createInfo;
1637 char psz[200];
1638 GLint winID;
1639 unsigned long key;
1640
1641 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1642 AssertRCReturn(rc, rc);
1643 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1644 AssertRCReturn(rc, rc);
1645
1646 if (createInfo.pszDpyName)
1647 {
1648 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1649 AssertRCReturn(rc, rc);
1650 createInfo.pszDpyName = psz;
1651 }
1652
1653 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1654 CRASSERT((int64_t)winID == (int64_t)key);
1655 }
1656
1657 /* Load cr_server.muralTable */
1658 rc = SSMR3GetU32(pSSM, &uiNumElems);
1659 AssertRCReturn(rc, rc);
1660 for (ui=0; ui<uiNumElems; ++ui)
1661 {
1662 CRMuralInfo muralInfo;
1663
1664 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1665 AssertRCReturn(rc, rc);
1666 rc = SSMR3GetMem(pSSM, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo));
1667 AssertRCReturn(rc, rc);
1668
1669 if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
1670 muralInfo.bFbDraw = GL_TRUE;
1671
1672 if (muralInfo.pVisibleRects)
1673 {
1674 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
1675 if (!muralInfo.pVisibleRects)
1676 {
1677 return VERR_NO_MEMORY;
1678 }
1679
1680 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
1681 AssertRCReturn(rc, rc);
1682 }
1683
1684 if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
1685 {
1686 CRMuralInfo *pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);;
1687 CRASSERT(pActualMural);
1688 rc = SSMR3GetMem(pSSM, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
1689 CRASSERT(rc == VINF_SUCCESS);
1690 }
1691
1692 /* Restore windows geometry info */
1693 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
1694 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
1695 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
1696 if (muralInfo.bReceivedRects)
1697 {
1698 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
1699 }
1700 crServerDispatchWindowShow(key, muralInfo.bVisible);
1701
1702 if (muralInfo.pVisibleRects)
1703 {
1704 crFree(muralInfo.pVisibleRects);
1705 }
1706 }
1707
1708 CRASSERT(RT_SUCCESS(rc));
1709 return VINF_SUCCESS;
1710}
1711
1712static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
1713 CRContextInfo* pContextInfo, CRMuralInfo *pMural)
1714{
1715 CRContext *pContext = pContextInfo->pContext;
1716 int32_t rc = VINF_SUCCESS;
1717 GLuint i;
1718 /* can apply the data right away */
1719 struct
1720 {
1721 CRFBData data;
1722 CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
1723 } Data;
1724
1725 Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4]));
1726
1727 if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
1728 {
1729 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1730 CRASSERT(cr_server.currentMural = pMural);
1731
1732 if (!pMural->width || !pMural->height)
1733 return VINF_SUCCESS;
1734
1735 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
1736 if (!RT_SUCCESS(rc))
1737 {
1738 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1739 return rc;
1740 }
1741 }
1742 else
1743 {
1744 GLint storedWidth, storedHeight;
1745
1746 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1747 {
1748 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1749 CRASSERT(cr_server.currentMural = pMural);
1750 storedWidth = pMural->width;
1751 storedHeight = pMural->height;
1752 }
1753 else
1754 {
1755 storedWidth = pContext->buffer.storedWidth;
1756 storedHeight = pContext->buffer.storedHeight;
1757 }
1758
1759 if (!storedWidth || !storedHeight)
1760 return VINF_SUCCESS;
1761
1762 rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
1763 if (!RT_SUCCESS(rc))
1764 {
1765 crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
1766 return rc;
1767 }
1768 }
1769
1770 CRASSERT(Data.data.cElements);
1771
1772 for (i = 0; i < Data.data.cElements; ++i)
1773 {
1774 CRFBDataElement * pEl = &Data.data.aElements[i];
1775 rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
1776 AssertRCReturn(rc, rc);
1777 }
1778
1779 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1780 {
1781 CRBufferState *pBuf = &pContext->buffer;
1782 /* can apply the data right away */
1783 CRASSERT(cr_server.currentCtxInfo == pContextInfo);
1784 CRASSERT(cr_server.currentMural = pMural);
1785
1786 crStateApplyFBImage(pContext, &Data.data);
1787 AssertRCReturn(rc, rc);
1788 CRASSERT(!pBuf->pFrontImg);
1789 CRASSERT(!pBuf->pBackImg);
1790 crVBoxServerFBImageDataTerm(&Data.data);
1791
1792 if (pMural->fUseFBO && pMural->bVisible)
1793 {
1794 crServerPresentFBO(pMural);
1795 }
1796 }
1797 else
1798 {
1799 CRBufferState *pBuf = &pContext->buffer;
1800 CRASSERT(!pBuf->pFrontImg);
1801 CRASSERT(!pBuf->pBackImg);
1802 CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
1803
1804 if (Data.data.cElements)
1805 {
1806 CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1807 if (!RT_SUCCESS(rc))
1808 {
1809 crVBoxServerFBImageDataTerm(&Data.data);
1810 crWarning("crAlloc failed");
1811 return VERR_NO_MEMORY;
1812 }
1813
1814 crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements]));
1815 pBuf->pFrontImg = pLazyData;
1816 }
1817 }
1818
1819 CRASSERT(RT_SUCCESS(rc));
1820 return VINF_SUCCESS;
1821}
1822
1823DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
1824{
1825 int32_t rc, i;
1826 uint32_t ui, uiNumElems;
1827 unsigned long key;
1828 GLenum err;
1829
1830 if (!cr_server.bIsInLoadingState)
1831 {
1832 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
1833 cr_server.bIsInLoadingState = GL_TRUE;
1834
1835 /* Read number of clients */
1836 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
1837 AssertRCReturn(rc, rc);
1838 }
1839
1840 g_hackVBoxServerSaveLoadCallsLeft--;
1841
1842 /* Do nothing until we're being called last time */
1843 if (g_hackVBoxServerSaveLoadCallsLeft>0)
1844 {
1845 return VINF_SUCCESS;
1846 }
1847
1848 if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
1849 {
1850 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1851 }
1852
1853 /* Load and recreate rendering contexts */
1854 rc = SSMR3GetU32(pSSM, &uiNumElems);
1855 AssertRCReturn(rc, rc);
1856 for (ui=0; ui<uiNumElems; ++ui)
1857 {
1858 CRCreateInfo_t createInfo;
1859 char psz[200];
1860 GLint ctxID;
1861 CRContextInfo* pContextInfo;
1862 CRContext* pContext;
1863
1864 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1865 AssertRCReturn(rc, rc);
1866 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1867 AssertRCReturn(rc, rc);
1868
1869 if (createInfo.pszDpyName)
1870 {
1871 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1872 AssertRCReturn(rc, rc);
1873 createInfo.pszDpyName = psz;
1874 }
1875
1876 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
1877 CRASSERT((int64_t)ctxID == (int64_t)key);
1878
1879 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1880 CRASSERT(pContextInfo);
1881 CRASSERT(pContextInfo->pContext);
1882 pContext = pContextInfo->pContext;
1883 pContext->shared->id=-1;
1884 }
1885
1886 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1887 {
1888 /* we have a mural data here */
1889 rc = crVBoxServerLoadMurals(pSSM, version);
1890 AssertRCReturn(rc, rc);
1891 }
1892
1893 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
1894 {
1895 /* set the current client to allow doing crServerPerformMakeCurrent later */
1896 CRASSERT(cr_server.numClients);
1897 cr_server.curClient = cr_server.clients[0];
1898 }
1899
1900 rc = crStateLoadGlobals(pSSM, version);
1901 AssertRCReturn(rc, rc);
1902
1903 /* Restore context state data */
1904 for (ui=0; ui<uiNumElems; ++ui)
1905 {
1906 CRContextInfo* pContextInfo;
1907 CRContext *pContext;
1908 CRMuralInfo *pMural = NULL;
1909 int32_t winId = 0;
1910
1911 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1912 AssertRCReturn(rc, rc);
1913
1914 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
1915 CRASSERT(pContextInfo);
1916 CRASSERT(pContextInfo->pContext);
1917 pContext = pContextInfo->pContext;
1918
1919 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1920 {
1921 rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
1922 AssertRCReturn(rc, rc);
1923
1924 if (winId)
1925 {
1926 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
1927 CRASSERT(pMural);
1928 }
1929 else
1930 {
1931 /* null winId means a dummy mural, get it */
1932 pMural = crServerGetDummyMural(pContextInfo->CreateInfo.visualBits);
1933 CRASSERT(pMural);
1934 }
1935
1936 crServerPerformMakeCurrent(pMural, pContextInfo);
1937 }
1938
1939 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
1940 AssertRCReturn(rc, rc);
1941
1942 /*Restore front/back buffer images*/
1943 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1944 AssertRCReturn(rc, rc);
1945 }
1946
1947 if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
1948 {
1949 CRContextInfo *pContextInfo;
1950 CRMuralInfo *pMural;
1951 GLint ctxId;
1952
1953 rc = SSMR3GetU32(pSSM, &uiNumElems);
1954 AssertRCReturn(rc, rc);
1955 for (ui=0; ui<uiNumElems; ++ui)
1956 {
1957 CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
1958 CRMuralInfo *pInitialCurMural;
1959
1960 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1961 AssertRCReturn(rc, rc);
1962
1963 rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
1964 AssertRCReturn(rc, rc);
1965
1966 pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
1967 CRASSERT(pMural);
1968 if (ctxId)
1969 {
1970 pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
1971 CRASSERT(pContextInfo);
1972 }
1973 else
1974 pContextInfo = &cr_server.MainContextInfo;
1975
1976 crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
1977 pInitialCurMural = pContextInfo->currentMural;
1978
1979 crServerPerformMakeCurrent(pMural, pContextInfo);
1980
1981 rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
1982 AssertRCReturn(rc, rc);
1983
1984 /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
1985 crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
1986 pContextInfo->currentMural = pInitialCurMural;
1987 }
1988
1989 if (cr_server.currentCtxInfo != &cr_server.MainContextInfo)
1990 {
1991 /* most ogl data gets loaded to hw on chromium 3D state switch, i.e. inside crStateMakeCurrent -> crStateSwitchContext
1992 * to force the crStateSwitchContext being called later, we need to set the current context to our dummy one */
1993 pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.visualBits);
1994 CRASSERT(pMural);
1995 crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
1996 }
1997
1998 cr_server.curClient = NULL;
1999 cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
2000 }
2001 else
2002 {
2003 CRServerFreeIDsPool_t dummyIdsPool;
2004
2005 /* we have a mural data here */
2006 rc = crVBoxServerLoadMurals(pSSM, version);
2007 AssertRCReturn(rc, rc);
2008
2009 /* not used any more, just read it out and ignore */
2010 rc = SSMR3GetMem(pSSM, &dummyIdsPool, sizeof(dummyIdsPool));
2011 CRASSERT(rc == VINF_SUCCESS);
2012 }
2013
2014 /* Load clients info */
2015 for (i = 0; i < cr_server.numClients; i++)
2016 {
2017 if (cr_server.clients[i] && cr_server.clients[i]->conn)
2018 {
2019 CRClient *pClient = cr_server.clients[i];
2020 CRClient client;
2021 unsigned long ctxID=-1, winID=-1;
2022
2023 rc = SSMR3GetU32(pSSM, &ui);
2024 AssertRCReturn(rc, rc);
2025 /* If this assert fires, then we should search correct client in the list first*/
2026 CRASSERT(ui == pClient->conn->u32ClientID);
2027
2028 if (version>=4)
2029 {
2030 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
2031 AssertRCReturn(rc, rc);
2032
2033 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
2034 AssertRCReturn(rc, rc);
2035 }
2036
2037 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
2038 CRASSERT(rc == VINF_SUCCESS);
2039
2040 client.conn = pClient->conn;
2041 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
2042 * and fail to bind old textures.
2043 */
2044 /*client.number = pClient->number;*/
2045 *pClient = client;
2046
2047 pClient->currentContextNumber = -1;
2048 pClient->currentCtxInfo = &cr_server.MainContextInfo;
2049 pClient->currentMural = NULL;
2050 pClient->currentWindow = -1;
2051
2052 cr_server.curClient = pClient;
2053
2054 if (client.currentCtxInfo && client.currentContextNumber>=0)
2055 {
2056 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
2057 AssertRCReturn(rc, rc);
2058 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
2059 CRASSERT(client.currentCtxInfo);
2060 CRASSERT(client.currentCtxInfo->pContext);
2061 //pClient->currentCtx = client.currentCtx;
2062 //pClient->currentContextNumber = ctxID;
2063 }
2064
2065 if (client.currentMural && client.currentWindow>=0)
2066 {
2067 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
2068 AssertRCReturn(rc, rc);
2069 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
2070 CRASSERT(client.currentMural);
2071 //pClient->currentMural = client.currentMural;
2072 //pClient->currentWindow = winID;
2073 }
2074
2075 /* Restore client active context and window */
2076 crServerDispatchMakeCurrent(winID, 0, ctxID);
2077
2078 if (0)
2079 {
2080// CRContext *tmpCtx;
2081// CRCreateInfo_t *createInfo;
2082 GLfloat one[4] = { 1, 1, 1, 1 };
2083 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
2084
2085 crServerDispatchMakeCurrent(winID, 0, ctxID);
2086
2087 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
2088
2089 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
2090 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
2091 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
2092#ifdef CR_ARB_texture_cube_map
2093 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
2094#endif
2095#ifdef CR_NV_texture_rectangle
2096 //@todo this doesn't work as expected
2097 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
2098#endif
2099 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
2100 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
2101 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
2102
2103 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
2104 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
2105 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
2106
2107 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
2108 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
2109
2110 //crStateViewport( 0, 0, 600, 600 );
2111 //pClient->currentMural->viewportValidated = GL_FALSE;
2112 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
2113
2114 //crStateMatrixMode(GL_PROJECTION);
2115 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
2116
2117 //crStateLoadIdentity();
2118 //cr_server.head_spu->dispatch_table.LoadIdentity();
2119
2120 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2121 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2122
2123 //crStateMatrixMode(GL_MODELVIEW);
2124 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
2125 //crServerDispatchLoadIdentity();
2126 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2127 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
2128 //crServerDispatchLoadIdentity();
2129
2130 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
2131 CRASSERT(createInfo);
2132 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
2133 CRASSERT(tmpCtx);
2134 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
2135 crStateDestroyContext(tmpCtx);*/
2136 }
2137 }
2138 }
2139
2140 //crServerDispatchMakeCurrent(-1, 0, -1);
2141
2142 cr_server.curClient = NULL;
2143
2144 while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
2145 crWarning("crServer: glGetError %d after loading snapshot", err);
2146
2147 cr_server.bIsInLoadingState = GL_FALSE;
2148
2149#if 0
2150 crVBoxServerCheckConsistency();
2151#endif
2152
2153 return VINF_SUCCESS;
2154}
2155
2156#define SCREEN(i) (cr_server.screen[i])
2157#define MAPPED(screen) ((screen).winID != 0)
2158
2159static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
2160{
2161 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2162 int *sIndex = (int*) data2;
2163
2164 if (pMI->screenId == *sIndex)
2165 {
2166 renderspuReparentWindow(pMI->spuWindow);
2167 }
2168}
2169
2170static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
2171{
2172 CRMuralInfo *pMI = (CRMuralInfo*) data1;
2173 (void) data2;
2174
2175 crServerCheckMuralGeometry(pMI);
2176}
2177
2178DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
2179{
2180 int i;
2181
2182 if (sCount>CR_MAX_GUEST_MONITORS)
2183 return VERR_INVALID_PARAMETER;
2184
2185 /*Shouldn't happen yet, but to be safe in future*/
2186 for (i=0; i<cr_server.screenCount; ++i)
2187 {
2188 if (MAPPED(SCREEN(i)))
2189 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
2190 return VERR_NOT_IMPLEMENTED;
2191 }
2192
2193 cr_server.screenCount = sCount;
2194
2195 for (i=0; i<sCount; ++i)
2196 {
2197 SCREEN(i).winID = 0;
2198 }
2199
2200 return VINF_SUCCESS;
2201}
2202
2203DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
2204{
2205 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
2206
2207 if (sIndex<0 || sIndex>=cr_server.screenCount)
2208 return VERR_INVALID_PARAMETER;
2209
2210 if (MAPPED(SCREEN(sIndex)))
2211 {
2212 SCREEN(sIndex).winID = 0;
2213 renderspuSetWindowId(0);
2214
2215 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2216 }
2217
2218 renderspuSetWindowId(SCREEN(0).winID);
2219 return VINF_SUCCESS;
2220}
2221
2222DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
2223{
2224 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
2225
2226 if (sIndex<0 || sIndex>=cr_server.screenCount)
2227 return VERR_INVALID_PARAMETER;
2228
2229 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
2230 {
2231 crDebug("Mapped screen[%i] is being remapped.", sIndex);
2232 crVBoxServerUnmapScreen(sIndex);
2233 }
2234
2235 SCREEN(sIndex).winID = winID;
2236 SCREEN(sIndex).x = x;
2237 SCREEN(sIndex).y = y;
2238 SCREEN(sIndex).w = w;
2239 SCREEN(sIndex).h = h;
2240
2241 renderspuSetWindowId(SCREEN(sIndex).winID);
2242 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
2243 renderspuSetWindowId(SCREEN(0).winID);
2244
2245 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2246
2247#ifndef WINDOWS
2248 /*Restore FB content for clients, which have current window on a screen being remapped*/
2249 {
2250 GLint i;
2251
2252 for (i = 0; i < cr_server.numClients; i++)
2253 {
2254 cr_server.curClient = cr_server.clients[i];
2255 if (cr_server.curClient->currentCtxInfo
2256 && cr_server.curClient->currentCtxInfo->pContext
2257 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
2258 && cr_server.curClient->currentMural
2259 && cr_server.curClient->currentMural->screenId == sIndex
2260 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
2261 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
2262 {
2263 int clientWindow = cr_server.curClient->currentWindow;
2264 int clientContext = cr_server.curClient->currentContextNumber;
2265 CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
2266
2267 if (clientWindow && clientWindow != cr_server.currentWindow)
2268 {
2269 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
2270 }
2271
2272 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
2273 crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
2274 }
2275 }
2276 cr_server.curClient = NULL;
2277 }
2278#endif
2279
2280 {
2281 PCR_DISPLAY pDisplay = crServerDisplayGetInitialized(sIndex);
2282 if (pDisplay)
2283 CrDpResize(pDisplay, w, h, w, h);
2284 }
2285
2286 return VINF_SUCCESS;
2287}
2288
2289DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
2290{
2291 renderspuSetRootVisibleRegion(cRects, pRects);
2292
2293 return VINF_SUCCESS;
2294}
2295
2296DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
2297{
2298 cr_server.pfnPresentFBO = pfnPresentFBO;
2299}
2300
2301int32_t crServerSetOffscreenRenderingMode(GLubyte value)
2302{
2303 if (cr_server.bForceOffscreenRendering==value)
2304 {
2305 return VINF_SUCCESS;
2306 }
2307
2308 if (value > CR_SERVER_REDIR_MAXVAL)
2309 {
2310 crWarning("crServerSetOffscreenRenderingMode: invalid arg: %d", value);
2311 return VERR_INVALID_PARAMETER;
2312 }
2313
2314 if (value && !crServerSupportRedirMuralFBO())
2315 {
2316 return VERR_NOT_SUPPORTED;
2317 }
2318
2319 cr_server.bForceOffscreenRendering=value;
2320
2321 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
2322
2323 return VINF_SUCCESS;
2324}
2325
2326DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
2327{
2328 return crServerSetOffscreenRenderingMode(value ? CR_SERVER_REDIR_FBO_RAM : cr_server.bOffscreenRenderingDefault);
2329}
2330
2331DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
2332{
2333 /* No need for a synchronization as this is single threaded. */
2334 if (pCallbacks)
2335 {
2336 cr_server.outputRedirect = *pCallbacks;
2337 cr_server.bUseOutputRedirect = true;
2338 }
2339 else
2340 {
2341 cr_server.bUseOutputRedirect = false;
2342 }
2343
2344 // @todo dynamically intercept already existing output:
2345 // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
2346
2347 return VINF_SUCCESS;
2348}
2349
2350static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2)
2351{
2352 CRMuralInfo *mural = (CRMuralInfo*) data1;
2353 int *sIndex = (int*) data2;
2354
2355 if (mural->screenId != *sIndex)
2356 return;
2357
2358 crServerCheckMuralGeometry(mural);
2359}
2360
2361
2362DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
2363{
2364 CRScreenViewportInfo *pVieport;
2365 GLboolean fPosChanged, fSizeChanged;
2366
2367 crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
2368
2369 if (sIndex<0 || sIndex>=cr_server.screenCount)
2370 {
2371 crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
2372 return VERR_INVALID_PARAMETER;
2373 }
2374
2375 pVieport = &cr_server.screenVieport[sIndex];
2376 fPosChanged = (pVieport->x != x || pVieport->y != y);
2377 fSizeChanged = (pVieport->w != w || pVieport->h != h);
2378
2379 if (!fPosChanged && !fSizeChanged)
2380 {
2381 crDebug("crVBoxServerSetScreenViewport: no changes");
2382 return VINF_SUCCESS;
2383 }
2384
2385 if (fPosChanged)
2386 {
2387 pVieport->x = x;
2388 pVieport->y = y;
2389
2390 crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex);
2391 }
2392
2393 if (fSizeChanged)
2394 {
2395 pVieport->w = w;
2396 pVieport->h = h;
2397
2398 /* no need to do anything here actually */
2399 }
2400 return VINF_SUCCESS;
2401}
2402
2403
2404#ifdef VBOX_WITH_CRHGSMI
2405/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
2406 *
2407 * 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.
2408 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
2409 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
2410 * to block the lower-priority thread trying to complete the blocking command.
2411 * And removed extra memcpy done on blocked command arrival.
2412 *
2413 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
2414 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
2415 *
2416 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
2417 * */
2418int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
2419{
2420 int32_t rc;
2421 uint32_t cBuffers = pCmd->cBuffers;
2422 uint32_t cParams;
2423 uint32_t cbHdr;
2424 CRVBOXHGSMIHDR *pHdr;
2425 uint32_t u32Function;
2426 uint32_t u32ClientID;
2427 CRClient *pClient;
2428
2429 if (!g_pvVRamBase)
2430 {
2431 crWarning("g_pvVRamBase is not initialized");
2432 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
2433 return VINF_SUCCESS;
2434 }
2435
2436 if (!cBuffers)
2437 {
2438 crWarning("zero buffers passed in!");
2439 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2440 return VINF_SUCCESS;
2441 }
2442
2443 cParams = cBuffers-1;
2444
2445 cbHdr = pCmd->aBuffers[0].cbBuffer;
2446 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
2447 if (!pHdr)
2448 {
2449 crWarning("invalid header buffer!");
2450 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2451 return VINF_SUCCESS;
2452 }
2453
2454 if (cbHdr < sizeof (*pHdr))
2455 {
2456 crWarning("invalid header buffer size!");
2457 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
2458 return VINF_SUCCESS;
2459 }
2460
2461 u32Function = pHdr->u32Function;
2462 u32ClientID = pHdr->u32ClientID;
2463
2464 switch (u32Function)
2465 {
2466 case SHCRGL_GUEST_FN_WRITE:
2467 {
2468 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
2469
2470 /* @todo: Verify */
2471 if (cParams == 1)
2472 {
2473 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
2474 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2475 /* Fetch parameters. */
2476 uint32_t cbBuffer = pBuf->cbBuffer;
2477 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2478
2479 if (cbHdr < sizeof (*pFnCmd))
2480 {
2481 crWarning("invalid write cmd buffer size!");
2482 rc = VERR_INVALID_PARAMETER;
2483 break;
2484 }
2485
2486 CRASSERT(cbBuffer);
2487 if (!pBuffer)
2488 {
2489 crWarning("invalid buffer data received from guest!");
2490 rc = VERR_INVALID_PARAMETER;
2491 break;
2492 }
2493
2494 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2495 if (RT_FAILURE(rc))
2496 {
2497 break;
2498 }
2499
2500 /* This should never fire unless we start to multithread */
2501 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2502 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2503
2504 pClient->conn->pBuffer = pBuffer;
2505 pClient->conn->cbBuffer = cbBuffer;
2506 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2507 rc = crVBoxServerInternalClientWriteRead(pClient);
2508 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2509 return rc;
2510 }
2511 else
2512 {
2513 crWarning("invalid number of args");
2514 rc = VERR_INVALID_PARAMETER;
2515 break;
2516 }
2517 break;
2518 }
2519
2520 case SHCRGL_GUEST_FN_INJECT:
2521 {
2522 crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
2523
2524 /* @todo: Verify */
2525 if (cParams == 1)
2526 {
2527 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
2528 /* Fetch parameters. */
2529 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
2530 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2531 uint32_t cbBuffer = pBuf->cbBuffer;
2532 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2533
2534 if (cbHdr < sizeof (*pFnCmd))
2535 {
2536 crWarning("invalid inject cmd buffer size!");
2537 rc = VERR_INVALID_PARAMETER;
2538 break;
2539 }
2540
2541 CRASSERT(cbBuffer);
2542 if (!pBuffer)
2543 {
2544 crWarning("invalid buffer data received from guest!");
2545 rc = VERR_INVALID_PARAMETER;
2546 break;
2547 }
2548
2549 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
2550 if (RT_FAILURE(rc))
2551 {
2552 break;
2553 }
2554
2555 /* This should never fire unless we start to multithread */
2556 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2557 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2558
2559 pClient->conn->pBuffer = pBuffer;
2560 pClient->conn->cbBuffer = cbBuffer;
2561 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
2562 rc = crVBoxServerInternalClientWriteRead(pClient);
2563 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2564 return rc;
2565 }
2566
2567 crWarning("invalid number of args");
2568 rc = VERR_INVALID_PARAMETER;
2569 break;
2570 }
2571
2572 case SHCRGL_GUEST_FN_READ:
2573 {
2574 crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n"));
2575
2576 /* @todo: Verify */
2577 if (cParams == 1)
2578 {
2579 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
2580 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2581 /* Fetch parameters. */
2582 uint32_t cbBuffer = pBuf->cbBuffer;
2583 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2584
2585 if (cbHdr < sizeof (*pFnCmd))
2586 {
2587 crWarning("invalid read cmd buffer size!");
2588 rc = VERR_INVALID_PARAMETER;
2589 break;
2590 }
2591
2592
2593 if (!pBuffer)
2594 {
2595 crWarning("invalid buffer data received from guest!");
2596 rc = VERR_INVALID_PARAMETER;
2597 break;
2598 }
2599
2600 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2601 if (RT_FAILURE(rc))
2602 {
2603 break;
2604 }
2605
2606 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2607
2608 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
2609
2610 /* Return the required buffer size always */
2611 pFnCmd->cbBuffer = cbBuffer;
2612
2613 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2614
2615 /* the read command is never pended, complete it right away */
2616 pHdr->result = rc;
2617 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2618 return VINF_SUCCESS;
2619 }
2620
2621 crWarning("invalid number of args");
2622 rc = VERR_INVALID_PARAMETER;
2623 break;
2624 }
2625
2626 case SHCRGL_GUEST_FN_WRITE_READ:
2627 {
2628 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
2629
2630 /* @todo: Verify */
2631 if (cParams == 2)
2632 {
2633 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
2634 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
2635 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
2636
2637 /* Fetch parameters. */
2638 uint32_t cbBuffer = pBuf->cbBuffer;
2639 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
2640
2641 uint32_t cbWriteback = pWbBuf->cbBuffer;
2642 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
2643
2644 if (cbHdr < sizeof (*pFnCmd))
2645 {
2646 crWarning("invalid write_read cmd buffer size!");
2647 rc = VERR_INVALID_PARAMETER;
2648 break;
2649 }
2650
2651
2652 CRASSERT(cbBuffer);
2653 if (!pBuffer)
2654 {
2655 crWarning("invalid write buffer data received from guest!");
2656 rc = VERR_INVALID_PARAMETER;
2657 break;
2658 }
2659
2660 CRASSERT(cbWriteback);
2661 if (!pWriteback)
2662 {
2663 crWarning("invalid writeback buffer data received from guest!");
2664 rc = VERR_INVALID_PARAMETER;
2665 break;
2666 }
2667 rc = crVBoxServerClientGet(u32ClientID, &pClient);
2668 if (RT_FAILURE(rc))
2669 {
2670 pHdr->result = rc;
2671 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2672 return rc;
2673 }
2674
2675 /* This should never fire unless we start to multithread */
2676 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
2677 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2678
2679 pClient->conn->pBuffer = pBuffer;
2680 pClient->conn->cbBuffer = cbBuffer;
2681 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
2682 rc = crVBoxServerInternalClientWriteRead(pClient);
2683 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
2684 return rc;
2685 }
2686
2687 crWarning("invalid number of args");
2688 rc = VERR_INVALID_PARAMETER;
2689 break;
2690 }
2691
2692 case SHCRGL_GUEST_FN_SET_VERSION:
2693 {
2694 crWarning("invalid function");
2695 rc = VERR_NOT_IMPLEMENTED;
2696 break;
2697 }
2698
2699 case SHCRGL_GUEST_FN_SET_PID:
2700 {
2701 crWarning("invalid function");
2702 rc = VERR_NOT_IMPLEMENTED;
2703 break;
2704 }
2705
2706 default:
2707 {
2708 crWarning("invalid function");
2709 rc = VERR_NOT_IMPLEMENTED;
2710 break;
2711 }
2712
2713 }
2714
2715 /* we can be on fail only here */
2716 CRASSERT(RT_FAILURE(rc));
2717 pHdr->result = rc;
2718 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
2719 return rc;
2720}
2721
2722int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
2723{
2724 int rc = VINF_SUCCESS;
2725
2726 switch (pCtl->enmType)
2727 {
2728 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
2729 {
2730 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
2731 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
2732 g_cbVRam = pSetup->cbVRam;
2733 rc = VINF_SUCCESS;
2734 break;
2735 }
2736 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
2737 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
2738 rc = VINF_SUCCESS;
2739 break;
2740 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
2741 {
2742 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
2743 g_hCrHgsmiCompletion = pSetup->hCompletion;
2744 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
2745 rc = VINF_SUCCESS;
2746 break;
2747 }
2748 default:
2749 AssertMsgFailed(("invalid param %d", pCtl->enmType));
2750 rc = VERR_INVALID_PARAMETER;
2751 }
2752
2753 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
2754 * to complete them accordingly.
2755 * This approach allows using host->host and host->guest commands in the same way here
2756 * making the command completion to be the responsibility of the command originator.
2757 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
2758 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
2759 return rc;
2760}
2761#endif
Note: See TracBrowser for help on using the repository browser.

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