diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 56f0e7b870..dec26f328d 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -24,6 +24,18 @@ namespace Vulkan { namespace { +constexpr u32 COMPACT_VERTEX_BINDINGS = 8; + +template +struct VertexBindings { + std::array buffers; + std::array offsets; + std::array sizes; + std::array strides; + u32 first; + u32 count; +}; + VkBufferCopy MakeBufferCopy(const VideoCommon::BufferCopy& copy) { return VkBufferCopy{ .srcOffset = copy.src_offset, @@ -670,36 +682,52 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset } } -void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings& bindings) { - boost::container::static_vector buffer_handles(bindings.buffers.size()); - for (u32 i = 0; i < bindings.buffers.size(); ++i) { - auto handle = bindings.buffers[i]->Handle(); - if (handle == VK_NULL_HANDLE) { - bindings.offsets[i] = 0; - bindings.sizes[i] = VK_WHOLE_SIZE; +template +void BufferCacheRuntime::RecordVertexBuffers(const VideoCommon::HostBindings& bindings, + u32 count) { + VertexBindings vertex{}; + vertex.first = bindings.min_index; + vertex.count = count; + for (u32 i = 0; i < count; ++i) { + vertex.buffers[i] = bindings.buffers[i]->Handle(); + vertex.offsets[i] = bindings.offsets[i]; + vertex.sizes[i] = bindings.sizes[i]; + vertex.strides[i] = bindings.strides[i]; + if (vertex.buffers[i] == VK_NULL_HANDLE) { + vertex.offsets[i] = 0; + vertex.sizes[i] = VK_WHOLE_SIZE; if (!device.HasNullDescriptor()) { ReserveNullBuffer(); - handle = *null_buffer; + vertex.buffers[i] = *null_buffer; } } - buffer_handles[i] = handle; - } - const u32 device_max = device.GetMaxVertexInputBindings(); - const u32 min_binding = (std::min)(bindings.min_index, device_max); - const u32 max_binding = (std::min)(bindings.max_index, device_max); - const u32 binding_count = max_binding - min_binding; - if (binding_count == 0) { - return; } if (device.IsExtExtendedDynamicStateSupported()) { - scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) { - cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data(), bindings_.strides.data()); - }); - } else { - scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) { - cmdbuf.BindVertexBuffers(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data()); + scheduler.Record([vertex](vk::CommandBuffer cmdbuf) { + cmdbuf.BindVertexBuffers2EXT(vertex.first, vertex.count, vertex.buffers.data(), + vertex.offsets.data(), vertex.sizes.data(), + vertex.strides.data()); }); + return; } + scheduler.Record([vertex](vk::CommandBuffer cmdbuf) { + cmdbuf.BindVertexBuffers(vertex.first, vertex.count, vertex.buffers.data(), + vertex.offsets.data()); + }); +} + +void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings& bindings) { + const u32 device_max = device.GetMaxVertexInputBindings(); + const u32 count = (std::min)(bindings.max_index, device_max) - + (std::min)(bindings.min_index, device_max); + if (count == 0) { + return; + } + if (count <= COMPACT_VERTEX_BINDINGS) { + RecordVertexBuffers(bindings, count); + return; + } + RecordVertexBuffers(bindings, count); } void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index fbd8c2e753..582f665b4e 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -244,6 +244,9 @@ private: VkFormat TexelBufferFormat(VideoCore::Surface::PixelFormat format) const; + template + void RecordVertexBuffers(const VideoCommon::HostBindings& bindings, u32 count); + void ReserveNullBuffer(); vk::Buffer CreateNullBuffer(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 52227ab290..c32cbd2a0d 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1032,23 +1032,22 @@ void RasterizerVulkan::LoadDiskResources(u64 title_id, std::stop_token stop_load void RasterizerVulkan::FlushWork() { #ifdef __ANDROID__ - static constexpr u32 DRAWS_TO_DISPATCH = 512; - static constexpr u32 CHECK_MASK = 3; + static constexpr u32 DRAWS_TO_DISPATCH = 1024; #else static constexpr u32 DRAWS_TO_DISPATCH = 4096; - static constexpr u32 CHECK_MASK = 7; #endif // __ANDROID__ + static constexpr u32 CHECK_MASK = 7; - static_assert(DRAWS_TO_DISPATCH % (CHECK_MASK + 1) == 0); - if ((++draw_counter & CHECK_MASK) != CHECK_MASK) { + if (++draw_counter >= DRAWS_TO_DISPATCH && + (!scheduler.IsRenderPassActive() || + maxwell3d->dirty.flags[VideoCommon::Dirty::RenderTargets])) { + scheduler.Flush(); + draw_counter = 0; return; } - if (draw_counter < DRAWS_TO_DISPATCH) { + if ((draw_counter & CHECK_MASK) == CHECK_MASK) { scheduler.DispatchWork(); - return; } - scheduler.Flush(); - draw_counter = 0; } AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_, diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 5c07c99828..33b03ea8f2 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -13,6 +13,7 @@ #include "video_core/renderer_vulkan/vk_query_cache.h" +#include "common/make_unique_for_overwrite.h" #include "common/settings.h" #include "common/thread.h" #include "video_core/gpu_logging/gpu_logging.h" @@ -484,7 +485,7 @@ void Scheduler::AcquireNewChunk() { if (chunk_reserve.empty()) { // If we don't have anything reserved, we need to make a new chunk. - chunk = std::make_unique(); + chunk = Common::make_unique_for_overwrite(); } else { // Otherwise, we can just take from the reserve. chunk = std::move(chunk_reserve.back()); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 08ae0bfca1..e82b0414fc 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -251,7 +251,7 @@ private: size_t command_offset = 0; bool submit = false; - alignas(std::max_align_t) std::array data{}; + alignas(std::max_align_t) std::array data; }; struct State {