VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.cpp@ 55747

Last change on this file since 55747 was 55747, checked in by vboxsync, 10 years ago

SharedOpenGL: fix CrFbBltGetContents and crFbBltGetContentsScaledDirect in server_presenter

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 115.8 KB
Line 
1/* $Id: server_presenter.cpp 55747 2015-05-08 09:11:45Z vboxsync $ */
2
3/** @file
4 * Presenter API
5 */
6
7/*
8 * Copyright (C) 2012-2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.215389.xyz. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#ifdef DEBUG_misha
20# define VBOXVDBG_MEMCACHE_DISABLE
21#endif
22
23#ifndef VBOXVDBG_MEMCACHE_DISABLE
24# include <iprt/memcache.h>
25#endif
26
27#include "server_presenter.h"
28
29//#define CR_SERVER_WITH_CLIENT_CALLOUTS
30
31#define PCR_FBTEX_FROM_TEX(_pTex) ((CR_FBTEX*)((uint8_t*)(_pTex) - RT_OFFSETOF(CR_FBTEX, Tex)))
32#define PCR_FRAMEBUFFER_FROM_COMPOSITOR(_pCompositor) ((CR_FRAMEBUFFER*)((uint8_t*)(_pCompositor) - RT_OFFSETOF(CR_FRAMEBUFFER, Compositor)))
33#define PCR_FBENTRY_FROM_ENTRY(_pEntry) ((CR_FRAMEBUFFER_ENTRY*)((uint8_t*)(_pEntry) - RT_OFFSETOF(CR_FRAMEBUFFER_ENTRY, Entry)))
34
35
36static int crPMgrFbConnectTargetDisplays(HCR_FRAMEBUFFER hFb, CR_FBDISPLAY_INFO *pDpInfo, uint32_t u32ModeAdd);
37
38CR_PRESENTER_GLOBALS g_CrPresenter;
39
40/* FRAMEBUFFER */
41
42void CrFbInit(CR_FRAMEBUFFER *pFb, uint32_t idFb)
43{
44 RTRECT Rect;
45 Rect.xLeft = 0;
46 Rect.yTop = 0;
47 Rect.xRight = 1;
48 Rect.yBottom = 1;
49 memset(pFb, 0, sizeof (*pFb));
50 pFb->ScreenInfo.u16Flags = VBVA_SCREEN_F_DISABLED;
51 pFb->ScreenInfo.u32ViewIndex = idFb;
52 CrVrScrCompositorInit(&pFb->Compositor, &Rect);
53 RTListInit(&pFb->EntriesList);
54 CrHTableCreate(&pFb->SlotTable, 0);
55}
56
57
58bool CrFbIsEnabled(CR_FRAMEBUFFER *pFb)
59{
60 return !(pFb->ScreenInfo.u16Flags & VBVA_SCREEN_F_DISABLED);
61}
62
63
64const struct VBOXVR_SCR_COMPOSITOR* CrFbGetCompositor(CR_FRAMEBUFFER *pFb)
65{
66 return &pFb->Compositor;
67}
68
69DECLINLINE(CR_FRAMEBUFFER*) CrFbFromCompositor(const struct VBOXVR_SCR_COMPOSITOR* pCompositor)
70{
71 return RT_FROM_MEMBER(pCompositor, CR_FRAMEBUFFER, Compositor);
72}
73
74const struct VBVAINFOSCREEN* CrFbGetScreenInfo(HCR_FRAMEBUFFER hFb)
75{
76 return &hFb->ScreenInfo;
77}
78
79void* CrFbGetVRAM(HCR_FRAMEBUFFER hFb)
80{
81 return hFb->pvVram;
82}
83
84int CrFbUpdateBegin(CR_FRAMEBUFFER *pFb)
85{
86 ++pFb->cUpdating;
87
88 if (pFb->cUpdating == 1)
89 {
90 if (pFb->pDisplay)
91 pFb->pDisplay->UpdateBegin(pFb);
92 }
93
94 return VINF_SUCCESS;
95}
96
97void CrFbUpdateEnd(CR_FRAMEBUFFER *pFb)
98{
99 if (!pFb->cUpdating)
100 {
101 WARN(("invalid UpdateEnd call!"));
102 return;
103 }
104
105 --pFb->cUpdating;
106
107 if (!pFb->cUpdating)
108 {
109 if (pFb->pDisplay)
110 pFb->pDisplay->UpdateEnd(pFb);
111 }
112}
113
114bool CrFbIsUpdating(const CR_FRAMEBUFFER *pFb)
115{
116 return !!pFb->cUpdating;
117}
118
119bool CrFbHas3DData(HCR_FRAMEBUFFER hFb)
120{
121 return !CrVrScrCompositorIsEmpty(&hFb->Compositor);
122}
123
124static void crFbImgFromScreenVram(const VBVAINFOSCREEN *pScreen, void *pvVram, CR_BLITTER_IMG *pImg)
125{
126 pImg->pvData = pvVram;
127 pImg->cbData = pScreen->u32LineSize * pScreen->u32Height;
128 pImg->enmFormat = GL_BGRA;
129 pImg->width = pScreen->u32Width;
130 pImg->height = pScreen->u32Height;
131 pImg->bpp = pScreen->u16BitsPerPixel;
132 pImg->pitch = pScreen->u32LineSize;
133}
134
135static void crFbImgFromDimPtrBGRA(void *pvVram, uint32_t width, uint32_t height, CR_BLITTER_IMG *pImg)
136{
137 pImg->pvData = pvVram;
138 pImg->cbData = width * height * 4;
139 pImg->enmFormat = GL_BGRA;
140 pImg->width = width;
141 pImg->height = height;
142 pImg->bpp = 32;
143 pImg->pitch = width * 4;
144}
145
146static int8_t crFbImgFromDimOffVramBGRA(VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, CR_BLITTER_IMG *pImg)
147{
148 uint32_t cbBuff = width * height * 4;
149 if (offVRAM >= g_cbVRam
150 || offVRAM + cbBuff >= g_cbVRam)
151 {
152 WARN(("invalid param"));
153 return -1;
154 }
155
156 uint8_t *pu8Buf = g_pvVRamBase + offVRAM;
157 crFbImgFromDimPtrBGRA(pu8Buf, width, height, pImg);
158
159 return 0;
160}
161
162static int8_t crFbImgFromDescBGRA(const VBOXCMDVBVA_ALLOCDESC *pDesc, CR_BLITTER_IMG *pImg)
163{
164 return crFbImgFromDimOffVramBGRA(pDesc->Info.u.offVRAM, pDesc->u16Width, pDesc->u16Height, pImg);
165}
166
167static void crFbImgFromFb(HCR_FRAMEBUFFER hFb, CR_BLITTER_IMG *pImg)
168{
169 const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
170 void *pvVram = CrFbGetVRAM(hFb);
171 crFbImgFromScreenVram(pScreen, pvVram, pImg);
172}
173
174static int crFbTexDataGetContents(CR_TEXDATA *pTex, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst)
175{
176 const CR_BLITTER_IMG *pSrcImg;
177 int rc = CrTdBltDataAcquire(pTex, GL_BGRA, false, &pSrcImg);
178 if (!RT_SUCCESS(rc))
179 {
180 WARN(("CrTdBltDataAcquire failed rc %d", rc));
181 return rc;
182 }
183
184 CrMBltImg(pSrcImg, pPos, cRects, pRects, pDst);
185
186 CrTdBltDataRelease(pTex);
187
188 return VINF_SUCCESS;
189}
190
191static int crFbBltGetContentsScaledDirect(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst)
192{
193 VBOXVR_LIST List;
194 uint32_t c2DRects = 0;
195 CR_TEXDATA *pEnteredTex = NULL;
196 PCR_BLITTER pEnteredBlitter = NULL;
197
198 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
199 int32_t srcWidth = pSrcRectSize->cx;
200 int32_t srcHeight = pSrcRectSize->cy;
201 int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
202 int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
203
204 RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop};
205 float strX = ((float)dstWidth) / srcWidth;
206 float strY = ((float)dstHeight) / srcHeight;
207 bool fScale = (dstWidth != srcWidth || dstHeight != srcHeight);
208 Assert(fScale);
209
210 /* 'List' contains the destination rectangles to be updated (in pDst coords). */
211 VBoxVrListInit(&List);
212 int rc = VBoxVrListRectsAdd(&List, cRects, pRects, NULL);
213 if (!RT_SUCCESS(rc))
214 {
215 WARN(("VBoxVrListRectsAdd failed rc %d", rc));
216 goto end;
217 }
218
219 CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter);
220
221 for(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrVrScrCompositorConstIterNext(&Iter);
222 pEntry;
223 pEntry = CrVrScrCompositorConstIterNext(&Iter))
224 {
225 /* Where the entry would be located in pDst coords, i.e. convert pEntry hFb coord to pDst coord. */
226 RTPOINT ScaledEntryPoint;
227 ScaledEntryPoint.x = CR_FLOAT_RCAST(int32_t, strX * CrVrScrCompositorEntryRectGet(pEntry)->xLeft) + pDstRect->xLeft;
228 ScaledEntryPoint.y = CR_FLOAT_RCAST(int32_t, strY * CrVrScrCompositorEntryRectGet(pEntry)->yTop) + pDstRect->yTop;
229
230 /* Scaled texture size and rect. */
231 uint32_t width = 0, height = 0;
232 RTRECT ScaledSrcRect = {0};
233
234 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
235
236 /* Optimization to avoid entering/leaving the same texture and its blitter. */
237 if (pEnteredTex != pTex)
238 {
239 if (!pEnteredBlitter)
240 {
241 pEnteredBlitter = CrTdBlitterGet(pTex);
242 rc = CrBltEnter(pEnteredBlitter);
243 if (!RT_SUCCESS(rc))
244 {
245 WARN(("CrBltEnter failed %d", rc));
246 pEnteredBlitter = NULL;
247 goto end;
248 }
249 }
250
251 if (pEnteredTex)
252 {
253 CrTdBltLeave(pEnteredTex);
254
255 pEnteredTex = NULL;
256
257 if (pEnteredBlitter != CrTdBlitterGet(pTex))
258 {
259 WARN(("blitters not equal!"));
260 CrBltLeave(pEnteredBlitter);
261
262 pEnteredBlitter = CrTdBlitterGet(pTex);
263 rc = CrBltEnter(pEnteredBlitter);
264 if (!RT_SUCCESS(rc))
265 {
266 WARN(("CrBltEnter failed %d", rc));
267 pEnteredBlitter = NULL;
268 goto end;
269 }
270 }
271 }
272
273 rc = CrTdBltEnter(pTex);
274 if (!RT_SUCCESS(rc))
275 {
276 WARN(("CrTdBltEnter failed %d", rc));
277 goto end;
278 }
279
280 pEnteredTex = pTex;
281
282 const VBOXVR_TEXTURE *pVrTex = CrTdTexGet(pTex);
283
284 width = CR_FLOAT_RCAST(uint32_t, strX * pVrTex->width);
285 height = CR_FLOAT_RCAST(uint32_t, strY * pVrTex->height);
286 ScaledSrcRect.xLeft = ScaledEntryPoint.x;
287 ScaledSrcRect.yTop = ScaledEntryPoint.y;
288 ScaledSrcRect.xRight = width + ScaledEntryPoint.x;
289 ScaledSrcRect.yBottom = height + ScaledEntryPoint.y;
290 }
291
292 bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS);
293
294 /* pRegions is where the pEntry was drawn in hFb coords. */
295 uint32_t cRegions;
296 const RTRECT *pRegions;
297 rc = CrVrScrCompositorEntryRegionsGet(&hFb->Compositor, pEntry, &cRegions, NULL, NULL, &pRegions);
298 if (!RT_SUCCESS(rc))
299 {
300 WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc));
301 goto end;
302 }
303
304 /* CrTdBltDataAcquireScaled/CrTdBltDataReleaseScaled can use cached data,
305 * so it is not necessary to optimize and Aquire only when Tex changes.
306 */
307 const CR_BLITTER_IMG *pSrcImg;
308 rc = CrTdBltDataAcquireScaled(pTex, GL_BGRA, false, width, height, &pSrcImg);
309 if (!RT_SUCCESS(rc))
310 {
311 WARN(("CrTdBltDataAcquire failed rc %d", rc));
312 goto end;
313 }
314
315 for (uint32_t j = 0; j < cRegions; ++j)
316 {
317 /* rects are in dst coordinates,
318 * while the pReg is in source coords
319 * convert */
320 const RTRECT * pReg = &pRegions[j];
321 RTRECT ScaledReg;
322 /* scale */
323 VBoxRectScaled(pReg, strX, strY, &ScaledReg);
324 /* translate */
325 VBoxRectTranslate(&ScaledReg, pDstRect->xLeft, pDstRect->yTop);
326
327 /* Exclude the pEntry rectangle, because it will be updated now in pDst.
328 * List uses dst coords and pRegions use hFb coords, therefore use
329 * ScaledReg which is already translated to dst.
330 */
331 rc = VBoxVrListRectsSubst(&List, 1, &ScaledReg, NULL);
332 if (!RT_SUCCESS(rc))
333 {
334 WARN(("VBoxVrListRectsSubst failed rc %d", rc));
335 goto end;
336 }
337
338 for (uint32_t i = 0; i < cRects; ++i)
339 {
340 const RTRECT * pRect = &pRects[i];
341
342 RTRECT Intersection;
343 VBoxRectIntersected(pRect, &ScaledReg, &Intersection);
344 if (VBoxRectIsZero(&Intersection))
345 continue;
346
347 VBoxRectIntersect(&Intersection, &ScaledSrcRect);
348 if (VBoxRectIsZero(&Intersection))
349 continue;
350
351 CrMBltImgRect(pSrcImg, &ScaledEntryPoint, fInvert, &Intersection, pDst);
352 }
353 }
354
355 CrTdBltDataReleaseScaled(pTex, pSrcImg);
356 }
357
358 /* Blit still not updated dst rects, i.e. not covered by 3D entries. */
359 c2DRects = VBoxVrListRectsCount(&List);
360 if (c2DRects)
361 {
362 if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT))
363 {
364 if (g_CrPresenter.pvTmpBuf2)
365 RTMemFree(g_CrPresenter.pvTmpBuf2);
366
367 g_CrPresenter.cbTmpBuf2 = (c2DRects + 10) * sizeof (RTRECT);
368 g_CrPresenter.pvTmpBuf2 = RTMemAlloc(g_CrPresenter.cbTmpBuf2);
369 if (!g_CrPresenter.pvTmpBuf2)
370 {
371 WARN(("RTMemAlloc failed!"));
372 g_CrPresenter.cbTmpBuf2 = 0;
373 rc = VERR_NO_MEMORY;
374 goto end;
375 }
376 }
377
378 RTRECT *p2DRects = (RTRECT *)g_CrPresenter.pvTmpBuf2;
379
380 rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects);
381 if (!RT_SUCCESS(rc))
382 {
383 WARN(("VBoxVrListRectsGet failed, rc %d", rc));
384 goto end;
385 }
386
387 /* p2DRects are in pDst coords and already scaled. */
388
389 CR_BLITTER_IMG FbImg;
390
391 crFbImgFromFb(hFb, &FbImg);
392
393 CrMBltImgScaled(&FbImg, pSrcRectSize, pDstRect, c2DRects, p2DRects, pDst);
394 }
395
396end:
397
398 if (pEnteredTex)
399 CrTdBltLeave(pEnteredTex);
400
401 if (pEnteredBlitter)
402 CrBltLeave(pEnteredBlitter);
403
404 VBoxVrListClear(&List);
405
406 return rc;
407}
408
409static int crFbBltGetContentsScaledCPU(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
410{
411 WARN(("not implemented!"));
412 return VERR_NOT_IMPLEMENTED;
413#if 0
414 int32_t srcWidth = pSrcRectSize->cx;
415 int32_t srcHeight = pSrcRectSize->cy;
416 int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
417 int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
418
419 RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop};
420 float strX = ((float)dstWidth) / srcWidth;
421 float strY = ((float)dstHeight) / srcHeight;
422
423 RTPOINT UnscaledPos;
424 UnscaledPos.x = CR_FLOAT_RCAST(int32_t, pDstRect->xLeft / strX);
425 UnscaledPos.y = CR_FLOAT_RCAST(int32_t, pDstRect->yTop / strY);
426
427 /* destination is bigger than the source, do 3D data stretching with CPU */
428 CR_BLITTER_IMG Img;
429 Img.cbData = srcWidth * srcHeight * 4;
430 Img.pvData = RTMemAlloc(Img.cbData);
431 if (!Img.pvData)
432 {
433 WARN(("RTMemAlloc Failed"));
434 return VERR_NO_MEMORY;
435 }
436 Img.enmFormat = pImg->enmFormat;
437 Img.width = srcWidth;
438 Img.height = srcHeight;
439 Img.bpp = pImg->bpp;
440 Img.pitch = Img.width * 4;
441
442 int rc = CrFbBltGetContents(hFb, &UnscaledPos, cRects, pRects, &Img);
443 if (RT_SUCCESS(rc))
444 {
445 CrBmpScale32((uint8_t *)pImg->pvData,
446 pImg->pitch,
447 pImg->width, pImg->height,
448 (const uint8_t *)Img.pvData,
449 Img.pitch,
450 Img.width, Img.height);
451 }
452 else
453 WARN(("CrFbBltGetContents failed %d", rc));
454
455 RTMemFree(Img.pvData);
456
457 return rc;
458#endif
459}
460
461static int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst)
462{
463 VBOXVR_LIST List;
464 uint32_t c2DRects = 0;
465 CR_TEXDATA *pEnteredTex = NULL;
466 PCR_BLITTER pEnteredBlitter = NULL;
467
468 /* 'List' contains the destination rectangles to be updated (in pDst coords). */
469 VBoxVrListInit(&List);
470 int rc = VBoxVrListRectsAdd(&List, cRects, pRects, NULL);
471 if (!RT_SUCCESS(rc))
472 {
473 WARN(("VBoxVrListRectsAdd failed rc %d", rc));
474 goto end;
475 }
476
477 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
478 CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter);
479
480 for(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrVrScrCompositorConstIterNext(&Iter);
481 pEntry;
482 pEntry = CrVrScrCompositorConstIterNext(&Iter))
483 {
484 /* Where the entry would be located in pDst coords (pPos = pDst_coord - hFb_coord). */
485 RTPOINT EntryPoint;
486 EntryPoint.x = CrVrScrCompositorEntryRectGet(pEntry)->xLeft + pPos->x;
487 EntryPoint.y = CrVrScrCompositorEntryRectGet(pEntry)->yTop + pPos->y;
488
489 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
490
491 /* Optimization to avoid entering/leaving the same texture and its blitter. */
492 if (pEnteredTex != pTex)
493 {
494 if (!pEnteredBlitter)
495 {
496 pEnteredBlitter = CrTdBlitterGet(pTex);
497 rc = CrBltEnter(pEnteredBlitter);
498 if (!RT_SUCCESS(rc))
499 {
500 WARN(("CrBltEnter failed %d", rc));
501 pEnteredBlitter = NULL;
502 goto end;
503 }
504 }
505
506 if (pEnteredTex)
507 {
508 CrTdBltLeave(pEnteredTex);
509
510 pEnteredTex = NULL;
511
512 if (pEnteredBlitter != CrTdBlitterGet(pTex))
513 {
514 WARN(("blitters not equal!"));
515 CrBltLeave(pEnteredBlitter);
516
517 pEnteredBlitter = CrTdBlitterGet(pTex);
518 rc = CrBltEnter(pEnteredBlitter);
519 if (!RT_SUCCESS(rc))
520 {
521 WARN(("CrBltEnter failed %d", rc));
522 pEnteredBlitter = NULL;
523 goto end;
524 }
525 }
526 }
527
528 rc = CrTdBltEnter(pTex);
529 if (!RT_SUCCESS(rc))
530 {
531 WARN(("CrTdBltEnter failed %d", rc));
532 goto end;
533 }
534
535 pEnteredTex = pTex;
536 }
537
538 bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS);
539
540 /* pRegions is where the pEntry was drawn in hFb coords. */
541 uint32_t cRegions;
542 const RTRECT *pRegions;
543 rc = CrVrScrCompositorEntryRegionsGet(&hFb->Compositor, pEntry, &cRegions, NULL, NULL, &pRegions);
544 if (!RT_SUCCESS(rc))
545 {
546 WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc));
547 goto end;
548 }
549
550 /* CrTdBltDataAcquire/CrTdBltDataRelease can use cached data,
551 * so it is not necessary to optimize and Aquire only when Tex changes.
552 */
553 const CR_BLITTER_IMG *pSrcImg;
554 rc = CrTdBltDataAcquire(pTex, GL_BGRA, false, &pSrcImg);
555 if (!RT_SUCCESS(rc))
556 {
557 WARN(("CrTdBltDataAcquire failed rc %d", rc));
558 goto end;
559 }
560
561 for (uint32_t j = 0; j < cRegions; ++j)
562 {
563 /* rects are in dst coordinates,
564 * while the pReg is in source coords
565 * convert */
566 const RTRECT * pReg = &pRegions[j];
567 RTRECT SrcReg;
568 /* translate */
569 VBoxRectTranslated(pReg, pPos->x, pPos->y, &SrcReg);
570
571 /* Exclude the pEntry rectangle, because it will be updated now in pDst.
572 * List uses dst coords and pRegions use hFb coords, therefore use
573 * SrcReg which is already translated to dst.
574 */
575 rc = VBoxVrListRectsSubst(&List, 1, &SrcReg, NULL);
576 if (!RT_SUCCESS(rc))
577 {
578 WARN(("VBoxVrListRectsSubst failed rc %d", rc));
579 goto end;
580 }
581
582 for (uint32_t i = 0; i < cRects; ++i)
583 {
584 const RTRECT * pRect = &pRects[i];
585
586 RTRECT Intersection;
587 VBoxRectIntersected(pRect, &SrcReg, &Intersection);
588 if (VBoxRectIsZero(&Intersection))
589 continue;
590
591 CrMBltImgRect(pSrcImg, &EntryPoint, fInvert, &Intersection, pDst);
592 }
593 }
594
595 CrTdBltDataRelease(pTex);
596 }
597
598 /* Blit still not updated dst rects, i.e. not covered by 3D entries. */
599 c2DRects = VBoxVrListRectsCount(&List);
600 if (c2DRects)
601 {
602 if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT))
603 {
604 if (g_CrPresenter.pvTmpBuf2)
605 RTMemFree(g_CrPresenter.pvTmpBuf2);
606
607 g_CrPresenter.cbTmpBuf2 = (c2DRects + 10) * sizeof (RTRECT);
608 g_CrPresenter.pvTmpBuf2 = RTMemAlloc(g_CrPresenter.cbTmpBuf2);
609 if (!g_CrPresenter.pvTmpBuf2)
610 {
611 WARN(("RTMemAlloc failed!"));
612 g_CrPresenter.cbTmpBuf2 = 0;
613 rc = VERR_NO_MEMORY;
614 goto end;
615 }
616 }
617
618 RTRECT *p2DRects = (RTRECT *)g_CrPresenter.pvTmpBuf2;
619
620 rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects);
621 if (!RT_SUCCESS(rc))
622 {
623 WARN(("VBoxVrListRectsGet failed, rc %d", rc));
624 goto end;
625 }
626
627 CR_BLITTER_IMG FbImg;
628
629 crFbImgFromFb(hFb, &FbImg);
630
631 CrMBltImg(&FbImg, pPos, c2DRects, p2DRects, pDst);
632 }
633
634end:
635
636 if (pEnteredTex)
637 CrTdBltLeave(pEnteredTex);
638
639 if (pEnteredBlitter)
640 CrBltLeave(pEnteredBlitter);
641
642 VBoxVrListClear(&List);
643
644 return rc;
645}
646
647int CrFbBltGetContentsEx(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
648{
649 uint32_t srcWidth = pSrcRectSize->cx;
650 uint32_t srcHeight = pSrcRectSize->cy;
651 uint32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
652 uint32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
653 if (srcWidth == dstWidth
654 && srcHeight == dstHeight)
655 {
656 RTPOINT Pos = {pDstRect->xLeft, pDstRect->yTop};
657 return CrFbBltGetContents(hFb, &Pos, cRects, pRects, pImg);
658 }
659 if (!CrFbHas3DData(hFb)
660 || (srcWidth * srcHeight > dstWidth * dstHeight))
661 return crFbBltGetContentsScaledDirect(hFb, pSrcRectSize, pDstRect, cRects, pRects, pImg);
662
663 return crFbBltGetContentsScaledCPU(hFb, pSrcRectSize, pDstRect, cRects, pRects, pImg);
664}
665
666static void crFbBltPutContentsFbVram(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pSrc)
667{
668 const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor);
669
670 CR_BLITTER_IMG FbImg;
671
672 crFbImgFromFb(hFb, &FbImg);
673
674 CrMBltImg(pSrc, pPos, cRects, pRects, &FbImg);
675}
676
677static void crFbClrFillFbVram(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color)
678{
679 CR_BLITTER_IMG FbImg;
680
681 crFbImgFromFb(hFb, &FbImg);
682
683 CrMClrFillImg(&FbImg, cRects, pRects, u32Color);
684}
685
686int CrFbClrFill(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color)
687{
688 if (!hFb->cUpdating)
689 {
690 WARN(("framebuffer not updating"));
691 return VERR_INVALID_STATE;
692 }
693
694 crFbClrFillFbVram(hFb, cRects, pRects, u32Color);
695
696 RTPOINT DstPoint = {0, 0};
697
698 int rc = CrFbEntryRegionsAdd(hFb, NULL, &DstPoint, cRects, pRects, false);
699 if (!RT_SUCCESS(rc))
700 {
701 WARN(("CrFbEntryRegionsAdd failed %d", rc));
702 return rc;
703 }
704
705 return VINF_SUCCESS;
706}
707
708static int crFbBltPutContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
709{
710 crFbBltPutContentsFbVram(hFb, pPos, cRects, pRects, pImg);
711
712 int rc = CrFbEntryRegionsAdd(hFb, NULL, pPos, cRects, pRects, false);
713 if (!RT_SUCCESS(rc))
714 {
715 WARN(("CrFbEntryRegionsAdd failed %d", rc));
716 return rc;
717 }
718
719 return VINF_SUCCESS;
720}
721
722int CrFbBltPutContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
723{
724 if (!hFb->cUpdating)
725 {
726 WARN(("framebuffer not updating"));
727 return VERR_INVALID_STATE;
728 }
729
730 return crFbBltPutContents(hFb, pPos, cRects, pRects, pImg);
731}
732
733static int crFbRegionsIsIntersectRects(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, bool *pfRegChanged)
734{
735 uint32_t cCompRects;
736 const RTRECT *pCompRects;
737 int rc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cCompRects, NULL, NULL, &pCompRects);
738 if (!RT_SUCCESS(rc))
739 {
740 WARN(("CrVrScrCompositorRegionsGet failed rc %d", rc));
741 return rc;
742 }
743
744 bool fRegChanged = false;
745 for (uint32_t i = 0; i < cCompRects; ++i)
746 {
747 const RTRECT *pCompRect = &pCompRects[i];
748 for (uint32_t j = 0; j < cRects; ++j)
749 {
750 const RTRECT *pRect = &pRects[j];
751 if (VBoxRectIsIntersect(pCompRect, pRect))
752 {
753 *pfRegChanged = true;
754 return VINF_SUCCESS;
755 }
756 }
757 }
758
759 *pfRegChanged = false;
760 return VINF_SUCCESS;
761}
762
763int CrFbBltPutContentsNe(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
764{
765 bool fRegChanged = false;
766 int rc = crFbRegionsIsIntersectRects(hFb, cRects, pRects, &fRegChanged);
767 if (!RT_SUCCESS(rc))
768 {
769 WARN(("crFbRegionsIsIntersectRects failed rc %d", rc));
770 return rc;
771 }
772
773 if (fRegChanged)
774 {
775 rc = CrFbUpdateBegin(hFb);
776 if (RT_SUCCESS(rc))
777 {
778 rc = CrFbBltPutContents(hFb, pPos, cRects, pRects, pImg);
779 if (!RT_SUCCESS(rc))
780 WARN(("CrFbBltPutContents failed rc %d", rc));
781 CrFbUpdateEnd(hFb);
782 }
783 else
784 WARN(("CrFbUpdateBegin failed rc %d", rc));
785
786 return rc;
787 }
788
789 crFbBltPutContentsFbVram(hFb, pPos, cRects, pRects, pImg);
790 return VINF_SUCCESS;
791}
792
793int CrFbClrFillNe(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color)
794{
795 bool fRegChanged = false;
796 int rc = crFbRegionsIsIntersectRects(hFb, cRects, pRects, &fRegChanged);
797 if (!RT_SUCCESS(rc))
798 {
799 WARN(("crFbRegionsIsIntersectRects failed rc %d", rc));
800 return rc;
801 }
802
803 if (fRegChanged)
804 {
805 rc = CrFbUpdateBegin(hFb);
806 if (RT_SUCCESS(rc))
807 {
808 rc = CrFbClrFill(hFb, cRects, pRects, u32Color);
809 if (!RT_SUCCESS(rc))
810 WARN(("CrFbClrFill failed rc %d", rc));
811 CrFbUpdateEnd(hFb);
812 }
813 else
814 WARN(("CrFbUpdateBegin failed rc %d", rc));
815
816 return rc;
817 }
818
819 crFbClrFillFbVram(hFb, cRects, pRects, u32Color);
820 return VINF_SUCCESS;
821}
822
823int CrFbResize(CR_FRAMEBUFFER *pFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM)
824{
825 if (!pFb->cUpdating)
826 {
827 WARN(("no update in progress"));
828 return VERR_INVALID_STATE;
829 }
830
831 int rc = VINF_SUCCESS;
832 if (CrFbIsEnabled(pFb))
833 {
834 rc = CrFbRegionsClear(pFb);
835 if (RT_FAILURE(rc))
836 {
837 WARN(("CrFbRegionsClear failed %d", rc));
838 return rc;
839 }
840 }
841
842 RTRECT Rect;
843 Rect.xLeft = 0;
844 Rect.yTop = 0;
845 Rect.xRight = pScreen->u32Width;
846 Rect.yBottom = pScreen->u32Height;
847 rc = CrVrScrCompositorRectSet(&pFb->Compositor, &Rect, NULL);
848 if (!RT_SUCCESS(rc))
849 {
850 WARN(("CrVrScrCompositorRectSet failed rc %d", rc));
851 return rc;
852 }
853
854 pFb->ScreenInfo = *pScreen;
855 pFb->pvVram = pvVRAM ? pvVRAM : g_pvVRamBase + pScreen->u32StartOffset;
856
857 if (pFb->pDisplay)
858 pFb->pDisplay->FramebufferChanged(pFb);
859
860 return VINF_SUCCESS;
861}
862
863void CrFbTerm(CR_FRAMEBUFFER *pFb)
864{
865 if (pFb->cUpdating)
866 {
867 WARN(("update in progress"));
868 return;
869 }
870 uint32_t idFb = pFb->ScreenInfo.u32ViewIndex;
871
872 CrVrScrCompositorClear(&pFb->Compositor);
873 CrHTableDestroy(&pFb->SlotTable);
874
875 Assert(RTListIsEmpty(&pFb->EntriesList));
876 Assert(!pFb->cEntries);
877
878 memset(pFb, 0, sizeof (*pFb));
879
880 pFb->ScreenInfo.u16Flags = VBVA_SCREEN_F_DISABLED;
881 pFb->ScreenInfo.u32ViewIndex = idFb;
882}
883
884ICrFbDisplay* CrFbDisplayGet(CR_FRAMEBUFFER *pFb)
885{
886 return pFb->pDisplay;
887}
888
889int CrFbDisplaySet(CR_FRAMEBUFFER *pFb, ICrFbDisplay *pDisplay)
890{
891 if (pFb->cUpdating)
892 {
893 WARN(("update in progress"));
894 return VERR_INVALID_STATE;
895 }
896
897 if (pFb->pDisplay == pDisplay)
898 return VINF_SUCCESS;
899
900 pFb->pDisplay = pDisplay;
901
902 return VINF_SUCCESS;
903}
904
905#define CR_PMGR_MODE_WINDOW 0x1
906/* mutually exclusive with CR_PMGR_MODE_WINDOW */
907#define CR_PMGR_MODE_ROOTVR 0x2
908#define CR_PMGR_MODE_VRDP 0x4
909#define CR_PMGR_MODE_ALL 0x7
910
911static int crPMgrModeModifyGlobal(uint32_t u32ModeAdd, uint32_t u32ModeRemove);
912static void crPMgrCleanUnusedDisplays();
913
914static CR_FBTEX* crFbTexAlloc()
915{
916#ifndef VBOXVDBG_MEMCACHE_DISABLE
917 return (CR_FBTEX*)RTMemCacheAlloc(g_CrPresenter.FbTexLookasideList);
918#else
919 return (CR_FBTEX*)RTMemAlloc(sizeof (CR_FBTEX));
920#endif
921}
922
923static void crFbTexFree(CR_FBTEX *pTex)
924{
925#ifndef VBOXVDBG_MEMCACHE_DISABLE
926 RTMemCacheFree(g_CrPresenter.FbTexLookasideList, pTex);
927#else
928 RTMemFree(pTex);
929#endif
930}
931
932static CR_FRAMEBUFFER_ENTRY* crFbEntryAlloc()
933{
934#ifndef VBOXVDBG_MEMCACHE_DISABLE
935 return (CR_FRAMEBUFFER_ENTRY*)RTMemCacheAlloc(g_CrPresenter.FbEntryLookasideList);
936#else
937 return (CR_FRAMEBUFFER_ENTRY*)RTMemAlloc(sizeof (CR_FRAMEBUFFER_ENTRY));
938#endif
939}
940
941static void crFbEntryFree(CR_FRAMEBUFFER_ENTRY *pEntry)
942{
943 Assert(!CrVrScrCompositorEntryIsUsed(&pEntry->Entry));
944#ifndef VBOXVDBG_MEMCACHE_DISABLE
945 RTMemCacheFree(g_CrPresenter.FbEntryLookasideList, pEntry);
946#else
947 RTMemFree(pEntry);
948#endif
949}
950
951DECLCALLBACK(void) crFbTexRelease(CR_TEXDATA *pTex)
952{
953 CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTex);
954 CRTextureObj *pTobj = pFbTex->pTobj;
955
956 CrTdBltDataCleanupNe(pTex);
957
958 if (pTobj)
959 {
960 crHashtableDelete(g_CrPresenter.pFbTexMap, pTobj->id, NULL);
961
962 crStateReleaseTexture(cr_server.MainContextInfo.pContext, pTobj);
963
964
965 crStateGlobalSharedRelease();
966 }
967
968 crFbTexFree(pFbTex);
969}
970
971void CrFbTexDataInit(CR_TEXDATA* pFbTex, const VBOXVR_TEXTURE *pTex, PFNCRTEXDATA_RELEASED pfnTextureReleased)
972{
973 PCR_BLITTER pBlitter = crServerVBoxBlitterGet();
974
975 CrTdInit(pFbTex, pTex, pBlitter, pfnTextureReleased);
976}
977
978static CR_FBTEX* crFbTexCreate(const VBOXVR_TEXTURE *pTex)
979{
980 CR_FBTEX *pFbTex = crFbTexAlloc();
981 if (!pFbTex)
982 {
983 WARN(("crFbTexAlloc failed!"));
984 return NULL;
985 }
986
987 CrFbTexDataInit(&pFbTex->Tex, pTex, crFbTexRelease);
988 pFbTex->pTobj = NULL;
989
990 return pFbTex;
991}
992
993CR_TEXDATA* CrFbTexDataCreate(const VBOXVR_TEXTURE *pTex)
994{
995 CR_FBTEX *pFbTex = crFbTexCreate(pTex);
996 if (!pFbTex)
997 {
998 WARN(("crFbTexCreate failed!"));
999 return NULL;
1000 }
1001
1002 return &pFbTex->Tex;
1003}
1004
1005static CR_FBTEX* crFbTexAcquire(GLuint idTexture)
1006{
1007 CR_FBTEX *pFbTex = (CR_FBTEX *)crHashtableSearch(g_CrPresenter.pFbTexMap, idTexture);
1008 if (pFbTex)
1009 {
1010 CrTdAddRef(&pFbTex->Tex);
1011 return pFbTex;
1012 }
1013
1014 CRSharedState *pShared = crStateGlobalSharedAcquire();
1015 if (!pShared)
1016 {
1017 WARN(("pShared is null!"));
1018 return NULL;
1019 }
1020
1021 CRTextureObj *pTobj = (CRTextureObj*)crHashtableSearch(pShared->textureTable, idTexture);
1022 if (!pTobj)
1023 {
1024 LOG(("pTobj is null!"));
1025 crStateGlobalSharedRelease();
1026 return NULL;
1027 }
1028
1029 Assert(pTobj->id == idTexture);
1030
1031 GLuint hwid = crStateGetTextureObjHWID(pTobj);
1032 if (!hwid)
1033 {
1034 WARN(("hwId is null!"));
1035 crStateGlobalSharedRelease();
1036 return NULL;
1037 }
1038
1039 VBOXVR_TEXTURE Tex;
1040 Tex.width = pTobj->level[0]->width;
1041 Tex.height = pTobj->level[0]->height;
1042 Tex.hwid = hwid;
1043 Tex.target = pTobj->target;
1044
1045 pFbTex = crFbTexCreate(&Tex);
1046 if (!pFbTex)
1047 {
1048 WARN(("crFbTexCreate failed!"));
1049 crStateGlobalSharedRelease();
1050 return NULL;
1051 }
1052
1053 CR_STATE_SHAREDOBJ_USAGE_SET(pTobj, cr_server.MainContextInfo.pContext);
1054
1055 pFbTex->pTobj = pTobj;
1056
1057 crHashtableAdd(g_CrPresenter.pFbTexMap, idTexture, pFbTex);
1058
1059 return pFbTex;
1060}
1061
1062static CR_TEXDATA* CrFbTexDataAcquire(GLuint idTexture)
1063{
1064 CR_FBTEX* pTex = crFbTexAcquire(idTexture);
1065 if (!pTex)
1066 {
1067 WARN(("crFbTexAcquire failed for %d", idTexture));
1068 return NULL;
1069 }
1070
1071 return &pTex->Tex;
1072}
1073
1074static void crFbEntryMarkDestroyed(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry)
1075{
1076 if (pEntry->Flags.fCreateNotified)
1077 {
1078 pEntry->Flags.fCreateNotified = 0;
1079 if (pFb->pDisplay)
1080 pFb->pDisplay->EntryDestroyed(pFb, pEntry);
1081
1082 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry);
1083 if (pTex)
1084 CrTdBltDataInvalidateNe(pTex);
1085 }
1086}
1087
1088static void crFbEntryDestroy(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry)
1089{
1090 crFbEntryMarkDestroyed(pFb, pEntry);
1091 CrVrScrCompositorEntryCleanup(&pEntry->Entry);
1092 CrHTableDestroy(&pEntry->HTable);
1093 Assert(pFb->cEntries);
1094 RTListNodeRemove(&pEntry->Node);
1095 --pFb->cEntries;
1096 crFbEntryFree(pEntry);
1097}
1098
1099DECLINLINE(uint32_t) crFbEntryAddRef(CR_FRAMEBUFFER_ENTRY* pEntry)
1100{
1101 return ++pEntry->cRefs;
1102}
1103
1104DECLINLINE(uint32_t) crFbEntryRelease(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry)
1105{
1106 uint32_t cRefs = --pEntry->cRefs;
1107 if (!cRefs)
1108 crFbEntryDestroy(pFb, pEntry);
1109 return cRefs;
1110}
1111
1112static DECLCALLBACK(void) crFbEntryReleased(const struct VBOXVR_SCR_COMPOSITOR *pCompositor, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacingEntry)
1113{
1114 CR_FRAMEBUFFER *pFb = PCR_FRAMEBUFFER_FROM_COMPOSITOR(pCompositor);
1115 CR_FRAMEBUFFER_ENTRY *pFbEntry = PCR_FBENTRY_FROM_ENTRY(pEntry);
1116 CR_FRAMEBUFFER_ENTRY *pFbReplacingEntry = pReplacingEntry ? PCR_FBENTRY_FROM_ENTRY(pReplacingEntry) : NULL;
1117 if (pFbReplacingEntry)
1118 {
1119 /*replace operation implies the replaced entry gets auto-destroyed,
1120 * while all its data gets moved to the *clean* replacing entry
1121 * 1. ensure the replacing entry is cleaned up */
1122 crFbEntryMarkDestroyed(pFb, pFbReplacingEntry);
1123
1124 CrHTableMoveTo(&pFbEntry->HTable, &pFbReplacingEntry->HTable);
1125
1126 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry);
1127 CR_TEXDATA *pReplacingTex = CrVrScrCompositorEntryTexGet(&pFbReplacingEntry->Entry);
1128
1129 CrTdBltScaleCacheMoveTo(pTex, pReplacingTex);
1130
1131 if (pFb->pDisplay)
1132 pFb->pDisplay->EntryReplaced(pFb, pFbReplacingEntry, pFbEntry);
1133
1134 CrTdBltDataInvalidateNe(pTex);
1135
1136 /* 2. mark the replaced entry is destroyed */
1137 Assert(pFbEntry->Flags.fCreateNotified);
1138 Assert(pFbEntry->Flags.fInList);
1139 pFbEntry->Flags.fCreateNotified = 0;
1140 pFbEntry->Flags.fInList = 0;
1141 pFbReplacingEntry->Flags.fCreateNotified = 1;
1142 pFbReplacingEntry->Flags.fInList = 1;
1143 }
1144 else
1145 {
1146 if (pFbEntry->Flags.fInList)
1147 {
1148 pFbEntry->Flags.fInList = 0;
1149 if (pFb->pDisplay)
1150 pFb->pDisplay->EntryRemoved(pFb, pFbEntry);
1151
1152 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry);
1153 if (pTex)
1154 CrTdBltDataInvalidateNe(pTex);
1155 }
1156 }
1157
1158 crFbEntryRelease(pFb, pFbEntry);
1159}
1160
1161static CR_FRAMEBUFFER_ENTRY* crFbEntryCreate(CR_FRAMEBUFFER *pFb, CR_TEXDATA* pTex, const RTRECT *pRect, uint32_t fFlags)
1162{
1163 CR_FRAMEBUFFER_ENTRY *pEntry = crFbEntryAlloc();
1164 if (!pEntry)
1165 {
1166 WARN(("crFbEntryAlloc failed!"));
1167 return NULL;
1168 }
1169
1170 CrVrScrCompositorEntryInit(&pEntry->Entry, pRect, pTex, crFbEntryReleased);
1171 CrVrScrCompositorEntryFlagsSet(&pEntry->Entry, fFlags);
1172 pEntry->cRefs = 1;
1173 pEntry->Flags.Value = 0;
1174 CrHTableCreate(&pEntry->HTable, 0);
1175
1176 RTListAppend(&pFb->EntriesList, &pEntry->Node);
1177 ++pFb->cEntries;
1178
1179 return pEntry;
1180}
1181
1182int CrFbEntryCreateForTexData(CR_FRAMEBUFFER *pFb, struct CR_TEXDATA *pTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry)
1183{
1184 RTRECT Rect;
1185 Rect.xLeft = 0;
1186 Rect.yTop = 0;
1187 Rect.xRight = pTex->Tex.width;
1188 Rect.yBottom = pTex->Tex.height;
1189 CR_FRAMEBUFFER_ENTRY* pEntry = crFbEntryCreate(pFb, pTex, &Rect, fFlags);
1190 if (!pEntry)
1191 {
1192 WARN(("crFbEntryCreate failed"));
1193 return VERR_NO_MEMORY;
1194 }
1195
1196 *phEntry = pEntry;
1197 return VINF_SUCCESS;
1198}
1199
1200int CrFbEntryTexDataUpdate(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY pEntry, struct CR_TEXDATA *pTex)
1201{
1202 if (!pFb->cUpdating)
1203 {
1204 WARN(("framebuffer not updating"));
1205 return VERR_INVALID_STATE;
1206 }
1207
1208 if (pTex)
1209 CrVrScrCompositorEntryTexSet(&pEntry->Entry, pTex);
1210
1211 if (CrVrScrCompositorEntryIsUsed(&pEntry->Entry))
1212 {
1213 if (pFb->pDisplay)
1214 pFb->pDisplay->EntryTexChanged(pFb, pEntry);
1215
1216 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry);
1217 if (pTex)
1218 CrTdBltDataInvalidateNe(pTex);
1219 }
1220
1221 return VINF_SUCCESS;
1222}
1223
1224
1225int CrFbEntryCreateForTexId(CR_FRAMEBUFFER *pFb, GLuint idTexture, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry)
1226{
1227 CR_FBTEX* pFbTex = crFbTexAcquire(idTexture);
1228 if (!pFbTex)
1229 {
1230 LOG(("crFbTexAcquire failed"));
1231 return VERR_INVALID_PARAMETER;
1232 }
1233
1234 CR_TEXDATA* pTex = &pFbTex->Tex;
1235 int rc = CrFbEntryCreateForTexData(pFb, pTex, fFlags, phEntry);
1236 if (!RT_SUCCESS(rc))
1237 {
1238 WARN(("CrFbEntryCreateForTexData failed rc %d", rc));
1239 }
1240
1241 /*always release the tex, the CrFbEntryCreateForTexData will do incref as necessary */
1242 CrTdRelease(pTex);
1243 return rc;
1244}
1245
1246void CrFbEntryAddRef(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
1247{
1248 ++hEntry->cRefs;
1249}
1250
1251void CrFbEntryRelease(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
1252{
1253 crFbEntryRelease(pFb, hEntry);
1254}
1255
1256static int8_t crVBoxServerCrCmdBltPrimaryVramGenericProcess(uint32_t u32PrimaryID, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, bool fToPrimary);
1257
1258int CrFbRegionsClear(HCR_FRAMEBUFFER hFb)
1259{
1260 if (!hFb->cUpdating)
1261 {
1262 WARN(("framebuffer not updating"));
1263 return VERR_INVALID_STATE;
1264 }
1265
1266 uint32_t cRegions;
1267 const RTRECT *pRegions;
1268 int rc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cRegions, NULL, NULL, &pRegions);
1269 if (!RT_SUCCESS(rc))
1270 {
1271 WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc));
1272 return rc;
1273 }
1274
1275 const struct VBVAINFOSCREEN* pScreen = CrFbGetScreenInfo(hFb);
1276 VBOXCMDVBVAOFFSET offVRAM = (VBOXCMDVBVAOFFSET)(((uintptr_t)CrFbGetVRAM(hFb)) - ((uintptr_t)g_pvVRamBase));
1277 RTPOINT Pos = {0,0};
1278 int8_t i8Result = crVBoxServerCrCmdBltPrimaryVramGenericProcess(pScreen->u32ViewIndex, offVRAM, pScreen->u32Width, pScreen->u32Height, &Pos, cRegions, pRegions, true);
1279 if (i8Result)
1280 {
1281 WARN(("crVBoxServerCrCmdBltPrimaryVramGenericProcess failed"));
1282 return VERR_INTERNAL_ERROR;
1283 }
1284
1285#ifdef DEBUG
1286 {
1287 uint32_t cTmpRegions;
1288 const RTRECT *pTmpRegions;
1289 int tmpRc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cTmpRegions, NULL, NULL, &pTmpRegions);
1290 if (!RT_SUCCESS(tmpRc))
1291 {
1292 WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", tmpRc));
1293 }
1294 Assert(!cTmpRegions);
1295 }
1296#endif
1297
1298 /* just in case */
1299 bool fChanged = false;
1300 CrVrScrCompositorRegionsClear(&hFb->Compositor, &fChanged);
1301 Assert(!fChanged);
1302
1303 if (cRegions)
1304 {
1305 if (hFb->pDisplay)
1306 hFb->pDisplay->RegionsChanged(hFb);
1307 }
1308
1309 return VINF_SUCCESS;
1310}
1311
1312int CrFbEntryRegionsAdd(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated)
1313{
1314 if (!pFb->cUpdating)
1315 {
1316 WARN(("framebuffer not updating"));
1317 return VERR_INVALID_STATE;
1318 }
1319
1320 uint32_t fChangeFlags = 0;
1321 VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = NULL;
1322 VBOXVR_SCR_COMPOSITOR_ENTRY *pNewEntry;
1323 bool fEntryWasInList;
1324
1325 if (hEntry)
1326 {
1327 crFbEntryAddRef(hEntry);
1328 pNewEntry = &hEntry->Entry;
1329 fEntryWasInList = CrVrScrCompositorEntryIsUsed(pNewEntry);
1330
1331 Assert(!hEntry->Flags.fInList == !fEntryWasInList);
1332 }
1333 else
1334 {
1335 pNewEntry = NULL;
1336 fEntryWasInList = false;
1337 }
1338
1339 int rc = CrVrScrCompositorEntryRegionsAdd(&pFb->Compositor, hEntry ? &hEntry->Entry : NULL, pPos, cRegions, paRegions, fPosRelated, &pReplacedScrEntry, &fChangeFlags);
1340 if (RT_SUCCESS(rc))
1341 {
1342 if (fChangeFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED)
1343 {
1344 if (!fEntryWasInList && pNewEntry)
1345 {
1346 Assert(CrVrScrCompositorEntryIsUsed(pNewEntry));
1347 if (!hEntry->Flags.fCreateNotified)
1348 {
1349 hEntry->Flags.fCreateNotified = 1;
1350 if (pFb->pDisplay)
1351 pFb->pDisplay->EntryCreated(pFb, hEntry);
1352 }
1353
1354#ifdef DEBUG_misha
1355 /* in theory hEntry->Flags.fInList can be set if entry is replaced,
1356 * but then modified to fit the compositor rects,
1357 * and so we get the regions changed notification as a result
1358 * this should not generally happen though, so put an assertion to debug that situation */
1359 Assert(!hEntry->Flags.fInList);
1360#endif
1361 if (!hEntry->Flags.fInList)
1362 {
1363 hEntry->Flags.fInList = 1;
1364
1365 if (pFb->pDisplay)
1366 pFb->pDisplay->EntryAdded(pFb, hEntry);
1367 }
1368 }
1369 if (pFb->pDisplay)
1370 pFb->pDisplay->RegionsChanged(pFb);
1371
1372 Assert(!pReplacedScrEntry);
1373 }
1374 else if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED)
1375 {
1376 Assert(pReplacedScrEntry);
1377 /* we have already processed that in a "release" callback */
1378 Assert(hEntry);
1379 }
1380 else
1381 {
1382 Assert(!fChangeFlags);
1383 Assert(!pReplacedScrEntry);
1384 }
1385
1386 if (hEntry)
1387 {
1388 if (CrVrScrCompositorEntryIsUsed(&hEntry->Entry))
1389 {
1390 if (pFb->pDisplay)
1391 pFb->pDisplay->EntryTexChanged(pFb, hEntry);
1392
1393 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry);
1394 if (pTex)
1395 CrTdBltDataInvalidateNe(pTex);
1396 }
1397 }
1398 }
1399 else
1400 WARN(("CrVrScrCompositorEntryRegionsAdd failed, rc %d", rc));
1401
1402 return rc;
1403}
1404
1405int CrFbEntryRegionsSet(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated)
1406{
1407 if (!pFb->cUpdating)
1408 {
1409 WARN(("framebuffer not updating"));
1410 return VERR_INVALID_STATE;
1411 }
1412
1413 bool fChanged = 0;
1414 VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = NULL;
1415 VBOXVR_SCR_COMPOSITOR_ENTRY *pNewEntry;
1416 bool fEntryWasInList;
1417
1418 if (hEntry)
1419 {
1420 crFbEntryAddRef(hEntry);
1421 pNewEntry = &hEntry->Entry;
1422 fEntryWasInList = CrVrScrCompositorEntryIsUsed(pNewEntry);
1423 Assert(!hEntry->Flags.fInList == !fEntryWasInList);
1424 }
1425 else
1426 {
1427 pNewEntry = NULL;
1428 fEntryWasInList = false;
1429 }
1430
1431 int rc = CrVrScrCompositorEntryRegionsSet(&pFb->Compositor, pNewEntry, pPos, cRegions, paRegions, fPosRelated, &fChanged);
1432 if (RT_SUCCESS(rc))
1433 {
1434 if (fChanged)
1435 {
1436 if (!fEntryWasInList && pNewEntry)
1437 {
1438 if (CrVrScrCompositorEntryIsUsed(pNewEntry))
1439 {
1440 if (!hEntry->Flags.fCreateNotified)
1441 {
1442 hEntry->Flags.fCreateNotified = 1;
1443
1444 if (pFb->pDisplay)
1445 pFb->pDisplay->EntryCreated(pFb, hEntry);
1446 }
1447
1448 Assert(!hEntry->Flags.fInList);
1449 hEntry->Flags.fInList = 1;
1450
1451 if (pFb->pDisplay)
1452 pFb->pDisplay->EntryAdded(pFb, hEntry);
1453 }
1454 }
1455
1456 if (pFb->pDisplay)
1457 pFb->pDisplay->RegionsChanged(pFb);
1458 }
1459
1460 if (hEntry)
1461 {
1462 if (CrVrScrCompositorEntryIsUsed(&hEntry->Entry))
1463 {
1464 if (pFb->pDisplay)
1465 pFb->pDisplay->EntryTexChanged(pFb, hEntry);
1466
1467 CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry);
1468 if (pTex)
1469 CrTdBltDataInvalidateNe(pTex);
1470 }
1471 }
1472 }
1473 else
1474 WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc));
1475
1476 return rc;
1477}
1478
1479const struct VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbEntryGetCompositorEntry(HCR_FRAMEBUFFER_ENTRY hEntry)
1480{
1481 return &hEntry->Entry;
1482}
1483
1484HCR_FRAMEBUFFER_ENTRY CrFbEntryFromCompositorEntry(const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry)
1485{
1486 return RT_FROM_MEMBER(pCEntry, CR_FRAMEBUFFER_ENTRY, Entry);
1487}
1488
1489void CrFbVisitCreatedEntries(HCR_FRAMEBUFFER hFb, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB pfnVisitorCb, void *pvContext)
1490{
1491 HCR_FRAMEBUFFER_ENTRY hEntry, hNext;
1492 RTListForEachSafe(&hFb->EntriesList, hEntry, hNext, CR_FRAMEBUFFER_ENTRY, Node)
1493 {
1494 if (hEntry->Flags.fCreateNotified)
1495 {
1496 if (!pfnVisitorCb(hFb, hEntry, pvContext))
1497 return;
1498 }
1499 }
1500}
1501
1502
1503CRHTABLE_HANDLE CrFbDDataAllocSlot(CR_FRAMEBUFFER *pFb)
1504{
1505 return CrHTablePut(&pFb->SlotTable, (void*)1);
1506}
1507
1508void CrFbDDataReleaseSlot(CR_FRAMEBUFFER *pFb, CRHTABLE_HANDLE hSlot, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB pfnReleaseCb, void *pvContext)
1509{
1510 HCR_FRAMEBUFFER_ENTRY hEntry, hNext;
1511 RTListForEachSafe(&pFb->EntriesList, hEntry, hNext, CR_FRAMEBUFFER_ENTRY, Node)
1512 {
1513 if (CrFbDDataEntryGet(hEntry, hSlot))
1514 {
1515 if (pfnReleaseCb)
1516 pfnReleaseCb(pFb, hEntry, pvContext);
1517
1518 CrFbDDataEntryClear(hEntry, hSlot);
1519 }
1520 }
1521
1522 CrHTableRemove(&pFb->SlotTable, hSlot);
1523}
1524
1525int CrFbDDataEntryPut(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot, void *pvData)
1526{
1527 return CrHTablePutToSlot(&hEntry->HTable, hSlot, pvData);
1528}
1529
1530void* CrFbDDataEntryClear(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot)
1531{
1532 return CrHTableRemove(&hEntry->HTable, hSlot);
1533}
1534
1535void* CrFbDDataEntryGet(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot)
1536{
1537 return CrHTableGet(&hEntry->HTable, hSlot);
1538}
1539
1540int CrPMgrDisable()
1541{
1542 if (!g_CrPresenter.fEnabled)
1543 return VINF_SUCCESS;
1544
1545 g_CrPresenter.u32DisabledDisplayMode = g_CrPresenter.u32DisplayMode;
1546
1547 int rc = crPMgrModeModifyGlobal(0, CR_PMGR_MODE_WINDOW);
1548 if (RT_FAILURE(rc))
1549 {
1550 WARN(("crPMgrModeModifyGlobal failed %d", rc));
1551 return rc;
1552 }
1553
1554 crPMgrCleanUnusedDisplays();
1555
1556 g_CrPresenter.fEnabled = false;
1557
1558 return VINF_SUCCESS;
1559}
1560
1561int CrPMgrEnable()
1562{
1563 if (g_CrPresenter.fEnabled)
1564 return VINF_SUCCESS;
1565
1566 g_CrPresenter.fEnabled = true;
1567
1568 int rc = crPMgrModeModifyGlobal(g_CrPresenter.u32DisabledDisplayMode, 0);
1569 if (RT_FAILURE(rc))
1570 {
1571 WARN(("crPMgrModeModifyGlobal failed %d", rc));
1572 g_CrPresenter.fEnabled = false;
1573 return rc;
1574 }
1575
1576 g_CrPresenter.u32DisabledDisplayMode = 0;
1577
1578 return VINF_SUCCESS;
1579}
1580
1581int CrPMgrInit()
1582{
1583 int rc = VINF_SUCCESS;
1584 memset(&g_CrPresenter, 0, sizeof (g_CrPresenter));
1585 g_CrPresenter.fEnabled = true;
1586 for (int i = 0; i < RT_ELEMENTS(g_CrPresenter.aDisplayInfos); ++i)
1587 {
1588 g_CrPresenter.aDisplayInfos[i].u32Id = i;
1589 g_CrPresenter.aDisplayInfos[i].iFb = -1;
1590
1591 g_CrPresenter.aFbInfos[i].u32Id = i;
1592 }
1593
1594 g_CrPresenter.pFbTexMap = crAllocHashtable();
1595 if (g_CrPresenter.pFbTexMap)
1596 {
1597#ifndef VBOXVDBG_MEMCACHE_DISABLE
1598 rc = RTMemCacheCreate(&g_CrPresenter.FbEntryLookasideList, sizeof (CR_FRAMEBUFFER_ENTRY),
1599 0, /* size_t cbAlignment */
1600 UINT32_MAX, /* uint32_t cMaxObjects */
1601 NULL, /* PFNMEMCACHECTOR pfnCtor*/
1602 NULL, /* PFNMEMCACHEDTOR pfnDtor*/
1603 NULL, /* void *pvUser*/
1604 0 /* uint32_t fFlags*/
1605 );
1606 if (RT_SUCCESS(rc))
1607 {
1608 rc = RTMemCacheCreate(&g_CrPresenter.FbTexLookasideList, sizeof (CR_FBTEX),
1609 0, /* size_t cbAlignment */
1610 UINT32_MAX, /* uint32_t cMaxObjects */
1611 NULL, /* PFNMEMCACHECTOR pfnCtor*/
1612 NULL, /* PFNMEMCACHEDTOR pfnDtor*/
1613 NULL, /* void *pvUser*/
1614 0 /* uint32_t fFlags*/
1615 );
1616 if (RT_SUCCESS(rc))
1617 {
1618 rc = RTMemCacheCreate(&g_CrPresenter.CEntryLookasideList, sizeof (VBOXVR_SCR_COMPOSITOR_ENTRY),
1619 0, /* size_t cbAlignment */
1620 UINT32_MAX, /* uint32_t cMaxObjects */
1621 NULL, /* PFNMEMCACHECTOR pfnCtor*/
1622 NULL, /* PFNMEMCACHEDTOR pfnDtor*/
1623 NULL, /* void *pvUser*/
1624 0 /* uint32_t fFlags*/
1625 );
1626 if (RT_SUCCESS(rc))
1627 {
1628#endif
1629 rc = crPMgrModeModifyGlobal(CR_PMGR_MODE_WINDOW, 0);
1630 if (RT_SUCCESS(rc))
1631 return VINF_SUCCESS;
1632 else
1633 WARN(("crPMgrModeModifyGlobal failed rc %d", rc));
1634#ifndef VBOXVDBG_MEMCACHE_DISABLE
1635 RTMemCacheDestroy(g_CrPresenter.CEntryLookasideList);
1636 }
1637 else
1638 WARN(("RTMemCacheCreate failed rc %d", rc));
1639
1640 RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList);
1641 }
1642 else
1643 WARN(("RTMemCacheCreate failed rc %d", rc));
1644
1645 RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList);
1646 }
1647 else
1648 WARN(("RTMemCacheCreate failed rc %d", rc));
1649#endif
1650 }
1651 else
1652 {
1653 WARN(("crAllocHashtable failed"));
1654 rc = VERR_NO_MEMORY;
1655 }
1656 return rc;
1657}
1658
1659void CrPMgrTerm()
1660{
1661 crPMgrModeModifyGlobal(0, CR_PMGR_MODE_ALL);
1662
1663 HCR_FRAMEBUFFER hFb;
1664
1665 for (hFb = CrPMgrFbGetFirstInitialized();
1666 hFb;
1667 hFb = CrPMgrFbGetNextInitialized(hFb))
1668 {
1669 uint32_t iFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
1670 CrFbDisplaySet(hFb, NULL);
1671 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[iFb];
1672 if (pFbInfo->pDpComposite)
1673 {
1674 delete pFbInfo->pDpComposite;
1675 pFbInfo->pDpComposite = NULL;
1676 }
1677
1678 CrFbTerm(hFb);
1679 }
1680
1681 crPMgrCleanUnusedDisplays();
1682
1683#ifndef VBOXVDBG_MEMCACHE_DISABLE
1684 RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList);
1685 RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList);
1686 RTMemCacheDestroy(g_CrPresenter.CEntryLookasideList);
1687#endif
1688 crFreeHashtable(g_CrPresenter.pFbTexMap, NULL);
1689
1690 if (g_CrPresenter.pvTmpBuf)
1691 RTMemFree(g_CrPresenter.pvTmpBuf);
1692
1693 if (g_CrPresenter.pvTmpBuf2)
1694 RTMemFree(g_CrPresenter.pvTmpBuf2);
1695
1696 memset(&g_CrPresenter, 0, sizeof (g_CrPresenter));
1697}
1698
1699HCR_FRAMEBUFFER CrPMgrFbGet(uint32_t idFb)
1700{
1701 if (idFb >= CR_MAX_GUEST_MONITORS)
1702 {
1703 WARN(("invalid idFb %d", idFb));
1704 return NULL;
1705 }
1706
1707 if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idFb))
1708 {
1709 CrFbInit(&g_CrPresenter.aFramebuffers[idFb], idFb);
1710 CrFBmSetAtomic(&g_CrPresenter.FramebufferInitMap, idFb);
1711 }
1712 else
1713 Assert(g_CrPresenter.aFramebuffers[idFb].ScreenInfo.u32ViewIndex == idFb);
1714
1715 return &g_CrPresenter.aFramebuffers[idFb];
1716}
1717
1718HCR_FRAMEBUFFER CrPMgrFbGetInitialized(uint32_t idFb)
1719{
1720 if (idFb >= CR_MAX_GUEST_MONITORS)
1721 {
1722 WARN(("invalid idFb %d", idFb));
1723 return NULL;
1724 }
1725
1726 if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idFb))
1727 {
1728 return NULL;
1729 }
1730 else
1731 Assert(g_CrPresenter.aFramebuffers[idFb].ScreenInfo.u32ViewIndex == idFb);
1732
1733 return &g_CrPresenter.aFramebuffers[idFb];
1734}
1735
1736HCR_FRAMEBUFFER CrPMgrFbGetEnabled(uint32_t idFb)
1737{
1738 HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(idFb);
1739
1740 if(hFb && CrFbIsEnabled(hFb))
1741 return hFb;
1742
1743 return NULL;
1744}
1745
1746HCR_FRAMEBUFFER CrPMgrFbGetEnabledForScreen(uint32_t idScreen)
1747{
1748 if (idScreen >= (uint32_t)cr_server.screenCount)
1749 {
1750 WARN(("invalid target id"));
1751 return NULL;
1752 }
1753
1754 const CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
1755 if (pDpInfo->iFb < 0)
1756 return NULL;
1757
1758 return CrPMgrFbGetEnabled(pDpInfo->iFb);
1759}
1760
1761static HCR_FRAMEBUFFER crPMgrFbGetNextEnabled(uint32_t i)
1762{
1763 for (;i < (uint32_t)cr_server.screenCount; ++i)
1764 {
1765 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(i);
1766 if (hFb)
1767 return hFb;
1768 }
1769
1770 return NULL;
1771}
1772
1773static HCR_FRAMEBUFFER crPMgrFbGetNextInitialized(uint32_t i)
1774{
1775 for (;i < (uint32_t)cr_server.screenCount; ++i)
1776 {
1777 HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(i);
1778 if (hFb)
1779 return hFb;
1780 }
1781
1782 return NULL;
1783}
1784
1785HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled()
1786{
1787 HCR_FRAMEBUFFER hFb = crPMgrFbGetNextEnabled(0);
1788// if (!hFb)
1789// WARN(("no enabled framebuffer found"));
1790 return hFb;
1791}
1792
1793HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb)
1794{
1795 return crPMgrFbGetNextEnabled(hFb->ScreenInfo.u32ViewIndex+1);
1796}
1797
1798HCR_FRAMEBUFFER CrPMgrFbGetFirstInitialized()
1799{
1800 HCR_FRAMEBUFFER hFb = crPMgrFbGetNextInitialized(0);
1801// if (!hFb)
1802// WARN(("no initialized framebuffer found"));
1803 return hFb;
1804}
1805
1806HCR_FRAMEBUFFER CrPMgrFbGetNextInitialized(HCR_FRAMEBUFFER hFb)
1807{
1808 return crPMgrFbGetNextInitialized(hFb->ScreenInfo.u32ViewIndex+1);
1809}
1810
1811HCR_FRAMEBUFFER CrPMgrFbGetEnabledByVramStart(VBOXCMDVBVAOFFSET offVRAM)
1812{
1813 for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
1814 hFb;
1815 hFb = CrPMgrFbGetNextEnabled(hFb))
1816 {
1817 const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
1818 if (pScreen->u32StartOffset == offVRAM)
1819 return hFb;
1820 }
1821
1822 return NULL;
1823}
1824
1825
1826static uint32_t crPMgrModeAdjustVal(uint32_t u32Mode)
1827{
1828 u32Mode = CR_PMGR_MODE_ALL & u32Mode;
1829 if (CR_PMGR_MODE_ROOTVR & u32Mode)
1830 u32Mode &= ~CR_PMGR_MODE_WINDOW;
1831 return u32Mode;
1832}
1833
1834static int crPMgrCheckInitWindowDisplays(uint32_t idScreen)
1835{
1836#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
1837 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
1838 if (pDpInfo->iFb >= 0)
1839 {
1840 uint32_t u32ModeAdd = g_CrPresenter.u32DisplayMode & (CR_PMGR_MODE_WINDOW | CR_PMGR_MODE_ROOTVR);
1841 int rc = crPMgrFbConnectTargetDisplays(&g_CrPresenter.aFramebuffers[pDpInfo->iFb], pDpInfo, u32ModeAdd);
1842 if (RT_FAILURE(rc))
1843 {
1844 WARN(("crPMgrFbConnectTargetDisplays failed %d", rc));
1845 return rc;
1846 }
1847 }
1848#endif
1849 return VINF_SUCCESS;
1850}
1851
1852extern "C" DECLEXPORT(int) VBoxOglSetScaleFactor(uint32_t idScreen, double dScaleFactorW, double dScaleFactorH)
1853{
1854 if (idScreen >= CR_MAX_GUEST_MONITORS)
1855 {
1856 crDebug("Can't set scale factor because specified screen ID (%u) is out of range (max=%d).", idScreen, CR_MAX_GUEST_MONITORS);
1857 return VERR_INVALID_PARAMETER;
1858 }
1859
1860 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
1861 if (pDpInfo->pDpWin)
1862 {
1863 CrFbWindow *pWin = pDpInfo->pDpWin->getWindow();
1864 if (pWin)
1865 {
1866 bool rc;
1867 crDebug("Set scale factor for initialized display.");
1868 rc = pWin->SetScaleFactor((GLdouble)dScaleFactorW, (GLdouble)dScaleFactorH);
1869 return rc ? 0 : VERR_LOCK_FAILED;
1870 }
1871 else
1872 crDebug("Can't apply scale factor at the moment bacause overlay window obgect not yet created. Will be chached.");
1873 }
1874 else
1875 crDebug("Can't apply scale factor at the moment bacause display not yet initialized. Will be chached.");
1876
1877 /* Display output not yet initialized. Let's cache values. */
1878 pDpInfo->dInitialScaleFactorW = dScaleFactorW;
1879 pDpInfo->dInitialScaleFactorH = dScaleFactorH;
1880
1881 return 0;
1882}
1883
1884int CrPMgrScreenChanged(uint32_t idScreen)
1885{
1886 if (idScreen >= CR_MAX_GUEST_MONITORS)
1887 {
1888 WARN(("invalid idScreen %d", idScreen));
1889 return VERR_INVALID_PARAMETER;
1890 }
1891
1892 int rc = VINF_SUCCESS;
1893
1894 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
1895 HCR_FRAMEBUFFER hFb = pDpInfo->iFb >= 0 ? CrPMgrFbGet(pDpInfo->iFb) : NULL;
1896
1897 if (hFb && CrFbIsUpdating(hFb))
1898 {
1899 WARN(("trying to update viewport while framebuffer is being updated"));
1900 return VERR_INVALID_STATE;
1901 }
1902
1903 if (pDpInfo->pDpWin)
1904 {
1905 CRASSERT(pDpInfo->pDpWin->getWindow());
1906
1907 rc = pDpInfo->pDpWin->UpdateBegin(hFb);
1908 if (RT_SUCCESS(rc))
1909 {
1910 pDpInfo->pDpWin->reparent(cr_server.screen[idScreen].winID);
1911 pDpInfo->pDpWin->UpdateEnd(hFb);
1912 }
1913 }
1914 else
1915 {
1916 if (pDpInfo->pWindow)
1917 {
1918 rc = pDpInfo->pWindow->UpdateBegin();
1919 if (RT_SUCCESS(rc))
1920 {
1921 rc = pDpInfo->pWindow->SetVisible(false);
1922 if (RT_SUCCESS(rc))
1923 rc = pDpInfo->pWindow->Reparent(cr_server.screen[idScreen].winID);
1924
1925 pDpInfo->pWindow->UpdateEnd();
1926 }
1927 }
1928
1929 if (RT_SUCCESS(rc))
1930 rc = crPMgrCheckInitWindowDisplays(idScreen);
1931 }
1932
1933 CRASSERT(!rc);
1934
1935 return rc;
1936}
1937
1938int CrPMgrViewportUpdate(uint32_t idScreen)
1939{
1940 if (idScreen >= CR_MAX_GUEST_MONITORS)
1941 {
1942 WARN(("invalid idScreen %d", idScreen));
1943 return VERR_INVALID_PARAMETER;
1944 }
1945
1946 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
1947 if (pDpInfo->iFb >= 0)
1948 {
1949 HCR_FRAMEBUFFER hFb = CrPMgrFbGet(pDpInfo->iFb);
1950 if (CrFbIsUpdating(hFb))
1951 {
1952 WARN(("trying to update viewport while framebuffer is being updated"));
1953 return VERR_INVALID_STATE;
1954 }
1955
1956 if (pDpInfo->pDpWin)
1957 {
1958 CRASSERT(pDpInfo->pDpWin->getWindow());
1959 int rc = pDpInfo->pDpWin->UpdateBegin(hFb);
1960 if (RT_SUCCESS(rc))
1961 {
1962 pDpInfo->pDpWin->setViewportRect(&cr_server.screenVieport[idScreen].Rect);
1963 pDpInfo->pDpWin->UpdateEnd(hFb);
1964 }
1965 else
1966 WARN(("UpdateBegin failed %d", rc));
1967 }
1968 }
1969
1970 return VINF_SUCCESS;
1971}
1972
1973static int crPMgrFbDisconnectDisplay(HCR_FRAMEBUFFER hFb, CrFbDisplayBase *pDp)
1974{
1975 if (pDp->getFramebuffer() != hFb)
1976 return VINF_SUCCESS;
1977
1978 CrFbDisplayBase * pCurDp = (CrFbDisplayBase*)CrFbDisplayGet(hFb);
1979 if (!pCurDp)
1980 {
1981 WARN(("no display set, unexpected"));
1982 return VERR_INTERNAL_ERROR;
1983 }
1984
1985 if (pCurDp == pDp)
1986 {
1987 pDp->setFramebuffer(NULL);
1988 CrFbDisplaySet(hFb, NULL);
1989 return VINF_SUCCESS;
1990 }
1991
1992 uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
1993 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
1994 if (pFbInfo->pDpComposite != pCurDp)
1995 {
1996 WARN(("misconfig, expectig the curret framebuffer to be present, and thus composite is expected"));
1997 return VERR_INTERNAL_ERROR;
1998 }
1999
2000 if (pDp->getContainer() == pFbInfo->pDpComposite)
2001 {
2002 pFbInfo->pDpComposite->remove(pDp);
2003 uint32_t cDisplays = pFbInfo->pDpComposite->getDisplayCount();
2004 if (cDisplays <= 1)
2005 {
2006 Assert(cDisplays == 1);
2007 CrFbDisplayBase *pDpFirst = pFbInfo->pDpComposite->first();
2008 if (pDpFirst)
2009 pFbInfo->pDpComposite->remove(pDpFirst, false);
2010 CrFbDisplaySet(hFb, pDpFirst);
2011 }
2012 return VINF_SUCCESS;
2013 }
2014
2015 WARN(("misconfig"));
2016 return VERR_INTERNAL_ERROR;
2017}
2018
2019static int crPMgrFbConnectDisplay(HCR_FRAMEBUFFER hFb, CrFbDisplayBase *pDp)
2020{
2021 if (pDp->getFramebuffer() == hFb)
2022 return VINF_SUCCESS;
2023
2024 CrFbDisplayBase * pCurDp = (CrFbDisplayBase*)CrFbDisplayGet(hFb);
2025 if (!pCurDp)
2026 {
2027 pDp->setFramebuffer(hFb);
2028 CrFbDisplaySet(hFb, pDp);
2029 return VINF_SUCCESS;
2030 }
2031
2032 if (pCurDp == pDp)
2033 {
2034 WARN(("misconfig, current framebuffer is not expected to be set"));
2035 return VERR_INTERNAL_ERROR;
2036 }
2037
2038 uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
2039 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
2040 if (pFbInfo->pDpComposite != pCurDp)
2041 {
2042 if (!pFbInfo->pDpComposite)
2043 {
2044 pFbInfo->pDpComposite = new CrFbDisplayComposite();
2045 pFbInfo->pDpComposite->setFramebuffer(hFb);
2046 }
2047
2048 pFbInfo->pDpComposite->add(pCurDp);
2049 CrFbDisplaySet(hFb, pFbInfo->pDpComposite);
2050 }
2051
2052 pFbInfo->pDpComposite->add(pDp);
2053 return VINF_SUCCESS;
2054}
2055
2056static int crPMgrFbDisconnectTarget(HCR_FRAMEBUFFER hFb, uint32_t i)
2057{
2058 uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
2059 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
2060 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
2061 if (pDpInfo->iFb != idFb)
2062 {
2063 WARN(("target not connected"));
2064 Assert(!ASMBitTest(pFbInfo->aTargetMap, i));
2065 return VINF_SUCCESS;
2066 }
2067
2068 Assert(ASMBitTest(pFbInfo->aTargetMap, i));
2069
2070 int rc = VINF_SUCCESS;
2071 if (pDpInfo->pDpVrdp)
2072 {
2073 rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpVrdp);
2074 if (RT_FAILURE(rc))
2075 {
2076 WARN(("crPMgrFbDisconnectDisplay failed %d", rc));
2077 return rc;
2078 }
2079 }
2080
2081 if (pDpInfo->pDpWinRootVr)
2082 {
2083#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
2084 CrFbWindow *pWindow = pDpInfo->pDpWinRootVr->windowDetach(false);
2085 Assert(pWindow == pDpInfo->pWindow);
2086#endif
2087 rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWinRootVr);
2088 if (RT_FAILURE(rc))
2089 {
2090 WARN(("crPMgrFbDisconnectDisplay failed %d", rc));
2091 return rc;
2092 }
2093 }
2094 else if (pDpInfo->pDpWin)
2095 {
2096#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
2097 CrFbWindow *pWindow = pDpInfo->pDpWin->windowDetach(false);
2098 Assert(pWindow == pDpInfo->pWindow);
2099#endif
2100 rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWin);
2101 if (RT_FAILURE(rc))
2102 {
2103 WARN(("crPMgrFbDisconnectDisplay failed %d", rc));
2104 return rc;
2105 }
2106 }
2107
2108 ASMBitClear(pFbInfo->aTargetMap, i);
2109 pDpInfo->iFb = -1;
2110
2111 return VINF_SUCCESS;
2112}
2113
2114static void crPMgrDpWinRootVrCreate(CR_FBDISPLAY_INFO *pDpInfo)
2115{
2116 if (!pDpInfo->pDpWinRootVr)
2117 {
2118 if (pDpInfo->pDpWin)
2119 {
2120 CrFbWindow *pWin = pDpInfo->pDpWin->windowDetach();
2121 CRASSERT(pWin);
2122 Assert(pWin == pDpInfo->pWindow);
2123 delete pDpInfo->pDpWin;
2124 pDpInfo->pDpWin = NULL;
2125 }
2126 else if (!pDpInfo->pWindow)
2127 {
2128 pDpInfo->pWindow = new CrFbWindow(0);
2129 }
2130
2131 pDpInfo->pDpWinRootVr = new CrFbDisplayWindowRootVr(&cr_server.screenVieport[pDpInfo->u32Id].Rect, cr_server.screen[pDpInfo->u32Id].winID);
2132 pDpInfo->pDpWin = pDpInfo->pDpWinRootVr;
2133 pDpInfo->pDpWinRootVr->windowAttach(pDpInfo->pWindow);
2134
2135 /* Set scale factor once it was previously cached when display output was not yet initialized. */
2136 if (pDpInfo->dInitialScaleFactorW || pDpInfo->dInitialScaleFactorH)
2137 {
2138 crDebug("Set cached scale factor for seamless mode.");
2139 pDpInfo->pWindow->SetScaleFactor((GLdouble)pDpInfo->dInitialScaleFactorW, (GLdouble)pDpInfo->dInitialScaleFactorH);
2140 /* Invalidate cache. */
2141 pDpInfo->dInitialScaleFactorW = pDpInfo->dInitialScaleFactorH = 0;
2142 }
2143 }
2144}
2145
2146static void crPMgrDpWinCreate(CR_FBDISPLAY_INFO *pDpInfo)
2147{
2148 if (pDpInfo->pDpWinRootVr)
2149 {
2150 CRASSERT(pDpInfo->pDpWinRootVr == pDpInfo->pDpWin);
2151 CrFbWindow *pWin = pDpInfo->pDpWin->windowDetach();
2152 CRASSERT(pWin);
2153 Assert(pWin == pDpInfo->pWindow);
2154 delete pDpInfo->pDpWinRootVr;
2155 pDpInfo->pDpWinRootVr = NULL;
2156 pDpInfo->pDpWin = NULL;
2157 }
2158
2159 if (!pDpInfo->pDpWin)
2160 {
2161 if (!pDpInfo->pWindow)
2162 pDpInfo->pWindow = new CrFbWindow(0);
2163
2164 pDpInfo->pDpWin = new CrFbDisplayWindow(&cr_server.screenVieport[pDpInfo->u32Id].Rect, cr_server.screen[pDpInfo->u32Id].winID);
2165 pDpInfo->pDpWin->windowAttach(pDpInfo->pWindow);
2166
2167 /* Set scale factor once it was previously cached when display output was not yet initialized. */
2168 if (pDpInfo->dInitialScaleFactorW || pDpInfo->dInitialScaleFactorH)
2169 {
2170 crDebug("Set cached scale factor for host window.");
2171 pDpInfo->pWindow->SetScaleFactor((GLdouble)pDpInfo->dInitialScaleFactorW, (GLdouble)pDpInfo->dInitialScaleFactorH);
2172 /* Invalidate cache. */
2173 pDpInfo->dInitialScaleFactorW = pDpInfo->dInitialScaleFactorH = 0;
2174 }
2175 }
2176}
2177
2178static int crPMgrFbDisconnectTargetDisplays(HCR_FRAMEBUFFER hFb, CR_FBDISPLAY_INFO *pDpInfo, uint32_t u32ModeRemove)
2179{
2180 int rc = VINF_SUCCESS;
2181 if (u32ModeRemove & CR_PMGR_MODE_ROOTVR)
2182 {
2183 if (pDpInfo->pDpWinRootVr)
2184 {
2185#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
2186 CrFbWindow *pWindow = pDpInfo->pDpWinRootVr->windowDetach(false);
2187 Assert(pWindow == pDpInfo->pWindow);
2188#endif
2189 CRASSERT(pDpInfo->pDpWin == pDpInfo->pDpWinRootVr);
2190 rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWinRootVr);
2191 if (RT_FAILURE(rc))
2192 {
2193 WARN(("crPMgrFbDisconnectDisplay pDpWinRootVr failed %d", rc));
2194 return rc;
2195 }
2196 }
2197 }
2198 else if (u32ModeRemove & CR_PMGR_MODE_WINDOW)
2199 {
2200 CRASSERT(!pDpInfo->pDpWinRootVr);
2201 if (pDpInfo->pDpWin)
2202 {
2203#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
2204 CrFbWindow *pWindow = pDpInfo->pDpWin->windowDetach(false);
2205 Assert(pWindow == pDpInfo->pWindow);
2206#endif
2207 rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWin);
2208 if (RT_FAILURE(rc))
2209 {
2210 WARN(("crPMgrFbDisconnectDisplay pDpWin failed %d", rc));
2211 return rc;
2212 }
2213 }
2214 }
2215
2216 if (u32ModeRemove & CR_PMGR_MODE_VRDP)
2217 {
2218 if (pDpInfo->pDpVrdp)
2219 {
2220 rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpVrdp);
2221 if (RT_FAILURE(rc))
2222 {
2223 WARN(("crPMgrFbDisconnectDisplay pDpVrdp failed %d", rc));
2224 return rc;
2225 }
2226 }
2227 }
2228
2229 pDpInfo->u32DisplayMode &= ~u32ModeRemove;
2230
2231 return VINF_SUCCESS;
2232}
2233
2234static int crPMgrFbConnectTargetDisplays(HCR_FRAMEBUFFER hFb, CR_FBDISPLAY_INFO *pDpInfo, uint32_t u32ModeAdd)
2235{
2236 int rc = VINF_SUCCESS;
2237
2238 if (u32ModeAdd & CR_PMGR_MODE_ROOTVR)
2239 {
2240 crPMgrDpWinRootVrCreate(pDpInfo);
2241
2242 rc = crPMgrFbConnectDisplay(hFb, pDpInfo->pDpWinRootVr);
2243 if (RT_FAILURE(rc))
2244 {
2245 WARN(("crPMgrFbConnectDisplay pDpWinRootVr failed %d", rc));
2246 return rc;
2247 }
2248 }
2249 else if (u32ModeAdd & CR_PMGR_MODE_WINDOW)
2250 {
2251 crPMgrDpWinCreate(pDpInfo);
2252
2253 rc = crPMgrFbConnectDisplay(hFb, pDpInfo->pDpWin);
2254 if (RT_FAILURE(rc))
2255 {
2256 WARN(("crPMgrFbConnectDisplay pDpWin failed %d", rc));
2257 return rc;
2258 }
2259 }
2260
2261 if (u32ModeAdd & CR_PMGR_MODE_VRDP)
2262 {
2263 if (!pDpInfo->pDpVrdp)
2264 pDpInfo->pDpVrdp = new CrFbDisplayVrdp();
2265
2266 rc = crPMgrFbConnectDisplay(hFb, pDpInfo->pDpVrdp);
2267 if (RT_FAILURE(rc))
2268 {
2269 WARN(("crPMgrFbConnectDisplay pDpVrdp failed %d", rc));
2270 return rc;
2271 }
2272 }
2273
2274 pDpInfo->u32DisplayMode |= u32ModeAdd;
2275
2276 return VINF_SUCCESS;
2277}
2278
2279static int crPMgrFbConnectTarget(HCR_FRAMEBUFFER hFb, uint32_t i)
2280{
2281 uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
2282 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
2283 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
2284 if (pDpInfo->iFb == idFb)
2285 {
2286 WARN(("target not connected"));
2287 Assert(ASMBitTest(pFbInfo->aTargetMap, i));
2288 return VINF_SUCCESS;
2289 }
2290
2291 Assert(!ASMBitTest(pFbInfo->aTargetMap, i));
2292
2293 int rc = VINF_SUCCESS;
2294
2295 if (pDpInfo->iFb != -1)
2296 {
2297 Assert(pDpInfo->iFb < cr_server.screenCount);
2298 HCR_FRAMEBUFFER hAssignedFb = CrPMgrFbGet(pDpInfo->iFb);
2299 Assert(hAssignedFb);
2300 rc = crPMgrFbDisconnectTarget(hAssignedFb, i);
2301 if (RT_FAILURE(rc))
2302 {
2303 WARN(("crPMgrFbDisconnectTarget failed %d", rc));
2304 return rc;
2305 }
2306 }
2307
2308 rc = crPMgrFbConnectTargetDisplays(hFb, pDpInfo, g_CrPresenter.u32DisplayMode
2309#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
2310 & ~(CR_PMGR_MODE_WINDOW | CR_PMGR_MODE_ROOTVR)
2311#endif
2312 );
2313 if (RT_FAILURE(rc))
2314 {
2315 WARN(("crPMgrFbConnectTargetDisplays failed %d", rc));
2316 return rc;
2317 }
2318
2319 ASMBitSet(pFbInfo->aTargetMap, i);
2320 pDpInfo->iFb = idFb;
2321
2322 return VINF_SUCCESS;
2323}
2324
2325static int crPMgrFbDisconnect(HCR_FRAMEBUFFER hFb, const uint32_t *pTargetMap)
2326{
2327 int rc = VINF_SUCCESS;
2328 for (int i = ASMBitFirstSet(pTargetMap, cr_server.screenCount);
2329 i >= 0;
2330 i = ASMBitNextSet(pTargetMap, cr_server.screenCount, i))
2331 {
2332 rc = crPMgrFbDisconnectTarget(hFb, (uint32_t)i);
2333 if (RT_FAILURE(rc))
2334 {
2335 WARN(("crPMgrFbDisconnectTarget failed %d", rc));
2336 return rc;
2337 }
2338 }
2339
2340 return VINF_SUCCESS;
2341}
2342
2343static int crPMgrFbConnect(HCR_FRAMEBUFFER hFb, const uint32_t *pTargetMap)
2344{
2345 int rc = VINF_SUCCESS;
2346 for (int i = ASMBitFirstSet(pTargetMap, cr_server.screenCount);
2347 i >= 0;
2348 i = ASMBitNextSet(pTargetMap, cr_server.screenCount, i))
2349 {
2350 rc = crPMgrFbConnectTarget(hFb, (uint32_t)i);
2351 if (RT_FAILURE(rc))
2352 {
2353 WARN(("crPMgrFbConnectTarget failed %d", rc));
2354 return rc;
2355 }
2356 }
2357
2358 return VINF_SUCCESS;
2359}
2360
2361static int crPMgrModeModifyTarget(HCR_FRAMEBUFFER hFb, uint32_t iDisplay, uint32_t u32ModeAdd, uint32_t u32ModeRemove)
2362{
2363 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[iDisplay];
2364 int rc = crPMgrFbDisconnectTargetDisplays(hFb, pDpInfo, u32ModeRemove);
2365 if (RT_FAILURE(rc))
2366 {
2367 WARN(("crPMgrFbDisconnectTargetDisplays failed %d", rc));
2368 return rc;
2369 }
2370
2371 rc = crPMgrFbConnectTargetDisplays(hFb, pDpInfo, u32ModeAdd);
2372 if (RT_FAILURE(rc))
2373 {
2374 WARN(("crPMgrFbConnectTargetDisplays failed %d", rc));
2375 return rc;
2376 }
2377
2378 return VINF_SUCCESS;
2379}
2380
2381static int crPMgrModeModify(HCR_FRAMEBUFFER hFb, uint32_t u32ModeAdd, uint32_t u32ModeRemove)
2382{
2383 int rc = VINF_SUCCESS;
2384 uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
2385 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
2386 for (int i = ASMBitFirstSet(pFbInfo->aTargetMap, cr_server.screenCount);
2387 i >= 0;
2388 i = ASMBitNextSet(pFbInfo->aTargetMap, cr_server.screenCount, i))
2389 {
2390 rc = crPMgrModeModifyTarget(hFb, (uint32_t)i, u32ModeAdd, u32ModeRemove);
2391 if (RT_FAILURE(rc))
2392 {
2393 WARN(("crPMgrModeModifyTarget failed %d", rc));
2394 return rc;
2395 }
2396 }
2397
2398 return VINF_SUCCESS;
2399}
2400
2401static void crPMgrCleanUnusedDisplays()
2402{
2403 for (int i = 0; i < cr_server.screenCount; ++i)
2404 {
2405 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
2406
2407 if (pDpInfo->pDpWinRootVr)
2408 {
2409 if (!pDpInfo->pDpWinRootVr->getFramebuffer())
2410 {
2411 pDpInfo->pDpWinRootVr->windowDetach(false);
2412 delete pDpInfo->pDpWinRootVr;
2413 pDpInfo->pDpWinRootVr = NULL;
2414 pDpInfo->pDpWin = NULL;
2415 if (pDpInfo->pWindow)
2416 {
2417 delete pDpInfo->pWindow;
2418 pDpInfo->pWindow = NULL;
2419 }
2420 }
2421 else
2422 WARN(("pDpWinRootVr is used"));
2423 }
2424 else if (pDpInfo->pDpWin)
2425 {
2426 if (!pDpInfo->pDpWin->getFramebuffer())
2427 {
2428 pDpInfo->pDpWin->windowDetach(false);
2429 delete pDpInfo->pDpWin;
2430 pDpInfo->pDpWin = NULL;
2431 if (pDpInfo->pWindow)
2432 {
2433 delete pDpInfo->pWindow;
2434 pDpInfo->pWindow = NULL;
2435 }
2436 }
2437 else
2438 WARN(("pDpWin is used"));
2439 }
2440
2441 if (pDpInfo->pDpVrdp)
2442 {
2443 if (!pDpInfo->pDpVrdp->getFramebuffer())
2444 {
2445 delete pDpInfo->pDpVrdp;
2446 pDpInfo->pDpVrdp = NULL;
2447 }
2448 else
2449 WARN(("pDpVrdp is used"));
2450 }
2451 }
2452}
2453
2454static int crPMgrModeModifyGlobal(uint32_t u32ModeAdd, uint32_t u32ModeRemove)
2455{
2456 uint32_t u32InternalMode = g_CrPresenter.fEnabled ? g_CrPresenter.u32DisplayMode : g_CrPresenter.u32DisabledDisplayMode;
2457
2458 u32ModeRemove = ((u32ModeRemove | crPMgrModeAdjustVal(u32ModeRemove)) & CR_PMGR_MODE_ALL);
2459 u32ModeAdd = crPMgrModeAdjustVal(u32ModeAdd);
2460 u32ModeRemove &= u32InternalMode;
2461 u32ModeAdd &= ~(u32ModeRemove | u32InternalMode);
2462 uint32_t u32ModeResulting = ((u32InternalMode | u32ModeAdd) & ~u32ModeRemove);
2463 uint32_t u32Tmp = crPMgrModeAdjustVal(u32ModeResulting);
2464 if (u32Tmp != u32ModeResulting)
2465 {
2466 u32ModeAdd |= (u32Tmp & ~u32ModeResulting);
2467 u32ModeRemove |= (~u32Tmp & u32ModeResulting);
2468 u32ModeResulting = u32Tmp;
2469 Assert(u32ModeResulting == ((u32InternalMode | u32ModeAdd) & ~u32ModeRemove));
2470 }
2471 if (!u32ModeRemove && !u32ModeAdd)
2472 return VINF_SUCCESS;
2473
2474 uint32_t u32DisplayMode = (g_CrPresenter.u32DisplayMode | u32ModeAdd) & ~u32ModeRemove;
2475 if (!g_CrPresenter.fEnabled)
2476 {
2477 Assert(g_CrPresenter.u32DisplayMode == 0);
2478 g_CrPresenter.u32DisabledDisplayMode = u32DisplayMode;
2479 return VINF_SUCCESS;
2480 }
2481
2482 g_CrPresenter.u32DisplayMode = u32DisplayMode;
2483
2484 /* disabled framebuffers may still have displays attached */
2485 for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstInitialized();
2486 hFb;
2487 hFb = CrPMgrFbGetNextInitialized(hFb))
2488 {
2489 crPMgrModeModify(hFb, u32ModeAdd, u32ModeRemove);
2490 }
2491
2492 return VINF_SUCCESS;
2493}
2494
2495int CrPMgrClearRegionsGlobal()
2496{
2497 for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
2498 hFb;
2499 hFb = CrPMgrFbGetNextEnabled(hFb))
2500 {
2501 int rc = CrFbUpdateBegin(hFb);
2502 if (RT_SUCCESS(rc))
2503 {
2504 rc = CrFbRegionsClear(hFb);
2505 if (RT_FAILURE(rc))
2506 {
2507 WARN(("CrFbRegionsClear failed %d", rc));
2508 }
2509
2510 CrFbUpdateEnd(hFb);
2511 }
2512 }
2513
2514 return VINF_SUCCESS;
2515}
2516
2517int CrPMgrModeVrdp(bool fEnable)
2518{
2519 uint32_t u32ModeAdd, u32ModeRemove;
2520 if (fEnable)
2521 {
2522 u32ModeAdd = CR_PMGR_MODE_VRDP;
2523 u32ModeRemove = 0;
2524 }
2525 else
2526 {
2527 u32ModeAdd = 0;
2528 u32ModeRemove = CR_PMGR_MODE_VRDP;
2529 }
2530 return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove);
2531}
2532
2533int CrPMgrModeRootVr(bool fEnable)
2534{
2535 uint32_t u32ModeAdd, u32ModeRemove;
2536 if (fEnable)
2537 {
2538 u32ModeAdd = CR_PMGR_MODE_ROOTVR;
2539 u32ModeRemove = CR_PMGR_MODE_WINDOW;
2540 }
2541 else
2542 {
2543 u32ModeAdd = CR_PMGR_MODE_WINDOW;
2544 u32ModeRemove = CR_PMGR_MODE_ROOTVR;
2545 }
2546
2547 return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove);
2548}
2549
2550int CrPMgrModeWinVisible(bool fEnable)
2551{
2552 if (!g_CrPresenter.fWindowsForceHidden == !!fEnable)
2553 return VINF_SUCCESS;
2554
2555 g_CrPresenter.fWindowsForceHidden = !fEnable;
2556
2557 for (int i = 0; i < cr_server.screenCount; ++i)
2558 {
2559 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
2560
2561 if (pDpInfo->pDpWin)
2562 pDpInfo->pDpWin->winVisibilityChanged();
2563 }
2564
2565 return VINF_SUCCESS;
2566}
2567
2568int CrPMgrRootVrUpdate()
2569{
2570 for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
2571 hFb;
2572 hFb = CrPMgrFbGetNextEnabled(hFb))
2573 {
2574 if (!CrFbHas3DData(hFb))
2575 continue;
2576
2577 uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
2578 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
2579 int rc = CrFbUpdateBegin(hFb);
2580 if (RT_SUCCESS(rc))
2581 {
2582 for (int i = ASMBitFirstSet(pFbInfo->aTargetMap, cr_server.screenCount);
2583 i >= 0;
2584 i = ASMBitNextSet(pFbInfo->aTargetMap, cr_server.screenCount, i))
2585 {
2586 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
2587 Assert(pDpInfo->iFb == (int32_t)idFb);
2588
2589 pDpInfo->pDpWinRootVr->RegionsChanged(hFb);
2590 }
2591
2592 CrFbUpdateEnd(hFb);
2593 }
2594 else
2595 WARN(("CrFbUpdateBegin failed %d", rc));
2596 }
2597
2598 return VINF_SUCCESS;
2599}
2600
2601/*helper function that calls CrFbUpdateBegin for all enabled framebuffers */
2602int CrPMgrHlpGlblUpdateBegin(CR_FBMAP *pMap)
2603{
2604 CrFBmInit(pMap);
2605 for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
2606 hFb;
2607 hFb = CrPMgrFbGetNextEnabled(hFb))
2608 {
2609 int rc = CrFbUpdateBegin(hFb);
2610 if (!RT_SUCCESS(rc))
2611 {
2612 WARN(("UpdateBegin failed, rc %d", rc));
2613 for (HCR_FRAMEBUFFER hTmpFb = CrPMgrFbGetFirstEnabled();
2614 hFb != hTmpFb;
2615 hTmpFb = CrPMgrFbGetNextEnabled(hTmpFb))
2616 {
2617 CrFbUpdateEnd(hTmpFb);
2618 CrFBmClear(pMap, CrFbGetScreenInfo(hFb)->u32ViewIndex);
2619 }
2620 return rc;
2621 }
2622
2623 CrFBmSet(pMap, CrFbGetScreenInfo(hFb)->u32ViewIndex);
2624 }
2625
2626 return VINF_SUCCESS;
2627}
2628
2629/*helper function that calls CrFbUpdateEnd for all framebuffers being updated */
2630void CrPMgrHlpGlblUpdateEnd(CR_FBMAP *pMap)
2631{
2632 for (uint32_t i = 0; i < (uint32_t)cr_server.screenCount; ++i)
2633 {
2634 if (!CrFBmIsSet(pMap, i))
2635 continue;
2636
2637 HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(i);
2638 CRASSERT(hFb);
2639 CrFbUpdateEnd(hFb);
2640 }
2641}
2642
2643int CrPMgrResize(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM, const uint32_t *pTargetMap)
2644{
2645 int rc = VINF_SUCCESS;
2646
2647 if (pScreen->u32ViewIndex == 0xffffffff)
2648 {
2649 /* this is just a request to disable targets, search and disable */
2650 for (int i = ASMBitFirstSet(pTargetMap, cr_server.screenCount);
2651 i >= 0;
2652 i = ASMBitNextSet(pTargetMap, cr_server.screenCount, i))
2653 {
2654 CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
2655 if (pDpInfo->iFb < 0)
2656 continue;
2657
2658 Assert(pDpInfo->iFb < cr_server.screenCount);
2659 HCR_FRAMEBUFFER hAssignedFb = CrPMgrFbGet(pDpInfo->iFb);
2660
2661 rc = crPMgrFbDisconnectTarget(hAssignedFb, (uint32_t)i);
2662 if (RT_FAILURE(rc))
2663 {
2664 WARN(("crPMgrFbDisconnectTarget failed %d", rc));
2665 return rc;
2666 }
2667 }
2668
2669 return VINF_SUCCESS;
2670 }
2671
2672 HCR_FRAMEBUFFER hFb = CrPMgrFbGet(pScreen->u32ViewIndex);
2673 if (!hFb)
2674 {
2675 WARN(("CrPMgrFbGet failed"));
2676 return VERR_INVALID_PARAMETER;
2677 }
2678
2679 const VBVAINFOSCREEN *pFbScreen = CrFbGetScreenInfo(hFb);
2680 bool fFbInfoChanged = true;
2681
2682 if (!memcmp(pFbScreen, pScreen, sizeof (*pScreen)))
2683 {
2684 if (!pvVRAM || pvVRAM == CrFbGetVRAM(hFb))
2685 fFbInfoChanged = false;
2686 }
2687
2688 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[pScreen->u32ViewIndex];
2689
2690 VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aRemovedTargetMap);
2691 VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aAddedTargetMap);
2692
2693 bool fDisplaysAdded = false, fDisplaysRemoved = false;
2694
2695 memcpy(aRemovedTargetMap, pFbInfo->aTargetMap, sizeof (aRemovedTargetMap));
2696
2697 if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)
2698 {
2699 /* so far there is no need in keeping displays attached to disabled Framebffer,
2700 * just disconnect everything */
2701 for (int i = 0; i < RT_ELEMENTS(aRemovedTargetMap); ++i)
2702 {
2703 if (aRemovedTargetMap[i])
2704 {
2705 fDisplaysRemoved = true;
2706 break;
2707 }
2708 }
2709
2710 memset(aAddedTargetMap, 0, sizeof (aAddedTargetMap));
2711 }
2712 else
2713 {
2714 for (int i = 0; i < RT_ELEMENTS(aRemovedTargetMap); ++i)
2715 {
2716 aRemovedTargetMap[i] = (aRemovedTargetMap[i] & ~pTargetMap[i]);
2717 if (aRemovedTargetMap[i])
2718 fDisplaysRemoved = true;
2719 }
2720
2721 memcpy(aAddedTargetMap, pFbInfo->aTargetMap, sizeof (aAddedTargetMap));
2722 for (int i = 0; i < RT_ELEMENTS(aAddedTargetMap); ++i)
2723 {
2724 aAddedTargetMap[i] = (pTargetMap[i] & ~aAddedTargetMap[i]);
2725 if (aAddedTargetMap[i])
2726 fDisplaysAdded = true;
2727 }
2728 }
2729
2730 if (!fFbInfoChanged && !fDisplaysRemoved && !fDisplaysAdded)
2731 {
2732 crDebug("resize: no changes");
2733 return VINF_SUCCESS;
2734 }
2735
2736 if (fDisplaysRemoved)
2737 {
2738 rc = crPMgrFbDisconnect(hFb, aRemovedTargetMap);
2739 if (RT_FAILURE(rc))
2740 {
2741 WARN(("crPMgrFbDisconnect failed %d", rc));
2742 return rc;
2743 }
2744 }
2745
2746 if (fFbInfoChanged)
2747 {
2748#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
2749 rc = crPMgrModeModify(hFb, 0, CR_PMGR_MODE_WINDOW | CR_PMGR_MODE_ROOTVR);
2750 if (!RT_SUCCESS(rc))
2751 {
2752 WARN(("crPMgrModeModifyTarget failed %d", rc));
2753 return rc;
2754 }
2755#endif
2756 rc = CrFbUpdateBegin(hFb);
2757 if (!RT_SUCCESS(rc))
2758 {
2759 WARN(("CrFbUpdateBegin failed %d", rc));
2760 return rc;
2761 }
2762
2763 crVBoxServerMuralFbResizeBegin(hFb);
2764
2765 rc = CrFbResize(hFb, pScreen, pvVRAM);
2766 if (!RT_SUCCESS(rc))
2767 {
2768 WARN(("CrFbResize failed %d", rc));
2769 }
2770
2771 crVBoxServerMuralFbResizeEnd(hFb);
2772
2773 CrFbUpdateEnd(hFb);
2774 }
2775
2776 if (fDisplaysAdded)
2777 {
2778 rc = crPMgrFbConnect(hFb, aAddedTargetMap);
2779 if (RT_FAILURE(rc))
2780 {
2781 WARN(("crPMgrFbConnect failed %d", rc));
2782 return rc;
2783 }
2784 }
2785
2786 return VINF_SUCCESS;
2787}
2788
2789int CrFbEntrySaveState(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY *hEntry, PSSMHANDLE pSSM)
2790{
2791 const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrFbEntryGetCompositorEntry(hEntry);
2792 CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2793 CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData);
2794 int rc = SSMR3PutU32(pSSM, pFbTex->pTobj->id);
2795 AssertRCReturn(rc, rc);
2796 uint32_t u32 = 0;
2797
2798 u32 = CrVrScrCompositorEntryFlagsGet(pEntry);
2799 rc = SSMR3PutU32(pSSM, u32);
2800 AssertRCReturn(rc, rc);
2801
2802 const RTRECT *pRect = CrVrScrCompositorEntryRectGet(pEntry);
2803
2804 rc = SSMR3PutS32(pSSM, pRect->xLeft);
2805 AssertRCReturn(rc, rc);
2806 rc = SSMR3PutS32(pSSM, pRect->yTop);
2807 AssertRCReturn(rc, rc);
2808#if 0
2809 rc = SSMR3PutS32(pSSM, pRect->xRight);
2810 AssertRCReturn(rc, rc);
2811 rc = SSMR3PutS32(pSSM, pRect->yBottom);
2812 AssertRCReturn(rc, rc);
2813#endif
2814
2815 rc = CrVrScrCompositorEntryRegionsGet(&pFb->Compositor, pEntry, &u32, NULL, NULL, &pRect);
2816 AssertRCReturn(rc, rc);
2817
2818 rc = SSMR3PutU32(pSSM, u32);
2819 AssertRCReturn(rc, rc);
2820
2821 if (u32)
2822 {
2823 rc = SSMR3PutMem(pSSM, pRect, u32 * sizeof (*pRect));
2824 AssertRCReturn(rc, rc);
2825 }
2826 return rc;
2827}
2828
2829int CrFbSaveState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM)
2830{
2831 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
2832 CrVrScrCompositorConstIterInit(&pFb->Compositor, &Iter);
2833 const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
2834 uint32_t u32 = 0;
2835 while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL)
2836 {
2837 CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2838 CRASSERT(pTexData);
2839 CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData);
2840 if (pFbTex->pTobj)
2841 ++u32;
2842 }
2843
2844 int rc = SSMR3PutU32(pSSM, u32);
2845 AssertRCReturn(rc, rc);
2846
2847 CrVrScrCompositorConstIterInit(&pFb->Compositor, &Iter);
2848
2849 while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL)
2850 {
2851 CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2852 CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData);
2853 if (pFbTex->pTobj)
2854 {
2855 HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry);
2856 rc = CrFbEntrySaveState(pFb, hEntry, pSSM);
2857 AssertRCReturn(rc, rc);
2858 }
2859 }
2860
2861 return VINF_SUCCESS;
2862}
2863
2864int CrPMgrSaveState(PSSMHANDLE pSSM)
2865{
2866 int rc;
2867 int cDisplays = 0, i;
2868
2869 for (i = 0; i < cr_server.screenCount; ++i)
2870 {
2871 if (CrPMgrFbGetEnabled(i))
2872 ++cDisplays;
2873 }
2874
2875 rc = SSMR3PutS32(pSSM, cDisplays);
2876 AssertRCReturn(rc, rc);
2877
2878 if (!cDisplays)
2879 return VINF_SUCCESS;
2880
2881 rc = SSMR3PutS32(pSSM, cr_server.screenCount);
2882 AssertRCReturn(rc, rc);
2883
2884 for (i = 0; i < cr_server.screenCount; ++i)
2885 {
2886 CR_FRAMEBUFFER *hFb = CrPMgrFbGetEnabled(i);
2887 if (hFb)
2888 {
2889 Assert(hFb->ScreenInfo.u32ViewIndex == i);
2890 rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32ViewIndex);
2891 AssertRCReturn(rc, rc);
2892
2893 rc = SSMR3PutS32(pSSM, hFb->ScreenInfo.i32OriginX);
2894 AssertRCReturn(rc, rc);
2895
2896 rc = SSMR3PutS32(pSSM, hFb->ScreenInfo.i32OriginY);
2897 AssertRCReturn(rc, rc);
2898
2899 rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32StartOffset);
2900 AssertRCReturn(rc, rc);
2901
2902 rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32LineSize);
2903 AssertRCReturn(rc, rc);
2904
2905 rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32Width);
2906 AssertRCReturn(rc, rc);
2907
2908 rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32Height);
2909 AssertRCReturn(rc, rc);
2910
2911 rc = SSMR3PutU16(pSSM, hFb->ScreenInfo.u16BitsPerPixel);
2912 AssertRCReturn(rc, rc);
2913
2914 rc = SSMR3PutU16(pSSM, hFb->ScreenInfo.u16Flags);
2915 AssertRCReturn(rc, rc);
2916
2917 rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32StartOffset);
2918 AssertRCReturn(rc, rc);
2919
2920 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[hFb->ScreenInfo.u32ViewIndex];
2921 rc = SSMR3PutMem(pSSM, pFbInfo->aTargetMap, sizeof (pFbInfo->aTargetMap));
2922 AssertRCReturn(rc, rc);
2923
2924 rc = CrFbSaveState(hFb, pSSM);
2925 AssertRCReturn(rc, rc);
2926 }
2927 }
2928
2929 return VINF_SUCCESS;
2930}
2931
2932int CrFbEntryLoadState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM, uint32_t version)
2933{
2934 uint32_t texture;
2935 int rc = SSMR3GetU32(pSSM, &texture);
2936 AssertRCReturn(rc, rc);
2937
2938 uint32_t fFlags;
2939 rc = SSMR3GetU32(pSSM, &fFlags);
2940 AssertRCReturn(rc, rc);
2941
2942
2943 HCR_FRAMEBUFFER_ENTRY hEntry;
2944
2945 rc = CrFbEntryCreateForTexId(pFb, texture, fFlags, &hEntry);
2946 if (!RT_SUCCESS(rc))
2947 {
2948 WARN(("CrFbEntryCreateForTexId Failed"));
2949 return rc;
2950 }
2951
2952 Assert(hEntry);
2953
2954 const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrFbEntryGetCompositorEntry(hEntry);
2955 CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2956 CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData);
2957
2958 RTPOINT Point;
2959 rc = SSMR3GetS32(pSSM, &Point.x);
2960 AssertRCReturn(rc, rc);
2961
2962 rc = SSMR3GetS32(pSSM, &Point.y);
2963 AssertRCReturn(rc, rc);
2964
2965 uint32_t cRects;
2966 rc = SSMR3GetU32(pSSM, &cRects);
2967 AssertRCReturn(rc, rc);
2968
2969 RTRECT * pRects = NULL;
2970 if (cRects)
2971 {
2972 pRects = (RTRECT *)crAlloc(cRects * sizeof (*pRects));
2973 AssertReturn(pRects, VERR_NO_MEMORY);
2974
2975 rc = SSMR3GetMem(pSSM, pRects, cRects * sizeof (*pRects));
2976 AssertRCReturn(rc, rc);
2977 }
2978
2979 rc = CrFbEntryRegionsSet(pFb, hEntry, &Point, cRects, pRects, false);
2980 AssertRCReturn(rc, rc);
2981
2982 if (pRects)
2983 crFree(pRects);
2984
2985 CrFbEntryRelease(pFb, hEntry);
2986
2987 return VINF_SUCCESS;
2988}
2989
2990int CrFbLoadState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM, uint32_t version)
2991{
2992 uint32_t u32 = 0;
2993 int rc = SSMR3GetU32(pSSM, &u32);
2994 AssertRCReturn(rc, rc);
2995
2996 if (!u32)
2997 return VINF_SUCCESS;
2998
2999 rc = CrFbUpdateBegin(pFb);
3000 AssertRCReturn(rc, rc);
3001
3002 for (uint32_t i = 0; i < u32; ++i)
3003 {
3004 rc = CrFbEntryLoadState(pFb, pSSM, version);
3005 AssertRCReturn(rc, rc);
3006 }
3007
3008 CrFbUpdateEnd(pFb);
3009
3010 return VINF_SUCCESS;
3011}
3012
3013int CrPMgrLoadState(PSSMHANDLE pSSM, uint32_t version)
3014{
3015 int rc;
3016 int cDisplays, screenCount, i;
3017
3018 rc = SSMR3GetS32(pSSM, &cDisplays);
3019 AssertRCReturn(rc, rc);
3020
3021 if (!cDisplays)
3022 return VINF_SUCCESS;
3023
3024 rc = SSMR3GetS32(pSSM, &screenCount);
3025 AssertRCReturn(rc, rc);
3026
3027 CRASSERT(screenCount == cr_server.screenCount);
3028
3029 CRScreenInfo screen[CR_MAX_GUEST_MONITORS];
3030
3031 if (version < SHCROGL_SSM_VERSION_WITH_FB_INFO)
3032 {
3033 for (i = 0; i < cr_server.screenCount; ++i)
3034 {
3035 rc = SSMR3GetS32(pSSM, &screen[i].x);
3036 AssertRCReturn(rc, rc);
3037
3038 rc = SSMR3GetS32(pSSM, &screen[i].y);
3039 AssertRCReturn(rc, rc);
3040
3041 rc = SSMR3GetU32(pSSM, &screen[i].w);
3042 AssertRCReturn(rc, rc);
3043
3044 rc = SSMR3GetU32(pSSM, &screen[i].h);
3045 AssertRCReturn(rc, rc);
3046 }
3047 }
3048
3049 for (i = 0; i < cDisplays; ++i)
3050 {
3051 int iScreen;
3052
3053 rc = SSMR3GetS32(pSSM, &iScreen);
3054 AssertRCReturn(rc, rc);
3055
3056 CR_FRAMEBUFFER *pFb = CrPMgrFbGet(iScreen);
3057 Assert(pFb);
3058
3059 VBVAINFOSCREEN Screen;
3060
3061 Screen.u32ViewIndex = iScreen;
3062
3063 VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
3064
3065 memset(aTargetMap, 0, sizeof (aTargetMap));
3066 ASMBitSet(aTargetMap, iScreen);
3067
3068 if (version < SHCROGL_SSM_VERSION_WITH_FB_INFO)
3069 {
3070 memset(&Screen, 0, sizeof (Screen));
3071 Screen.u32LineSize = 4 * screen[iScreen].w;
3072 Screen.u32Width = screen[iScreen].w;
3073 Screen.u32Height = screen[iScreen].h;
3074 Screen.u16BitsPerPixel = 4;
3075 Screen.u16Flags = VBVA_SCREEN_F_ACTIVE;
3076 }
3077 else
3078 {
3079 rc = SSMR3GetS32(pSSM, &Screen.i32OriginX);
3080 AssertRCReturn(rc, rc);
3081
3082 rc = SSMR3GetS32(pSSM, &Screen.i32OriginY);
3083 AssertRCReturn(rc, rc);
3084
3085 rc = SSMR3GetU32(pSSM, &Screen.u32StartOffset);
3086 AssertRCReturn(rc, rc);
3087
3088 rc = SSMR3GetU32(pSSM, &Screen.u32LineSize);
3089 AssertRCReturn(rc, rc);
3090
3091 rc = SSMR3GetU32(pSSM, &Screen.u32Width);
3092 AssertRCReturn(rc, rc);
3093
3094 rc = SSMR3GetU32(pSSM, &Screen.u32Height);
3095 AssertRCReturn(rc, rc);
3096
3097 rc = SSMR3GetU16(pSSM, &Screen.u16BitsPerPixel);
3098 AssertRCReturn(rc, rc);
3099
3100 rc = SSMR3GetU16(pSSM, &Screen.u16Flags);
3101 AssertRCReturn(rc, rc);
3102
3103 rc = SSMR3GetU32(pSSM, &Screen.u32StartOffset);
3104 AssertRCReturn(rc, rc);
3105 if (Screen.u32StartOffset == 0xffffffff)
3106 {
3107 WARN(("not expected offVram"));
3108 Screen.u32StartOffset = 0;
3109 }
3110
3111 if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_MAP_REORDERED)
3112 {
3113 rc = SSMR3GetMem(pSSM, aTargetMap, sizeof (aTargetMap));
3114 AssertRCReturn(rc, rc);
3115 }
3116
3117 if (version == SHCROGL_SSM_VERSION_WITH_SCREEN_MAP)
3118 {
3119 VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aEmptyTargetMap);
3120
3121 memset(aEmptyTargetMap, 0, sizeof (aEmptyTargetMap));
3122
3123 rc = CrPMgrResize(&Screen, cr_server.fCrCmdEnabled ? NULL : CrFbGetVRAM(pFb), aEmptyTargetMap);
3124 AssertRCReturn(rc, rc);
3125
3126 rc = CrFbLoadState(pFb, pSSM, version);
3127 AssertRCReturn(rc, rc);
3128
3129 rc = SSMR3GetMem(pSSM, aTargetMap, sizeof (aTargetMap));
3130 AssertRCReturn(rc, rc);
3131 }
3132 }
3133
3134 rc = CrPMgrResize(&Screen, cr_server.fCrCmdEnabled ? NULL : CrFbGetVRAM(pFb), aTargetMap);
3135 AssertRCReturn(rc, rc);
3136
3137 if (version >= SHCROGL_SSM_VERSION_WITH_FB_INFO && version != SHCROGL_SSM_VERSION_WITH_SCREEN_MAP)
3138 {
3139 rc = CrFbLoadState(pFb, pSSM, version);
3140 AssertRCReturn(rc, rc);
3141 }
3142 }
3143
3144 return VINF_SUCCESS;
3145}
3146
3147
3148void SERVER_DISPATCH_APIENTRY
3149crServerDispatchVBoxTexPresent(GLuint texture, GLuint cfg, GLint xPos, GLint yPos, GLint cRects, const GLint *pRects)
3150{
3151 uint32_t idFb = CR_PRESENT_GET_SCREEN(cfg);
3152 if (idFb >= CR_MAX_GUEST_MONITORS)
3153 {
3154 WARN(("Invalid guest screen"));
3155 return;
3156 }
3157
3158 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(idFb);
3159 if (!hFb)
3160 {
3161 WARN(("request to present on disabled framebuffer, ignore"));
3162 return;
3163 }
3164
3165 HCR_FRAMEBUFFER_ENTRY hEntry;
3166 int rc;
3167 if (texture)
3168 {
3169 rc = CrFbEntryCreateForTexId(hFb, texture, (cfg & CR_PRESENT_FLAG_TEX_NONINVERT_YCOORD) ? 0 : CRBLT_F_INVERT_SRC_YCOORDS, &hEntry);
3170 if (!RT_SUCCESS(rc))
3171 {
3172 LOG(("CrFbEntryCreateForTexId Failed"));
3173 return;
3174 }
3175
3176 Assert(hEntry);
3177
3178#if 0
3179 if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS))
3180 {
3181 CR_SERVER_DUMP_TEXPRESENT(&pEntry->CEntry.Tex);
3182 }
3183#endif
3184 }
3185 else
3186 hEntry = NULL;
3187
3188 rc = CrFbUpdateBegin(hFb);
3189 if (RT_SUCCESS(rc))
3190 {
3191 if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS))
3192 {
3193 RTPOINT Point = {xPos, yPos};
3194 rc = CrFbEntryRegionsAdd(hFb, hEntry, &Point, (uint32_t)cRects, (const RTRECT*)pRects, false);
3195 }
3196 else
3197 {
3198 CrFbRegionsClear(hFb);
3199 }
3200
3201 CrFbUpdateEnd(hFb);
3202 }
3203 else
3204 {
3205 WARN(("CrFbUpdateBegin Failed"));
3206 }
3207
3208 if (hEntry)
3209 CrFbEntryRelease(hFb, hEntry);
3210}
3211
3212DECLINLINE(void) crVBoxPRectUnpack(const VBOXCMDVBVA_RECT *pVbvaRect, RTRECT *pRect)
3213{
3214 pRect->xLeft = pVbvaRect->xLeft;
3215 pRect->yTop = pVbvaRect->yTop;
3216 pRect->xRight = pVbvaRect->xRight;
3217 pRect->yBottom = pVbvaRect->yBottom;
3218}
3219
3220DECLINLINE(void) crVBoxPRectUnpacks(const VBOXCMDVBVA_RECT *paVbvaRects, RTRECT *paRects, uint32_t cRects)
3221{
3222 uint32_t i = 0;
3223 for (; i < cRects; ++i)
3224 {
3225 crVBoxPRectUnpack(&paVbvaRects[i], &paRects[i]);
3226 }
3227}
3228
3229static RTRECT * crVBoxServerCrCmdBltRecsUnpack(const VBOXCMDVBVA_RECT *pPRects, uint32_t cRects)
3230{
3231 if (g_CrPresenter.cbTmpBuf < cRects * sizeof (RTRECT))
3232 {
3233 if (g_CrPresenter.pvTmpBuf)
3234 RTMemFree(g_CrPresenter.pvTmpBuf);
3235
3236 g_CrPresenter.cbTmpBuf = (cRects + 10) * sizeof (RTRECT);
3237 g_CrPresenter.pvTmpBuf = RTMemAlloc(g_CrPresenter.cbTmpBuf);
3238 if (!g_CrPresenter.pvTmpBuf)
3239 {
3240 WARN(("RTMemAlloc failed!"));
3241 g_CrPresenter.cbTmpBuf = 0;
3242 return NULL;
3243 }
3244 }
3245
3246 RTRECT *pRects = (RTRECT *)g_CrPresenter.pvTmpBuf;
3247 crVBoxPRectUnpacks(pPRects, pRects, cRects);
3248
3249 return pRects;
3250}
3251
3252static void crPMgrPrimaryUpdateScreen(HCR_FRAMEBUFFER hFb, uint32_t idScreen, uint32_t cRects, const RTRECT *pRects)
3253{
3254 const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
3255
3256 bool fDirtyEmpty = true;
3257 RTRECT dirtyRect = {0};
3258 cr_server.CrCmdClientInfo.pfnCltScrUpdateBegin(cr_server.CrCmdClientInfo.hCltScr, idScreen);
3259
3260 VBVACMDHDR hdr;
3261 for (uint32_t i = 0; i < cRects; ++i)
3262 {
3263 hdr.x = pRects[i].xLeft;
3264 hdr.y = pRects[i].yTop;
3265 hdr.w = hdr.x + pRects[i].xRight;
3266 hdr.h = hdr.y + pRects[i].yBottom;
3267
3268 cr_server.CrCmdClientInfo.pfnCltScrUpdateProcess(cr_server.CrCmdClientInfo.hCltScr, idScreen, &hdr, sizeof (hdr));
3269
3270 if (fDirtyEmpty)
3271 {
3272 /* This is the first rectangle to be added. */
3273 dirtyRect.xLeft = pRects[i].xLeft;
3274 dirtyRect.yTop = pRects[i].yTop;
3275 dirtyRect.xRight = pRects[i].xRight;
3276 dirtyRect.yBottom = pRects[i].yBottom;
3277 fDirtyEmpty = false;
3278 }
3279 else
3280 {
3281 /* Adjust region coordinates. */
3282 if (dirtyRect.xLeft > pRects[i].xLeft)
3283 {
3284 dirtyRect.xLeft = pRects[i].xLeft;
3285 }
3286
3287 if (dirtyRect.yTop > pRects[i].yTop)
3288 {
3289 dirtyRect.yTop = pRects[i].yTop;
3290 }
3291
3292 if (dirtyRect.xRight < pRects[i].xRight)
3293 {
3294 dirtyRect.xRight = pRects[i].xRight;
3295 }
3296
3297 if (dirtyRect.yBottom < pRects[i].yBottom)
3298 {
3299 dirtyRect.yBottom = pRects[i].yBottom;
3300 }
3301 }
3302 }
3303
3304 if (dirtyRect.xRight - dirtyRect.xLeft)
3305 {
3306 cr_server.CrCmdClientInfo.pfnCltScrUpdateEnd(cr_server.CrCmdClientInfo.hCltScr, idScreen, pScreen->i32OriginX + dirtyRect.xLeft, pScreen->i32OriginY + dirtyRect.yTop,
3307 dirtyRect.xRight - dirtyRect.xLeft, dirtyRect.yBottom - dirtyRect.yTop);
3308 }
3309 else
3310 {
3311 cr_server.CrCmdClientInfo.pfnCltScrUpdateEnd(cr_server.CrCmdClientInfo.hCltScr, idScreen, 0, 0, 0, 0);
3312 }
3313
3314}
3315
3316static void crPMgrPrimaryUpdate(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects)
3317{
3318 if (!cRects)
3319 return;
3320
3321 const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
3322
3323 uint32_t idFb = pScreen->u32ViewIndex;
3324 CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
3325
3326 for (int i = ASMBitFirstSet(pFbInfo->aTargetMap, cr_server.screenCount);
3327 i >= 0;
3328 i = ASMBitNextSet(pFbInfo->aTargetMap, cr_server.screenCount, i))
3329 {
3330 crPMgrPrimaryUpdateScreen(hFb, i, cRects, pRects);
3331 }
3332}
3333
3334static int8_t crVBoxServerCrCmdBltPrimaryVramGenericProcess(uint32_t u32PrimaryID, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, bool fToPrimary)
3335{
3336 CR_BLITTER_IMG Img;
3337 int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img);
3338 if (i8Result)
3339 {
3340 WARN(("invalid param"));
3341 return -1;
3342 }
3343
3344 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32PrimaryID);
3345 if (!hFb)
3346 {
3347 WARN(("request to present on disabled framebuffer"));
3348 return -1;
3349 }
3350
3351 if (!fToPrimary)
3352 {
3353 int rc = CrFbBltGetContents(hFb, pPos, cRects, pRects, &Img);
3354 if (!RT_SUCCESS(rc))
3355 {
3356 WARN(("CrFbBltGetContents failed %d", rc));
3357 return -1;
3358 }
3359
3360 return 0;
3361 }
3362
3363 int rc = CrFbBltPutContentsNe(hFb, pPos, cRects, pRects, &Img);
3364 if (!RT_SUCCESS(rc))
3365 {
3366 WARN(("CrFbBltPutContentsNe failed %d", rc));
3367 return -1;
3368 }
3369
3370 return 0;
3371}
3372
3373static int8_t crVBoxServerCrCmdBltPrimaryProcess(const VBOXCMDVBVA_BLT_PRIMARY *pCmd, uint32_t cbCmd)
3374{
3375 uint32_t u32PrimaryID = (uint32_t)pCmd->Hdr.Hdr.u.u8PrimaryID;
3376 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32PrimaryID);
3377 if (!hFb)
3378 {
3379 WARN(("request to present on disabled framebuffer, ignore"));
3380 return 0;
3381 }
3382
3383 uint32_t cRects;
3384 const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
3385 if ((cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) % sizeof (VBOXCMDVBVA_RECT))
3386 {
3387 WARN(("invalid argument size"));
3388 return -1;
3389 }
3390
3391 cRects = (cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) / sizeof (VBOXCMDVBVA_RECT);
3392
3393 RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
3394 if (!pRects)
3395 {
3396 WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
3397 return -1;
3398 }
3399
3400 uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
3401
3402 if (u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID)
3403 {
3404 uint32_t texId = pCmd->alloc.u.id;
3405 if (!texId)
3406 {
3407 WARN(("texId is NULL!\n"));
3408 return -1;
3409 }
3410
3411 if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
3412 {
3413 WARN(("blit from primary to texture not implemented"));
3414 return -1;
3415 }
3416
3417 crServerDispatchVBoxTexPresent(texId, u32PrimaryID, pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y, cRects, (const GLint*)pRects);
3418
3419 return 0;
3420 }
3421 else
3422 {
3423 const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
3424 uint32_t width = pScreen->u32Width, height = pScreen->u32Height;
3425 VBOXCMDVBVAOFFSET offVRAM = pCmd->alloc.u.offVRAM;
3426
3427 bool fToPrymary = !(u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2);
3428 RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
3429 int8_t i8Result = crVBoxServerCrCmdBltPrimaryVramGenericProcess(u32PrimaryID, offVRAM, width, height, &Pos, cRects, pRects, fToPrymary);
3430 if (i8Result < 0)
3431 {
3432 WARN(("crVBoxServerCrCmdBltPrimaryVramGenericProcess failed"));
3433 return i8Result;
3434 }
3435
3436 if (!fToPrymary)
3437 return 0;
3438 }
3439
3440 crPMgrPrimaryUpdate(hFb, cRects, pRects);
3441
3442 return 0;
3443}
3444
3445static int8_t crVBoxServerCrCmdBltIdToVramMem(uint32_t hostId, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects)
3446{
3447 CR_TEXDATA* pTex = CrFbTexDataAcquire(hostId);
3448 if (!pTex)
3449 {
3450 WARN(("pTex failed for %d", hostId));
3451 return -1;
3452 }
3453
3454 const VBOXVR_TEXTURE *pVrTex = CrTdTexGet(pTex);
3455 if (!width)
3456 {
3457 width = pVrTex->width;
3458 height = pVrTex->height;
3459 }
3460
3461 CR_BLITTER_IMG Img;
3462 int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img);
3463 if (i8Result)
3464 {
3465 WARN(("invalid param"));
3466 return -1;
3467 }
3468
3469 int rc = CrTdBltEnter(pTex);
3470 if (!RT_SUCCESS(rc))
3471 {
3472 WARN(("CrTdBltEnter failed %d", rc));
3473 return -1;
3474 }
3475
3476 rc = crFbTexDataGetContents(pTex, pPos, cRects, pRects, &Img);
3477
3478 CrTdBltLeave(pTex);
3479
3480 CrTdRelease(pTex);
3481
3482 if (!RT_SUCCESS(rc))
3483 {
3484 WARN(("crFbTexDataGetContents failed %d", rc));
3485 return -1;
3486 }
3487
3488 return 0;
3489}
3490
3491static int8_t crVBoxServerCrCmdBltIdToVram(uint32_t hostId, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects)
3492{
3493 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabledByVramStart(offVRAM);
3494 if (hFb)
3495 {
3496 const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
3497 Assert(!width || pScreen->u32Width == width);
3498 Assert(!height || pScreen->u32Height == height);
3499
3500 crServerDispatchVBoxTexPresent(hostId, pScreen->u32ViewIndex, pPos->x, pPos->y, cRects, (const GLint*)pRects);
3501 return 0;
3502 }
3503
3504 return crVBoxServerCrCmdBltIdToVramMem(hostId, offVRAM, width, height, pPos, cRects, pRects);
3505}
3506
3507static int8_t crVBoxServerCrCmdBltVramToVramMem(VBOXCMDVBVAOFFSET offSrcVRAM, uint32_t srcWidth, uint32_t srcHeight, VBOXCMDVBVAOFFSET offDstVRAM, uint32_t dstWidth, uint32_t dstHeight, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects)
3508{
3509 CR_BLITTER_IMG srcImg, dstImg;
3510 int8_t i8Result = crFbImgFromDimOffVramBGRA(offSrcVRAM, srcWidth, srcHeight, &srcImg);
3511 if (i8Result)
3512 {
3513 WARN(("invalid param"));
3514 return -1;
3515 }
3516
3517 i8Result = crFbImgFromDimOffVramBGRA(offDstVRAM, dstWidth, dstHeight, &dstImg);
3518 if (i8Result)
3519 {
3520 WARN(("invalid param"));
3521 return -1;
3522 }
3523
3524 CrMBltImg(&srcImg, pPos, cRects, pRects, &dstImg);
3525
3526 return 0;
3527}
3528
3529static int8_t crVBoxServerCrCmdBltVramToVram(VBOXCMDVBVAOFFSET offSrcVRAM, uint32_t srcWidth, uint32_t srcHeight,
3530 VBOXCMDVBVAOFFSET offDstVRAM, uint32_t dstWidth, uint32_t dstHeight,
3531 const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects)
3532{
3533 HCR_FRAMEBUFFER hSrcFb = CrPMgrFbGetEnabledByVramStart(offSrcVRAM);
3534 HCR_FRAMEBUFFER hDstFb = CrPMgrFbGetEnabledByVramStart(offDstVRAM);
3535
3536 if (hDstFb)
3537 {
3538 if (hSrcFb)
3539 {
3540 LOG(("blit from one framebuffer, wow"));
3541
3542 int rc = CrFbUpdateBegin(hSrcFb);
3543 if (RT_SUCCESS(rc))
3544 {
3545 CrFbRegionsClear(hSrcFb);
3546
3547 CrFbUpdateEnd(hSrcFb);
3548 }
3549 else
3550 WARN(("CrFbUpdateBegin failed %d", rc));
3551 }
3552
3553 CR_BLITTER_IMG Img;
3554 int8_t i8Result = crFbImgFromDimOffVramBGRA(offSrcVRAM, srcWidth, srcHeight, &Img);
3555 if (i8Result)
3556 {
3557 WARN(("invalid param"));
3558 return -1;
3559 }
3560
3561 const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hDstFb);
3562 if (pScreen->u32Width == dstWidth && pScreen->u32Height == dstHeight)
3563 {
3564 int rc = CrFbBltPutContentsNe(hDstFb, pPos, cRects, pRects, &Img);
3565 if (RT_FAILURE(rc))
3566 {
3567 WARN(("CrFbBltPutContentsNe failed %d", rc));
3568 return -1;
3569 }
3570 }
3571 else
3572 {
3573 int rc = CrFbUpdateBegin(hDstFb);
3574 if (RT_SUCCESS(rc))
3575 {
3576 CrFbRegionsClear(hDstFb);
3577
3578 CrFbUpdateEnd(hDstFb);
3579 }
3580 else
3581 WARN(("CrFbUpdateBegin failed %d", rc));
3582
3583 rc = crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects);
3584 if (RT_FAILURE(rc))
3585 {
3586 WARN(("crVBoxServerCrCmdBltVramToVramMem failed, %d", rc));
3587 return -1;
3588 }
3589 }
3590
3591 crPMgrPrimaryUpdate(hDstFb, cRects, pRects);
3592
3593 return 0;
3594 }
3595 else if (hSrcFb)
3596 {
3597 CR_BLITTER_IMG Img;
3598 int8_t i8Result = crFbImgFromDimOffVramBGRA(offDstVRAM, dstWidth, dstHeight, &Img);
3599 if (i8Result)
3600 {
3601 WARN(("invalid param"));
3602 return -1;
3603 }
3604
3605 const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hSrcFb);
3606 if (pScreen->u32Width == srcWidth && pScreen->u32Height == srcHeight)
3607 {
3608 int rc = CrFbBltGetContents(hSrcFb, pPos, cRects, pRects, &Img);
3609 if (RT_FAILURE(rc))
3610 {
3611 WARN(("CrFbBltGetContents failed %d", rc));
3612 return -1;
3613 }
3614 }
3615 else
3616 {
3617 int rc = CrFbUpdateBegin(hSrcFb);
3618 if (RT_SUCCESS(rc))
3619 {
3620 CrFbRegionsClear(hSrcFb);
3621
3622 CrFbUpdateEnd(hSrcFb);
3623 }
3624 else
3625 WARN(("CrFbUpdateBegin failed %d", rc));
3626
3627 rc = crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects);
3628 if (RT_FAILURE(rc))
3629 {
3630 WARN(("crVBoxServerCrCmdBltVramToVramMem failed, %d", rc));
3631 return -1;
3632 }
3633 }
3634
3635 return 0;
3636 }
3637
3638 return crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects);
3639}
3640
3641
3642static int8_t crVBoxServerCrCmdBltOffIdProcess(const VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID *pCmd, uint32_t cbCmd)
3643{
3644 uint32_t cRects;
3645 const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
3646 if ((cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, aRects)) % sizeof (VBOXCMDVBVA_RECT))
3647 {
3648 WARN(("invalid argument size"));
3649 return -1;
3650 }
3651
3652 cRects = (cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, aRects)) / sizeof (VBOXCMDVBVA_RECT);
3653
3654 RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
3655 if (!pRects)
3656 {
3657 WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
3658 return -1;
3659 }
3660
3661 uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
3662 uint32_t hostId = pCmd->id;
3663
3664 Assert(u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID);
3665
3666 if (!hostId)
3667 {
3668 WARN(("zero host id"));
3669 return -1;
3670 }
3671
3672 if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
3673 {
3674 WARN(("blit from texture to texture not implemented"));
3675 return -1;
3676 }
3677
3678 if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
3679 {
3680 WARN(("blit to texture not implemented"));
3681 return -1;
3682 }
3683
3684 VBOXCMDVBVAOFFSET offVRAM = pCmd->alloc.u.offVRAM;
3685
3686 RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
3687 return crVBoxServerCrCmdBltIdToVram(hostId, offVRAM, 0, 0, &Pos, cRects, pRects);
3688}
3689
3690static int8_t crVBoxServerCrCmdBltSameDimOrId(const VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8 *pCmd, uint32_t cbCmd)
3691{
3692 uint32_t cRects;
3693 const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
3694 if ((cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8, aRects)) % sizeof (VBOXCMDVBVA_RECT))
3695 {
3696 WARN(("invalid argument size"));
3697 return -1;
3698 }
3699
3700 cRects = (cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8, aRects)) / sizeof (VBOXCMDVBVA_RECT);
3701
3702 RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
3703 if (!pRects)
3704 {
3705 WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
3706 return -1;
3707 }
3708
3709 uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
3710 VBOXCMDVBVAOFFSET offVRAM = pCmd->alloc1.Info.u.offVRAM;
3711 uint32_t width = pCmd->alloc1.u16Width;
3712 uint32_t height = pCmd->alloc1.u16Height;
3713 RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
3714
3715 if (u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID)
3716 {
3717 uint32_t hostId = pCmd->info2.u.id;
3718
3719 if (!hostId)
3720 {
3721 WARN(("zero host id"));
3722 return -1;
3723 }
3724
3725 if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
3726 {
3727 WARN(("blit from texture to texture not implemented"));
3728 return -1;
3729 }
3730
3731 if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
3732 {
3733 WARN(("blit to texture not implemented"));
3734 return -1;
3735 }
3736
3737 return crVBoxServerCrCmdBltIdToVram(hostId, offVRAM, width, height, &Pos, cRects, pRects);
3738 }
3739
3740 if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
3741 {
3742 if (!(u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2))
3743 {
3744 WARN(("blit to texture not implemented"));
3745 return -1;
3746 }
3747
3748 return crVBoxServerCrCmdBltIdToVram(pCmd->alloc1.Info.u.id, pCmd->info2.u.offVRAM, width, height, &Pos, cRects, pRects);
3749 }
3750
3751 if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
3752 crVBoxServerCrCmdBltVramToVram(offVRAM, width, height, pCmd->info2.u.offVRAM, width, height, &Pos, cRects, pRects);
3753 else
3754 crVBoxServerCrCmdBltVramToVram(pCmd->info2.u.offVRAM, width, height, offVRAM, width, height, &Pos, cRects, pRects);
3755
3756 return 0;
3757}
3758
3759static int8_t crVBoxServerCrCmdBltGenericBGRAProcess(const VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8 *pCmd, uint32_t cbCmd)
3760{
3761 uint32_t cRects;
3762 const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
3763 if ((cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8, aRects)) % sizeof (VBOXCMDVBVA_RECT))
3764 {
3765 WARN(("invalid argument size"));
3766 return -1;
3767 }
3768
3769 cRects = (cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8, aRects)) / sizeof (VBOXCMDVBVA_RECT);
3770
3771 RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
3772 if (!pRects)
3773 {
3774 WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
3775 return -1;
3776 }
3777
3778 uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
3779 RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
3780
3781 if (u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID)
3782 {
3783 if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
3784 {
3785 WARN(("blit from texture to texture not implemented"));
3786 return -1;
3787 }
3788
3789 if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
3790 {
3791 WARN(("blit to texture not implemented"));
3792 return -1;
3793 }
3794
3795 return crVBoxServerCrCmdBltIdToVram(pCmd->alloc2.Info.u.id, pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, &Pos, cRects, pRects);
3796 }
3797 else
3798 {
3799 if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
3800 {
3801 if (!(u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2))
3802 {
3803 WARN(("blit to texture not implemented"));
3804 return -1;
3805 }
3806
3807 RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
3808 return crVBoxServerCrCmdBltIdToVram(pCmd->alloc1.Info.u.id, pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, &Pos, cRects, pRects);
3809 }
3810
3811 if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
3812 crVBoxServerCrCmdBltVramToVram(pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, &Pos, cRects, pRects);
3813 else
3814 crVBoxServerCrCmdBltVramToVram(pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, &Pos, cRects, pRects);
3815
3816 return 0;
3817 }
3818}
3819
3820static int8_t crVBoxServerCrCmdClrFillPrimaryGenericProcess(uint32_t u32PrimaryID, const RTRECT *pRects, uint32_t cRects, uint32_t u32Color)
3821{
3822 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32PrimaryID);
3823 if (!hFb)
3824 {
3825 WARN(("request to present on disabled framebuffer, ignore"));
3826 return 0;
3827 }
3828
3829 int rc = CrFbClrFillNe(hFb, cRects, pRects, u32Color);
3830 if (!RT_SUCCESS(rc))
3831 {
3832 WARN(("CrFbClrFillNe failed %d", rc));
3833 return -1;
3834 }
3835
3836 return 0;
3837}
3838
3839static int8_t crVBoxServerCrCmdClrFillVramGenericProcess(VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTRECT *pRects, uint32_t cRects, uint32_t u32Color)
3840{
3841 CR_BLITTER_IMG Img;
3842 int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img);
3843 if (i8Result)
3844 {
3845 WARN(("invalid param"));
3846 return -1;
3847 }
3848
3849 CrMClrFillImg(&Img, cRects, pRects, u32Color);
3850
3851 return 0;
3852}
3853
3854static int8_t crVBoxServerCrCmdClrFillGenericBGRAProcess(const VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8 *pCmd, uint32_t cbCmd)
3855{
3856 uint32_t cRects;
3857 const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
3858 if ((cbCmd - RT_OFFSETOF(VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8, aRects)) % sizeof (VBOXCMDVBVA_RECT))
3859 {
3860 WARN(("invalid argument size"));
3861 return -1;
3862 }
3863
3864 cRects = (cbCmd - RT_OFFSETOF(VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8, aRects)) / sizeof (VBOXCMDVBVA_RECT);
3865
3866 RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
3867 if (!pRects)
3868 {
3869 WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
3870 return -1;
3871 }
3872
3873// uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
3874 int8_t i8Result = crVBoxServerCrCmdClrFillVramGenericProcess(pCmd->dst.Info.u.offVRAM, pCmd->dst.u16Width, pCmd->dst.u16Height, pRects, cRects, pCmd->Hdr.u32Color);
3875 if (i8Result < 0)
3876 {
3877 WARN(("crVBoxServerCrCmdClrFillVramGenericProcess failed"));
3878 return i8Result;
3879 }
3880
3881 return 0;
3882}
3883
3884int8_t crVBoxServerCrCmdClrFillProcess(const VBOXCMDVBVA_CLRFILL_HDR *pCmd, uint32_t cbCmd)
3885{
3886 uint8_t u8Flags = pCmd->Hdr.u8Flags;
3887 uint8_t u8Cmd = (VBOXCMDVBVA_OPF_CLRFILL_TYPE_MASK & u8Flags);
3888
3889 switch (u8Cmd)
3890 {
3891 case VBOXCMDVBVA_OPF_CLRFILL_TYPE_GENERIC_A8R8G8B8:
3892 {
3893 if (cbCmd < sizeof (VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8))
3894 {
3895 WARN(("VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8: invalid command size"));
3896 return -1;
3897 }
3898
3899 return crVBoxServerCrCmdClrFillGenericBGRAProcess((const VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8*)pCmd, cbCmd);
3900 }
3901 default:
3902 WARN(("unsupported command"));
3903 return -1;
3904 }
3905
3906}
3907
3908int8_t crVBoxServerCrCmdBltProcess(const VBOXCMDVBVA_BLT_HDR *pCmd, uint32_t cbCmd)
3909{
3910 uint8_t u8Flags = pCmd->Hdr.u8Flags;
3911 uint8_t u8Cmd = (VBOXCMDVBVA_OPF_BLT_TYPE_MASK & u8Flags);
3912
3913 switch (u8Cmd)
3914 {
3915 case VBOXCMDVBVA_OPF_BLT_TYPE_SAMEDIM_A8R8G8B8:
3916 {
3917 if (cbCmd < sizeof (VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8))
3918 {
3919 WARN(("VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8: invalid command size"));
3920 return -1;
3921 }
3922
3923 return crVBoxServerCrCmdBltSameDimOrId((const VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8 *)pCmd, cbCmd);
3924 }
3925 case VBOXCMDVBVA_OPF_BLT_TYPE_OFFPRIMSZFMT_OR_ID:
3926 {
3927 if (cbCmd < sizeof (VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID))
3928 {
3929 WARN(("VBOXCMDVBVA_OPF_BLT_TYPE_OFFPRIMSZFMT_OR_ID: invalid command size"));
3930 return -1;
3931 }
3932
3933 return crVBoxServerCrCmdBltOffIdProcess((const VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID *)pCmd, cbCmd);
3934 }
3935 case VBOXCMDVBVA_OPF_BLT_TYPE_GENERIC_A8R8G8B8:
3936 {
3937 if (cbCmd < sizeof (VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8))
3938 {
3939 WARN(("VBOXCMDVBVA_OPF_BLT_TYPE_GENERIC_A8R8G8B8: invalid command size"));
3940 return -1;
3941 }
3942
3943 return crVBoxServerCrCmdBltGenericBGRAProcess((const VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8 *)pCmd, cbCmd);
3944 }
3945 default:
3946 WARN(("unsupported command"));
3947 return -1;
3948 }
3949}
3950
3951int8_t crVBoxServerCrCmdFlipProcess(const VBOXCMDVBVA_FLIP *pFlip)
3952{
3953 uint32_t hostId;
3954 if (pFlip->Hdr.u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
3955 {
3956 hostId = pFlip->src.u.id;
3957 if (!hostId)
3958 {
3959 WARN(("hostId is NULL"));
3960 return -1;
3961 }
3962 }
3963 else
3964 {
3965 WARN(("VBOXCMDVBVA_OPF_ALLOC_SRCID not specified"));
3966 hostId = 0;
3967 }
3968
3969 uint32_t idFb = pFlip->Hdr.u.u8PrimaryID;
3970 HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(idFb);
3971 if (!hFb)
3972 {
3973 WARN(("request to present on disabled framebuffer, ignore"));
3974 return 0;
3975 }
3976
3977 const RTRECT *pRect = CrVrScrCompositorRectGet(&hFb->Compositor);
3978 crServerDispatchVBoxTexPresent(hostId, idFb, 0, 0, 1, (const GLint*)pRect);
3979 return 0;
3980}
3981
3982typedef struct CRSERVER_CLIENT_CALLOUT
3983{
3984 VBOXCRCMDCTL_CALLOUT_LISTENTRY Entry;
3985 PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb;
3986 void*pvCb;
3987} CRSERVER_CLIENT_CALLOUT;
3988
3989static DECLCALLBACK(void) crServerClientCalloutCb(struct VBOXCRCMDCTL_CALLOUT_LISTENTRY *pEntry)
3990{
3991 CRSERVER_CLIENT_CALLOUT *pCallout = RT_FROM_MEMBER(pEntry, CRSERVER_CLIENT_CALLOUT, Entry);
3992 pCallout->pfnCb(pCallout->pvCb);
3993 int rc = RTSemEventSignal(cr_server.hCalloutCompletionEvent);
3994 if (RT_FAILURE(rc))
3995 WARN(("RTSemEventSignal failed rc %d", rc));
3996}
3997
3998static DECLCALLBACK(void) crServerClientCallout(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void*pvCb)
3999{
4000 Assert(cr_server.pCurrentCalloutCtl);
4001 CRSERVER_CLIENT_CALLOUT Callout;
4002 Callout.pfnCb = pfnCb;
4003 Callout.pvCb = pvCb;
4004 cr_server.ClientInfo.pfnCallout(cr_server.ClientInfo.hClient, cr_server.pCurrentCalloutCtl, &Callout.Entry, crServerClientCalloutCb);
4005
4006 int rc = RTSemEventWait(cr_server.hCalloutCompletionEvent, RT_INDEFINITE_WAIT);
4007 if (RT_FAILURE(rc))
4008 WARN(("RTSemEventWait failed %d", rc));
4009}
4010
4011
4012DECLEXPORT(void) crVBoxServerCalloutEnable(VBOXCRCMDCTL *pCtl)
4013{
4014#if 1 //def CR_SERVER_WITH_CLIENT_CALLOUTS
4015 Assert(!cr_server.pCurrentCalloutCtl);
4016 cr_server.pCurrentCalloutCtl = pCtl;
4017
4018 cr_server.head_spu->dispatch_table.ChromiumParametervCR(GL_HH_SET_CLIENT_CALLOUT, 0, 0, (void*)crServerClientCallout);
4019#endif
4020}
4021
4022extern DECLEXPORT(void) crVBoxServerCalloutDisable()
4023{
4024#if 1 //def CR_SERVER_WITH_CLIENT_CALLOUTS
4025 Assert(cr_server.pCurrentCalloutCtl);
4026
4027 cr_server.head_spu->dispatch_table.ChromiumParametervCR(GL_HH_SET_CLIENT_CALLOUT, 0, 0, NULL);
4028
4029 cr_server.pCurrentCalloutCtl = NULL;
4030#endif
4031}
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