VirtualBox

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

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

crOpenGL: basics for using multiple contexts on host

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

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