vreg.cpp revision 7b6926b2bf44f326f40e1d9d1ce33a4dff0a2c67
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync/* $Id$ */
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync/** @file
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * Visible Regions processing API implementation
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync */
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync/*
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * Copyright (C) 2012 Oracle Corporation
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync *
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * available from http://www.virtualbox.org. This file is free software;
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync */
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <cr_vreg.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <iprt/err.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <iprt/assert.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <iprt/asm.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <cr_error.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#define WARN(_m) do { crWarning _m ; } while (0)
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#ifndef IN_RING0
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include <iprt/memcache.h>
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync#ifndef VBOXVDBG_VR_LAL_DISABLE
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsyncstatic RTMEMCACHE g_VBoxVrLookasideList;
154e1d5579ca6c8bee571a8d1ced5d76a0234030vboxsync#define vboxVrRegLaAlloc(_c) RTMemCacheAlloc((_c))
154e1d5579ca6c8bee571a8d1ced5d76a0234030vboxsync#define vboxVrRegLaFree(_c, _e) RTMemCacheFree((_c), (_e))
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsyncDECLINLINE(int) vboxVrLaCreate(RTMEMCACHE *pCache, size_t cbElement)
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync{
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync int rc = RTMemCacheCreate(pCache, cbElement,
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync 0, /* size_t cbAlignment */
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync UINT32_MAX, /* uint32_t cMaxObjects */
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync NULL, /* PFNMEMCACHECTOR pfnCtor*/
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync NULL, /* PFNMEMCACHEDTOR pfnDtor*/
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync NULL, /* void *pvUser*/
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync 0 /* uint32_t fFlags*/
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync );
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync if (!RT_SUCCESS(rc))
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync {
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync WARN(("RTMemCacheCreate failed rc %d", rc));
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync return rc;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync }
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync return VINF_SUCCESS;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync}
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync#define vboxVrLaDestroy(_c) RTMemCacheDestroy((_c))
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync#endif
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync#else
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# ifdef RT_OS_WINDOWS
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync# ifdef PAGE_SIZE
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# undef PAGE_SIZE
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# endif
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# ifdef PAGE_SHIFT
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# undef PAGE_SHIFT
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync# endif
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# define VBOX_WITH_WORKAROUND_MISSING_PACK
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# if (_MSC_VER >= 1400) && !defined(VBOX_WITH_PATCHED_DDK)
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync# define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync# define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync# pragma warning(disable : 4163)
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# pragma warning(disable : 4103)
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# endif
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# include <ntddk.h>
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync# pragma warning(default : 4163)
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# pragma pack()
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# pragma warning(default : 4103)
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync# endif
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# undef _InterlockedExchange
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# undef _InterlockedExchangeAdd
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync# undef _InterlockedCompareExchange
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# undef _InterlockedAddLargeStatistic
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# undef _interlockedbittestandset
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync# undef _interlockedbittestandreset
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync# undef _interlockedbittestandset64
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# undef _interlockedbittestandreset64
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync# else
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync# include <ntddk.h>
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync# endif
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync#ifndef VBOXVDBG_VR_LAL_DISABLE
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsyncstatic LOOKASIDE_LIST_EX g_VBoxVrLookasideList;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync#define vboxVrRegLaAlloc(_c) ExAllocateFromLookasideListEx(&(_c))
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync#define vboxVrRegLaFree(_c, _e) ExFreeToLookasideListEx(&(_c), (_e))
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync#define VBOXWDDMVR_MEMTAG 'vDBV'
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsyncDECLINLINE(int) vboxVrLaCreate(LOOKASIDE_LIST_EX *pCache, size_t cbElement)
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync{
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync NTSTATUS Status = ExInitializeLookasideListEx(pCache,
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync NULL, /* PALLOCATE_FUNCTION_EX Allocate */
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync NULL, /* PFREE_FUNCTION_EX Free */
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync NonPagedPool,
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync 0, /* ULONG Flags */
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync cbElement,
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync VBOXWDDMVR_MEMTAG,
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync 0 /* USHORT Depth - reserved, must be null */
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync );
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync if (!NT_SUCCESS(Status))
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync {
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync WARN(("ExInitializeLookasideListEx failed, Status (0x%x)", Status));
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync return VERR_GENERAL_FAILURE;
cb13ee8e628d04a773894bf4f9e8047d74f2ee21vboxsync }
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync return VINF_SUCCESS;
40af749e457b7d704c869ea986a042f0d4b6e09avboxsync}
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync#define vboxVrLaDestroy(_c) ExDeleteLookasideListEx(&(_c))
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#endif
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync# else
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync# error "port me!"
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync# endif
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#endif
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#ifdef DEBUG_misha
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync//# define VBOXVDBG_VR_LAL_DISABLE
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#endif
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#ifndef VBOXVDBG_VR_LAL_DISABLE
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsyncstatic volatile int32_t g_cVBoxVrInits = 0;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#endif
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsyncstatic PVBOXVR_REG vboxVrRegCreate()
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync{
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#ifndef VBOXVDBG_VR_LAL_DISABLE
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync PVBOXVR_REG pReg = (PVBOXVR_REG)vboxVrRegLaAlloc(g_VBoxVrLookasideList);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync if (!pReg)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync WARN(("ExAllocateFromLookasideListEx failed!"));
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync }
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync return pReg;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#else
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync return (PVBOXVR_REG)RTMemAlloc(sizeof (VBOXVR_REG));
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync#endif
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync}
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsyncstatic void vboxVrRegTerm(PVBOXVR_REG pReg)
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync{
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync#ifndef VBOXVDBG_VR_LAL_DISABLE
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync vboxVrRegLaFree(g_VBoxVrLookasideList, pReg);
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync#else
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync RTMemFree(pReg);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync#endif
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync}
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsyncVBOXVREGDECL(void) VBoxVrListClear(PVBOXVR_LIST pList)
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync{
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync PVBOXVR_REG pReg, pRegNext;
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync RTListForEachSafe(&pList->ListHead, pReg, pRegNext, VBOXVR_REG, ListEntry)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync {
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync vboxVrRegTerm(pReg);
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync }
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync VBoxVrListInit(pList);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync}
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync#define VBOXVR_MEMTAG 'vDBV'
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsyncVBOXVREGDECL(int) VBoxVrInit()
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync{
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync int32_t cNewRefs = ASMAtomicIncS32(&g_cVBoxVrInits);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync Assert(cNewRefs >= 1);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync Assert(cNewRefs == 1); /* <- debugging */
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync if (cNewRefs > 1)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync return VINF_SUCCESS;
6cb96ab7d4ba4dab39ef47e8d7c3dcfbf7582959vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync#ifndef VBOXVDBG_VR_LAL_DISABLE
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync int rc = vboxVrLaCreate(&g_VBoxVrLookasideList, sizeof (VBOXVR_REG));
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync if (!RT_SUCCESS(rc))
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync WARN(("ExInitializeLookasideListEx failed, rc (%d)", rc));
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync return rc;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync }
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#endif
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync return VINF_SUCCESS;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync}
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsyncVBOXVREGDECL(void) VBoxVrTerm()
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync{
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync int32_t cNewRefs = ASMAtomicDecS32(&g_cVBoxVrInits);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync Assert(cNewRefs >= 0);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync if (cNewRefs > 0)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync return;
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#ifndef VBOXVDBG_VR_LAL_DISABLE
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync vboxVrLaDestroy(g_VBoxVrLookasideList);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#endif
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync}
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsynctypedef DECLCALLBACK(int) FNVBOXVR_CB_COMPARATOR(const VBOXVR_REG *pReg1, const VBOXVR_REG *pReg2);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsynctypedef FNVBOXVR_CB_COMPARATOR *PFNVBOXVR_CB_COMPARATOR;
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsyncstatic DECLCALLBACK(int) vboxVrRegNonintersectedComparator(const RTRECT* pRect1, const RTRECT* pRect2)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync{
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync Assert(!VBoxRectIsIntersect(pRect1, pRect2));
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync if (pRect1->yTop != pRect2->yTop)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync return pRect1->yTop - pRect2->yTop;
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync return pRect1->xLeft - pRect2->xLeft;
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync}
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync#ifdef DEBUG_misha
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsyncstatic void vboxVrDbgListDoVerify(PVBOXVR_LIST pList)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync{
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync PVBOXVR_REG pReg1, pReg2;
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync RTListForEach(&pList->ListHead, pReg1, VBOXVR_REG, ListEntry)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync {
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync Assert(!VBoxRectIsZero(&pReg1->Rect));
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync for (RTLISTNODE *pEntry2 = pReg1->ListEntry.pNext; pEntry2 != &pList->ListHead; pEntry2 = pEntry2->pNext)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync {
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync Assert(vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync }
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync }
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync}
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync#define vboxVrDbgListVerify vboxVrDbgListDoVerify
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync#else
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync#define vboxVrDbgListVerify(_p) do {} while (0)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync#endif
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsyncstatic int vboxVrListUniteIntersection(PVBOXVR_LIST pList, PVBOXVR_LIST pIntersection);
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync#define VBOXVR_INVALID_COORD (~0U)
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsync
062b8a43e237d9e2edde03b5837d44506e35eb47vboxsyncDECLINLINE(void) vboxVrListRegAdd(PVBOXVR_LIST pList, PVBOXVR_REG pReg, PRTLISTNODE pPlace, bool fAfter)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync{
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync if (fAfter)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync RTListPrepend(pPlace, &pReg->ListEntry);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync else
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync RTListAppend(pPlace, &pReg->ListEntry);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync ++pList->cEntries;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync vboxVrDbgListVerify(pList);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync}
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsyncDECLINLINE(void) vboxVrListRegRemove(PVBOXVR_LIST pList, PVBOXVR_REG pReg)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync{
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync RTListNodeRemove(&pReg->ListEntry);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync --pList->cEntries;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync vboxVrDbgListVerify(pList);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync}
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsyncstatic void vboxVrListRegAddOrder(PVBOXVR_LIST pList, PRTLISTNODE pMemberEntry, PVBOXVR_REG pReg)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync{
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync do
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync if (pMemberEntry != &pList->ListHead)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync PVBOXVR_REG pMemberReg = PVBOXVR_REG_FROM_ENTRY(pMemberEntry);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync if (vboxVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync pMemberEntry = pMemberEntry->pNext;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync continue;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync }
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync }
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync vboxVrListRegAdd(pList, pReg, pMemberEntry, false);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync break;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync } while (1);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync}
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsyncstatic void vboxVrListAddNonintersected(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync{
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync for (PRTLISTNODE pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.pNext)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync do {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync if (pEntry1 != &pList1->ListHead)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync if (vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync pEntry1 = pEntry1->pNext;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync continue;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync }
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync }
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync vboxVrListRegRemove(pList2, pReg2);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync vboxVrListRegAdd(pList1, pReg2, pEntry1, false);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync break;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync } while (1);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync }
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync Assert(VBoxVrListIsEmpty(pList2));
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync}
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsyncstatic int vboxVrListRegIntersectSubstNoJoin(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync{
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync uint32_t topLim = VBOXVR_INVALID_COORD;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync uint32_t bottomLim = VBOXVR_INVALID_COORD;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync RTLISTNODE List;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync PVBOXVR_REG pBottomReg = NULL;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#ifdef DEBUG_misha
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync RTRECT tmpRect = pReg1->Rect;
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync vboxVrDbgListVerify(pList1);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync#endif
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync Assert(!VBoxRectIsZero(pRect2));
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync RTListInit(&List);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync if (pReg1->Rect.yTop < pRect2->yTop)
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync {
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync Assert(pRect2->yTop < pReg1->Rect.yBottom);
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync PVBOXVR_REG pRegResult = vboxVrRegCreate();
6fea4abcc6ee0f2797ac01ef79c374d506aedc02vboxsync pRegResult->Rect.yTop = pReg1->Rect.yTop;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync pRegResult->Rect.yBottom = pRect2->yTop;
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync pRegResult->Rect.xRight = pReg1->Rect.xRight;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync topLim = pRect2->yTop;
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync RTListAppend(&List, &pRegResult->ListEntry);
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync }
07db1daf0ffed7a0fe1224c296fc1e7ac40d7681vboxsync
if (pReg1->Rect.yBottom > pRect2->yBottom)
{
Assert(pRect2->yBottom > pReg1->Rect.yTop);
PVBOXVR_REG pRegResult = vboxVrRegCreate();
pRegResult->Rect.yTop = pRect2->yBottom;
pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
pRegResult->Rect.yBottom = pReg1->Rect.yBottom;
pRegResult->Rect.xRight = pReg1->Rect.xRight;
bottomLim = pRect2->yBottom;
pBottomReg = pRegResult;
}
if (pReg1->Rect.xLeft < pRect2->xLeft)
{
Assert(pRect2->xLeft < pReg1->Rect.xRight);
PVBOXVR_REG pRegResult = vboxVrRegCreate();
pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
pRegResult->Rect.xLeft = pReg1->Rect.xLeft;
pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
pRegResult->Rect.xRight = pRect2->xLeft;
RTListAppend(&List, &pRegResult->ListEntry);
}
if (pReg1->Rect.xRight > pRect2->xRight)
{
Assert(pRect2->xRight > pReg1->Rect.xLeft);
PVBOXVR_REG pRegResult = vboxVrRegCreate();
pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim;
pRegResult->Rect.xLeft = pRect2->xRight;
pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim;
pRegResult->Rect.xRight = pReg1->Rect.xRight;
RTListAppend(&List, &pRegResult->ListEntry);
}
if (pBottomReg)
RTListAppend(&List, &pBottomReg->ListEntry);
PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
vboxVrListRegRemove(pList1, pReg1);
vboxVrRegTerm(pReg1);
if (RTListIsEmpty(&List))
return VINF_SUCCESS; /* the region is covered by the pRect2 */
PRTLISTNODE pEntry = List.pNext, pNext;
for (; pEntry != &List; pEntry = pNext)
{
pNext = pEntry->pNext;
PVBOXVR_REG pReg = PVBOXVR_REG_FROM_ENTRY(pEntry);
vboxVrListRegAddOrder(pList1, pMemberEntry, pReg);
pMemberEntry = pEntry->pNext; /* the following elements should go after the given pEntry since they are ordered already */
}
return VINF_SUCCESS;
}
/* @returns Entry to be used for continuing the rectangles iterations being made currently on the callback call.
* ListHead is returned to break the current iteration
* @param ppNext specifies next reg entry to be used for iteration. the default is pReg1->ListEntry.pNext */
typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_INTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2, void *pvContext, PRTLISTNODE *ppNext);
typedef FNVBOXVR_CB_INTERSECTED_VISITOR *PFNVBOXVR_CB_INTERSECTED_VISITOR;
static void vboxVrListVisitIntersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
{
PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
PRTLISTNODE pNext1;
uint32_t iFirst2 = 0;
for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
{
pNext1 = pEntry1->pNext;
PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
for (uint32_t i = iFirst2; i < cRects; ++i)
{
const RTRECT *pRect2 = &aRects[i];
if (VBoxRectIsZero(pRect2))
continue;
if (!VBoxRectIsIntersect(&pReg1->Rect, pRect2))
continue;
/* the visitor can modify the list 1, apply necessary adjustments after it */
pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1);
if (pEntry1 == &pList1->ListHead)
break;
else
pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
}
}
}
/* @returns Entry to be iterated next. ListHead is returned to break the iteration
*
*/
typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_NONINTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext);
typedef FNVBOXVR_CB_NONINTERSECTED_VISITOR *PFNVBOXVR_CB_NONINTERSECTED_VISITOR;
static void vboxVrListVisitNonintersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_NONINTERSECTED_VISITOR pfnVisitor, void* pvVisitor)
{
PRTLISTNODE pEntry1 = pList1->ListHead.pNext;
PRTLISTNODE pNext1;
uint32_t iFirst2 = 0;
for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1)
{
PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
uint32_t i = iFirst2;
for (; i < cRects; ++i)
{
const RTRECT *pRect2 = &aRects[i];
if (VBoxRectIsZero(pRect2))
continue;
if (VBoxRectIsIntersect(&pReg1->Rect, pRect2))
break;
}
if (i == cRects)
pNext1 = pfnVisitor(pList1, pReg1, pvVisitor);
else
pNext1 = pEntry1->pNext;
}
}
static void vboxVrListJoinRectsHV(PVBOXVR_LIST pList, bool fHorizontal)
{
PRTLISTNODE pNext1, pNext2;
for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
{
PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
pNext1 = pEntry1->pNext;
for (PRTLISTNODE pEntry2 = pEntry1->pNext; pEntry2 != &pList->ListHead; pEntry2 = pNext2)
{
PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
pNext2 = pEntry2->pNext;
if (fHorizontal)
{
if (pReg1->Rect.yTop == pReg2->Rect.yTop)
{
if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
{
/* join rectangles */
vboxVrListRegRemove(pList, pReg2);
if (pReg1->Rect.yBottom > pReg2->Rect.yBottom)
{
int32_t oldRight1 = pReg1->Rect.xRight;
int32_t oldBottom1 = pReg1->Rect.yBottom;
pReg1->Rect.xRight = pReg2->Rect.xRight;
pReg1->Rect.yBottom = pReg2->Rect.yBottom;
vboxVrDbgListVerify(pList);
pReg2->Rect.xLeft = pReg1->Rect.xLeft;
pReg2->Rect.yTop = pReg1->Rect.yBottom;
pReg2->Rect.xRight = oldRight1;
pReg2->Rect.yBottom = oldBottom1;
vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
/* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
* and thus can match one of the previous rects */
pNext1 = pList->ListHead.pNext;
break;
}
else if (pReg1->Rect.yBottom < pReg2->Rect.yBottom)
{
pReg1->Rect.xRight = pReg2->Rect.xRight;
vboxVrDbgListVerify(pList);
pReg2->Rect.yTop = pReg1->Rect.yBottom;
vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2);
/* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
* and thus can match one of the previous rects */
pNext1 = pList->ListHead.pNext;
break;
}
else
{
pReg1->Rect.xRight = pReg2->Rect.xRight;
vboxVrDbgListVerify(pList);
/* reset the pNext1 since it could be the pReg2 being destroyed */
pNext1 = pEntry1->pNext;
/* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
vboxVrRegTerm(pReg2);
}
}
continue;
}
else if (pReg1->Rect.yBottom == pReg2->Rect.yBottom)
{
Assert(pReg1->Rect.yTop < pReg2->Rect.yTop); /* <- since pReg1 > pReg2 && pReg1->Rect.yTop != pReg2->Rect.yTop*/
if (pReg1->Rect.xRight == pReg2->Rect.xLeft)
{
/* join rectangles */
vboxVrListRegRemove(pList, pReg2);
pReg1->Rect.yBottom = pReg2->Rect.yTop;
vboxVrDbgListVerify(pList);
pReg2->Rect.xLeft = pReg1->Rect.xLeft;
vboxVrListRegAddOrder(pList, pNext2, pReg2);
/* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
* and thus can match one of the previous rects */
pNext1 = pList->ListHead.pNext;
break;
}
else if (pReg1->Rect.xLeft == pReg2->Rect.xRight)
{
/* join rectangles */
vboxVrListRegRemove(pList, pReg2);
pReg1->Rect.yBottom = pReg2->Rect.yTop;
vboxVrDbgListVerify(pList);
pReg2->Rect.xRight = pReg1->Rect.xRight;
vboxVrListRegAddOrder(pList, pNext2, pReg2);
/* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension
* and thus can match one of the previous rects */
pNext1 = pList->ListHead.pNext;
break;
}
continue;
}
}
else
{
if (pReg1->Rect.yBottom == pReg2->Rect.yTop)
{
if (pReg1->Rect.xLeft == pReg2->Rect.xLeft)
{
if (pReg1->Rect.xRight == pReg2->Rect.xRight)
{
/* join rects */
vboxVrListRegRemove(pList, pReg2);
pReg1->Rect.yBottom = pReg2->Rect.yBottom;
vboxVrDbgListVerify(pList);
/* reset the pNext1 since it could be the pReg2 being destroyed */
pNext1 = pEntry1->pNext;
/* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */
vboxVrRegTerm(pReg2);
continue;
}
/* no more to be done for for pReg1 */
break;
}
else if (pReg1->Rect.xRight > pReg2->Rect.xLeft)
{
/* no more to be done for for pReg1 */
break;
}
continue;
}
else if (pReg1->Rect.yBottom < pReg2->Rect.yTop)
{
/* no more to be done for for pReg1 */
break;
}
}
}
}
}
static void vboxVrListJoinRects(PVBOXVR_LIST pList)
{
vboxVrListJoinRectsHV(pList, true);
vboxVrListJoinRectsHV(pList, false);
}
typedef struct VBOXVR_CBDATA_SUBST
{
int rc;
bool fChanged;
} VBOXVR_CBDATA_SUBST, *PVBOXVR_CBDATA_SUBST;
static DECLCALLBACK(PRTLISTNODE) vboxVrListSubstNoJoinCb(PVBOXVR_LIST pList, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
{
PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
/* store the prev to get the new pNext out of it*/
PRTLISTNODE pPrev = pReg1->ListEntry.pPrev;
pData->fChanged = true;
Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
/* NOTE: the pReg1 will be invalid after the vboxVrListRegIntersectSubstNoJoin call!!! */
int rc = vboxVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2);
if (RT_SUCCESS(rc))
{
*ppNext = pPrev->pNext;
return &pList->ListHead;
}
WARN(("vboxVrListRegIntersectSubstNoJoin failed!"));
Assert(!RT_SUCCESS(rc));
pData->rc = rc;
*ppNext = &pList->ListHead;
return &pList->ListHead;
}
static int vboxVrListSubstNoJoin(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
{
*pfChanged = false;
if (VBoxVrListIsEmpty(pList))
return VINF_SUCCESS;
VBOXVR_CBDATA_SUBST Data;
Data.rc = VINF_SUCCESS;
Data.fChanged = false;
vboxVrListVisitIntersected(pList, cRects, aRects, vboxVrListSubstNoJoinCb, &Data);
if (!RT_SUCCESS(Data.rc))
{
WARN(("vboxVrListVisitIntersected failed!"));
return Data.rc;
}
*pfChanged = Data.fChanged;
return VINF_SUCCESS;
}
#if 0
static const RTRECT * vboxVrRectsOrder(uint32_t cRects, const RTRECT * aRects)
{
#ifdef DEBUG
{
for (uint32_t i = 0; i < cRects; ++i)
{
RTRECT *pRectI = &aRects[i];
for (uint32_t j = i + 1; j < cRects; ++j)
{
RTRECT *pRectJ = &aRects[j];
Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
}
}
}
#endif
RTRECT * pRects = (RTRECT *)aRects;
/* check if rects are ordered already */
for (uint32_t i = 0; i < cRects - 1; ++i)
{
RTRECT *pRect1 = &pRects[i];
RTRECT *pRect2 = &pRects[i+1];
if (vboxVrRegNonintersectedComparator(pRect1, pRect2) < 0)
continue;
WARN(("rects are unoreded!"));
if (pRects == aRects)
{
pRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cRects);
if (!pRects)
{
WARN(("RTMemAlloc failed!"));
return NULL;
}
memcpy(pRects, aRects, sizeof (RTRECT) * cRects);
}
Assert(pRects != aRects);
int j = (int)i - 1;
do {
RTRECT Tmp = *pRect1;
*pRect1 = *pRect2;
*pRect2 = Tmp;
if (j < 0)
break;
if (vboxVrRegNonintersectedComparator(pRect1, pRect1-1) > 0)
break;
pRect2 = pRect1--;
--j;
} while (1);
}
return pRects;
}
#endif
VBOXVREGDECL(void) VBoxVrListTranslate(PVBOXVR_LIST pList, int32_t x, int32_t y)
{
for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
{
PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
VBoxRectTranslate(&pReg1->Rect, x, y);
}
}
static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinNonintersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext)
{
VBOXVR_CBDATA_SUBST *pData = (VBOXVR_CBDATA_SUBST*)pvContext;
PRTLISTNODE pNext = pReg1->ListEntry.pNext;
vboxVrDbgListVerify(pList1);
vboxVrListRegRemove(pList1, pReg1);
vboxVrRegTerm(pReg1);
vboxVrDbgListVerify(pList1);
pData->fChanged = true;
return pNext;
}
static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinIntersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext)
{
PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext;
pData->fChanged = true;
vboxVrDbgListVerify(pList1);
PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2));
Assert(!VBoxRectIsZero(pRect2));
vboxVrListRegRemove(pList1, pReg1);
VBoxRectIntersect(&pReg1->Rect, pRect2);
Assert(!VBoxRectIsZero(&pReg1->Rect));
vboxVrListRegAddOrder(pList1, pMemberEntry, pReg1);
vboxVrDbgListVerify(pList1);
return &pReg1->ListEntry;
}
static int vboxVrListIntersectNoJoin(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged)
{
bool fChanged = false;
*pfChanged = false;
if (VBoxVrListIsEmpty(pList))
return VINF_SUCCESS;
if (VBoxVrListIsEmpty(pList2))
{
if (pfChanged)
*pfChanged = true;
VBoxVrListClear(pList);
return VINF_SUCCESS;
}
PRTLISTNODE pNext1;
for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1)
{
pNext1 = pEntry1->pNext;
PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
RTRECT RegRect1 = pReg1->Rect;
PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext;
for (const RTLISTNODE *pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pEntry2->pNext)
{
const VBOXVR_REG *pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2);
const RTRECT *pRect2 = &pReg2->Rect;
if (!VBoxRectIsIntersect(&RegRect1, pRect2))
continue;
if (pReg1)
{
if (!VBoxRectCmp(&pReg1->Rect, pRect2))
{
/* no change, and we can break the iteration here */
/* zero up the pReg1 to mark it as intersected (see the code after this inner loop) */
pReg1 = NULL;
break;
}
/* @todo: this can have false-alarming sometimes if the separated rects will then be joind into the original rect,
* so far this should not be a problem for VReg clients, so keep it this way for now */
fChanged = true;
/* re-use the reg entry */
vboxVrListRegRemove(pList, pReg1);
VBoxRectIntersect(&pReg1->Rect, pRect2);
Assert(!VBoxRectIsZero(&pReg1->Rect));
vboxVrListRegAddOrder(pList, pMemberEntry, pReg1);
pReg1 = NULL;
}
else
{
Assert(fChanged); /* <- should be set by the if branch above */
PVBOXVR_REG pReg = vboxVrRegCreate();
if (!pReg)
{
WARN(("vboxVrRegCreate failed!"));
return VERR_NO_MEMORY;
}
VBoxRectIntersected(&RegRect1, pRect2, &pReg->Rect);
Assert(!VBoxRectIsZero(&pReg->Rect));
vboxVrListRegAddOrder(pList, pList->ListHead.pNext, pReg);
}
}
if (pReg1)
{
/* the region has no intersections, remove it */
vboxVrListRegRemove(pList, pReg1);
vboxVrRegTerm(pReg1);
fChanged = true;
}
}
*pfChanged = fChanged;
return VINF_SUCCESS;
}
VBOXVREGDECL(int) VBoxVrListIntersect(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged)
{
if (pfChanged)
*pfChanged = false;
int rc = vboxVrListIntersectNoJoin(pList, pList2, pfChanged);
if (!RT_SUCCESS(rc))
{
WARN(("vboxVrListSubstNoJoin failed!"));
return rc;
}
if (*pfChanged)
{
vboxVrListJoinRects(pList);
}
return rc;
}
VBOXVREGDECL(int) VBoxVrListRectsIntersect(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
{
if (pfChanged)
*pfChanged = false;
if (VBoxVrListIsEmpty(pList))
return VINF_SUCCESS;
if (!cRects)
{
if (pfChanged)
*pfChanged = true;
VBoxVrListClear(pList);
return VINF_SUCCESS;
}
/* we perform intersection using lists because the algorythm axpects the rects to be non-intersected,
* which list guaranties to us */
VBOXVR_LIST TmpList;
VBoxVrListInit(&TmpList);
int rc = VBoxVrListRectsAdd(&TmpList, cRects, aRects, NULL);
if (RT_SUCCESS(rc))
{
rc = VBoxVrListIntersect(pList, &TmpList, pfChanged);
if (!RT_SUCCESS(rc))
{
WARN(("VBoxVrListIntersect failed! rc %d", rc));
}
}
else
{
WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
}
VBoxVrListClear(&TmpList);
return rc;
}
VBOXVREGDECL(int) VBoxVrListRectsSubst(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
{
#if 0
const RTRECT * pRects = vboxVrRectsOrder(cRects, aRects);
if (!pRects)
{
WARN(("vboxVrRectsOrder failed!"));
return VERR_NO_MEMORY;
}
#endif
int rc = vboxVrListSubstNoJoin(pList, cRects, aRects, pfChanged);
if (!RT_SUCCESS(rc))
{
WARN(("vboxVrListSubstNoJoin failed!"));
goto done;
}
if (!*pfChanged)
goto done;
vboxVrListJoinRects(pList);
done:
#if 0
if (pRects != aRects)
RTMemFree(pRects);
#endif
return rc;
}
VBOXVREGDECL(int) VBoxVrListRectsSet(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
{
if (pfChanged)
*pfChanged = false;
if (!cRects && VBoxVrListIsEmpty(pList))
{
return VINF_SUCCESS;
}
/* @todo: fChanged will have false alarming here, fix if needed */
VBoxVrListClear(pList);
int rc = VBoxVrListRectsAdd(pList, cRects, aRects, NULL);
if (!RT_SUCCESS(rc))
{
WARN(("VBoxVrListRectsSet failed rc %d", rc));
return rc;
}
if (pfChanged)
*pfChanged = true;
return VINF_SUCCESS;
}
VBOXVREGDECL(int) VBoxVrListRectsAdd(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged)
{
uint32_t cCovered = 0;
if (pfChanged)
*pfChanged = false;
#if 0
#ifdef DEBUG
{
for (uint32_t i = 0; i < cRects; ++i)
{
RTRECT *pRectI = &aRects[i];
for (uint32_t j = i + 1; j < cRects; ++j)
{
RTRECT *pRectJ = &aRects[j];
Assert(!VBoxRectIsIntersect(pRectI, pRectJ));
}
}
}
#endif
#endif
/* early sort out the case when there are no new rects */
for (uint32_t i = 0; i < cRects; ++i)
{
if (VBoxRectIsZero(&aRects[i]))
{
cCovered++;
continue;
}
for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext)
{
PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
if (VBoxRectIsCoveres(&pReg1->Rect, &aRects[i]))
{
cCovered++;
break;
}
}
}
if (cCovered == cRects)
return VINF_SUCCESS;
/* rects are not covered, need to go the slow way */
VBOXVR_LIST DiffList;
VBoxVrListInit(&DiffList);
RTRECT * pListRects = NULL;
uint32_t cAllocatedRects = 0;
bool fNeedRectreate = true;
bool fChanged = false;
int rc = VINF_SUCCESS;
for (uint32_t i = 0; i < cRects; ++i)
{
if (VBoxRectIsZero(&aRects[i]))
continue;
PVBOXVR_REG pReg = vboxVrRegCreate();
if (!pReg)
{
WARN(("vboxVrRegCreate failed!"));
rc = VERR_NO_MEMORY;
break;
}
pReg->Rect = aRects[i];
uint32_t cListRects = VBoxVrListRectsCount(pList);
if (!cListRects)
{
vboxVrListRegAdd(pList, pReg, &pList->ListHead, false);
fChanged = true;
continue;
}
else
{
Assert(VBoxVrListIsEmpty(&DiffList));
vboxVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, false);
}
if (cAllocatedRects < cListRects)
{
cAllocatedRects = cListRects + cRects;
Assert(fNeedRectreate);
if (pListRects)
RTMemFree(pListRects);
pListRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cAllocatedRects);
if (!pListRects)
{
WARN(("RTMemAlloc failed!"));
rc = VERR_NO_MEMORY;
break;
}
}
if (fNeedRectreate)
{
rc = VBoxVrListRectsGet(pList, cListRects, pListRects);
Assert(rc == VINF_SUCCESS);
fNeedRectreate = false;
}
bool fDummyChanged = false;
rc = vboxVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged);
if (!RT_SUCCESS(rc))
{
WARN(("vboxVrListSubstNoJoin failed!"));
rc = VERR_NO_MEMORY;
break;
}
if (!VBoxVrListIsEmpty(&DiffList))
{
vboxVrListAddNonintersected(pList, &DiffList);
fNeedRectreate = true;
fChanged = true;
}
Assert(VBoxVrListIsEmpty(&DiffList));
}
if (pListRects)
RTMemFree(pListRects);
Assert(VBoxVrListIsEmpty(&DiffList) || rc != VINF_SUCCESS);
VBoxVrListClear(&DiffList);
if (fChanged)
vboxVrListJoinRects(pList);
if (pfChanged)
*pfChanged = fChanged;
return VINF_SUCCESS;
}
VBOXVREGDECL(int) VBoxVrListRectsGet(PVBOXVR_LIST pList, uint32_t cRects, RTRECT * aRects)
{
if (cRects < VBoxVrListRectsCount(pList))
return VERR_BUFFER_OVERFLOW;
uint32_t i = 0;
for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext, ++i)
{
PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1);
aRects[i] = pReg1->Rect;
}
return VINF_SUCCESS;
}
VBOXVREGDECL(int) VBoxVrListCmp(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2)
{
int cTmp = pList1->cEntries - pList2->cEntries;
if (cTmp)
return cTmp;
PVBOXVR_REG pReg1, pReg2;
for (pReg1 = RTListNodeGetNext(&pList1->ListHead, VBOXVR_REG, ListEntry),
pReg2 = RTListNodeGetNext(&pList2->ListHead, VBOXVR_REG, ListEntry);
!RTListNodeIsDummy(&pList1->ListHead, pReg1, VBOXVR_REG, ListEntry);
pReg1 = RT_FROM_MEMBER(pReg1->ListEntry.pNext, VBOXVR_REG, ListEntry),
pReg2 = RT_FROM_MEMBER(pReg2->ListEntry.pNext, VBOXVR_REG, ListEntry))
{
Assert(!RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
cTmp = VBoxRectCmp(&pReg1->Rect, &pReg2->Rect);
if (cTmp)
return cTmp;
}
Assert(RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry));
return 0;
}
VBOXVREGDECL(void) VBoxVrCompositorInit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_ENTRY_REMOVED pfnEntryRemoved)
{
RTListInit(&pCompositor->List);
pCompositor->pfnEntryRemoved = pfnEntryRemoved;
}
VBOXVREGDECL(void) VBoxVrCompositorTerm(PVBOXVR_COMPOSITOR pCompositor)
{
PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
{
VBoxVrCompositorEntryRemove(pCompositor, pEntry);
}
}
DECLINLINE(void) vboxVrCompositorEntryAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
{
RTListPrepend(&pCompositor->List, &pEntry->Node);
}
DECLINLINE(void) vboxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry)
{
RTListNodeRemove(&pEntry->Node);
if (pCompositor->pfnEntryRemoved)
pCompositor->pfnEntryRemoved(pCompositor, pEntry, pReplacingEntry);
}
VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry)
{
VBoxVrListInit(&pEntry->Vr);
}
VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry)
{
if (!VBoxVrCompositorEntryIsInList(pEntry))
return false;
VBoxVrListClear(&pEntry->Vr);
vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
return true;
}
static int vboxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
{
bool fChanged;
int rc = VBoxVrListRectsSubst(&pEntry->Vr, cRects, paRects, &fChanged);
if (RT_SUCCESS(rc))
{
if (VBoxVrListIsEmpty(&pEntry->Vr))
{
Assert(fChanged);
vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
}
if (pfChanged)
*pfChanged = false;
return VINF_SUCCESS;
}
WARN(("VBoxVrListRectsSubst failed, rc %d", rc));
return rc;
}
VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, uint32_t *pfChangeFlags)
{
bool fOthersChanged = false, fCurChanged = false, fEntryChanged = false, fEntryWasInList = false, fEntryReplaced = false;
PVBOXVR_COMPOSITOR_ENTRY pCur;
int rc = VINF_SUCCESS;
if (!cRects)
{
if (pfChangeFlags)
*pfChangeFlags = 0;
return VINF_SUCCESS;
}
if (pEntry)
{
fEntryWasInList = VBoxVrCompositorEntryIsInList(pEntry);
rc = VBoxVrListRectsAdd(&pEntry->Vr, cRects, paRects, &fEntryChanged);
if (RT_SUCCESS(rc))
{
if (VBoxVrListIsEmpty(&pEntry->Vr))
{
// WARN(("Empty rectangles passed in, is it expected?"));
if (pfChangeFlags)
*pfChangeFlags = 0;
return VINF_SUCCESS;
}
}
else
{
WARN(("VBoxVrListRectsAdd failed, rc %d", rc));
return rc;
}
Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
}
RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
{
Assert(!VBoxVrListIsEmpty(&pCur->Vr));
if (pCur == pEntry)
{
Assert(fEntryWasInList);
}
else
{
if (pEntry && !VBoxVrListCmp(&pCur->Vr, &pEntry->Vr))
{
VBoxVrListClear(&pCur->Vr);
vboxVrCompositorEntryRemove(pCompositor, pCur, pEntry);
fEntryReplaced = true;
break;
}
else
{
rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, &fCurChanged);
if (RT_SUCCESS(rc))
fOthersChanged |= fCurChanged;
else
{
WARN(("vboxVrCompositorEntryRegionsSubst failed, rc %d", rc));
return rc;
}
}
}
}
AssertRC(rc);
if (pEntry && !fEntryWasInList)
{
Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
vboxVrCompositorEntryAdd(pCompositor, pEntry);
}
if (pfChangeFlags)
{
uint32_t fFlags = 0;
if (fOthersChanged)
fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED;
else if (fEntryReplaced)
{
Assert(fEntryChanged);
fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED;
}
else if (fEntryChanged)
fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED;
if (!fEntryWasInList)
Assert(fEntryChanged);
*pfChangeFlags = fFlags;
}
return VINF_SUCCESS;
}
VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged)
{
if (!pEntry)
{
WARN(("VBoxVrCompositorEntryRegionsSubst called with zero entry, unsupported!"));
if (pfChanged)
*pfChanged = false;
return VERR_INVALID_PARAMETER;
}
if (VBoxVrListIsEmpty(&pEntry->Vr))
{
if (pfChanged)
*pfChanged = false;
return VINF_SUCCESS;
}
int rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pEntry, cRects, paRects, pfChanged);
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
WARN(("pfChanged failed, rc %d", rc));
return rc;
}
VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
{
if (!pEntry)
{
WARN(("VBoxVrCompositorEntryRegionsSet called with zero entry, unsupported!"));
if (pfChanged)
*pfChanged = false;
return VERR_INVALID_PARAMETER;
}
bool fChanged = false, fCurChanged = false;
uint32_t fChangeFlags = 0;
int rc;
fCurChanged = VBoxVrCompositorEntryRemove(pCompositor, pEntry);
fChanged |= fCurChanged;
rc = VBoxVrCompositorEntryRegionsAdd(pCompositor, pEntry, cRects, paRects, &fChangeFlags);
if (RT_SUCCESS(rc))
fChanged |= !!fChangeFlags;
else
{
WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
return rc;
}
AssertRC(rc);
if (pfChanged)
*pfChanged = fChanged;
return VINF_SUCCESS;
}
VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
{
int rc = VINF_SUCCESS;
bool fChanged = false;
if (VBoxVrCompositorEntryIsInList(pEntry))
{
rc = VBoxVrListIntersect(&pEntry->Vr, pList2, &fChanged);
if (RT_SUCCESS(rc))
{
if (VBoxVrListIsEmpty(&pEntry->Vr))
{
Assert(fChanged);
vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
}
}
else
{
WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
}
}
if (pfChanged)
*pfChanged = fChanged;
return rc;
}
VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged)
{
int rc = VINF_SUCCESS;
bool fChanged = false;
if (VBoxVrCompositorEntryIsInList(pEntry))
{
rc = VBoxVrListRectsIntersect(&pEntry->Vr, cRects, paRects, &fChanged);
if (RT_SUCCESS(rc))
{
if (VBoxVrListIsEmpty(&pEntry->Vr))
{
Assert(fChanged);
vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL);
}
}
else
{
WARN(("VBoxVrListRectsIntersect failed, rc %d", rc));
}
}
if (pfChanged)
*pfChanged = fChanged;
return rc;
}
VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersectAll(PVBOXVR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
{
VBOXVR_COMPOSITOR_ITERATOR Iter;
VBoxVrCompositorIterInit(pCompositor, &Iter);
PVBOXVR_COMPOSITOR_ENTRY pEntry;
int rc = VINF_SUCCESS;
bool fChanged = false;
while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
{
bool fTmpChanged = false;
int tmpRc = VBoxVrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
if (RT_SUCCESS(tmpRc))
{
fChanged |= fChanged;
}
else
{
WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
rc = tmpRc;
}
}
if (pfChanged)
*pfChanged = fChanged;
return rc;
}
VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersectAll(PVBOXVR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
{
VBOXVR_COMPOSITOR_ITERATOR Iter;
VBoxVrCompositorIterInit(pCompositor, &Iter);
PVBOXVR_COMPOSITOR_ENTRY pEntry;
int rc = VINF_SUCCESS;
bool fChanged = false;
while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL)
{
bool fTmpChanged = false;
int tmpRc = VBoxVrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
if (RT_SUCCESS(tmpRc))
{
fChanged |= fChanged;
}
else
{
WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
rc = tmpRc;
}
}
if (pfChanged)
*pfChanged = fChanged;
return rc;
}
VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, int32_t x, int32_t y, bool *pfChanged)
{
if (!pEntry)
{
WARN(("VBoxVrCompositorEntryRegionsTranslate called with zero entry, unsupported!"));
if (pfChanged)
*pfChanged = false;
return VERR_INVALID_PARAMETER;
}
if ((!x && !y)
|| !VBoxVrCompositorEntryIsInList(pEntry))
{
if (pfChanged)
*pfChanged = false;
return VINF_SUCCESS;
}
VBoxVrListTranslate(&pEntry->Vr, x, y);
Assert(!VBoxVrListIsEmpty(&pEntry->Vr));
PVBOXVR_COMPOSITOR_ENTRY pCur;
uint32_t cRects = 0;
RTRECT *paRects = NULL;
int rc = VINF_SUCCESS;
RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node)
{
Assert(!VBoxVrListIsEmpty(&pCur->Vr));
if (pCur == pEntry)
continue;
if (!paRects)
{
cRects = VBoxVrListRectsCount(&pEntry->Vr);
Assert(cRects);
paRects = (RTRECT*)RTMemAlloc(cRects * sizeof (RTRECT));
if (!paRects)
{
WARN(("RTMemAlloc failed!"));
rc = VERR_NO_MEMORY;
break;
}
rc = VBoxVrListRectsGet(&pEntry->Vr, cRects, paRects);
if (!RT_SUCCESS(rc))
{
WARN(("VBoxVrListRectsGet failed! rc %d", rc));
break;
}
}
rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, NULL);
if (!RT_SUCCESS(rc))
{
WARN(("vboxVrCompositorEntryRegionsSubst failed! rc %d", rc));
break;
}
}
if (pfChanged)
*pfChanged = true;
if (paRects)
RTMemFree(paRects);
return rc;
}
VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
{
PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext;
RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node)
{
if (!pfnVisitor(pCompositor, pEntry, pvVisitor))
return;
}
}
#define VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED UINT32_MAX
static int crVrScrCompositorRectsAssignBuffer(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRects)
{
Assert(cRects);
if (pCompositor->cRectsBuffer >= cRects)
{
pCompositor->cRects = cRects;
return VINF_SUCCESS;
}
if (pCompositor->cRectsBuffer)
{
Assert(pCompositor->paSrcRects);
RTMemFree(pCompositor->paSrcRects);
Assert(pCompositor->paDstRects);
RTMemFree(pCompositor->paDstRects);
}
pCompositor->paSrcRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paSrcRects) * cRects);
if (pCompositor->paSrcRects)
{
pCompositor->paDstRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstRects) * cRects);
if (pCompositor->paDstRects)
{
pCompositor->cRects = cRects;
pCompositor->cRectsBuffer = cRects;
return VINF_SUCCESS;
}
else
{
WARN(("RTMemAlloc failed!"));
RTMemFree(pCompositor->paSrcRects);
pCompositor->paSrcRects = NULL;
}
}
else
{
WARN(("RTMemAlloc failed!"));
pCompositor->paDstRects = NULL;
}
pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
pCompositor->cRectsBuffer = 0;
return VERR_NO_MEMORY;
}
static void crVrScrCompositorRectsInvalidate(PVBOXVR_SCR_COMPOSITOR pCompositor)
{
pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED;
}
static DECLCALLBACK(bool) crVrScrCompositorRectsCounterCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor)
{
uint32_t* pCounter = (uint32_t*)pvVisitor;
Assert(VBoxVrListRectsCount(&pEntry->Vr));
*pCounter += VBoxVrListRectsCount(&pEntry->Vr);
return true;
}
typedef struct VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER
{
PRTRECT paSrcRects;
PRTRECT paDstRects;
uint32_t cRects;
} VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER, *PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER;
static DECLCALLBACK(bool) crVrScrCompositorRectsAssignerCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
{
PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER pData = (PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER)pvVisitor;
PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
pEntry->paSrcRects = pData->paSrcRects;
pEntry->paDstRects = pData->paDstRects;
uint32_t cRects = VBoxVrListRectsCount(&pCEntry->Vr);
Assert(cRects);
Assert(cRects >= pData->cRects);
int rc = VBoxVrListRectsGet(&pCEntry->Vr, cRects, pEntry->paDstRects);
AssertRC(rc);
if (
#ifndef IN_RING0
pCompositor->StretchX >= 1. && pCompositor->StretchY >= 1. /* <- stretching can not zero some rects */
&&
#endif
!pEntry->Pos.x && !pEntry->Pos.y
)
{
memcpy(pEntry->paSrcRects, pEntry->paDstRects, cRects * sizeof (*pEntry->paSrcRects));
}
else
{
for (uint32_t i = 0; i < cRects; ++i)
{
pEntry->paSrcRects[i].xLeft = (int32_t)((pEntry->paDstRects[i].xLeft - pEntry->Pos.x));
pEntry->paSrcRects[i].yTop = (int32_t)((pEntry->paDstRects[i].yTop - pEntry->Pos.y));
pEntry->paSrcRects[i].xRight = (int32_t)((pEntry->paDstRects[i].xRight - pEntry->Pos.x));
pEntry->paSrcRects[i].yBottom = (int32_t)((pEntry->paDstRects[i].yBottom - pEntry->Pos.y));
#ifndef IN_RING0
if (pCompositor->StretchX != 1.)
{
pEntry->paSrcRects[i].xLeft = (int32_t)(pEntry->paSrcRects[i].xLeft * pCompositor->StretchX);
pEntry->paSrcRects[i].xRight = (int32_t)(pEntry->paSrcRects[i].xRight * pCompositor->StretchX);
}
if (pCompositor->StretchY != 1.)
{
pEntry->paSrcRects[i].yTop = (int32_t)(pEntry->paSrcRects[i].yTop * pCompositor->StretchY);
pEntry->paSrcRects[i].yBottom = (int32_t)(pEntry->paSrcRects[i].yBottom * pCompositor->StretchY);
}
#endif
}
#ifndef IN_RING0
bool canZeroX = (pCompositor->StretchX < 1.);
bool canZeroY = (pCompositor->StretchY < 1.);
if (canZeroX && canZeroY)
{
/* filter out zero rectangles*/
uint32_t iOrig, iNew;
for (iOrig = 0, iNew = 0; iOrig < cRects; ++iOrig)
{
PRTRECT pOrigRect = &pEntry->paSrcRects[iOrig];
if (pOrigRect->xLeft == pOrigRect->xRight
|| pOrigRect->yTop == pOrigRect->yBottom)
continue;
if (iNew != iOrig)
{
PRTRECT pNewRect = &pEntry->paSrcRects[iNew];
*pNewRect = *pOrigRect;
}
++iNew;
}
Assert(iNew <= iOrig);
uint32_t cDiff = iOrig - iNew;
if (cDiff)
{
pCompositor->cRects -= cDiff;
cRects -= cDiff;
}
}
#endif
}
pEntry->cRects = cRects;
pData->paDstRects += cRects;
pData->paSrcRects += cRects;
pData->cRects -= cRects;
return true;
}
static int crVrScrCompositorRectsCheckInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
{
if (pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED)
return VINF_SUCCESS;
uint32_t cRects = 0;
VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsCounterCb, &cRects);
if (!cRects)
{
pCompositor->cRects = 0;
return VINF_SUCCESS;
}
int rc = crVrScrCompositorRectsAssignBuffer(pCompositor, cRects);
if (!RT_SUCCESS(rc))
return rc;
VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER AssignerData;
AssignerData.paSrcRects = pCompositor->paSrcRects;
AssignerData.paDstRects = pCompositor->paDstRects;
AssignerData.cRects = pCompositor->cRects;
VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsAssignerCb, &AssignerData);
Assert(!AssignerData.cRects);
return VINF_SUCCESS;
}
static int crVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, uint32_t *pfChangedFlags)
{
uint32_t fChangedFlags = 0;
int rc = VBoxVrCompositorEntryRegionsAdd(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChangedFlags);
if (!RT_SUCCESS(rc))
{
WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc));
return rc;
}
if (fChangedFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED)
{
crVrScrCompositorRectsInvalidate(pCompositor);
}
if (fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)
{
CrVrScrCompositorEntrySetChanged(pEntry, true);
}
if (pfChangedFlags)
*pfChangedFlags = fChangedFlags;
return VINF_SUCCESS;
}
static int crVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
{
bool fChanged;
CrVrScrCompositorEntryIsInList(pEntry);
int rc = VBoxVrCompositorEntryRegionsSet(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
if (!RT_SUCCESS(rc))
{
WARN(("VBoxVrCompositorEntryRegionsSet failed, rc %d", rc));
return rc;
}
if (fChanged)
{
CrVrScrCompositorEntrySetChanged(pEntry, true);
if (!CrVrScrCompositorEntryIsInList(pEntry))
{
pEntry->cRects = 0;
pEntry->paSrcRects = NULL;
pEntry->paDstRects = NULL;
}
crVrScrCompositorRectsInvalidate(pCompositor);
}
CrVrScrCompositorEntrySetChanged(pEntry, true);
if (pfChanged)
*pfChanged = fChanged;
return VINF_SUCCESS;
}
static int crVrScrCompositorEntryPositionSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, bool *pfChanged)
{
if (pfChanged)
*pfChanged = false;
if (pEntry && (pEntry->Pos.x != pPos->x || pEntry->Pos.y != pPos->y))
{
int rc = VBoxVrCompositorEntryRegionsTranslate(&pCompositor->Compositor, &pEntry->Ce, pPos->x - pEntry->Pos.x, pPos->y - pEntry->Pos.y, pfChanged);
if (!RT_SUCCESS(rc))
{
WARN(("VBoxVrCompositorEntryRegionsTranslate failed rc %d", rc));
return rc;
}
if (VBoxVrCompositorEntryIsInList(&pEntry->Ce))
{
crVrScrCompositorRectsInvalidate(pCompositor);
}
pEntry->Pos = *pPos;
CrVrScrCompositorEntrySetChanged(pEntry, true);
if (pfChanged)
*pfChanged = true;
}
return VINF_SUCCESS;
}
static int crVrScrCompositorEntryEnsureRegionsInTex(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
{
RTRECT Rect;
Rect.xLeft = pEntry->Pos.x;
Rect.yTop = pEntry->Pos.y;
Rect.xRight = pEntry->Pos.x + pEntry->Tex.width;
Rect.yBottom = pEntry->Pos.y + pEntry->Tex.height;
int rc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, 1, &Rect, NULL);
if (!RT_SUCCESS(rc))
WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", rc));
return rc;
}
VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, uint32_t *pfChangeFlags)
{
int rc;
uint32_t fChangeFlags = 0;
bool fPosChanged = false;
if (pPos)
{
rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
if (!RT_SUCCESS(rc))
{
WARN(("RegionsAdd: crVrScrCompositorEntryPositionSet failed rc %d", rc));
return rc;
}
}
rc = crVrScrCompositorEntryRegionsAdd(pCompositor, pEntry, cRegions, paRegions, &fChangeFlags);
if (!RT_SUCCESS(rc))
{
WARN(("crVrScrCompositorEntryRegionsAdd failed, rc %d", rc));
return rc;
}
if ((fPosChanged || (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)) && pEntry)
{
rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry);
if (!RT_SUCCESS(rc))
{
WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed, rc %d", rc));
return rc;
}
}
if (pfChangeFlags)
{
if (fPosChanged)
{
/* means entry was in list and was moved, so regions changed */
*pfChangeFlags = VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED;
}
else
*pfChangeFlags = fChangeFlags;
}
return VINF_SUCCESS;
}
VBOXVREGDECL(int) CrVrScrCompositorEntryTexUpdate(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_TEXTURE *pTex)
{
bool fCompositorChanged = CrVrScrCompositorEntryIsUsed(pEntry) && (pEntry->Tex.width != pTex->width || pEntry->Tex.height != pTex->height);
pEntry->Tex = *pTex;
CrVrScrCompositorEntrySetChanged(pEntry, true);
if (fCompositorChanged)
{
int rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry);
if (!RT_SUCCESS(rc))
{
WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed rc %d", rc));
return rc;
}
}
return VINF_SUCCESS;
}
VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
{
/* @todo: the fChanged sate calculation is really rough now, this is enough for now though */
bool fChanged = false, fPosChanged = false;
bool fWasInList = CrVrScrCompositorEntryIsInList(pEntry);
int rc = CrVrScrCompositorEntryRemove(pCompositor, pEntry);
if (!RT_SUCCESS(rc))
{
WARN(("RegionsSet: CrVrScrCompositorEntryRemove failed rc %d", rc));
return rc;
}
if (pPos)
{
rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged);
if (!RT_SUCCESS(rc))
{
WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
return rc;
}
}
rc = crVrScrCompositorEntryRegionsSet(pCompositor, pEntry, cRegions, paRegions, &fChanged);
if (!RT_SUCCESS(rc))
{
WARN(("crVrScrCompositorEntryRegionsSet failed, rc %d", rc));
return rc;
}
if (fChanged && CrVrScrCompositorEntryIsUsed(pEntry))
{
rc = crVrScrCompositorEntryEnsureRegionsInTex(pCompositor, pEntry);
if (!RT_SUCCESS(rc))
{
WARN(("crVrScrCompositorEntryEnsureRegionsInTex failed, rc %d", rc));
return rc;
}
}
if (pfChanged)
*pfChanged = fPosChanged || fChanged || fWasInList;
return VINF_SUCCESS;
}
VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged)
{
bool fChanged = false;
int rc = VBoxVrCompositorEntryListIntersect(&pCompositor->Compositor, &pEntry->Ce, pList2, &fChanged);
if (!RT_SUCCESS(rc))
{
WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
return rc;
}
if (fChanged)
{
CrVrScrCompositorEntrySetChanged(pEntry, true);
crVrScrCompositorRectsInvalidate(pCompositor);
}
if (pfChanged)
*pfChanged = fChanged;
return VINF_SUCCESS;
}
VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
{
bool fChanged = false;
int rc = VBoxVrCompositorEntryRegionsIntersect(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged);
if (!RT_SUCCESS(rc))
{
WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc));
return rc;
}
if (fChanged)
{
CrVrScrCompositorEntrySetChanged(pEntry, true);
crVrScrCompositorRectsInvalidate(pCompositor);
}
if (pfChanged)
*pfChanged = fChanged;
return VINF_SUCCESS;
}
VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged)
{
VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
CrVrScrCompositorIterInit(pCompositor, &Iter);
PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
int rc = VINF_SUCCESS;
bool fChanged = false;
while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
{
bool fTmpChanged = false;
int tmpRc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged);
if (RT_SUCCESS(tmpRc))
{
fChanged |= fTmpChanged;
}
else
{
WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
rc = tmpRc;
}
}
if (pfChanged)
*pfChanged = fChanged;
return rc;
}
VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged)
{
VBOXVR_SCR_COMPOSITOR_ITERATOR Iter;
CrVrScrCompositorIterInit(pCompositor, &Iter);
PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
int rc = VINF_SUCCESS;
bool fChanged = false;
while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL)
{
bool fTmpChanged = false;
int tmpRc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged);
if (RT_SUCCESS(tmpRc))
{
fChanged |= fTmpChanged;
}
else
{
WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc));
rc = tmpRc;
}
}
if (pfChanged)
*pfChanged = fChanged;
return rc;
}
VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos)
{
int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL);
if (!RT_SUCCESS(rc))
{
WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc));
return rc;
}
return VINF_SUCCESS;
}
/* regions are valid until the next CrVrScrCompositor call */
VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
{
int rc = crVrScrCompositorRectsCheckInit(pCompositor);
if (!RT_SUCCESS(rc))
{
WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
return rc;
}
Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
*pcRegions = pEntry->cRects;
if (ppaSrcRegions)
*ppaSrcRegions = pEntry->paSrcRects;
if (ppaDstRegions)
*ppaDstRegions = pEntry->paDstRects;
return VINF_SUCCESS;
}
VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry)
{
if (!VBoxVrCompositorEntryRemove(&pCompositor->Compositor, &pEntry->Ce))
return VINF_SUCCESS;
CrVrScrCompositorEntrySetChanged(pEntry, true);
pEntry->cRects = 0;
pEntry->paSrcRects = NULL;
pEntry->paDstRects = NULL;
crVrScrCompositorRectsInvalidate(pCompositor);
return VINF_SUCCESS;
}
VBOXVREGDECL(int) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor)
{
memset(pCompositor, 0, sizeof (*pCompositor));
#ifndef IN_RING0
int rc = RTCritSectInit(&pCompositor->CritSect);
if (!RT_SUCCESS(rc))
{
WARN(("RTCritSectInit failed rc %d", rc));
return rc;
}
#endif
VBoxVrCompositorInit(&pCompositor->Compositor, NULL);
#ifndef IN_RING0
pCompositor->StretchX = 1.0;
pCompositor->StretchY = 1.0;
#endif
return VINF_SUCCESS;
}
VBOXVREGDECL(void) CrVrScrCompositorTerm(PVBOXVR_SCR_COMPOSITOR pCompositor)
{
VBoxVrCompositorTerm(&pCompositor->Compositor);
if (pCompositor->paDstRects)
RTMemFree(pCompositor->paDstRects);
if (pCompositor->paSrcRects)
RTMemFree(pCompositor->paSrcRects);
#ifndef IN_RING0
RTCritSectDelete(&pCompositor->CritSect);
#endif
}
static DECLCALLBACK(bool) crVrScrCompositorEntrySetAllChangedCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
{
PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
CrVrScrCompositorEntrySetChanged(pEntry, !!pvVisitor);
return true;
}
VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged)
{
VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorEntrySetAllChangedCb, (void*)fChanged);
}
#ifndef IN_RING0
VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY)
{
pCompositor->StretchX = StretchX;
pCompositor->StretchY = StretchY;
crVrScrCompositorRectsInvalidate(pCompositor);
CrVrScrCompositorEntrySetAllChanged(pCompositor, true);
}
#endif
/* regions are valid until the next CrVrScrCompositor call */
VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions)
{
int rc = crVrScrCompositorRectsCheckInit(pCompositor);
if (!RT_SUCCESS(rc))
{
WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc));
return rc;
}
Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED);
*pcRegions = pCompositor->cRects;
if (ppaSrcRegions)
*ppaSrcRegions = pCompositor->paSrcRects;
if (ppaDstRegions)
*ppaDstRegions = pCompositor->paDstRects;
return VINF_SUCCESS;
}
typedef struct VBOXVR_SCR_COMPOSITOR_VISITOR_CB
{
PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor;
void *pvVisitor;
} VBOXVR_SCR_COMPOSITOR_VISITOR_CB, *PVBOXVR_SCR_COMPOSITOR_VISITOR_CB;
static DECLCALLBACK(bool) crVrScrCompositorVisitCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor)
{
PVBOXVR_SCR_COMPOSITOR_VISITOR_CB pData = (PVBOXVR_SCR_COMPOSITOR_VISITOR_CB)pvVisitor;
PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor);
PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry);
return pData->pfnVisitor(pCompositor, pEntry, pData->pvVisitor);
}
VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor)
{
VBOXVR_SCR_COMPOSITOR_VISITOR_CB Data;
Data.pfnVisitor = pfnVisitor;
Data.pvVisitor = pvVisitor;
VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorVisitCb, &Data);
}