private void SplitHandle(int handleIndex, int splitIndex) { RegionHandle handle = _handles[handleIndex]; ulong address = _address + HandlesToBytes(handleIndex); ulong size = HandlesToBytes(splitIndex - handleIndex); // First, the target handle must be removed. Its data can still be used to determine the new handles. RegionSignal signal = handle.PreAction; handle.Dispose(); RegionHandle splitLow = _tracking.BeginTracking(address, size); splitLow.Parent = this; if (signal != null) { splitLow.RegisterAction(signal); } _handles[handleIndex] = splitLow; RegionHandle splitHigh = _tracking.BeginTracking(address + size, handle.Size - size); splitHigh.Parent = this; if (signal != null) { splitHigh.RegisterAction(signal); } _handles[splitIndex] = splitHigh; }
/// <summary> /// Register an action to perform when the tracked region is read or written. /// The action is automatically removed after it runs. /// </summary> /// <param name="action">Action to call on read or write</param> public void RegisterAction(RegionSignal action) { foreach (var regionHandle in _cpuRegionHandles) { regionHandle.RegisterAction(action); } }
/// <summary> /// Creates a new instance of the buffer. /// </summary> /// <param name="context">GPU context that the buffer belongs to</param> /// <param name="physicalMemory">Physical memory where the buffer is mapped</param> /// <param name="address">Start address of the buffer</param> /// <param name="size">Size of the buffer in bytes</param> /// <param name="baseBuffers">Buffers which this buffer contains, and will inherit tracking handles from</param> public Buffer(GpuContext context, PhysicalMemory physicalMemory, ulong address, ulong size, IEnumerable <Buffer> baseBuffers = null) { _context = context; _physicalMemory = physicalMemory; Address = address; Size = size; Handle = context.Renderer.CreateBuffer((int)size); _useGranular = size > GranularBufferThreshold; IEnumerable <IRegionHandle> baseHandles = null; if (baseBuffers != null) { baseHandles = baseBuffers.SelectMany(buffer => { if (buffer._useGranular) { return(buffer._memoryTrackingGranular.GetHandles()); } else { return(Enumerable.Repeat(buffer._memoryTracking.GetHandle(), 1)); } }); } if (_useGranular) { _memoryTrackingGranular = physicalMemory.BeginGranularTracking(address, size, baseHandles); _memoryTrackingGranular.RegisterPreciseAction(address, size, PreciseAction); } else { _memoryTracking = physicalMemory.BeginTracking(address, size); if (baseHandles != null) { _memoryTracking.Reprotect(false); foreach (IRegionHandle handle in baseHandles) { if (handle.Dirty) { _memoryTracking.Reprotect(true); } handle.Dispose(); } } _memoryTracking.RegisterPreciseAction(PreciseAction); } _externalFlushDelegate = new RegionSignal(ExternalFlush); _loadDelegate = new Action <ulong, ulong>(LoadRegion); _modifiedDelegate = new Action <ulong, ulong>(RegionModified); }
public void RegisterAction(RegionSignal action) { foreach (var handle in _handles) { if (handle != null) { handle?.RegisterAction((address, size) => action(handle.Address, handle.Size)); } } }
public void RegisterAction(ulong address, ulong size, RegionSignal action) { int startHandle = (int)((address - Address) / Granularity); int lastHandle = (int)((address + (size - 1) - Address) / Granularity); for (int i = startHandle; i <= lastHandle; i++) { _handles[i].RegisterAction(action); } }
/// <summary> /// Signal that a memory action occurred within this handle's virtual regions. /// </summary> /// <param name="write">Whether the region was written to or read</param> internal void Signal(ulong address, ulong size, bool write) { RegionSignal action = Interlocked.Exchange(ref _preAction, null); action?.Invoke(address, size); if (write) { Dirty = true; Parent?.SignalWrite(); } }
/// <summary> /// Register an action to perform when the tracked region is read or written. /// The action is automatically removed after it runs. /// </summary> /// <param name="action">Action to call on read or write</param> public void RegisterAction(RegionSignal action) { RegionSignal lastAction = Interlocked.Exchange(ref _preAction, action); if (lastAction == null && action != lastAction) { lock (_tracking.TrackingLock) { foreach (VirtualRegion region in _regions) { region.UpdateProtection(); } } } }
/// <summary> /// Signal that a memory action occurred within this handle's virtual regions. /// </summary> /// <param name="address">Address accessed</param> /// <param name="size">Size of the region affected in bytes</param> /// <param name="write">Whether the region was written to or read</param> /// <param name="handleIterable">Reference to the handles being iterated, in case the list needs to be copied</param> internal void Signal(ulong address, ulong size, bool write, ref IList <RegionHandle> handleIterable) { // If this handle was already unmapped (even if just partially), // then we have nothing to do until it is mapped again. // The pre-action should be still consumed to avoid flushing on remap. if (Unmapped) { Interlocked.Exchange(ref _preAction, null); return; } if (_preAction != null) { // Copy the handles list in case it changes when we're out of the lock. if (handleIterable is List <RegionHandle> ) { handleIterable = handleIterable.ToArray(); } // Temporarily release the tracking lock while we're running the action. Monitor.Exit(_tracking.TrackingLock); try { lock (_preActionLock) { _preAction?.Invoke(address, size); _preAction = null; } } finally { Monitor.Enter(_tracking.TrackingLock); } } if (write) { bool oldDirty = Dirty; Dirty = true; if (!oldDirty) { _onDirty?.Invoke(); } Parent?.SignalWrite(); } }
/// <summary> /// Register an action to perform when the tracked region is read or written. /// The action is automatically removed after it runs. /// </summary> /// <param name="action">Action to call on read or write</param> public void RegisterAction(RegionSignal action) { ClearVolatile(); lock (_preActionLock) { RegionSignal lastAction = _preAction; _preAction = action; if (lastAction == null && action != lastAction) { lock (_tracking.TrackingLock) { foreach (VirtualRegion region in _regions) { region.UpdateProtection(); } } } } }
/// <summary> /// Creates a new instance of the buffer. /// </summary> /// <param name="context">GPU context that the buffer belongs to</param> /// <param name="address">Start address of the buffer</param> /// <param name="size">Size of the buffer in bytes</param> public Buffer(GpuContext context, ulong address, ulong size) { _context = context; Address = address; Size = size; Handle = context.Renderer.CreateBuffer((int)size); _useGranular = size > GranularBufferThreshold; if (_useGranular) { _memoryTrackingGranular = context.PhysicalMemory.BeginGranularTracking(address, size); } else { _memoryTracking = context.PhysicalMemory.BeginTracking(address, size); } _externalFlushDelegate = new RegionSignal(ExternalFlush); _loadDelegate = new Action <ulong, ulong>(LoadRegion); _modifiedDelegate = new Action <ulong, ulong>(RegionModified); }
public void RegisterAction(RegionSignal action) => _impl.RegisterAction(action);
internal MultiRegionHandle(MemoryTracking tracking, ulong address, ulong size, IEnumerable <IRegionHandle> handles, ulong granularity) { _handles = new RegionHandle[size / granularity]; Granularity = granularity; int i = 0; if (handles != null) { // Inherit from the handles we were given. Any gaps must be filled with new handles, // and old handles larger than our granularity must copy their state onto new granular handles and dispose. // It is assumed that the provided handles do not overlap, in order, are on page boundaries, // and don't extend past the requested range. foreach (RegionHandle handle in handles) { int startIndex = (int)((handle.Address - address) / granularity); // Fill any gap left before this handle. while (i < startIndex) { RegionHandle fillHandle = tracking.BeginTracking(address + (ulong)i * granularity, granularity); fillHandle.Parent = this; _handles[i++] = fillHandle; } if (handle.Size == granularity) { handle.Parent = this; _handles[i++] = handle; } else { int endIndex = (int)((handle.EndAddress - address) / granularity); while (i < endIndex) { RegionHandle splitHandle = tracking.BeginTracking(address + (ulong)i * granularity, granularity); splitHandle.Parent = this; splitHandle.Reprotect(handle.Dirty); RegionSignal signal = handle.PreAction; if (signal != null) { splitHandle.RegisterAction(signal); } _handles[i++] = splitHandle; } handle.Dispose(); } } } // Fill any remaining space with new handles. while (i < _handles.Length) { RegionHandle handle = tracking.BeginTracking(address + (ulong)i * granularity, granularity); handle.Parent = this; _handles[i++] = handle; } Address = address; Size = size; }
public void RegisterAction(ulong address, ulong size, RegionSignal action) => _impl.RegisterAction(address, size, action);