diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 9580f2f7ee..d1bf945bd0 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -225,6 +225,7 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor // TODO: We can just change the texture format and flip some bits around instead of this. // Could share code with the texture cache perhaps. + // Could also convert directly into the pushbuffer easily. const uint8_t *data = srcPixels; if (srcPixelFormat != GE_FORMAT_8888 || srcStride != width) { u32 neededSize = width * height * 4; diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index d8b358ea79..8a7b4ccafd 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -68,7 +68,7 @@ void VulkanQueueRunner::InitBackbufferRenderPass() { attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments[1].flags = 0; - VkAttachmentReference color_reference = {}; + VkAttachmentReference color_reference{}; color_reference.attachment = 0; color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -76,7 +76,7 @@ void VulkanQueueRunner::InitBackbufferRenderPass() { depth_reference.attachment = 1; depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - VkSubpassDescription subpass = {}; + VkSubpassDescription subpass{}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.flags = 0; subpass.inputAttachmentCount = 0; @@ -88,14 +88,23 @@ void VulkanQueueRunner::InitBackbufferRenderPass() { subpass.preserveAttachmentCount = 0; subpass.pPreserveAttachments = nullptr; - VkRenderPassCreateInfo rp_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; - rp_info.pNext = nullptr; + // For the built-in layout transitions. + VkSubpassDependency dep{}; + dep.srcSubpass = VK_SUBPASS_EXTERNAL; + dep.dstSubpass = 0; + dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dep.srcAccessMask = 0; + dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dep.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + VkRenderPassCreateInfo rp_info{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; rp_info.attachmentCount = 2; rp_info.pAttachments = attachments; rp_info.subpassCount = 1; rp_info.pSubpasses = &subpass; - rp_info.dependencyCount = 0; - rp_info.pDependencies = nullptr; + rp_info.dependencyCount = 1; + rp_info.pDependencies = &dep; res = vkCreateRenderPass(vulkan_->GetDevice(), &rp_info, nullptr, &backbufferRenderPass_); assert(res == VK_SUCCESS); @@ -112,7 +121,7 @@ void VulkanQueueRunner::InitRenderpasses() { attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // TODO: Look into auto-transitioning to SAMPLED when appropriate. attachments[0].flags = 0; attachments[1].format = vulkan_->GetDeviceInfo().preferredDepthStencilFormat; @@ -125,15 +134,15 @@ void VulkanQueueRunner::InitRenderpasses() { attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; attachments[1].flags = 0; - VkAttachmentReference color_reference = {}; + VkAttachmentReference color_reference{}; color_reference.attachment = 0; color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkAttachmentReference depth_reference = {}; + VkAttachmentReference depth_reference{}; depth_reference.attachment = 1; depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - VkSubpassDescription subpass = {}; + VkSubpassDescription subpass{}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.flags = 0; subpass.inputAttachmentCount = 0; @@ -145,13 +154,12 @@ void VulkanQueueRunner::InitRenderpasses() { subpass.preserveAttachmentCount = 0; subpass.pPreserveAttachments = nullptr; - VkRenderPassCreateInfo rp = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; rp.attachmentCount = 2; rp.pAttachments = attachments; rp.subpassCount = 1; rp.pSubpasses = &subpass; rp.dependencyCount = 0; - rp.pDependencies = nullptr; for (int depth = 0; depth < 3; depth++) { switch ((VKRRenderPassAction)depth) { @@ -201,6 +209,73 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, const std::vector &steps) { + ILOG("======================================="); + for (int i = 0; i < steps.size(); i++) { + const VKRStep &step = *steps[i]; + switch (step.stepType) { + case VKRStepType::RENDER: + LogRenderPass(step); + break; + case VKRStepType::COPY: + LogCopy(step); + break; + case VKRStepType::BLIT: + LogBlit(step); + break; + case VKRStepType::READBACK: + LogReadback(step); + break; + } + } +} + +void VulkanQueueRunner::LogRenderPass(const VKRStep &pass) { + int fb = (int)(intptr_t)(pass.render.framebuffer ? pass.render.framebuffer->framebuf : 0); + ILOG("RenderPass Begin(%x)", fb); + for (auto &cmd : pass.commands) { + switch (cmd.cmd) { + case VKRRenderCommand::BIND_PIPELINE: + ILOG(" BindPipeline(%x)", (int)(intptr_t)cmd.pipeline.pipeline); + break; + case VKRRenderCommand::BLEND: + ILOG(" Blend(%f, %f, %f, %f)", cmd.blendColor.color[0], cmd.blendColor.color[1], cmd.blendColor.color[2], cmd.blendColor.color[3]); + break; + case VKRRenderCommand::CLEAR: + ILOG(" Clear"); + break; + case VKRRenderCommand::DRAW: + ILOG(" Draw(%d)", cmd.draw.count); + break; + case VKRRenderCommand::DRAW_INDEXED: + ILOG(" DrawIndexed(%d)", cmd.drawIndexed.count); + break; + case VKRRenderCommand::SCISSOR: + ILOG(" Scissor(%d, %d, %d, %d)", (int)cmd.scissor.scissor.offset.x, (int)cmd.scissor.scissor.offset.y, (int)cmd.scissor.scissor.extent.width, (int)cmd.scissor.scissor.extent.height); + break; + case VKRRenderCommand::STENCIL: + ILOG(" Stencil(ref=%d, compare=%d, write=%d)", cmd.stencil.stencilRef, cmd.stencil.stencilCompareMask, cmd.stencil.stencilWriteMask); + break; + case VKRRenderCommand::VIEWPORT: + ILOG(" Viewport(%f, %f, %f, %f, %f, %f)", cmd.viewport.vp.x, cmd.viewport.vp.y, cmd.viewport.vp.width, cmd.viewport.vp.height, cmd.viewport.vp.minDepth, cmd.viewport.vp.maxDepth); + break; + } + } + ILOG("RenderPass End(%x)", fb); +} + +void VulkanQueueRunner::LogCopy(const VKRStep &pass) { + ILOG("Copy()"); +} + +void VulkanQueueRunner::LogBlit(const VKRStep &pass) { + ILOG("Blit()"); +} + +void VulkanQueueRunner::LogReadback(const VKRStep &pass) { + ILOG("Readback"); +} + void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd) { // TODO: If there are multiple, we can transition them together. for (const auto &iter : step.preTransitions) { diff --git a/ext/native/thin3d/VulkanQueueRunner.h b/ext/native/thin3d/VulkanQueueRunner.h index 05accdf6a5..a35a664f35 100644 --- a/ext/native/thin3d/VulkanQueueRunner.h +++ b/ext/native/thin3d/VulkanQueueRunner.h @@ -141,6 +141,7 @@ public: backbuffer_ = fb; } void RunSteps(VkCommandBuffer cmd, const std::vector &steps); + void LogSteps(const std::vector &steps); void CreateDeviceObjects(); void DestroyDeviceObjects(); @@ -168,6 +169,11 @@ private: void PerformBlit(const VKRStep &pass, VkCommandBuffer cmd); void PerformReadback(const VKRStep &pass, VkCommandBuffer cmd); + void LogRenderPass(const VKRStep &pass); + void LogCopy(const VKRStep &pass); + void LogBlit(const VKRStep &pass); + void LogReadback(const VKRStep &pass); + static void SetupTransitionToTransferSrc(VKRImage &img, VkImageMemoryBarrier &barrier, VkPipelineStageFlags &stage, VkImageAspectFlags aspect); static void SetupTransitionToTransferDst(VKRImage &img, VkImageMemoryBarrier &barrier, VkPipelineStageFlags &stage, VkImageAspectFlags aspect); diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 2bcee4cb28..58ed64bbc1 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -597,13 +597,13 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { cmdBufs.push_back(frameData.mainCmd); - VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + VkSubmitInfo submit_info{ VK_STRUCTURE_TYPE_SUBMIT_INFO }; if (triggerFence) { submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &acquireSemaphore_; } - VkPipelineStageFlags waitStage[1] = { VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT }; + VkPipelineStageFlags waitStage[1]{ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT }; submit_info.pWaitDstStageMask = waitStage; submit_info.commandBufferCount = (uint32_t)cmdBufs.size(); submit_info.pCommandBuffers = cmdBufs.data(); @@ -612,7 +612,12 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) { submit_info.pSignalSemaphores = &renderingCompleteSemaphore_; } res = vkQueueSubmit(vulkan_->GetGraphicsQueue(), 1, &submit_info, triggerFence ? frameData.fence : VK_NULL_HANDLE); - assert(res == VK_SUCCESS); + if (res == VK_ERROR_DEVICE_LOST) { + // _assert_msg_(G3D, false, "Lost the Vulkan device! What did we do wrong?"); + ELOG("DEVICE LOST"); + } else { + assert(res == VK_SUCCESS); + } if (useThread) { VLOG("PULL: Frame %d.readyForFence = true", frame); @@ -655,6 +660,7 @@ void VulkanRenderManager::Run(int frame) { FrameData &frameData = frameData_[frame]; auto &stepsOnThread = frameData_[frame].steps; VkCommandBuffer cmd = frameData.mainCmd; + // queueRunner_.LogSteps(stepsOnThread); queueRunner_.RunSteps(cmd, stepsOnThread); stepsOnThread.clear(); @@ -677,6 +683,8 @@ void VulkanRenderManager::FlushSync() { Submit(frame, false); + // This is brutal! Should probably wait for a fence instead, not that it'll matter much since we'll + // still stall everything. vkDeviceWaitIdle(vulkan_->GetDevice()); // At this point we can resume filling the command buffers for the current frame since