mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-22 11:56:58 +02:00
shader: materialize exact buffer capacity through shared clean reads
Co-authored-by: shadowbeat070 <70843316+shadowbeat070@users.noreply.github.com>
This commit is contained in:
@@ -41,16 +41,29 @@ bool AddSignedAddress(uint64_t base, int64_t offset, uint64_t& result) {
|
||||
|
||||
bool IsRawRead(const ResourcePlan& values, const Inst& inst) {
|
||||
const auto op = inst.GetOpcode();
|
||||
if (op != ValueOpcode::LoadAddressU32 && op != ValueOpcode::ReadConstBuffer) {
|
||||
if (op != ValueOpcode::LoadAddressU32 && op != ValueOpcode::ReadConstBuffer &&
|
||||
op != ValueOpcode::LoadBufferU32) {
|
||||
return false;
|
||||
}
|
||||
const auto index = inst.Flags<MemoryFlags>().index;
|
||||
if (index >= values.memory_info.size()) {
|
||||
return false;
|
||||
}
|
||||
const auto kind = values.memory_info[index].kind;
|
||||
return (op == ValueOpcode::LoadAddressU32 && kind == ResourceKind::ScalarAddress) ||
|
||||
(op == ValueOpcode::ReadConstBuffer && kind == ResourceKind::ScalarBuffer);
|
||||
const auto& memory = values.memory_info[index];
|
||||
if (op != ValueOpcode::LoadBufferU32) {
|
||||
return (op == ValueOpcode::LoadAddressU32 && memory.kind == ResourceKind::ScalarAddress) ||
|
||||
(op == ValueOpcode::ReadConstBuffer && memory.kind == ResourceKind::ScalarBuffer);
|
||||
}
|
||||
if (inst.NumArgs() != 5u || memory.kind != ResourceKind::Buffer || memory.typed ||
|
||||
memory.formatted || memory.coherent || memory.data_bits != 32u ||
|
||||
memory.data_dwords != 1u || memory.idxen || memory.offen || memory.offset != 0u ||
|
||||
inst.Arg(4).GetType() != Type::U1) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t arg = 1; arg <= 3; ++arg) {
|
||||
if (inst.Arg(arg).Resolve() != Value(0u)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsDescriptorHandle(ValueOpcode opcode) {
|
||||
@@ -89,6 +102,7 @@ bool IsRuntimeUniformOp(ValueOpcode op) {
|
||||
case ValueOpcode::ISub64:
|
||||
case ValueOpcode::IMul32:
|
||||
case ValueOpcode::IMul64:
|
||||
case ValueOpcode::UMulHi:
|
||||
case ValueOpcode::UMin32:
|
||||
case ValueOpcode::ShiftLeftLogical32:
|
||||
case ValueOpcode::ShiftLeftLogical64:
|
||||
@@ -105,6 +119,7 @@ bool IsRuntimeUniformOp(ValueOpcode op) {
|
||||
case ValueOpcode::SelectU32:
|
||||
case ValueOpcode::SelectF32:
|
||||
case ValueOpcode::ULessThan32:
|
||||
case ValueOpcode::ULessThanEqual32:
|
||||
case ValueOpcode::IEqual32:
|
||||
case ValueOpcode::UGreaterThan32:
|
||||
case ValueOpcode::SGreaterThanEqual32:
|
||||
@@ -117,6 +132,7 @@ bool IsRuntimeUniformOp(ValueOpcode op) {
|
||||
case ValueOpcode::FPOrdGreaterThanEqual32:
|
||||
case ValueOpcode::FPIsNan32:
|
||||
case ValueOpcode::FPMul32:
|
||||
case ValueOpcode::FPRecipIFlag32:
|
||||
case ValueOpcode::FPTrunc32: return true;
|
||||
default: return false;
|
||||
}
|
||||
@@ -157,6 +173,7 @@ private:
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
if (require_uniform && !m_active_mask.IsEmpty() && value == m_active_mask) return true;
|
||||
// Integer-only dependency checks do not depend on the active EXEC mask.
|
||||
if (!require_uniform && m_validated_dependencies.contains(inst)) return true;
|
||||
if (!m_visiting.insert(inst).second) {
|
||||
@@ -246,7 +263,8 @@ private:
|
||||
}
|
||||
return finish(true);
|
||||
}
|
||||
if (op == ValueOpcode::LoadAddressU32 || op == ValueOpcode::ReadConstBuffer) {
|
||||
if (op == ValueOpcode::LoadAddressU32 || op == ValueOpcode::ReadConstBuffer ||
|
||||
op == ValueOpcode::LoadBufferU32) {
|
||||
const auto expected = op == ValueOpcode::LoadAddressU32
|
||||
? ValueOpcode::GetAddressResource
|
||||
: ValueOpcode::GetBufferResource;
|
||||
@@ -255,6 +273,11 @@ private:
|
||||
handle->GetOpcode() != expected) {
|
||||
return finish(false);
|
||||
}
|
||||
if (op == ValueOpcode::LoadBufferU32) {
|
||||
const auto guard = inst->Arg(4).Resolve();
|
||||
return finish(Validate(inst->Arg(0)) &&
|
||||
((!m_active_mask.IsEmpty() && guard == m_active_mask) || Validate(guard)));
|
||||
}
|
||||
} else if (op == ValueOpcode::CompositeExtractU64) {
|
||||
const auto index = inst->NumArgs() == 2 ? inst->Arg(1).Resolve() : Value {};
|
||||
if (!index.IsImmediate() || index.GetType() != Type::U32 || index.U32() >= 2u) {
|
||||
@@ -341,6 +364,10 @@ bool SrtWalker::EvaluateWide(Value value, uint64_t& result) {
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
if (!m_active_mask.IsEmpty() && value == m_active_mask) {
|
||||
result = 1u;
|
||||
return true;
|
||||
}
|
||||
auto* inst = value.TryInstruction();
|
||||
if (inst == nullptr) {
|
||||
return false;
|
||||
@@ -430,6 +457,16 @@ bool SrtWalker::EvaluateRawRead(const Inst& inst, uint64_t& result) {
|
||||
return false;
|
||||
}
|
||||
const auto& mem = m_program.memory_info[flags.index];
|
||||
const bool vector = inst.GetOpcode() == ValueOpcode::LoadBufferU32;
|
||||
const auto guard = vector ? inst.Arg(4).Resolve() : Value {};
|
||||
if (vector && (guard.IsImmediate() || guard != m_active_mask)) {
|
||||
uint64_t enabled = 0;
|
||||
if (!Arg(inst, 4, enabled)) return false;
|
||||
if (enabled == 0u) {
|
||||
result = 0u;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto* handle = inst.Arg(0).ResolveInstruction();
|
||||
if (handle == nullptr) {
|
||||
return false;
|
||||
@@ -443,7 +480,7 @@ bool SrtWalker::EvaluateRawRead(const Inst& inst, uint64_t& result) {
|
||||
const auto base = (high << 32u) | static_cast<uint32_t>(low);
|
||||
const auto immediate = static_cast<int64_t>(static_cast<int32_t>(mem.offset));
|
||||
uint64_t address = 0;
|
||||
if (inst.GetOpcode() == ValueOpcode::ReadConstBuffer) {
|
||||
if (inst.GetOpcode() == ValueOpcode::ReadConstBuffer || vector) {
|
||||
uint64_t records = 0;
|
||||
uint64_t word3 = 0;
|
||||
if (handle->NumArgs() != 4u || !Arg(*handle, 2, records) || !Arg(*handle, 3, word3)) {
|
||||
@@ -455,6 +492,15 @@ bool SrtWalker::EvaluateRawRead(const Inst& inst, uint64_t& result) {
|
||||
const auto byte_offset =
|
||||
(static_cast<uint64_t>(immediate) & ~uint64_t {3}) + (static_cast<uint32_t>(offset) & ~3u);
|
||||
const auto stride = (static_cast<uint32_t>(high) >> 16u) & 0x3fffu;
|
||||
if (vector) {
|
||||
// Only the uniform, unswizzled structured DWORD address is evaluated on the host.
|
||||
if ((high & (1u << 31u)) != 0u || (word3 & ((1u << 23u) | 0xf0000000u)) != 0u)
|
||||
return false;
|
||||
if (stride == 0u || records == 0u || ((word3 >> 12u) & 0x7fu) == 0u) {
|
||||
result = 0u;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto size = stride == 0u
|
||||
? static_cast<uint64_t>(static_cast<uint32_t>(records))
|
||||
: static_cast<uint64_t>(stride) * static_cast<uint32_t>(records);
|
||||
@@ -470,11 +516,13 @@ bool SrtWalker::EvaluateRawRead(const Inst& inst, uint64_t& result) {
|
||||
}
|
||||
}
|
||||
uint32_t word = 0;
|
||||
if (m_runtime.read_memory != nullptr) {
|
||||
if (!m_runtime.read_memory(m_runtime.userdata, address, {&word, 1})) {
|
||||
const auto reader = vector ? m_runtime.read_specialization_memory : m_runtime.read_memory;
|
||||
if (reader != nullptr) {
|
||||
if (!reader(m_runtime.userdata, address, {&word, 1})) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (vector) return false;
|
||||
std::memcpy(&word, reinterpret_cast<const void*>(address), sizeof(word));
|
||||
}
|
||||
result = word;
|
||||
@@ -502,6 +550,9 @@ bool SrtWalker::EvaluateInst(const Inst& inst, uint64_t& result) {
|
||||
case ValueOpcode::GetShaderBase: result = m_runtime.shader_base; return true;
|
||||
case ValueOpcode::Phi: return EvaluatePhi(inst, result);
|
||||
case ValueOpcode::ReadFirstLane: {
|
||||
if (!m_active_mask.IsEmpty() && inst.Arg(1).Resolve() == m_active_mask) {
|
||||
return EvaluateWide(inst.Arg(0), result);
|
||||
}
|
||||
const auto clean_runtime = CleanRuntime(m_runtime);
|
||||
SrtWalker clean_active(m_program, clean_runtime, {}, nullptr, inst.Arg(1));
|
||||
SrtWalker active(m_program, m_runtime, m_clean_flat_slots, &clean_active,
|
||||
@@ -534,7 +585,12 @@ bool SrtWalker::EvaluateInst(const Inst& inst, uint64_t& result) {
|
||||
}
|
||||
case ValueOpcode::LoadAddressU32:
|
||||
case ValueOpcode::ReadConstBuffer:
|
||||
case ValueOpcode::LoadBufferU32:
|
||||
if (IsRawRead(m_program, inst)) {
|
||||
if (inst.GetOpcode() == ValueOpcode::LoadBufferU32 && m_clean_evaluator != nullptr &&
|
||||
m_clean_evaluator->m_active_mask == m_active_mask) {
|
||||
return m_clean_evaluator->EvaluateWide(Value(const_cast<Inst*>(&inst)), result);
|
||||
}
|
||||
return EvaluateRawRead(inst, result);
|
||||
}
|
||||
break;
|
||||
@@ -574,6 +630,12 @@ bool SrtWalker::EvaluateInst(const Inst& inst, uint64_t& result) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ValueOpcode::UMulHi:
|
||||
if (binary()) {
|
||||
result = (static_cast<uint64_t>(static_cast<uint32_t>(a)) * static_cast<uint32_t>(b)) >> 32u;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ValueOpcode::UMin32:
|
||||
if (binary()) {
|
||||
result = std::min(static_cast<uint32_t>(a), static_cast<uint32_t>(b));
|
||||
@@ -609,6 +671,15 @@ bool SrtWalker::EvaluateInst(const Inst& inst, uint64_t& result) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ValueOpcode::FPRecipIFlag32:
|
||||
if (Arg(inst, 0, a)) {
|
||||
const auto exponent = (a >> 23u) & 0xffu;
|
||||
// Normal positive powers of two have exact normal reciprocals in every FP mode.
|
||||
if ((a & 0x807fffffu) != 0u || exponent == 0u || exponent >= 254u) return false;
|
||||
result = (254u - exponent) << 23u;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ValueOpcode::FPIsNan32:
|
||||
if (Arg(inst, 0, a)) {
|
||||
result = std::isnan(Float32(a));
|
||||
@@ -779,6 +850,12 @@ bool SrtWalker::EvaluateInst(const Inst& inst, uint64_t& result) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ValueOpcode::ULessThanEqual32:
|
||||
if (binary()) {
|
||||
result = static_cast<uint32_t>(a) <= static_cast<uint32_t>(b);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case ValueOpcode::UGreaterThan32:
|
||||
if (binary()) {
|
||||
result = static_cast<uint32_t>(a) > static_cast<uint32_t>(b);
|
||||
|
||||
Reference in New Issue
Block a user