From 2698e311aaec09d9b0e34fc659349f3b668a1644 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 31 Jul 2019 15:33:05 +1000 Subject: [PATCH 1/2] Vulkan: Use correct aspect for D24S8 textures --- .../Core/VideoBackends/Vulkan/VKTexture.cpp | 19 +++++++++++++++++-- Source/Core/VideoBackends/Vulkan/VKTexture.h | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp index 27b079a779..89e4a29d41 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp @@ -138,7 +138,7 @@ bool VKTexture::CreateView(VkImageViewType type) GetVkFormat(), {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, - {GetImageAspectForFormat(GetFormat()), 0, GetLevels(), 0, GetLayers()}}; + {GetImageViewAspectForFormat(GetFormat()), 0, GetLevels(), 0, GetLayers()}}; VkResult res = vkCreateImageView(g_vulkan_context->GetDevice(), &view_info, nullptr, &m_view); if (res != VK_SUCCESS) @@ -237,6 +237,21 @@ VkImageAspectFlags VKTexture::GetImageAspectForFormat(AbstractTextureFormat form } } +VkImageAspectFlags VKTexture::GetImageViewAspectForFormat(AbstractTextureFormat format) +{ + switch (format) + { + case AbstractTextureFormat::D16: + case AbstractTextureFormat::D24_S8: + case AbstractTextureFormat::D32F_S8: + case AbstractTextureFormat::D32F: + return VK_IMAGE_ASPECT_DEPTH_BIT; + + default: + return VK_IMAGE_ASPECT_COLOR_BIT; + } +} + void VKTexture::CopyRectangleFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& src_rect, u32 src_layer, u32 src_level, const MathUtil::Rectangle& dst_rect, @@ -743,7 +758,7 @@ void VKStagingTexture::CopyFromTexture(const AbstractTexture* src, // Issue the image->buffer copy, but delay it for now. VkBufferImageCopy image_copy = {}; - const VkImageAspectFlags aspect = VKTexture::GetImageAspectForFormat(src_tex->GetFormat()); + const VkImageAspectFlags aspect = VKTexture::GetImageViewAspectForFormat(src_tex->GetFormat()); image_copy.bufferOffset = static_cast(static_cast(dst_rect.top) * m_config.GetStride() + static_cast(dst_rect.left) * m_texel_size); diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.h b/Source/Core/VideoBackends/Vulkan/VKTexture.h index 2a194acc4d..91d3e54eac 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.h +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.h @@ -37,6 +37,7 @@ public: static VkFormat GetLinearFormat(VkFormat format); static VkFormat GetVkFormatForHostTextureFormat(AbstractTextureFormat format); static VkImageAspectFlags GetImageAspectForFormat(AbstractTextureFormat format); + static VkImageAspectFlags GetImageViewAspectForFormat(AbstractTextureFormat format); void CopyRectangleFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& src_rect, u32 src_layer, From 06daf5803243c5f36069d8f7a936e62857ce1eca Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 31 Jul 2019 15:33:27 +1000 Subject: [PATCH 2/2] FramebufferManager: Correctly handle read back D24S8 textures Needed for the Adreno/Vulkan workaround, and if we ever switch to a D24 texture for the depth buffer w/ unrestricted depth range. --- Source/Core/VideoCommon/AbstractTexture.cpp | 13 ++-- Source/Core/VideoCommon/AbstractTexture.h | 3 +- .../Core/VideoCommon/FramebufferManager.cpp | 76 +++++++++++-------- Source/Core/VideoCommon/FramebufferManager.h | 1 + 4 files changed, 54 insertions(+), 39 deletions(-) diff --git a/Source/Core/VideoCommon/AbstractTexture.cpp b/Source/Core/VideoCommon/AbstractTexture.cpp index d0c27617db..23ade1f99b 100644 --- a/Source/Core/VideoCommon/AbstractTexture.cpp +++ b/Source/Core/VideoCommon/AbstractTexture.cpp @@ -88,20 +88,19 @@ bool AbstractTexture::IsStencilFormat(AbstractTextureFormat format) return format == AbstractTextureFormat::D24_S8 || format == AbstractTextureFormat::D32F_S8; } -AbstractTextureFormat AbstractTexture::GetColorFormatForDepthFormat(AbstractTextureFormat format) +bool AbstractTexture::IsCompatibleDepthAndColorFormats(AbstractTextureFormat depth_format, + AbstractTextureFormat color_format) { - switch (format) + switch (depth_format) { case AbstractTextureFormat::D16: - return AbstractTextureFormat::R16; + return color_format == AbstractTextureFormat::R16; - case AbstractTextureFormat::D24_S8: // TODO: Incorrect case AbstractTextureFormat::D32F: - case AbstractTextureFormat::D32F_S8: - return AbstractTextureFormat::R32F; + return color_format == AbstractTextureFormat::R32F; default: - return format; + return false; } } diff --git a/Source/Core/VideoCommon/AbstractTexture.h b/Source/Core/VideoCommon/AbstractTexture.h index 6ff80e9703..99b5c0c398 100644 --- a/Source/Core/VideoCommon/AbstractTexture.h +++ b/Source/Core/VideoCommon/AbstractTexture.h @@ -44,7 +44,8 @@ public: static bool IsCompressedFormat(AbstractTextureFormat format); static bool IsDepthFormat(AbstractTextureFormat format); static bool IsStencilFormat(AbstractTextureFormat format); - static AbstractTextureFormat GetColorFormatForDepthFormat(AbstractTextureFormat format); + static bool IsCompatibleDepthAndColorFormats(AbstractTextureFormat depth_format, + AbstractTextureFormat color_format); static u32 CalculateStrideForFormat(AbstractTextureFormat format, u32 row_length); static u32 GetTexelSizeForFormat(AbstractTextureFormat format); static u32 GetBlockSizeForFormat(AbstractTextureFormat format); diff --git a/Source/Core/VideoCommon/FramebufferManager.cpp b/Source/Core/VideoCommon/FramebufferManager.cpp index f61ebcf4a9..8304a90e1a 100644 --- a/Source/Core/VideoCommon/FramebufferManager.cpp +++ b/Source/Core/VideoCommon/FramebufferManager.cpp @@ -129,6 +129,11 @@ AbstractTextureFormat FramebufferManager::GetEFBDepthFormat() return AbstractTextureFormat::D32F; } +AbstractTextureFormat FramebufferManager::GetEFBDepthCopyFormat() +{ + return AbstractTextureFormat::R32F; +} + static u32 CalculateEFBLayers() { return (g_ActiveConfig.stereo_mode != StereoMode::Off) ? 2 : 1; @@ -183,11 +188,10 @@ bool FramebufferManager::CreateEFBFramebuffer() m_efb_resolve_color_texture = g_renderer->CreateTexture( TextureConfig(efb_color_texture_config.width, efb_color_texture_config.height, 1, efb_color_texture_config.layers, 1, efb_color_texture_config.format, 0)); - m_efb_depth_resolve_texture = g_renderer->CreateTexture(TextureConfig( - efb_depth_texture_config.width, efb_depth_texture_config.height, 1, - efb_depth_texture_config.layers, 1, - AbstractTexture::GetColorFormatForDepthFormat(efb_depth_texture_config.format), - AbstractTextureFlag_RenderTarget)); + m_efb_depth_resolve_texture = g_renderer->CreateTexture( + TextureConfig(efb_depth_texture_config.width, efb_depth_texture_config.height, 1, + efb_depth_texture_config.layers, 1, GetEFBDepthCopyFormat(), + AbstractTextureFlag_RenderTarget)); if (!m_efb_resolve_color_texture || !m_efb_depth_resolve_texture) return false; @@ -447,8 +451,7 @@ bool FramebufferManager::CompileReadbackPipelines() return false; // same for depth, except different format - config.framebuffer_state.color_texture_format = - AbstractTexture::GetColorFormatForDepthFormat(GetEFBDepthFormat()); + config.framebuffer_state.color_texture_format = GetEFBDepthCopyFormat(); m_efb_depth_cache.copy_pipeline = g_renderer->CreatePipeline(config); if (!m_efb_depth_cache.copy_pipeline) return false; @@ -492,29 +495,39 @@ void FramebufferManager::DestroyReadbackPipelines() bool FramebufferManager::CreateReadbackFramebuffer() { - // Since we can't partially copy from a depth buffer directly to the staging texture in D3D, we - // use an intermediate buffer to avoid copying the whole texture. - if ((IsUsingTiledEFBCache() && !g_ActiveConfig.backend_info.bSupportsPartialDepthCopies) || - g_renderer->GetEFBScale() != 1) + if (g_renderer->GetEFBScale() != 1) { const TextureConfig color_config(IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_WIDTH, IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_HEIGHT, 1, 1, 1, GetEFBColorFormat(), AbstractTextureFlag_RenderTarget); - const TextureConfig depth_config( - color_config.width, color_config.height, 1, 1, 1, - AbstractTexture::GetColorFormatForDepthFormat(GetEFBDepthFormat()), - AbstractTextureFlag_RenderTarget); - m_efb_color_cache.texture = g_renderer->CreateTexture(color_config); - m_efb_depth_cache.texture = g_renderer->CreateTexture(depth_config); - if (!m_efb_color_cache.texture || !m_efb_depth_cache.texture) + if (!m_efb_color_cache.texture) return false; m_efb_color_cache.framebuffer = g_renderer->CreateFramebuffer(m_efb_color_cache.texture.get(), nullptr); + if (!m_efb_color_cache.framebuffer) + return false; + } + + // Since we can't partially copy from a depth buffer directly to the staging texture in D3D, we + // use an intermediate buffer to avoid copying the whole texture. + if ((IsUsingTiledEFBCache() && !g_ActiveConfig.backend_info.bSupportsPartialDepthCopies) || + !AbstractTexture::IsCompatibleDepthAndColorFormats(m_efb_depth_texture->GetFormat(), + GetEFBDepthCopyFormat()) || + g_renderer->GetEFBScale() != 1) + { + const TextureConfig depth_config(IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_WIDTH, + IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_HEIGHT, 1, + 1, 1, GetEFBDepthCopyFormat(), + AbstractTextureFlag_RenderTarget); + m_efb_depth_cache.texture = g_renderer->CreateTexture(depth_config); + if (!m_efb_depth_cache.texture) + return false; + m_efb_depth_cache.framebuffer = g_renderer->CreateFramebuffer(m_efb_depth_cache.texture.get(), nullptr); - if (!m_efb_color_cache.framebuffer || !m_efb_depth_cache.framebuffer) + if (!m_efb_depth_cache.framebuffer) return false; } @@ -524,8 +537,7 @@ bool FramebufferManager::CreateReadbackFramebuffer() TextureConfig(EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, GetEFBColorFormat(), 0)); m_efb_depth_cache.readback_texture = g_renderer->CreateStagingTexture( StagingTextureType::Mutable, - TextureConfig(EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, - AbstractTexture::GetColorFormatForDepthFormat(GetEFBDepthFormat()), 0)); + TextureConfig(EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, GetEFBDepthCopyFormat(), 0)); if (!m_efb_color_cache.readback_texture || !m_efb_depth_cache.readback_texture) return false; @@ -563,7 +575,10 @@ void FramebufferManager::PopulateEFBCache(bool depth, u32 tile_index) // Force the path through the intermediate texture, as we can't do an image copy from a depth // buffer directly to a staging texture (must be the whole resource). const bool force_intermediate_copy = - depth && !g_ActiveConfig.backend_info.bSupportsPartialDepthCopies && IsUsingTiledEFBCache(); + depth && + ((!g_ActiveConfig.backend_info.bSupportsPartialDepthCopies && IsUsingTiledEFBCache()) || + !AbstractTexture::IsCompatibleDepthAndColorFormats(m_efb_depth_texture->GetFormat(), + GetEFBDepthCopyFormat())); // Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on. EFBCacheData& data = depth ? m_efb_depth_cache : m_efb_color_cache; @@ -888,21 +903,20 @@ void FramebufferManager::DoSaveState(PointerWrap& p) 1, GetEFBColorFormat(), 0); g_texture_cache->SerializeTexture(color_texture, color_texture_config, p); - if (GetEFBDepthFormat() == AbstractTextureFormat::D32F) + if (AbstractTexture::IsCompatibleDepthAndColorFormats(m_efb_depth_texture->GetFormat(), + GetEFBDepthCopyFormat())) { - const TextureConfig depth_texture_config( - depth_texture->GetWidth(), depth_texture->GetHeight(), depth_texture->GetLevels(), - depth_texture->GetLayers(), 1, - AbstractTexture::GetColorFormatForDepthFormat(GetEFBDepthFormat()), 0); + const TextureConfig depth_texture_config(depth_texture->GetWidth(), depth_texture->GetHeight(), + depth_texture->GetLevels(), depth_texture->GetLayers(), + 1, GetEFBDepthCopyFormat(), 0); g_texture_cache->SerializeTexture(depth_texture, depth_texture_config, p); } else { // If the EFB is backed by a D24S8 texture, we first have to convert it to R32F. - const TextureConfig temp_texture_config(depth_texture->GetWidth(), depth_texture->GetHeight(), - depth_texture->GetLevels(), depth_texture->GetLayers(), - 1, AbstractTextureFormat::R32F, - AbstractTextureFlag_RenderTarget); + const TextureConfig temp_texture_config( + depth_texture->GetWidth(), depth_texture->GetHeight(), depth_texture->GetLevels(), + depth_texture->GetLayers(), 1, GetEFBDepthCopyFormat(), AbstractTextureFlag_RenderTarget); std::unique_ptr temp_texture = g_renderer->CreateTexture(temp_texture_config); std::unique_ptr temp_fb = g_renderer->CreateFramebuffer(temp_texture.get(), nullptr); diff --git a/Source/Core/VideoCommon/FramebufferManager.h b/Source/Core/VideoCommon/FramebufferManager.h index b4ae99361d..786f22e537 100644 --- a/Source/Core/VideoCommon/FramebufferManager.h +++ b/Source/Core/VideoCommon/FramebufferManager.h @@ -44,6 +44,7 @@ public: // Does not require the framebuffer to be created. Slower than direct queries. static AbstractTextureFormat GetEFBColorFormat(); static AbstractTextureFormat GetEFBDepthFormat(); + static AbstractTextureFormat GetEFBDepthCopyFormat(); static TextureConfig GetEFBColorTextureConfig(); static TextureConfig GetEFBDepthTextureConfig();