diff options
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 22 | ||||
| -rw-r--r-- | src/video_core/dma_pusher.cpp | 14 | ||||
| -rw-r--r-- | src/video_core/dma_pusher.h | 1 | ||||
| -rw-r--r-- | src/video_core/engines/draw_manager.cpp | 21 | ||||
| -rw-r--r-- | src/video_core/engines/draw_manager.h | 20 | ||||
| -rw-r--r-- | src/video_core/engines/engine_interface.h | 2 | ||||
| -rw-r--r-- | src/video_core/macro/macro_hle.cpp | 53 | ||||
| -rw-r--r-- | src/video_core/rasterizer_interface.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.cpp | 57 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.h | 4 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_device.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.h | 15 |
13 files changed, 169 insertions, 47 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index f1c60d1f3..99abe0edf 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -170,6 +170,9 @@ public: | |||
| 170 | void BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size, PixelFormat format, | 170 | void BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size, PixelFormat format, |
| 171 | bool is_written, bool is_image); | 171 | bool is_written, bool is_image); |
| 172 | 172 | ||
| 173 | [[nodiscard]] std::pair<Buffer*, u32> ObtainBuffer(GPUVAddr gpu_addr, u32 size, | ||
| 174 | bool synchronize, bool mark_as_written); | ||
| 175 | |||
| 173 | void FlushCachedWrites(); | 176 | void FlushCachedWrites(); |
| 174 | 177 | ||
| 175 | /// Return true when there are uncommitted buffers to be downloaded | 178 | /// Return true when there are uncommitted buffers to be downloaded |
| @@ -791,6 +794,25 @@ void BufferCache<P>::BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_add | |||
| 791 | } | 794 | } |
| 792 | 795 | ||
| 793 | template <class P> | 796 | template <class P> |
| 797 | std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainBuffer(GPUVAddr gpu_addr, u32 size, | ||
| 798 | bool synchronize, | ||
| 799 | bool mark_as_written) { | ||
| 800 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); | ||
| 801 | if (!cpu_addr) { | ||
| 802 | return {&slot_buffers[NULL_BUFFER_ID], 0}; | ||
| 803 | } | ||
| 804 | const BufferId buffer_id = FindBuffer(*cpu_addr, size); | ||
| 805 | Buffer& buffer = slot_buffers[buffer_id]; | ||
| 806 | if (synchronize) { | ||
| 807 | SynchronizeBuffer(buffer, *cpu_addr, size); | ||
| 808 | } | ||
| 809 | if (mark_as_written) { | ||
| 810 | MarkWrittenBuffer(buffer_id, *cpu_addr, size); | ||
| 811 | } | ||
| 812 | return {&buffer, buffer.Offset(*cpu_addr)}; | ||
| 813 | } | ||
| 814 | |||
| 815 | template <class P> | ||
| 794 | void BufferCache<P>::FlushCachedWrites() { | 816 | void BufferCache<P>::FlushCachedWrites() { |
| 795 | for (const BufferId buffer_id : cached_write_buffer_ids) { | 817 | for (const BufferId buffer_id : cached_write_buffer_ids) { |
| 796 | slot_buffers[buffer_id].FlushCachedWrites(); | 818 | slot_buffers[buffer_id].FlushCachedWrites(); |
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp index 322de2606..eb1371612 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp | |||
| @@ -61,7 +61,7 @@ bool DmaPusher::Step() { | |||
| 61 | } else { | 61 | } else { |
| 62 | const CommandListHeader command_list_header{ | 62 | const CommandListHeader command_list_header{ |
| 63 | command_list.command_lists[dma_pushbuffer_subindex++]}; | 63 | command_list.command_lists[dma_pushbuffer_subindex++]}; |
| 64 | const GPUVAddr dma_get = command_list_header.addr; | 64 | dma_state.dma_get = command_list_header.addr; |
| 65 | 65 | ||
| 66 | if (dma_pushbuffer_subindex >= command_list.command_lists.size()) { | 66 | if (dma_pushbuffer_subindex >= command_list.command_lists.size()) { |
| 67 | // We've gone through the current list, remove it from the queue | 67 | // We've gone through the current list, remove it from the queue |
| @@ -75,11 +75,11 @@ bool DmaPusher::Step() { | |||
| 75 | 75 | ||
| 76 | // Push buffer non-empty, read a word | 76 | // Push buffer non-empty, read a word |
| 77 | command_headers.resize_destructive(command_list_header.size); | 77 | command_headers.resize_destructive(command_list_header.size); |
| 78 | if (Settings::IsGPULevelHigh()) { | 78 | if (Settings::IsGPULevelExtreme()) { |
| 79 | memory_manager.ReadBlock(dma_get, command_headers.data(), | 79 | memory_manager.ReadBlock(dma_state.dma_get, command_headers.data(), |
| 80 | command_list_header.size * sizeof(u32)); | 80 | command_list_header.size * sizeof(u32)); |
| 81 | } else { | 81 | } else { |
| 82 | memory_manager.ReadBlockUnsafe(dma_get, command_headers.data(), | 82 | memory_manager.ReadBlockUnsafe(dma_state.dma_get, command_headers.data(), |
| 83 | command_list_header.size * sizeof(u32)); | 83 | command_list_header.size * sizeof(u32)); |
| 84 | } | 84 | } |
| 85 | ProcessCommands(command_headers); | 85 | ProcessCommands(command_headers); |
| @@ -174,8 +174,10 @@ void DmaPusher::CallMultiMethod(const u32* base_start, u32 num_methods) const { | |||
| 174 | puller.CallMultiMethod(dma_state.method, dma_state.subchannel, base_start, num_methods, | 174 | puller.CallMultiMethod(dma_state.method, dma_state.subchannel, base_start, num_methods, |
| 175 | dma_state.method_count); | 175 | dma_state.method_count); |
| 176 | } else { | 176 | } else { |
| 177 | subchannels[dma_state.subchannel]->CallMultiMethod(dma_state.method, base_start, | 177 | auto subchannel = subchannels[dma_state.subchannel]; |
| 178 | num_methods, dma_state.method_count); | 178 | subchannel->current_dma_segment = dma_state.dma_get; |
| 179 | subchannel->CallMultiMethod(dma_state.method, base_start, num_methods, | ||
| 180 | dma_state.method_count); | ||
| 179 | } | 181 | } |
| 180 | } | 182 | } |
| 181 | 183 | ||
diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h index 6f00de937..ca0899ba7 100644 --- a/src/video_core/dma_pusher.h +++ b/src/video_core/dma_pusher.h | |||
| @@ -156,6 +156,7 @@ private: | |||
| 156 | u32 subchannel; ///< Current subchannel | 156 | u32 subchannel; ///< Current subchannel |
| 157 | u32 method_count; ///< Current method count | 157 | u32 method_count; ///< Current method count |
| 158 | u32 length_pending; ///< Large NI command length pending | 158 | u32 length_pending; ///< Large NI command length pending |
| 159 | GPUVAddr dma_get; ///< Currently read segment | ||
| 159 | bool non_incrementing; ///< Current command's NI flag | 160 | bool non_incrementing; ///< Current command's NI flag |
| 160 | bool is_last_call; | 161 | bool is_last_call; |
| 161 | }; | 162 | }; |
diff --git a/src/video_core/engines/draw_manager.cpp b/src/video_core/engines/draw_manager.cpp index 3a78421f6..4fa77b684 100644 --- a/src/video_core/engines/draw_manager.cpp +++ b/src/video_core/engines/draw_manager.cpp | |||
| @@ -91,6 +91,16 @@ void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 ind | |||
| 91 | ProcessDraw(true, num_instances); | 91 | ProcessDraw(true, num_instances); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | void DrawManager::DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first, u32 index_count) { | ||
| 95 | const auto& regs{maxwell3d->regs}; | ||
| 96 | draw_state.topology = topology; | ||
| 97 | draw_state.index_buffer = regs.index_buffer; | ||
| 98 | draw_state.index_buffer.first = index_first; | ||
| 99 | draw_state.index_buffer.count = index_count; | ||
| 100 | |||
| 101 | ProcessDrawIndirect(true); | ||
| 102 | } | ||
| 103 | |||
| 94 | void DrawManager::SetInlineIndexBuffer(u32 index) { | 104 | void DrawManager::SetInlineIndexBuffer(u32 index) { |
| 95 | draw_state.inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff)); | 105 | draw_state.inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff)); |
| 96 | draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8)); | 106 | draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8)); |
| @@ -198,4 +208,15 @@ void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) { | |||
| 198 | maxwell3d->rasterizer->Draw(draw_indexed, instance_count); | 208 | maxwell3d->rasterizer->Draw(draw_indexed, instance_count); |
| 199 | } | 209 | } |
| 200 | } | 210 | } |
| 211 | |||
| 212 | void DrawManager::ProcessDrawIndirect(bool draw_indexed) { | ||
| 213 | LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology, | ||
| 214 | draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count); | ||
| 215 | |||
| 216 | UpdateTopology(); | ||
| 217 | |||
| 218 | if (maxwell3d->ShouldExecute()) { | ||
| 219 | maxwell3d->rasterizer->DrawIndirect(draw_indexed); | ||
| 220 | } | ||
| 221 | } | ||
| 201 | } // namespace Tegra::Engines | 222 | } // namespace Tegra::Engines |
diff --git a/src/video_core/engines/draw_manager.h b/src/video_core/engines/draw_manager.h index 0e6930a9c..0cdb37f83 100644 --- a/src/video_core/engines/draw_manager.h +++ b/src/video_core/engines/draw_manager.h | |||
| @@ -32,6 +32,13 @@ public: | |||
| 32 | std::vector<u8> inline_index_draw_indexes; | 32 | std::vector<u8> inline_index_draw_indexes; |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | struct IndirectParams { | ||
| 36 | GPUVAddr start_address; | ||
| 37 | size_t buffer_size; | ||
| 38 | size_t max_draw_counts; | ||
| 39 | size_t stride; | ||
| 40 | }; | ||
| 41 | |||
| 35 | explicit DrawManager(Maxwell3D* maxwell_3d); | 42 | explicit DrawManager(Maxwell3D* maxwell_3d); |
| 36 | 43 | ||
| 37 | void ProcessMethodCall(u32 method, u32 argument); | 44 | void ProcessMethodCall(u32 method, u32 argument); |
| @@ -46,10 +53,20 @@ public: | |||
| 46 | void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, | 53 | void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, |
| 47 | u32 base_instance, u32 num_instances); | 54 | u32 base_instance, u32 num_instances); |
| 48 | 55 | ||
| 56 | void DrawIndexedIndirect(PrimitiveTopology topology, u32 index_first, u32 index_count); | ||
| 57 | |||
| 49 | const State& GetDrawState() const { | 58 | const State& GetDrawState() const { |
| 50 | return draw_state; | 59 | return draw_state; |
| 51 | } | 60 | } |
| 52 | 61 | ||
| 62 | IndirectParams& GetIndirectParams() { | ||
| 63 | return indirect_state; | ||
| 64 | } | ||
| 65 | |||
| 66 | const IndirectParams& GetIndirectParams() const { | ||
| 67 | return indirect_state; | ||
| 68 | } | ||
| 69 | |||
| 53 | private: | 70 | private: |
| 54 | void SetInlineIndexBuffer(u32 index); | 71 | void SetInlineIndexBuffer(u32 index); |
| 55 | 72 | ||
| @@ -63,7 +80,10 @@ private: | |||
| 63 | 80 | ||
| 64 | void ProcessDraw(bool draw_indexed, u32 instance_count); | 81 | void ProcessDraw(bool draw_indexed, u32 instance_count); |
| 65 | 82 | ||
| 83 | void ProcessDrawIndirect(bool draw_indexed); | ||
| 84 | |||
| 66 | Maxwell3D* maxwell3d{}; | 85 | Maxwell3D* maxwell3d{}; |
| 67 | State draw_state{}; | 86 | State draw_state{}; |
| 87 | IndirectParams indirect_state{}; | ||
| 68 | }; | 88 | }; |
| 69 | } // namespace Tegra::Engines | 89 | } // namespace Tegra::Engines |
diff --git a/src/video_core/engines/engine_interface.h b/src/video_core/engines/engine_interface.h index 26cde8584..76630272d 100644 --- a/src/video_core/engines/engine_interface.h +++ b/src/video_core/engines/engine_interface.h | |||
| @@ -17,6 +17,8 @@ public: | |||
| 17 | /// Write multiple values to the register identified by method. | 17 | /// Write multiple values to the register identified by method. |
| 18 | virtual void CallMultiMethod(u32 method, const u32* base_start, u32 amount, | 18 | virtual void CallMultiMethod(u32 method, const u32* base_start, u32 amount, |
| 19 | u32 methods_pending) = 0; | 19 | u32 methods_pending) = 0; |
| 20 | |||
| 21 | GPUVAddr current_dma_segment; | ||
| 20 | }; | 22 | }; |
| 21 | 23 | ||
| 22 | } // namespace Tegra::Engines | 24 | } // namespace Tegra::Engines |
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 8549db2e4..1cc202cc7 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp | |||
| @@ -53,42 +53,43 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||
| 53 | 53 | ||
| 54 | // Multidraw Indirect | 54 | // Multidraw Indirect |
| 55 | void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | 55 | void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { |
| 56 | SCOPE_EXIT({ | ||
| 57 | // Clean everything. | ||
| 58 | maxwell3d.regs.vertex_id_base = 0x0; | ||
| 59 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 60 | maxwell3d.CallMethod(0x8e4, 0x0, true); | ||
| 61 | maxwell3d.CallMethod(0x8e5, 0x0, true); | ||
| 62 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 63 | }); | ||
| 64 | const u32 start_indirect = parameters[0]; | 56 | const u32 start_indirect = parameters[0]; |
| 65 | const u32 end_indirect = parameters[1]; | 57 | const u32 end_indirect = parameters[1]; |
| 66 | if (start_indirect >= end_indirect) { | 58 | if (start_indirect >= end_indirect) { |
| 67 | // Nothing to do. | 59 | // Nothing to do. |
| 68 | return; | 60 | return; |
| 69 | } | 61 | } |
| 70 | const u32 padding = parameters[3]; | 62 | const auto topology = |
| 71 | const std::size_t max_draws = parameters[4]; | 63 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]); |
| 64 | const u32 padding = parameters[3]; // padding is in words | ||
| 72 | 65 | ||
| 66 | // size of each indirect segment | ||
| 73 | const u32 indirect_words = 5 + padding; | 67 | const u32 indirect_words = 5 + padding; |
| 74 | const std::size_t first_draw = start_indirect; | 68 | const u32 stride = indirect_words * sizeof(u32); |
| 75 | const std::size_t effective_draws = end_indirect - start_indirect; | 69 | const GPUVAddr start_address = maxwell3d.current_dma_segment + 4 * sizeof(u32); |
| 76 | const std::size_t last_draw = start_indirect + std::min(effective_draws, max_draws); | 70 | const std::size_t draw_count = end_indirect - start_indirect; |
| 77 | 71 | u32 lowest_first = std::numeric_limits<u32>::max(); | |
| 78 | for (std::size_t index = first_draw; index < last_draw; index++) { | 72 | u32 highest_limit = std::numeric_limits<u32>::min(); |
| 73 | for (std::size_t index = 0; index < draw_count; index++) { | ||
| 79 | const std::size_t base = index * indirect_words + 5; | 74 | const std::size_t base = index * indirect_words + 5; |
| 80 | const u32 base_vertex = parameters[base + 3]; | 75 | const u32 count = parameters[base]; |
| 81 | const u32 base_instance = parameters[base + 4]; | 76 | const u32 first_index = parameters[base + 2]; |
| 82 | maxwell3d.regs.vertex_id_base = base_vertex; | 77 | lowest_first = std::min(lowest_first, first_index); |
| 83 | maxwell3d.CallMethod(0x8e3, 0x640, true); | 78 | highest_limit = std::max(highest_limit, first_index + count); |
| 84 | maxwell3d.CallMethod(0x8e4, base_vertex, true); | ||
| 85 | maxwell3d.CallMethod(0x8e5, base_instance, true); | ||
| 86 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 87 | maxwell3d.draw_manager->DrawIndex( | ||
| 88 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]), | ||
| 89 | parameters[base + 2], parameters[base], base_vertex, base_instance, | ||
| 90 | parameters[base + 1]); | ||
| 91 | } | 79 | } |
| 80 | |||
| 81 | const u32 base_vertex = parameters[8]; | ||
| 82 | const u32 base_instance = parameters[9]; | ||
| 83 | maxwell3d.CallMethod(0x8e3, 0x640, true); | ||
| 84 | maxwell3d.CallMethod(0x8e4, base_vertex, true); | ||
| 85 | maxwell3d.CallMethod(0x8e5, base_instance, true); | ||
| 86 | auto& params = maxwell3d.draw_manager->GetIndirectParams(); | ||
| 87 | params.start_address = start_address; | ||
| 88 | params.buffer_size = sizeof(u32) + stride * draw_count; | ||
| 89 | params.max_draw_counts = draw_count; | ||
| 90 | params.stride = stride; | ||
| 91 | maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||
| 92 | maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, highest_limit); | ||
| 92 | } | 93 | } |
| 93 | 94 | ||
| 94 | // Multi-layer Clear | 95 | // Multi-layer Clear |
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index b6907463c..a2a651f34 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -42,6 +42,9 @@ public: | |||
| 42 | /// Dispatches a draw invocation | 42 | /// Dispatches a draw invocation |
| 43 | virtual void Draw(bool is_indexed, u32 instance_count) = 0; | 43 | virtual void Draw(bool is_indexed, u32 instance_count) = 0; |
| 44 | 44 | ||
| 45 | /// Dispatches an indirect draw invocation | ||
| 46 | virtual void DrawIndirect(bool is_indexed) {} | ||
| 47 | |||
| 45 | /// Clear the current framebuffer | 48 | /// Clear the current framebuffer |
| 46 | virtual void Clear(u32 layer_count) = 0; | 49 | virtual void Clear(u32 layer_count) = 0; |
| 47 | 50 | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index ac1eb9895..9b75f33dd 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -180,7 +180,8 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra | |||
| 180 | 180 | ||
| 181 | RasterizerVulkan::~RasterizerVulkan() = default; | 181 | RasterizerVulkan::~RasterizerVulkan() = default; |
| 182 | 182 | ||
| 183 | void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { | 183 | template <typename Func> |
| 184 | void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { | ||
| 184 | MICROPROFILE_SCOPE(Vulkan_Drawing); | 185 | MICROPROFILE_SCOPE(Vulkan_Drawing); |
| 185 | 186 | ||
| 186 | SCOPE_EXIT({ gpu.TickWork(); }); | 187 | SCOPE_EXIT({ gpu.TickWork(); }); |
| @@ -201,22 +202,50 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { | |||
| 201 | 202 | ||
| 202 | UpdateDynamicStates(); | 203 | UpdateDynamicStates(); |
| 203 | 204 | ||
| 204 | const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); | 205 | draw_func(); |
| 205 | const u32 num_instances{instance_count}; | 206 | |
| 206 | const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)}; | ||
| 207 | scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { | ||
| 208 | if (draw_params.is_indexed) { | ||
| 209 | cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, | ||
| 210 | draw_params.first_index, draw_params.base_vertex, | ||
| 211 | draw_params.base_instance); | ||
| 212 | } else { | ||
| 213 | cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances, | ||
| 214 | draw_params.base_vertex, draw_params.base_instance); | ||
| 215 | } | ||
| 216 | }); | ||
| 217 | EndTransformFeedback(); | 207 | EndTransformFeedback(); |
| 218 | } | 208 | } |
| 219 | 209 | ||
| 210 | void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { | ||
| 211 | PrepareDraw(is_indexed, [this, is_indexed, instance_count] { | ||
| 212 | const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); | ||
| 213 | const u32 num_instances{instance_count}; | ||
| 214 | const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)}; | ||
| 215 | scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { | ||
| 216 | if (draw_params.is_indexed) { | ||
| 217 | cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, | ||
| 218 | draw_params.first_index, draw_params.base_vertex, | ||
| 219 | draw_params.base_instance); | ||
| 220 | } else { | ||
| 221 | cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances, | ||
| 222 | draw_params.base_vertex, draw_params.base_instance); | ||
| 223 | } | ||
| 224 | }); | ||
| 225 | }); | ||
| 226 | } | ||
| 227 | |||
| 228 | void RasterizerVulkan::DrawIndirect(bool is_indexed) { | ||
| 229 | PrepareDraw(is_indexed, [this, is_indexed] { | ||
| 230 | const auto params = maxwell3d->draw_manager->GetIndirectParams(); | ||
| 231 | const auto [buffer, offset] = buffer_cache.ObtainBuffer( | ||
| 232 | params.start_address, static_cast<u32>(params.buffer_size), true, false); | ||
| 233 | scheduler.Record([buffer_obj = buffer->Handle(), offset, | ||
| 234 | max_draw_counts = params.max_draw_counts, stride = params.stride, | ||
| 235 | is_indexed](vk::CommandBuffer cmdbuf) { | ||
| 236 | if (is_indexed) { | ||
| 237 | cmdbuf.DrawIndexedIndirectCount(buffer_obj, offset + 4ULL, buffer_obj, offset, | ||
| 238 | static_cast<u32>(max_draw_counts), | ||
| 239 | static_cast<u32>(stride)); | ||
| 240 | } else { | ||
| 241 | cmdbuf.DrawIndirectCount(buffer_obj, offset + 4ULL, buffer_obj, offset, | ||
| 242 | static_cast<u32>(max_draw_counts), | ||
| 243 | static_cast<u32>(stride)); | ||
| 244 | } | ||
| 245 | }); | ||
| 246 | }); | ||
| 247 | } | ||
| 248 | |||
| 220 | void RasterizerVulkan::Clear(u32 layer_count) { | 249 | void RasterizerVulkan::Clear(u32 layer_count) { |
| 221 | MICROPROFILE_SCOPE(Vulkan_Clearing); | 250 | MICROPROFILE_SCOPE(Vulkan_Clearing); |
| 222 | 251 | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index ee483cfd9..bc43a8a1f 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -65,6 +65,7 @@ public: | |||
| 65 | ~RasterizerVulkan() override; | 65 | ~RasterizerVulkan() override; |
| 66 | 66 | ||
| 67 | void Draw(bool is_indexed, u32 instance_count) override; | 67 | void Draw(bool is_indexed, u32 instance_count) override; |
| 68 | void DrawIndirect(bool is_indexed) override; | ||
| 68 | void Clear(u32 layer_count) override; | 69 | void Clear(u32 layer_count) override; |
| 69 | void DispatchCompute() override; | 70 | void DispatchCompute() override; |
| 70 | void ResetCounter(VideoCore::QueryType type) override; | 71 | void ResetCounter(VideoCore::QueryType type) override; |
| @@ -114,6 +115,9 @@ private: | |||
| 114 | 115 | ||
| 115 | static constexpr VkDeviceSize DEFAULT_BUFFER_SIZE = 4 * sizeof(float); | 116 | static constexpr VkDeviceSize DEFAULT_BUFFER_SIZE = 4 * sizeof(float); |
| 116 | 117 | ||
| 118 | template <typename Func> | ||
| 119 | void PrepareDraw(bool is_indexed, Func&&); | ||
| 120 | |||
| 117 | void FlushWork(); | 121 | void FlushWork(); |
| 118 | 122 | ||
| 119 | void UpdateDynamicStates(); | 123 | void UpdateDynamicStates(); |
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index c4d31681a..477fc428b 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -350,7 +350,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 350 | .sampleRateShading = true, | 350 | .sampleRateShading = true, |
| 351 | .dualSrcBlend = true, | 351 | .dualSrcBlend = true, |
| 352 | .logicOp = true, | 352 | .logicOp = true, |
| 353 | .multiDrawIndirect = false, | 353 | .multiDrawIndirect = true, |
| 354 | .drawIndirectFirstInstance = false, | 354 | .drawIndirectFirstInstance = false, |
| 355 | .depthClamp = true, | 355 | .depthClamp = true, |
| 356 | .depthBiasClamp = true, | 356 | .depthBiasClamp = true, |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 7dca7341c..c58c4c1c4 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp | |||
| @@ -94,6 +94,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 94 | X(vkCmdDispatch); | 94 | X(vkCmdDispatch); |
| 95 | X(vkCmdDraw); | 95 | X(vkCmdDraw); |
| 96 | X(vkCmdDrawIndexed); | 96 | X(vkCmdDrawIndexed); |
| 97 | X(vkCmdDrawIndirectCount); | ||
| 98 | X(vkCmdDrawIndexedIndirectCount); | ||
| 97 | X(vkCmdEndQuery); | 99 | X(vkCmdEndQuery); |
| 98 | X(vkCmdEndRenderPass); | 100 | X(vkCmdEndRenderPass); |
| 99 | X(vkCmdEndTransformFeedbackEXT); | 101 | X(vkCmdEndTransformFeedbackEXT); |
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 8bd4fd4d9..9bd158dce 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h | |||
| @@ -213,6 +213,8 @@ struct DeviceDispatch : InstanceDispatch { | |||
| 213 | PFN_vkCmdDispatch vkCmdDispatch{}; | 213 | PFN_vkCmdDispatch vkCmdDispatch{}; |
| 214 | PFN_vkCmdDraw vkCmdDraw{}; | 214 | PFN_vkCmdDraw vkCmdDraw{}; |
| 215 | PFN_vkCmdDrawIndexed vkCmdDrawIndexed{}; | 215 | PFN_vkCmdDrawIndexed vkCmdDrawIndexed{}; |
| 216 | PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount{}; | ||
| 217 | PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount{}; | ||
| 216 | PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{}; | 218 | PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{}; |
| 217 | PFN_vkCmdEndQuery vkCmdEndQuery{}; | 219 | PFN_vkCmdEndQuery vkCmdEndQuery{}; |
| 218 | PFN_vkCmdEndRenderPass vkCmdEndRenderPass{}; | 220 | PFN_vkCmdEndRenderPass vkCmdEndRenderPass{}; |
| @@ -1019,6 +1021,19 @@ public: | |||
| 1019 | first_instance); | 1021 | first_instance); |
| 1020 | } | 1022 | } |
| 1021 | 1023 | ||
| 1024 | void DrawIndirectCount(VkBuffer src_buffer, VkDeviceSize src_offset, VkBuffer count_buffer, | ||
| 1025 | VkDeviceSize count_offset, u32 draw_count, u32 stride) const noexcept { | ||
| 1026 | dld->vkCmdDrawIndirectCount(handle, src_buffer, src_offset, count_buffer, count_offset, | ||
| 1027 | draw_count, stride); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | void DrawIndexedIndirectCount(VkBuffer src_buffer, VkDeviceSize src_offset, | ||
| 1031 | VkBuffer count_buffer, VkDeviceSize count_offset, u32 draw_count, | ||
| 1032 | u32 stride) const noexcept { | ||
| 1033 | dld->vkCmdDrawIndexedIndirectCount(handle, src_buffer, src_offset, count_buffer, | ||
| 1034 | count_offset, draw_count, stride); | ||
| 1035 | } | ||
| 1036 | |||
| 1022 | void ClearAttachments(Span<VkClearAttachment> attachments, | 1037 | void ClearAttachments(Span<VkClearAttachment> attachments, |
| 1023 | Span<VkClearRect> rects) const noexcept { | 1038 | Span<VkClearRect> rects) const noexcept { |
| 1024 | dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(), | 1039 | dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(), |