VirtualBox

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

最後變更 在這個檔案從43233是 43182,由 vboxsync 提交於 12 年 前

crOpenGL: 1. VRDP+3D fixes, 2. Generic bugfixes, 3. Intel GPU-related fixes

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

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