VirtualBox

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

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

crOpenGL: fix VRDP+3D for Intel graphics, more VRDP+3D fixes

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

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