Browse Source

[vk] Fix user reported issue

pull/2724/head
Ribbit 5 months ago
committed by crueter
parent
commit
60fc5bb401
  1. 111
      src/video_core/renderer_vulkan/vk_texture_cache.cpp
  2. 23
      src/video_core/renderer_vulkan/vk_texture_cache.h

111
src/video_core/renderer_vulkan/vk_texture_cache.cpp

@ -917,14 +917,29 @@ bool TextureCacheRuntime::ShouldReinterpret(Image& dst, Image& src) {
} }
VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) { VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
const auto level = (8 * sizeof(size_t)) - std::countl_zero(needed_size - 1ULL);
if (buffers[level]) {
return *buffers[level];
const size_t safe_size = needed_size == 0 ? 1 : needed_size;
size_t level = 0;
if (safe_size > 1) {
level =
(8 * sizeof(size_t)) - std::countl_zero(static_cast<unsigned long long>(safe_size - 1));
} }
const auto new_size = Common::NextPow2(needed_size);
level = std::min(level, indexing_slots - 1);
auto& entry = temporary_buffers[level];
const size_t new_size = Common::NextPow2(safe_size);
auto& master_semaphore = scheduler.GetMasterSemaphore();
const u64 current_tick = master_semaphore.CurrentTick();
if (entry.buffer && entry.size >= new_size) {
entry.last_frame_used = temp_buffer_frame_index;
entry.last_tick_used = current_tick;
return *entry.buffer;
}
static constexpr VkBufferUsageFlags flags = static constexpr VkBufferUsageFlags flags =
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT; VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
const VkBufferCreateInfo temp_ci = { const VkBufferCreateInfo temp_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
@ -935,8 +950,14 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
.queueFamilyIndexCount = 0, .queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr, .pQueueFamilyIndices = nullptr,
}; };
buffers[level] = memory_allocator.CreateBuffer(temp_ci, MemoryUsage::DeviceLocal);
return *buffers[level];
entry.buffer = memory_allocator.CreateBuffer(temp_ci, MemoryUsage::DeviceLocal);
entry.size = new_size;
entry.last_frame_used = temp_buffer_frame_index;
entry.last_tick_used = current_tick;
TrimTemporaryBuffers();
return *entry.buffer;
} }
void TextureCacheRuntime::BarrierFeedbackLoop() { void TextureCacheRuntime::BarrierFeedbackLoop() {
@ -1501,11 +1522,85 @@ bool TextureCacheRuntime::CanReportMemoryUsage() const {
return device.CanReportMemoryUsage(); return device.CanReportMemoryUsage();
} }
void TextureCacheRuntime::TickFrame() {}
void TextureCacheRuntime::TickFrame() {
++temp_buffer_frame_index;
auto& master_semaphore = scheduler.GetMasterSemaphore();
master_semaphore.Refresh();
const u64 gpu_tick = master_semaphore.KnownGpuTick();
for (auto& entry : temporary_buffers) {
if (!entry.buffer) {
continue;
}
if (gpu_tick < entry.last_tick_used) {
continue;
}
const u64 age = temp_buffer_frame_index >= entry.last_frame_used
? temp_buffer_frame_index - entry.last_frame_used
: 0;
if (age > temp_buffer_retirement_frames) {
entry.buffer = {};
entry.size = 0;
entry.last_frame_used = 0;
entry.last_tick_used = 0;
}
}
TrimTemporaryBuffers();
}
void TextureCacheRuntime::TrimTemporaryBuffers() {
auto& master_semaphore = scheduler.GetMasterSemaphore();
master_semaphore.Refresh();
const u64 gpu_tick = master_semaphore.KnownGpuTick();
u64 total_size = 0;
for (const auto& entry : temporary_buffers) {
total_size += entry.size;
}
if (total_size <= temp_buffer_budget_bytes) {
return;
}
while (total_size > temp_buffer_budget_bytes) {
TemporaryBufferEntry* oldest = nullptr;
for (auto& entry : temporary_buffers) {
if (!entry.buffer) {
continue;
}
if (entry.last_frame_used == temp_buffer_frame_index) {
continue;
}
if (gpu_tick < entry.last_tick_used) {
continue;
}
const u64 age = temp_buffer_frame_index >= entry.last_frame_used
? temp_buffer_frame_index - entry.last_frame_used
: 0;
if (age < temp_buffer_min_lifetime_frames) {
continue;
}
if (!oldest || entry.last_frame_used < oldest->last_frame_used) {
oldest = &entry;
}
}
if (oldest == nullptr) {
break;
}
total_size -= static_cast<u64>(oldest->size);
oldest->buffer = {};
oldest->size = 0;
oldest->last_frame_used = 0;
oldest->last_tick_used = 0;
}
}
Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_, Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_,
VAddr cpu_addr_) VAddr cpu_addr_)
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler},
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.GetScheduler()},
runtime{&runtime_}, original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info, runtime{&runtime_}, original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info,
runtime->ViewFormats(info.format))), runtime->ViewFormats(info.format))),
aspect_mask(ImageAspectMask(info.format)) { aspect_mask(ImageAspectMask(info.format)) {

23
src/video_core/renderer_vulkan/vk_texture_cache.h

@ -102,6 +102,10 @@ public:
return true; return true;
} }
[[nodiscard]] Scheduler& GetScheduler() const noexcept {
return scheduler;
}
[[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size); [[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size);
std::span<const VkFormat> ViewFormats(PixelFormat format) { std::span<const VkFormat> ViewFormats(PixelFormat format) {
@ -115,6 +119,10 @@ public:
VkFormat GetSupportedFormat(VkFormat requested_format, VkFormatFeatureFlags required_features) const; VkFormat GetSupportedFormat(VkFormat requested_format, VkFormatFeatureFlags required_features) const;
private:
void TrimTemporaryBuffers();
public:
const Device& device; const Device& device;
Scheduler& scheduler; Scheduler& scheduler;
MemoryAllocator& memory_allocator; MemoryAllocator& memory_allocator;
@ -126,8 +134,21 @@ public:
const Settings::ResolutionScalingInfo& resolution; const Settings::ResolutionScalingInfo& resolution;
std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats; std::array<std::vector<VkFormat>, VideoCore::Surface::MaxPixelFormat> view_formats;
private:
struct TemporaryBufferEntry {
vk::Buffer buffer{};
size_t size{};
u64 last_frame_used{};
u64 last_tick_used{};
};
static constexpr size_t indexing_slots = 8 * sizeof(size_t); static constexpr size_t indexing_slots = 8 * sizeof(size_t);
std::array<vk::Buffer, indexing_slots> buffers{};
static constexpr u64 temp_buffer_retirement_frames = 120;
static constexpr u64 temp_buffer_budget_bytes = 256ULL * 1024ULL * 1024ULL;
static constexpr u64 temp_buffer_min_lifetime_frames = 2;
std::array<TemporaryBufferEntry, indexing_slots> temporary_buffers{};
u64 temp_buffer_frame_index{};
}; };
class Image : public VideoCommon::ImageBase { class Image : public VideoCommon::ImageBase {

Loading…
Cancel
Save