diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index cd50970b7a..970f635313 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1168,7 +1168,7 @@ void BufferCache
::DoUpdateGraphicsBuffers(bool is_indexed) {
if (is_indexed) {
UpdateIndexBuffer();
}
- UpdateVertexBuffers();
+ UpdateVertexBuffers(is_indexed);
UpdateTransformFeedbackBuffers();
for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
UpdateUniformBuffers(stage);
@@ -1242,21 +1242,56 @@ void BufferCache
::UpdateIndexBuffer() {
}
template
-void BufferCache::UpdateVertexBuffers() {
- auto& flags = maxwell3d->dirty.flags;
- const u32 base_instance = maxwell3d->draw_manager.draw_state.base_instance;
- if (draw_instance_count != last_draw_instance_count ||
- base_instance != last_draw_base_instance) {
- last_draw_instance_count = draw_instance_count;
- last_draw_base_instance = base_instance;
- const auto& instances = maxwell3d->regs.vertex_stream_instances;
- for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
- if (!instances.IsInstancingEnabled(index)) {
- continue;
- }
- flags[Dirty::VertexBuffer0 + index] = true;
- flags[Dirty::VertexBuffers] = true;
+u64 BufferCache
::DrawVertexBound(u32 index, bool is_indexed) const {
+ const auto& array = maxwell3d->regs.vertex_streams[index];
+ const u64 stride = static_cast(array.stride);
+ if (array.enable == 0 || stride == 0) {
+ return 0;
+ }
+ const auto& draw_state = maxwell3d->draw_manager.draw_state;
+ if (maxwell3d->regs.vertex_stream_instances.IsInstancingEnabled(index)) {
+ if (draw_instance_count == 0) {
+ return 0;
}
+ const u64 base_instance = static_cast(draw_state.base_instance);
+ u64 elements = base_instance + 1;
+ if (array.frequency != 0) {
+ elements = (base_instance + static_cast(draw_instance_count) - 1) /
+ static_cast(array.frequency) +
+ 1;
+ }
+ return (elements + 1) * stride;
+ }
+ if (!is_indexed) {
+ const u64 elements = static_cast(draw_state.vertex_buffer.first) +
+ static_cast(draw_state.vertex_buffer.count);
+ return (elements + 1) * stride;
+ }
+ u64 max_index = 0;
+ switch (draw_state.index_buffer.format) {
+ case Maxwell::IndexFormat::UnsignedByte:
+ max_index = 0xFF;
+ break;
+ case Maxwell::IndexFormat::UnsignedShort:
+ max_index = 0xFFFF;
+ break;
+ default:
+ return 0;
+ }
+ const u64 elements = static_cast(draw_state.base_index) + max_index + 1;
+ return (elements + 1) * stride;
+}
+
+template
+void BufferCache::UpdateVertexBuffers(bool is_indexed) {
+ auto& flags = maxwell3d->dirty.flags;
+ for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
+ const u64 bound = DrawVertexBound(index, is_indexed);
+ if (bound <= last_draw_bounds[index]) {
+ continue;
+ }
+ flags[Dirty::VertexBuffer0 + index] = true;
+ flags[Dirty::VertexBuffers] = true;
}
if (!maxwell3d->dirty.flags[Dirty::VertexBuffers]) {
return;
@@ -1264,12 +1299,12 @@ void BufferCache
::UpdateVertexBuffers() {
flags[Dirty::VertexBuffers] = false;
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
- UpdateVertexBuffer(index);
+ UpdateVertexBuffer(index, is_indexed);
}
}
template
-void BufferCache::UpdateVertexBuffer(u32 index) {
+void BufferCache
::UpdateVertexBuffer(u32 index, bool is_indexed) {
if (!maxwell3d->dirty.flags[Dirty::VertexBuffer0 + index]) {
return;
}
@@ -1289,17 +1324,11 @@ void BufferCache
::UpdateVertexBuffer(u32 index) {
if (address_size > u64{(std::numeric_limits::max)()}) {
address_size = implausible_size;
}
- const bool is_instanced = maxwell3d->regs.vertex_stream_instances.IsInstancingEnabled(index);
- const u64 stride = static_cast(array.stride);
- if (is_instanced && stride != 0 && draw_instance_count != 0) {
- const u64 base_instance = static_cast(maxwell3d->draw_manager.draw_state.base_instance);
- u64 elements = base_instance + 1;
- if (array.frequency != 0) {
- elements = (base_instance + static_cast(draw_instance_count) - 1) /
- static_cast(array.frequency) +
- 1;
- }
- address_size = (std::min)(address_size, (elements + 1) * stride);
+ const u64 draw_bound = DrawVertexBound(index, is_indexed);
+ last_draw_bounds[index] = (std::numeric_limits::max)();
+ if (draw_bound != 0) {
+ last_draw_bounds[index] = draw_bound;
+ address_size = (std::min)(address_size, draw_bound);
}
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || address_size >= implausible_size) {
address_size = gpu_memory->MaxContinuousRange(gpu_addr_begin, address_size);
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
index b3f0eb83c9..ef05e7b778 100644
--- a/src/video_core/buffer_cache/buffer_cache_base.h
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -390,9 +390,11 @@ private:
void UpdateIndexBuffer();
- void UpdateVertexBuffers();
+ void UpdateVertexBuffers(bool is_indexed);
- void UpdateVertexBuffer(u32 index);
+ void UpdateVertexBuffer(u32 index, bool is_indexed);
+
+ [[nodiscard]] u64 DrawVertexBound(u32 index, bool is_indexed) const;
void UpdateDrawIndirect();
@@ -485,8 +487,7 @@ private:
const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect{};
u32 draw_instance_count = 0;
- u32 last_draw_instance_count = 0;
- u32 last_draw_base_instance = 0;
+ std::array last_draw_bounds{};
u32 last_index_count = 0;