From ca3be1877ecae3e08a9016c83d57529df8f66c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 8 Nov 2017 17:01:38 +0100 Subject: [PATCH] Vulkan: Apply simple workaround for Mali driver bug (see #10070), and minor cleanup. --- Common/Vulkan/VulkanContext.cpp | 7 +++-- Common/Vulkan/VulkanContext.h | 2 +- ext/native/thin3d/VulkanQueueRunner.cpp | 37 ++++++++++++++----------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index d8e03413e3..6c1ce1eb5c 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -786,7 +786,8 @@ bool VulkanContext::CreateShaderModule(const std::vector &spirv, VkSha void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, - VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask) { + VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, + int numMipLevels) { VkImageMemoryBarrier image_memory_barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; image_memory_barrier.srcAccessMask = srcAccessMask; image_memory_barrier.dstAccessMask = dstAccessMask; @@ -795,8 +796,8 @@ void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFla image_memory_barrier.image = image; image_memory_barrier.subresourceRange.aspectMask = aspectMask; image_memory_barrier.subresourceRange.baseMipLevel = 0; - image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; - image_memory_barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + image_memory_barrier.subresourceRange.levelCount = numMipLevels; + image_memory_barrier.subresourceRange.layerCount = 1; // We never use more than one layer, and old Mali drivers have problems with VK_REMAINING_ARRAY_LAYERS/VK_REMAINING_MIP_LEVELS. image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; vkCmdPipelineBarrier(cmd, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 52df35a5ff..8c40442197 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -393,7 +393,7 @@ private: void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, - VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask); + VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, int mipLevels = VK_REMAINING_MIP_LEVELS); // GLSL compiler void init_glslang(); diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 7006735086..df43465603 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -2,6 +2,8 @@ #include "VulkanQueueRunner.h" #include "VulkanRenderManager.h" +// Debug help: adb logcat -s DEBUG NativeActivity NativeApp PPSSPP + // TODO: This is only enough for 4x render resolution / 4x texture upscale for debugger. // Maybe we should use a dynamically allocated one for larger? const uint32_t readbackBufferSize = 2048 * 2048 * 4; @@ -342,6 +344,12 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c iter.fb->Release(); } + // Don't execute empty renderpasses. + if (step.commands.empty() && step.render.color == VKRRenderPassAction::KEEP && step.render.depthStencil == VKRRenderPassAction::KEEP) { + // Nothing to do. + return; + } + // This is supposed to bind a vulkan render pass to the command buffer. PerformBindFramebufferAsRenderTarget(step, cmd); @@ -481,28 +489,17 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step, VkCommandBuffer cmd) { + VkRenderPass renderPass; + int numClearVals = 0; + VkClearValue clearVal[2]{}; VkFramebuffer framebuf; int w; int h; - VkImageLayout prevLayout; if (step.render.framebuffer) { VKRFramebuffer *fb = step.render.framebuffer; framebuf = fb->framebuf; w = fb->width; h = fb->height; - prevLayout = fb->color.layout; - } else { - framebuf = backbuffer_; - w = vulkan_->GetBackbufferWidth(); - h = vulkan_->GetBackbufferHeight(); - } - - VkRenderPass renderPass; - int numClearVals = 0; - VkClearValue clearVal[2]; - memset(clearVal, 0, sizeof(clearVal)); - if (step.render.framebuffer) { - VKRFramebuffer *fb = step.render.framebuffer; // 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) { @@ -526,15 +523,17 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step break; } + // Due to a known bug in the Mali driver, pass the level count explicitly. 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); + srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, 1); fb->color.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; } if (fb->depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { VkAccessFlags srcAccessMask; VkPipelineStageFlags srcStage; + switch (fb->depth.layout) { case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: srcAccessMask = VK_ACCESS_SHADER_READ_BIT; @@ -552,10 +551,13 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step Crash(); break; } + + // Due to a known bug in the Mali driver, pass the level count explicitly (last param). TransitionImageLayout2(cmd, fb->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, fb->depth.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); + srcAccessMask, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + 1); fb->depth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } @@ -570,6 +572,9 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step numClearVals = 2; } } else { + framebuf = backbuffer_; + w = vulkan_->GetBackbufferWidth(); + h = vulkan_->GetBackbufferHeight(); renderPass = GetBackbufferRenderPass(); assert(step.render.color == VKRRenderPassAction::CLEAR || step.render.color == VKRRenderPassAction::DONT_CARE); assert(step.render.depthStencil == VKRRenderPassAction::CLEAR || step.render.depthStencil == VKRRenderPassAction::DONT_CARE);