/// <summary> /// Writes data to the application process, using the supplied callback method. /// </summary> /// <param name="range">Ranges of physical memory where the data is located</param> /// <param name="data">Data to be written</param> /// <param name="writeCallback">Callback method that will perform the write</param> private static void WriteImpl(MultiRange range, ReadOnlySpan <byte> data, WriteCallback writeCallback) { if (range.Count == 1) { var singleRange = range.GetSubRange(0); if (singleRange.Address != MemoryManager.PteUnmapped) { writeCallback(singleRange.Address, data); } } else { int offset = 0; for (int i = 0; i < range.Count; i++) { var currentRange = range.GetSubRange(i); int size = (int)currentRange.Size; if (currentRange.Address != MemoryManager.PteUnmapped) { writeCallback(currentRange.Address, data.Slice(offset, size)); } offset += size; } } }
/// <summary> /// Gets a writable region from GPU mapped memory. /// </summary> /// <param name="range">Range</param> /// <param name="tracked">True if write tracking is triggered on the span</param> /// <returns>A writable region with the data at the specified memory location</returns> public WritableRegion GetWritableRegion(MultiRange range, bool tracked = false) { if (range.Count == 1) { MemoryRange subrange = range.GetSubRange(0); return(GetWritableRegion(subrange.Address, (int)subrange.Size, tracked)); } else { Memory <byte> memory = new byte[range.GetSize()]; int offset = 0; for (int i = 0; i < range.Count; i++) { var currentRange = range.GetSubRange(i); int size = (int)currentRange.Size; if (currentRange.Address != MemoryManager.PteUnmapped) { GetSpan(currentRange.Address, size).CopyTo(memory.Span.Slice(offset, size)); } offset += size; } return(new WritableRegion(new MultiRangeWritableBlock(range, this), 0, memory, tracked)); } }
/// <summary> /// Gets a span of data from the application process. /// </summary> /// <param name="range">Ranges of physical memory where the data is located</param> /// <param name="tracked">True if read tracking is triggered on the span</param> /// <returns>A read only span of the data at the specified memory location</returns> public ReadOnlySpan <byte> GetSpan(MultiRange range, bool tracked = false) { if (range.Count == 1) { var singleRange = range.GetSubRange(0); if (singleRange.Address != MemoryManager.PteUnmapped) { return(_cpuMemory.GetSpan(singleRange.Address, (int)singleRange.Size, tracked)); } } Span <byte> data = new byte[range.GetSize()]; int offset = 0; for (int i = 0; i < range.Count; i++) { var currentRange = range.GetSubRange(i); int size = (int)currentRange.Size; if (currentRange.Address != MemoryManager.PteUnmapped) { _cpuMemory.GetSpan(currentRange.Address, size, tracked).CopyTo(data.Slice(offset, size)); } offset += size; } return(data); }
/// <summary> /// Checks if a given GPU virtual memory range is mapped to the same physical regions /// as the specified physical memory multi-range. /// </summary> /// <param name="range">Physical memory multi-range</param> /// <param name="va">GPU virtual memory address</param> /// <returns>True if the virtual memory region is mapped into the specified physical one, false otherwise</returns> public bool CompareRange(MultiRange range, ulong va) { va &= ~PageMask; for (int i = 0; i < range.Count; i++) { MemoryRange currentRange = range.GetSubRange(i); ulong address = currentRange.Address & ~PageMask; ulong endAddress = (currentRange.EndAddress + PageMask) & ~PageMask; while (address < endAddress) { if (Translate(va) != address) { return(false); } va += PageSize; address += PageSize; } } return(true); }
/// <summary> /// Handles removal of textures written to a memory region being unmapped. /// </summary> /// <param name="sender">Sender object</param> /// <param name="e">Event arguments</param> public void MemoryUnmappedHandler(object sender, UnmapEventArgs e) { Texture[] overlaps = new Texture[10]; int overlapCount; MultiRange unmapped = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size); lock (_textures) { overlapCount = _textures.FindOverlaps(unmapped, ref overlaps); } for (int i = 0; i < overlapCount; i++) { overlaps[i].Unmapped(unmapped); } // If any range was previously unmapped, we also need to purge // all partially mapped texture, as they might be fully mapped now. for (int i = 0; i < unmapped.Count; i++) { if (unmapped.GetSubRange(i).Address == MemoryManager.PteUnmapped) { lock (_partiallyMappedTextures) { foreach (var texture in _partiallyMappedTextures) { texture.Unmapped(unmapped); } } break; } } }
/// <summary> /// Obtains a memory tracking handle for the given virtual region. This should be disposed when finished with. /// </summary> /// <param name="range">Ranges of physical memory where the data is located</param> /// <returns>The memory tracking handle</returns> public GpuRegionHandle BeginTracking(MultiRange range) { var cpuRegionHandles = new CpuRegionHandle[range.Count]; for (int i = 0; i < range.Count; i++) { var currentRange = range.GetSubRange(i); cpuRegionHandles[i] = _cpuMemory.BeginTracking(currentRange.Address, currentRange.Size); } return(new GpuRegionHandle(cpuRegionHandles)); }
/// <summary> /// Obtains a memory tracking handle for the given virtual region. This should be disposed when finished with. /// </summary> /// <param name="range">Ranges of physical memory where the data is located</param> /// <returns>The memory tracking handle</returns> public GpuRegionHandle BeginTracking(MultiRange range) { var cpuRegionHandles = new CpuRegionHandle[range.Count]; int count = 0; for (int i = 0; i < range.Count; i++) { var currentRange = range.GetSubRange(i); if (currentRange.Address != MemoryManager.PteUnmapped) { cpuRegionHandles[count++] = _cpuMemory.BeginTracking(currentRange.Address, currentRange.Size); } } if (count != range.Count) { Array.Resize(ref cpuRegionHandles, count); } return(new GpuRegionHandle(cpuRegionHandles)); }