From a6b4ca69dbedc19c55a5913fc10af50e4576fb8b Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Fri, 21 Jan 2022 20:09:47 +1000 Subject: [PATCH] GS/Vulkan: Support rendering without D32S8 --- pcsx2/GS/Renderers/Common/GSDevice.h | 1 + pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 1 + pcsx2/GS/Renderers/HW/GSRendererNew.cpp | 14 ++--- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 1 + pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 69 +++++++++++++++++------ pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h | 2 + pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp | 29 ++-------- pcsx2/GS/Renderers/Vulkan/GSTextureVK.h | 3 +- 8 files changed, 70 insertions(+), 50 deletions(-) diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index 9fa33eee7d..9d6189f64d 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -580,6 +580,7 @@ public: bool bptc_textures : 1; ///< Supports BC6/7 texture compression. bool framebuffer_fetch : 1; ///< Can sample from the framebuffer without texture barriers. bool dual_source_blend : 1; ///< Can use alpha output as a blend factor. + bool stencil_buffer : 1; ///< Supports stencil buffer, and can use for DATE. FeatureSupport() { memset(this, 0, sizeof(*this)); diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 3306655d41..382f2dba29 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -55,6 +55,7 @@ GSDevice11::GSDevice11() m_features.bptc_textures = false; m_features.framebuffer_fetch = false; m_features.dual_source_blend = true; + m_features.stencil_buffer = true; } bool GSDevice11::Create(HostDisplay* display) diff --git a/pcsx2/GS/Renderers/HW/GSRendererNew.cpp b/pcsx2/GS/Renderers/HW/GSRendererNew.cpp index c9bbbe5850..61a97320f9 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererNew.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererNew.cpp @@ -1445,13 +1445,13 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour // Performance note: check alpha range with GetAlphaMinMax() // Note: all my dump are already above 120fps, but it seems to reduce GPU load // with big upscaling - if (m_context->TEST.DATM && GetAlphaMinMax().max < 128) + if (m_context->TEST.DATM && GetAlphaMinMax().max < 128 && features.stencil_buffer) { // Only first pixel (write 0) will pass (alpha is 1) GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max); DATE_one = true; } - else if (!m_context->TEST.DATM && GetAlphaMinMax().min >= 128) + else if (!m_context->TEST.DATM && GetAlphaMinMax().min >= 128 && features.stencil_buffer) { // Only first pixel (write 1) will pass (alpha is 0) GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max); @@ -1462,7 +1462,7 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour // texture barrier will split the draw call into n draw call. It is very efficient for // few primitive draws. Otherwise it sucks. GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max); - if (g_gs_device->Features().texture_barrier) + if (features.texture_barrier) { m_conf.require_full_barrier = true; DATE_BARRIER = true; @@ -1472,16 +1472,16 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour { // Note: Fast level (DATE_one) was removed as it's less accurate. GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max); - if (g_gs_device->Features().image_load_store) + if (features.image_load_store) { DATE_PRIMID = true; } - else if (g_gs_device->Features().texture_barrier) + else if (features.texture_barrier) { m_conf.require_full_barrier = true; DATE_BARRIER = true; } - else + else if (features.stencil_buffer) { DATE_one = true; } @@ -1545,7 +1545,7 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking; else if (DATE_BARRIER) m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Full; - else + else if (features.stencil_buffer) m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil; m_conf.datm = m_context->TEST.DATM; diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index 1656aa1b14..ee3ef9fad4 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -225,6 +225,7 @@ bool GSDeviceOGL::Create(HostDisplay* display) m_features.prefer_new_textures = false; m_features.framebuffer_fetch = GLLoader::found_framebuffer_fetch; m_features.dual_source_blend = GLLoader::has_dual_source_blend && !GSConfig.DisableDualSourceBlend; + m_features.stencil_buffer = true; GLint point_range[2] = {}; GLint line_range[2] = {}; diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 1b2cc9ebc9..d95a2c9c94 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -252,6 +252,13 @@ bool GSDeviceVK::CheckFeatures() if (!m_features.texture_barrier) Console.Warning("Texture buffers are disabled. This may break some graphical effects."); + // Test for D32S8 support. + { + VkFormatProperties props = {}; + vkGetPhysicalDeviceFormatProperties(g_vulkan_context->GetPhysicalDevice(), VK_FORMAT_D32_SFLOAT_S8_UINT, &props); + m_features.stencil_buffer = ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0); + } + // whether we can do point/line expand depends on the range of the device const float f_upscale = static_cast(GSConfig.UpscaleMultiplier); m_features.point_expand = @@ -265,7 +272,7 @@ bool GSDeviceVK::CheckFeatures() // Check texture format support before we try to create them. for (u32 fmt = static_cast(GSTexture::Format::Color); fmt < static_cast(GSTexture::Format::Int32); fmt++) { - const VkFormat vkfmt = GSTextureVK::LookupNativeFormat(static_cast(fmt)); + const VkFormat vkfmt = LookupNativeFormat(static_cast(fmt)); const VkFormatFeatureFlags bits = (static_cast(fmt) == GSTexture::Format::DepthStencil) ? (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) : (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT); @@ -283,6 +290,13 @@ bool GSDeviceVK::CheckFeatures() m_features.dxt_textures = g_vulkan_context->GetDeviceFeatures().textureCompressionBC; m_features.bptc_textures = g_vulkan_context->GetDeviceFeatures().textureCompressionBC; + + if (!m_features.texture_barrier && !m_features.stencil_buffer) + { + Host::AddKeyedOSDMessage("GSDeviceVK_NoTextureBarrierOrStencilBuffer", + "Stencil buffers and texture barriers are both unavailable, this will break some graphical effects.", 10.0f); + } + return true; } @@ -358,6 +372,28 @@ void GSDeviceVK::ClearStencil(GSTexture* t, u8 c) static_cast(t)->TransitionToLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); } +VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const +{ + static constexpr std::array(GSTexture::Format::BC7) + 1> s_format_mapping = {{ + VK_FORMAT_UNDEFINED, // Invalid + VK_FORMAT_R8G8B8A8_UNORM, // Color + VK_FORMAT_R32G32B32A32_SFLOAT, // FloatColor + VK_FORMAT_D32_SFLOAT_S8_UINT, // DepthStencil + VK_FORMAT_R8_UNORM, // UNorm8 + VK_FORMAT_R16_UINT, // UInt16 + VK_FORMAT_R32_UINT, // UInt32 + VK_FORMAT_R32_SFLOAT, // Int32 + VK_FORMAT_BC1_RGBA_UNORM_BLOCK, // BC1 + VK_FORMAT_BC2_UNORM_BLOCK, // BC2 + VK_FORMAT_BC3_UNORM_BLOCK, // BC3 + VK_FORMAT_BC7_UNORM_BLOCK, // BC7 + }}; + + return (format != GSTexture::Format::DepthStencil || m_features.stencil_buffer) ? + s_format_mapping[static_cast(format)] : + VK_FORMAT_D32_SFLOAT; +} + GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) { pxAssert(type != GSTexture::Type::Offscreen && type != GSTexture::Type::SparseRenderTarget && @@ -366,7 +402,7 @@ GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height const u32 clamped_width = static_cast(std::clamp(1, width, g_vulkan_context->GetMaxImageDimension2D())); const u32 clamped_height = static_cast(std::clamp(1, height, g_vulkan_context->GetMaxImageDimension2D())); - return GSTextureVK::Create(type, clamped_width, clamped_height, levels, format).release(); + return GSTextureVK::Create(type, clamped_width, clamped_height, levels, format, LookupNativeFormat(format)).release(); } bool GSDeviceVK::DownloadTexture(GSTexture* src, const GSVector4i& rect, GSTexture::GSMap& out_map) @@ -1161,9 +1197,9 @@ bool GSDeviceVK::CreateRenderPasses() return false; \ } while (0) - const VkFormat rt_format = GSTextureVK::LookupNativeFormat(GSTexture::Format::Color); - const VkFormat hdr_rt_format = GSTextureVK::LookupNativeFormat(GSTexture::Format::FloatColor); - const VkFormat depth_format = GSTextureVK::LookupNativeFormat(GSTexture::Format::DepthStencil); + const VkFormat rt_format = LookupNativeFormat(GSTexture::Format::Color); + const VkFormat hdr_rt_format = LookupNativeFormat(GSTexture::Format::FloatColor); + const VkFormat depth_format = LookupNativeFormat(GSTexture::Format::DepthStencil); for (u32 rt = 0; rt < 2; rt++) { @@ -1183,7 +1219,7 @@ bool GSDeviceVK::CreateRenderPasses() (rt != 0) ? ((hdr != 0) ? hdr_rt_format : rt_format) : VK_FORMAT_UNDEFINED; const VkFormat rp_depth_format = (ds != 0) ? depth_format : VK_FORMAT_UNDEFINED; const VkAttachmentLoadOp opc = - ((date == DATE_RENDER_PASS_NONE) ? + ((date == DATE_RENDER_PASS_NONE || !m_features.stencil_buffer) ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : (date == DATE_RENDER_PASS_STENCIL_ONE ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD)); @@ -1212,8 +1248,9 @@ bool GSDeviceVK::CreateRenderPasses() VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE); m_date_setup_render_pass = g_vulkan_context->GetRenderPass(VK_FORMAT_UNDEFINED, depth_format, - VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + m_features.stencil_buffer ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE, + m_features.stencil_buffer ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE); if (m_date_setup_render_pass == VK_NULL_HANDLE) return false; @@ -1271,13 +1308,13 @@ bool GSDeviceVK::CompileConvertPipelines() case ShaderConvert::RGBA8_TO_16_BITS: case ShaderConvert::FLOAT32_TO_16_BITS: { - rp = g_vulkan_context->GetRenderPass(GSTextureVK::LookupNativeFormat(GSTexture::Format::UInt16), + rp = g_vulkan_context->GetRenderPass(LookupNativeFormat(GSTexture::Format::UInt16), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_DONT_CARE); } break; case ShaderConvert::FLOAT32_TO_32_BITS: { - rp = g_vulkan_context->GetRenderPass(GSTextureVK::LookupNativeFormat(GSTexture::Format::UInt32), + rp = g_vulkan_context->GetRenderPass(LookupNativeFormat(GSTexture::Format::UInt32), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_DONT_CARE); } break; @@ -1290,8 +1327,8 @@ bool GSDeviceVK::CompileConvertPipelines() default: { rp = g_vulkan_context->GetRenderPass( - GSTextureVK::LookupNativeFormat(depth ? GSTexture::Format::Invalid : GSTexture::Format::Color), - GSTextureVK::LookupNativeFormat( + LookupNativeFormat(depth ? GSTexture::Format::Invalid : GSTexture::Format::Color), + LookupNativeFormat( depth ? GSTexture::Format::DepthStencil : GSTexture::Format::Invalid), VK_ATTACHMENT_LOAD_OP_DONT_CARE); } @@ -1411,8 +1448,8 @@ bool GSDeviceVK::CompileConvertPipelines() for (u32 clear = 0; clear < 2; clear++) { m_date_image_setup_render_passes[ds][clear] = - g_vulkan_context->GetRenderPass(GSTextureVK::LookupNativeFormat(GSTexture::Format::Int32), - ds ? GSTextureVK::LookupNativeFormat(GSTexture::Format::DepthStencil) : VK_FORMAT_UNDEFINED, + g_vulkan_context->GetRenderPass(LookupNativeFormat(GSTexture::Format::Int32), + ds ? LookupNativeFormat(GSTexture::Format::DepthStencil) : VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, ds ? (clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD) : VK_ATTACHMENT_LOAD_OP_DONT_CARE, @@ -1462,7 +1499,7 @@ bool GSDeviceVK::CompileInterlacePipelines() } VkRenderPass rp = g_vulkan_context->GetRenderPass( - GSTextureVK::LookupNativeFormat(GSTexture::Format::Color), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD); + LookupNativeFormat(GSTexture::Format::Color), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD); if (!rp) return false; @@ -1516,7 +1553,7 @@ bool GSDeviceVK::CompileMergePipelines() } VkRenderPass rp = g_vulkan_context->GetRenderPass( - GSTextureVK::LookupNativeFormat(GSTexture::Format::Color), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD); + LookupNativeFormat(GSTexture::Format::Color), VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD); if (!rp) return false; diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index 125e8b92e9..10771968d7 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -146,6 +146,8 @@ private: std::string m_tfx_source; + VkFormat LookupNativeFormat(GSTexture::Format format) const; + GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override; void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp index 6a1aeda64f..ca7bed43b5 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp @@ -59,7 +59,7 @@ GSTextureVK::~GSTextureVK() } } -std::unique_ptr GSTextureVK::Create(Type type, u32 width, u32 height, u32 levels, Format format) +std::unique_ptr GSTextureVK::Create(Type type, u32 width, u32 height, u32 levels, Format format, VkFormat vk_format) { switch (type) { @@ -77,7 +77,7 @@ std::unique_ptr GSTextureVK::Create(Type type, u32 width, u32 heigh } Vulkan::Texture texture; - if (!texture.Create(width, height, levels, 1, LookupNativeFormat(format), VK_SAMPLE_COUNT_1_BIT, + if (!texture.Create(width, height, levels, 1, vk_format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage, swizzle)) { return {}; @@ -93,7 +93,7 @@ std::unique_ptr GSTextureVK::Create(Type type, u32 width, u32 heigh pxAssert(levels == 1); Vulkan::Texture texture; - if (!texture.Create(width, height, levels, 1, LookupNativeFormat(format), VK_SAMPLE_COUNT_1_BIT, + if (!texture.Create(width, height, levels, 1, vk_format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | @@ -112,7 +112,7 @@ std::unique_ptr GSTextureVK::Create(Type type, u32 width, u32 heigh pxAssert(levels == 1); Vulkan::Texture texture; - if (!texture.Create(width, height, levels, 1, LookupNativeFormat(format), VK_SAMPLE_COUNT_1_BIT, + if (!texture.Create(width, height, levels, 1, vk_format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) @@ -130,27 +130,6 @@ std::unique_ptr GSTextureVK::Create(Type type, u32 width, u32 heigh } } -VkFormat GSTextureVK::LookupNativeFormat(Format format) -{ - static constexpr std::array(GSTexture::Format::BC7) + 1> s_format_mapping = {{ - VK_FORMAT_UNDEFINED, // Invalid - VK_FORMAT_R8G8B8A8_UNORM, // Color - VK_FORMAT_R32G32B32A32_SFLOAT, // FloatColor - VK_FORMAT_D32_SFLOAT_S8_UINT, // DepthStencil - VK_FORMAT_R8_UNORM, // UNorm8 - VK_FORMAT_R16_UINT, // UInt16 - VK_FORMAT_R32_UINT, // UInt32 - VK_FORMAT_R32_SFLOAT, // Int32 - VK_FORMAT_BC1_RGBA_UNORM_BLOCK, // BC1 - VK_FORMAT_BC2_UNORM_BLOCK, // BC2 - VK_FORMAT_BC3_UNORM_BLOCK, // BC3 - VK_FORMAT_BC7_UNORM_BLOCK, // BC7 - }}; - - - return s_format_mapping[static_cast(format)]; -} - void* GSTextureVK::GetNativeHandle() const { return const_cast(&m_texture); } VkCommandBuffer GSTextureVK::GetCommandBufferForUpdate() diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h index 905cb20e9a..6afd77dd34 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h @@ -33,8 +33,7 @@ public: GSTextureVK(Type type, Format format, Vulkan::Texture texture); ~GSTextureVK() override; - static std::unique_ptr Create(Type type, u32 width, u32 height, u32 levels, Format format); - static VkFormat LookupNativeFormat(Format format); + static std::unique_ptr Create(Type type, u32 width, u32 height, u32 levels, Format format, VkFormat vk_format); __fi Vulkan::Texture& GetTexture() { return m_texture; } __fi VkFormat GetNativeFormat() const { return m_texture.GetFormat(); }