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:
TheThunderTurner
2026-10-11 20:10:47 +03:00
committed by GitHub
parent 8bafaa5aca
commit 995e37e4e7
3 changed files with 133 additions and 23 deletions
+34 -3
View File
@@ -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);
+65 -16
View File
@@ -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);
}
{
+34 -4
View File
@@ -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;
};