diff --git a/src/shader_recompiler/frontend/fetch_shader.cpp b/src/shader_recompiler/frontend/fetch_shader.cpp index 81e4093f2..70c63e260 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 0858061a1..4ae0d2373 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 4070560ae..2a3b35033 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 b1eb6aea7..48220ce27 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 02d6b2ce4..ea762d1f2 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) {