texture_cache: Improve support for stencil reads

This commit is contained in:
IndecisiveTurtle 2024-12-13 01:17:54 +02:00
parent 3f1061de56
commit ef81d72836
8 changed files with 48 additions and 9 deletions

View File

@ -431,6 +431,10 @@ struct Liverpool {
return u64(z_read_base) << 8; return u64(z_read_base) << 8;
} }
u64 StencilAddress() const {
return u64(stencil_read_base) << 8;
}
u32 NumSamples() const { u32 NumSamples() const {
return 1u << z_info.num_samples; // spec doesn't say it is a log2 return 1u << z_info.num_samples; // spec doesn't say it is a log2
} }

View File

@ -616,18 +616,24 @@ void Rasterizer::BindTextures(const Shader::Info& stage, Shader::Backend::Bindin
auto& [image_id, desc] = image_bindings.emplace_back(std::piecewise_construct, std::tuple{}, auto& [image_id, desc] = image_bindings.emplace_back(std::piecewise_construct, std::tuple{},
std::tuple{tsharp, image_desc}); std::tuple{tsharp, image_desc});
image_id = texture_cache.FindImage(desc); image_id = texture_cache.FindImage(desc);
auto& image = texture_cache.GetImage(image_id); auto* image = &texture_cache.GetImage(image_id);
if (image.binding.is_bound) { if (image->depth_id) {
// If this image has an associated depth image, it's a stencil attachment.
// Redirect the access to the actual depth-stencil buffer.
image_id = image->depth_id;
image = &texture_cache.GetImage(image_id);
}
if (image->binding.is_bound) {
// The image is already bound. In case if it is about to be used as storage we need // The image is already bound. In case if it is about to be used as storage we need
// to force general layout on it. // to force general layout on it.
image.binding.force_general |= image_desc.is_storage; image->binding.force_general |= image_desc.is_storage;
} }
if (image.binding.is_target) { if (image->binding.is_target) {
// The image is already bound as target. Since we read and output to it need to force // The image is already bound as target. Since we read and output to it need to force
// general layout too. // general layout too.
image.binding.force_general = 1u; image->binding.force_general = 1u;
} }
image.binding.is_bound = 1u; image->binding.is_bound = 1u;
} }
// Second pass to re-bind images that were updated after binding // Second pass to re-bind images that were updated after binding

View File

@ -145,8 +145,10 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
const ImageInfo& info_) const ImageInfo& info_)
: instance{&instance_}, scheduler{&scheduler_}, info{info_}, : instance{&instance_}, scheduler{&scheduler_}, info{info_},
image{instance->GetDevice(), instance->GetAllocator()} { image{instance->GetDevice(), instance->GetAllocator()} {
if (info.pixel_format == vk::Format::eUndefined) {
return;
}
mip_hashes.resize(info.resources.levels); mip_hashes.resize(info.resources.levels);
ASSERT(info.pixel_format != vk::Format::eUndefined);
// Here we force `eExtendedUsage` as don't know all image usage cases beforehand. In normal case // Here we force `eExtendedUsage` as don't know all image usage cases beforehand. In normal case
// the texture cache should re-create the resource with the usage requested // the texture cache should re-create the resource with the usage requested
vk::ImageCreateFlags flags{vk::ImageCreateFlagBits::eMutableFormat | vk::ImageCreateFlags flags{vk::ImageCreateFlagBits::eMutableFormat |

View File

@ -92,6 +92,12 @@ struct Image {
return image_view_ids[std::distance(image_view_infos.begin(), it)]; return image_view_ids[std::distance(image_view_infos.begin(), it)];
} }
void AssociateDepth(ImageId image_id) {
ASSERT_MSG(!depth_id || image_id == depth_id,
"Stencil attachment bound to multiple depth targets");
depth_id = image_id;
}
boost::container::small_vector<vk::ImageMemoryBarrier2, 32> GetBarriers( boost::container::small_vector<vk::ImageMemoryBarrier2, 32> GetBarriers(
vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits2> dst_mask, vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits2> dst_mask,
vk::PipelineStageFlags2 dst_stage, std::optional<SubresourceRange> subres_range); vk::PipelineStageFlags2 dst_stage, std::optional<SubresourceRange> subres_range);
@ -116,6 +122,7 @@ struct Image {
VAddr track_addr_end = 0; VAddr track_addr_end = 0;
std::vector<ImageViewInfo> image_view_infos; std::vector<ImageViewInfo> image_view_infos;
std::vector<ImageViewId> image_view_ids; std::vector<ImageViewId> image_view_ids;
ImageId depth_id{};
// Resource state tracking // Resource state tracking
struct { struct {

View File

@ -298,6 +298,9 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::DepthBuffer& buffer, u32 num_slice
resources.layers = num_slices; resources.layers = num_slices;
meta_info.htile_addr = buffer.z_info.tile_surface_en ? htile_address : 0; meta_info.htile_addr = buffer.z_info.tile_surface_en ? htile_address : 0;
stencil_addr = buffer.StencilAddress();
stencil_size = pitch * size.height * sizeof(u8);
guest_address = buffer.Address(); guest_address = buffer.Address();
const auto depth_slice_sz = buffer.GetDepthSliceSize(); const auto depth_slice_sz = buffer.GetDepthSliceSize();
guest_size_bytes = depth_slice_sz * num_slices; guest_size_bytes = depth_slice_sz * num_slices;

View File

@ -69,7 +69,7 @@ struct ImageInfo {
} props{}; // Surface properties with impact on various calculation factors } props{}; // Surface properties with impact on various calculation factors
vk::Format pixel_format = vk::Format::eUndefined; vk::Format pixel_format = vk::Format::eUndefined;
vk::ImageType type = vk::ImageType::e1D; vk::ImageType type = vk::ImageType::e2D;
SubresourceExtent resources; SubresourceExtent resources;
Extent3D size{1, 1, 1}; Extent3D size{1, 1, 1};
u32 num_bits{}; u32 num_bits{};

View File

@ -170,7 +170,7 @@ ImageView::ImageView(const Vulkan::Instance& instance, const ImageViewInfo& info
format = image.info.pixel_format; format = image.info.pixel_format;
aspect = vk::ImageAspectFlagBits::eDepth; aspect = vk::ImageAspectFlagBits::eDepth;
} }
if (image.aspect_mask & vk::ImageAspectFlagBits::eStencil && format == vk::Format::eR8Unorm) { if (image.aspect_mask & vk::ImageAspectFlagBits::eStencil && format == vk::Format::eR8Uint) {
format = image.info.pixel_format; format = image.info.pixel_format;
aspect = vk::ImageAspectFlagBits::eStencil; aspect = vk::ImageAspectFlagBits::eStencil;
} }

View File

@ -443,6 +443,23 @@ ImageView& TextureCache::FindDepthTarget(BaseDesc& desc) {
} }
} }
// If there is a stencil attachment, link depth and stencil.
if (desc.info.stencil_addr != 0) {
ImageId stencil_id{};
ForEachImageInRegion(desc.info.stencil_addr, desc.info.stencil_size,
[&](ImageId image_id, Image&) { stencil_id = image_id; });
if (!stencil_id) {
ImageInfo info{};
info.guest_address = desc.info.stencil_addr;
info.guest_size_bytes = desc.info.stencil_size;
info.size = desc.info.size;
stencil_id = slot_images.insert(instance, scheduler, info);
RegisterImage(stencil_id);
}
Image& image = slot_images[stencil_id];
image.AssociateDepth(image_id);
}
return RegisterImageView(image_id, desc.view_info); return RegisterImageView(image_id, desc.view_info);
} }