VirtualBox

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

Last change on this file since 62492 was 62492, checked in by vboxsync, 8 years ago

(C) 2016

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