Example #1
0
        /// <summary>
        /// Explicitly recreate buffer with given data. Usually called after a <see cref="GraphicsDevice"/> reset.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataPointer"></param>
        public unsafe void Recreate(IntPtr dataPointer)
        {
            var createInfo = new BufferCreateInfo
            {
                StructureType = StructureType.BufferCreateInfo,
                Size          = (ulong)bufferDescription.SizeInBytes,
                Flags         = BufferCreateFlags.None,
            };

            createInfo.Usage |= BufferUsageFlags.TransferSource;

            // We always fill using transfer
            //if (bufferDescription.Usage != GraphicsResourceUsage.Immutable)
            createInfo.Usage |= BufferUsageFlags.TransferDestination;

            if (Usage == GraphicsResourceUsage.Staging)
            {
                NativeAccessMask         = AccessFlags.HostRead | AccessFlags.HostWrite;
                NativePipelineStageMask |= PipelineStageFlags.Host;
            }
            else
            {
                if ((ViewFlags & BufferFlags.VertexBuffer) != 0)
                {
                    createInfo.Usage        |= BufferUsageFlags.VertexBuffer;
                    NativeAccessMask        |= AccessFlags.VertexAttributeRead;
                    NativePipelineStageMask |= PipelineStageFlags.VertexInput;
                }

                if ((ViewFlags & BufferFlags.IndexBuffer) != 0)
                {
                    createInfo.Usage        |= BufferUsageFlags.IndexBuffer;
                    NativeAccessMask        |= AccessFlags.IndexRead;
                    NativePipelineStageMask |= PipelineStageFlags.VertexInput;
                }

                if ((ViewFlags & BufferFlags.ConstantBuffer) != 0)
                {
                    createInfo.Usage        |= BufferUsageFlags.UniformBuffer;
                    NativeAccessMask        |= AccessFlags.UniformRead;
                    NativePipelineStageMask |= PipelineStageFlags.VertexShader | PipelineStageFlags.FragmentShader;
                }

                if ((ViewFlags & BufferFlags.ShaderResource) != 0)
                {
                    createInfo.Usage        |= BufferUsageFlags.UniformTexelBuffer;
                    NativeAccessMask        |= AccessFlags.ShaderRead;
                    NativePipelineStageMask |= PipelineStageFlags.VertexShader | PipelineStageFlags.FragmentShader;

                    if ((ViewFlags & BufferFlags.UnorderedAccess) != 0)
                    {
                        createInfo.Usage |= BufferUsageFlags.StorageTexelBuffer;
                        NativeAccessMask |= AccessFlags.ShaderWrite;
                    }
                }
            }

            // Create buffer
            NativeBuffer = GraphicsDevice.NativeDevice.CreateBuffer(ref createInfo);

            // Allocate memory
            var memoryProperties = MemoryPropertyFlags.DeviceLocal;

            if (bufferDescription.Usage == GraphicsResourceUsage.Staging || Usage == GraphicsResourceUsage.Dynamic)
            {
                memoryProperties = MemoryPropertyFlags.HostVisible | MemoryPropertyFlags.HostCoherent;
            }

            MemoryRequirements memoryRequirements;

            GraphicsDevice.NativeDevice.GetBufferMemoryRequirements(NativeBuffer, out memoryRequirements);

            AllocateMemory(memoryProperties, memoryRequirements);

            if (NativeMemory != DeviceMemory.Null)
            {
                GraphicsDevice.NativeDevice.BindBufferMemory(NativeBuffer, NativeMemory, 0);
            }

            if (SizeInBytes > 0)
            {
                // Begin copy command buffer
                var commandBufferAllocateInfo = new CommandBufferAllocateInfo
                {
                    StructureType      = StructureType.CommandBufferAllocateInfo,
                    CommandPool        = GraphicsDevice.NativeCopyCommandPool,
                    CommandBufferCount = 1,
                    Level = CommandBufferLevel.Primary
                };
                CommandBuffer commandBuffer;

                lock (GraphicsDevice.QueueLock)
                {
                    GraphicsDevice.NativeDevice.AllocateCommandBuffers(ref commandBufferAllocateInfo, &commandBuffer);
                }

                var beginInfo = new CommandBufferBeginInfo {
                    StructureType = StructureType.CommandBufferBeginInfo, Flags = CommandBufferUsageFlags.OneTimeSubmit
                };
                commandBuffer.Begin(ref beginInfo);

                // Copy to upload buffer
                if (dataPointer != IntPtr.Zero)
                {
                    if (Usage == GraphicsResourceUsage.Dynamic)
                    {
                        var uploadMemory = GraphicsDevice.NativeDevice.MapMemory(NativeMemory, 0, (ulong)SizeInBytes, MemoryMapFlags.None);
                        Utilities.CopyMemory(uploadMemory, dataPointer, SizeInBytes);
                        GraphicsDevice.NativeDevice.UnmapMemory(NativeMemory);
                    }
                    else
                    {
                        var sizeInBytes = bufferDescription.SizeInBytes;
                        SharpVulkan.Buffer uploadResource;
                        int uploadOffset;
                        var uploadMemory = GraphicsDevice.AllocateUploadBuffer(sizeInBytes, out uploadResource, out uploadOffset);

                        Utilities.CopyMemory(uploadMemory, dataPointer, sizeInBytes);

                        // Barrier
                        var memoryBarrier = new BufferMemoryBarrier(uploadResource, AccessFlags.HostWrite, AccessFlags.TransferRead, (ulong)uploadOffset, (ulong)sizeInBytes);
                        commandBuffer.PipelineBarrier(PipelineStageFlags.Host, PipelineStageFlags.Transfer, DependencyFlags.None, 0, null, 1, &memoryBarrier, 0, null);

                        // Copy
                        var bufferCopy = new BufferCopy
                        {
                            SourceOffset      = (uint)uploadOffset,
                            DestinationOffset = 0,
                            Size = (uint)sizeInBytes
                        };
                        commandBuffer.CopyBuffer(uploadResource, NativeBuffer, 1, &bufferCopy);
                    }
                }
                else
                {
                    commandBuffer.FillBuffer(NativeBuffer, 0, (uint)bufferDescription.SizeInBytes, 0);
                }

                // Barrier
                var bufferMemoryBarrier = new BufferMemoryBarrier(NativeBuffer, AccessFlags.TransferWrite, NativeAccessMask);
                commandBuffer.PipelineBarrier(PipelineStageFlags.Transfer, PipelineStageFlags.AllCommands, DependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 0, null);

                // Close and submit
                commandBuffer.End();

                var submitInfo = new SubmitInfo
                {
                    StructureType      = StructureType.SubmitInfo,
                    CommandBufferCount = 1,
                    CommandBuffers     = new IntPtr(&commandBuffer),
                };

                lock (GraphicsDevice.QueueLock)
                {
                    GraphicsDevice.NativeCommandQueue.Submit(1, &submitInfo, Fence.Null);
                    GraphicsDevice.NativeCommandQueue.WaitIdle();
                    //commandBuffer.Reset(CommandBufferResetFlags.None);
                    GraphicsDevice.NativeDevice.FreeCommandBuffers(GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer);
                }

                InitializeViews();
            }
        }
