texture_cache: metadata registration

This commit is contained in:
psucien 2024-06-26 12:17:52 +02:00
parent 9f600dfab3
commit ac6a60d809
5 changed files with 101 additions and 12 deletions

View file

@ -352,7 +352,7 @@ struct Liverpool {
return u64(z_read_base) << 8;
}
[[nodiscard]] size_t GetSizeAligned() const {
size_t GetSizeAligned() const {
return depth_slice.tile_max * 8;
}
};
@ -688,11 +688,15 @@ struct Liverpool {
return u64(base_address) << 8;
}
u64 CmaskAddress() const {
return u64(cmask_base_address) << 8;
VAddr CmaskAddress() const {
return VAddr(cmask_base_address) << 8;
}
[[nodiscard]] size_t GetSizeAligned() const {
VAddr FmaskAddress() const {
return VAddr(fmask_base_address) << 8;
}
size_t GetSizeAligned() const {
const auto num_bytes_per_element = NumBits(info.format) / 8u;
const auto slice_size = (slice.tile_max + 1) * 64u;
const auto total_size = slice_size * (view.slice_max + 1) * num_bytes_per_element;
@ -700,11 +704,11 @@ struct Liverpool {
return total_size;
}
[[nodiscard]] TilingMode GetTilingMode() const {
TilingMode GetTilingMode() const {
return attrib.tile_mode_index;
}
[[nodiscard]] bool IsTiled() const {
bool IsTiled() const {
return !info.linear_general;
}

View file

@ -149,6 +149,8 @@ ImageInfo::ImageInfo(const AmdGpu::Liverpool::ColorBuffer& buffer,
size.depth = 1;
pitch = size.width;
guest_size_bytes = buffer.GetSizeAligned();
meta_info.cmask_addr = buffer.info.fast_clear ? buffer.CmaskAddress() : 0;
meta_info.fmask_addr = buffer.info.compression ? buffer.FmaskAddress() : 0;
usage.render_target = true;
}

View file

@ -25,11 +25,12 @@ VK_DEFINE_HANDLE(VmaAllocator)
namespace VideoCore {
enum ImageFlagBits : u32 {
CpuModified = 1 << 2, ///< Contents have been modified from the CPU
GpuModified = 1 << 3, ///< Contents have been modified from the GPU
Tracked = 1 << 4, ///< Writes and reads are being hooked from the CPU
Registered = 1 << 6, ///< True when the image is registered
Picked = 1 << 7, ///< Temporary flag to mark the image as picked
CpuModified = 1 << 2, ///< Contents have been modified from the CPU
GpuModified = 1 << 3, ///< Contents have been modified from the GPU
Tracked = 1 << 4, ///< Writes and reads are being hooked from the CPU
Registered = 1 << 6, ///< True when the image is registered
Picked = 1 << 7, ///< Temporary flag to mark the image as picked
MetaRegistered = 1 << 8, ///< True when metadata for this surface is known and registered
};
DECLARE_ENUM_FLAG_OPERATORS(ImageFlagBits)
@ -49,6 +50,12 @@ struct ImageInfo {
bool IsPacked() const;
bool IsDepthStencil() const;
struct {
VAddr cmask_addr{};
VAddr fmask_addr{};
VAddr htile_addr{};
} meta_info;
struct {
u32 texture : 1;
u32 storage : 1;
@ -58,7 +65,6 @@ struct ImageInfo {
} usage; // Usage data tracked during image lifetime
bool is_tiled = false;
bool is_storage = false;
vk::Format pixel_format = vk::Format::eUndefined;
vk::ImageType type = vk::ImageType::e1D;
SubresourceExtent resources;

View file

@ -131,6 +131,8 @@ Image& TextureCache::FindImage(const ImageInfo& info, VAddr cpu_address, bool re
image_id = image_ids[0];
}
RegisterMeta(info, image_id);
Image& image = slot_images[image_id];
if (True(image.flags & ImageFlagBits::CpuModified) &&
(!image_ids.empty() || refresh_on_create)) {
@ -283,6 +285,47 @@ void TextureCache::RegisterImage(ImageId image_id) {
[this, image_id](u64 page) { page_table[page].push_back(image_id); });
}
void TextureCache::RegisterMeta(const ImageInfo& info, ImageId image_id) {
Image& image = slot_images[image_id];
if (image.flags & ImageFlagBits::MetaRegistered) {
return;
}
bool registered = true;
// Current resource tracking implementation allows us to detect usage of meta only in the last
// moment, so we likely will miss its first clear. To avoid this and make first frame, where
// the meta is encountered, looks correct we set its state to "cleared" at registrations time.
if (info.usage.render_target) {
if (info.meta_info.cmask_addr) {
surface_metas.emplace(
info.meta_info.cmask_addr,
MetaDataInfo{.type = MetaDataInfo::Type::CMask, .is_cleared = true});
image.info.meta_info.cmask_addr = info.meta_info.cmask_addr;
}
if (info.meta_info.fmask_addr) {
surface_metas.emplace(
info.meta_info.fmask_addr,
MetaDataInfo{.type = MetaDataInfo::Type::FMask, .is_cleared = true});
image.info.meta_info.fmask_addr = info.meta_info.fmask_addr;
}
} else if (info.usage.depth_target) {
if (info.meta_info.htile_addr) {
surface_metas.emplace(
info.meta_info.htile_addr,
MetaDataInfo{.type = MetaDataInfo::Type::HTile, .is_cleared = true});
image.info.meta_info.htile_addr = info.meta_info.htile_addr;
}
} else {
registered = false;
}
if (registered) {
image.flags |= ImageFlagBits::MetaRegistered;
}
}
void TextureCache::UnregisterImage(ImageId image_id) {
Image& image = slot_images[image_id];
ASSERT_MSG(True(image.flags & ImageFlagBits::Registered),

View file

@ -29,6 +29,17 @@ class TextureCache {
static constexpr u64 PageBits = 20;
static constexpr u64 PageMask = (1ULL << PageBits) - 1;
struct MetaDataInfo {
enum class Type {
CMask,
FMask,
HTile,
};
Type type;
bool is_cleared;
};
public:
explicit TextureCache(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler);
~TextureCache();
@ -60,6 +71,25 @@ public:
return slot_images[id];
}
bool IsMeta(VAddr address) const {
return surface_metas.contains(address);
}
bool IsMetaCleared(VAddr address) const {
const auto& it = surface_metas.find(address);
if (it != surface_metas.end()) {
return it.value().is_cleared;
}
return false;
}
void TouchMeta(VAddr address, bool is_clear) {
auto it = surface_metas.find(address);
if (it != surface_metas.end()) {
it.value().is_cleared = is_clear;
}
}
private:
ImageView& RegisterImageView(Image& image, const ImageViewInfo& view_info);
@ -123,6 +153,9 @@ private:
/// Register image in the page table
void RegisterImage(ImageId image);
/// Register meta data surfaces attached to the image
void RegisterMeta(const ImageInfo& info, ImageId image);
/// Unregister image from the page table
void UnregisterImage(ImageId image);
@ -145,6 +178,7 @@ private:
tsl::robin_map<u64, Sampler> samplers;
tsl::robin_pg_map<u64, std::vector<ImageId>> page_table;
boost::icl::interval_map<VAddr, s32> cached_pages;
tsl::robin_map<VAddr, MetaDataInfo> surface_metas;
std::mutex mutex;
#ifdef _WIN64
void* veh_handle{};