Merge pull request #9401 from vonchenplus/draw_manager
video_core: Implement maxwell3d draw manager and split draw logic
This commit is contained in:
		| @@ -33,6 +33,8 @@ add_library(video_core STATIC | |||||||
|     engines/sw_blitter/converter.cpp |     engines/sw_blitter/converter.cpp | ||||||
|     engines/sw_blitter/converter.h |     engines/sw_blitter/converter.h | ||||||
|     engines/const_buffer_info.h |     engines/const_buffer_info.h | ||||||
|  |     engines/draw_manager.cpp | ||||||
|  |     engines/draw_manager.h | ||||||
|     engines/engine_interface.h |     engines/engine_interface.h | ||||||
|     engines/engine_upload.cpp |     engines/engine_upload.cpp | ||||||
|     engines/engine_upload.h |     engines/engine_upload.h | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ | |||||||
| #include "video_core/control/channel_state_cache.h" | #include "video_core/control/channel_state_cache.h" | ||||||
| #include "video_core/delayed_destruction_ring.h" | #include "video_core/delayed_destruction_ring.h" | ||||||
| #include "video_core/dirty_flags.h" | #include "video_core/dirty_flags.h" | ||||||
|  | #include "video_core/engines/draw_manager.h" | ||||||
| #include "video_core/engines/kepler_compute.h" | #include "video_core/engines/kepler_compute.h" | ||||||
| #include "video_core/engines/maxwell_3d.h" | #include "video_core/engines/maxwell_3d.h" | ||||||
| #include "video_core/memory_manager.h" | #include "video_core/memory_manager.h" | ||||||
| @@ -664,9 +665,10 @@ void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) { | |||||||
|     if (is_indexed) { |     if (is_indexed) { | ||||||
|         BindHostIndexBuffer(); |         BindHostIndexBuffer(); | ||||||
|     } else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { |     } else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { | ||||||
|         const auto& regs = maxwell3d->regs; |         const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); | ||||||
|         if (regs.draw.topology == Maxwell::PrimitiveTopology::Quads) { |         if (draw_state.topology == Maxwell::PrimitiveTopology::Quads) { | ||||||
|             runtime.BindQuadArrayIndexBuffer(regs.vertex_buffer.first, regs.vertex_buffer.count); |             runtime.BindQuadArrayIndexBuffer(draw_state.vertex_buffer.first, | ||||||
|  |                                              draw_state.vertex_buffer.count); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     BindHostVertexBuffers(); |     BindHostVertexBuffers(); | ||||||
| @@ -993,28 +995,29 @@ void BufferCache<P>::BindHostIndexBuffer() { | |||||||
|     TouchBuffer(buffer, index_buffer.buffer_id); |     TouchBuffer(buffer, index_buffer.buffer_id); | ||||||
|     const u32 offset = buffer.Offset(index_buffer.cpu_addr); |     const u32 offset = buffer.Offset(index_buffer.cpu_addr); | ||||||
|     const u32 size = index_buffer.size; |     const u32 size = index_buffer.size; | ||||||
|     if (maxwell3d->inline_index_draw_indexes.size()) { |     const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); | ||||||
|  |     if (!draw_state.inline_index_draw_indexes.empty()) { | ||||||
|         if constexpr (USE_MEMORY_MAPS) { |         if constexpr (USE_MEMORY_MAPS) { | ||||||
|             auto upload_staging = runtime.UploadStagingBuffer(size); |             auto upload_staging = runtime.UploadStagingBuffer(size); | ||||||
|             std::array<BufferCopy, 1> copies{ |             std::array<BufferCopy, 1> copies{ | ||||||
|                 {BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}}; |                 {BufferCopy{.src_offset = upload_staging.offset, .dst_offset = 0, .size = size}}}; | ||||||
|             std::memcpy(upload_staging.mapped_span.data(), |             std::memcpy(upload_staging.mapped_span.data(), | ||||||
|                         maxwell3d->inline_index_draw_indexes.data(), size); |                         draw_state.inline_index_draw_indexes.data(), size); | ||||||
|             runtime.CopyBuffer(buffer, upload_staging.buffer, copies); |             runtime.CopyBuffer(buffer, upload_staging.buffer, copies); | ||||||
|         } else { |         } else { | ||||||
|             buffer.ImmediateUpload(0, maxwell3d->inline_index_draw_indexes); |             buffer.ImmediateUpload(0, draw_state.inline_index_draw_indexes); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         SynchronizeBuffer(buffer, index_buffer.cpu_addr, size); |         SynchronizeBuffer(buffer, index_buffer.cpu_addr, size); | ||||||
|     } |     } | ||||||
|     if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { |     if constexpr (HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { | ||||||
|         const u32 new_offset = offset + maxwell3d->regs.index_buffer.first * |         const u32 new_offset = | ||||||
|                                             maxwell3d->regs.index_buffer.FormatSizeInBytes(); |             offset + draw_state.index_buffer.first * draw_state.index_buffer.FormatSizeInBytes(); | ||||||
|         runtime.BindIndexBuffer(buffer, new_offset, size); |         runtime.BindIndexBuffer(buffer, new_offset, size); | ||||||
|     } else { |     } else { | ||||||
|         runtime.BindIndexBuffer(maxwell3d->regs.draw.topology, maxwell3d->regs.index_buffer.format, |         runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format, | ||||||
|                                 maxwell3d->regs.index_buffer.first, |                                 draw_state.index_buffer.first, draw_state.index_buffer.count, | ||||||
|                                 maxwell3d->regs.index_buffer.count, buffer, offset, size); |                                 buffer, offset, size); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1282,15 +1285,16 @@ template <class P> | |||||||
| void BufferCache<P>::UpdateIndexBuffer() { | void BufferCache<P>::UpdateIndexBuffer() { | ||||||
|     // We have to check for the dirty flags and index count |     // We have to check for the dirty flags and index count | ||||||
|     // The index count is currently changed without updating the dirty flags |     // The index count is currently changed without updating the dirty flags | ||||||
|     const auto& index_array = maxwell3d->regs.index_buffer; |     const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); | ||||||
|  |     const auto& index_array = draw_state.index_buffer; | ||||||
|     auto& flags = maxwell3d->dirty.flags; |     auto& flags = maxwell3d->dirty.flags; | ||||||
|     if (!flags[Dirty::IndexBuffer] && last_index_count == index_array.count) { |     if (!flags[Dirty::IndexBuffer] && last_index_count == index_array.count) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     flags[Dirty::IndexBuffer] = false; |     flags[Dirty::IndexBuffer] = false; | ||||||
|     last_index_count = index_array.count; |     last_index_count = index_array.count; | ||||||
|     if (maxwell3d->inline_index_draw_indexes.size()) { |     if (!draw_state.inline_index_draw_indexes.empty()) { | ||||||
|         auto inline_index_size = static_cast<u32>(maxwell3d->inline_index_draw_indexes.size()); |         auto inline_index_size = static_cast<u32>(draw_state.inline_index_draw_indexes.size()); | ||||||
|         index_buffer = Binding{ |         index_buffer = Binding{ | ||||||
|             .cpu_addr = 0, |             .cpu_addr = 0, | ||||||
|             .size = inline_index_size, |             .size = inline_index_size, | ||||||
|   | |||||||
							
								
								
									
										191
									
								
								src/video_core/engines/draw_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								src/video_core/engines/draw_manager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #include "video_core/dirty_flags.h" | ||||||
|  | #include "video_core/engines/draw_manager.h" | ||||||
|  | #include "video_core/rasterizer_interface.h" | ||||||
|  |  | ||||||
|  | namespace Tegra::Engines { | ||||||
|  | DrawManager::DrawManager(Maxwell3D* maxwell3d_) : maxwell3d(maxwell3d_) {} | ||||||
|  |  | ||||||
|  | void DrawManager::ProcessMethodCall(u32 method, u32 argument) { | ||||||
|  |     const auto& regs{maxwell3d->regs}; | ||||||
|  |     switch (method) { | ||||||
|  |     case MAXWELL3D_REG_INDEX(clear_surface): | ||||||
|  |         return Clear(1); | ||||||
|  |     case MAXWELL3D_REG_INDEX(draw.begin): | ||||||
|  |         return DrawBegin(); | ||||||
|  |     case MAXWELL3D_REG_INDEX(draw.end): | ||||||
|  |         return DrawEnd(); | ||||||
|  |     case MAXWELL3D_REG_INDEX(vertex_buffer.first): | ||||||
|  |     case MAXWELL3D_REG_INDEX(vertex_buffer.count): | ||||||
|  |     case MAXWELL3D_REG_INDEX(index_buffer.first): | ||||||
|  |         break; | ||||||
|  |     case MAXWELL3D_REG_INDEX(index_buffer.count): | ||||||
|  |         draw_state.draw_indexed = true; | ||||||
|  |         break; | ||||||
|  |     case MAXWELL3D_REG_INDEX(index_buffer32_subsequent): | ||||||
|  |     case MAXWELL3D_REG_INDEX(index_buffer16_subsequent): | ||||||
|  |     case MAXWELL3D_REG_INDEX(index_buffer8_subsequent): | ||||||
|  |         draw_state.instance_count++; | ||||||
|  |         [[fallthrough]]; | ||||||
|  |     case MAXWELL3D_REG_INDEX(index_buffer32_first): | ||||||
|  |     case MAXWELL3D_REG_INDEX(index_buffer16_first): | ||||||
|  |     case MAXWELL3D_REG_INDEX(index_buffer8_first): | ||||||
|  |         return DrawIndexSmall(argument); | ||||||
|  |     case MAXWELL3D_REG_INDEX(draw_inline_index): | ||||||
|  |         SetInlineIndexBuffer(argument); | ||||||
|  |         break; | ||||||
|  |     case MAXWELL3D_REG_INDEX(inline_index_2x16.even): | ||||||
|  |         SetInlineIndexBuffer(regs.inline_index_2x16.even); | ||||||
|  |         SetInlineIndexBuffer(regs.inline_index_2x16.odd); | ||||||
|  |         break; | ||||||
|  |     case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): | ||||||
|  |         SetInlineIndexBuffer(regs.inline_index_4x8.index0); | ||||||
|  |         SetInlineIndexBuffer(regs.inline_index_4x8.index1); | ||||||
|  |         SetInlineIndexBuffer(regs.inline_index_4x8.index2); | ||||||
|  |         SetInlineIndexBuffer(regs.inline_index_4x8.index3); | ||||||
|  |         break; | ||||||
|  |     case MAXWELL3D_REG_INDEX(topology_override): | ||||||
|  |         use_topology_override = true; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::Clear(u32 layer_count) { | ||||||
|  |     maxwell3d->rasterizer->Clear(layer_count); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::DrawDeferred() { | ||||||
|  |     if (draw_state.draw_mode != DrawMode::Instance || draw_state.instance_count == 0) | ||||||
|  |         return; | ||||||
|  |     DrawEnd(draw_state.instance_count + 1, true); | ||||||
|  |     draw_state.instance_count = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, | ||||||
|  |                             u32 base_instance, u32 num_instances) { | ||||||
|  |     draw_state.topology = topology; | ||||||
|  |     draw_state.vertex_buffer.first = vertex_first; | ||||||
|  |     draw_state.vertex_buffer.count = vertex_count; | ||||||
|  |     draw_state.base_instance = base_instance; | ||||||
|  |     ProcessDraw(false, num_instances); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, | ||||||
|  |                             u32 base_index, u32 base_instance, u32 num_instances) { | ||||||
|  |     const auto& regs{maxwell3d->regs}; | ||||||
|  |     draw_state.topology = topology; | ||||||
|  |     draw_state.index_buffer = regs.index_buffer; | ||||||
|  |     draw_state.index_buffer.first = index_first; | ||||||
|  |     draw_state.index_buffer.count = index_count; | ||||||
|  |     draw_state.base_index = base_index; | ||||||
|  |     draw_state.base_instance = base_instance; | ||||||
|  |     ProcessDraw(true, num_instances); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::SetInlineIndexBuffer(u32 index) { | ||||||
|  |     draw_state.inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff)); | ||||||
|  |     draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8)); | ||||||
|  |     draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16)); | ||||||
|  |     draw_state.inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24)); | ||||||
|  |     draw_state.draw_mode = DrawMode::InlineIndex; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::DrawBegin() { | ||||||
|  |     const auto& regs{maxwell3d->regs}; | ||||||
|  |     auto reset_instance_count = regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First; | ||||||
|  |     auto increment_instance_count = | ||||||
|  |         regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent; | ||||||
|  |     if (reset_instance_count) { | ||||||
|  |         DrawDeferred(); | ||||||
|  |         draw_state.instance_count = 0; | ||||||
|  |         draw_state.draw_mode = DrawMode::General; | ||||||
|  |     } else if (increment_instance_count) { | ||||||
|  |         draw_state.instance_count++; | ||||||
|  |         draw_state.draw_mode = DrawMode::Instance; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     draw_state.topology = regs.draw.topology; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::DrawEnd(u32 instance_count, bool force_draw) { | ||||||
|  |     const auto& regs{maxwell3d->regs}; | ||||||
|  |     switch (draw_state.draw_mode) { | ||||||
|  |     case DrawMode::Instance: | ||||||
|  |         if (!force_draw) | ||||||
|  |             break; | ||||||
|  |         [[fallthrough]]; | ||||||
|  |     case DrawMode::General: | ||||||
|  |         draw_state.base_instance = regs.global_base_instance_index; | ||||||
|  |         draw_state.base_index = regs.global_base_vertex_index; | ||||||
|  |         if (draw_state.draw_indexed) { | ||||||
|  |             draw_state.index_buffer = regs.index_buffer; | ||||||
|  |             ProcessDraw(true, instance_count); | ||||||
|  |         } else { | ||||||
|  |             draw_state.vertex_buffer = regs.vertex_buffer; | ||||||
|  |             ProcessDraw(false, instance_count); | ||||||
|  |         } | ||||||
|  |         draw_state.draw_indexed = false; | ||||||
|  |         break; | ||||||
|  |     case DrawMode::InlineIndex: | ||||||
|  |         draw_state.base_instance = regs.global_base_instance_index; | ||||||
|  |         draw_state.base_index = regs.global_base_vertex_index; | ||||||
|  |         draw_state.index_buffer = regs.index_buffer; | ||||||
|  |         draw_state.index_buffer.count = | ||||||
|  |             static_cast<u32>(draw_state.inline_index_draw_indexes.size() / 4); | ||||||
|  |         draw_state.index_buffer.format = Maxwell3D::Regs::IndexFormat::UnsignedInt; | ||||||
|  |         ProcessDraw(true, instance_count); | ||||||
|  |         draw_state.inline_index_draw_indexes.clear(); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::DrawIndexSmall(u32 argument) { | ||||||
|  |     const auto& regs{maxwell3d->regs}; | ||||||
|  |     IndexBufferSmall index_small_params{argument}; | ||||||
|  |     draw_state.base_instance = regs.global_base_instance_index; | ||||||
|  |     draw_state.base_index = regs.global_base_vertex_index; | ||||||
|  |     draw_state.index_buffer = regs.index_buffer; | ||||||
|  |     draw_state.index_buffer.first = index_small_params.first; | ||||||
|  |     draw_state.index_buffer.count = index_small_params.count; | ||||||
|  |     draw_state.topology = index_small_params.topology; | ||||||
|  |     maxwell3d->dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||||||
|  |     ProcessDraw(true, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::ProcessTopologyOverride() { | ||||||
|  |     if (!use_topology_override) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     const auto& regs{maxwell3d->regs}; | ||||||
|  |     switch (regs.topology_override) { | ||||||
|  |     case PrimitiveTopologyOverride::None: | ||||||
|  |         break; | ||||||
|  |     case PrimitiveTopologyOverride::Points: | ||||||
|  |         draw_state.topology = PrimitiveTopology::Points; | ||||||
|  |         break; | ||||||
|  |     case PrimitiveTopologyOverride::Lines: | ||||||
|  |         draw_state.topology = PrimitiveTopology::Lines; | ||||||
|  |         break; | ||||||
|  |     case PrimitiveTopologyOverride::LineStrip: | ||||||
|  |         draw_state.topology = PrimitiveTopology::LineStrip; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         draw_state.topology = static_cast<PrimitiveTopology>(regs.topology_override); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void DrawManager::ProcessDraw(bool draw_indexed, u32 instance_count) { | ||||||
|  |     LOG_TRACE(HW_GPU, "called, topology={}, count={}", draw_state.topology.Value(), | ||||||
|  |               draw_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count); | ||||||
|  |  | ||||||
|  |     ProcessTopologyOverride(); | ||||||
|  |  | ||||||
|  |     if (maxwell3d->ShouldExecute()) | ||||||
|  |         maxwell3d->rasterizer->Draw(draw_indexed, instance_count); | ||||||
|  | } | ||||||
|  | } // namespace Tegra::Engines | ||||||
							
								
								
									
										69
									
								
								src/video_core/engines/draw_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/video_core/engines/draw_manager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "video_core/engines/maxwell_3d.h" | ||||||
|  |  | ||||||
|  | namespace VideoCore { | ||||||
|  | class RasterizerInterface; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | namespace Tegra::Engines { | ||||||
|  | using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology; | ||||||
|  | using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride; | ||||||
|  | using IndexBuffer = Maxwell3D::Regs::IndexBuffer; | ||||||
|  | using VertexBuffer = Maxwell3D::Regs::VertexBuffer; | ||||||
|  | using IndexBufferSmall = Maxwell3D::Regs::IndexBufferSmall; | ||||||
|  |  | ||||||
|  | class DrawManager { | ||||||
|  | public: | ||||||
|  |     enum class DrawMode : u32 { General = 0, Instance, InlineIndex }; | ||||||
|  |     struct State { | ||||||
|  |         PrimitiveTopology topology{}; | ||||||
|  |         DrawMode draw_mode{}; | ||||||
|  |         bool draw_indexed{}; | ||||||
|  |         u32 base_index{}; | ||||||
|  |         VertexBuffer vertex_buffer; | ||||||
|  |         IndexBuffer index_buffer; | ||||||
|  |         u32 base_instance{}; | ||||||
|  |         u32 instance_count{}; | ||||||
|  |         std::vector<u8> inline_index_draw_indexes; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     explicit DrawManager(Maxwell3D* maxwell_3d); | ||||||
|  |  | ||||||
|  |     void ProcessMethodCall(u32 method, u32 argument); | ||||||
|  |  | ||||||
|  |     void Clear(u32 layer_count); | ||||||
|  |  | ||||||
|  |     void DrawDeferred(); | ||||||
|  |  | ||||||
|  |     void DrawArray(PrimitiveTopology topology, u32 vertex_first, u32 vertex_count, | ||||||
|  |                    u32 base_instance, u32 num_instances); | ||||||
|  |  | ||||||
|  |     void DrawIndex(PrimitiveTopology topology, u32 index_first, u32 index_count, u32 base_index, | ||||||
|  |                    u32 base_instance, u32 num_instances); | ||||||
|  |  | ||||||
|  |     const State& GetDrawState() const { | ||||||
|  |         return draw_state; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void SetInlineIndexBuffer(u32 index); | ||||||
|  |  | ||||||
|  |     void DrawBegin(); | ||||||
|  |  | ||||||
|  |     void DrawEnd(u32 instance_count = 1, bool force_draw = false); | ||||||
|  |  | ||||||
|  |     void DrawIndexSmall(u32 argument); | ||||||
|  |  | ||||||
|  |     void ProcessTopologyOverride(); | ||||||
|  |  | ||||||
|  |     void ProcessDraw(bool draw_indexed, u32 instance_count); | ||||||
|  |  | ||||||
|  |     Maxwell3D* maxwell3d{}; | ||||||
|  |     State draw_state{}; | ||||||
|  |     bool use_topology_override{}; | ||||||
|  | }; | ||||||
|  | } // namespace Tegra::Engines | ||||||
| @@ -7,6 +7,7 @@ | |||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/core_timing.h" | #include "core/core_timing.h" | ||||||
| #include "video_core/dirty_flags.h" | #include "video_core/dirty_flags.h" | ||||||
|  | #include "video_core/engines/draw_manager.h" | ||||||
| #include "video_core/engines/maxwell_3d.h" | #include "video_core/engines/maxwell_3d.h" | ||||||
| #include "video_core/gpu.h" | #include "video_core/gpu.h" | ||||||
| #include "video_core/memory_manager.h" | #include "video_core/memory_manager.h" | ||||||
| @@ -21,8 +22,10 @@ using VideoCore::QueryType; | |||||||
| constexpr u32 MacroRegistersStart = 0xE00; | constexpr u32 MacroRegistersStart = 0xE00; | ||||||
|  |  | ||||||
| Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_) | Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_) | ||||||
|     : system{system_}, memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, |     : draw_manager{std::make_unique<DrawManager>(this)}, system{system_}, | ||||||
|       upload_state{memory_manager, regs.upload} { |       memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, upload_state{ | ||||||
|  |                                                                                 memory_manager, | ||||||
|  |                                                                                 regs.upload} { | ||||||
|     dirty.flags.flip(); |     dirty.flags.flip(); | ||||||
|     InitializeRegisterDefaults(); |     InitializeRegisterDefaults(); | ||||||
| } | } | ||||||
| @@ -116,16 +119,6 @@ void Maxwell3D::InitializeRegisterDefaults() { | |||||||
|     regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill; |     regs.polygon_mode_front = Maxwell3D::Regs::PolygonMode::Fill; | ||||||
|  |  | ||||||
|     shadow_state = regs; |     shadow_state = regs; | ||||||
|  |  | ||||||
|     draw_command[MAXWELL3D_REG_INDEX(draw.end)] = true; |  | ||||||
|     draw_command[MAXWELL3D_REG_INDEX(draw.begin)] = true; |  | ||||||
|     draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.first)] = true; |  | ||||||
|     draw_command[MAXWELL3D_REG_INDEX(vertex_buffer.count)] = true; |  | ||||||
|     draw_command[MAXWELL3D_REG_INDEX(index_buffer.first)] = true; |  | ||||||
|     draw_command[MAXWELL3D_REG_INDEX(index_buffer.count)] = true; |  | ||||||
|     draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true; |  | ||||||
|     draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true; |  | ||||||
|     draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { | void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { | ||||||
| @@ -213,29 +206,6 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume | |||||||
|         return ProcessCBBind(3); |         return ProcessCBBind(3); | ||||||
|     case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): |     case MAXWELL3D_REG_INDEX(bind_groups[4].raw_config): | ||||||
|         return ProcessCBBind(4); |         return ProcessCBBind(4); | ||||||
|     case MAXWELL3D_REG_INDEX(index_buffer32_first): |  | ||||||
|         regs.index_buffer.count = regs.index_buffer32_first.count; |  | ||||||
|         regs.index_buffer.first = regs.index_buffer32_first.first; |  | ||||||
|         dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; |  | ||||||
|         draw_indexed = true; |  | ||||||
|         return ProcessDraw(); |  | ||||||
|     case MAXWELL3D_REG_INDEX(index_buffer16_first): |  | ||||||
|         regs.index_buffer.count = regs.index_buffer16_first.count; |  | ||||||
|         regs.index_buffer.first = regs.index_buffer16_first.first; |  | ||||||
|         dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; |  | ||||||
|         draw_indexed = true; |  | ||||||
|         return ProcessDraw(); |  | ||||||
|     case MAXWELL3D_REG_INDEX(index_buffer8_first): |  | ||||||
|         regs.index_buffer.count = regs.index_buffer8_first.count; |  | ||||||
|         regs.index_buffer.first = regs.index_buffer8_first.first; |  | ||||||
|         dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; |  | ||||||
|         draw_indexed = true; |  | ||||||
|         return ProcessDraw(); |  | ||||||
|     case MAXWELL3D_REG_INDEX(topology_override): |  | ||||||
|         use_topology_override = true; |  | ||||||
|         return; |  | ||||||
|     case MAXWELL3D_REG_INDEX(clear_surface): |  | ||||||
|         return ProcessClearBuffers(1); |  | ||||||
|     case MAXWELL3D_REG_INDEX(report_semaphore.query): |     case MAXWELL3D_REG_INDEX(report_semaphore.query): | ||||||
|         return ProcessQueryGet(); |         return ProcessQueryGet(); | ||||||
|     case MAXWELL3D_REG_INDEX(render_enable.mode): |     case MAXWELL3D_REG_INDEX(render_enable.mode): | ||||||
| @@ -254,6 +224,9 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume | |||||||
|         return rasterizer->FragmentBarrier(); |         return rasterizer->FragmentBarrier(); | ||||||
|     case MAXWELL3D_REG_INDEX(tiled_cache_barrier): |     case MAXWELL3D_REG_INDEX(tiled_cache_barrier): | ||||||
|         return rasterizer->TiledCacheBarrier(); |         return rasterizer->TiledCacheBarrier(); | ||||||
|  |     default: | ||||||
|  |         draw_manager->ProcessMethodCall(method, argument); | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -268,7 +241,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) | |||||||
|     // Execute the current macro. |     // Execute the current macro. | ||||||
|     macro_engine->Execute(macro_positions[entry], parameters); |     macro_engine->Execute(macro_positions[entry], parameters); | ||||||
|  |  | ||||||
|     ProcessDeferredDraw(); |     draw_manager->DrawDeferred(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { | void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { | ||||||
| @@ -291,62 +264,7 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { | |||||||
|     const u32 argument = ProcessShadowRam(method, method_argument); |     const u32 argument = ProcessShadowRam(method, method_argument); | ||||||
|     ProcessDirtyRegisters(method, argument); |     ProcessDirtyRegisters(method, argument); | ||||||
|  |  | ||||||
|     if (draw_command[method]) { |     ProcessMethodCall(method, argument, method_argument, is_last_call); | ||||||
|         regs.reg_array[method] = method_argument; |  | ||||||
|         deferred_draw_method.push_back(method); |  | ||||||
|         auto update_inline_index = [&](const u32 index) { |  | ||||||
|             inline_index_draw_indexes.push_back(static_cast<u8>(index & 0x000000ff)); |  | ||||||
|             inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x0000ff00) >> 8)); |  | ||||||
|             inline_index_draw_indexes.push_back(static_cast<u8>((index & 0x00ff0000) >> 16)); |  | ||||||
|             inline_index_draw_indexes.push_back(static_cast<u8>((index & 0xff000000) >> 24)); |  | ||||||
|             draw_mode = DrawMode::InlineIndex; |  | ||||||
|         }; |  | ||||||
|         switch (method) { |  | ||||||
|         case MAXWELL3D_REG_INDEX(draw.begin): { |  | ||||||
|             draw_mode = |  | ||||||
|                 (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || |  | ||||||
|                         (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) |  | ||||||
|                     ? DrawMode::Instance |  | ||||||
|                     : DrawMode::General; |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|         case MAXWELL3D_REG_INDEX(draw.end): |  | ||||||
|             switch (draw_mode) { |  | ||||||
|             case DrawMode::General: |  | ||||||
|                 ProcessDraw(); |  | ||||||
|                 break; |  | ||||||
|             case DrawMode::InlineIndex: |  | ||||||
|                 regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4); |  | ||||||
|                 regs.index_buffer.format = Regs::IndexFormat::UnsignedInt; |  | ||||||
|                 draw_indexed = true; |  | ||||||
|                 ProcessDraw(); |  | ||||||
|                 inline_index_draw_indexes.clear(); |  | ||||||
|                 break; |  | ||||||
|             case DrawMode::Instance: |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|             break; |  | ||||||
|         case MAXWELL3D_REG_INDEX(index_buffer.count): |  | ||||||
|             draw_indexed = true; |  | ||||||
|             break; |  | ||||||
|         case MAXWELL3D_REG_INDEX(draw_inline_index): |  | ||||||
|             update_inline_index(method_argument); |  | ||||||
|             break; |  | ||||||
|         case MAXWELL3D_REG_INDEX(inline_index_2x16.even): |  | ||||||
|             update_inline_index(regs.inline_index_2x16.even); |  | ||||||
|             update_inline_index(regs.inline_index_2x16.odd); |  | ||||||
|             break; |  | ||||||
|         case MAXWELL3D_REG_INDEX(inline_index_4x8.index0): |  | ||||||
|             update_inline_index(regs.inline_index_4x8.index0); |  | ||||||
|             update_inline_index(regs.inline_index_4x8.index1); |  | ||||||
|             update_inline_index(regs.inline_index_4x8.index2); |  | ||||||
|             update_inline_index(regs.inline_index_4x8.index3); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         ProcessDeferredDraw(); |  | ||||||
|         ProcessMethodCall(method, argument, method_argument, is_last_call); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, | void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, | ||||||
| @@ -387,35 +305,6 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void Maxwell3D::ProcessTopologyOverride() { |  | ||||||
|     using PrimitiveTopology = Maxwell3D::Regs::PrimitiveTopology; |  | ||||||
|     using PrimitiveTopologyOverride = Maxwell3D::Regs::PrimitiveTopologyOverride; |  | ||||||
|  |  | ||||||
|     PrimitiveTopology topology{}; |  | ||||||
|  |  | ||||||
|     switch (regs.topology_override) { |  | ||||||
|     case PrimitiveTopologyOverride::None: |  | ||||||
|         topology = regs.draw.topology; |  | ||||||
|         break; |  | ||||||
|     case PrimitiveTopologyOverride::Points: |  | ||||||
|         topology = PrimitiveTopology::Points; |  | ||||||
|         break; |  | ||||||
|     case PrimitiveTopologyOverride::Lines: |  | ||||||
|         topology = PrimitiveTopology::Lines; |  | ||||||
|         break; |  | ||||||
|     case PrimitiveTopologyOverride::LineStrip: |  | ||||||
|         topology = PrimitiveTopology::LineStrip; |  | ||||||
|         break; |  | ||||||
|     default: |  | ||||||
|         topology = static_cast<PrimitiveTopology>(regs.topology_override); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (use_topology_override) { |  | ||||||
|         regs.draw.topology.Assign(topology); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Maxwell3D::ProcessMacroUpload(u32 data) { | void Maxwell3D::ProcessMacroUpload(u32 data) { | ||||||
|     macro_engine->AddCode(regs.load_mme.instruction_ptr++, data); |     macro_engine->AddCode(regs.load_mme.instruction_ptr++, data); | ||||||
| } | } | ||||||
| @@ -635,44 +524,4 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const { | |||||||
|     return regs.reg_array[method]; |     return regs.reg_array[method]; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Maxwell3D::ProcessClearBuffers(u32 layer_count) { |  | ||||||
|     rasterizer->Clear(layer_count); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Maxwell3D::ProcessDraw(u32 instance_count) { |  | ||||||
|     LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), |  | ||||||
|               draw_indexed ? regs.index_buffer.count : regs.vertex_buffer.count); |  | ||||||
|  |  | ||||||
|     ProcessTopologyOverride(); |  | ||||||
|  |  | ||||||
|     if (ShouldExecute()) { |  | ||||||
|         rasterizer->Draw(draw_indexed, instance_count); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     draw_indexed = false; |  | ||||||
|     deferred_draw_method.clear(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Maxwell3D::ProcessDeferredDraw() { |  | ||||||
|     if (draw_mode != DrawMode::Instance || deferred_draw_method.empty()) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const auto method_count = deferred_draw_method.size(); |  | ||||||
|     u32 instance_count = 1; |  | ||||||
|     u32 vertex_buffer_count = 0; |  | ||||||
|     u32 index_buffer_count = 0; |  | ||||||
|     for (size_t index = 0; index < method_count; ++index) { |  | ||||||
|         const u32 method = deferred_draw_method[index]; |  | ||||||
|         if (method == MAXWELL3D_REG_INDEX(vertex_buffer.count)) { |  | ||||||
|             instance_count = ++vertex_buffer_count; |  | ||||||
|         } else if (method == MAXWELL3D_REG_INDEX(index_buffer.count)) { |  | ||||||
|             instance_count = ++index_buffer_count; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     ASSERT_MSG(!(vertex_buffer_count && index_buffer_count), "Instance both indexed and direct?"); |  | ||||||
|  |  | ||||||
|     ProcessDraw(instance_count); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| } // namespace Tegra::Engines | } // namespace Tegra::Engines | ||||||
|   | |||||||
| @@ -37,6 +37,8 @@ class RasterizerInterface; | |||||||
|  |  | ||||||
| namespace Tegra::Engines { | namespace Tegra::Engines { | ||||||
|  |  | ||||||
|  | class DrawManager; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * This Engine is known as GF100_3D. Documentation can be found in: |  * This Engine is known as GF100_3D. Documentation can be found in: | ||||||
|  * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/3d/clb197.h |  * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/3d/clb197.h | ||||||
| @@ -2223,6 +2225,7 @@ public: | |||||||
|  |  | ||||||
|         struct IndexBufferSmall { |         struct IndexBufferSmall { | ||||||
|             union { |             union { | ||||||
|  |                 u32 raw; | ||||||
|                 BitField<0, 16, u32> first; |                 BitField<0, 16, u32> first; | ||||||
|                 BitField<16, 12, u32> count; |                 BitField<16, 12, u32> count; | ||||||
|                 BitField<28, 4, PrimitiveTopology> topology; |                 BitField<28, 4, PrimitiveTopology> topology; | ||||||
| @@ -3061,10 +3064,8 @@ public: | |||||||
|         Tables tables{}; |         Tables tables{}; | ||||||
|     } dirty; |     } dirty; | ||||||
|  |  | ||||||
|     std::vector<u8> inline_index_draw_indexes; |     std::unique_ptr<DrawManager> draw_manager; | ||||||
|  |     friend class DrawManager; | ||||||
|     /// Handles a write to the CLEAR_BUFFERS register. |  | ||||||
|     void ProcessClearBuffers(u32 layer_count); |  | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     void InitializeRegisterDefaults(); |     void InitializeRegisterDefaults(); | ||||||
| @@ -3122,15 +3123,6 @@ private: | |||||||
|     /// Handles a write to the CB_BIND register. |     /// Handles a write to the CB_BIND register. | ||||||
|     void ProcessCBBind(size_t stage_index); |     void ProcessCBBind(size_t stage_index); | ||||||
|  |  | ||||||
|     /// Handles use of topology overrides (e.g., to avoid using a topology assigned from a macro) |  | ||||||
|     void ProcessTopologyOverride(); |  | ||||||
|  |  | ||||||
|     /// Handles deferred draw(e.g., instance draw). |  | ||||||
|     void ProcessDeferredDraw(); |  | ||||||
|  |  | ||||||
|     /// Handles a draw. |  | ||||||
|     void ProcessDraw(u32 instance_count = 1); |  | ||||||
|  |  | ||||||
|     /// Returns a query's value or an empty object if the value will be deferred through a cache. |     /// Returns a query's value or an empty object if the value will be deferred through a cache. | ||||||
|     std::optional<u64> GetQueryResult(); |     std::optional<u64> GetQueryResult(); | ||||||
|  |  | ||||||
| @@ -3153,13 +3145,6 @@ private: | |||||||
|     Upload::State upload_state; |     Upload::State upload_state; | ||||||
|  |  | ||||||
|     bool execute_on{true}; |     bool execute_on{true}; | ||||||
|     bool use_topology_override{false}; |  | ||||||
|  |  | ||||||
|     std::array<bool, Regs::NUM_REGS> draw_command{}; |  | ||||||
|     std::vector<u32> deferred_draw_method; |  | ||||||
|     enum class DrawMode : u32 { General = 0, Instance, InlineIndex }; |  | ||||||
|     DrawMode draw_mode{DrawMode::General}; |  | ||||||
|     bool draw_indexed{}; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #define ASSERT_REG_POSITION(field_name, position)                                                  \ | #define ASSERT_REG_POSITION(field_name, position)                                                  \ | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #include <vector> | #include <vector> | ||||||
| #include "common/scope_exit.h" | #include "common/scope_exit.h" | ||||||
| #include "video_core/dirty_flags.h" | #include "video_core/dirty_flags.h" | ||||||
|  | #include "video_core/engines/draw_manager.h" | ||||||
| #include "video_core/engines/maxwell_3d.h" | #include "video_core/engines/maxwell_3d.h" | ||||||
| #include "video_core/macro/macro.h" | #include "video_core/macro/macro.h" | ||||||
| #include "video_core/macro/macro_hle.h" | #include "video_core/macro/macro_hle.h" | ||||||
| @@ -18,57 +19,33 @@ using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u3 | |||||||
| // HLE'd functions | // HLE'd functions | ||||||
| void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | ||||||
|     const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B); |     const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B); | ||||||
|  |     maxwell3d.draw_manager->DrawIndex( | ||||||
|     maxwell3d.regs.draw.topology.Assign( |         static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff), | ||||||
|         static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff)); |         parameters[4], parameters[1], parameters[3], parameters[5], instance_count); | ||||||
|     maxwell3d.regs.global_base_instance_index = parameters[5]; |  | ||||||
|     maxwell3d.regs.global_base_vertex_index = parameters[3]; |  | ||||||
|     maxwell3d.regs.index_buffer.count = parameters[1]; |  | ||||||
|     maxwell3d.regs.index_buffer.first = parameters[4]; |  | ||||||
|  |  | ||||||
|     if (maxwell3d.ShouldExecute()) { |  | ||||||
|         maxwell3d.Rasterizer().Draw(true, instance_count); |  | ||||||
|     } |  | ||||||
|     maxwell3d.regs.index_buffer.count = 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | ||||||
|     const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); |     const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); | ||||||
|  |     maxwell3d.draw_manager->DrawArray( | ||||||
|     maxwell3d.regs.vertex_buffer.first = parameters[3]; |         static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]), | ||||||
|     maxwell3d.regs.vertex_buffer.count = parameters[1]; |         parameters[3], parameters[1], parameters[4], instance_count); | ||||||
|     maxwell3d.regs.global_base_instance_index = parameters[4]; |  | ||||||
|     maxwell3d.regs.draw.topology.Assign( |  | ||||||
|         static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); |  | ||||||
|  |  | ||||||
|     if (maxwell3d.ShouldExecute()) { |  | ||||||
|         maxwell3d.Rasterizer().Draw(false, instance_count); |  | ||||||
|     } |  | ||||||
|     maxwell3d.regs.vertex_buffer.count = 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { | ||||||
|     const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); |     const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); | ||||||
|     const u32 element_base = parameters[4]; |     const u32 element_base = parameters[4]; | ||||||
|     const u32 base_instance = parameters[5]; |     const u32 base_instance = parameters[5]; | ||||||
|     maxwell3d.regs.index_buffer.first = parameters[3]; |  | ||||||
|     maxwell3d.regs.vertex_id_base = element_base; |     maxwell3d.regs.vertex_id_base = element_base; | ||||||
|     maxwell3d.regs.index_buffer.count = parameters[1]; |  | ||||||
|     maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; |     maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||||||
|     maxwell3d.regs.global_base_vertex_index = element_base; |  | ||||||
|     maxwell3d.regs.global_base_instance_index = base_instance; |  | ||||||
|     maxwell3d.CallMethod(0x8e3, 0x640, true); |     maxwell3d.CallMethod(0x8e3, 0x640, true); | ||||||
|     maxwell3d.CallMethod(0x8e4, element_base, true); |     maxwell3d.CallMethod(0x8e4, element_base, true); | ||||||
|     maxwell3d.CallMethod(0x8e5, base_instance, true); |     maxwell3d.CallMethod(0x8e5, base_instance, true); | ||||||
|     maxwell3d.regs.draw.topology.Assign( |  | ||||||
|         static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); |     maxwell3d.draw_manager->DrawIndex( | ||||||
|     if (maxwell3d.ShouldExecute()) { |         static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]), | ||||||
|         maxwell3d.Rasterizer().Draw(true, instance_count); |         parameters[3], parameters[1], element_base, base_instance, instance_count); | ||||||
|     } |  | ||||||
|     maxwell3d.regs.vertex_id_base = 0x0; |     maxwell3d.regs.vertex_id_base = 0x0; | ||||||
|     maxwell3d.regs.index_buffer.count = 0; |  | ||||||
|     maxwell3d.regs.global_base_vertex_index = 0x0; |  | ||||||
|     maxwell3d.regs.global_base_instance_index = 0x0; |  | ||||||
|     maxwell3d.CallMethod(0x8e3, 0x640, true); |     maxwell3d.CallMethod(0x8e3, 0x640, true); | ||||||
|     maxwell3d.CallMethod(0x8e4, 0x0, true); |     maxwell3d.CallMethod(0x8e4, 0x0, true); | ||||||
|     maxwell3d.CallMethod(0x8e5, 0x0, true); |     maxwell3d.CallMethod(0x8e5, 0x0, true); | ||||||
| @@ -79,9 +56,6 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||||||
|     SCOPE_EXIT({ |     SCOPE_EXIT({ | ||||||
|         // Clean everything. |         // Clean everything. | ||||||
|         maxwell3d.regs.vertex_id_base = 0x0; |         maxwell3d.regs.vertex_id_base = 0x0; | ||||||
|         maxwell3d.regs.index_buffer.count = 0; |  | ||||||
|         maxwell3d.regs.global_base_vertex_index = 0x0; |  | ||||||
|         maxwell3d.regs.global_base_instance_index = 0x0; |  | ||||||
|         maxwell3d.CallMethod(0x8e3, 0x640, true); |         maxwell3d.CallMethod(0x8e3, 0x640, true); | ||||||
|         maxwell3d.CallMethod(0x8e4, 0x0, true); |         maxwell3d.CallMethod(0x8e4, 0x0, true); | ||||||
|         maxwell3d.CallMethod(0x8e5, 0x0, true); |         maxwell3d.CallMethod(0x8e5, 0x0, true); | ||||||
| @@ -93,9 +67,6 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||||||
|         // Nothing to do. |         // Nothing to do. | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     const auto topology = |  | ||||||
|         static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]); |  | ||||||
|     maxwell3d.regs.draw.topology.Assign(topology); |  | ||||||
|     const u32 padding = parameters[3]; |     const u32 padding = parameters[3]; | ||||||
|     const std::size_t max_draws = parameters[4]; |     const std::size_t max_draws = parameters[4]; | ||||||
|  |  | ||||||
| @@ -106,23 +77,17 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||||||
|  |  | ||||||
|     for (std::size_t index = first_draw; index < last_draw; index++) { |     for (std::size_t index = first_draw; index < last_draw; index++) { | ||||||
|         const std::size_t base = index * indirect_words + 5; |         const std::size_t base = index * indirect_words + 5; | ||||||
|         const u32 num_vertices = parameters[base]; |  | ||||||
|         const u32 instance_count = parameters[base + 1]; |  | ||||||
|         const u32 first_index = parameters[base + 2]; |  | ||||||
|         const u32 base_vertex = parameters[base + 3]; |         const u32 base_vertex = parameters[base + 3]; | ||||||
|         const u32 base_instance = parameters[base + 4]; |         const u32 base_instance = parameters[base + 4]; | ||||||
|         maxwell3d.regs.index_buffer.first = first_index; |  | ||||||
|         maxwell3d.regs.vertex_id_base = base_vertex; |         maxwell3d.regs.vertex_id_base = base_vertex; | ||||||
|         maxwell3d.regs.index_buffer.count = num_vertices; |  | ||||||
|         maxwell3d.regs.global_base_vertex_index = base_vertex; |  | ||||||
|         maxwell3d.regs.global_base_instance_index = base_instance; |  | ||||||
|         maxwell3d.CallMethod(0x8e3, 0x640, true); |         maxwell3d.CallMethod(0x8e3, 0x640, true); | ||||||
|         maxwell3d.CallMethod(0x8e4, base_vertex, true); |         maxwell3d.CallMethod(0x8e4, base_vertex, true); | ||||||
|         maxwell3d.CallMethod(0x8e5, base_instance, true); |         maxwell3d.CallMethod(0x8e5, base_instance, true); | ||||||
|         maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; |         maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; | ||||||
|         if (maxwell3d.ShouldExecute()) { |         maxwell3d.draw_manager->DrawIndex( | ||||||
|             maxwell3d.Rasterizer().Draw(true, instance_count); |             static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]), | ||||||
|         } |             parameters[base + 2], parameters[base], base_vertex, base_instance, | ||||||
|  |             parameters[base + 1]); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -136,7 +101,7 @@ void HLE_EAD26C3E2109B06B(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||||||
|     ASSERT(clear_params.layer == 0); |     ASSERT(clear_params.layer == 0); | ||||||
|  |  | ||||||
|     maxwell3d.regs.clear_surface.raw = clear_params.raw; |     maxwell3d.regs.clear_surface.raw = clear_params.raw; | ||||||
|     maxwell3d.ProcessClearBuffers(num_layers); |     maxwell3d.draw_manager->Clear(num_layers); | ||||||
| } | } | ||||||
|  |  | ||||||
| constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{ | constexpr std::array<std::pair<u64, HLEFunction>, 5> hle_funcs{{ | ||||||
|   | |||||||
| @@ -224,16 +224,18 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { | |||||||
|  |  | ||||||
|     SyncState(); |     SyncState(); | ||||||
|  |  | ||||||
|     const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology); |     const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); | ||||||
|  |  | ||||||
|  |     const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(draw_state.topology); | ||||||
|     BeginTransformFeedback(pipeline, primitive_mode); |     BeginTransformFeedback(pipeline, primitive_mode); | ||||||
|  |  | ||||||
|     const GLuint base_instance = static_cast<GLuint>(maxwell3d->regs.global_base_instance_index); |     const GLuint base_instance = static_cast<GLuint>(draw_state.base_instance); | ||||||
|     const GLsizei num_instances = static_cast<GLsizei>(instance_count); |     const GLsizei num_instances = static_cast<GLsizei>(instance_count); | ||||||
|     if (is_indexed) { |     if (is_indexed) { | ||||||
|         const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.global_base_vertex_index); |         const GLint base_vertex = static_cast<GLint>(draw_state.base_index); | ||||||
|         const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.index_buffer.count); |         const GLsizei num_vertices = static_cast<GLsizei>(draw_state.index_buffer.count); | ||||||
|         const GLvoid* const offset = buffer_cache_runtime.IndexOffset(); |         const GLvoid* const offset = buffer_cache_runtime.IndexOffset(); | ||||||
|         const GLenum format = MaxwellToGL::IndexFormat(maxwell3d->regs.index_buffer.format); |         const GLenum format = MaxwellToGL::IndexFormat(draw_state.index_buffer.format); | ||||||
|         if (num_instances == 1 && base_instance == 0 && base_vertex == 0) { |         if (num_instances == 1 && base_instance == 0 && base_vertex == 0) { | ||||||
|             glDrawElements(primitive_mode, num_vertices, format, offset); |             glDrawElements(primitive_mode, num_vertices, format, offset); | ||||||
|         } else if (num_instances == 1 && base_instance == 0) { |         } else if (num_instances == 1 && base_instance == 0) { | ||||||
| @@ -252,8 +254,8 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { | |||||||
|                                                           base_instance); |                                                           base_instance); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         const GLint base_vertex = static_cast<GLint>(maxwell3d->regs.vertex_buffer.first); |         const GLint base_vertex = static_cast<GLint>(draw_state.vertex_buffer.first); | ||||||
|         const GLsizei num_vertices = static_cast<GLsizei>(maxwell3d->regs.vertex_buffer.count); |         const GLsizei num_vertices = static_cast<GLsizei>(draw_state.vertex_buffer.count); | ||||||
|         if (num_instances == 1 && base_instance == 0) { |         if (num_instances == 1 && base_instance == 0) { | ||||||
|             glDrawArrays(primitive_mode, base_vertex, num_vertices); |             glDrawArrays(primitive_mode, base_vertex, num_vertices); | ||||||
|         } else if (base_instance == 0) { |         } else if (base_instance == 0) { | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ | |||||||
| #include "shader_recompiler/frontend/maxwell/control_flow.h" | #include "shader_recompiler/frontend/maxwell/control_flow.h" | ||||||
| #include "shader_recompiler/frontend/maxwell/translate_program.h" | #include "shader_recompiler/frontend/maxwell/translate_program.h" | ||||||
| #include "shader_recompiler/profile.h" | #include "shader_recompiler/profile.h" | ||||||
|  | #include "video_core/engines/draw_manager.h" | ||||||
| #include "video_core/engines/kepler_compute.h" | #include "video_core/engines/kepler_compute.h" | ||||||
| #include "video_core/engines/maxwell_3d.h" | #include "video_core/engines/maxwell_3d.h" | ||||||
| #include "video_core/memory_manager.h" | #include "video_core/memory_manager.h" | ||||||
| @@ -327,7 +328,7 @@ GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() { | |||||||
|     const auto& regs{maxwell3d->regs}; |     const auto& regs{maxwell3d->regs}; | ||||||
|     graphics_key.raw = 0; |     graphics_key.raw = 0; | ||||||
|     graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0); |     graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0); | ||||||
|     graphics_key.gs_input_topology.Assign(regs.draw.topology.Value()); |     graphics_key.gs_input_topology.Assign(maxwell3d->draw_manager->GetDrawState().topology); | ||||||
|     graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value()); |     graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value()); | ||||||
|     graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value()); |     graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value()); | ||||||
|     graphics_key.tessellation_clockwise.Assign( |     graphics_key.tessellation_clockwise.Assign( | ||||||
| @@ -371,7 +372,8 @@ GraphicsPipeline* ShaderCache::BuiltPipeline(GraphicsPipeline* pipeline) const n | |||||||
|     // If games are using a small index count, we can assume these are full screen quads. |     // If games are using a small index count, we can assume these are full screen quads. | ||||||
|     // Usually these shaders are only used once for building textures so we can assume they |     // Usually these shaders are only used once for building textures so we can assume they | ||||||
|     // can't be built async |     // can't be built async | ||||||
|     if (maxwell3d->regs.index_buffer.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) { |     const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); | ||||||
|  |     if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) { | ||||||
|         return pipeline; |         return pipeline; | ||||||
|     } |     } | ||||||
|     return nullptr; |     return nullptr; | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
| #include "common/cityhash.h" | #include "common/cityhash.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/polyfill_ranges.h" | #include "common/polyfill_ranges.h" | ||||||
|  | #include "video_core/engines/draw_manager.h" | ||||||
| #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | ||||||
| #include "video_core/renderer_vulkan/vk_state_tracker.h" | #include "video_core/renderer_vulkan/vk_state_tracker.h" | ||||||
|  |  | ||||||
| @@ -50,12 +51,13 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& | |||||||
| void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, | void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, | ||||||
|                                  bool has_extended_dynamic_state, bool has_dynamic_vertex_input) { |                                  bool has_extended_dynamic_state, bool has_dynamic_vertex_input) { | ||||||
|     const Maxwell& regs = maxwell3d.regs; |     const Maxwell& regs = maxwell3d.regs; | ||||||
|  |     const auto topology_ = maxwell3d.draw_manager->GetDrawState().topology; | ||||||
|     const std::array enabled_lut{ |     const std::array enabled_lut{ | ||||||
|         regs.polygon_offset_point_enable, |         regs.polygon_offset_point_enable, | ||||||
|         regs.polygon_offset_line_enable, |         regs.polygon_offset_line_enable, | ||||||
|         regs.polygon_offset_fill_enable, |         regs.polygon_offset_fill_enable, | ||||||
|     }; |     }; | ||||||
|     const u32 topology_index = static_cast<u32>(regs.draw.topology.Value()); |     const u32 topology_index = static_cast<u32>(topology_); | ||||||
|  |  | ||||||
|     raw1 = 0; |     raw1 = 0; | ||||||
|     extended_dynamic_state.Assign(has_extended_dynamic_state ? 1 : 0); |     extended_dynamic_state.Assign(has_extended_dynamic_state ? 1 : 0); | ||||||
| @@ -78,7 +80,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, | |||||||
|                                   Maxwell::Tessellation::OutputPrimitives::Triangles_CW); |                                   Maxwell::Tessellation::OutputPrimitives::Triangles_CW); | ||||||
|     logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); |     logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); | ||||||
|     logic_op.Assign(PackLogicOp(regs.logic_op.op)); |     logic_op.Assign(PackLogicOp(regs.logic_op.op)); | ||||||
|     topology.Assign(regs.draw.topology); |     topology.Assign(topology_); | ||||||
|     msaa_mode.Assign(regs.anti_alias_samples_mode); |     msaa_mode.Assign(regs.anti_alias_samples_mode); | ||||||
|  |  | ||||||
|     raw2 = 0; |     raw2 = 0; | ||||||
|   | |||||||
| @@ -507,7 +507,8 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const | |||||||
|     // If games are using a small index count, we can assume these are full screen quads. |     // If games are using a small index count, we can assume these are full screen quads. | ||||||
|     // Usually these shaders are only used once for building textures so we can assume they |     // Usually these shaders are only used once for building textures so we can assume they | ||||||
|     // can't be built async |     // can't be built async | ||||||
|     if (maxwell3d->regs.index_buffer.count <= 6 || maxwell3d->regs.vertex_buffer.count <= 6) { |     const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); | ||||||
|  |     if (draw_state.index_buffer.count <= 6 || draw_state.vertex_buffer.count <= 6) { | ||||||
|         return pipeline; |         return pipeline; | ||||||
|     } |     } | ||||||
|     return nullptr; |     return nullptr; | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ | |||||||
| #include "common/scope_exit.h" | #include "common/scope_exit.h" | ||||||
| #include "common/settings.h" | #include "common/settings.h" | ||||||
| #include "video_core/control/channel_state.h" | #include "video_core/control/channel_state.h" | ||||||
|  | #include "video_core/engines/draw_manager.h" | ||||||
| #include "video_core/engines/kepler_compute.h" | #include "video_core/engines/kepler_compute.h" | ||||||
| #include "video_core/engines/maxwell_3d.h" | #include "video_core/engines/maxwell_3d.h" | ||||||
| #include "video_core/renderer_vulkan/blit_image.h" | #include "video_core/renderer_vulkan/blit_image.h" | ||||||
| @@ -36,6 +37,7 @@ | |||||||
| namespace Vulkan { | namespace Vulkan { | ||||||
|  |  | ||||||
| using Maxwell = Tegra::Engines::Maxwell3D::Regs; | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||||||
|  | using MaxwellDrawState = Tegra::Engines::DrawManager::State; | ||||||
| using VideoCommon::ImageViewId; | using VideoCommon::ImageViewId; | ||||||
| using VideoCommon::ImageViewType; | using VideoCommon::ImageViewType; | ||||||
|  |  | ||||||
| @@ -127,16 +129,16 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3 | |||||||
|     return scissor; |     return scissor; | ||||||
| } | } | ||||||
|  |  | ||||||
| DrawParams MakeDrawParams(const Maxwell& regs, u32 num_instances, bool is_indexed) { | DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed) { | ||||||
|     DrawParams params{ |     DrawParams params{ | ||||||
|         .base_instance = regs.global_base_instance_index, |         .base_instance = draw_state.base_instance, | ||||||
|         .num_instances = num_instances, |         .num_instances = num_instances, | ||||||
|         .base_vertex = is_indexed ? regs.global_base_vertex_index : regs.vertex_buffer.first, |         .base_vertex = is_indexed ? draw_state.base_index : draw_state.vertex_buffer.first, | ||||||
|         .num_vertices = is_indexed ? regs.index_buffer.count : regs.vertex_buffer.count, |         .num_vertices = is_indexed ? draw_state.index_buffer.count : draw_state.vertex_buffer.count, | ||||||
|         .first_index = is_indexed ? regs.index_buffer.first : 0, |         .first_index = is_indexed ? draw_state.index_buffer.first : 0, | ||||||
|         .is_indexed = is_indexed, |         .is_indexed = is_indexed, | ||||||
|     }; |     }; | ||||||
|     if (regs.draw.topology == Maxwell::PrimitiveTopology::Quads) { |     if (draw_state.topology == Maxwell::PrimitiveTopology::Quads) { | ||||||
|         // 6 triangle vertices per quad, base vertex is part of the index |         // 6 triangle vertices per quad, base vertex is part of the index | ||||||
|         // See BindQuadArrayIndexBuffer for more details |         // See BindQuadArrayIndexBuffer for more details | ||||||
|         params.num_vertices = (params.num_vertices / 4) * 6; |         params.num_vertices = (params.num_vertices / 4) * 6; | ||||||
| @@ -195,9 +197,9 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { | |||||||
|  |  | ||||||
|     UpdateDynamicStates(); |     UpdateDynamicStates(); | ||||||
|  |  | ||||||
|     const auto& regs{maxwell3d->regs}; |     const auto& draw_state = maxwell3d->draw_manager->GetDrawState(); | ||||||
|     const u32 num_instances{instance_count}; |     const u32 num_instances{instance_count}; | ||||||
|     const DrawParams draw_params{MakeDrawParams(regs, num_instances, is_indexed)}; |     const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)}; | ||||||
|     scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { |     scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) { | ||||||
|         if (draw_params.is_indexed) { |         if (draw_params.is_indexed) { | ||||||
|             cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, |             cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user