diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index 03983c62a6..260be7d9d6 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -47,9 +47,9 @@ bool VulkanPushBuffer::AddBuffer() { return false; } + // Make validation happy. VkMemoryRequirements reqs; vkGetBufferMemoryRequirements(device_, info.buffer, &reqs); - // TODO: We really should use memoryTypeIndex here.. // Okay, that's the buffer. Now let's allocate some memory for it. diff --git a/Common/Vulkan/VulkanRenderManager.cpp b/Common/Vulkan/VulkanRenderManager.cpp index 734ae34ac8..eab92174aa 100644 --- a/Common/Vulkan/VulkanRenderManager.cpp +++ b/Common/Vulkan/VulkanRenderManager.cpp @@ -3,7 +3,7 @@ #include "VulkanRenderManager.h" #include "VulkanContext.h" -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color) { +void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color) { VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; ici.arrayLayers = 1; ici.mipLevels = 1; @@ -74,10 +74,17 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKImage &img, int w } VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan) { + VkSemaphoreCreateInfo semaphoreCreateInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + semaphoreCreateInfo.flags = 0; + VkResult res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, NULL, &acquireSemaphore_); + assert(res == VK_SUCCESS); + res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, NULL, &renderingCompleteSemaphore); + assert(res == VK_SUCCESS); + for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { VkCommandPoolCreateInfo cmd_pool_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; cmd_pool_info.queueFamilyIndex = vulkan_->GetGraphicsQueueFamilyIndex(); - cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; + cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VkResult res = vkCreateCommandPool(vulkan_->GetDevice(), &cmd_pool_info, nullptr, &frameData_[i].cmdPool); assert(res == VK_SUCCESS); @@ -93,23 +100,23 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan frameData_[i].initCmd = cmdBuf[1]; frameData_[i].fence = vulkan_->CreateFence(true); // So it can be instantly waited on } +} - VkSwapchainKHR swapChain = vulkan_->GetSwapchain(); - VkResult res = vkGetSwapchainImagesKHR(vulkan->GetDevice(), swapChain, &swapchainImageCount, nullptr); +void VulkanRenderManager::CreateBackbuffers() { + VkResult res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, nullptr); assert(res == VK_SUCCESS); - ILOG("Vulkan swapchain image count: %d", swapchainImageCount); + ILOG("Vulkan swapchain image count: %d", swapchainImageCount_); - VkImage* swapchainImages = new VkImage[swapchainImageCount]; - assert(swapchainImages); - res = vkGetSwapchainImagesKHR(vulkan->GetDevice(), swapChain, &swapchainImageCount, swapchainImages); + VkImage* swapchainImages = new VkImage[swapchainImageCount_]; + res = vkGetSwapchainImagesKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), &swapchainImageCount_, swapchainImages); assert(res == VK_SUCCESS); - VkCommandBuffer cmdInit = frameData_[0].initCmd; - frameData_[0].hasInitCommands = true; + VkCommandBuffer cmdInit = GetInitCmd(); - for (uint32_t i = 0; i < swapchainImageCount; i++) { + for (uint32_t i = 0; i < swapchainImageCount_; i++) { SwapchainImageData sc_buffer; + sc_buffer.image = swapchainImages[i]; VkImageViewCreateInfo color_image_view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; color_image_view.format = vulkan_->GetSwapchainFormat(); @@ -124,8 +131,7 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan color_image_view.subresourceRange.layerCount = 1; color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D; color_image_view.flags = 0; - - sc_buffer.image = swapchainImages[i]; + color_image_view.image = sc_buffer.image; // Pre-set them to PRESENT_SRC_KHR, as the first thing we do after acquiring // in image to render to will be to transition them away from that. @@ -135,33 +141,36 @@ VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); - color_image_view.image = sc_buffer.image; - res = vkCreateImageView(vulkan_->GetDevice(), &color_image_view, NULL, &sc_buffer.view); swapchainImages_.push_back(sc_buffer); assert(res == VK_SUCCESS); } delete[] swapchainImages; - current_buffer = 0; + current_buffer = -1; - VkSemaphoreCreateInfo semaphoreCreateInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; - semaphoreCreateInfo.flags = 0; - res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, NULL, &acquireSemaphore_); - assert(res == VK_SUCCESS); - res = vkCreateSemaphore(vulkan_->GetDevice(), &semaphoreCreateInfo, NULL, &renderingCompleteSemaphore); - assert(res == VK_SUCCESS); + InitDepthStencilBuffer(cmdInit); // Must be before InitBackbufferRenderPass. + InitBackbufferRenderPass(); // Must be before InitFramebuffers. + InitBackbufferFramebuffers(vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + InitRenderpasses(); + curWidth_ = -1; + curHeight_ = -1; +} - InitDepthStencilBuffer(cmdInit); - InitSurfaceRenderPass(); +void VulkanRenderManager::DestroyBackbuffers() { + VkDevice device = vulkan_->GetDevice(); + for (uint32_t i = 0; i < swapchainImageCount_; i++) { + vulkan_->Delete().QueueDeleteImageView(swapchainImages_[i].view); + } + vulkan_->Delete().QueueDeleteImageView(depth_.view); + vulkan_->Delete().QueueDeleteImage(depth_.image); + vulkan_->Delete().QueueDeleteDeviceMemory(depth_.mem); + swapchainImages_.clear(); } VulkanRenderManager::~VulkanRenderManager() { VkDevice device = vulkan_->GetDevice(); - for (uint32_t i = 0; i < swapchainImageCount; i++) { - vkDestroyImageView(device, swapchainImages_[i].view, nullptr); - } - swapchainImages_.clear(); + vulkan_->WaitUntilQueueIdle(); vkDestroySemaphore(device, acquireSemaphore_, nullptr); vkDestroySemaphore(device, renderingCompleteSemaphore, nullptr); for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { @@ -176,58 +185,64 @@ VulkanRenderManager::~VulkanRenderManager() { vkDestroyFramebuffer(device, framebuffers_[i], nullptr); } framebuffers_.clear(); - for (int i = 0; i < 9; i++) { - vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]); + for (int i = 0; i < ARRAY_SIZE(renderPasses_); i++) { + // vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]); + vkDestroyRenderPass(device, renderPasses_[i], nullptr); } } +// TODO: Activate this code. void VulkanRenderManager::ThreadFunc() { while (true) { std::unique_lock lock(mutex_); condVar_.wait(lock); - if (steps_.size()) { - stepsOnThread_ = std::move(steps_); - } - // ... + Flush(); } } -void VulkanRenderManager::BeginFrameWrites() { - vulkan_->BeginFrame(); +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); + assert(res == VK_SUCCESS); + // Make sure the very last command buffer from the frame before the previous has been fully executed. vkWaitForFences(device, 1, &frameData.fence, true, UINT64_MAX); vkResetFences(device, 1, &frameData.fence); - // Reset both command buffers in one fell swoop. - // Note that on the first frame, there might already be commands so don't reset in that case. - if (!frameData.hasInitCommands) { - vkResetCommandPool(vulkan_->GetDevice(), frameData.cmdPool, 0); - } + // Must be after the fence - this performs deletes. + vulkan_->BeginFrame(); - VkCommandBufferBeginInfo begin = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - begin.pInheritanceInfo = nullptr; - VkResult res = vkBeginCommandBuffer(frameData.mainCmd, &begin); + insideFrame_ = true; } VkCommandBuffer VulkanRenderManager::GetInitCmd() { - FrameData &frameData = frameData_[vulkan_->GetCurFrame()]; - if (!frameData_->hasInitCommands) { + // assert(insideFrame_ || firstFrame_); + + int curFrame = vulkan_->GetCurFrame(); + FrameData &frameData = frameData_[curFrame]; + if (!frameData.hasInitCommands) { VkCommandBufferBeginInfo begin = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; begin.pInheritanceInfo = nullptr; - VkResult res = vkBeginCommandBuffer(frameData.mainCmd, &begin); + VkResult res = vkBeginCommandBuffer(frameData.initCmd, &begin); + assert(res == VK_SUCCESS); + frameData.hasInitCommands = true; } return frameData_[vulkan_->GetCurFrame()].initCmd; } +// After flush. Should probably be part of it? void VulkanRenderManager::EndFrame() { + insideFrame_ = false; + FrameData &frame = frameData_[vulkan_->GetCurFrame()]; + TransitionToPresent(frame.mainCmd, swapchainImages_[current_buffer].image); VkResult res = vkEndCommandBuffer(frame.mainCmd); @@ -243,10 +258,13 @@ void VulkanRenderManager::EndFrame() { vkEndCommandBuffer(frame.initCmd); cmdBufs.push_back(frame.initCmd); frame.hasInitCommands = false; + ILOG("Frame %d had init commands", vulkan_->GetCurFrame()); } cmdBufs.push_back(frame.mainCmd); + vulkan_->EndFrame(); + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &acquireSemaphore_; @@ -259,74 +277,63 @@ void VulkanRenderManager::EndFrame() { res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, frame.fence); assert(res == VK_SUCCESS); + VkSwapchainKHR swapchain = vulkan_->GetSwapchain(); VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; present.swapchainCount = 1; - VkSwapchainKHR swapchain = vulkan_->GetSwapchain(); present.pSwapchains = &swapchain; present.pImageIndices = ¤t_buffer; present.pWaitSemaphores = &renderingCompleteSemaphore; present.waitSemaphoreCount = 1; present.pResults = nullptr; - res = vkQueuePresentKHR(vulkan_->GetGraphicsQueue(), &present); // TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI // return codes assert(res == VK_SUCCESS); - - vulkan_->EndFrame(); } void VulkanRenderManager::Sync() { } -void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb) { +void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil) { + VKRStep *step = new VKRStep{ VKRStepType::RENDER }; // This is what queues up new passes, and can end previous ones. + step->render.framebuffer = fb; + step->render.color = color; + step->render.depthStencil = depth; + step->render.clearColor = clearColor; + step->render.clearDepth = clearDepth; + step->render.clearStencil = clearStencil; + steps_.push_back(step); + curRenderStep_ = step; + curWidth_ = fb ? fb->width : vulkan_->GetBackbufferWidth(); + curHeight_ = fb ? fb->height : vulkan_->GetBackbufferHeight(); } - -void VulkanRenderManager::BeginSurfaceRenderPass(VkCommandBuffer cmd, VkClearValue clear_value) { - FrameData &frame = frameData_[vulkan_->GetCurFrame()]; - VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; - rp_begin.renderPass = backbufferRenderPass_; - rp_begin.framebuffer = framebuffers_[current_buffer]; - rp_begin.renderArea.offset.x = 0; - rp_begin.renderArea.offset.y = 0; - rp_begin.renderArea.extent.width = curWidth_; - rp_begin.renderArea.extent.height = curHeight_; - rp_begin.clearValueCount = 1; - rp_begin.pClearValues = &clear_value; - vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); -} - -void VulkanRenderManager::EndSurfaceRenderPass(VkCommandBuffer cmd) { - // ILOG("VulkanContext::EndSurfaceRenderPass"); - vkCmdEndRenderPass(cmd); -} - -void VulkanRenderManager::InitFramebuffers() { +void VulkanRenderManager::InitBackbufferFramebuffers(int width, int height) { VkResult U_ASSERT_ONLY res; - VkImageView attachments[1]; + // We share the same depth buffer but have multiple color buffers, see the loop below. + VkImageView attachments[2] = { VK_NULL_HANDLE, depth_.view }; - ILOG("InitFramebuffers: %dx%d", curWidth_, curHeight_); + ILOG("InitFramebuffers: %dx%d", width, height); VkFramebufferCreateInfo fb_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; fb_info.renderPass = backbufferRenderPass_; - fb_info.attachmentCount = 1; + fb_info.attachmentCount = 2; fb_info.pAttachments = attachments; - fb_info.width = curWidth_; - fb_info.height = curHeight_; + fb_info.width = width; + fb_info.height = height; fb_info.layers = 1; - framebuffers_.resize(swapchainImageCount); + framebuffers_.resize(swapchainImageCount_); - for (uint32_t i = 0; i < swapchainImageCount; i++) { + for (uint32_t i = 0; i < swapchainImageCount_; i++) { attachments[0] = swapchainImages_[i].view; res = vkCreateFramebuffer(vulkan_->GetDevice(), &fb_info, nullptr, &framebuffers_[i]); assert(res == VK_SUCCESS); } } -void VulkanRenderManager::InitSurfaceRenderPass() { +void VulkanRenderManager::InitBackbufferRenderPass() { VkResult U_ASSERT_ONLY res; VkAttachmentDescription attachments[2]; @@ -340,6 +347,7 @@ void VulkanRenderManager::InitSurfaceRenderPass() { attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachments[0].flags = 0; + assert(depth_.format != VK_FORMAT_UNDEFINED); attachments[1].format = depth_.format; attachments[1].samples = VK_SAMPLE_COUNT_1_BIT; attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; @@ -392,8 +400,8 @@ void VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { VkImageCreateInfo image_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; image_info.imageType = VK_IMAGE_TYPE_2D; image_info.format = depth_format; - image_info.extent.width = curWidth_; - image_info.extent.height = curHeight_; + image_info.extent.width = vulkan_->GetBackbufferWidth(); + image_info.extent.height = vulkan_->GetBackbufferHeight(); image_info.extent.depth = 1; image_info.mipLevels = 1; image_info.arrayLayers = 1; @@ -509,64 +517,70 @@ void VulkanRenderManager::InitRenderpasses() { rp.pDependencies = nullptr; for (int depth = 0; depth < 3; depth++) { - switch ((RenderPassAction)depth) { - case RenderPassAction::CLEAR: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break; - case RenderPassAction::KEEP: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break; - case RenderPassAction::DONT_CARE: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break; + switch ((VKRRenderPassAction)depth) { + case VKRRenderPassAction::CLEAR: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break; + case VKRRenderPassAction::KEEP: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break; + case VKRRenderPassAction::DONT_CARE: attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break; } for (int color = 0; color < 3; color++) { - switch ((RenderPassAction)color) { - case RenderPassAction::CLEAR: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break; - case RenderPassAction::KEEP: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break; - case RenderPassAction::DONT_CARE: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break; + switch ((VKRRenderPassAction)color) { + case VKRRenderPassAction::CLEAR: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break; + case VKRRenderPassAction::KEEP: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break; + case VKRRenderPassAction::DONT_CARE: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break; } - vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &renderPasses_[RPIndex((RenderPassAction)color, (RenderPassAction)depth)]); + vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &renderPasses_[RPIndex((VKRRenderPassAction)color, (VKRRenderPassAction)depth)]); } } } -void VulkanRenderManager::BeginRenderPass() { - std::unique_lock lock(rpLock_); - - VKRStep *pass = new VKRStep(VKStepType::RENDER); - pass->stepType = VKStepType::RENDER; - steps_.push_back(pass); - curStep_ = steps_.back(); -} - void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask) { - _dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER); + _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); // If this is the first drawing command, merge it into the pass. - if (curStep_->render.numDraws == 0) { - curStep_->render.clearColor = clearColor; - curStep_->render.clearDepth = clearZ; - curStep_->render.clearStencil = clearStencil; - curStep_->render.color = (clearMask & VK_IMAGE_ASPECT_COLOR_BIT) ? RenderPassAction::CLEAR : RenderPassAction::KEEP; - curStep_->render.depthStencil = (clearMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) ? RenderPassAction::CLEAR : RenderPassAction::KEEP; + if (curRenderStep_->render.numDraws == 0) { + curRenderStep_->render.clearColor = clearColor; + curRenderStep_->render.clearDepth = clearZ; + curRenderStep_->render.clearStencil = clearStencil; + curRenderStep_->render.color = (clearMask & VK_IMAGE_ASPECT_COLOR_BIT) ? VKRRenderPassAction::CLEAR : VKRRenderPassAction::KEEP; + curRenderStep_->render.depthStencil = (clearMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) ? VKRRenderPassAction::CLEAR : VKRRenderPassAction::KEEP; } else { - VkRenderData data{ VkRenderCmd::CLEAR }; + VkRenderData data{ VKRRenderCommand::CLEAR }; data.clear.clearColor = clearColor; data.clear.clearZ = clearZ; data.clear.clearStencil = clearStencil; data.clear.clearMask = clearMask; - curStep_->commands.push_back(data); + curRenderStep_->commands.push_back(data); } } -void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPoint) { - FrameData &frameData = frameData_[vulkan_->GetCurFrame()]; - EndCurrentRenderpass(frameData.mainCmd); +void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, int aspectMask) { + VKRStep *step = new VKRStep{ VKRStepType::COPY }; + step->copy.aspectMask = aspectMask; + step->copy.src = src; + step->copy.srcRect = srcRect; + step->copy.dst = dst; + step->copy.dstPos = dstPos; + std::unique_lock lock(mutex_); + steps_.push_back(step); + curRenderStep_ = nullptr; } -void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkFilter filter) { - FrameData &frameData = frameData_[vulkan_->GetCurFrame()]; - EndCurrentRenderpass(frameData.mainCmd); +void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, int aspectMask, VkFilter filter) { + VKRStep *step = new VKRStep{ VKRStepType::BLIT }; + step->blit.aspectMask = aspectMask; + step->blit.src = src; + step->blit.srcRect = srcRect; + step->blit.dst = dst; + step->blit.dstRect = dstRect; + step->blit.filter = filter; + std::unique_lock lock(mutex_); + steps_.push_back(step); + curRenderStep_ = nullptr; } 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++) { - if (steps_[i]->stepType == VKStepType::RENDER && steps_[i]->render.framebuffer == fb) { + if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == fb) { if (steps_[i]->render.finalColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) steps_[i]->render.finalColorLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; else @@ -598,37 +612,43 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in void VulkanRenderManager::Flush() { { - std::unique_lock lock(rpLock_); + std::unique_lock lock(mutex_); stepsOnThread_ = std::move(steps_); + curRenderStep_ = nullptr; } FrameData &frameData = frameData_[vulkan_->GetCurFrame()]; - VkCommandBuffer cmd = frameData.mainCmd; VkDevice device = vulkan_->GetDevice(); - // 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_, VK_NULL_HANDLE, ¤t_buffer); + VkCommandBuffer cmd = frameData.mainCmd; + + VkCommandBufferBeginInfo begin = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + begin.pInheritanceInfo = nullptr; + VkResult res = vkBeginCommandBuffer(cmd, &begin); + assert(res == VK_SUCCESS); + // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR // 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(frameData.mainCmd, swapchainImages_[current_buffer].image); + TransitionFromPresent(cmd, swapchainImages_[current_buffer].image); // Optimizes renderpasses, then sequences them. for (int i = 0; i < stepsOnThread_.size(); i++) { const VKRStep &step = *stepsOnThread_[i]; switch (step.stepType) { - case VKStepType::RENDER: + case VKRStepType::RENDER: PerformRenderPass(step, cmd); break; - case VKStepType::COPY: + case VKRStepType::COPY: PerformCopy(step, cmd); break; - case VKStepType::BLIT: + case VKRStepType::BLIT: PerformBlit(step, cmd); break; - case VKStepType::READBACK: + case VKRStepType::READBACK: // PerformReadback break; } @@ -642,25 +662,25 @@ void VulkanRenderManager::PerformRenderPass(const VKRStep &step, VkCommandBuffer auto &commands = step.commands; for (const auto &c : commands) { switch (c.cmd) { - case VkRenderCmd::VIEWPORT: + case VKRRenderCommand::VIEWPORT: vkCmdSetViewport(cmd, 0, 1, &c.viewport.vp); break; - case VkRenderCmd::SCISSOR: + case VKRRenderCommand::SCISSOR: vkCmdSetScissor(cmd, 0, 1, &c.scissor.scissor); break; - case VkRenderCmd::BLEND: + case VKRRenderCommand::BLEND: vkCmdSetBlendConstants(cmd, c.blendColor.color); break; - case VkRenderCmd::STENCIL: + case VKRRenderCommand::STENCIL: vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilWriteMask); vkCmdSetStencilCompareMask(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilCompareMask); vkCmdSetStencilReference(cmd, VK_STENCIL_FRONT_AND_BACK, c.stencil.stencilRef); break; - case VkRenderCmd::DRAW_INDEXED: + case VKRRenderCommand::DRAW_INDEXED: vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.drawIndexed.pipeline); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.drawIndexed.pipelineLayout, 0, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, VK_INDEX_TYPE_UINT16); @@ -668,14 +688,14 @@ void VulkanRenderManager::PerformRenderPass(const VKRStep &step, VkCommandBuffer vkCmdDrawIndexed(cmd, c.drawIndexed.count, c.drawIndexed.instances, 0, 0, 0); break; - case VkRenderCmd::DRAW: + case VKRRenderCommand::DRAW: vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.draw.pipeline); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.draw.pipelineLayout, 0, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); vkCmdBindVertexBuffers(cmd, 0, 1, &c.draw.vbuffer, &c.draw.voffset); vkCmdDraw(cmd, c.draw.count, 1, 0, 0); break; - case VkRenderCmd::CLEAR: + case VKRRenderCommand::CLEAR: { int numAttachments = 0; VkClearRect rc{}; @@ -735,21 +755,19 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st if (framebuf == curFramebuffer_) { if (framebuf == 0) Crash(); - if (!curRenderPass_) - Crash(); // If we're asking to clear, but already bound, we'll just keep it bound but send a clear command. // We will try to avoid this as much as possible. VkClearAttachment clear[2]{}; int count = 0; - if (step.render.color == RenderPassAction::CLEAR) { + if (step.render.color == VKRRenderPassAction::CLEAR) { clear[count].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; Uint8x4ToFloat4(clear[count].clearValue.color.float32, step.render.clearColor); clear[count].colorAttachment = 0; count++; } - if (step.render.depthStencil == RenderPassAction::CLEAR) { + if (step.render.depthStencil == VKRRenderPassAction::CLEAR) { clear[count].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; clear[count].clearValue.depthStencil.depth = step.render.clearDepth; clear[count].clearValue.depthStencil.stencil = step.render.clearStencil; @@ -765,13 +783,6 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st return; } - // OK, we're switching framebuffers. - if (curRenderPass_) { - vkCmdEndRenderPass(cmd); - curRenderPass_ = VK_NULL_HANDLE; - curFramebuffer_ = VK_NULL_HANDLE; - } - VkRenderPass renderPass; int numClearVals = 0; VkClearValue clearVal[2]; @@ -835,18 +846,20 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st renderPass = renderPasses_[RPIndex(step.render.color, step.render.depthStencil)]; // ILOG("Switching framebuffer to FBO (fc=%d, cmd=%x, rp=%x)", frameNum_, (int)(uintptr_t)cmd_, (int)(uintptr_t)renderPass); - if (step.render.color == RenderPassAction::CLEAR) { + if (step.render.color == VKRRenderPassAction::CLEAR) { Uint8x4ToFloat4(clearVal[0].color.float32, step.render.clearColor); numClearVals = 1; } - if (step.render.depthStencil == RenderPassAction::CLEAR) { + if (step.render.depthStencil == VKRRenderPassAction::CLEAR) { clearVal[1].depthStencil.depth = step.render.clearDepth; clearVal[1].depthStencil.stencil = step.render.clearStencil; numClearVals = 2; } } else { renderPass = GetSurfaceRenderPass(); - numClearVals = 2; + numClearVals = 2; // We don't bother with a depth buffer here. + clearVal[1].depthStencil.depth = 0.0f; + clearVal[1].depthStencil.stencil = 0; } VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; @@ -859,17 +872,9 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st rp_begin.clearValueCount = numClearVals; rp_begin.pClearValues = numClearVals ? clearVal : nullptr; vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); - curFramebuffer_ = framebuf; - curRenderPass_ = renderPass; curWidth_ = w; curHeight_ = h; -} - -void VulkanRenderManager::EndCurrentRenderpass(VkCommandBuffer cmd) { - if (curRenderPass_) { - vkCmdEndRenderPass(cmd); - curRenderPass_ = nullptr; - } + curFramebuffer_ = framebuf; } void VulkanRenderManager::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { @@ -1020,7 +1025,7 @@ void VulkanRenderManager::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) } } -void VulkanRenderManager::SetupTransitionToTransferSrc(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect) { +void VulkanRenderManager::SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect) { barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.oldLayout = img.layout; barrier.subresourceRange.layerCount = 1; @@ -1049,7 +1054,7 @@ void VulkanRenderManager::SetupTransitionToTransferSrc(VKImage &img, VkImageMemo img.layout = barrier.newLayout; } -void VulkanRenderManager::SetupTransitionToTransferDst(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect) { +void VulkanRenderManager::SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect) { barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.oldLayout = img.layout; barrier.subresourceRange.layerCount = 1; diff --git a/Common/Vulkan/VulkanRenderManager.h b/Common/Vulkan/VulkanRenderManager.h index fbc8f0976c..490fea3e1b 100644 --- a/Common/Vulkan/VulkanRenderManager.h +++ b/Common/Vulkan/VulkanRenderManager.h @@ -15,7 +15,7 @@ // The cool thing is that you can Flush on a different thread than you record the commands on! -enum class VkRenderCmd : uint8_t { +enum class VKRRenderCommand : uint8_t { STENCIL, BLEND, VIEWPORT, @@ -26,7 +26,7 @@ enum class VkRenderCmd : uint8_t { }; struct VkRenderData { - VkRenderCmd cmd; + VKRRenderCommand cmd; union { struct { VkPipeline pipeline; @@ -82,7 +82,7 @@ struct VkRenderData { }; }; -enum class VKStepType : uint8_t { +enum class VKRStepType : uint8_t { RENDER, COPY, BLIT, @@ -91,21 +91,21 @@ enum class VKStepType : uint8_t { class VKRFramebuffer; -enum class RenderPassAction { +enum class VKRRenderPassAction { DONT_CARE, CLEAR, KEEP, }; struct VKRStep { - VKRStep(VKStepType _type) : stepType(_type) {} - VKStepType stepType; + VKRStep(VKRStepType _type) : stepType(_type) {} + VKRStepType stepType; std::vector commands; union { struct { VKRFramebuffer *framebuffer; - RenderPassAction color; - RenderPassAction depthStencil; + VKRRenderPassAction color; + VKRRenderPassAction depthStencil; uint32_t clearColor; float clearDepth; int clearStencil; @@ -137,13 +137,13 @@ struct VKRStep { // Simple independent framebuffer image. Gets its own allocation, we don't have that many framebuffers so it's fine // to let them have individual non-pooled allocations. Until it's not fine. We'll see. -struct VKImage { +struct VKRImage { VkImage image; VkImageView imageView; VkDeviceMemory memory; VkImageLayout layout; }; -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color); +void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color); class VKRFramebuffer { public: @@ -175,15 +175,14 @@ public: vulkan_->Delete().QueueDeleteImageView(depth.imageView); vulkan_->Delete().QueueDeleteDeviceMemory(color.memory); vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory); - vulkan_->Delete().QueueDeleteFramebuffer(framebuf); } int numShadows = 1; // TODO: Support this. VkFramebuffer framebuf = VK_NULL_HANDLE; - VKImage color{}; - VKImage depth{}; + VKRImage color{}; + VKRImage depth{}; int width = 0; int height = 0; @@ -199,43 +198,41 @@ public: void ThreadFunc(); // Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again. - void BeginFrameWrites(); + void BeginFrame(); void EndFrame(); - void BindFramebufferAsRenderTarget(VKRFramebuffer *fb); + void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil); VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment); - void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPoint); - void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkFilter filter); - - void BeginRenderPass(); + void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, int aspectMask); + void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, int aspectMask, VkFilter filter); void SetViewport(const VkViewport &vp) { - _dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER); - VkRenderData data{ VkRenderCmd::VIEWPORT }; + _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + VkRenderData data{ VKRRenderCommand::VIEWPORT }; data.viewport.vp = vp; - curStep_->commands.push_back(data); + curRenderStep_->commands.push_back(data); } void SetScissor(const VkRect2D &rc) { - _dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER); - VkRenderData data{ VkRenderCmd::SCISSOR }; + _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + VkRenderData data{ VKRRenderCommand::SCISSOR }; data.scissor.scissor = rc; - curStep_->commands.push_back(data); + curRenderStep_->commands.push_back(data); } void SetBlendFactor(float color[4]) { - _dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER); - VkRenderData data{ VkRenderCmd::BLEND }; + _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + VkRenderData data{ VKRRenderCommand::BLEND }; CopyFloat4(data.blendColor.color, color); - curStep_->commands.push_back(data); + curRenderStep_->commands.push_back(data); } 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) { - _dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER); - VkRenderData data{ VkRenderCmd::DRAW }; + _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + VkRenderData data{ VKRRenderCommand::DRAW }; data.draw.count = count; data.draw.pipeline = pipeline; data.draw.pipelineLayout = layout; @@ -245,13 +242,13 @@ public: data.draw.numUboOffsets = numUboOffsets; for (int i = 0; i < numUboOffsets; i++) data.draw.uboOffsets[i] = uboOffsets[i]; - curStep_->commands.push_back(data); - curStep_->render.numDraws++; + curRenderStep_->commands.push_back(data); + 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) { - _dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER); - VkRenderData data{ VkRenderCmd::DRAW_INDEXED }; + _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + VkRenderData data{ VKRRenderCommand::DRAW_INDEXED }; data.drawIndexed.count = count; data.drawIndexed.pipeline = pipeline; data.drawIndexed.pipelineLayout = layout; @@ -264,8 +261,8 @@ public: for (int i = 0; i < numUboOffsets; i++) data.drawIndexed.uboOffsets[i] = uboOffsets[i]; data.drawIndexed.indexType = indexType; - curStep_->commands.push_back(data); - curStep_->render.numDraws++; + curRenderStep_->commands.push_back(data); + curRenderStep_->render.numDraws++; } // Can run on a different thread! Just make sure to use BeginFrameWrites. @@ -274,12 +271,6 @@ public: // Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot). void Sync(); - std::vector steps_; - std::vector stepsOnThread_; - std::mutex rpLock_; - - VKRStep *curStep_; - VkCommandBuffer GetInitCmd(); VkCommandBuffer GetSurfaceCommandBuffer() { return frameData_[vulkan_->GetCurFrame()].mainCmd; @@ -291,33 +282,27 @@ public: return renderPasses_[i]; } + void CreateBackbuffers(); + void DestroyBackbuffers(); + private: - void InitFramebuffers(); - void InitSurfaceRenderPass(); + void InitBackbufferFramebuffers(int width, int height); + void InitBackbufferRenderPass(); void InitRenderpasses(); void InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering. - // The surface render pass is special because it has to acquire the backbuffer, and may thus "block". - // Use the returned command buffer to enqueue commands that render to the backbuffer. - // To render to other buffers first, you can submit additional commandbuffers using QueueBeforeSurfaceRender(cmd). - void BeginSurfaceRenderPass(VkCommandBuffer cmd, VkClearValue clear_value); - // May eventually need the ability to break and resume the backbuffer render pass in a few rare cases. - void EndSurfaceRenderPass(VkCommandBuffer cmd); - - void EndCurrentRenderpass(VkCommandBuffer cmd); - void PerformBindFramebufferAsRenderTarget(const VKRStep &pass, VkCommandBuffer cmd); void PerformRenderPass(const VKRStep &pass, VkCommandBuffer cmd); void PerformCopy(const VKRStep &pass, VkCommandBuffer cmd); void PerformBlit(const VKRStep &pass, VkCommandBuffer cmd); - inline int RPIndex(RenderPassAction color, RenderPassAction depth) { + inline int RPIndex(VKRRenderPassAction color, VKRRenderPassAction depth) { return (int)depth * 3 + (int)color; } - static void SetupTransitionToTransferSrc(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect); - static void SetupTransitionToTransferDst(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect); + static void SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect); + static void SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect); VkSemaphore acquireSemaphore_; VkSemaphore renderingCompleteSemaphore; @@ -331,17 +316,21 @@ private: VkCommandPool cmdPool; VkCommandBuffer initCmd; VkCommandBuffer mainCmd; - bool hasInitCommands; + bool hasInitCommands = false; }; FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]; VulkanContext *vulkan_; int curWidth_; int curHeight_; + bool insideFrame_ = false; std::thread submissionThread; std::mutex mutex_; std::condition_variable condVar_; + std::vector steps_; + std::vector stepsOnThread_; + VKRStep *curRenderStep_; struct SwapchainImageData { VkImage image; @@ -349,18 +338,17 @@ private: }; std::vector framebuffers_; std::vector swapchainImages_; - uint32_t swapchainImageCount; + uint32_t swapchainImageCount_; uint32_t current_buffer = 0; VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE; struct DepthBufferInfo { - VkFormat format; + VkFormat format = VK_FORMAT_UNDEFINED; VkImage image = VK_NULL_HANDLE; VkDeviceMemory mem = VK_NULL_HANDLE; VkImageView view = VK_NULL_HANDLE; }; DepthBufferInfo depth_; // Interpreter state - VkFramebuffer curFramebuffer_; - VkRenderPass curRenderPass_; - + VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE; + // VkRenderPass curRenderPass_ = VK_NULL_HANDLE; }; diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index ef322d90e2..6f87a00cd7 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -128,7 +128,6 @@ static VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugRep return false; if (msgCode == 64) // Another useless perf warning that will be seen less and less as we optimize - vkCmdClearAttachments() issued on command buffer object 0x00000195296C6D40 prior to any Draw Cmds. It is recommended you use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw. return false; - #ifdef _WIN32 std::string msg = message.str(); OutputDebugStringA(msg.c_str()); @@ -197,10 +196,13 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m draw_ = Draw::T3DCreateVulkanContext(g_Vulkan); bool success = draw_->CreatePresets(); assert(success); // Doesn't fail, we include the compiler. - return success; + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + return true; } void WindowsVulkanContext::Shutdown() { + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); + delete draw_; draw_ = nullptr; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 2d409843cd..bb5e9dc64b 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -699,6 +699,8 @@ VKContext::VKContext(VulkanContext *vulkan) for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { frame_[i].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024); + VkResult res = vkCreateDescriptorPool(device_, &dp, nullptr, &frame_[i].descriptorPool); + assert(res == VK_SUCCESS); } // binding 0 - uniform data @@ -746,7 +748,7 @@ VKContext::~VKContext() { } void VKContext::BeginFrame() { - renderManager_.BeginFrameWrites(); + renderManager_.BeginFrame(); FrameData &frame = frame_[frameNum_]; push_ = frame.pushBuffer; @@ -758,8 +760,6 @@ void VKContext::BeginFrame() { frame.descSets_.clear(); VkResult result = vkResetDescriptorPool(device_, frame.descriptorPool, 0); assert(result == VK_SUCCESS); - - SetScissorRect(0, 0, pixel_xres, pixel_yres); } void VKContext::WaitRenderCompletion(Framebuffer *fbo) { @@ -1146,7 +1146,7 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) { VkDeviceSize offsets[1] = { vbBindOffset }; VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf); - renderManager_.Draw(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, vbBindOffset, vertexCount); + renderManager_.Draw(curPipeline_->vkpipeline, pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vertexCount); } // TODO: We should avoid this function as much as possible, instead use renderpass on-load clearing. @@ -1279,20 +1279,32 @@ void VKContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y VKFramebuffer *src = (VKFramebuffer *)srcfb; VKFramebuffer *dst = (VKFramebuffer *)dstfb; - renderManager_.CopyFramebuffer(src->GetFB(), VkRect2D{ {x, y}, {(uint32_t)width, (uint32_t)height } }, dst->GetFB(), VkOffset2D{ dstX, dstY }); + int aspectMask = 0; + if (channelBits & FBChannel::FB_COLOR_BIT) aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT; + if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + + renderManager_.CopyFramebuffer(src->GetFB(), VkRect2D{ {x, y}, {(uint32_t)width, (uint32_t)height } }, dst->GetFB(), VkOffset2D{ dstX, dstY }, aspectMask); } bool VKContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { VKFramebuffer *src = (VKFramebuffer *)srcfb; VKFramebuffer *dst = (VKFramebuffer *)dstfb; - renderManager_.BlitFramebuffer(src->GetFB(), VkRect2D{ {srcX1, srcY1}, {(uint32_t)(srcX2 - srcX1), (uint32_t)(srcY2 - srcY1) } }, dst->GetFB(), VkRect2D{ {dstX1, dstY1}, {(uint32_t)(dstX2 - dstX1), (uint32_t)(dstY2 - dstY1) } }, filter == FB_BLIT_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST); + int aspectMask = 0; + if (channelBits & FBChannel::FB_COLOR_BIT) aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT; + if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + + renderManager_.BlitFramebuffer(src->GetFB(), VkRect2D{ {srcX1, srcY1}, {(uint32_t)(srcX2 - srcX1), (uint32_t)(srcY2 - srcY1) } }, dst->GetFB(), VkRect2D{ {dstX1, dstY1}, {(uint32_t)(dstX2 - dstX1), (uint32_t)(dstY2 - dstY1) } }, aspectMask, filter == FB_BLIT_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST); return true; } void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp) { VKFramebuffer *fb = (VKFramebuffer *)fbo; - renderManager_.BindFramebufferAsRenderTarget(fb->GetFB()); + VKRRenderPassAction color = (VKRRenderPassAction)rp.color; // same values. + VKRRenderPassAction depth = (VKRRenderPassAction)rp.color; // same values. + renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, rp.clearColor, rp.clearDepth, rp.clearStencil); } // color must be 0, for now. @@ -1324,8 +1336,10 @@ void VKContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { void VKContext::HandleEvent(Event ev, int width, int height, void *param1, void *param2) { switch (ev) { case Event::LOST_BACKBUFFER: + renderManager_.DestroyBackbuffers(); break; case Event::GOT_BACKBUFFER: + renderManager_.CreateBackbuffers(); break; } // Noop