mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
shader: expose graphics compute queue fields to GETREG
This commit is contained in:
@@ -1003,7 +1003,7 @@ void CommandProcessor::DispatchDirect(uint32_t thread_group_x, uint32_t thread_g
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_renderer.GetRenderExecutor().DispatchDirect(m_submit_id, CurrentBuffer(), thread_group_x,
|
m_renderer.GetRenderExecutor().DispatchDirect(m_submit_id, CurrentBuffer(), thread_group_x,
|
||||||
thread_group_y, thread_group_z, mode);
|
thread_group_y, thread_group_z, mode, IsAsyncComputeQueue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1015,7 +1015,8 @@ void CommandProcessor::DispatchIndirect(uint64_t args_addr, uint32_t mode) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_sh_ctx.SetCsWaveSize(Pm4::ComputeWaveSize(mode));
|
m_sh_ctx.SetCsWaveSize(Pm4::ComputeWaveSize(mode));
|
||||||
m_renderer.GetRenderExecutor().DispatchIndirect(m_submit_id, CurrentBuffer(), args_addr, mode);
|
m_renderer.GetRenderExecutor().DispatchIndirect(m_submit_id, CurrentBuffer(), args_addr, mode,
|
||||||
|
IsAsyncComputeQueue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandProcessor::DrawIndexAuto(DrawAutoArgs args) {
|
void CommandProcessor::DrawIndexAuto(DrawAutoArgs args) {
|
||||||
|
|||||||
@@ -156,9 +156,9 @@ public:
|
|||||||
KYTY_CLASS_NO_COPY(RenderExecutor);
|
KYTY_CLASS_NO_COPY(RenderExecutor);
|
||||||
|
|
||||||
void DispatchDirect(uint64_t submit_id, CommandBuffer& buffer, uint32_t thread_group_x,
|
void DispatchDirect(uint64_t submit_id, CommandBuffer& buffer, uint32_t thread_group_x,
|
||||||
uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode);
|
uint32_t thread_group_y, uint32_t thread_group_z, uint32_t mode, bool async_compute);
|
||||||
void DispatchIndirect(uint64_t submit_id, CommandBuffer& buffer, uint64_t args_addr,
|
void DispatchIndirect(uint64_t submit_id, CommandBuffer& buffer, uint64_t args_addr,
|
||||||
uint32_t mode);
|
uint32_t mode, bool async_compute);
|
||||||
|
|
||||||
void PrepareBindings(const ShaderStageRuntime& runtime, PreparedBindings& prepared);
|
void PrepareBindings(const ShaderStageRuntime& runtime, PreparedBindings& prepared);
|
||||||
void FindBuffers(std::span<PreparedBindings* const> stages);
|
void FindBuffers(std::span<PreparedBindings* const> stages);
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ static void BindSharedMemory(RenderContext& context, ShaderComputeInputInfo& inp
|
|||||||
|
|
||||||
void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
||||||
uint32_t thread_group_x, uint32_t thread_group_y,
|
uint32_t thread_group_x, uint32_t thread_group_y,
|
||||||
uint32_t thread_group_z, uint32_t mode) {
|
uint32_t thread_group_z, uint32_t mode, bool async_compute) {
|
||||||
EXIT_IF(buffer.IsInvalid());
|
EXIT_IF(buffer.IsInvalid());
|
||||||
m_context.GetCommandScheduler().PopPendingOperations();
|
m_context.GetCommandScheduler().PopPendingOperations();
|
||||||
auto& ctx = buffer.GetRegisters();
|
auto& ctx = buffer.GetRegisters();
|
||||||
@@ -281,6 +281,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
const auto& sh_regs = ctx.GetShaderRegisters();
|
const auto& sh_regs = ctx.GetShaderRegisters();
|
||||||
|
|
||||||
ShaderComputeInputInfo input_info {};
|
ShaderComputeInputInfo input_info {};
|
||||||
|
input_info.async_compute = async_compute;
|
||||||
const bool use_thread_dimensions = (mode & DISPATCH_INITIATOR_USE_THREAD_DIMENSIONS) != 0;
|
const bool use_thread_dimensions = (mode & DISPATCH_INITIATOR_USE_THREAD_DIMENSIONS) != 0;
|
||||||
input_info.dispatch_thread_dimensions = use_thread_dimensions;
|
input_info.dispatch_thread_dimensions = use_thread_dimensions;
|
||||||
input_info.workgroup_counts[0] = thread_group_x;
|
input_info.workgroup_counts[0] = thread_group_x;
|
||||||
@@ -437,7 +438,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RenderExecutor::DispatchIndirect(uint64_t submit_id, CommandBuffer& buffer,
|
void RenderExecutor::DispatchIndirect(uint64_t submit_id, CommandBuffer& buffer,
|
||||||
uint64_t args_addr, uint32_t mode) {
|
uint64_t args_addr, uint32_t mode, bool async_compute) {
|
||||||
EXIT_IF(buffer.IsInvalid() || args_addr == 0 || (args_addr & 3u) != 0 ||
|
EXIT_IF(buffer.IsInvalid() || args_addr == 0 || (args_addr & 3u) != 0 ||
|
||||||
(mode & Pm4::COMPUTE_DISPATCH_INITIATOR_USE_THREAD_DIMENSIONS) != 0);
|
(mode & Pm4::COMPUTE_DISPATCH_INITIATOR_USE_THREAD_DIMENSIONS) != 0);
|
||||||
m_context.GetCommandScheduler().PopPendingOperations();
|
m_context.GetCommandScheduler().PopPendingOperations();
|
||||||
@@ -450,6 +451,7 @@ void RenderExecutor::DispatchIndirect(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ShaderComputeInputInfo input_info {};
|
ShaderComputeInputInfo input_info {};
|
||||||
|
input_info.async_compute = async_compute;
|
||||||
const auto compute_program = m_context.GetPipelineCache().GetComputeProgram(
|
const auto compute_program = m_context.GetPipelineCache().GetComputeProgram(
|
||||||
cs_regs, buffer.GetRegisters().GetShaderRegisters(), input_info);
|
cs_regs, buffer.GetRegisters().GetShaderRegisters(), input_info);
|
||||||
buffer.EndRendering();
|
buffer.EndRendering();
|
||||||
|
|||||||
@@ -534,7 +534,8 @@ void PrepareCallTarget(ShaderSource& source, const CompileOptions& options) {
|
|||||||
if (inserted) {
|
if (inserted) {
|
||||||
Block translated;
|
Block translated;
|
||||||
Frontend::Translator translator(query, &translated, 1u,
|
Frontend::Translator translator(query, &translated, 1u,
|
||||||
(options.input_info.compute->float_mode & 0x10u) == 0u);
|
(options.input_info.compute->float_mode & 0x10u) == 0u,
|
||||||
|
!options.input_info.compute->async_compute);
|
||||||
translator.TranslateInstruction(source.decoded.instructions[index]);
|
translator.TranslateInstruction(source.decoded.instructions[index]);
|
||||||
for (const auto& inst: translated) {
|
for (const auto& inst: translated) {
|
||||||
uint32_t destination = UINT32_MAX;
|
uint32_t destination = UINT32_MAX;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ constexpr OpcodeMap SOPK_OPCODE_LIST[] = {
|
|||||||
{0x08u, Opcode::S_CMP_LE_I32}, {0x09u, Opcode::S_CMP_EQ_U32}, {0x0au, Opcode::S_CMP_LG_U32},
|
{0x08u, Opcode::S_CMP_LE_I32}, {0x09u, Opcode::S_CMP_EQ_U32}, {0x0au, Opcode::S_CMP_LG_U32},
|
||||||
{0x0bu, Opcode::S_CMP_GT_U32}, {0x0cu, Opcode::S_CMP_GE_U32}, {0x0du, Opcode::S_CMP_LT_U32},
|
{0x0bu, Opcode::S_CMP_GT_U32}, {0x0cu, Opcode::S_CMP_GE_U32}, {0x0du, Opcode::S_CMP_LT_U32},
|
||||||
{0x0eu, Opcode::S_CMP_LE_U32}, {0x0fu, Opcode::S_ADD_I32}, {0x10u, Opcode::S_MULK_I32},
|
{0x0eu, Opcode::S_CMP_LE_U32}, {0x0fu, Opcode::S_ADD_I32}, {0x10u, Opcode::S_MULK_I32},
|
||||||
{0x13u, Opcode::S_SETREG_B32}, {0x17u, Opcode::S_WAITCNT_VSCNT}, {0x18u, Opcode::S_WAITCNT},
|
{0x12u, Opcode::S_GETREG_B32}, {0x13u, Opcode::S_SETREG_B32}, {0x17u, Opcode::S_WAITCNT_VSCNT}, {0x18u, Opcode::S_WAITCNT},
|
||||||
{0x19u, Opcode::S_WAITCNT}, {0x1au, Opcode::S_WAITCNT},
|
{0x19u, Opcode::S_WAITCNT}, {0x1au, Opcode::S_WAITCNT},
|
||||||
{0x1bu, Opcode::S_SUBVECTOR_LOOP_BEGIN}, {0x1cu, Opcode::S_SUBVECTOR_LOOP_END},
|
{0x1bu, Opcode::S_SUBVECTOR_LOOP_BEGIN}, {0x1cu, Opcode::S_SUBVECTOR_LOOP_END},
|
||||||
};
|
};
|
||||||
@@ -207,7 +207,7 @@ void DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
|||||||
const uint32_t word = code[word_index];
|
const uint32_t word = code[word_index];
|
||||||
const uint32_t opcode = (word >> 23u) & 0x1fu;
|
const uint32_t opcode = (word >> 23u) & 0x1fu;
|
||||||
const uint32_t sdst = (word >> 16u) & 0x7fu;
|
const uint32_t sdst = (word >> 16u) & 0x7fu;
|
||||||
const auto imm = opcode >= 0x09u && opcode <= 0x0eu
|
const auto imm = (opcode >= 0x09u && opcode <= 0x0eu) || opcode == 0x12u
|
||||||
? static_cast<int32_t>(word & 0xffffu)
|
? static_cast<int32_t>(word & 0xffffu)
|
||||||
: static_cast<int32_t>(static_cast<int16_t>(word & 0xffffu));
|
: static_cast<int32_t>(static_cast<int16_t>(word & 0xffffu));
|
||||||
|
|
||||||
@@ -227,6 +227,7 @@ void DecodeSopk(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (inst.opcode) {
|
switch (inst.opcode) {
|
||||||
|
case Opcode::S_GETREG_B32:
|
||||||
case Opcode::S_MOVK_I32: DecodeScalarDestination(sdst, pc, inst.dst); return;
|
case Opcode::S_MOVK_I32: DecodeScalarDestination(sdst, pc, inst.dst); return;
|
||||||
case Opcode::S_SUBVECTOR_LOOP_BEGIN:
|
case Opcode::S_SUBVECTOR_LOOP_BEGIN:
|
||||||
case Opcode::S_SUBVECTOR_LOOP_END:
|
case Opcode::S_SUBVECTOR_LOOP_END:
|
||||||
|
|||||||
@@ -679,6 +679,7 @@ enum class Opcode {
|
|||||||
S_CBRANCH_CDBGSYS,
|
S_CBRANCH_CDBGSYS,
|
||||||
S_CBRANCH_CDBGSYS_OR_USER,
|
S_CBRANCH_CDBGSYS_OR_USER,
|
||||||
S_SENDMSG,
|
S_SENDMSG,
|
||||||
|
S_GETREG_B32,
|
||||||
S_SETREG_B32,
|
S_SETREG_B32,
|
||||||
S_SLEEP,
|
S_SLEEP,
|
||||||
S_TRAP,
|
S_TRAP,
|
||||||
|
|||||||
@@ -18,6 +18,13 @@ void Translator::EmitScalar(const Decoder::Instruction& inst) {
|
|||||||
case O::S_CSELECT_B32: S_CSELECT_B32(inst); return;
|
case O::S_CSELECT_B32: S_CSELECT_B32(inst); return;
|
||||||
case O::S_CSELECT_B64: ScalarSelect64(inst, inst.src1); return;
|
case O::S_CSELECT_B64: ScalarSelect64(inst, inst.src1); return;
|
||||||
case O::S_CMOV_B64: ScalarSelect64(inst, inst.dst); return;
|
case O::S_CMOV_B64: ScalarSelect64(inst, inst.dst); return;
|
||||||
|
case O::S_GETREG_B32:
|
||||||
|
if (!graphics_compute || (inst.src0.value != 0x1818u && inst.src0.value != 0x0a18u))
|
||||||
|
EXIT("unsupported S_GETREG_B32 at pc 0x%08x: selector=0x%04x graphics_compute=%u",
|
||||||
|
inst.pc, inst.src0.value, static_cast<unsigned>(graphics_compute));
|
||||||
|
// HW_ID2 identifies graphics compute as QUEUE=6, ME=0.
|
||||||
|
WriteOperand(inst.dst, IR::Value(inst.src0.value == 0x1818u ? 6u : 0u));
|
||||||
|
return;
|
||||||
case O::S_SETREG_B32: EmitControlNop(); return;
|
case O::S_SETREG_B32: EmitControlNop(); return;
|
||||||
case O::S_WAITCNT_VSCNT: S_WAITCNT_VSCNT(inst); return;
|
case O::S_WAITCNT_VSCNT: S_WAITCNT_VSCNT(inst); return;
|
||||||
case O::S_WAITCNT: return;
|
case O::S_WAITCNT: return;
|
||||||
|
|||||||
@@ -1356,7 +1356,8 @@ IR::Program TranslateProgram(const Decoder::Program& decoded, const CFG::Graph&
|
|||||||
(options.input_info.compute->float_mode & 0x10u) == 0;
|
(options.input_info.compute->float_mode & 0x10u) == 0;
|
||||||
for (const auto& cfg_block: cfg.blocks) {
|
for (const auto& cfg_block: cfg.blocks) {
|
||||||
auto* block = blocks_by_id.at(cfg_block.id);
|
auto* block = blocks_by_id.at(cfg_block.id);
|
||||||
Translator translator(result, block, vector_limit, flush_f32_inputs);
|
Translator translator(result, block, vector_limit, flush_f32_inputs,
|
||||||
|
options.stage == ShaderType::Compute && !options.input_info.compute->async_compute);
|
||||||
for (uint32_t index = cfg_block.inst_begin; index < cfg_block.inst_end; index++) {
|
for (uint32_t index = cfg_block.inst_begin; index < cfg_block.inst_end; index++) {
|
||||||
const auto& instruction = decoded.instructions[index];
|
const auto& instruction = decoded.instructions[index];
|
||||||
if (IsCodeTableLoad(cfg, instruction.pc)) {
|
if (IsCodeTableLoad(cfg, instruction.pc)) {
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ namespace Libs::Graphics::ShaderRecompiler::Frontend {
|
|||||||
class Translator {
|
class Translator {
|
||||||
public:
|
public:
|
||||||
Translator(IR::Program& program, IR::Block* block, uint32_t vector_limit,
|
Translator(IR::Program& program, IR::Block* block, uint32_t vector_limit,
|
||||||
bool flush_f32_inputs)
|
bool flush_f32_inputs, bool graphics_compute)
|
||||||
: program(program), ir(block), current_vector_limit(vector_limit),
|
: program(program), ir(block), current_vector_limit(vector_limit),
|
||||||
flush_f32_inputs(flush_f32_inputs) {}
|
flush_f32_inputs(flush_f32_inputs), graphics_compute(graphics_compute) {}
|
||||||
|
|
||||||
void TranslateInstruction(const Decoder::Instruction& inst);
|
void TranslateInstruction(const Decoder::Instruction& inst);
|
||||||
void TranslateEmbeddedFetch(const Decoder::Instruction& inst, uint32_t attribute,
|
void TranslateEmbeddedFetch(const Decoder::Instruction& inst, uint32_t attribute,
|
||||||
@@ -264,6 +264,7 @@ private:
|
|||||||
uint32_t current_pc = 0;
|
uint32_t current_pc = 0;
|
||||||
uint32_t current_vector_limit = 1;
|
uint32_t current_vector_limit = 1;
|
||||||
bool flush_f32_inputs;
|
bool flush_f32_inputs;
|
||||||
|
bool graphics_compute;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
} // namespace Libs::Graphics::ShaderRecompiler::Frontend
|
||||||
|
|||||||
@@ -574,10 +574,12 @@ static void ShaderGetStaticInputInfoPS(
|
|||||||
static void ShaderGetStaticInputInfoCS(const HW::ComputeShaderInfo& regs,
|
static void ShaderGetStaticInputInfoCS(const HW::ComputeShaderInfo& regs,
|
||||||
const HW::ShaderRegisters& /*sh*/,
|
const HW::ShaderRegisters& /*sh*/,
|
||||||
const ShaderMappedData& data, ShaderComputeInputInfo& info) {
|
const ShaderMappedData& data, ShaderComputeInputInfo& info) {
|
||||||
|
const bool async_compute = info.async_compute;
|
||||||
const bool dispatch_thread_dimensions = info.dispatch_thread_dimensions;
|
const bool dispatch_thread_dimensions = info.dispatch_thread_dimensions;
|
||||||
const auto host_subgroup_size = info.host_subgroup_size;
|
const auto host_subgroup_size = info.host_subgroup_size;
|
||||||
const auto workgroup_counts = std::to_array(info.workgroup_counts);
|
const auto workgroup_counts = std::to_array(info.workgroup_counts);
|
||||||
info = {};
|
info = {};
|
||||||
|
info.async_compute = async_compute;
|
||||||
info.dispatch_thread_dimensions = dispatch_thread_dimensions;
|
info.dispatch_thread_dimensions = dispatch_thread_dimensions;
|
||||||
info.host_subgroup_size = host_subgroup_size;
|
info.host_subgroup_size = host_subgroup_size;
|
||||||
std::ranges::copy(workgroup_counts, info.workgroup_counts);
|
std::ranges::copy(workgroup_counts, info.workgroup_counts);
|
||||||
@@ -693,7 +695,8 @@ void BuildStageStaticKey(const ShaderComputeInputInfo& info, std::vector<uint32_
|
|||||||
key.push_back(info.thread_ids_num);
|
key.push_back(info.thread_ids_num);
|
||||||
key.push_back(info.lds_size_dwords);
|
key.push_back(info.lds_size_dwords);
|
||||||
key.push_back(info.scratch_size_dwords);
|
key.push_back(info.scratch_size_dwords);
|
||||||
key.push_back(static_cast<uint32_t>(info.dispatch_thread_dimensions));
|
key.push_back(static_cast<uint32_t>(info.dispatch_thread_dimensions) |
|
||||||
|
(static_cast<uint32_t>(info.async_compute) << 1u));
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
key.push_back(info.threads_num[i]);
|
key.push_back(info.threads_num[i]);
|
||||||
key.push_back(static_cast<uint32_t>(info.group_id[i]));
|
key.push_back(static_cast<uint32_t>(info.group_id[i]));
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ struct ShaderVertexInputInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ShaderComputeInputInfo: ShaderWorkgroupInputInfo {
|
struct ShaderComputeInputInfo: ShaderWorkgroupInputInfo {
|
||||||
|
bool async_compute = false;
|
||||||
uint8_t float_mode = 0xc0;
|
uint8_t float_mode = 0xc0;
|
||||||
uint32_t dispatch_threads_num[3] = {0, 0, 0};
|
uint32_t dispatch_threads_num[3] = {0, 0, 0};
|
||||||
uint32_t workgroup_counts[3] = {0, 0, 0};
|
uint32_t workgroup_counts[3] = {0, 0, 0};
|
||||||
|
|||||||
@@ -5055,7 +5055,7 @@ public:
|
|||||||
for (const auto mode : {0x41u, 0x61u}) {
|
for (const auto mode : {0x41u, 0x61u}) {
|
||||||
for (const auto &groups : empty_dispatches) {
|
for (const auto &groups : empty_dispatches) {
|
||||||
context.GetRenderExecutor().DispatchDirect(
|
context.GetRenderExecutor().DispatchDirect(
|
||||||
0, scheduler.Current(), groups[0], groups[1], groups[2], mode);
|
0, scheduler.Current(), groups[0], groups[1], groups[2], mode, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Require(name, "HTile fixture",
|
Require(name, "HTile fixture",
|
||||||
@@ -10006,14 +10006,22 @@ public:
|
|||||||
for (u32 i = 0; i < 4; ++i)
|
for (u32 i = 0; i < 4; ++i)
|
||||||
shaders.SetCsUserSgpr(i, out.fields[i], HW::UserSgprType::Unknown);
|
shaders.SetCsUserSgpr(i, out.fields[i], HW::UserSgprType::Unknown);
|
||||||
uint64_t original_id = 0;
|
uint64_t original_id = 0;
|
||||||
struct Case { uint64_t address; u32 value; bool update; };
|
struct Case { uint64_t address; u32 value; bool update; u32 field = 0; };
|
||||||
for (const auto test : {Case{first, 41, false}, Case{first, 41, false},
|
for (const auto test : {Case{first, 41, false}, Case{first, 41, false},
|
||||||
Case{second, 41, false}, Case{second, 73, true},
|
Case{second, 41, false}, Case{second, 73, true},
|
||||||
Case{first, 41, false}}) {
|
Case{first, 41, false}, Case{first, 6, false, 0x1818},
|
||||||
|
Case{first, 0, false, 0x0a18}}) {
|
||||||
Require(name, "refresh function pointer", context.InvalidateMemory(table + 0x20, 8),
|
Require(name, "refresh function pointer", context.InvalidateMemory(table + 0x20, 8),
|
||||||
"function table escaped mapped memory");
|
"function table escaped mapped memory");
|
||||||
const uint64_t target = test.address | 3u;
|
const uint64_t target = test.address | 3u;
|
||||||
LibKernel::Memory::WriteBacking(table + 0x20, &target, sizeof(target));
|
LibKernel::Memory::WriteBacking(table + 0x20, &target, sizeof(target));
|
||||||
|
if (test.field != 0) {
|
||||||
|
Require(name, "refresh hardware-field leaf", context.InvalidateMemory(first, sizeof(leaf)),
|
||||||
|
"hardware-field leaf escaped mapped memory");
|
||||||
|
const std::array field_leaf{0xb96a0000u | test.field,
|
||||||
|
EncodeSMovB32(20, 106), EncodeSop1(0x21, 125, 14)};
|
||||||
|
LibKernel::Memory::WriteBacking(first, field_leaf.data(), sizeof(field_leaf));
|
||||||
|
}
|
||||||
if (test.update) {
|
if (test.update) {
|
||||||
auto [buffer, offset] = cache.ObtainBuffer(test.address + 4, 4, true);
|
auto [buffer, offset] = cache.ObtainBuffer(test.address + 4, 4, true);
|
||||||
buffer->Fill(offset, 4, test.value);
|
buffer->Fill(offset, 4, test.value);
|
||||||
@@ -10703,7 +10711,7 @@ public:
|
|||||||
for (uint32_t i = 0; i < user_data.size(); i++) {
|
for (uint32_t i = 0; i < user_data.size(); i++) {
|
||||||
shaders.SetCsUserSgpr(i, user_data[i], HW::UserSgprType::Unknown);
|
shaders.SetCsUserSgpr(i, user_data[i], HW::UserSgprType::Unknown);
|
||||||
}
|
}
|
||||||
executor.DispatchDirect(0, scheduler.Current(), (count + 63) / 64, 1, 1, 0x41u);
|
executor.DispatchDirect(0, scheduler.Current(), (count + 63) / 64, 1, 1, 0x41u, false);
|
||||||
};
|
};
|
||||||
const auto metadata_words = static_cast<uint32_t>(metadata_size / 4);
|
const auto metadata_words = static_cast<uint32_t>(metadata_size / 4);
|
||||||
fill_metadata(metadata_words);
|
fill_metadata(metadata_words);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "graphics/shader/recompiler/frontend/cfg/ShaderCFG.h"
|
#include "graphics/shader/recompiler/frontend/cfg/ShaderCFG.h"
|
||||||
#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h"
|
#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h"
|
||||||
#include "graphics/shader/recompiler/frontend/translate/Translate.h"
|
#include "graphics/shader/recompiler/frontend/translate/Translate.h"
|
||||||
|
#include "graphics/shader/recompiler/frontend/translate/Translator.h"
|
||||||
#include "graphics/shader/recompiler/ir/IREmitter.h"
|
#include "graphics/shader/recompiler/ir/IREmitter.h"
|
||||||
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
||||||
#include "graphics/shader/recompiler/ir/passes/ConstantPropagation.h"
|
#include "graphics/shader/recompiler/ir/passes/ConstantPropagation.h"
|
||||||
@@ -10308,6 +10309,62 @@ void TestNewShaderRecompilerBranchConditionForms() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestGraphicsComputeGetreg() {
|
||||||
|
using namespace ShaderRecompiler;
|
||||||
|
for (const auto [word, expected] : {std::pair{0xb96a1818u, 6u}, std::pair{0xb96a0a18u, 0u}}) {
|
||||||
|
Decoder::Instruction decoded;
|
||||||
|
Decoder::DecodeInstruction(std::span(&word, 1), 0, decoded);
|
||||||
|
Check(decoded.opcode == Decoder::Opcode::S_GETREG_B32 &&
|
||||||
|
decoded.dst.kind == Decoder::OperandKind::VccLo &&
|
||||||
|
decoded.src0.value == (word & 0xffffu), "GETREG field or VCC destination decoded incorrectly");
|
||||||
|
for (const auto wave : {32u, 64u}) {
|
||||||
|
IR::Program program;
|
||||||
|
program.wave_size = wave;
|
||||||
|
IR::Block block;
|
||||||
|
Frontend::Translator translator(program, &block, 1, false, true);
|
||||||
|
translator.TranslateInstruction(decoded);
|
||||||
|
bool wrote_vcc = false;
|
||||||
|
for (const auto& inst : block) {
|
||||||
|
Check(inst.GetOpcode() != IR::ValueOpcode::SetScc, "GETREG changed SCC");
|
||||||
|
if (inst.GetOpcode() == IR::ValueOpcode::SetVccLo) {
|
||||||
|
Check(inst.Arg(0).IsImmediate() && inst.Arg(0).U32() == expected,
|
||||||
|
"graphics compute hardware field has the wrong value");
|
||||||
|
wrote_vcc = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Check(wrote_vcc, "GETREG did not write VCC_LO");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const uint32_t shader[] = {0xb96a1818u, EncodeSopp(0x01)};
|
||||||
|
HW::ComputeShaderInfo regs{};
|
||||||
|
regs.cs_regs.data_addr = reinterpret_cast<uint64_t>(shader);
|
||||||
|
ShaderMappedData mapped{};
|
||||||
|
mapped.code_size_bytes = sizeof(shader);
|
||||||
|
ShaderMapUserData(regs.cs_regs.data_addr, mapped);
|
||||||
|
HW::ShaderRegisters sh{};
|
||||||
|
ShaderComputeInputInfo graphics{}, async{};
|
||||||
|
async.async_compute = true;
|
||||||
|
(void)PrepareProgram(regs, sh, graphics);
|
||||||
|
(void)PrepareProgram(regs, sh, async);
|
||||||
|
Check(!graphics.async_compute && async.async_compute &&
|
||||||
|
MakeStageStaticKey(graphics) != MakeStageStaticKey(async) &&
|
||||||
|
MakeStageStaticKey(graphics).size() == MakeStageStaticKey(async).size(),
|
||||||
|
"compute input reset or cache identity lost queue provenance");
|
||||||
|
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||||
|
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||||
|
options.input_info.compute = &async;
|
||||||
|
ExpectFatal([&] { (void)TranslateProgram(shader, options); }, "async GETREG used graphics constants");
|
||||||
|
auto vertex = MakeCompileOptions(ShaderType::Vertex);
|
||||||
|
ExpectFatal([&] { (void)TranslateProgram(shader, vertex); }, "vertex GETREG used compute constants");
|
||||||
|
options.input_info.compute = &graphics;
|
||||||
|
const uint32_t unsupported[] = {0xb96af818u, EncodeSopp(0x01)};
|
||||||
|
Decoder::Program decoded;
|
||||||
|
Decoder::DecodeProgram(unsupported, decoded);
|
||||||
|
Check(decoded.instructions[0].src0.value == 0xf818u, "GETREG selector was sign extended");
|
||||||
|
ExpectFatal([&] { (void)TranslateProgram(unsupported, options); }, "unsupported GETREG field was accepted");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void TestMemoryFedScalarLeafCall() {
|
void TestMemoryFedScalarLeafCall() {
|
||||||
using namespace ShaderRecompiler;
|
using namespace ShaderRecompiler;
|
||||||
constexpr uint64_t base = 0xfe0040000ull;
|
constexpr uint64_t base = 0xfe0040000ull;
|
||||||
@@ -15586,6 +15643,7 @@ int main() {
|
|||||||
TestNewShaderRecompilerPixelImageSampleLodSelection();
|
TestNewShaderRecompilerPixelImageSampleLodSelection();
|
||||||
TestNewShaderRecompilerBranchConditionForms();
|
TestNewShaderRecompilerBranchConditionForms();
|
||||||
TestNewShaderRecompilerSetpcBranch();
|
TestNewShaderRecompilerSetpcBranch();
|
||||||
|
TestGraphicsComputeGetreg();
|
||||||
TestMemoryFedScalarLeafCall();
|
TestMemoryFedScalarLeafCall();
|
||||||
TestFusedShaderHandoffPreservesRegisters();
|
TestFusedShaderHandoffPreservesRegisters();
|
||||||
TestMeshExportStorage();
|
TestMeshExportStorage();
|
||||||
|
|||||||
Reference in New Issue
Block a user