VirtualBox

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

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

crOpenGL: fix viewport update

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

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