Fence Manager: Force ordering on WFI.

This commit is contained in:
Fernando Sahmkow 2021-07-07 16:42:26 +02:00
parent 73638ca593
commit cf38faee9b
4 changed files with 71 additions and 38 deletions

View file

@ -152,6 +152,8 @@ public:
/// Return true when there are uncommitted buffers to be downloaded /// Return true when there are uncommitted buffers to be downloaded
[[nodiscard]] bool HasUncommittedFlushes() const noexcept; [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
void AccumulateFlushes();
/// Return true when the caller should wait for async downloads /// Return true when the caller should wait for async downloads
[[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept; [[nodiscard]] bool ShouldWaitAsyncFlushes() const noexcept;
@ -334,6 +336,7 @@ private:
std::vector<BufferId> cached_write_buffer_ids; std::vector<BufferId> cached_write_buffer_ids;
IntervalSet uncommitted_ranges; IntervalSet uncommitted_ranges;
std::deque<IntervalSet> committed_ranges;
size_t immediate_buffer_capacity = 0; size_t immediate_buffer_capacity = 0;
std::unique_ptr<u8[]> immediate_buffer_alloc; std::unique_ptr<u8[]> immediate_buffer_alloc;
@ -551,7 +554,19 @@ void BufferCache<P>::FlushCachedWrites() {
template <class P> template <class P>
bool BufferCache<P>::HasUncommittedFlushes() const noexcept { bool BufferCache<P>::HasUncommittedFlushes() const noexcept {
return !uncommitted_ranges.empty(); return !uncommitted_ranges.empty() || !committed_ranges.empty();
}
template <class P>
void BufferCache<P>::AccumulateFlushes() {
if (Settings::values.gpu_accuracy.GetValue() != Settings::GPUAccuracy::High) {
uncommitted_ranges.clear();
return;
}
if (uncommitted_ranges.empty()) {
return;
}
committed_ranges.emplace_back(std::move(uncommitted_ranges));
} }
template <class P> template <class P>
@ -561,8 +576,8 @@ bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
template <class P> template <class P>
void BufferCache<P>::CommitAsyncFlushesHigh() { void BufferCache<P>::CommitAsyncFlushesHigh() {
const IntervalSet& intervals = uncommitted_ranges; AccumulateFlushes();
if (intervals.empty()) { if (committed_ranges.empty()) {
return; return;
} }
MICROPROFILE_SCOPE(GPU_DownloadMemory); MICROPROFILE_SCOPE(GPU_DownloadMemory);
@ -570,43 +585,46 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads; boost::container::small_vector<std::pair<BufferCopy, BufferId>, 1> downloads;
u64 total_size_bytes = 0; u64 total_size_bytes = 0;
u64 largest_copy = 0; u64 largest_copy = 0;
for (auto& interval : intervals) { for (const IntervalSet& intervals : committed_ranges) {
const std::size_t size = interval.upper() - interval.lower(); for (auto& interval : intervals) {
const VAddr cpu_addr = interval.lower(); const std::size_t size = interval.upper() - interval.lower();
const VAddr cpu_addr_end = interval.upper(); const VAddr cpu_addr = interval.lower();
ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) { const VAddr cpu_addr_end = interval.upper();
boost::container::small_vector<BufferCopy, 1> copies; ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
buffer.ForEachDownloadRange( boost::container::small_vector<BufferCopy, 1> copies;
cpu_addr, size, false, [&](u64 range_offset, u64 range_size) { buffer.ForEachDownloadRange(
VAddr cpu_addr_base = buffer.CpuAddr() + range_offset; cpu_addr, size, false, [&](u64 range_offset, u64 range_size) {
VAddr cpu_addr_end2 = cpu_addr_base + range_size; VAddr cpu_addr_base = buffer.CpuAddr() + range_offset;
const s64 difference = s64(cpu_addr_end2 - cpu_addr_end); VAddr cpu_addr_end2 = cpu_addr_base + range_size;
cpu_addr_end2 -= u64(std::max<s64>(difference, 0)); const s64 difference = s64(cpu_addr_end2 - cpu_addr_end);
const s64 difference2 = s64(cpu_addr - cpu_addr_base); cpu_addr_end2 -= u64(std::max<s64>(difference, 0));
cpu_addr_base += u64(std::max<s64>(difference2, 0)); const s64 difference2 = s64(cpu_addr - cpu_addr_base);
const u64 new_size = cpu_addr_end2 - cpu_addr_base; cpu_addr_base += u64(std::max<s64>(difference2, 0));
const u64 new_offset = cpu_addr_base - buffer.CpuAddr(); const u64 new_size = cpu_addr_end2 - cpu_addr_base;
downloads.push_back({ const u64 new_offset = cpu_addr_base - buffer.CpuAddr();
BufferCopy{ downloads.push_back({
.src_offset = new_offset, BufferCopy{
.dst_offset = total_size_bytes, .src_offset = new_offset,
.size = new_size, .dst_offset = total_size_bytes,
}, .size = new_size,
buffer_id, },
buffer_id,
});
total_size_bytes += new_size;
largest_copy = std::max(largest_copy, new_size);
constexpr u64 align_mask = ~(32ULL - 1);
const VAddr align_up_address = (cpu_addr_base + 31) & align_mask;
const u64 difference_base = align_up_address - cpu_addr_base;
if (difference_base > new_size) {
return;
}
const u64 fixed_size = new_size - difference_base;
buffer.UnmarkRegionAsGpuModified(align_up_address, fixed_size & align_mask);
}); });
total_size_bytes += new_size; });
largest_copy = std::max(largest_copy, new_size); }
constexpr u64 align_mask = ~(32ULL - 1);
const VAddr align_up_address = (cpu_addr_base + 31) & align_mask;
const u64 difference_base = align_up_address - cpu_addr_base;
if (difference_base > new_size) {
return;
}
const u64 fixed_size = new_size - difference_base;
buffer.UnmarkRegionAsGpuModified(align_up_address, fixed_size & align_mask);
});
});
} }
committed_ranges.clear();
if (downloads.empty()) { if (downloads.empty()) {
return; return;
} }
@ -644,6 +662,7 @@ void BufferCache<P>::CommitAsyncFlushes() {
CommitAsyncFlushesHigh(); CommitAsyncFlushesHigh();
} else { } else {
uncommitted_ranges.clear(); uncommitted_ranges.clear();
committed_ranges.clear();
} }
} }

