VirtualBox

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

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

src/VBox: Make the use of the iterator for RTListForEach()/RTListForEachSafe() more obvious. There is no need to initialize the iterator and we also must not depend on the iterator being NULL if the list was empty.

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