VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/vreg.cpp@ 45009

Last change on this file since 45009 was 45009, checked in by vboxsync, 12 years ago

crOpenGL: offscreen rendering & VRDP+3D-related fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.9 KB
Line 
1/* $Id: vreg.cpp 45009 2013-03-12 17:27:04Z vboxsync $ */
2
3/** @file
4 * Visible Regions processing API implementation
5 */
6
7/*
8 * Copyright (C) 2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. 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#include <cr_vreg.h>
19#include <iprt/memcache.h>
20#include <iprt/err.h>
21#include <iprt/assert.h>
22#include <iprt/asm.h>
23
24#ifndef IN_RING0
25#include <cr_error.h>
26#define WARN(_m) do { crWarning _m ; } while (0)
27#else
28# error port me!
29#endif
30
31#ifdef DEBUG_misha
32//# define VBOXVDBG_VR_LAL_DISABLE
33#endif
34
35#ifndef VBOXVDBG_VR_LAL_DISABLE
36static volatile int32_t g_cVBoxVrInits = 0;
37static RTMEMCACHE g_VBoxVrLookasideList;
38#endif
39
40static PVBOXVR_REG vboxVrRegCreate()
41{
42#ifndef VBOXVDBG_VR_LAL_DISABLE
43 PVBOXVR_REG pReg = (PVBOXVR_REG)RTMemCacheAlloc(g_VBoxVrLookasideList);
44 if (!pReg)
45 {
46 WARN(("ExAllocateFromLookasideListEx failed!"));
47 }
48 return pReg;
49#else
50 return (PVBOXVR_REG)RTMemAlloc(sizeof (VBOXVR_REG));
51#endif
52}
53
54static void vboxVrRegTerm(PVBOXVR_REG pReg)
55{
56#ifndef VBOXVDBG_VR_LAL_DISABLE
57 RTMemCacheFree(g_VBoxVrLookasideList, pReg);
58#else
59 RTMemFree(pReg);
60#endif
61}
62
63VBOXVREGDECL(void) VBoxVrListClear(PVBOXVR_LIST pList)
64{
65 PVBOXVR_REG pReg, pRegNext;
66
67 RTListForEachSafe(&pList->ListHead, pReg, pRegNext, VBOXVR_REG, ListEntry)
68 {
69 vboxVrRegTerm(pReg);
70 }
71 VBoxVrListInit(pList);
72}
73
74#define VBOXVR_MEMTAG 'vDBV'
75
76VBOXVREGDECL(int) VBoxVrInit()
77{
78 int32_t cNewRefs = ASMAtomicIncS32(&g_cVBoxVrInits);
79 Assert(cNewRefs >= 1);
80 Assert(cNewRefs == 1); /* <- debugging */
81 if (cNewRefs > 1)
82 return VINF_SUCCESS;
83
84#ifndef VBOXVDBG_VR_LAL_DISABLE
85 int rc = RTMemCacheCreate(&g_VBoxVrLookasideList, sizeof (VBOXVR_REG),
86 0, /* size_t cbAlignment */
87 UINT32_MAX, /* uint32_t cMaxObjects */
88 NULL, /* PFNMEMCACHECTOR pfnCtor*/
89 NULL, /* PFNMEMCACHEDTOR pfnDtor*/
90 NULL, /* void *pvUser*/
91 0 /* uint32_t fFlags*/
92 );
93 if (!RT_SUCCESS(rc))
94 {
95 WARN(("ExInitializeLookasideListEx failed, rc (%d)", rc));
96 return rc;
97 }
98#endif
99
100 return VINF_SUCCESS;
101}
102
103VBOXVREGDECL(void) VBoxVrTerm()
104{
105 int32_t cNewRefs = ASMAtomicDecS32(&g_cVBoxVrInits);
106 Assert(cNewRefs >= 0);
107 if (cNewRefs > 0)
108 return;
109
110#ifndef VBOXVDBG_VR_LAL_DISABLE
111 RTMemCacheDestroy(g_VBoxVrLookasideList);
112#endif
113}
114
115typedef DECLCALLBACK(int) FNVBOXVR_CB_COMPARATOR(const PVBOXVR_REG pReg1, const PVBOXVR_REG pReg2);
116typedef FNVBOXVR_CB_COMPARATOR *PFNVBOXVR_CB_COMPARATOR;
117
118static DECLCALLBACK(int) vboxVrRegNonintersectedComparator(const RTRECT* pRect1, const RTRECT* pRect2)
119{
120 Assert(!VBoxRectIsIntersect(pRect1, pRect2));
121 if (pRect1->yTop != pRect2->yTop)
122 return pRect1->yTop - pRect2->yTop;
123 return pRect1->xLeft - pRect2->xLeft;
124}
125
126#ifdef DEBUG_misha
127static void vboxVrDbgListDoVerify(PVBOXVR_LIST pList)
128{
129 PVBOXVR_REG pReg1, pReg2;
130 RTListForEach(&pList->ListHead, pReg1, VBOXVR_REG, ListEntry)
131 {
132 Assert(!VBoxRectIsZero(&pReg1->Rect));
133 for (RTLISTNODE *pEntry2 = pReg1->ListEntry.pNext; pEntry2 != &pList->ListHead; pEntry2 = pEntry2->pNext)
134 {
135 pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
136 Assert(vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0);
137 }
138 }
139}
140
141#define vboxVrDbgListVerify vboxVrDbgListDoVerify
142#else
143#define vboxVrDbgListVerify(_p) do {} while (0)
144#endif
145
146static int vboxVrListUniteIntersection(PVBOXVR_LIST pList, PVBOXVR_LIST pIntersection);
147
148#define VBOXVR_INVALID_COORD (~0U)
149
150DECLINLINE(void) vboxVrListRegAdd(PVBOXVR_LIST pList, PVBOXVR_REG pReg, PRTLISTNODE pPlace, bool fAfter)
151{
152 if (fAfter)
153 RTListPrepend(pPlace, &pReg->ListEntry);
154 else
155 RTListAppend(pPlace, &pReg->ListEntry);
156 ++pList->cEntries;
157 vboxVrDbgListVerify(pList);
158}
159
160DECLINLINE(void) vboxVrListRegRemove(PVBOXVR_LIST pList, PVBOXVR_REG pReg)
161{
162 RTListNodeRemove(&pReg->ListEntry);
163 --pList->cEntries;
164}
165
166static void vboxVrListRegAddOrder(PVBOXVR_LIST pList, PRTLISTNODE pMemberEntry, PVBOXVR_REG pReg)
167{
168 do
169 {
170 if (pMemberEntry != &pList->ListHead)
171 {
172 PVBOXVR_REG pMemberReg = PVBOXVR_REG_FROM_ENTRY(pMemberEntry);
173 if (vboxVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0)
174 {
175 pMemberEntry = pMemberEntry->pNext;
176 continue;
177 }
178 }
179 vboxVrListRegAdd(pList, pReg, pMemberEntry, false);
180 break;
181 } while (1);
182}
183
184static void vboxVrListAddNonintersected(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
185{
186 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
187
188 for (PRTLISTNODE pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.pNext)
189 {
190 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
191 do {
192 if (pEntry1 != &pList1->ListHead)
193 {
194 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
195 if (vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0)
196 {
197 pEntry1 = pEntry1->pNext;
198 continue;
199 }
200 }
201 vboxVrListRegRemove(pList2, pReg2);
202 vboxVrListRegAdd(pList1, pReg2, pEntry1, false);
203 break;
204 } while (1);
205 }
206
207 Assert(VBoxVrListIsEmpty(pList2));
208}
209
210static int vboxVrListRegIntersectSubstNoJoin(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2)
211{
212 uint32_t topLim = VBOXVR_INVALID_COORD;
213 uint32_t bottomLim = VBOXVR_INVALID_COORD;
214 RTLISTNODE List;
215 PVBOXVR_REG pBottomReg = NULL;
216#ifdef DEBUG_misha
217 RTRECT tmpRect = pReg1->Rect;
218 vboxVrDbgListVerify(pList1);
219#endif
220 Assert(!VBoxRectIsZero(pRect2));
221
222 RTListInit(&List);
223
224 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
225
226 if (pReg1->Rect.yTop < pRect2->yTop)
227 {
228 Assert(pRect2->yTop < pReg1->Rect.yBottom);
229 PVBOXVR_REG pRegResult = vboxVrRegCreate();
230 pRegResult->Rect.yTop = pReg1->Rect.yTop;
231 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
232 pRegResult->Rect.yBottom = pRect2->yTop;
233 pRegResult->Rect.xRight = pReg1->Rect.xRight;
234 topLim = pRect2->yTop;
235 RTListAppend(&List, &pRegResult->ListEntry);
236 }
237
238 if (pReg1->Rect.yBottom > pRect2->yBottom)
239 {
240 Assert(pRect2->yBottom > pReg1->Rect.yTop);
241 PVBOXVR_REG pRegResult = vboxVrRegCreate();
242 pRegResult->Rect.yTop = pRect2->yBottom;
243 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
244 pRegResult->Rect.yBottom = pReg1->Rect.yBottom;
245 pRegResult->Rect.xRight = pReg1->Rect.xRight;
246 bottomLim = pRect2->yBottom;
247 pBottomReg = pRegResult;
248 }
249
250 if (pReg1->Rect.xLeft < pRect2->xLeft)
251 {
252 Assert(pRect2->xLeft < pReg1->Rect.xRight);
253 PVBOXVR_REG pRegResult = vboxVrRegCreate();
254 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
255 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
256 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
257 pRegResult->Rect.xRight = pRect2->xLeft;
258 RTListAppend(&List, &pRegResult->ListEntry);
259 }
260
261 if (pReg1->Rect.xRight > pRect2->xRight)
262 {
263 Assert(pRect2->xRight > pReg1->Rect.xLeft);
264 PVBOXVR_REG pRegResult = vboxVrRegCreate();
265 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
266 pRegResult->Rect.xLeft = pRect2->xRight;
267 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
268 pRegResult->Rect.xRight = pReg1->Rect.xRight;
269 RTListAppend(&List, &pRegResult->ListEntry);
270 }
271
272 if (pBottomReg)
273 RTListAppend(&List, &pBottomReg->ListEntry);
274
275 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
276 vboxVrListRegRemove(pList1, pReg1);
277 vboxVrRegTerm(pReg1);
278
279 if (RTListIsEmpty(&List))
280 return VINF_SUCCESS; /* the region is covered by the pRect2 */
281
282 PRTLISTNODE pEntry = List.pNext, pNext;
283 for (; pEntry != &List; pEntry = pNext)
284 {
285 pNext = pEntry->pNext;
286 PVBOXVR_REG pReg = PVBOXVR_REG_FROM_ENTRY(pEntry);
287
288 vboxVrListRegAddOrder(pList1, pMemberEntry, pReg);
289 pMemberEntry = pEntry->pNext; /* the following elements should go after the given pEntry since they are ordered already */
290 }
291 return VINF_SUCCESS;
292}
293
294typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_INTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2, void *pvContext, PRTLISTNODE *ppNext);
295typedef FNVBOXVR_CB_INTERSECTED_VISITOR *PFNVBOXVR_CB_INTERSECTED_VISITOR;
296
297static void vboxVrListVisitIntersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
298{
299 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
300 PRTLISTNODE pNext1;
301 uint32_t iFirst2 = 0;
302
303 for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
304 {
305 pNext1 = pEntry1->pNext;
306 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
307 for (uint32_t i = iFirst2; i < cRects; ++i)
308 {
309 const RTRECT *pRect2 = &aRects[i];
310 if (VBoxRectIsZero(pRect2))
311 continue;
312 if (pReg1->Rect.yBottom <= pRect2->yTop)
313 continue;
314 else if (pRect2->yBottom <= pReg1->Rect.yTop)
315 continue;
316 /* y coords intersect */
317 else if (pReg1->Rect.xRight <= pRect2->xLeft)
318 continue;
319 else if (pRect2->xRight <= pReg1->Rect.xLeft)
320 continue;
321 /* x coords intersect */
322
323 /* the visitor can modify the list 1, apply necessary adjustments after it */
324 PRTLISTNODE pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1);
325 if (pEntry1 == &pList1->ListHead)
326 break;
327 }
328 }
329}
330
331
332static void vboxVrListJoinRectsHV(PVBOXVR_LIST pList, bool fHorizontal)
333{
334 PRTLISTNODE pNext1, pNext2;
335
336 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
337 {
338 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
339 pNext1 = pEntry1->pNext;
340 for (PRTLISTNODE pEntry2 = pEntry1->pNext; pEntry2 != &pList->ListHead; pEntry2 = pNext2)
341 {
342 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
343 pNext2 = pEntry2->pNext;
344 if (fHorizontal)
345 {
346 if (pReg1->Rect.yTop == pReg2->Rect.yTop)
347 {
348 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
349 {
350 /* join rectangles */
351 vboxVrListRegRemove(pList, pReg2);
352 if (pReg1->Rect.yBottom > pReg2->Rect.yBottom)
353 {
354 int32_t oldRight1 = pReg1->Rect.xRight;
355 int32_t oldBottom1 = pReg1->Rect.yBottom;
356 pReg1->Rect.xRight = pReg2->Rect.xRight;
357 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
358
359 vboxVrDbgListVerify(pList);
360
361 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
362 pReg2->Rect.yTop = pReg1->Rect.yBottom;
363 pReg2->Rect.xRight = oldRight1;
364 pReg2->Rect.yBottom = oldBottom1;
365 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
366 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
367 * and thus can match one of the previous rects */
368 pNext1 = pList->ListHead.pNext;
369 break;
370 }
371 else if (pReg1->Rect.yBottom < pReg2->Rect.yBottom)
372 {
373 pReg1->Rect.xRight = pReg2->Rect.xRight;
374 vboxVrDbgListVerify(pList);
375 pReg2->Rect.yTop = pReg1->Rect.yBottom;
376 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
377 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
378 * and thus can match one of the previous rects */
379 pNext1 = pList->ListHead.pNext;
380 break;
381 }
382 else
383 {
384 pReg1->Rect.xRight = pReg2->Rect.xRight;
385 vboxVrDbgListVerify(pList);
386 /* reset the pNext1 since it could be the pReg2 being destroyed */
387 pNext1 = pEntry1->pNext;
388 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
389 vboxVrRegTerm(pReg2);
390 }
391 }
392 continue;
393 }
394 else if (pReg1->Rect.yBottom == pReg2->Rect.yBottom)
395 {
396 Assert(pReg1->Rect.yTop < pReg2->Rect.yTop); /* <- since pReg1 > pReg2 && pReg1->Rect.yTop != pReg2->Rect.yTop*/
397 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
398 {
399 /* join rectangles */
400 vboxVrListRegRemove(pList, pReg2);
401
402 pReg1->Rect.yBottom = pReg2->Rect.yTop;
403 vboxVrDbgListVerify(pList);
404 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
405
406 vboxVrListRegAddOrder(pList, pReg2->ListEntry.pNext, pReg2);
407
408 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
409 * and thus can match one of the previous rects */
410 pNext1 = pList->ListHead.pNext;
411 break;
412 }
413 else if (pReg1->Rect.xLeft == pReg2->Rect.xRight)
414 {
415 /* join rectangles */
416 vboxVrListRegRemove(pList, pReg2);
417
418 pReg1->Rect.yBottom = pReg2->Rect.yTop;
419 vboxVrDbgListVerify(pList);
420 pReg2->Rect.xRight = pReg1->Rect.xRight;
421
422 vboxVrListRegAddOrder(pList, pReg2->ListEntry.pNext, pReg2);
423
424 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
425 * and thus can match one of the previous rects */
426 pNext1 = pList->ListHead.pNext;
427 break;
428 }
429 continue;
430 }
431 }
432 else
433 {
434 if (pReg1->Rect.yBottom == pReg2->Rect.yTop)
435 {
436 if (pReg1->Rect.xLeft == pReg2->Rect.xLeft)
437 {
438 if (pReg1->Rect.xRight == pReg2->Rect.xRight)
439 {
440 /* join rects */
441 vboxVrListRegRemove(pList, pReg2);
442
443 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
444 vboxVrDbgListVerify(pList);
445
446 /* reset the pNext1 since it could be the pReg2 being destroyed */
447 pNext1 = pEntry1->pNext;
448 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
449 vboxVrRegTerm(pReg2);
450 continue;
451 }
452 /* no more to be done for for pReg1 */
453 break;
454 }
455 else if (pReg1->Rect.xRight > pReg2->Rect.xLeft)
456 {
457 /* no more to be done for for pReg1 */
458 break;
459 }
460
461 continue;
462 }
463 else if (pReg1->Rect.yBottom < pReg2->Rect.yTop)
464 {
465 /* no more to be done for for pReg1 */
466 break;
467 }
468 }
469 }
470 }
471}
472
473static void vboxVrListJoinRects(PVBOXVR_LIST pList)
474{
475 vboxVrListJoinRectsHV(pList, true);
476 vboxVrListJoinRectsHV(pList, false);
477}
478
479typedef struct VBOXVR_CBDATA_SUBST
480{
481 int rc;
482 bool fChanged;
483} VBOXVR_CBDATA_SUBST, *PVBOXVR_CBDATA_SUBST;
484
485static DECLCALLBACK(PRTLISTNODE) vboxVrListSubstNoJoinCb(PVBOXVR_LIST pList, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
486{
487 PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
488 /* store the prev to get the new pNext out of it*/
489 PRTLISTNODE pPrev = pReg1->ListEntry.pPrev;
490 pData->fChanged = true;
491
492 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
493
494 /* NOTE: the pReg1 will be invalid after the vboxVrListRegIntersectSubstNoJoin call!!! */
495 int rc = vboxVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2);
496 if (RT_SUCCESS(rc))
497 {
498 *ppNext = pPrev->pNext;
499 return &pList->ListHead;
500 }
501 WARN(("vboxVrListRegIntersectSubstNoJoin failed!"));
502 Assert(!RT_SUCCESS(rc));
503 pData->rc = rc;
504 *ppNext = &pList->ListHead;
505 return &pList->ListHead;
506}
507
508static int vboxVrListSubstNoJoin(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
509{
510 if (VBoxVrListIsEmpty(pList))
511 return VINF_SUCCESS;
512
513 VBOXVR_CBDATA_SUBST Data;
514 Data.rc = VINF_SUCCESS;
515 Data.fChanged = false;
516
517 *pfChanged = false;
518
519 vboxVrListVisitIntersected(pList, cRects, aRects, vboxVrListSubstNoJoinCb, &Data);
520 if (!RT_SUCCESS(Data.rc))
521 {
522 WARN(("vboxVrListVisitIntersected failed!"));
523 return Data.rc;
524 }
525
526 *pfChanged = Data.fChanged;
527 return VINF_SUCCESS;
528}
529
530#if 0
531static const RTRECT * vboxVrRectsOrder(uint32_t cRects, const RTRECT * aRects)
532{
533#ifdef DEBUG
534 {
535 for (uint32_t i = 0; i < cRects; ++i)
536 {
537 RTRECT *pRectI = &aRects[i];
538 for (uint32_t j = i + 1; j < cRects; ++j)
539 {
540 RTRECT *pRectJ = &aRects[j];
541 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
542 }
543 }
544 }
545#endif
546
547 RTRECT * pRects = (RTRECT *)aRects;
548 /* check if rects are ordered already */
549 for (uint32_t i = 0; i < cRects - 1; ++i)
550 {
551 RTRECT *pRect1 = &pRects[i];
552 RTRECT *pRect2 = &pRects[i+1];
553 if (vboxVrRegNonintersectedComparator(pRect1, pRect2) < 0)
554 continue;
555
556 WARN(("rects are unoreded!"));
557
558 if (pRects == aRects)
559 {
560 pRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cRects);
561 if (!pRects)
562 {
563 WARN(("RTMemAlloc failed!"));
564 return NULL;
565 }
566
567 memcpy(pRects, aRects, sizeof (RTRECT) * cRects);
568 }
569
570 Assert(pRects != aRects);
571
572 int j = (int)i - 1;
573 do {
574 RTRECT Tmp = *pRect1;
575 *pRect1 = *pRect2;
576 *pRect2 = Tmp;
577
578 if (j < 0)
579 break;
580
581 if (vboxVrRegNonintersectedComparator(pRect1, pRect1-1) > 0)
582 break;
583
584 pRect2 = pRect1--;
585 --j;
586 } while (1);
587 }
588
589 return pRects;
590}
591#endif
592
593VBOXVREGDECL(void) VBoxVrListTranslate(PVBOXVR_LIST pList, int32_t x, int32_t y)
594{
595 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
596 {
597 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
598 VBoxRectTranslate(&pReg1->Rect, x, y);
599 }
600}
601
602VBOXVREGDECL(int) VBoxVrListRectsSubst(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
603{
604#if 0
605 const RTRECT * pRects = vboxVrRectsOrder(cRects, aRects);
606 if (!pRects)
607 {
608 WARN(("vboxVrRectsOrder failed!"));
609 return VERR_NO_MEMORY;
610 }
611#endif
612
613 int rc = vboxVrListSubstNoJoin(pList, cRects, aRects, pfChanged);
614 if (!RT_SUCCESS(rc))
615 {
616 WARN(("vboxVrListSubstNoJoin failed!"));
617 goto done;
618 }
619
620 if (!*pfChanged)
621 goto done;
622
623 vboxVrListJoinRects(pList);
624
625done:
626#if 0
627 if (pRects != aRects)
628 RTMemFree(pRects);
629#endif
630 return rc;
631}
632
633VBOXVREGDECL(int) VBoxVrListRectsAdd(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
634{
635 uint32_t cCovered = 0;
636
637#if 0
638#ifdef DEBUG
639 {
640 for (uint32_t i = 0; i < cRects; ++i)
641 {
642 RTRECT *pRectI = &aRects[i];
643 for (uint32_t j = i + 1; j < cRects; ++j)
644 {
645 RTRECT *pRectJ = &aRects[j];
646 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
647 }
648 }
649 }
650#endif
651#endif
652
653 /* early sort out the case when there are no new rects */
654 for (uint32_t i = 0; i < cRects; ++i)
655 {
656 if (VBoxRectIsZero(&aRects[i]))
657 {
658 cCovered++;
659 continue;
660 }
661
662 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
663 {
664 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
665
666 if (VBoxRectIsCoveres(&pReg1->Rect, &aRects[i]))
667 {
668 cCovered++;
669 break;
670 }
671 }
672 }
673
674 if (cCovered == cRects)
675 {
676 *pfChanged = false;
677 return VINF_SUCCESS;
678 }
679
680 /* rects are not covered, need to go the slow way */
681
682 VBOXVR_LIST DiffList;
683 VBoxVrListInit(&DiffList);
684 RTRECT * pListRects = NULL;
685 uint32_t cAllocatedRects = 0;
686 bool fNeedRectreate = true;
687 bool fChanged = false;
688 int rc = VINF_SUCCESS;
689
690 for (uint32_t i = 0; i < cRects; ++i)
691 {
692 if (VBoxRectIsZero(&aRects[i]))
693 continue;
694
695 PVBOXVR_REG pReg = vboxVrRegCreate();
696 if (!pReg)
697 {
698 WARN(("vboxVrRegCreate failed!"));
699 rc = VERR_NO_MEMORY;
700 break;
701 }
702 pReg->Rect = aRects[i];
703
704 uint32_t cListRects = VBoxVrListRectsCount(pList);
705 if (!cListRects)
706 {
707 vboxVrListRegAdd(pList, pReg, &pList->ListHead, false);
708 fChanged = true;
709 continue;
710 }
711 else
712 {
713 Assert(VBoxVrListIsEmpty(&DiffList));
714 vboxVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, false);
715 }
716
717 if (cAllocatedRects < cListRects)
718 {
719 cAllocatedRects = cListRects + cRects;
720 Assert(fNeedRectreate);
721 if (pListRects)
722 RTMemFree(pListRects);
723 pListRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cAllocatedRects);
724 if (!pListRects)
725 {
726 WARN(("RTMemAlloc failed!"));
727 rc = VERR_NO_MEMORY;
728 break;
729 }
730 }
731
732
733 if (fNeedRectreate)
734 {
735 rc = VBoxVrListRectsGet(pList, cListRects, pListRects);
736 Assert(rc == VINF_SUCCESS);
737 fNeedRectreate = false;
738 }
739
740 bool fDummyChanged = false;
741 rc = vboxVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged);
742 if (!RT_SUCCESS(rc))
743 {
744 WARN(("vboxVrListSubstNoJoin failed!"));
745 rc = VERR_NO_MEMORY;
746 break;
747 }
748
749 if (!VBoxVrListIsEmpty(&DiffList))
750 {
751 vboxVrListAddNonintersected(pList, &DiffList);
752 fNeedRectreate = true;
753 fChanged = true;
754 }
755
756 Assert(VBoxVrListIsEmpty(&DiffList));
757 }
758
759 if (pListRects)
760 RTMemFree(pListRects);
761
762 Assert(VBoxVrListIsEmpty(&DiffList) || rc != VINF_SUCCESS);
763 VBoxVrListClear(&DiffList);
764
765 if (fChanged)
766 vboxVrListJoinRects(pList);
767
768 *pfChanged = fChanged;
769
770 return VINF_SUCCESS;
771}
772
773VBOXVREGDECL(int) VBoxVrListRectsGet(PVBOXVR_LIST pList, uint32_t cRects, RTRECT * aRects)
774{
775 if (cRects < VBoxVrListRectsCount(pList))
776 return VERR_BUFFER_OVERFLOW;
777
778 uint32_t i = 0;
779 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext, ++i)
780 {
781 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
782 aRects[i] = pReg1->Rect;
783 }
784 return VINF_SUCCESS;
785}
786
787VBOXVREGDECL(int) VBoxVrListCmp(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
788{
789 int cTmp = pList1->cEntries - pList2->cEntries;
790 if (cTmp)
791 return cTmp;
792
793 PVBOXVR_REG pReg1, pReg2;
794
795 for (pReg1 = RTListNodeGetNext(&pList1->ListHead, VBOXVR_REG, ListEntry),
796 pReg2 = RTListNodeGetNext(&pList2->ListHead, VBOXVR_REG, ListEntry);
797 !RTListNodeIsDummy(&pList1->ListHead, pReg1, VBOXVR_REG, ListEntry);
798 pReg1 = RT_FROM_MEMBER(pReg1->ListEntry.pNext, VBOXVR_REG, ListEntry),
799 pReg2 = RT_FROM_MEMBER(pReg2->ListEntry.pNext, VBOXVR_REG, ListEntry))
800 {
801 Assert(!RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
802 cTmp = VBoxRectCmp(&pReg1->Rect, &pReg2->Rect);
803 if (cTmp)
804 return cTmp;
805 }
806 Assert(RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
807 return 0;
808}
809
810VBOXVREGDECL(void) VBoxVrCompositorInit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_ENTRY_REMOVED pfnEntryRemoved)
811{
812 RTListInit(&pCompositor->List);
813 pCompositor->pfnEntryRemoved = pfnEntryRemoved;
814}
815
816VBOXVREGDECL(void) VBoxVrCompositorTerm(PVBOXVR_COMPOSITOR pCompositor)
817{
818 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
819 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
820 {
821 VBoxVrCompositorEntryRemove(pCompositor, pEntry);
822 }
823}
824
825DECLINLINE(void) vboxVrCompositorEntryAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
826{
827 RTListPrepend(&pCompositor->List, &pEntry->Node);
828}
829
830DECLINLINE(void) vboxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
831{
832 RTListNodeRemove(&pEntry->Node);
833 if (pCompositor->pfnEntryRemoved)
834 pCompositor->pfnEntryRemoved(pCompositor, pEntry, pReplacingEntry);
835}
836
837VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry)
838{
839 VBoxVrListInit(&pEntry->Vr);
840}
841
842VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
843{
844 if (!VBoxVrCompositorEntryIsInList(pEntry))
845 return false;
846 VBoxVrListClear(&pEntry->Vr);
847 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
848 return true;
849}
850
851static int vboxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
852{
853 bool fChanged;
854 int rc = VBoxVrListRectsSubst(&pEntry->Vr, cRects, paRects, &fChanged);
855 if (RT_SUCCESS(rc))
856 {
857 if (VBoxVrListIsEmpty(&pEntry->Vr))
858 {
859 Assert(fChanged);
860 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
861 }
862 if (pfChanged)
863 *pfChanged = false;
864 return VINF_SUCCESS;
865 }
866
867 WARN(("VBoxVrListRectsSubst failed, rc %d", rc));
868 return rc;
869}
870
871VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, uint32_t *pfChangeFlags)
872{
873 bool fOthersChanged = false, fCurChanged = false, fEntryChanged = false, fEntryInList = false, fEntryReplaces = false;
874 PVBOXVR_COMPOSITOR_ENTRY pCur;
875 int rc = VINF_SUCCESS;
876
877 if (!cRects)
878 {
879 if (pfChangeFlags)
880 *pfChangeFlags = 0;
881 return VINF_SUCCESS;
882 }
883
884 if (pEntry)
885 {
886 fEntryInList = VBoxVrCompositorEntryIsInList(pEntry);
887 rc = VBoxVrListRectsAdd(&pEntry->Vr, cRects, paRects, &fEntryChanged);
888 if (RT_SUCCESS(rc))
889 {
890 if (VBoxVrListIsEmpty(&pEntry->Vr))
891 {
892 WARN(("Empty rectangles passed in, is it expected?"));
893 if (pfChangeFlags)
894 *pfChangeFlags = 0;
895 return VINF_SUCCESS;
896 }
897 }
898 else
899 {
900 WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
901 return rc;
902 }
903
904 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
905 }
906
907 RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
908 {
909 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
910 if (pCur == pEntry)
911 {
912 Assert(fEntryInList);
913 }
914 else
915 {
916 if (pEntry && !VBoxVrListCmp(&pCur->Vr, &pEntry->Vr))
917 {
918 VBoxVrListClear(&pCur->Vr);
919 vboxVrCompositorEntryRemove(pCompositor, pCur, pEntry);
920 fEntryReplaces = true;
921 }
922 else
923 {
924 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, &fCurChanged);
925 if (RT_SUCCESS(rc))
926 fOthersChanged |= fCurChanged;
927 else
928 {
929 WARN(("vboxVrCompositorEntryRegionsSubst failed, rc %d", rc));
930 return rc;
931 }
932 }
933 }
934 }
935
936 AssertRC(rc);
937
938 if (pEntry && !fEntryInList)
939 {
940 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
941 vboxVrCompositorEntryAdd(pCompositor, pEntry);
942 }
943
944 if (pfChangeFlags)
945 {
946 uint32_t fFlags = 0;
947 if (fOthersChanged)
948 fFlags = VBOXVR_COMPOSITOR_CF_ENTRIES_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_COMPOSITED_REGIONS_CHANGED;
949 else if (fEntryReplaces)
950 {
951 Assert(fEntryChanged);
952 fFlags = VBOXVR_COMPOSITOR_CF_ENTRIES_REGIONS_CHANGED;
953 }
954 else if (fEntryChanged)
955 fFlags = VBOXVR_COMPOSITOR_CF_ENTRIES_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_COMPOSITED_REGIONS_CHANGED;
956 if (!fEntryInList)
957 fFlags |= VBOXVR_COMPOSITOR_CF_ENTRY_ADDED;
958
959 *pfChangeFlags = fFlags;
960 }
961
962 return VINF_SUCCESS;
963}
964
965VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
966{
967 if (!pEntry)
968 {
969 WARN(("VBoxVrCompositorEntryRegionsSubst called with zero entry, unsupported!"));
970 if (pfChanged)
971 *pfChanged = false;
972 return VERR_INVALID_PARAMETER;
973 }
974
975 if (VBoxVrListIsEmpty(&pEntry->Vr))
976 {
977 if (pfChanged)
978 *pfChanged = false;
979 return VINF_SUCCESS;
980
981 }
982
983 int rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pEntry, cRects, paRects, pfChanged);
984 if (RT_SUCCESS(rc))
985 return VINF_SUCCESS;
986
987 WARN(("pfChanged failed, rc %d", rc));
988 return rc;
989}
990
991VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
992{
993 if (!pEntry)
994 {
995 WARN(("VBoxVrCompositorEntryRegionsSet called with zero entry, unsupported!"));
996 if (pfChanged)
997 *pfChanged = false;
998 return VERR_INVALID_PARAMETER;
999 }
1000
1001 bool fChanged = false, fCurChanged = false;
1002 uint32_t fChangeFlags = 0;
1003 int rc;
1004 fCurChanged = VBoxVrCompositorEntryRemove(pCompositor, pEntry);
1005 fChanged |= fCurChanged;
1006
1007 rc = VBoxVrCompositorEntryRegionsAdd(pCompositor, pEntry, cRects, paRects, &fChangeFlags);
1008 if (RT_SUCCESS(rc))
1009 fChanged |= !!fChangeFlags;
1010 else
1011 {
1012 WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
1013 return rc;
1014 }
1015
1016 AssertRC(rc);
1017
1018 if (pfChanged)
1019 *pfChanged = fChanged;
1020 return VINF_SUCCESS;
1021}
1022
1023VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, int32_t x, int32_t y, bool *pfChanged)
1024{
1025 if (!pEntry)
1026 {
1027 WARN(("VBoxVrCompositorEntryRegionsTranslate called with zero entry, unsupported!"));
1028 if (pfChanged)
1029 *pfChanged = false;
1030 return VERR_INVALID_PARAMETER;
1031 }
1032
1033 if ((!x && !y)
1034 || !VBoxVrCompositorEntryIsInList(pEntry))
1035 {
1036 if (pfChanged)
1037 *pfChanged = false;
1038 return VINF_SUCCESS;
1039 }
1040
1041 VBoxVrListTranslate(&pEntry->Vr, x, y);
1042
1043 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1044
1045 PVBOXVR_COMPOSITOR_ENTRY pCur;
1046 uint32_t cRects = 0;
1047 RTRECT *paRects = NULL;
1048 int rc = VINF_SUCCESS;
1049 RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
1050 {
1051 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1052
1053 if (pCur == pEntry)
1054 continue;
1055
1056 if (!paRects)
1057 {
1058 cRects = VBoxVrListRectsCount(&pEntry->Vr);
1059 Assert(cRects);
1060 paRects = (RTRECT*)RTMemAlloc(cRects * sizeof (RTRECT));
1061 if (!paRects)
1062 {
1063 WARN(("RTMemAlloc failed!"));
1064 rc = VERR_NO_MEMORY;
1065 break;
1066 }
1067
1068 rc = VBoxVrListRectsGet(&pEntry->Vr, cRects, paRects);
1069 if (!RT_SUCCESS(rc))
1070 {
1071 WARN(("VBoxVrListRectsGet failed! rc %d", rc));
1072 break;
1073 }
1074 }
1075
1076 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, NULL);
1077 if (!RT_SUCCESS(rc))
1078 {
1079 WARN(("vboxVrCompositorEntryRegionsSubst failed! rc %d", rc));
1080 break;
1081 }
1082 }
1083
1084 if (pfChanged)
1085 *pfChanged = true;
1086
1087 if (paRects)
1088 RTMemFree(paRects);
1089
1090 return rc;
1091}
1092
1093VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
1094{
1095 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
1096 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1097 {
1098 if (!pfnVisitor(pCompositor, pEntry, pvVisitor))
1099 return;
1100 }
1101}
1102
1103
1104
1105#define VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED UINT32_MAX
1106
1107static int crVrScrCompositorRectsAssignBuffer(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRects)
1108{
1109 Assert(cRects);
1110
1111 if (pCompositor->cRectsBuffer >= cRects)
1112 {
1113 pCompositor->cRects = cRects;
1114 return VINF_SUCCESS;
1115 }
1116
1117 if (pCompositor->cRectsBuffer)
1118 {
1119 Assert(pCompositor->paSrcRects);
1120 RTMemFree(pCompositor->paSrcRects);
1121 Assert(pCompositor->paDstRects);
1122 RTMemFree(pCompositor->paDstRects);
1123 }
1124
1125 pCompositor->paSrcRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paSrcRects) * cRects);
1126 if (pCompositor->paSrcRects)
1127 {
1128 pCompositor->paDstRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstRects) * cRects);
1129 if (pCompositor->paDstRects)
1130 {
1131 pCompositor->cRects = cRects;
1132 pCompositor->cRectsBuffer = cRects;
1133 return VINF_SUCCESS;
1134 }
1135 else
1136 {
1137 crWarning("RTMemAlloc failed!");
1138 RTMemFree(pCompositor->paSrcRects);
1139 pCompositor->paSrcRects = NULL;
1140 }
1141 }
1142 else
1143 {
1144 crWarning("RTMemAlloc failed!");
1145 pCompositor->paDstRects = NULL;
1146 }
1147
1148 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1149 pCompositor->cRectsBuffer = 0;
1150
1151 return VERR_NO_MEMORY;
1152}
1153
1154static void crVrScrCompositorRectsInvalidate(PVBOXVR_SCR_COMPOSITOR pCompositor)
1155{
1156 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1157}
1158
1159static DECLCALLBACK(bool) crVrScrCompositorRectsCounterCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor)
1160{
1161 uint32_t* pCounter = (uint32_t*)pvVisitor;
1162 Assert(VBoxVrListRectsCount(&pEntry->Vr));
1163 *pCounter += VBoxVrListRectsCount(&pEntry->Vr);
1164 return true;
1165}
1166
1167typedef struct VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER
1168{
1169 PRTRECT paSrcRects;
1170 PRTRECT paDstRects;
1171 uint32_t cRects;
1172} VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER, *PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER;
1173
1174static DECLCALLBACK(bool) crVrScrCompositorRectsAssignerCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
1175{
1176 PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER pData = (PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER)pvVisitor;
1177 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
1178 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
1179 pEntry->paSrcRects = pData->paSrcRects;
1180 pEntry->paDstRects = pData->paDstRects;
1181 uint32_t cRects = VBoxVrListRectsCount(&pCEntry->Vr);
1182 Assert(cRects);
1183 Assert(cRects >= pData->cRects);
1184 int rc = VBoxVrListRectsGet(&pCEntry->Vr, cRects, pEntry->paDstRects);
1185 AssertRC(rc);
1186 if (pCompositor->StretchX >= 1. && pCompositor->StretchY >= 1. /* <- stretching can not zero some rects */
1187 && !pEntry->Pos.x && !pEntry->Pos.y)
1188 {
1189 memcpy(pEntry->paSrcRects, pEntry->paDstRects, cRects * sizeof (*pEntry->paSrcRects));
1190 }
1191 else
1192 {
1193 for (uint32_t i = 0; i < cRects; ++i)
1194 {
1195 pEntry->paSrcRects[i].xLeft = (int32_t)((pEntry->paDstRects[i].xLeft - pEntry->Pos.x) * pCompositor->StretchX);
1196 pEntry->paSrcRects[i].yTop = (int32_t)((pEntry->paDstRects[i].yTop - pEntry->Pos.y) * pCompositor->StretchY);
1197 pEntry->paSrcRects[i].xRight = (int32_t)((pEntry->paDstRects[i].xRight - pEntry->Pos.x) * pCompositor->StretchX);
1198 pEntry->paSrcRects[i].yBottom = (int32_t)((pEntry->paDstRects[i].yBottom - pEntry->Pos.y) * pCompositor->StretchY);
1199 }
1200
1201 bool canZeroX = (pCompositor->StretchX < 1);
1202 bool canZeroY = (pCompositor->StretchY < 1);
1203 if (canZeroX && canZeroY)
1204 {
1205 /* filter out zero rectangles*/
1206 uint32_t iOrig, iNew;
1207 for (iOrig = 0, iNew = 0; iOrig < cRects; ++iOrig)
1208 {
1209 PRTRECT pOrigRect = &pEntry->paSrcRects[iOrig];
1210 if (pOrigRect->xLeft == pOrigRect->xRight
1211 || pOrigRect->yTop == pOrigRect->yBottom)
1212 continue;
1213
1214 if (iNew != iOrig)
1215 {
1216 PRTRECT pNewRect = &pEntry->paSrcRects[iNew];
1217 *pNewRect = *pOrigRect;
1218 }
1219
1220 ++iNew;
1221 }
1222
1223 Assert(iNew <= iOrig);
1224
1225 uint32_t cDiff = iOrig - iNew;
1226
1227 if (cDiff)
1228 {
1229 pCompositor->cRects -= cDiff;
1230 cRects -= cDiff;
1231 }
1232 }
1233 }
1234
1235 pEntry->cRects = cRects;
1236 pData->paDstRects += cRects;
1237 pData->paSrcRects += cRects;
1238 pData->cRects -= cRects;
1239 return true;
1240}
1241
1242static int crVrScrCompositorRectsCheckInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
1243{
1244 if (pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED)
1245 return VINF_SUCCESS;
1246
1247 uint32_t cRects = 0;
1248 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsCounterCb, &cRects);
1249
1250 if (!cRects)
1251 {
1252 pCompositor->cRects = 0;
1253 return VINF_SUCCESS;
1254 }
1255
1256 int rc = crVrScrCompositorRectsAssignBuffer(pCompositor, cRects);
1257 if (!RT_SUCCESS(rc))
1258 return rc;
1259
1260 VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER AssignerData;
1261 AssignerData.paSrcRects = pCompositor->paSrcRects;
1262 AssignerData.paDstRects = pCompositor->paDstRects;
1263 AssignerData.cRects = pCompositor->cRects;
1264 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsAssignerCb, &AssignerData);
1265 Assert(!AssignerData.cRects);
1266 return VINF_SUCCESS;
1267}
1268
1269
1270static int crVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1271{
1272 uint32_t fChangedFlags = 0;
1273 int rc = VBoxVrCompositorEntryRegionsAdd(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChangedFlags);
1274 if (!RT_SUCCESS(rc))
1275 {
1276 crWarning("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc);
1277 return rc;
1278 }
1279
1280 if (fChangedFlags & VBOXVR_COMPOSITOR_CF_COMPOSITED_REGIONS_CHANGED)
1281 {
1282 crVrScrCompositorRectsInvalidate(pCompositor);
1283 }
1284
1285 CrVrScrCompositorEntrySetChanged(pEntry, true);
1286
1287 if (pfChanged)
1288 *pfChanged = !!fChangedFlags;
1289 return VINF_SUCCESS;
1290}
1291
1292static int crVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1293{
1294 bool fChanged;
1295 int rc = VBoxVrCompositorEntryRegionsSet(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
1296 if (!RT_SUCCESS(rc))
1297 {
1298 crWarning("VBoxVrCompositorEntryRegionsSet failed, rc %d", rc);
1299 return rc;
1300 }
1301
1302 if (fChanged)
1303 {
1304 crVrScrCompositorRectsInvalidate(pCompositor);
1305 }
1306
1307 CrVrScrCompositorEntrySetChanged(pEntry, true);
1308
1309 if (pfChanged)
1310 *pfChanged = fChanged;
1311 return VINF_SUCCESS;
1312}
1313
1314static int crVrScrCompositorEntryPositionSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, bool *pfChanged)
1315{
1316 if (pEntry && (pEntry->Pos.x != pPos->x || pEntry->Pos.y != pPos->y))
1317 {
1318 int rc = VBoxVrCompositorEntryRegionsTranslate(&pCompositor->Compositor, &pEntry->Ce, pPos->x - pEntry->Pos.x, pPos->y - pEntry->Pos.y, pfChanged);
1319 if (!RT_SUCCESS(rc))
1320 {
1321 crWarning("VBoxVrCompositorEntryRegionsTranslate failed rc %d", rc);
1322 return rc;
1323 }
1324
1325 if (VBoxVrCompositorEntryIsInList(&pEntry->Ce))
1326 {
1327 crVrScrCompositorRectsInvalidate(pCompositor);
1328 }
1329
1330 pEntry->Pos = *pPos;
1331 CrVrScrCompositorEntrySetChanged(pEntry, true);
1332 }
1333 return VINF_SUCCESS;
1334}
1335
1336VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions)
1337{
1338 int rc;
1339 if (pPos)
1340 {
1341 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
1342 if (!RT_SUCCESS(rc))
1343 {
1344 crWarning("RegionsAdd: crVrScrCompositorEntryPositionSet failed rc %d", rc);
1345 return rc;
1346 }
1347 }
1348
1349 rc = crVrScrCompositorEntryRegionsAdd(pCompositor, pEntry, cRegions, paRegions, NULL);
1350 if (!RT_SUCCESS(rc))
1351 {
1352 crWarning("crVrScrCompositorEntryRegionsAdd failed, rc %d", rc);
1353 return rc;
1354 }
1355
1356 return VINF_SUCCESS;
1357}
1358
1359VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions)
1360{
1361 int rc = CrVrScrCompositorEntryRemove(pCompositor, pEntry);
1362 if (!RT_SUCCESS(rc))
1363 {
1364 crWarning("RegionsSet: CrVrScrCompositorEntryRemove failed rc %d", rc);
1365 return rc;
1366 }
1367
1368 if (pPos)
1369 {
1370 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
1371 if (!RT_SUCCESS(rc))
1372 {
1373 crWarning("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc);
1374 return rc;
1375 }
1376 }
1377
1378 rc = crVrScrCompositorEntryRegionsSet(pCompositor, pEntry, cRegions, paRegions, NULL);
1379 if (!RT_SUCCESS(rc))
1380 {
1381 crWarning("crVrScrCompositorEntryRegionsSet failed, rc %d", rc);
1382 return rc;
1383 }
1384
1385 return VINF_SUCCESS;
1386}
1387
1388VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos)
1389{
1390 int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
1391 if (!RT_SUCCESS(rc))
1392 {
1393 crWarning("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc);
1394 return rc;
1395 }
1396 return VINF_SUCCESS;
1397}
1398
1399/* regions are valid until the next CrVrScrCompositor call */
1400VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
1401{
1402 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
1403 if (!RT_SUCCESS(rc))
1404 {
1405 crWarning("crVrScrCompositorRectsCheckInit failed, rc %d", rc);
1406 return rc;
1407 }
1408
1409 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
1410
1411 *pcRegions = pEntry->cRects;
1412 if (ppaSrcRegions)
1413 *ppaSrcRegions = pEntry->paSrcRects;
1414 if (ppaDstRegions)
1415 *ppaDstRegions = pEntry->paDstRects;
1416
1417 return VINF_SUCCESS;
1418}
1419
1420VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
1421{
1422 if (!VBoxVrCompositorEntryRemove(&pCompositor->Compositor, &pEntry->Ce))
1423 return VINF_SUCCESS;
1424
1425 crVrScrCompositorRectsInvalidate(pCompositor);
1426 return VINF_SUCCESS;
1427}
1428
1429VBOXVREGDECL(int) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
1430{
1431 memset(pCompositor, 0, sizeof (*pCompositor));
1432 int rc = RTCritSectInit(&pCompositor->CritSect);
1433 if (RT_SUCCESS(rc))
1434 {
1435 VBoxVrCompositorInit(&pCompositor->Compositor, NULL);
1436 pCompositor->StretchX = 1.0;
1437 pCompositor->StretchY = 1.0;
1438 return VINF_SUCCESS;
1439 }
1440 else
1441 {
1442 crWarning("RTCritSectInit failed rc %d", rc);
1443 }
1444 return rc;
1445}
1446
1447VBOXVREGDECL(void) CrVrScrCompositorTerm(PVBOXVR_SCR_COMPOSITOR pCompositor)
1448{
1449 VBoxVrCompositorTerm(&pCompositor->Compositor);
1450 if (pCompositor->paDstRects)
1451 RTMemFree(pCompositor->paDstRects);
1452 if (pCompositor->paSrcRects)
1453 RTMemFree(pCompositor->paSrcRects);
1454
1455 RTCritSectDelete(&pCompositor->CritSect);
1456}
1457
1458
1459static DECLCALLBACK(bool) crVrScrCompositorEntrySetAllChangedCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
1460{
1461 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
1462 CrVrScrCompositorEntrySetChanged(pEntry, !!pvVisitor);
1463 return true;
1464}
1465
1466VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged)
1467{
1468 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorEntrySetAllChangedCb, (void*)fChanged);
1469}
1470
1471VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY)
1472{
1473 pCompositor->StretchX = StretchX;
1474 pCompositor->StretchY = StretchY;
1475 crVrScrCompositorRectsInvalidate(pCompositor);
1476 CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
1477}
1478
1479/* regions are valid until the next CrVrScrCompositor call */
1480VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
1481{
1482 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
1483 if (!RT_SUCCESS(rc))
1484 {
1485 crWarning("crVrScrCompositorRectsCheckInit failed, rc %d", rc);
1486 return rc;
1487 }
1488
1489 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
1490
1491 *pcRegions = pCompositor->cRects;
1492 if (ppaSrcRegions)
1493 *ppaSrcRegions = pCompositor->paSrcRects;
1494 if (ppaDstRegions)
1495 *ppaDstRegions = pCompositor->paDstRects;
1496
1497 return VINF_SUCCESS;
1498}
1499
1500typedef struct VBOXVR_SCR_COMPOSITOR_VISITOR_CB
1501{
1502 PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor;
1503 void *pvVisitor;
1504} VBOXVR_SCR_COMPOSITOR_VISITOR_CB, *PVBOXVR_SCR_COMPOSITOR_VISITOR_CB;
1505
1506static DECLCALLBACK(bool) crVrScrCompositorVisitCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
1507{
1508 PVBOXVR_SCR_COMPOSITOR_VISITOR_CB pData = (PVBOXVR_SCR_COMPOSITOR_VISITOR_CB)pvVisitor;
1509 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
1510 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
1511 return pData->pfnVisitor(pCompositor, pEntry, pData->pvVisitor);
1512}
1513
1514VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
1515{
1516 VBOXVR_SCR_COMPOSITOR_VISITOR_CB Data;
1517 Data.pfnVisitor = pfnVisitor;
1518 Data.pvVisitor = pvVisitor;
1519 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorVisitCb, &Data);
1520}
Note: See TracBrowser for help on using the repository browser.

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