diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 9efac6a5bf..8f7ca3fe3c 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -802,6 +802,21 @@ void BufferCache
::BindHostIndexBuffer() {
const u32 offset = buffer.Offset(channel_state->index_buffer.device_addr);
const u32 size = channel_state->index_buffer.size;
const auto& draw_state = maxwell3d->draw_manager.draw_state;
+ if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
+ if (draw_state.topology == Maxwell::PrimitiveTopology::Quads ||
+ draw_state.topology == Maxwell::PrimitiveTopology::QuadStrip) {
+ const DAddr device_addr = channel_state->index_buffer.device_addr;
+ std::span indices = draw_state.inline_index_draw_indexes;
+ if (indices.empty() && !IsRegionGpuModified(device_addr, size)) {
+ indices = ImmediateBufferWithData(device_addr, size);
+ }
+ if (runtime.BindQuadIndices(draw_state.topology, draw_state.index_buffer.format,
+ draw_state.index_buffer.first,
+ draw_state.index_buffer.count, indices)) {
+ return;
+ }
+ }
+ }
if (draw_state.inline_index_draw_indexes.empty()) {
SynchronizeBuffer(buffer, channel_state->index_buffer.device_addr, size);
} else if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 20db32b52a..0547e7ed71 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -677,6 +677,57 @@ void BufferCacheRuntime::BindQuadIndexBuffer(PrimitiveTopology topology, u32 fir
}
}
+bool BufferCacheRuntime::BindQuadIndices(PrimitiveTopology topology, IndexFormat index_format,
+ u32 base_vertex, u32 num_indices,
+ std::span indices) {
+ const size_t index_size = size_t{1} << static_cast(index_format);
+ if (indices.size() < num_indices * index_size) {
+ return false;
+ }
+ u32 quads = num_indices / 4;
+ u32 stride = 4;
+ std::array swizzle{0, 1, 2, 0, 2, 3};
+ if (topology == PrimitiveTopology::QuadStrip) {
+ quads = 0;
+ if (num_indices >= 2) {
+ quads = (num_indices - 2) / 2;
+ }
+ stride = 2;
+ swizzle = {0, 3, 1, 0, 2, 3};
+ }
+ const size_t size = (std::max)(quads, 1U) * sizeof(swizzle);
+ const StagingBufferRef staging = staging_pool.Request(size, MemoryUsage::Upload);
+ const auto convert = [&](auto index_type) {
+ u8* output = staging.mapped_span.data();
+ for (u32 quad = 0; quad < quads; ++quad) {
+ std::array triangles;
+ for (size_t vertex = 0; vertex < triangles.size(); ++vertex) {
+ decltype(index_type) index;
+ std::memcpy(&index,
+ indices.data() + (quad * stride + swizzle[vertex]) * sizeof(index),
+ sizeof(index));
+ triangles[vertex] = index + base_vertex;
+ }
+ std::memcpy(output, triangles.data(), sizeof(triangles));
+ output += sizeof(triangles);
+ }
+ };
+ switch (index_format) {
+ case IndexFormat::UnsignedByte:
+ convert(u8{});
+ break;
+ case IndexFormat::UnsignedShort:
+ convert(u16{});
+ break;
+ case IndexFormat::UnsignedInt:
+ convert(u32{});
+ break;
+ }
+ BindIndexBuffer(PrimitiveTopology::Triangles, IndexFormat::UnsignedInt, 0, 0, staging.buffer,
+ static_cast(staging.offset), static_cast(size));
+ return true;
+}
+
void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride) {
if (index >= device.GetMaxVertexInputBindings()) {
return;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index c963990385..fa6829e623 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -178,6 +178,9 @@ public:
void BindQuadIndexBuffer(PrimitiveTopology topology, u32 first, u32 count);
+ bool BindQuadIndices(PrimitiveTopology topology, IndexFormat index_format, u32 base_vertex,
+ u32 num_indices, std::span indices);
+
void BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride);
void BindVertexBuffers(VideoCommon::HostBindings& bindings);