From 6ee0248eab7622d2db19f28f120b447b5db11379 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Tue, 21 Jun 2022 02:07:35 -0500 Subject: [PATCH] VideoBackends:Metal: MSAA support --- Source/Core/VideoBackends/D3D/D3DMain.cpp | 1 + .../Core/VideoBackends/D3D12/VideoBackend.cpp | 1 + Source/Core/VideoBackends/Metal/MTLMain.mm | 11 +++- .../VideoBackends/Metal/MTLObjectCache.mm | 2 + Source/Core/VideoBackends/Metal/MTLUtil.mm | 10 ++++ .../Core/VideoBackends/Null/NullBackend.cpp | 1 + Source/Core/VideoBackends/OGL/OGLMain.cpp | 1 + Source/Core/VideoBackends/Software/SWmain.cpp | 1 + .../VideoBackends/Vulkan/VulkanContext.cpp | 1 + .../Core/VideoCommon/FramebufferManager.cpp | 52 +++++++++++++++++-- Source/Core/VideoCommon/FramebufferManager.h | 2 + .../Core/VideoCommon/FramebufferShaderGen.cpp | 16 ++++++ .../Core/VideoCommon/FramebufferShaderGen.h | 1 + Source/Core/VideoCommon/VideoConfig.h | 1 + 14 files changed, 95 insertions(+), 6 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/D3DMain.cpp b/Source/Core/VideoBackends/D3D/D3DMain.cpp index 6fc2c285a1..b8d7fb5871 100644 --- a/Source/Core/VideoBackends/D3D/D3DMain.cpp +++ b/Source/Core/VideoBackends/D3D/D3DMain.cpp @@ -111,6 +111,7 @@ void VideoBackend::FillBackendInfo() g_Config.backend_info.bSupportsLodBiasInSampler = true; g_Config.backend_info.bSupportsLogicOp = D3D::SupportsLogicOp(g_Config.iAdapter); g_Config.backend_info.bSupportsSettingObjectNames = true; + g_Config.backend_info.bSupportsPartialMultisampleResolve = true; g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames(); g_Config.backend_info.AAModes = D3D::GetAAModes(g_Config.iAdapter); diff --git a/Source/Core/VideoBackends/D3D12/VideoBackend.cpp b/Source/Core/VideoBackends/D3D12/VideoBackend.cpp index 197d309332..b0611a8690 100644 --- a/Source/Core/VideoBackends/D3D12/VideoBackend.cpp +++ b/Source/Core/VideoBackends/D3D12/VideoBackend.cpp @@ -86,6 +86,7 @@ void VideoBackend::FillBackendInfo() g_Config.backend_info.bSupportsTextureQueryLevels = true; g_Config.backend_info.bSupportsLodBiasInSampler = true; g_Config.backend_info.bSupportsSettingObjectNames = true; + g_Config.backend_info.bSupportsPartialMultisampleResolve = true; // We can only check texture support once we have a device. if (g_dx_context) diff --git a/Source/Core/VideoBackends/Metal/MTLMain.mm b/Source/Core/VideoBackends/Metal/MTLMain.mm index 2b54d93784..f294f297f2 100644 --- a/Source/Core/VideoBackends/Metal/MTLMain.mm +++ b/Source/Core/VideoBackends/Metal/MTLMain.mm @@ -141,7 +141,16 @@ void Metal::VideoBackend::InitBackendInfo() @autoreleasepool { Util::PopulateBackendInfo(&g_Config); - Util::PopulateBackendInfoAdapters(&g_Config, Util::GetAdapterList()); + auto adapters = Util::GetAdapterList(); + Util::PopulateBackendInfoAdapters(&g_Config, adapters); + if (!adapters.empty()) + { + // Use the selected adapter, or the first to fill features. + size_t index = static_cast(g_Config.iAdapter); + if (index >= adapters.size()) + index = 0; + Util::PopulateBackendInfoFeatures(&g_Config, adapters[index]); + } } } diff --git a/Source/Core/VideoBackends/Metal/MTLObjectCache.mm b/Source/Core/VideoBackends/Metal/MTLObjectCache.mm index e9b836ce1c..3181e1fdee 100644 --- a/Source/Core/VideoBackends/Metal/MTLObjectCache.mm +++ b/Source/Core/VideoBackends/Metal/MTLObjectCache.mm @@ -311,6 +311,7 @@ public: fragment_shader = static_cast(cfg.pixel_shader); framebuffer.color_texture_format = cfg.framebuffer_state.color_texture_format.Value(); framebuffer.depth_texture_format = cfg.framebuffer_state.depth_texture_format.Value(); + framebuffer.samples = cfg.framebuffer_state.samples.Value(); blend.colorupdate = cfg.blending_state.colorupdate.Value(); blend.alphaupdate = cfg.blending_state.alphaupdate.Value(); if (cfg.blending_state.blendenable) @@ -416,6 +417,7 @@ public: // clang-format on } FramebufferState fs = config.framebuffer_state; + [desc setRasterSampleCount:fs.samples]; [color0 setPixelFormat:Util::FromAbstract(fs.color_texture_format)]; [desc setDepthAttachmentPixelFormat:Util::FromAbstract(fs.depth_texture_format)]; if (Util::HasStencil(fs.depth_texture_format)) diff --git a/Source/Core/VideoBackends/Metal/MTLUtil.mm b/Source/Core/VideoBackends/Metal/MTLUtil.mm index edb250e43f..b80b235436 100644 --- a/Source/Core/VideoBackends/Metal/MTLUtil.mm +++ b/Source/Core/VideoBackends/Metal/MTLUtil.mm @@ -68,6 +68,8 @@ void Metal::Util::PopulateBackendInfo(VideoConfig* config) config->backend_info.bSupportsTextureQueryLevels = true; config->backend_info.bSupportsLodBiasInSampler = false; config->backend_info.bSupportsSettingObjectNames = true; + // Metal requires multisample resolve to be done on a render pass + config->backend_info.bSupportsPartialMultisampleResolve = false; } void Metal::Util::PopulateBackendInfoAdapters(VideoConfig* config, @@ -201,6 +203,14 @@ void Metal::Util::PopulateBackendInfoFeatures(VideoConfig* config, id config->backend_info.bSupportsBPTCTextures = supports_mac1; config->backend_info.bSupportsFramebufferFetch = true; #endif + + config->backend_info.AAModes.clear(); + for (u32 i = 1; i <= 64; i <<= 1) + { + if ([device supportsTextureSampleCount:i]) + config->backend_info.AAModes.push_back(i); + } + if (char* env = getenv("MTL_UNIFIED_MEMORY")) g_features.unified_memory = env[0] == '1' || env[0] == 'y' || env[0] == 'Y'; else if (@available(macOS 10.15, iOS 13.0, *)) diff --git a/Source/Core/VideoBackends/Null/NullBackend.cpp b/Source/Core/VideoBackends/Null/NullBackend.cpp index 5d04a5adac..b68c9cfd94 100644 --- a/Source/Core/VideoBackends/Null/NullBackend.cpp +++ b/Source/Core/VideoBackends/Null/NullBackend.cpp @@ -59,6 +59,7 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsTextureQueryLevels = false; g_Config.backend_info.bSupportsLodBiasInSampler = false; g_Config.backend_info.bSupportsSettingObjectNames = false; + g_Config.backend_info.bSupportsPartialMultisampleResolve = true; // aamodes: We only support 1 sample, so no MSAA g_Config.backend_info.Adapters.clear(); diff --git a/Source/Core/VideoBackends/OGL/OGLMain.cpp b/Source/Core/VideoBackends/OGL/OGLMain.cpp index a286625b34..24a65f746d 100644 --- a/Source/Core/VideoBackends/OGL/OGLMain.cpp +++ b/Source/Core/VideoBackends/OGL/OGLMain.cpp @@ -93,6 +93,7 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsShaderBinaries = false; g_Config.backend_info.bSupportsPipelineCacheData = false; g_Config.backend_info.bSupportsLodBiasInSampler = true; + g_Config.backend_info.bSupportsPartialMultisampleResolve = true; // TODO: There is a bug here, if texel buffers or SSBOs/atomics are not supported the graphics // options will show the option when it is not supported. The only way around this would be diff --git a/Source/Core/VideoBackends/Software/SWmain.cpp b/Source/Core/VideoBackends/Software/SWmain.cpp index a74b2eb1c9..80dc4603f2 100644 --- a/Source/Core/VideoBackends/Software/SWmain.cpp +++ b/Source/Core/VideoBackends/Software/SWmain.cpp @@ -88,6 +88,7 @@ void VideoSoftware::InitBackendInfo() g_Config.backend_info.bSupportsTextureQueryLevels = false; g_Config.backend_info.bSupportsLodBiasInSampler = false; g_Config.backend_info.bSupportsSettingObjectNames = false; + g_Config.backend_info.bSupportsPartialMultisampleResolve = true; // aamodes g_Config.backend_info.AAModes = {1}; diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index a6cb201d72..cad326c83a 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -294,6 +294,7 @@ void VulkanContext::PopulateBackendInfo(VideoConfig* config) config->backend_info.bSupportsTextureQueryLevels = true; // Assumed support. config->backend_info.bSupportsLodBiasInSampler = false; // Dependent on OS. config->backend_info.bSupportsSettingObjectNames = false; // Dependent on features. + config->backend_info.bSupportsPartialMultisampleResolve = true; // Assumed support. } void VulkanContext::PopulateBackendInfoAdapters(VideoConfig* config, const GPUList& gpu_list) diff --git a/Source/Core/VideoCommon/FramebufferManager.cpp b/Source/Core/VideoCommon/FramebufferManager.cpp index d4fdfd0ff2..76c265c76a 100644 --- a/Source/Core/VideoCommon/FramebufferManager.cpp +++ b/Source/Core/VideoCommon/FramebufferManager.cpp @@ -188,12 +188,23 @@ bool FramebufferManager::CreateEFBFramebuffer() // Create resolved textures if MSAA is on if (g_ActiveConfig.MultisamplingEnabled()) { + u32 flags = 0; + if (!g_ActiveConfig.backend_info.bSupportsPartialMultisampleResolve) + flags |= AbstractTextureFlag_RenderTarget; 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), + efb_color_texture_config.layers, 1, efb_color_texture_config.format, flags), "EFB color resolve texture"); if (!m_efb_resolve_color_texture) return false; + + if (!g_ActiveConfig.backend_info.bSupportsPartialMultisampleResolve) + { + m_efb_color_resolve_framebuffer = + g_renderer->CreateFramebuffer(m_efb_resolve_color_texture.get(), nullptr); + if (!m_efb_color_resolve_framebuffer) + return false; + } } // We also need one to convert the D24S8 to R32F if that is being used (Adreno). @@ -248,12 +259,27 @@ AbstractTexture* FramebufferManager::ResolveEFBColorTexture(const MathUtil::Rect clamped_region.ClampUL(0, 0, GetEFBWidth(), GetEFBHeight()); // Resolve to our already-created texture. - for (u32 layer = 0; layer < GetEFBLayers(); layer++) + if (g_ActiveConfig.backend_info.bSupportsPartialMultisampleResolve) { - m_efb_resolve_color_texture->ResolveFromTexture(m_efb_color_texture.get(), clamped_region, - layer, 0); + for (u32 layer = 0; layer < GetEFBLayers(); layer++) + { + m_efb_resolve_color_texture->ResolveFromTexture(m_efb_color_texture.get(), clamped_region, + layer, 0); + } + } + else + { + m_efb_color_texture->FinishedRendering(); + g_renderer->BeginUtilityDrawing(); + g_renderer->SetAndDiscardFramebuffer(m_efb_color_resolve_framebuffer.get()); + g_renderer->SetPipeline(m_efb_color_resolve_pipeline.get()); + g_renderer->SetTexture(0, m_efb_color_texture.get()); + g_renderer->SetSamplerState(0, RenderState::GetPointSamplerState()); + g_renderer->SetViewportAndScissor(clamped_region); + g_renderer->Draw(0, 3); + m_efb_resolve_color_texture->FinishedRendering(); + g_renderer->EndUtilityDrawing(); } - m_efb_resolve_color_texture->FinishedRendering(); return m_efb_resolve_color_texture.get(); } @@ -487,6 +513,22 @@ bool FramebufferManager::CompileReadbackPipelines() m_efb_depth_resolve_pipeline = g_renderer->CreatePipeline(config); if (!m_efb_depth_resolve_pipeline) return false; + + if (!g_ActiveConfig.backend_info.bSupportsPartialMultisampleResolve) + { + config.framebuffer_state.color_texture_format = GetEFBColorFormat(); + auto color_resolve_shader = g_renderer->CreateShaderFromSource( + ShaderStage::Pixel, + FramebufferShaderGen::GenerateResolveColorPixelShader(GetEFBSamples()), + "Color resolve pixel shader"); + if (!color_resolve_shader) + return false; + + config.pixel_shader = color_resolve_shader.get(); + m_efb_color_resolve_pipeline = g_renderer->CreatePipeline(config); + if (!m_efb_color_resolve_pipeline) + return false; + } } // EFB restore pipeline diff --git a/Source/Core/VideoCommon/FramebufferManager.h b/Source/Core/VideoCommon/FramebufferManager.h index b9144f83ef..2d27fef09b 100644 --- a/Source/Core/VideoCommon/FramebufferManager.h +++ b/Source/Core/VideoCommon/FramebufferManager.h @@ -170,7 +170,9 @@ protected: std::unique_ptr m_efb_framebuffer; std::unique_ptr m_efb_convert_framebuffer; + std::unique_ptr m_efb_color_resolve_framebuffer; std::unique_ptr m_efb_depth_resolve_framebuffer; + std::unique_ptr m_efb_color_resolve_pipeline; std::unique_ptr m_efb_depth_resolve_pipeline; // Pipeline for restoring the contents of the EFB from a save state diff --git a/Source/Core/VideoCommon/FramebufferShaderGen.cpp b/Source/Core/VideoCommon/FramebufferShaderGen.cpp index 6426b259b4..49684bb518 100644 --- a/Source/Core/VideoCommon/FramebufferShaderGen.cpp +++ b/Source/Core/VideoCommon/FramebufferShaderGen.cpp @@ -338,6 +338,22 @@ std::string GenerateColorPixelShader() return code.GetBuffer(); } +std::string GenerateResolveColorPixelShader(u32 samples) +{ + ShaderCode code; + EmitSamplerDeclarations(code, 0, 1, true); + EmitPixelMainDeclaration(code, 1, 0); + code.Write("{{\n" + " int layer = int(v_tex0.z);\n" + " int3 coords = int3(int2(gl_FragCoord.xy), layer);\n" + " ocol0 = float4(0.0f);\n"); + code.Write(" for (int i = 0; i < {}; i++)\n", samples); + code.Write(" ocol0 += texelFetch(samp0, coords, i);\n"); + code.Write(" ocol0 /= {}.0f;\n", samples); + code.Write("}}\n"); + return code.GetBuffer(); +} + std::string GenerateResolveDepthPixelShader(u32 samples) { ShaderCode code; diff --git a/Source/Core/VideoCommon/FramebufferShaderGen.h b/Source/Core/VideoCommon/FramebufferShaderGen.h index 9d487f7a5a..8a6aac553f 100644 --- a/Source/Core/VideoCommon/FramebufferShaderGen.h +++ b/Source/Core/VideoCommon/FramebufferShaderGen.h @@ -15,6 +15,7 @@ std::string GenerateScreenQuadVertexShader(); std::string GeneratePassthroughGeometryShader(u32 num_tex, u32 num_colors); std::string GenerateTextureCopyVertexShader(); std::string GenerateTextureCopyPixelShader(); +std::string GenerateResolveColorPixelShader(u32 samples); std::string GenerateResolveDepthPixelShader(u32 samples); std::string GenerateClearVertexShader(); std::string GenerateEFBPokeVertexShader(); diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index 6ce7bed379..8de5d1e593 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -238,6 +238,7 @@ struct VideoConfig final bool bSupportsTextureQueryLevels = false; bool bSupportsLodBiasInSampler = false; bool bSupportsSettingObjectNames = false; + bool bSupportsPartialMultisampleResolve = false; } backend_info; // Utility