Esempio n. 1
0
 public AllocationException(string message, int requestedSize, int requestedAlignment, AllocationMode requestedMode)
     : base(message)
 {
     RequestedSize      = requestedSize;
     RequestedAlignment = requestedAlignment;
     RequestedMode      = requestedMode;
 }
Esempio n. 2
0
        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);
                        }
                    }
                }
            }
        }
Esempio n. 3
0
 public AllocationException(int requestedSize, int requestedAlignment, AllocationMode requestedMode)
     : this($"Could not allocate the requested size of {requestedSize}. Alignment: {requestedAlignment}, mode: {requestedMode}",
            requestedSize,
            requestedAlignment,
            requestedMode)
 {
 }
Esempio n. 4
0
    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);
     }
 }
Esempio n. 7
0
 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);
        }
Esempio n. 9
0
        /// <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,
            });
        }
Esempio n. 11
0
    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);
        }
    }
Esempio n. 12
0
        /// <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();
            }
        }
Esempio n. 14
0
 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);
     }
 }
Esempio n. 15
0
 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);
     }
 }
Esempio n. 16
0
    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);
            }
        }
    }
Esempio n. 17
0
        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);
                }
            }
        }
Esempio n. 18
0
    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);
            }
        }
    }
Esempio n. 20
0
    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)
 {
 }
Esempio n. 22
0
 /// <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)
 {
 }
Esempio n. 23
0
        /// <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);
        }
Esempio n. 24
0
 /// <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)
 {
 }
Esempio n. 25
0
 /// <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)
 {
 }
Esempio n. 26
0
 /// <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)
 {
 }
Esempio n. 27
0
 public static extern ResultCode GpioCfgMemAlloc(AllocationMode allocationMode);
Esempio n. 28
0
    /// <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)
 {
 }