@@ -736,11 +736,24 @@ struct VertexBufferRange {
736736 [[nodiscard]] uint64_t RequestedSize () const { return requested_end - base_address; }
737737};
738738
739- static std::vector<BufferBinding> AcquireVertexBuffers (RenderCommandBuffer& buffer,
740- const ShaderVertexInputInfo& vs_input_info) {
739+ struct PreparedVertexBuffers {
740+ static constexpr uint32_t MaxBuffers = ShaderVertexInputInfo::RES_MAX ;
741+
742+ std::array<vk::Buffer, MaxBuffers> buffers {};
743+ std::array<vk::DeviceSize, MaxBuffers> offsets {};
744+ std::array<std::shared_ptr<void >, MaxBuffers> owners {};
745+ uint32_t count = 0 ;
746+ uint32_t owner_count = 0 ;
747+ };
748+
749+ static PreparedVertexBuffers AcquireVertexBuffers (RenderCommandBuffer& buffer,
750+ const ShaderVertexInputInfo& vs_input_info) {
751+ EXIT_IF (vs_input_info.buffers_num < 0 ||
752+ vs_input_info.buffers_num > ShaderVertexInputInfo::RES_MAX );
753+
741754 // Collect the non-empty guest vertex ranges.
742- std::vector <VertexBufferRange> ranges;
743- ranges. reserve (vs_input_info. buffers_num ) ;
755+ std::array <VertexBufferRange, ShaderVertexInputInfo:: RES_MAX > ranges {} ;
756+ uint32_t range_count = 0 ;
744757 for (int i = 0 ; i < vs_input_info.buffers_num ; i++) {
745758 const auto & vertex = vs_input_info.buffers [i];
746759 const auto size = VertexBufferDescriptorSize (vertex);
@@ -751,27 +764,31 @@ static std::vector<BufferBinding> AcquireVertexBuffers(RenderCommandBuffer&
751764 EXIT (" invalid vertex buffer range: addr=0x%016" PRIx64 " size=0x%016" PRIx64 " \n " ,
752765 vertex.addr , size);
753766 }
754- ranges. push_back ( {vertex.addr , vertex.addr + size}) ;
767+ ranges[range_count++] = {vertex.addr , vertex.addr + size};
755768 }
756769
757- std::ranges::sort (ranges, [](const VertexBufferRange& left, const VertexBufferRange& right) {
758- return left.base_address < right.base_address ;
759- });
770+ std::sort (ranges.begin (), ranges.begin () + range_count,
771+ [](const VertexBufferRange& left, const VertexBufferRange& right) {
772+ return left.base_address < right.base_address ;
773+ });
760774
761775 // Merge overlapping or touching ranges before acquiring host buffers.
762- std::vector<VertexBufferRange> merged_ranges;
763- merged_ranges.reserve (ranges.size ());
764- for (const auto & range: ranges) {
765- if (!merged_ranges.empty () && merged_ranges.back ().requested_end >= range.base_address ) {
766- merged_ranges.back ().requested_end =
767- std::max (merged_ranges.back ().requested_end , range.requested_end );
776+ std::array<VertexBufferRange, ShaderVertexInputInfo::RES_MAX > merged_ranges {};
777+ uint32_t merged_count = 0 ;
778+ for (uint32_t i = 0 ; i < range_count; i++) {
779+ const auto & range = ranges[i];
780+ if (merged_count != 0 &&
781+ merged_ranges[merged_count - 1 ].requested_end >= range.base_address ) {
782+ merged_ranges[merged_count - 1 ].requested_end =
783+ std::max (merged_ranges[merged_count - 1 ].requested_end , range.requested_end );
768784 continue ;
769785 }
770- merged_ranges. push_back ( range) ;
786+ merged_ranges[merged_count++] = {range. base_address , range. requested_end } ;
771787 }
772788
773789 auto & cache = buffer.GetContext ().GetBufferCache ();
774- for (auto & range: merged_ranges) {
790+ for (uint32_t i = 0 ; i < merged_count; i++) {
791+ auto & range = merged_ranges[i];
775792 // PPSA20298
776793 const auto size =
777794 Libs::LibKernel::Memory::ClampRangeSize (range.base_address , range.RequestedSize ());
@@ -780,30 +797,47 @@ static std::vector<BufferBinding> AcquireVertexBuffers(RenderCommandBuffer&
780797 }
781798
782799 // Rebuild slot bindings, offsetting non-empty slots into their acquired merged range.
783- std::vector<BufferBinding> bindings;
784- bindings.reserve (vs_input_info.buffers_num );
800+ PreparedVertexBuffers prepared;
801+ prepared.count = static_cast <uint32_t >(vs_input_info.buffers_num );
802+ std::shared_ptr<Buffer> null_owner;
803+ vk::Buffer null_buffer = nullptr ;
785804 for (int i = 0 ; i < vs_input_info.buffers_num ; i++) {
786805 const auto & vertex = vs_input_info.buffers [i];
787806 const auto size = VertexBufferDescriptorSize (vertex);
788807 if (size == 0 ) {
789- auto owner = cache.ObtainNullBuffer ();
790- bindings.push_back ({owner, owner->Handle (), 0 });
808+ if (null_owner == nullptr ) {
809+ null_owner = cache.ObtainNullBuffer ();
810+ null_buffer = null_owner->Handle ();
811+ }
812+ prepared.buffers [i] = null_buffer;
813+ prepared.offsets [i] = 0 ;
791814 continue ;
792815 }
793816
794- const auto range = std::ranges::find_if (merged_ranges, [&](const VertexBufferRange& value) {
795- return vertex.addr >= value.base_address && vertex.addr < value.acquired_end ;
796- });
797- if (range == merged_ranges.end ()) {
817+ const auto range = std::find_if (merged_ranges.begin (), merged_ranges.begin () + merged_count,
818+ [&](const VertexBufferRange& value) {
819+ return vertex.addr >= value.base_address &&
820+ vertex.addr < value.acquired_end ;
821+ });
822+ if (range == merged_ranges.begin () + merged_count) {
798823 EXIT (" vertex buffer address is outside the acquired range: addr=0x%016" PRIx64 " \n " ,
799824 vertex.addr );
800825 }
801826
802- auto binding = range->binding ;
803- binding.offset += vertex.addr - range->base_address ;
804- bindings.push_back (std::move (binding));
827+ prepared.buffers [i] = range->binding .buffer ;
828+ prepared.offsets [i] = range->binding .offset + vertex.addr - range->base_address ;
829+ }
830+
831+ if (null_owner != nullptr ) {
832+ prepared.owners [prepared.owner_count ++] = std::move (null_owner);
833+ }
834+ for (uint32_t i = 0 ; i < merged_count; i++) {
835+ if (merged_ranges[i].binding .owner != nullptr ) {
836+ EXIT_IF (prepared.owner_count >= PreparedVertexBuffers::MaxBuffers);
837+ prepared.owners [prepared.owner_count ++] = std::move (merged_ranges[i].binding .owner );
838+ }
805839 }
806- return bindings ;
840+ return prepared ;
807841}
808842
809843static void SetDrawDebugPhase (RenderCommandBuffer& buffer, uint64_t submit_id,
@@ -937,7 +971,7 @@ static bool RefreshShaders(RenderCommandBuffer& buffer, const DrawCallInfo& draw
937971 return true ;
938972}
939973
940- static std::vector<BufferBinding> PrepareVertexBuffers (uint64_t submit_id,
974+ static PreparedVertexBuffers PrepareVertexBuffers (uint64_t submit_id,
941975 RenderCommandBuffer& buffer,
942976 const DrawCallInfo& draw,
943977 const ShaderVertexInputInfo& vs_input_info) {
@@ -950,8 +984,8 @@ static std::vector<BufferBinding> PrepareVertexBuffers(uint64_t
950984
951985static void RebindVertexBuffers (RenderCommandBuffer& buffer,
952986 const ShaderVertexInputInfo& vs_input_info,
953- std::vector<BufferBinding> & bindings ) {
954- bindings = AcquireVertexBuffers (buffer, vs_input_info);
987+ PreparedVertexBuffers & prepared ) {
988+ prepared = AcquireVertexBuffers (buffer, vs_input_info);
955989}
956990
957991static PreparedIndexBuffer PrepareIndexBuffer (RenderCommandBuffer& buffer,
@@ -993,14 +1027,18 @@ static void RebindIndexBuffer(RenderCommandBuffer& buffer, PreparedIndexBuffer&
9931027}
9941028
9951029static void CommitVertexBuffers (RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer,
996- std::vector<BufferBinding>& bindings) {
997- for (uint32_t slot = 0 ; slot < bindings.size (); slot++) {
998- auto & binding = bindings[slot];
999- if (binding.owner != nullptr ) {
1000- buffer.RetainResourceUntilFence (binding.owner );
1030+ PreparedVertexBuffers& prepared) {
1031+ for (uint32_t i = 0 ; i < prepared.owner_count ; i++) {
1032+ if (prepared.owners [i] != nullptr ) {
1033+ buffer.RetainResourceUntilFence (std::move (prepared.owners [i]));
10011034 }
1002- EXIT_IF (binding.buffer == nullptr );
1003- vk_buffer.bindVertexBuffers (slot, 1 , &binding.buffer , &binding.offset );
1035+ }
1036+ for (uint32_t i = 0 ; i < prepared.count ; i++) {
1037+ EXIT_IF (prepared.buffers [i] == nullptr );
1038+ }
1039+ if (prepared.count != 0 ) {
1040+ vk_buffer.bindVertexBuffers (0 , prepared.count , prepared.buffers .data (),
1041+ prepared.offsets .data ());
10041042 }
10051043}
10061044
0 commit comments