diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 084b7c34..620e5f10 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -102,9 +102,6 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) { continue; } - const bool is_clear = texture_cache.IsMetaCleared(col_buf.CmaskAddress()); - texture_cache.TouchMeta(col_buf.CmaskAddress(), false); - const auto& hint = liverpool->last_cb_extent[col_buf_id]; auto& [image_id, desc] = cb_descs.emplace_back(std::piecewise_construct, std::tuple{}, std::tuple{col_buf, hint}); @@ -113,6 +110,10 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) { auto& image = texture_cache.GetImage(image_id); image.binding.is_target = 1u; + const auto slice = image_view.info.range.base.layer; + const bool is_clear = texture_cache.IsMetaCleared(col_buf.CmaskAddress(), slice); + texture_cache.TouchMeta(col_buf.CmaskAddress(), slice, false); + const auto mip = image_view.info.range.base.level; state.width = std::min(state.width, std::max(image.info.size.width >> mip, 1u)); state.height = std::min(state.height, std::max(image.info.size.height >> mip, 1u)); @@ -134,8 +135,6 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) { (regs.depth_control.stencil_enable && regs.depth_buffer.stencil_info.format != StencilFormat::Invalid))) { const auto htile_address = regs.depth_htile_data_base.GetAddress(); - const bool is_clear = regs.depth_render_control.depth_clear_enable || - texture_cache.IsMetaCleared(htile_address); const auto& hint = liverpool->last_db_extent; auto& [image_id, desc] = db_desc.emplace(std::piecewise_construct, std::tuple{}, @@ -146,6 +145,11 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) { auto& image = texture_cache.GetImage(image_id); image.binding.is_target = 1u; + const auto slice = image_view.info.range.base.layer; + const bool is_clear = regs.depth_render_control.depth_clear_enable || + texture_cache.IsMetaCleared(htile_address, slice); + ASSERT(desc.view_info.range.extent.layers == 1); + state.width = std::min(state.width, image.info.size.width); state.height = std::min(state.height, image.info.size.height); state.depth_image = image.image; @@ -157,7 +161,7 @@ RenderState Rasterizer::PrepareRenderState(u32 mrt_mask) { .clearValue = vk::ClearValue{.depthStencil = {.depth = regs.depth_clear, .stencil = regs.stencil_clear}}, }; - texture_cache.TouchMeta(htile_address, false); + texture_cache.TouchMeta(htile_address, slice, false); state.has_depth = regs.depth_buffer.z_info.format != AmdGpu::Liverpool::DepthBuffer::ZFormat::Invalid; state.has_stencil = regs.depth_buffer.stencil_info.format != @@ -359,9 +363,11 @@ bool Rasterizer::BindResources(const Pipeline* pipeline) { // will need its full emulation anyways. For cases of metadata read a warning will be // logged. const auto IsMetaUpdate = [&](const auto& desc) { - const VAddr address = desc.GetSharp(info).base_address; + const auto sharp = desc.GetSharp(info); + const VAddr address = sharp.base_address; if (desc.is_written) { - if (texture_cache.TouchMeta(address, true)) { + // Assume all slices were updates + if (texture_cache.ClearMeta(address)) { LOG_TRACE(Render_Vulkan, "Metadata update skipped"); return true; } @@ -373,17 +379,36 @@ bool Rasterizer::BindResources(const Pipeline* pipeline) { return false; }; + // Assume if a shader reads and writes metas at the same time, it is a copy shader. + bool meta_read = false; for (const auto& desc : info.buffers) { if (desc.is_gds_buffer) { continue; } - if (IsMetaUpdate(desc)) { - return false; + if (!desc.is_written) { + const VAddr address = desc.GetSharp(info).base_address; + meta_read = texture_cache.IsMeta(address); } } + for (const auto& desc : info.texture_buffers) { - if (IsMetaUpdate(desc)) { - return false; + if (!desc.is_written) { + const VAddr address = desc.GetSharp(info).base_address; + meta_read = texture_cache.IsMeta(address); + } + } + + if (!meta_read) { + for (const auto& desc : info.buffers) { + if (IsMetaUpdate(desc)) { + return false; + } + } + + for (const auto& desc : info.texture_buffers) { + if (IsMetaUpdate(desc)) { + return false; + } } } } diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 4373fdc5..1670648b 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -398,17 +398,15 @@ ImageView& TextureCache::FindRenderTarget(BaseDesc& desc) { // Register meta data for this color buffer if (!(image.flags & ImageFlagBits::MetaRegistered)) { if (desc.info.meta_info.cmask_addr) { - surface_metas.emplace( - desc.info.meta_info.cmask_addr, - MetaDataInfo{.type = MetaDataInfo::Type::CMask, .is_cleared = true}); + surface_metas.emplace(desc.info.meta_info.cmask_addr, + MetaDataInfo{.type = MetaDataInfo::Type::CMask}); image.info.meta_info.cmask_addr = desc.info.meta_info.cmask_addr; image.flags |= ImageFlagBits::MetaRegistered; } if (desc.info.meta_info.fmask_addr) { - surface_metas.emplace( - desc.info.meta_info.fmask_addr, - MetaDataInfo{.type = MetaDataInfo::Type::FMask, .is_cleared = true}); + surface_metas.emplace(desc.info.meta_info.fmask_addr, + MetaDataInfo{.type = MetaDataInfo::Type::FMask}); image.info.meta_info.fmask_addr = desc.info.meta_info.fmask_addr; image.flags |= ImageFlagBits::MetaRegistered; } @@ -428,9 +426,8 @@ ImageView& TextureCache::FindDepthTarget(BaseDesc& desc) { // Register meta data for this depth buffer if (!(image.flags & ImageFlagBits::MetaRegistered)) { if (desc.info.meta_info.htile_addr) { - surface_metas.emplace( - desc.info.meta_info.htile_addr, - MetaDataInfo{.type = MetaDataInfo::Type::HTile, .is_cleared = true}); + surface_metas.emplace(desc.info.meta_info.htile_addr, + MetaDataInfo{.type = MetaDataInfo::Type::HTile}); image.info.meta_info.htile_addr = desc.info.meta_info.htile_addr; image.flags |= ImageFlagBits::MetaRegistered; } diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index fab4c832..676ede77 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -156,18 +156,31 @@ public: return surface_metas.contains(address); } - bool IsMetaCleared(VAddr address) const { + bool IsMetaCleared(VAddr address, u32 slice) const { const auto& it = surface_metas.find(address); if (it != surface_metas.end()) { - return it.value().is_cleared; + return it.value().clear_mask & (1u << slice); } return false; } - bool TouchMeta(VAddr address, bool is_clear) { + bool ClearMeta(VAddr address) { auto it = surface_metas.find(address); if (it != surface_metas.end()) { - it.value().is_cleared = is_clear; + it.value().clear_mask = u32(-1); + return true; + } + return false; + } + + bool TouchMeta(VAddr address, u32 slice, bool is_clear) { + auto it = surface_metas.find(address); + if (it != surface_metas.end()) { + if (is_clear) { + it.value().clear_mask |= 1u << slice; + } else { + it.value().clear_mask &= ~(1u << slice); + } return true; } return false; @@ -280,7 +293,7 @@ private: HTile, }; Type type; - bool is_cleared; + u32 clear_mask{u32(-1)}; }; tsl::robin_map surface_metas; };