|
|
|
@ -132,6 +132,30 @@ void SetPatch(Info& info, IR::Patch patch) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void CheckCBufNVN(Info& info, IR::Inst& inst) { |
|
|
|
const IR::Value cbuf_index{inst.Arg(0)}; |
|
|
|
if (!cbuf_index.IsImmediate()) { |
|
|
|
info.nvn_buffer_used.set(); |
|
|
|
return; |
|
|
|
} |
|
|
|
const u32 index{cbuf_index.U32()}; |
|
|
|
if (index != 0) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const IR::Value cbuf_offset{inst.Arg(1)}; |
|
|
|
if (!cbuf_offset.IsImmediate()) { |
|
|
|
info.nvn_buffer_used.set(); |
|
|
|
return; |
|
|
|
} |
|
|
|
const u32 offset{cbuf_offset.U32()}; |
|
|
|
const u32 descriptor_size{0x10}; |
|
|
|
const u32 upper_limit{info.nvn_buffer_base + descriptor_size * 16}; |
|
|
|
if (offset >= info.nvn_buffer_base && offset < upper_limit) { |
|
|
|
const std::size_t nvn_index{(offset - info.nvn_buffer_base) / descriptor_size}; |
|
|
|
info.nvn_buffer_used.set(nvn_index, true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void VisitUsages(Info& info, IR::Inst& inst) { |
|
|
|
switch (inst.GetOpcode()) { |
|
|
|
case IR::Opcode::CompositeConstructF16x2: |
|
|
|
@ -382,13 +406,6 @@ void VisitUsages(Info& info, IR::Inst& inst) { |
|
|
|
break; |
|
|
|
} |
|
|
|
switch (inst.GetOpcode()) { |
|
|
|
case IR::Opcode::LoadGlobalU8: |
|
|
|
case IR::Opcode::LoadGlobalS8: |
|
|
|
case IR::Opcode::LoadGlobalU16: |
|
|
|
case IR::Opcode::LoadGlobalS16: |
|
|
|
case IR::Opcode::LoadGlobal32: |
|
|
|
case IR::Opcode::LoadGlobal64: |
|
|
|
case IR::Opcode::LoadGlobal128: |
|
|
|
case IR::Opcode::WriteGlobalU8: |
|
|
|
case IR::Opcode::WriteGlobalS8: |
|
|
|
case IR::Opcode::WriteGlobalU16: |
|
|
|
@ -423,6 +440,15 @@ void VisitUsages(Info& info, IR::Inst& inst) { |
|
|
|
case IR::Opcode::GlobalAtomicMinF32x2: |
|
|
|
case IR::Opcode::GlobalAtomicMaxF16x2: |
|
|
|
case IR::Opcode::GlobalAtomicMaxF32x2: |
|
|
|
info.stores_global_memory = true; |
|
|
|
[[fallthrough]]; |
|
|
|
case IR::Opcode::LoadGlobalU8: |
|
|
|
case IR::Opcode::LoadGlobalS8: |
|
|
|
case IR::Opcode::LoadGlobalU16: |
|
|
|
case IR::Opcode::LoadGlobalS16: |
|
|
|
case IR::Opcode::LoadGlobal32: |
|
|
|
case IR::Opcode::LoadGlobal64: |
|
|
|
case IR::Opcode::LoadGlobal128: |
|
|
|
info.uses_int64 = true; |
|
|
|
info.uses_global_memory = true; |
|
|
|
info.used_constant_buffer_types |= IR::Type::U32 | IR::Type::U32x2; |
|
|
|
@ -800,9 +826,27 @@ void VisitFpModifiers(Info& info, IR::Inst& inst) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void VisitCbufs(Info& info, IR::Inst& inst) { |
|
|
|
switch (inst.GetOpcode()) { |
|
|
|
case IR::Opcode::GetCbufU8: |
|
|
|
case IR::Opcode::GetCbufS8: |
|
|
|
case IR::Opcode::GetCbufU16: |
|
|
|
case IR::Opcode::GetCbufS16: |
|
|
|
case IR::Opcode::GetCbufU32: |
|
|
|
case IR::Opcode::GetCbufF32: |
|
|
|
case IR::Opcode::GetCbufU32x2: { |
|
|
|
CheckCBufNVN(info, inst); |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void Visit(Info& info, IR::Inst& inst) { |
|
|
|
VisitUsages(info, inst); |
|
|
|
VisitFpModifiers(info, inst); |
|
|
|
VisitCbufs(info, inst); |
|
|
|
} |
|
|
|
|
|
|
|
void GatherInfoFromHeader(Environment& env, Info& info) { |
|
|
|
@ -839,6 +883,26 @@ void GatherInfoFromHeader(Environment& env, Info& info) { |
|
|
|
|
|
|
|
void CollectShaderInfoPass(Environment& env, IR::Program& program) { |
|
|
|
Info& info{program.info}; |
|
|
|
const u32 base{[&] { |
|
|
|
switch (program.stage) { |
|
|
|
case Stage::VertexA: |
|
|
|
case Stage::VertexB: |
|
|
|
return 0x110u; |
|
|
|
case Stage::TessellationControl: |
|
|
|
return 0x210u; |
|
|
|
case Stage::TessellationEval: |
|
|
|
return 0x310u; |
|
|
|
case Stage::Geometry: |
|
|
|
return 0x410u; |
|
|
|
case Stage::Fragment: |
|
|
|
return 0x510u; |
|
|
|
case Stage::Compute: |
|
|
|
return 0x310u; |
|
|
|
} |
|
|
|
throw InvalidArgument("Invalid stage {}", program.stage); |
|
|
|
}()}; |
|
|
|
info.nvn_buffer_base = base; |
|
|
|
|
|
|
|
for (IR::Block* const block : program.post_order_blocks) { |
|
|
|
for (IR::Inst& inst : block->Instructions()) { |
|
|
|
Visit(info, inst); |
|
|
|
|