Example #2
0
        private unsafe void InitializeImage(DataBox[] dataBoxes)
        {
            var commandBuffer = GraphicsDevice.NativeCopyCommandBuffer;
            var beginInfo     = new CommandBufferBeginInfo {
                StructureType = StructureType.CommandBufferBeginInfo
            };

            commandBuffer.Begin(ref beginInfo);

            if (dataBoxes != null && dataBoxes.Length > 0)
            {
                int totalSize = dataBoxes.Length * 4;
                for (int i = 0; i < dataBoxes.Length; i++)
                {
                    totalSize += dataBoxes[i].SlicePitch;
                }

                SharpVulkan.Buffer uploadResource;
                int uploadOffset;
                var uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset);

                // Upload buffer barrier
                var bufferMemoryBarrier = new BufferMemoryBarrier(uploadResource, AccessFlags.HostWrite, AccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize);

                // Image barrier
                var initialBarrier = new ImageMemoryBarrier(NativeImage, ImageLayout.Undefined, ImageLayout.TransferDestinationOptimal, AccessFlags.None, AccessFlags.TransferWrite, new ImageSubresourceRange(NativeImageAspect));
                commandBuffer.PipelineBarrier(PipelineStageFlags.TopOfPipe, PipelineStageFlags.Transfer, DependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 1, &initialBarrier);

                // Copy data boxes to upload buffer
                var copies = new BufferImageCopy[dataBoxes.Length];
                for (int i = 0; i < copies.Length; i++)
                {
                    var slicePitch = dataBoxes[i].SlicePitch;

                    int arraySlice        = i / MipLevels;
                    int mipSlice          = i % MipLevels;
                    var mipMapDescription = GetMipMapDescription(mipSlice);

                    SubresourceLayout layout;
                    GraphicsDevice.NativeDevice.GetImageSubresourceLayout(NativeImage, new ImageSubresource(NativeImageAspect, (uint)arraySlice, (uint)mipSlice), out layout);

                    var alignment = ((uploadOffset + 3) & ~3) - uploadOffset;
                    uploadMemory += alignment;
                    uploadOffset += alignment;

                    Utilities.CopyMemory(uploadMemory, dataBoxes[i].DataPointer, slicePitch);

                    // TODO VULKAN: Check if pitches are valid
                    copies[i] = new BufferImageCopy
                    {
                        BufferOffset      = (ulong)uploadOffset,
                        ImageSubresource  = new ImageSubresourceLayers(ImageAspectFlags.Color, (uint)arraySlice, 1, (uint)mipSlice),
                        BufferRowLength   = 0, //(uint)(dataBoxes[i].RowPitch / pixelSize),
                        BufferImageHeight = 0, //(uint)(dataBoxes[i].SlicePitch / dataBoxes[i].RowPitch),
                        ImageOffset       = new Offset3D(0, 0, arraySlice),
                        ImageExtent       = new Extent3D((uint)mipMapDescription.Width, (uint)mipMapDescription.Height, 1)
                    };

                    uploadMemory += slicePitch;
                    uploadOffset += slicePitch;
                }

                // Copy from upload buffer to image
                fixed(BufferImageCopy *copiesPointer = &copies[0])
                {
                    commandBuffer.CopyBufferToImage(uploadResource, NativeImage, ImageLayout.TransferDestinationOptimal, (uint)copies.Length, copiesPointer);
                }

                IsInitialized = true;
            }

            // Transition to default layout
            var imageMemoryBarrier = new ImageMemoryBarrier(NativeImage,
                                                            dataBoxes == null || dataBoxes.Length == 0 ? ImageLayout.Undefined : ImageLayout.TransferDestinationOptimal, NativeLayout,
                                                            dataBoxes == null || dataBoxes.Length == 0 ? AccessFlags.None : AccessFlags.TransferWrite, NativeAccessMask, new ImageSubresourceRange(NativeImageAspect));

            commandBuffer.PipelineBarrier(PipelineStageFlags.Transfer, PipelineStageFlags.AllCommands, DependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier);

            // Close and submit
            commandBuffer.End();

            var submitInfo = new SubmitInfo
            {
                StructureType      = StructureType.SubmitInfo,
                CommandBufferCount = 1,
                CommandBuffers     = new IntPtr(&commandBuffer),
            };

            GraphicsDevice.NativeCommandQueue.Submit(1, &submitInfo, Fence.Null);
            GraphicsDevice.NativeCommandQueue.WaitIdle();
            commandBuffer.Reset(CommandBufferResetFlags.None);
        }
