diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index 74769e8c..3b4d310f 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -24,6 +24,20 @@ using namespace AmdGpu; static std::unique_ptr liverpool; +enum ShaderStages : u32 { + Cs, + Ps, + Vs, + Gs, + Es, + Hs, + Ls, + + Max +}; + +static constexpr std::array indirect_sgpr_offsets{0u, 0u, 0x4cu, 0u, 0xccu, 0u, 0x14cu}; + // In case of precise gnm driver emulation we need to send a bunch of HW-specific // initialization commands. It may slowdown development at early stage as their // support is not important and can be ignored for a while. @@ -347,9 +361,29 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexAuto(u32* cmdbuf, u32 size, u32 index_count, u32 return -1; } -int PS4_SYSV_ABI sceGnmDrawIndexIndirect() { - LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); - return ORBIS_OK; +s32 PS4_SYSV_ABI sceGnmDrawIndexIndirect(u32* cmdbuf, u32 size, u32 data_offset, u32 shader_stage, + u32 vertex_sgpr_offset, u32 instance_vgpr_offset, + u32 flags) { + LOG_TRACE(Lib_GnmDriver, "called"); + + if (cmdbuf && (size == 9) && (shader_stage < ShaderStages::Max) && + (vertex_sgpr_offset < 0x10u) && (instance_vgpr_offset < 0x10u)) { + + const auto predicate = flags & 1 ? PM4Predicate::PredEnable : PM4Predicate::PredDisable; + cmdbuf = WriteHeader( + cmdbuf, 4, PM4ShaderType::ShaderGraphics, predicate); + + const auto sgpr_offset = indirect_sgpr_offsets[shader_stage]; + + cmdbuf[0] = data_offset; + cmdbuf[1] = vertex_sgpr_offset == 0 ? 0 : (vertex_sgpr_offset & 0xffffu) + sgpr_offset; + cmdbuf[2] = instance_vgpr_offset == 0 ? 0 : (instance_vgpr_offset & 0xffffu) + sgpr_offset; + cmdbuf[3] = 0; + + WriteTrailingNop<3>(cmdbuf); + return ORBIS_OK; + } + return -1; } int PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti() { @@ -383,9 +417,28 @@ s32 PS4_SYSV_ABI sceGnmDrawIndexOffset(u32* cmdbuf, u32 size, u32 index_offset, return -1; } -int PS4_SYSV_ABI sceGnmDrawIndirect() { - LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); - return ORBIS_OK; +s32 PS4_SYSV_ABI sceGnmDrawIndirect(u32* cmdbuf, u32 size, u32 data_offset, u32 shader_stage, + u32 vertex_sgpr_offset, u32 instance_vgpr_offset, u32 flags) { + LOG_TRACE(Lib_GnmDriver, "called"); + + if (cmdbuf && (size == 9) && (shader_stage < ShaderStages::Max) && + (vertex_sgpr_offset < 0x10u) && (instance_vgpr_offset < 0x10u)) { + + const auto predicate = flags & 1 ? PM4Predicate::PredEnable : PM4Predicate::PredDisable; + cmdbuf = WriteHeader(cmdbuf, 4, PM4ShaderType::ShaderGraphics, + predicate); + + const auto sgpr_offset = indirect_sgpr_offsets[shader_stage]; + + cmdbuf[0] = data_offset; + cmdbuf[1] = vertex_sgpr_offset == 0 ? 0 : (vertex_sgpr_offset & 0xffffu) + sgpr_offset; + cmdbuf[2] = instance_vgpr_offset == 0 ? 0 : (instance_vgpr_offset & 0xffffu) + sgpr_offset; + cmdbuf[3] = 2; // auto index + + WriteTrailingNop<3>(cmdbuf); + return ORBIS_OK; + } + return -1; } int PS4_SYSV_ABI sceGnmDrawIndirectCountMulti() { diff --git a/src/core/libraries/gnmdriver/gnmdriver.h b/src/core/libraries/gnmdriver/gnmdriver.h index d55aab49..b05d15f9 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.h +++ b/src/core/libraries/gnmdriver/gnmdriver.h @@ -44,13 +44,16 @@ u32 PS4_SYSV_ABI sceGnmDispatchInitDefaultHardwareState(u32* cmdbuf, u32 size); s32 PS4_SYSV_ABI sceGnmDrawIndex(u32* cmdbuf, u32 size, u32 index_count, uintptr_t index_addr, u32 flags, u32 type); s32 PS4_SYSV_ABI sceGnmDrawIndexAuto(u32* cmdbuf, u32 size, u32 index_count, u32 flags); -int PS4_SYSV_ABI sceGnmDrawIndexIndirect(); +s32 PS4_SYSV_ABI sceGnmDrawIndexIndirect(u32* cmdbuf, u32 size, u32 data_offset, u32 shader_stage, + u32 vertex_sgpr_offset, u32 instance_vgpr_offset, + u32 flags); int PS4_SYSV_ABI sceGnmDrawIndexIndirectCountMulti(); int PS4_SYSV_ABI sceGnmDrawIndexIndirectMulti(); int PS4_SYSV_ABI sceGnmDrawIndexMultiInstanced(); s32 PS4_SYSV_ABI sceGnmDrawIndexOffset(u32* cmdbuf, u32 size, u32 index_offset, u32 index_count, u32 flags); -int PS4_SYSV_ABI sceGnmDrawIndirect(); +s32 PS4_SYSV_ABI sceGnmDrawIndirect(u32* cmdbuf, u32 size, u32 data_offset, u32 shader_stage, + u32 vertex_sgpr_offset, u32 instance_vgpr_offset, u32 flags); int PS4_SYSV_ABI sceGnmDrawIndirectCountMulti(); int PS4_SYSV_ABI sceGnmDrawIndirectMulti(); int PS4_SYSV_ABI sceGnmDrawInitDefaultHardwareState(); diff --git a/src/video_core/amdgpu/pm4_cmds.h b/src/video_core/amdgpu/pm4_cmds.h index a3f6cf63..88697d31 100644 --- a/src/video_core/amdgpu/pm4_cmds.h +++ b/src/video_core/amdgpu/pm4_cmds.h @@ -253,6 +253,20 @@ struct PM4CmdDrawIndexAuto { u32 draw_initiator; }; +struct PM4CmdDrawIndirect { + PM4Type3Header header; ///< header + u32 data_offset; ///< DWORD aligned offset + union { + u32 dw2; + BitField<0, 16, u32> base_vtx_loc; ///< base vertex location + }; + union { + u32 dw3; + BitField<0, 16, u32> start_inst_loc; ///< start instance location + }; + u32 draw_initiator; ///< Draw Initiator Register +}; + enum class DataSelect : u32 { None = 0, Data32Low = 1,