VirtualBox

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

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

crOpenGL: some cleanup

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.2 KB
Line 
1/* $Id: vreg.cpp 48733 2013-09-27 13:07:23Z vboxsync $ */
2
3/** @file
4 * Visible Regions processing API implementation
5 */
6
7/*
8 * Copyright (C) 2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18#include <cr_vreg.h>
19#include <iprt/err.h>
20#include <iprt/assert.h>
21#include <iprt/asm.h>
22
23#include <cr_error.h>
24#define WARN(_m) do { crWarning _m ; } while (0)
25
26#ifndef IN_RING0
27#include <iprt/memcache.h>
28#ifndef VBOXVDBG_VR_LAL_DISABLE
29static RTMEMCACHE g_VBoxVrLookasideList;
30#define vboxVrRegLaAlloc(_c) RTMemCacheAlloc((_c))
31#define vboxVrRegLaFree(_c, _e) RTMemCacheFree((_c), (_e))
32DECLINLINE(int) vboxVrLaCreate(RTMEMCACHE *pCache, size_t cbElement)
33{
34 int rc = RTMemCacheCreate(pCache, cbElement,
35 0, /* size_t cbAlignment */
36 UINT32_MAX, /* uint32_t cMaxObjects */
37 NULL, /* PFNMEMCACHECTOR pfnCtor*/
38 NULL, /* PFNMEMCACHEDTOR pfnDtor*/
39 NULL, /* void *pvUser*/
40 0 /* uint32_t fFlags*/
41 );
42 if (!RT_SUCCESS(rc))
43 {
44 WARN(("RTMemCacheCreate failed rc %d", rc));
45 return rc;
46 }
47 return VINF_SUCCESS;
48}
49#define vboxVrLaDestroy(_c) RTMemCacheDestroy((_c))
50#endif
51#else
52# ifdef RT_OS_WINDOWS
53# ifdef PAGE_SIZE
54# undef PAGE_SIZE
55# endif
56# ifdef PAGE_SHIFT
57# undef PAGE_SHIFT
58# endif
59# define VBOX_WITH_WORKAROUND_MISSING_PACK
60# if (_MSC_VER >= 1400) && !defined(VBOX_WITH_PATCHED_DDK)
61# define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap
62# define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap
63# define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap
64# define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap
65# define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap
66# define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap
67# define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap
68# define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap
69# pragma warning(disable : 4163)
70# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK
71# pragma warning(disable : 4103)
72# endif
73# include <ntddk.h>
74# pragma warning(default : 4163)
75# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK
76# pragma pack()
77# pragma warning(default : 4103)
78# endif
79# undef _InterlockedExchange
80# undef _InterlockedExchangeAdd
81# undef _InterlockedCompareExchange
82# undef _InterlockedAddLargeStatistic
83# undef _interlockedbittestandset
84# undef _interlockedbittestandreset
85# undef _interlockedbittestandset64
86# undef _interlockedbittestandreset64
87# else
88# include <ntddk.h>
89# endif
90#ifndef VBOXVDBG_VR_LAL_DISABLE
91static LOOKASIDE_LIST_EX g_VBoxVrLookasideList;
92#define vboxVrRegLaAlloc(_c) ExAllocateFromLookasideListEx(&(_c))
93#define vboxVrRegLaFree(_c, _e) ExFreeToLookasideListEx(&(_c), (_e))
94#define VBOXWDDMVR_MEMTAG 'vDBV'
95DECLINLINE(int) vboxVrLaCreate(LOOKASIDE_LIST_EX *pCache, size_t cbElement)
96{
97 NTSTATUS Status = ExInitializeLookasideListEx(pCache,
98 NULL, /* PALLOCATE_FUNCTION_EX Allocate */
99 NULL, /* PFREE_FUNCTION_EX Free */
100 NonPagedPool,
101 0, /* ULONG Flags */
102 cbElement,
103 VBOXWDDMVR_MEMTAG,
104 0 /* USHORT Depth - reserved, must be null */
105 );
106 if (!NT_SUCCESS(Status))
107 {
108 WARN(("ExInitializeLookasideListEx failed, Status (0x%x)", Status));
109 return VERR_GENERAL_FAILURE;
110 }
111
112 return VINF_SUCCESS;
113}
114#define vboxVrLaDestroy(_c) ExDeleteLookasideListEx(&(_c))
115#endif
116# else
117# error "port me!"
118# endif
119#endif
120
121#ifdef DEBUG_misha
122//# define VBOXVDBG_VR_LAL_DISABLE
123#endif
124
125#ifndef VBOXVDBG_VR_LAL_DISABLE
126static volatile int32_t g_cVBoxVrInits = 0;
127#endif
128
129static PVBOXVR_REG vboxVrRegCreate()
130{
131#ifndef VBOXVDBG_VR_LAL_DISABLE
132 PVBOXVR_REG pReg = (PVBOXVR_REG)vboxVrRegLaAlloc(g_VBoxVrLookasideList);
133 if (!pReg)
134 {
135 WARN(("ExAllocateFromLookasideListEx failed!"));
136 }
137 return pReg;
138#else
139 return (PVBOXVR_REG)RTMemAlloc(sizeof (VBOXVR_REG));
140#endif
141}
142
143static void vboxVrRegTerm(PVBOXVR_REG pReg)
144{
145#ifndef VBOXVDBG_VR_LAL_DISABLE
146 vboxVrRegLaFree(g_VBoxVrLookasideList, pReg);
147#else
148 RTMemFree(pReg);
149#endif
150}
151
152VBOXVREGDECL(void) VBoxVrListClear(PVBOXVR_LIST pList)
153{
154 PVBOXVR_REG pReg, pRegNext;
155
156 RTListForEachSafe(&pList->ListHead, pReg, pRegNext, VBOXVR_REG, ListEntry)
157 {
158 vboxVrRegTerm(pReg);
159 }
160 VBoxVrListInit(pList);
161}
162
163/* moves list data to pDstList and empties the pList */
164VBOXVREGDECL(void) VBoxVrListMoveTo(PVBOXVR_LIST pList, PVBOXVR_LIST pDstList)
165{
166 *pDstList = *pList;
167 pDstList->ListHead.pNext->pPrev = &pDstList->ListHead;
168 pDstList->ListHead.pPrev->pNext = &pDstList->ListHead;
169 VBoxVrListInit(pList);
170}
171
172#define VBOXVR_MEMTAG 'vDBV'
173
174VBOXVREGDECL(int) VBoxVrInit()
175{
176 int32_t cNewRefs = ASMAtomicIncS32(&g_cVBoxVrInits);
177 Assert(cNewRefs >= 1);
178 Assert(cNewRefs == 1); /* <- debugging */
179 if (cNewRefs > 1)
180 return VINF_SUCCESS;
181
182#ifndef VBOXVDBG_VR_LAL_DISABLE
183 int rc = vboxVrLaCreate(&g_VBoxVrLookasideList, sizeof (VBOXVR_REG));
184 if (!RT_SUCCESS(rc))
185 {
186 WARN(("ExInitializeLookasideListEx failed, rc (%d)", rc));
187 return rc;
188 }
189#endif
190
191 return VINF_SUCCESS;
192}
193
194VBOXVREGDECL(void) VBoxVrTerm()
195{
196 int32_t cNewRefs = ASMAtomicDecS32(&g_cVBoxVrInits);
197 Assert(cNewRefs >= 0);
198 if (cNewRefs > 0)
199 return;
200
201#ifndef VBOXVDBG_VR_LAL_DISABLE
202 vboxVrLaDestroy(g_VBoxVrLookasideList);
203#endif
204}
205
206typedef DECLCALLBACK(int) FNVBOXVR_CB_COMPARATOR(const VBOXVR_REG *pReg1, const VBOXVR_REG *pReg2);
207typedef FNVBOXVR_CB_COMPARATOR *PFNVBOXVR_CB_COMPARATOR;
208
209static DECLCALLBACK(int) vboxVrRegNonintersectedComparator(const RTRECT* pRect1, const RTRECT* pRect2)
210{
211 Assert(!VBoxRectIsIntersect(pRect1, pRect2));
212 if (pRect1->yTop != pRect2->yTop)
213 return pRect1->yTop - pRect2->yTop;
214 return pRect1->xLeft - pRect2->xLeft;
215}
216
217#ifdef DEBUG_misha
218static void vboxVrDbgListDoVerify(PVBOXVR_LIST pList)
219{
220 PVBOXVR_REG pReg1, pReg2;
221 RTListForEach(&pList->ListHead, pReg1, VBOXVR_REG, ListEntry)
222 {
223 Assert(!VBoxRectIsZero(&pReg1->Rect));
224 for (RTLISTNODE *pEntry2 = pReg1->ListEntry.pNext; pEntry2 != &pList->ListHead; pEntry2 = pEntry2->pNext)
225 {
226 pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
227 Assert(vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0);
228 }
229 }
230}
231
232#define vboxVrDbgListVerify vboxVrDbgListDoVerify
233#else
234#define vboxVrDbgListVerify(_p) do {} while (0)
235#endif
236
237static int vboxVrListUniteIntersection(PVBOXVR_LIST pList, PVBOXVR_LIST pIntersection);
238
239#define VBOXVR_INVALID_COORD (~0U)
240
241DECLINLINE(void) vboxVrListRegAdd(PVBOXVR_LIST pList, PVBOXVR_REG pReg, PRTLISTNODE pPlace, bool fAfter)
242{
243 if (fAfter)
244 RTListPrepend(pPlace, &pReg->ListEntry);
245 else
246 RTListAppend(pPlace, &pReg->ListEntry);
247 ++pList->cEntries;
248 vboxVrDbgListVerify(pList);
249}
250
251DECLINLINE(void) vboxVrListRegRemove(PVBOXVR_LIST pList, PVBOXVR_REG pReg)
252{
253 RTListNodeRemove(&pReg->ListEntry);
254 --pList->cEntries;
255 vboxVrDbgListVerify(pList);
256}
257
258static void vboxVrListRegAddOrder(PVBOXVR_LIST pList, PRTLISTNODE pMemberEntry, PVBOXVR_REG pReg)
259{
260 do
261 {
262 if (pMemberEntry != &pList->ListHead)
263 {
264 PVBOXVR_REG pMemberReg = PVBOXVR_REG_FROM_ENTRY(pMemberEntry);
265 if (vboxVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0)
266 {
267 pMemberEntry = pMemberEntry->pNext;
268 continue;
269 }
270 }
271 vboxVrListRegAdd(pList, pReg, pMemberEntry, false);
272 break;
273 } while (1);
274}
275
276static void vboxVrListAddNonintersected(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
277{
278 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
279
280 for (PRTLISTNODE pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.pNext)
281 {
282 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
283 do {
284 if (pEntry1 != &pList1->ListHead)
285 {
286 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
287 if (vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0)
288 {
289 pEntry1 = pEntry1->pNext;
290 continue;
291 }
292 }
293 vboxVrListRegRemove(pList2, pReg2);
294 vboxVrListRegAdd(pList1, pReg2, pEntry1, false);
295 break;
296 } while (1);
297 }
298
299 Assert(VBoxVrListIsEmpty(pList2));
300}
301
302static int vboxVrListRegIntersectSubstNoJoin(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2)
303{
304 uint32_t topLim = VBOXVR_INVALID_COORD;
305 uint32_t bottomLim = VBOXVR_INVALID_COORD;
306 RTLISTNODE List;
307 PVBOXVR_REG pBottomReg = NULL;
308#ifdef DEBUG_misha
309 RTRECT tmpRect = pReg1->Rect;
310 vboxVrDbgListVerify(pList1);
311#endif
312 Assert(!VBoxRectIsZero(pRect2));
313
314 RTListInit(&List);
315
316 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
317
318 if (pReg1->Rect.yTop < pRect2->yTop)
319 {
320 Assert(pRect2->yTop < pReg1->Rect.yBottom);
321 PVBOXVR_REG pRegResult = vboxVrRegCreate();
322 pRegResult->Rect.yTop = pReg1->Rect.yTop;
323 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
324 pRegResult->Rect.yBottom = pRect2->yTop;
325 pRegResult->Rect.xRight = pReg1->Rect.xRight;
326 topLim = pRect2->yTop;
327 RTListAppend(&List, &pRegResult->ListEntry);
328 }
329
330 if (pReg1->Rect.yBottom > pRect2->yBottom)
331 {
332 Assert(pRect2->yBottom > pReg1->Rect.yTop);
333 PVBOXVR_REG pRegResult = vboxVrRegCreate();
334 pRegResult->Rect.yTop = pRect2->yBottom;
335 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
336 pRegResult->Rect.yBottom = pReg1->Rect.yBottom;
337 pRegResult->Rect.xRight = pReg1->Rect.xRight;
338 bottomLim = pRect2->yBottom;
339 pBottomReg = pRegResult;
340 }
341
342 if (pReg1->Rect.xLeft < pRect2->xLeft)
343 {
344 Assert(pRect2->xLeft < pReg1->Rect.xRight);
345 PVBOXVR_REG pRegResult = vboxVrRegCreate();
346 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
347 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
348 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
349 pRegResult->Rect.xRight = pRect2->xLeft;
350 RTListAppend(&List, &pRegResult->ListEntry);
351 }
352
353 if (pReg1->Rect.xRight > pRect2->xRight)
354 {
355 Assert(pRect2->xRight > pReg1->Rect.xLeft);
356 PVBOXVR_REG pRegResult = vboxVrRegCreate();
357 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
358 pRegResult->Rect.xLeft = pRect2->xRight;
359 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
360 pRegResult->Rect.xRight = pReg1->Rect.xRight;
361 RTListAppend(&List, &pRegResult->ListEntry);
362 }
363
364 if (pBottomReg)
365 RTListAppend(&List, &pBottomReg->ListEntry);
366
367 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
368 vboxVrListRegRemove(pList1, pReg1);
369 vboxVrRegTerm(pReg1);
370
371 if (RTListIsEmpty(&List))
372 return VINF_SUCCESS; /* the region is covered by the pRect2 */
373
374 PRTLISTNODE pEntry = List.pNext, pNext;
375 for (; pEntry != &List; pEntry = pNext)
376 {
377 pNext = pEntry->pNext;
378 PVBOXVR_REG pReg = PVBOXVR_REG_FROM_ENTRY(pEntry);
379
380 vboxVrListRegAddOrder(pList1, pMemberEntry, pReg);
381 pMemberEntry = pEntry->pNext; /* the following elements should go after the given pEntry since they are ordered already */
382 }
383 return VINF_SUCCESS;
384}
385
386/* @returns Entry to be used for continuing the rectangles iterations being made currently on the callback call.
387 * ListHead is returned to break the current iteration
388 * @param ppNext specifies next reg entry to be used for iteration. the default is pReg1->ListEntry.pNext */
389typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_INTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2, void *pvContext, PRTLISTNODE *ppNext);
390typedef FNVBOXVR_CB_INTERSECTED_VISITOR *PFNVBOXVR_CB_INTERSECTED_VISITOR;
391
392static void vboxVrListVisitIntersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
393{
394 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
395 PRTLISTNODE pNext1;
396 uint32_t iFirst2 = 0;
397
398 for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
399 {
400 pNext1 = pEntry1->pNext;
401 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
402 for (uint32_t i = iFirst2; i < cRects; ++i)
403 {
404 const RTRECT *pRect2 = &aRects[i];
405 if (VBoxRectIsZero(pRect2))
406 continue;
407
408 if (!VBoxRectIsIntersect(&pReg1->Rect, pRect2))
409 continue;
410
411 /* the visitor can modify the list 1, apply necessary adjustments after it */
412 pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1);
413 if (pEntry1 == &pList1->ListHead)
414 break;
415 else
416 pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
417 }
418 }
419}
420
421/* @returns Entry to be iterated next. ListHead is returned to break the iteration
422 *
423 */
424typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_NONINTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext);
425typedef FNVBOXVR_CB_NONINTERSECTED_VISITOR *PFNVBOXVR_CB_NONINTERSECTED_VISITOR;
426
427static void vboxVrListVisitNonintersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_NONINTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
428{
429 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
430 PRTLISTNODE pNext1;
431 uint32_t iFirst2 = 0;
432
433 for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
434 {
435 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
436 uint32_t i = iFirst2;
437 for (; i < cRects; ++i)
438 {
439 const RTRECT *pRect2 = &aRects[i];
440 if (VBoxRectIsZero(pRect2))
441 continue;
442
443 if (VBoxRectIsIntersect(&pReg1->Rect, pRect2))
444 break;
445 }
446
447 if (i == cRects)
448 pNext1 = pfnVisitor(pList1, pReg1, pvVisitor);
449 else
450 pNext1 = pEntry1->pNext;
451 }
452}
453
454static void vboxVrListJoinRectsHV(PVBOXVR_LIST pList, bool fHorizontal)
455{
456 PRTLISTNODE pNext1, pNext2;
457
458 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
459 {
460 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
461 pNext1 = pEntry1->pNext;
462 for (PRTLISTNODE pEntry2 = pEntry1->pNext; pEntry2 != &pList->ListHead; pEntry2 = pNext2)
463 {
464 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
465 pNext2 = pEntry2->pNext;
466 if (fHorizontal)
467 {
468 if (pReg1->Rect.yTop == pReg2->Rect.yTop)
469 {
470 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
471 {
472 /* join rectangles */
473 vboxVrListRegRemove(pList, pReg2);
474 if (pReg1->Rect.yBottom > pReg2->Rect.yBottom)
475 {
476 int32_t oldRight1 = pReg1->Rect.xRight;
477 int32_t oldBottom1 = pReg1->Rect.yBottom;
478 pReg1->Rect.xRight = pReg2->Rect.xRight;
479 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
480
481 vboxVrDbgListVerify(pList);
482
483 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
484 pReg2->Rect.yTop = pReg1->Rect.yBottom;
485 pReg2->Rect.xRight = oldRight1;
486 pReg2->Rect.yBottom = oldBottom1;
487 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
488 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
489 * and thus can match one of the previous rects */
490 pNext1 = pList->ListHead.pNext;
491 break;
492 }
493 else if (pReg1->Rect.yBottom < pReg2->Rect.yBottom)
494 {
495 pReg1->Rect.xRight = pReg2->Rect.xRight;
496 vboxVrDbgListVerify(pList);
497 pReg2->Rect.yTop = pReg1->Rect.yBottom;
498 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
499 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
500 * and thus can match one of the previous rects */
501 pNext1 = pList->ListHead.pNext;
502 break;
503 }
504 else
505 {
506 pReg1->Rect.xRight = pReg2->Rect.xRight;
507 vboxVrDbgListVerify(pList);
508 /* reset the pNext1 since it could be the pReg2 being destroyed */
509 pNext1 = pEntry1->pNext;
510 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
511 vboxVrRegTerm(pReg2);
512 }
513 }
514 continue;
515 }
516 else if (pReg1->Rect.yBottom == pReg2->Rect.yBottom)
517 {
518 Assert(pReg1->Rect.yTop < pReg2->Rect.yTop); /* <- since pReg1 > pReg2 && pReg1->Rect.yTop != pReg2->Rect.yTop*/
519 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
520 {
521 /* join rectangles */
522 vboxVrListRegRemove(pList, pReg2);
523
524 pReg1->Rect.yBottom = pReg2->Rect.yTop;
525 vboxVrDbgListVerify(pList);
526 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
527
528 vboxVrListRegAddOrder(pList, pNext2, pReg2);
529
530 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
531 * and thus can match one of the previous rects */
532 pNext1 = pList->ListHead.pNext;
533 break;
534 }
535 else if (pReg1->Rect.xLeft == pReg2->Rect.xRight)
536 {
537 /* join rectangles */
538 vboxVrListRegRemove(pList, pReg2);
539
540 pReg1->Rect.yBottom = pReg2->Rect.yTop;
541 vboxVrDbgListVerify(pList);
542 pReg2->Rect.xRight = pReg1->Rect.xRight;
543
544 vboxVrListRegAddOrder(pList, pNext2, pReg2);
545
546 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
547 * and thus can match one of the previous rects */
548 pNext1 = pList->ListHead.pNext;
549 break;
550 }
551 continue;
552 }
553 }
554 else
555 {
556 if (pReg1->Rect.yBottom == pReg2->Rect.yTop)
557 {
558 if (pReg1->Rect.xLeft == pReg2->Rect.xLeft)
559 {
560 if (pReg1->Rect.xRight == pReg2->Rect.xRight)
561 {
562 /* join rects */
563 vboxVrListRegRemove(pList, pReg2);
564
565 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
566 vboxVrDbgListVerify(pList);
567
568 /* reset the pNext1 since it could be the pReg2 being destroyed */
569 pNext1 = pEntry1->pNext;
570 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
571 vboxVrRegTerm(pReg2);
572 continue;
573 }
574 /* no more to be done for for pReg1 */
575 break;
576 }
577 else if (pReg1->Rect.xRight > pReg2->Rect.xLeft)
578 {
579 /* no more to be done for for pReg1 */
580 break;
581 }
582
583 continue;
584 }
585 else if (pReg1->Rect.yBottom < pReg2->Rect.yTop)
586 {
587 /* no more to be done for for pReg1 */
588 break;
589 }
590 }
591 }
592 }
593}
594
595static void vboxVrListJoinRects(PVBOXVR_LIST pList)
596{
597 vboxVrListJoinRectsHV(pList, true);
598 vboxVrListJoinRectsHV(pList, false);
599}
600
601typedef struct VBOXVR_CBDATA_SUBST
602{
603 int rc;
604 bool fChanged;
605} VBOXVR_CBDATA_SUBST, *PVBOXVR_CBDATA_SUBST;
606
607static DECLCALLBACK(PRTLISTNODE) vboxVrListSubstNoJoinCb(PVBOXVR_LIST pList, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
608{
609 PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
610 /* store the prev to get the new pNext out of it*/
611 PRTLISTNODE pPrev = pReg1->ListEntry.pPrev;
612 pData->fChanged = true;
613
614 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
615
616 /* NOTE: the pReg1 will be invalid after the vboxVrListRegIntersectSubstNoJoin call!!! */
617 int rc = vboxVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2);
618 if (RT_SUCCESS(rc))
619 {
620 *ppNext = pPrev->pNext;
621 return &pList->ListHead;
622 }
623 WARN(("vboxVrListRegIntersectSubstNoJoin failed!"));
624 Assert(!RT_SUCCESS(rc));
625 pData->rc = rc;
626 *ppNext = &pList->ListHead;
627 return &pList->ListHead;
628}
629
630static int vboxVrListSubstNoJoin(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
631{
632 if (pfChanged)
633 *pfChanged = false;
634
635 if (VBoxVrListIsEmpty(pList))
636 return VINF_SUCCESS;
637
638 VBOXVR_CBDATA_SUBST Data;
639 Data.rc = VINF_SUCCESS;
640 Data.fChanged = false;
641
642 vboxVrListVisitIntersected(pList, cRects, aRects, vboxVrListSubstNoJoinCb, &Data);
643 if (!RT_SUCCESS(Data.rc))
644 {
645 WARN(("vboxVrListVisitIntersected failed!"));
646 return Data.rc;
647 }
648
649 if (pfChanged)
650 *pfChanged = Data.fChanged;
651
652 return VINF_SUCCESS;
653}
654
655#if 0
656static const RTRECT * vboxVrRectsOrder(uint32_t cRects, const RTRECT * aRects)
657{
658#ifdef DEBUG
659 {
660 for (uint32_t i = 0; i < cRects; ++i)
661 {
662 RTRECT *pRectI = &aRects[i];
663 for (uint32_t j = i + 1; j < cRects; ++j)
664 {
665 RTRECT *pRectJ = &aRects[j];
666 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
667 }
668 }
669 }
670#endif
671
672 RTRECT * pRects = (RTRECT *)aRects;
673 /* check if rects are ordered already */
674 for (uint32_t i = 0; i < cRects - 1; ++i)
675 {
676 RTRECT *pRect1 = &pRects[i];
677 RTRECT *pRect2 = &pRects[i+1];
678 if (vboxVrRegNonintersectedComparator(pRect1, pRect2) < 0)
679 continue;
680
681 WARN(("rects are unoreded!"));
682
683 if (pRects == aRects)
684 {
685 pRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cRects);
686 if (!pRects)
687 {
688 WARN(("RTMemAlloc failed!"));
689 return NULL;
690 }
691
692 memcpy(pRects, aRects, sizeof (RTRECT) * cRects);
693 }
694
695 Assert(pRects != aRects);
696
697 int j = (int)i - 1;
698 do {
699 RTRECT Tmp = *pRect1;
700 *pRect1 = *pRect2;
701 *pRect2 = Tmp;
702
703 if (j < 0)
704 break;
705
706 if (vboxVrRegNonintersectedComparator(pRect1, pRect1-1) > 0)
707 break;
708
709 pRect2 = pRect1--;
710 --j;
711 } while (1);
712 }
713
714 return pRects;
715}
716#endif
717
718VBOXVREGDECL(void) VBoxVrListTranslate(PVBOXVR_LIST pList, int32_t x, int32_t y)
719{
720 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
721 {
722 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
723 VBoxRectTranslate(&pReg1->Rect, x, y);
724 }
725}
726
727static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinNonintersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext)
728{
729 VBOXVR_CBDATA_SUBST *pData = (VBOXVR_CBDATA_SUBST*)pvContext;
730
731 PRTLISTNODE pNext = pReg1->ListEntry.pNext;
732
733 vboxVrDbgListVerify(pList1);
734
735 vboxVrListRegRemove(pList1, pReg1);
736 vboxVrRegTerm(pReg1);
737
738 vboxVrDbgListVerify(pList1);
739
740 pData->fChanged = true;
741
742 return pNext;
743}
744
745static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinIntersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
746{
747 PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
748 pData->fChanged = true;
749
750 vboxVrDbgListVerify(pList1);
751
752 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
753
754 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
755 Assert(!VBoxRectIsZero(pRect2));
756
757 vboxVrListRegRemove(pList1, pReg1);
758 VBoxRectIntersect(&pReg1->Rect, pRect2);
759 Assert(!VBoxRectIsZero(&pReg1->Rect));
760
761 vboxVrListRegAddOrder(pList1, pMemberEntry, pReg1);
762
763 vboxVrDbgListVerify(pList1);
764
765 return &pReg1->ListEntry;
766}
767
768static int vboxVrListIntersectNoJoin(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged)
769{
770 bool fChanged = false;
771 *pfChanged = false;
772
773 if (VBoxVrListIsEmpty(pList))
774 return VINF_SUCCESS;
775
776 if (VBoxVrListIsEmpty(pList2))
777 {
778 if (pfChanged)
779 *pfChanged = true;
780
781 VBoxVrListClear(pList);
782 return VINF_SUCCESS;
783 }
784
785 PRTLISTNODE pNext1;
786
787 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
788 {
789 pNext1 = pEntry1->pNext;
790 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
791 RTRECT RegRect1 = pReg1->Rect;
792 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
793
794 for (const RTLISTNODE *pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pEntry2->pNext)
795 {
796 const VBOXVR_REG *pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
797 const RTRECT *pRect2 = &pReg2->Rect;
798
799 if (!VBoxRectIsIntersect(&RegRect1, pRect2))
800 continue;
801
802 if (pReg1)
803 {
804 if (!VBoxRectCmp(&pReg1->Rect, pRect2))
805 {
806 /* no change, and we can break the iteration here */
807
808 /* zero up the pReg1 to mark it as intersected (see the code after this inner loop) */
809 pReg1 = NULL;
810 break;
811 }
812 /* @todo: this can have false-alarming sometimes if the separated rects will then be joind into the original rect,
813 * so far this should not be a problem for VReg clients, so keep it this way for now */
814 fChanged = true;
815
816 /* re-use the reg entry */
817 vboxVrListRegRemove(pList, pReg1);
818 VBoxRectIntersect(&pReg1->Rect, pRect2);
819 Assert(!VBoxRectIsZero(&pReg1->Rect));
820
821 vboxVrListRegAddOrder(pList, pMemberEntry, pReg1);
822 pReg1 = NULL;
823 }
824 else
825 {
826 Assert(fChanged); /* <- should be set by the if branch above */
827 PVBOXVR_REG pReg = vboxVrRegCreate();
828 if (!pReg)
829 {
830 WARN(("vboxVrRegCreate failed!"));
831 return VERR_NO_MEMORY;
832 }
833 VBoxRectIntersected(&RegRect1, pRect2, &pReg->Rect);
834 Assert(!VBoxRectIsZero(&pReg->Rect));
835 vboxVrListRegAddOrder(pList, pList->ListHead.pNext, pReg);
836 }
837 }
838
839 if (pReg1)
840 {
841 /* the region has no intersections, remove it */
842 vboxVrListRegRemove(pList, pReg1);
843 vboxVrRegTerm(pReg1);
844 fChanged = true;
845 }
846 }
847
848 *pfChanged = fChanged;
849 return VINF_SUCCESS;
850}
851
852VBOXVREGDECL(int) VBoxVrListIntersect(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged)
853{
854 if (pfChanged)
855 *pfChanged = false;
856
857 int rc = vboxVrListIntersectNoJoin(pList, pList2, pfChanged);
858 if (!RT_SUCCESS(rc))
859 {
860 WARN(("vboxVrListSubstNoJoin failed!"));
861 return rc;
862 }
863
864 if (*pfChanged)
865 {
866 vboxVrListJoinRects(pList);
867 }
868
869 return rc;
870}
871
872VBOXVREGDECL(int) VBoxVrListRectsIntersect(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
873{
874 if (pfChanged)
875 *pfChanged = false;
876
877 if (VBoxVrListIsEmpty(pList))
878 return VINF_SUCCESS;
879
880 if (!cRects)
881 {
882 if (pfChanged)
883 *pfChanged = true;
884
885 VBoxVrListClear(pList);
886 return VINF_SUCCESS;
887 }
888
889 /* we perform intersection using lists because the algorythm axpects the rects to be non-intersected,
890 * which list guaranties to us */
891
892 VBOXVR_LIST TmpList;
893 VBoxVrListInit(&TmpList);
894
895 int rc = VBoxVrListRectsAdd(&TmpList, cRects, aRects, NULL);
896 if (RT_SUCCESS(rc))
897 {
898 rc = VBoxVrListIntersect(pList, &TmpList, pfChanged);
899 if (!RT_SUCCESS(rc))
900 {
901 WARN(("VBoxVrListIntersect failed! rc %d", rc));
902 }
903 }
904 else
905 {
906 WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
907 }
908 VBoxVrListClear(&TmpList);
909
910 return rc;
911}
912
913VBOXVREGDECL(int) VBoxVrListRectsSubst(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
914{
915#if 0
916 const RTRECT * pRects = vboxVrRectsOrder(cRects, aRects);
917 if (!pRects)
918 {
919 WARN(("vboxVrRectsOrder failed!"));
920 return VERR_NO_MEMORY;
921 }
922#endif
923
924 bool fChanged = false;
925
926 int rc = vboxVrListSubstNoJoin(pList, cRects, aRects, &fChanged);
927 if (!RT_SUCCESS(rc))
928 {
929 WARN(("vboxVrListSubstNoJoin failed!"));
930 goto done;
931 }
932
933 if (fChanged)
934 goto done;
935
936 vboxVrListJoinRects(pList);
937
938done:
939#if 0
940 if (pRects != aRects)
941 RTMemFree(pRects);
942#endif
943
944 if (pfChanged)
945 *pfChanged = fChanged;
946
947 return rc;
948}
949
950VBOXVREGDECL(int) VBoxVrListRectsSet(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
951{
952 if (pfChanged)
953 *pfChanged = false;
954
955 if (!cRects && VBoxVrListIsEmpty(pList))
956 {
957 return VINF_SUCCESS;
958 }
959
960 /* @todo: fChanged will have false alarming here, fix if needed */
961 VBoxVrListClear(pList);
962
963 int rc = VBoxVrListRectsAdd(pList, cRects, aRects, NULL);
964 if (!RT_SUCCESS(rc))
965 {
966 WARN(("VBoxVrListRectsSet failed rc %d", rc));
967 return rc;
968 }
969
970 if (pfChanged)
971 *pfChanged = true;
972
973 return VINF_SUCCESS;
974}
975
976VBOXVREGDECL(int) VBoxVrListRectsAdd(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
977{
978 uint32_t cCovered = 0;
979
980 if (pfChanged)
981 *pfChanged = false;
982
983#if 0
984#ifdef DEBUG
985 {
986 for (uint32_t i = 0; i < cRects; ++i)
987 {
988 RTRECT *pRectI = &aRects[i];
989 for (uint32_t j = i + 1; j < cRects; ++j)
990 {
991 RTRECT *pRectJ = &aRects[j];
992 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
993 }
994 }
995 }
996#endif
997#endif
998
999 /* early sort out the case when there are no new rects */
1000 for (uint32_t i = 0; i < cRects; ++i)
1001 {
1002 if (VBoxRectIsZero(&aRects[i]))
1003 {
1004 cCovered++;
1005 continue;
1006 }
1007
1008 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
1009 {
1010 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
1011
1012 if (VBoxRectIsCoveres(&pReg1->Rect, &aRects[i]))
1013 {
1014 cCovered++;
1015 break;
1016 }
1017 }
1018 }
1019
1020 if (cCovered == cRects)
1021 return VINF_SUCCESS;
1022
1023 /* rects are not covered, need to go the slow way */
1024
1025 VBOXVR_LIST DiffList;
1026 VBoxVrListInit(&DiffList);
1027 RTRECT * pListRects = NULL;
1028 uint32_t cAllocatedRects = 0;
1029 bool fNeedRectreate = true;
1030 bool fChanged = false;
1031 int rc = VINF_SUCCESS;
1032
1033 for (uint32_t i = 0; i < cRects; ++i)
1034 {
1035 if (VBoxRectIsZero(&aRects[i]))
1036 continue;
1037
1038 PVBOXVR_REG pReg = vboxVrRegCreate();
1039 if (!pReg)
1040 {
1041 WARN(("vboxVrRegCreate failed!"));
1042 rc = VERR_NO_MEMORY;
1043 break;
1044 }
1045 pReg->Rect = aRects[i];
1046
1047 uint32_t cListRects = VBoxVrListRectsCount(pList);
1048 if (!cListRects)
1049 {
1050 vboxVrListRegAdd(pList, pReg, &pList->ListHead, false);
1051 fChanged = true;
1052 continue;
1053 }
1054 else
1055 {
1056 Assert(VBoxVrListIsEmpty(&DiffList));
1057 vboxVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, false);
1058 }
1059
1060 if (cAllocatedRects < cListRects)
1061 {
1062 cAllocatedRects = cListRects + cRects;
1063 Assert(fNeedRectreate);
1064 if (pListRects)
1065 RTMemFree(pListRects);
1066 pListRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cAllocatedRects);
1067 if (!pListRects)
1068 {
1069 WARN(("RTMemAlloc failed!"));
1070 rc = VERR_NO_MEMORY;
1071 break;
1072 }
1073 }
1074
1075
1076 if (fNeedRectreate)
1077 {
1078 rc = VBoxVrListRectsGet(pList, cListRects, pListRects);
1079 Assert(rc == VINF_SUCCESS);
1080 fNeedRectreate = false;
1081 }
1082
1083 bool fDummyChanged = false;
1084 rc = vboxVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged);
1085 if (!RT_SUCCESS(rc))
1086 {
1087 WARN(("vboxVrListSubstNoJoin failed!"));
1088 rc = VERR_NO_MEMORY;
1089 break;
1090 }
1091
1092 if (!VBoxVrListIsEmpty(&DiffList))
1093 {
1094 vboxVrListAddNonintersected(pList, &DiffList);
1095 fNeedRectreate = true;
1096 fChanged = true;
1097 }
1098
1099 Assert(VBoxVrListIsEmpty(&DiffList));
1100 }
1101
1102 if (pListRects)
1103 RTMemFree(pListRects);
1104
1105 Assert(VBoxVrListIsEmpty(&DiffList) || rc != VINF_SUCCESS);
1106 VBoxVrListClear(&DiffList);
1107
1108 if (fChanged)
1109 vboxVrListJoinRects(pList);
1110
1111 if (pfChanged)
1112 *pfChanged = fChanged;
1113
1114 return VINF_SUCCESS;
1115}
1116
1117VBOXVREGDECL(int) VBoxVrListRectsGet(PVBOXVR_LIST pList, uint32_t cRects, RTRECT * aRects)
1118{
1119 if (cRects < VBoxVrListRectsCount(pList))
1120 return VERR_BUFFER_OVERFLOW;
1121
1122 uint32_t i = 0;
1123 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext, ++i)
1124 {
1125 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
1126 aRects[i] = pReg1->Rect;
1127 }
1128 return VINF_SUCCESS;
1129}
1130
1131VBOXVREGDECL(int) VBoxVrListCmp(const VBOXVR_LIST *pList1, const VBOXVR_LIST *pList2)
1132{
1133 int cTmp = pList1->cEntries - pList2->cEntries;
1134 if (cTmp)
1135 return cTmp;
1136
1137 PVBOXVR_REG pReg1, pReg2;
1138
1139 for (pReg1 = RTListNodeGetNext(&pList1->ListHead, VBOXVR_REG, ListEntry),
1140 pReg2 = RTListNodeGetNext(&pList2->ListHead, VBOXVR_REG, ListEntry);
1141 !RTListNodeIsDummy(&pList1->ListHead, pReg1, VBOXVR_REG, ListEntry);
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(const VBOXVR_LIST *pList, VBOXVR_LIST *pDstList)
1155{
1156 VBoxVrListInit(pDstList);
1157 const VBOXVR_REG *pReg;
1158 RTListForEach(&pList->ListHead, pReg, const VBOXVR_REG, ListEntry)
1159 {
1160 PVBOXVR_REG pDstReg = (PVBOXVR_REG)vboxVrRegLaAlloc(g_VBoxVrLookasideList);
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, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
1202{
1203 if (--pEntry->cRefs)
1204 {
1205 Assert(pEntry->cRefs < UINT32_MAX/2);
1206 return;
1207 }
1208
1209 Assert(!VBoxVrCompositorEntryIsInList(pEntry));
1210
1211 if (pCompositor->pfnEntryReleased)
1212 pCompositor->pfnEntryReleased(pCompositor, pEntry, pReplacingEntry);
1213}
1214
1215DECLINLINE(void) vboxVrCompositorEntryAcquire(PVBOXVR_COMPOSITOR_ENTRY pEntry)
1216{
1217 ++pEntry->cRefs;
1218}
1219
1220DECLINLINE(void) vboxVrCompositorEntryAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
1221{
1222 RTListPrepend(&pCompositor->List, &pEntry->Node);
1223 vboxVrCompositorEntryAcquire(pEntry);
1224}
1225
1226DECLINLINE(void) vboxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
1227{
1228 RTListNodeRemove(&pEntry->Node);
1229 vboxVrCompositorEntryRelease(pCompositor, pEntry, pReplacingEntry);
1230}
1231
1232static void vboxVrCompositorEntryReplace(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
1233{
1234 VBoxVrListMoveTo(&pEntry->Vr, &pReplacingEntry->Vr);
1235
1236 pReplacingEntry->Node = pEntry->Node;
1237 pReplacingEntry->Node.pNext->pPrev = &pReplacingEntry->Node;
1238 pReplacingEntry->Node.pPrev->pNext = &pReplacingEntry->Node;
1239 pEntry->Node.pNext = NULL;
1240 pEntry->Node.pPrev = NULL;
1241
1242 vboxVrCompositorEntryAcquire(pReplacingEntry);
1243 vboxVrCompositorEntryRelease(pCompositor, pEntry, pReplacingEntry);
1244}
1245
1246
1247
1248VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry)
1249{
1250 VBoxVrListInit(&pEntry->Vr);
1251 pEntry->cRefs = 0;
1252}
1253
1254VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
1255{
1256 if (!VBoxVrCompositorEntryIsInList(pEntry))
1257 return false;
1258
1259 vboxVrCompositorEntryAcquire(pEntry);
1260
1261 VBoxVrListClear(&pEntry->Vr);
1262 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1263 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1264 return true;
1265}
1266
1267VBOXVREGDECL(bool) VBoxVrCompositorEntryReplace(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pNewEntry)
1268{
1269 if (!VBoxVrCompositorEntryIsInList(pEntry))
1270 return false;
1271
1272 vboxVrCompositorEntryReplace(pCompositor, pEntry, pNewEntry);
1273
1274 return true;
1275}
1276
1277static int vboxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
1278{
1279 bool fChanged;
1280 vboxVrCompositorEntryAcquire(pEntry);
1281
1282 int rc = VBoxVrListRectsSubst(&pEntry->Vr, cRects, paRects, &fChanged);
1283 if (RT_SUCCESS(rc))
1284 {
1285 if (VBoxVrListIsEmpty(&pEntry->Vr))
1286 {
1287 Assert(fChanged);
1288 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1289 }
1290 if (pfChanged)
1291 *pfChanged = false;
1292 }
1293 else
1294 WARN(("VBoxVrListRectsSubst failed, rc %d", rc));
1295
1296 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1297 return rc;
1298}
1299
1300VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, PVBOXVR_COMPOSITOR_ENTRY *ppReplacedEntry, uint32_t *pfChangeFlags)
1301{
1302 bool fOthersChanged = false, fCurChanged = false, fEntryChanged = false, fEntryWasInList = false, fEntryReplaced = false;
1303 PVBOXVR_COMPOSITOR_ENTRY pCur, pNext;
1304 int rc = VINF_SUCCESS;
1305
1306 if (pEntry)
1307 vboxVrCompositorEntryAcquire(pEntry);
1308
1309 if (!cRects)
1310 {
1311 if (pfChangeFlags)
1312 *pfChangeFlags = 0;
1313 if (pEntry)
1314 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1315 return VINF_SUCCESS;
1316 }
1317
1318 if (pEntry)
1319 {
1320 fEntryWasInList = VBoxVrCompositorEntryIsInList(pEntry);
1321 rc = VBoxVrListRectsAdd(&pEntry->Vr, cRects, paRects, &fEntryChanged);
1322 if (RT_SUCCESS(rc))
1323 {
1324 if (VBoxVrListIsEmpty(&pEntry->Vr))
1325 {
1326// WARN(("Empty rectangles passed in, is it expected?"));
1327 if (pfChangeFlags)
1328 *pfChangeFlags = 0;
1329 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1330 return VINF_SUCCESS;
1331 }
1332 }
1333 else
1334 {
1335 WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
1336 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1337 return rc;
1338 }
1339
1340 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1341 }
1342 else
1343 {
1344 fEntryChanged = true;
1345 }
1346
1347 RTListForEachSafe(&pCompositor->List, pCur, pNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1348 {
1349 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1350 if (pCur == pEntry)
1351 {
1352 Assert(fEntryWasInList);
1353 }
1354 else
1355 {
1356 if (pEntry && !VBoxVrListCmp(&pCur->Vr, &pEntry->Vr))
1357 {
1358 VBoxVrListClear(&pCur->Vr);
1359 vboxVrCompositorEntryRemove(pCompositor, pCur, pEntry);
1360 if (ppReplacedEntry)
1361 *ppReplacedEntry = pCur;
1362 fEntryReplaced = true;
1363 break;
1364 }
1365 else
1366 {
1367 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, &fCurChanged);
1368 if (RT_SUCCESS(rc))
1369 fOthersChanged |= fCurChanged;
1370 else
1371 {
1372 WARN(("vboxVrCompositorEntryRegionsSubst failed, rc %d", rc));
1373 return rc;
1374 }
1375 }
1376 }
1377 }
1378
1379 AssertRC(rc);
1380
1381 if (pEntry)
1382 {
1383 if (!fEntryWasInList)
1384 {
1385 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1386 vboxVrCompositorEntryAdd(pCompositor, pEntry);
1387 }
1388 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1389 }
1390
1391 if (pfChangeFlags)
1392 {
1393 uint32_t fFlags = 0;
1394 if (fOthersChanged)
1395 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED;
1396 else if (fEntryReplaced)
1397 {
1398 Assert(fEntryChanged);
1399 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED;
1400 }
1401 else if (fEntryChanged)
1402 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED;
1403
1404 if (!fEntryWasInList)
1405 Assert(fEntryChanged);
1406
1407 *pfChangeFlags = fFlags;
1408 }
1409
1410 return VINF_SUCCESS;
1411}
1412
1413VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
1414{
1415 if (!pEntry)
1416 {
1417 WARN(("VBoxVrCompositorEntryRegionsSubst called with zero entry, unsupported!"));
1418 if (pfChanged)
1419 *pfChanged = false;
1420 return VERR_INVALID_PARAMETER;
1421 }
1422
1423 vboxVrCompositorEntryAcquire(pEntry);
1424
1425 if (VBoxVrListIsEmpty(&pEntry->Vr))
1426 {
1427 if (pfChanged)
1428 *pfChanged = false;
1429 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1430 return VINF_SUCCESS;
1431
1432 }
1433
1434 int rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pEntry, cRects, paRects, pfChanged);
1435 if (!RT_SUCCESS(rc))
1436 WARN(("pfChanged failed, rc %d", rc));
1437
1438 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1439
1440 return rc;
1441}
1442
1443VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
1444{
1445 if (!pEntry)
1446 {
1447 WARN(("VBoxVrCompositorEntryRegionsSet called with zero entry, unsupported!"));
1448 if (pfChanged)
1449 *pfChanged = false;
1450 return VERR_INVALID_PARAMETER;
1451 }
1452
1453 vboxVrCompositorEntryAcquire(pEntry);
1454
1455 bool fChanged = false, fCurChanged = false;
1456 uint32_t fChangeFlags = 0;
1457 int rc;
1458 fCurChanged = VBoxVrCompositorEntryRemove(pCompositor, pEntry);
1459 fChanged |= fCurChanged;
1460
1461 rc = VBoxVrCompositorEntryRegionsAdd(pCompositor, pEntry, cRects, paRects, NULL, &fChangeFlags);
1462 if (RT_SUCCESS(rc))
1463 {
1464 fChanged |= !!fChangeFlags;
1465 if (pfChanged)
1466 *pfChanged = fChanged;
1467 }
1468 else
1469 WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
1470
1471 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1472
1473 return VINF_SUCCESS;
1474}
1475
1476VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
1477{
1478 int rc = VINF_SUCCESS;
1479 bool fChanged = false;
1480
1481 vboxVrCompositorEntryAcquire(pEntry);
1482
1483 if (VBoxVrCompositorEntryIsInList(pEntry))
1484 {
1485 rc = VBoxVrListIntersect(&pEntry->Vr, pList2, &fChanged);
1486 if (RT_SUCCESS(rc))
1487 {
1488 if (VBoxVrListIsEmpty(&pEntry->Vr))
1489 {
1490 Assert(fChanged);
1491 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1492 }
1493 }
1494 else
1495 {
1496 WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
1497 }
1498 }
1499
1500 if (pfChanged)
1501 *pfChanged = fChanged;
1502
1503 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1504
1505 return rc;
1506}
1507
1508VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
1509{
1510 int rc = VINF_SUCCESS;
1511 bool fChanged = false;
1512
1513 vboxVrCompositorEntryAcquire(pEntry);
1514
1515 if (VBoxVrCompositorEntryIsInList(pEntry))
1516 {
1517 rc = VBoxVrListRectsIntersect(&pEntry->Vr, cRects, paRects, &fChanged);
1518 if (RT_SUCCESS(rc))
1519 {
1520 if (VBoxVrListIsEmpty(&pEntry->Vr))
1521 {
1522 Assert(fChanged);
1523 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1524 }
1525 }
1526 else
1527 {
1528 WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
1529 }
1530 }
1531
1532 if (pfChanged)
1533 *pfChanged = fChanged;
1534
1535 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1536
1537 return rc;
1538}
1539
1540VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersectAll(PVBOXVR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
1541{
1542 VBOXVR_COMPOSITOR_ITERATOR Iter;
1543 VBoxVrCompositorIterInit(pCompositor, &Iter);
1544 PVBOXVR_COMPOSITOR_ENTRY pEntry;
1545 int rc = VINF_SUCCESS;
1546 bool fChanged = false;
1547
1548 while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
1549 {
1550 bool fTmpChanged = false;
1551 int tmpRc = VBoxVrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
1552 if (RT_SUCCESS(tmpRc))
1553 {
1554 fChanged |= fChanged;
1555 }
1556 else
1557 {
1558 WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1559 rc = tmpRc;
1560 }
1561 }
1562
1563 if (pfChanged)
1564 *pfChanged = fChanged;
1565
1566 return rc;
1567}
1568
1569VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersectAll(PVBOXVR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1570{
1571 VBOXVR_COMPOSITOR_ITERATOR Iter;
1572 VBoxVrCompositorIterInit(pCompositor, &Iter);
1573 PVBOXVR_COMPOSITOR_ENTRY pEntry;
1574 int rc = VINF_SUCCESS;
1575 bool fChanged = false;
1576
1577 while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
1578 {
1579 bool fTmpChanged = false;
1580 int tmpRc = VBoxVrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
1581 if (RT_SUCCESS(tmpRc))
1582 {
1583 fChanged |= fChanged;
1584 }
1585 else
1586 {
1587 WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1588 rc = tmpRc;
1589 }
1590 }
1591
1592 if (pfChanged)
1593 *pfChanged = fChanged;
1594
1595 return rc;
1596}
1597
1598VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, int32_t x, int32_t y, bool *pfChanged)
1599{
1600 if (!pEntry)
1601 {
1602 WARN(("VBoxVrCompositorEntryRegionsTranslate called with zero entry, unsupported!"));
1603 if (pfChanged)
1604 *pfChanged = false;
1605 return VERR_INVALID_PARAMETER;
1606 }
1607
1608 vboxVrCompositorEntryAcquire(pEntry);
1609
1610 if ((!x && !y)
1611 || !VBoxVrCompositorEntryIsInList(pEntry))
1612 {
1613 if (pfChanged)
1614 *pfChanged = false;
1615
1616 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1617 return VINF_SUCCESS;
1618 }
1619
1620 VBoxVrListTranslate(&pEntry->Vr, x, y);
1621
1622 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1623
1624 PVBOXVR_COMPOSITOR_ENTRY pCur;
1625 uint32_t cRects = 0;
1626 RTRECT *paRects = NULL;
1627 int rc = VINF_SUCCESS;
1628 RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
1629 {
1630 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1631
1632 if (pCur == pEntry)
1633 continue;
1634
1635 if (!paRects)
1636 {
1637 cRects = VBoxVrListRectsCount(&pEntry->Vr);
1638 Assert(cRects);
1639 paRects = (RTRECT*)RTMemAlloc(cRects * sizeof (RTRECT));
1640 if (!paRects)
1641 {
1642 WARN(("RTMemAlloc failed!"));
1643 rc = VERR_NO_MEMORY;
1644 break;
1645 }
1646
1647 rc = VBoxVrListRectsGet(&pEntry->Vr, cRects, paRects);
1648 if (!RT_SUCCESS(rc))
1649 {
1650 WARN(("VBoxVrListRectsGet failed! rc %d", rc));
1651 break;
1652 }
1653 }
1654
1655 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, NULL);
1656 if (!RT_SUCCESS(rc))
1657 {
1658 WARN(("vboxVrCompositorEntryRegionsSubst failed! rc %d", rc));
1659 break;
1660 }
1661 }
1662
1663 if (pfChanged)
1664 *pfChanged = true;
1665
1666 if (paRects)
1667 RTMemFree(paRects);
1668
1669 vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL);
1670
1671 return rc;
1672}
1673
1674VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
1675{
1676 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
1677 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1678 {
1679 if (!pfnVisitor(pCompositor, pEntry, pvVisitor))
1680 return;
1681 }
1682}
1683
1684
1685
1686#define VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED UINT32_MAX
1687
1688static int crVrScrCompositorRectsAssignBuffer(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRects)
1689{
1690 Assert(cRects);
1691
1692 if (pCompositor->cRectsBuffer >= cRects)
1693 {
1694 pCompositor->cRects = cRects;
1695 return VINF_SUCCESS;
1696 }
1697
1698 if (pCompositor->cRectsBuffer)
1699 {
1700 Assert(pCompositor->paSrcRects);
1701 RTMemFree(pCompositor->paSrcRects);
1702 pCompositor->paSrcRects = NULL;
1703 Assert(pCompositor->paDstRects);
1704 RTMemFree(pCompositor->paDstRects);
1705 pCompositor->paDstRects = NULL;
1706 Assert(pCompositor->paDstUnstretchedRects);
1707 RTMemFree(pCompositor->paDstUnstretchedRects);
1708 pCompositor->paDstUnstretchedRects = NULL;
1709 }
1710 else
1711 {
1712 Assert(!pCompositor->paSrcRects);
1713 Assert(!pCompositor->paDstRects);
1714 Assert(!pCompositor->paDstUnstretchedRects);
1715 }
1716
1717 pCompositor->paSrcRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paSrcRects) * cRects);
1718 if (pCompositor->paSrcRects)
1719 {
1720 pCompositor->paDstRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstRects) * cRects);
1721 if (pCompositor->paDstRects)
1722 {
1723 pCompositor->paDstUnstretchedRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstUnstretchedRects) * cRects);
1724 if (pCompositor->paDstUnstretchedRects)
1725 {
1726 pCompositor->cRects = cRects;
1727 pCompositor->cRectsBuffer = cRects;
1728 return VINF_SUCCESS;
1729 }
1730
1731 RTMemFree(pCompositor->paDstRects);
1732 pCompositor->paDstRects = NULL;
1733 }
1734 else
1735 {
1736 WARN(("RTMemAlloc failed!"));
1737 }
1738 RTMemFree(pCompositor->paSrcRects);
1739 pCompositor->paSrcRects = NULL;
1740 }
1741 else
1742 {
1743 WARN(("RTMemAlloc failed!"));
1744 }
1745
1746 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1747 pCompositor->cRectsBuffer = 0;
1748
1749 return VERR_NO_MEMORY;
1750}
1751
1752static void crVrScrCompositorRectsInvalidate(PVBOXVR_SCR_COMPOSITOR pCompositor)
1753{
1754 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1755}
1756
1757static DECLCALLBACK(bool) crVrScrCompositorRectsCounterCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor)
1758{
1759 uint32_t* pCounter = (uint32_t*)pvVisitor;
1760 Assert(VBoxVrListRectsCount(&pEntry->Vr));
1761 *pCounter += VBoxVrListRectsCount(&pEntry->Vr);
1762 return true;
1763}
1764
1765typedef struct VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER
1766{
1767 PRTRECT paSrcRects;
1768 PRTRECT paDstRects;
1769 PRTRECT paDstUnstretchedRects;
1770 uint32_t cRects;
1771} VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER, *PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER;
1772
1773static DECLCALLBACK(bool) crVrScrCompositorRectsAssignerCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
1774{
1775 PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER pData = (PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER)pvVisitor;
1776 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
1777 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
1778 pEntry->paSrcRects = pData->paSrcRects;
1779 pEntry->paDstRects = pData->paDstRects;
1780 pEntry->paDstUnstretchedRects = pData->paDstUnstretchedRects;
1781 uint32_t cRects = VBoxVrListRectsCount(&pCEntry->Vr);
1782 Assert(cRects);
1783 Assert(cRects <= pData->cRects);
1784 int rc = VBoxVrListRectsGet(&pCEntry->Vr, cRects, pEntry->paDstUnstretchedRects);
1785 AssertRC(rc);
1786
1787 if (!pEntry->Pos.x && !pEntry->Pos.y)
1788 {
1789 memcpy(pEntry->paSrcRects, pEntry->paDstUnstretchedRects, cRects * sizeof (*pEntry->paSrcRects));
1790 }
1791 else
1792 {
1793 for (uint32_t i = 0; i < cRects; ++i)
1794 {
1795 pEntry->paSrcRects[i].xLeft = (int32_t)((pEntry->paDstUnstretchedRects[i].xLeft - pEntry->Pos.x));
1796 pEntry->paSrcRects[i].yTop = (int32_t)((pEntry->paDstUnstretchedRects[i].yTop - pEntry->Pos.y));
1797 pEntry->paSrcRects[i].xRight = (int32_t)((pEntry->paDstUnstretchedRects[i].xRight - pEntry->Pos.x));
1798 pEntry->paSrcRects[i].yBottom = (int32_t)((pEntry->paDstUnstretchedRects[i].yBottom - pEntry->Pos.y));
1799 }
1800 }
1801
1802#ifndef IN_RING0
1803 if (pCompositor->StretchX != 1. || pCompositor->StretchY != 1.)
1804 {
1805 for (uint32_t i = 0; i < cRects; ++i)
1806 {
1807 if (pCompositor->StretchX != 1.)
1808 {
1809 pEntry->paDstRects[i].xLeft = (int32_t)(pEntry->paDstUnstretchedRects[i].xLeft * pCompositor->StretchX);
1810 pEntry->paDstRects[i].xRight = (int32_t)(pEntry->paDstUnstretchedRects[i].xRight * pCompositor->StretchX);
1811 }
1812 if (pCompositor->StretchY != 1.)
1813 {
1814 pEntry->paDstRects[i].yTop = (int32_t)(pEntry->paDstUnstretchedRects[i].yTop * pCompositor->StretchY);
1815 pEntry->paDstRects[i].yBottom = (int32_t)(pEntry->paDstUnstretchedRects[i].yBottom * pCompositor->StretchY);
1816 }
1817 }
1818 }
1819 else
1820#endif
1821 {
1822 memcpy(pEntry->paDstRects, pEntry->paDstUnstretchedRects, cRects * sizeof (*pEntry->paDstUnstretchedRects));
1823 }
1824
1825#if 0//ndef IN_RING0
1826 bool canZeroX = (pCompositor->StretchX < 1.);
1827 bool canZeroY = (pCompositor->StretchY < 1.);
1828 if (canZeroX && canZeroY)
1829 {
1830 /* filter out zero rectangles*/
1831 uint32_t iOrig, iNew;
1832 for (iOrig = 0, iNew = 0; iOrig < cRects; ++iOrig)
1833 {
1834 PRTRECT pOrigRect = &pEntry->paDstRects[iOrig];
1835 if (pOrigRect->xLeft != pOrigRect->xRight
1836 && pOrigRect->yTop != pOrigRect->yBottom)
1837 continue;
1838
1839 if (iNew != iOrig)
1840 {
1841 PRTRECT pNewRect = &pEntry->paSrcRects[iNew];
1842 *pNewRect = *pOrigRect;
1843 }
1844
1845 ++iNew;
1846 }
1847
1848 Assert(iNew <= iOrig);
1849
1850 uint32_t cDiff = iOrig - iNew;
1851
1852 if (cDiff)
1853 {
1854 pCompositor->cRects -= cDiff;
1855 cRects -= cDiff;
1856 }
1857 }
1858#endif
1859
1860 pEntry->cRects = cRects;
1861 pData->paDstRects += cRects;
1862 pData->paSrcRects += cRects;
1863 pData->paDstUnstretchedRects += cRects;
1864 pData->cRects -= cRects;
1865 return true;
1866}
1867
1868static int crVrScrCompositorRectsCheckInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
1869{
1870 if (pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED)
1871 return VINF_SUCCESS;
1872
1873 uint32_t cRects = 0;
1874 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsCounterCb, &cRects);
1875
1876 if (!cRects)
1877 {
1878 pCompositor->cRects = 0;
1879 return VINF_SUCCESS;
1880 }
1881
1882 int rc = crVrScrCompositorRectsAssignBuffer(pCompositor, cRects);
1883 if (!RT_SUCCESS(rc))
1884 return rc;
1885
1886 VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER AssignerData;
1887 AssignerData.paSrcRects = pCompositor->paSrcRects;
1888 AssignerData.paDstRects = pCompositor->paDstRects;
1889 AssignerData.paDstUnstretchedRects = pCompositor->paDstUnstretchedRects;
1890 AssignerData.cRects = pCompositor->cRects;
1891 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsAssignerCb, &AssignerData);
1892 Assert(!AssignerData.cRects);
1893 return VINF_SUCCESS;
1894}
1895
1896
1897static int crVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, VBOXVR_SCR_COMPOSITOR_ENTRY **ppReplacedScrEntry, uint32_t *pfChangedFlags)
1898{
1899 uint32_t fChangedFlags = 0;
1900 PVBOXVR_COMPOSITOR_ENTRY pReplacedEntry;
1901 int rc = VBoxVrCompositorEntryRegionsAdd(&pCompositor->Compositor, pEntry ? &pEntry->Ce : NULL, cRegions, paRegions, &pReplacedEntry, &fChangedFlags);
1902 if (!RT_SUCCESS(rc))
1903 {
1904 WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
1905 return rc;
1906 }
1907
1908 VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacedEntry);
1909
1910 if (fChangedFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED)
1911 {
1912 crVrScrCompositorRectsInvalidate(pCompositor);
1913 }
1914 else if (fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED)
1915 {
1916 Assert(!CrVrScrCompositorEntryIsInList(pReplacedScrEntry));
1917 Assert(CrVrScrCompositorEntryIsInList(pEntry));
1918 pEntry->cRects = pReplacedScrEntry->cRects;
1919 pEntry->paSrcRects = pReplacedScrEntry->paSrcRects;
1920 pEntry->paDstRects = pReplacedScrEntry->paDstRects;
1921 pEntry->paDstUnstretchedRects = pReplacedScrEntry->paDstUnstretchedRects;
1922 }
1923
1924 if (fChangedFlags & VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED)
1925 {
1926 CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
1927 }
1928 else if ((fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED) && pEntry)
1929 {
1930 CrVrScrCompositorEntrySetChanged(pEntry, true);
1931 }
1932
1933 if (pfChangedFlags)
1934 *pfChangedFlags = fChangedFlags;
1935
1936 if (ppReplacedScrEntry)
1937 *ppReplacedScrEntry = pReplacedScrEntry;
1938
1939 return VINF_SUCCESS;
1940}
1941
1942static int crVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1943{
1944 bool fChanged;
1945 CrVrScrCompositorEntryIsInList(pEntry);
1946 int rc = VBoxVrCompositorEntryRegionsSet(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
1947 if (!RT_SUCCESS(rc))
1948 {
1949 WARN(("VBoxVrCompositorEntryRegionsSet failed, rc %d", rc));
1950 return rc;
1951 }
1952
1953 if (fChanged)
1954 {
1955 CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
1956 if (!CrVrScrCompositorEntryIsInList(pEntry))
1957 {
1958 pEntry->cRects = 0;
1959 pEntry->paSrcRects = NULL;
1960 pEntry->paDstRects = NULL;
1961 pEntry->paDstUnstretchedRects = NULL;
1962 }
1963 crVrScrCompositorRectsInvalidate(pCompositor);
1964 }
1965
1966
1967 if (pfChanged)
1968 *pfChanged = fChanged;
1969 return VINF_SUCCESS;
1970}
1971
1972static int crVrScrCompositorEntryPositionSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, bool *pfChanged)
1973{
1974 if (pfChanged)
1975 *pfChanged = false;
1976 if (pEntry && (pEntry->Pos.x != pPos->x || pEntry->Pos.y != pPos->y))
1977 {
1978 if (VBoxVrCompositorEntryIsInList(&pEntry->Ce))
1979 {
1980 int rc = VBoxVrCompositorEntryRegionsTranslate(&pCompositor->Compositor, &pEntry->Ce, pPos->x - pEntry->Pos.x, pPos->y - pEntry->Pos.y, pfChanged);
1981 if (!RT_SUCCESS(rc))
1982 {
1983 WARN(("VBoxVrCompositorEntryRegionsTranslate failed rc %d", rc));
1984 return rc;
1985 }
1986
1987 crVrScrCompositorRectsInvalidate(pCompositor);
1988 }
1989
1990 pEntry->Pos = *pPos;
1991 CrVrScrCompositorEntrySetChanged(pEntry, true);
1992
1993 if (pfChanged)
1994 *pfChanged = true;
1995 }
1996 return VINF_SUCCESS;
1997}
1998
1999static int crVrScrCompositorEntryEnsureRegionsInTex(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, bool *pfChanged)
2000{
2001 RTRECT Rect;
2002 Rect.xLeft = pEntry->Pos.x;
2003 Rect.yTop = pEntry->Pos.y;
2004 Rect.xRight = pEntry->Pos.x + pEntry->Tex.width;
2005 Rect.yBottom = pEntry->Pos.y + pEntry->Tex.height;
2006 bool fChanged = false;
2007
2008 if (pfChanged)
2009 *pfChanged = false;
2010
2011 int rc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, 1, &Rect, &fChanged);
2012 if (!RT_SUCCESS(rc))
2013 WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", rc));
2014
2015 if (fChanged)
2016 {
2017 CrVrScrCompositorEntrySetChanged(pEntry, true);
2018 crVrScrCompositorRectsInvalidate(pCompositor);
2019 }
2020
2021 if (pfChanged)
2022 *pfChanged = fChanged;
2023 return rc;
2024}
2025
2026VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, VBOXVR_SCR_COMPOSITOR_ENTRY **ppReplacedScrEntry, uint32_t *pfChangeFlags)
2027{
2028 int rc;
2029 uint32_t fChangeFlags = 0;
2030 bool fPosChanged = false;
2031 RTRECT *paTranslatedRects = NULL;
2032 if (pPos)
2033 {
2034 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
2035 if (!RT_SUCCESS(rc))
2036 {
2037 WARN(("RegionsAdd: crVrScrCompositorEntryPositionSet failed rc %d", rc));
2038 return rc;
2039 }
2040 }
2041
2042 if (fPosRelated)
2043 {
2044 if (!pEntry)
2045 {
2046 WARN(("Entry is expected to be specified for pos-related regions"));
2047 return VERR_INVALID_PARAMETER;
2048 }
2049
2050 if (cRegions && (pEntry->Pos.x || pEntry->Pos.y))
2051 {
2052 paTranslatedRects = (RTRECT*)RTMemAlloc(sizeof (RTRECT) * cRegions);
2053 if (!paTranslatedRects)
2054 {
2055 WARN(("RTMemAlloc failed"));
2056 return VERR_NO_MEMORY;
2057 }
2058 memcpy (paTranslatedRects, paRegions, sizeof (RTRECT) * cRegions);
2059 for (uint32_t i = 0; i < cRegions; ++i)
2060 {
2061 VBoxRectTranslate(&paTranslatedRects[i], pEntry->Pos.x, pEntry->Pos.y);
2062 paRegions = paTranslatedRects;
2063 }
2064 }
2065 }
2066
2067 rc = crVrScrCompositorEntryRegionsAdd(pCompositor, pEntry, cRegions, paRegions, ppReplacedScrEntry, &fChangeFlags);
2068 if (!RT_SUCCESS(rc))
2069 {
2070 WARN(("crVrScrCompositorEntryRegionsAdd failed, rc %d", rc));
2071 goto done;
2072 }
2073
2074 if ((fPosChanged || (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)) && pEntry)
2075 {
2076 bool fAdjusted = false;
2077 rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry, &fAdjusted);
2078 if (!RT_SUCCESS(rc))
2079 {
2080 WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed, rc %d", rc));
2081 goto done;
2082 }
2083
2084 if (fAdjusted)
2085 {
2086 fChangeFlags &= ~VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED;
2087 fChangeFlags |= VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED;
2088 }
2089 }
2090
2091 if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED)
2092 fPosChanged = false;
2093 else if (ppReplacedScrEntry)
2094 *ppReplacedScrEntry = NULL;
2095
2096 if (pfChangeFlags)
2097 {
2098 if (fPosChanged)
2099 {
2100 /* means entry was in list and was moved, so regions changed */
2101 *pfChangeFlags = VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED;
2102 }
2103 else
2104 *pfChangeFlags = fChangeFlags;
2105 }
2106
2107done:
2108
2109 if (paTranslatedRects)
2110 RTMemFree(paTranslatedRects);
2111
2112 return rc;
2113}
2114
2115VBOXVREGDECL(int) CrVrScrCompositorEntryTexUpdate(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_TEXTURE *pTex)
2116{
2117 bool fCompositorChanged = CrVrScrCompositorEntryIsUsed(pEntry) && (pEntry->Tex.width != pTex->width || pEntry->Tex.height != pTex->height);
2118 pEntry->Tex = *pTex;
2119 CrVrScrCompositorEntrySetChanged(pEntry, true);
2120 if (fCompositorChanged)
2121 {
2122 int rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry, NULL);
2123 if (!RT_SUCCESS(rc))
2124 {
2125 WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed rc %d", rc));
2126 return rc;
2127 }
2128 }
2129 return VINF_SUCCESS;
2130}
2131
2132VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, bool *pfChanged)
2133{
2134 /* @todo: the fChanged sate calculation is really rough now, this is enough for now though */
2135 bool fChanged = false, fPosChanged = false;
2136 bool fWasInList = CrVrScrCompositorEntryIsInList(pEntry);
2137 RTRECT *paTranslatedRects = NULL;
2138 int rc = CrVrScrCompositorEntryRemove(pCompositor, pEntry);
2139 if (!RT_SUCCESS(rc))
2140 {
2141 WARN(("RegionsSet: CrVrScrCompositorEntryRemove failed rc %d", rc));
2142 return rc;
2143 }
2144
2145 if (pPos)
2146 {
2147 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
2148 if (!RT_SUCCESS(rc))
2149 {
2150 WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
2151 return rc;
2152 }
2153 }
2154
2155 if (fPosRelated)
2156 {
2157 if (!pEntry)
2158 {
2159 WARN(("Entry is expected to be specified for pos-related regions"));
2160 return VERR_INVALID_PARAMETER;
2161 }
2162
2163 if (cRegions && (pEntry->Pos.x || pEntry->Pos.y))
2164 {
2165 paTranslatedRects = (RTRECT*)RTMemAlloc(sizeof (RTRECT) * cRegions);
2166 if (!paTranslatedRects)
2167 {
2168 WARN(("RTMemAlloc failed"));
2169 return VERR_NO_MEMORY;
2170 }
2171 memcpy (paTranslatedRects, paRegions, sizeof (RTRECT) * cRegions);
2172 for (uint32_t i = 0; i < cRegions; ++i)
2173 {
2174 VBoxRectTranslate(&paTranslatedRects[i], pEntry->Pos.x, pEntry->Pos.y);
2175 paRegions = paTranslatedRects;
2176 }
2177 }
2178 }
2179
2180 rc = crVrScrCompositorEntryRegionsSet(pCompositor, pEntry, cRegions, paRegions, &fChanged);
2181 if (!RT_SUCCESS(rc))
2182 {
2183 WARN(("crVrScrCompositorEntryRegionsSet failed, rc %d", rc));
2184 return rc;
2185 }
2186
2187 if (fChanged && CrVrScrCompositorEntryIsUsed(pEntry))
2188 {
2189 rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry, NULL);
2190 if (!RT_SUCCESS(rc))
2191 {
2192 WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed, rc %d", rc));
2193 return rc;
2194 }
2195 }
2196
2197 if (pfChanged)
2198 *pfChanged = fPosChanged || fChanged || fWasInList;
2199
2200 return VINF_SUCCESS;
2201}
2202
2203VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
2204{
2205 bool fChanged = false;
2206 int rc = VBoxVrCompositorEntryListIntersect(&pCompositor->Compositor, &pEntry->Ce, pList2, &fChanged);
2207 if (!RT_SUCCESS(rc))
2208 {
2209 WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
2210 return rc;
2211 }
2212
2213 if (fChanged)
2214 {
2215 CrVrScrCompositorEntrySetChanged(pEntry, true);
2216 crVrScrCompositorRectsInvalidate(pCompositor);
2217 }
2218
2219 if (pfChanged)
2220 *pfChanged = fChanged;
2221
2222 return VINF_SUCCESS;
2223}
2224
2225VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
2226{
2227 bool fChanged = false;
2228 int rc = VBoxVrCompositorEntryRegionsIntersect(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
2229 if (!RT_SUCCESS(rc))
2230 {
2231 WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
2232 return rc;
2233 }
2234
2235 if (fChanged)
2236 {
2237 CrVrScrCompositorEntrySetChanged(pEntry, true);
2238 crVrScrCompositorRectsInvalidate(pCompositor);
2239 }
2240
2241 if (pfChanged)
2242 *pfChanged = fChanged;
2243
2244 return VINF_SUCCESS;
2245}
2246
2247VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
2248{
2249 VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
2250 CrVrScrCompositorIterInit(pCompositor, &Iter);
2251 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
2252 int rc = VINF_SUCCESS;
2253 bool fChanged = false;
2254
2255 while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
2256 {
2257 bool fTmpChanged = false;
2258 int tmpRc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
2259 if (RT_SUCCESS(tmpRc))
2260 {
2261 fChanged |= fTmpChanged;
2262 }
2263 else
2264 {
2265 WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
2266 rc = tmpRc;
2267 }
2268 }
2269
2270 if (pfChanged)
2271 *pfChanged = fChanged;
2272
2273 return rc;
2274}
2275
2276VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
2277{
2278 VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
2279 CrVrScrCompositorIterInit(pCompositor, &Iter);
2280 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
2281 int rc = VINF_SUCCESS;
2282 bool fChanged = false;
2283
2284 while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
2285 {
2286 bool fTmpChanged = false;
2287 int tmpRc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
2288 if (RT_SUCCESS(tmpRc))
2289 {
2290 fChanged |= fTmpChanged;
2291 }
2292 else
2293 {
2294 WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
2295 rc = tmpRc;
2296 }
2297 }
2298
2299 if (pfChanged)
2300 *pfChanged = fChanged;
2301
2302 return rc;
2303}
2304
2305VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos)
2306{
2307 int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
2308 if (!RT_SUCCESS(rc))
2309 {
2310 WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
2311 return rc;
2312 }
2313 return VINF_SUCCESS;
2314}
2315
2316/* regions are valid until the next CrVrScrCompositor call */
2317VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects)
2318{
2319 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
2320 if (!RT_SUCCESS(rc))
2321 {
2322 WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
2323 return rc;
2324 }
2325
2326 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
2327
2328 *pcRegions = pEntry->cRects;
2329 if (ppaSrcRegions)
2330 *ppaSrcRegions = pEntry->paSrcRects;
2331 if (ppaDstRegions)
2332 *ppaDstRegions = pEntry->paDstRects;
2333 if (ppaDstUnstretchedRects)
2334 *ppaDstUnstretchedRects = pEntry->paDstUnstretchedRects;
2335
2336 return VINF_SUCCESS;
2337}
2338
2339VBOXVREGDECL(uint32_t) CrVrScrCompositorEntryFlagsCombinedGet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
2340{
2341 return CRBLT_FOP_COMBINE(pCompositor->fFlags, pEntry->fFlags);
2342}
2343
2344VBOXVREGDECL(void) CrVrScrCompositorEntryFlagsSet(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t fFlags)
2345{
2346 if (pEntry->fFlags == fFlags)
2347 return;
2348
2349 pEntry->fFlags = fFlags;
2350 CrVrScrCompositorEntrySetChanged(pEntry, true);
2351}
2352
2353static void crVrScrCompositorEntryDataCleanup(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
2354{
2355 pEntry->cRects = 0;
2356 pEntry->paSrcRects = NULL;
2357 pEntry->paDstRects = NULL;
2358 pEntry->paDstUnstretchedRects = NULL;
2359}
2360
2361static void crVrScrCompositorEntryDataCopy(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, PVBOXVR_SCR_COMPOSITOR_ENTRY pToEntry)
2362{
2363 pToEntry->cRects = pEntry->cRects;
2364 pToEntry->paSrcRects = pEntry->paSrcRects;
2365 pToEntry->paDstRects = pEntry->paDstRects;
2366 pToEntry->paDstUnstretchedRects = pEntry->paDstUnstretchedRects;
2367 crVrScrCompositorEntryDataCleanup(pEntry);
2368}
2369
2370VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
2371{
2372 if (!VBoxVrCompositorEntryRemove(&pCompositor->Compositor, &pEntry->Ce))
2373 return VINF_SUCCESS;
2374
2375 CrVrScrCompositorEntrySetChanged(pEntry, true);
2376 crVrScrCompositorEntryDataCleanup(pEntry);
2377
2378 crVrScrCompositorRectsInvalidate(pCompositor);
2379 return VINF_SUCCESS;
2380}
2381
2382VBOXVREGDECL(bool) CrVrScrCompositorEntryReplace(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, PVBOXVR_SCR_COMPOSITOR_ENTRY pNewEntry)
2383{
2384 Assert(!CrVrScrCompositorEntryIsUsed(pNewEntry));
2385
2386 if (!VBoxVrCompositorEntryReplace(&pCompositor->Compositor, &pEntry->Ce, &pNewEntry->Ce))
2387 return false;
2388
2389 CrVrScrCompositorEntrySetChanged(pEntry, true);
2390 crVrScrCompositorEntryDataCopy(pEntry, pNewEntry);
2391 CrVrScrCompositorEntrySetChanged(pNewEntry, true);
2392
2393 return true;
2394}
2395
2396static DECLCALLBACK(void) crVrScrCompositorEntryReleasedCB(const struct VBOXVR_COMPOSITOR *pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
2397{
2398 PVBOXVR_SCR_COMPOSITOR_ENTRY pCEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pEntry);
2399 CrVrScrCompositorEntrySetChanged(pCEntry, true);
2400
2401 if (pCEntry->pfnEntryReleased)
2402 {
2403 PVBOXVR_SCR_COMPOSITOR_ENTRY pCReplacingEntry = pReplacingEntry ? VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacingEntry) : NULL;
2404 PVBOXVR_SCR_COMPOSITOR pCConpositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCompositor);
2405 pCEntry->pfnEntryReleased(pCConpositor, pCEntry, pCReplacingEntry);
2406 }
2407}
2408
2409VBOXVREGDECL(void) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
2410{
2411 memset(pCompositor, 0, sizeof (*pCompositor));
2412 VBoxVrCompositorInit(&pCompositor->Compositor, crVrScrCompositorEntryReleasedCB);
2413 pCompositor->fFlags = CRBLT_F_LINEAR | CRBLT_F_INVERT_YCOORDS;
2414#ifndef IN_RING0
2415 pCompositor->StretchX = 1.0;
2416 pCompositor->StretchY = 1.0;
2417#endif
2418}
2419
2420VBOXVREGDECL(void) CrVrScrCompositorRegionsClear(PVBOXVR_SCR_COMPOSITOR pCompositor, bool *pfChanged)
2421{
2422 /* set changed flag first, while entries are in the list and we have them */
2423 CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
2424 VBoxVrCompositorRegionsClear(&pCompositor->Compositor, pfChanged);
2425 crVrScrCompositorRectsInvalidate(pCompositor);
2426}
2427
2428VBOXVREGDECL(void) CrVrScrCompositorClear(PVBOXVR_SCR_COMPOSITOR pCompositor)
2429{
2430 CrVrScrCompositorRegionsClear(pCompositor, NULL);
2431 if (pCompositor->paDstRects)
2432 {
2433 RTMemFree(pCompositor->paDstRects);
2434 pCompositor->paDstRects = NULL;
2435 }
2436 if (pCompositor->paSrcRects)
2437 {
2438 RTMemFree(pCompositor->paSrcRects);
2439 pCompositor->paSrcRects = NULL;
2440 }
2441 if (pCompositor->paDstUnstretchedRects)
2442 {
2443 RTMemFree(pCompositor->paDstUnstretchedRects);
2444 pCompositor->paDstUnstretchedRects = NULL;
2445 }
2446
2447 pCompositor->cRects = 0;
2448 pCompositor->cRectsBuffer = 0;
2449}
2450
2451VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged)
2452{
2453 VBOXVR_SCR_COMPOSITOR_ITERATOR CIter;
2454 PVBOXVR_SCR_COMPOSITOR_ENTRY pCurEntry;
2455 CrVrScrCompositorIterInit(pCompositor, &CIter);
2456
2457 while ((pCurEntry = CrVrScrCompositorIterNext(&CIter)) != NULL)
2458 {
2459 CrVrScrCompositorEntrySetChanged(pCurEntry, fChanged);
2460 }
2461}
2462
2463#ifndef IN_RING0
2464VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY)
2465{
2466 if (pCompositor->StretchX == StretchX && pCompositor->StretchY == StretchY)
2467 return;
2468
2469 pCompositor->StretchX = StretchX;
2470 pCompositor->StretchY = StretchY;
2471 crVrScrCompositorRectsInvalidate(pCompositor);
2472 CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
2473}
2474#endif
2475
2476/* regions are valid until the next CrVrScrCompositor call */
2477VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects)
2478{
2479 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
2480 if (!RT_SUCCESS(rc))
2481 {
2482 WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
2483 return rc;
2484 }
2485
2486 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
2487
2488 *pcRegions = pCompositor->cRects;
2489 if (ppaSrcRegions)
2490 *ppaSrcRegions = pCompositor->paSrcRects;
2491 if (ppaDstRegions)
2492 *ppaDstRegions = pCompositor->paDstRects;
2493 if (ppaDstUnstretchedRects)
2494 *ppaDstUnstretchedRects = pCompositor->paDstUnstretchedRects;
2495
2496 return VINF_SUCCESS;
2497}
2498
2499typedef struct VBOXVR_SCR_COMPOSITOR_VISITOR_CB
2500{
2501 PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor;
2502 void *pvVisitor;
2503} VBOXVR_SCR_COMPOSITOR_VISITOR_CB, *PVBOXVR_SCR_COMPOSITOR_VISITOR_CB;
2504
2505static DECLCALLBACK(bool) crVrScrCompositorVisitCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
2506{
2507 PVBOXVR_SCR_COMPOSITOR_VISITOR_CB pData = (PVBOXVR_SCR_COMPOSITOR_VISITOR_CB)pvVisitor;
2508 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
2509 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
2510 return pData->pfnVisitor(pCompositor, pEntry, pData->pvVisitor);
2511}
2512
2513VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
2514{
2515 VBOXVR_SCR_COMPOSITOR_VISITOR_CB Data;
2516 Data.pfnVisitor = pfnVisitor;
2517 Data.pvVisitor = pvVisitor;
2518 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorVisitCb, &Data);
2519}
2520
2521VBOXVREGDECL(int) CrVrScrCompositorClone(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor)
2522{
2523 /* for simplicity just copy from one to another */
2524 CrVrScrCompositorInit(pDstCompositor);
2525 VBOXVR_SCR_COMPOSITOR_ITERATOR CIter;
2526 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
2527 CrVrScrCompositorIterInit(pCompositor, &CIter);
2528 int rc = VINF_SUCCESS;
2529 uint32_t cRects;
2530 const RTRECT *pRects;
2531
2532 while ((pEntry = CrVrScrCompositorIterNext(&CIter)) != NULL)
2533 {
2534 /* get source rects, that will be non-stretched and entry pos - pased */
2535 rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRects, NULL, NULL, &pRects);
2536 if (!RT_SUCCESS(rc))
2537 {
2538 WARN(("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc));
2539 return rc;
2540 }
2541
2542 PVBOXVR_SCR_COMPOSITOR_ENTRY pDstEntry = pfnEntryFor(pEntry, pvEntryFor);
2543 if (!pDstEntry)
2544 {
2545 WARN(("pfnEntryFor failed"));
2546 return VERR_INVALID_STATE;
2547 }
2548
2549 rc = CrVrScrCompositorEntryRegionsSet(pDstCompositor, pDstEntry, CrVrScrCompositorEntryPosGet(pEntry), cRects, pRects, false, NULL);
2550 if (!RT_SUCCESS(rc))
2551 {
2552 crWarning("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc);
2553 return rc;
2554 }
2555 }
2556
2557 return rc;
2558}
2559
2560VBOXVREGDECL(int) CrVrScrCompositorIntersectList(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pVr, bool *pfChanged)
2561{
2562 VBOXVR_SCR_COMPOSITOR_ITERATOR CIter;
2563 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
2564 CrVrScrCompositorIterInit(pCompositor, &CIter);
2565 int rc = VINF_SUCCESS;
2566 bool fChanged = false;
2567
2568 while ((pEntry = CrVrScrCompositorIterNext(&CIter)) != NULL)
2569 {
2570 bool fCurChanged = false;
2571
2572 rc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pVr, &fCurChanged);
2573 if (!RT_SUCCESS(rc))
2574 {
2575 crWarning("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc);
2576 break;
2577 }
2578
2579 fChanged |= fCurChanged;
2580 }
2581
2582 if (pfChanged)
2583 *pfChanged = fChanged;
2584
2585 return rc;
2586}
2587
2588VBOXVREGDECL(int) CrVrScrCompositorIntersectedList(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pVr, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor, bool *pfChanged)
2589{
2590 int rc = CrVrScrCompositorClone(pCompositor, pDstCompositor, pfnEntryFor, pvEntryFor);
2591 if (!RT_SUCCESS(rc))
2592 {
2593 WARN(("CrVrScrCompositorClone failed, rc %d", rc));
2594 return rc;
2595 }
2596
2597 rc = CrVrScrCompositorIntersectList(pDstCompositor, pVr, pfChanged);
2598 if (!RT_SUCCESS(rc))
2599 {
2600 WARN(("CrVrScrCompositorIntersectList failed, rc %d", rc));
2601 CrVrScrCompositorClear(pDstCompositor);
2602 return rc;
2603 }
2604
2605 return VINF_SUCCESS;
2606}
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