/// <summary> /// Create a new texture group handle, representing a range of views in a storage texture. /// </summary> /// <param name="group">The TextureGroup that the handle belongs to</param> /// <param name="offset">The byte offset from the start of the storage of the handle</param> /// <param name="size">The size in bytes covered by the handle</param> /// <param name="views">All views of the storage texture, used to calculate overlaps</param> /// <param name="firstLayer">The first layer of this handle in the storage texture</param> /// <param name="firstLevel">The first level of this handle in the storage texture</param> /// <param name="baseSlice">The base slice index of this handle</param> /// <param name="sliceCount">The number of slices this handle covers</param> /// <param name="handles">The memory tracking handles that cover this handle</param> public TextureGroupHandle(TextureGroup group, int offset, ulong size, List <Texture> views, int firstLayer, int firstLevel, int baseSlice, int sliceCount, CpuRegionHandle[] handles) { _group = group; _firstLayer = firstLayer; _firstLevel = firstLevel; Offset = offset; Size = (int)size; Overlaps = new List <Texture>(); Dependencies = new List <TextureDependency>(); BaseSlice = baseSlice; SliceCount = sliceCount; if (views != null) { RecalculateOverlaps(group, views); } Handles = handles; }
/// <summary> /// Check if this handle has a dependency to a given texture group. /// </summary> /// <param name="group">The texture group to check for</param> /// <returns>True if there is a dependency, false otherwise</returns> public bool HasDependencyTo(TextureGroup group) { foreach (TextureDependency dep in Dependencies) { if (dep.Other.Handle._group == group) { return(true); } } return(false); }
/// <summary> /// Inherit state from another texture group. /// </summary> /// <param name="other">The texture group to inherit from</param> public void Inherit(TextureGroup other) { bool layerViews = _hasLayerViews || other._hasLayerViews; bool mipViews = _hasMipViews || other._hasMipViews; if (layerViews != _hasLayerViews || mipViews != _hasMipViews) { _hasLayerViews = layerViews; _hasMipViews = mipViews; RecalculateHandleRegions(); } InheritHandles(other._handles, _handles); }
/// <summary> /// Calculate a list of which views overlap this handle. /// </summary> /// <param name="group">The parent texture group, used to find a view's base CPU VA offset</param> /// <param name="views">The list of views to search for overlaps</param> public void RecalculateOverlaps(TextureGroup group, List <Texture> views) { // Overlaps can be accessed from the memory tracking signal handler, so access must be atomic. lock (Overlaps) { int endOffset = Offset + Size; Overlaps.Clear(); foreach (Texture view in views) { int viewOffset = group.FindOffset(view); if (viewOffset < endOffset && Offset < viewOffset + (int)view.Size) { Overlaps.Add(view); } } } }
/// <summary> /// Create a copy dependency between this texture group, and a texture at a given layer/level offset. /// </summary> /// <param name="other">The view compatible texture to create a dependency to</param> /// <param name="firstLayer">The base layer of the given texture relative to the storage</param> /// <param name="firstLevel">The base level of the given texture relative to the storage</param> /// <param name="copyTo">True if this texture is first copied to the given one, false for the opposite direction</param> public void CreateCopyDependency(Texture other, int firstLayer, int firstLevel, bool copyTo) { TextureGroup otherGroup = other.Group; EnsureFullSubdivision(); otherGroup.EnsureFullSubdivision(); // Get the location of each texture within its storage, so we can find the handles to apply the dependency to. // This can consist of multiple disjoint regions, for example if this is a mip slice of an array texture. var targetRange = new List <(int BaseHandle, int RegionCount)>(); var otherRange = new List <(int BaseHandle, int RegionCount)>(); EvaluateRelevantHandles(firstLayer, firstLevel, other.Info.GetSlices(), other.Info.Levels, (baseHandle, regionCount, split) => targetRange.Add((baseHandle, regionCount))); otherGroup.EvaluateRelevantHandles(other, (baseHandle, regionCount, split) => otherRange.Add((baseHandle, regionCount))); int targetIndex = 0; int otherIndex = 0; (int Handle, int RegionCount)targetRegion = (0, 0); (int Handle, int RegionCount)otherRegion = (0, 0); while (true) { if (targetRegion.RegionCount == 0) { if (targetIndex >= targetRange.Count) { break; } targetRegion = targetRange[targetIndex++]; } if (otherRegion.RegionCount == 0) { if (otherIndex >= otherRange.Count) { break; } otherRegion = otherRange[otherIndex++]; } TextureGroupHandle handle = _handles[targetRegion.Handle++]; TextureGroupHandle otherHandle = other.Group._handles[otherRegion.Handle++]; targetRegion.RegionCount--; otherRegion.RegionCount--; handle.CreateCopyDependency(otherHandle, copyTo); // If "copyTo" is true, this texture must copy to the other. // Otherwise, it must copy to this texture. if (copyTo) { otherHandle.Copy(handle); } else { handle.Copy(otherHandle); } } }
/// <summary> /// Initialize a new texture group with this texture as storage. /// </summary> /// <param name="hasLayerViews">True if the texture will have layer views</param> /// <param name="hasMipViews">True if the texture will have mip views</param> public void InitializeGroup(bool hasLayerViews, bool hasMipViews) { Group = new TextureGroup(_context, this); Group.Initialize(ref _sizeInfo, hasLayerViews, hasMipViews); }