mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-25 12:26:51 +01:00
texture cache: select color-metadata clears on the GPU with conditional rendering
This commit is contained in:
@@ -174,6 +174,7 @@ bool BufferCache::DownloadBufferMemory(Buffer& buffer, uint64_t vaddr, uint64_t
|
||||
total_size += Common::AlignUp(end - start, 64);
|
||||
});
|
||||
m_gpu_modified_ranges.Subtract(address, bytes);
|
||||
ForgetColorMetadataChecks(address, bytes);
|
||||
});
|
||||
if (copies.empty()) {
|
||||
return false;
|
||||
@@ -519,6 +520,7 @@ std::pair<Buffer*, uint64_t> BufferCache::ObtainBuffer(uint64_t vaddr, uint64_t
|
||||
(void)SynchronizeBuffer(buffer, vaddr, size, is_written, is_texel_buffer);
|
||||
if (is_written) {
|
||||
m_gpu_modified_ranges.Add(vaddr, size);
|
||||
ForgetColorMetadataChecks(vaddr, size);
|
||||
}
|
||||
return {&buffer, buffer.Offset(vaddr)};
|
||||
}
|
||||
@@ -623,6 +625,29 @@ bool BufferCache::IsRegionRegistered(uint64_t vaddr, uint64_t size) {
|
||||
return address + m_slot_buffers[id].Size() > vaddr;
|
||||
}
|
||||
|
||||
void BufferCache::MarkColorMetadataChecked(uint64_t vaddr, uint64_t size, uint32_t keys) {
|
||||
for (uint32_t slot = 0; slot < m_checked_color_metadata.size(); slot++) {
|
||||
if ((keys & (1u << slot)) != 0) {
|
||||
m_checked_color_metadata[slot].Add(vaddr, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BufferCache::IsColorMetadataChecked(uint64_t vaddr, uint64_t size, uint32_t keys) const {
|
||||
for (uint32_t slot = 0; slot < m_checked_color_metadata.size(); slot++) {
|
||||
if ((keys & (1u << slot)) != 0 && !m_checked_color_metadata[slot].Contains(vaddr, size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BufferCache::ForgetColorMetadataChecks(uint64_t vaddr, uint64_t size) {
|
||||
for (auto& checked: m_checked_color_metadata) {
|
||||
checked.Subtract(vaddr, size);
|
||||
}
|
||||
}
|
||||
|
||||
bool BufferCache::IsRegionGpuModified(uint64_t vaddr, uint64_t size) {
|
||||
return m_memory_tracker.IsRegionGpuModified(vaddr, size);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "graphics/host_gpu/renderer/cache/multiLevelPageTable.h"
|
||||
#include "graphics/host_gpu/renderer/cache/streamBuffer.h"
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
@@ -79,6 +80,10 @@ public:
|
||||
[[nodiscard]] bool HasGpuDirtyBytes(uint64_t vaddr, uint64_t size);
|
||||
[[nodiscard]] bool IsRegionCpuModified(uint64_t vaddr, uint64_t size);
|
||||
[[nodiscard]] bool IsRegionGpuModified(uint64_t vaddr, uint64_t size);
|
||||
// Color metadata the GPU found free of the clear keys in `keys` (bits of code >> 5) stays so
|
||||
// until a GPU write or download.
|
||||
void MarkColorMetadataChecked(uint64_t vaddr, uint64_t size, uint32_t keys);
|
||||
[[nodiscard]] bool IsColorMetadataChecked(uint64_t vaddr, uint64_t size, uint32_t keys) const;
|
||||
void ProcessFaultBuffer();
|
||||
void SynchronizeBda(const RangeSet& mapped);
|
||||
void QueueBdaSync(uint64_t vaddr, uint64_t size) {
|
||||
@@ -124,6 +129,7 @@ private:
|
||||
// Synchronous downloads publish before returning; asynchronous callers wait before reuse.
|
||||
template <bool async>
|
||||
[[nodiscard]] bool DownloadBufferMemory(Buffer& buffer, uint64_t vaddr, uint64_t size);
|
||||
void ForgetColorMetadataChecks(uint64_t vaddr, uint64_t size);
|
||||
|
||||
GraphicContext& m_graphics;
|
||||
CommandScheduler& m_scheduler;
|
||||
@@ -135,6 +141,8 @@ private:
|
||||
BufferMap m_buffers;
|
||||
PageTable m_page_table;
|
||||
RangeSet m_gpu_modified_ranges;
|
||||
// One per TileManager::ColorClearSlots key slot.
|
||||
std::array<RangeSet, 8> m_checked_color_metadata;
|
||||
MemoryTracker m_memory_tracker;
|
||||
StreamBuffer m_staging_buffer;
|
||||
StreamBuffer m_stream_buffer;
|
||||
|
||||
+69
-5
@@ -1067,15 +1067,78 @@ void TextureCache::MaterializeColorClear(ImageId id, const ImageDesc& desc,
|
||||
if (first >= layers || count > layers - first) {
|
||||
EXIT("TextureCache: color view exceeds its native metadata slices\n");
|
||||
}
|
||||
// Finish native metadata writes before reading backing bytes. This can submit the scheduler,
|
||||
// so discovery runs before final draw uploads and never holds the texture lock across it.
|
||||
if (m_buffer_cache.IsRegionGpuModified(range.address, range.size)) {
|
||||
const auto slice_size = range.size / layers;
|
||||
const GuestRange viewed {range.address + slice_size * first, slice_size * count};
|
||||
if (m_buffer_cache.IsRegionGpuModified(viewed.address, viewed.size)) {
|
||||
std::array<vk::ClearAttachment, TileManager::ColorClearSlots> clears {};
|
||||
uint32_t keys = 0;
|
||||
for (uint32_t key = 0; key < clears.size(); key++) {
|
||||
clears[key].aspectMask = vk::ImageAspectFlagBits::eColor;
|
||||
if (DecodeColorClear(desc, static_cast<uint8_t>(key << 5u),
|
||||
clears[key].clearValue.color)) {
|
||||
keys |= 1u << key;
|
||||
}
|
||||
}
|
||||
// No selected key to clear, or none left since the last check.
|
||||
if (m_buffer_cache.IsColorMetadataChecked(viewed.address, viewed.size, keys)) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock {m_lock};
|
||||
auto& image = m_slot_images[id];
|
||||
// Compressed images cannot upload, so they must already hold native contents.
|
||||
const bool native_current = (image.usage.render_target || image.IsGpuModified()) &&
|
||||
!image.IsBufferModified() && !image.IsCpuDirty();
|
||||
// 2D-array attachment views select 2D layers or, of a volume, depth slices.
|
||||
if (m_graphics.conditional_rendering_enabled &&
|
||||
image.backing.image_type != vk::ImageType::e1D &&
|
||||
count <= m_graphics.GetPhysicalDeviceProperties().limits.maxFramebufferLayers &&
|
||||
(image.backing.usage & vk::ImageUsageFlagBits::eColorAttachment) &&
|
||||
(m_graphics.GetFormatProperties(view.format).optimalTilingFeatures &
|
||||
vk::FormatFeatureFlagBits::eColorAttachment) &&
|
||||
(desc.info.metadata.compression == VideoOutCompression::Uncompressed ||
|
||||
native_current)) {
|
||||
// The GPU selects each slice's clear, so the CPU never waits for the metadata.
|
||||
Common::DebugCounters::Add(Common::DebugCounters::Counter::ColorMetadataChecks);
|
||||
InitializeImage(id);
|
||||
const bool expand = desc.type != BindingType::VideoOut;
|
||||
const auto [buffer, offset] =
|
||||
m_buffer_cache.ObtainBuffer(viewed.address, viewed.size, expand);
|
||||
const auto predicates = m_tiler.CheckColorClear(
|
||||
{buffer->Handle(), offset, viewed.size}, count, keys, expand);
|
||||
if (expand) {
|
||||
m_buffer_cache.MarkColorMetadataChecked(viewed.address, viewed.size, keys);
|
||||
}
|
||||
const auto command = m_scheduler.Current().Handle();
|
||||
const auto area = BeginColorRendering(image, view.format, view.base_level,
|
||||
image_first, count, nullptr, command);
|
||||
vk::ClearRect rect {.rect = area, .layerCount = 1};
|
||||
for (uint32_t slice = 0; slice < count; slice++) {
|
||||
rect.baseArrayLayer = slice;
|
||||
for (uint32_t key = 0; key < clears.size(); key++) {
|
||||
if ((keys & (1u << key)) != 0) {
|
||||
const vk::ConditionalRenderingBeginInfoEXT predicate {
|
||||
.buffer = predicates,
|
||||
.offset = (slice * clears.size() + key) * sizeof(uint32_t)};
|
||||
command.beginConditionalRenderingEXT(&predicate);
|
||||
command.clearAttachments(1, &clears[key], 1, &rect);
|
||||
command.endConditionalRenderingEXT();
|
||||
}
|
||||
}
|
||||
}
|
||||
command.endRendering();
|
||||
CommitGpuWrite(image);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Finish native metadata writes before reading backing bytes. This can submit the
|
||||
// scheduler, so discovery runs before final draw uploads and never holds the texture
|
||||
// lock across it.
|
||||
Common::DebugCounters::ScopedTimer timer(
|
||||
Common::DebugCounters::Counter::ColorMetadataReadbacks,
|
||||
Common::DebugCounters::Counter::ColorMetadataReadbackNs);
|
||||
m_buffer_cache.ReadMemory(range.address, range.size, false);
|
||||
m_buffer_cache.ReadMemory(viewed.address, viewed.size, false);
|
||||
}
|
||||
const auto slice_size = range.size / layers;
|
||||
for (uint32_t slice = 0; slice < count; slice++) {
|
||||
const auto address = range.address + slice_size * (first + slice);
|
||||
uint8_t code = 0;
|
||||
@@ -1768,6 +1831,7 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uin
|
||||
copy_size != image.info.data.size)) {
|
||||
return false;
|
||||
}
|
||||
ForgetColorMetadataChecks(image.info.data.address, copy_size);
|
||||
m_texture_cache.DownloadImage(image, buffer, buf_offset, copy_size, levels);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user