From 81f8c642a6df4106d6cb289f2da677c90ea5671a Mon Sep 17 00:00:00 2001 From: Vinicius Rangel Date: Thu, 22 Aug 2024 21:27:32 -0300 Subject: [PATCH 1/4] shader_recompiler: handle fetch shader address offsets parse index & offset sgpr from fetch shader and propagate them to vkBindVertexBuffers --- .../frontend/fetch_shader.cpp | 23 ++++++++++++++++++- src/shader_recompiler/frontend/fetch_shader.h | 2 ++ .../frontend/translate/translate.cpp | 2 ++ src/shader_recompiler/runtime_info.h | 2 ++ src/video_core/buffer_cache/buffer_cache.cpp | 14 +++++++++-- 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/shader_recompiler/frontend/fetch_shader.cpp b/src/shader_recompiler/frontend/fetch_shader.cpp index 81e4093f24a..70c63e2608b 100644 --- a/src/shader_recompiler/frontend/fetch_shader.cpp +++ b/src/shader_recompiler/frontend/fetch_shader.cpp @@ -44,6 +44,7 @@ std::vector ParseFetchShader(const u32* code, u32* out_size) { s32 dst_reg{-1}; }; boost::container::static_vector loads; + std::array offsets{}; u32 semantic_index = 0; while (!code_slice.atEnd()) { @@ -59,6 +60,10 @@ std::vector ParseFetchShader(const u32* code, u32* out_size) { continue; } + if (inst.opcode == Opcode::V_ADD_I32) { + offsets[inst.dst[0].code] = inst.src[0].code; + } + if (inst.inst_class == InstClass::VectorMemBufFmt) { // SRSRC is in units of 4 SPGRs while SBASE is in pairs of SGPRs const u32 base_sgpr = inst.src[2].code * 4; @@ -68,13 +73,29 @@ std::vector ParseFetchShader(const u32* code, u32* out_size) { const auto it = std::ranges::find_if( loads, [&](VsharpLoad& load) { return load.dst_reg == base_sgpr; }); + auto mubuf = inst.control.mubuf; + auto& attrib = attributes.emplace_back(); attrib.semantic = semantic_index++; attrib.dest_vgpr = inst.src[1].code; - attrib.num_elements = inst.control.mubuf.count; + attrib.num_elements = mubuf.count; attrib.sgpr_base = it->base_sgpr; attrib.dword_offset = it->dword_offset; + u8 soofs = inst.src[0].code; + + if (mubuf.idxen != 0) { + attrib.index_sgpr = offsets[soofs++]; + } else { + attrib.index_sgpr = 0xFF; + } + + if (mubuf.offen != 0) { + attrib.offset_sgpr = offsets[soofs]; + } else { + attrib.offset_sgpr = 0xFF; + } + // Store instance id rate attrib.instance_data = inst.src[0].code; diff --git a/src/shader_recompiler/frontend/fetch_shader.h b/src/shader_recompiler/frontend/fetch_shader.h index 0858061a12f..4ae0d2373ba 100644 --- a/src/shader_recompiler/frontend/fetch_shader.h +++ b/src/shader_recompiler/frontend/fetch_shader.h @@ -15,6 +15,8 @@ struct VertexAttribute { u8 sgpr_base; ///< SGPR that contains the pointer to the list of vertex V# u8 dword_offset; ///< The dword offset of the V# that describes this attribute. u8 instance_data; ///< Indicates that the buffer will be accessed in instance rate + u8 index_sgpr; ///< Read index from VADDR + u8 offset_sgpr; ///< Offset from VADDR }; std::vector ParseFetchShader(const u32* code, u32* out_size); diff --git a/src/shader_recompiler/frontend/translate/translate.cpp b/src/shader_recompiler/frontend/translate/translate.cpp index 4070560aec0..2a3b350336f 100644 --- a/src/shader_recompiler/frontend/translate/translate.cpp +++ b/src/shader_recompiler/frontend/translate/translate.cpp @@ -412,6 +412,8 @@ void Translator::EmitFetch(const GcnInst& inst) { .num_components = std::min(attrib.num_elements, num_components), .sgpr_base = attrib.sgpr_base, .dword_offset = attrib.dword_offset, + .index_sgpr = attrib.index_sgpr, + .offset_sgpr = attrib.offset_sgpr, .instance_step_rate = step_rate, .instance_data_buf = instance_buf_handle, }); diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index b1eb6aea78d..48220ce2795 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -135,6 +135,8 @@ struct Info { u16 num_components; u8 sgpr_base; u8 dword_offset; + u8 index_sgpr; + u8 offset_sgpr; InstanceIdType instance_step_rate; s32 instance_data_buf; }; diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index 02d6b2ce46c..ea762d1f253 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -101,7 +101,7 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { } std::array host_buffers; - std::array host_offsets; + std::array host_offsets{}; boost::container::static_vector guest_buffers; struct BufferRange { @@ -131,6 +131,16 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { } guest_buffers.emplace_back(buffer); ranges.emplace_back(buffer.base_address, buffer.base_address + buffer.GetSize()); + + u32 offset = 0; + if (input.index_sgpr != 0xFF) { + offset += vs_info.user_data[input.index_sgpr] * buffer.GetStride(); + } + if (input.offset_sgpr != 0xFF) { + offset += vs_info.user_data[input.offset_sgpr]; + } + host_offsets[guest_buffers.size() - 1] = offset; + attributes.push_back({ .location = input.binding, .binding = input.binding, @@ -180,7 +190,7 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { ASSERT(host_buffer != ranges_merged.cend()); host_buffers[i] = host_buffer->vk_buffer; - host_offsets[i] = host_buffer->offset + buffer.base_address - host_buffer->base_address; + host_offsets[i] += host_buffer->offset + buffer.base_address - host_buffer->base_address; } if (num_buffers > 0) { From 68f042001c5b00544be13d6bede94151b6f6b69c Mon Sep 17 00:00:00 2001 From: Vinicius Rangel Date: Thu, 22 Aug 2024 22:11:16 -0300 Subject: [PATCH 2/4] shader_recompiler: fix fetch_shader when offset is not present --- src/shader_recompiler/frontend/fetch_shader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shader_recompiler/frontend/fetch_shader.cpp b/src/shader_recompiler/frontend/fetch_shader.cpp index 70c63e2608b..8f54e9b62c4 100644 --- a/src/shader_recompiler/frontend/fetch_shader.cpp +++ b/src/shader_recompiler/frontend/fetch_shader.cpp @@ -45,6 +45,7 @@ std::vector ParseFetchShader(const u32* code, u32* out_size) { }; boost::container::static_vector loads; std::array offsets{}; + offsets.fill(0xFF); u32 semantic_index = 0; while (!code_slice.atEnd()) { From d9ea23badce5c6ab1f32cca0f72e2b591bb46659 Mon Sep 17 00:00:00 2001 From: Vinicius Rangel Date: Fri, 23 Aug 2024 17:23:34 -0300 Subject: [PATCH 3/4] video_core: propagate index/offset SGPRs to vkCmdDraw instead of offsetting the buffer address --- .../frontend/fetch_shader.cpp | 45 ++++++++++--------- src/shader_recompiler/frontend/fetch_shader.h | 10 +++-- .../frontend/translate/translate.cpp | 9 ++-- src/shader_recompiler/runtime_info.h | 5 ++- src/video_core/buffer_cache/buffer_cache.cpp | 14 +----- .../renderer_vulkan/vk_rasterizer.cpp | 15 ++++++- 6 files changed, 53 insertions(+), 45 deletions(-) diff --git a/src/shader_recompiler/frontend/fetch_shader.cpp b/src/shader_recompiler/frontend/fetch_shader.cpp index 8f54e9b62c4..7f2a09890ca 100644 --- a/src/shader_recompiler/frontend/fetch_shader.cpp +++ b/src/shader_recompiler/frontend/fetch_shader.cpp @@ -3,6 +3,7 @@ #include #include +#include "common/assert.h" #include "shader_recompiler/frontend/decode.h" #include "shader_recompiler/frontend/fetch_shader.h" @@ -33,7 +34,7 @@ namespace Shader::Gcn { * We take the reverse way, extract the original input semantics from these instructions. **/ -std::vector ParseFetchShader(const u32* code, u32* out_size) { +FetchShaderData ParseFetchShader(const u32* code, u32* out_size) { std::vector attributes; GcnCodeSlice code_slice(code, code + std::numeric_limits::max()); GcnDecodeContext decoder; @@ -44,8 +45,9 @@ std::vector ParseFetchShader(const u32* code, u32* out_size) { s32 dst_reg{-1}; }; boost::container::static_vector loads; - std::array offsets{}; - offsets.fill(0xFF); + + s8 fetch_index_sgpr = -1; + s8 fetch_offset_sgpr = -1; u32 semantic_index = 0; while (!code_slice.atEnd()) { @@ -62,7 +64,18 @@ std::vector ParseFetchShader(const u32* code, u32* out_size) { } if (inst.opcode == Opcode::V_ADD_I32) { - offsets[inst.dst[0].code] = inst.src[0].code; + const auto vgpr = inst.dst[0].code; + const auto sgpr = s8(inst.src[0].code); + switch (vgpr) { + case 0: // V0 is always the index + fetch_index_sgpr = sgpr; + break; + case 3: // V3 is always the offset + fetch_offset_sgpr = sgpr; + break; + default: + UNREACHABLE(); + } } if (inst.inst_class == InstClass::VectorMemBufFmt) { @@ -74,29 +87,13 @@ std::vector ParseFetchShader(const u32* code, u32* out_size) { const auto it = std::ranges::find_if( loads, [&](VsharpLoad& load) { return load.dst_reg == base_sgpr; }); - auto mubuf = inst.control.mubuf; - auto& attrib = attributes.emplace_back(); attrib.semantic = semantic_index++; attrib.dest_vgpr = inst.src[1].code; - attrib.num_elements = mubuf.count; + attrib.num_elements = inst.control.mubuf.count; attrib.sgpr_base = it->base_sgpr; attrib.dword_offset = it->dword_offset; - u8 soofs = inst.src[0].code; - - if (mubuf.idxen != 0) { - attrib.index_sgpr = offsets[soofs++]; - } else { - attrib.index_sgpr = 0xFF; - } - - if (mubuf.offen != 0) { - attrib.offset_sgpr = offsets[soofs]; - } else { - attrib.offset_sgpr = 0xFF; - } - // Store instance id rate attrib.instance_data = inst.src[0].code; @@ -105,7 +102,11 @@ std::vector ParseFetchShader(const u32* code, u32* out_size) { } } - return attributes; + return FetchShaderData{ + .attributes = std::move(attributes), + .fetch_index_sgpr = fetch_index_sgpr, + .fetch_offset_sgpr = fetch_offset_sgpr, + }; } } // namespace Shader::Gcn diff --git a/src/shader_recompiler/frontend/fetch_shader.h b/src/shader_recompiler/frontend/fetch_shader.h index 4ae0d2373ba..4ea4853c0bf 100644 --- a/src/shader_recompiler/frontend/fetch_shader.h +++ b/src/shader_recompiler/frontend/fetch_shader.h @@ -15,10 +15,14 @@ struct VertexAttribute { u8 sgpr_base; ///< SGPR that contains the pointer to the list of vertex V# u8 dword_offset; ///< The dword offset of the V# that describes this attribute. u8 instance_data; ///< Indicates that the buffer will be accessed in instance rate - u8 index_sgpr; ///< Read index from VADDR - u8 offset_sgpr; ///< Offset from VADDR }; -std::vector ParseFetchShader(const u32* code, u32* out_size); +struct FetchShaderData { + std::vector attributes; + s8 fetch_index_sgpr; ///< Read index from VADDR + s8 fetch_offset_sgpr; ///< Read offset from VADDR +}; + +FetchShaderData ParseFetchShader(const u32* code, u32* out_size); } // namespace Shader::Gcn diff --git a/src/shader_recompiler/frontend/translate/translate.cpp b/src/shader_recompiler/frontend/translate/translate.cpp index 2a3b350336f..14e2e83bbd9 100644 --- a/src/shader_recompiler/frontend/translate/translate.cpp +++ b/src/shader_recompiler/frontend/translate/translate.cpp @@ -346,7 +346,7 @@ void Translator::EmitFetch(const GcnInst& inst) { // Parse the assembly to generate a list of attributes. u32 fetch_size{}; - const auto attribs = ParseFetchShader(code, &fetch_size); + const auto fetch_data = ParseFetchShader(code, &fetch_size); if (Config::dumpShaders()) { using namespace Common::FS; @@ -359,7 +359,10 @@ void Translator::EmitFetch(const GcnInst& inst) { file.WriteRaw(code, fetch_size); } - for (const auto& attrib : attribs) { + info.fetch_index_sgpr = fetch_data.fetch_index_sgpr; + info.fetch_offset_sgpr = fetch_data.fetch_offset_sgpr; + + for (const auto& attrib : fetch_data.attributes) { const IR::Attribute attr{IR::Attribute::Param0 + attrib.semantic}; IR::VectorReg dst_reg{attrib.dest_vgpr}; @@ -412,8 +415,6 @@ void Translator::EmitFetch(const GcnInst& inst) { .num_components = std::min(attrib.num_elements, num_components), .sgpr_base = attrib.sgpr_base, .dword_offset = attrib.dword_offset, - .index_sgpr = attrib.index_sgpr, - .offset_sgpr = attrib.offset_sgpr, .instance_step_rate = step_rate, .instance_data_buf = instance_buf_handle, }); diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 48220ce2795..099be527466 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -135,8 +135,6 @@ struct Info { u16 num_components; u8 sgpr_base; u8 dword_offset; - u8 index_sgpr; - u8 offset_sgpr; InstanceIdType instance_step_rate; s32 instance_data_buf; }; @@ -177,6 +175,9 @@ struct Info { AttributeFlags stores{}; boost::container::static_vector vs_outputs; + s8 fetch_index_sgpr = -1; + s8 fetch_offset_sgpr = -1; + BufferResourceList buffers; ImageResourceList images; SamplerResourceList samplers; diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index ea762d1f253..02d6b2ce46c 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -101,7 +101,7 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { } std::array host_buffers; - std::array host_offsets{}; + std::array host_offsets; boost::container::static_vector guest_buffers; struct BufferRange { @@ -131,16 +131,6 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { } guest_buffers.emplace_back(buffer); ranges.emplace_back(buffer.base_address, buffer.base_address + buffer.GetSize()); - - u32 offset = 0; - if (input.index_sgpr != 0xFF) { - offset += vs_info.user_data[input.index_sgpr] * buffer.GetStride(); - } - if (input.offset_sgpr != 0xFF) { - offset += vs_info.user_data[input.offset_sgpr]; - } - host_offsets[guest_buffers.size() - 1] = offset; - attributes.push_back({ .location = input.binding, .binding = input.binding, @@ -190,7 +180,7 @@ bool BufferCache::BindVertexBuffers(const Shader::Info& vs_info) { ASSERT(host_buffer != ranges_merged.cend()); host_buffers[i] = host_buffer->vk_buffer; - host_offsets[i] += host_buffer->offset + buffer.base_address - host_buffer->base_address; + host_offsets[i] = host_buffer->offset + buffer.base_address - host_buffer->base_address; } if (num_buffers > 0) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 542624a0e40..d80e268defe 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -51,13 +51,24 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) { BeginRendering(); UpdateDynamicState(*pipeline); + u32 instance_offset = 0; + if (vs_info.fetch_offset_sgpr != -1) { + instance_offset = vs_info.user_data[vs_info.fetch_offset_sgpr]; + } + if (is_indexed) { - cmdbuf.drawIndexed(num_indices, regs.num_instances.NumInstances(), 0, 0, 0); + u32 vertex_offset = 0; + if (vs_info.fetch_index_sgpr != -1) { + vertex_offset = vs_info.user_data[vs_info.fetch_index_sgpr]; + } + + cmdbuf.drawIndexed(num_indices, regs.num_instances.NumInstances(), 0, s32(vertex_offset), + instance_offset); } else { const u32 num_vertices = regs.primitive_type == AmdGpu::Liverpool::PrimitiveType::RectList ? 4 : regs.num_indices; - cmdbuf.draw(num_vertices, regs.num_instances.NumInstances(), 0, 0); + cmdbuf.draw(num_vertices, regs.num_instances.NumInstances(), 0, instance_offset); } } From a5e468af4793fb68f6a92da65e04a69bffcbbe37 Mon Sep 17 00:00:00 2001 From: Vinicius Rangel Date: Sat, 24 Aug 2024 11:21:50 -0300 Subject: [PATCH 4/4] video_core: add vertex_offset to non-indexed draw calls renamed fetch offset fields --- .../frontend/fetch_shader.cpp | 21 +++++++------------ src/shader_recompiler/frontend/fetch_shader.h | 4 ++-- .../frontend/translate/translate.cpp | 4 ++-- src/shader_recompiler/runtime_info.h | 16 ++++++++++++-- .../renderer_vulkan/vk_rasterizer.cpp | 13 +++--------- 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/shader_recompiler/frontend/fetch_shader.cpp b/src/shader_recompiler/frontend/fetch_shader.cpp index 7f2a09890ca..16938410cca 100644 --- a/src/shader_recompiler/frontend/fetch_shader.cpp +++ b/src/shader_recompiler/frontend/fetch_shader.cpp @@ -35,7 +35,7 @@ namespace Shader::Gcn { **/ FetchShaderData ParseFetchShader(const u32* code, u32* out_size) { - std::vector attributes; + FetchShaderData data{}; GcnCodeSlice code_slice(code, code + std::numeric_limits::max()); GcnDecodeContext decoder; @@ -46,9 +46,6 @@ FetchShaderData ParseFetchShader(const u32* code, u32* out_size) { }; boost::container::static_vector loads; - s8 fetch_index_sgpr = -1; - s8 fetch_offset_sgpr = -1; - u32 semantic_index = 0; while (!code_slice.atEnd()) { const auto inst = decoder.decodeInstruction(code_slice); @@ -67,11 +64,11 @@ FetchShaderData ParseFetchShader(const u32* code, u32* out_size) { const auto vgpr = inst.dst[0].code; const auto sgpr = s8(inst.src[0].code); switch (vgpr) { - case 0: // V0 is always the index - fetch_index_sgpr = sgpr; + case 0: // V0 is always the vertex offset + data.vertex_offset_sgpr = sgpr; break; - case 3: // V3 is always the offset - fetch_offset_sgpr = sgpr; + case 3: // V3 is always the instance offset + data.instance_offset_sgpr = sgpr; break; default: UNREACHABLE(); @@ -87,7 +84,7 @@ FetchShaderData ParseFetchShader(const u32* code, u32* out_size) { const auto it = std::ranges::find_if( loads, [&](VsharpLoad& load) { return load.dst_reg == base_sgpr; }); - auto& attrib = attributes.emplace_back(); + auto& attrib = data.attributes.emplace_back(); attrib.semantic = semantic_index++; attrib.dest_vgpr = inst.src[1].code; attrib.num_elements = inst.control.mubuf.count; @@ -102,11 +99,7 @@ FetchShaderData ParseFetchShader(const u32* code, u32* out_size) { } } - return FetchShaderData{ - .attributes = std::move(attributes), - .fetch_index_sgpr = fetch_index_sgpr, - .fetch_offset_sgpr = fetch_offset_sgpr, - }; + return data; } } // namespace Shader::Gcn diff --git a/src/shader_recompiler/frontend/fetch_shader.h b/src/shader_recompiler/frontend/fetch_shader.h index 4ea4853c0bf..0e5d1541950 100644 --- a/src/shader_recompiler/frontend/fetch_shader.h +++ b/src/shader_recompiler/frontend/fetch_shader.h @@ -19,8 +19,8 @@ struct VertexAttribute { struct FetchShaderData { std::vector attributes; - s8 fetch_index_sgpr; ///< Read index from VADDR - s8 fetch_offset_sgpr; ///< Read offset from VADDR + s8 vertex_offset_sgpr = -1; ///< SGPR of vertex offset from VADDR + s8 instance_offset_sgpr = -1; ///< SGPR of instance offset from VADDR }; FetchShaderData ParseFetchShader(const u32* code, u32* out_size); diff --git a/src/shader_recompiler/frontend/translate/translate.cpp b/src/shader_recompiler/frontend/translate/translate.cpp index 14e2e83bbd9..e59cd5656d7 100644 --- a/src/shader_recompiler/frontend/translate/translate.cpp +++ b/src/shader_recompiler/frontend/translate/translate.cpp @@ -359,8 +359,8 @@ void Translator::EmitFetch(const GcnInst& inst) { file.WriteRaw(code, fetch_size); } - info.fetch_index_sgpr = fetch_data.fetch_index_sgpr; - info.fetch_offset_sgpr = fetch_data.fetch_offset_sgpr; + info.vertex_offset_sgpr = fetch_data.vertex_offset_sgpr; + info.instance_offset_sgpr = fetch_data.instance_offset_sgpr; for (const auto& attrib : fetch_data.attributes) { const IR::Attribute attr{IR::Attribute::Param0 + attrib.semantic}; diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 099be527466..7d36dbe1bee 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -175,8 +175,8 @@ struct Info { AttributeFlags stores{}; boost::container::static_vector vs_outputs; - s8 fetch_index_sgpr = -1; - s8 fetch_offset_sgpr = -1; + s8 vertex_offset_sgpr = -1; + s8 instance_offset_sgpr = -1; BufferResourceList buffers; ImageResourceList images; @@ -213,6 +213,18 @@ struct Info { std::memcpy(&data, base + dword_offset, sizeof(T)); return data; } + + [[nodiscard]] std::pair GetDrawOffsets() const noexcept { + u32 vertex_offset = 0; + u32 instance_offset = 0; + if (vertex_offset_sgpr != -1) { + vertex_offset = user_data[vertex_offset_sgpr]; + } + if (instance_offset_sgpr != -1) { + instance_offset = user_data[instance_offset_sgpr]; + } + return {vertex_offset, instance_offset}; + } }; constexpr AmdGpu::Buffer BufferResource::GetVsharp(const Info& info) const noexcept { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index d80e268defe..90dee1fef9b 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -51,24 +51,17 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) { BeginRendering(); UpdateDynamicState(*pipeline); - u32 instance_offset = 0; - if (vs_info.fetch_offset_sgpr != -1) { - instance_offset = vs_info.user_data[vs_info.fetch_offset_sgpr]; - } + const auto [vertex_offset, instance_offset] = vs_info.GetDrawOffsets(); if (is_indexed) { - u32 vertex_offset = 0; - if (vs_info.fetch_index_sgpr != -1) { - vertex_offset = vs_info.user_data[vs_info.fetch_index_sgpr]; - } - cmdbuf.drawIndexed(num_indices, regs.num_instances.NumInstances(), 0, s32(vertex_offset), instance_offset); } else { const u32 num_vertices = regs.primitive_type == AmdGpu::Liverpool::PrimitiveType::RectList ? 4 : regs.num_indices; - cmdbuf.draw(num_vertices, regs.num_instances.NumInstances(), 0, instance_offset); + cmdbuf.draw(num_vertices, regs.num_instances.NumInstances(), vertex_offset, + instance_offset); } }