VirtualBox

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

Last change on this file since 46959 was 46885, checked in by vboxsync, 12 years ago

crOpenGL: TexPresent fixes

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

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