|
|
|
@ -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"); |
|
|
|
} |
|
|
|
|