protected void TransitionImageLayout(VkImage image, uint mipLevels, uint baseArrayLayer, uint layerCount, VkImageLayout oldLayout, VkImageLayout newLayout) { VkCommandBuffer cb = BeginOneTimeCommands(); VkImageMemoryBarrier barrier = VkImageMemoryBarrier.New(); barrier.oldLayout = oldLayout; barrier.newLayout = newLayout; barrier.srcQueueFamilyIndex = QueueFamilyIgnored; barrier.dstQueueFamilyIndex = QueueFamilyIgnored; barrier.image = image; barrier.subresourceRange.aspectMask = VkImageAspectFlags.Color; barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.levelCount = mipLevels; barrier.subresourceRange.baseArrayLayer = baseArrayLayer; barrier.subresourceRange.layerCount = layerCount; vkCmdPipelineBarrier( cb, VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.TopOfPipe, VkDependencyFlags.None, 0, null, 0, null, 1, &barrier); EndOneTimeCommands(cb); }
private void setImageMemoryBarrier(VkCommandBuffer command, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout, VkImage image, VkImageAspectFlags aspectFlags) { var imageMemoryBarrier = new VkImageMemoryBarrier() { srcAccessMask = srcAccessMask, dstAccessMask = dstAccessMask, oldLayout = oldLayout, newLayout = newLayout, srcQueueFamilyIndex = ~0u, dstQueueFamilyIndex = ~0u, subresourceRange = new VkImageSubresourceRange { aspectMask = aspectFlags, baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1, }, image = image }; VulkanAPI.vkCmdPipelineBarrier( command, VkPipelineStageFlags.VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VkPipelineStageFlags.VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, null, // MemoryBarriers null, // BufferMemoryBarriers new VkImageMemoryBarrier[] { imageMemoryBarrier } ); }
public void SetLayout( CommandBuffer cmdbuffer, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkImageSubresourceRange subresourceRange, VkPipelineStageFlags srcStageMask = VkPipelineStageFlags.AllCommands, VkPipelineStageFlags dstStageMask = VkPipelineStageFlags.AllCommands, uint srcQueueFamilyIndex = Vk.QueueFamilyIgnored, uint dstQueueFamilyIndex = Vk.QueueFamilyIgnored) { VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New(); imageMemoryBarrier.srcQueueFamilyIndex = srcQueueFamilyIndex; imageMemoryBarrier.dstQueueFamilyIndex = dstQueueFamilyIndex; imageMemoryBarrier.oldLayout = oldImageLayout; imageMemoryBarrier.newLayout = newImageLayout; imageMemoryBarrier.image = handle; imageMemoryBarrier.subresourceRange = subresourceRange; imageMemoryBarrier.srcAccessMask = srcAccessMask; imageMemoryBarrier.dstAccessMask = dstAccessMask; Vk.vkCmdPipelineBarrier( cmdbuffer.Handle, srcStageMask, dstStageMask, 0, 0, IntPtr.Zero, 0, IntPtr.Zero, 1, ref imageMemoryBarrier); }
public void Barrier(PipelineStage srcStage, PipelineStage dstStage, BufferMemoryBarrier[] bufferBarriers, ImageMemoryBarrier[] imageBarriers) { if (locked) { var bufferBarrier = new VkBufferMemoryBarrier[bufferBarriers == null ? 0 : bufferBarriers.Length]; if (bufferBarriers != null) { for (int i = 0; i < bufferBarrier.Length; i++) { bufferBarrier[i] = new VkBufferMemoryBarrier() { sType = VkStructureType.StructureTypeBufferMemoryBarrier, buffer = bufferBarriers[i].Buffer.hndl, srcQueueFamilyIndex = GraphicsDevice.GetFamilyIndex(devID, bufferBarriers[i].SrcFamily), dstQueueFamilyIndex = GraphicsDevice.GetFamilyIndex(devID, bufferBarriers[i].DstFamily), srcAccessMask = (VkAccessFlags)bufferBarriers[i].Accesses, dstAccessMask = (VkAccessFlags)bufferBarriers[i].Stores, offset = bufferBarriers[i].Offset, size = bufferBarriers[i].Size, }; } } var imageBarrier = new VkImageMemoryBarrier[imageBarriers == null ? 0 : imageBarriers.Length]; if (imageBarriers != null) { for (int i = 0; i < imageBarrier.Length; i++) { imageBarrier[i] = new VkImageMemoryBarrier() { sType = VkStructureType.StructureTypeImageMemoryBarrier, oldLayout = (VkImageLayout)imageBarriers[i].OldLayout, newLayout = (VkImageLayout)imageBarriers[i].NewLayout, image = imageBarriers[i].Image.hndl, srcQueueFamilyIndex = GraphicsDevice.GetFamilyIndex(devID, imageBarriers[i].SrcFamily), dstQueueFamilyIndex = GraphicsDevice.GetFamilyIndex(devID, imageBarriers[i].DstFamily), srcAccessMask = (VkAccessFlags)imageBarriers[i].Accesses, dstAccessMask = (VkAccessFlags)imageBarriers[i].Stores, subresourceRange = new VkImageSubresourceRange() { aspectMask = (imageBarriers[i].Image.Format == ImageFormat.Depth32f ? VkImageAspectFlags.ImageAspectDepthBit : VkImageAspectFlags.ImageAspectColorBit), baseArrayLayer = imageBarriers[i].BaseArrayLayer, baseMipLevel = imageBarriers[i].BaseMipLevel, layerCount = imageBarriers[i].LayerCount, levelCount = imageBarriers[i].LevelCount, }, }; } } var imageBarrier_ptr = imageBarrier.Pointer(); var bufferBarrier_ptr = bufferBarrier.Pointer(); vkCmdPipelineBarrier(hndl, (VkPipelineStageFlags)srcStage, (VkPipelineStageFlags)dstStage, 0, 0, IntPtr.Zero, (uint)bufferBarrier.Length, bufferBarrier_ptr, (uint)imageBarrier.Length, imageBarrier_ptr); IsEmpty = false; } else { throw new Exception("Command buffer not built."); } }
/** @brief Initialize an image memory barrier with no image transfer ownership */ public static VkImageMemoryBarrier imageMemoryBarrier() { VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New(); imageMemoryBarrier.srcQueueFamilyIndex = QueueFamilyIgnored; imageMemoryBarrier.dstQueueFamilyIndex = QueueFamilyIgnored; return(imageMemoryBarrier); }
void TransitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) { var commandBuffer = BeginSingleTimeCommands(); var barrier = new VkImageMemoryBarrier(); barrier.oldLayout = oldLayout; barrier.newLayout = newLayout; barrier.srcQueueFamilyIndex = -1; //VK_QUEUE_FAMILY_IGNORED barrier.dstQueueFamilyIndex = -1; barrier.image = image; barrier.subresourceRange.aspectMask = VkImageAspectFlags.ColorBit; barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.levelCount = 1; barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.layerCount = 1; VkPipelineStageFlags source; VkPipelineStageFlags dest; if (oldLayout == VkImageLayout.Undefined && newLayout == VkImageLayout.TransferSrcOptimal) { barrier.srcAccessMask = VkAccessFlags.HostWriteBit; barrier.dstAccessMask = VkAccessFlags.TransferReadBit; source = VkPipelineStageFlags.HostBit; dest = VkPipelineStageFlags.TransferBit; } else if (oldLayout == VkImageLayout.Undefined && newLayout == VkImageLayout.TransferDstOptimal) { barrier.srcAccessMask = VkAccessFlags.HostWriteBit; barrier.dstAccessMask = VkAccessFlags.TransferWriteBit; source = VkPipelineStageFlags.HostBit; dest = VkPipelineStageFlags.TransferBit; } else if (oldLayout == VkImageLayout.TransferDstOptimal && newLayout == VkImageLayout.ShaderReadOnlyOptimal) { barrier.srcAccessMask = VkAccessFlags.TransferWriteBit; barrier.dstAccessMask = VkAccessFlags.ShaderReadBit; source = VkPipelineStageFlags.TransferBit; dest = VkPipelineStageFlags.FragmentShaderBit; } else { throw new Exception("Unsupported transition"); } commandBuffer.PipelineBarrier( source, dest, VkDependencyFlags.None, null, null, new List <VkImageMemoryBarrier> { barrier }); EndSingleTimeCommand(commandBuffer); }
/// <summary> /// To record a pipeline barrier, call: /// </summary> /// <param name="srcStageMask">is a bitmask of <c>VkPipelineStageFlagBits</c> specifying the <a href='https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#synchronization-pipeline-stages-masks'> source stage mask</a>.</param> /// <param name="dstStageMask">is a bitmask of <c>VkPipelineStageFlagBits</c> specifying the <a href='https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#synchronization-pipeline-stages-masks'> destination stage mask</a>.</param> /// <param name="dependencyFlags">is a bitmask of <c>VkDependencyFlagBits</c> specifying how execution and memory dependencies are formed.</param> /// <param name="barrier">is a pointer to an array of <see cref="VkMemoryBarrier"/> structures.</param> /// <param name="bufferBarrier">is a pointer to an array of <see cref="VkBufferMemoryBarrier"/> structures.</param> /// <param name="imageBarrier">is a pointer to an array of <see cref="VkImageMemoryBarrier"/> structures.</param> public void PipelineBarrier(VkPipelineStageFlag srcStageMask, VkPipelineStageFlag dstStageMask, VkDependencyFlag dependencyFlags, VkMemoryBarrier barrier = default(VkMemoryBarrier), VkBufferMemoryBarrier bufferBarrier = default(VkBufferMemoryBarrier), VkImageMemoryBarrier imageBarrier = default(VkImageMemoryBarrier)) { unsafe { VkCommandBuffer.vkCmdPipelineBarrier(Handle, srcStageMask, dstStageMask, dependencyFlags, barrier.SType != VkStructureType.BufferMemoryBarrier ? 0 : 1u, &barrier, bufferBarrier.SType != VkStructureType.BufferMemoryBarrier ? 0 : 1u, &bufferBarrier, imageBarrier.SType != VkStructureType.ImageMemoryBarrier ? 0 : 1u, &imageBarrier); } }
public unsafe void TransferImageLayout( VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint mipLevel = 0 ) { var aspect = GetAspectFlags(image.Handle, format, newLayout); var sourceFlags = GetImageTransferFlags(oldLayout); var destinationFlags = GetImageTransferFlags(newLayout); var barrier = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, oldLayout = oldLayout, newLayout = newLayout, srcQueueFamilyIndex = VulkanNative.QueueFamilyIgnored, dstQueueFamilyIndex = VulkanNative.QueueFamilyIgnored, image = image.Handle, srcAccessMask = sourceFlags.Key, dstAccessMask = destinationFlags.Key, subresourceRange = new VkImageSubresourceRange { aspectMask = aspect, baseMipLevel = mipLevel, levelCount = 1, baseArrayLayer = 0, layerCount = 1, } }; VulkanNative.vkCmdPipelineBarrier( _handle, sourceFlags.Value, destinationFlags.Value, 0, 0, null, 0, null, 1, &barrier ); }
/// <summary> /// Records the an image memory barrier /// </summary> /// <param name="img">image</param> /// <param name="format">format</param> /// <param name="old">old layout</param> /// <param name="new">new layout</param> /// <param name="range">resource range</param> /// <param name="srcQueue">source queue</param> /// <param name="dstQueue">destination queue</param> /// <param name="flags">dependency flags</param> /// <returns>this</returns> public void ImageMemoryBarrier(VkImage img, VkFormat format, VkImageLayout old, VkImageLayout @new, VkImageSubresourceRange range, VkDependencyFlag flags = 0, uint srcQueue = Vulkan.QueueFamilyIgnored, uint dstQueue = Vulkan.QueueFamilyIgnored) { var spec = new VkImageMemoryBarrier() { SType = VkStructureType.ImageMemoryBarrier, PNext = IntPtr.Zero, OldLayout = old, NewLayout = @new, SrcQueueFamilyIndex = srcQueue, DstQueueFamilyIndex = dstQueue, Image = img, SubresourceRange = range, SrcAccessMask = VkAccessFlag.None, DstAccessMask = VkAccessFlag.None }; GetStageInfo(old, out VkPipelineStageFlag srcFlag, out spec.SrcAccessMask); GetStageInfo(@new, out VkPipelineStageFlag dstFlag, out spec.DstAccessMask); PipelineBarrier(srcFlag, dstFlag, flags, default(VkMemoryBarrier), default(VkBufferMemoryBarrier), spec); }
public void WaitEvents(List <Event> events, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, List <MemoryBarrier> memoryBarriers, List <BufferMemoryBarrier> bufferMemoryBarriers, List <ImageMemoryBarrier> imageMemoryBarriers) { unsafe { var eventsNative = stackalloc VkEvent[events.Count]; Interop.Marshal <VkEvent, Event>(events, eventsNative); int mbCount = 0; int bbCount = 0; int ibCount = 0; if (memoryBarriers != null) { mbCount = memoryBarriers.Count; } if (bufferMemoryBarriers != null) { bbCount = bufferMemoryBarriers.Count; } if (imageMemoryBarriers != null) ibCount = imageMemoryBarriers.Count; } var mbNative = stackalloc VkMemoryBarrier[mbCount]; var bbNative = stackalloc VkBufferMemoryBarrier[bbCount]; var ibNative = stackalloc VkImageMemoryBarrier[ibCount]; for (int i = 0; i < mbCount; i++) { var mb = memoryBarriers[i]; mbNative[i] = new VkMemoryBarrier(); mbNative[i].sType = VkStructureType.MemoryBarrier; mbNative[i].srcAccessMask = mb.srcAccessMask; mbNative[i].dstAccessMask = mb.dstAccessMask; } for (int i = 0; i < bbCount; i++) { var bb = bufferMemoryBarriers[i]; bbNative[i] = new VkBufferMemoryBarrier(); bbNative[i].sType = VkStructureType.BufferMemoryBarrier; bbNative[i].srcAccessMask = bb.srcAccessMask; bbNative[i].dstAccessMask = bb.dstAccessMask; bbNative[i].srcQueueFamilyIndex = bb.srcQueueFamilyIndex; bbNative[i].dstQueueFamilyIndex = bb.dstQueueFamilyIndex; bbNative[i].buffer = bb.buffer.Native; bbNative[i].offset = bb.offset; bbNative[i].size = bb.size; } for (int i = 0; i < ibCount; i++) { var ib = imageMemoryBarriers[i]; ibNative[i] = new VkImageMemoryBarrier(); ibNative[i].sType = VkStructureType.ImageMemoryBarrier; ibNative[i].srcAccessMask = ib.srcAccessMask; ibNative[i].dstAccessMask = ib.dstAccessMask; ibNative[i].oldLayout = ib.oldLayout; ibNative[i].newLayout = ib.newLayout; ibNative[i].srcQueueFamilyIndex = ib.srcQueueFamilyIndex; ibNative[i].dstQueueFamilyIndex = ib.dstQueueFamilyIndex; ibNative[i].image = ib.image.Native; ibNative[i].subresourceRange = ib.subresourceRange; } Device.Commands.cmdWaitEvents(commandBuffer, (uint)events.Count, (IntPtr)eventsNative, srcStageMask, dstStageMask, (uint)mbCount, (IntPtr)mbNative, (uint)bbCount, (IntPtr)bbNative, (uint)ibCount, (IntPtr)ibNative); }
void Preprocess() { Shader shader = Resources.Load <Shader>("shaders/brdf.shader"); { Pass pass = shader.GetPass("SpMap"); uint numMipTailLevels = (uint)kEnvMapLevels - 1; // Compute pre-filtered specular environment map. var specializationInfo = new SpecializationInfo(new VkSpecializationMapEntry(0, 0, sizeof(uint))); specializationInfo.Write(0, numMipTailLevels); pass.ComputeShader.SpecializationInfo = specializationInfo; DescriptorSetLayout resLayout = pass.GetResourceLayout(0); spSet = new DescriptorSet(resLayout); CommandBuffer commandBuffer = Graphics.BeginPrimaryCmd(); // Copy base mipmap level into destination environment map. { Span <VkImageMemoryBarrier> preCopyBarriers = stackalloc[] { new VkImageMemoryBarrier(cubeMap.image, 0, VkAccessFlags.TransferRead, VkImageLayout.ShaderReadOnlyOptimal, VkImageLayout.TransferSrcOptimal, VkImageAspectFlags.Color, 0, 1), new VkImageMemoryBarrier(envMap.image, 0, VkAccessFlags.TransferWrite, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal), }; Span <VkImageMemoryBarrier> postCopyBarriers = stackalloc[] { new VkImageMemoryBarrier(cubeMap.image, VkAccessFlags.TransferRead, VkAccessFlags.ShaderRead, VkImageLayout.TransferSrcOptimal, VkImageLayout.ShaderReadOnlyOptimal, VkImageAspectFlags.Color, 0, 1), new VkImageMemoryBarrier(envMap.image, VkAccessFlags.TransferWrite, VkAccessFlags.ShaderWrite, VkImageLayout.TransferDstOptimal, VkImageLayout.General), }; commandBuffer.PipelineBarrier(VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.Transfer, preCopyBarriers); VkImageCopy copyRegion = new VkImageCopy { extent = new VkExtent3D(envMap.width, envMap.height, 1) }; copyRegion.srcSubresource.aspectMask = VkImageAspectFlags.Color; copyRegion.srcSubresource.layerCount = envMap.layers; copyRegion.dstSubresource = copyRegion.srcSubresource; commandBuffer.CopyImage(cubeMap.image, VkImageLayout.TransferSrcOptimal, envMap.image, VkImageLayout.TransferDstOptimal, ref copyRegion); commandBuffer.PipelineBarrier(VkPipelineStageFlags.Transfer, VkPipelineStageFlags.ComputeShader, postCopyBarriers); // Pre-filter rest of the mip-chain. List <ImageView> envTextureMipTailViews = new List <ImageView>(); var inputTexture = new VkDescriptorImageInfo(computeSampler, cubeMap.imageView, VkImageLayout.ShaderReadOnlyOptimal); spSet.Bind(0, ref inputTexture); Span <VkDescriptorImageInfo> envTextureMipTailDescriptors = stackalloc VkDescriptorImageInfo[(int)numMipTailLevels]; for (uint level = 0; level < numMipTailLevels; ++level) { var view = ImageView.Create(envMap.image, VkImageViewType.ImageCube, VkFormat.R16G16B16A16SFloat, VkImageAspectFlags.Color, level + 1, 1, 0, envMap.image.arrayLayers); envTextureMipTailViews.Add(view); envTextureMipTailDescriptors[(int)level] = new VkDescriptorImageInfo(VkSampler.Null, view, VkImageLayout.General); } spSet.Bind(1, envTextureMipTailDescriptors); spSet.UpdateSets(); commandBuffer.BindComputePipeline(pass); commandBuffer.BindComputeResourceSet(pass.PipelineLayout, 0, spSet); float deltaRoughness = 1.0f / Math.Max((float)numMipTailLevels, 1.0f); for (uint level = 1, size = kEnvMapSize / 2; level < kEnvMapLevels; ++level, size /= 2) { uint numGroups = Math.Max(1, size / 32); var pushConstants = new SpecularFilterPushConstants { level = level - 1, roughness = level * deltaRoughness }; commandBuffer.PushConstants(pass.PipelineLayout, VkShaderStageFlags.Compute, 0, ref pushConstants); commandBuffer.Dispatch(numGroups, numGroups, 6); } var barrier = new VkImageMemoryBarrier(envMap.image, VkAccessFlags.ShaderWrite, 0, VkImageLayout.General, VkImageLayout.ShaderReadOnlyOptimal); commandBuffer.PipelineBarrier(VkPipelineStageFlags.ComputeShader, VkPipelineStageFlags.BottomOfPipe, ref barrier); } Graphics.EndPrimaryCmd(commandBuffer); } // Compute diffuse irradiance cubemap { Pass pass = shader.GetPass("IrMap"); DescriptorSetLayout resLayout = pass.GetResourceLayout(0); irSet = new DescriptorSet(resLayout, cubeMap, irMap); CommandBuffer commandBuffer = Graphics.BeginPrimaryCmd(); { Span <VkImageMemoryBarrier> barriers = stackalloc [] { new VkImageMemoryBarrier(irMap.image, 0, VkAccessFlags.ShaderWrite, VkImageLayout.Undefined, VkImageLayout.General) }; commandBuffer.PipelineBarrier(VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.ComputeShader, barriers); commandBuffer.BindComputePipeline(pass); commandBuffer.BindComputeResourceSet(pass.PipelineLayout, 0, irSet); commandBuffer.Dispatch(kIrradianceMapSize / 32, kIrradianceMapSize / 32, 6); Span <VkImageMemoryBarrier> postDispatchBarrier = stackalloc [] { new VkImageMemoryBarrier(irMap.image, VkAccessFlags.ShaderWrite, 0, VkImageLayout.General, VkImageLayout.ShaderReadOnlyOptimal) }; commandBuffer.PipelineBarrier(VkPipelineStageFlags.ComputeShader, VkPipelineStageFlags.BottomOfPipe, postDispatchBarrier); } Graphics.EndPrimaryCmd(commandBuffer); } // Compute Cook-Torrance BRDF 2D LUT for split-sum approximation. { var pass = shader.GetPass("BrdfLUT"); DescriptorSetLayout resLayout = pass.GetResourceLayout(0); brdfLUTSet = new DescriptorSet(resLayout, brdfLUT); CommandBuffer commandBuffer = Graphics.BeginPrimaryCmd(); { Span <VkImageMemoryBarrier> barriers = stackalloc [] { new VkImageMemoryBarrier(brdfLUT.image, 0, VkAccessFlags.ShaderWrite, VkImageLayout.Undefined, VkImageLayout.General) }; commandBuffer.PipelineBarrier(VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.ComputeShader, barriers); commandBuffer.BindComputePipeline(pass); commandBuffer.BindComputeResourceSet(pass.PipelineLayout, 0, brdfLUTSet); commandBuffer.Dispatch(kBRDF_LUT_Size / 32, kBRDF_LUT_Size / 32, 6); Span <VkImageMemoryBarrier> postDispatchBarrier = stackalloc [] { new VkImageMemoryBarrier(brdfLUT.image, VkAccessFlags.ShaderWrite, 0, VkImageLayout.General, VkImageLayout.ShaderReadOnlyOptimal) }; commandBuffer.PipelineBarrier(VkPipelineStageFlags.ComputeShader, VkPipelineStageFlags.BottomOfPipe, postDispatchBarrier); } Graphics.EndPrimaryCmd(commandBuffer); } } int selected = 0;
private unsafe void CreateBackBuffers() { // Create the texture object var backBufferDescription = new TextureDescription { ArraySize = 1, Dimension = TextureDimension.Texture2D, Height = Description.BackBufferHeight, Width = Description.BackBufferWidth, Depth = 1, Flags = TextureFlags.RenderTarget, Format = Description.BackBufferFormat, MipLevels = 1, MultisampleCount = MultisampleCount.None, Usage = GraphicsResourceUsage.Default }; backbuffer.InitializeWithoutResources(backBufferDescription); var createInfo = new VkImageViewCreateInfo { sType = VkStructureType.ImageViewCreateInfo, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1), format = backbuffer.NativeFormat, viewType = VkImageViewType.Image2D, }; // We initialize swapchain images to PresentSource, since we swap them out while in this layout. backbuffer.NativeAccessMask = VkAccessFlags.MemoryRead; backbuffer.NativeLayout = VkImageLayout.PresentSrcKHR; var imageMemoryBarrier = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1), oldLayout = VkImageLayout.Undefined, newLayout = VkImageLayout.PresentSrcKHR, srcAccessMask = VkAccessFlags.None, dstAccessMask = VkAccessFlags.MemoryRead }; var commandBufferAllocationInfo = new VkCommandBufferAllocateInfo { sType = VkStructureType.CommandBufferAllocateInfo, level = VkCommandBufferLevel.Primary, commandPool = GraphicsDevice.NativeCopyCommandPools.Value, commandBufferCount = 1 }; VkCommandBuffer commandBuffer; vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocationInfo, &commandBuffer); var beginInfo = new VkCommandBufferBeginInfo { sType = VkStructureType.CommandBufferBeginInfo }; vkBeginCommandBuffer(commandBuffer, &beginInfo); var buffers = vkGetSwapchainImagesKHR(GraphicsDevice.NativeDevice, swapChain); swapchainImages = new SwapChainImageInfo[buffers.Length]; for (int i = 0; i < buffers.Length; i++) { // Create image views swapchainImages[i].NativeImage = createInfo.image = buffers[i]; vkCreateImageView(GraphicsDevice.NativeDevice, &createInfo, null, out swapchainImages[i].NativeColorAttachmentView); // Transition to default layout imageMemoryBarrier.image = buffers[i]; vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.AllCommands, 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); // Get next image vkAcquireNextImageKHR(GraphicsDevice.NativeDevice, swapChain, ulong.MaxValue, GraphicsDevice.GetNextPresentSemaphore(), VkFence.Null, out currentBufferIndex); // Apply the first swap chain image to the texture backbuffer.SetNativeHandles(swapchainImages[currentBufferIndex].NativeImage, swapchainImages[currentBufferIndex].NativeColorAttachmentView); }
private void RecordCommandBuffers() { VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange() { aspectMask = VkImageAspectFlags.Color, baseMipLevel = 0, baseArrayLayer = 0, layerCount = 1, levelCount = 1 }; for (int i = 0; i < CommandBuffers.Length; i++) { VkCommandBuffer cmdBuffer = CommandBuffers[i]; VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo() { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.SimultaneousUse }; vkBeginCommandBuffer(cmdBuffer, &beginInfo); if (Context.PresentQueue != Context.GraphicsQueue) { var barrierFromPresentToDraw = new VkImageMemoryBarrier( SwapchainImages[i], subresourceRange, VkAccessFlags.MemoryRead, VkAccessFlags.ColorAttachmentWrite, VkImageLayout.Undefined, VkImageLayout.PresentSrcKHR, (uint)Context.PresentQueueFamilyIndex, (uint)Context.GraphicsQueueFamilyIndex); vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.ColorAttachmentOutput, 0, 0, null, 0, null, 1, &barrierFromPresentToDraw ); } RecordCommandBuffer(cmdBuffer, i); if (Context.PresentQueue != Context.GraphicsQueue) { var barrierFromDrawToPresent = new VkImageMemoryBarrier( SwapchainImages[i], subresourceRange, VkAccessFlags.ColorAttachmentWrite, VkAccessFlags.MemoryRead, VkImageLayout.PresentSrcKHR, VkImageLayout.PresentSrcKHR, (uint)Context.GraphicsQueueFamilyIndex, (uint)Context.PresentQueueFamilyIndex); vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.ColorAttachmentOutput, VkPipelineStageFlags.BottomOfPipe, 0, 0, null, 0, null, 1, &barrierFromDrawToPresent ); } VkResult result = vkEndCommandBuffer(cmdBuffer); result.CheckResult(); } }
public void Execute(VkCommandBuffer buffer) { VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New(); imageMemoryBarrier.srcAccessMask = VkAccessFlags.None; imageMemoryBarrier.dstAccessMask = VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite; imageMemoryBarrier.oldLayout = VkImageLayout.Undefined; imageMemoryBarrier.newLayout = VkImageLayout.ColorAttachmentOptimal; imageMemoryBarrier.srcQueueFamilyIndex = VulkanNative.QueueFamilyIgnored; imageMemoryBarrier.dstQueueFamilyIndex = VulkanNative.QueueFamilyIgnored; imageMemoryBarrier.image = swapchainImage; imageMemoryBarrier.subresourceRange = new VkImageSubresourceRange() { baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1, aspectMask = VkImageAspectFlags.Color }; vkCmdPipelineBarrier(buffer, VkPipelineStageFlags.AllGraphics, VkPipelineStageFlags.AllGraphics, VkDependencyFlags.ByRegion, 0, null, 0, null, 1, &imageMemoryBarrier); VkClearColorValue clearColorValue = new VkClearColorValue { float32_0 = 3f / 255f, float32_1 = 2f / 255, float32_2 = 12f / 255, float32_3 = 1 }; VkClearDepthStencilValue clearDepthStencilValue = new VkClearDepthStencilValue(1, 0); VkClearValue[] clearValues = new VkClearValue[2]; clearValues[0].color = clearColorValue; clearValues[1].depthStencil = clearDepthStencilValue; VkRenderPassBeginInfo passBeginInfo = VkRenderPassBeginInfo.New(); passBeginInfo.renderPass = renderPass; passBeginInfo.framebuffer = swapchainFramebuffer; passBeginInfo.renderArea.extent.width = (uint)Program.width; passBeginInfo.renderArea.extent.height = (uint)Program.height; passBeginInfo.clearValueCount = (uint)clearValues.Length; fixed(VkClearValue *ptr = clearValues) passBeginInfo.pClearValues = ptr; vkCmdBeginRenderPass(buffer, &passBeginInfo, VkSubpassContents.Inline); VkViewport viewport = new VkViewport(); viewport.x = 0; viewport.y = (float)Program.height; viewport.width = (float)Program.width; viewport.height = -(float)Program.height; VkRect2D scissor = new VkRect2D(); scissor.offset.x = 0; scissor.offset.y = 0; scissor.extent.width = (uint)Program.width; scissor.extent.height = (uint)Program.height; vkCmdSetViewport(buffer, 0, 1, &viewport); vkCmdSetScissor(buffer, 0, 1, &scissor); vkCmdBindPipeline(buffer, VkPipelineBindPoint.Graphics, pipeline); if (mesh.IsReady) { mesh.Use(); VkBuffer[] databuffers = new VkBuffer[] { mesh.Mesh.vertices.Buffer, mesh.Mesh.vertices.Buffer, mesh.Mesh.vertices.Buffer, mesh.Mesh.vertices.Buffer }; ulong[] offsets = new ulong[] { 0, 3 * 4, 6 * 4, 6 * 4 + 2 * 4 }; fixed(VkBuffer *bptr = databuffers) fixed(ulong *optr = offsets) vkCmdBindVertexBuffers(buffer, 0, 4, bptr, optr); vkCmdBindIndexBuffer(buffer, mesh.Mesh.indices.Buffer, 0, VkIndexType.Uint32); uniformdata.Write(0, camera.View.ToFloatArray()); uniformdata.Write(16, camera.Projection.ToFloatArray()); UpdateUniformData(uniformdata, swapchainImageIndex); VkDescriptorSet sets = descriptorSets[swapchainImageIndex]; VkPipelineLayout layout = pipelineLayout; vkCmdBindDescriptorSets(buffer, VkPipelineBindPoint.Graphics, layout, 0, 1, &sets, 0, null); vkCmdDrawIndexed(buffer, (uint)mesh.Mesh.indices.Length, 1, 0, 0, 0); mesh.StopUse(); } vkCmdEndRenderPass(buffer); }
/// <inheritdoc cref="Copy(GraphicsTexture, GraphicsBuffer)" /> public void Copy(VulkanGraphicsTexture destination, VulkanGraphicsBuffer source) { ThrowIfNull(destination, nameof(destination)); ThrowIfNull(source, nameof(source)); var vulkanCommandBuffer = VulkanCommandBuffer; var vulkanImage = destination.VulkanImage; BeginCopy(); var vulkanBufferImageCopy = new VkBufferImageCopy { imageSubresource = new VkImageSubresourceLayers { aspectMask = (uint)VK_IMAGE_ASPECT_COLOR_BIT, layerCount = 1, }, imageExtent = new VkExtent3D { width = (uint)destination.Width, height = destination.Height, depth = destination.Depth, }, }; vkCmdCopyBufferToImage(vulkanCommandBuffer, source.VulkanBuffer, vulkanImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vulkanBufferImageCopy); EndCopy(); void BeginCopy() { var vulkanImageMemoryBarrier = new VkImageMemoryBarrier { sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, dstAccessMask = (uint)VK_ACCESS_TRANSFER_WRITE_BIT, oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image = vulkanImage, subresourceRange = new VkImageSubresourceRange { aspectMask = (uint)VK_IMAGE_ASPECT_COLOR_BIT, levelCount = 1, layerCount = 1, }, }; vkCmdPipelineBarrier(vulkanCommandBuffer, (uint)VK_PIPELINE_STAGE_HOST_BIT, (uint)VK_PIPELINE_STAGE_TRANSFER_BIT, dependencyFlags: 0, memoryBarrierCount: 0, pMemoryBarriers: null, bufferMemoryBarrierCount: 0, pBufferMemoryBarriers: null, imageMemoryBarrierCount: 1, &vulkanImageMemoryBarrier); } void EndCopy() { var vulkanImageMemoryBarrier = new VkImageMemoryBarrier { sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, srcAccessMask = (uint)VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask = (uint)VK_ACCESS_SHADER_READ_BIT, oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, image = vulkanImage, subresourceRange = new VkImageSubresourceRange { aspectMask = (uint)VK_IMAGE_ASPECT_COLOR_BIT, levelCount = 1, layerCount = 1, }, }; vkCmdPipelineBarrier(vulkanCommandBuffer, (uint)VK_PIPELINE_STAGE_TRANSFER_BIT, (uint)VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, dependencyFlags: 0, memoryBarrierCount: 0, pMemoryBarriers: null, bufferMemoryBarrierCount: 0, pBufferMemoryBarriers: null, imageMemoryBarrierCount: 1, &vulkanImageMemoryBarrier); } }
public void PipelineBarrier(VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint memoryBarrierCount, VkMemoryBarrier *memoryBarriers, uint bufferMemoryBarrierCount, VkBufferMemoryBarrier *bufferMemoryBarriers, VkImageMemoryBarrier imageMemoryBarriers) { vkCmdPipelineBarrier(handle, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, memoryBarriers, bufferMemoryBarrierCount, null, 1, &imageMemoryBarriers); }
internal static VulkanImage Texture2D(VulkanContext ctx, TextureData tex2D) { ulong size = (ulong)tex2D.Mipmaps[0].Size; VkBuffer stagingBuffer; var bufferCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, size = (ulong)tex2D.Mipmaps[0].Size, usage = VkBufferUsageFlags.TransferSrc }; vkCreateBuffer(ctx.Device, &bufferCreateInfo, null, out stagingBuffer); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); vkGetBufferMemoryRequirements(ctx.Device, stagingBuffer, out VkMemoryRequirements stagingMemReq); uint heapIndex = BufferHelper.GetMemoryTypeIndex(stagingMemReq.memoryTypeBits, VkMemoryPropertyFlags.HostVisible, memoryProperties); VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo() { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = stagingMemReq.size, memoryTypeIndex = heapIndex }; VkDeviceMemory stagingMemory; VkResult result = vkAllocateMemory(ctx.Device, &memAllocInfo, null, &stagingMemory); result.CheckResult(); result = vkBindBufferMemory(ctx.Device, stagingBuffer, stagingMemory, 0); result.CheckResult(); void *vertexPtr; result = vkMapMemory(ctx.Device, stagingMemory, 0, (ulong)tex2D.Mipmaps[0].Size, 0, &vertexPtr); result.CheckResult(); fixed(byte *dataPtr = &tex2D.Mipmaps[0].Data[0]) { Buffer.MemoryCopy(dataPtr, vertexPtr, size, size); } vkUnmapMemory(ctx.Device, stagingMemory); // Setup buffer copy regions for each mip level. var bufferCopyRegions = new VkBufferImageCopy[tex2D.Mipmaps.Length]; // TODO: stackalloc int offset = 0; for (int i = 0; i < bufferCopyRegions.Length; i++) { // TODO: from VulkanCore, doesn't look correct (reassigns bufferCopyRegions in each loop) bufferCopyRegions = new[] { new VkBufferImageCopy { imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)i, 0, 1), imageExtent = tex2D.Mipmaps[0].Extent, bufferOffset = (ulong)offset } }; offset += tex2D.Mipmaps[i].Size; } // Create optimal tiled target image. var createInfo = new VkImageCreateInfo { sType = VkStructureType.ImageCreateInfo, pNext = null, imageType = VkImageType.Image2D, format = tex2D.Format, mipLevels = (uint)tex2D.Mipmaps.Length, arrayLayers = 1, samples = VkSampleCountFlags.Count1, tiling = VkImageTiling.Optimal, sharingMode = VkSharingMode.Exclusive, initialLayout = VkImageLayout.Undefined, extent = tex2D.Mipmaps[0].Extent, usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst }; VkImage image; result = vkCreateImage(ctx.Device, &createInfo, null, out image); result.CheckResult(); VkMemoryRequirements imageMemReq; vkGetImageMemoryRequirements(ctx.Device, image, out imageMemReq); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties imageMemoryProperties); uint imageHeapIndex = BufferHelper.GetMemoryTypeIndex(imageMemReq.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, imageMemoryProperties); var allocInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = imageMemReq.size, memoryTypeIndex = imageHeapIndex, }; VkDeviceMemory memory; result = vkAllocateMemory(ctx.Device, &allocInfo, null, &memory); result.CheckResult(); result = vkBindImageMemory(ctx.Device, image, memory, 0); result.CheckResult(); var subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, (uint)tex2D.Mipmaps.Length, 0, 1); // Copy the data from staging buffers to device local buffers. var allocInfo2 = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = ctx.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = 1, }; VkCommandBuffer cmdBuffer; vkAllocateCommandBuffers(ctx.Device, &allocInfo2, &cmdBuffer); VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo() { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit, }; vkBeginCommandBuffer(cmdBuffer, &beginInfo); VkImageMemoryBarrier imageMemoryBarrier = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = image, subresourceRange = subresourceRange, srcAccessMask = 0, dstAccessMask = VkAccessFlags.TransferWrite, oldLayout = VkImageLayout.Undefined, newLayout = VkImageLayout.TransferDstOptimal, srcQueueFamilyIndex = QueueFamilyIgnored, dstQueueFamilyIndex = QueueFamilyIgnored }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); fixed(VkBufferImageCopy *regionsPtr = bufferCopyRegions) { vkCmdCopyBufferToImage(cmdBuffer, stagingBuffer, image, VkImageLayout.TransferDstOptimal, (uint)bufferCopyRegions.Length, regionsPtr); } VkImageMemoryBarrier imageMemoryBarrier2 = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = image, subresourceRange = subresourceRange, srcAccessMask = VkAccessFlags.TransferWrite, dstAccessMask = VkAccessFlags.ShaderRead, oldLayout = VkImageLayout.TransferDstOptimal, newLayout = VkImageLayout.ShaderReadOnlyOptimal, srcQueueFamilyIndex = (uint)QueueFamilyIgnored, dstQueueFamilyIndex = (uint)QueueFamilyIgnored }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier2); vkEndCommandBuffer(cmdBuffer); // Submit. VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo, pNext = null }; VkFence fence; result = vkCreateFence(ctx.Device, &fenceCreateInfo, null, out fence); result.CheckResult(); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, pNext = null, commandBufferCount = 1, pCommandBuffers = &cmdBuffer }; vkQueueSubmit(ctx.GraphicsQueue, submitInfo, fence); result = vkWaitForFences(ctx.Device, 1, &fence, false, ulong.MaxValue); result.CheckResult(); // Cleanup staging resources. vkDestroyFence(ctx.Device, fence, null); vkFreeMemory(ctx.Device, stagingMemory, null); vkDestroyBuffer(ctx.Device, stagingBuffer, null); // Create image view. VkImageViewCreateInfo imageViewCreateInfo = new VkImageViewCreateInfo() { sType = VkStructureType.ImageViewCreateInfo, image = image, viewType = VkImageViewType.Image2D, format = tex2D.Format, subresourceRange = subresourceRange }; VkImageView view; vkCreateImageView(ctx.Device, &imageViewCreateInfo, null, out view); return(new VulkanImage(ctx, image, memory, view, tex2D.Format)); }
// Create an image memory barrier for changing the layout of // an image and put it into an active command buffer void setImageLayout( VkCommandBuffer cmdBuffer, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkImageSubresourceRange subresourceRange) { // Create an image barrier object VkImageMemoryBarrier imageMemoryBarrier = Initializers.imageMemoryBarrier();; imageMemoryBarrier.oldLayout = oldImageLayout; imageMemoryBarrier.newLayout = newImageLayout; imageMemoryBarrier.image = image; imageMemoryBarrier.subresourceRange = subresourceRange; // Only sets masks for layouts used in this example // For a more complete version that can be used with other layouts see vks::tools::setImageLayout // Source layouts (old) switch (oldImageLayout) { case VkImageLayout.Undefined: // Only valid as initial layout, memory contents are not preserved // Can be accessed directly, no source dependency required imageMemoryBarrier.srcAccessMask = 0; break; case VkImageLayout.Preinitialized: // Only valid as initial layout for linear images, preserves memory contents // Make sure host writes to the image have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.HostWrite; break; case VkImageLayout.TransferDstOptimal: // Old layout is transfer destination // Make sure any writes to the image have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferWrite; break; } // Target layouts (new) switch (newImageLayout) { case VkImageLayout.TransferSrcOptimal: // Transfer source (copy, blit) // Make sure any reads from the image have been finished imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferRead; break; case VkImageLayout.TransferDstOptimal: // Transfer destination (copy, blit) // Make sure any writes to the image have been finished imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferWrite; break; case VkImageLayout.ShaderReadOnlyOptimal: // Shader read (sampler, input attachment) imageMemoryBarrier.dstAccessMask = VkAccessFlags.ShaderRead; break; } // Put barrier on top of pipeline VkPipelineStageFlags srcStageFlags = VkPipelineStageFlags.TopOfPipe; VkPipelineStageFlags destStageFlags = VkPipelineStageFlags.TopOfPipe; // Put barrier inside setup command buffer vkCmdPipelineBarrier( cmdBuffer, srcStageFlags, destStageFlags, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); }
private static VkImage LoadTexture(VkDevice device, VkPhysicalDevice physicalDevice, int cmdPoolID, VkQueue queue, string[] paths, uint mipLevels) { Bitmap[] bitmaps = new Bitmap[paths.Length]; FDataBuffer <byte>[] tempBuffer = new FDataBuffer <byte> [paths.Length]; uint width = 0, height = 0; for (int j = 0; j < paths.Length; j++) { bitmaps[j] = new Bitmap(System.Drawing.Image.FromFile(paths[j])); var data = bitmaps[j].LockBits(new Rectangle(0, 0, bitmaps[j].Width, bitmaps[j].Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmaps[j].PixelFormat); width = (uint)data.Width; height = (uint)data.Height;//TODO add size check Span <byte> img = new Span <byte>((void *)data.Scan0, data.Stride * data.Height); tempBuffer[j] = new FDataBuffer <byte>(device, physicalDevice, img.Length, VkBufferUsageFlags.TransferSrc, VkSharingMode.Exclusive); Span <byte> buffer = tempBuffer[j].Map(); for (int i = 0; i < img.Length; i += 4) { buffer[i + 2] = img[i]; buffer[i + 1] = img[i + 1]; buffer[i] = img[i + 2]; buffer[i + 3] = img[i + 3]; } buffer = tempBuffer[j].UnMap(); } VkImage texture = VkImage.Null; VkDeviceMemory memory = VkDeviceMemory.Null; VkImageCreateInfo createInfo = VkImageCreateInfo.New(); createInfo.imageType = VkImageType.Image2D; createInfo.extent.width = width; createInfo.extent.height = height; createInfo.extent.depth = 1; createInfo.mipLevels = mipLevels; createInfo.arrayLayers = (uint)paths.Length; createInfo.format = VkFormat.R8g8b8a8Unorm; createInfo.tiling = VkImageTiling.Optimal; createInfo.initialLayout = VkImageLayout.Undefined; createInfo.usage = VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferSrc; createInfo.sharingMode = VkSharingMode.Exclusive; createInfo.samples = VkSampleCountFlags.Count1; Assert(vkCreateImage(device, &createInfo, null, &texture)); VkMemoryRequirements memoryRequirements; vkGetImageMemoryRequirements(device, texture, &memoryRequirements); VkPhysicalDeviceMemoryProperties memoryProperties = new VkPhysicalDeviceMemoryProperties(); vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties); VkMemoryAllocateInfo allocateInfo = VkMemoryAllocateInfo.New(); allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.memoryTypeIndex = FDataBuffer <byte> .SelectMemoryType(memoryProperties, memoryRequirements.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal); Assert(vkAllocateMemory(device, &allocateInfo, null, &memory)); vkBindImageMemory(device, texture, memory, 0); VkCommandBufferAllocateInfo pAllocateInfo = VkCommandBufferAllocateInfo.New(); pAllocateInfo.commandPool = CommandPoolManager.GetPool(cmdPoolID); pAllocateInfo.level = VkCommandBufferLevel.Primary; pAllocateInfo.commandBufferCount = 1; VkCommandBuffer cmdBuffer = VkCommandBuffer.Null; Assert(vkAllocateCommandBuffers(device, &pAllocateInfo, &cmdBuffer)); VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.New(); beginInfo.flags = VkCommandBufferUsageFlags.OneTimeSubmit; Assert(vkBeginCommandBuffer(cmdBuffer, &beginInfo)); VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New(); imageMemoryBarrier.srcAccessMask = VkAccessFlags.None; imageMemoryBarrier.dstAccessMask = VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite; imageMemoryBarrier.oldLayout = VkImageLayout.Undefined; imageMemoryBarrier.newLayout = VkImageLayout.TransferDstOptimal; imageMemoryBarrier.srcQueueFamilyIndex = VulkanNative.QueueFamilyIgnored; imageMemoryBarrier.dstQueueFamilyIndex = VulkanNative.QueueFamilyIgnored; imageMemoryBarrier.image = texture; imageMemoryBarrier.subresourceRange = new VkImageSubresourceRange() { baseMipLevel = 0, levelCount = mipLevels, baseArrayLayer = 0, layerCount = (uint)paths.Length, aspectMask = VkImageAspectFlags.Color }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.ByRegion, 0, null, 0, null, 1, &imageMemoryBarrier); for (int j = 0; j < tempBuffer.Length; j++) { VkBufferImageCopy region = new VkBufferImageCopy(); region.bufferOffset = 0; region.bufferRowLength = 0; region.bufferImageHeight = 0; region.imageSubresource.aspectMask = VkImageAspectFlags.Color; region.imageSubresource.mipLevel = 0; region.imageSubresource.baseArrayLayer = (uint)j; region.imageSubresource.layerCount = 1; region.imageOffset = new VkOffset3D(); region.imageExtent = new VkExtent3D() { width = width, height = height, depth = 1 }; vkCmdCopyBufferToImage(cmdBuffer, tempBuffer[j].Buffer, texture, VkImageLayout.TransferDstOptimal, 1, ®ion); } imageMemoryBarrier.oldLayout = VkImageLayout.TransferDstOptimal; imageMemoryBarrier.newLayout = VkImageLayout.ShaderReadOnlyOptimal; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.ByRegion, 0, null, 0, null, 1, &imageMemoryBarrier); Assert(vkEndCommandBuffer(cmdBuffer)); VkSubmitInfo submitInfo = VkSubmitInfo.New(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdBuffer; Assert(vkQueueSubmit(queue, 1, &submitInfo, VkFence.Null)); Assert(vkQueueWaitIdle(queue)); vkFreeCommandBuffers(device, CommandPoolManager.GetPool(cmdPoolID), 1, &cmdBuffer); return(texture); }
// Create an image memory barrier for changing the layout of // an image and put it into an active command buffer // See chapter 11.4 "Image Layout" for details public static void setImageLayout( VkCommandBuffer cmdbuffer, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkImageSubresourceRange subresourceRange, VkPipelineStageFlags srcStageMask = VkPipelineStageFlags.AllCommands, VkPipelineStageFlags dstStageMask = VkPipelineStageFlags.AllCommands) { // Create an image barrier object VkImageMemoryBarrier imageMemoryBarrier = Initializers.imageMemoryBarrier(); imageMemoryBarrier.oldLayout = oldImageLayout; imageMemoryBarrier.newLayout = newImageLayout; imageMemoryBarrier.image = image; imageMemoryBarrier.subresourceRange = subresourceRange; // Source layouts (old) // Source access mask controls actions that have to be finished on the old layout // before it will be transitioned to the new layout switch (oldImageLayout) { case VkImageLayout.Undefined: // Image layout is undefined (or does not matter) // Only valid as initial layout // No flags required, listed only for completeness imageMemoryBarrier.srcAccessMask = 0; break; case VkImageLayout.Preinitialized: // Image is preinitialized // Only valid as initial layout for linear images, preserves memory contents // Make sure host writes have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.HostWrite; break; case VkImageLayout.ColorAttachmentOptimal: // Image is a color attachment // Make sure any writes to the color buffer have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.ColorAttachmentWrite; break; case VkImageLayout.DepthStencilAttachmentOptimal: // Image is a depth/stencil attachment // Make sure any writes to the depth/stencil buffer have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.DepthStencilAttachmentWrite; break; case VkImageLayout.TransferSrcOptimal: // Image is a transfer source // Make sure any reads from the image have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; break; case VkImageLayout.TransferDstOptimal: // Image is a transfer destination // Make sure any writes to the image have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferWrite; break; case VkImageLayout.ShaderReadOnlyOptimal: // Image is read by a shader // Make sure any shader reads from the image have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.ShaderRead; break; } // Target layouts (new) // Destination access mask controls the dependency for the new image layout switch (newImageLayout) { case VkImageLayout.TransferDstOptimal: // Image will be used as a transfer destination // Make sure any writes to the image have been finished imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferWrite; break; case VkImageLayout.TransferSrcOptimal: // Image will be used as a transfer source // Make sure any reads from and writes to the image have been finished imageMemoryBarrier.srcAccessMask = imageMemoryBarrier.srcAccessMask | VkAccessFlags.TransferRead; imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferRead; break; case VkImageLayout.ColorAttachmentOptimal: // Image will be used as a color attachment // Make sure any writes to the color buffer have been finished imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; imageMemoryBarrier.dstAccessMask = VkAccessFlags.ColorAttachmentWrite; break; case VkImageLayout.DepthStencilAttachmentOptimal: // Image layout will be used as a depth/stencil attachment // Make sure any writes to depth/stencil buffer have been finished imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VkAccessFlags.DepthStencilAttachmentWrite; break; case VkImageLayout.ShaderReadOnlyOptimal: // Image will be read in a shader (sampler, input attachment) // Make sure any writes to the image have been finished if (imageMemoryBarrier.srcAccessMask == 0) { imageMemoryBarrier.srcAccessMask = VkAccessFlags.HostWrite | VkAccessFlags.TransferWrite; } imageMemoryBarrier.dstAccessMask = VkAccessFlags.ShaderRead; break; } // Put barrier inside setup command buffer vkCmdPipelineBarrier( cmdbuffer, srcStageMask, dstStageMask, 0, 0, null, 0, null, 1, &imageMemoryBarrier); }
private static void InitMips(VkDevice device, VkQueue queue, VkImage image, int width, int height, uint mipLevels, uint layerCount, int cmdPool) { VkCommandBufferAllocateInfo pAllocateInfo = VkCommandBufferAllocateInfo.New(); pAllocateInfo.commandPool = CommandPoolManager.GetPool(cmdPool); pAllocateInfo.level = VkCommandBufferLevel.Primary; pAllocateInfo.commandBufferCount = 1; VkCommandBuffer cmdBuffer = VkCommandBuffer.Null; Assert(vkAllocateCommandBuffers(device, &pAllocateInfo, &cmdBuffer)); Assert(vkResetCommandBuffer(cmdBuffer, VkCommandBufferResetFlags.None)); VkCommandBufferBeginInfo beginInfo = VkCommandBufferBeginInfo.New(); beginInfo.flags = VkCommandBufferUsageFlags.OneTimeSubmit; Assert(vkBeginCommandBuffer(cmdBuffer, &beginInfo)); VkImageMemoryBarrier imageMemoryBarrier = VkImageMemoryBarrier.New(); imageMemoryBarrier.srcAccessMask = VkAccessFlags.None; imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferWrite; imageMemoryBarrier.oldLayout = VkImageLayout.Undefined; imageMemoryBarrier.newLayout = VkImageLayout.TransferDstOptimal; imageMemoryBarrier.srcQueueFamilyIndex = VulkanNative.QueueFamilyIgnored; imageMemoryBarrier.dstQueueFamilyIndex = VulkanNative.QueueFamilyIgnored; imageMemoryBarrier.image = image; imageMemoryBarrier.subresourceRange = new VkImageSubresourceRange() { baseMipLevel = 0, levelCount = mipLevels, baseArrayLayer = 0, layerCount = layerCount, aspectMask = VkImageAspectFlags.Color }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.ByRegion, 0, null, 0, null, 1, &imageMemoryBarrier); for (int i = 1; i < mipLevels; i++) { imageMemoryBarrier.oldLayout = VkImageLayout.TransferDstOptimal; imageMemoryBarrier.newLayout = VkImageLayout.TransferSrcOptimal; imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferWrite; imageMemoryBarrier.dstAccessMask = VkAccessFlags.TransferRead; imageMemoryBarrier.subresourceRange.baseMipLevel = (uint)(i - 1); imageMemoryBarrier.subresourceRange.levelCount = 1; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.ByRegion, 0, null, 0, null, 1, &imageMemoryBarrier); VkImageBlit blit = new VkImageBlit(); blit.srcOffsets_0 = new VkOffset3D { x = 0, y = 0, z = 0 }; blit.srcOffsets_1 = new VkOffset3D { x = width, y = height, z = 1 }; blit.srcSubresource.aspectMask = VkImageAspectFlags.Color; blit.srcSubresource.mipLevel = (uint)(i - 1); blit.srcSubresource.baseArrayLayer = 0; blit.srcSubresource.layerCount = layerCount; blit.dstOffsets_0 = new VkOffset3D { x = 0, y = 0, z = 0 }; blit.dstOffsets_1 = new VkOffset3D { x = width / 2, y = height / 2, z = 1 }; blit.dstSubresource.aspectMask = VkImageAspectFlags.Color; blit.dstSubresource.mipLevel = (uint)i; blit.dstSubresource.baseArrayLayer = 0; blit.dstSubresource.layerCount = layerCount; vkCmdBlitImage(cmdBuffer, image, VkImageLayout.TransferSrcOptimal, image, VkImageLayout.TransferDstOptimal, 1, &blit, VkFilter.Linear); width /= 2; height /= 2; imageMemoryBarrier.oldLayout = VkImageLayout.TransferSrcOptimal; imageMemoryBarrier.newLayout = VkImageLayout.ShaderReadOnlyOptimal; imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; imageMemoryBarrier.dstAccessMask = VkAccessFlags.ShaderRead; imageMemoryBarrier.subresourceRange.baseMipLevel = (uint)(i - 1); imageMemoryBarrier.subresourceRange.levelCount = 1; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.ByRegion, 0, null, 0, null, 1, &imageMemoryBarrier); } imageMemoryBarrier.oldLayout = VkImageLayout.Undefined; imageMemoryBarrier.newLayout = VkImageLayout.ShaderReadOnlyOptimal; imageMemoryBarrier.srcAccessMask = VkAccessFlags.TransferRead; imageMemoryBarrier.dstAccessMask = VkAccessFlags.ShaderRead; imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevels - 1; imageMemoryBarrier.subresourceRange.levelCount = 1; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.ByRegion, 0, null, 0, null, 1, &imageMemoryBarrier); Assert(vkEndCommandBuffer(cmdBuffer)); VkSubmitInfo submitInfo = VkSubmitInfo.New(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdBuffer; Assert(vkQueueSubmit(queue, 1, &submitInfo, VkFence.Null)); }
public static void TransitionImageLayout( VkCommandBuffer cb, VkImage image, uint baseMipLevel, uint levelCount, uint baseArrayLayer, uint layerCount, VkImageAspectFlags aspectMask, VkImageLayout oldLayout, VkImageLayout newLayout) { Debug.Assert(oldLayout != newLayout); VkImageMemoryBarrier barrier = VkImageMemoryBarrier.New(); barrier.oldLayout = oldLayout; barrier.newLayout = newLayout; barrier.srcQueueFamilyIndex = QueueFamilyIgnored; barrier.dstQueueFamilyIndex = QueueFamilyIgnored; barrier.image = image; barrier.subresourceRange.aspectMask = aspectMask; barrier.subresourceRange.baseMipLevel = baseMipLevel; barrier.subresourceRange.levelCount = levelCount; barrier.subresourceRange.baseArrayLayer = baseArrayLayer; barrier.subresourceRange.layerCount = layerCount; VkPipelineStageFlags srcStageFlags = VkPipelineStageFlags.None; VkPipelineStageFlags dstStageFlags = VkPipelineStageFlags.None; if ((oldLayout == VkImageLayout.Undefined || oldLayout == VkImageLayout.Preinitialized) && newLayout == VkImageLayout.TransferDstOptimal) { barrier.srcAccessMask = VkAccessFlags.None; barrier.dstAccessMask = VkAccessFlags.TransferWrite; srcStageFlags = VkPipelineStageFlags.TopOfPipe; dstStageFlags = VkPipelineStageFlags.Transfer; } else if (oldLayout == VkImageLayout.ShaderReadOnlyOptimal && newLayout == VkImageLayout.TransferSrcOptimal) { barrier.srcAccessMask = VkAccessFlags.ShaderRead; barrier.dstAccessMask = VkAccessFlags.TransferRead; srcStageFlags = VkPipelineStageFlags.FragmentShader; dstStageFlags = VkPipelineStageFlags.Transfer; } else if (oldLayout == VkImageLayout.ShaderReadOnlyOptimal && newLayout == VkImageLayout.TransferDstOptimal) { barrier.srcAccessMask = VkAccessFlags.ShaderRead; barrier.dstAccessMask = VkAccessFlags.TransferWrite; srcStageFlags = VkPipelineStageFlags.FragmentShader; dstStageFlags = VkPipelineStageFlags.Transfer; } else if (oldLayout == VkImageLayout.Preinitialized && newLayout == VkImageLayout.TransferSrcOptimal) { barrier.srcAccessMask = VkAccessFlags.None; barrier.dstAccessMask = VkAccessFlags.TransferRead; srcStageFlags = VkPipelineStageFlags.TopOfPipe; dstStageFlags = VkPipelineStageFlags.Transfer; } else if (oldLayout == VkImageLayout.TransferSrcOptimal && newLayout == VkImageLayout.ShaderReadOnlyOptimal) { barrier.srcAccessMask = VkAccessFlags.TransferRead; barrier.dstAccessMask = VkAccessFlags.ShaderRead; srcStageFlags = VkPipelineStageFlags.Transfer; dstStageFlags = VkPipelineStageFlags.FragmentShader; } else if (oldLayout == VkImageLayout.TransferDstOptimal && newLayout == VkImageLayout.ShaderReadOnlyOptimal) { barrier.srcAccessMask = VkAccessFlags.TransferWrite; barrier.dstAccessMask = VkAccessFlags.ShaderRead; srcStageFlags = VkPipelineStageFlags.Transfer; dstStageFlags = VkPipelineStageFlags.FragmentShader; } else if (oldLayout == VkImageLayout.TransferSrcOptimal && newLayout == VkImageLayout.TransferDstOptimal) { barrier.srcAccessMask = VkAccessFlags.TransferRead; barrier.dstAccessMask = VkAccessFlags.TransferWrite; srcStageFlags = VkPipelineStageFlags.Transfer; dstStageFlags = VkPipelineStageFlags.Transfer; } else if (oldLayout == VkImageLayout.TransferDstOptimal && newLayout == VkImageLayout.TransferSrcOptimal) { barrier.srcAccessMask = VkAccessFlags.TransferWrite; barrier.dstAccessMask = VkAccessFlags.TransferRead; srcStageFlags = VkPipelineStageFlags.Transfer; dstStageFlags = VkPipelineStageFlags.Transfer; } else if (oldLayout == VkImageLayout.ColorAttachmentOptimal && newLayout == VkImageLayout.TransferSrcOptimal) { barrier.srcAccessMask = VkAccessFlags.ColorAttachmentWrite; barrier.dstAccessMask = VkAccessFlags.TransferRead; srcStageFlags = VkPipelineStageFlags.ColorAttachmentOutput; dstStageFlags = VkPipelineStageFlags.Transfer; } else if (oldLayout == VkImageLayout.ColorAttachmentOptimal && newLayout == VkImageLayout.TransferDstOptimal) { barrier.srcAccessMask = VkAccessFlags.ColorAttachmentWrite; barrier.dstAccessMask = VkAccessFlags.TransferWrite; srcStageFlags = VkPipelineStageFlags.ColorAttachmentOutput; dstStageFlags = VkPipelineStageFlags.Transfer; } else if (oldLayout == VkImageLayout.ColorAttachmentOptimal && newLayout == VkImageLayout.ShaderReadOnlyOptimal) { barrier.srcAccessMask = VkAccessFlags.ColorAttachmentWrite; barrier.dstAccessMask = VkAccessFlags.ShaderRead; srcStageFlags = VkPipelineStageFlags.ColorAttachmentOutput; dstStageFlags = VkPipelineStageFlags.FragmentShader; } else if (oldLayout == VkImageLayout.DepthStencilAttachmentOptimal && newLayout == VkImageLayout.ShaderReadOnlyOptimal) { barrier.srcAccessMask = VkAccessFlags.DepthStencilAttachmentWrite; barrier.dstAccessMask = VkAccessFlags.ShaderRead; srcStageFlags = VkPipelineStageFlags.LateFragmentTests; dstStageFlags = VkPipelineStageFlags.FragmentShader; } else if (oldLayout == VkImageLayout.ColorAttachmentOptimal && newLayout == VkImageLayout.PresentSrcKHR) { barrier.srcAccessMask = VkAccessFlags.ColorAttachmentWrite; barrier.dstAccessMask = VkAccessFlags.MemoryRead; srcStageFlags = VkPipelineStageFlags.ColorAttachmentOutput; dstStageFlags = VkPipelineStageFlags.BottomOfPipe; } else if (oldLayout == VkImageLayout.TransferDstOptimal && newLayout == VkImageLayout.ColorAttachmentOptimal) { barrier.srcAccessMask = VkAccessFlags.TransferWrite; barrier.dstAccessMask = VkAccessFlags.ColorAttachmentWrite; srcStageFlags = VkPipelineStageFlags.Transfer; dstStageFlags = VkPipelineStageFlags.ColorAttachmentOutput; } else if (oldLayout == VkImageLayout.TransferDstOptimal && newLayout == VkImageLayout.DepthStencilAttachmentOptimal) { barrier.srcAccessMask = VkAccessFlags.TransferWrite; barrier.dstAccessMask = VkAccessFlags.DepthStencilAttachmentWrite; srcStageFlags = VkPipelineStageFlags.Transfer; dstStageFlags = VkPipelineStageFlags.LateFragmentTests; } else { Debug.Fail("Invalid image layout transition."); } vkCmdPipelineBarrier( cb, srcStageFlags, dstStageFlags, VkDependencyFlags.None, 0, null, 0, null, 1, &barrier); }
private unsafe void InitializeImage(DataBox[] dataBoxes) { // 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); 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; } VkBuffer uploadResource; int uploadOffset; var uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset); // Upload buffer barrier var bufferMemoryBarrier = new VkBufferMemoryBarrier(uploadResource, VkAccessFlags.HostWrite, VkAccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize); // 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, &bufferMemoryBarrier, 1, &initialBarrier); // Copy data boxes to upload buffer var copies = new VkBufferImageCopy[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 VkBufferImageCopy { bufferOffset = (ulong)uploadOffset, imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)mipSlice, (uint)arraySlice, 1), bufferRowLength = 0, //(uint)(dataBoxes[i].RowPitch / pixelSize), bufferImageHeight = 0, //(uint)(dataBoxes[i].SlicePitch / dataBoxes[i].RowPitch), imageOffset = new Vortice.Mathematics.Point3(0, 0, 0), imageExtent = new Vortice.Mathematics.Size3(mipMapDescription.Width, mipMapDescription.Height, mipMapDescription.Depth) }; uploadMemory += slicePitch; uploadOffset += slicePitch; } // Copy from upload buffer to image fixed(VkBufferImageCopy *copiesPointer = &copies[0]) { vkCmdCopyBufferToImage(commandBuffer, uploadResource, NativeImage, VkImageLayout.TransferDstOptimal, (uint)copies.Length, copiesPointer); } IsInitialized = true; } // 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.NativeCopyCommandPool, 1, &commandBuffer); } }