VirtualBox

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

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

crOpenGL: host 3d window repaint impl for Win host; enable offscreen rendering for Win; 3D window repaint generics

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.6 KB
Line 
1/* $Id: vreg.cpp 44766 2013-02-20 15:43:52Z 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/memcache.h>
20#include <iprt/err.h>
21#include <iprt/assert.h>
22#include <iprt/asm.h>
23
24#ifndef IN_RING0
25#include <cr_error.h>
26#define WARN(_m) do { crWarning _m ; } while (0)
27#else
28# error port me!
29#endif
30
31#ifdef DEBUG_misha
32//# define VBOXVDBG_VR_LAL_DISABLE
33#endif
34
35#ifndef VBOXVDBG_VR_LAL_DISABLE
36static volatile int32_t g_cVBoxVrInits = 0;
37static RTMEMCACHE g_VBoxVrLookasideList;
38#endif
39
40static PVBOXVR_REG vboxVrRegCreate()
41{
42#ifndef VBOXVDBG_VR_LAL_DISABLE
43 PVBOXVR_REG pReg = (PVBOXVR_REG)RTMemCacheAlloc(g_VBoxVrLookasideList);
44 if (!pReg)
45 {
46 WARN(("ExAllocateFromLookasideListEx failed!"));
47 }
48 return pReg;
49#else
50 return (PVBOXVR_REG)RTMemAlloc(sizeof (VBOXVR_REG));
51#endif
52}
53
54static void vboxVrRegTerm(PVBOXVR_REG pReg)
55{
56#ifndef VBOXVDBG_VR_LAL_DISABLE
57 RTMemCacheFree(g_VBoxVrLookasideList, pReg);
58#else
59 RTMemFree(pReg);
60#endif
61}
62
63VBOXVREGDECL(void) VBoxVrListClear(PVBOXVR_LIST pList)
64{
65 PVBOXVR_REG pReg, pRegNext;
66
67 RTListForEachSafe(&pList->ListHead, pReg, pRegNext, VBOXVR_REG, ListEntry)
68 {
69 vboxVrRegTerm(pReg);
70 }
71 VBoxVrListInit(pList);
72}
73
74#define VBOXVR_MEMTAG 'vDBV'
75
76VBOXVREGDECL(int) VBoxVrInit()
77{
78 int32_t cNewRefs = ASMAtomicIncS32(&g_cVBoxVrInits);
79 Assert(cNewRefs >= 1);
80 Assert(cNewRefs == 1); /* <- debugging */
81 if (cNewRefs > 1)
82 return VINF_SUCCESS;
83
84#ifndef VBOXVDBG_VR_LAL_DISABLE
85 int rc = RTMemCacheCreate(&g_VBoxVrLookasideList, sizeof (VBOXVR_REG),
86 0, /* size_t cbAlignment */
87 UINT32_MAX, /* uint32_t cMaxObjects */
88 NULL, /* PFNMEMCACHECTOR pfnCtor*/
89 NULL, /* PFNMEMCACHEDTOR pfnDtor*/
90 NULL, /* void *pvUser*/
91 0 /* uint32_t fFlags*/
92 );
93 if (!RT_SUCCESS(rc))
94 {
95 WARN(("ExInitializeLookasideListEx failed, rc (%d)", rc));
96 return rc;
97 }
98#endif
99
100 return VINF_SUCCESS;
101}
102
103VBOXVREGDECL(void) VBoxVrTerm()
104{
105 int32_t cNewRefs = ASMAtomicDecS32(&g_cVBoxVrInits);
106 Assert(cNewRefs >= 0);
107 if (cNewRefs > 0)
108 return;
109
110#ifndef VBOXVDBG_VR_LAL_DISABLE
111 RTMemCacheDestroy(g_VBoxVrLookasideList);
112#endif
113}
114
115typedef DECLCALLBACK(int) FNVBOXVR_CB_COMPARATOR(const PVBOXVR_REG pReg1, const PVBOXVR_REG pReg2);
116typedef FNVBOXVR_CB_COMPARATOR *PFNVBOXVR_CB_COMPARATOR;
117
118static DECLCALLBACK(int) vboxVrRegNonintersectedComparator(const RTRECT* pRect1, const RTRECT* pRect2)
119{
120 Assert(!VBoxRectIsIntersect(pRect1, pRect2));
121 if (pRect1->yTop != pRect2->yTop)
122 return pRect1->yTop - pRect2->yTop;
123 return pRect1->xLeft - pRect2->xLeft;
124}
125
126#ifdef DEBUG_misha
127static void vboxVrDbgListDoVerify(PVBOXVR_LIST pList)
128{
129 PVBOXVR_REG pReg1, pReg2;
130 RTListForEach(&pList->ListHead, pReg1, VBOXVR_REG, ListEntry)
131 {
132 for (RTLISTNODE *pEntry2 = pReg1->ListEntry.pNext; pEntry2 != &pList->ListHead; pEntry2 = pEntry2->pNext)
133 {
134 pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
135 Assert(vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0);
136 }
137 }
138}
139
140#define vboxVrDbgListVerify vboxVrDbgListDoVerify
141#else
142#define vboxVrDbgListVerify(_p) do {} while (0)
143#endif
144
145static int vboxVrListUniteIntersection(PVBOXVR_LIST pList, PVBOXVR_LIST pIntersection);
146
147#define VBOXVR_INVALID_COORD (~0U)
148
149DECLINLINE(void) vboxVrListRegAdd(PVBOXVR_LIST pList, PVBOXVR_REG pReg, PRTLISTNODE pPlace, bool fAfter)
150{
151 if (fAfter)
152 RTListPrepend(pPlace, &pReg->ListEntry);
153 else
154 RTListAppend(pPlace, &pReg->ListEntry);
155 ++pList->cEntries;
156 vboxVrDbgListVerify(pList);
157}
158
159DECLINLINE(void) vboxVrListRegRemove(PVBOXVR_LIST pList, PVBOXVR_REG pReg)
160{
161 RTListNodeRemove(&pReg->ListEntry);
162 --pList->cEntries;
163}
164
165static void vboxVrListRegAddOrder(PVBOXVR_LIST pList, PRTLISTNODE pMemberEntry, PVBOXVR_REG pReg)
166{
167 do
168 {
169 if (pMemberEntry != &pList->ListHead)
170 {
171 PVBOXVR_REG pMemberReg = PVBOXVR_REG_FROM_ENTRY(pMemberEntry);
172 if (vboxVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0)
173 {
174 pMemberEntry = pMemberEntry->pNext;
175 continue;
176 }
177 }
178 vboxVrListRegAdd(pList, pReg, pMemberEntry, false);
179 break;
180 } while (1);
181}
182
183static void vboxVrListAddNonintersected(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
184{
185 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
186
187 for (PRTLISTNODE pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.pNext)
188 {
189 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
190 do {
191 if (pEntry1 != &pList1->ListHead)
192 {
193 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
194 if (vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0)
195 {
196 pEntry1 = pEntry1->pNext;
197 continue;
198 }
199 }
200 vboxVrListRegRemove(pList2, pReg2);
201 vboxVrListRegAdd(pList1, pReg2, pEntry1, false);
202 break;
203 } while (1);
204 }
205
206 Assert(VBoxVrListIsEmpty(pList2));
207}
208
209static int vboxVrListRegIntersectSubstNoJoin(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2)
210{
211 uint32_t topLim = VBOXVR_INVALID_COORD;
212 uint32_t bottomLim = VBOXVR_INVALID_COORD;
213 RTLISTNODE List;
214 PVBOXVR_REG pBottomReg = NULL;
215#ifdef DEBUG_misha
216 RTRECT tmpRect = pReg1->Rect;
217 vboxVrDbgListVerify(pList1);
218#endif
219
220 RTListInit(&List);
221
222 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
223
224 if (pReg1->Rect.yTop < pRect2->yTop)
225 {
226 Assert(pRect2->yTop < pReg1->Rect.yBottom);
227 PVBOXVR_REG pRegResult = vboxVrRegCreate();
228 pRegResult->Rect.yTop = pReg1->Rect.yTop;
229 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
230 pRegResult->Rect.yBottom = pRect2->yTop;
231 pRegResult->Rect.xRight = pReg1->Rect.xRight;
232 topLim = pRect2->yTop;
233 RTListAppend(&List, &pRegResult->ListEntry);
234 }
235
236 if (pReg1->Rect.yBottom > pRect2->yBottom)
237 {
238 Assert(pRect2->yBottom > pReg1->Rect.yTop);
239 PVBOXVR_REG pRegResult = vboxVrRegCreate();
240 pRegResult->Rect.yTop = pRect2->yBottom;
241 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
242 pRegResult->Rect.yBottom = pReg1->Rect.yBottom;
243 pRegResult->Rect.xRight = pReg1->Rect.xRight;
244 bottomLim = pRect2->yBottom;
245 pBottomReg = pRegResult;
246 }
247
248 if (pReg1->Rect.xLeft < pRect2->xLeft)
249 {
250 Assert(pRect2->xLeft < pReg1->Rect.xRight);
251 PVBOXVR_REG pRegResult = vboxVrRegCreate();
252 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
253 pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
254 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
255 pRegResult->Rect.xRight = pRect2->xLeft;
256 RTListAppend(&List, &pRegResult->ListEntry);
257 }
258
259 if (pReg1->Rect.xRight > pRect2->xRight)
260 {
261 Assert(pRect2->xRight > pReg1->Rect.xLeft);
262 PVBOXVR_REG pRegResult = vboxVrRegCreate();
263 pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
264 pRegResult->Rect.xLeft = pRect2->xRight;
265 pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
266 pRegResult->Rect.xRight = pReg1->Rect.xRight;
267 RTListAppend(&List, &pRegResult->ListEntry);
268 }
269
270 if (pBottomReg)
271 RTListAppend(&List, &pBottomReg->ListEntry);
272
273 PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
274 vboxVrListRegRemove(pList1, pReg1);
275 vboxVrRegTerm(pReg1);
276
277 if (RTListIsEmpty(&List))
278 return VINF_SUCCESS; /* the region is covered by the pRect2 */
279
280 PRTLISTNODE pEntry = List.pNext, pNext;
281 for (; pEntry != &List; pEntry = pNext)
282 {
283 pNext = pEntry->pNext;
284 PVBOXVR_REG pReg = PVBOXVR_REG_FROM_ENTRY(pEntry);
285
286 vboxVrListRegAddOrder(pList1, pMemberEntry, pReg);
287 pMemberEntry = pEntry->pNext; /* the following elements should go after the given pEntry since they are ordered already */
288 }
289 return VINF_SUCCESS;
290}
291
292typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_INTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2, void *pvContext, PRTLISTNODE *ppNext);
293typedef FNVBOXVR_CB_INTERSECTED_VISITOR *PFNVBOXVR_CB_INTERSECTED_VISITOR;
294
295static void vboxVrListVisitIntersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
296{
297 PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
298 PRTLISTNODE pNext1;
299 uint32_t iFirst2 = 0;
300
301 for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
302 {
303 pNext1 = pEntry1->pNext;
304 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
305 for (uint32_t i = iFirst2; i < cRects; ++i)
306 {
307 const RTRECT *pRect2 = &aRects[i];
308 if (pReg1->Rect.yBottom <= pRect2->yTop)
309 continue;
310 else if (pRect2->yBottom <= pReg1->Rect.yTop)
311 continue;
312 /* y coords intersect */
313 else if (pReg1->Rect.xRight <= pRect2->xLeft)
314 continue;
315 else if (pRect2->xRight <= pReg1->Rect.xLeft)
316 continue;
317 /* x coords intersect */
318
319 /* the visitor can modify the list 1, apply necessary adjustments after it */
320 PRTLISTNODE pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1);
321 if (pEntry1 == &pList1->ListHead)
322 break;
323 }
324 }
325}
326
327
328static void vboxVrListJoinRectsHV(PVBOXVR_LIST pList, bool fHorizontal)
329{
330 PRTLISTNODE pNext1, pNext2;
331
332 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
333 {
334 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
335 pNext1 = pEntry1->pNext;
336 for (PRTLISTNODE pEntry2 = pEntry1->pNext; pEntry2 != &pList->ListHead; pEntry2 = pNext2)
337 {
338 PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
339 pNext2 = pEntry2->pNext;
340 if (fHorizontal)
341 {
342 if (pReg1->Rect.yTop == pReg2->Rect.yTop)
343 {
344 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
345 {
346 /* join rectangles */
347 vboxVrListRegRemove(pList, pReg2);
348 if (pReg1->Rect.yBottom > pReg2->Rect.yBottom)
349 {
350 int32_t oldRight1 = pReg1->Rect.xRight;
351 int32_t oldBottom1 = pReg1->Rect.yBottom;
352 pReg1->Rect.xRight = pReg2->Rect.xRight;
353 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
354
355 vboxVrDbgListVerify(pList);
356
357 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
358 pReg2->Rect.yTop = pReg1->Rect.yBottom;
359 pReg2->Rect.xRight = oldRight1;
360 pReg2->Rect.yBottom = oldBottom1;
361 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
362 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
363 * and thus can match one of the previous rects */
364 pNext1 = pList->ListHead.pNext;
365 break;
366 }
367 else if (pReg1->Rect.yBottom < pReg2->Rect.yBottom)
368 {
369 pReg1->Rect.xRight = pReg2->Rect.xRight;
370 vboxVrDbgListVerify(pList);
371 pReg2->Rect.yTop = pReg1->Rect.yBottom;
372 vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
373 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
374 * and thus can match one of the previous rects */
375 pNext1 = pList->ListHead.pNext;
376 break;
377 }
378 else
379 {
380 pReg1->Rect.xRight = pReg2->Rect.xRight;
381 vboxVrDbgListVerify(pList);
382 /* reset the pNext1 since it could be the pReg2 being destroyed */
383 pNext1 = pEntry1->pNext;
384 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
385 vboxVrRegTerm(pReg2);
386 }
387 }
388 continue;
389 }
390 else if (pReg1->Rect.yBottom == pReg2->Rect.yBottom)
391 {
392 Assert(pReg1->Rect.yTop < pReg2->Rect.yTop); /* <- since pReg1 > pReg2 && pReg1->Rect.yTop != pReg2->Rect.yTop*/
393 if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
394 {
395 /* join rectangles */
396 vboxVrListRegRemove(pList, pReg2);
397
398 pReg1->Rect.yBottom = pReg2->Rect.yTop;
399 vboxVrDbgListVerify(pList);
400 pReg2->Rect.xLeft = pReg1->Rect.xLeft;
401
402 vboxVrListRegAddOrder(pList, pReg2->ListEntry.pNext, pReg2);
403
404 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
405 * and thus can match one of the previous rects */
406 pNext1 = pList->ListHead.pNext;
407 break;
408 }
409 else if (pReg1->Rect.xLeft == pReg2->Rect.xRight)
410 {
411 /* join rectangles */
412 vboxVrListRegRemove(pList, pReg2);
413
414 pReg1->Rect.yBottom = pReg2->Rect.yTop;
415 vboxVrDbgListVerify(pList);
416 pReg2->Rect.xRight = pReg1->Rect.xRight;
417
418 vboxVrListRegAddOrder(pList, pReg2->ListEntry.pNext, pReg2);
419
420 /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
421 * and thus can match one of the previous rects */
422 pNext1 = pList->ListHead.pNext;
423 break;
424 }
425 continue;
426 }
427 }
428 else
429 {
430 if (pReg1->Rect.yBottom == pReg2->Rect.yTop)
431 {
432 if (pReg1->Rect.xLeft == pReg2->Rect.xLeft)
433 {
434 if (pReg1->Rect.xRight == pReg2->Rect.xRight)
435 {
436 /* join rects */
437 vboxVrListRegRemove(pList, pReg2);
438
439 pReg1->Rect.yBottom = pReg2->Rect.yBottom;
440 vboxVrDbgListVerify(pList);
441
442 /* reset the pNext1 since it could be the pReg2 being destroyed */
443 pNext1 = pEntry1->pNext;
444 /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
445 vboxVrRegTerm(pReg2);
446 continue;
447 }
448 /* no more to be done for for pReg1 */
449 break;
450 }
451 else if (pReg1->Rect.xRight > pReg2->Rect.xLeft)
452 {
453 /* no more to be done for for pReg1 */
454 break;
455 }
456
457 continue;
458 }
459 else if (pReg1->Rect.yBottom < pReg2->Rect.yTop)
460 {
461 /* no more to be done for for pReg1 */
462 break;
463 }
464 }
465 }
466 }
467}
468
469static void vboxVrListJoinRects(PVBOXVR_LIST pList)
470{
471 vboxVrListJoinRectsHV(pList, true);
472 vboxVrListJoinRectsHV(pList, false);
473}
474
475typedef struct VBOXVR_CBDATA_SUBST
476{
477 int rc;
478 bool fChanged;
479} VBOXVR_CBDATA_SUBST, *PVBOXVR_CBDATA_SUBST;
480
481static DECLCALLBACK(PRTLISTNODE) vboxVrListSubstNoJoinCb(PVBOXVR_LIST pList, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
482{
483 PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
484 /* store the prev to get the new pNext out of it*/
485 PRTLISTNODE pPrev = pReg1->ListEntry.pPrev;
486 pData->fChanged = true;
487
488 Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
489
490 /* NOTE: the pReg1 will be invalid after the vboxVrListRegIntersectSubstNoJoin call!!! */
491 int rc = vboxVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2);
492 if (RT_SUCCESS(rc))
493 {
494 *ppNext = pPrev->pNext;
495 return &pList->ListHead;
496 }
497 WARN(("vboxVrListRegIntersectSubstNoJoin failed!"));
498 Assert(!RT_SUCCESS(rc));
499 pData->rc = rc;
500 *ppNext = &pList->ListHead;
501 return &pList->ListHead;
502}
503
504static int vboxVrListSubstNoJoin(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
505{
506 if (VBoxVrListIsEmpty(pList))
507 return VINF_SUCCESS;
508
509 VBOXVR_CBDATA_SUBST Data;
510 Data.rc = VINF_SUCCESS;
511 Data.fChanged = false;
512
513 *pfChanged = false;
514
515 vboxVrListVisitIntersected(pList, cRects, aRects, vboxVrListSubstNoJoinCb, &Data);
516 if (!RT_SUCCESS(Data.rc))
517 {
518 WARN(("vboxVrListVisitIntersected failed!"));
519 return Data.rc;
520 }
521
522 *pfChanged = Data.fChanged;
523 return VINF_SUCCESS;
524}
525
526#if 0
527static const RTRECT * vboxVrRectsOrder(uint32_t cRects, const RTRECT * aRects)
528{
529#ifdef DEBUG
530 {
531 for (uint32_t i = 0; i < cRects; ++i)
532 {
533 RTRECT *pRectI = &aRects[i];
534 for (uint32_t j = i + 1; j < cRects; ++j)
535 {
536 RTRECT *pRectJ = &aRects[j];
537 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
538 }
539 }
540 }
541#endif
542
543 RTRECT * pRects = (RTRECT *)aRects;
544 /* check if rects are ordered already */
545 for (uint32_t i = 0; i < cRects - 1; ++i)
546 {
547 RTRECT *pRect1 = &pRects[i];
548 RTRECT *pRect2 = &pRects[i+1];
549 if (vboxVrRegNonintersectedComparator(pRect1, pRect2) < 0)
550 continue;
551
552 WARN(("rects are unoreded!"));
553
554 if (pRects == aRects)
555 {
556 pRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cRects);
557 if (!pRects)
558 {
559 WARN(("RTMemAlloc failed!"));
560 return NULL;
561 }
562
563 memcpy(pRects, aRects, sizeof (RTRECT) * cRects);
564 }
565
566 Assert(pRects != aRects);
567
568 int j = (int)i - 1;
569 do {
570 RTRECT Tmp = *pRect1;
571 *pRect1 = *pRect2;
572 *pRect2 = Tmp;
573
574 if (j < 0)
575 break;
576
577 if (vboxVrRegNonintersectedComparator(pRect1, pRect1-1) > 0)
578 break;
579
580 pRect2 = pRect1--;
581 --j;
582 } while (1);
583 }
584
585 return pRects;
586}
587#endif
588
589VBOXVREGDECL(void) VBoxVrListTranslate(PVBOXVR_LIST pList, int32_t x, int32_t y)
590{
591 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
592 {
593 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
594 VBoxRectTranslate(&pReg1->Rect, x, y);
595 }
596}
597
598VBOXVREGDECL(int) VBoxVrListRectsSubst(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
599{
600#if 0
601 const RTRECT * pRects = vboxVrRectsOrder(cRects, aRects);
602 if (!pRects)
603 {
604 WARN(("vboxVrRectsOrder failed!"));
605 return VERR_NO_MEMORY;
606 }
607#endif
608
609 int rc = vboxVrListSubstNoJoin(pList, cRects, aRects, pfChanged);
610 if (!RT_SUCCESS(rc))
611 {
612 WARN(("vboxVrListSubstNoJoin failed!"));
613 goto done;
614 }
615
616 if (!*pfChanged)
617 goto done;
618
619 vboxVrListJoinRects(pList);
620
621done:
622#if 0
623 if (pRects != aRects)
624 RTMemFree(pRects);
625#endif
626 return rc;
627}
628
629VBOXVREGDECL(int) VBoxVrListRectsAdd(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
630{
631 uint32_t cCovered = 0;
632
633#if 0
634#ifdef DEBUG
635 {
636 for (uint32_t i = 0; i < cRects; ++i)
637 {
638 RTRECT *pRectI = &aRects[i];
639 for (uint32_t j = i + 1; j < cRects; ++j)
640 {
641 RTRECT *pRectJ = &aRects[j];
642 Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
643 }
644 }
645 }
646#endif
647#endif
648
649 /* early sort out the case when there are no new rects */
650 for (uint32_t i = 0; i < cRects; ++i)
651 {
652 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
653 {
654 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
655 if (VBoxRectIsCoveres(&pReg1->Rect, &aRects[i]))
656 {
657 cCovered++;
658 break;
659 }
660 }
661 }
662
663 if (cCovered == cRects)
664 {
665 *pfChanged = false;
666 return VINF_SUCCESS;
667 }
668
669 /* rects are not covered, need to go the slow way */
670
671 VBOXVR_LIST DiffList;
672 VBoxVrListInit(&DiffList);
673 RTRECT * pListRects = NULL;
674 uint32_t cAllocatedRects = 0;
675 bool fNeedRectreate = true;
676 bool fChanged = false;
677 int rc = VINF_SUCCESS;
678
679 for (uint32_t i = 0; i < cRects; ++i)
680 {
681 PVBOXVR_REG pReg = vboxVrRegCreate();
682 if (!pReg)
683 {
684 WARN(("vboxVrRegCreate failed!"));
685 rc = VERR_NO_MEMORY;
686 break;
687 }
688 pReg->Rect = aRects[i];
689
690 uint32_t cListRects = VBoxVrListRectsCount(pList);
691 if (!cListRects)
692 {
693 vboxVrListRegAdd(pList, pReg, &pList->ListHead, false);
694 fChanged = true;
695 continue;
696 }
697 else
698 {
699 Assert(VBoxVrListIsEmpty(&DiffList));
700 vboxVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, false);
701 }
702
703 if (cAllocatedRects < cListRects)
704 {
705 cAllocatedRects = cListRects + cRects;
706 Assert(fNeedRectreate);
707 if (pListRects)
708 RTMemFree(pListRects);
709 pListRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cAllocatedRects);
710 if (!pListRects)
711 {
712 WARN(("RTMemAlloc failed!"));
713 rc = VERR_NO_MEMORY;
714 break;
715 }
716 }
717
718
719 if (fNeedRectreate)
720 {
721 rc = VBoxVrListRectsGet(pList, cListRects, pListRects);
722 Assert(rc == VINF_SUCCESS);
723 fNeedRectreate = false;
724 }
725
726 bool fDummyChanged = false;
727 rc = vboxVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged);
728 if (!RT_SUCCESS(rc))
729 {
730 WARN(("vboxVrListSubstNoJoin failed!"));
731 rc = VERR_NO_MEMORY;
732 break;
733 }
734
735 if (!VBoxVrListIsEmpty(&DiffList))
736 {
737 vboxVrListAddNonintersected(pList, &DiffList);
738 fNeedRectreate = true;
739 fChanged = true;
740 }
741
742 Assert(VBoxVrListIsEmpty(&DiffList));
743 }
744
745 if (pListRects)
746 RTMemFree(pListRects);
747
748 Assert(VBoxVrListIsEmpty(&DiffList) || rc != VINF_SUCCESS);
749 VBoxVrListClear(&DiffList);
750
751 if (fChanged)
752 vboxVrListJoinRects(pList);
753
754 *pfChanged = fChanged;
755
756 return VINF_SUCCESS;
757}
758
759VBOXVREGDECL(int) VBoxVrListRectsGet(PVBOXVR_LIST pList, uint32_t cRects, RTRECT * aRects)
760{
761 if (cRects < VBoxVrListRectsCount(pList))
762 return VERR_BUFFER_OVERFLOW;
763
764 uint32_t i = 0;
765 for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext, ++i)
766 {
767 PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
768 aRects[i] = pReg1->Rect;
769 }
770 return VINF_SUCCESS;
771}
772
773VBOXVREGDECL(int) VBoxVrListCmp(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
774{
775 int cTmp = pList1->cEntries - pList2->cEntries;
776 if (cTmp)
777 return cTmp;
778
779 PVBOXVR_REG pReg1, pReg2;
780
781 for (pReg1 = RTListNodeGetNext(&pList1->ListHead, VBOXVR_REG, ListEntry),
782 pReg2 = RTListNodeGetNext(&pList2->ListHead, VBOXVR_REG, ListEntry);
783 !RTListNodeIsDummy(&pList1->ListHead, pReg1, VBOXVR_REG, ListEntry);
784 pReg1 = RT_FROM_MEMBER(pReg1->ListEntry.pNext, VBOXVR_REG, ListEntry),
785 pReg2 = RT_FROM_MEMBER(pReg2->ListEntry.pNext, VBOXVR_REG, ListEntry))
786 {
787 Assert(!RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
788 cTmp = VBoxRectCmp(&pReg1->Rect, &pReg2->Rect);
789 if (cTmp)
790 return cTmp;
791 }
792 Assert(RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
793 return 0;
794}
795
796VBOXVREGDECL(void) VBoxVrCompositorInit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_ENTRY_REMOVED pfnEntryRemoved)
797{
798 RTListInit(&pCompositor->List);
799 pCompositor->pfnEntryRemoved = pfnEntryRemoved;
800}
801
802VBOXVREGDECL(void) VBoxVrCompositorTerm(PVBOXVR_COMPOSITOR pCompositor)
803{
804 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
805 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
806 {
807 VBoxVrCompositorEntryRemove(pCompositor, pEntry);
808 }
809}
810
811DECLINLINE(void) vboxVrCompositorEntryAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
812{
813 RTListPrepend(&pCompositor->List, &pEntry->Node);
814}
815
816DECLINLINE(void) vboxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
817{
818 RTListNodeRemove(&pEntry->Node);
819 if (pCompositor->pfnEntryRemoved)
820 pCompositor->pfnEntryRemoved(pCompositor, pEntry, pReplacingEntry);
821}
822
823VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry)
824{
825 VBoxVrListInit(&pEntry->Vr);
826}
827
828VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
829{
830 if (!VBoxVrCompositorEntryIsInList(pEntry))
831 return false;
832 VBoxVrListClear(&pEntry->Vr);
833 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
834 return true;
835}
836
837static int vboxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
838{
839 bool fChanged;
840 int rc = VBoxVrListRectsSubst(&pEntry->Vr, cRects, paRects, &fChanged);
841 if (RT_SUCCESS(rc))
842 {
843 if (VBoxVrListIsEmpty(&pEntry->Vr))
844 {
845 Assert(fChanged);
846 vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
847 }
848 if (pfChanged)
849 *pfChanged = false;
850 return VINF_SUCCESS;
851 }
852
853 WARN(("VBoxVrListRectsSubst failed, rc %d", rc));
854 return rc;
855}
856
857VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, uint32_t *pfChangeFlags)
858{
859 bool fOthersChanged = false, fCurChanged = false, fEntryChanged = false, fEntryInList = false, fEntryReplaces = false;
860 PVBOXVR_COMPOSITOR_ENTRY pCur;
861 int rc = VINF_SUCCESS;
862
863 if (!cRects)
864 {
865 if (pfChangeFlags)
866 *pfChangeFlags = 0;
867 return VINF_SUCCESS;
868 }
869
870 if (pEntry)
871 {
872 fEntryInList = VBoxVrCompositorEntryIsInList(pEntry);
873 rc = VBoxVrListRectsAdd(&pEntry->Vr, cRects, paRects, &fEntryChanged);
874 if (RT_SUCCESS(rc))
875 {
876 if (VBoxVrListIsEmpty(&pEntry->Vr))
877 {
878 WARN(("Empty rectangles passed in, is it expected?"));
879 if (pfChangeFlags)
880 *pfChangeFlags = 0;
881 return VINF_SUCCESS;
882 }
883 }
884 else
885 {
886 WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
887 return rc;
888 }
889
890 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
891 }
892
893 RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
894 {
895 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
896 if (pCur == pEntry)
897 {
898 Assert(fEntryInList);
899 }
900 else
901 {
902 if (pEntry && !VBoxVrListCmp(&pCur->Vr, &pEntry->Vr))
903 {
904 VBoxVrListClear(&pCur->Vr);
905 vboxVrCompositorEntryRemove(pCompositor, pCur, pEntry);
906 fEntryReplaces = true;
907 }
908 else
909 {
910 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, &fCurChanged);
911 if (RT_SUCCESS(rc))
912 fOthersChanged |= fCurChanged;
913 else
914 {
915 WARN(("vboxVrCompositorEntryRegionsSubst failed, rc %d", rc));
916 return rc;
917 }
918 }
919 }
920 }
921
922 AssertRC(rc);
923
924 if (pEntry && !fEntryInList)
925 {
926 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
927 vboxVrCompositorEntryAdd(pCompositor, pEntry);
928 }
929
930 if (pfChangeFlags)
931 {
932 uint32_t fFlags = 0;
933 if (fOthersChanged)
934 fFlags = VBOXVR_COMPOSITOR_CF_ENTRIES_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_COMPOSITED_REGIONS_CHANGED;
935 else if (fEntryReplaces)
936 {
937 Assert(fEntryChanged);
938 fFlags = VBOXVR_COMPOSITOR_CF_ENTRIES_REGIONS_CHANGED;
939 }
940 else if (fEntryChanged)
941 fFlags = VBOXVR_COMPOSITOR_CF_ENTRIES_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_COMPOSITED_REGIONS_CHANGED;
942 if (!fEntryInList)
943 fFlags |= VBOXVR_COMPOSITOR_CF_ENTRY_ADDED;
944
945 *pfChangeFlags = fFlags;
946 }
947
948 return VINF_SUCCESS;
949}
950
951VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
952{
953 if (!pEntry)
954 {
955 WARN(("VBoxVrCompositorEntryRegionsSubst called with zero entry, unsupported!"));
956 if (pfChanged)
957 *pfChanged = false;
958 return VERR_INVALID_PARAMETER;
959 }
960
961 if (VBoxVrListIsEmpty(&pEntry->Vr))
962 {
963 if (pfChanged)
964 *pfChanged = false;
965 return VINF_SUCCESS;
966
967 }
968
969 int rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pEntry, cRects, paRects, pfChanged);
970 if (RT_SUCCESS(rc))
971 return VINF_SUCCESS;
972
973 WARN(("pfChanged failed, rc %d", rc));
974 return rc;
975}
976
977VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
978{
979 if (!pEntry)
980 {
981 WARN(("VBoxVrCompositorEntryRegionsSet called with zero entry, unsupported!"));
982 if (pfChanged)
983 *pfChanged = false;
984 return VERR_INVALID_PARAMETER;
985 }
986
987 bool fChanged = false, fCurChanged = false;
988 uint32_t fChangeFlags = 0;
989 int rc;
990 fCurChanged = VBoxVrCompositorEntryRemove(pCompositor, pEntry);
991 fChanged |= fCurChanged;
992
993 rc = VBoxVrCompositorEntryRegionsAdd(pCompositor, pEntry, cRects, paRects, &fChangeFlags);
994 if (RT_SUCCESS(rc))
995 fChanged |= !!fChangeFlags;
996 else
997 {
998 WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
999 return rc;
1000 }
1001
1002 AssertRC(rc);
1003
1004 if (pfChanged)
1005 *pfChanged = fChanged;
1006 return VINF_SUCCESS;
1007}
1008
1009VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, int32_t x, int32_t y, bool *pfChanged)
1010{
1011 if (!pEntry)
1012 {
1013 WARN(("VBoxVrCompositorEntryRegionsTranslate called with zero entry, unsupported!"));
1014 if (pfChanged)
1015 *pfChanged = false;
1016 return VERR_INVALID_PARAMETER;
1017 }
1018
1019 if ((!x && !y)
1020 || !VBoxVrCompositorEntryIsInList(pEntry))
1021 {
1022 if (pfChanged)
1023 *pfChanged = false;
1024 return VINF_SUCCESS;
1025 }
1026
1027 VBoxVrListTranslate(&pEntry->Vr, x, y);
1028
1029 Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
1030
1031 PVBOXVR_COMPOSITOR_ENTRY pCur;
1032 uint32_t cRects = 0;
1033 RTRECT *paRects = NULL;
1034 int rc = VINF_SUCCESS;
1035 RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
1036 {
1037 Assert(!VBoxVrListIsEmpty(&pCur->Vr));
1038
1039 if (pCur == pEntry)
1040 continue;
1041
1042 if (!paRects)
1043 {
1044 cRects = VBoxVrListRectsCount(&pEntry->Vr);
1045 Assert(cRects);
1046 paRects = (RTRECT*)RTMemAlloc(cRects * sizeof (RTRECT));
1047 if (!paRects)
1048 {
1049 WARN(("RTMemAlloc failed!"));
1050 rc = VERR_NO_MEMORY;
1051 break;
1052 }
1053
1054 rc = VBoxVrListRectsGet(&pEntry->Vr, cRects, paRects);
1055 if (!RT_SUCCESS(rc))
1056 {
1057 WARN(("VBoxVrListRectsGet failed! rc %d", rc));
1058 break;
1059 }
1060 }
1061
1062 rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, NULL);
1063 if (!RT_SUCCESS(rc))
1064 {
1065 WARN(("vboxVrCompositorEntryRegionsSubst failed! rc %d", rc));
1066 break;
1067 }
1068 }
1069
1070 if (pfChanged)
1071 *pfChanged = true;
1072
1073 if (paRects)
1074 RTMemFree(paRects);
1075
1076 return rc;
1077}
1078
1079VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
1080{
1081 PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
1082 RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
1083 {
1084 if (!pfnVisitor(pCompositor, pEntry, pvVisitor))
1085 return;
1086 }
1087}
1088
1089
1090
1091#define VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED UINT32_MAX
1092
1093static int crVrScrCompositorRectsAssignBuffer(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRects)
1094{
1095 Assert(cRects);
1096
1097 if (pCompositor->cRectsBuffer >= cRects)
1098 {
1099 pCompositor->cRects = cRects;
1100 return VINF_SUCCESS;
1101 }
1102
1103 if (pCompositor->cRectsBuffer)
1104 {
1105 Assert(pCompositor->paSrcRects);
1106 RTMemFree(pCompositor->paSrcRects);
1107 Assert(pCompositor->paDstRects);
1108 RTMemFree(pCompositor->paDstRects);
1109 }
1110
1111 pCompositor->paSrcRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paSrcRects) * cRects);
1112 if (pCompositor->paSrcRects)
1113 {
1114 pCompositor->paDstRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstRects) * cRects);
1115 if (pCompositor->paDstRects)
1116 {
1117 pCompositor->cRects = cRects;
1118 pCompositor->cRectsBuffer = cRects;
1119 return VINF_SUCCESS;
1120 }
1121 else
1122 {
1123 crWarning("RTMemAlloc failed!");
1124 RTMemFree(pCompositor->paSrcRects);
1125 pCompositor->paSrcRects = NULL;
1126 }
1127 }
1128 else
1129 {
1130 crWarning("RTMemAlloc failed!");
1131 pCompositor->paDstRects = NULL;
1132 }
1133
1134 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1135 pCompositor->cRectsBuffer = 0;
1136
1137 return VERR_NO_MEMORY;
1138}
1139
1140static void crVrScrCompositorRectsInvalidate(PVBOXVR_SCR_COMPOSITOR pCompositor)
1141{
1142 pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
1143}
1144
1145static DECLCALLBACK(bool) crVrScrCompositorRectsCounterCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor)
1146{
1147 uint32_t* pCounter = (uint32_t*)pvVisitor;
1148 Assert(VBoxVrListRectsCount(&pEntry->Vr));
1149 *pCounter += VBoxVrListRectsCount(&pEntry->Vr);
1150 return true;
1151}
1152
1153typedef struct VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER
1154{
1155 PRTRECT paSrcRects;
1156 PRTRECT paDstRects;
1157 uint32_t cRects;
1158} VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER, *PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER;
1159
1160static DECLCALLBACK(bool) crVrScrCompositorRectsAssignerCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
1161{
1162 PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER pData = (PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER)pvVisitor;
1163 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
1164 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
1165 pEntry->paSrcRects = pData->paSrcRects;
1166 pEntry->paDstRects = pData->paDstRects;
1167 uint32_t cRects = VBoxVrListRectsCount(&pCEntry->Vr);
1168 Assert(cRects);
1169 Assert(cRects >= pData->cRects);
1170 int rc = VBoxVrListRectsGet(&pCEntry->Vr, cRects, pEntry->paDstRects);
1171 AssertRC(rc);
1172 if (pCompositor->StretchX >= 1. && pCompositor->StretchY >= 1. /* <- stretching can not zero some rects */
1173 && !pEntry->Pos.x && !pEntry->Pos.y)
1174 {
1175 memcpy(pEntry->paSrcRects, pEntry->paDstRects, cRects * sizeof (*pEntry->paSrcRects));
1176 }
1177 else
1178 {
1179 for (uint32_t i = 0; i < cRects; ++i)
1180 {
1181 pEntry->paSrcRects[i].xLeft = (int32_t)((pEntry->paDstRects[i].xLeft - pEntry->Pos.x) * pCompositor->StretchX);
1182 pEntry->paSrcRects[i].yTop = (int32_t)((pEntry->paDstRects[i].yTop - pEntry->Pos.y) * pCompositor->StretchY);
1183 pEntry->paSrcRects[i].xRight = (int32_t)((pEntry->paDstRects[i].xRight - pEntry->Pos.x) * pCompositor->StretchX);
1184 pEntry->paSrcRects[i].yBottom = (int32_t)((pEntry->paDstRects[i].yBottom - pEntry->Pos.y) * pCompositor->StretchY);
1185 }
1186
1187 bool canZeroX = (pCompositor->StretchX < 1);
1188 bool canZeroY = (pCompositor->StretchY < 1);
1189 if (canZeroX && canZeroY)
1190 {
1191 /* filter out zero rectangles*/
1192 uint32_t iOrig, iNew;
1193 for (iOrig = 0, iNew = 0; iOrig < cRects; ++iOrig)
1194 {
1195 PRTRECT pOrigRect = &pEntry->paSrcRects[iOrig];
1196 if (pOrigRect->xLeft == pOrigRect->xRight
1197 || pOrigRect->yTop == pOrigRect->yBottom)
1198 continue;
1199
1200 if (iNew != iOrig)
1201 {
1202 PRTRECT pNewRect = &pEntry->paSrcRects[iNew];
1203 *pNewRect = *pOrigRect;
1204 }
1205
1206 ++iNew;
1207 }
1208
1209 Assert(iNew <= iOrig);
1210
1211 uint32_t cDiff = iOrig - iNew;
1212
1213 if (cDiff)
1214 {
1215 pCompositor->cRects -= cDiff;
1216 cRects -= cDiff;
1217 }
1218 }
1219 }
1220
1221 pEntry->cRects = cRects;
1222 pData->paDstRects += cRects;
1223 pData->paSrcRects += cRects;
1224 pData->cRects -= cRects;
1225 return true;
1226}
1227
1228static int crVrScrCompositorRectsCheckInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
1229{
1230 if (pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED)
1231 return VINF_SUCCESS;
1232
1233 uint32_t cRects = 0;
1234 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsCounterCb, &cRects);
1235
1236 if (!cRects)
1237 {
1238 pCompositor->cRects = 0;
1239 return VINF_SUCCESS;
1240 }
1241
1242 int rc = crVrScrCompositorRectsAssignBuffer(pCompositor, cRects);
1243 if (!RT_SUCCESS(rc))
1244 return rc;
1245
1246 VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER AssignerData;
1247 AssignerData.paSrcRects = pCompositor->paSrcRects;
1248 AssignerData.paDstRects = pCompositor->paDstRects;
1249 AssignerData.cRects = pCompositor->cRects;
1250 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsAssignerCb, &AssignerData);
1251 Assert(!AssignerData.cRects);
1252 return VINF_SUCCESS;
1253}
1254
1255
1256static int crVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1257{
1258 uint32_t fChangedFlags = 0;
1259 int rc = VBoxVrCompositorEntryRegionsAdd(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChangedFlags);
1260 if (!RT_SUCCESS(rc))
1261 {
1262 crWarning("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc);
1263 return rc;
1264 }
1265
1266 if (fChangedFlags & VBOXVR_COMPOSITOR_CF_COMPOSITED_REGIONS_CHANGED)
1267 {
1268 crVrScrCompositorRectsInvalidate(pCompositor);
1269 }
1270
1271 CrVrScrCompositorEntrySetChanged(pEntry, true);
1272
1273 if (pfChanged)
1274 *pfChanged = !!fChangedFlags;
1275 return VINF_SUCCESS;
1276}
1277
1278static int crVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
1279{
1280 bool fChanged;
1281 int rc = VBoxVrCompositorEntryRegionsSet(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
1282 if (!RT_SUCCESS(rc))
1283 {
1284 crWarning("VBoxVrCompositorEntryRegionsSet failed, rc %d", rc);
1285 return rc;
1286 }
1287
1288 if (fChanged)
1289 {
1290 crVrScrCompositorRectsInvalidate(pCompositor);
1291 }
1292
1293 CrVrScrCompositorEntrySetChanged(pEntry, true);
1294
1295 if (pfChanged)
1296 *pfChanged = fChanged;
1297 return VINF_SUCCESS;
1298}
1299
1300static int crVrScrCompositorEntryPositionSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, bool *pfChanged)
1301{
1302 if (pEntry && (pEntry->Pos.x != pPos->x || pEntry->Pos.y != pPos->y))
1303 {
1304 int rc = VBoxVrCompositorEntryRegionsTranslate(&pCompositor->Compositor, &pEntry->Ce, pPos->x - pEntry->Pos.x, pPos->y - pEntry->Pos.y, pfChanged);
1305 if (!RT_SUCCESS(rc))
1306 {
1307 crWarning("VBoxVrCompositorEntryRegionsTranslate failed rc %d", rc);
1308 return rc;
1309 }
1310
1311 if (VBoxVrCompositorEntryIsInList(&pEntry->Ce))
1312 {
1313 crVrScrCompositorRectsInvalidate(pCompositor);
1314 }
1315
1316 pEntry->Pos = *pPos;
1317 CrVrScrCompositorEntrySetChanged(pEntry, true);
1318 }
1319 return VINF_SUCCESS;
1320}
1321
1322VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions)
1323{
1324 int rc;
1325 if (pPos)
1326 {
1327 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
1328 if (!RT_SUCCESS(rc))
1329 {
1330 crWarning("RegionsAdd: crVrScrCompositorEntryPositionSet failed rc %d", rc);
1331 return rc;
1332 }
1333 }
1334
1335 rc = crVrScrCompositorEntryRegionsAdd(pCompositor, pEntry, cRegions, paRegions, NULL);
1336 if (!RT_SUCCESS(rc))
1337 {
1338 crWarning("crVrScrCompositorEntryRegionsAdd failed, rc %d", rc);
1339 return rc;
1340 }
1341
1342 return VINF_SUCCESS;
1343}
1344
1345VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions)
1346{
1347 int rc = CrVrScrCompositorEntryRemove(pCompositor, pEntry);
1348 if (!RT_SUCCESS(rc))
1349 {
1350 crWarning("RegionsSet: CrVrScrCompositorEntryRemove failed rc %d", rc);
1351 return rc;
1352 }
1353
1354 if (pPos)
1355 {
1356 rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
1357 if (!RT_SUCCESS(rc))
1358 {
1359 crWarning("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc);
1360 return rc;
1361 }
1362 }
1363
1364 rc = crVrScrCompositorEntryRegionsSet(pCompositor, pEntry, cRegions, paRegions, NULL);
1365 if (!RT_SUCCESS(rc))
1366 {
1367 crWarning("crVrScrCompositorEntryRegionsSet failed, rc %d", rc);
1368 return rc;
1369 }
1370
1371 return VINF_SUCCESS;
1372}
1373
1374VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos)
1375{
1376 int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
1377 if (!RT_SUCCESS(rc))
1378 {
1379 crWarning("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc);
1380 return rc;
1381 }
1382 return VINF_SUCCESS;
1383}
1384
1385/* regions are valid until the next CrVrScrCompositor call */
1386VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
1387{
1388 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
1389 if (!RT_SUCCESS(rc))
1390 {
1391 crWarning("crVrScrCompositorRectsCheckInit failed, rc %d", rc);
1392 return rc;
1393 }
1394
1395 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
1396
1397 *pcRegions = pEntry->cRects;
1398 if (ppaSrcRegions)
1399 *ppaSrcRegions = pEntry->paSrcRects;
1400 if (ppaDstRegions)
1401 *ppaDstRegions = pEntry->paDstRects;
1402
1403 return VINF_SUCCESS;
1404}
1405
1406VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
1407{
1408 if (!VBoxVrCompositorEntryRemove(&pCompositor->Compositor, &pEntry->Ce))
1409 return VINF_SUCCESS;
1410
1411 crVrScrCompositorRectsInvalidate(pCompositor);
1412 return VINF_SUCCESS;
1413}
1414
1415VBOXVREGDECL(int) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
1416{
1417 memset(pCompositor, 0, sizeof (*pCompositor));
1418 int rc = RTCritSectInit(&pCompositor->CritSect);
1419 if (RT_SUCCESS(rc))
1420 {
1421 VBoxVrCompositorInit(&pCompositor->Compositor, NULL);
1422 pCompositor->StretchX = 1.0;
1423 pCompositor->StretchY = 1.0;
1424 return VINF_SUCCESS;
1425 }
1426 else
1427 {
1428 crWarning("RTCritSectInit failed rc %d", rc);
1429 }
1430 return rc;
1431}
1432
1433VBOXVREGDECL(void) CrVrScrCompositorTerm(PVBOXVR_SCR_COMPOSITOR pCompositor)
1434{
1435 VBoxVrCompositorTerm(&pCompositor->Compositor);
1436 if (pCompositor->paDstRects)
1437 RTMemFree(pCompositor->paDstRects);
1438 if (pCompositor->paSrcRects)
1439 RTMemFree(pCompositor->paSrcRects);
1440
1441 RTCritSectDelete(&pCompositor->CritSect);
1442}
1443
1444
1445static DECLCALLBACK(bool) crVrScrCompositorEntrySetAllChangedCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
1446{
1447 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
1448 CrVrScrCompositorEntrySetChanged(pEntry, !!pvVisitor);
1449 return true;
1450}
1451
1452VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged)
1453{
1454 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorEntrySetAllChangedCb, (void*)fChanged);
1455}
1456
1457VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY)
1458{
1459 pCompositor->StretchX = StretchX;
1460 pCompositor->StretchY = StretchY;
1461 crVrScrCompositorRectsInvalidate(pCompositor);
1462 CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
1463}
1464
1465/* regions are valid until the next CrVrScrCompositor call */
1466VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
1467{
1468 int rc = crVrScrCompositorRectsCheckInit(pCompositor);
1469 if (!RT_SUCCESS(rc))
1470 {
1471 crWarning("crVrScrCompositorRectsCheckInit failed, rc %d", rc);
1472 return rc;
1473 }
1474
1475 Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
1476
1477 *pcRegions = pCompositor->cRects;
1478 if (ppaSrcRegions)
1479 *ppaSrcRegions = pCompositor->paSrcRects;
1480 if (ppaDstRegions)
1481 *ppaDstRegions = pCompositor->paDstRects;
1482
1483 return VINF_SUCCESS;
1484}
1485
1486typedef struct VBOXVR_SCR_COMPOSITOR_VISITOR_CB
1487{
1488 PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor;
1489 void *pvVisitor;
1490} VBOXVR_SCR_COMPOSITOR_VISITOR_CB, *PVBOXVR_SCR_COMPOSITOR_VISITOR_CB;
1491
1492static DECLCALLBACK(bool) crVrScrCompositorVisitCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
1493{
1494 PVBOXVR_SCR_COMPOSITOR_VISITOR_CB pData = (PVBOXVR_SCR_COMPOSITOR_VISITOR_CB)pvVisitor;
1495 PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
1496 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
1497 return pData->pfnVisitor(pCompositor, pEntry, pData->pvVisitor);
1498}
1499
1500VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
1501{
1502 VBOXVR_SCR_COMPOSITOR_VISITOR_CB Data;
1503 Data.pfnVisitor = pfnVisitor;
1504 Data.pvVisitor = pvVisitor;
1505 VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorVisitCb, &Data);
1506}
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