VirtualBox

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

Last change on this file since 50095 was 50095, checked in by vboxsync, 11 years ago

crOpenGL: presentation infrastructure rework (still work in progress)

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

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