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, MultiSampleLevel = MSAALevel.None, Usage = GraphicsResourceUsage.Default }; backbuffer.InitializeWithoutResources(backBufferDescription); var createInfo = new ImageViewCreateInfo { StructureType = StructureType.ImageViewCreateInfo, SubresourceRange = new ImageSubresourceRange(ImageAspectFlags.Color, 0, 1, 0, 1), Format = backbuffer.NativeFormat, }; // We initialize swapchain images to PresentSource, since we swap them out while in this layout. backbuffer.NativeAccessMask = AccessFlags.MemoryRead; backbuffer.NativeLayout = ImageLayout.PresentSource; var imageMemoryBarrier = new ImageMemoryBarrier { StructureType = StructureType.ImageMemoryBarrier, SubresourceRange = new ImageSubresourceRange(ImageAspectFlags.Color, 0, 1, 0, 1), OldLayout = ImageLayout.Undefined, NewLayout = ImageLayout.PresentSource, SourceAccessMask = AccessFlags.None, DestinationAccessMask = AccessFlags.MemoryRead }; var commandBuffer = GraphicsDevice.NativeCopyCommandBuffer; var beginInfo = new CommandBufferBeginInfo { StructureType = StructureType.CommandBufferBeginInfo }; commandBuffer.Begin(ref beginInfo); var buffers = GraphicsDevice.NativeDevice.GetSwapchainImages(swapChain); swapchainImages = new SwapChainImageInfo[buffers.Length]; for (int i = 0; i < buffers.Length; i++) { // Create image views swapchainImages[i].NativeImage = createInfo.Image = buffers[i]; swapchainImages[i].NativeColorAttachmentView = GraphicsDevice.NativeDevice.CreateImageView(ref createInfo); // Transition to default layout imageMemoryBarrier.Image = buffers[i]; commandBuffer.PipelineBarrier(PipelineStageFlags.AllCommands, PipelineStageFlags.AllCommands, DependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); } // Close and submit commandBuffer.End(); var submitInfo = new SubmitInfo { StructureType = StructureType.SubmitInfo, CommandBufferCount = 1, CommandBuffers = new IntPtr(&commandBuffer), }; GraphicsDevice.NativeCommandQueue.Submit(1, &submitInfo, Fence.Null); GraphicsDevice.NativeCommandQueue.WaitIdle(); commandBuffer.Reset(CommandBufferResetFlags.None); // Get next image currentBufferIndex = GraphicsDevice.NativeDevice.AcquireNextImage(swapChain, ulong.MaxValue, GraphicsDevice.GetNextPresentSemaphore(), Fence.Null); // Apply the first swap chain image to the texture backbuffer.SetNativeHandles(swapchainImages[currentBufferIndex].NativeImage, swapchainImages[currentBufferIndex].NativeColorAttachmentView); }
private void DrawInternal() { // Update descriptors var descriptorSets = stackalloc DescriptorSet[2]; var setLayouts = stackalloc DescriptorSetLayout[2]; setLayouts[0] = setLayouts[1] = descriptorSetLayout; var allocateInfo = new DescriptorSetAllocateInfo { StructureType = StructureType.DescriptorSetAllocateInfo, DescriptorPool = descriptorPool, DescriptorSetCount = 2, SetLayouts = new IntPtr(setLayouts), }; device.AllocateDescriptorSets(ref allocateInfo, descriptorSets); var bufferInfo = new DescriptorBufferInfo { Buffer = uniformBuffer, Range = Vulkan.WholeSize }; var write = new WriteDescriptorSet { StructureType = StructureType.WriteDescriptorSet, DescriptorCount = 1, DestinationSet = descriptorSets[0], DestinationBinding = 0, DescriptorType = DescriptorType.UniformBuffer, BufferInfo = new IntPtr(&bufferInfo) }; var copy = new CopyDescriptorSet { StructureType = StructureType.CopyDescriptorSet, DescriptorCount = 1, SourceBinding = 0, DestinationBinding = 0, SourceSet = descriptorSets[0], DestinationSet = descriptorSets[1] }; device.UpdateDescriptorSets(1, &write, 0, null); device.UpdateDescriptorSets(0, null, 1, ©); // Post-present transition var memoryBarrier = new ImageMemoryBarrier { StructureType = StructureType.ImageMemoryBarrier, Image = backBuffers[currentBackBufferIndex], SubresourceRange = new ImageSubresourceRange(ImageAspectFlags.Color, 0, 1, 0, 1), OldLayout = ImageLayout.PresentSource, NewLayout = ImageLayout.ColorAttachmentOptimal, SourceAccessMask = AccessFlags.MemoryRead, DestinationAccessMask = AccessFlags.ColorAttachmentWrite }; commandBuffer.PipelineBarrier(PipelineStageFlags.TopOfPipe, PipelineStageFlags.TopOfPipe, DependencyFlags.None, 0, null, 0, null, 1, &memoryBarrier); // Clear render target var clearRange = new ImageSubresourceRange(ImageAspectFlags.Color, 0, 1, 0, 1); commandBuffer.ClearColorImage(backBuffers[currentBackBufferIndex], ImageLayout.TransferDestinationOptimal, new RawColor4(0, 0, 0, 1), 1, &clearRange); // Begin render pass var renderPassBeginInfo = new RenderPassBeginInfo { StructureType = StructureType.RenderPassBeginInfo, RenderPass = renderPass, Framebuffer = framebuffers[currentBackBufferIndex], RenderArea = new Rect2D(0, 0, (uint)form.ClientSize.Width, (uint)form.ClientSize.Height), }; commandBuffer.BeginRenderPass(ref renderPassBeginInfo, SubpassContents.Inline); // Bind pipeline commandBuffer.BindPipeline(PipelineBindPoint.Graphics, pipeline); // Bind descriptor sets commandBuffer.BindDescriptorSets(PipelineBindPoint.Graphics, pipelineLayout, 0, 1, descriptorSets + 1, 0, null); // Set viewport and scissor var viewport = new Viewport(0, 0, form.ClientSize.Width, form.ClientSize.Height); commandBuffer.SetViewport(0, 1, &viewport); var scissor = new Rect2D(0, 0, (uint)form.ClientSize.Width, (uint)form.ClientSize.Height); commandBuffer.SetScissor(0, 1, &scissor); // Bind vertex buffer var vertexBufferCopy = vertexBuffer; ulong offset = 0; commandBuffer.BindVertexBuffers(0, 1, &vertexBufferCopy, &offset); // Draw vertices commandBuffer.Draw(3, 1, 0, 0); // End render pass commandBuffer.EndRenderPass(); // Pre-present transition memoryBarrier = new ImageMemoryBarrier { StructureType = StructureType.ImageMemoryBarrier, Image = backBuffers[currentBackBufferIndex], SubresourceRange = new ImageSubresourceRange(ImageAspectFlags.Color, 0, 1, 0, 1), OldLayout = ImageLayout.ColorAttachmentOptimal, NewLayout = ImageLayout.PresentSource, SourceAccessMask = AccessFlags.ColorAttachmentWrite, DestinationAccessMask = AccessFlags.MemoryRead }; commandBuffer.PipelineBarrier(PipelineStageFlags.AllCommands, PipelineStageFlags.BottomOfPipe, DependencyFlags.None, 0, null, 0, null, 1, &memoryBarrier); }
private void SetImageLayout(Image image, ImageAspectFlags imageAspect, ImageLayout oldLayout, ImageLayout newLayout) { if (setupCommanBuffer == CommandBuffer.Null) { // Create command buffer CommandBuffer setupCommandBuffer; var allocateInfo = new CommandBufferAllocateInfo { StructureType = StructureType.CommandBufferAllocateInfo, CommandPool = commandPool, Level = CommandBufferLevel.Primary, CommandBufferCount = 1, }; device.AllocateCommandBuffers(ref allocateInfo, &setupCommandBuffer); setupCommanBuffer = setupCommandBuffer; // Begin command buffer var inheritanceInfo = new CommandBufferInheritanceInfo { StructureType = StructureType.CommandBufferInheritanceInfo }; var beginInfo = new CommandBufferBeginInfo { StructureType = StructureType.CommandBufferBeginInfo, InheritanceInfo = new IntPtr(&inheritanceInfo) }; setupCommanBuffer.Begin(ref beginInfo); } var imageMemoryBarrier = new ImageMemoryBarrier { StructureType = StructureType.ImageMemoryBarrier, OldLayout = oldLayout, NewLayout = newLayout, Image = image, SubresourceRange = new ImageSubresourceRange(imageAspect, 0, 1, 0, 1) }; switch (newLayout) { case ImageLayout.TransferDestinationOptimal: imageMemoryBarrier.DestinationAccessMask = AccessFlags.TransferRead; break; case ImageLayout.ColorAttachmentOptimal: imageMemoryBarrier.DestinationAccessMask = AccessFlags.ColorAttachmentWrite; break; case ImageLayout.DepthStencilAttachmentOptimal: imageMemoryBarrier.DestinationAccessMask = AccessFlags.DepthStencilAttachmentWrite; break; case ImageLayout.ShaderReadOnlyOptimal: imageMemoryBarrier.DestinationAccessMask = AccessFlags.ShaderRead | AccessFlags.InputAttachmentRead; break; } var sourceStages = PipelineStageFlags.TopOfPipe; var destinationStages = PipelineStageFlags.TopOfPipe; setupCommanBuffer.PipelineBarrier(sourceStages, destinationStages, DependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); }
private unsafe void InitializeImage(DataBox[] dataBoxes) { var commandBuffer = GraphicsDevice.NativeCopyCommandBuffer; var beginInfo = new CommandBufferBeginInfo { StructureType = StructureType.CommandBufferBeginInfo }; commandBuffer.Begin(ref beginInfo); if (dataBoxes != null && dataBoxes.Length > 0) { // Buffer-to-image copies need to be aligned to the pixel size and 4 (always a power of 2) var blockSize = Format.IsCompressed() ? NativeFormat.BlockSizeInBytes() : TexturePixelSize; var alignmentMask = (blockSize < 4 ? 4 : blockSize) - 1; int totalSize = dataBoxes.Length * alignmentMask; for (int i = 0; i < dataBoxes.Length; i++) { totalSize += dataBoxes[i].SlicePitch; } SharpVulkan.Buffer uploadResource; int uploadOffset; var uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset); // Upload buffer barrier var bufferMemoryBarrier = new BufferMemoryBarrier(uploadResource, AccessFlags.HostWrite, AccessFlags.TransferRead, (ulong)uploadOffset, (ulong)totalSize); // Image barrier var initialBarrier = new ImageMemoryBarrier(NativeImage, ImageLayout.Undefined, ImageLayout.TransferDestinationOptimal, AccessFlags.None, AccessFlags.TransferWrite, new ImageSubresourceRange(NativeImageAspect)); commandBuffer.PipelineBarrier(PipelineStageFlags.TopOfPipe, PipelineStageFlags.Transfer, DependencyFlags.None, 0, null, 1, &bufferMemoryBarrier, 1, &initialBarrier); // Copy data boxes to upload buffer var copies = new BufferImageCopy[dataBoxes.Length]; for (int i = 0; i < copies.Length; i++) { var slicePitch = dataBoxes[i].SlicePitch; int arraySlice = i / MipLevels; int mipSlice = i % MipLevels; var mipMapDescription = GetMipMapDescription(mipSlice); SubresourceLayout layout; GraphicsDevice.NativeDevice.GetImageSubresourceLayout(NativeImage, new ImageSubresource(NativeImageAspect, (uint)arraySlice, (uint)mipSlice), out layout); var alignment = ((uploadOffset + alignmentMask) & ~alignmentMask) - uploadOffset; uploadMemory += alignment; uploadOffset += alignment; Utilities.CopyMemory(uploadMemory, dataBoxes[i].DataPointer, slicePitch); // TODO VULKAN: Check if pitches are valid copies[i] = new BufferImageCopy { BufferOffset = (ulong)uploadOffset, ImageSubresource = new ImageSubresourceLayers(ImageAspectFlags.Color, (uint)arraySlice, 1, (uint)mipSlice), BufferRowLength = 0, //(uint)(dataBoxes[i].RowPitch / pixelSize), BufferImageHeight = 0, //(uint)(dataBoxes[i].SlicePitch / dataBoxes[i].RowPitch), ImageOffset = new Offset3D(0, 0, arraySlice), ImageExtent = new Extent3D((uint)mipMapDescription.Width, (uint)mipMapDescription.Height, 1) }; uploadMemory += slicePitch; uploadOffset += slicePitch; } // Copy from upload buffer to image fixed (BufferImageCopy* copiesPointer = &copies[0]) { commandBuffer.CopyBufferToImage(uploadResource, NativeImage, ImageLayout.TransferDestinationOptimal, (uint)copies.Length, copiesPointer); } IsInitialized = true; } // Transition to default layout var imageMemoryBarrier = new ImageMemoryBarrier(NativeImage, dataBoxes == null || dataBoxes.Length == 0 ? ImageLayout.Undefined : ImageLayout.TransferDestinationOptimal, NativeLayout, dataBoxes == null || dataBoxes.Length == 0 ? AccessFlags.None : AccessFlags.TransferWrite, NativeAccessMask, new ImageSubresourceRange(NativeImageAspect)); commandBuffer.PipelineBarrier(PipelineStageFlags.Transfer, PipelineStageFlags.AllCommands, DependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); // Close and submit commandBuffer.End(); var submitInfo = new SubmitInfo { StructureType = StructureType.SubmitInfo, CommandBufferCount = 1, CommandBuffers = new IntPtr(&commandBuffer), }; lock (GraphicsDevice.QueueLock) { GraphicsDevice.NativeCommandQueue.Submit(1, &submitInfo, Fence.Null); GraphicsDevice.NativeCommandQueue.WaitIdle(); commandBuffer.Reset(CommandBufferResetFlags.None); } }
internal static unsafe extern void vkCmdWaitEvents(CommandBuffer commandBuffer, uint eventCount, Event* events, PipelineStageFlags sourceStageMask, PipelineStageFlags destinationStageMask, uint memoryBarrierCount, MemoryBarrier* memoryBarriers, uint bufferMemoryBarrierCount, BufferMemoryBarrier* bufferMemoryBarriers, uint imageMemoryBarrierCount, ImageMemoryBarrier* imageMemoryBarriers);
internal static unsafe extern void vkCmdPipelineBarrier(CommandBuffer commandBuffer, PipelineStageFlags sourceStageMask, PipelineStageFlags destinationStageMask, DependencyFlags dependencyFlags, uint memoryBarrierCount, MemoryBarrier* memoryBarriers, uint bufferMemoryBarrierCount, BufferMemoryBarrier* bufferMemoryBarriers, uint imageMemoryBarrierCount, ImageMemoryBarrier* imageMemoryBarriers);
public unsafe void WaitEvents(uint eventCount, Event events, PipelineStageFlags sourceStageMask, PipelineStageFlags destinationStageMask, uint memoryBarrierCount, MemoryBarrier* memoryBarriers, uint bufferMemoryBarrierCount, BufferMemoryBarrier* bufferMemoryBarriers, uint imageMemoryBarrierCount, ImageMemoryBarrier* imageMemoryBarriers) { vkCmdWaitEvents(this, eventCount, &events, sourceStageMask, destinationStageMask, memoryBarrierCount, memoryBarriers, bufferMemoryBarrierCount, bufferMemoryBarriers, imageMemoryBarrierCount, imageMemoryBarriers); }
public unsafe void PipelineBarrier(PipelineStageFlags sourceStageMask, PipelineStageFlags destinationStageMask, DependencyFlags dependencyFlags, uint memoryBarrierCount, MemoryBarrier* memoryBarriers, uint bufferMemoryBarrierCount, BufferMemoryBarrier* bufferMemoryBarriers, uint imageMemoryBarrierCount, ImageMemoryBarrier* imageMemoryBarriers) { vkCmdPipelineBarrier(this, sourceStageMask, destinationStageMask, dependencyFlags, memoryBarrierCount, memoryBarriers, bufferMemoryBarrierCount, bufferMemoryBarriers, imageMemoryBarrierCount, imageMemoryBarriers); }