From 32f5930e15a5a97a8cf7fd467c20d23fd14d056b Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Wed, 30 Mar 2016 23:26:16 +0200 Subject: [PATCH] Move clear handling to FramebufferVulkan, center the clear properly in non-buffered. more cleanup. --- Common/Vulkan/VulkanContext.h | 8 +++ GPU/Vulkan/DrawEngineVulkan.cpp | 46 +--------------- GPU/Vulkan/FramebufferVulkan.cpp | 78 ++++++++++++++++++++++------ GPU/Vulkan/FramebufferVulkan.h | 7 ++- Windows/GPU/WindowsVulkanContext.cpp | 3 ++ 5 files changed, 80 insertions(+), 62 deletions(-) diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index ab87a7f5ac..33aac54e36 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -74,6 +74,7 @@ public: void QueueDeleteImageView(VkImageView imageView) { imageViews_.push_back(imageView); } void QueueDeleteDeviceMemory(VkDeviceMemory deviceMemory) { deviceMemory_.push_back(deviceMemory); } void QueueDeleteSampler(VkSampler sampler) { samplers_.push_back(sampler); } + void QueueDeletePipeline(VkPipeline pipeline) { pipelines_.push_back(pipeline); } void QueueDeletePipelineCache(VkPipelineCache pipelineCache) { pipelineCaches_.push_back(pipelineCache); } void QueueDeleteRenderPass(VkRenderPass renderPass) { renderPasses_.push_back(renderPass); } void QueueDeleteFramebuffer(VkFramebuffer framebuffer) { framebuffers_.push_back(framebuffer); } @@ -88,6 +89,7 @@ public: assert(imageViews_.size() == 0); assert(deviceMemory_.size() == 0); assert(samplers_.size() == 0); + assert(pipelines_.size() == 0); assert(pipelineCaches_.size() == 0); assert(renderPasses_.size() == 0); assert(framebuffers_.size() == 0); @@ -100,6 +102,7 @@ public: imageViews_ = std::move(del.imageViews_); deviceMemory_ = std::move(del.deviceMemory_); samplers_ = std::move(del.samplers_); + pipelines_ = std::move(del.pipelines_); pipelineCaches_ = std::move(del.pipelineCaches_); renderPasses_ = std::move(del.renderPasses_); framebuffers_ = std::move(del.framebuffers_); @@ -139,6 +142,10 @@ public: vkDestroySampler(device, sampler, nullptr); } samplers_.clear(); + for (auto &pipeline : pipelines_) { + vkDestroyPipeline(device, pipeline, nullptr); + } + pipelines_.clear(); for (auto &pcache : pipelineCaches_) { vkDestroyPipelineCache(device, pcache, nullptr); } @@ -166,6 +173,7 @@ private: std::vector imageViews_; std::vector deviceMemory_; std::vector samplers_; + std::vector pipelines_; std::vector pipelineCaches_; std::vector renderPasses_; std::vector framebuffers_; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index e700b8ee46..c3d69b2324 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -800,51 +800,9 @@ void DrawEngineVulkan::DoFlush(VkCommandBuffer cmd) { } } 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. - // A rectangle will be used instead. - // TODO: If this is the first clear in a frame, translate to a cleared attachment load instead. - int mask = gstate.isClearModeColorMask() ? 1 : 0; - if (gstate.isClearModeAlphaMask()) mask |= 2; - if (gstate.isClearModeDepthMask()) mask |= 4; - - VkClearValue colorValue, depthValue; - colorValue.color.float32[0] = (result.color & 0xFF) * (1.0f / 255.0f); - colorValue.color.float32[1] = ((result.color >> 8) & 0xFF) * (1.0f / 255.0f); - colorValue.color.float32[2] = ((result.color >> 16) & 0xFF) * (1.0f / 255.0f); - colorValue.color.float32[3] = ((result.color >> 24) & 0xFF) * (1.0f / 255.0f); - depthValue.depthStencil.depth = result.depth; - depthValue.depthStencil.stencil = (result.color >> 24) & 0xFF; - - VkClearRect rect; - rect.baseArrayLayer = 0; - rect.layerCount = 1; - rect.rect.offset.x = 0; - rect.rect.offset.y = 0; - rect.rect.extent.width = gstate_c.curRTRenderWidth; - rect.rect.extent.height = gstate_c.curRTRenderHeight; - - int count = 0; - VkClearAttachment attach[2]; - if (mask & 3) { - attach[count].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - attach[count].clearValue = colorValue; - attach[count].colorAttachment = 0; - count++; - } - if (mask & 4) { - attach[count].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - attach[count].clearValue = depthValue; - attach[count].colorAttachment = 0; - count++; - } - vkCmdClearAttachments(cmd_, count, attach, 1, &rect); - - if (mask & 1) { - framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); - } - if (mask & 4) { - framebufferManager_->SetDepthUpdated(); - } + // We let the framebuffer manager handle the clear. It can use renderpasses to optimize on tilers. + framebufferManager_->NotifyClear(gstate.isClearModeColorMask(), gstate.isClearModeAlphaMask(), gstate.isClearModeDepthMask(), result.color, result.depth); } } diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 79dc059b71..53a2afafab 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -93,6 +93,8 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(VulkanContext *vulkan) : pixelBufObj_(nullptr), currentPBO_(0), curFrame_(0), + pipelineBasicTex_(VK_NULL_HANDLE), + pipelinePostShader_(VK_NULL_HANDLE), vulkan2D_(vulkan) { // Create a bunch of render pass objects, for normal rendering with a depth buffer, @@ -175,6 +177,7 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(VulkanContext *vulkan) : vsBasicTex_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, tex_vs, &vs_errors); assert(fsBasicTex_ != VK_NULL_HANDLE); assert(vsBasicTex_ != VK_NULL_HANDLE); + pipelineBasicTex_ = vulkan2D_.GetPipeline(pipelineCache2D_, rpClearColorClearDepth_, vsBasicTex_, fsBasicTex_); VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; @@ -212,12 +215,59 @@ FramebufferManagerVulkan::~FramebufferManagerVulkan() { vulkan_->Delete().QueueDeleteSampler(linearSampler_); vulkan_->Delete().QueueDeleteSampler(nearestSampler_); - + vulkan_->Delete().QueueDeletePipeline(pipelineBasicTex_); + if (pipelinePostShader_ != VK_NULL_HANDLE) + vulkan_->Delete().QueueDeletePipeline(pipelinePostShader_); vulkan_->Delete().QueueDeletePipelineCache(pipelineCache2D_); } -void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearDepth, uint32_t color, float depth) { +void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth) { + if (!this->useBufferedRendering_) { + float x, y, w, h; + CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL); + VkClearValue colorValue, depthValue; + colorValue.color.float32[0] = (color & 0xFF) * (1.0f / 255.0f); + colorValue.color.float32[1] = ((color >> 8) & 0xFF) * (1.0f / 255.0f); + colorValue.color.float32[2] = ((color >> 16) & 0xFF) * (1.0f / 255.0f); + colorValue.color.float32[3] = ((color >> 24) & 0xFF) * (1.0f / 255.0f); + depthValue.depthStencil.depth = depth; + depthValue.depthStencil.stencil = (color >> 24) & 0xFF; + + VkClearRect rect; + rect.baseArrayLayer = 0; + rect.layerCount = 1; + rect.rect.offset.x = x; + rect.rect.offset.y = y; + rect.rect.extent.width = w; + rect.rect.extent.height = h; + + int count = 0; + VkClearAttachment attach[2]; + // TODO: Should change to a rectangle draw with color mask if both aren't set. + if (clearColor || clearAlpha) { + attach[count].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + attach[count].clearValue = colorValue; + attach[count].colorAttachment = 0; + count++; + } + if (clearDepth) { + attach[count].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + attach[count].clearValue = depthValue; + attach[count].colorAttachment = 0; + count++; + } + vkCmdClearAttachments(curCmd_, count, attach, 1, &rect); + + if (clearColor) { + SetColorUpdated(gstate_c.skipDrawReason); + } + if (clearAlpha) { + SetDepthUpdated(); + } + } else { + // TODO: Clever render pass magic. + } } void FramebufferManagerVulkan::DoNotifyDraw() { @@ -328,8 +378,6 @@ void FramebufferManagerVulkan::DrawPixels(VirtualFramebuffer *vfb, int dstX, int vp.minDepth = 0.0; vp.maxDepth = 1.0; if (useBufferedRendering_ && vfb && vfb->fbo_vk) { - // fbo_bind_as_render_target(vfb->fbo_vk); - // glViewport(0, 0, vfb->renderWidth, vfb->renderHeight); vp.x = 0; vp.y = 0; vp.width = vfb->renderWidth; @@ -699,17 +747,16 @@ void FramebufferManagerVulkan::BlitFramebufferDepth(VirtualFramebuffer *src, Vir } } -void FramebufferManagerVulkan::BindFramebufferColor(int stage, u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags) { +VulkanTexture *FramebufferManagerVulkan::GetFramebufferColor(u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags) { if (framebuffer == NULL) { framebuffer = currentRenderVfb_; } if (!framebuffer->fbo_vk || !useBufferedRendering_) { gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; - return; + return nullptr; } - /* // currentRenderVfb_ will always be set when this is called, except from the GE debugger. // Let's just not bother with the copy in that case. bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0; @@ -717,8 +764,11 @@ void FramebufferManagerVulkan::BindFramebufferColor(int stage, u32 fbRawAddress, skipCopy = true; } if (!skipCopy && currentRenderVfb_ && framebuffer->fb_address == fbRawAddress) { + // TODO: Enable the below code + return framebuffer->fbo_vk->GetColor(); + /* // TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size. - fbo_vk *renderCopy = GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, (FBOColorDepth)framebuffer->colorDepth); + VulkanFBO *renderCopy = GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, (FBOColorDepth)framebuffer->colorDepth); if (renderCopy) { VirtualFramebuffer copyInfo = *framebuffer; copyInfo.fbo_vk = renderCopy; @@ -745,18 +795,14 @@ void FramebufferManagerVulkan::BindFramebufferColor(int stage, u32 fbRawAddress, BlitFramebuffer(©Info, x, y, framebuffer, x, y, w, h, 0); - fbo_bind_color_as_texture(renderCopy, 0); + return nullptr; // fbo_bind_color_as_texture(renderCopy, 0); } else { - fbo_bind_color_as_texture(framebuffer->fbo_vk, 0); + return framebuffer->fbo_vk->GetColor(); } + */ } else { - fbo_bind_color_as_texture(framebuffer->fbo_vk, 0); + return framebuffer->fbo_vk->GetColor(); } - - if (stage != GL_TEXTURE0) { - glActiveTexture(stage); - } - */ } struct CardboardSettings * FramebufferManagerVulkan::GetCardboardSettings(struct CardboardSettings * cardboardSettings) { diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index 353a1f3eef..55aeb1847b 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -111,7 +111,7 @@ public: void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst); // For use when texturing from a framebuffer. May create a duplicate if target. - void BindFramebufferColor(int stage, u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags); + VulkanTexture *GetFramebufferColor(u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags); // Reads a rectangular subregion of a framebuffer to the right position in its backing memory. void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override; @@ -141,7 +141,7 @@ public: // If within a render pass, this will just issue a regular clear. If beginning a new render pass, // do that. - void NotifyClear(bool clearColor, bool clearDepth, uint32_t color, float depth); + void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth); void NotifyDraw() { DoNotifyDraw(); } @@ -228,6 +228,9 @@ private: VkShaderModule vsBasicTex_; VkPipeline pipelineBasicTex_; + // Postprocessing + VkPipeline pipelinePostShader_; + VkSampler linearSampler_; VkSampler nearestSampler_; diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index eba73bb2d1..e250aacfbf 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -128,6 +128,9 @@ static VkBool32 VKAPI_CALL Vulkan_Dbg(VkDebugReportFlagsEXT msgFlags, VkDebugRep // https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/121 if (msgCode == 6 && (!memcmp(pMsg, "Cannot map", 10) || !memcmp(pMsg, "Cannot sub", 10))) return false; + // And for dynamic offsets. + if (msgCode == 62 && (!memcmp(pMsg, "VkDesc", 6))) + return false; #ifdef _WIN32 OutputDebugStringA(message.str().c_str());