/// <summary> /// Submits a sequence of semaphores or command buffers to a queue. /// </summary> /// <param name="submit">Specifies a command buffer submission batch.</param> /// <param name="fence"> /// An optional handle to a fence to be signaled. If fence is not <c>null</c>, it defines a /// fence signal operation. /// </param> /// <exception cref="VulkanException">Vulkan returns an error code.</exception> public void Submit(SubmitInfo submit, Fence fence = null) { submit.ToNative(out SubmitInfo.Native nativeSubmit); Result result = vkQueueSubmit(this, 1, &nativeSubmit, fence); nativeSubmit.Free(); VulkanException.ThrowForInvalidResult(result); }
private void displayRenderTarget(RenderTarget rt) { var cimg = _swapChainImages[_syncObjects.CurrentImage]; // Begin recording _commandBuffer.Begin(ONE_TIME_SUBMIT); if (rt != null) { // Trasition the rt to transfer src, and the sc image to transfer dst _rtTransferBarrier.Image = rt.VkImage.Handle; _commandBuffer.CmdPipelineBarrier(Vk.PipelineStages.AllCommands, Vk.PipelineStages.AllCommands, imageMemoryBarriers: new[] { _rtTransferBarrier, cimg.TransferBarrier }); if (rt.Size != Extent) // We need to do a filtered blit because of the size mismatch { var blit = new Vk.ImageBlit { SrcOffset1 = BLIT_ZERO, SrcOffset2 = new Vk.Offset3D(rt.Size.X, rt.Size.Y, 1), SrcSubresource = BLIT_SUBRESOURCE, DstOffset1 = BLIT_ZERO, DstOffset2 = new Vk.Offset3D(Extent.X, Extent.Y, 1), DstSubresource = BLIT_SUBRESOURCE }; _commandBuffer.CmdBlitImage(rt.VkImage, Vk.ImageLayout.TransferSrcOptimal, cimg.Image.Handle, Vk.ImageLayout.TransferDstOptimal, new[] { blit }, Vk.Filter.Linear); } else // Same size, we can do a much faster direct image copy { var copy = new Vk.ImageCopy { SrcOffset = BLIT_ZERO, SrcSubresource = BLIT_SUBRESOURCE, DstOffset = BLIT_ZERO, DstSubresource = BLIT_SUBRESOURCE, Extent = new Vk.Extent3D(rt.Size.X, rt.Size.Y, 1) }; _commandBuffer.CmdCopyImage(rt.VkImage, Vk.ImageLayout.TransferSrcOptimal, cimg.Image, Vk.ImageLayout.TransferDstOptimal, new[] { copy }); } // Transition both images back to their standard layouts _rtAttachBarrier.Image = rt.VkImage.Handle; _commandBuffer.CmdPipelineBarrier(Vk.PipelineStages.AllCommands, Vk.PipelineStages.AllCommands, imageMemoryBarriers: new[] { _rtAttachBarrier, cimg.PresentBarrier }); } else // No render target, valid possibility if there is no active scene { // Trasition the sc image to transfer dst _commandBuffer.CmdPipelineBarrier(Vk.PipelineStages.AllCommands, Vk.PipelineStages.AllCommands, imageMemoryBarriers: new[] { cimg.TransferBarrier }); // Simply clear the swapchain image to black var clear = new Vk.ClearColorValue(0, 0, 0, 1); _commandBuffer.CmdClearColorImage(cimg.Image, Vk.ImageLayout.TransferDstOptimal, clear, new Vk.ImageSubresourceRange(Vk.ImageAspects.Color, 0, 1, 0, 1)); // Transition the image back to its present layout _commandBuffer.CmdPipelineBarrier(Vk.PipelineStages.AllCommands, Vk.PipelineStages.AllCommands, imageMemoryBarriers: new[] { cimg.PresentBarrier }); } // End the buffer, submit, and wait for the blit to complete // This performs GPU-GPU synchonrization by waiting for the swapchain image to be available before blitting _commandBuffer.End(); var si = new Vk.SubmitInfo(waitDstStageMask: new[] { Vk.PipelineStages.Transfer }, waitSemaphores: new[] { _syncObjects.CurrentImageAvailable }, commandBuffers: new[] { _commandBuffer }, signalSemaphores: new[] { _syncObjects.CurrentBlitComplete }); _blitFence.Reset(); // Can need to happen when the swapchain is invalidated or resized _presentQueue.Submit(si, _blitFence); }