VirtualBox

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

Last change on this file since 41111 was 41111, checked in by vboxsync, 13 years ago

crOpenGL: rename env var for enabling multiple contexts to CR_SERVER_ENABLE_MULTIPLE_CONTEXTS

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 52.7 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_environment.h"
16#include "server_dispatch.h"
17#include "state/cr_texture.h"
18#include "render/renderspu.h"
19#include <signal.h>
20#include <stdlib.h>
21#define DEBUG_FP_EXCEPTIONS 0
22#if DEBUG_FP_EXCEPTIONS
23#include <fpu_control.h>
24#include <math.h>
25#endif
26#include <iprt/assert.h>
27#include <VBox/err.h>
28
29#ifdef VBOXCR_LOGFPS
30#include <iprt/timer.h>
31#endif
32
33#ifdef VBOX_WITH_CRHGSMI
34# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
35uint8_t* g_pvVRamBase = NULL;
36uint32_t g_cbVRam = 0;
37HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion = NULL;
38PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion = NULL;
39#endif
40
41/**
42 * \mainpage CrServerLib
43 *
44 * \section CrServerLibIntroduction Introduction
45 *
46 * Chromium consists of all the top-level files in the cr
47 * directory. The core module basically takes care of API dispatch,
48 * and OpenGL state management.
49 */
50
51
52/**
53 * CRServer global data
54 */
55CRServer cr_server;
56
57int tearingdown = 0; /* can't be static */
58
59DECLINLINE(int32_t) crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
60{
61 CRClient *pClient = NULL;
62 int32_t i;
63
64 *ppClient = NULL;
65
66 for (i = 0; i < cr_server.numClients; i++)
67 {
68 if (cr_server.clients[i] && cr_server.clients[i]->conn
69 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
70 {
71 pClient = cr_server.clients[i];
72 break;
73 }
74 }
75 if (!pClient)
76 {
77 crWarning("client not found!");
78 return VERR_INVALID_PARAMETER;
79 }
80
81 if (!pClient->conn->vMajor)
82 {
83 crWarning("no major version specified for client!");
84 return VERR_NOT_SUPPORTED;
85 }
86
87 *ppClient = pClient;
88
89 return VINF_SUCCESS;
90}
91
92
93/**
94 * Return pointer to server's first SPU.
95 */
96SPU*
97crServerHeadSPU(void)
98{
99 return cr_server.head_spu;
100}
101
102
103
104static void DeleteBarrierCallback( void *data )
105{
106 CRServerBarrier *barrier = (CRServerBarrier *) data;
107 crFree(barrier->waiting);
108 crFree(barrier);
109}
110
111
112static void deleteContextInfoCallback( void *data )
113{
114 CRContextInfo *c = (CRContextInfo *) data;
115 crStateDestroyContext(c->pContext);
116 if (c->CreateInfo.pszDpyName)
117 crFree(c->CreateInfo.pszDpyName);
118 crFree(c);
119}
120
121
122static void crServerTearDown( void )
123{
124 GLint i;
125 CRClientNode *pNode, *pNext;
126
127 /* avoid a race condition */
128 if (tearingdown)
129 return;
130
131 tearingdown = 1;
132
133 crStateSetCurrent( NULL );
134
135 cr_server.curClient = NULL;
136 cr_server.run_queue = NULL;
137
138 crFree( cr_server.overlap_intens );
139 cr_server.overlap_intens = NULL;
140
141 /* Deallocate all semaphores */
142 crFreeHashtable(cr_server.semaphores, crFree);
143 cr_server.semaphores = NULL;
144
145 /* Deallocate all barriers */
146 crFreeHashtable(cr_server.barriers, DeleteBarrierCallback);
147 cr_server.barriers = NULL;
148
149 /* Free all context info */
150 crFreeHashtable(cr_server.contextTable, deleteContextInfoCallback);
151
152 /* Free context/window creation info */
153 crFreeHashtable(cr_server.pWindowCreateInfoTable, crServerCreateInfoDeleteCB);
154
155 /* Free vertex programs */
156 crFreeHashtable(cr_server.programTable, crFree);
157
158 for (i = 0; i < cr_server.numClients; i++) {
159 if (cr_server.clients[i]) {
160 CRConnection *conn = cr_server.clients[i]->conn;
161 crNetFreeConnection(conn);
162 crFree(cr_server.clients[i]);
163 }
164 }
165 cr_server.numClients = 0;
166
167 pNode = cr_server.pCleanupClient;
168 while (pNode)
169 {
170 pNext=pNode->next;
171 crFree(pNode->pClient);
172 crFree(pNode);
173 pNode=pNext;
174 }
175 cr_server.pCleanupClient = NULL;
176
177#if 1
178 /* disable these two lines if trying to get stack traces with valgrind */
179 crSPUUnloadChain(cr_server.head_spu);
180 cr_server.head_spu = NULL;
181#endif
182
183 crStateDestroy();
184
185 crNetTearDown();
186}
187
188static void crServerClose( unsigned int id )
189{
190 crError( "Client disconnected!" );
191 (void) id;
192}
193
194static void crServerCleanup( int sigio )
195{
196 crServerTearDown();
197
198 tearingdown = 0;
199}
200
201
202void
203crServerSetPort(int port)
204{
205 cr_server.tcpip_port = port;
206}
207
208
209
210static void
211crPrintHelp(void)
212{
213 printf("Usage: crserver [OPTIONS]\n");
214 printf("Options:\n");
215 printf(" -mothership URL Specifies URL for contacting the mothership.\n");
216 printf(" URL is of the form [protocol://]hostname[:port]\n");
217 printf(" -port N Specifies the port number this server will listen to.\n");
218 printf(" -help Prints this information.\n");
219}
220
221
222/**
223 * Do CRServer initializations. After this, we can begin servicing clients.
224 */
225void
226crServerInit(int argc, char *argv[])
227{
228 int i;
229 char *mothership = NULL;
230 CRMuralInfo *defaultMural;
231
232 for (i = 1 ; i < argc ; i++)
233 {
234 if (!crStrcmp( argv[i], "-mothership" ))
235 {
236 if (i == argc - 1)
237 {
238 crError( "-mothership requires an argument" );
239 }
240 mothership = argv[i+1];
241 i++;
242 }
243 else if (!crStrcmp( argv[i], "-port" ))
244 {
245 /* This is the port on which we'll accept client connections */
246 if (i == argc - 1)
247 {
248 crError( "-port requires an argument" );
249 }
250 cr_server.tcpip_port = crStrToInt(argv[i+1]);
251 i++;
252 }
253 else if (!crStrcmp( argv[i], "-vncmode" ))
254 {
255 cr_server.vncMode = 1;
256 }
257 else if (!crStrcmp( argv[i], "-help" ))
258 {
259 crPrintHelp();
260 exit(0);
261 }
262 }
263
264 signal( SIGTERM, crServerCleanup );
265 signal( SIGINT, crServerCleanup );
266#ifndef WINDOWS
267 signal( SIGPIPE, SIG_IGN );
268#endif
269
270#if DEBUG_FP_EXCEPTIONS
271 {
272 fpu_control_t mask;
273 _FPU_GETCW(mask);
274 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
275 | _FPU_MASK_OM | _FPU_MASK_UM);
276 _FPU_SETCW(mask);
277 }
278#endif
279
280 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
281
282 if (cr_server.bUseMultipleContexts)
283 {
284 crInfo("Info: using multiple contexts!");
285 crDebug("Debug: using multiple contexts!");
286 }
287
288 cr_server.firstCallCreateContext = GL_TRUE;
289 cr_server.firstCallMakeCurrent = GL_TRUE;
290
291 /*
292 * Create default mural info and hash table.
293 */
294 cr_server.muralTable = crAllocHashtable();
295 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
296 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
297
298 cr_server.programTable = crAllocHashtable();
299
300 crNetInit(crServerRecv, crServerClose);
301 crStateInit();
302
303 crServerSetVBoxConfiguration();
304
305 crStateLimitsInit( &(cr_server.limits) );
306
307 /*
308 * Default context
309 */
310 cr_server.contextTable = crAllocHashtable();
311 cr_server.MainContextInfo.pContext = crStateCreateContext( &cr_server.limits,
312 CR_RGB_BIT | CR_DEPTH_BIT, NULL );
313 cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
314
315 crServerInitDispatch();
316 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
317
318 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
319 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
320
321 cr_server.barriers = crAllocHashtable();
322 cr_server.semaphores = crAllocHashtable();
323}
324
325void crVBoxServerTearDown(void)
326{
327 crServerTearDown();
328}
329
330/**
331 * Do CRServer initializations. After this, we can begin servicing clients.
332 */
333GLboolean crVBoxServerInit(void)
334{
335 CRMuralInfo *defaultMural;
336
337#if DEBUG_FP_EXCEPTIONS
338 {
339 fpu_control_t mask;
340 _FPU_GETCW(mask);
341 mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
342 | _FPU_MASK_OM | _FPU_MASK_UM);
343 _FPU_SETCW(mask);
344 }
345#endif
346
347 cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
348
349 if (cr_server.bUseMultipleContexts)
350 {
351 crInfo("Info: using multiple contexts!");
352 crDebug("Debug: using multiple contexts!");
353 }
354
355 crNetInit(crServerRecv, crServerClose);
356
357 cr_server.firstCallCreateContext = GL_TRUE;
358 cr_server.firstCallMakeCurrent = GL_TRUE;
359
360 cr_server.bIsInLoadingState = GL_FALSE;
361 cr_server.bIsInSavingState = GL_FALSE;
362
363
364 cr_server.pCleanupClient = NULL;
365
366 /*
367 * Create default mural info and hash table.
368 */
369 cr_server.muralTable = crAllocHashtable();
370 defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
371 crHashtableAdd(cr_server.muralTable, 0, defaultMural);
372
373 cr_server.programTable = crAllocHashtable();
374
375 crStateInit();
376
377 crStateLimitsInit( &(cr_server.limits) );
378
379 cr_server.barriers = crAllocHashtable();
380 cr_server.semaphores = crAllocHashtable();
381
382 crUnpackSetReturnPointer( &(cr_server.return_ptr) );
383 crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
384
385 /*
386 * Default context
387 */
388 cr_server.contextTable = crAllocHashtable();
389 cr_server.MainContextInfo.pContext = crStateCreateContext( &cr_server.limits,
390 CR_RGB_BIT | CR_DEPTH_BIT, NULL );
391// cr_server.pContextCreateInfoTable = crAllocHashtable();
392 cr_server.pWindowCreateInfoTable = crAllocHashtable();
393
394 crServerSetVBoxConfigurationHGCM();
395
396 if (!cr_server.head_spu)
397 return GL_FALSE;
398
399 crServerInitDispatch();
400 crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
401
402 /*Check for PBO support*/
403 if (crStateGetCurrent()->extensions.ARB_pixel_buffer_object)
404 {
405 cr_server.bUsePBOForReadback=GL_TRUE;
406 }
407
408 return GL_TRUE;
409}
410
411int32_t crVBoxServerAddClient(uint32_t u32ClientID)
412{
413 CRClient *newClient;
414
415 if (cr_server.numClients>=CR_MAX_CLIENTS)
416 {
417 return VERR_MAX_THRDS_REACHED;
418 }
419
420 newClient = (CRClient *) crCalloc(sizeof(CRClient));
421 crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
422
423 newClient->spu_id = 0;
424 newClient->currentCtxInfo = &cr_server.MainContextInfo;
425 newClient->currentContextNumber = -1;
426 newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
427 cr_server.tcpip_port,
428 cr_server.mtu, 0);
429 newClient->conn->u32ClientID = u32ClientID;
430
431 cr_server.clients[cr_server.numClients++] = newClient;
432
433 crServerAddToRunQueue(newClient);
434
435 return VINF_SUCCESS;
436}
437
438void crVBoxServerRemoveClient(uint32_t u32ClientID)
439{
440 CRClient *pClient=NULL;
441 int32_t i;
442
443 crDebug("crServer: RemoveClient u32ClientID=%d", u32ClientID);
444
445 for (i = 0; i < cr_server.numClients; i++)
446 {
447 if (cr_server.clients[i] && cr_server.clients[i]->conn
448 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
449 {
450 pClient = cr_server.clients[i];
451 break;
452 }
453 }
454 //if (!pClient) return VERR_INVALID_PARAMETER;
455 if (!pClient)
456 {
457 crWarning("Invalid client id %u passed to crVBoxServerRemoveClient", u32ClientID);
458 return;
459 }
460
461#ifdef VBOX_WITH_CRHGSMI
462 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
463#endif
464
465 /* Disconnect the client */
466 pClient->conn->Disconnect(pClient->conn);
467
468 /* Let server clear client from the queue */
469 crServerDeleteClient(pClient);
470}
471
472static int32_t crVBoxServerInternalClientWriteRead(CRClient *pClient)
473{
474#ifdef VBOXCR_LOGFPS
475 uint64_t tstart, tend;
476#endif
477
478 /*crDebug("=>crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
479
480
481#ifdef VBOXCR_LOGFPS
482 tstart = RTTimeNanoTS();
483#endif
484
485 /* This should be setup already */
486 CRASSERT(pClient->conn->pBuffer);
487 CRASSERT(pClient->conn->cbBuffer);
488#ifdef VBOX_WITH_CRHGSMI
489 CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&pClient->conn->CmdData);
490#endif
491
492 if (
493#ifdef VBOX_WITH_CRHGSMI
494 !CRVBOXHGSMI_CMDDATA_IS_SET(&pClient->conn->CmdData) &&
495#endif
496 cr_server.run_queue->client != pClient
497 && crServerClientInBeginEnd(cr_server.run_queue->client))
498 {
499 crDebug("crServer: client %d blocked, allow_redir_ptr = 0", pClient->conn->u32ClientID);
500 pClient->conn->allow_redir_ptr = 0;
501 }
502 else
503 {
504 pClient->conn->allow_redir_ptr = 1;
505 }
506
507 crNetRecv();
508 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
509 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
510
511 crServerServiceClients();
512
513#if 0
514 if (pClient->currentMural) {
515 crStateViewport( 0, 0, 500, 500 );
516 pClient->currentMural->viewportValidated = GL_FALSE;
517 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 500, 500 );
518 crStateViewport( 0, 0, 600, 600 );
519 pClient->currentMural->viewportValidated = GL_FALSE;
520 cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
521
522 crStateMatrixMode(GL_PROJECTION);
523 cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
524 crServerDispatchLoadIdentity();
525 crStateFrustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
526 cr_server.head_spu->dispatch_table.Frustum(-0.6, 0.6, -0.5, 0.5, 1.5, 150.0);
527 crServerDispatchLoadIdentity();
528 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
529 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
530
531 crStateMatrixMode(GL_MODELVIEW);
532 cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
533 crServerDispatchLoadIdentity();
534 crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
535 cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
536 crServerDispatchLoadIdentity();
537 }
538#endif
539
540 crStateResetCurrentPointers(&cr_server.current);
541
542#ifndef VBOX_WITH_CRHGSMI
543 CRASSERT(!pClient->conn->allow_redir_ptr || crNetNumMessages(pClient->conn)==0);
544#endif
545
546#ifdef VBOXCR_LOGFPS
547 tend = RTTimeNanoTS();
548 pClient->timeUsed += tend-tstart;
549#endif
550 /*crDebug("<=crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
551
552 return VINF_SUCCESS;
553}
554
555
556int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer)
557{
558 CRClient *pClient=NULL;
559 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
560
561 if (RT_FAILURE(rc))
562 return rc;
563
564
565 CRASSERT(pBuffer);
566
567 /* This should never fire unless we start to multithread */
568 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
569
570 pClient->conn->pBuffer = pBuffer;
571 pClient->conn->cbBuffer = cbBuffer;
572#ifdef VBOX_WITH_CRHGSMI
573 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
574#endif
575
576 return crVBoxServerInternalClientWriteRead(pClient);
577}
578
579int32_t crVBoxServerInternalClientRead(CRClient *pClient, uint8_t *pBuffer, uint32_t *pcbBuffer)
580{
581 if (pClient->conn->cbHostBuffer > *pcbBuffer)
582 {
583 crDebug("crServer: [%lx] ClientRead u32ClientID=%d FAIL, host buffer too small %d of %d",
584 crThreadID(), pClient->conn->u32ClientID, *pcbBuffer, pClient->conn->cbHostBuffer);
585
586 /* Return the size of needed buffer */
587 *pcbBuffer = pClient->conn->cbHostBuffer;
588
589 return VERR_BUFFER_OVERFLOW;
590 }
591
592 *pcbBuffer = pClient->conn->cbHostBuffer;
593
594 if (*pcbBuffer)
595 {
596 CRASSERT(pClient->conn->pHostBuffer);
597
598 crMemcpy(pBuffer, pClient->conn->pHostBuffer, *pcbBuffer);
599 pClient->conn->cbHostBuffer = 0;
600 }
601
602 return VINF_SUCCESS;
603}
604
605int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t *pcbBuffer)
606{
607 CRClient *pClient=NULL;
608 int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
609
610 if (RT_FAILURE(rc))
611 return rc;
612
613#ifdef VBOX_WITH_CRHGSMI
614 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
615#endif
616
617 return crVBoxServerInternalClientRead(pClient, pBuffer, pcbBuffer);
618}
619
620int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor)
621{
622 CRClient *pClient=NULL;
623 int32_t i;
624
625 for (i = 0; i < cr_server.numClients; i++)
626 {
627 if (cr_server.clients[i] && cr_server.clients[i]->conn
628 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
629 {
630 pClient = cr_server.clients[i];
631 break;
632 }
633 }
634 if (!pClient) return VERR_INVALID_PARAMETER;
635
636 pClient->conn->vMajor = vMajor;
637 pClient->conn->vMinor = vMinor;
638
639 if (vMajor != CR_PROTOCOL_VERSION_MAJOR
640 || vMinor != CR_PROTOCOL_VERSION_MINOR)
641 {
642 return VERR_NOT_SUPPORTED;
643 }
644 else return VINF_SUCCESS;
645}
646
647int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid)
648{
649 CRClient *pClient=NULL;
650 int32_t i;
651
652 for (i = 0; i < cr_server.numClients; i++)
653 {
654 if (cr_server.clients[i] && cr_server.clients[i]->conn
655 && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
656 {
657 pClient = cr_server.clients[i];
658 break;
659 }
660 }
661 if (!pClient) return VERR_INVALID_PARAMETER;
662
663 pClient->pid = pid;
664
665 return VINF_SUCCESS;
666}
667
668int
669CRServerMain(int argc, char *argv[])
670{
671 crServerInit(argc, argv);
672
673 crServerSerializeRemoteStreams();
674
675 crServerTearDown();
676
677 tearingdown = 0;
678
679 return 0;
680}
681
682static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2)
683{
684 CRMuralInfo *pMI = (CRMuralInfo*) data1;
685 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
686 int32_t rc;
687
688 CRASSERT(pMI && pSSM);
689
690 /* Don't store default mural */
691 if (!key) return;
692
693 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
694 CRASSERT(rc == VINF_SUCCESS);
695
696 rc = SSMR3PutMem(pSSM, pMI, sizeof(*pMI));
697 CRASSERT(rc == VINF_SUCCESS);
698
699 if (pMI->pVisibleRects)
700 {
701 rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects);
702 }
703}
704
705/* @todo add hashtable walker with result info and intermediate abort */
706static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *data2)
707{
708 CRCreateInfo_t *pCreateInfo = (CRCreateInfo_t *)data1;
709 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
710 int32_t rc;
711
712 CRASSERT(pCreateInfo && pSSM);
713
714 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
715 CRASSERT(rc == VINF_SUCCESS);
716
717 rc = SSMR3PutMem(pSSM, pCreateInfo, sizeof(*pCreateInfo));
718 CRASSERT(rc == VINF_SUCCESS);
719
720 if (pCreateInfo->pszDpyName)
721 {
722 rc = SSMR3PutStrZ(pSSM, pCreateInfo->pszDpyName);
723 CRASSERT(rc == VINF_SUCCESS);
724 }
725}
726
727static void crVBoxServerSaveCreateInfoFromCtxInfoCB(unsigned long key, void *data1, void *data2)
728{
729 CRContextInfo *pContextInfo = (CRContextInfo *)data1;
730 CRCreateInfo_t *pCreateInfo = &pContextInfo->CreateInfo;
731 crVBoxServerSaveCreateInfoCB(key, pCreateInfo, data2);
732}
733
734static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data2)
735{
736 CRTextureObj *pTexture = (CRTextureObj *) data1;
737 CRContext *pContext = (CRContext *) data2;
738
739 CRASSERT(pTexture && pContext);
740 crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
741}
742
743static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
744{
745 CRContextInfo *pContextInfo = (CRContextInfo *) data1;
746 CRContext *pContext = pContextInfo->pContext;
747 PSSMHANDLE pSSM = (PSSMHANDLE) data2;
748 int32_t rc;
749
750 CRASSERT(pContext && pSSM);
751
752 /* We could have skipped saving the key and use similar callback to load context states back,
753 * but there's no guarantee we'd traverse hashtable in same order after loading.
754 */
755 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
756 CRASSERT(rc == VINF_SUCCESS);
757
758#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
759 if (cr_server.curClient)
760 {
761 unsigned long id;
762 if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
763 {
764 crWarning("No client id for server ctx %d", pContext->id);
765 }
766 else
767 {
768 crServerDispatchMakeCurrent(cr_server.curClient->currentWindow, 0, id);
769 }
770 }
771#endif
772
773 rc = crStateSaveContext(pContext, pSSM);
774 CRASSERT(rc == VINF_SUCCESS);
775}
776
777static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
778
779DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
780{
781 int32_t rc, i;
782 uint32_t ui32;
783 GLboolean b;
784 unsigned long key;
785#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
786 unsigned long ctxID=-1, winID=-1;
787#endif
788
789 /* We shouldn't be called if there's no clients at all*/
790 CRASSERT(cr_server.numClients>0);
791
792 /* @todo it's hack atm */
793 /* We want to be called only once to save server state but atm we're being called from svcSaveState
794 * for every connected client (e.g. guest opengl application)
795 */
796 if (!cr_server.bIsInSavingState) /* It's first call */
797 {
798 cr_server.bIsInSavingState = GL_TRUE;
799
800 /* Store number of clients */
801 rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
802 AssertRCReturn(rc, rc);
803
804 g_hackVBoxServerSaveLoadCallsLeft = cr_server.numClients;
805 }
806
807 g_hackVBoxServerSaveLoadCallsLeft--;
808
809 /* Do nothing until we're being called last time */
810 if (g_hackVBoxServerSaveLoadCallsLeft>0)
811 {
812 return VINF_SUCCESS;
813 }
814
815 /* Save rendering contexts creation info */
816 ui32 = crHashtableNumElements(cr_server.contextTable);
817 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
818 AssertRCReturn(rc, rc);
819 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
820
821#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
822 /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
823 if (cr_server.curClient)
824 {
825 ctxID = cr_server.curClient->currentContextNumber;
826 winID = cr_server.curClient->currentWindow;
827 }
828#endif
829
830 /* Save contexts state tracker data */
831 /* @todo For now just some blind data dumps,
832 * but I've a feeling those should be saved/restored in a very strict sequence to
833 * allow diff_api to work correctly.
834 * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
835 */
836 crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, pSSM);
837
838#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
839 /* Restore original win and ctx IDs*/
840 if (cr_server.curClient)
841 {
842 crServerDispatchMakeCurrent(winID, 0, ctxID);
843 }
844#endif
845
846 /* Save windows creation info */
847 ui32 = crHashtableNumElements(cr_server.pWindowCreateInfoTable);
848 rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
849 AssertRCReturn(rc, rc);
850 crHashtableWalk(cr_server.pWindowCreateInfoTable, crVBoxServerSaveCreateInfoCB, pSSM);
851
852 /* Save cr_server.muralTable
853 * @todo we don't need it all, just geometry info actually
854 */
855 ui32 = crHashtableNumElements(cr_server.muralTable);
856 /* There should be default mural always */
857 CRASSERT(ui32>=1);
858 rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
859 AssertRCReturn(rc, rc);
860 crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
861
862 /* Save starting free context and window IDs */
863 rc = SSMR3PutMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool));
864 AssertRCReturn(rc, rc);
865
866 /* Save clients info */
867 for (i = 0; i < cr_server.numClients; i++)
868 {
869 if (cr_server.clients[i] && cr_server.clients[i]->conn)
870 {
871 CRClient *pClient = cr_server.clients[i];
872
873 rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
874 AssertRCReturn(rc, rc);
875
876 rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
877 AssertRCReturn(rc, rc);
878
879 rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
880 AssertRCReturn(rc, rc);
881
882 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
883 AssertRCReturn(rc, rc);
884
885 if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0)
886 {
887 b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
888 CRASSERT(b);
889 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
890 AssertRCReturn(rc, rc);
891 }
892
893 if (pClient->currentMural && pClient->currentWindow>=0)
894 {
895 b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
896 CRASSERT(b);
897 rc = SSMR3PutMem(pSSM, &key, sizeof(key));
898 AssertRCReturn(rc, rc);
899 }
900 }
901 }
902
903 cr_server.bIsInSavingState = GL_FALSE;
904
905 return VINF_SUCCESS;
906}
907
908static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
909{
910 CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
911 CRASSERT(pContextInfo);
912 CRASSERT(pContextInfo->pContext);
913 return pContextInfo->pContext;
914}
915
916DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
917{
918 int32_t rc, i;
919 uint32_t ui, uiNumElems;
920 unsigned long key;
921
922 if (!cr_server.bIsInLoadingState)
923 {
924 /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
925 cr_server.bIsInLoadingState = GL_TRUE;
926
927 /* Read number of clients */
928 rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
929 AssertRCReturn(rc, rc);
930 }
931
932 g_hackVBoxServerSaveLoadCallsLeft--;
933
934 /* Do nothing until we're being called last time */
935 if (g_hackVBoxServerSaveLoadCallsLeft>0)
936 {
937 return VINF_SUCCESS;
938 }
939
940 if (version!=SHCROGL_SSM_VERSION)
941 {
942 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
943 }
944
945 /* Load and recreate rendering contexts */
946 rc = SSMR3GetU32(pSSM, &uiNumElems);
947 AssertRCReturn(rc, rc);
948 for (ui=0; ui<uiNumElems; ++ui)
949 {
950 CRCreateInfo_t createInfo;
951 char psz[200];
952 GLint ctxID;
953 CRContextInfo* pContextInfo;
954 CRContext* pContext;
955
956 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
957 AssertRCReturn(rc, rc);
958 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
959 AssertRCReturn(rc, rc);
960
961 if (createInfo.pszDpyName)
962 {
963 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
964 AssertRCReturn(rc, rc);
965 createInfo.pszDpyName = psz;
966 }
967
968 ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.internalID);
969 CRASSERT((int64_t)ctxID == (int64_t)key);
970
971 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
972 CRASSERT(pContextInfo);
973 CRASSERT(pContextInfo->pContext);
974 pContext = pContextInfo->pContext;
975 pContext->shared->id=-1;
976 }
977
978 /* Restore context state data */
979 for (ui=0; ui<uiNumElems; ++ui)
980 {
981 CRContextInfo* pContextInfo;
982 CRContext *pContext;
983
984 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
985 AssertRCReturn(rc, rc);
986
987 pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
988 CRASSERT(pContextInfo);
989 CRASSERT(pContextInfo->pContext);
990 pContext = pContextInfo->pContext;
991
992 rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM);
993 AssertRCReturn(rc, rc);
994 }
995
996 /* Load windows */
997 rc = SSMR3GetU32(pSSM, &uiNumElems);
998 AssertRCReturn(rc, rc);
999 for (ui=0; ui<uiNumElems; ++ui)
1000 {
1001 CRCreateInfo_t createInfo;
1002 char psz[200];
1003 GLint winID;
1004 unsigned long key;
1005
1006 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1007 AssertRCReturn(rc, rc);
1008 rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
1009 AssertRCReturn(rc, rc);
1010
1011 if (createInfo.pszDpyName)
1012 {
1013 rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
1014 AssertRCReturn(rc, rc);
1015 createInfo.pszDpyName = psz;
1016 }
1017
1018 winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
1019 CRASSERT((int64_t)winID == (int64_t)key);
1020 }
1021
1022 /* Load cr_server.muralTable */
1023 rc = SSMR3GetU32(pSSM, &uiNumElems);
1024 AssertRCReturn(rc, rc);
1025 for (ui=0; ui<uiNumElems; ++ui)
1026 {
1027 CRMuralInfo muralInfo;
1028
1029 rc = SSMR3GetMem(pSSM, &key, sizeof(key));
1030 AssertRCReturn(rc, rc);
1031 rc = SSMR3GetMem(pSSM, &muralInfo, sizeof(muralInfo));
1032 AssertRCReturn(rc, rc);
1033
1034 if (muralInfo.pVisibleRects)
1035 {
1036 muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
1037 if (!muralInfo.pVisibleRects)
1038 {
1039 return VERR_NO_MEMORY;
1040 }
1041
1042 rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
1043 AssertRCReturn(rc, rc);
1044 }
1045
1046 /* Restore windows geometry info */
1047 crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
1048 crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
1049 /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
1050 if (muralInfo.bReceivedRects)
1051 {
1052 crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
1053 }
1054 crServerDispatchWindowShow(key, muralInfo.bVisible);
1055
1056 if (muralInfo.pVisibleRects)
1057 {
1058 crFree(muralInfo.pVisibleRects);
1059 }
1060 }
1061
1062 /* Load starting free context and window IDs */
1063 rc = SSMR3GetMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool));
1064 CRASSERT(rc == VINF_SUCCESS);
1065
1066 /* Load clients info */
1067 for (i = 0; i < cr_server.numClients; i++)
1068 {
1069 if (cr_server.clients[i] && cr_server.clients[i]->conn)
1070 {
1071 CRClient *pClient = cr_server.clients[i];
1072 CRClient client;
1073 unsigned long ctxID=-1, winID=-1;
1074
1075 rc = SSMR3GetU32(pSSM, &ui);
1076 AssertRCReturn(rc, rc);
1077 /* If this assert fires, then we should search correct client in the list first*/
1078 CRASSERT(ui == pClient->conn->u32ClientID);
1079
1080 if (version>=4)
1081 {
1082 rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor);
1083 AssertRCReturn(rc, rc);
1084
1085 rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor);
1086 AssertRCReturn(rc, rc);
1087 }
1088
1089 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
1090 CRASSERT(rc == VINF_SUCCESS);
1091
1092 client.conn = pClient->conn;
1093 /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
1094 * and fail to bind old textures.
1095 */
1096 /*client.number = pClient->number;*/
1097 *pClient = client;
1098
1099 pClient->currentContextNumber = -1;
1100 pClient->currentCtxInfo = &cr_server.MainContextInfo;
1101 pClient->currentMural = NULL;
1102 pClient->currentWindow = -1;
1103
1104 cr_server.curClient = pClient;
1105
1106 if (client.currentCtxInfo && client.currentContextNumber>=0)
1107 {
1108 rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID));
1109 AssertRCReturn(rc, rc);
1110 client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
1111 CRASSERT(client.currentCtxInfo);
1112 CRASSERT(client.currentCtxInfo->pContext);
1113 //pClient->currentCtx = client.currentCtx;
1114 //pClient->currentContextNumber = ctxID;
1115 }
1116
1117 if (client.currentMural && client.currentWindow>=0)
1118 {
1119 rc = SSMR3GetMem(pSSM, &winID, sizeof(winID));
1120 AssertRCReturn(rc, rc);
1121 client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
1122 CRASSERT(client.currentMural);
1123 //pClient->currentMural = client.currentMural;
1124 //pClient->currentWindow = winID;
1125 }
1126
1127 /* Restore client active context and window */
1128 crServerDispatchMakeCurrent(winID, 0, ctxID);
1129
1130 if (0)
1131 {
1132// CRContext *tmpCtx;
1133// CRCreateInfo_t *createInfo;
1134 GLfloat one[4] = { 1, 1, 1, 1 };
1135 GLfloat amb[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
1136
1137 crServerDispatchMakeCurrent(winID, 0, ctxID);
1138
1139 crHashtableWalk(client.currentCtxInfo->pContext->shared->textureTable, crVBoxServerSyncTextureCB, client.currentCtxInfo->pContext);
1140
1141 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base1D, GL_TRUE);
1142 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base2D, GL_TRUE);
1143 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.base3D, GL_TRUE);
1144#ifdef CR_ARB_texture_cube_map
1145 crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseCubeMap, GL_TRUE);
1146#endif
1147#ifdef CR_NV_texture_rectangle
1148 //@todo this doesn't work as expected
1149 //crStateTextureObjectDiff(client.currentCtxInfo->pContext, NULL, NULL, &client.currentCtxInfo->pContext->texture.baseRect, GL_TRUE);
1150#endif
1151 /*cr_server.head_spu->dispatch_table.Materialfv(GL_FRONT_AND_BACK, GL_AMBIENT, amb);
1152 cr_server.head_spu->dispatch_table.LightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
1153 cr_server.head_spu->dispatch_table.Lightfv(GL_LIGHT1, GL_DIFFUSE, one);
1154
1155 cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
1156 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT0);
1157 cr_server.head_spu->dispatch_table.Enable(GL_LIGHT1);
1158
1159 cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
1160 cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);*/
1161
1162 //crStateViewport( 0, 0, 600, 600 );
1163 //pClient->currentMural->viewportValidated = GL_FALSE;
1164 //cr_server.head_spu->dispatch_table.Viewport( 0, 0, 600, 600 );
1165
1166 //crStateMatrixMode(GL_PROJECTION);
1167 //cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
1168
1169 //crStateLoadIdentity();
1170 //cr_server.head_spu->dispatch_table.LoadIdentity();
1171
1172 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1173 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1174
1175 //crStateMatrixMode(GL_MODELVIEW);
1176 //cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
1177 //crServerDispatchLoadIdentity();
1178 //crStateFrustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1179 //cr_server.head_spu->dispatch_table.Frustum(-0.5, 0.5, -0.5, 0.5, 1.5, 150.0);
1180 //crServerDispatchLoadIdentity();
1181
1182 /*createInfo = (CRCreateInfo_t *) crHashtableSearch(cr_server.pContextCreateInfoTable, ctxID);
1183 CRASSERT(createInfo);
1184 tmpCtx = crStateCreateContext(NULL, createInfo->visualBits, NULL);
1185 CRASSERT(tmpCtx);
1186 crStateDiffContext(tmpCtx, client.currentCtxInfo->pContext);
1187 crStateDestroyContext(tmpCtx);*/
1188 }
1189 }
1190 }
1191
1192 //crServerDispatchMakeCurrent(-1, 0, -1);
1193
1194 cr_server.curClient = NULL;
1195
1196 {
1197 GLenum err = crServerDispatchGetError();
1198
1199 if (err != GL_NO_ERROR)
1200 {
1201 crWarning("crServer: glGetError %d after loading snapshot", err);
1202 }
1203 }
1204
1205 cr_server.bIsInLoadingState = GL_FALSE;
1206
1207 return VINF_SUCCESS;
1208}
1209
1210#define SCREEN(i) (cr_server.screen[i])
1211#define MAPPED(screen) ((screen).winID != 0)
1212
1213static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
1214{
1215 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1216 int *sIndex = (int*) data2;
1217
1218 if (pMI->screenId == *sIndex)
1219 {
1220 renderspuReparentWindow(pMI->spuWindow);
1221 }
1222}
1223
1224static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2)
1225{
1226 CRMuralInfo *pMI = (CRMuralInfo*) data1;
1227 (void) data2;
1228
1229 crServerCheckMuralGeometry(pMI);
1230}
1231
1232DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
1233{
1234 int i;
1235
1236 if (sCount>CR_MAX_GUEST_MONITORS)
1237 return VERR_INVALID_PARAMETER;
1238
1239 /*Shouldn't happen yet, but to be safe in future*/
1240 for (i=0; i<cr_server.screenCount; ++i)
1241 {
1242 if (MAPPED(SCREEN(i)))
1243 crWarning("Screen count is changing, but screen[%i] is still mapped", i);
1244 return VERR_NOT_IMPLEMENTED;
1245 }
1246
1247 cr_server.screenCount = sCount;
1248
1249 for (i=0; i<sCount; ++i)
1250 {
1251 SCREEN(i).winID = 0;
1252 }
1253
1254 return VINF_SUCCESS;
1255}
1256
1257DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
1258{
1259 crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
1260
1261 if (sIndex<0 || sIndex>=cr_server.screenCount)
1262 return VERR_INVALID_PARAMETER;
1263
1264 if (MAPPED(SCREEN(sIndex)))
1265 {
1266 SCREEN(sIndex).winID = 0;
1267 renderspuSetWindowId(0);
1268
1269 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
1270 }
1271
1272 renderspuSetWindowId(SCREEN(0).winID);
1273 return VINF_SUCCESS;
1274}
1275
1276DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
1277{
1278 crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
1279
1280 if (sIndex<0 || sIndex>=cr_server.screenCount)
1281 return VERR_INVALID_PARAMETER;
1282
1283 if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
1284 {
1285 crDebug("Mapped screen[%i] is being remapped.", sIndex);
1286 crVBoxServerUnmapScreen(sIndex);
1287 }
1288
1289 SCREEN(sIndex).winID = winID;
1290 SCREEN(sIndex).x = x;
1291 SCREEN(sIndex).y = y;
1292 SCREEN(sIndex).w = w;
1293 SCREEN(sIndex).h = h;
1294
1295 renderspuSetWindowId(SCREEN(sIndex).winID);
1296 crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
1297 renderspuSetWindowId(SCREEN(0).winID);
1298
1299 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
1300
1301#ifndef WINDOWS
1302 /*Restore FB content for clients, which have current window on a screen being remapped*/
1303 {
1304 GLint i;
1305
1306 for (i = 0; i < cr_server.numClients; i++)
1307 {
1308 cr_server.curClient = cr_server.clients[i];
1309 if (cr_server.curClient->currentCtxInfo
1310 && cr_server.curClient->currentCtxInfo->pContext
1311 && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg || cr_server.curClient->currentCtxInfo->pContext->buffer.pBackImg)
1312 && cr_server.curClient->currentMural
1313 && cr_server.curClient->currentMural->screenId == sIndex
1314 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
1315 && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
1316 {
1317 int clientWindow = cr_server.curClient->currentWindow;
1318 int clientContext = cr_server.curClient->currentContextNumber;
1319
1320 if (clientWindow && clientWindow != cr_server.currentWindow)
1321 {
1322 crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
1323 }
1324
1325 crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext);
1326 }
1327 }
1328 cr_server.curClient = NULL;
1329 }
1330#endif
1331
1332 return VINF_SUCCESS;
1333}
1334
1335DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects)
1336{
1337 renderspuSetRootVisibleRegion(cRects, pRects);
1338
1339 return VINF_SUCCESS;
1340}
1341
1342DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO)
1343{
1344 cr_server.pfnPresentFBO = pfnPresentFBO;
1345}
1346
1347DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
1348{
1349 if (cr_server.bForceOffscreenRendering==value)
1350 {
1351 return VINF_SUCCESS;
1352 }
1353
1354 if (value && !crServerSupportRedirMuralFBO())
1355 {
1356 return VERR_NOT_SUPPORTED;
1357 }
1358
1359 cr_server.bForceOffscreenRendering=value;
1360
1361 crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL);
1362
1363 return VINF_SUCCESS;
1364}
1365
1366DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
1367{
1368 /* No need for a synchronization as this is single threaded. */
1369 if (pCallbacks)
1370 {
1371 cr_server.outputRedirect = *pCallbacks;
1372 cr_server.bUseOutputRedirect = true;
1373 }
1374 else
1375 {
1376 cr_server.bUseOutputRedirect = false;
1377 }
1378
1379 // @todo dynamically intercept already existing output:
1380 // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL);
1381
1382 return VINF_SUCCESS;
1383}
1384
1385
1386#ifdef VBOX_WITH_CRHGSMI
1387/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
1388 *
1389 * 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.
1390 * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
1391 * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
1392 * to block the lower-priority thread trying to complete the blocking command.
1393 * And removed extra memcpy done on blocked command arrival.
1394 *
1395 * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
1396 * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
1397 *
1398 * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
1399 * */
1400int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
1401{
1402 int32_t rc;
1403 uint32_t cBuffers = pCmd->cBuffers;
1404 uint32_t cParams;
1405 uint32_t cbHdr;
1406 CRVBOXHGSMIHDR *pHdr;
1407 uint32_t u32Function;
1408 uint32_t u32ClientID;
1409 CRClient *pClient;
1410
1411 if (!g_pvVRamBase)
1412 {
1413 crWarning("g_pvVRamBase is not initialized");
1414 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
1415 return VINF_SUCCESS;
1416 }
1417
1418 if (!cBuffers)
1419 {
1420 crWarning("zero buffers passed in!");
1421 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
1422 return VINF_SUCCESS;
1423 }
1424
1425 cParams = cBuffers-1;
1426
1427 cbHdr = pCmd->aBuffers[0].cbBuffer;
1428 pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
1429 if (!pHdr)
1430 {
1431 crWarning("invalid header buffer!");
1432 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
1433 return VINF_SUCCESS;
1434 }
1435
1436 if (cbHdr < sizeof (*pHdr))
1437 {
1438 crWarning("invalid header buffer size!");
1439 crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
1440 return VINF_SUCCESS;
1441 }
1442
1443 u32Function = pHdr->u32Function;
1444 u32ClientID = pHdr->u32ClientID;
1445
1446 switch (u32Function)
1447 {
1448 case SHCRGL_GUEST_FN_WRITE:
1449 {
1450 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
1451
1452 /* @todo: Verify */
1453 if (cParams == 1)
1454 {
1455 CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
1456 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
1457 /* Fetch parameters. */
1458 uint32_t cbBuffer = pBuf->cbBuffer;
1459 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
1460
1461 if (cbHdr < sizeof (*pFnCmd))
1462 {
1463 crWarning("invalid write cmd buffer size!");
1464 rc = VERR_INVALID_PARAMETER;
1465 break;
1466 }
1467
1468 CRASSERT(cbBuffer);
1469 if (!pBuffer)
1470 {
1471 crWarning("invalid buffer data received from guest!");
1472 rc = VERR_INVALID_PARAMETER;
1473 break;
1474 }
1475
1476 rc = crVBoxServerClientGet(u32ClientID, &pClient);
1477 if (RT_FAILURE(rc))
1478 {
1479 break;
1480 }
1481
1482 /* This should never fire unless we start to multithread */
1483 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
1484 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
1485
1486 pClient->conn->pBuffer = pBuffer;
1487 pClient->conn->cbBuffer = cbBuffer;
1488 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
1489 rc = crVBoxServerInternalClientWriteRead(pClient);
1490 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
1491 return rc;
1492 }
1493 else
1494 {
1495 crWarning("invalid number of args");
1496 rc = VERR_INVALID_PARAMETER;
1497 break;
1498 }
1499 break;
1500 }
1501
1502 case SHCRGL_GUEST_FN_INJECT:
1503 {
1504 crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
1505
1506 /* @todo: Verify */
1507 if (cParams == 1)
1508 {
1509 CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
1510 /* Fetch parameters. */
1511 uint32_t u32InjectClientID = pFnCmd->u32ClientID;
1512 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
1513 uint32_t cbBuffer = pBuf->cbBuffer;
1514 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
1515
1516 if (cbHdr < sizeof (*pFnCmd))
1517 {
1518 crWarning("invalid inject cmd buffer size!");
1519 rc = VERR_INVALID_PARAMETER;
1520 break;
1521 }
1522
1523 CRASSERT(cbBuffer);
1524 if (!pBuffer)
1525 {
1526 crWarning("invalid buffer data received from guest!");
1527 rc = VERR_INVALID_PARAMETER;
1528 break;
1529 }
1530
1531 rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
1532 if (RT_FAILURE(rc))
1533 {
1534 break;
1535 }
1536
1537 /* This should never fire unless we start to multithread */
1538 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
1539 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
1540
1541 pClient->conn->pBuffer = pBuffer;
1542 pClient->conn->cbBuffer = cbBuffer;
1543 CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr);
1544 rc = crVBoxServerInternalClientWriteRead(pClient);
1545 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
1546 return rc;
1547 }
1548
1549 crWarning("invalid number of args");
1550 rc = VERR_INVALID_PARAMETER;
1551 break;
1552 }
1553
1554 case SHCRGL_GUEST_FN_READ:
1555 {
1556 crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n"));
1557
1558 /* @todo: Verify */
1559 if (cParams == 1)
1560 {
1561 CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
1562 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
1563 /* Fetch parameters. */
1564 uint32_t cbBuffer = pBuf->cbBuffer;
1565 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
1566
1567 if (cbHdr < sizeof (*pFnCmd))
1568 {
1569 crWarning("invalid read cmd buffer size!");
1570 rc = VERR_INVALID_PARAMETER;
1571 break;
1572 }
1573
1574
1575 if (!pBuffer)
1576 {
1577 crWarning("invalid buffer data received from guest!");
1578 rc = VERR_INVALID_PARAMETER;
1579 break;
1580 }
1581
1582 rc = crVBoxServerClientGet(u32ClientID, &pClient);
1583 if (RT_FAILURE(rc))
1584 {
1585 break;
1586 }
1587
1588 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
1589
1590 rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
1591
1592 /* Return the required buffer size always */
1593 pFnCmd->cbBuffer = cbBuffer;
1594
1595 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
1596
1597 /* the read command is never pended, complete it right away */
1598 pHdr->result = rc;
1599 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
1600 return VINF_SUCCESS;
1601 }
1602
1603 crWarning("invalid number of args");
1604 rc = VERR_INVALID_PARAMETER;
1605 break;
1606 }
1607
1608 case SHCRGL_GUEST_FN_WRITE_READ:
1609 {
1610 crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
1611
1612 /* @todo: Verify */
1613 if (cParams == 2)
1614 {
1615 CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
1616 VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
1617 VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
1618
1619 /* Fetch parameters. */
1620 uint32_t cbBuffer = pBuf->cbBuffer;
1621 uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
1622
1623 uint32_t cbWriteback = pWbBuf->cbBuffer;
1624 char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
1625
1626 if (cbHdr < sizeof (*pFnCmd))
1627 {
1628 crWarning("invalid write_read cmd buffer size!");
1629 rc = VERR_INVALID_PARAMETER;
1630 break;
1631 }
1632
1633
1634 CRASSERT(cbBuffer);
1635 if (!pBuffer)
1636 {
1637 crWarning("invalid write buffer data received from guest!");
1638 rc = VERR_INVALID_PARAMETER;
1639 break;
1640 }
1641
1642 CRASSERT(cbWriteback);
1643 if (!pWriteback)
1644 {
1645 crWarning("invalid writeback buffer data received from guest!");
1646 rc = VERR_INVALID_PARAMETER;
1647 break;
1648 }
1649 rc = crVBoxServerClientGet(u32ClientID, &pClient);
1650 if (RT_FAILURE(rc))
1651 {
1652 pHdr->result = rc;
1653 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
1654 return rc;
1655 }
1656
1657 /* This should never fire unless we start to multithread */
1658 CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
1659 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
1660
1661 pClient->conn->pBuffer = pBuffer;
1662 pClient->conn->cbBuffer = cbBuffer;
1663 CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback);
1664 rc = crVBoxServerInternalClientWriteRead(pClient);
1665 CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
1666 return rc;
1667 }
1668
1669 crWarning("invalid number of args");
1670 rc = VERR_INVALID_PARAMETER;
1671 break;
1672 }
1673
1674 case SHCRGL_GUEST_FN_SET_VERSION:
1675 {
1676 crWarning("invalid function");
1677 rc = VERR_NOT_IMPLEMENTED;
1678 break;
1679 }
1680
1681 case SHCRGL_GUEST_FN_SET_PID:
1682 {
1683 crWarning("invalid function");
1684 rc = VERR_NOT_IMPLEMENTED;
1685 break;
1686 }
1687
1688 default:
1689 {
1690 crWarning("invalid function");
1691 rc = VERR_NOT_IMPLEMENTED;
1692 break;
1693 }
1694
1695 }
1696
1697 /* we can be on fail only here */
1698 CRASSERT(RT_FAILURE(rc));
1699 pHdr->result = rc;
1700 crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
1701 return rc;
1702}
1703
1704int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
1705{
1706 int rc = VINF_SUCCESS;
1707
1708 switch (pCtl->enmType)
1709 {
1710 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
1711 {
1712 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
1713 g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
1714 g_cbVRam = pSetup->cbVRam;
1715 rc = VINF_SUCCESS;
1716 break;
1717 }
1718 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
1719 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
1720 rc = VINF_SUCCESS;
1721 break;
1722 case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION:
1723 {
1724 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl;
1725 g_hCrHgsmiCompletion = pSetup->hCompletion;
1726 g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
1727 rc = VINF_SUCCESS;
1728 break;
1729 }
1730 default:
1731 AssertMsgFailed(("invalid param %d", pCtl->enmType));
1732 rc = VERR_INVALID_PARAMETER;
1733 }
1734
1735 /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
1736 * to complete them accordingly.
1737 * This approach allows using host->host and host->guest commands in the same way here
1738 * making the command completion to be the responsibility of the command originator.
1739 * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
1740 * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
1741 return rc;
1742}
1743#endif
Note: See TracBrowser for help on using the repository browser.

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