mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-18 09:21:34 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b7570b24d |
@@ -1,8 +1,12 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <queue>
|
||||
@@ -13,9 +17,10 @@
|
||||
|
||||
namespace Shader::IR {
|
||||
|
||||
template <typename Pred>
|
||||
auto BreadthFirstSearch(const Value& value, Pred&& pred)
|
||||
template <typename Pred, typename Resolve = std::identity>
|
||||
auto BreadthFirstSearch(Value value, Pred&& pred, Resolve&& resolve = {})
|
||||
-> std::invoke_result_t<Pred, const Inst*> {
|
||||
value = resolve(value);
|
||||
if (value.IsImmediate()) {
|
||||
// Nothing to do with immediates
|
||||
return std::nullopt;
|
||||
@@ -36,7 +41,7 @@ auto BreadthFirstSearch(const Value& value, Pred&& pred)
|
||||
}
|
||||
// Visit the right most arguments first
|
||||
for (size_t arg = inst->NumArgs(); arg--;) {
|
||||
const Value arg_value{inst->Arg(arg)};
|
||||
const Value arg_value{resolve(inst->Arg(arg))};
|
||||
if (arg_value.IsImmediate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,60 @@ struct TextureInst {
|
||||
|
||||
using TextureInstVector = boost::container::small_vector<TextureInst, 24>;
|
||||
|
||||
const IR::Block* ConditionalHeader(const IR::Block* body) {
|
||||
const auto predecessors{body->ImmPredecessors()};
|
||||
const auto successors{body->ImmSuccessors()};
|
||||
if (predecessors.size() != 1 || successors.size() != 1) return nullptr;
|
||||
const IR::Block* const header{predecessors[0]};
|
||||
const auto targets{header->ImmSuccessors()};
|
||||
if (targets.size() != 2 || targets[0] != body || targets[1] != successors[0] ||
|
||||
targets[1]->ImmPredecessors().size() != 2 || header->empty() ||
|
||||
header->back().GetOpcode() != IR::Opcode::ConditionRef) {
|
||||
return nullptr;
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
std::pair<IR::Value, bool> Condition(IR::Value value) {
|
||||
bool negated{};
|
||||
while (const IR::Inst* inst = value.TryInstRecursive()) {
|
||||
if (inst->GetOpcode() == IR::Opcode::LogicalNot) negated = !negated;
|
||||
else if (inst->GetOpcode() != IR::Opcode::ConditionRef) break;
|
||||
value = inst->Arg(0);
|
||||
}
|
||||
return {value.Resolve(), negated};
|
||||
}
|
||||
|
||||
IR::Value ResolveConditionalPhi(IR::Value value, const IR::Block* block) {
|
||||
if (!value.Resolve().IsPhi() || !(block = ConditionalHeader(block))) return value;
|
||||
const auto [condition, negated]{Condition(block->back().Arg(0))};
|
||||
boost::container::small_vector<const IR::Block*, 16> visited;
|
||||
while (value.Resolve().IsPhi() && std::ranges::find(visited, block) == visited.end()) {
|
||||
visited.push_back(block);
|
||||
const IR::Inst* const phi{value.InstRecursive()};
|
||||
const auto predecessors{block->ImmPredecessors()};
|
||||
if (predecessors.size() == 1) {
|
||||
block = predecessors[0];
|
||||
continue;
|
||||
}
|
||||
if (predecessors.size() != 2 || phi->NumArgs() != 2) break;
|
||||
const IR::Block* body{predecessors[0]};
|
||||
const IR::Block* header{ConditionalHeader(body)};
|
||||
if (header != predecessors[1]) {
|
||||
body = predecessors[1];
|
||||
header = ConditionalHeader(body);
|
||||
if (header != predecessors[0]) break;
|
||||
}
|
||||
const auto [other_condition, other_negated]{Condition(header->back().Arg(0))};
|
||||
if (condition == other_condition && (phi->PhiBlock(0) == header || phi->PhiBlock(0) == body)) {
|
||||
const IR::Block* const incoming{negated == other_negated ? body : header};
|
||||
value = phi->Arg(phi->PhiBlock(0) == incoming ? 0 : 1);
|
||||
}
|
||||
block = header;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr u32 DESCRIPTOR_SIZE = 8;
|
||||
constexpr u32 DESCRIPTOR_SIZE_SHIFT = u32(std::countr_zero(DESCRIPTOR_SIZE));
|
||||
constexpr u32 DESCRIPTOR_MAX_COUNT = 1024;
|
||||
@@ -299,23 +353,23 @@ static inline bool IsTexturePixelFormatIntegerCached(Environment& env,
|
||||
}
|
||||
|
||||
|
||||
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info);
|
||||
static inline std::optional<ConstBufferAddr> TrackCached(const IR::Value& v, Environment& env, const HostTranslateInfo& host_info) {
|
||||
if (const IR::Inst* key = v.InstRecursive()) {
|
||||
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block);
|
||||
static inline std::optional<ConstBufferAddr> TrackCached(const IR::Value& v, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block) {
|
||||
if (const IR::Inst* key = v.TryInstRecursive()) {
|
||||
if (auto it = env.track_cache.find(key); it != env.track_cache.end()) return it->second;
|
||||
auto found = Track(v, env, host_info);
|
||||
auto found = Track(v, env, host_info, block);
|
||||
if (found) env.track_cache.emplace(key, *found);
|
||||
return found;
|
||||
}
|
||||
return Track(v, env, host_info);
|
||||
return Track(v, env, host_info, block);
|
||||
}
|
||||
|
||||
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info);
|
||||
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block);
|
||||
|
||||
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info) {
|
||||
return IR::BreadthFirstSearch(value, [&env, &host_info](const IR::Inst* inst) {
|
||||
return TryGetConstBuffer(inst, env, host_info);
|
||||
});
|
||||
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block) {
|
||||
return IR::BreadthFirstSearch(value, [&env, &host_info, block](const IR::Inst* inst) {
|
||||
return TryGetConstBuffer(inst, env, host_info, block);
|
||||
}, [&](IR::Value operand) { return ResolveConditionalPhi(operand, block); });
|
||||
}
|
||||
|
||||
std::optional<u32> TryGetConstant(IR::Value& value, Environment& env) {
|
||||
@@ -339,13 +393,13 @@ std::optional<u32> TryGetConstant(IR::Value& value, Environment& env) {
|
||||
return ReadCbufCached(env, index_number, offset_number);
|
||||
}
|
||||
|
||||
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info) {
|
||||
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env, const HostTranslateInfo& host_info, const IR::Block* block) {
|
||||
switch (inst->GetOpcode()) {
|
||||
default:
|
||||
return std::nullopt;
|
||||
case IR::Opcode::BitwiseOr32: {
|
||||
std::optional lhs{TrackCached(inst->Arg(0), env, host_info)};
|
||||
std::optional rhs{TrackCached(inst->Arg(1), env, host_info)};
|
||||
std::optional lhs{TrackCached(inst->Arg(0), env, host_info, block)};
|
||||
std::optional rhs{TrackCached(inst->Arg(1), env, host_info, block)};
|
||||
if (!lhs || !rhs) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -375,7 +429,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
||||
if (!shift.IsImmediate()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::optional lhs{TrackCached(inst->Arg(0), env, host_info)};
|
||||
std::optional lhs{TrackCached(inst->Arg(0), env, host_info, block)};
|
||||
if (lhs) {
|
||||
lhs->shift_left = shift.U32();
|
||||
}
|
||||
@@ -403,7 +457,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
||||
return std::nullopt;
|
||||
} while (false);
|
||||
}
|
||||
std::optional lhs{TrackCached(op1, env, host_info)};
|
||||
std::optional lhs{TrackCached(op1, env, host_info, block)};
|
||||
if (lhs) {
|
||||
lhs->shift_left = static_cast<u32>(std::countr_zero(op2.U32()));
|
||||
}
|
||||
@@ -469,7 +523,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
|
||||
TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst, const HostTranslateInfo& host_info) {
|
||||
ConstBufferAddr addr;
|
||||
if (IsBindless(inst)) {
|
||||
const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env, host_info)};
|
||||
const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env, host_info, block)};
|
||||
|
||||
if (!track_addr) {
|
||||
throw NotImplementedException("Failed to track bindless texture constant buffer");
|
||||
@@ -671,6 +725,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
||||
env.track_cache.clear();
|
||||
TextureInstVector to_replace;
|
||||
for (IR::Block* const block : program.post_order_blocks) {
|
||||
env.track_cache.clear();
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
if (!IsTextureInstruction(inst)) {
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user