graphics: preserve stencil view layers through uploads and clears

This commit is contained in:
nmzik
2026-10-04 02:26:19 +04:00
parent d890bb190c
commit 068d7621db
4 changed files with 142 additions and 11 deletions
+42 -10
View File
@@ -1037,6 +1037,8 @@ void TextureCache::UploadImage(Image& image, Buffer& source, uint64_t source_off
auto info = destination.info;
if (image.depth_id) {
info.data = image.info.data;
info.resources = {image.stencil_subresources.level_count,
image.stencil_subresources.layer_count};
info.guest_format = Prospero::BufferFormat::k8UInt;
info.bytes_per_block = 1;
if (info.IsTiled()) info.pitch = TileGetDepthPitch(info.extent.width, 1, 0);
@@ -1051,6 +1053,11 @@ void TextureCache::UploadImage(Image& image, Buffer& source, uint64_t source_off
auto copies = BuildDepthCopies(info, full_slice_size, image.depth_id
? vk::ImageAspectFlagBits::eStencil
: vk::ImageAspectFlagBits::eDepth);
if (image.depth_id) {
for (auto& copy: copies) {
copy.imageSubresource.baseArrayLayer += image.stencil_subresources.base_layer;
}
}
TileManager::Result linear {source.Handle(), source_offset, source.Size() - source_offset};
if (info.IsTiled()) {
const auto tiles = BuildDepthTiles(info);
@@ -1239,7 +1246,8 @@ ImageId TextureCache::AssociateStencil(ImageId depth_id, GuestRange stencil) {
}
auto& record = m_slot_images[association];
TouchImage(record);
record.depth_id = depth_id;
record.depth_id = depth_id;
record.stencil_subresources = depth.stencil_subresources;
return association;
}
@@ -1445,6 +1453,18 @@ vk::ImageView TextureCache::FindDepthTarget(ImageId id, const ImageDesc& desc) {
TouchImage(image);
image.MarkGpuModified();
image.usage.depth_target = true;
if (desc.info.HasStencil()) {
const auto layers = image.info.resources.layers;
EXIT_IF(layers == 0 || image.info.data.size % layers != 0 ||
desc.info.data.address < image.info.data.address);
const auto slice_size = image.info.data.size / layers;
const auto offset = desc.info.data.address - image.info.data.address;
EXIT_IF(slice_size == 0 || offset % slice_size != 0 || offset / slice_size >= layers ||
desc.info.resources.layers > layers - offset / slice_size);
image.stencil_subresources = {0, desc.info.resources.levels,
static_cast<uint32_t>(offset / slice_size),
desc.info.resources.layers};
}
image.info.stencil = desc.info.stencil;
image.info.metadata = desc.info.metadata;
if (desc.info.HasMetadata()) {
@@ -1491,9 +1511,11 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer& command, uint64_t address
if (command.IsInvalid() || !GuestRange {address, size}.Valid()) {
EXIT("TextureCache: invalid image clear\n");
}
std::scoped_lock lock {m_lock};
ImageId selected {};
vk::ImageAspectFlags aspect {};
std::scoped_lock lock {m_lock};
ImageId selected {};
ImageId stencil_id {};
vk::ImageAspectFlags aspect {};
ImageSubresourceRange subresources;
for (const auto id: FindImagesInRegion(address, size, false)) {
auto owner = m_slot_images.try_get(id);
if (owner == nullptr) {
@@ -1501,10 +1523,13 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer& command, uint64_t address
}
vk::ImageAspectFlags candidate {};
ImageId candidate_id = id;
ImageSubresourceRange candidate_subresources {
0, owner->info.resources.levels, 0, owner->info.TransferLayers()};
if (owner->depth_id && owner->info.data.address == address &&
owner->info.data.size == size) {
candidate = vk::ImageAspectFlagBits::eStencil;
candidate_id = owner->depth_id;
candidate = vk::ImageAspectFlagBits::eStencil;
candidate_id = owner->depth_id;
candidate_subresources = owner->stencil_subresources;
owner = m_slot_images.try_get(candidate_id);
if (owner == nullptr || owner->backing.image == nullptr || !owner->info.HasStencil()) {
continue;
@@ -1517,11 +1542,13 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer& command, uint64_t address
if (!candidate) {
continue;
}
if (selected && selected != candidate_id) {
if (selected && (selected != candidate_id || subresources != candidate_subresources)) {
return false;
}
selected = candidate_id;
aspect = candidate;
selected = candidate_id;
stencil_id = candidate == vk::ImageAspectFlagBits::eStencil ? id : ImageId {};
aspect = candidate;
subresources = candidate_subresources;
}
if (!selected) {
return false;
@@ -1543,7 +1570,12 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer& command, uint64_t address
clear.depthStencil.stencil = stencil_clear;
}
ClearImage(command, selected, image.backing.format,
{aspect, 0, image.info.resources.levels, 0, image.info.TransferLayers()}, clear);
{aspect, subresources.base_level, subresources.level_count,
subresources.base_layer, subresources.layer_count}, clear);
if (stencil_id) {
TrackImage(stencil_id);
CommitGpuWrite(m_slot_images[stencil_id]);
}
return true;
}
@@ -673,7 +673,9 @@ Prospero::BufferFormat RenderTargetTransferFormat(uint32_t bytes_per_element) {
} // namespace ImageOps
Image::Image(GraphicContext& graphics, CommandScheduler& scheduler, const ImageInfo& image_info)
: info(image_info), m_graphics(graphics), m_scheduler(scheduler) {
: info(image_info),
stencil_subresources {0, image_info.resources.levels, 0, image_info.resources.layers},
m_graphics(graphics), m_scheduler(scheduler) {
KYTY_PROFILER_FUNCTION();
ImageOps::Validate(info);
m_cpu_dirty =
@@ -148,6 +148,8 @@ public:
uint64_t track_addr = 0;
uint64_t track_addr_end = 0;
ImageId depth_id {};
// The current stencil plane's mapping into the depth image, also retained by its association.
ImageSubresourceRange stencil_subresources;
uint64_t tick_accessed_last = 0;
size_t lru_id = 0;