Fence Manager: Force ordering on WFI.
This commit is contained in:
parent
73638ca593
commit
cf38faee9b
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Reference in New Issue