video_core: check if depth image is valid before using it (#4479)

* check if depth image is valid before using it

* fix uid usage
This commit is contained in:
Lander Gallastegi 2026-05-27 13:49:34 +02:00 committed by GitHub
parent f1873bb1d8
commit 2ff3487dbc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 62 additions and 7 deletions

View File

@ -741,6 +741,7 @@ set(COMMON src/common/logging/classes.h
src/common/elf_info.h
src/common/endian.h
src/common/enum.h
src/common/incremental_id.h
src/common/io_file.cpp
src/common/io_file.h
src/common/lru_cache.h

View File

@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
namespace Common {
template <typename CounterType>
class IncrementalIdProvider {
public:
IncrementalIdProvider() : counter(0) {}
~IncrementalIdProvider() = default;
CounterType Next() {
return counter.fetch_add(1, std::memory_order_relaxed) + 1;
}
private:
std::atomic<CounterType> counter;
};
} // namespace Common

View File

@ -702,10 +702,10 @@ void Rasterizer::BindTextures(const Shader::Info& stage, Shader::Backend::Bindin
image_id = texture_cache.FindImage(desc);
auto* image = &texture_cache.GetImage(image_id);
if (image->depth_id) {
if (auto depth_image_id = texture_cache.GetAssociatedDepth(*image)) {
// If this image has an associated depth image, it's a stencil attachment.
// Redirect the access to the actual depth-stencil buffer.
image_id = image->depth_id;
image_id = depth_image_id;
image = &texture_cache.GetImage(image_id);
}
if (image->binding.is_bound) {

View File

@ -15,6 +15,8 @@ namespace VideoCore {
using namespace Vulkan;
Common::IncrementalIdProvider<u64> Image::global_image_uid{};
static vk::ImageUsageFlags ImageUsageFlags(const Vulkan::Instance* instance,
const ImageInfo& info) {
vk::ImageUsageFlags usage = vk::ImageUsageFlagBits::eTransferSrc |
@ -119,6 +121,7 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
if (info.pixel_format == vk::Format::eUndefined) {
return;
}
image_uid = global_image_uid.Next();
mip_hashes.resize(info.resources.levels);
// Here we force `eExtendedUsage` as don't know all image usage cases beforehand. In normal case
// the texture cache should re-create the resource with the usage requested

View File

@ -4,6 +4,7 @@
#pragma once
#include "common/enum.h"
#include "common/incremental_id.h"
#include "common/types.h"
#include "video_core/renderer_vulkan/vk_common.h"
#include "video_core/texture_cache/image_info.h"
@ -111,8 +112,14 @@ struct Image {
return True(flags & ImageFlagBits::GpuModified) && False(flags & (ImageFlagBits::Dirty));
}
void AssociateDepth(ImageId image_id) {
depth_id = image_id;
void AssociateDepth(ImageId depth_image_id, u64 depth_image_uid) {
depth_id = depth_image_id;
depth_uid = depth_image_uid;
}
void DisassociateDepth() {
depth_id = {};
depth_uid = {};
}
ImageView& FindView(const ImageViewInfo& view_info, bool ensure_guest_samples = true);
@ -149,6 +156,7 @@ public:
VAddr track_addr = 0;
VAddr track_addr_end = 0;
ImageId depth_id{};
u64 depth_uid{};
// Resource state tracking
vk::ImageUsageFlags usage_flags;
@ -169,6 +177,7 @@ public:
std::deque<BackingImage> backing_images;
BackingImage* backing{};
boost::container::static_vector<u64, 16> mip_hashes{};
u64 image_uid{};
u64 lru_id{};
u64 tick_accessed_last{};
u64 hash{};
@ -187,6 +196,9 @@ public:
u32 needs_rebind : 1;
u32 force_general : 1;
} binding{};
private:
static Common::IncrementalIdProvider<u64> global_image_uid;
};
} // namespace VideoCore

View File

@ -708,9 +708,9 @@ ImageView& TextureCache::FindDepthTarget(ImageId image_id, const ImageDesc& desc
slot_images.insert(instance, scheduler, blit_helper, slot_image_views, info);
RegisterImage(stencil_id);
}
Image& image = slot_images[stencil_id];
TouchImage(image);
image.AssociateDepth(image_id);
Image& stencil_image = slot_images[stencil_id];
TouchImage(stencil_image);
stencil_image.AssociateDepth(image_id, image.image_uid);
}
return image.FindView(desc.view_info, false);

View File

@ -152,6 +152,23 @@ public:
return slot_image_views[id];
}
/// Get the associated depth stencil image if it is still valid.
ImageId GetAssociatedDepth(Image& image) {
if (!image.depth_id) {
return {};
}
if (slot_images.is_allocated(image.depth_id)) {
auto& depth_image = slot_images[image.depth_id];
if (depth_image.image_uid == image.depth_uid &&
depth_image.flags & ImageFlagBits::Registered) {
return image.depth_id;
}
}
// The linked depth image is no longer valid, disassociate it.
image.DisassociateDepth();
return {};
}
/// Returns true if the specified address is a metadata surface.
bool IsMeta(VAddr address) const {
return surface_metas.contains(address);