VirtualBox

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

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

crOpenGL: vreg fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.1 KB
Line 
1/* $Id: vreg.cpp 45627 2013-04-19 06:09:30Z 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 VBOXVR_REG *pReg1, const VBOXVR_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 vboxVrDbgListVerify(pList);
165}
166
167static void vboxVrListRegAddOrder(PVBOXVR_LIST pList, PRTLISTNODE pMemberEntry, PVBOXVR_REG pReg)
168{
169 do
170 {
171 if (pMemberEntry != &pList->ListHead)
172 {
173 PVBOXVR_REG pMemberReg = PVBOXVR_REG_FROM_ENTRY(pMemberEntry);
174 if (vboxVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0)
175 {
176 pMemberEntry = pMemberEntry->pNext;
177 continue;
178 }
179 }
180 vboxVrListRegAdd(pList, pReg, pMemberEntry, false);
181 break;
182 } while (1);
183}
184
185static void vboxVrListAddNonintersected(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
186{
187 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
188
189 for (PRTLISTNODE pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.pNext)
190 {
191 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
192 do {
193 if (pEntry1 != &pList1->ListHead)
194 {
195 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
196 if (vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0)
197 {
198 pEntry1 = pEntry1->pNext;
199 continue;
200 }
201 }
202 vboxVrListRegRemove(pList2, pReg2);
203 vboxVrListRegAdd(pList1, pReg2, pEntry1, false);
204 break;
205 } while (1);
206 }
207
208 Assert(VBoxVrListIsEmpty(pList2));
209}
210
211static int vboxVrListRegIntersectSubstNoJoin(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2)
212{
213 uint32_t topLim = VBOXVR_INVALID_COORD;
214 uint32_t bottomLim = VBOXVR_INVALID_COORD;
215 RTLISTNODE List;
216 PVBOXVR_REG pBottomReg = NULL;
217#ifdef DEBUG_misha
218 RTRECT tmpRect = pReg1->Rect;
219 vboxVrDbgListVerify(pList1);
220#endif
221 Assert(!VBoxRectIsZero(pRect2));
222
223 RTListInit(&List);
224
225 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
226
227 if (pReg1->Rect.yTop < pRect2->yTop)
228 {
229 Assert(pRect2->yTop < pReg1->Rect.yBottom);
230 PVBOXVR_REG pRegResult = vboxVrRegCreate();
231 pRegResult->Rect.yTop = pReg1->Rect.yTop;
232 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
233 pRegResult->Rect.yBottom = pRect2->yTop;
234 pRegResult->Rect.xRight = pReg1->Rect.xRight;
235 topLim = pRect2->yTop;
236 RTListAppend(&List, &pRegResult->ListEntry);
237 }
238
239 if (pReg1->Rect.yBottom > pRect2->yBottom)
240 {
241 Assert(pRect2->yBottom > pReg1->Rect.yTop);
242 PVBOXVR_REG pRegResult = vboxVrRegCreate();
243 pRegResult->Rect.yTop = pRect2->yBottom;
244 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
245 pRegResult->Rect.yBottom = pReg1->Rect.yBottom;
246 pRegResult->Rect.xRight = pReg1->Rect.xRight;
247 bottomLim = pRect2->yBottom;
248 pBottomReg = pRegResult;
249 }
250
251 if (pReg1->Rect.xLeft < pRect2->xLeft)
252 {
253 Assert(pRect2->xLeft < pReg1->Rect.xRight);
254 PVBOXVR_REG pRegResult = vboxVrRegCreate();
255 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
256 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
257 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
258 pRegResult->Rect.xRight = pRect2->xLeft;
259 RTListAppend(&List, &pRegResult->ListEntry);
260 }
261
262 if (pReg1->Rect.xRight > pRect2->xRight)
263 {
264 Assert(pRect2->xRight > pReg1->Rect.xLeft);
265 PVBOXVR_REG pRegResult = vboxVrRegCreate();
266 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
267 pRegResult->Rect.xLeft = pRect2->xRight;
268 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
269 pRegResult->Rect.xRight = pReg1->Rect.xRight;
270 RTListAppend(&List, &pRegResult->ListEntry);
271 }
272
273 if (pBottomReg)
274 RTListAppend(&List, &pBottomReg->ListEntry);
275
276 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
277 vboxVrListRegRemove(pList1, pReg1);
278 vboxVrRegTerm(pReg1);
279
280 if (RTListIsEmpty(&List))
281 return VINF_SUCCESS; /* the region is covered by the pRect2 */
282
283 PRTLISTNODE pEntry = List.pNext, pNext;
284 for (; pEntry != &List; pEntry = pNext)
285 {
286 pNext = pEntry->pNext;
287 PVBOXVR_REG pReg = PVBOXVR_REG_FROM_ENTRY(pEntry);
288
289 vboxVrListRegAddOrder(pList1, pMemberEntry, pReg);
290 pMemberEntry = pEntry->pNext; /* the following elements should go after the given pEntry since they are ordered already */
291 }
292 return VINF_SUCCESS;
293}
294
295/* @returns Entry to be used for continuing the rectangles iterations being made currently on the callback call.
296 * ListHead is returned to break the current iteration
297 * @param ppNext specifies next reg entry to be used for iteration. the default is pReg1->ListEntry.pNext */
298typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_INTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2, void *pvContext, PRTLISTNODE *ppNext);
299typedef FNVBOXVR_CB_INTERSECTED_VISITOR *PFNVBOXVR_CB_INTERSECTED_VISITOR;
300
301static void vboxVrListVisitIntersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
302{
303 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
304 PRTLISTNODE pNext1;
305 uint32_t iFirst2 = 0;
306
307 for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
308 {
309 pNext1 = pEntry1->pNext;
310 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
311 for (uint32_t i = iFirst2; i < cRects; ++i)
312 {
313 const RTRECT *pRect2 = &aRects[i];
314 if (VBoxRectIsZero(pRect2))
315 continue;
316
317 if (!VBoxRectIsIntersect(&pReg1->Rect, pRect2))
318 continue;
319
320 /* the visitor can modify the list 1, apply necessary adjustments after it */
321 pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1);
322 if (pEntry1 == &pList1->ListHead)
323 break;
324 else
325 pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
326 }
327 }
328}
329
330/* @returns Entry to be iterated next. ListHead is returned to break the iteration
331 *
332 */
333typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_NONINTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext);
334typedef FNVBOXVR_CB_NONINTERSECTED_VISITOR *PFNVBOXVR_CB_NONINTERSECTED_VISITOR;
335
336static void vboxVrListVisitNonintersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_NONINTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
337{
338 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
339 PRTLISTNODE pNext1;
340 uint32_t iFirst2 = 0;
341
342 for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
343 {
344 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
345 uint32_t i = iFirst2;
346 for (; i < cRects; ++i)
347 {
348 const RTRECT *pRect2 = &aRects[i];
349 if (VBoxRectIsZero(pRect2))
350 continue;
351
352 if (VBoxRectIsIntersect(&pReg1->Rect, pRect2))
353 break;
354 }
355
356 if (i == cRects)
357 pNext1 = pfnVisitor(pList1, pReg1, pvVisitor);
358 else
359 pNext1 = pEntry1->pNext;
360 }
361}
362
363static void vboxVrListJoinRectsHV(PVBOXVR_LIST pList, bool fHorizontal)
364{
365 PRTLISTNODE pNext1, pNext2;
366
367 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
368 {
369 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
370 pNext1 = pEntry1->pNext;
371 for (PRTLISTNODE pEntry2 = pEntry1->pNext; pEntry2 != &pList->ListHead; pEntry2 = pNext2)
372 {
373 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
374 pNext2 = pEntry2->pNext;
375 if (fHorizontal)
376 {
377 if (pReg1->Rect.yTop == pReg2->Rect.yTop)
378 {
379 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
380 {
381 /* join rectangles */
382 vboxVrListRegRemove(pList, pReg2);
383 if (pReg1->Rect.yBottom > pReg2->Rect.yBottom)
384 {
385 int32_t oldRight1 = pReg1->Rect.xRight;
386 int32_t oldBottom1 = pReg1->Rect.yBottom;
387 pReg1->Rect.xRight = pReg2->Rect.xRight;
388 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
389
390 vboxVrDbgListVerify(pList);
391
392 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
393 pReg2->Rect.yTop = pReg1->Rect.yBottom;
394 pReg2->Rect.xRight = oldRight1;
395 pReg2->Rect.yBottom = oldBottom1;
396 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
397 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
398 * and thus can match one of the previous rects */
399 pNext1 = pList->ListHead.pNext;
400 break;
401 }
402 else if (pReg1->Rect.yBottom < pReg2->Rect.yBottom)
403 {
404 pReg1->Rect.xRight = pReg2->Rect.xRight;
405 vboxVrDbgListVerify(pList);
406 pReg2->Rect.yTop = pReg1->Rect.yBottom;
407 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
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
414 {
415 pReg1->Rect.xRight = pReg2->Rect.xRight;
416 vboxVrDbgListVerify(pList);
417 /* reset the pNext1 since it could be the pReg2 being destroyed */
418 pNext1 = pEntry1->pNext;
419 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
420 vboxVrRegTerm(pReg2);
421 }
422 }
423 continue;
424 }
425 else if (pReg1->Rect.yBottom == pReg2->Rect.yBottom)
426 {
427 Assert(pReg1->Rect.yTop < pReg2->Rect.yTop); /* <- since pReg1 > pReg2 && pReg1->Rect.yTop != pReg2->Rect.yTop*/
428 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
429 {
430 /* join rectangles */
431 vboxVrListRegRemove(pList, pReg2);
432
433 pReg1->Rect.yBottom = pReg2->Rect.yTop;
434 vboxVrDbgListVerify(pList);
435 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
436
437 vboxVrListRegAddOrder(pList, pNext2, pReg2);
438
439 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
440 * and thus can match one of the previous rects */
441 pNext1 = pList->ListHead.pNext;
442 break;
443 }
444 else if (pReg1->Rect.xLeft == pReg2->Rect.xRight)
445 {
446 /* join rectangles */
447 vboxVrListRegRemove(pList, pReg2);
448
449 pReg1->Rect.yBottom = pReg2->Rect.yTop;
450 vboxVrDbgListVerify(pList);
451 pReg2->Rect.xRight = pReg1->Rect.xRight;
452
453 vboxVrListRegAddOrder(pList, pNext2, pReg2);
454
455 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
456 * and thus can match one of the previous rects */
457 pNext1 = pList->ListHead.pNext;
458 break;
459 }
460 continue;
461 }
462 }
463 else
464 {
465 if (pReg1->Rect.yBottom == pReg2->Rect.yTop)
466 {
467 if (pReg1->Rect.xLeft == pReg2->Rect.xLeft)
468 {
469 if (pReg1->Rect.xRight == pReg2->Rect.xRight)
470 {
471 /* join rects */
472 vboxVrListRegRemove(pList, pReg2);
473
474 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
475 vboxVrDbgListVerify(pList);
476
477 /* reset the pNext1 since it could be the pReg2 being destroyed */
478 pNext1 = pEntry1->pNext;
479 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
480 vboxVrRegTerm(pReg2);
481 continue;
482 }
483 /* no more to be done for for pReg1 */
484 break;
485 }
486 else if (pReg1->Rect.xRight > pReg2->Rect.xLeft)
487 {
488 /* no more to be done for for pReg1 */
489 break;
490 }
491
492 continue;
493 }
494 else if (pReg1->Rect.yBottom < pReg2->Rect.yTop)
495 {
496 /* no more to be done for for pReg1 */
497 break;
498 }
499 }
500 }
501 }
502}
503
504static void vboxVrListJoinRects(PVBOXVR_LIST pList)
505{
506 vboxVrListJoinRectsHV(pList, true);
507 vboxVrListJoinRectsHV(pList, false);
508}
509
510typedef struct VBOXVR_CBDATA_SUBST
511{
512 int rc;
513 bool fChanged;
514} VBOXVR_CBDATA_SUBST, *PVBOXVR_CBDATA_SUBST;
515
516static DECLCALLBACK(PRTLISTNODE) vboxVrListSubstNoJoinCb(PVBOXVR_LIST pList, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
517{
518 PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
519 /* store the prev to get the new pNext out of it*/
520 PRTLISTNODE pPrev = pReg1->ListEntry.pPrev;
521 pData->fChanged = true;
522
523 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
524
525 /* NOTE: the pReg1 will be invalid after the vboxVrListRegIntersectSubstNoJoin call!!! */
526 int rc = vboxVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2);
527 if (RT_SUCCESS(rc))
528 {
529 *ppNext = pPrev->pNext;
530 return &pList->ListHead;
531 }
532 WARN(("vboxVrListRegIntersectSubstNoJoin failed!"));
533 Assert(!RT_SUCCESS(rc));
534 pData->rc = rc;
535 *ppNext = &pList->ListHead;
536 return &pList->ListHead;
537}
538
539static int vboxVrListSubstNoJoin(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
540{
541 *pfChanged = false;
542
543 if (VBoxVrListIsEmpty(pList))
544 return VINF_SUCCESS;
545
546 VBOXVR_CBDATA_SUBST Data;
547 Data.rc = VINF_SUCCESS;
548 Data.fChanged = false;
549
550 vboxVrListVisitIntersected(pList, cRects, aRects, vboxVrListSubstNoJoinCb, &Data);
551 if (!RT_SUCCESS(Data.rc))
552 {
553 WARN(("vboxVrListVisitIntersected failed!"));
554 return Data.rc;
555 }
556
557 *pfChanged = Data.fChanged;
558 return VINF_SUCCESS;
559}
560
561#if 0
562static const RTRECT * vboxVrRectsOrder(uint32_t cRects, const RTRECT * aRects)
563{
564#ifdef DEBUG
565 {
566 for (uint32_t i = 0; i < cRects; ++i)
567 {
568 RTRECT *pRectI = &aRects[i];
569 for (uint32_t j = i + 1; j < cRects; ++j)
570 {
571 RTRECT *pRectJ = &aRects[j];
572 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
573 }
574 }
575 }
576#endif
577
578 RTRECT * pRects = (RTRECT *)aRects;
579 /* check if rects are ordered already */
580 for (uint32_t i = 0; i < cRects - 1; ++i)
581 {
582 RTRECT *pRect1 = &pRects[i];
583 RTRECT *pRect2 = &pRects[i+1];
584 if (vboxVrRegNonintersectedComparator(pRect1, pRect2) < 0)
585 continue;
586
587 WARN(("rects are unoreded!"));
588
589 if (pRects == aRects)
590 {
591 pRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cRects);
592 if (!pRects)
593 {
594 WARN(("RTMemAlloc failed!"));
595 return NULL;
596 }
597
598 memcpy(pRects, aRects, sizeof (RTRECT) * cRects);
599 }
600
601 Assert(pRects != aRects);
602
603 int j = (int)i - 1;
604 do {
605 RTRECT Tmp = *pRect1;
606 *pRect1 = *pRect2;
607 *pRect2 = Tmp;
608
609 if (j < 0)
610 break;
611
612 if (vboxVrRegNonintersectedComparator(pRect1, pRect1-1) > 0)
613 break;
614
615 pRect2 = pRect1--;
616 --j;
617 } while (1);
618 }
619
620 return pRects;
621}
622#endif
623
624VBOXVREGDECL(void) VBoxVrListTranslate(PVBOXVR_LIST pList, int32_t x, int32_t y)
625{
626 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
627 {
628 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
629 VBoxRectTranslate(&pReg1->Rect, x, y);
630 }
631}
632
633static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinNonintersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext)
634{
635 VBOXVR_CBDATA_SUBST *pData = (VBOXVR_CBDATA_SUBST*)pvContext;
636
637 PRTLISTNODE pNext = pReg1->ListEntry.pNext;
638
639 vboxVrDbgListVerify(pList1);
640
641 vboxVrListRegRemove(pList1, pReg1);
642 vboxVrRegTerm(pReg1);
643
644 vboxVrDbgListVerify(pList1);
645
646 pData->fChanged = true;
647
648 return pNext;
649}
650
651static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinIntersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
652{
653 PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
654 pData->fChanged = true;
655
656 vboxVrDbgListVerify(pList1);
657
658 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
659
660 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
661 Assert(!VBoxRectIsZero(pRect2));
662
663 vboxVrListRegRemove(pList1, pReg1);
664 VBoxRectIntersect(&pReg1->Rect, pRect2);
665 Assert(!VBoxRectIsZero(&pReg1->Rect));
666
667 vboxVrListRegAddOrder(pList1, pMemberEntry, pReg1);
668
669 vboxVrDbgListVerify(pList1);
670
671 return &pReg1->ListEntry;
672}
673
674static int vboxVrListIntersectNoJoin(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged)
675{
676 bool fChanged = false;
677 *pfChanged = false;
678
679 if (VBoxVrListIsEmpty(pList))
680 return VINF_SUCCESS;
681
682 if (VBoxVrListIsEmpty(pList2))
683 {
684 if (pfChanged)
685 *pfChanged = true;
686
687 VBoxVrListClear(pList);
688 return VINF_SUCCESS;
689 }
690
691 PRTLISTNODE pNext1;
692
693 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
694 {
695 pNext1 = pEntry1->pNext;
696 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
697 RTRECT RegRect1 = pReg1->Rect;
698 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
699
700 for (const RTLISTNODE *pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pEntry2->pNext)
701 {
702 const VBOXVR_REG *pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
703 const RTRECT *pRect2 = &pReg2->Rect;
704
705 if (!VBoxRectIsIntersect(&RegRect1, pRect2))
706 continue;
707
708 if (pReg1)
709 {
710 if (!VBoxRectCmp(&pReg1->Rect, pRect2))
711 {
712 /* no change, and we can break the iteration here */
713
714 /* zero up the pReg1 to mark it as intersected (see the code after this inner loop) */
715 pReg1 = NULL;
716 break;
717 }
718 /* @todo: this can have false-alarming sometimes if the separated rects will then be joind into the original rect,
719 * so far this should not be a problem for VReg clients, so keep it this way for now */
720 fChanged = true;
721
722 /* re-use the reg entry */
723 vboxVrListRegRemove(pList, pReg1);
724 VBoxRectIntersect(&pReg1->Rect, pRect2);
725 Assert(!VBoxRectIsZero(&pReg1->Rect));
726
727 vboxVrListRegAddOrder(pList, pMemberEntry, pReg1);
728 pReg1 = NULL;
729 }
730 else
731 {
732 Assert(fChanged); /* <- should be set by the if branch above */
733 PVBOXVR_REG pReg = vboxVrRegCreate();
734 if (!pReg)
735 {
736 WARN(("vboxVrRegCreate failed!"));
737 return VERR_NO_MEMORY;
738 }
739 VBoxRectIntersected(&RegRect1, pRect2, &pReg->Rect);
740 Assert(!VBoxRectIsZero(&pReg->Rect));
741 vboxVrListRegAddOrder(pList, pList->ListHead.pNext, pReg);
742 }
743 }
744
745 if (pReg1)
746 {
747 /* the region has no intersections, remove it */
748 vboxVrListRegRemove(pList, pReg1);
749 vboxVrRegTerm(pReg1);
750 fChanged = true;
751 }
752 }
753
754 *pfChanged = fChanged;
755 return VINF_SUCCESS;
756}
757
758VBOXVREGDECL(int) VBoxVrListIntersect(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged)
759{
760 if (pfChanged)
761 *pfChanged = false;
762
763 int rc = vboxVrListIntersectNoJoin(pList, pList2, pfChanged);
764 if (!RT_SUCCESS(rc))
765 {
766 WARN(("vboxVrListSubstNoJoin failed!"));
767 return rc;
768 }
769
770 if (*pfChanged)
771 {
772 vboxVrListJoinRects(pList);
773 }
774
775 return rc;
776}
777
778VBOXVREGDECL(int) VBoxVrListRectsIntersect(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
779{
780 if (pfChanged)
781 *pfChanged = false;
782
783 if (VBoxVrListIsEmpty(pList))
784 return VINF_SUCCESS;
785
786 if (!cRects)
787 {
788 if (pfChanged)
789 *pfChanged = true;
790
791 VBoxVrListClear(pList);
792 return VINF_SUCCESS;
793 }
794
795 /* we perform intersection using lists because the algorythm axpects the rects to be non-intersected,
796 * which list guaranties to us */
797
798 VBOXVR_LIST TmpList;
799 VBoxVrListInit(&TmpList);
800
801 int rc = VBoxVrListRectsAdd(&TmpList, cRects, aRects, NULL);
802 if (RT_SUCCESS(rc))
803 {
804 rc = VBoxVrListIntersect(pList, &TmpList, pfChanged);
805 if (!RT_SUCCESS(rc))
806 {
807 WARN(("VBoxVrListIntersect failed! rc %d", rc));
808 }
809 }
810 else
811 {
812 WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
813 }
814 VBoxVrListClear(&TmpList);
815
816 return rc;
817}
818
819VBOXVREGDECL(int) VBoxVrListRectsSubst(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
820{
821#if 0
822 const RTRECT * pRects = vboxVrRectsOrder(cRects, aRects);
823 if (!pRects)
824 {
825 WARN(("vboxVrRectsOrder failed!"));
826 return VERR_NO_MEMORY;
827 }
828#endif
829
830 int rc = vboxVrListSubstNoJoin(pList, cRects, aRects, pfChanged);
831 if (!RT_SUCCESS(rc))
832 {
833 WARN(("vboxVrListSubstNoJoin failed!"));
834 goto done;
835 }
836
837 if (!*pfChanged)
838 goto done;
839
840 vboxVrListJoinRects(pList);
841
842done:
843#if 0
844 if (pRects != aRects)
845 RTMemFree(pRects);
846#endif
847 return rc;
848}
849
850VBOXVREGDECL(int) VBoxVrListRectsSet(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
851{
852 if (pfChanged)
853 *pfChanged = false;
854
855 if (!cRects && VBoxVrListIsEmpty(pList))
856 {
857 return VINF_SUCCESS;
858 }
859
860 /* @todo: fChanged will have false alarming here, fix if needed */
861 VBoxVrListClear(pList);
862
863 int rc = VBoxVrListRectsAdd(pList, cRects, aRects, NULL);
864 if (!RT_SUCCESS(rc))
865 {
866 WARN(("VBoxVrListRectsSet failed rc %d", rc));
867 return rc;
868 }
869
870 if (pfChanged)
871 *pfChanged = true;
872
873 return VINF_SUCCESS;
874}
875
876VBOXVREGDECL(int) VBoxVrListRectsAdd(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
877{
878 uint32_t cCovered = 0;
879
880 if (pfChanged)
881 *pfChanged = false;
882
883#if 0
884#ifdef DEBUG
885 {
886 for (uint32_t i = 0; i < cRects; ++i)
887 {
888 RTRECT *pRectI = &aRects[i];
889 for (uint32_t j = i + 1; j < cRects; ++j)
890 {
891 RTRECT *pRectJ = &aRects[j];
892 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
893 }
894 }
895 }
896#endif
897#endif
898
899 /* early sort out the case when there are no new rects */
900 for (uint32_t i = 0; i < cRects; ++i)
901 {
902 if (VBoxRectIsZero(&aRects[i]))
903 {
904 cCovered++;
905 continue;
906 }
907
908 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
909 {
910 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
911
912 if (VBoxRectIsCoveres(&pReg1->Rect, &aRects[i]))
913 {
914 cCovered++;
915 break;
916 }
917 }
918 }
919
920 if (cCovered == cRects)
921 return VINF_SUCCESS;
922
923 /* rects are not covered, need to go the slow way */
924
925 VBOXVR_LIST DiffList;
926 VBoxVrListInit(&DiffList);
927 RTRECT * pListRects = NULL;
928 uint32_t cAllocatedRects = 0;
929 bool fNeedRectreate = true;
930 bool fChanged = false;
931 int rc = VINF_SUCCESS;
932
933 for (uint32_t i = 0; i < cRects; ++i)
934 {
935 if (VBoxRectIsZero(&aRects[i]))
936 continue;
937
938 PVBOXVR_REG pReg = vboxVrRegCreate();
939 if (!pReg)
940 {
941 WARN(("vboxVrRegCreate failed!"));
942 rc = VERR_NO_MEMORY;
943 break;
944 }
945 pReg->Rect = aRects[i];
946
947 uint32_t cListRects = VBoxVrListRectsCount(pList);
948 if (!cListRects)
949 {
950 vboxVrListRegAdd(pList, pReg, &pList->ListHead, false);
951 fChanged = true;
952 continue;
953 }
954 else
955 {
956 Assert(VBoxVrListIsEmpty(&DiffList));
957 vboxVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, false);
958 }
959
960 if (cAllocatedRects < cListRects)
961 {
962 cAllocatedRects = cListRects + cRects;
963 Assert(fNeedRectreate);
964 if (pListRects)
965 RTMemFree(pListRects);
966 pListRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cAllocatedRects);
967 if (!pListRects)
968 {
969 WARN(("RTMemAlloc failed!"));
970 rc = VERR_NO_MEMORY;
971 break;
972 }
973 }
974
975
976 if (fNeedRectreate)
977 {
978 rc = VBoxVrListRectsGet(pList, cListRects, pListRects);
979 Assert(rc == VINF_SUCCESS);
980 fNeedRectreate = false;
981 }
982
983 bool fDummyChanged = false;
984 rc = vboxVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged);
985 if (!RT_SUCCESS(rc))
986 {
987 WARN(("vboxVrListSubstNoJoin failed!"));
988 rc = VERR_NO_MEMORY;
989 break;
990 }
991
992 if (!VBoxVrListIsEmpty(&DiffList))
993 {
994 vboxVrListAddNonintersected(pList, &DiffList);
995 fNeedRectreate = true;
996 fChanged = true;
997 }
998
999 Assert(VBoxVrListIsEmpty(&DiffList));
1000 }
1001
1002 if (pListRects)
1003 RTMemFree(pListRects);
1004
1005 Assert(VBoxVrListIsEmpty(&DiffList) || rc != VINF_SUCCESS);
1006 VBoxVrListClear(&DiffList);
1007
1008 if (fChanged)
1009 vboxVrListJoinRects(pList);
1010
1011 if (pfChanged)
1012 *pfChanged = fChanged;
1013
1014 return VINF_SUCCESS;
1015}
1016
1017VBOXVREGDECL(int) VBoxVrListRectsGet(PVBOXVR_LIST pList, uint32_t cRects, RTRECT * aRects)
1018{
1019 if (cRects < VBoxVrListRectsCount(pList))
1020 return VERR_BUFFER_OVERFLOW;
1021
1022 uint32_t i = 0;
1023 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext, ++i)
1024 {
1025 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
1026 aRects[i] = pReg1->Rect;
1027 }
1028 return VINF_SUCCESS;
1029}
1030
1031VBOXVREGDECL(int) VBoxVrListCmp(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
1032{
1033 int cTmp = pList1->cEntries - pList2->cEntries;
1034 if (cTmp)
1035 return cTmp;
1036
1037 PVBOXVR_REG pReg1, pReg2;
1038
1039 for (pReg1 = RTListNodeGetNext(&pList1->ListHead, VBOXVR_REG, ListEntry),
1040 pReg2 = RTListNodeGetNext(&pList2->ListHead, VBOXVR_REG, ListEntry);
1041 !RTListNodeIsDummy(&pList1->ListHead, pReg1, VBOXVR_REG, ListEntry);
1042 pReg1 = RT_FROM_MEMBER(pReg1->ListEntry.pNext, VBOXVR_REG, ListEntry),
1043 pReg2 = RT_FROM_MEMBER(pReg2->ListEntry.pNext, VBOXVR_REG, ListEntry))
1044 {
1045 Assert(!RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
1046 cTmp = VBoxRectCmp(&pReg1->Rect, &pReg2->Rect);
1047 if (cTmp)
1048 return cTmp;
1049 }
1050 Assert(RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
1051 return 0;
1052}
1053
1054VBOXVREGDECL(void) VBoxVrCompositorInit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_ENTRY_REMOVED pfnEntryRemoved)
1055{
1056 RTListInit(&pCompositor->List);
1057 pCompositor->pfnEntryRemoved = pfnEntryRemoved;
1058}
1059
1060VBOXVREGDECL(void) VBoxVrCompositorTerm(PVBOXVR_COMPOSITOR pCompositor)
1061{
1062 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
1063 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1064 {
1065 VBoxVrCompositorEntryRemove(pCompositor, pEntry);
1066 }
1067}
1068
1069DECLINLINE(void) vboxVrCompositorEntryAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
1070{
1071 RTListPrepend(&pCompositor->List, &pEntry->Node);
1072}
1073
1074DECLINLINE(void) vboxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
1075{
1076 RTListNodeRemove(&pEntry->Node);
1077 if (pCompositor->pfnEntryRemoved)
1078 pCompositor->pfnEntryRemoved(pCompositor, pEntry, pReplacingEntry);
1079}
1080
1081VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry)
1082{
1083 VBoxVrListInit(&pEntry->Vr);
1084}
1085
1086VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
1087{
1088 if (!VBoxVrCompositorEntryIsInList(pEntry))
1089 return false;
1090 VBoxVrListClear(&pEntry->Vr);
1091 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1092 return true;
1093}
1094
1095static int vboxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
1096{
1097 bool fChanged;
1098 int rc = VBoxVrListRectsSubst(&pEntry->Vr, cRects, paRects, &fChanged);
1099 if (RT_SUCCESS(rc))
1100 {
1101 if (VBoxVrListIsEmpty(&pEntry->Vr))
1102 {
1103 Assert(fChanged);
1104 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1105 }
1106 if (pfChanged)
1107 *pfChanged = false;
1108 return VINF_SUCCESS;
1109 }
1110
1111 WARN(("VBoxVrListRectsSubst failed, rc %d", rc));
1112 return rc;
1113}
1114
1115VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, uint32_t *pfChangeFlags)
1116{
1117 bool fOthersChanged = false, fCurChanged = false, fEntryChanged = false, fEntryWasInList = false, fEntryReplaced = false;
1118 PVBOXVR_COMPOSITOR_ENTRY pCur;
1119 int rc = VINF_SUCCESS;
1120
1121 if (!cRects)
1122 {
1123 if (pfChangeFlags)
1124 *pfChangeFlags = 0;
1125 return VINF_SUCCESS;
1126 }
1127
1128 if (pEntry)
1129 {
1130 fEntryWasInList = VBoxVrCompositorEntryIsInList(pEntry);
1131 rc = VBoxVrListRectsAdd(&pEntry->Vr, cRects, paRects, &fEntryChanged);
1132 if (RT_SUCCESS(rc))
1133 {
1134 if (VBoxVrListIsEmpty(&pEntry->Vr))
1135 {
1136// WARN(("Empty rectangles passed in, is it expected?"));
1137 if (pfChangeFlags)
1138 *pfChangeFlags = 0;
1139 return VINF_SUCCESS;
1140 }
1141 }
1142 else
1143 {
1144 WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
1145 return rc;
1146 }
1147
1148 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1149 }
1150
1151 RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
1152 {
1153 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1154 if (pCur == pEntry)
1155 {
1156 Assert(fEntryWasInList);
1157 }
1158 else
1159 {
1160 if (pEntry && !VBoxVrListCmp(&pCur->Vr, &pEntry->Vr))
1161 {
1162 VBoxVrListClear(&pCur->Vr);
1163 vboxVrCompositorEntryRemove(pCompositor, pCur, pEntry);
1164 fEntryReplaced = true;
1165 break;
1166 }
1167 else
1168 {
1169 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, &fCurChanged);
1170 if (RT_SUCCESS(rc))
1171 fOthersChanged |= fCurChanged;
1172 else
1173 {
1174 WARN(("vboxVrCompositorEntryRegionsSubst failed, rc %d", rc));
1175 return rc;
1176 }
1177 }
1178 }
1179 }
1180
1181 AssertRC(rc);
1182
1183 if (pEntry && !fEntryWasInList)
1184 {
1185 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1186 vboxVrCompositorEntryAdd(pCompositor, pEntry);
1187 }
1188
1189 if (pfChangeFlags)
1190 {
1191 uint32_t fFlags = 0;
1192 if (fOthersChanged)
1193 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED;
1194 else if (fEntryReplaced)
1195 {
1196 Assert(fEntryChanged);
1197 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED;
1198 }
1199 else if (fEntryChanged)
1200 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED;
1201
1202 if (!fEntryWasInList)
1203 Assert(fEntryChanged);
1204
1205 *pfChangeFlags = fFlags;
1206 }
1207
1208 return VINF_SUCCESS;
1209}
1210
1211VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
1212{
1213 if (!pEntry)
1214 {
1215 WARN(("VBoxVrCompositorEntryRegionsSubst called with zero entry, unsupported!"));
1216 if (pfChanged)
1217 *pfChanged = false;
1218 return VERR_INVALID_PARAMETER;
1219 }
1220
1221 if (VBoxVrListIsEmpty(&pEntry->Vr))
1222 {
1223 if (pfChanged)
1224 *pfChanged = false;
1225 return VINF_SUCCESS;
1226
1227 }
1228
1229 int rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pEntry, cRects, paRects, pfChanged);
1230 if (RT_SUCCESS(rc))
1231 return VINF_SUCCESS;
1232
1233 WARN(("pfChanged failed, rc %d", rc));
1234 return rc;
1235}
1236
1237VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
1238{
1239 if (!pEntry)
1240 {
1241 WARN(("VBoxVrCompositorEntryRegionsSet called with zero entry, unsupported!"));
1242 if (pfChanged)
1243 *pfChanged = false;
1244 return VERR_INVALID_PARAMETER;
1245 }
1246
1247 bool fChanged = false, fCurChanged = false;
1248 uint32_t fChangeFlags = 0;
1249 int rc;
1250 fCurChanged = VBoxVrCompositorEntryRemove(pCompositor, pEntry);
1251 fChanged |= fCurChanged;
1252
1253 rc = VBoxVrCompositorEntryRegionsAdd(pCompositor, pEntry, cRects, paRects, &fChangeFlags);
1254 if (RT_SUCCESS(rc))
1255 fChanged |= !!fChangeFlags;
1256 else
1257 {
1258 WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
1259 return rc;
1260 }
1261
1262 AssertRC(rc);
1263
1264 if (pfChanged)
1265 *pfChanged = fChanged;
1266 return VINF_SUCCESS;
1267}
1268
1269VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
1270{
1271 int rc = VINF_SUCCESS;
1272 bool fChanged = false;
1273 if (VBoxVrCompositorEntryIsInList(pEntry))
1274 {
1275 rc = VBoxVrListIntersect(&pEntry->Vr, pList2, &fChanged);
1276 if (RT_SUCCESS(rc))
1277 {
1278 if (VBoxVrListIsEmpty(&pEntry->Vr))
1279 {
1280 Assert(fChanged);
1281 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1282 }
1283 }
1284 else
1285 {
1286 WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
1287 }
1288 }
1289
1290 if (pfChanged)
1291 *pfChanged = fChanged;
1292
1293 return rc;
1294}
1295
1296VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
1297{
1298 int rc = VINF_SUCCESS;
1299 bool fChanged = false;
1300 if (VBoxVrCompositorEntryIsInList(pEntry))
1301 {
1302 rc = VBoxVrListRectsIntersect(&pEntry->Vr, cRects, paRects, &fChanged);
1303 if (RT_SUCCESS(rc))
1304 {
1305 if (VBoxVrListIsEmpty(&pEntry->Vr))
1306 {
1307 Assert(fChanged);
1308 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1309 }
1310 }
1311 else
1312 {
1313 WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
1314 }
1315 }
1316
1317 if (pfChanged)
1318 *pfChanged = fChanged;
1319
1320 return rc;
1321}
1322
1323VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersectAll(PVBOXVR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
1324{
1325 VBOXVR_COMPOSITOR_ITERATOR Iter;
1326 VBoxVrCompositorIterInit(pCompositor, &Iter);
1327 PVBOXVR_COMPOSITOR_ENTRY pEntry;
1328 int rc = VINF_SUCCESS;
1329 bool fChanged = false;
1330
1331 while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
1332 {
1333 bool fTmpChanged = false;
1334 int tmpRc = VBoxVrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
1335 if (RT_SUCCESS(tmpRc))
1336 {
1337 fChanged |= fChanged;
1338 }
1339 else
1340 {
1341 WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1342 rc = tmpRc;
1343 }
1344 }
1345
1346 if (pfChanged)
1347 *pfChanged = fChanged;
1348
1349 return rc;
1350}
1351
1352VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersectAll(PVBOXVR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1353{
1354 VBOXVR_COMPOSITOR_ITERATOR Iter;
1355 VBoxVrCompositorIterInit(pCompositor, &Iter);
1356 PVBOXVR_COMPOSITOR_ENTRY pEntry;
1357 int rc = VINF_SUCCESS;
1358 bool fChanged = false;
1359
1360 while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
1361 {
1362 bool fTmpChanged = false;
1363 int tmpRc = VBoxVrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
1364 if (RT_SUCCESS(tmpRc))
1365 {
1366 fChanged |= fChanged;
1367 }
1368 else
1369 {
1370 WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1371 rc = tmpRc;
1372 }
1373 }
1374
1375 if (pfChanged)
1376 *pfChanged = fChanged;
1377
1378 return rc;
1379}
1380
1381VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, int32_t x, int32_t y, bool *pfChanged)
1382{
1383 if (!pEntry)
1384 {
1385 WARN(("VBoxVrCompositorEntryRegionsTranslate called with zero entry, unsupported!"));
1386 if (pfChanged)
1387 *pfChanged = false;
1388 return VERR_INVALID_PARAMETER;
1389 }
1390
1391 if ((!x && !y)
1392 || !VBoxVrCompositorEntryIsInList(pEntry))
1393 {
1394 if (pfChanged)
1395 *pfChanged = false;
1396 return VINF_SUCCESS;
1397 }
1398
1399 VBoxVrListTranslate(&pEntry->Vr, x, y);
1400
1401 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1402
1403 PVBOXVR_COMPOSITOR_ENTRY pCur;
1404 uint32_t cRects = 0;
1405 RTRECT *paRects = NULL;
1406 int rc = VINF_SUCCESS;
1407 RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
1408 {
1409 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1410
1411 if (pCur == pEntry)
1412 continue;
1413
1414 if (!paRects)
1415 {
1416 cRects = VBoxVrListRectsCount(&pEntry->Vr);
1417 Assert(cRects);
1418 paRects = (RTRECT*)RTMemAlloc(cRects * sizeof (RTRECT));
1419 if (!paRects)
1420 {
1421 WARN(("RTMemAlloc failed!"));
1422 rc = VERR_NO_MEMORY;
1423 break;
1424 }
1425
1426 rc = VBoxVrListRectsGet(&pEntry->Vr, cRects, paRects);
1427 if (!RT_SUCCESS(rc))
1428 {
1429 WARN(("VBoxVrListRectsGet failed! rc %d", rc));
1430 break;
1431 }
1432 }
1433
1434 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, NULL);
1435 if (!RT_SUCCESS(rc))
1436 {
1437 WARN(("vboxVrCompositorEntryRegionsSubst failed! rc %d", rc));
1438 break;
1439 }
1440 }
1441
1442 if (pfChanged)
1443 *pfChanged = true;
1444
1445 if (paRects)
1446 RTMemFree(paRects);
1447
1448 return rc;
1449}
1450
1451VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
1452{
1453 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
1454 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1455 {
1456 if (!pfnVisitor(pCompositor, pEntry, pvVisitor))
1457 return;
1458 }
1459}
1460
1461
1462
1463#define VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED UINT32_MAX
1464
1465static int crVrScrCompositorRectsAssignBuffer(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRects)
1466{
1467 Assert(cRects);
1468
1469 if (pCompositor->cRectsBuffer >= cRects)
1470 {
1471 pCompositor->cRects = cRects;
1472 return VINF_SUCCESS;
1473 }
1474
1475 if (pCompositor->cRectsBuffer)
1476 {
1477 Assert(pCompositor->paSrcRects);
1478 RTMemFree(pCompositor->paSrcRects);
1479 Assert(pCompositor->paDstRects);
1480 RTMemFree(pCompositor->paDstRects);
1481 }
1482
1483 pCompositor->paSrcRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paSrcRects) * cRects);
1484 if (pCompositor->paSrcRects)
1485 {
1486 pCompositor->paDstRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstRects) * cRects);
1487 if (pCompositor->paDstRects)
1488 {
1489 pCompositor->cRects = cRects;
1490 pCompositor->cRectsBuffer = cRects;
1491 return VINF_SUCCESS;
1492 }
1493 else
1494 {
1495 WARN(("RTMemAlloc failed!"));
1496 RTMemFree(pCompositor->paSrcRects);
1497 pCompositor->paSrcRects = NULL;
1498 }
1499 }
1500 else
1501 {
1502 WARN(("RTMemAlloc failed!"));
1503 pCompositor->paDstRects = NULL;
1504 }
1505
1506 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1507 pCompositor->cRectsBuffer = 0;
1508
1509 return VERR_NO_MEMORY;
1510}
1511
1512static void crVrScrCompositorRectsInvalidate(PVBOXVR_SCR_COMPOSITOR pCompositor)
1513{
1514 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1515}
1516
1517static DECLCALLBACK(bool) crVrScrCompositorRectsCounterCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor)
1518{
1519 uint32_t* pCounter = (uint32_t*)pvVisitor;
1520 Assert(VBoxVrListRectsCount(&pEntry->Vr));
1521 *pCounter += VBoxVrListRectsCount(&pEntry->Vr);
1522 return true;
1523}
1524
1525typedef struct VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER
1526{
1527 PRTRECT paSrcRects;
1528 PRTRECT paDstRects;
1529 uint32_t cRects;
1530} VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER, *PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER;
1531
1532static DECLCALLBACK(bool) crVrScrCompositorRectsAssignerCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
1533{
1534 PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER pData = (PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER)pvVisitor;
1535 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
1536 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
1537 pEntry->paSrcRects = pData->paSrcRects;
1538 pEntry->paDstRects = pData->paDstRects;
1539 uint32_t cRects = VBoxVrListRectsCount(&pCEntry->Vr);
1540 Assert(cRects);
1541 Assert(cRects >= pData->cRects);
1542 int rc = VBoxVrListRectsGet(&pCEntry->Vr, cRects, pEntry->paDstRects);
1543 AssertRC(rc);
1544 if (pCompositor->StretchX >= 1. && pCompositor->StretchY >= 1. /* <- stretching can not zero some rects */
1545 && !pEntry->Pos.x && !pEntry->Pos.y)
1546 {
1547 memcpy(pEntry->paSrcRects, pEntry->paDstRects, cRects * sizeof (*pEntry->paSrcRects));
1548 }
1549 else
1550 {
1551 for (uint32_t i = 0; i < cRects; ++i)
1552 {
1553 pEntry->paSrcRects[i].xLeft = (int32_t)((pEntry->paDstRects[i].xLeft - pEntry->Pos.x) * pCompositor->StretchX);
1554 pEntry->paSrcRects[i].yTop = (int32_t)((pEntry->paDstRects[i].yTop - pEntry->Pos.y) * pCompositor->StretchY);
1555 pEntry->paSrcRects[i].xRight = (int32_t)((pEntry->paDstRects[i].xRight - pEntry->Pos.x) * pCompositor->StretchX);
1556 pEntry->paSrcRects[i].yBottom = (int32_t)((pEntry->paDstRects[i].yBottom - pEntry->Pos.y) * pCompositor->StretchY);
1557 }
1558
1559 bool canZeroX = (pCompositor->StretchX < 1);
1560 bool canZeroY = (pCompositor->StretchY < 1);
1561 if (canZeroX && canZeroY)
1562 {
1563 /* filter out zero rectangles*/
1564 uint32_t iOrig, iNew;
1565 for (iOrig = 0, iNew = 0; iOrig < cRects; ++iOrig)
1566 {
1567 PRTRECT pOrigRect = &pEntry->paSrcRects[iOrig];
1568 if (pOrigRect->xLeft == pOrigRect->xRight
1569 || pOrigRect->yTop == pOrigRect->yBottom)
1570 continue;
1571
1572 if (iNew != iOrig)
1573 {
1574 PRTRECT pNewRect = &pEntry->paSrcRects[iNew];
1575 *pNewRect = *pOrigRect;
1576 }
1577
1578 ++iNew;
1579 }
1580
1581 Assert(iNew <= iOrig);
1582
1583 uint32_t cDiff = iOrig - iNew;
1584
1585 if (cDiff)
1586 {
1587 pCompositor->cRects -= cDiff;
1588 cRects -= cDiff;
1589 }
1590 }
1591 }
1592
1593 pEntry->cRects = cRects;
1594 pData->paDstRects += cRects;
1595 pData->paSrcRects += cRects;
1596 pData->cRects -= cRects;
1597 return true;
1598}
1599
1600static int crVrScrCompositorRectsCheckInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
1601{
1602 if (pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED)
1603 return VINF_SUCCESS;
1604
1605 uint32_t cRects = 0;
1606 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsCounterCb, &cRects);
1607
1608 if (!cRects)
1609 {
1610 pCompositor->cRects = 0;
1611 return VINF_SUCCESS;
1612 }
1613
1614 int rc = crVrScrCompositorRectsAssignBuffer(pCompositor, cRects);
1615 if (!RT_SUCCESS(rc))
1616 return rc;
1617
1618 VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER AssignerData;
1619 AssignerData.paSrcRects = pCompositor->paSrcRects;
1620 AssignerData.paDstRects = pCompositor->paDstRects;
1621 AssignerData.cRects = pCompositor->cRects;
1622 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsAssignerCb, &AssignerData);
1623 Assert(!AssignerData.cRects);
1624 return VINF_SUCCESS;
1625}
1626
1627
1628static int crVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, uint32_t *pfChangedFlags)
1629{
1630 uint32_t fChangedFlags = 0;
1631 int rc = VBoxVrCompositorEntryRegionsAdd(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChangedFlags);
1632 if (!RT_SUCCESS(rc))
1633 {
1634 WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
1635 return rc;
1636 }
1637
1638 if (fChangedFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED)
1639 {
1640 crVrScrCompositorRectsInvalidate(pCompositor);
1641 }
1642
1643 if (fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)
1644 {
1645 CrVrScrCompositorEntrySetChanged(pEntry, true);
1646 }
1647
1648 if (pfChangedFlags)
1649 *pfChangedFlags = fChangedFlags;
1650 return VINF_SUCCESS;
1651}
1652
1653static int crVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1654{
1655 bool fChanged;
1656 CrVrScrCompositorEntryIsInList(pEntry);
1657 int rc = VBoxVrCompositorEntryRegionsSet(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
1658 if (!RT_SUCCESS(rc))
1659 {
1660 WARN(("VBoxVrCompositorEntryRegionsSet failed, rc %d", rc));
1661 return rc;
1662 }
1663
1664 if (fChanged)
1665 {
1666 CrVrScrCompositorEntrySetChanged(pEntry, true);
1667 if (!CrVrScrCompositorEntryIsInList(pEntry))
1668 {
1669 pEntry->cRects = 0;
1670 pEntry->paSrcRects = NULL;
1671 pEntry->paDstRects = NULL;
1672 }
1673 crVrScrCompositorRectsInvalidate(pCompositor);
1674 }
1675
1676 CrVrScrCompositorEntrySetChanged(pEntry, true);
1677
1678 if (pfChanged)
1679 *pfChanged = fChanged;
1680 return VINF_SUCCESS;
1681}
1682
1683static int crVrScrCompositorEntryPositionSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, bool *pfChanged)
1684{
1685 if (pfChanged)
1686 *pfChanged = false;
1687 if (pEntry && (pEntry->Pos.x != pPos->x || pEntry->Pos.y != pPos->y))
1688 {
1689 int rc = VBoxVrCompositorEntryRegionsTranslate(&pCompositor->Compositor, &pEntry->Ce, pPos->x - pEntry->Pos.x, pPos->y - pEntry->Pos.y, pfChanged);
1690 if (!RT_SUCCESS(rc))
1691 {
1692 WARN(("VBoxVrCompositorEntryRegionsTranslate failed rc %d", rc));
1693 return rc;
1694 }
1695
1696 if (VBoxVrCompositorEntryIsInList(&pEntry->Ce))
1697 {
1698 crVrScrCompositorRectsInvalidate(pCompositor);
1699 }
1700
1701 pEntry->Pos = *pPos;
1702 CrVrScrCompositorEntrySetChanged(pEntry, true);
1703
1704 if (pfChanged)
1705 *pfChanged = true;
1706 }
1707 return VINF_SUCCESS;
1708}
1709
1710static int crVrScrCompositorEntryEnsureRegionsInTex(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
1711{
1712 RTRECT Rect;
1713 Rect.xLeft = pEntry->Pos.x;
1714 Rect.yTop = pEntry->Pos.y;
1715 Rect.xRight = pEntry->Pos.x + pEntry->Tex.width;
1716 Rect.yBottom = pEntry->Pos.y + pEntry->Tex.height;
1717 int rc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, 1, &Rect, NULL);
1718 if (!RT_SUCCESS(rc))
1719 WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", rc));
1720 return rc;
1721}
1722
1723VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, uint32_t *pfChangeFlags)
1724{
1725 int rc;
1726 uint32_t fChangeFlags = 0;
1727 bool fPosChanged = false;
1728 if (pPos)
1729 {
1730 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
1731 if (!RT_SUCCESS(rc))
1732 {
1733 WARN(("RegionsAdd: crVrScrCompositorEntryPositionSet failed rc %d", rc));
1734 return rc;
1735 }
1736 }
1737
1738 rc = crVrScrCompositorEntryRegionsAdd(pCompositor, pEntry, cRegions, paRegions, &fChangeFlags);
1739 if (!RT_SUCCESS(rc))
1740 {
1741 WARN(("crVrScrCompositorEntryRegionsAdd failed, rc %d", rc));
1742 return rc;
1743 }
1744
1745 if ((fPosChanged || (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)) && pEntry)
1746 {
1747 rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry);
1748 if (!RT_SUCCESS(rc))
1749 {
1750 WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed, rc %d", rc));
1751 return rc;
1752 }
1753 }
1754
1755 if (pfChangeFlags)
1756 {
1757 if (fPosChanged)
1758 {
1759 /* means entry was in list and was moved, so regions changed */
1760 *pfChangeFlags = VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED;
1761 }
1762 else
1763 *pfChangeFlags = fChangeFlags;
1764 }
1765
1766 return VINF_SUCCESS;
1767}
1768
1769VBOXVREGDECL(int) CrVrScrCompositorEntryTexUpdate(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_TEXTURE *pTex)
1770{
1771 bool fCompositorChanged = CrVrScrCompositorEntryIsUsed(pEntry) && (pEntry->Tex.width != pTex->width || pEntry->Tex.height != pTex->height);
1772 pEntry->Tex = *pTex;
1773 CrVrScrCompositorEntrySetChanged(pEntry, true);
1774 if (fCompositorChanged)
1775 {
1776 int rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry);
1777 if (!RT_SUCCESS(rc))
1778 {
1779 WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed rc %d", rc));
1780 return rc;
1781 }
1782 }
1783 return VINF_SUCCESS;
1784}
1785
1786VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1787{
1788 /* @todo: the fChanged sate calculation is really rough now, this is enough for now though */
1789 bool fChanged = false, fPosChanged = false;
1790 bool fWasInList = CrVrScrCompositorEntryIsInList(pEntry);
1791 int rc = CrVrScrCompositorEntryRemove(pCompositor, pEntry);
1792 if (!RT_SUCCESS(rc))
1793 {
1794 WARN(("RegionsSet: CrVrScrCompositorEntryRemove failed rc %d", rc));
1795 return rc;
1796 }
1797
1798 if (pPos)
1799 {
1800 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
1801 if (!RT_SUCCESS(rc))
1802 {
1803 WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
1804 return rc;
1805 }
1806 }
1807
1808 rc = crVrScrCompositorEntryRegionsSet(pCompositor, pEntry, cRegions, paRegions, &fChanged);
1809 if (!RT_SUCCESS(rc))
1810 {
1811 WARN(("crVrScrCompositorEntryRegionsSet failed, rc %d", rc));
1812 return rc;
1813 }
1814
1815 if (fChanged && CrVrScrCompositorEntryIsUsed(pEntry))
1816 {
1817 rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry);
1818 if (!RT_SUCCESS(rc))
1819 {
1820 WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed, rc %d", rc));
1821 return rc;
1822 }
1823 }
1824
1825 if (pfChanged)
1826 *pfChanged = fPosChanged || fChanged || fWasInList;
1827
1828 return VINF_SUCCESS;
1829}
1830
1831VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
1832{
1833 bool fChanged = false;
1834 int rc = VBoxVrCompositorEntryListIntersect(&pCompositor->Compositor, &pEntry->Ce, pList2, &fChanged);
1835 if (!RT_SUCCESS(rc))
1836 {
1837 WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
1838 return rc;
1839 }
1840
1841 if (fChanged)
1842 {
1843 CrVrScrCompositorEntrySetChanged(pEntry, true);
1844 crVrScrCompositorRectsInvalidate(pCompositor);
1845 }
1846
1847 if (pfChanged)
1848 *pfChanged = fChanged;
1849
1850 return VINF_SUCCESS;
1851}
1852
1853VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1854{
1855 bool fChanged = false;
1856 int rc = VBoxVrCompositorEntryRegionsIntersect(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
1857 if (!RT_SUCCESS(rc))
1858 {
1859 WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
1860 return rc;
1861 }
1862
1863 if (fChanged)
1864 {
1865 CrVrScrCompositorEntrySetChanged(pEntry, true);
1866 crVrScrCompositorRectsInvalidate(pCompositor);
1867 }
1868
1869 if (pfChanged)
1870 *pfChanged = fChanged;
1871
1872 return VINF_SUCCESS;
1873}
1874
1875VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
1876{
1877 VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
1878 CrVrScrCompositorIterInit(pCompositor, &Iter);
1879 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
1880 int rc = VINF_SUCCESS;
1881 bool fChanged = false;
1882
1883 while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
1884 {
1885 bool fTmpChanged = false;
1886 int tmpRc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
1887 if (RT_SUCCESS(tmpRc))
1888 {
1889 fChanged |= fTmpChanged;
1890 }
1891 else
1892 {
1893 WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1894 rc = tmpRc;
1895 }
1896 }
1897
1898 if (pfChanged)
1899 *pfChanged = fChanged;
1900
1901 return rc;
1902}
1903
1904VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1905{
1906 VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
1907 CrVrScrCompositorIterInit(pCompositor, &Iter);
1908 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
1909 int rc = VINF_SUCCESS;
1910 bool fChanged = false;
1911
1912 while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
1913 {
1914 bool fTmpChanged = false;
1915 int tmpRc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
1916 if (RT_SUCCESS(tmpRc))
1917 {
1918 fChanged |= fTmpChanged;
1919 }
1920 else
1921 {
1922 WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1923 rc = tmpRc;
1924 }
1925 }
1926
1927 if (pfChanged)
1928 *pfChanged = fChanged;
1929
1930 return rc;
1931}
1932
1933VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos)
1934{
1935 int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
1936 if (!RT_SUCCESS(rc))
1937 {
1938 WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
1939 return rc;
1940 }
1941 return VINF_SUCCESS;
1942}
1943
1944/* regions are valid until the next CrVrScrCompositor call */
1945VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
1946{
1947 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
1948 if (!RT_SUCCESS(rc))
1949 {
1950 WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
1951 return rc;
1952 }
1953
1954 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
1955
1956 *pcRegions = pEntry->cRects;
1957 if (ppaSrcRegions)
1958 *ppaSrcRegions = pEntry->paSrcRects;
1959 if (ppaDstRegions)
1960 *ppaDstRegions = pEntry->paDstRects;
1961
1962 return VINF_SUCCESS;
1963}
1964
1965VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
1966{
1967 if (!VBoxVrCompositorEntryRemove(&pCompositor->Compositor, &pEntry->Ce))
1968 return VINF_SUCCESS;
1969
1970 CrVrScrCompositorEntrySetChanged(pEntry, true);
1971 pEntry->cRects = 0;
1972 pEntry->paSrcRects = NULL;
1973 pEntry->paDstRects = NULL;
1974
1975 crVrScrCompositorRectsInvalidate(pCompositor);
1976 return VINF_SUCCESS;
1977}
1978
1979VBOXVREGDECL(int) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
1980{
1981 memset(pCompositor, 0, sizeof (*pCompositor));
1982 int rc = RTCritSectInit(&pCompositor->CritSect);
1983 if (RT_SUCCESS(rc))
1984 {
1985 VBoxVrCompositorInit(&pCompositor->Compositor, NULL);
1986 pCompositor->StretchX = 1.0;
1987 pCompositor->StretchY = 1.0;
1988 return VINF_SUCCESS;
1989 }
1990 else
1991 {
1992 WARN(("RTCritSectInit failed rc %d", rc));
1993 }
1994 return rc;
1995}
1996
1997VBOXVREGDECL(void) CrVrScrCompositorTerm(PVBOXVR_SCR_COMPOSITOR pCompositor)
1998{
1999 VBoxVrCompositorTerm(&pCompositor->Compositor);
2000 if (pCompositor->paDstRects)
2001 RTMemFree(pCompositor->paDstRects);
2002 if (pCompositor->paSrcRects)
2003 RTMemFree(pCompositor->paSrcRects);
2004
2005 RTCritSectDelete(&pCompositor->CritSect);
2006}
2007
2008
2009static DECLCALLBACK(bool) crVrScrCompositorEntrySetAllChangedCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
2010{
2011 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
2012 CrVrScrCompositorEntrySetChanged(pEntry, !!pvVisitor);
2013 return true;
2014}
2015
2016VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged)
2017{
2018 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorEntrySetAllChangedCb, (void*)fChanged);
2019}
2020
2021VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY)
2022{
2023 pCompositor->StretchX = StretchX;
2024 pCompositor->StretchY = StretchY;
2025 crVrScrCompositorRectsInvalidate(pCompositor);
2026 CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
2027}
2028
2029/* regions are valid until the next CrVrScrCompositor call */
2030VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
2031{
2032 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
2033 if (!RT_SUCCESS(rc))
2034 {
2035 WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
2036 return rc;
2037 }
2038
2039 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
2040
2041 *pcRegions = pCompositor->cRects;
2042 if (ppaSrcRegions)
2043 *ppaSrcRegions = pCompositor->paSrcRects;
2044 if (ppaDstRegions)
2045 *ppaDstRegions = pCompositor->paDstRects;
2046
2047 return VINF_SUCCESS;
2048}
2049
2050typedef struct VBOXVR_SCR_COMPOSITOR_VISITOR_CB
2051{
2052 PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor;
2053 void *pvVisitor;
2054} VBOXVR_SCR_COMPOSITOR_VISITOR_CB, *PVBOXVR_SCR_COMPOSITOR_VISITOR_CB;
2055
2056static DECLCALLBACK(bool) crVrScrCompositorVisitCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
2057{
2058 PVBOXVR_SCR_COMPOSITOR_VISITOR_CB pData = (PVBOXVR_SCR_COMPOSITOR_VISITOR_CB)pvVisitor;
2059 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
2060 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
2061 return pData->pfnVisitor(pCompositor, pEntry, pData->pvVisitor);
2062}
2063
2064VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
2065{
2066 VBOXVR_SCR_COMPOSITOR_VISITOR_CB Data;
2067 Data.pfnVisitor = pfnVisitor;
2068 Data.pvVisitor = pvVisitor;
2069 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorVisitCb, &Data);
2070}
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