From 2f90694797e30088820937855acf613bdcf27247 Mon Sep 17 00:00:00 2001 From: FengChen Date: Fri, 21 Oct 2022 19:14:22 +0800 Subject: [PATCH] video_core: Implement maxwell inline_index method --- src/video_core/engines/maxwell_3d.cpp | 170 ++++++++++-------- src/video_core/engines/maxwell_3d.h | 13 +- .../renderer_opengl/gl_rasterizer.cpp | 12 ++ .../renderer_opengl/gl_rasterizer.h | 2 + .../renderer_vulkan/vk_rasterizer.cpp | 15 ++ .../renderer_vulkan/vk_rasterizer.h | 2 + 6 files changed, 135 insertions(+), 79 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index b41aa6fc1..25fcdb1e3 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -126,6 +126,9 @@ void Maxwell3D::InitializeRegisterDefaults() { draw_command[MAXWELL3D_REG_INDEX(index_buffer32_first)] = true; draw_command[MAXWELL3D_REG_INDEX(index_buffer16_first)] = true; draw_command[MAXWELL3D_REG_INDEX(index_buffer8_first)] = 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) { @@ -271,6 +274,23 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { if (draw_command[method]) { regs.reg_array[method] = method_argument; deferred_draw_method.push_back(method); + auto u32_to_u8 = [&](const u32 argument) { + inline_index_draw_indexes.push_back(static_cast(argument & 0x000000ff)); + inline_index_draw_indexes.push_back(static_cast((argument & 0x0000ff00) >> 8)); + inline_index_draw_indexes.push_back(static_cast((argument & 0x00ff0000) >> 16)); + inline_index_draw_indexes.push_back(static_cast((argument & 0xff000000) >> 24)); + }; + if (MAXWELL3D_REG_INDEX(draw_inline_index) == method) { + u32_to_u8(method_argument); + } else if (MAXWELL3D_REG_INDEX(inline_index_2x16.even) == method) { + u32_to_u8(regs.inline_index_2x16.even); + u32_to_u8(regs.inline_index_2x16.odd); + } else if (MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == method) { + u32_to_u8(regs.inline_index_4x8.index0); + u32_to_u8(regs.inline_index_4x8.index1); + u32_to_u8(regs.inline_index_4x8.index2); + u32_to_u8(regs.inline_index_4x8.index3); + } } else { ProcessDeferredDraw(); @@ -567,86 +587,94 @@ void Maxwell3D::ProcessClearBuffers() { } void Maxwell3D::ProcessDeferredDraw() { - auto method_count = deferred_draw_method.size(); - if (method_count) { - enum class DrawMode { - Undefined, - General, - Instance, - }; - DrawMode draw_mode{DrawMode::Undefined}; - u32 instance_count = 1; + if (deferred_draw_method.empty()) { + return; + } - auto first_method = deferred_draw_method[0]; - if (MAXWELL3D_REG_INDEX(draw.begin) == first_method) { - // The minimum number of methods for drawing must be greater than or equal to - // 3[draw.begin->vertex(index)count->draw.end] to avoid errors in index mode drawing - if (method_count < 3) { - return; - } - draw_mode = - (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || - (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) - ? DrawMode::Instance - : DrawMode::General; - } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method || - MAXWELL3D_REG_INDEX(index_buffer16_first) == first_method || - MAXWELL3D_REG_INDEX(index_buffer8_first) == first_method) { - draw_mode = DrawMode::General; - } + enum class DrawMode { + Undefined, + General, + Instance, + }; + DrawMode draw_mode{DrawMode::Undefined}; + u32 instance_count = 1; - // Drawing will only begin with draw.begin or index_buffer method, other methods directly - // clear - if (draw_mode == DrawMode::Undefined) { - deferred_draw_method.clear(); + auto first_method = deferred_draw_method[0]; + if (MAXWELL3D_REG_INDEX(draw.begin) == first_method) { + // The minimum number of methods for drawing must be greater than or equal to + // 3[draw.begin->vertex(index)count->draw.end] to avoid errors in index mode drawing + if (deferred_draw_method.size() < 3) { return; } + draw_mode = (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || + (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) + ? DrawMode::Instance + : DrawMode::General; + } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method || + MAXWELL3D_REG_INDEX(index_buffer16_first) == first_method || + MAXWELL3D_REG_INDEX(index_buffer8_first) == first_method) { + draw_mode = DrawMode::General; + } - if (draw_mode == DrawMode::Instance) { - ASSERT_MSG(deferred_draw_method.size() % 4 == 0, "Instance mode method size error"); - instance_count = static_cast(deferred_draw_method.size()) / 4; + // Drawing will only begin with draw.begin or index_buffer method, other methods directly + // clear + if (draw_mode == DrawMode::Undefined) { + deferred_draw_method.clear(); + return; + } + + if (draw_mode == DrawMode::Instance) { + ASSERT_MSG(deferred_draw_method.size() % 4 == 0, "Instance mode method size error"); + instance_count = static_cast(deferred_draw_method.size()) / 4; + } else { + if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { + regs.index_buffer.count = regs.index_buffer32_first.count; + regs.index_buffer.first = regs.index_buffer32_first.first; + dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { + regs.index_buffer.count = regs.index_buffer16_first.count; + regs.index_buffer.first = regs.index_buffer16_first.first; + dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { + regs.index_buffer.count = regs.index_buffer8_first.count; + regs.index_buffer.first = regs.index_buffer8_first.first; + dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; } else { - if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { - regs.index_buffer.count = regs.index_buffer32_first.count; - regs.index_buffer.first = regs.index_buffer32_first.first; - dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { - regs.index_buffer.count = regs.index_buffer16_first.count; - regs.index_buffer.first = regs.index_buffer16_first.first; - dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - } else if (MAXWELL3D_REG_INDEX(index_buffer32_first) == first_method) { - regs.index_buffer.count = regs.index_buffer8_first.count; - regs.index_buffer.first = regs.index_buffer8_first.first; - dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + auto second_method = deferred_draw_method[1]; + if (MAXWELL3D_REG_INDEX(draw_inline_index) == second_method || + MAXWELL3D_REG_INDEX(inline_index_2x16.even) == second_method || + MAXWELL3D_REG_INDEX(inline_index_4x8.index0) == second_method) { + regs.index_buffer.count = static_cast(inline_index_draw_indexes.size() / 4); + regs.index_buffer.format = Regs::IndexFormat::UnsignedInt; } } - - LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), - regs.vertex_buffer.count); - - ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), - "Both indexed and direct?"); - - // Both instance configuration registers can not be set at the same time. - ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || - regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, - "Illegal combination of instancing parameters"); - - ProcessTopologyOverride(); - - const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count; - if (ShouldExecute()) { - rasterizer->Draw(is_indexed, instance_count); - } - - if (is_indexed) { - regs.index_buffer.count = 0; - } else { - regs.vertex_buffer.count = 0; - } - - deferred_draw_method.clear(); } + + LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), + regs.vertex_buffer.count); + + ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); + + // Both instance configuration registers can not be set at the same time. + ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || + regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, + "Illegal combination of instancing parameters"); + + ProcessTopologyOverride(); + + const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count; + if (ShouldExecute()) { + rasterizer->Draw(is_indexed, instance_count); + } + + if (is_indexed) { + regs.index_buffer.count = 0; + } else { + regs.vertex_buffer.count = 0; + } + + deferred_draw_method.clear(); + inline_index_draw_indexes.clear(); } } // namespace Tegra::Engines diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 1472e8871..bd23ebc12 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -1739,14 +1739,11 @@ public: Footprint_1x1_Virtual = 2, }; - struct InlineIndex4x8Align { + struct InlineIndex4x8 { union { BitField<0, 30, u32> count; BitField<30, 2, u32> start; }; - }; - - struct InlineIndex4x8Index { union { BitField<0, 8, u32> index0; BitField<8, 8, u32> index1; @@ -2836,8 +2833,7 @@ public: u32 depth_write_enabled; ///< 0x12E8 u32 alpha_test_enabled; ///< 0x12EC INSERT_PADDING_BYTES_NOINIT(0x10); - InlineIndex4x8Align inline_index_4x8_align; ///< 0x1300 - InlineIndex4x8Index inline_index_4x8_index; ///< 0x1304 + InlineIndex4x8 inline_index_4x8; ///< 0x1300 D3DCullMode d3d_cull_mode; ///< 0x1308 ComparisonOp depth_test_func; ///< 0x130C f32 alpha_test_ref; ///< 0x1310 @@ -3083,6 +3079,8 @@ public: Tables tables{}; } dirty; + std::vector inline_index_draw_indexes; + private: void InitializeRegisterDefaults(); @@ -3377,8 +3375,7 @@ ASSERT_REG_POSITION(alpha_to_coverage_dither, 0x12E0); ASSERT_REG_POSITION(blend_per_target_enabled, 0x12E4); ASSERT_REG_POSITION(depth_write_enabled, 0x12E8); ASSERT_REG_POSITION(alpha_test_enabled, 0x12EC); -ASSERT_REG_POSITION(inline_index_4x8_align, 0x1300); -ASSERT_REG_POSITION(inline_index_4x8_index, 0x1304); +ASSERT_REG_POSITION(inline_index_4x8, 0x1300); ASSERT_REG_POSITION(d3d_cull_mode, 0x1308); ASSERT_REG_POSITION(depth_test_func, 0x130C); ASSERT_REG_POSITION(alpha_test_ref, 0x1310); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 21bac6ebf..1590b21de 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -222,6 +222,8 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); + BindInlineIndexBuffer(); + SyncState(); const GLenum primitive_mode = MaxwellToGL::PrimitiveTopology(maxwell3d->regs.draw.topology); @@ -1128,6 +1130,16 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) { query_cache.EraseChannel(channel_id); } +void RasterizerOpenGL::BindInlineIndexBuffer() { + if (maxwell3d->inline_index_draw_indexes.empty()) { + return; + } + const auto data_count = static_cast(maxwell3d->inline_index_draw_indexes.size()); + auto buffer = Buffer(buffer_cache_runtime, *this, 0, data_count); + buffer.ImmediateUpload(0, maxwell3d->inline_index_draw_indexes); + buffer_cache_runtime.BindIndexBuffer(buffer, 0, data_count); +} + AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {} bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index c93ba3b42..793e0d608 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -199,6 +199,8 @@ private: /// End a transform feedback void EndTransformFeedback(); + void BindInlineIndexBuffer(); + Tegra::GPU& gpu; const Device& device; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 9a7d90b2a..9f05a7a18 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -193,6 +193,8 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); + BindInlineIndexBuffer(); + BeginTransformFeedback(); UpdateDynamicStates(); @@ -1008,4 +1010,17 @@ void RasterizerVulkan::ReleaseChannel(s32 channel_id) { query_cache.EraseChannel(channel_id); } +void RasterizerVulkan::BindInlineIndexBuffer() { + if (maxwell3d->inline_index_draw_indexes.empty()) { + return; + } + const auto data_count = static_cast(maxwell3d->inline_index_draw_indexes.size()); + auto buffer = buffer_cache_runtime.UploadStagingBuffer(data_count); + std::memcpy(buffer.mapped_span.data(), maxwell3d->inline_index_draw_indexes.data(), data_count); + buffer_cache_runtime.BindIndexBuffer( + maxwell3d->regs.draw.topology, maxwell3d->regs.index_buffer.format, + maxwell3d->regs.index_buffer.first, maxwell3d->regs.index_buffer.count, buffer.buffer, + static_cast(buffer.offset), data_count); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index b3a182588..e2fdc7611 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -141,6 +141,8 @@ private: void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs); + void BindInlineIndexBuffer(); + Tegra::GPU& gpu; ScreenInfo& screen_info;