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.h115
1 files changed, 82 insertions, 33 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index b368ffea05..7b92edecaa 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
@@ -382,6 +382,10 @@ void BufferCache<P>::BindHostComputeBuffers() {
BindHostComputeUniformBuffers();
BindHostComputeStorageBuffers();
BindHostComputeTextureBuffers();
+ if (any_buffer_uploaded) {
+ runtime.PostCopyBarrier();
+ any_buffer_uploaded = false;
+ }
}
template <class P>
@@ -764,44 +768,84 @@ void BufferCache<P>::BindHostIndexBuffer() {
}
template <class P>
+void BufferCache<P>::BindHostVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size,
+ u32 stride) {
+ if constexpr (IS_OPENGL) {
+ runtime.BindVertexBuffer(index, buffer, offset, size, stride);
+ } else {
+ runtime.BindVertexBuffer(index, buffer.Handle(), offset, size, stride);
+ }
+}
+
+template <class P>
+Binding& BufferCache<P>::VertexBufferSlot(u32 index) {
+ ASSERT(index < NUM_VERTEX_BUFFERS);
+ return v_buffer[index];
+}
+
+template <class P>
+const Binding& BufferCache<P>::VertexBufferSlot(u32 index) const {
+ ASSERT(index < NUM_VERTEX_BUFFERS);
+ return v_buffer[index];
+}
+
+template <class P>
+void BufferCache<P>::UpdateVertexBufferSlot(u32 index, const Binding& binding) {
+ Binding& slot = VertexBufferSlot(index);
+ if (slot.device_addr != binding.device_addr || slot.size != binding.size) {
+ ++vertex_buffers_serial;
+ }
+ slot = binding;
+ if (binding.buffer_id != NULL_BUFFER_ID && binding.size != 0) {
+ enabled_vertex_buffers_mask |= (1u << index);
+ } else {
+ enabled_vertex_buffers_mask &= ~(1u << index);
+ }
+}
+
+template <class P>
void BufferCache<P>::BindHostVertexBuffers() {
- HostBindings<typename P::Buffer> host_bindings;
- bool any_valid{false};
auto& flags = maxwell3d->dirty.flags;
- for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
- const Binding& binding = channel_state->vertex_buffers[index];
+ u32 enabled_mask = enabled_vertex_buffers_mask;
+ HostBindings<Buffer> bindings{};
+ u32 last_index = std::numeric_limits<u32>::max();
+ const auto flush_bindings = [&]() {
+ if (bindings.buffers.empty()) {
+ return;
+ }
+ bindings.max_index = bindings.min_index + static_cast<u32>(bindings.buffers.size());
+ runtime.BindVertexBuffers(bindings);
+ bindings = HostBindings<Buffer>{};
+ last_index = std::numeric_limits<u32>::max();
+ };
+ while (enabled_mask != 0) {
+ const u32 index = std::countr_zero(enabled_mask);
+ enabled_mask &= (enabled_mask - 1);
+ const Binding& binding = VertexBufferSlot(index);
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer, binding.buffer_id);
SynchronizeBuffer(buffer, binding.device_addr, binding.size);
if (!flags[Dirty::VertexBuffer0 + index]) {
+ flush_bindings();
continue;
}
flags[Dirty::VertexBuffer0 + index] = false;
-
- host_bindings.min_index = (std::min)(host_bindings.min_index, index);
- host_bindings.max_index = (std::max)(host_bindings.max_index, index);
- any_valid = true;
- }
-
- if (any_valid) {
- host_bindings.max_index++;
- for (u32 index = host_bindings.min_index; index < host_bindings.max_index; index++) {
- flags[Dirty::VertexBuffer0 + index] = false;
-
- const Binding& binding = channel_state->vertex_buffers[index];
- Buffer& buffer = slot_buffers[binding.buffer_id];
-
- const u32 stride = maxwell3d->regs.vertex_streams[index].stride;
- const u32 offset = buffer.Offset(binding.device_addr);
- buffer.MarkUsage(offset, binding.size);
-
- host_bindings.buffers.push_back(&buffer);
- host_bindings.offsets.push_back(offset);
- host_bindings.sizes.push_back(binding.size);
- host_bindings.strides.push_back(stride);
+ const u32 stride = maxwell3d->regs.vertex_streams[index].stride;
+ const u32 offset = buffer.Offset(binding.device_addr);
+ buffer.MarkUsage(offset, binding.size);
+ if (!bindings.buffers.empty() && index != last_index + 1) {
+ flush_bindings();
}
- runtime.BindVertexBuffers(host_bindings);
+ if (bindings.buffers.empty()) {
+ bindings.min_index = index;
+ }
+ bindings.buffers.push_back(&buffer);
+ bindings.offsets.push_back(offset);
+ bindings.sizes.push_back(binding.size);
+ bindings.strides.push_back(stride);
+ last_index = index;
}
+ flush_bindings();
}
template <class P>
@@ -1205,17 +1249,20 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
u32 size = address_size; // TODO: Analyze stride and number of vertices
if (array.enable == 0 || size == 0 || !device_addr) {
channel_state->vertex_buffers[index] = NULL_BINDING;
+ UpdateVertexBufferSlot(index, NULL_BINDING);
return;
}
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);
- channel_state->vertex_buffers[index] = Binding{
+ const Binding binding{
.device_addr = *device_addr,
.size = size,
.buffer_id = buffer_id,
};
+ channel_state->vertex_buffers[index] = binding;
+ UpdateVertexBufferSlot(index, binding);
}
template <class P>
@@ -1528,12 +1575,12 @@ void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
template <class P>
bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size) {
- boost::container::small_vector<BufferCopy, 4> copies;
+ upload_copies.clear();
u64 total_size_bytes = 0;
u64 largest_copy = 0;
- DAddr buffer_start = buffer.CpuAddr();
+ const DAddr buffer_start = buffer.cpu_addr_cached;
memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
- copies.push_back(BufferCopy{
+ upload_copies.push_back(BufferCopy{
.src_offset = total_size_bytes,
.dst_offset = device_addr_out - buffer_start,
.size = range_size,
@@ -1544,8 +1591,9 @@ bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
if (total_size_bytes == 0) {
return true;
}
- const std::span<BufferCopy> copies_span(copies.data(), copies.size());
+ const std::span<BufferCopy> copies_span(upload_copies.data(), upload_copies.size());
UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
+ any_buffer_uploaded = true;
return false;
}
@@ -1735,6 +1783,7 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) {
auto& binding = channel_state->vertex_buffers[index];
if (binding.buffer_id == buffer_id) {
binding.buffer_id = BufferId{};
+ UpdateVertexBufferSlot(index, binding);
dirty_vertex_buffers.push_back(index);
}
}