mirror of
https://github.com/yuzu-mirror/yuzu
synced 2024-11-27 19:50:18 +00:00
Shader Decompiler: implement better tracking for Vulkan samplers.
This commit is contained in:
parent
ba34cf0a69
commit
3d02143476
1 changed files with 59 additions and 9 deletions
|
@ -174,20 +174,41 @@ bool IsTextureInstruction(const IR::Inst& inst) {
|
|||
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) {
|
||||
return IR::BreadthFirstSearch(value, TryGetConstBuffer);
|
||||
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env) {
|
||||
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()) {
|
||||
default:
|
||||
return std::nullopt;
|
||||
case IR::Opcode::BitwiseXor32:
|
||||
case IR::Opcode::BitwiseOr32: {
|
||||
std::optional lhs{Track(inst->Arg(0))};
|
||||
std::optional rhs{Track(inst->Arg(1))};
|
||||
std::optional lhs{Track(inst->Arg(0), env)};
|
||||
std::optional rhs{Track(inst->Arg(1), env)};
|
||||
if (!lhs || !rhs) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -217,13 +238,42 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) {
|
|||
if (!shift.IsImmediate()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional lhs{Track(inst->Arg(0))};
|
||||
std::optional lhs{Track(inst->Arg(0), env)};
|
||||
if (lhs) {
|
||||
lhs->shift_left = shift.U32();
|
||||
}
|
||||
return lhs;
|
||||
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::GetCbufU32:
|
||||
break;
|
||||
|
@ -279,7 +329,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst) {
|
|||
TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
|
||||
ConstBufferAddr addr;
|
||||
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) {
|
||||
throw NotImplementedException("Failed to track bindless texture constant buffer");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue