VirtualBox

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

Last change on this file since 69989 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.3 KB
Line 
1/* $Id: vreg.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
2/** @file
3 * Visible Regions processing API implementation
4 */
5
6/*
7 * Copyright (C) 2012-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#ifdef IN_VMSVGA3D
23# include "../include/cr_vreg.h"
24# define WARN AssertMsgFailed
25#else
26# include <cr_vreg.h>
27# include <cr_error.h>
28#endif
29
30#include <iprt/err.h>
31#include <iprt/assert.h>
32#include <iprt/asm.h>
33
34#ifdef DEBUG_misha
35# define VBOXVDBG_VR_LAL_DISABLE
36#endif
37
38#ifndef IN_RING0
39# include <iprt/memcache.h>
40# ifndef VBOXVDBG_VR_LAL_DISABLE
41static RTMEMCACHE g_VBoxVrLookasideList;
42# define vboxVrRegLaAlloc(_c) RTMemCacheAlloc((_c))
43# define vboxVrRegLaFree(_c, _e) RTMemCacheFree((_c), (_e))
44
45DECLINLINE(int) vboxVrLaCreate(PRTMEMCACHE phCache, size_t cbElement)
46{
47 int rc = RTMemCacheCreate(phCache,
48 cbElement,
49 0 /* cbAlignment */,
50 UINT32_MAX /* cMaxObjects */,
51 NULL /* pfnCtor*/,
52 NULL /* pfnDtor*/,
53 NULL /* pvUser*/,
54 0 /* fFlags*/);
55 if (!RT_SUCCESS(rc))
56 {
57 WARN(("RTMemCacheCreate failed rc %d", rc));
58 return rc;
59 }
60 return VINF_SUCCESS;
61}
62# define vboxVrLaDestroy(_c) RTMemCacheDestroy((_c))
63# endif /* !VBOXVDBG_VR_LAL_DISABLE */
64
65#else /* IN_RING0 */
66# ifdef RT_OS_WINDOWS
67# undef PAGE_SIZE
68# undef PAGE_SHIFT
69# include <iprt/nt/ntddk.h>
70# ifndef VBOXVDBG_VR_LAL_DISABLE
71static LOOKASIDE_LIST_EX g_VBoxVrLookasideList;
72# define vboxVrRegLaAlloc(_c) ExAllocateFromLookasideListEx(&(_c))
73# define vboxVrRegLaFree(_c, _e) ExFreeToLookasideListEx(&(_c), (_e))
74# define VBOXWDDMVR_MEMTAG 'vDBV'
75DECLINLINE(int) vboxVrLaCreate(LOOKASIDE_LIST_EX *pCache, size_t cbElement)
76{
77 NTSTATUS Status = ExInitializeLookasideListEx(pCache,
78 NULL, /* PALLOCATE_FUNCTION_EX Allocate */
79 NULL, /* PFREE_FUNCTION_EX Free */
80 NonPagedPool,
81 0, /* ULONG Flags */
82 cbElement,
83 VBOXWDDMVR_MEMTAG,
84 0 /* USHORT Depth - reserved, must be null */
85 );
86 if (!NT_SUCCESS(Status))
87 {
88 WARN(("ExInitializeLookasideListEx failed, Status (0x%x)", Status));
89 return VERR_GENERAL_FAILURE;
90 }
91
92 return VINF_SUCCESS;
93}
94# define vboxVrLaDestroy(_c) ExDeleteLookasideListEx(&(_c))
95# endif
96# else /* !RT_OS_WINDOWS */
97# error "port me!"
98# endif /* !RT_OS_WINDOWS */
99#endif /* IN_RING0 */
100
101
102/*********************************************************************************************************************************
103* Defined Constants And Macros *
104*********************************************************************************************************************************/
105#define VBOXVR_INVALID_COORD (~0U)
106
107
108/*********************************************************************************************************************************
109* Global Variables *
110*********************************************************************************************************************************/
111static volatile int32_t g_cVBoxVrInits = 0;
112
113
114static PVBOXVR_REG vboxVrRegCreate(void)
115{
116#ifndef VBOXVDBG_VR_LAL_DISABLE
117 PVBOXVR_REG pReg = (PVBOXVR_REG)vboxVrRegLaAlloc(g_VBoxVrLookasideList);
118 if (!pReg)
119 {
120 WARN(("ExAllocateFromLookasideListEx failed!"));
121 }
122 return pReg;
123#else
124 return (PVBOXVR_REG)RTMemAlloc(sizeof(VBOXVR_REG));
125#endif
126}
127
128static void vboxVrRegTerm(PVBOXVR_REG pReg)
129{
130#ifndef VBOXVDBG_VR_LAL_DISABLE
131 vboxVrRegLaFree(g_VBoxVrLookasideList, pReg);
132#else
133 RTMemFree(pReg);
134#endif
135}
136
137VBOXVREGDECL(void) VBoxVrListClear(PVBOXVR_LIST pList)
138{
139 PVBOXVR_REG pReg, pRegNext;
140 RTListForEachSafe(&pList->ListHead, pReg, pRegNext, VBOXVR_REG, ListEntry)
141 {
142 vboxVrRegTerm(pReg);
143 }
144 VBoxVrListInit(pList);
145}
146
147/* moves list data to pDstList and empties the pList */
148VBOXVREGDECL(void) VBoxVrListMoveTo(PVBOXVR_LIST pList, PVBOXVR_LIST pDstList)
149{
150 *pDstList = *pList;
151 pDstList->ListHead.pNext->pPrev = &pDstList->ListHead;
152 pDstList->ListHead.pPrev->pNext = &pDstList->ListHead;
153 VBoxVrListInit(pList);
154}
155
156VBOXVREGDECL(int) VBoxVrInit(void)
157{
158 int32_t cNewRefs = ASMAtomicIncS32(&g_cVBoxVrInits);
159 Assert(cNewRefs >= 1);
160 Assert(cNewRefs == 1); /* <- debugging */
161 if (cNewRefs > 1)
162 return VINF_SUCCESS;
163
164#ifndef VBOXVDBG_VR_LAL_DISABLE
165 int rc = vboxVrLaCreate(&g_VBoxVrLookasideList, sizeof(VBOXVR_REG));
166 if (!RT_SUCCESS(rc))
167 {
168 WARN(("ExInitializeLookasideListEx failed, rc (%d)", rc));
169 return rc;
170 }
171#endif
172
173 return VINF_SUCCESS;
174}
175
176VBOXVREGDECL(void) VBoxVrTerm(void)
177{
178 int32_t cNewRefs = ASMAtomicDecS32(&g_cVBoxVrInits);
179 Assert(cNewRefs >= 0);
180 if (cNewRefs > 0)
181 return;
182
183#ifndef VBOXVDBG_VR_LAL_DISABLE
184 vboxVrLaDestroy(g_VBoxVrLookasideList);
185#endif
186}
187
188typedef DECLCALLBACK(int) FNVBOXVR_CB_COMPARATOR(PCVBOXVR_REG pReg1, PCVBOXVR_REG pReg2);
189typedef FNVBOXVR_CB_COMPARATOR *PFNVBOXVR_CB_COMPARATOR;
190
191static DECLCALLBACK(int) vboxVrRegNonintersectedComparator(PCRTRECT pRect1, PCRTRECT pRect2)
192{
193 Assert(!VBoxRectIsIntersect(pRect1, pRect2));
194 if (pRect1->yTop != pRect2->yTop)
195 return pRect1->yTop - pRect2->yTop;
196 return pRect1->xLeft - pRect2->xLeft;
197}
198
199#ifdef DEBUG_misha
200static void vboxVrDbgListDoVerify(PVBOXVR_LIST pList)
201{
202 PVBOXVR_REG pReg1, pReg2;
203 RTListForEach(&pList->ListHead, pReg1, VBOXVR_REG, ListEntry)
204 {
205 Assert(!VBoxRectIsZero(&pReg1->Rect));
206 for (RTLISTNODE *pEntry2 = pReg1->ListEntry.pNext; pEntry2 != &pList->ListHead; pEntry2 = pEntry2->pNext)
207 {
208 pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
209 Assert(vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0);
210 }
211 }
212}
213# define vboxVrDbgListVerify(_p) vboxVrDbgListDoVerify(_p)
214#else
215# define vboxVrDbgListVerify(_p) do {} while (0)
216#endif
217
218
219DECLINLINE(void) vboxVrListRegAdd(PVBOXVR_LIST pList, PVBOXVR_REG pReg, PRTLISTNODE pPlace, bool fAfter)
220{
221 if (fAfter)
222 RTListPrepend(pPlace, &pReg->ListEntry);
223 else
224 RTListAppend(pPlace, &pReg->ListEntry);
225 ++pList->cEntries;
226 vboxVrDbgListVerify(pList);
227}
228
229DECLINLINE(void) vboxVrListRegRemove(PVBOXVR_LIST pList, PVBOXVR_REG pReg)
230{
231 RTListNodeRemove(&pReg->ListEntry);
232 --pList->cEntries;
233 vboxVrDbgListVerify(pList);
234}
235
236static void vboxVrListRegAddOrder(PVBOXVR_LIST pList, PRTLISTNODE pMemberEntry, PVBOXVR_REG pReg)
237{
238 for (;;)
239 {
240 if (pMemberEntry != &pList->ListHead)
241 {
242 PVBOXVR_REG pMemberReg = PVBOXVR_REG_FROM_ENTRY(pMemberEntry);
243 if (vboxVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0)
244 {
245 pMemberEntry = pMemberEntry->pNext;
246 continue;
247 }
248 }
249 vboxVrListRegAdd(pList, pReg, pMemberEntry, false);
250 break;
251 }
252}
253
254static void vboxVrListAddNonintersected(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
255{
256 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
257
258 for (PRTLISTNODE pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.pNext)
259 {
260 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
261 for (;;)
262 {
263 if (pEntry1 != &pList1->ListHead)
264 {
265 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
266 if (vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0)
267 {
268 pEntry1 = pEntry1->pNext;
269 continue;
270 }
271 }
272 vboxVrListRegRemove(pList2, pReg2);
273 vboxVrListRegAdd(pList1, pReg2, pEntry1, false);
274 break;
275 }
276 }
277
278 Assert(VBoxVrListIsEmpty(pList2));
279}
280
281static int vboxVrListRegIntersectSubstNoJoin(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, PCRTRECT pRect2)
282{
283 uint32_t topLim = VBOXVR_INVALID_COORD;
284 uint32_t bottomLim = VBOXVR_INVALID_COORD;
285 RTLISTNODE List;
286 PVBOXVR_REG pBottomReg = NULL;
287#ifdef DEBUG_misha
288 RTRECT tmpRect = pReg1->Rect;
289 vboxVrDbgListVerify(pList1);
290#endif
291 Assert(!VBoxRectIsZero(pRect2));
292
293 RTListInit(&List);
294
295 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
296
297 if (pReg1->Rect.yTop < pRect2->yTop)
298 {
299 Assert(pRect2->yTop < pReg1->Rect.yBottom);
300 PVBOXVR_REG pRegResult = vboxVrRegCreate();
301 pRegResult->Rect.yTop = pReg1->Rect.yTop;
302 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
303 pRegResult->Rect.yBottom = pRect2->yTop;
304 pRegResult->Rect.xRight = pReg1->Rect.xRight;
305 topLim = pRect2->yTop;
306 RTListAppend(&List, &pRegResult->ListEntry);
307 }
308
309 if (pReg1->Rect.yBottom > pRect2->yBottom)
310 {
311 Assert(pRect2->yBottom > pReg1->Rect.yTop);
312 PVBOXVR_REG pRegResult = vboxVrRegCreate();
313 pRegResult->Rect.yTop = pRect2->yBottom;
314 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
315 pRegResult->Rect.yBottom = pReg1->Rect.yBottom;
316 pRegResult->Rect.xRight = pReg1->Rect.xRight;
317 bottomLim = pRect2->yBottom;
318 pBottomReg = pRegResult;
319 }
320
321 if (pReg1->Rect.xLeft < pRect2->xLeft)
322 {
323 Assert(pRect2->xLeft < pReg1->Rect.xRight);
324 PVBOXVR_REG pRegResult = vboxVrRegCreate();
325 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
326 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
327 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
328 pRegResult->Rect.xRight = pRect2->xLeft;
329 RTListAppend(&List, &pRegResult->ListEntry);
330 }
331
332 if (pReg1->Rect.xRight > pRect2->xRight)
333 {
334 Assert(pRect2->xRight > pReg1->Rect.xLeft);
335 PVBOXVR_REG pRegResult = vboxVrRegCreate();
336 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
337 pRegResult->Rect.xLeft = pRect2->xRight;
338 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
339 pRegResult->Rect.xRight = pReg1->Rect.xRight;
340 RTListAppend(&List, &pRegResult->ListEntry);
341 }
342
343 if (pBottomReg)
344 RTListAppend(&List, &pBottomReg->ListEntry);
345
346 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
347 vboxVrListRegRemove(pList1, pReg1);
348 vboxVrRegTerm(pReg1);
349
350 if (RTListIsEmpty(&List))
351 return VINF_SUCCESS; /* the region is covered by the pRect2 */
352
353 PRTLISTNODE pNext;
354 PRTLISTNODE pEntry = List.pNext;
355 for (; pEntry != &List; pEntry = pNext)
356 {
357 pNext = pEntry->pNext;
358 PVBOXVR_REG pReg = PVBOXVR_REG_FROM_ENTRY(pEntry);
359
360 vboxVrListRegAddOrder(pList1, pMemberEntry, pReg);
361 pMemberEntry = pEntry->pNext; /* the following elements should go after the given pEntry since they are ordered already */
362 }
363 return VINF_SUCCESS;
364}
365
366/**
367 * @returns Entry to be used for continuing the rectangles iterations being made currently on the callback call.
368 * ListHead is returned to break the current iteration
369 * @param ppNext specifies next reg entry to be used for iteration. the default is pReg1->ListEntry.pNext */
370typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_INTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1,
371 PCRTRECT pRect2, void *pvContext, PRTLISTNODE *ppNext);
372typedef FNVBOXVR_CB_INTERSECTED_VISITOR *PFNVBOXVR_CB_INTERSECTED_VISITOR;
373
374static void vboxVrListVisitIntersected(PVBOXVR_LIST pList1, uint32_t cRects, PCRTRECT aRects,
375 PFNVBOXVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
376{
377 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
378 PRTLISTNODE pNext1;
379 uint32_t iFirst2 = 0;
380
381 for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
382 {
383 pNext1 = pEntry1->pNext;
384 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
385 for (uint32_t i = iFirst2; i < cRects; ++i)
386 {
387 PCRTRECT pRect2 = &aRects[i];
388 if (VBoxRectIsZero(pRect2))
389 continue;
390
391 if (!VBoxRectIsIntersect(&pReg1->Rect, pRect2))
392 continue;
393
394 /* the visitor can modify the list 1, apply necessary adjustments after it */
395 pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1);
396 if (pEntry1 == &pList1->ListHead)
397 break;
398 pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
399 }
400 }
401}
402
403#if 0 /* unused */
404/**
405 * @returns Entry to be iterated next. ListHead is returned to break the
406 * iteration
407 */
408typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_NONINTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext);
409typedef FNVBOXVR_CB_NONINTERSECTED_VISITOR *PFNVBOXVR_CB_NONINTERSECTED_VISITOR;
410
411static void vboxVrListVisitNonintersected(PVBOXVR_LIST pList1, uint32_t cRects, PCRTRECT aRects,
412 PFNVBOXVR_CB_NONINTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
413{
414 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
415 PRTLISTNODE pNext1;
416 uint32_t iFirst2 = 0;
417
418 for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
419 {
420 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
421 uint32_t i = iFirst2;
422 for (; i < cRects; ++i)
423 {
424 PCRTRECT pRect2 = &aRects[i];
425 if (VBoxRectIsZero(pRect2))
426 continue;
427
428 if (VBoxRectIsIntersect(&pReg1->Rect, pRect2))
429 break;
430 }
431
432 if (i == cRects)
433 pNext1 = pfnVisitor(pList1, pReg1, pvVisitor);
434 else
435 pNext1 = pEntry1->pNext;
436 }
437}
438#endif /* unused */
439
440static void vboxVrListJoinRectsHV(PVBOXVR_LIST pList, bool fHorizontal)
441{
442 PRTLISTNODE pNext1, pNext2;
443
444 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
445 {
446 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
447 pNext1 = pEntry1->pNext;
448 for (PRTLISTNODE pEntry2 = pEntry1->pNext; pEntry2 != &pList->ListHead; pEntry2 = pNext2)
449 {
450 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
451 pNext2 = pEntry2->pNext;
452 if (fHorizontal)
453 {
454 if (pReg1->Rect.yTop == pReg2->Rect.yTop)
455 {
456 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
457 {
458 /* join rectangles */
459 vboxVrListRegRemove(pList, pReg2);
460 if (pReg1->Rect.yBottom > pReg2->Rect.yBottom)
461 {
462 int32_t oldRight1 = pReg1->Rect.xRight;
463 int32_t oldBottom1 = pReg1->Rect.yBottom;
464 pReg1->Rect.xRight = pReg2->Rect.xRight;
465 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
466
467 vboxVrDbgListVerify(pList);
468
469 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
470 pReg2->Rect.yTop = pReg1->Rect.yBottom;
471 pReg2->Rect.xRight = oldRight1;
472 pReg2->Rect.yBottom = oldBottom1;
473 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
474 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
475 * and thus can match one of the previous rects */
476 pNext1 = pList->ListHead.pNext;
477 break;
478 }
479
480 if (pReg1->Rect.yBottom < pReg2->Rect.yBottom)
481 {
482 pReg1->Rect.xRight = pReg2->Rect.xRight;
483 vboxVrDbgListVerify(pList);
484 pReg2->Rect.yTop = pReg1->Rect.yBottom;
485 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
486 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
487 * and thus can match one of the previous rects */
488 pNext1 = pList->ListHead.pNext;
489 break;
490 }
491
492 pReg1->Rect.xRight = pReg2->Rect.xRight;
493 vboxVrDbgListVerify(pList);
494 /* reset the pNext1 since it could be the pReg2 being destroyed */
495 pNext1 = pEntry1->pNext;
496 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
497 vboxVrRegTerm(pReg2);
498 }
499 continue;
500 }
501 else if (pReg1->Rect.yBottom == pReg2->Rect.yBottom)
502 {
503 Assert(pReg1->Rect.yTop < pReg2->Rect.yTop); /* <- since pReg1 > pReg2 && pReg1->Rect.yTop != pReg2->Rect.yTop*/
504 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
505 {
506 /* join rectangles */
507 vboxVrListRegRemove(pList, pReg2);
508
509 pReg1->Rect.yBottom = pReg2->Rect.yTop;
510 vboxVrDbgListVerify(pList);
511 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
512
513 vboxVrListRegAddOrder(pList, pNext2, pReg2);
514
515 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
516 * and thus can match one of the previous rects */
517 pNext1 = pList->ListHead.pNext;
518 break;
519 }
520
521 if (pReg1->Rect.xLeft == pReg2->Rect.xRight)
522 {
523 /* join rectangles */
524 vboxVrListRegRemove(pList, pReg2);
525
526 pReg1->Rect.yBottom = pReg2->Rect.yTop;
527 vboxVrDbgListVerify(pList);
528 pReg2->Rect.xRight = pReg1->Rect.xRight;
529
530 vboxVrListRegAddOrder(pList, pNext2, pReg2);
531
532 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
533 * and thus can match one of the previous rects */
534 pNext1 = pList->ListHead.pNext;
535 break;
536 }
537 continue;
538 }
539 }
540 else
541 {
542 if (pReg1->Rect.yBottom == pReg2->Rect.yTop)
543 {
544 if (pReg1->Rect.xLeft == pReg2->Rect.xLeft)
545 {
546 if (pReg1->Rect.xRight == pReg2->Rect.xRight)
547 {
548 /* join rects */
549 vboxVrListRegRemove(pList, pReg2);
550
551 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
552 vboxVrDbgListVerify(pList);
553
554 /* reset the pNext1 since it could be the pReg2 being destroyed */
555 pNext1 = pEntry1->pNext;
556 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
557 vboxVrRegTerm(pReg2);
558 continue;
559 }
560 /* no more to be done for for pReg1 */
561 break;
562 }
563
564 if (pReg1->Rect.xRight > pReg2->Rect.xLeft)
565 {
566 /* no more to be done for for pReg1 */
567 break;
568 }
569
570 continue;
571 }
572
573 if (pReg1->Rect.yBottom < pReg2->Rect.yTop)
574 {
575 /* no more to be done for for pReg1 */
576 break;
577 }
578 }
579 }
580 }
581}
582
583static void vboxVrListJoinRects(PVBOXVR_LIST pList)
584{
585 vboxVrListJoinRectsHV(pList, true);
586 vboxVrListJoinRectsHV(pList, false);
587}
588
589typedef struct VBOXVR_CBDATA_SUBST
590{
591 int rc;
592 bool fChanged;
593} VBOXVR_CBDATA_SUBST;
594typedef VBOXVR_CBDATA_SUBST *PVBOXVR_CBDATA_SUBST;
595
596static DECLCALLBACK(PRTLISTNODE) vboxVrListSubstNoJoinCb(PVBOXVR_LIST pList, PVBOXVR_REG pReg1, PCRTRECT pRect2,
597 void *pvContext, PRTLISTNODE *ppNext)
598{
599 PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
600 /* store the prev to get the new pNext out of it*/
601 PRTLISTNODE pPrev = pReg1->ListEntry.pPrev;
602 pData->fChanged = true;
603
604 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
605
606 /* NOTE: the pReg1 will be invalid after the vboxVrListRegIntersectSubstNoJoin call!!! */
607 int rc = vboxVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2);
608 if (RT_SUCCESS(rc))
609 {
610 *ppNext = pPrev->pNext;
611 return &pList->ListHead;
612 }
613 WARN(("vboxVrListRegIntersectSubstNoJoin failed!"));
614 Assert(!RT_SUCCESS(rc));
615 pData->rc = rc;
616 *ppNext = &pList->ListHead;
617 return &pList->ListHead;
618}
619
620static int vboxVrListSubstNoJoin(PVBOXVR_LIST pList, uint32_t cRects, PCRTRECT aRects, bool *pfChanged)
621{
622 if (pfChanged)
623 *pfChanged = false;
624
625 if (VBoxVrListIsEmpty(pList))
626 return VINF_SUCCESS;
627
628 VBOXVR_CBDATA_SUBST Data;
629 Data.rc = VINF_SUCCESS;
630 Data.fChanged = false;
631
632 vboxVrListVisitIntersected(pList, cRects, aRects, vboxVrListSubstNoJoinCb, &Data);
633 if (!RT_SUCCESS(Data.rc))
634 {
635 WARN(("vboxVrListVisitIntersected failed!"));
636 return Data.rc;
637 }
638
639 if (pfChanged)
640 *pfChanged = Data.fChanged;
641
642 return VINF_SUCCESS;
643}
644
645#if 0
646static PCRTRECT vboxVrRectsOrder(uint32_t cRects, PCRTRECT aRects)
647{
648#ifdef VBOX_STRICT
649 for (uint32_t i = 0; i < cRects; ++i)
650 {
651 PRTRECT pRectI = &aRects[i];
652 for (uint32_t j = i + 1; j < cRects; ++j)
653 {
654 PRTRECT pRectJ = &aRects[j];
655 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
656 }
657 }
658#endif
659
660 PRTRECT pRects = (PRTRECT)aRects;
661 /* check if rects are ordered already */
662 for (uint32_t i = 0; i < cRects - 1; ++i)
663 {
664 PRTRECT pRect1 = &pRects[i];
665 PRTRECT pRect2 = &pRects[i+1];
666 if (vboxVrRegNonintersectedComparator(pRect1, pRect2) < 0)
667 continue;
668
669 WARN(("rects are unoreded!"));
670
671 if (pRects == aRects)
672 {
673 pRects = (PRTRECT)RTMemAlloc(sizeof(RTRECT) * cRects);
674 if (!pRects)
675 {
676 WARN(("RTMemAlloc failed!"));
677 return NULL;
678 }
679
680 memcpy(pRects, aRects, sizeof(RTRECT) * cRects);
681 }
682
683 Assert(pRects != aRects);
684
685 int j = (int)i - 1;
686 for (;;)
687 {
688 RTRECT Tmp = *pRect1;
689 *pRect1 = *pRect2;
690 *pRect2 = Tmp;
691
692 if (j < 0)
693 break;
694
695 if (vboxVrRegNonintersectedComparator(pRect1, pRect1-1) > 0)
696 break;
697
698 pRect2 = pRect1--;
699 --j;
700 }
701 }
702
703 return pRects;
704}
705#endif
706
707VBOXVREGDECL(void) VBoxVrListTranslate(PVBOXVR_LIST pList, int32_t x, int32_t y)
708{
709 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
710 {
711 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
712 VBoxRectTranslate(&pReg1->Rect, x, y);
713 }
714}
715
716#if 0 /* unused */
717
718static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinNonintersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext)
719{
720 VBOXVR_CBDATA_SUBST *pData = (VBOXVR_CBDATA_SUBST*)pvContext;
721
722 PRTLISTNODE pNext = pReg1->ListEntry.pNext;
723
724 vboxVrDbgListVerify(pList1);
725
726 vboxVrListRegRemove(pList1, pReg1);
727 vboxVrRegTerm(pReg1);
728
729 vboxVrDbgListVerify(pList1);
730
731 pData->fChanged = true;
732
733 return pNext;
734}
735
736static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinIntersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, PCRTRECT pRect2,
737 void *pvContext, PPRTLISTNODE ppNext)
738{
739 RT_NOREF1(ppNext);
740 PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
741 pData->fChanged = true;
742
743 vboxVrDbgListVerify(pList1);
744
745 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
746
747 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
748 Assert(!VBoxRectIsZero(pRect2));
749
750 vboxVrListRegRemove(pList1, pReg1);
751 VBoxRectIntersect(&pReg1->Rect, pRect2);
752 Assert(!VBoxRectIsZero(&pReg1->Rect));
753
754 vboxVrListRegAddOrder(pList1, pMemberEntry, pReg1);
755
756 vboxVrDbgListVerify(pList1);
757
758 return &pReg1->ListEntry;
759}
760
761#endif /* unused */
762
763static int vboxVrListIntersectNoJoin(PVBOXVR_LIST pList, PCVBOXVR_LIST pList2, bool *pfChanged)
764{
765 bool fChanged = false;
766 if (pfChanged)
767 *pfChanged = false;
768
769 if (VBoxVrListIsEmpty(pList))
770 return VINF_SUCCESS;
771
772 if (VBoxVrListIsEmpty(pList2))
773 {
774 if (pfChanged)
775 *pfChanged = true;
776
777 VBoxVrListClear(pList);
778 return VINF_SUCCESS;
779 }
780
781 PRTLISTNODE pNext1;
782
783 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
784 {
785 pNext1 = pEntry1->pNext;
786 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
787 RTRECT RegRect1 = pReg1->Rect;
788 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
789
790 for (const RTLISTNODE *pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pEntry2->pNext)
791 {
792 PCVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
793 PCRTRECT pRect2 = &pReg2->Rect;
794
795 if (!VBoxRectIsIntersect(&RegRect1, pRect2))
796 continue;
797
798 if (pReg1)
799 {
800 if (VBoxRectCovers(pRect2, &RegRect1))
801 {
802 /* no change */
803
804 /* zero up the pReg1 to mark it as intersected (see the code after this inner loop) */
805 pReg1 = NULL;
806
807 if (!VBoxRectCmp(pRect2, &RegRect1))
808 break; /* and we can break the iteration here */
809 }
810 else
811 {
812 /*just to ensure the VBoxRectCovers is true for equal rects */
813 Assert(VBoxRectCmp(pRect2, &RegRect1));
814
815 /** @todo this can have false-alarming sometimes if the separated rects will then be joind into the original rect,
816 * so far this should not be a problem for VReg clients, so keep it this way for now */
817 fChanged = true;
818
819 /* re-use the reg entry */
820 vboxVrListRegRemove(pList, pReg1);
821 VBoxRectIntersect(&pReg1->Rect, pRect2);
822 Assert(!VBoxRectIsZero(&pReg1->Rect));
823
824 vboxVrListRegAddOrder(pList, pMemberEntry, pReg1);
825 pReg1 = NULL;
826 }
827 }
828 else
829 {
830 Assert(fChanged); /* <- should be set by the if branch above */
831 PVBOXVR_REG pReg = vboxVrRegCreate();
832 if (!pReg)
833 {
834 WARN(("vboxVrRegCreate failed!"));
835 return VERR_NO_MEMORY;
836 }
837 VBoxRectIntersected(&RegRect1, pRect2, &pReg->Rect);
838 Assert(!VBoxRectIsZero(&pReg->Rect));
839 vboxVrListRegAddOrder(pList, pList->ListHead.pNext, pReg);
840 }
841 }
842
843 if (pReg1)
844 {
845 /* the region has no intersections, remove it */
846 vboxVrListRegRemove(pList, pReg1);
847 vboxVrRegTerm(pReg1);
848 fChanged = true;
849 }
850 }
851
852 *pfChanged = fChanged;
853 return VINF_SUCCESS;
854}
855
856VBOXVREGDECL(int) VBoxVrListIntersect(PVBOXVR_LIST pList, PCVBOXVR_LIST pList2, bool *pfChanged)
857{
858 bool fChanged = false;
859
860 int rc = vboxVrListIntersectNoJoin(pList, pList2, &fChanged);
861 if (pfChanged)
862 *pfChanged = fChanged;
863
864 if (!RT_SUCCESS(rc))
865 {
866 WARN(("vboxVrListSubstNoJoin failed!"));
867 return rc;
868 }
869
870 if (fChanged)
871 {
872 vboxVrListJoinRects(pList);
873 }
874
875 return rc;
876}
877
878VBOXVREGDECL(int) VBoxVrListRectsIntersect(PVBOXVR_LIST pList, uint32_t cRects, PCRTRECT aRects, bool *pfChanged)
879{
880 if (pfChanged)
881 *pfChanged = false;
882
883 if (VBoxVrListIsEmpty(pList))
884 return VINF_SUCCESS;
885
886 if (!cRects)
887 {
888 if (pfChanged)
889 *pfChanged = true;
890
891 VBoxVrListClear(pList);
892 return VINF_SUCCESS;
893 }
894
895 /* we perform intersection using lists because the algorythm axpects the rects to be non-intersected,
896 * which list guaranties to us */
897
898 VBOXVR_LIST TmpList;
899 VBoxVrListInit(&TmpList);
900
901 int rc = VBoxVrListRectsAdd(&TmpList, cRects, aRects, NULL);
902 if (RT_SUCCESS(rc))
903 {
904 rc = VBoxVrListIntersect(pList, &TmpList, pfChanged);
905 if (!RT_SUCCESS(rc))
906 {
907 WARN(("VBoxVrListIntersect failed! rc %d", rc));
908 }
909 }
910 else
911 {
912 WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
913 }
914 VBoxVrListClear(&TmpList);
915
916 return rc;
917}
918
919VBOXVREGDECL(int) VBoxVrListRectsSubst(PVBOXVR_LIST pList, uint32_t cRects, PCRTRECT aRects, bool *pfChanged)
920{
921#if 0
922 PCRTRECT pRects = vboxVrRectsOrder(cRects, aRects);
923 if (!pRects)
924 {
925 WARN(("vboxVrRectsOrder failed!"));
926 return VERR_NO_MEMORY;
927 }
928#endif
929
930 bool fChanged = false;
931
932 int rc = vboxVrListSubstNoJoin(pList, cRects, aRects, &fChanged);
933 if (!RT_SUCCESS(rc))
934 {
935 WARN(("vboxVrListSubstNoJoin failed!"));
936 goto done;
937 }
938
939 if (fChanged)
940 goto done;
941
942 vboxVrListJoinRects(pList);
943
944done:
945#if 0
946 if (pRects != aRects)
947 RTMemFree(pRects);
948#endif
949
950 if (pfChanged)
951 *pfChanged = fChanged;
952
953 return rc;
954}
955
956VBOXVREGDECL(int) VBoxVrListRectsSet(PVBOXVR_LIST pList, uint32_t cRects, PCRTRECT aRects, bool *pfChanged)
957{
958 if (pfChanged)
959 *pfChanged = false;
960
961 if (!cRects && VBoxVrListIsEmpty(pList))
962 return VINF_SUCCESS;
963
964 /** @todo fChanged will have false alarming here, fix if needed */
965 VBoxVrListClear(pList);
966
967 int rc = VBoxVrListRectsAdd(pList, cRects, aRects, NULL);
968 if (!RT_SUCCESS(rc))
969 {
970 WARN(("VBoxVrListRectsSet failed rc %d", rc));
971 return rc;
972 }
973
974 if (pfChanged)
975 *pfChanged = true;
976
977 return VINF_SUCCESS;
978}
979
980VBOXVREGDECL(int) VBoxVrListRectsAdd(PVBOXVR_LIST pList, uint32_t cRects, PCRTRECT aRects, bool *pfChanged)
981{
982 uint32_t cCovered = 0;
983
984 if (pfChanged)
985 *pfChanged = false;
986
987#if 0
988#ifdef VBOX_STRICT
989 for (uint32_t i = 0; i < cRects; ++i)
990 {
991 PRTRECT pRectI = &aRects[i];
992 for (uint32_t j = i + 1; j < cRects; ++j)
993 {
994 PRTRECT pRectJ = &aRects[j];
995 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
996 }
997 }
998#endif
999#endif
1000
1001 /* early sort out the case when there are no new rects */
1002 for (uint32_t i = 0; i < cRects; ++i)
1003 {
1004 if (VBoxRectIsZero(&aRects[i]))
1005 {
1006 cCovered++;
1007 continue;
1008 }
1009
1010 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
1011 {
1012 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
1013
1014 if (VBoxRectCovers(&pReg1->Rect, &aRects[i]))
1015 {
1016 cCovered++;
1017 break;
1018 }
1019 }
1020 }
1021
1022 if (cCovered == cRects)
1023 return VINF_SUCCESS;
1024
1025 /* rects are not covered, need to go the slow way */
1026
1027 VBOXVR_LIST DiffList;
1028 VBoxVrListInit(&DiffList);
1029 PRTRECT pListRects = NULL;
1030 uint32_t cAllocatedRects = 0;
1031 bool fNeedRectreate = true;
1032 bool fChanged = false;
1033 int rc = VINF_SUCCESS;
1034
1035 for (uint32_t i = 0; i < cRects; ++i)
1036 {
1037 if (VBoxRectIsZero(&aRects[i]))
1038 continue;
1039
1040 PVBOXVR_REG pReg = vboxVrRegCreate();
1041 if (!pReg)
1042 {
1043 WARN(("vboxVrRegCreate failed!"));
1044 rc = VERR_NO_MEMORY;
1045 break;
1046 }
1047 pReg->Rect = aRects[i];
1048
1049 uint32_t cListRects = VBoxVrListRectsCount(pList);
1050 if (!cListRects)
1051 {
1052 vboxVrListRegAdd(pList, pReg, &pList->ListHead, false);
1053 fChanged = true;
1054 continue;
1055 }
1056 Assert(VBoxVrListIsEmpty(&DiffList));
1057 vboxVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, false);
1058
1059 if (cAllocatedRects < cListRects)
1060 {
1061 cAllocatedRects = cListRects + cRects;
1062 Assert(fNeedRectreate);
1063 if (pListRects)
1064 RTMemFree(pListRects);
1065 pListRects = (RTRECT *)RTMemAlloc(sizeof(RTRECT) * cAllocatedRects);
1066 if (!pListRects)
1067 {
1068 WARN(("RTMemAlloc failed!"));
1069 rc = VERR_NO_MEMORY;
1070 break;
1071 }
1072 }
1073
1074
1075 if (fNeedRectreate)
1076 {
1077 rc = VBoxVrListRectsGet(pList, cListRects, pListRects);
1078 Assert(rc == VINF_SUCCESS);
1079 fNeedRectreate = false;
1080 }
1081
1082 bool fDummyChanged = false;
1083 rc = vboxVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged);
1084 if (!RT_SUCCESS(rc))
1085 {
1086 WARN(("vboxVrListSubstNoJoin failed!"));
1087 rc = VERR_NO_MEMORY;
1088 break;
1089 }
1090
1091 if (!VBoxVrListIsEmpty(&DiffList))
1092 {
1093 vboxVrListAddNonintersected(pList, &DiffList);
1094 fNeedRectreate = true;
1095 fChanged = true;
1096 }
1097
1098 Assert(VBoxVrListIsEmpty(&DiffList));
1099 }
1100
1101 if (pListRects)
1102 RTMemFree(pListRects);
1103
1104 Assert(VBoxVrListIsEmpty(&DiffList) || rc != VINF_SUCCESS);
1105 VBoxVrListClear(&DiffList);
1106
1107 if (fChanged)
1108 vboxVrListJoinRects(pList);
1109
1110 if (pfChanged)
1111 *pfChanged = fChanged;
1112
1113 return VINF_SUCCESS;
1114}
1115
1116VBOXVREGDECL(int) VBoxVrListRectsGet(PVBOXVR_LIST pList, uint32_t cRects, RTRECT * aRects)
1117{
1118 if (cRects < VBoxVrListRectsCount(pList))
1119 return VERR_BUFFER_OVERFLOW;
1120
1121 uint32_t i = 0;
1122 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext, ++i)
1123 {
1124 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
1125 aRects[i] = pReg1->Rect;
1126 }
1127 return VINF_SUCCESS;
1128}
1129
1130VBOXVREGDECL(int) VBoxVrListCmp(const VBOXVR_LIST *pList1, const VBOXVR_LIST *pList2)
1131{
1132 int cTmp = pList1->cEntries - pList2->cEntries;
1133 if (cTmp)
1134 return cTmp;
1135
1136 PVBOXVR_REG pReg1, pReg2;
1137
1138 for (pReg1 = RTListNodeGetNext(&pList1->ListHead, VBOXVR_REG, ListEntry),
1139 pReg2 = RTListNodeGetNext(&pList2->ListHead, VBOXVR_REG, ListEntry);
1140
1141 !RTListNodeIsDummy(&pList1->ListHead, pReg1, VBOXVR_REG, ListEntry);
1142
1143 pReg1 = RT_FROM_MEMBER(pReg1->ListEntry.pNext, VBOXVR_REG, ListEntry),
1144 pReg2 = RT_FROM_MEMBER(pReg2->ListEntry.pNext, VBOXVR_REG, ListEntry) )
1145 {
1146 Assert(!RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
1147 cTmp = VBoxRectCmp(&pReg1->Rect, &pReg2->Rect);
1148 if (cTmp)
1149 return cTmp;
1150 }
1151 Assert(RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
1152 return 0;
1153}
1154
1155VBOXVREGDECL(int) VBoxVrListClone(PCVBOXVR_LIST pList, PVBOXVR_LIST pDstList)
1156{
1157 VBoxVrListInit(pDstList);
1158 PCVBOXVR_REG pReg;
1159 RTListForEach(&pList->ListHead, pReg, const VBOXVR_REG, ListEntry)
1160 {
1161 PVBOXVR_REG pDstReg = vboxVrRegCreate();
1162 if (!pDstReg)
1163 {
1164 WARN(("vboxVrRegLaAlloc failed"));
1165 VBoxVrListClear(pDstList);
1166 return VERR_NO_MEMORY;
1167 }
1168 pDstReg->Rect = pReg->Rect;
1169 vboxVrListRegAdd(pDstList, pDstReg, &pDstList->ListHead, true /*bool fAfter*/);
1170 }
1171
1172 Assert(pDstList->cEntries == pList->cEntries);
1173
1174 return VINF_SUCCESS;
1175}
1176
1177VBOXVREGDECL(void) VBoxVrCompositorInit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_ENTRY_RELEASED pfnEntryReleased)
1178{
1179 RTListInit(&pCompositor->List);
1180 pCompositor->pfnEntryReleased = pfnEntryReleased;
1181}
1182
1183VBOXVREGDECL(void) VBoxVrCompositorRegionsClear(PVBOXVR_COMPOSITOR pCompositor, bool *pfChanged)
1184{
1185 bool fChanged = false;
1186 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
1187 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1188 {
1189 VBoxVrCompositorEntryRemove(pCompositor, pEntry);
1190 fChanged = true;
1191 }
1192
1193 if (pfChanged)
1194 *pfChanged = fChanged;
1195}
1196
1197VBOXVREGDECL(void) VBoxVrCompositorClear(PVBOXVR_COMPOSITOR pCompositor)
1198{
1199 VBoxVrCompositorRegionsClear(pCompositor, NULL);
1200}
1201
1202DECLINLINE(void) vboxVrCompositorEntryRelease(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1203 PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
1204{
1205 if (--pEntry->cRefs)
1206 {
1207 Assert(pEntry->cRefs < UINT32_MAX/2);
1208 return;
1209 }
1210
1211 Assert(!VBoxVrCompositorEntryIsInList(pEntry));
1212
1213 if (pCompositor->pfnEntryReleased)
1214 pCompositor->pfnEntryReleased(pCompositor, pEntry, pReplacingEntry);
1215}
1216
1217DECLINLINE(void) vboxVrCompositorEntryAddRef(PVBOXVR_COMPOSITOR_ENTRY pEntry)
1218{
1219 ++pEntry->cRefs;
1220}
1221
1222DECLINLINE(void) vboxVrCompositorEntryAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
1223{
1224 RTListPrepend(&pCompositor->List, &pEntry->Node);
1225 vboxVrCompositorEntryAddRef(pEntry);
1226}
1227
1228DECLINLINE(void) vboxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1229 PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
1230{
1231 RTListNodeRemove(&pEntry->Node);
1232 vboxVrCompositorEntryRelease(pCompositor, pEntry, pReplacingEntry);
1233}
1234
1235static void vboxVrCompositorEntryReplace(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1236 PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
1237{
1238 VBoxVrListMoveTo(&pEntry->Vr, &pReplacingEntry->Vr);
1239
1240 pReplacingEntry->Node = pEntry->Node;
1241 pReplacingEntry->Node.pNext->pPrev = &pReplacingEntry->Node;
1242 pReplacingEntry->Node.pPrev->pNext = &pReplacingEntry->Node;
1243 pEntry->Node.pNext = NULL;
1244 pEntry->Node.pPrev = NULL;
1245
1246 vboxVrCompositorEntryAddRef(pReplacingEntry);
1247 vboxVrCompositorEntryRelease(pCompositor, pEntry, pReplacingEntry);
1248}
1249
1250
1251
1252VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry)
1253{
1254 VBoxVrListInit(&pEntry->Vr);
1255 pEntry->cRefs = 0;
1256}
1257
1258VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
1259{
1260 if (!VBoxVrCompositorEntryIsInList(pEntry))
1261 return false;
1262
1263 vboxVrCompositorEntryAddRef(pEntry);
1264
1265 VBoxVrListClear(&pEntry->Vr);
1266 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1267 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1268 return true;
1269}
1270
1271VBOXVREGDECL(bool) VBoxVrCompositorEntryReplace(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1272 PVBOXVR_COMPOSITOR_ENTRY pNewEntry)
1273{
1274 if (!VBoxVrCompositorEntryIsInList(pEntry))
1275 return false;
1276
1277 vboxVrCompositorEntryReplace(pCompositor, pEntry, pNewEntry);
1278
1279 return true;
1280}
1281
1282static int vboxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1283 uint32_t cRects, PCRTRECT paRects, bool *pfChanged)
1284{
1285 bool fChanged;
1286 vboxVrCompositorEntryAddRef(pEntry);
1287
1288 int rc = VBoxVrListRectsSubst(&pEntry->Vr, cRects, paRects, &fChanged);
1289 if (RT_SUCCESS(rc))
1290 {
1291 if (VBoxVrListIsEmpty(&pEntry->Vr))
1292 {
1293 Assert(fChanged);
1294 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1295 }
1296 if (pfChanged)
1297 *pfChanged = false;
1298 }
1299 else
1300 WARN(("VBoxVrListRectsSubst failed, rc %d", rc));
1301
1302 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1303 return rc;
1304}
1305
1306VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1307 uint32_t cRects, PCRTRECT paRects, PVBOXVR_COMPOSITOR_ENTRY *ppReplacedEntry,
1308 uint32_t *pfChangeFlags)
1309{
1310 bool fOthersChanged = false;
1311 bool fCurChanged = false;
1312 bool fEntryChanged = false;
1313 bool fEntryWasInList = false;
1314 PVBOXVR_COMPOSITOR_ENTRY pCur;
1315 PVBOXVR_COMPOSITOR_ENTRY pNext;
1316 PVBOXVR_COMPOSITOR_ENTRY pReplacedEntry = NULL;
1317 int rc = VINF_SUCCESS;
1318
1319 if (pEntry)
1320 vboxVrCompositorEntryAddRef(pEntry);
1321
1322 if (!cRects)
1323 {
1324 if (pfChangeFlags)
1325 *pfChangeFlags = 0;
1326 if (pEntry)
1327 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1328 return VINF_SUCCESS;
1329 }
1330
1331 if (pEntry)
1332 {
1333 fEntryWasInList = VBoxVrCompositorEntryIsInList(pEntry);
1334 rc = VBoxVrListRectsAdd(&pEntry->Vr, cRects, paRects, &fEntryChanged);
1335 if (RT_SUCCESS(rc))
1336 {
1337 if (VBoxVrListIsEmpty(&pEntry->Vr))
1338 {
1339// WARN(("Empty rectangles passed in, is it expected?"));
1340 if (pfChangeFlags)
1341 *pfChangeFlags = 0;
1342 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1343 return VINF_SUCCESS;
1344 }
1345 }
1346 else
1347 {
1348 WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
1349 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1350 return rc;
1351 }
1352
1353 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1354 }
1355 else
1356 {
1357 fEntryChanged = true;
1358 }
1359
1360 RTListForEachSafe(&pCompositor->List, pCur, pNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1361 {
1362 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1363 if (pCur != pEntry)
1364 {
1365 if (pEntry && !VBoxVrListCmp(&pCur->Vr, &pEntry->Vr))
1366 {
1367 VBoxVrListClear(&pCur->Vr);
1368 pReplacedEntry = pCur;
1369 vboxVrCompositorEntryAddRef(pReplacedEntry);
1370 vboxVrCompositorEntryRemove(pCompositor, pCur, pEntry);
1371 if (ppReplacedEntry)
1372 *ppReplacedEntry = pReplacedEntry;
1373 break;
1374 }
1375
1376 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, &fCurChanged);
1377 if (RT_SUCCESS(rc))
1378 fOthersChanged |= fCurChanged;
1379 else
1380 {
1381 WARN(("vboxVrCompositorEntryRegionsSubst failed, rc %d", rc));
1382 return rc;
1383 }
1384 }
1385 }
1386
1387 AssertRC(rc);
1388
1389 if (pEntry)
1390 {
1391 if (!fEntryWasInList)
1392 {
1393 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1394 vboxVrCompositorEntryAdd(pCompositor, pEntry);
1395 }
1396 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1397 }
1398
1399 uint32_t fFlags = 0;
1400 if (fOthersChanged)
1401 {
1402 Assert(!pReplacedEntry);
1403 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED
1404 | VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED;
1405 }
1406 else if (pReplacedEntry)
1407 {
1408 vboxVrCompositorEntryRelease(pCompositor, pReplacedEntry, pEntry);
1409 Assert(fEntryChanged);
1410 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED;
1411 }
1412 else if (fEntryChanged)
1413 {
1414 Assert(!pReplacedEntry);
1415 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED;
1416 }
1417 else
1418 {
1419 Assert(!pReplacedEntry);
1420 }
1421
1422 if (!fEntryWasInList)
1423 Assert(fEntryChanged);
1424
1425 if (pfChangeFlags)
1426 *pfChangeFlags = fFlags;
1427
1428 return VINF_SUCCESS;
1429}
1430
1431VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1432 uint32_t cRects, PCRTRECT paRects, bool *pfChanged)
1433{
1434 if (!pEntry)
1435 {
1436 WARN(("VBoxVrCompositorEntryRegionsSubst called with zero entry, unsupported!"));
1437 if (pfChanged)
1438 *pfChanged = false;
1439 return VERR_INVALID_PARAMETER;
1440 }
1441
1442 vboxVrCompositorEntryAddRef(pEntry);
1443
1444 if (VBoxVrListIsEmpty(&pEntry->Vr))
1445 {
1446 if (pfChanged)
1447 *pfChanged = false;
1448 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1449 return VINF_SUCCESS;
1450 }
1451
1452 int rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pEntry, cRects, paRects, pfChanged);
1453 if (!RT_SUCCESS(rc))
1454 WARN(("pfChanged failed, rc %d", rc));
1455
1456 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1457
1458 return rc;
1459}
1460
1461VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1462 uint32_t cRects, PCRTRECT paRects, bool *pfChanged)
1463{
1464 if (!pEntry)
1465 {
1466 WARN(("VBoxVrCompositorEntryRegionsSet called with zero entry, unsupported!"));
1467 if (pfChanged)
1468 *pfChanged = false;
1469 return VERR_INVALID_PARAMETER;
1470 }
1471
1472 vboxVrCompositorEntryAddRef(pEntry);
1473
1474 bool fChanged = false, fCurChanged = false;
1475 uint32_t fChangeFlags = 0;
1476 int rc;
1477 fCurChanged = VBoxVrCompositorEntryRemove(pCompositor, pEntry);
1478 fChanged |= fCurChanged;
1479
1480 rc = VBoxVrCompositorEntryRegionsAdd(pCompositor, pEntry, cRects, paRects, NULL, &fChangeFlags);
1481 if (RT_SUCCESS(rc))
1482 {
1483 fChanged |= !!fChangeFlags;
1484 if (pfChanged)
1485 *pfChanged = fChanged;
1486 }
1487 else
1488 WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
1489
1490 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1491
1492 return VINF_SUCCESS;
1493}
1494
1495VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1496 PCVBOXVR_LIST pList2, bool *pfChanged)
1497{
1498 int rc = VINF_SUCCESS;
1499 bool fChanged = false;
1500
1501 vboxVrCompositorEntryAddRef(pEntry);
1502
1503 if (VBoxVrCompositorEntryIsInList(pEntry))
1504 {
1505 rc = VBoxVrListIntersect(&pEntry->Vr, pList2, &fChanged);
1506 if (RT_SUCCESS(rc))
1507 {
1508 if (VBoxVrListIsEmpty(&pEntry->Vr))
1509 {
1510 Assert(fChanged);
1511 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1512 }
1513 }
1514 else
1515 {
1516 WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
1517 }
1518 }
1519
1520 if (pfChanged)
1521 *pfChanged = fChanged;
1522
1523 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1524
1525 return rc;
1526}
1527
1528VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1529 uint32_t cRects, PCRTRECT paRects, bool *pfChanged)
1530{
1531 int rc = VINF_SUCCESS;
1532 bool fChanged = false;
1533
1534 vboxVrCompositorEntryAddRef(pEntry);
1535
1536 if (VBoxVrCompositorEntryIsInList(pEntry))
1537 {
1538 rc = VBoxVrListRectsIntersect(&pEntry->Vr, cRects, paRects, &fChanged);
1539 if (RT_SUCCESS(rc))
1540 {
1541 if (VBoxVrListIsEmpty(&pEntry->Vr))
1542 {
1543 Assert(fChanged);
1544 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1545 }
1546 }
1547 else
1548 {
1549 WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
1550 }
1551 }
1552
1553 if (pfChanged)
1554 *pfChanged = fChanged;
1555
1556 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1557
1558 return rc;
1559}
1560
1561VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersectAll(PVBOXVR_COMPOSITOR pCompositor, PCVBOXVR_LIST pList2, bool *pfChanged)
1562{
1563 VBOXVR_COMPOSITOR_ITERATOR Iter;
1564 VBoxVrCompositorIterInit(pCompositor, &Iter);
1565 PVBOXVR_COMPOSITOR_ENTRY pEntry;
1566 int rc = VINF_SUCCESS;
1567 bool fChanged = false;
1568
1569 while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
1570 {
1571 bool fTmpChanged = false;
1572 int tmpRc = VBoxVrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
1573 if (RT_SUCCESS(tmpRc))
1574 fChanged |= fTmpChanged;
1575 else
1576 {
1577 WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1578 rc = tmpRc;
1579 }
1580 }
1581
1582 if (pfChanged)
1583 *pfChanged = fChanged;
1584
1585 return rc;
1586}
1587
1588VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersectAll(PVBOXVR_COMPOSITOR pCompositor, uint32_t cRegions, PCRTRECT paRegions,
1589 bool *pfChanged)
1590{
1591 VBOXVR_COMPOSITOR_ITERATOR Iter;
1592 VBoxVrCompositorIterInit(pCompositor, &Iter);
1593 PVBOXVR_COMPOSITOR_ENTRY pEntry;
1594 int rc = VINF_SUCCESS;
1595 bool fChanged = false;
1596
1597 while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
1598 {
1599 bool fTmpChanged = false;
1600 int tmpRc = VBoxVrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
1601 if (RT_SUCCESS(tmpRc))
1602 fChanged |= fTmpChanged;
1603 else
1604 {
1605 WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1606 rc = tmpRc;
1607 }
1608 }
1609
1610 if (pfChanged)
1611 *pfChanged = fChanged;
1612
1613 return rc;
1614}
1615
1616VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry,
1617 int32_t x, int32_t y, bool *pfChanged)
1618{
1619 if (!pEntry)
1620 {
1621 WARN(("VBoxVrCompositorEntryRegionsTranslate called with zero entry, unsupported!"));
1622 if (pfChanged)
1623 *pfChanged = false;
1624 return VERR_INVALID_PARAMETER;
1625 }
1626
1627 vboxVrCompositorEntryAddRef(pEntry);
1628
1629 if ( (!x && !y)
1630 || !VBoxVrCompositorEntryIsInList(pEntry))
1631 {
1632 if (pfChanged)
1633 *pfChanged = false;
1634
1635 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1636 return VINF_SUCCESS;
1637 }
1638
1639 VBoxVrListTranslate(&pEntry->Vr, x, y);
1640
1641 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1642
1643 PVBOXVR_COMPOSITOR_ENTRY pCur;
1644 uint32_t cRects = 0;
1645 PRTRECT paRects = NULL;
1646 int rc = VINF_SUCCESS;
1647 RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
1648 {
1649 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1650
1651 if (pCur == pEntry)
1652 continue;
1653
1654 if (!paRects)
1655 {
1656 cRects = VBoxVrListRectsCount(&pEntry->Vr);
1657 Assert(cRects);
1658 paRects = (RTRECT*)RTMemAlloc(cRects * sizeof(RTRECT));
1659 if (!paRects)
1660 {
1661 WARN(("RTMemAlloc failed!"));
1662 rc = VERR_NO_MEMORY;
1663 break;
1664 }
1665
1666 rc = VBoxVrListRectsGet(&pEntry->Vr, cRects, paRects);
1667 if (!RT_SUCCESS(rc))
1668 {
1669 WARN(("VBoxVrListRectsGet failed! rc %d", rc));
1670 break;
1671 }
1672 }
1673
1674 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, NULL);
1675 if (!RT_SUCCESS(rc))
1676 {
1677 WARN(("vboxVrCompositorEntryRegionsSubst failed! rc %d", rc));
1678 break;
1679 }
1680 }
1681
1682 if (pfChanged)
1683 *pfChanged = true;
1684
1685 if (paRects)
1686 RTMemFree(paRects);
1687
1688 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1689
1690 return rc;
1691}
1692
1693VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
1694{
1695 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
1696 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1697 {
1698 if (!pfnVisitor(pCompositor, pEntry, pvVisitor))
1699 return;
1700 }
1701}
1702
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use