diff --git a/src/Veldrid/Vk/VkCommandList.cs b/src/Veldrid/Vk/VkCommandList.cs index dda8c8118..d88006dd4 100644 --- a/src/Veldrid/Vk/VkCommandList.cs +++ b/src/Veldrid/Vk/VkCommandList.cs @@ -42,6 +42,9 @@ internal unsafe class VkCommandList : CommandList private readonly Queue _availableCommandBuffers = new Queue(); private readonly List _submittedCommandBuffers = new List(); + // Render pass cycle state + private bool _newFramebuffer; + public VkCommandPool CommandPool => _pool; public VkCommandBuffer CommandBuffer => _cb; public uint SubmittedCommandBufferCount { get; private set; } @@ -173,14 +176,12 @@ protected override void ClearDepthStencilCore(float depth, byte stencil) if (_activeRenderPass != VkRenderPass.Null) { - VkImageAspectFlags aspectMask = VkImageAspectFlags.Depth; - if (FormatHelpers.IsStencilFormat(_currentFramebuffer.DepthTarget.Value.Target.Format)) - { - aspectMask |= VkImageAspectFlags.Stencil; - } + VkImageAspectFlags aspect = FormatHelpers.IsStencilFormat(_currentFramebuffer.DepthTarget.Value.Target.Format) + ? VkImageAspectFlags.Depth | VkImageAspectFlags.Stencil + : VkImageAspectFlags.Depth; VkClearAttachment clearAttachment = new VkClearAttachment { - aspectMask = aspectMask, + aspectMask = aspect, clearValue = clearValue }; @@ -379,14 +380,14 @@ public override void End() _commandBufferBegun = false; _commandBufferEnded = true; - if (_activeRenderPass != VkRenderPass.Null) + if (!_currentFramebufferEverActive && _currentFramebuffer != null) { - EndCurrentRenderPass(); + BeginCurrentRenderPass(); } - else if (!_currentFramebufferEverActive && _currentFramebuffer != null) + if (_activeRenderPass != VkRenderPass.Null) { - BeginCurrentRenderPass(); EndCurrentRenderPass(); + _currentFramebuffer.TransitionToFinalLayout(_cb); } vkEndCommandBuffer(_cb); @@ -395,6 +396,7 @@ public override void End() protected override void SetFramebufferCore(Framebuffer fb) { + _newFramebuffer = true; if (_activeRenderPass.Handle != VkRenderPass.Null) { EndCurrentRenderPass(); @@ -406,6 +408,11 @@ protected override void SetFramebufferCore(Framebuffer fb) EndCurrentRenderPass(); } + if (_currentFramebuffer != null) + { + _currentFramebuffer.TransitionToFinalLayout(_cb); + } + VkFramebufferBase vkFB = Util.AssertSubtype(fb); _currentFramebuffer = vkFB; _currentFramebufferEverActive = false; @@ -461,9 +468,11 @@ private void BeginCurrentRenderPass() if (!haveAnyAttachments || !haveAllClearValues) { - renderPassBI.renderPass = _currentFramebuffer.RenderPassNoClear; + renderPassBI.renderPass = _newFramebuffer + ? _currentFramebuffer.RenderPassNoClear_Init + : _currentFramebuffer.RenderPassNoClear_Load; vkCmdBeginRenderPass(_cb, ref renderPassBI, VkSubpassContents.Inline); - _activeRenderPass = _currentFramebuffer.RenderPassNoClear; + _activeRenderPass = renderPassBI.renderPass; if (haveAnyClearValues) { @@ -508,25 +517,7 @@ private void BeginCurrentRenderPass() } } - // Set new image layouts - foreach (FramebufferAttachment colorTarget in _currentFramebuffer.ColorTargets) - { - VkTexture vkTex = Util.AssertSubtype(colorTarget.Target); - VkImageLayout layout = (vkTex.Usage & TextureUsage.Sampled) != 0 - ? VkImageLayout.ShaderReadOnlyOptimal - : VkImageLayout.ColorAttachmentOptimal; - vkTex.SetImageLayout(colorTarget.ArrayLayer, layout); - } - - if (_currentFramebuffer.DepthTarget != null) - { - VkTexture vkDepthTex = Util.AssertSubtype(_currentFramebuffer.DepthTarget.Value.Target); - VkImageLayout layout = (vkDepthTex.Usage & TextureUsage.Sampled) != 0 - ? VkImageLayout.ShaderReadOnlyOptimal - : VkImageLayout.DepthStencilAttachmentOptimal; - - vkDepthTex.SetImageLayout(_currentFramebuffer.DepthTarget.Value.ArrayLayer, layout); - } + _newFramebuffer = false; } private void EndCurrentRenderPass() diff --git a/src/Veldrid/Vk/VkFramebuffer.cs b/src/Veldrid/Vk/VkFramebuffer.cs index e031e7b36..f8b280c09 100644 --- a/src/Veldrid/Vk/VkFramebuffer.cs +++ b/src/Veldrid/Vk/VkFramebuffer.cs @@ -11,6 +11,7 @@ internal unsafe class VkFramebuffer : VkFramebufferBase { private readonly VkGraphicsDevice _gd; private readonly Vulkan.VkFramebuffer _deviceFramebuffer; + private readonly VkRenderPass _renderPassNoClearLoad; private readonly VkRenderPass _renderPassNoClear; private readonly VkRenderPass _renderPassClear; private readonly List _attachmentViews = new List(); @@ -18,7 +19,8 @@ internal unsafe class VkFramebuffer : VkFramebufferBase private string _name; public override Vulkan.VkFramebuffer CurrentFramebuffer => _deviceFramebuffer; - public override VkRenderPass RenderPassNoClear => _renderPassNoClear; + public override VkRenderPass RenderPassNoClear_Init => _renderPassNoClear; + public override VkRenderPass RenderPassNoClear_Load => _renderPassNoClearLoad; public override VkRenderPass RenderPassClear => _renderPassClear; public override uint RenderableWidth => Width; @@ -43,16 +45,12 @@ public VkFramebuffer(VkGraphicsDevice gd, ref FramebufferDescription description VkAttachmentDescription colorAttachmentDesc = new VkAttachmentDescription(); colorAttachmentDesc.format = vkColorTex.VkFormat; colorAttachmentDesc.samples = vkColorTex.VkSampleCount; - colorAttachmentDesc.loadOp = VkAttachmentLoadOp.Load; + colorAttachmentDesc.loadOp = VkAttachmentLoadOp.DontCare; colorAttachmentDesc.storeOp = VkAttachmentStoreOp.Store; colorAttachmentDesc.stencilLoadOp = VkAttachmentLoadOp.DontCare; colorAttachmentDesc.stencilStoreOp = VkAttachmentStoreOp.DontCare; colorAttachmentDesc.initialLayout = VkImageLayout.Undefined; - colorAttachmentDesc.finalLayout = isPresented - ? VkImageLayout.PresentSrcKHR - : (vkColorTex.Usage & TextureUsage.Sampled) != 0 - ? VkImageLayout.ShaderReadOnlyOptimal - : VkImageLayout.ColorAttachmentOptimal; + colorAttachmentDesc.finalLayout = VkImageLayout.ColorAttachmentOptimal; attachments.Add(colorAttachmentDesc); VkAttachmentReference colorAttachmentRef = new VkAttachmentReference(); @@ -69,14 +67,12 @@ public VkFramebuffer(VkGraphicsDevice gd, ref FramebufferDescription description bool hasStencil = FormatHelpers.IsStencilFormat(vkDepthTex.Format); depthAttachmentDesc.format = vkDepthTex.VkFormat; depthAttachmentDesc.samples = vkDepthTex.VkSampleCount; - depthAttachmentDesc.loadOp = VkAttachmentLoadOp.Load; + depthAttachmentDesc.loadOp = VkAttachmentLoadOp.DontCare; depthAttachmentDesc.storeOp = VkAttachmentStoreOp.Store; - depthAttachmentDesc.stencilLoadOp = hasStencil ? VkAttachmentLoadOp.Load : VkAttachmentLoadOp.DontCare; + depthAttachmentDesc.stencilLoadOp = VkAttachmentLoadOp.DontCare; depthAttachmentDesc.stencilStoreOp = hasStencil ? VkAttachmentStoreOp.Store : VkAttachmentStoreOp.DontCare; depthAttachmentDesc.initialLayout = VkImageLayout.Undefined; - depthAttachmentDesc.finalLayout = (vkDepthTex.Usage & TextureUsage.Sampled) != 0 - ? VkImageLayout.ShaderReadOnlyOptimal - : VkImageLayout.DepthStencilAttachmentOptimal; + depthAttachmentDesc.finalLayout = VkImageLayout.DepthStencilAttachmentOptimal; depthAttachmentRef.attachment = (uint)description.ColorTargets.Length; depthAttachmentRef.layout = VkImageLayout.DepthStencilAttachmentOptimal; @@ -116,14 +112,43 @@ public VkFramebuffer(VkGraphicsDevice gd, ref FramebufferDescription description VkResult creationResult = vkCreateRenderPass(_gd.Device, ref renderPassCI, null, out _renderPassNoClear); CheckResult(creationResult); + for (int i = 0; i < colorAttachmentCount; i++) + { + attachments[i].loadOp = VkAttachmentLoadOp.Load; + attachments[i].initialLayout = VkImageLayout.ColorAttachmentOptimal; + } + if (DepthTarget != null) + { + attachments[attachments.Count - 1].loadOp = VkAttachmentLoadOp.Load; + attachments[attachments.Count - 1].initialLayout = VkImageLayout.DepthStencilAttachmentOptimal; + bool hasStencil = FormatHelpers.IsStencilFormat(DepthTarget.Value.Target.Format); + if (hasStencil) + { + attachments[attachments.Count - 1].stencilLoadOp = VkAttachmentLoadOp.Load; + } + + } + creationResult = vkCreateRenderPass(_gd.Device, ref renderPassCI, null, out _renderPassNoClearLoad); + CheckResult(creationResult); + + + // Load version + if (DepthTarget != null) { attachments[attachments.Count - 1].loadOp = VkAttachmentLoadOp.Clear; + attachments[attachments.Count - 1].initialLayout = VkImageLayout.Undefined; + bool hasStencil = FormatHelpers.IsStencilFormat(DepthTarget.Value.Target.Format); + if (hasStencil) + { + attachments[attachments.Count - 1].stencilLoadOp = VkAttachmentLoadOp.Load; + } } for (int i = 0; i < colorAttachmentCount; i++) { attachments[i].loadOp = VkAttachmentLoadOp.Clear; + attachments[i].initialLayout = VkImageLayout.Undefined; } creationResult = vkCreateRenderPass(_gd.Device, ref renderPassCI, null, out _renderPassClear); @@ -203,6 +228,28 @@ public VkFramebuffer(VkGraphicsDevice gd, ref FramebufferDescription description AttachmentCount += (uint)ColorTargets.Count; } + public override void TransitionToFinalLayout(VkCommandBuffer cb) + { + foreach (FramebufferAttachment ca in ColorTargets) + { + VkTexture vkTex = Util.AssertSubtype(ca.Target); + vkTex.SetImageLayout(ca.ArrayLayer, VkImageLayout.ColorAttachmentOptimal); + if ((vkTex.Usage & TextureUsage.Sampled) != 0) + { + vkTex.TransitionImageLayout(cb, 0, 1, ca.ArrayLayer, 1, VkImageLayout.ShaderReadOnlyOptimal); + } + } + if (DepthTarget != null) + { + VkTexture vkTex = Util.AssertSubtype(DepthTarget.Value.Target); + vkTex.SetImageLayout(DepthTarget.Value.ArrayLayer, VkImageLayout.DepthStencilAttachmentOptimal); + if ((vkTex.Usage & TextureUsage.Sampled) != 0) + { + vkTex.TransitionImageLayout(cb, 0, 1, DepthTarget.Value.ArrayLayer, 1, VkImageLayout.ShaderReadOnlyOptimal); + } + } + } + public override string Name { get => _name; diff --git a/src/Veldrid/Vk/VkFramebufferBase.cs b/src/Veldrid/Vk/VkFramebufferBase.cs index 19fc3bb77..fca731a84 100644 --- a/src/Veldrid/Vk/VkFramebufferBase.cs +++ b/src/Veldrid/Vk/VkFramebufferBase.cs @@ -20,8 +20,10 @@ public VkFramebufferBase() } public abstract Vulkan.VkFramebuffer CurrentFramebuffer { get; } - public abstract VkRenderPass RenderPassNoClear { get; } + public abstract VkRenderPass RenderPassNoClear_Init { get; } + public abstract VkRenderPass RenderPassNoClear_Load { get; } public abstract VkRenderPass RenderPassClear { get; } public abstract uint AttachmentCount { get; } + public abstract void TransitionToFinalLayout(VkCommandBuffer cb); } } diff --git a/src/Veldrid/Vk/VkGraphicsDevice.cs b/src/Veldrid/Vk/VkGraphicsDevice.cs index 0db8ea692..407d188a4 100644 --- a/src/Veldrid/Vk/VkGraphicsDevice.cs +++ b/src/Veldrid/Vk/VkGraphicsDevice.cs @@ -1077,6 +1077,7 @@ internal void ClearColorTexture(VkTexture texture, VkClearColorValue color) VkCommandBuffer cb = pool.BeginNewCommandBuffer(); texture.TransitionImageLayout(cb, 0, texture.MipLevels, 0, texture.ArrayLayers, VkImageLayout.TransferDstOptimal); vkCmdClearColorImage(cb, texture.OptimalDeviceImage, VkImageLayout.TransferDstOptimal, &color, 1, &range); + texture.TransitionImageLayout(cb, 0, texture.MipLevels, 0, texture.ArrayLayers, VkImageLayout.ColorAttachmentOptimal); pool.EndAndSubmit(cb); } @@ -1098,6 +1099,7 @@ internal void ClearDepthTexture(VkTexture texture, VkClearDepthStencilValue clea &clearValue, 1, &range); + texture.TransitionImageLayout(cb, 0, texture.MipLevels, 0, texture.ArrayLayers, VkImageLayout.DepthStencilAttachmentOptimal); pool.EndAndSubmit(cb); } diff --git a/src/Veldrid/Vk/VkSwapchainFramebuffer.cs b/src/Veldrid/Vk/VkSwapchainFramebuffer.cs index d8ebb9a6c..4d261a266 100644 --- a/src/Veldrid/Vk/VkSwapchainFramebuffer.cs +++ b/src/Veldrid/Vk/VkSwapchainFramebuffer.cs @@ -29,7 +29,8 @@ internal unsafe class VkSwapchainFramebuffer : VkFramebufferBase public override Vulkan.VkFramebuffer CurrentFramebuffer => _scFramebuffers[(int)_currentImageIndex].CurrentFramebuffer; - public override VkRenderPass RenderPassNoClear => _scFramebuffers[0].RenderPassNoClear; + public override VkRenderPass RenderPassNoClear_Init => _scFramebuffers[0].RenderPassNoClear_Init; + public override VkRenderPass RenderPassNoClear_Load => _scFramebuffers[0].RenderPassNoClear_Load; public override VkRenderPass RenderPassClear => _scFramebuffers[0].RenderPassClear; public override IReadOnlyList ColorTargets => _scColorTextures[(int)_currentImageIndex]; @@ -147,6 +148,16 @@ private void CreateFramebuffers() } } + public override void TransitionToFinalLayout(VkCommandBuffer cb) + { + foreach (FramebufferAttachment ca in ColorTargets) + { + VkTexture vkTex = Util.AssertSubtype(ca.Target); + vkTex.SetImageLayout(ca.ArrayLayer, VkImageLayout.ColorAttachmentOptimal); + vkTex.TransitionImageLayout(cb, 0, 1, ca.ArrayLayer, 1, VkImageLayout.PresentSrcKHR); + } + } + public override string Name { get => _name; diff --git a/src/Veldrid/Vk/VulkanUtil.cs b/src/Veldrid/Vk/VulkanUtil.cs index ece5d4258..3f9ef5577 100644 --- a/src/Veldrid/Vk/VulkanUtil.cs +++ b/src/Veldrid/Vk/VulkanUtil.cs @@ -228,6 +228,41 @@ public static bool IsVulkanLoaded() 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.");