mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-10-12 02:22:27 +00:00
Read CMask metadata (#5046)
* logging * WIP * handle register/unregister * remove debugging * i hope clang is ok now * clang >:( * function changed name * clang complain * clang complain
This commit is contained in:
@@ -25,6 +25,24 @@ namespace VideoCore {
|
||||
static constexpr size_t GDS_BUFFER_SIZE = 64_KB;
|
||||
static constexpr size_t NULL_INDEX_BUFFER_SIZE = 16;
|
||||
static constexpr size_t STREAM_BUFFER_SIZE = 128_MB;
|
||||
constexpr std::optional<u32> CmaskColorExpandedValue(u32 num_samples) {
|
||||
switch (num_samples) {
|
||||
case 1:
|
||||
return 0xFFFFFFFF;
|
||||
case 2:
|
||||
return 0xDDDDDDDD;
|
||||
case 4:
|
||||
return 0xEEEEEEEE;
|
||||
case 8:
|
||||
return 0xFFFFFFFF;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static_assert(CmaskColorExpandedValue(1) == 0xFFFFFFFF);
|
||||
static_assert(CmaskColorExpandedValue(2) == 0xDDDDDDDD);
|
||||
static_assert(CmaskColorExpandedValue(4) == 0xEEEEEEEE);
|
||||
static_assert(CmaskColorExpandedValue(8) == 0xFFFFFFFF);
|
||||
|
||||
static constexpr auto ARENA_USAGE =
|
||||
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst |
|
||||
@@ -361,13 +379,26 @@ bool BufferCache::SynchronizeMemory(const Buffer* arena, VAddr device_addr, u32
|
||||
}
|
||||
|
||||
bool BufferCache::SynchronizeMemoryFromImage(const Buffer* arena, VAddr device_addr, u32 size) {
|
||||
if (auto type = texture_cache.IsMeta(device_addr)) {
|
||||
if (*type == TextureCache::MetaType::HTile) {
|
||||
if (const auto meta = texture_cache.GetMetaInfo(device_addr)) {
|
||||
if (meta->type == TextureCache::MetaType::HTile) {
|
||||
static constexpr u32 ZmaskUncompressed = 0xf;
|
||||
runtime.FillBuffer(arena, arena->Offset(device_addr), size, ZmaskUncompressed);
|
||||
return true;
|
||||
} else if (meta->type == TextureCache::MetaType::CMask) {
|
||||
const auto expanded_value = CmaskColorExpandedValue(meta->num_samples);
|
||||
if (!expanded_value) {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Unsupported CMask sample count: address={:#x}, size={:#x}, "
|
||||
"samples={}, owner={}:{}",
|
||||
device_addr, size, meta->num_samples, meta->owner_id.index,
|
||||
meta->owner_uid);
|
||||
return false;
|
||||
}
|
||||
runtime.FillBuffer(arena, arena->Offset(device_addr), size, *expanded_value);
|
||||
return true;
|
||||
} else {
|
||||
LOG_WARNING(Render_Vulkan, "Unhandled metadata type {}", magic_enum::enum_name(*type));
|
||||
LOG_WARNING(Render_Vulkan, "Unhandled metadata type {}",
|
||||
magic_enum::enum_name(meta->type));
|
||||
}
|
||||
}
|
||||
const ImageId image_id = texture_cache.FindImageFromRange(device_addr, size);
|
||||
|
||||
@@ -639,6 +639,31 @@ ImageView& TextureCache::FindTexture(ImageId image_id, const ImageDesc& desc) {
|
||||
return image.FindView(desc.view_info);
|
||||
}
|
||||
|
||||
void TextureCache::RegisterMeta(VAddr address, MetaDataInfo info) {
|
||||
const auto it = surface_metas.find(address);
|
||||
if (it == surface_metas.end()) {
|
||||
surface_metas.emplace(address, info);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& registered = it->second;
|
||||
if (registered.type != info.type || registered.owner_uid != info.owner_uid) {
|
||||
registered = info;
|
||||
return;
|
||||
}
|
||||
|
||||
// Preserve the current clear state when the same render target is rebound.
|
||||
registered.owner_id = info.owner_id;
|
||||
registered.num_samples = info.num_samples;
|
||||
}
|
||||
|
||||
void TextureCache::UnregisterMeta(VAddr address, u64 owner_uid) {
|
||||
const auto it = surface_metas.find(address);
|
||||
if (it != surface_metas.end() && it->second.owner_uid == owner_uid) {
|
||||
surface_metas.erase(address);
|
||||
}
|
||||
}
|
||||
|
||||
ImageView& TextureCache::FindRenderTarget(ImageId image_id, const ImageDesc& desc) {
|
||||
Image& image = slot_images[image_id];
|
||||
image.flags |= ImageFlagBits::GpuModified;
|
||||
@@ -650,16 +675,32 @@ ImageView& TextureCache::FindRenderTarget(ImageId image_id, const ImageDesc& des
|
||||
UpdateImage(image_id);
|
||||
|
||||
// Register meta data for this color buffer
|
||||
if (desc.info.meta_info.cmask_addr) {
|
||||
surface_metas.emplace(desc.info.meta_info.cmask_addr,
|
||||
MetaDataInfo{.type = MetaType::CMask});
|
||||
image.info.meta_info.cmask_addr = desc.info.meta_info.cmask_addr;
|
||||
const VAddr cmask_addr = desc.info.meta_info.cmask_addr;
|
||||
if (image.info.meta_info.cmask_addr != cmask_addr) {
|
||||
UnregisterMeta(image.info.meta_info.cmask_addr, image.image_uid);
|
||||
image.info.meta_info.cmask_addr = cmask_addr;
|
||||
}
|
||||
if (cmask_addr) {
|
||||
RegisterMeta(cmask_addr, MetaDataInfo{
|
||||
.type = MetaType::CMask,
|
||||
.owner_id = image_id,
|
||||
.owner_uid = image.image_uid,
|
||||
.num_samples = image.info.num_samples,
|
||||
});
|
||||
}
|
||||
|
||||
if (desc.info.meta_info.fmask_addr) {
|
||||
surface_metas.emplace(desc.info.meta_info.fmask_addr,
|
||||
MetaDataInfo{.type = MetaType::FMask});
|
||||
image.info.meta_info.fmask_addr = desc.info.meta_info.fmask_addr;
|
||||
const VAddr fmask_addr = desc.info.meta_info.fmask_addr;
|
||||
if (image.info.meta_info.fmask_addr != fmask_addr) {
|
||||
UnregisterMeta(image.info.meta_info.fmask_addr, image.image_uid);
|
||||
image.info.meta_info.fmask_addr = fmask_addr;
|
||||
}
|
||||
if (fmask_addr) {
|
||||
RegisterMeta(fmask_addr, MetaDataInfo{
|
||||
.type = MetaType::FMask,
|
||||
.owner_id = image_id,
|
||||
.owner_uid = image.image_uid,
|
||||
.num_samples = image.info.num_samples,
|
||||
});
|
||||
}
|
||||
|
||||
return image.FindView(desc.view_info, false);
|
||||
@@ -672,11 +713,19 @@ ImageView& TextureCache::FindDepthTarget(ImageId image_id, const ImageDesc& desc
|
||||
UpdateImage(image_id);
|
||||
|
||||
// Register meta data for this depth buffer
|
||||
if (desc.info.meta_info.htile_addr) {
|
||||
surface_metas.emplace(desc.info.meta_info.htile_addr,
|
||||
MetaDataInfo{.type = MetaType::HTile,
|
||||
.clear_mask = image.info.meta_info.htile_clear_mask});
|
||||
image.info.meta_info.htile_addr = desc.info.meta_info.htile_addr;
|
||||
const VAddr htile_addr = desc.info.meta_info.htile_addr;
|
||||
if (image.info.meta_info.htile_addr != htile_addr) {
|
||||
UnregisterMeta(image.info.meta_info.htile_addr, image.image_uid);
|
||||
image.info.meta_info.htile_addr = htile_addr;
|
||||
}
|
||||
if (htile_addr) {
|
||||
RegisterMeta(htile_addr, MetaDataInfo{
|
||||
.type = MetaType::HTile,
|
||||
.owner_id = image_id,
|
||||
.owner_uid = image.image_uid,
|
||||
.num_samples = image.info.num_samples,
|
||||
.clear_mask = image.info.meta_info.htile_clear_mask,
|
||||
});
|
||||
}
|
||||
|
||||
AssociateStencil(image_id, desc.info);
|
||||
@@ -1036,13 +1085,13 @@ void TextureCache::DeleteImage(ImageId image_id) {
|
||||
// Remove any registered meta areas.
|
||||
const auto& meta_info = image.info.meta_info;
|
||||
if (meta_info.cmask_addr) {
|
||||
surface_metas.erase(meta_info.cmask_addr);
|
||||
UnregisterMeta(meta_info.cmask_addr, image.image_uid);
|
||||
}
|
||||
if (meta_info.fmask_addr) {
|
||||
surface_metas.erase(meta_info.fmask_addr);
|
||||
UnregisterMeta(meta_info.fmask_addr, image.image_uid);
|
||||
}
|
||||
if (meta_info.htile_addr) {
|
||||
surface_metas.erase(meta_info.htile_addr);
|
||||
UnregisterMeta(meta_info.htile_addr, image.image_uid);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -4,8 +4,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
#include <absl/container/flat_hash_set.h>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <queue>
|
||||
#include <tsl/robin_map.h>
|
||||
|
||||
#include "common/lru_cache.h"
|
||||
#include "common/multi_level_page_table.h"
|
||||
@@ -198,6 +204,31 @@ public:
|
||||
HTile,
|
||||
};
|
||||
|
||||
struct MetaDataInfo {
|
||||
MetaType type;
|
||||
ImageId owner_id{};
|
||||
u64 owner_uid{};
|
||||
u32 num_samples = 1;
|
||||
s32 clear_mask = -1;
|
||||
};
|
||||
|
||||
/// Returns metadata information if the specified address belongs to a live image.
|
||||
std::optional<MetaDataInfo> GetMetaInfo(VAddr address) const {
|
||||
const auto it = surface_metas.find(address);
|
||||
if (it == surface_metas.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto& meta = it->second;
|
||||
if (!meta.owner_id || !slot_images.IsAllocated(meta.owner_id)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto& owner = slot_images[meta.owner_id];
|
||||
if (owner.image_uid != meta.owner_uid || False(owner.flags & ImageFlagBits::Registered)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
/// Returns meta type if the specified address is a metadata surface.
|
||||
std::optional<MetaType> IsMeta(VAddr address) const {
|
||||
auto it = surface_metas.find(address);
|
||||
@@ -330,6 +361,9 @@ private:
|
||||
|
||||
void MarkAsMaybeDirty(ImageId image_id, Image& image);
|
||||
|
||||
void RegisterMeta(VAddr address, MetaDataInfo info);
|
||||
void UnregisterMeta(VAddr address, u64 owner_uid);
|
||||
|
||||
/// Removes the image and any views/surface metas that reference it.
|
||||
void DeleteImage(ImageId image_id);
|
||||
|
||||
@@ -379,10 +413,6 @@ private:
|
||||
Common::LRUCache<Sampler> sampler_lru_cache;
|
||||
const bool readback_linear_images;
|
||||
std::mutex download_images_mutex;
|
||||
struct MetaDataInfo {
|
||||
MetaType type;
|
||||
s32 clear_mask = -1;
|
||||
};
|
||||
absl::flat_hash_map<VAddr, MetaDataInfo> surface_metas;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user