VirtualBox

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

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

wddm/crOpenGL: more TexPresent fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 68.0 KB
Line 
1/* $Id: vreg.cpp 46801 2013-06-26 13:01:07Z vboxsync $ */
2
3/** @file
4 * Visible Regions processing API implementation
5 */
6
7/*
8 * Copyright (C) 2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18#include <cr_vreg.h>
19#include <iprt/err.h>
20#include <iprt/assert.h>
21#include <iprt/asm.h>
22
23#include <cr_error.h>
24#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(PVBOXVR_LIST pList1, PVBOXVR_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(void) VBoxVrCompositorInit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_ENTRY_REMOVED pfnEntryRemoved)
1146{
1147 RTListInit(&pCompositor->List);
1148 pCompositor->pfnEntryRemoved = pfnEntryRemoved;
1149}
1150
1151VBOXVREGDECL(void) VBoxVrCompositorTerm(PVBOXVR_COMPOSITOR pCompositor)
1152{
1153 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
1154 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1155 {
1156 VBoxVrCompositorEntryRemove(pCompositor, pEntry);
1157 }
1158}
1159
1160DECLINLINE(void) vboxVrCompositorEntryAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
1161{
1162 RTListPrepend(&pCompositor->List, &pEntry->Node);
1163}
1164
1165DECLINLINE(void) vboxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
1166{
1167 RTListNodeRemove(&pEntry->Node);
1168 if (pCompositor->pfnEntryRemoved)
1169 pCompositor->pfnEntryRemoved(pCompositor, pEntry, pReplacingEntry);
1170}
1171
1172VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry)
1173{
1174 VBoxVrListInit(&pEntry->Vr);
1175}
1176
1177VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
1178{
1179 if (!VBoxVrCompositorEntryIsInList(pEntry))
1180 return false;
1181 VBoxVrListClear(&pEntry->Vr);
1182 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1183 return true;
1184}
1185
1186static int vboxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
1187{
1188 bool fChanged;
1189 int rc = VBoxVrListRectsSubst(&pEntry->Vr, cRects, paRects, &fChanged);
1190 if (RT_SUCCESS(rc))
1191 {
1192 if (VBoxVrListIsEmpty(&pEntry->Vr))
1193 {
1194 Assert(fChanged);
1195 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1196 }
1197 if (pfChanged)
1198 *pfChanged = false;
1199 return VINF_SUCCESS;
1200 }
1201
1202 WARN(("VBoxVrListRectsSubst failed, rc %d", rc));
1203 return rc;
1204}
1205
1206VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, uint32_t *pfChangeFlags)
1207{
1208 bool fOthersChanged = false, fCurChanged = false, fEntryChanged = false, fEntryWasInList = false, fEntryReplaced = false;
1209 PVBOXVR_COMPOSITOR_ENTRY pCur, pNext;
1210 int rc = VINF_SUCCESS;
1211
1212 if (!cRects)
1213 {
1214 if (pfChangeFlags)
1215 *pfChangeFlags = 0;
1216 return VINF_SUCCESS;
1217 }
1218
1219 if (pEntry)
1220 {
1221 fEntryWasInList = VBoxVrCompositorEntryIsInList(pEntry);
1222 rc = VBoxVrListRectsAdd(&pEntry->Vr, cRects, paRects, &fEntryChanged);
1223 if (RT_SUCCESS(rc))
1224 {
1225 if (VBoxVrListIsEmpty(&pEntry->Vr))
1226 {
1227// WARN(("Empty rectangles passed in, is it expected?"));
1228 if (pfChangeFlags)
1229 *pfChangeFlags = 0;
1230 return VINF_SUCCESS;
1231 }
1232 }
1233 else
1234 {
1235 WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
1236 return rc;
1237 }
1238
1239 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1240 }
1241 else
1242 {
1243 fEntryChanged = true;
1244 }
1245
1246 RTListForEachSafe(&pCompositor->List, pCur, pNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1247 {
1248 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1249 if (pCur == pEntry)
1250 {
1251 Assert(fEntryWasInList);
1252 }
1253 else
1254 {
1255 if (pEntry && !VBoxVrListCmp(&pCur->Vr, &pEntry->Vr))
1256 {
1257 VBoxVrListClear(&pCur->Vr);
1258 vboxVrCompositorEntryRemove(pCompositor, pCur, pEntry);
1259 fEntryReplaced = true;
1260 break;
1261 }
1262 else
1263 {
1264 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, &fCurChanged);
1265 if (RT_SUCCESS(rc))
1266 fOthersChanged |= fCurChanged;
1267 else
1268 {
1269 WARN(("vboxVrCompositorEntryRegionsSubst failed, rc %d", rc));
1270 return rc;
1271 }
1272 }
1273 }
1274 }
1275
1276 AssertRC(rc);
1277
1278 if (pEntry && !fEntryWasInList)
1279 {
1280 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1281 vboxVrCompositorEntryAdd(pCompositor, pEntry);
1282 }
1283
1284 if (pfChangeFlags)
1285 {
1286 uint32_t fFlags = 0;
1287 if (fOthersChanged)
1288 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED;
1289 else if (fEntryReplaced)
1290 {
1291 Assert(fEntryChanged);
1292 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED;
1293 }
1294 else if (fEntryChanged)
1295 fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED;
1296
1297 if (!fEntryWasInList)
1298 Assert(fEntryChanged);
1299
1300 *pfChangeFlags = fFlags;
1301 }
1302
1303 return VINF_SUCCESS;
1304}
1305
1306VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
1307{
1308 if (!pEntry)
1309 {
1310 WARN(("VBoxVrCompositorEntryRegionsSubst called with zero entry, unsupported!"));
1311 if (pfChanged)
1312 *pfChanged = false;
1313 return VERR_INVALID_PARAMETER;
1314 }
1315
1316 if (VBoxVrListIsEmpty(&pEntry->Vr))
1317 {
1318 if (pfChanged)
1319 *pfChanged = false;
1320 return VINF_SUCCESS;
1321
1322 }
1323
1324 int rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pEntry, cRects, paRects, pfChanged);
1325 if (RT_SUCCESS(rc))
1326 return VINF_SUCCESS;
1327
1328 WARN(("pfChanged failed, rc %d", rc));
1329 return rc;
1330}
1331
1332VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
1333{
1334 if (!pEntry)
1335 {
1336 WARN(("VBoxVrCompositorEntryRegionsSet called with zero entry, unsupported!"));
1337 if (pfChanged)
1338 *pfChanged = false;
1339 return VERR_INVALID_PARAMETER;
1340 }
1341
1342 bool fChanged = false, fCurChanged = false;
1343 uint32_t fChangeFlags = 0;
1344 int rc;
1345 fCurChanged = VBoxVrCompositorEntryRemove(pCompositor, pEntry);
1346 fChanged |= fCurChanged;
1347
1348 rc = VBoxVrCompositorEntryRegionsAdd(pCompositor, pEntry, cRects, paRects, &fChangeFlags);
1349 if (RT_SUCCESS(rc))
1350 fChanged |= !!fChangeFlags;
1351 else
1352 {
1353 WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
1354 return rc;
1355 }
1356
1357 AssertRC(rc);
1358
1359 if (pfChanged)
1360 *pfChanged = fChanged;
1361 return VINF_SUCCESS;
1362}
1363
1364VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
1365{
1366 int rc = VINF_SUCCESS;
1367 bool fChanged = false;
1368 if (VBoxVrCompositorEntryIsInList(pEntry))
1369 {
1370 rc = VBoxVrListIntersect(&pEntry->Vr, pList2, &fChanged);
1371 if (RT_SUCCESS(rc))
1372 {
1373 if (VBoxVrListIsEmpty(&pEntry->Vr))
1374 {
1375 Assert(fChanged);
1376 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1377 }
1378 }
1379 else
1380 {
1381 WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
1382 }
1383 }
1384
1385 if (pfChanged)
1386 *pfChanged = fChanged;
1387
1388 return rc;
1389}
1390
1391VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
1392{
1393 int rc = VINF_SUCCESS;
1394 bool fChanged = false;
1395 if (VBoxVrCompositorEntryIsInList(pEntry))
1396 {
1397 rc = VBoxVrListRectsIntersect(&pEntry->Vr, cRects, paRects, &fChanged);
1398 if (RT_SUCCESS(rc))
1399 {
1400 if (VBoxVrListIsEmpty(&pEntry->Vr))
1401 {
1402 Assert(fChanged);
1403 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
1404 }
1405 }
1406 else
1407 {
1408 WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
1409 }
1410 }
1411
1412 if (pfChanged)
1413 *pfChanged = fChanged;
1414
1415 return rc;
1416}
1417
1418VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersectAll(PVBOXVR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
1419{
1420 VBOXVR_COMPOSITOR_ITERATOR Iter;
1421 VBoxVrCompositorIterInit(pCompositor, &Iter);
1422 PVBOXVR_COMPOSITOR_ENTRY pEntry;
1423 int rc = VINF_SUCCESS;
1424 bool fChanged = false;
1425
1426 while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
1427 {
1428 bool fTmpChanged = false;
1429 int tmpRc = VBoxVrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
1430 if (RT_SUCCESS(tmpRc))
1431 {
1432 fChanged |= fChanged;
1433 }
1434 else
1435 {
1436 WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1437 rc = tmpRc;
1438 }
1439 }
1440
1441 if (pfChanged)
1442 *pfChanged = fChanged;
1443
1444 return rc;
1445}
1446
1447VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersectAll(PVBOXVR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1448{
1449 VBOXVR_COMPOSITOR_ITERATOR Iter;
1450 VBoxVrCompositorIterInit(pCompositor, &Iter);
1451 PVBOXVR_COMPOSITOR_ENTRY pEntry;
1452 int rc = VINF_SUCCESS;
1453 bool fChanged = false;
1454
1455 while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
1456 {
1457 bool fTmpChanged = false;
1458 int tmpRc = VBoxVrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
1459 if (RT_SUCCESS(tmpRc))
1460 {
1461 fChanged |= fChanged;
1462 }
1463 else
1464 {
1465 WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
1466 rc = tmpRc;
1467 }
1468 }
1469
1470 if (pfChanged)
1471 *pfChanged = fChanged;
1472
1473 return rc;
1474}
1475
1476VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, int32_t x, int32_t y, bool *pfChanged)
1477{
1478 if (!pEntry)
1479 {
1480 WARN(("VBoxVrCompositorEntryRegionsTranslate called with zero entry, unsupported!"));
1481 if (pfChanged)
1482 *pfChanged = false;
1483 return VERR_INVALID_PARAMETER;
1484 }
1485
1486 if ((!x && !y)
1487 || !VBoxVrCompositorEntryIsInList(pEntry))
1488 {
1489 if (pfChanged)
1490 *pfChanged = false;
1491 return VINF_SUCCESS;
1492 }
1493
1494 VBoxVrListTranslate(&pEntry->Vr, x, y);
1495
1496 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1497
1498 PVBOXVR_COMPOSITOR_ENTRY pCur;
1499 uint32_t cRects = 0;
1500 RTRECT *paRects = NULL;
1501 int rc = VINF_SUCCESS;
1502 RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
1503 {
1504 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1505
1506 if (pCur == pEntry)
1507 continue;
1508
1509 if (!paRects)
1510 {
1511 cRects = VBoxVrListRectsCount(&pEntry->Vr);
1512 Assert(cRects);
1513 paRects = (RTRECT*)RTMemAlloc(cRects * sizeof (RTRECT));
1514 if (!paRects)
1515 {
1516 WARN(("RTMemAlloc failed!"));
1517 rc = VERR_NO_MEMORY;
1518 break;
1519 }
1520
1521 rc = VBoxVrListRectsGet(&pEntry->Vr, cRects, paRects);
1522 if (!RT_SUCCESS(rc))
1523 {
1524 WARN(("VBoxVrListRectsGet failed! rc %d", rc));
1525 break;
1526 }
1527 }
1528
1529 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, NULL);
1530 if (!RT_SUCCESS(rc))
1531 {
1532 WARN(("vboxVrCompositorEntryRegionsSubst failed! rc %d", rc));
1533 break;
1534 }
1535 }
1536
1537 if (pfChanged)
1538 *pfChanged = true;
1539
1540 if (paRects)
1541 RTMemFree(paRects);
1542
1543 return rc;
1544}
1545
1546VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
1547{
1548 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
1549 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1550 {
1551 if (!pfnVisitor(pCompositor, pEntry, pvVisitor))
1552 return;
1553 }
1554}
1555
1556
1557
1558#define VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED UINT32_MAX
1559
1560static int crVrScrCompositorRectsAssignBuffer(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRects)
1561{
1562 Assert(cRects);
1563
1564 if (pCompositor->cRectsBuffer >= cRects)
1565 {
1566 pCompositor->cRects = cRects;
1567 return VINF_SUCCESS;
1568 }
1569
1570 if (pCompositor->cRectsBuffer)
1571 {
1572 Assert(pCompositor->paSrcRects);
1573 RTMemFree(pCompositor->paSrcRects);
1574 Assert(pCompositor->paDstRects);
1575 RTMemFree(pCompositor->paDstRects);
1576 }
1577
1578 pCompositor->paSrcRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paSrcRects) * cRects);
1579 if (pCompositor->paSrcRects)
1580 {
1581 pCompositor->paDstRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstRects) * cRects);
1582 if (pCompositor->paDstRects)
1583 {
1584 pCompositor->cRects = cRects;
1585 pCompositor->cRectsBuffer = cRects;
1586 return VINF_SUCCESS;
1587 }
1588 else
1589 {
1590 WARN(("RTMemAlloc failed!"));
1591 RTMemFree(pCompositor->paSrcRects);
1592 pCompositor->paSrcRects = NULL;
1593 }
1594 }
1595 else
1596 {
1597 WARN(("RTMemAlloc failed!"));
1598 pCompositor->paDstRects = NULL;
1599 }
1600
1601 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1602 pCompositor->cRectsBuffer = 0;
1603
1604 return VERR_NO_MEMORY;
1605}
1606
1607static void crVrScrCompositorRectsInvalidate(PVBOXVR_SCR_COMPOSITOR pCompositor)
1608{
1609 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1610}
1611
1612static DECLCALLBACK(bool) crVrScrCompositorRectsCounterCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor)
1613{
1614 uint32_t* pCounter = (uint32_t*)pvVisitor;
1615 Assert(VBoxVrListRectsCount(&pEntry->Vr));
1616 *pCounter += VBoxVrListRectsCount(&pEntry->Vr);
1617 return true;
1618}
1619
1620typedef struct VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER
1621{
1622 PRTRECT paSrcRects;
1623 PRTRECT paDstRects;
1624 uint32_t cRects;
1625} VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER, *PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER;
1626
1627static DECLCALLBACK(bool) crVrScrCompositorRectsAssignerCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
1628{
1629 PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER pData = (PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER)pvVisitor;
1630 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
1631 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
1632 pEntry->paSrcRects = pData->paSrcRects;
1633 pEntry->paDstRects = pData->paDstRects;
1634 uint32_t cRects = VBoxVrListRectsCount(&pCEntry->Vr);
1635 Assert(cRects);
1636 Assert(cRects <= pData->cRects);
1637 int rc = VBoxVrListRectsGet(&pCEntry->Vr, cRects, pEntry->paDstRects);
1638 AssertRC(rc);
1639 if (
1640#ifndef IN_RING0
1641 pCompositor->StretchX >= 1. && pCompositor->StretchY >= 1. /* <- stretching can not zero some rects */
1642 &&
1643#endif
1644 !pEntry->Pos.x && !pEntry->Pos.y
1645 )
1646 {
1647 memcpy(pEntry->paSrcRects, pEntry->paDstRects, cRects * sizeof (*pEntry->paSrcRects));
1648 }
1649 else
1650 {
1651 for (uint32_t i = 0; i < cRects; ++i)
1652 {
1653 pEntry->paSrcRects[i].xLeft = (int32_t)((pEntry->paDstRects[i].xLeft - pEntry->Pos.x));
1654 pEntry->paSrcRects[i].yTop = (int32_t)((pEntry->paDstRects[i].yTop - pEntry->Pos.y));
1655 pEntry->paSrcRects[i].xRight = (int32_t)((pEntry->paDstRects[i].xRight - pEntry->Pos.x));
1656 pEntry->paSrcRects[i].yBottom = (int32_t)((pEntry->paDstRects[i].yBottom - pEntry->Pos.y));
1657#ifndef IN_RING0
1658 if (pCompositor->StretchX != 1.)
1659 {
1660 pEntry->paSrcRects[i].xLeft = (int32_t)(pEntry->paSrcRects[i].xLeft * pCompositor->StretchX);
1661 pEntry->paSrcRects[i].xRight = (int32_t)(pEntry->paSrcRects[i].xRight * pCompositor->StretchX);
1662 }
1663 if (pCompositor->StretchY != 1.)
1664 {
1665 pEntry->paSrcRects[i].yTop = (int32_t)(pEntry->paSrcRects[i].yTop * pCompositor->StretchY);
1666 pEntry->paSrcRects[i].yBottom = (int32_t)(pEntry->paSrcRects[i].yBottom * pCompositor->StretchY);
1667 }
1668#endif
1669 }
1670
1671#ifndef IN_RING0
1672 bool canZeroX = (pCompositor->StretchX < 1.);
1673 bool canZeroY = (pCompositor->StretchY < 1.);
1674 if (canZeroX && canZeroY)
1675 {
1676 /* filter out zero rectangles*/
1677 uint32_t iOrig, iNew;
1678 for (iOrig = 0, iNew = 0; iOrig < cRects; ++iOrig)
1679 {
1680 PRTRECT pOrigRect = &pEntry->paSrcRects[iOrig];
1681 if (pOrigRect->xLeft == pOrigRect->xRight
1682 || pOrigRect->yTop == pOrigRect->yBottom)
1683 continue;
1684
1685 if (iNew != iOrig)
1686 {
1687 PRTRECT pNewRect = &pEntry->paSrcRects[iNew];
1688 *pNewRect = *pOrigRect;
1689 }
1690
1691 ++iNew;
1692 }
1693
1694 Assert(iNew <= iOrig);
1695
1696 uint32_t cDiff = iOrig - iNew;
1697
1698 if (cDiff)
1699 {
1700 pCompositor->cRects -= cDiff;
1701 cRects -= cDiff;
1702 }
1703 }
1704#endif
1705 }
1706 pEntry->cRects = cRects;
1707 pData->paDstRects += cRects;
1708 pData->paSrcRects += cRects;
1709 pData->cRects -= cRects;
1710 return true;
1711}
1712
1713static int crVrScrCompositorRectsCheckInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
1714{
1715 if (pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED)
1716 return VINF_SUCCESS;
1717
1718 uint32_t cRects = 0;
1719 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsCounterCb, &cRects);
1720
1721 if (!cRects)
1722 {
1723 pCompositor->cRects = 0;
1724 return VINF_SUCCESS;
1725 }
1726
1727 int rc = crVrScrCompositorRectsAssignBuffer(pCompositor, cRects);
1728 if (!RT_SUCCESS(rc))
1729 return rc;
1730
1731 VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER AssignerData;
1732 AssignerData.paSrcRects = pCompositor->paSrcRects;
1733 AssignerData.paDstRects = pCompositor->paDstRects;
1734 AssignerData.cRects = pCompositor->cRects;
1735 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsAssignerCb, &AssignerData);
1736 Assert(!AssignerData.cRects);
1737 return VINF_SUCCESS;
1738}
1739
1740
1741static int crVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, uint32_t *pfChangedFlags)
1742{
1743 uint32_t fChangedFlags = 0;
1744 int rc = VBoxVrCompositorEntryRegionsAdd(&pCompositor->Compositor, pEntry ? &pEntry->Ce : NULL, cRegions, paRegions, &fChangedFlags);
1745 if (!RT_SUCCESS(rc))
1746 {
1747 WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
1748 return rc;
1749 }
1750
1751 if (fChangedFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED)
1752 {
1753 crVrScrCompositorRectsInvalidate(pCompositor);
1754 }
1755
1756 if (fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)
1757 {
1758 CrVrScrCompositorEntrySetChanged(pEntry, true);
1759 }
1760
1761 if (pfChangedFlags)
1762 *pfChangedFlags = fChangedFlags;
1763 return VINF_SUCCESS;
1764}
1765
1766static int crVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1767{
1768 bool fChanged;
1769 CrVrScrCompositorEntryIsInList(pEntry);
1770 int rc = VBoxVrCompositorEntryRegionsSet(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
1771 if (!RT_SUCCESS(rc))
1772 {
1773 WARN(("VBoxVrCompositorEntryRegionsSet failed, rc %d", rc));
1774 return rc;
1775 }
1776
1777 if (fChanged)
1778 {
1779 CrVrScrCompositorEntrySetChanged(pEntry, true);
1780 if (!CrVrScrCompositorEntryIsInList(pEntry))
1781 {
1782 pEntry->cRects = 0;
1783 pEntry->paSrcRects = NULL;
1784 pEntry->paDstRects = NULL;
1785 }
1786 crVrScrCompositorRectsInvalidate(pCompositor);
1787 }
1788
1789 CrVrScrCompositorEntrySetChanged(pEntry, true);
1790
1791 if (pfChanged)
1792 *pfChanged = fChanged;
1793 return VINF_SUCCESS;
1794}
1795
1796static int crVrScrCompositorEntryPositionSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, bool *pfChanged)
1797{
1798 if (pfChanged)
1799 *pfChanged = false;
1800 if (pEntry && (pEntry->Pos.x != pPos->x || pEntry->Pos.y != pPos->y))
1801 {
1802 int rc = VBoxVrCompositorEntryRegionsTranslate(&pCompositor->Compositor, &pEntry->Ce, pPos->x - pEntry->Pos.x, pPos->y - pEntry->Pos.y, pfChanged);
1803 if (!RT_SUCCESS(rc))
1804 {
1805 WARN(("VBoxVrCompositorEntryRegionsTranslate failed rc %d", rc));
1806 return rc;
1807 }
1808
1809 if (VBoxVrCompositorEntryIsInList(&pEntry->Ce))
1810 {
1811 crVrScrCompositorRectsInvalidate(pCompositor);
1812 }
1813
1814 pEntry->Pos = *pPos;
1815 CrVrScrCompositorEntrySetChanged(pEntry, true);
1816
1817 if (pfChanged)
1818 *pfChanged = true;
1819 }
1820 return VINF_SUCCESS;
1821}
1822
1823static int crVrScrCompositorEntryEnsureRegionsInTex(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
1824{
1825 RTRECT Rect;
1826 Rect.xLeft = pEntry->Pos.x;
1827 Rect.yTop = pEntry->Pos.y;
1828 Rect.xRight = pEntry->Pos.x + pEntry->Tex.width;
1829 Rect.yBottom = pEntry->Pos.y + pEntry->Tex.height;
1830 int rc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, 1, &Rect, NULL);
1831 if (!RT_SUCCESS(rc))
1832 WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", rc));
1833 return rc;
1834}
1835
1836VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, uint32_t *pfChangeFlags)
1837{
1838 int rc;
1839 uint32_t fChangeFlags = 0;
1840 bool fPosChanged = false;
1841 if (pPos)
1842 {
1843 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
1844 if (!RT_SUCCESS(rc))
1845 {
1846 WARN(("RegionsAdd: crVrScrCompositorEntryPositionSet failed rc %d", rc));
1847 return rc;
1848 }
1849 }
1850
1851 rc = crVrScrCompositorEntryRegionsAdd(pCompositor, pEntry, cRegions, paRegions, &fChangeFlags);
1852 if (!RT_SUCCESS(rc))
1853 {
1854 WARN(("crVrScrCompositorEntryRegionsAdd failed, rc %d", rc));
1855 return rc;
1856 }
1857
1858 if ((fPosChanged || (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)) && pEntry)
1859 {
1860 rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry);
1861 if (!RT_SUCCESS(rc))
1862 {
1863 WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed, rc %d", rc));
1864 return rc;
1865 }
1866 }
1867
1868 if (pfChangeFlags)
1869 {
1870 if (fPosChanged)
1871 {
1872 /* means entry was in list and was moved, so regions changed */
1873 *pfChangeFlags = VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED;
1874 }
1875 else
1876 *pfChangeFlags = fChangeFlags;
1877 }
1878
1879 return VINF_SUCCESS;
1880}
1881
1882VBOXVREGDECL(int) CrVrScrCompositorEntryTexUpdate(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_TEXTURE *pTex)
1883{
1884 bool fCompositorChanged = CrVrScrCompositorEntryIsUsed(pEntry) && (pEntry->Tex.width != pTex->width || pEntry->Tex.height != pTex->height);
1885 pEntry->Tex = *pTex;
1886 CrVrScrCompositorEntrySetChanged(pEntry, true);
1887 if (fCompositorChanged)
1888 {
1889 int rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry);
1890 if (!RT_SUCCESS(rc))
1891 {
1892 WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed rc %d", rc));
1893 return rc;
1894 }
1895 }
1896 return VINF_SUCCESS;
1897}
1898
1899VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1900{
1901 /* @todo: the fChanged sate calculation is really rough now, this is enough for now though */
1902 bool fChanged = false, fPosChanged = false;
1903 bool fWasInList = CrVrScrCompositorEntryIsInList(pEntry);
1904 int rc = CrVrScrCompositorEntryRemove(pCompositor, pEntry);
1905 if (!RT_SUCCESS(rc))
1906 {
1907 WARN(("RegionsSet: CrVrScrCompositorEntryRemove failed rc %d", rc));
1908 return rc;
1909 }
1910
1911 if (pPos)
1912 {
1913 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
1914 if (!RT_SUCCESS(rc))
1915 {
1916 WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
1917 return rc;
1918 }
1919 }
1920
1921 rc = crVrScrCompositorEntryRegionsSet(pCompositor, pEntry, cRegions, paRegions, &fChanged);
1922 if (!RT_SUCCESS(rc))
1923 {
1924 WARN(("crVrScrCompositorEntryRegionsSet failed, rc %d", rc));
1925 return rc;
1926 }
1927
1928 if (fChanged && CrVrScrCompositorEntryIsUsed(pEntry))
1929 {
1930 rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry);
1931 if (!RT_SUCCESS(rc))
1932 {
1933 WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed, rc %d", rc));
1934 return rc;
1935 }
1936 }
1937
1938 if (pfChanged)
1939 *pfChanged = fPosChanged || fChanged || fWasInList;
1940
1941 return VINF_SUCCESS;
1942}
1943
1944VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
1945{
1946 bool fChanged = false;
1947 int rc = VBoxVrCompositorEntryListIntersect(&pCompositor->Compositor, &pEntry->Ce, pList2, &fChanged);
1948 if (!RT_SUCCESS(rc))
1949 {
1950 WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
1951 return rc;
1952 }
1953
1954 if (fChanged)
1955 {
1956 CrVrScrCompositorEntrySetChanged(pEntry, true);
1957 crVrScrCompositorRectsInvalidate(pCompositor);
1958 }
1959
1960 if (pfChanged)
1961 *pfChanged = fChanged;
1962
1963 return VINF_SUCCESS;
1964}
1965
1966VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1967{
1968 bool fChanged = false;
1969 int rc = VBoxVrCompositorEntryRegionsIntersect(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
1970 if (!RT_SUCCESS(rc))
1971 {
1972 WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
1973 return rc;
1974 }
1975
1976 if (fChanged)
1977 {
1978 CrVrScrCompositorEntrySetChanged(pEntry, true);
1979 crVrScrCompositorRectsInvalidate(pCompositor);
1980 }
1981
1982 if (pfChanged)
1983 *pfChanged = fChanged;
1984
1985 return VINF_SUCCESS;
1986}
1987
1988VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
1989{
1990 VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
1991 CrVrScrCompositorIterInit(pCompositor, &Iter);
1992 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
1993 int rc = VINF_SUCCESS;
1994 bool fChanged = false;
1995
1996 while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
1997 {
1998 bool fTmpChanged = false;
1999 int tmpRc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
2000 if (RT_SUCCESS(tmpRc))
2001 {
2002 fChanged |= fTmpChanged;
2003 }
2004 else
2005 {
2006 WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
2007 rc = tmpRc;
2008 }
2009 }
2010
2011 if (pfChanged)
2012 *pfChanged = fChanged;
2013
2014 return rc;
2015}
2016
2017VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
2018{
2019 VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
2020 CrVrScrCompositorIterInit(pCompositor, &Iter);
2021 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
2022 int rc = VINF_SUCCESS;
2023 bool fChanged = false;
2024
2025 while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
2026 {
2027 bool fTmpChanged = false;
2028 int tmpRc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
2029 if (RT_SUCCESS(tmpRc))
2030 {
2031 fChanged |= fTmpChanged;
2032 }
2033 else
2034 {
2035 WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
2036 rc = tmpRc;
2037 }
2038 }
2039
2040 if (pfChanged)
2041 *pfChanged = fChanged;
2042
2043 return rc;
2044}
2045
2046VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos)
2047{
2048 int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
2049 if (!RT_SUCCESS(rc))
2050 {
2051 WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
2052 return rc;
2053 }
2054 return VINF_SUCCESS;
2055}
2056
2057/* regions are valid until the next CrVrScrCompositor call */
2058VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
2059{
2060 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
2061 if (!RT_SUCCESS(rc))
2062 {
2063 WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
2064 return rc;
2065 }
2066
2067 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
2068
2069 *pcRegions = pEntry->cRects;
2070 if (ppaSrcRegions)
2071 *ppaSrcRegions = pEntry->paSrcRects;
2072 if (ppaDstRegions)
2073 *ppaDstRegions = pEntry->paDstRects;
2074
2075 return VINF_SUCCESS;
2076}
2077
2078VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
2079{
2080 if (!VBoxVrCompositorEntryRemove(&pCompositor->Compositor, &pEntry->Ce))
2081 return VINF_SUCCESS;
2082
2083 CrVrScrCompositorEntrySetChanged(pEntry, true);
2084 pEntry->cRects = 0;
2085 pEntry->paSrcRects = NULL;
2086 pEntry->paDstRects = NULL;
2087
2088 crVrScrCompositorRectsInvalidate(pCompositor);
2089 return VINF_SUCCESS;
2090}
2091
2092VBOXVREGDECL(int) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
2093{
2094 memset(pCompositor, 0, sizeof (*pCompositor));
2095#ifndef IN_RING0
2096 int rc = RTCritSectInit(&pCompositor->CritSect);
2097 if (!RT_SUCCESS(rc))
2098 {
2099 WARN(("RTCritSectInit failed rc %d", rc));
2100 return rc;
2101 }
2102#endif
2103 VBoxVrCompositorInit(&pCompositor->Compositor, NULL);
2104#ifndef IN_RING0
2105 pCompositor->StretchX = 1.0;
2106 pCompositor->StretchY = 1.0;
2107#endif
2108 return VINF_SUCCESS;
2109}
2110
2111VBOXVREGDECL(void) CrVrScrCompositorTerm(PVBOXVR_SCR_COMPOSITOR pCompositor)
2112{
2113 VBoxVrCompositorTerm(&pCompositor->Compositor);
2114 if (pCompositor->paDstRects)
2115 RTMemFree(pCompositor->paDstRects);
2116 if (pCompositor->paSrcRects)
2117 RTMemFree(pCompositor->paSrcRects);
2118#ifndef IN_RING0
2119 RTCritSectDelete(&pCompositor->CritSect);
2120#endif
2121}
2122
2123
2124static DECLCALLBACK(bool) crVrScrCompositorEntrySetAllChangedCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
2125{
2126 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
2127 CrVrScrCompositorEntrySetChanged(pEntry, !!pvVisitor);
2128 return true;
2129}
2130
2131VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged)
2132{
2133 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorEntrySetAllChangedCb, (void*)fChanged);
2134}
2135#ifndef IN_RING0
2136VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY)
2137{
2138 pCompositor->StretchX = StretchX;
2139 pCompositor->StretchY = StretchY;
2140 crVrScrCompositorRectsInvalidate(pCompositor);
2141 CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
2142}
2143#endif
2144/* regions are valid until the next CrVrScrCompositor call */
2145VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
2146{
2147 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
2148 if (!RT_SUCCESS(rc))
2149 {
2150 WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
2151 return rc;
2152 }
2153
2154 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
2155
2156 *pcRegions = pCompositor->cRects;
2157 if (ppaSrcRegions)
2158 *ppaSrcRegions = pCompositor->paSrcRects;
2159 if (ppaDstRegions)
2160 *ppaDstRegions = pCompositor->paDstRects;
2161
2162 return VINF_SUCCESS;
2163}
2164
2165typedef struct VBOXVR_SCR_COMPOSITOR_VISITOR_CB
2166{
2167 PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor;
2168 void *pvVisitor;
2169} VBOXVR_SCR_COMPOSITOR_VISITOR_CB, *PVBOXVR_SCR_COMPOSITOR_VISITOR_CB;
2170
2171static DECLCALLBACK(bool) crVrScrCompositorVisitCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
2172{
2173 PVBOXVR_SCR_COMPOSITOR_VISITOR_CB pData = (PVBOXVR_SCR_COMPOSITOR_VISITOR_CB)pvVisitor;
2174 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
2175 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
2176 return pData->pfnVisitor(pCompositor, pEntry, pData->pvVisitor);
2177}
2178
2179VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
2180{
2181 VBOXVR_SCR_COMPOSITOR_VISITOR_CB Data;
2182 Data.pfnVisitor = pfnVisitor;
2183 Data.pvVisitor = pvVisitor;
2184 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorVisitCb, &Data);
2185}
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