diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index 58a8fac99a..07fc66510c 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -249,6 +249,7 @@ + @@ -321,6 +322,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index c3ae5eea9e..413f08cb8b 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -75,7 +75,12 @@ - + + Vulkan + + + Vulkan + @@ -139,7 +144,12 @@ - + + Vulkan + + + Vulkan + @@ -155,4 +165,4 @@ {c14d66ef-5f7c-4565-975a-72774e7ccfb9} - + \ No newline at end of file diff --git a/Common/Vulkan/VulkanQueueRunner.cpp b/Common/Vulkan/VulkanQueueRunner.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Common/Vulkan/VulkanQueueRunner.h b/Common/Vulkan/VulkanQueueRunner.h new file mode 100644 index 0000000000..9da875a95c --- /dev/null +++ b/Common/Vulkan/VulkanQueueRunner.h @@ -0,0 +1,6 @@ +#pragma once + +class VulkanQueueRunner { +public: + +}; \ No newline at end of file diff --git a/Common/Vulkan/VulkanRenderManager.cpp b/Common/Vulkan/VulkanRenderManager.cpp index eab92174aa..a2e2d7fd1f 100644 --- a/Common/Vulkan/VulkanRenderManager.cpp +++ b/Common/Vulkan/VulkanRenderManager.cpp @@ -141,13 +141,12 @@ void VulkanRenderManager::CreateBackbuffers() { VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); - res = vkCreateImageView(vulkan_->GetDevice(), - &color_image_view, NULL, &sc_buffer.view); + res = vkCreateImageView(vulkan_->GetDevice(), &color_image_view, NULL, &sc_buffer.view); swapchainImages_.push_back(sc_buffer); assert(res == VK_SUCCESS); } delete[] swapchainImages; - current_buffer = -1; + curSwapchainImage_ = -1; InitDepthStencilBuffer(cmdInit); // Must be before InitBackbufferRenderPass. InitBackbufferRenderPass(); // Must be before InitFramebuffers. @@ -186,7 +185,6 @@ VulkanRenderManager::~VulkanRenderManager() { } framebuffers_.clear(); for (int i = 0; i < ARRAY_SIZE(renderPasses_); i++) { - // vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]); vkDestroyRenderPass(device, renderPasses_[i], nullptr); } } @@ -201,14 +199,13 @@ void VulkanRenderManager::ThreadFunc() { } void VulkanRenderManager::BeginFrame() { - VkDevice device = vulkan_->GetDevice(); FrameData &frameData = frameData_[vulkan_->GetCurFrame()]; // Get the index of the next available swapchain image, and a semaphore to block command buffer execution on. // Now, I wonder if we should do this early in the frame or late? Right now we do it early, which should be fine. - VkResult res = vkAcquireNextImageKHR(device, vulkan_->GetSwapchain(), UINT64_MAX, acquireSemaphore_, (VkFence)VK_NULL_HANDLE, ¤t_buffer); + VkResult res = vkAcquireNextImageKHR(device, vulkan_->GetSwapchain(), UINT64_MAX, acquireSemaphore_, (VkFence)VK_NULL_HANDLE, &curSwapchainImage_); assert(res == VK_SUCCESS); // Make sure the very last command buffer from the frame before the previous has been fully executed. @@ -243,7 +240,7 @@ void VulkanRenderManager::EndFrame() { FrameData &frame = frameData_[vulkan_->GetCurFrame()]; - TransitionToPresent(frame.mainCmd, swapchainImages_[current_buffer].image); + TransitionToPresent(frame.mainCmd, swapchainImages_[curSwapchainImage_].image); VkResult res = vkEndCommandBuffer(frame.mainCmd); assert(res == VK_SUCCESS); @@ -281,7 +278,7 @@ void VulkanRenderManager::EndFrame() { VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; present.swapchainCount = 1; present.pSwapchains = &swapchain; - present.pImageIndices = ¤t_buffer; + present.pImageIndices = &curSwapchainImage_; present.pWaitSemaphores = &renderingCompleteSemaphore; present.waitSemaphoreCount = 1; present.pResults = nullptr; @@ -296,6 +293,14 @@ void VulkanRenderManager::Sync() { } void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil) { + // Eliminate dupes. + if (steps_.size() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) { + if (color != VKRRenderPassAction::CLEAR && depth != VKRRenderPassAction::CLEAR) { + // We don't move to a new step, this bind was unnecessary. + return; + } + } + VKRStep *step = new VKRStep{ VKRStepType::RENDER }; // This is what queues up new passes, and can end previous ones. step->render.framebuffer = fb; @@ -304,7 +309,10 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR step->render.clearColor = clearColor; step->render.clearDepth = clearDepth; step->render.clearStencil = clearStencil; + step->render.numDraws = 0; + step->render.finalColorLayout = !fb ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED; steps_.push_back(step); + curRenderStep_ = step; curWidth_ = fb ? fb->width : vulkan_->GetBackbufferWidth(); curHeight_ = fb ? fb->height : vulkan_->GetBackbufferHeight(); @@ -579,34 +587,20 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment) { // Should just mark the dependency and return the image. - for (int i = 0; i < (int)steps_.size() - 1; i++) { + for (int i = (int)steps_.size() - 1; i >= 0; i--) { if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == fb) { - if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) + // If this framebuffer was rendered to earlier in this frame, make sure to pre-transition it to the correct layout. + if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - else - Crash(); // May need to shadow the framebuffer? + break; + } + else { + // May need to shadow the framebuffer if we re-order passes later. + } } } - /* - VkAccessFlags srcAccessMask; - VkPipelineStageFlags srcStage; - switch (fb->color.layout) { - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; - srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - } - TransitionImageLayout2(transitionCmdBuf, fb->color.image, VK_IMAGE_ASPECT_COLOR_BIT, - fb->color.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - srcStage, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - srcAccessMask, VK_ACCESS_SHADER_READ_BIT); - fb->color.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - */ + curRenderStep_->preTransitions.push_back({ fb, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }); return fb->color.imageView; } @@ -633,7 +627,7 @@ void VulkanRenderManager::Flush() { // return codes // TODO: Is it best to do this here, or combine with some other transition, or just do it right before the backbuffer bind-for-render? assert(res == VK_SUCCESS); - TransitionFromPresent(cmd, swapchainImages_[current_buffer].image); + TransitionFromPresent(cmd, swapchainImages_[curSwapchainImage_].image); // Optimizes renderpasses, then sequences them. for (int i = 0; i < stepsOnThread_.size(); i++) { @@ -658,8 +652,60 @@ void VulkanRenderManager::Flush() { } void VulkanRenderManager::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd) { + // TODO: If there are multiple, we can transition them together. + for (const auto &iter : step.preTransitions) { + if (iter.fb->color.layout != iter.targetLayout) { + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = iter.fb->color.layout; + barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.levelCount = 1; + barrier.image = iter.fb->color.image; + barrier.srcAccessMask = 0; + VkPipelineStageFlags srcStage; + VkPipelineStageFlags dstStage; + switch (barrier.oldLayout) { + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + default: + Crash(); + break; + } + barrier.newLayout = iter.targetLayout; + switch (barrier.newLayout) { + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + default: + Crash(); + break; + } + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + + vkCmdPipelineBarrier(cmd, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); + iter.fb->color.layout = barrier.newLayout; + } + } + PerformBindFramebufferAsRenderTarget(step, cmd); + + VKRFramebuffer *fb = step.render.framebuffer; + auto &commands = step.commands; + + // TODO: Dynamic state commands (SetViewport, SetScissor, SetBlendConstants, SetStencil*) are only + // valid when a pipeline is bound with those as dynamic state. So we need to add some state tracking here + // for this to be correct. This is a bit of a pain but also will let us eliminate redundant calls. + for (const auto &c : commands) { switch (c.cmd) { case VKRRenderCommand::VIEWPORT: @@ -733,6 +779,41 @@ void VulkanRenderManager::PerformRenderPass(const VKRStep &step, VkCommandBuffer } } vkCmdEndRenderPass(cmd); + + // Transition the framebuffer if requested. + if (fb && step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED) { + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = fb->color.layout; + barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.levelCount = 1; + barrier.image = fb->color.image; + barrier.srcAccessMask = 0; + switch (barrier.oldLayout) { + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + default: + Crash(); + } + barrier.newLayout = step.render.finalColorLayout; + switch (barrier.newLayout) { + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + default: + Crash(); + } + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + // we're between passes so it's OK. + // ARM Best Practices guide recommends these stage bits. + vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); + fb->color.layout = barrier.newLayout; + } } void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &step, VkCommandBuffer cmd) { @@ -747,7 +828,7 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st h = fb->height; prevLayout = fb->color.layout; } else { - framebuf = framebuffers_[current_buffer]; + framebuf = framebuffers_[curSwapchainImage_]; w = vulkan_->GetBackbufferWidth(); h = vulkan_->GetBackbufferHeight(); } @@ -792,56 +873,51 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st // Now, if the image needs transitioning, let's transition. // The backbuffer does not, that's handled by VulkanContext. if (step.render.framebuffer->color.layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = fb->color.layout; - barrier.subresourceRange.layerCount = 1; - barrier.subresourceRange.levelCount = 1; - barrier.image = fb->color.image; - barrier.srcAccessMask = 0; + VkAccessFlags srcAccessMask; + VkPipelineStageFlags srcStage; switch (fb->color.layout) { case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; break; case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; break; } - barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; - barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - // TODO: Double-check these flags. Should be fine. - vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); - fb->color.layout = barrier.newLayout; + + TransitionImageLayout2(cmd, fb->color.image, VK_IMAGE_ASPECT_COLOR_BIT, + fb->color.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + srcStage, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT); + fb->color.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } if (fb->depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = fb->depth.layout; - barrier.subresourceRange.layerCount = 1; - barrier.subresourceRange.levelCount = 1; - barrier.image = fb->depth.image; - barrier.srcAccessMask = 0; + VkAccessFlags srcAccessMask; + VkPipelineStageFlags srcStage; switch (fb->depth.layout) { case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break; case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; break; case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; break; } - barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - // TODO: Double-check these flags. Should be fine. - vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); - fb->depth.layout = barrier.newLayout; + TransitionImageLayout2(cmd, fb->color.image, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, + fb->color.layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + srcStage, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + srcAccessMask, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT); + fb->depth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } renderPass = renderPasses_[RPIndex(step.render.color, step.render.depthStencil)]; @@ -856,7 +932,7 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st numClearVals = 2; } } else { - renderPass = GetSurfaceRenderPass(); + renderPass = GetBackbufferRenderpass(); numClearVals = 2; // We don't bother with a depth buffer here. clearVal[1].depthStencil.depth = 0.0f; clearVal[1].depthStencil.stencil = 0; diff --git a/Common/Vulkan/VulkanRenderManager.h b/Common/Vulkan/VulkanRenderManager.h index 490fea3e1b..e46072a223 100644 --- a/Common/Vulkan/VulkanRenderManager.h +++ b/Common/Vulkan/VulkanRenderManager.h @@ -97,10 +97,16 @@ enum class VKRRenderPassAction { KEEP, }; +struct TransitionRequest { + VKRFramebuffer *fb; + VkImageLayout targetLayout; +}; + struct VKRStep { VKRStep(VKRStepType _type) : stepType(_type) {} VKRStepType stepType; std::vector commands; + std::vector preTransitions; union { struct { VKRFramebuffer *framebuffer; @@ -221,6 +227,15 @@ public: curRenderStep_->commands.push_back(data); } + void SetStencilParams(uint8_t writeMask, uint8_t compareMask, uint8_t refValue) { + _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + VkRenderData data{ VKRRenderCommand::STENCIL }; + data.stencil.stencilWriteMask = writeMask; + data.stencil.stencilCompareMask = compareMask; + data.stencil.stencilRef = refValue; + curRenderStep_->commands.push_back(data); + } + void SetBlendFactor(float color[4]) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); VkRenderData data{ VKRRenderCommand::BLEND }; @@ -230,7 +245,7 @@ public: void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask); - void Draw(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count) { + void Draw(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); VkRenderData data{ VKRRenderCommand::DRAW }; data.draw.count = count; @@ -246,10 +261,11 @@ public: curRenderStep_->render.numDraws++; } - void DrawIndexed(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, VkIndexType indexType) { + void DrawIndexed(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, int numInstances, VkIndexType indexType) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); VkRenderData data{ VKRRenderCommand::DRAW_INDEXED }; data.drawIndexed.count = count; + data.drawIndexed.instances = numInstances; data.drawIndexed.pipeline = pipeline; data.drawIndexed.pipelineLayout = layout; data.drawIndexed.ds = descSet; @@ -272,15 +288,19 @@ public: void Sync(); VkCommandBuffer GetInitCmd(); - VkCommandBuffer GetSurfaceCommandBuffer() { - return frameData_[vulkan_->GetCurFrame()].mainCmd; - } - VkRenderPass GetSurfaceRenderPass() const { + VkRenderPass GetBackbufferRenderpass() const { return backbufferRenderPass_; } VkRenderPass GetRenderPass(int i) const { return renderPasses_[i]; } + VkRenderPass GetCompatibleRenderpass() const { + if (curRenderStep_ && curRenderStep_->render.framebuffer != nullptr) { + return GetRenderPass(0); + } else { + return backbufferRenderPass_; + } + } void CreateBackbuffers(); void DestroyBackbuffers(); @@ -304,13 +324,15 @@ private: static void SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect); static void SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect); + // Permanent objects VkSemaphore acquireSemaphore_; VkSemaphore renderingCompleteSemaphore; - + VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE; // Renderpasses, all combinations of preserving or clearing or dont-care-ing fb contents. // TODO: Create these on demand. VkRenderPass renderPasses_[9]; + // Per-frame data, round-robin so we can overlap submission with execution of the previous frame. struct FrameData { VkFence fence; VkCommandPool cmdPool; @@ -320,18 +342,23 @@ private: }; FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]; - VulkanContext *vulkan_; + // Submission time state int curWidth_; int curHeight_; bool insideFrame_ = false; + VKRStep *curRenderStep_; + VKRFramebuffer *boundFramebuffer_; + std::vector steps_; + // Execution time state + VulkanContext *vulkan_; std::thread submissionThread; std::mutex mutex_; std::condition_variable condVar_; - std::vector steps_; std::vector stepsOnThread_; - VKRStep *curRenderStep_; + VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE; + // Swap chain management struct SwapchainImageData { VkImage image; VkImageView view; @@ -339,8 +366,7 @@ private: std::vector framebuffers_; std::vector swapchainImages_; uint32_t swapchainImageCount_; - uint32_t current_buffer = 0; - VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE; + uint32_t curSwapchainImage_ = 0; struct DepthBufferInfo { VkFormat format = VK_FORMAT_UNDEFINED; VkImage image = VK_NULL_HANDLE; @@ -348,7 +374,4 @@ private: VkImageView view = VK_NULL_HANDLE; }; DepthBufferInfo depth_; - // Interpreter state - VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE; - // VkRenderPass curRenderPass_ = VK_NULL_HANDLE; }; diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 266d48a480..c10f7ac653 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -809,7 +809,7 @@ void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) { } void FramebufferManagerCommon::CopyDisplayToOutput() { - DownloadFramebufferOnSwitch(currentRenderVfb_); + // DownloadFramebufferOnSwitch(currentRenderVfb_); currentRenderVfb_ = 0; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 896067b97e..692ce13ec2 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -23,6 +23,7 @@ #include "profiler/profiler.h" #include "Common/MemoryUtil.h" +#include "Common/Vulkan/VulkanRenderManager.h" #include "Core/MemMap.h" #include "Core/Host.h" #include "Core/System.h" @@ -275,7 +276,6 @@ void DrawEngineVulkan::DeviceRestore(VulkanContext *vulkan) { } void DrawEngineVulkan::BeginFrame() { - lastCmd_ = VK_NULL_HANDLE; lastPipeline_ = nullptr; FrameData *frame = &frame_[curFrame_]; @@ -644,19 +644,12 @@ void DrawEngineVulkan::DoFlush() { // TODO: Should be enough to update this once per frame? gpuStats.numTrackedVertexArrays = (int)vai_.size(); - /* - VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS_COMMANDBUFFER); - if (cmd != lastCmd_) { - lastPipeline_ = nullptr; - lastCmd_ = cmd; - // Since we have a new cmdbuf, dirty our dynamic state so it gets re-set. - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE|DIRTY_DEPTHSTENCIL_STATE|DIRTY_BLEND_STATE); - }*/ - VkCommandBuffer cmd = VK_NULL_HANDLE; - - VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::CURRENT_RENDERPASS); - if (!rp) - Crash(); + VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + + // HACK: These two lines should only execute if we started on a new render pass. + lastPipeline_ = nullptr; + // Since we have a new cmdbuf, dirty our dynamic state so it gets re-set. + // gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE|DIRTY_DEPTHSTENCIL_STATE|DIRTY_BLEND_STATE); FrameData *frame = &frame_[curFrame_]; @@ -873,26 +866,28 @@ void DrawEngineVulkan::DoFlush() { sampler = nullSampler_; } - if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) { + VulkanPipeline *pipeline = lastPipeline_; + if (!lastPipeline_ || !gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) { shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform); if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } - VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, true); + Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS; + VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object); + pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, true); if (!pipeline) { // Already logged, let's bail out. return; } if (pipeline != lastPipeline_) { - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); if (lastPipeline_ && !lastPipeline_->useBlendConstant && pipeline->useBlendConstant) { gstate_c.Dirty(DIRTY_BLEND_STATE); } lastPipeline_ = pipeline; } - ApplyDrawStateLate(cmd, false, 0, pipeline->useBlendConstant); + ApplyDrawStateLate(renderManager, false, 0, pipeline->useBlendConstant); gstate_c.Clean(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE); + lastPipeline_ = pipeline; } lastPrim_ = prim; @@ -902,28 +897,22 @@ void DrawEngineVulkan::DoFlush() { VkDescriptorSet ds = GetOrCreateDescriptorSet(imageView, sampler, baseBuf, lightBuf, boneBuf); { - PROFILE_THIS_SCOPE("vkdraw"); + PROFILE_THIS_SCOPE("renderman_q"); const uint32_t dynamicUBOOffsets[3] = { baseUBOOffset, lightUBOOffset, boneUBOOffset, }; - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &ds, 3, dynamicUBOOffsets); + // vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &ds, 3, dynamicUBOOffsets); int stride = dec_->GetDecVtxFmt().stride; - VkDeviceSize offsets[1] = { vbOffset }; if (useElements) { if (!ibuf) ibOffset = (uint32_t)frame->pushIndex->Push(decIndex, sizeof(uint16_t) * indexGen.VertexCount(), &ibuf); - // TODO (maybe): Avoid rebinding vertex/index buffers if the vertex size stays the same by using the offset arguments. - // Not sure if actually worth it, binding buffers should be fast. - vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets); - vkCmdBindIndexBuffer(cmd, ibuf, ibOffset, VK_INDEX_TYPE_UINT16); int numInstances = (gstate_c.bezier || gstate_c.spline) ? numPatches : 1; - vkCmdDrawIndexed(cmd, vertexCount, numInstances, 0, 0, 0); + renderManager->DrawIndexed(pipeline->pipeline, pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, numInstances, VK_INDEX_TYPE_UINT16); } else { - vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets); - vkCmdDraw(cmd, vertexCount, 1, 0, 0); + renderManager->Draw(pipeline->pipeline, pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, vertexCount); } } } else { @@ -977,27 +966,28 @@ void DrawEngineVulkan::DoFlush() { if (sampler == VK_NULL_HANDLE) sampler = nullSampler_; } - + VulkanPipeline *pipeline = lastPipeline_; if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) { shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform); if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } - VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS); - VulkanPipeline *pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, false); + Draw::NativeObject object = g_Config.iRenderingMode != 0 ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS; + VkRenderPass renderPass = (VkRenderPass)draw_->GetNativeObject(object); + pipeline = pipelineManager_->GetOrCreatePipeline(pipelineLayout_, renderPass, pipelineKey_, dec_, vshader, fshader, false); if (!pipeline) { // Already logged, let's bail out. return; } if (pipeline != lastPipeline_) { - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline); // TODO: Avoid if same as last draw. if (lastPipeline_ && !lastPipeline_->useBlendConstant && pipeline->useBlendConstant) { gstate_c.Dirty(DIRTY_BLEND_STATE); } lastPipeline_ = pipeline; } - ApplyDrawStateLate(cmd, false, 0, pipeline->useBlendConstant); + ApplyDrawStateLate(renderManager, false, 0, pipeline->useBlendConstant); gstate_c.Clean(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE); + lastPipeline_ = pipeline; } lastPrim_ = prim; @@ -1011,25 +1001,19 @@ void DrawEngineVulkan::DoFlush() { baseUBOOffset, lightUBOOffset, boneUBOOffset, }; - PROFILE_THIS_SCOPE("vkdrawsoft"); - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &ds, 3, dynamicUBOOffsets); + PROFILE_THIS_SCOPE("renderman_q"); if (drawIndexed) { VkBuffer vbuf, ibuf; vbOffset = (uint32_t)frame->pushVertex->Push(drawBuffer, maxIndex * sizeof(TransformedVertex), &vbuf); ibOffset = (uint32_t)frame->pushIndex->Push(inds, sizeof(short) * numTrans, &ibuf); VkDeviceSize offsets[1] = { vbOffset }; - // TODO: Avoid rebinding if the vertex size stays the same by using the offset arguments - vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets); - vkCmdBindIndexBuffer(cmd, ibuf, ibOffset, VK_INDEX_TYPE_UINT16); - vkCmdDrawIndexed(cmd, numTrans, 1, 0, 0, 0); + renderManager->DrawIndexed(pipeline->pipeline, pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, numTrans, 1, VK_INDEX_TYPE_UINT16); } else { VkBuffer vbuf; vbOffset = (uint32_t)frame->pushVertex->Push(drawBuffer, numTrans * sizeof(TransformedVertex), &vbuf); VkDeviceSize offsets[1] = { vbOffset }; - // TODO: Avoid rebinding if the vertex size stays the same by using the offset arguments - vkCmdBindVertexBuffers(cmd, 0, 1, &vbuf, offsets); - vkCmdDraw(cmd, numTrans, 1, 0, 0); + renderManager->Draw(pipeline->pipeline, pipelineLayout_, ds, 3, dynamicUBOOffsets, vbuf, vbOffset, numTrans); } } else if (result.action == SW_CLEAR) { // Note: we won't get here if the clear is alpha but not color, or color but not alpha. diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 098a16a5f6..5ecd84ad61 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -113,6 +113,8 @@ public: u8 flags = 0; }; +class VulkanRenderManager; + // Handles transform, lighting and drawing. class DrawEngineVulkan : public DrawEngineCommon { public: @@ -161,6 +163,10 @@ public: void DirtyAllUBOs(); + void DirtyPipeline() { + lastPipeline_ = nullptr; + } + VulkanPushBuffer *GetPushBufferForTextureData() { return frame_[curFrame_].pushUBO; } @@ -171,7 +177,7 @@ public: private: struct FrameData; - void ApplyDrawStateLate(VkCommandBuffer cmd, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant); + void ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant); void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState); void InitDeviceObjects(); @@ -191,7 +197,6 @@ private: // We use a single descriptor set layout for all PSP draws. VkDescriptorSetLayout descriptorSetLayout_; VkPipelineLayout pipelineLayout_; - VkCommandBuffer lastCmd_ = VK_NULL_HANDLE; VulkanPipeline *lastPipeline_; VkDescriptorSet lastDs_ = VK_NULL_HANDLE; diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 96e08b8923..3422f8a117 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -132,8 +132,8 @@ void FramebufferManagerVulkan::InitDeviceObjects() { assert(vsBasicTex_ != VK_NULL_HANDLE); // Prime the 2D pipeline cache. - vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_); - vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS), vsBasicTex_, fsBasicTex_); + // vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_); + // vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_); VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index dc390ef2af..3e919eec92 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Common/Vulkan/VulkanLoader.h" +#include "Common/Vulkan/VulkanRenderManager.h" #include "math/dataconv.h" #include "GPU/Math3D.h" @@ -369,7 +370,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag } } -void DrawEngineVulkan::ApplyDrawStateLate(VkCommandBuffer cmd, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant) { +void DrawEngineVulkan::ApplyDrawStateLate(VulkanRenderManager *renderManager, bool applyStencilRef, uint8_t stencilRef, bool useBlendConstant) { // At this point, we know if the vertices are full alpha or not. // TODO: Set the nearest/linear here (since we correctly know if alpha/color tests are needed)? if (!gstate.isModeClear()) { @@ -386,24 +387,15 @@ void DrawEngineVulkan::ApplyDrawStateLate(VkCommandBuffer cmd, bool applyStencil } if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) { - vkCmdSetScissor(cmd, 0, 1, &dynState_.scissor); - vkCmdSetViewport(cmd, 0, 1, &dynState_.viewport); + renderManager->SetScissor(dynState_.scissor); + renderManager->SetViewport(dynState_.viewport); } - if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) { - if (dynState_.useStencil) { - vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilWriteMask); - vkCmdSetStencilCompareMask(cmd, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilCompareMask); - if (!applyStencilRef) { - vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, dynState_.stencilRef); - } - } - } - if (applyStencilRef) { - vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, stencilRef); + if ((gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE) && dynState_.useStencil) || applyStencilRef) { + renderManager->SetStencilParams(dynState_.stencilWriteMask, dynState_.stencilCompareMask, applyStencilRef ? stencilRef : dynState_.stencilRef); } if (gstate_c.IsDirty(DIRTY_BLEND_STATE) && useBlendConstant) { float bc[4]; Uint8x4ToFloat4(bc, dynState_.blendColor); - vkCmdSetBlendConstants(cmd, bc); + renderManager->SetBlendFactor(bc); } } diff --git a/GPU/Vulkan/StateMappingVulkan.h b/GPU/Vulkan/StateMappingVulkan.h index e4b67a3b57..f1d8013f69 100644 --- a/GPU/Vulkan/StateMappingVulkan.h +++ b/GPU/Vulkan/StateMappingVulkan.h @@ -57,7 +57,4 @@ struct VulkanPipelineRasterStateKey { size_t size = sizeof(VulkanPipelineRasterStateKey); return memcmp(this, &other, size) < 0; } -}; - -class ShaderManagerVulkan; -void ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManager, ShaderManagerVulkan *shaderManager, int prim, VulkanPipelineRasterStateKey &key, VulkanDynamicState &dynState); +}; \ No newline at end of file diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 5e18ad9927..fdb68a3849 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -321,9 +321,9 @@ enum class NativeObject { BACKBUFFER_COLOR_TEX, BACKBUFFER_DEPTH_TEX, FEATURE_LEVEL, - BACKBUFFER_RENDERPASS, COMPATIBLE_RENDERPASS, - CURRENT_RENDERPASS, + BACKBUFFER_RENDERPASS, + FRAMEBUFFER_RENDERPASS, INIT_COMMANDBUFFER, BOUND_TEXTURE_IMAGEVIEW, RENDER_MANAGER, diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index bb5e9dc64b..967b27c85e 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -452,16 +452,13 @@ public: uintptr_t GetNativeObject(NativeObject obj) override { switch (obj) { - case NativeObject::COMPATIBLE_RENDERPASS: + case NativeObject::FRAMEBUFFER_RENDERPASS: // Return a representative renderpass. - if (curRenderPass_ == renderManager_.GetSurfaceRenderPass()) - return (uintptr_t)curRenderPass_; - else - return (uintptr_t)renderManager_.GetRenderPass(0); + return (uintptr_t)renderManager_.GetRenderPass(0); case NativeObject::BACKBUFFER_RENDERPASS: - return (uintptr_t)renderManager_.GetSurfaceRenderPass(); - case NativeObject::CURRENT_RENDERPASS: - return (uintptr_t)curRenderPass_; + return (uintptr_t)renderManager_.GetBackbufferRenderpass(); + case NativeObject::COMPATIBLE_RENDERPASS: + return (uintptr_t)renderManager_.GetCompatibleRenderpass(); case NativeObject::INIT_COMMANDBUFFER: return (uintptr_t)renderManager_.GetInitCmd(); case NativeObject::BOUND_TEXTURE_IMAGEVIEW: @@ -470,6 +467,7 @@ public: case NativeObject::RENDER_MANAGER: return (uintptr_t)&renderManager_; default: + Crash(); return 0; } } @@ -521,9 +519,6 @@ private: VulkanPushBuffer *push_ = nullptr; DeviceCaps caps_{}; - - VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE; - VkRenderPass curRenderPass_ = VK_NULL_HANDLE; }; static int GetBpp(VkFormat format) { @@ -907,7 +902,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { info.pViewportState = &vs; // Must set viewport and scissor counts even if we set the actual state dynamically. info.layout = pipelineLayout_; info.subpass = 0; - info.renderPass = renderManager_.GetSurfaceRenderPass(); + info.renderPass = renderManager_.GetBackbufferRenderpass(); // OK, need to create a new pipeline. VkResult result = vkCreateGraphicsPipelines(device_, pipelineCache_, 1, &info, nullptr, &pipeline->vkpipeline); @@ -1134,7 +1129,7 @@ void VKContext::DrawIndexed(int vertexCount, int offset) { VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf); - renderManager_.DrawIndexed(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, vertexCount, VK_INDEX_TYPE_UINT32); + renderManager_.DrawIndexed(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, vertexCount, 1, VK_INDEX_TYPE_UINT32); } void VKContext::DrawUP(const void *vdata, int vertexCount) { @@ -1151,11 +1146,6 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) { // TODO: We should avoid this function as much as possible, instead use renderpass on-load clearing. void VKContext::Clear(int clearMask, uint32_t colorval, float depthVal, int stencilVal) { - if (!curRenderPass_) { - ELOG("Clear: Need an active render pass"); - return; - } - int mask = 0; if (clearMask & FBChannel::FB_COLOR_BIT) mask |= VK_IMAGE_ASPECT_COLOR_BIT; @@ -1315,7 +1305,7 @@ void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChanne if (channelBit & FBChannel::FB_COLOR_BIT) aspect |= VK_IMAGE_ASPECT_COLOR_BIT; if (channelBit & FBChannel::FB_DEPTH_BIT) aspect |= VK_IMAGE_ASPECT_DEPTH_BIT; if (channelBit & FBChannel::FB_STENCIL_BIT) aspect |= VK_IMAGE_ASPECT_STENCIL_BIT; - renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment); + boundImageView_[0] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, attachment); } uintptr_t VKContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) {