View file

@ -54,6 +54,12 @@ public:
delayed_destruction_ring.Tick(); delayed_destruction_ring.Tick();
} }
// Unlike other fences, this one doesn't
void SignalOrdering() {
std::scoped_lock lock{buffer_cache.mutex};
buffer_cache.AccumulateFlushes();
}
void SignalReference() { void SignalReference() {
// Only sync references on High // Only sync references on High
if (Settings::values.gpu_accuracy.GetValue() != Settings::GPUAccuracy::High) { if (Settings::values.gpu_accuracy.GetValue() != Settings::GPUAccuracy::High) {

View file

@ -657,6 +657,10 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(VAddr addr, u64 size) {
void RasterizerOpenGL::WaitForIdle() { void RasterizerOpenGL::WaitForIdle() {
glMemoryBarrier(GL_ALL_BARRIER_BITS); glMemoryBarrier(GL_ALL_BARRIER_BITS);
if (!gpu.IsAsync()) {
return;
}
fence_manager.SignalOrdering();
} }
void RasterizerOpenGL::FragmentBarrier() { void RasterizerOpenGL::FragmentBarrier() {

View file

@ -619,6 +619,10 @@ void RasterizerVulkan::WaitForIdle() {
cmdbuf.SetEvent(event, flags); cmdbuf.SetEvent(event, flags);
cmdbuf.WaitEvents(event, flags, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, {}, {}, {}); cmdbuf.WaitEvents(event, flags, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, {}, {}, {});
}); });
if (!gpu.IsAsync()) {
return;
}
fence_manager.SignalOrdering();
} }
void RasterizerVulkan::FragmentBarrier() { void RasterizerVulkan::FragmentBarrier() {