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);