mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-20 19:44:46 +00:00
texture_cache: metadata registration
This commit is contained in:
parent
9f600dfab3
commit
ac6a60d809
5 changed files with 101 additions and 12 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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{};
|
||||
|
|
Loading…
Add table
Reference in a new issue