Beispiel #1
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.RegisterTextureMemoryUsage(SizeInBytes);

                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);
        }
Beispiel #2
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);
        }