Shader Decompiler: implement better tracking for Vulkan samplers.

This commit is contained in:
Fernando Sahmkow 2022-03-26 13:40:42 +01:00
parent ba34cf0a69
commit 3d02143476
1 changed files with 59 additions and 9 deletions

View File

@ -174,20 +174,41 @@ bool IsTextureInstruction(const IR::Inst& inst) {
return IndexedInstruction(inst) != IR::Opcode::Void; return IndexedInstruction(inst) != IR::Opcode::Void;
} }
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst); std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env);
std::optional<ConstBufferAddr> Track(const IR::Value& value) { std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env) {
return IR::BreadthFirstSearch(value, TryGetConstBuffer); return IR::BreadthFirstSearch(
value, [&env](const IR::Inst* inst) { return TryGetConstBuffer(inst, env); });
} }
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) { std::optional<u32> TryGetConstant(IR::Value& value, Environment& env) {
const IR::Inst* inst = value.InstRecursive();
if (inst->GetOpcode() != IR::Opcode::GetCbufU32) {
return std::nullopt;
}
const IR::Value index{inst->Arg(0)};
const IR::Value offset{inst->Arg(1)};
if (!index.IsImmediate()) {
return std::nullopt;
}
if (!offset.IsImmediate()) {
return std::nullopt;
}
const auto index_number = index.U32();
if (index_number != 1) {
return std::nullopt;
}
const auto offset_number = offset.U32();
return env.ReadCbufValue(index_number, offset_number);
}
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env) {
switch (inst->GetOpcode()) { switch (inst->GetOpcode()) {
default: default:
return std::nullopt; return std::nullopt;
case IR::Opcode::BitwiseXor32:
case IR::Opcode::BitwiseOr32: { case IR::Opcode::BitwiseOr32: {
std::optional lhs{Track(inst->Arg(0))}; std::optional lhs{Track(inst->Arg(0), env)};
std::optional rhs{Track(inst->Arg(1))}; std::optional rhs{Track(inst->Arg(1), env)};
if (!lhs || !rhs) { if (!lhs || !rhs) {
return std::nullopt; return std::nullopt;
} }
@ -217,13 +238,42 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) {
if (!shift.IsImmediate()) { if (!shift.IsImmediate()) {
return std::nullopt; return std::nullopt;
} }
std::optional lhs{Track(inst->Arg(0))}; std::optional lhs{Track(inst->Arg(0), env)};
if (lhs) { if (lhs) {
lhs->shift_left = shift.U32(); lhs->shift_left = shift.U32();
} }
return lhs; return lhs;
break; break;
} }
case IR::Opcode::BitwiseAnd32: {
IR::Value op1{inst->Arg(0)};
IR::Value op2{inst->Arg(1)};
if (op1.IsImmediate()) {
std::swap(op1, op2);
}
if (!op2.IsImmediate() && !op1.IsImmediate()) {
do {
auto try_index = TryGetConstant(op1, env);
if (try_index) {
op1 = op2;
op2 = IR::Value{*try_index};
break;
}
auto try_index_2 = TryGetConstant(op2, env);
if (try_index_2) {
op2 = IR::Value{*try_index_2};
break;
}
return std::nullopt;
} while (false);
}
std::optional lhs{Track(op1, env)};
if (lhs) {
lhs->shift_left = std::countr_zero(op2.U32());
}
return lhs;
break;
}
case IR::Opcode::GetCbufU32x2: case IR::Opcode::GetCbufU32x2:
case IR::Opcode::GetCbufU32: case IR::Opcode::GetCbufU32:
break; break;
@ -279,7 +329,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) {
TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
ConstBufferAddr addr; ConstBufferAddr addr;
if (IsBindless(inst)) { if (IsBindless(inst)) {
const std::optional<ConstBufferAddr> track_addr{Track(inst.Arg(0))}; const std::optional<ConstBufferAddr> track_addr{Track(inst.Arg(0), env)};
if (!track_addr) { if (!track_addr) {
throw NotImplementedException("Failed to track bindless texture constant buffer"); throw NotImplementedException("Failed to track bindless texture constant buffer");
} }