aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/buffer_cache/buffer_cache.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/buffer_cache/buffer_cache.h')
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h160
1 files changed, 134 insertions, 26 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index e40aad1fb5..4c345dd213 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -113,6 +113,13 @@ void BufferCache<P>::TickFrame() {
}
template <class P>
+void BufferCache<P>::UnmapGPUMemory(size_t as_id, GPUVAddr gpu_addr, size_t size) {
+ if constexpr (requires { runtime.BindMultiRangeStorageBuffer(u64{}, bool{}); }) {
+ virtual_ranges.Unmap(as_id, gpu_addr, size);
+ }
+}
+
+template <class P>
void BufferCache<P>::WriteMemory(DAddr device_addr, u64 size) {
if (memory_tracker.IsRegionGpuModified(device_addr, size)) {
ClearDownload(device_addr, size);
@@ -208,8 +215,8 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
BufferId buffer_b;
do {
channel_state->has_deleted_buffers = false;
- buffer_a = FindBuffer(*cpu_src_address, static_cast<u32>(amount));
- buffer_b = FindBuffer(*cpu_dest_address, static_cast<u32>(amount));
+ buffer_a = FindBuffer(*cpu_src_address, static_cast<u32>(amount), false);
+ buffer_b = FindBuffer(*cpu_dest_address, static_cast<u32>(amount), false);
} while (channel_state->has_deleted_buffers);
auto& src_buffer = slot_buffers[buffer_a];
auto& dest_buffer = slot_buffers[buffer_b];
@@ -265,7 +272,7 @@ bool BufferCache<P>::DMAClear(GPUVAddr dst_address, u64 amount, u32 value) {
ClearDownload(*cpu_dst_address, size);
gpu_modified_ranges.Subtract(*cpu_dst_address, size);
- const BufferId buffer = FindBuffer(*cpu_dst_address, static_cast<u32>(size));
+ const BufferId buffer = FindBuffer(*cpu_dst_address, static_cast<u32>(size), false);
Buffer& dest_buffer = slot_buffers[buffer];
const u32 offset = dest_buffer.Offset(*cpu_dst_address);
runtime.ClearBuffer(dest_buffer, offset, size, value);
@@ -287,7 +294,7 @@ std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainBuffer(GPUVAddr gpu_ad
template <class P>
std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainCPUBuffer(
DAddr device_addr, u32 size, ObtainBufferSynchronize sync_info, ObtainBufferOperation post_op) {
- const BufferId buffer_id = FindBuffer(device_addr, size);
+ const BufferId buffer_id = FindBuffer(device_addr, size, false);
Buffer& buffer = slot_buffers[buffer_id];
// synchronize op
@@ -999,10 +1006,84 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
}
template <class P>
+void BufferCache<P>::ResolveMultiRangeStorage(Binding& binding, bool is_written,
+ std::vector<MultiRangeSegment>& pool) {
+ binding.segment_first = 0;
+ binding.segment_count = 0;
+ if constexpr (requires { runtime.BindMultiRangeStorageBuffer(u64{}, bool{}); }) {
+ if (binding.gpu_addr == 0 || binding.size == 0) {
+ return;
+ }
+ if (is_written && !runtime.PrefersSparseSources()) {
+ return;
+ }
+ const VirtualSegments* found =
+ virtual_ranges.Query(*gpu_memory, binding.gpu_addr, binding.size);
+ if (!found || found->size() < 2) {
+ return;
+ }
+ const VirtualSegments segments = *found;
+ const u32 first = static_cast<u32>(pool.size());
+ const bool prefer_sparse = runtime.PrefersSparseSources();
+ for (const VirtualSegment& segment : segments) {
+ const BufferId buffer_id =
+ FindBuffer(segment.device_addr, segment.size, prefer_sparse);
+ if (!buffer_id) {
+ pool.resize(first);
+ return;
+ }
+ pool.push_back(MultiRangeSegment{
+ .buffer_id = buffer_id,
+ .device_addr = segment.device_addr,
+ .size = segment.size,
+ });
+ }
+ binding.segment_first = first;
+ binding.segment_count = static_cast<u32>(segments.size());
+ }
+}
+
+template <class P>
+bool BufferCache<P>::BindMultiRangeStorage(const Binding& binding, bool is_written,
+ std::span<const MultiRangeSegment> pool) {
+ if constexpr (requires { runtime.BindMultiRangeStorageBuffer(u64{}, bool{}); }) {
+ if (binding.segment_count < 2) {
+ return false;
+ }
+ if (binding.segment_first + binding.segment_count > pool.size()) {
+ return false;
+ }
+ const u64 key = (static_cast<u64>(gpu_memory->GetID()) << 48) ^ binding.gpu_addr;
+ runtime.ResetMultiRange();
+ for (u32 index = 0; index < binding.segment_count; ++index) {
+ const MultiRangeSegment& segment = pool[binding.segment_first + index];
+ Buffer& buffer = slot_buffers[segment.buffer_id];
+ TouchBuffer(buffer, segment.buffer_id);
+ if (SynchronizeBuffer(buffer, segment.device_addr, segment.size)) {
+ runtime.InvalidateMultiRange(key);
+ }
+ const u32 offset = buffer.Offset(segment.device_addr);
+ buffer.MarkUsage(offset, segment.size);
+ if (is_written) {
+ MarkWrittenBuffer(segment.buffer_id, segment.device_addr, segment.size);
+ }
+ runtime.PushMultiRangeSource(buffer, offset, segment.size);
+ }
+ return runtime.BindMultiRangeStorageBuffer(key, is_written);
+ } else {
+ return false;
+ }
+}
+
+template <class P>
void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
u32 binding_index = 0;
ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) {
const Binding& binding = channel_state->storage_buffers[stage][index];
+ const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0;
+ if (BindMultiRangeStorage(binding, is_written, graphics_segments)) {
+ return;
+ }
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer, binding.buffer_id);
const u32 size = binding.size;
@@ -1010,7 +1091,6 @@ void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
const u32 offset = buffer.Offset(binding.device_addr);
buffer.MarkUsage(offset, size);
- const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0;
if (is_written) {
MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
@@ -1139,6 +1219,11 @@ void BufferCache<P>::BindHostComputeStorageBuffers() {
u32 binding_index = 0;
ForEachEnabledBit(channel_state->enabled_compute_storage_buffers, [&](u32 index) {
const Binding& binding = channel_state->compute_storage_buffers[index];
+ const bool is_written =
+ ((channel_state->written_compute_storage_buffers >> index) & 1) != 0;
+ if (BindMultiRangeStorage(binding, is_written, compute_segments)) {
+ return;
+ }
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer, binding.buffer_id);
const u32 size = binding.size;
@@ -1146,8 +1231,6 @@ void BufferCache<P>::BindHostComputeStorageBuffers() {
const u32 offset = buffer.Offset(binding.device_addr);
buffer.MarkUsage(offset, size);
- const bool is_written =
- ((channel_state->written_compute_storage_buffers >> index) & 1) != 0;
if (is_written) {
MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
@@ -1193,6 +1276,7 @@ void BufferCache<P>::BindHostComputeTextureBuffers() {
template <class P>
void BufferCache<P>::DoUpdateGraphicsBuffers(bool is_indexed) {
+ graphics_segments.clear();
BufferOperations([&]() {
if (is_indexed) {
UpdateIndexBuffer();
@@ -1212,6 +1296,7 @@ void BufferCache<P>::DoUpdateGraphicsBuffers(bool is_indexed) {
template <class P>
void BufferCache<P>::DoUpdateComputeBuffers() {
+ compute_segments.clear();
BufferOperations([&]() {
UpdateComputeUniformBuffers();
UpdateComputeStorageBuffers();
@@ -1234,11 +1319,11 @@ void BufferCache<P>::UpdateIndexBuffer() {
auto inline_index_size = static_cast<u32>(draw_state.inline_index_draw_indexes.size());
u32 buffer_size = Common::AlignUp(inline_index_size, CACHING_PAGESIZE);
if (inline_buffer_id == NULL_BUFFER_ID) [[unlikely]] {
- inline_buffer_id = CreateBuffer(0, buffer_size);
+ inline_buffer_id = CreateBuffer(0, buffer_size, false);
}
if (slot_buffers[inline_buffer_id].SizeBytes() < buffer_size) [[unlikely]] {
slot_buffers.erase(inline_buffer_id);
- inline_buffer_id = CreateBuffer(0, buffer_size);
+ inline_buffer_id = CreateBuffer(0, buffer_size, false);
}
channel_state->index_buffer = Binding{
.device_addr = 0,
@@ -1261,7 +1346,7 @@ void BufferCache<P>::UpdateIndexBuffer() {
channel_state->index_buffer = Binding{
.device_addr = *device_addr,
.size = size,
- .buffer_id = FindBuffer(*device_addr, size),
+ .buffer_id = FindBuffer(*device_addr, size, false),
};
}
@@ -1298,7 +1383,7 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || size >= 64_MiB) {
size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size));
}
- const BufferId buffer_id = FindBuffer(*device_addr, size);
+ const BufferId buffer_id = FindBuffer(*device_addr, size, false);
const Binding binding{
.device_addr = *device_addr,
.size = size,
@@ -1319,7 +1404,7 @@ void BufferCache<P>::UpdateDrawIndirect() {
binding = Binding{
.device_addr = *device_addr,
.size = static_cast<u32>(size),
- .buffer_id = FindBuffer(*device_addr, static_cast<u32>(size)),
+ .buffer_id = FindBuffer(*device_addr, static_cast<u32>(size), false),
};
};
if (current_draw_indirect->include_count) {
@@ -1343,7 +1428,7 @@ void BufferCache<P>::UpdateUniformBuffers(size_t stage) {
channel_state->dirty_uniform_buffers[stage] |= 1U << index;
}
// Resolve buffer
- binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
+ binding.buffer_id = FindBuffer(binding.device_addr, binding.size, false);
});
}
@@ -1352,8 +1437,10 @@ void BufferCache<P>::UpdateStorageBuffers(size_t stage) {
ForEachEnabledBit(channel_state->enabled_storage_buffers[stage], [&](u32 index) {
// Resolve buffer
Binding& binding = channel_state->storage_buffers[stage][index];
- const BufferId buffer_id = FindBuffer(binding.device_addr, binding.size);
+ const BufferId buffer_id = FindBuffer(binding.device_addr, binding.size, false);
binding.buffer_id = buffer_id;
+ const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0;
+ ResolveMultiRangeStorage(binding, is_written, graphics_segments);
});
}
@@ -1361,7 +1448,7 @@ template <class P>
void BufferCache<P>::UpdateTextureBuffers(size_t stage) {
ForEachEnabledBit(channel_state->enabled_texture_buffers[stage], [&](u32 index) {
Binding& binding = channel_state->texture_buffers[stage][index];
- binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
+ binding.buffer_id = FindBuffer(binding.device_addr, binding.size, false);
});
}
@@ -1385,7 +1472,7 @@ void BufferCache<P>::UpdateTransformFeedbackBuffer(u32 index) {
channel_state->transform_feedback_buffers[index] = NULL_BINDING;
return;
}
- const BufferId buffer_id = FindBuffer(*device_addr, size);
+ const BufferId buffer_id = FindBuffer(*device_addr, size, false);
channel_state->transform_feedback_buffers[index] = Binding{
.device_addr = *device_addr,
.size = size,
@@ -1407,7 +1494,7 @@ void BufferCache<P>::UpdateComputeUniformBuffers() {
binding.size = cbuf.size;
}
}
- binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
+ binding.buffer_id = FindBuffer(binding.device_addr, binding.size, false);
});
}
@@ -1416,7 +1503,10 @@ void BufferCache<P>::UpdateComputeStorageBuffers() {
ForEachEnabledBit(channel_state->enabled_compute_storage_buffers, [&](u32 index) {
// Resolve buffer
Binding& binding = channel_state->compute_storage_buffers[index];
- binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
+ binding.buffer_id = FindBuffer(binding.device_addr, binding.size, false);
+ const bool is_written =
+ ((channel_state->written_compute_storage_buffers >> index) & 1) != 0;
+ ResolveMultiRangeStorage(binding, is_written, compute_segments);
});
}
@@ -1424,7 +1514,7 @@ template <class P>
void BufferCache<P>::UpdateComputeTextureBuffers() {
ForEachEnabledBit(channel_state->enabled_compute_texture_buffers, [&](u32 index) {
Binding& binding = channel_state->compute_texture_buffers[index];
- binding.buffer_id = FindBuffer(binding.device_addr, binding.size);
+ binding.buffer_id = FindBuffer(binding.device_addr, binding.size, false);
});
}
@@ -1440,7 +1530,7 @@ void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u3
}
template <class P>
-BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size) {
+BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size, bool sparse_compatible) {
if (device_addr == 0) {
return NULL_BUFFER_ID;
}
@@ -1450,10 +1540,18 @@ BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size) {
Buffer& buffer = slot_buffers[buffer_id];
WaitForGpuFenceIfNeeded(buffer);
if (buffer.IsInBounds(device_addr, size)) {
- return buffer_id;
+ bool usable = true;
+ if constexpr (requires { buffer.IsSparseCompatible(); }) {
+ if (sparse_compatible && !buffer.IsSparseCompatible()) {
+ usable = false;
+ }
+ }
+ if (usable) {
+ return buffer_id;
+ }
}
}
- return CreateBuffer(device_addr, size);
+ return CreateBuffer(device_addr, size, sparse_compatible);
}
template <class P>
@@ -1575,13 +1673,15 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
}
template <class P>
-BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) {
+BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size,
+ bool sparse_compatible) {
DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE);
device_addr = Common::AlignDown(device_addr, CACHING_PAGESIZE);
wanted_size = static_cast<u32>(device_addr_end - device_addr);
const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size);
const u32 size = static_cast<u32>(overlap.end - overlap.begin);
- const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size);
+ const BufferId new_buffer_id =
+ slot_buffers.insert(runtime, overlap.begin, size, sparse_compatible);
auto& new_buffer = slot_buffers[new_buffer_id];
const size_t size_bytes = new_buffer.SizeBytes();
runtime.ClearBuffer(new_buffer, 0, size_bytes, 0);
@@ -1745,7 +1845,7 @@ void BufferCache<P>::InlineMemoryImplementation(DAddr dest_address, size_t copy_
ClearDownload(dest_address, copy_size);
gpu_modified_ranges.Subtract(dest_address, copy_size);
- BufferId buffer_id = FindBuffer(dest_address, static_cast<u32>(copy_size));
+ BufferId buffer_id = FindBuffer(dest_address, static_cast<u32>(copy_size), false);
auto& buffer = slot_buffers[buffer_id];
SynchronizeBuffer(buffer, dest_address, static_cast<u32>(copy_size));
@@ -1831,6 +1931,9 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, DAddr device_addr, u64
template <class P>
void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) {
+ if constexpr (requires { runtime.OnBufferDeleted(slot_buffers[buffer_id]); }) {
+ runtime.OnBufferDeleted(slot_buffers[buffer_id]);
+ }
bool dirty_index{false};
boost::container::small_vector<u64, NUM_VERTEX_BUFFERS> dirty_vertex_buffers;
const auto scalar_replace = [buffer_id](Binding& binding) {
@@ -1934,9 +2037,14 @@ Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index,
// The end address used for size calculation does not need to be aligned
const DAddr cpu_end = Common::AlignUp(*device_addr + size, Core::DEVICE_PAGESIZE);
+ u32 binding_size = static_cast<u32>(cpu_end - *aligned_device_addr);
+ if (is_written) {
+ binding_size = aligned_size;
+ }
const Binding binding{
.device_addr = *aligned_device_addr,
- .size = is_written ? aligned_size : static_cast<u32>(cpu_end - *aligned_device_addr),
+ .gpu_addr = aligned_gpu_addr,
+ .size = binding_size,
.buffer_id = BufferId{},
};
return binding;