Example #3
0
        internal void UpdateSubresource(GraphicsResource resource, int subResourceIndex, DataBox databox, ResourceRegion region)
        {
            var texture = resource as Texture;

            if (texture != null)
            {
                var width  = region.Right - region.Left;
                var height = region.Bottom - region.Top;
                var depth  = region.Back - region.Front;

                ResourceDescription resourceDescription;
                switch (texture.Dimension)
                {
                case TextureDimension.Texture1D:
                    resourceDescription = ResourceDescription.Texture1D((SharpDX.DXGI.Format)texture.Format, width, 1, 1);
                    break;

                case TextureDimension.Texture2D:
                case TextureDimension.TextureCube:
                    resourceDescription = ResourceDescription.Texture2D((SharpDX.DXGI.Format)texture.Format, width, height, 1, 1);
                    break;

                case TextureDimension.Texture3D:
                    resourceDescription = ResourceDescription.Texture3D((SharpDX.DXGI.Format)texture.Format, width, height, (short)depth, 1);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                // TODO D3D12 allocate in upload heap (placed resources?)
                var nativeUploadTexture = NativeDevice.CreateCommittedResource(new HeapProperties(CpuPageProperty.WriteBack, MemoryPool.L0), HeapFlags.None,
                                                                               resourceDescription,
                                                                               ResourceStates.GenericRead);


                GraphicsDevice.TemporaryResources.Enqueue(new KeyValuePair <long, Pageable>(GraphicsDevice.NextFenceValue, nativeUploadTexture));

                nativeUploadTexture.WriteToSubresource(0, null, databox.DataPointer, databox.RowPitch, databox.SlicePitch);

                var parentResource = resource.ParentResource ?? resource;

                // Trigger copy
                NativeCommandList.ResourceBarrierTransition(resource.NativeResource, parentResource.NativeResourceState, ResourceStates.CopyDestination);
                NativeCommandList.CopyTextureRegion(new TextureCopyLocation(resource.NativeResource, subResourceIndex), region.Left, region.Top, region.Front, new TextureCopyLocation(nativeUploadTexture, 0), null);
                NativeCommandList.ResourceBarrierTransition(resource.NativeResource, ResourceStates.CopyDestination, parentResource.NativeResourceState);
            }
            else
            {
                var buffer = resource as Buffer;
                if (buffer != null)
                {
                    SharpDX.Direct3D12.Resource uploadResource;
                    int uploadOffset;
                    var uploadSize   = region.Right - region.Left;
                    var uploadMemory = GraphicsDevice.AllocateUploadBuffer(region.Right - region.Left, out uploadResource, out uploadOffset);

                    Utilities.CopyMemory(uploadMemory, databox.DataPointer, uploadSize);

                    NativeCommandList.ResourceBarrierTransition(resource.NativeResource, resource.NativeResourceState, ResourceStates.CopyDestination);
                    NativeCommandList.CopyBufferRegion(resource.NativeResource, region.Left, uploadResource, uploadOffset, uploadSize);
                    NativeCommandList.ResourceBarrierTransition(resource.NativeResource, ResourceStates.CopyDestination, resource.NativeResourceState);
                }
                else
                {
                    throw new InvalidOperationException("Unknown resource type");
                }
            }
        }
Example #4
0
        // TODO GRAPHICS REFACTOR what should we do with this?
        /// <summary>
        /// Maps a subresource.
        /// </summary>
        /// <param name="resource">The resource.</param>
        /// <param name="subResourceIndex">Index of the sub resource.</param>
        /// <param name="mapMode">The map mode.</param>
        /// <param name="doNotWait">if set to <c>true</c> this method will return immediately if the resource is still being used by the GPU for writing. Default is false</param>
        /// <param name="offsetInBytes">The offset information in bytes.</param>
        /// <param name="lengthInBytes">The length information in bytes.</param>
        /// <returns>Pointer to the sub resource to map.</returns>
        public MappedResource MapSubresource(GraphicsResource resource, int subResourceIndex, MapMode mapMode, bool doNotWait = false, int offsetInBytes = 0, int lengthInBytes = 0)
        {
            if (resource == null)
            {
                throw new ArgumentNullException("resource");
            }

            var rowPitch    = 0;
            var depthStride = 0;
            var usage       = GraphicsResourceUsage.Default;

            var texture = resource as Texture;

            if (texture != null)
            {
                usage = texture.Usage;
                if (lengthInBytes == 0)
                {
                    lengthInBytes = texture.ComputeSubresourceSize(subResourceIndex);
                }

                rowPitch    = texture.ComputeRowPitch(subResourceIndex % texture.MipLevels);
                depthStride = texture.ComputeSlicePitch(subResourceIndex % texture.MipLevels);

                if (texture.Usage == GraphicsResourceUsage.Staging)
                {
                    // Internally it's a buffer, so adapt resource index and offset
                    offsetInBytes    = texture.ComputeBufferOffset(subResourceIndex, 0);
                    subResourceIndex = 0;
                }
            }
            else
            {
                var buffer = resource as Buffer;
                if (buffer != null)
                {
                    usage = buffer.Usage;
                    if (lengthInBytes == 0)
                    {
                        lengthInBytes = buffer.SizeInBytes;
                    }
                }
            }

            // TODO D3D12 WriteDiscard should just reallocate new buffer, and WriteNoOverwrite shouldn't use that path (for now we defer to upload buffer)
            if (mapMode == MapMode.WriteDiscard || mapMode == MapMode.WriteNoOverwrite)
            {
                SharpDX.Direct3D12.Resource uploadResource;
                int uploadOffset;
                var uploadMemory = GraphicsDevice.AllocateUploadBuffer(lengthInBytes, out uploadResource, out uploadOffset);

                return(new MappedResource(resource, subResourceIndex, new DataBox(uploadMemory, rowPitch, depthStride), offsetInBytes, lengthInBytes)
                {
                    UploadResource = uploadResource, UploadOffset = uploadOffset,
                });
            }
            else if (mapMode == MapMode.Read || mapMode == MapMode.ReadWrite || mapMode == MapMode.Write)
            {
                // Is non-staging ever possible?
                if (usage != GraphicsResourceUsage.Staging)
                {
                    throw new InvalidOperationException();
                }

                if (mapMode != MapMode.WriteNoOverwrite)
                {
                    // Need to wait?
                    if (!GraphicsDevice.IsFenceCompleteInternal(resource.StagingFenceValue))
                    {
                        if (doNotWait)
                        {
                            return(new MappedResource(resource, subResourceIndex, new DataBox(IntPtr.Zero, 0, 0)));
                        }

                        // Need to flush (part of current command list)
                        if (resource.StagingFenceValue == GraphicsDevice.NextFenceValue)
                        {
                            FlushInternal(false);
                        }

                        GraphicsDevice.WaitForFenceInternal(resource.StagingFenceValue);
                    }
                }

                var mappedMemory = resource.NativeResource.Map(subResourceIndex) + offsetInBytes;
                return(new MappedResource(resource, subResourceIndex, new DataBox(mappedMemory, rowPitch, depthStride), offsetInBytes, lengthInBytes));
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Example #5
0
        /// <summary>
        /// Explicitly recreate buffer with given data. Usually called after a <see cref="GraphicsDevice"/> reset.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataPointer"></param>
        public void Recreate(IntPtr dataPointer)
        {
            // TODO D3D12 where should that go longer term? should it be precomputed for future use? (cost would likely be additional check on SetDescriptorSets/Draw)
            NativeResourceState = ResourceStates.Common;
            var bufferFlags = bufferDescription.BufferFlags;

            if ((bufferFlags & BufferFlags.ConstantBuffer) != 0)
            {
                NativeResourceState |= ResourceStates.VertexAndConstantBuffer;
            }

            if ((bufferFlags & BufferFlags.IndexBuffer) != 0)
            {
                NativeResourceState |= ResourceStates.IndexBuffer;
            }

            if ((bufferFlags & BufferFlags.VertexBuffer) != 0)
            {
                NativeResourceState |= ResourceStates.VertexAndConstantBuffer;
            }

            if ((bufferFlags & BufferFlags.ShaderResource) != 0)
            {
                NativeResourceState |= ResourceStates.PixelShaderResource | ResourceStates.NonPixelShaderResource;
            }

            if ((bufferFlags & BufferFlags.UnorderedAccess) != 0)
            {
                NativeResourceState |= ResourceStates.UnorderedAccess;
            }

            if ((bufferFlags & BufferFlags.StructuredBuffer) != 0)
            {
                throw new NotImplementedException();
                if (bufferDescription.StructureByteStride == 0)
                {
                    throw new ArgumentException("Element size cannot be set to 0 for structured buffer");
                }
            }

            if ((bufferFlags & BufferFlags.RawBuffer) == BufferFlags.RawBuffer)
            {
                throw new NotImplementedException();
            }

            if ((bufferFlags & BufferFlags.ArgumentBuffer) == BufferFlags.ArgumentBuffer)
            {
                NativeResourceState |= ResourceStates.IndirectArgument;
            }

            // TODO D3D12 move that to a global allocator in bigger committed resources
            NativeDeviceChild = GraphicsDevice.NativeDevice.CreateCommittedResource(new HeapProperties(HeapType.Default), HeapFlags.None, nativeDescription, dataPointer != IntPtr.Zero ? ResourceStates.CopyDestination : NativeResourceState);

            if (dataPointer != IntPtr.Zero)
            {
                // Copy data in upload heap for later copy
                // TODO D3D12 move that to a shared upload heap
                SharpDX.Direct3D12.Resource uploadResource;
                int uploadOffset;
                var uploadMemory = GraphicsDevice.AllocateUploadBuffer(SizeInBytes, out uploadResource, out uploadOffset);
                Utilities.CopyMemory(uploadMemory, dataPointer, SizeInBytes);

                // TODO D3D12 lock NativeCopyCommandList usages
                var commandList = GraphicsDevice.NativeCopyCommandList;
                commandList.Reset(GraphicsDevice.NativeCopyCommandAllocator, null);
                // Copy from upload heap to actual resource
                commandList.CopyBufferRegion(NativeResource, 0, uploadResource, uploadOffset, SizeInBytes);

                // Switch resource to proper read state
                commandList.ResourceBarrierTransition(NativeResource, 0, ResourceStates.CopyDestination, NativeResourceState);

                commandList.Close();

                GraphicsDevice.NativeCommandQueue.ExecuteCommandList(commandList);

                // TODO D3D12 release uploadResource (using a fence to know when copy is done)
            }
        }
Example #6
0
        /// <summary>
        /// Explicitly recreate buffer with given data. Usually called after a <see cref="GraphicsDevice"/> reset.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataPointer"></param>
        public void Recreate(IntPtr dataPointer)
        {
            // TODO D3D12 where should that go longer term? should it be precomputed for future use? (cost would likely be additional check on SetDescriptorSets/Draw)
            NativeResourceState = ResourceStates.Common;
            var bufferFlags = bufferDescription.BufferFlags;

            if ((bufferFlags & BufferFlags.ConstantBuffer) != 0)
            {
                NativeResourceState |= ResourceStates.VertexAndConstantBuffer;
            }

            if ((bufferFlags & BufferFlags.IndexBuffer) != 0)
            {
                NativeResourceState |= ResourceStates.IndexBuffer;
            }

            if ((bufferFlags & BufferFlags.VertexBuffer) != 0)
            {
                NativeResourceState |= ResourceStates.VertexAndConstantBuffer;
            }

            if ((bufferFlags & BufferFlags.ShaderResource) != 0)
            {
                NativeResourceState |= ResourceStates.PixelShaderResource | ResourceStates.NonPixelShaderResource;
            }

            if ((bufferFlags & BufferFlags.StructuredBuffer) != 0)
            {
                if (bufferDescription.StructureByteStride <= 0)
                {
                    throw new ArgumentException("Element size cannot be less or equal 0 for structured buffer");
                }
            }

            if ((bufferFlags & BufferFlags.ArgumentBuffer) == BufferFlags.ArgumentBuffer)
            {
                NativeResourceState |= ResourceStates.IndirectArgument;
            }

            var heapType = HeapType.Default;

            if (Usage == GraphicsResourceUsage.Staging)
            {
                if (dataPointer != IntPtr.Zero)
                {
                    throw new NotImplementedException("D3D12: Staging buffers can't be created with initial data.");
                }

                heapType            = HeapType.Readback;
                NativeResourceState = ResourceStates.CopyDestination;
            }
            else if (Usage == GraphicsResourceUsage.Dynamic)
            {
                heapType            = HeapType.Upload;
                NativeResourceState = ResourceStates.GenericRead;
            }

            // TODO D3D12 move that to a global allocator in bigger committed resources
            NativeDeviceChild = GraphicsDevice.NativeDevice.CreateCommittedResource(new HeapProperties(heapType), HeapFlags.None, nativeDescription, dataPointer != IntPtr.Zero ? ResourceStates.CopyDestination : NativeResourceState);
            GPUVirtualAddress = NativeResource.GPUVirtualAddress;

            if (dataPointer != IntPtr.Zero)
            {
                if (heapType == HeapType.Upload)
                {
                    var uploadMemory = NativeResource.Map(0);
                    Utilities.CopyMemory(uploadMemory, dataPointer, SizeInBytes);
                    NativeResource.Unmap(0);
                }
                else
                {
                    // Copy data in upload heap for later copy
                    // TODO D3D12 move that to a shared upload heap
                    SharpDX.Direct3D12.Resource uploadResource;
                    int uploadOffset;
                    var uploadMemory = GraphicsDevice.AllocateUploadBuffer(SizeInBytes, out uploadResource, out uploadOffset);
                    Utilities.CopyMemory(uploadMemory, dataPointer, SizeInBytes);

                    // TODO D3D12 lock NativeCopyCommandList usages
                    var commandList = GraphicsDevice.NativeCopyCommandList;
                    commandList.Reset(GraphicsDevice.NativeCopyCommandAllocator, null);
                    // Copy from upload heap to actual resource
                    commandList.CopyBufferRegion(NativeResource, 0, uploadResource, uploadOffset, SizeInBytes);

                    // Switch resource to proper read state
                    commandList.ResourceBarrierTransition(NativeResource, 0, ResourceStates.CopyDestination, NativeResourceState);

                    commandList.Close();

                    GraphicsDevice.WaitCopyQueue();
                }
            }

            NativeShaderResourceView  = GetShaderResourceView(ViewFormat);
            NativeUnorderedAccessView = GetUnorderedAccessView(ViewFormat);
        }
        private void InitializeFromImpl(DataBox[] dataBoxes = null)
        {
            if (ParentTexture != null)
            {
                ParentResource    = ParentTexture;
                NativeDeviceChild = ParentTexture.NativeDeviceChild;
            }

            if (NativeDeviceChild == null)
            {
                ResourceDescription nativeDescription;
                switch (Dimension)
                {
                case TextureDimension.Texture1D:
                    nativeDescription = ConvertToNativeDescription1D();
                    break;

                case TextureDimension.Texture2D:
                case TextureDimension.TextureCube:
                    nativeDescription = ConvertToNativeDescription2D();
                    break;

                case TextureDimension.Texture3D:
                    nativeDescription = ConvertToNativeDescription3D();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                var initialResourceState = ResourceStates.GenericRead;

                var heapType             = HeapType.Default;
                var currentResourceState = initialResourceState;
                if (Usage == GraphicsResourceUsage.Staging)
                {
                    if (dataBoxes != null)
                    {
                        throw new NotImplementedException();
                    }

                    heapType             = HeapType.Readback;
                    initialResourceState = ResourceStates.CopyDestination;
                    currentResourceState = ResourceStates.CopyDestination;
                    nativeDescription    = ResourceDescription.Buffer(ComputeBufferTotalSize());

                    // TODO: Alloc in readback heap as a buffer
                    //return;
                }

                if (dataBoxes != null && dataBoxes.Length > 0)
                {
                    currentResourceState = ResourceStates.CopyDestination;
                }

                // TODO D3D12 move that to a global allocator in bigger committed resources
                NativeDeviceChild             = GraphicsDevice.NativeDevice.CreateCommittedResource(new HeapProperties(heapType), HeapFlags.None, nativeDescription, currentResourceState);
                GraphicsDevice.TextureMemory += (Depth * DepthStride) / (float)0x100000;

                if (dataBoxes != null && dataBoxes.Length > 0)
                {
                    if (Usage == GraphicsResourceUsage.Staging)
                    {
                        throw new NotImplementedException("D3D12: Staging textures can't be created with initial data");
                    }

                    // Trigger copy
                    var commandList = GraphicsDevice.NativeCopyCommandList;
                    commandList.Reset(GraphicsDevice.NativeCopyCommandAllocator, null);

                    long textureCopySize;
                    var  placedSubresources = new PlacedSubResourceFootprint[dataBoxes.Length];
                    var  rowCounts          = new int[dataBoxes.Length];
                    var  rowSizeInBytes     = new long[dataBoxes.Length];
                    GraphicsDevice.NativeDevice.GetCopyableFootprints(ref nativeDescription, 0, dataBoxes.Length, 0, placedSubresources, rowCounts, rowSizeInBytes, out textureCopySize);

                    SharpDX.Direct3D12.Resource uploadResource;
                    int uploadOffset;
                    var uploadMemory = GraphicsDevice.AllocateUploadBuffer((int)textureCopySize, out uploadResource, out uploadOffset, TextureSubresourceAlignment);

                    for (int i = 0; i < dataBoxes.Length; ++i)
                    {
                        var databox     = dataBoxes[i];
                        var dataPointer = databox.DataPointer;

                        var rowCount     = rowCounts[i];
                        var sliceCount   = placedSubresources[i].Footprint.Depth;
                        var rowSize      = (int)rowSizeInBytes[i];
                        var destRowPitch = placedSubresources[i].Footprint.RowPitch;

                        // Memcpy data
                        for (int z = 0; z < sliceCount; ++z)
                        {
                            var uploadMemoryCurrent = uploadMemory + (int)placedSubresources[i].Offset + z * destRowPitch * rowCount;
                            var dataPointerCurrent  = dataPointer + z * databox.SlicePitch;
                            for (int y = 0; y < rowCount; ++y)
                            {
                                Utilities.CopyMemory(uploadMemoryCurrent, dataPointerCurrent, rowSize);
                                uploadMemoryCurrent += destRowPitch;
                                dataPointerCurrent  += databox.RowPitch;
                            }
                        }

                        // Adjust upload offset (circular dependency between GetCopyableFootprints and AllocateUploadBuffer)
                        placedSubresources[i].Offset += uploadOffset;

                        commandList.CopyTextureRegion(new TextureCopyLocation(NativeResource, i), 0, 0, 0, new TextureCopyLocation(uploadResource, placedSubresources[i]), null);
                    }

                    commandList.ResourceBarrierTransition(NativeResource, ResourceStates.CopyDestination, initialResourceState);
                    commandList.Close();

                    GraphicsDevice.WaitCopyQueue();
                }

                NativeResourceState = initialResourceState;
            }

            NativeShaderResourceView = GetShaderResourceView(ViewType, ArraySlice, MipLevel);
            NativeRenderTargetView   = GetRenderTargetView(ViewType, ArraySlice, MipLevel);
            NativeDepthStencilView   = GetDepthStencilView(out HasStencil);
        }
Example #8
0
        private void InitializeFromImpl(DataBox[] dataBoxes = null)
        {
            bool hasInitData = dataBoxes != null && dataBoxes.Length > 0;

            if (ParentTexture != null)
            {
                ParentResource    = ParentTexture;
                NativeDeviceChild = ParentTexture.NativeDeviceChild;
            }

            if (NativeDeviceChild == null)
            {
                ClearValue?clearValue = GetClearValue();

                ResourceDescription nativeDescription;
                switch (Dimension)
                {
                case TextureDimension.Texture1D:
                    nativeDescription = ConvertToNativeDescription1D();
                    break;

                case TextureDimension.Texture2D:
                case TextureDimension.TextureCube:
                    nativeDescription = ConvertToNativeDescription2D();
                    break;

                case TextureDimension.Texture3D:
                    nativeDescription = ConvertToNativeDescription3D();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                var initialResourceState = ResourceStates.GenericRead;

                var heapType             = HeapType.Default;
                var currentResourceState = initialResourceState;
                if (Usage == GraphicsResourceUsage.Staging)
                {
                    heapType            = HeapType.Readback;
                    NativeResourceState = ResourceStates.CopyDestination;
                    int totalSize = ComputeBufferTotalSize();
                    nativeDescription = ResourceDescription.Buffer(totalSize);

                    // Staging textures on DirectX 12 use buffer internally
                    NativeDeviceChild = GraphicsDevice.NativeDevice.CreateCommittedResource(new HeapProperties(heapType), HeapFlags.None, nativeDescription, NativeResourceState);

                    if (hasInitData)
                    {
                        var commandList = GraphicsDevice.NativeCopyCommandList;
                        commandList.Reset(GraphicsDevice.NativeCopyCommandAllocator, null);

                        Resource uploadResource;
                        int      uploadOffset;
                        var      uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset, TextureSubresourceAlignment);

                        // Copy data to the upload buffer
                        int dataBoxIndex         = 0;
                        var uploadMemoryMipStart = uploadMemory;
                        for (int arraySlice = 0; arraySlice < ArraySize; arraySlice++)
                        {
                            for (int mipLevel = 0; mipLevel < MipLevels; mipLevel++)
                            {
                                var databox     = dataBoxes[dataBoxIndex++];
                                var mipHeight   = CalculateMipSize(Width, mipLevel);
                                var mipRowPitch = ComputeRowPitch(mipLevel);

                                var uploadMemoryCurrent = uploadMemoryMipStart;
                                var dataPointerCurrent  = databox.DataPointer;
                                for (int rowIndex = 0; rowIndex < mipHeight; rowIndex++)
                                {
                                    Utilities.CopyMemory(uploadMemoryCurrent, dataPointerCurrent, mipRowPitch);
                                    uploadMemoryCurrent += mipRowPitch;
                                    dataPointerCurrent  += databox.RowPitch;
                                }

                                uploadMemoryMipStart += ComputeSubresourceSize(mipLevel);
                            }
                        }

                        // Copy from upload heap to actual resource
                        commandList.CopyBufferRegion(NativeResource, 0, uploadResource, uploadOffset, totalSize);

                        commandList.Close();

                        StagingFenceValue = 0;
                        GraphicsDevice.WaitCopyQueue();
                    }

                    return;
                }

                if (hasInitData)
                {
                    currentResourceState = ResourceStates.CopyDestination;
                }

                // TODO D3D12 move that to a global allocator in bigger committed resources
                NativeDeviceChild             = GraphicsDevice.NativeDevice.CreateCommittedResource(new HeapProperties(heapType), HeapFlags.None, nativeDescription, currentResourceState, clearValue);
                GraphicsDevice.TextureMemory += (Depth * DepthStride) / (float)0x100000;

                if (hasInitData)
                {
                    // Trigger copy
                    var commandList = GraphicsDevice.NativeCopyCommandList;
                    commandList.Reset(GraphicsDevice.NativeCopyCommandAllocator, null);

                    long textureCopySize;
                    var  placedSubresources = new PlacedSubResourceFootprint[dataBoxes.Length];
                    var  rowCounts          = new int[dataBoxes.Length];
                    var  rowSizeInBytes     = new long[dataBoxes.Length];
                    GraphicsDevice.NativeDevice.GetCopyableFootprints(ref nativeDescription, 0, dataBoxes.Length, 0, placedSubresources, rowCounts, rowSizeInBytes, out textureCopySize);

                    SharpDX.Direct3D12.Resource uploadResource;
                    int uploadOffset;
                    var uploadMemory = GraphicsDevice.AllocateUploadBuffer((int)textureCopySize, out uploadResource, out uploadOffset, TextureSubresourceAlignment);

                    for (int i = 0; i < dataBoxes.Length; ++i)
                    {
                        var databox     = dataBoxes[i];
                        var dataPointer = databox.DataPointer;

                        var rowCount     = rowCounts[i];
                        var sliceCount   = placedSubresources[i].Footprint.Depth;
                        var rowSize      = (int)rowSizeInBytes[i];
                        var destRowPitch = placedSubresources[i].Footprint.RowPitch;

                        // Memcpy data
                        for (int z = 0; z < sliceCount; ++z)
                        {
                            var uploadMemoryCurrent = uploadMemory + (int)placedSubresources[i].Offset + z * destRowPitch * rowCount;
                            var dataPointerCurrent  = dataPointer + z * databox.SlicePitch;
                            for (int y = 0; y < rowCount; ++y)
                            {
                                Utilities.CopyMemory(uploadMemoryCurrent, dataPointerCurrent, rowSize);
                                uploadMemoryCurrent += destRowPitch;
                                dataPointerCurrent  += databox.RowPitch;
                            }
                        }

                        // Adjust upload offset (circular dependency between GetCopyableFootprints and AllocateUploadBuffer)
                        placedSubresources[i].Offset += uploadOffset;

                        commandList.CopyTextureRegion(new TextureCopyLocation(NativeResource, i), 0, 0, 0, new TextureCopyLocation(uploadResource, placedSubresources[i]), null);
                    }

                    commandList.ResourceBarrierTransition(NativeResource, ResourceStates.CopyDestination, initialResourceState);
                    commandList.Close();

                    GraphicsDevice.WaitCopyQueue();
                }

                NativeResourceState = initialResourceState;
            }

            NativeShaderResourceView  = GetShaderResourceView(ViewType, ArraySlice, MipLevel);
            NativeRenderTargetView    = GetRenderTargetView(ViewType, ArraySlice, MipLevel);
            NativeDepthStencilView    = GetDepthStencilView(out HasStencil);
            NativeUnorderedAccessView = GetUnorderedAccessView(ViewType, ArraySlice, MipLevel);
        }
Example #9
0
        private unsafe void InitializeImage(DataBox[] dataBoxes)
        {
            // Begin copy command buffer
            var commandBufferAllocateInfo = new CommandBufferAllocateInfo
            {
                StructureType      = StructureType.CommandBufferAllocateInfo,
                CommandPool        = GraphicsDevice.NativeCopyCommandPool,
                CommandBufferCount = 1,
                Level = CommandBufferLevel.Primary
            };
            CommandBuffer commandBuffer;

            lock (GraphicsDevice.QueueLock)
            {
                GraphicsDevice.NativeDevice.AllocateCommandBuffers(ref commandBufferAllocateInfo, &commandBuffer);
            }

            var beginInfo = new CommandBufferBeginInfo {
                StructureType = StructureType.CommandBufferBeginInfo, Flags = CommandBufferUsageFlags.OneTimeSubmit
            };

            commandBuffer.Begin(ref beginInfo);

            if (dataBoxes != null && dataBoxes.Length > 0)
            {
                // Buffer-to-image copies need to be aligned to the pixel size and 4 (always a power of 2)
                var blockSize     = Format.IsCompressed() ? NativeFormat.BlockSizeInBytes() : TexturePixelSize;
                var alignmentMask = (blockSize < 4 ? 4 : blockSize) - 1;

                int totalSize = dataBoxes.Length * alignmentMask;
                for (int i = 0; i < dataBoxes.Length; i++)
                {
                    totalSize += dataBoxes[i].SlicePitch;
                }

                SharpVulkan.Buffer uploadResource;
                int uploadOffset;
                var uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset);

                // Upload buffer barrier
                var bufferMemoryBarrier = new BufferMemoryBarrier(uploadResource, AccessFlags.HostWrite, AccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize);

                // Image barrier
                var initialBarrier = new ImageMemoryBarrier(NativeImage, ImageLayout.Undefined, ImageLayout.TransferDestinationOptimal, AccessFlags.None, AccessFlags.TransferWrite, new ImageSubresourceRange(NativeImageAspect));
                commandBuffer.PipelineBarrier(PipelineStageFlags.TopOfPipe, PipelineStageFlags.Transfer, DependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 1, &initialBarrier);

                // Copy data boxes to upload buffer
                var copies = new BufferImageCopy[dataBoxes.Length];
                for (int i = 0; i < copies.Length; i++)
                {
                    var slicePitch = dataBoxes[i].SlicePitch;

                    int arraySlice        = i / MipLevels;
                    int mipSlice          = i % MipLevels;
                    var mipMapDescription = GetMipMapDescription(mipSlice);

                    var alignment = ((uploadOffset + alignmentMask) & ~alignmentMask) - uploadOffset;
                    uploadMemory += alignment;
                    uploadOffset += alignment;

                    Utilities.CopyMemory(uploadMemory, dataBoxes[i].DataPointer, slicePitch);

                    // TODO VULKAN: Check if pitches are valid
                    copies[i] = new BufferImageCopy
                    {
                        BufferOffset      = (ulong)uploadOffset,
                        ImageSubresource  = new ImageSubresourceLayers(ImageAspectFlags.Color, (uint)arraySlice, 1, (uint)mipSlice),
                        BufferRowLength   = 0, //(uint)(dataBoxes[i].RowPitch / pixelSize),
                        BufferImageHeight = 0, //(uint)(dataBoxes[i].SlicePitch / dataBoxes[i].RowPitch),
                        ImageOffset       = new Offset3D(0, 0, 0),
                        ImageExtent       = new Extent3D((uint)mipMapDescription.Width, (uint)mipMapDescription.Height, (uint)mipMapDescription.Depth)
                    };

                    uploadMemory += slicePitch;
                    uploadOffset += slicePitch;
                }

                // Copy from upload buffer to image
                fixed(BufferImageCopy *copiesPointer = &copies[0])
                {
                    commandBuffer.CopyBufferToImage(uploadResource, NativeImage, ImageLayout.TransferDestinationOptimal, (uint)copies.Length, copiesPointer);
                }

                IsInitialized = true;
            }

            // Transition to default layout
            var imageMemoryBarrier = new ImageMemoryBarrier(NativeImage,
                                                            dataBoxes == null || dataBoxes.Length == 0 ? ImageLayout.Undefined : ImageLayout.TransferDestinationOptimal, NativeLayout,
                                                            dataBoxes == null || dataBoxes.Length == 0 ? AccessFlags.None : AccessFlags.TransferWrite, NativeAccessMask, new ImageSubresourceRange(NativeImageAspect));

            commandBuffer.PipelineBarrier(PipelineStageFlags.Transfer, PipelineStageFlags.AllCommands, DependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier);

            // Close and submit
            commandBuffer.End();

            var submitInfo = new SubmitInfo
            {
                StructureType      = StructureType.SubmitInfo,
                CommandBufferCount = 1,
                CommandBuffers     = new IntPtr(&commandBuffer),
            };

            lock (GraphicsDevice.QueueLock)
            {
                GraphicsDevice.NativeCommandQueue.Submit(1, &submitInfo, Fence.Null);
                GraphicsDevice.NativeCommandQueue.WaitIdle();
                GraphicsDevice.NativeDevice.FreeCommandBuffers(GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer);
            }
        }