/// <summary> /// To copy data between buffer objects, call: /// </summary> /// <param name="src">is the source buffer.</param> /// <param name="dest">is the destination buffer.</param> /// <param name="region">is a pointer to an array of <see cref="VkBufferCopy"/> structures specifying the regions to copy.</param> public void CopyBuffer(Buffer src, Buffer dest, VkBufferCopy region) { unsafe { VkCommandBuffer.vkCmdCopyBuffer(Handle, src.Handle, dest.Handle, 1, ®ion); } }
protected override void CopyBufferCore( DeviceBuffer source, uint sourceOffset, DeviceBuffer destination, uint destinationOffset, uint sizeInBytes) { EnsureNoRenderPass(); VkBuffer srcVkBuffer = Util.AssertSubtype <DeviceBuffer, VkBuffer>(source); VkBuffer dstVkBuffer = Util.AssertSubtype <DeviceBuffer, VkBuffer>(destination); VkBufferCopy region = new VkBufferCopy { srcOffset = sourceOffset, dstOffset = destinationOffset, size = sizeInBytes }; vkCmdCopyBuffer(_cb, srcVkBuffer.DeviceBuffer, dstVkBuffer.DeviceBuffer, 1, ref region); VkMemoryBarrier barrier; barrier.sType = VkStructureType.MemoryBarrier; barrier.srcAccessMask = VkAccessFlags.TransferWrite; barrier.dstAccessMask = VkAccessFlags.VertexAttributeRead; barrier.pNext = null; vkCmdPipelineBarrier( _cb, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.VertexInput, VkDependencyFlags.None, 1, ref barrier, 0, null, 0, null); }
public void CopyBuffer(Buffer srcBuffer, Buffer dstBuffer, VkBufferCopy region) { unsafe { Device.Commands.cmdCopyBuffer(commandBuffer, srcBuffer.Native, dstBuffer.Native, 1, (IntPtr)(®ion)); } }
public unsafe void CopyBuffer( Buffer source, Buffer destination ) { if (source.Size > destination.Size) { throw new InvalidOperationException("source size cannot be greater than destination"); } var region = new VkBufferCopy { dstOffset = 0, srcOffset = 0, size = source.Size }; VulkanNative.vkCmdCopyBuffer( _handle, source.Handle, destination.Handle, 1, ®ion ); }
public void CopyTo(CommandBuffer cmd, Buffer buff, ulong size = 0, ulong srcOffset = 0, ulong dstOffset = 0) { VkBufferCopy bufferCopy = new VkBufferCopy { size = (size == 0) ? AllocatedDeviceMemorySize : size, srcOffset = srcOffset, dstOffset = dstOffset }; vkCmdCopyBuffer(cmd.Handle, handle, buff.handle, 1, ref bufferCopy); }
public void CopyTo(CommandBuffer cmd, Buffer buff, ulong size = 0, ulong srcOffset = 0, ulong dstOffset = 0) { VkBufferCopy bufferCopy = new VkBufferCopy { size = size, srcOffset = srcOffset, dstOffset = dstOffset }; vkCmdCopyBuffer(cmd.handle, handle, buff.handle, 1, &bufferCopy); }
public void CopyBuffer(Buffer srcBuffer, Buffer dstBuffer) { unsafe { VkBufferCopy region = new VkBufferCopy(); region.srcOffset = 0; region.dstOffset = 0; region.size = System.Math.Min(srcBuffer.Size, dstBuffer.Size); Device.Commands.cmdCopyBuffer(commandBuffer, srcBuffer.Native, dstBuffer.Native, 1, (IntPtr)(®ion)); } }
/// <inheritdoc cref="Copy(GraphicsBuffer, GraphicsBuffer)" /> public void Copy(VulkanGraphicsBuffer destination, VulkanGraphicsBuffer source) { ThrowIfNull(destination, nameof(destination)); ThrowIfNull(source, nameof(source)); var vulkanBufferCopy = new VkBufferCopy { srcOffset = 0, dstOffset = 0, size = Math.Min(destination.Size, source.Size), }; vkCmdCopyBuffer(VulkanCommandBuffer, source.VulkanBuffer, destination.VulkanBuffer, 1, &vulkanBufferCopy); }
void CopyBuffer(VkBuffer src, VkBuffer dst, long size) { var buffer = BeginSingleTimeCommands(); VkBufferCopy region = new VkBufferCopy(); region.srcOffset = 0; region.dstOffset = 0; region.size = size; buffer.CopyBuffer(src, dst, new VkBufferCopy[] { region }); EndSingleTimeCommand(buffer); }
public void Stage(GpuBuffer src, ulong src_off, GpuBuffer dst, ulong dst_off, ulong len) { if (locked) { var bufCopy = new VkBufferCopy() { dstOffset = dst_off, srcOffset = src_off, size = len }; vkCmdCopyBuffer(hndl, src.hndl, dst.hndl, 1, bufCopy.Pointer()); IsEmpty = false; } else { throw new Exception("Command buffer not built."); } }
internal void Copy_Buffer(VkBuffer sourceBuffer, VkBuffer destinationBuffer, VkBufferCopy bufferCopy) { VkBufferMemoryBarrier *bufferBarriers = stackalloc VkBufferMemoryBarrier[2]; bufferBarriers[0x0] = new() { sType = VkStructureType.BufferMemoryBarrier, pNext = null, }; bufferBarriers[0x1] = new() { sType = VkStructureType.BufferMemoryBarrier, pNext = null, }; //vkCmdPipelineBarrier() vkCmdCopyBuffer(handle, sourceBuffer, destinationBuffer, 1, &bufferCopy); }
protected override void CopyBufferCore(Buffer source, uint sourceOffset, Buffer destination, uint destinationOffset, uint sizeInBytes) { EnsureNoRenderPass(); VkBuffer srcVkBuffer = Util.AssertSubtype <Buffer, VkBuffer>(source); VkBuffer dstVkBuffer = Util.AssertSubtype <Buffer, VkBuffer>(destination); VkBufferCopy region = new VkBufferCopy { srcOffset = sourceOffset, dstOffset = destinationOffset, size = sizeInBytes }; vkCmdCopyBuffer(_cb, srcVkBuffer.DeviceBuffer, dstVkBuffer.DeviceBuffer, 1, ref region); _referencedResources.Add(srcVkBuffer); _referencedResources.Add(dstVkBuffer); }
public void SetData(IntPtr data, ulong offset, ulong size) { if ((memoryPropertyFlags & VkMemoryPropertyFlags.HostCoherent) == 0) { using Buffer stagingBuffer = CreateStagingBuffer(size, data); Graphics.WithCommandBuffer((cmd) => { VkBufferCopy copyRegion = new VkBufferCopy { srcOffset = offset, size = size }; cmd.CopyBuffer(stagingBuffer, this, ref copyRegion); }); } else { IntPtr mapped = Map(offset, size); Utilities.CopyBlock(mapped, data, (int)size); Unmap(); } }
internal void CopyBufferTo(VkBuffer srcBuffer, VkBuffer dstBuffer, ulong srcOffset, ulong dstOffset, ulong numBytes) { if (vkCmd.Handle == NullHandle) { return; } CheckBegun(); CheckNotInRenderPass(); VkBufferCopy copyRegion = new VkBufferCopy(); copyRegion.size = numBytes; copyRegion.srcOffset = srcOffset; copyRegion.dstOffset = dstOffset; vkCmdCopyBuffer( vkCmd, srcBuffer, dstBuffer, 1, ©Region); }
void CopyBuffer(VkBuffer src, VkBuffer dst, long size) { var info = new VkCommandBufferAllocateInfo(); info.level = VkCommandBufferLevel.Primary; info.commandBufferCount = 1; var buffers = commandPool.Allocate(info); var buffer = buffers[0]; var beginInfo = new VkCommandBufferBeginInfo(); beginInfo.flags = VkCommandBufferUsageFlags.OneTimeSubmitBit; buffer.Begin(beginInfo); VkBufferCopy region = new VkBufferCopy(); region.srcOffset = 0; region.dstOffset = 0; region.size = size; buffer.CopyBuffer(src, dst, new VkBufferCopy[] { region }); buffer.End(); var submitInfo = new VkSubmitInfo(); submitInfo.commandBuffers = new List <VkCommandBuffer> { buffer }; graphicsQueue.Submit(new List <VkSubmitInfo> { submitInfo }, null); graphicsQueue.WaitIdle(); commandPool.Free(buffers); }
private void EnsureBufferSize(int dataSizeInBytes) { if (_bufferCapacity < (ulong)dataSizeInBytes) { VkBufferCreateInfo newBufferCI = VkBufferCreateInfo.New(); newBufferCI.size = (ulong)dataSizeInBytes; newBufferCI.usage = _usage | VkBufferUsageFlags.TransferDst; VkResult result = vkCreateBuffer(_rc.Device, ref newBufferCI, null, out VkBuffer newBuffer); CheckResult(result); vkGetBufferMemoryRequirements(_rc.Device, newBuffer, out VkMemoryRequirements newMemoryRequirements); uint memoryType = FindMemoryType(_rc.PhysicalDevice, newMemoryRequirements.memoryTypeBits, _memoryProperties); VkMemoryBlock newMemory = _rc.MemoryManager.Allocate( memoryType, newMemoryRequirements.size, newMemoryRequirements.alignment); result = vkBindBufferMemory(_rc.Device, newBuffer, newMemory.DeviceMemory, newMemory.Offset); CheckResult(result); if (_bufferDataSize > 0) { VkCommandBuffer copyCmd = _rc.BeginOneTimeCommands(); VkBufferCopy region = new VkBufferCopy(); region.size = _bufferDataSize; vkCmdCopyBuffer(copyCmd, _buffer, newBuffer, 1, ref region); _rc.EndOneTimeCommands(copyCmd, VkFence.Null); } _rc.MemoryManager.Free(_memory); vkDestroyBuffer(_rc.Device, _buffer, null); _buffer = newBuffer; _memory = newMemory; _bufferCapacity = (ulong)dataSizeInBytes; } }
// Load a model from file using the ASSIMP model loader and generate all resources required to render the model void loadModel(string filename) { // Load the model from file using ASSIMP // Flags for loading the mesh PostProcessSteps assimpFlags = PostProcessSteps.FlipWindingOrder | PostProcessSteps.Triangulate | PostProcessSteps.PreTransformVertices; var scene = new AssimpContext().ImportFile(filename, assimpFlags); // Generate vertex buffer from ASSIMP scene data float scale = 1.0f; NativeList <Vertex> vertexBuffer = new NativeList <Vertex>(); // Iterate through all meshes in the file and extract the vertex components for (int m = 0; m < scene.MeshCount; m++) { for (int v = 0; v < scene.Meshes[(int)m].VertexCount; v++) { Vertex vertex; Mesh mesh = scene.Meshes[m]; // Use glm make_* functions to convert ASSIMP vectors to glm vectors vertex.pos = new Vector3(mesh.Vertices[v].X, mesh.Vertices[v].Y, mesh.Vertices[v].Z) * scale; vertex.normal = new Vector3(mesh.Normals[v].X, mesh.Normals[v].Y, mesh.Normals[v].Z); // Texture coordinates and colors may have multiple channels, we only use the first [0] one vertex.uv = new Vector2(mesh.TextureCoordinateChannels[0][v].X, mesh.TextureCoordinateChannels[0][v].Y); // Mesh may not have vertex colors if (mesh.HasVertexColors(0)) { vertex.color = new Vector3(mesh.VertexColorChannels[0][v].R, mesh.VertexColorChannels[0][v].G, mesh.VertexColorChannels[0][v].B); } else { vertex.color = new Vector3(1f); } // Vulkan uses a right-handed NDC (contrary to OpenGL), so simply flip Y-Axis vertex.pos.Y *= -1.0f; vertexBuffer.Add(vertex); } } ulong vertexBufferSize = (ulong)(vertexBuffer.Count * sizeof(Vertex)); // Generate index buffer from ASSIMP scene data NativeList <uint> indexBuffer = new NativeList <uint>(); for (int m = 0; m < scene.MeshCount; m++) { uint indexBase = indexBuffer.Count; for (int f = 0; f < scene.Meshes[m].FaceCount; f++) { // We assume that all faces are triangulated for (int i = 0; i < 3; i++) { indexBuffer.Add((uint)scene.Meshes[m].Faces[f].Indices[i] + indexBase); } } } ulong indexBufferSize = (ulong)(indexBuffer.Count * sizeof(uint)); model_indices_count = (int)indexBuffer.Count; // Static mesh should always be Device local bool useStaging = true; if (useStaging) { VkBuffer vertexStaging_buffer; VkDeviceMemory vertexStaging_memory; VkBuffer indexStaging_buffer; VkDeviceMemory indexStaging_memory; // Create staging buffers // Vertex data Util.CheckResult(vulkanDevice.createBuffer( VkBufferUsageFlags.TransferSrc, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, vertexBufferSize, &vertexStaging_buffer, &vertexStaging_memory, vertexBuffer.Data.ToPointer())); // Index data Util.CheckResult(vulkanDevice.createBuffer( VkBufferUsageFlags.TransferSrc, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, indexBufferSize, &indexStaging_buffer, &indexStaging_memory, indexBuffer.Data.ToPointer())); // Create Device local buffers // Vertex buffer Util.CheckResult(vulkanDevice.createBuffer( VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst, VkMemoryPropertyFlags.DeviceLocal, vertexBufferSize, out model_vertices_buffer, out model_vertices_memory)); // Index buffer Util.CheckResult(vulkanDevice.createBuffer( VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst, VkMemoryPropertyFlags.DeviceLocal, indexBufferSize, out model_indices_buffer, out model_indices_memory)); // Copy from staging buffers VkCommandBuffer copyCmd = createCommandBuffer(VkCommandBufferLevel.Primary, true); VkBufferCopy copyRegion = new VkBufferCopy(); copyRegion.size = vertexBufferSize; vkCmdCopyBuffer( copyCmd, vertexStaging_buffer, model_vertices_buffer, 1, ©Region); copyRegion.size = indexBufferSize; vkCmdCopyBuffer( copyCmd, indexStaging_buffer, model_indices_buffer, 1, ©Region); flushCommandBuffer(copyCmd, queue, true); vkDestroyBuffer(device, vertexStaging_buffer, null); vkFreeMemory(device, vertexStaging_memory, null); vkDestroyBuffer(device, indexStaging_buffer, null); vkFreeMemory(device, indexStaging_memory, null); } else { // Vertex buffer Util.CheckResult(vulkanDevice.createBuffer( VkBufferUsageFlags.VertexBuffer, VkMemoryPropertyFlags.HostVisible, vertexBufferSize, out model_vertices_buffer, out model_vertices_memory, vertexBuffer.Data.ToPointer())); // Index buffer Util.CheckResult(vulkanDevice.createBuffer( VkBufferUsageFlags.IndexBuffer, VkMemoryPropertyFlags.HostVisible, indexBufferSize, out model_indices_buffer, out model_indices_memory, indexBuffer.Data.ToPointer())); } }
internal static void CopyTextureCore_VkCommandBuffer( VkCommandBuffer cb, Texture source, uint srcX, uint srcY, uint srcZ, uint srcMipLevel, uint srcBaseArrayLayer, Texture destination, uint dstX, uint dstY, uint dstZ, uint dstMipLevel, uint dstBaseArrayLayer, uint width, uint height, uint depth, uint layerCount) { VkTexture srcVkTexture = Util.AssertSubtype <Texture, VkTexture>(source); VkTexture dstVkTexture = Util.AssertSubtype <Texture, VkTexture>(destination); bool sourceIsStaging = (source.Usage & TextureUsage.Staging) == TextureUsage.Staging; bool destIsStaging = (destination.Usage & TextureUsage.Staging) == TextureUsage.Staging; if (!sourceIsStaging && !destIsStaging) { VkImageSubresourceLayers srcSubresource = new VkImageSubresourceLayers { aspectMask = VkImageAspectFlags.Color, layerCount = layerCount, mipLevel = srcMipLevel, baseArrayLayer = srcBaseArrayLayer }; VkImageSubresourceLayers dstSubresource = new VkImageSubresourceLayers { aspectMask = VkImageAspectFlags.Color, layerCount = layerCount, mipLevel = dstMipLevel, baseArrayLayer = dstBaseArrayLayer }; VkImageCopy region = new VkImageCopy { srcOffset = new VkOffset3D { x = (int)srcX, y = (int)srcY, z = (int)srcZ }, dstOffset = new VkOffset3D { x = (int)dstX, y = (int)dstY, z = (int)dstZ }, srcSubresource = srcSubresource, dstSubresource = dstSubresource, extent = new VkExtent3D { width = width, height = height, depth = depth } }; srcVkTexture.TransitionImageLayout( cb, srcMipLevel, 1, srcBaseArrayLayer, layerCount, VkImageLayout.TransferSrcOptimal); dstVkTexture.TransitionImageLayout( cb, dstMipLevel, 1, dstBaseArrayLayer, layerCount, VkImageLayout.TransferDstOptimal); vkCmdCopyImage( cb, srcVkTexture.OptimalDeviceImage, VkImageLayout.TransferSrcOptimal, dstVkTexture.OptimalDeviceImage, VkImageLayout.TransferDstOptimal, 1, ref region); } else if (sourceIsStaging && !destIsStaging) { Vulkan.VkBuffer srcBuffer = srcVkTexture.StagingBuffer; VkSubresourceLayout srcLayout = srcVkTexture.GetSubresourceLayout( srcVkTexture.CalculateSubresource(srcMipLevel, srcBaseArrayLayer)); VkImage dstImage = dstVkTexture.OptimalDeviceImage; dstVkTexture.TransitionImageLayout( cb, dstMipLevel, 1, dstBaseArrayLayer, layerCount, VkImageLayout.TransferDstOptimal); VkImageSubresourceLayers dstSubresource = new VkImageSubresourceLayers { aspectMask = VkImageAspectFlags.Color, layerCount = layerCount, mipLevel = dstMipLevel, baseArrayLayer = dstBaseArrayLayer }; Util.GetMipDimensions(srcVkTexture, srcMipLevel, out uint mipWidth, out uint mipHeight, out uint mipDepth); uint blockSize = FormatHelpers.IsCompressedFormat(srcVkTexture.Format) ? 4u : 1u; uint bufferRowLength = Math.Max(mipWidth, blockSize); uint bufferImageHeight = Math.Max(mipHeight, blockSize); uint compressedX = srcX / blockSize; uint compressedY = srcY / blockSize; uint blockSizeInBytes = blockSize == 1 ? FormatHelpers.GetSizeInBytes(srcVkTexture.Format) : FormatHelpers.GetBlockSizeInBytes(srcVkTexture.Format); uint rowPitch = FormatHelpers.GetRowPitch(bufferRowLength, srcVkTexture.Format); uint depthPitch = FormatHelpers.GetDepthPitch(rowPitch, bufferImageHeight, srcVkTexture.Format); VkBufferImageCopy regions = new VkBufferImageCopy { bufferOffset = srcLayout.offset + (srcZ * depthPitch) + (compressedY * rowPitch) + (compressedX * blockSizeInBytes), bufferRowLength = bufferRowLength, bufferImageHeight = bufferImageHeight, imageExtent = new VkExtent3D { width = width, height = height, depth = depth }, imageOffset = new VkOffset3D { x = (int)dstX, y = (int)dstY, z = (int)dstZ }, imageSubresource = dstSubresource }; vkCmdCopyBufferToImage(cb, srcBuffer, dstImage, VkImageLayout.TransferDstOptimal, 1, ref regions); } else if (!sourceIsStaging && destIsStaging) { VkImage srcImage = srcVkTexture.OptimalDeviceImage; srcVkTexture.TransitionImageLayout( cb, srcMipLevel, 1, srcBaseArrayLayer, layerCount, VkImageLayout.TransferSrcOptimal); Vulkan.VkBuffer dstBuffer = dstVkTexture.StagingBuffer; VkSubresourceLayout dstLayout = dstVkTexture.GetSubresourceLayout( dstVkTexture.CalculateSubresource(dstMipLevel, dstBaseArrayLayer)); VkImageSubresourceLayers srcSubresource = new VkImageSubresourceLayers { aspectMask = VkImageAspectFlags.Color, layerCount = layerCount, mipLevel = srcMipLevel, baseArrayLayer = srcBaseArrayLayer }; Util.GetMipDimensions(dstVkTexture, dstMipLevel, out uint mipWidth, out uint mipHeight, out uint mipDepth); VkBufferImageCopy region = new VkBufferImageCopy { bufferRowLength = mipWidth, bufferImageHeight = mipHeight, bufferOffset = dstLayout.offset + (dstX * FormatHelpers.GetSizeInBytes(dstVkTexture.Format)), imageExtent = new VkExtent3D { width = width, height = height, depth = depth }, imageOffset = new VkOffset3D { x = (int)dstX, y = (int)dstY, z = (int)dstZ }, imageSubresource = srcSubresource }; vkCmdCopyImageToBuffer(cb, srcImage, VkImageLayout.TransferSrcOptimal, dstBuffer, 1, ref region); } else { Debug.Assert(sourceIsStaging && destIsStaging); Vulkan.VkBuffer srcBuffer = srcVkTexture.StagingBuffer; VkSubresourceLayout srcLayout = srcVkTexture.GetSubresourceLayout( srcVkTexture.CalculateSubresource(srcMipLevel, srcBaseArrayLayer)); Vulkan.VkBuffer dstBuffer = dstVkTexture.StagingBuffer; VkSubresourceLayout dstLayout = dstVkTexture.GetSubresourceLayout( dstVkTexture.CalculateSubresource(dstMipLevel, dstBaseArrayLayer)); uint zLimit = Math.Max(depth, layerCount); if (!FormatHelpers.IsCompressedFormat(source.Format)) { uint pixelSize = FormatHelpers.GetSizeInBytes(srcVkTexture.Format); for (uint zz = 0; zz < zLimit; zz++) { for (uint yy = 0; yy < height; yy++) { VkBufferCopy region = new VkBufferCopy { srcOffset = srcLayout.offset + srcLayout.depthPitch * (zz + srcZ) + srcLayout.rowPitch * (yy + srcY) + pixelSize * srcX, dstOffset = dstLayout.offset + dstLayout.depthPitch * (zz + dstZ) + dstLayout.rowPitch * (yy + dstY) + pixelSize * dstX, size = width * pixelSize, }; vkCmdCopyBuffer(cb, srcBuffer, dstBuffer, 1, ref region); } } } else // IsCompressedFormat { uint denseRowSize = FormatHelpers.GetRowPitch(width, source.Format); uint numRows = FormatHelpers.GetNumRows(height, source.Format); uint compressedSrcX = srcX / 4; uint compressedSrcY = srcY / 4; uint compressedDstX = dstX / 4; uint compressedDstY = dstY / 4; uint blockSizeInBytes = FormatHelpers.GetBlockSizeInBytes(source.Format); for (uint zz = 0; zz < zLimit; zz++) { for (uint row = 0; row < numRows; row++) { VkBufferCopy region = new VkBufferCopy { srcOffset = srcLayout.offset + srcLayout.depthPitch * (zz + srcZ) + srcLayout.rowPitch * (row + compressedSrcY) + blockSizeInBytes * compressedSrcX, dstOffset = dstLayout.offset + dstLayout.depthPitch * (zz + dstZ) + dstLayout.rowPitch * (row + compressedDstY) + blockSizeInBytes * compressedDstX, size = denseRowSize, }; vkCmdCopyBuffer(cb, srcBuffer, dstBuffer, 1, ref region); } } } } }
/** * Loads a 3D model from a file into Vulkan buffers * * @param device Pointer to the Vulkan device used to generated the vertex and index buffers on * @param filename File to load (must be a model format supported by ASSIMP) * @param layout Vertex layout components (position, normals, tangents, etc.) * @param createInfo MeshCreateInfo structure for load time settings like scale, center, etc. * @param copyQueue Queue used for the memory staging copy commands (must support transfer) * @param (Optional) flags ASSIMP model loading flags */ //public bool loadFromFile(string filename, vksVertexLayout layout, vksModelCreateInfo* createInfo, vksVulkanDevice device, VkQueue copyQueue, int flags) //{ // this.device = device.LogicalDevice; // ObjFile objFile; // using (var fs = File.OpenRead(filename)) // { // objFile = new ObjParser().Parse(fs); // } // string mtlFilename = Path.ChangeExtension(filename, "mtl"); // MtlFile mtlFile; // using (var fs = File.OpenRead(mtlFilename)) // { // mtlFile = new MtlParser().Parse(fs); // } // if (objFile != null) // { // parts.Clear(); // parts.Resize((uint)objFile.MeshGroups.Length); // Vector3 scale = new Vector3(1.0f); // Vector2 uvscale = new Vector2(1.0f); // Vector3 center = new Vector3(0.0f); // if (createInfo != null) // { // scale = createInfo->Scale; // uvscale = createInfo->UVScale; // center = createInfo->Center; // } // NativeList<float> vertexBuffer = new NativeList<float>(); // NativeList<uint> indexBuffer = new NativeList<uint>(); // vertexCount = 0; // indexCount = 0; // // Load meshes // parts.Count = (uint)objFile.MeshGroups.Length; // for (uint i = 0; i < objFile.MeshGroups.Length; i++) // { // ConstructedMeshInfo mesh = objFile.GetMesh(objFile.MeshGroups[i]); // parts[i] = new ModelPart(); // parts[i].vertexBase = vertexCount; // parts[i].indexBase = indexCount; // vertexCount += (uint)mesh.Vertices.Length; // var material = mtlFile.Definitions[objFile.MeshGroups[i].Material]; // Vector3 pColor = material.DiffuseReflectivity; // Vector3 Zero3D = Vector3.Zero; // for (uint j = 0; j < mesh.Vertices.Length; j++) // { // VertexPositionNormalTexture vertex = mesh.Vertices[j]; // Vector3* pPos = &vertex.Position; // Vector3* pNormal = &vertex.Normal; // Vector2* pTexCoord = &vertex.TextureCoordinates; // Vector3* pTangent = &Zero3D; // Vector3* pBiTangent = &Zero3D; // /* // const aiVector3D* pPos = &(paiMesh->mVertices[j]); // const aiVector3D* pNormal = &(paiMesh->mNormals[j]); // const aiVector3D* pTexCoord = (paiMesh->HasTextureCoords(0)) ? &(paiMesh->mTextureCoords[0][j]) : &Zero3D; // const aiVector3D* pTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mTangents[j]) : &Zero3D; // const aiVector3D* pBiTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mBitangents[j]) : &Zero3D; // */ // foreach (var component in layout.Components) // { // switch (component) // { // case VertexComponent.VERTEX_COMPONENT_POSITION: // vertexBuffer.Add(pPos.X * scale.X + center.X); // vertexBuffer.Add(-pPos.Y * scale.Y + center.Y); // vertexBuffer.Add(pPos.Z * scale.Z + center.Z); // break; // case VertexComponent.VERTEX_COMPONENT_NORMAL: // vertexBuffer.Add(pNormal.X); // vertexBuffer.Add(-pNormal.Y); // vertexBuffer.Add(pNormal.Z); // break; // case VertexComponent.VERTEX_COMPONENT_UV: // vertexBuffer.Add(pTexCoord.X * uvscale.X); // vertexBuffer.Add(pTexCoord.Y * uvscale.Y); // break; // case VertexComponent.VERTEX_COMPONENT_COLOR: // vertexBuffer.Add(pColor.X); // vertexBuffer.Add(pColor.Y); // vertexBuffer.Add(pColor.Z); // break; // case VertexComponent.VERTEX_COMPONENT_TANGENT: // vertexBuffer.Add(pTangent.X); // vertexBuffer.Add(pTangent.Y); // vertexBuffer.Add(pTangent.Z); // break; // case VertexComponent.VERTEX_COMPONENT_BITANGENT: // vertexBuffer.Add(pBiTangent.X); // vertexBuffer.Add(pBiTangent.Y); // vertexBuffer.Add(pBiTangent.Z); // break; // // Dummy components for padding // case VertexComponent.VERTEX_COMPONENT_DUMMY_FLOAT: // vertexBuffer.Add(0.0f); // break; // case VertexComponent.VERTEX_COMPONENT_DUMMY_VEC4: // vertexBuffer.Add(0.0f); // vertexBuffer.Add(0.0f); // vertexBuffer.Add(0.0f); // vertexBuffer.Add(0.0f); // break; // }; // } // dim.Max.X = Math.Max(pPos.X, dim.Max.X); // dim.Max.Y = Math.Max(pPos.Y, dim.Max.Y); // dim.Max.Z = Math.Max(pPos.Z, dim.Max.Z); // dim.Min.X = Math.Min(pPos.X, dim.Min.X); // dim.Min.Y = Math.Min(pPos.Y, dim.Min.Y); // dim.Min.Z = Math.Min(pPos.Z, dim.Min.Z); // } // dim.Size = dim.Max - dim.Min; // parts[i].vertexCount = (uint)mesh.Vertices.Length; // uint indexBase = indexBuffer.Count; // foreach (var index in mesh.Indices) // { // indexBuffer.Add(index); // } // indexCount += (uint)mesh.Indices.Length; // parts[i].indexCount += (uint)mesh.Indices.Length; // /* // for (uint j = 0; j < paiMesh->mNumFaces; j++) // { // const aiFace&Face = paiMesh->mFaces[j]; // if (Face.mNumIndices != 3) // continue; // indexBuffer.Add(indexBase + Face.mIndices[0]); // indexBuffer.Add(indexBase + Face.mIndices[1]); // indexBuffer.Add(indexBase + Face.mIndices[2]); // parts[i].indexCount += 3; // indexCount += 3; // } // */ // } // uint vBufferSize = vertexBuffer.Count * sizeof(float); // uint iBufferSize = indexBuffer.Count * sizeof(uint); // // Use staging buffer to move vertex and index buffer to device local memory // // Create staging buffers // vksBuffer vertexStaging = new vksBuffer(); // vksBuffer indexStaging = new vksBuffer(); // // Vertex buffer // Util.CheckResult(device.createBuffer( // VkBufferUsageFlags.TransferSrc, // VkMemoryPropertyFlags.HostVisible, // vertexStaging, // vBufferSize, // vertexBuffer.Data.ToPointer())); // // Index buffer // Util.CheckResult(device.createBuffer( // VkBufferUsageFlags.TransferSrc, // VkMemoryPropertyFlags.HostVisible, // indexStaging, // iBufferSize, // indexBuffer.Data.ToPointer())); // // Create device local target buffers // // Vertex buffer // Util.CheckResult(device.createBuffer( // VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst, // VkMemoryPropertyFlags.DeviceLocal, // vertices, // vBufferSize)); // // Index buffer // Util.CheckResult(device.createBuffer( // VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst, // VkMemoryPropertyFlags.DeviceLocal, // indices, // iBufferSize)); // // Copy from staging buffers // VkCommandBuffer copyCmd = device.createCommandBuffer(VkCommandBufferLevel.Primary, true); // VkBufferCopy copyRegion = new VkBufferCopy(); // copyRegion.size = vertices.size; // vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, vertices.buffer, 1, ©Region); // copyRegion.size = indices.size; // vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, ©Region); // device.flushCommandBuffer(copyCmd, copyQueue); // // Destroy staging resources // vkDestroyBuffer(device.LogicalDevice, vertexStaging.buffer, null); // vkFreeMemory(device.LogicalDevice, vertexStaging.memory, null); // vkDestroyBuffer(device.LogicalDevice, indexStaging.buffer, null); // vkFreeMemory(device.LogicalDevice, indexStaging.memory, null); // return true; // } // else // { // Console.WriteLine("Error loading file."); // return false; // } //} /** * Loads a 3D model from a file into Vulkan buffers * * @param device Pointer to the Vulkan device used to generated the vertex and index buffers on * @param filename File to load (must be a model format supported by ASSIMP) * @param layout Vertex layout components (position, normals, tangents, etc.) * @param createInfo MeshCreateInfo structure for load time settings like scale, center, etc. * @param copyQueue Queue used for the memory staging copy commands (must support transfer) * @param (Optional) flags ASSIMP model loading flags */ bool loadFromFile(string filename, vksVertexLayout layout, vksModelCreateInfo *createInfo, vksVulkanDevice device, VkQueue copyQueue, PostProcessSteps flags = DefaultPostProcessSteps) { this.device = device.LogicalDevice; // Load file var assimpContext = new AssimpContext(); var pScene = assimpContext.ImportFile(filename, flags); parts.Clear(); parts.Count = (uint)pScene.Meshes.Count; Vector3 scale = new Vector3(1.0f); Vector2 uvscale = new Vector2(1.0f); Vector3 center = new Vector3(0.0f); if (createInfo != null) { scale = createInfo->Scale; uvscale = createInfo->UVScale; center = createInfo->Center; } NativeList <float> vertexBuffer = new NativeList <float>(); NativeList <uint> indexBuffer = new NativeList <uint>(); vertexCount = 0; indexCount = 0; // Load meshes for (int i = 0; i < pScene.Meshes.Count; i++) { var paiMesh = pScene.Meshes[i]; parts[i] = new ModelPart(); parts[i].vertexBase = vertexCount; parts[i].indexBase = indexCount; vertexCount += (uint)paiMesh.VertexCount; var pColor = pScene.Materials[paiMesh.MaterialIndex].ColorDiffuse; Vector3D Zero3D = new Vector3D(0.0f, 0.0f, 0.0f); for (int j = 0; j < paiMesh.VertexCount; j++) { Vector3D pPos = paiMesh.Vertices[j]; Vector3D pNormal = paiMesh.Normals[j]; Vector3D pTexCoord = paiMesh.HasTextureCoords(0) ? paiMesh.TextureCoordinateChannels[0][j] : Zero3D; Vector3D pTangent = paiMesh.HasTangentBasis ? paiMesh.Tangents[j] : Zero3D; Vector3D pBiTangent = paiMesh.HasTangentBasis ? paiMesh.BiTangents[j] : Zero3D; foreach (var component in layout.Components) { switch (component) { case VertexComponent.VERTEX_COMPONENT_POSITION: vertexBuffer.Add(pPos.X * scale.X + center.X); vertexBuffer.Add(-pPos.Y * scale.Y + center.Y); vertexBuffer.Add(pPos.Z * scale.Z + center.Z); break; case VertexComponent.VERTEX_COMPONENT_NORMAL: vertexBuffer.Add(pNormal.X); vertexBuffer.Add(-pNormal.Y); vertexBuffer.Add(pNormal.Z); break; case VertexComponent.VERTEX_COMPONENT_UV: vertexBuffer.Add(pTexCoord.X * uvscale.X); vertexBuffer.Add(pTexCoord.Y * uvscale.Y); break; case VertexComponent.VERTEX_COMPONENT_COLOR: vertexBuffer.Add(pColor.R); vertexBuffer.Add(pColor.G); vertexBuffer.Add(pColor.B); break; case VertexComponent.VERTEX_COMPONENT_TANGENT: vertexBuffer.Add(pTangent.X); vertexBuffer.Add(pTangent.Y); vertexBuffer.Add(pTangent.Z); break; case VertexComponent.VERTEX_COMPONENT_BITANGENT: vertexBuffer.Add(pBiTangent.X); vertexBuffer.Add(pBiTangent.Y); vertexBuffer.Add(pBiTangent.Z); break; // Dummy components for padding case VertexComponent.VERTEX_COMPONENT_DUMMY_FLOAT: vertexBuffer.Add(0.0f); break; case VertexComponent.VERTEX_COMPONENT_DUMMY_VEC4: vertexBuffer.Add(0.0f); vertexBuffer.Add(0.0f); vertexBuffer.Add(0.0f); vertexBuffer.Add(0.0f); break; } ; } dim.Max.X = (float)Math.Max(pPos.X, dim.Max.X); dim.Max.Y = (float)Math.Max(pPos.Y, dim.Max.Y); dim.Max.Z = (float)Math.Max(pPos.Z, dim.Max.Z); dim.Min.X = (float)Math.Min(pPos.X, dim.Min.X); dim.Min.Y = (float)Math.Min(pPos.Y, dim.Min.Y); dim.Min.Z = (float)Math.Min(pPos.Z, dim.Min.Z); } dim.Size = dim.Max - dim.Min; parts[i].vertexCount = (uint)paiMesh.VertexCount; uint indexBase = indexBuffer.Count; for (uint j = 0; j < paiMesh.FaceCount; j++) { var Face = paiMesh.Faces[(int)j]; if (Face.IndexCount != 3) { continue; } indexBuffer.Add(indexBase + (uint)Face.Indices[0]); indexBuffer.Add(indexBase + (uint)Face.Indices[1]); indexBuffer.Add(indexBase + (uint)Face.Indices[2]); parts[i].indexCount += 3; indexCount += 3; } } uint vBufferSize = (vertexBuffer.Count) * sizeof(float); uint iBufferSize = (indexBuffer.Count) * sizeof(uint); // Use staging buffer to move vertex and index buffer to device local memory // Create staging buffers vksBuffer vertexStaging = new vksBuffer(); vksBuffer indexStaging = new vksBuffer(); // Vertex buffer Util.CheckResult(device.createBuffer( VkBufferUsageFlags.TransferSrc, VkMemoryPropertyFlags.HostVisible, vertexStaging, vBufferSize, vertexBuffer.Data.ToPointer())); // Index buffer Util.CheckResult(device.createBuffer( VkBufferUsageFlags.TransferSrc, VkMemoryPropertyFlags.HostVisible, indexStaging, iBufferSize, indexBuffer.Data.ToPointer())); // Create device local target buffers // Vertex buffer Util.CheckResult(device.createBuffer( VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst, VkMemoryPropertyFlags.DeviceLocal, vertices, vBufferSize)); // Index buffer Util.CheckResult(device.createBuffer( VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst, VkMemoryPropertyFlags.DeviceLocal, indices, iBufferSize)); // Copy from staging buffers VkCommandBuffer copyCmd = device.createCommandBuffer(VkCommandBufferLevel.Primary, true); VkBufferCopy copyRegion = new VkBufferCopy(); copyRegion.size = vertices.size; vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, vertices.buffer, 1, ©Region); copyRegion.size = indices.size; vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, ©Region); device.flushCommandBuffer(copyCmd, copyQueue); // Destroy staging resources vkDestroyBuffer(device.LogicalDevice, vertexStaging.buffer, null); vkFreeMemory(device.LogicalDevice, vertexStaging.memory, null); vkDestroyBuffer(device.LogicalDevice, indexStaging.buffer, null); vkFreeMemory(device.LogicalDevice, indexStaging.memory, null); return(true); }
private unsafe void InitializeData(DataBox[] dataBoxes) { // Begin copy command buffer var commandBufferAllocateInfo = new VkCommandBufferAllocateInfo { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = GraphicsDevice.NativeCopyCommandPools.Value, commandBufferCount = 1, level = VkCommandBufferLevel.Primary }; VkCommandBuffer commandBuffer; vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocateInfo, &commandBuffer); var beginInfo = new VkCommandBufferBeginInfo { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit }; vkBeginCommandBuffer(commandBuffer, &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.BlockSize(); var alignmentMask = (blockSize < 4 ? 4 : blockSize) - 1; int totalSize = dataBoxes.Length * alignmentMask; for (int i = 0; i < dataBoxes.Length; i++) { totalSize += dataBoxes[i].SlicePitch; } VkBuffer uploadResource; int uploadOffset; var uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset); // Upload buffer barrier var bufferBarriers = stackalloc VkBufferMemoryBarrier[2]; bufferBarriers[0] = new VkBufferMemoryBarrier(uploadResource, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize); if (Usage == GraphicsResourceUsage.Staging) { bufferBarriers[1] = new VkBufferMemoryBarrier(NativeBuffer, NativeAccessMask, VkAccessFlags.TransferWrite); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 2, bufferBarriers, 0, null); } else { // Image barrier var initialBarrier = new VkImageMemoryBarrier(NativeImage, new VkImageSubresourceRange(NativeImageAspect, 0, uint.MaxValue, 0, uint.MaxValue), VkAccessFlags.None, VkAccessFlags.TransferWrite, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 1, bufferBarriers, 1, &initialBarrier); } // Copy data boxes to upload buffer for (int i = 0; i < dataBoxes.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); if (Usage == GraphicsResourceUsage.Staging) { var copy = new VkBufferCopy { srcOffset = (ulong)uploadOffset, dstOffset = (ulong)ComputeBufferOffset(i, 0), size = (uint)ComputeSubresourceSize(i), }; vkCmdCopyBuffer(commandBuffer, uploadResource, NativeBuffer, 1, ©); } else { // TODO VULKAN: Check if pitches are valid var copy = new VkBufferImageCopy { bufferOffset = (ulong)uploadOffset, imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)mipSlice, (uint)arraySlice, 1), bufferRowLength = (uint)(dataBoxes[i].RowPitch * Format.BlockWidth() / Format.BlockSize()), bufferImageHeight = (uint)(dataBoxes[i].SlicePitch * Format.BlockHeight() / dataBoxes[i].RowPitch), imageOffset = new Vortice.Mathematics.Point3(0, 0, 0), imageExtent = new Vortice.Mathematics.Size3(mipMapDescription.Width, mipMapDescription.Height, mipMapDescription.Depth) }; // Copy from upload buffer to image vkCmdCopyBufferToImage(commandBuffer, uploadResource, NativeImage, VkImageLayout.TransferDstOptimal, 1, ©); } uploadMemory += slicePitch; uploadOffset += slicePitch; } if (Usage == GraphicsResourceUsage.Staging) { bufferBarriers[0] = new VkBufferMemoryBarrier(NativeBuffer, VkAccessFlags.TransferWrite, NativeAccessMask); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 1, bufferBarriers, 0, null); } IsInitialized = true; } if (Usage != GraphicsResourceUsage.Staging) { // Transition to default layout var imageMemoryBarrier = new VkImageMemoryBarrier(NativeImage, new VkImageSubresourceRange(NativeImageAspect, 0, uint.MaxValue, 0, uint.MaxValue), dataBoxes == null || dataBoxes.Length == 0 ? VkAccessFlags.None : VkAccessFlags.TransferWrite, NativeAccessMask, dataBoxes == null || dataBoxes.Length == 0 ? VkImageLayout.Undefined : VkImageLayout.TransferDstOptimal, NativeLayout); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); } // Close and submit vkEndCommandBuffer(commandBuffer); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, commandBufferCount = 1, pCommandBuffers = &commandBuffer, }; lock (GraphicsDevice.QueueLock) { vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, VkFence.Null); vkQueueWaitIdle(GraphicsDevice.NativeCommandQueue); } vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPools.Value, 1, &commandBuffer); }
private static VulkanBuffer GetBuffer <T>(VulkanContext ctx, T[] data, VkBufferUsageFlags usage) where T : unmanaged { long size = data.Length * Unsafe.SizeOf <T>(); // Create a staging buffer that is writable by host. var stagingCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, usage = VkBufferUsageFlags.TransferSrc, sharingMode = VkSharingMode.Exclusive, size = (ulong)size }; VkBuffer stagingBuffer; VkResult result = vkCreateBuffer( ctx.Device, &stagingCreateInfo, null, out stagingBuffer); result.CheckResult(); VkMemoryRequirements stagingReq; vkGetBufferMemoryRequirements(ctx.Device, stagingBuffer, out stagingReq); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); uint stagingMemoryTypeIndex = BufferHelper.GetMemoryTypeIndex(stagingReq.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent, memoryProperties); VkMemoryAllocateInfo allocateInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = stagingReq.size, memoryTypeIndex = stagingMemoryTypeIndex }; VkDeviceMemory stagingMemory; result = vkAllocateMemory(ctx.Device, &allocateInfo, null, &stagingMemory); result.CheckResult(); void *vertexPtr; result = vkMapMemory(ctx.Device, stagingMemory, 0, (ulong)stagingReq.size, 0, &vertexPtr); result.CheckResult(); fixed(T *dataPtr = &data[0]) { System.Buffer.MemoryCopy(dataPtr, vertexPtr, size, size); } vkUnmapMemory(ctx.Device, stagingMemory); result = vkBindBufferMemory(ctx.Device, stagingBuffer, stagingMemory, 0); // Create a device local buffer where the data will be copied and which will be used for rendering. var bufferCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, usage = usage | VkBufferUsageFlags.TransferDst, sharingMode = VkSharingMode.Exclusive, size = (ulong)size }; VkBuffer buffer; result = vkCreateBuffer( ctx.Device, &bufferCreateInfo, null, out buffer); result.CheckResult(); VkMemoryRequirements req; vkGetBufferMemoryRequirements(ctx.Device, buffer, out req); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memProps); uint memoryTypeIndex = BufferHelper.GetMemoryTypeIndex(req.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, memProps); VkMemoryAllocateInfo bufferAllocInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = req.size, memoryTypeIndex = memoryTypeIndex }; VkDeviceMemory memory; result = vkAllocateMemory(ctx.Device, &bufferAllocInfo, null, &memory); result.CheckResult(); result = vkBindBufferMemory(ctx.Device, buffer, memory, 0); // Copy the data from staging buffers to device local buffers. VkCommandBufferAllocateInfo allocInfo = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = ctx.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = 1, }; VkCommandBuffer cmdBuffer; vkAllocateCommandBuffers(ctx.Device, &allocInfo, &cmdBuffer); VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo() { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit, }; result = vkBeginCommandBuffer(cmdBuffer, &beginInfo); result.CheckResult(); VkBufferCopy bufferCopy = new VkBufferCopy { size = (ulong)size }; vkCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, 1, &bufferCopy); result = vkEndCommandBuffer(cmdBuffer); result.CheckResult(); // Submit. VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo, pNext = null }; VkFence fence; result = vkCreateFence(ctx.Device, &fenceCreateInfo, null, out fence); result.CheckResult(); VkSubmitInfo submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, pNext = null, commandBufferCount = 1, pCommandBuffers = &cmdBuffer }; result = vkQueueSubmit(ctx.GraphicsQueue, 1, &submitInfo, fence); result = vkWaitForFences(ctx.Device, 1, &fence, false, ulong.MaxValue); result.CheckResult(); // Cleanup. vkDestroyFence(ctx.Device, fence, null); vkFreeCommandBuffers(ctx.Device, ctx.GraphicsCommandPool, 1, &cmdBuffer); vkDestroyBuffer(ctx.Device, stagingBuffer, null); vkFreeMemory(ctx.Device, stagingMemory, null); return(new VulkanBuffer(ctx.Device, ctx.GraphicsCommandPool, buffer, memory, data.Length)); }
/// <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 VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, size = (ulong)bufferDescription.SizeInBytes, flags = VkBufferCreateFlags.None, }; createInfo.usage |= VkBufferUsageFlags.TransferSrc; // We always fill using transfer //if (bufferDescription.Usage != GraphicsResourceUsage.Immutable) createInfo.usage |= VkBufferUsageFlags.TransferDst; if (Usage == GraphicsResourceUsage.Staging) { NativeAccessMask = VkAccessFlags.HostRead | VkAccessFlags.HostWrite; NativePipelineStageMask |= VkPipelineStageFlags.Host; } else { if ((ViewFlags & BufferFlags.VertexBuffer) != 0) { createInfo.usage |= VkBufferUsageFlags.VertexBuffer; NativeAccessMask |= VkAccessFlags.VertexAttributeRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexInput; } if ((ViewFlags & BufferFlags.IndexBuffer) != 0) { createInfo.usage |= VkBufferUsageFlags.IndexBuffer; NativeAccessMask |= VkAccessFlags.IndexRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexInput; } if ((ViewFlags & BufferFlags.ConstantBuffer) != 0) { createInfo.usage |= VkBufferUsageFlags.UniformBuffer; NativeAccessMask |= VkAccessFlags.UniformRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader; } if ((ViewFlags & BufferFlags.ShaderResource) != 0) { createInfo.usage |= VkBufferUsageFlags.UniformTexelBuffer; NativeAccessMask |= VkAccessFlags.ShaderRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader; if ((ViewFlags & BufferFlags.UnorderedAccess) != 0) { createInfo.usage |= VkBufferUsageFlags.StorageTexelBuffer; NativeAccessMask |= VkAccessFlags.ShaderWrite; } } } // Create buffer vkCreateBuffer(GraphicsDevice.NativeDevice, &createInfo, null, out NativeBuffer); // Allocate memory var memoryProperties = VkMemoryPropertyFlags.DeviceLocal; if (bufferDescription.Usage == GraphicsResourceUsage.Staging || Usage == GraphicsResourceUsage.Dynamic) { memoryProperties = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent; } vkGetBufferMemoryRequirements(GraphicsDevice.NativeDevice, NativeBuffer, out var memoryRequirements); AllocateMemory(memoryProperties, memoryRequirements); if (NativeMemory != VkDeviceMemory.Null) { vkBindBufferMemory(GraphicsDevice.NativeDevice, NativeBuffer, NativeMemory, 0); } if (SizeInBytes > 0) { // Begin copy command buffer var commandBufferAllocateInfo = new VkCommandBufferAllocateInfo { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = GraphicsDevice.NativeCopyCommandPool, commandBufferCount = 1, level = VkCommandBufferLevel.Primary }; VkCommandBuffer commandBuffer; lock (GraphicsDevice.QueueLock) { vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocateInfo, &commandBuffer); } var beginInfo = new VkCommandBufferBeginInfo { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit }; vkBeginCommandBuffer(commandBuffer, &beginInfo); // Copy to upload buffer if (dataPointer != IntPtr.Zero) { if (Usage == GraphicsResourceUsage.Dynamic) { void *uploadMemory; vkMapMemory(GraphicsDevice.NativeDevice, NativeMemory, 0, (ulong)SizeInBytes, VkMemoryMapFlags.None, &uploadMemory); Utilities.CopyMemory((IntPtr)uploadMemory, dataPointer, SizeInBytes); vkUnmapMemory(GraphicsDevice.NativeDevice, NativeMemory); } else { var sizeInBytes = bufferDescription.SizeInBytes; VkBuffer uploadResource; int uploadOffset; var uploadMemory = GraphicsDevice.AllocateUploadBuffer(sizeInBytes, out uploadResource, out uploadOffset); Utilities.CopyMemory(uploadMemory, dataPointer, sizeInBytes); // Barrier var memoryBarrier = new VkBufferMemoryBarrier(uploadResource, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, (ulong)uploadOffset, (ulong)sizeInBytes); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 1, &memoryBarrier, 0, null); // Copy var bufferCopy = new VkBufferCopy { srcOffset = (uint)uploadOffset, dstOffset = 0, size = (uint)sizeInBytes }; vkCmdCopyBuffer(commandBuffer, uploadResource, NativeBuffer, 1, &bufferCopy); } } else { vkCmdFillBuffer(commandBuffer, NativeBuffer, 0, (uint)bufferDescription.SizeInBytes, 0); } // Barrier var bufferMemoryBarrier = new VkBufferMemoryBarrier(NativeBuffer, VkAccessFlags.TransferWrite, NativeAccessMask); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 0, null); // Close and submit vkEndCommandBuffer(commandBuffer); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, commandBufferCount = 1, pCommandBuffers = &commandBuffer, }; lock (GraphicsDevice.QueueLock) { vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, VkFence.Null); vkQueueWaitIdle(GraphicsDevice.NativeCommandQueue); //commandBuffer.Reset(VkCommandBufferResetFlags.None); vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer); } InitializeViews(); } }
/// <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) { // capture vertex information for things less than ~512 verts for possible later easy batching if (dataPointer != IntPtr.Zero && (ViewFlags == BufferFlags.VertexBuffer && bufferDescription.SizeInBytes <= CaptureVertexBuffersOfSize || ViewFlags == BufferFlags.IndexBuffer && bufferDescription.SizeInBytes <= CaptureIndexBuffersOfSize)) { VertIndexData = new byte[Description.SizeInBytes]; fixed(byte *vid = &VertIndexData[0]) { Utilities.CopyMemory((IntPtr)vid, dataPointer, VertIndexData.Length); } } else { VertIndexData = null; } var createInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, size = (ulong)bufferDescription.SizeInBytes, flags = VkBufferCreateFlags.None, }; createInfo.usage |= VkBufferUsageFlags.TransferSrc; // We always fill using transfer //if (bufferDescription.Usage != GraphicsResourceUsage.Immutable) createInfo.usage |= VkBufferUsageFlags.TransferDst; if (Usage == GraphicsResourceUsage.Staging) { NativeAccessMask = VkAccessFlags.HostRead | VkAccessFlags.HostWrite; NativePipelineStageMask |= VkPipelineStageFlags.Host; } else { if ((ViewFlags & BufferFlags.VertexBuffer) != 0) { createInfo.usage |= VkBufferUsageFlags.VertexBuffer; NativeAccessMask |= VkAccessFlags.VertexAttributeRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexInput; } if ((ViewFlags & BufferFlags.IndexBuffer) != 0) { createInfo.usage |= VkBufferUsageFlags.IndexBuffer; NativeAccessMask |= VkAccessFlags.IndexRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexInput; } if ((ViewFlags & BufferFlags.ConstantBuffer) != 0) { createInfo.usage |= VkBufferUsageFlags.UniformBuffer; NativeAccessMask |= VkAccessFlags.UniformRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader; } if ((ViewFlags & BufferFlags.ShaderResource) != 0) { createInfo.usage |= VkBufferUsageFlags.UniformTexelBuffer; NativeAccessMask |= VkAccessFlags.ShaderRead; NativePipelineStageMask |= VkPipelineStageFlags.VertexShader | VkPipelineStageFlags.FragmentShader; if ((ViewFlags & BufferFlags.UnorderedAccess) != 0) { createInfo.usage |= VkBufferUsageFlags.StorageTexelBuffer; NativeAccessMask |= VkAccessFlags.ShaderWrite; } } } // Create buffer vkCreateBuffer(GraphicsDevice.NativeDevice, &createInfo, null, out NativeBuffer); // Allocate memory var memoryProperties = VkMemoryPropertyFlags.DeviceLocal; if (bufferDescription.Usage == GraphicsResourceUsage.Staging || Usage == GraphicsResourceUsage.Dynamic) { memoryProperties = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent; } vkGetBufferMemoryRequirements(GraphicsDevice.NativeDevice, NativeBuffer, out var memoryRequirements); AllocateMemory(memoryProperties, memoryRequirements); if (NativeMemory != VkDeviceMemory.Null) { vkBindBufferMemory(GraphicsDevice.NativeDevice, NativeBuffer, NativeMemory, 0); } if (SizeInBytes > 0) { // Begin copy command buffer var commandBufferAllocateInfo = new VkCommandBufferAllocateInfo { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = GraphicsDevice.NativeCopyCommandPool, commandBufferCount = 1, level = VkCommandBufferLevel.Primary }; VkCommandBuffer commandBuffer; lock (BufferLocker) { vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocateInfo, &commandBuffer); } var beginInfo = new VkCommandBufferBeginInfo { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit }; vkBeginCommandBuffer(commandBuffer, &beginInfo); GraphicsDevice.UploadBuffer?uploadBuffer = null; // Copy to upload buffer if (dataPointer != IntPtr.Zero) { if (Usage == GraphicsResourceUsage.Dynamic) { void *uploadMemory; vkMapMemory(GraphicsDevice.NativeDevice, NativeMemory, 0, (ulong)SizeInBytes, VkMemoryMapFlags.None, &uploadMemory); Utilities.CopyMemory((IntPtr)uploadMemory, dataPointer, SizeInBytes); lock (BufferLocker) { vkUnmapMemory(GraphicsDevice.NativeDevice, NativeMemory); } } else { var sizeInBytes = bufferDescription.SizeInBytes; int uploadOffset; GraphicsDevice.AllocateOneTimeUploadBuffer(sizeInBytes, out var upBuf); uploadBuffer = upBuf; Utilities.CopyMemory(uploadBuffer.Value.address, dataPointer, sizeInBytes); // Barrier var memoryBarrier = new VkBufferMemoryBarrier(uploadBuffer.Value.buffer, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, 0, (ulong)sizeInBytes); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Host, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 1, &memoryBarrier, 0, null); // Copy var bufferCopy = new VkBufferCopy { srcOffset = 0, dstOffset = 0, size = (uint)sizeInBytes }; vkCmdCopyBuffer(commandBuffer, uploadBuffer.Value.buffer, NativeBuffer, 1, &bufferCopy); } } else { vkCmdFillBuffer(commandBuffer, NativeBuffer, 0, (uint)bufferDescription.SizeInBytes, 0); } // Barrier var bufferMemoryBarrier = new VkBufferMemoryBarrier(NativeBuffer, VkAccessFlags.TransferWrite, NativeAccessMask); vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 0, null); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, commandBufferCount = 1, pCommandBuffers = &commandBuffer, }; var fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo }; vkCreateFence(GraphicsDevice.NativeDevice, &fenceCreateInfo, null, out var fence); // Close and submit vkEndCommandBuffer(commandBuffer); using (GraphicsDevice.QueueLock.ReadLock()) { vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, fence); } vkWaitForFences(GraphicsDevice.NativeDevice, 1, &fence, true, ulong.MaxValue); vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPool, 1, &commandBuffer); vkDestroyFence(GraphicsDevice.NativeDevice, fence, null); if (uploadBuffer.HasValue) { GraphicsDevice.FreeOneTimeUploadBuffer(uploadBuffer.Value); } InitializeViews(); } }