diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/Vop3QuadSad.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/Vop3QuadSad.cpp new file mode 100644 index 000000000..f8f913466 --- /dev/null +++ b/core/libs/prx/libSceAgcDriver/tests/execution/Vop3QuadSad.cpp @@ -0,0 +1,170 @@ +#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp" +#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp" +#include "Recompiler.hpp" +#include "VulkanTestDevice.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using AgcDriver::Graphics::Require; +using ShaderRecompiler::ShaderStage; + +constexpr std::uint32_t Threads = 32; +constexpr std::uint32_t Inputs = 4; +constexpr std::uint32_t Results = 16; +alignas(256) std::array Input{}; +alignas(256) std::array Output{}; + +alignas(256) constexpr std::array Code{ + 0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0xd572000a, 0x041a0d04, 0xd573000c, + 0x041a0d04, 0xd575000e, 0x04120d04, 0xd5720012, 0x02020906, 0xd5750014, 0x04120b06, 0xd5730018, + 0x04120b06, 0xe0701000, 0x80010a03, 0xe0701004, 0x80010b03, 0xe0701008, 0x80010c03, 0xe070100c, + 0x80010d03, 0xe0701010, 0x80010e03, 0xe0701014, 0x80010f03, 0xe0701018, 0x80011003, 0xe070101c, + 0x80011103, 0xe0701020, 0x80011203, 0xe0701024, 0x80011303, 0xe0701028, 0x80011403, 0xe070102c, + 0x80011503, 0xe0701030, 0x80011603, 0xe0701034, 0x80011703, 0xe0701038, 0x80011803, 0xe070103c, + 0x80011903, 0xbf810000, +}; + +constexpr std::uint32_t Rows[32][4] = { + {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0xffffffffu, 0xffffffffu, 0x00000000u, 0x00000000u}, + {0x00000000u, 0x00000000u, 0xffffffffu, 0xffffffffu}, + {0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu}, + {0x01020304u, 0x05060708u, 0x00ff00ffu, 0xfffefffdu}, + {0xff00ff00u, 0x00ff00ffu, 0x00000000u, 0xffffffffu}, + {0x12345678u, 0x9abcdef0u, 0x00010203u, 0xffff0000u}, + {0xffffffffu, 0x00000000u, 0x00ff0000u, 0xfffffff0u}, + {0x80808080u, 0x7f7f7f7fu, 0x01000001u, 0x00010000u}, + {0xfffffff0u, 0xfffffff0u, 0xffffffffu, 0xffff0001u}, + {0xecc3f80cu, 0xc7859faeu, 0xf2d7d40fu, 0x4a37fa2du}, + {0xe47682e6u, 0xd46375dcu, 0x156393d8u, 0x045f21dau}, + {0x978f18a7u, 0x4e86c4fau, 0x6c7ab5c9u, 0x611244c0u}, + {0x87b3d90eu, 0x5bab1eecu, 0x215b8892u, 0xb9d8249eu}, + {0x3126b9c3u, 0x44732494u, 0x71cf92e3u, 0x039a7b88u}, + {0x389605feu, 0x9ec2d776u, 0x747d0a2bu, 0xe6d30f0au}, + {0x065720ceu, 0x1b1c3f27u, 0x15f54a5cu, 0xfb34ccc5u}, + {0xb5c318e9u, 0x7f8cb6d1u, 0x6bd6eed6u, 0x05032a7eu}, + {0x833bfa03u, 0xa0aeb4e5u, 0xbbf5204au, 0x6e6944d3u}, + {0x5be72f6eu, 0xc55176d5u, 0x0ebbe4d0u, 0x34a3f451u}, + {0xc8796571u, 0x090a0e01u, 0x96d0cbffu, 0x5e7db530u}, + {0xa86cf7b4u, 0x2c03a513u, 0x9ef94bdau, 0x374ebe5au}, + {0xf8821a96u, 0xbc36c297u, 0x5cdff86du, 0x90c68e93u}, + {0xc2816017u, 0xdc3260fdu, 0x5e620fe9u, 0xf7f3a683u}, + {0x9271a86fu, 0x4801920eu, 0xa918a1dcu, 0xf9810e12u}, + {0x507bef95u, 0x92af2f03u, 0x15f2cd71u, 0xd0745cc1u}, + {0x795c6ad3u, 0x2d794610u, 0xb7c93640u, 0x7bab67bcu}, + {0x97323268u, 0xca9f211eu, 0x728c2f7bu, 0xacfc4403u}, + {0xa472ea5fu, 0x29e0b1f5u, 0x2e99777fu, 0xcc8ba3e3u}, + {0x2db4cb47u, 0x8899230bu, 0x52cb26d8u, 0xac61e3a6u}, + {0xd0dd15d6u, 0x85232575u, 0x32135b34u, 0x951179a0u}, + {0x1d42d810u, 0x15136429u, 0x193e1ff7u, 0x6d17abfbu} +}; +constexpr std::uint32_t Expected[32][16] = { + {0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}, + {0x03fc03fcu, 0x03fc03fcu, 0x00000000u, 0x00000000u, 0xffffffffu, 0xffffffffu, 0x00000000u, 0x00000000u, 0x03fc03fcu, 0x03fc03fcu, 0x000003fbu, 0x000003fbu, 0x000003fcu, 0x000003fcu, 0x03fb03fbu, 0x03fb03fbu}, + {0x03fb03fbu, 0x03fb03fbu, 0x03fb03fbu, 0x03fb03fbu, 0x000003fcu, 0x000003fcu, 0x000003fbu, 0x000003fbu, 0x03fc03fcu, 0x03fc03fcu, 0x00000000u, 0x00000000u, 0xffffffffu, 0xffffffffu, 0x00000000u, 0x00000000u}, + {0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0x00000000u, 0x00000000u, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu}, + {0x030302fbu, 0x020201f9u, 0x02f902f7u, 0x01f401f1u, 0x010204fcu, 0x05060902u, 0x00ff02f3u, 0xffff01f3u, 0x01fe01fcu, 0x02f802f7u, 0x01020500u, 0x05060906u, 0x00ff03eeu, 0xffff02edu, 0x03000500u, 0x07f609f7u}, + {0x02fd01feu, 0x02fc01fdu, 0x00000000u, 0xffffffffu, 0xff00ff00u, 0x00ff00ffu, 0x00000000u, 0xffffffffu, 0x00ff01feu, 0x00ff01feu, 0xff0100feu, 0x00ff02fdu, 0x000000ffu, 0x000000feu, 0x00fe00feu, 0x01fe01feu}, + {0x01870311u, 0x0295020eu, 0x009702ffu, 0x01d90130u, 0x12345774u, 0x9abcdf86u, 0x00010333u, 0xffff01dau, 0x0111010eu, 0x01ef0113u, 0x12345996u, 0x9abce211u, 0x00010526u, 0xffff02efu, 0x15555996u, 0x9dabe213u}, + {0x02fd02fdu, 0x01fd02edu, 0x00ff0000u, 0x00fe00efu, 0xffffffffu, 0x00000000u, 0x00ff00ffu, 0x000000efu, 0x020d02fdu, 0x010e010eu, 0xffffffffu, 0x00000000u, 0x00ff0000u, 0xfffffff0u, 0xffffffffu, 0x00000000u}, + {0x02fd01ffu, 0x01fc01fcu, 0x01fd00ffu, 0x00fe00fdu, 0x8080817eu, 0x7f7f807cu, 0x010000feu, 0x000100fdu, 0x01ff01feu, 0x01fe01ffu, 0x8080827au, 0x7f7f817au, 0x010001fcu, 0x000101fau, 0x827b827au, 0x8179817au}, + {0x000e000eu, 0x000e0010u, 0x000e000eu, 0x000e0010u, 0xffffffffu, 0xffffffffu, 0x0000000eu, 0xffff0010u, 0x010d000fu, 0x020c020cu, 0xffffffffu, 0x000000fdu, 0x0000020bu, 0xffff020du, 0x010cffffu, 0x020b01fcu}, + {0xf42ad450u, 0x4bdffb75u, 0xf42ad450u, 0x4bdffb75u, 0xecc3f84du, 0xc785a101u, 0xf2d7d557u, 0x4a37fbd5u, 0x01d70041u, 0x029d0175u, 0xecc3f95du, 0xc785a113u, 0xf2d7d516u, 0x4a37fbe8u, 0xee28f95du, 0xc940a0b5u}, + {0x171e94d9u, 0x05142366u, 0x171e94d9u, 0x05142366u, 0xe47683e7u, 0xd4637797u, 0x15639564u, 0x045f228fu, 0x00dd0101u, 0x02030217u, 0xe47683c7u, 0xd463768bu, 0x156395dbu, 0x045f23bdu, 0xe52583c7u, 0xd64677dfu}, + {0x6dfcb6c8u, 0x61ed45f0u, 0x6dfcb6c8u, 0x61ed45f0u, 0x978f19a6u, 0x4e86c67cu, 0x6c7ab6f9u, 0x6112459bu, 0x00bc00ffu, 0x01b30105u, 0x978f1911u, 0x4e86c615u, 0x6c7ab6e5u, 0x611245d0u, 0x98aa1911u, 0x4f96c616u}, + {0x22c48a25u, 0xbb0e2554u, 0x22c48a25u, 0xbb0e2554u, 0x87b3daa1u, 0x5bab2055u, 0x215b8948u, 0xb9d825d4u, 0x01a10193u, 0x012e017du, 0x87b3da5cu, 0x5bab205au, 0x215b896au, 0xb9d826edu, 0x8921da5cu, 0x5dfa1fc4u}, + {0x73269413u, 0x04fb7d2eu, 0x73269413u, 0x04fb7d2eu, 0x3126baf3u, 0x447325ebu, 0x71cf9489u, 0x039a7ce9u, 0x00e90130u, 0x01410100u, 0x3126bb09u, 0x44732587u, 0x71cf93b7u, 0x039a7c6du, 0x3219bb09u, 0x45582568u}, + {0x75760b58u, 0xe7f4100du, 0x75760b58u, 0xe7f4100du, 0x3896072bu, 0x9ec2d86fu, 0x747d0b2eu, 0xe6d3102bu, 0x01bc012du, 0x01b101a5u, 0x38960785u, 0x9ec2d91eu, 0x747d0bdcu, 0xe6d310c1u, 0x3a3e0785u, 0xa079d927u}, + {0x173f4ba5u, 0xfc6ace06u, 0x173f4ba5u, 0xfc6ace06u, 0x06572217u, 0x1b1c4071u, 0x15f54b9du, 0xfb34cdfbu, 0x025a0149u, 0x02010166u, 0x065721edu, 0x1b1c40b1u, 0x15f54caeu, 0xfb34ce26u, 0x07e121edu, 0x1c7d4179u}, + {0x6d46f01cu, 0x05822b1au, 0x6d46f01cu, 0x05822b1au, 0xb5c31a2fu, 0x7f8cb841u, 0x6bd6ef72u, 0x05032afdu, 0x01520146u, 0x022f0136u, 0xb5c31984u, 0x7f8cb730u, 0x6bd6ef89u, 0x05032bfau, 0xb6221984u, 0x8108b784u}, + {0xbd5c225du, 0x6fb5455cu, 0xbd5c225du, 0x6fb5455cu, 0x833bfc16u, 0xa0aeb64cu, 0xbbf520d3u, 0x6e69461fu, 0x00f20213u, 0x01020208u, 0x833bfb94u, 0xa0aeb62bu, 0xbbf520e2u, 0x6e6945bdu, 0x8481fb94u, 0xa198b57du}, + {0x1086e660u, 0x35aff573u, 0x1086e660u, 0x35aff573u, 0x5be730feu, 0xc55178a0u, 0x0ebbe5f2u, 0x34a3f55du, 0x01e50190u, 0x00d7019du, 0x5be73102u, 0xc55177e0u, 0x0ebbe581u, 0x34a3f602u, 0x5cf23102u, 0xc7027786u}, + {0x9859cd7cu, 0x60ccb710u, 0x9859cd7cu, 0x60ccb710u, 0xc87966eeu, 0x090a0f8au, 0x96d0cddfu, 0x5e7db77fu, 0x017a017du, 0x00e100ecu, 0xc879687fu, 0x090a1040u, 0x96d0ce28u, 0x5e7db706u, 0xcab8687fu, 0x0ae0102au}, + {0xa0134d43u, 0x38a7c012u, 0xa0134d43u, 0x38a7c012u, 0xa86cf91du, 0x2c03a62du, 0x9ef94d92u, 0x374ebfb3u, 0x00eb0169u, 0x015f00c6u, 0xa86cfa3du, 0x2c03a668u, 0x9ef94db0u, 0x374ec00du, 0xa9c1fa3du, 0x2db6a6e9u}, + {0x5dfcfa6du, 0x91f58f56u, 0x5dfcfa6du, 0x91f58f56u, 0xf8821c96u, 0xbc36c3b4u, 0x5cdff930u, 0x90c68fc2u, 0x01b20200u, 0x00f10106u, 0xf8821bffu, 0xbc36c364u, 0x5cdff9a6u, 0x90c68f5fu, 0xf94f1bffu, 0xbd02c3d0u}, + {0x605c118fu, 0xf936a83bu, 0x605c118fu, 0xf936a83bu, 0xc28161bdu, 0xdc3262f7u, 0x5e6211a1u, 0xf7f3a7c6u, 0x006c01a6u, 0x00c0006bu, 0xc281612au, 0xdc326272u, 0x5e62110du, 0xf7f3a7d0u, 0xc3f6612au, 0xdd7f6221u}, + {0xaa91a2c0u, 0xfb800eadu, 0xaa91a2c0u, 0xfb800eadu, 0x9271a953u, 0x48019387u, 0xa918a277u, 0xf9811011u, 0x017a00e4u, 0x0144013bu, 0x9271a9c4u, 0x480193f9u, 0xa918a248u, 0xf9810f73u, 0x945ca9c4u, 0x4962927au}, + {0x1776ce69u, 0xd2bc5e51u, 0x1776ce69u, 0xd2bc5e51u, 0x507bf08du, 0x92af3087u, 0x15f2cf01u, 0xd0745f09u, 0x011200f8u, 0x00f10189u, 0x507bf161u, 0x92af3159u, 0x15f2cec2u, 0xd0745dd6u, 0x52d1f161u, 0x93c43054u}, + {0xb91037b2u, 0x7ccb6945u, 0xb91037b2u, 0x7ccb6945u, 0x795c6c45u, 0x2d794757u, 0xb7c937c9u, 0x7bab68dcu, 0x019a0172u, 0x00ab00c9u, 0x795c6bedu, 0x2d794786u, 0xb7c937e7u, 0x7bab6969u, 0x7ad26bedu, 0x2f2647b7u}, + {0x73373010u, 0xadc14573u, 0x73373010u, 0xadc14573u, 0x973232fdu, 0xca9f21c9u, 0x728c30ebu, 0xacfc44c8u, 0x01670095u, 0x00b000e6u, 0x9732333eu, 0xca9f228eu, 0x728c315cu, 0xacfc4502u, 0x98a2333eu, 0xcb9e22ffu}, + {0x2fdb78afu, 0xcdf8a4fcu, 0x2fdb78afu, 0xcdf8a4fcu, 0xa472eb8fu, 0x29e0b337u, 0x2e997898u, 0xcc8ba550u, 0x00ec0130u, 0x00820168u, 0xa472eb5bu, 0x29e0b3f7u, 0x2e9978dbu, 0xcc8ba57bu, 0xa674eb5bu, 0x2b78b351u}, + {0x544b284au, 0xae16e4c0u, 0x544b284au, 0xae16e4c0u, 0x2db4ccb9u, 0x8899248bu, 0x52cb27f2u, 0xac61e55bu, 0x00fc0172u, 0x009301c1u, 0x2db4cc7fu, 0x88992433u, 0x52cb282fu, 0xac61e4e1u, 0x2edccc7fu, 0x89d42462u}, + {0x33b45d84u, 0x95e87b2du, 0x33b45d84u, 0x95e87b2du, 0xd0dd1826u, 0x85232716u, 0x32135cc1u, 0x95117a77u, 0x01580250u, 0x02520174u, 0xd0dd16b0u, 0x852325cbu, 0x32135c2cu, 0x95117b28u, 0xd13316b0u, 0x86ab266du}, + {0x19b1219fu, 0x6e27ad12u, 0x19b1219fu, 0x6e27ad12u, 0x1d42d9b8u, 0x1513649cu, 0x193e210eu, 0x6d17ad0bu, 0x01b001a8u, 0x009b0234u, 0x1d42d952u, 0x15136545u, 0x193e21d5u, 0x6d17ad3cu, 0x1e5ed952u, 0x16546607u} +}; +constexpr const char* Names[16] = {"qsad lo", "qsad hi", "mqsad_pk lo", "mqsad_pk hi", "mqsad_u32 0", "mqsad_u32 1", "mqsad_u32 2", "mqsad_u32 3", "qsad const lo", "qsad const hi", "mqsad_u32 b0", "mqsad_u32 b1", "mqsad_u32 b2", "mqsad_u32 b3", "mqsad_pk b lo", "mqsad_pk b hi"}; + +void Fill(std::uint32_t tid, std::uint32_t* words) { + std::copy(std::begin(Rows[tid]), std::end(Rows[tid]), words); +} + +std::array BufferDescriptor(const void* data, std::uint32_t bytes) { + const auto address = reinterpret_cast(data); + return {static_cast(address), static_cast((address >> 32u) & 0xffffu), bytes, 0x01016facu}; +} + +std::string Hex(std::uint32_t value) { + char text[16]; + std::snprintf(text, sizeof(text), "0x%08x", value); + return text; +} + +void Expect(std::uint32_t tid, std::uint32_t actual, std::uint32_t expected, const char* name) { + Require(actual == expected, std::string("vop3 quad sad: lane ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected)); +} + +void Run(AgcDriver::VulkanDevice& device) { + for (std::uint32_t tid = 0; tid < Threads; ++tid) Fill(tid, &Input[tid * Inputs]); + Output.fill(0xdeadbeefu); + std::vector userData(8, 0u); + const auto input = BufferDescriptor(Input.data(), static_cast(Input.size() * 4u)); + const auto output = BufferDescriptor(Output.data(), static_cast(Output.size() * 4u)); + std::copy(input.begin(), input.end(), userData.begin()); + std::copy(output.begin(), output.end(), userData.begin() + 4); + const std::span code(Code); + const std::array memory{{{reinterpret_cast(code.data()), std::as_bytes(code)}}}; + const ShaderRecompiler::ShaderComputeStageInfo compute{{Threads, 1, 1}, 0u, {false, false, false}, false, 1}; + ShaderRecompiler::RecompileRequest request{ + {ShaderStage::Compute, reinterpret_cast(code.data()), code, 0, {}}, + {32, 0, userData, compute, std::nullopt, std::nullopt, memory}, + device.Target(), + {0, 0, 0, 128} + }; + request.useCache = false; + const auto result = ShaderRecompiler::Recompile(request); + device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast(code.data())); + device.WaitIdle(); +} + +void Check() { + for (std::uint32_t tid = 0; tid < Threads; ++tid) { + const std::uint32_t* in = &Input[tid * Inputs]; + const std::uint32_t* out = &Output[tid * Results]; + for (std::uint32_t i = 0; i < 16; ++i) Expect(tid, out[i], Expected[tid][i], Names[i]); + } +} + +} + +int main() { + try { + const auto device = OpenVulkanTestDevice(); + if (!device) return VulkanTestSkipped; + Run(*device); + Check(); + std::puts("vop3 quad sad tests passed"); + return 0; + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp index 65ae52da9..a67fcd2ab 100644 --- a/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp +++ b/core/shader/recompiler/RdnaDecoder/include/RdnaDecoder/RdnaOpcode.hpp @@ -63,6 +63,9 @@ enum class RdnaOpcode : std::uint16_t { VSadHiU8, VSadU16, VMsadU8, + VQsadPkU16U8, + VMqsadPkU16U8, + VMqsadU32U8, VAndB32, VOrB32, VXorB32, diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp index 01506a024..10d89cdc9 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaOpcode.cpp @@ -174,6 +174,9 @@ bool IsVectorAluOpcode(RdnaOpcode opcode) { case RdnaOpcode::VSadHiU8: case RdnaOpcode::VSadU16: case RdnaOpcode::VMsadU8: + case RdnaOpcode::VQsadPkU16U8: + case RdnaOpcode::VMqsadPkU16U8: + case RdnaOpcode::VMqsadU32U8: case RdnaOpcode::VAndB32: case RdnaOpcode::VOrB32: case RdnaOpcode::VXorB32: diff --git a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp index 844ea91db..ab452dd00 100644 --- a/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp +++ b/core/shader/recompiler/RdnaDecoder/src/RdnaVectorOpDecoder.cpp @@ -465,6 +465,9 @@ constexpr VectorOpcodeInfo vop3Opcodes[] = { {0x15cu, RdnaOpcode::VSadU16}, {0x15du, RdnaOpcode::VSadU32}, {0x171u, RdnaOpcode::VMsadU8}, + {0x172u, RdnaOpcode::VQsadPkU16U8}, + {0x173u, RdnaOpcode::VMqsadPkU16U8}, + {0x175u, RdnaOpcode::VMqsadU32U8}, {0x15eu, RdnaOpcode::VCvtPkU8F32}, {0x178u, RdnaOpcode::VXor3B32}, {0x12fu, RdnaOpcode::VCvtPkrtzF16F32}, diff --git a/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp b/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp index 00f729539..7b73b382d 100644 --- a/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp +++ b/core/shader/recompiler/Translation/include/Translation/TranslationContext.hpp @@ -190,7 +190,9 @@ private: bool integer24(const RdnaInstruction& inst, bool sign, bool addend, bool high = false); bool vMadU64U32(const RdnaInstruction& inst); bool vSadU32(const RdnaInstruction& inst); + IrU32 byteSad(const IrU32& lhs, const IrU32& rhs, std::uint32_t fieldBits, bool masked); bool subwordSad(const RdnaInstruction& inst, std::uint32_t fieldBits, std::uint32_t sumShift, bool masked); + bool vQsadU8(const RdnaInstruction& inst, bool masked, bool wide); bool vAdd3U32(const RdnaInstruction& inst); bool sBitsetB32(const RdnaInstruction& inst, bool set); bool sBitsetB64(const RdnaInstruction& inst, bool set); diff --git a/core/shader/recompiler/Translation/src/EmbeddedVertexFetch.cpp b/core/shader/recompiler/Translation/src/EmbeddedVertexFetch.cpp index da66abcb0..e55a8ceaa 100644 --- a/core/shader/recompiler/Translation/src/EmbeddedVertexFetch.cpp +++ b/core/shader/recompiler/Translation/src/EmbeddedVertexFetch.cpp @@ -158,7 +158,16 @@ std::uint32_t decodedDstSize(const RdnaInstruction& inst) { } std::uint32_t embeddedFetchDstSize(const RdnaInstruction& inst) { - return inst.op == RdnaOpcode::VMadU64U32 ? 2u : decodedDstSize(inst); + switch (inst.op) { + case RdnaOpcode::VMadU64U32: + case RdnaOpcode::VQsadPkU16U8: + case RdnaOpcode::VMqsadPkU16U8: + return 2u; + case RdnaOpcode::VMqsadU32U8: + return 4u; + default: + return decodedDstSize(inst); + } } // How many consecutive SGPRs a scalar operand of the instruction names, over-estimated where the diff --git a/core/shader/recompiler/Translation/src/IntegerInstructions.cpp b/core/shader/recompiler/Translation/src/IntegerInstructions.cpp index 420b333f4..55bfc63f3 100644 --- a/core/shader/recompiler/Translation/src/IntegerInstructions.cpp +++ b/core/shader/recompiler/Translation/src/IntegerInstructions.cpp @@ -344,9 +344,7 @@ bool TranslationContext::vSadU32(const RdnaInstruction& inst) { return true; } -bool TranslationContext::subwordSad(const RdnaInstruction& inst, std::uint32_t fieldBits, std::uint32_t sumShift, bool masked) { - const IrU32 lhs = readU32(sourceAt(inst, 0u)); - const IrU32 rhs = readU32(sourceAt(inst, 1u)); +IrU32 TranslationContext::byteSad(const IrU32& lhs, const IrU32& rhs, std::uint32_t fieldBits, bool masked) { IrU32 sum(ir.Constant(0u)); for (std::uint32_t offset = 0u; offset < 32u; offset += fieldBits) { const IrU32 lhsField(ir.Emit(IrOpcode::BitFieldUExtract, IrType::U32, {&lhs.Value(), &ir.Constant(offset), &ir.Constant(fieldBits)})); @@ -360,6 +358,11 @@ bool TranslationContext::subwordSad(const RdnaInstruction& inst, std::uint32_t f } sum = IrU32(ir.IAdd(sum.Value(), difference.Value())); } + return sum; +} + +bool TranslationContext::subwordSad(const RdnaInstruction& inst, std::uint32_t fieldBits, std::uint32_t sumShift, bool masked) { + IrU32 sum = byteSad(readU32(sourceAt(inst, 0u)), readU32(sourceAt(inst, 1u)), fieldBits, masked); if (sumShift != 0u) { sum = IrU32(ir.ShiftLeftLogical(sum.Value(), ir.Constant(sumShift))); } @@ -369,6 +372,33 @@ bool TranslationContext::subwordSad(const RdnaInstruction& inst, std::uint32_t f return true; } +bool TranslationContext::vQsadU8(const RdnaInstruction& inst, bool masked, bool wide) { + const std::array source = readU32Pair(sourceAt(inst, 0u)); + const IrU32 reference = readU32(sourceAt(inst, 1u)); + const auto sad = [&](std::uint32_t shift) { + if (shift == 0u) { + return byteSad(source[0], reference, 8u, masked); + } + const IrU32 window(ir.BitwiseOr(ir.ShiftRightLogical(source[0].Value(), ir.Constant(shift)), ir.ShiftLeftLogical(source[1].Value(), ir.Constant(32u - shift)))); + return byteSad(window, reference, 8u, masked); + }; + const std::array accumulator = readU32Pair(sourceAt(inst, 2u)); + if (wide) { + const std::array accumulatorHigh = readU32Pair(offsetOperand(sourceAt(inst, 2u), 2u)); + writeU32Pair(inst.destination, {IrU32(ir.IAdd(accumulator[0].Value(), sad(0u).Value())), IrU32(ir.IAdd(accumulator[1].Value(), sad(8u).Value()))}); + writeU32Pair(offsetOperand(inst.destination, 2u), + {IrU32(ir.IAdd(accumulatorHigh[0].Value(), sad(16u).Value())), IrU32(ir.IAdd(accumulatorHigh[1].Value(), sad(24u).Value()))}); + return true; + } + const auto packed = [&](const IrU32& addend, std::uint32_t shift) { + const IrU32 low(ir.IAdd(addend.Value(), sad(shift).Value())); + const IrU32 high(ir.IAdd(ir.ShiftRightLogical(addend.Value(), ir.Constant(16u)), sad(shift + 8u).Value())); + return IrU32(ir.BitwiseOr(ir.BitwiseAnd(low.Value(), ir.Constant(0xffffu)), ir.ShiftLeftLogical(high.Value(), ir.Constant(16u)))); + }; + writeU32Pair(inst.destination, {packed(accumulator[0], 0u), packed(accumulator[1], 16u)}); + return true; +} + bool TranslationContext::vAdd3U32(const RdnaInstruction& inst) { const IrU32 lhs = readU32(sourceAt(inst, 0u)); const IrU32 rhs = readU32(sourceAt(inst, 1u)); diff --git a/core/shader/recompiler/Translation/src/VectorInstructions.cpp b/core/shader/recompiler/Translation/src/VectorInstructions.cpp index 44ed05310..d0bd343aa 100644 --- a/core/shader/recompiler/Translation/src/VectorInstructions.cpp +++ b/core/shader/recompiler/Translation/src/VectorInstructions.cpp @@ -1027,6 +1027,12 @@ bool TranslationContext::emitVector(const RdnaInstruction& inst) { return subwordSad(inst, 16u, 0u, false); case RdnaOpcode::VMsadU8: return subwordSad(inst, 8u, 0u, true); + case RdnaOpcode::VQsadPkU16U8: + return vQsadU8(inst, false, false); + case RdnaOpcode::VMqsadPkU16U8: + return vQsadU8(inst, true, false); + case RdnaOpcode::VMqsadU32U8: + return vQsadU8(inst, true, true); case RdnaOpcode::VAdd3U32: return vAdd3U32(inst); case RdnaOpcode::VBcntU32B32: