VirtualBox

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

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

crHgsmi: cleanup

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