/// <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); }
/// <summary> /// Called when the memory for this texture has been unmapped. /// Calls are from non-gpu threads. /// </summary> public void Unmapped() { IsModified = false; // We shouldn't flush this texture, as its memory is no longer mapped. CpuRegionHandle tracking = _memoryTracking; tracking?.Reprotect(); tracking?.RegisterAction(null); }
/// <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> /// 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.BeginSmartGranularTracking(address, size); } else { _memoryTracking = context.PhysicalMemory.BeginTracking(address, size); } }
/// <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)); }
/// <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); } _modifiedDelegate = new Action <ulong, ulong>(RegionModified); }
/// <summary> /// Initializes the data for a texture. Can optionally initialize the texture with or without data. /// If the texture is a view, it will initialize memory tracking to be non-dirty. /// </summary> /// <param name="isView">True if the texture is a view, false otherwise</param> /// <param name="withData">True if the texture is to be initialized with data</param> public void InitializeData(bool isView, bool withData = false) { _memoryTracking = _context.PhysicalMemory.BeginTracking(Address, Size); if (withData) { Debug.Assert(!isView); TextureCreateInfo createInfo = TextureManager.GetCreateInfo(Info, _context.Capabilities, ScaleFactor); HostTexture = _context.Renderer.CreateTexture(createInfo, ScaleFactor); SynchronizeMemory(); // Load the data. if (ScaleMode == TextureScaleMode.Scaled) { SetScale(GraphicsConfig.ResScale); // Scale the data up. } } else { // Don't update this texture the next time we synchronize. ConsumeModified(); _hasData = true; if (!isView) { if (ScaleMode == TextureScaleMode.Scaled) { // Don't need to start at 1x as there is no data to scale, just go straight to the target scale. ScaleFactor = GraphicsConfig.ResScale; } TextureCreateInfo createInfo = TextureManager.GetCreateInfo(Info, _context.Capabilities, ScaleFactor); HostTexture = _context.Renderer.CreateTexture(createInfo, ScaleFactor); } } }
/// <summary> /// Disables memory tracking on this texture. Currently used for view containers, as we assume their views are covering all memory regions. /// Textures with disabled memory tracking also cannot flush in most circumstances. /// </summary> public void DisableMemoryTracking() { _memoryTracking?.Dispose(); _memoryTracking = null; }
/// <summary> /// Recalculate handle regions for this texture group, and inherit existing state into the new handles. /// </summary> private void RecalculateHandleRegions() { TextureGroupHandle[] handles; if (!(_hasMipViews || _hasLayerViews)) { // Single dirty region. var cpuRegionHandles = new CpuRegionHandle[TextureRange.Count]; for (int i = 0; i < TextureRange.Count; i++) { var currentRange = TextureRange.GetSubRange(i); cpuRegionHandles[i] = GenerateHandle(currentRange.Address, currentRange.Size); } var groupHandle = new TextureGroupHandle(this, 0, Storage.Size, _views, 0, 0, cpuRegionHandles); foreach (CpuRegionHandle handle in cpuRegionHandles) { handle.RegisterDirtyEvent(() => DirtyAction(groupHandle)); } handles = new TextureGroupHandle[] { groupHandle }; } else { // Get views for the host texture. // It's worth noting that either the texture has layer views or mip views when getting to this point, which simplifies the logic a little. // Depending on if the texture is 3d, either the mip views imply that layer views are present (2d) or the other way around (3d). // This is enforced by the way the texture matched as a view, so we don't need to check. int layerHandles = _hasLayerViews ? _layers : 1; int levelHandles = _hasMipViews ? _levels : 1; int handleIndex = 0; if (_is3D) { var handlesList = new List <TextureGroupHandle>(); for (int i = 0; i < levelHandles; i++) { for (int j = 0; j < layerHandles; j++) { (int viewStart, int views) = Get3DLevelRange(i); viewStart += j; views = _hasLayerViews ? 1 : views; // A layer view is also a mip view. handlesList.Add(GenerateHandles(viewStart, views)); } layerHandles = Math.Max(1, layerHandles >> 1); } handles = handlesList.ToArray(); } else { handles = new TextureGroupHandle[layerHandles * levelHandles]; for (int i = 0; i < layerHandles; i++) { for (int j = 0; j < levelHandles; j++) { int viewStart = j + i * _levels; int views = _hasMipViews ? 1 : _levels; // A mip view is also a layer view. handles[handleIndex++] = GenerateHandles(viewStart, views); } } } } ReplaceHandles(handles); }