VirtualBox

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

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

crOpenGL: OSX backend rework; oddscreen rendering generalization

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