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