public AllocationException(string message, int requestedSize, int requestedAlignment, AllocationMode requestedMode) : base(message) { RequestedSize = requestedSize; RequestedAlignment = requestedAlignment; RequestedMode = requestedMode; }
public unsafe void Allocate_Uninitialized_Ok(Device device, Type bufferType, AllocationMode allocationMode) { using TransferTexture3D <float> texture = device.Get().AllocateTransferTexture3D <float>(bufferType, 128, 256, 32, allocationMode); Assert.IsNotNull(texture); Assert.AreEqual(texture.Width, 128); Assert.AreEqual(texture.Height, 256); Assert.AreEqual(texture.Depth, 32); Assert.AreEqual(texture.View.Width, 128); Assert.AreEqual(texture.View.Height, 256); Assert.AreEqual(texture.View.Depth, 32); Assert.AreSame(texture.GraphicsDevice, device.Get()); if (allocationMode == AllocationMode.Clear) { for (int z = 0; z < texture.Depth; z++) { for (int y = 0; y < texture.Height; y++) { foreach (float x in texture.View.GetRowSpan(y, z)) { Assert.AreEqual(x, 0f); } } } } }
public AllocationException(int requestedSize, int requestedAlignment, AllocationMode requestedMode) : this($"Could not allocate the requested size of {requestedSize}. Alignment: {requestedAlignment}, mode: {requestedMode}", requestedSize, requestedAlignment, requestedMode) { }
public void Dequeue_OnMultipleThreads(AllocationMode allocationMode) { using (var queue = AtomicQueue <int> .Create(allocationMode)) { Assert.That(queue.IsEmpty); int popped = 0; for (int i = 0; i < kWorkerCount; ++i) { queue.Enqueue((int *)i); } for (int i = 0; i < kWorkerCount; ++i) { ThreadPool.QueueUserWorkItem(o => { queue.Dequeue(); Interlocked.Increment(ref popped); }); } while (popped < kWorkerCount) { Utility.YieldProcessor(); } Assert.That(queue.IsEmpty); } }
/// <summary> /// Create a new AtomicFreeList /// </summary> /// <param name="allocationMode">The allocation mode to be used</param> /// <param name="allocator">The native allocator to be used</param> public AtomicFreeList(AllocationMode allocationMode, Allocator allocator = Allocator.Persistent) { // This is required because of casting T* => AtomicNode* tomfoolery when releasing nodes back into the free list ValidateTypeSize(); m_FreeList = Utility.AllocateUnsafe <long>(1, allocator); *m_FreeList = 0; m_AllocationMode = allocationMode; m_Allocator = allocator; }
public void CanAllocateFromEmptyList(AllocationMode allocationMode) { using (var list = new AtomicFreeList <AtomicNode>(allocationMode)) { var node = list.Acquire(); Assert.AreNotEqual(IntPtr.Zero, (IntPtr)node); list.Release(node); } }
public void Enqueue(AllocationMode allocationMode) { using (var queue = AtomicQueue <int> .Create(allocationMode)) { Assert.That(queue.IsEmpty); queue.Enqueue((int *)1); Assert.That(!queue.IsEmpty); } }
public static D3D12_HEAP_FLAGS GetD3D12HeapFlags(AllocationMode allocationMode) { if (allocationMode == AllocationMode.Default) { return(D3D12_HEAP_FLAG_CREATE_NOT_ZEROED); } return(D3D12_HEAP_FLAGS.D3D12_HEAP_FLAG_NONE); }
/// <summary> /// Initializes a new instance of the <see cref="SpanOwner{T}"/> struct with the specified parameters. /// </summary> /// <param name="length">The length of the new memory buffer to use.</param> /// <param name="mode">Indicates the allocation mode to use for the new buffer to rent.</param> private SpanOwner(int length, AllocationMode mode) { this.length = length; this.array = ArrayPool <T> .Shared.Rent(length); if (mode == AllocationMode.Clear) { this.array.AsSpan(0, length).Clear(); } }
/// <summary> /// Create an AtomicQueue<T> /// </summary> /// <remarks>This is the only valid way to create an AtomicQueue<T></remarks> /// <param name="allocationMode">Use the specified allocation mode for the queue's internal free list</param> /// <returns></returns> public static AtomicQueue <T> Create(AllocationMode allocationMode = AllocationMode.Pooled) { var root = (AtomicNode **)Utility.AllocateUnsafe <IntPtr>(); *root = AtomicNode.Create(0, 0, Allocator.Persistent); return(new AtomicQueue <T> { m_Root = root, m_FreeList = new AtomicFreeList <AtomicNode>(allocationMode).Description, }); }
public void PreservesItems_WithSimultaneousQueueDequeue(AllocationMode allocationMode) { using (var queue = AtomicQueue <int> .Create(allocationMode)) { var count = 0; var allItems = new HashSet <int>(); var foundItems = new HashSet <int>(); var threads = new List <Thread>(); for (int i = 0; i < kWorkerCount; ++i) { allItems.Add(i + 1); var thread = new Thread((o) => { try { var item = Interlocked.Increment(ref count); queue.Enqueue((int *)item); } catch (Exception e) { Debug.LogException(e); } }); thread.Start(); threads.Add(thread); if (queue.TryDequeue(out var result)) { foundItems.Add((int)result); } } foreach (var thread in threads) { thread.Join(); } while (foundItems.Count < kWorkerCount) { if (queue.TryDequeue(out var item)) { foundItems.Add((int)item); } else { Assert.Fail($"After adding was completed, queue was empty after popping only {foundItems.Count} items"); return; } } Assert.That(queue.IsEmpty); CollectionAssert.AreEquivalent(allItems, foundItems); } }
/// <inheritdoc/> public int Allocate(int size, int alignment, AllocationMode mode) { lock (_lockObj) { var query = _rangeList.EnumerateNodes().Where(n => n.Value.Size >= size); switch (mode) { case AllocationMode.Earliest: break; case AllocationMode.Smallest: query = query.OrderBy(n => n.Value.Size); break; case AllocationMode.Largest: query = query.OrderByDescending(n => n.Value.Size); break; default: throw new NotSupportedException(); } var match = query.FirstOrDefault(n => n.Value.GetAlignedSize(alignment) >= size); if (match == null) { throw new AllocationException( $"Could not allocate the requested block: size = {size}, alignment = {alignment}, mode = {mode}. Available ranges: {ToString()}", size, alignment, mode); } Range range = match.Value; int location = range.Start.Align(alignment); if (!DiscardUnalignedChunks && location > range.Start) { // Add a small chunk for the unaligned portion of the matched range Range before = Range.StartEnd(range.Start, location - 1); _rangeList.AddBefore(match, before); } if (location + size - 1 < range.End) { // Add a chunk for the remaining range Range after = Range.StartEnd(location + size, range.End); _rangeList.AddAfter(match, after); } _rangeList.Remove(match); return(location); } }
/// <summary> /// Initializes a new instance of the <see cref="MemoryOwner{T}"/> class with the specified parameters. /// </summary> /// <param name="length">The length of the new memory buffer to use.</param> /// <param name="pool">The <see cref="ArrayPool{T}"/> instance to use.</param> /// <param name="mode">Indicates the allocation mode to use for the new buffer to rent.</param> private MemoryOwner(int length, ArrayPool <T> pool, AllocationMode mode) { this.start = 0; this.length = length; this.pool = pool; this.array = pool.Rent(length); if (mode == AllocationMode.Clear) { this.array.AsSpan(0, length).Clear(); } }
public void TryDequeue(AllocationMode allocationMode) { using (var queue = AtomicQueue <int> .Create(allocationMode)) { var value = (int *)Random.Range(1, int.MaxValue); Assert.That(queue.IsEmpty); queue.Enqueue(value); Assert.That(!queue.IsEmpty); Assert.That(queue.TryDequeue(out var result) && result == value); Assert.That(queue.IsEmpty); } }
public void Peek(AllocationMode allocationMode) { using (var queue = AtomicQueue <int> .Create(allocationMode)) { var value = (int *)Random.Range(1, int.MaxValue); Assert.That(queue.IsEmpty); queue.Enqueue(value); queue.Enqueue(null); Assert.That(!queue.IsEmpty); Assert.That(queue.Peek() == value); Assert.That(queue.Peek() == value); Assert.That(queue.Peek() == value); } }
public void Allocate_Uninitialized_Ok(Device device, Type bufferType, AllocationMode allocationMode, int size) { using Buffer <float> buffer = device.Get().AllocateBuffer <float>(bufferType, size, allocationMode); Assert.IsNotNull(buffer); Assert.AreEqual(buffer.Length, size); Assert.AreSame(buffer.GraphicsDevice, device.Get()); if (allocationMode == AllocationMode.Clear) { foreach (float x in buffer.ToArray()) { Assert.AreEqual(x, 0f); } } }
public void Allocate_Uninitialized_Ok(Device device, Type textureType, AllocationMode allocationMode) { using Texture2D <float> texture = device.Get().AllocateTexture2D <float>(textureType, 128, 128, allocationMode); Assert.IsNotNull(texture); Assert.AreEqual(texture.Width, 128); Assert.AreEqual(texture.Height, 128); Assert.AreSame(texture.GraphicsDevice, device.Get()); if (allocationMode == AllocationMode.Clear) { foreach (float x in texture.ToArray()) { Assert.AreEqual(x, 0f); } } }
public void Empty_ThenReenqueue(AllocationMode allocationMode) { var value = (int *)Random.Range(1, int.MaxValue); using (var queue = AtomicQueue <int> .Create(allocationMode)) { Assert.That(queue.IsEmpty); queue.Enqueue(value); Assert.That(!queue.IsEmpty); Assert.AreEqual((long)value, (long)queue.Dequeue()); Assert.That(queue.IsEmpty); queue.Enqueue(value); Assert.That(!queue.IsEmpty); Assert.AreEqual((long)value, (long)queue.Dequeue()); Assert.That(queue.IsEmpty); } }
public unsafe void Allocate_Uninitialized_Ok(Device device, Type bufferType, AllocationMode allocationMode) { using TransferBuffer <float> buffer = device.Get().AllocateTransferBuffer <float>(bufferType, 128, allocationMode); Assert.IsNotNull(buffer); Assert.AreEqual(buffer.Length, 128); Assert.AreEqual(buffer.Memory.Length, 128); Assert.AreEqual(buffer.Span.Length, 128); Assert.IsTrue(Unsafe.AreSame(ref buffer.Memory.Span[0], ref buffer.Span[0])); Assert.IsTrue(Unsafe.AreSame(ref *(float *)buffer.Memory.Pin().Pointer, ref buffer.Span[0])); Assert.AreSame(buffer.GraphicsDevice, device.Get()); if (allocationMode == AllocationMode.Clear) { foreach (float x in buffer.Span) { Assert.AreEqual(x, 0f); } } }
public void PreservesItems(AllocationMode allocationMode) { using (var queue = AtomicQueue <int> .Create(allocationMode)) { var count = 0; var items = new HashSet <int>(); var threads = new List <Thread>(); for (int i = 0; i < kWorkerCount; ++i) { var thread = new Thread((o) => { var item = Interlocked.Increment(ref count); queue.Enqueue((int *)item); }); items.Add(i + 1); thread.Start(); threads.Add(thread); } foreach (var thread in threads) { thread.Join(); } Assert.That(!queue.IsEmpty); for (int i = 0; i < kWorkerCount; ++i) { var item = (int)queue.Dequeue(); Assert.That(items.Contains(item), $"Missing item {item} (iteration {i})"); items.Remove(item); } Assert.That(queue.IsEmpty); Assert.That(items.Count == 0); } }
/// <summary> /// Creates a new <see cref="UploadTexture3D{T}"/> instance with the specified parameters. /// </summary> /// <param name="device">The <see cref="GraphicsDevice"/> associated with the current instance.</param> /// <param name="width">The width of the texture.</param> /// <param name="height">The height of the texture.</param> /// <param name="depth">The depth of the texture.</param> /// <param name="allocationMode">The allocation mode to use for the new resource.</param> internal UploadTexture3D(GraphicsDevice device, int width, int height, int depth, AllocationMode allocationMode) : base(device, width, height, depth, ResourceType.Upload, allocationMode) { }
/// <summary> /// Creates a new <see cref="ReadOnlyBuffer{T}"/> instance with the specified parameters. /// </summary> /// <param name="device">The <see cref="GraphicsDevice"/> associated with the current instance.</param> /// <param name="length">The number of items to store in the current buffer.</param> /// <param name="allocationMode">The allocation mode to use for the new resource.</param> internal ReadOnlyBuffer(GraphicsDevice device, int length, AllocationMode allocationMode) : base(device, length, ResourceType.ReadOnly, allocationMode) { }
/// <summary> /// Creates a new <see cref="Texture2D{T}"/> instance with the specified parameters. /// </summary> /// <param name="device">The <see cref="ComputeSharp.GraphicsDevice"/> associated with the current instance.</param> /// <param name="height">The height of the texture.</param> /// <param name="width">The width of the texture.</param> /// <param name="resourceType">The resource type for the current texture.</param> /// <param name="allocationMode">The allocation mode to use for the new resource.</param> /// <param name="d3D12FormatSupport">The format support for the current texture type.</param> private protected Texture2D(GraphicsDevice device, int width, int height, ResourceType resourceType, AllocationMode allocationMode, D3D12_FORMAT_SUPPORT1 d3D12FormatSupport) { device.ThrowIfDisposed(); Guard.IsBetweenOrEqualTo(width, 1, FX.D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, nameof(width)); Guard.IsBetweenOrEqualTo(height, 1, FX.D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, nameof(height)); if (!device.D3D12Device->IsDxgiFormatSupported(DXGIFormatHelper.GetForType <T>(), d3D12FormatSupport)) { UnsupportedTextureTypeException.ThrowForTexture2D <T>(); } GraphicsDevice = device; if (device.IsCacheCoherentUMA) { this.d3D12Resource = device.D3D12Device->CreateCommittedResource( resourceType, allocationMode, DXGIFormatHelper.GetForType <T>(), (uint)width, (uint)height, true, out this.d3D12ResourceState); } else { this.allocation = device.Allocator->CreateResource( resourceType, allocationMode, DXGIFormatHelper.GetForType <T>(), (uint)width, (uint)height, out this.d3D12ResourceState); this.d3D12Resource = new ComPtr <ID3D12Resource>(this.allocation.Get()->GetResource()); } this.d3D12CommandListType = this.d3D12ResourceState == D3D12_RESOURCE_STATE_COMMON ? D3D12_COMMAND_LIST_TYPE_COPY : D3D12_COMMAND_LIST_TYPE_COMPUTE; device.D3D12Device->GetCopyableFootprint( DXGIFormatHelper.GetForType <T>(), (uint)width, (uint)height, out this.d3D12PlacedSubresourceFootprint, out _, out _); device.RentShaderResourceViewDescriptorHandles(out D3D12CpuDescriptorHandle, out D3D12GpuDescriptorHandle); switch (resourceType) { case ResourceType.ReadOnly: device.D3D12Device->CreateShaderResourceView(this.d3D12Resource.Get(), DXGIFormatHelper.GetForType <T>(), D3D12_SRV_DIMENSION_TEXTURE2D, D3D12CpuDescriptorHandle); break; case ResourceType.ReadWrite: device.D3D12Device->CreateUnorderedAccessView(this.d3D12Resource.Get(), DXGIFormatHelper.GetForType <T>(), D3D12_UAV_DIMENSION_TEXTURE2D, D3D12CpuDescriptorHandle); break; } this.d3D12Resource.Get()->SetName(this); }
/// <summary> /// Creates a new <see cref="ReadWriteTexture2D{T, TPixel}"/> instance with the specified parameters. /// </summary> /// <param name="device">The <see cref="GraphicsDevice"/> associated with the current instance.</param> /// <param name="width">The width of the texture.</param> /// <param name="height">The height of the texture.</param> /// <param name="allocationMode">The allocation mode to use for the new resource.</param> internal ReadWriteTexture2D(GraphicsDevice device, int width, int height, AllocationMode allocationMode) : base(device, width, height, ResourceType.ReadWrite, allocationMode, D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW) { }
/// <summary> /// Creates a new <see cref="UploadBuffer{T}"/> instance with the specified parameters. /// </summary> /// <param name="device">The <see cref="GraphicsDevice"/> associated with the current instance.</param> /// <param name="length">The number of items to store in the current buffer.</param> /// <param name="allocationMode">The allocation mode to use for the new resource.</param> internal UploadBuffer(GraphicsDevice device, int length, AllocationMode allocationMode) : base(device, length, ResourceType.Upload, allocationMode) { }
/// <summary> /// Creates a new <see cref="ReadOnlyTexture3D{T}"/> instance with the specified parameters. /// </summary> /// <param name="device">The <see cref="GraphicsDevice"/> associated with the current instance.</param> /// <param name="width">The width of the texture.</param> /// <param name="height">The height of the texture.</param> /// <param name="depth">The depth of the texture.</param> /// <param name="allocationMode">The allocation mode to use for the new resource.</param> internal ReadOnlyTexture3D(GraphicsDevice device, int width, int height, int depth, AllocationMode allocationMode) : base(device, width, height, depth, ResourceType.ReadOnly, allocationMode, D3D12_FORMAT_SUPPORT1_TEXTURE3D) { }
public static extern ResultCode GpioCfgMemAlloc(AllocationMode allocationMode);
/// <summary> /// Creates a new <see cref="Buffer{T}"/> instance with the specified parameters. /// </summary> /// <param name="device">The <see cref="GraphicsDevice"/> associated with the current instance.</param> /// <param name="length">The number of items to store in the current buffer.</param> /// <param name="elementSizeInBytes">The size in bytes of each buffer item (including padding, if any).</param> /// <param name="resourceType">The resource type for the current buffer.</param> /// <param name="allocationMode">The allocation mode to use for the new resource.</param> private protected Buffer(GraphicsDevice device, int length, uint elementSizeInBytes, ResourceType resourceType, AllocationMode allocationMode) { device.ThrowIfDisposed(); if (resourceType == ResourceType.Constant) { Guard.IsBetweenOrEqualTo(length, 1, D3D12.D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT, nameof(length)); } else { // The maximum length is set such that the aligned buffer size can't exceed uint.MaxValue Guard.IsBetweenOrEqualTo(length, 1, (uint.MaxValue / elementSizeInBytes) & ~255, nameof(length)); } if (TypeInfo <T> .IsDoubleOrContainsDoubles && device.D3D12Device->CheckFeatureSupport <D3D12_FEATURE_DATA_D3D12_OPTIONS>(D3D12_FEATURE_D3D12_OPTIONS).DoublePrecisionFloatShaderOps == 0) { UnsupportedDoubleOperationsException.Throw <T>(); } nint usableSizeInBytes = checked ((nint)(length * elementSizeInBytes)); nint effectiveSizeInBytes = resourceType == ResourceType.Constant ? AlignmentHelper.Pad(usableSizeInBytes, D3D12.D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT) : usableSizeInBytes; SizeInBytes = usableSizeInBytes; GraphicsDevice = device; Length = length; #if NET6_0_OR_GREATER this.allocation = device.Allocator->CreateResource(device.Pool, resourceType, allocationMode, (ulong)effectiveSizeInBytes); this.d3D12Resource = new ComPtr <ID3D12Resource>(this.allocation.Get()->GetResource()); #else this.d3D12Resource = device.D3D12Device->CreateCommittedResource(resourceType, (ulong)effectiveSizeInBytes, device.IsCacheCoherentUMA); #endif device.RegisterAllocatedResource(); device.RentShaderResourceViewDescriptorHandles(out this.d3D12ResourceDescriptorHandles); device.RentShaderResourceViewDescriptorHandles(out this.d3D12ResourceDescriptorHandlesForTypedUnorderedAccessView); switch (resourceType) { case ResourceType.Constant: device.D3D12Device->CreateConstantBufferView(this.d3D12Resource.Get(), effectiveSizeInBytes, this.d3D12ResourceDescriptorHandles.D3D12CpuDescriptorHandle); break; case ResourceType.ReadOnly: device.D3D12Device->CreateShaderResourceView(this.d3D12Resource.Get(), (uint)length, elementSizeInBytes, this.d3D12ResourceDescriptorHandles.D3D12CpuDescriptorHandle); break; case ResourceType.ReadWrite: device.D3D12Device->CreateUnorderedAccessView(this.d3D12Resource.Get(), (uint)length, elementSizeInBytes, this.d3D12ResourceDescriptorHandles.D3D12CpuDescriptorHandle); device.D3D12Device->CreateUnorderedAccessViewForClear( this.d3D12Resource.Get(), DXGI_FORMAT_R32_UINT, (uint)(usableSizeInBytes / sizeof(uint)), this.d3D12ResourceDescriptorHandlesForTypedUnorderedAccessView.D3D12CpuDescriptorHandle, this.d3D12ResourceDescriptorHandlesForTypedUnorderedAccessView.D3D12CpuDescriptorHandleNonShaderVisible); break; } this.d3D12Resource.Get()->SetName(this); }
/// <summary> /// Creates a new <see cref="TransferTexture2D{T}"/> instance with the specified parameters. /// </summary> /// <param name="device">The <see cref="ComputeSharp.GraphicsDevice"/> associated with the current instance.</param> /// <param name="height">The height of the texture.</param> /// <param name="width">The width of the texture.</param> /// <param name="resourceType">The resource type for the current texture.</param> /// <param name="allocationMode">The allocation mode to use for the new resource.</param> private protected TransferTexture2D(GraphicsDevice device, int width, int height, ResourceType resourceType, AllocationMode allocationMode) { device.ThrowIfDisposed(); Guard.IsBetweenOrEqualTo(width, 1, FX.D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, nameof(width)); Guard.IsBetweenOrEqualTo(height, 1, FX.D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, nameof(height)); if (!device.D3D12Device->IsDxgiFormatSupported(DXGIFormatHelper.GetForType <T>(), D3D12_FORMAT_SUPPORT1_TEXTURE2D)) { UnsupportedTextureTypeException.ThrowForTexture2D <T>(); } GraphicsDevice = device; device.D3D12Device->GetCopyableFootprint( DXGIFormatHelper.GetForType <T>(), (uint)width, (uint)height, out this.d3D12PlacedSubresourceFootprint, out _, out ulong totalSizeInBytes); if (device.IsCacheCoherentUMA) { this.d3D12Resource = device.D3D12Device->CreateCommittedResource(resourceType, allocationMode, totalSizeInBytes, true); } else { this.allocation = device.Allocator->CreateResource(resourceType, allocationMode, totalSizeInBytes); this.d3D12Resource = new ComPtr <ID3D12Resource>(this.allocation.Get()->GetResource()); } this.mappedData = (T *)this.d3D12Resource.Get()->Map().Pointer; this.d3D12Resource.Get()->SetName(this); }
/// <summary> /// Creates a new <see cref="ReadBackTexture3D{T}"/> instance with the specified parameters. /// </summary> /// <param name="device">The <see cref="GraphicsDevice"/> associated with the current instance.</param> /// <param name="width">The width of the texture.</param> /// <param name="height">The height of the texture.</param> /// <param name="depth">The depth of the texture.</param> /// <param name="allocationMode">The allocation mode to use for the new resource.</param> internal ReadBackTexture3D(GraphicsDevice device, int width, int height, int depth, AllocationMode allocationMode) : base(device, width, height, depth, ResourceType.ReadBack, allocationMode) { }