|
|
|
@ -417,14 +417,6 @@ void HLE_TransformFeedbackSetup::Execute(Core::System& system, Engines::Maxwell3 |
|
|
|
default: return std::monostate{}; |
|
|
|
} |
|
|
|
} |
|
|
|
[[nodiscard]] inline bool CanBeHLEProgram(u64 hash) noexcept { |
|
|
|
switch (hash) { |
|
|
|
#define HLE_MACRO_ELEM(HASH, TY, VAL) case HASH: return true;
|
|
|
|
HLE_MACRO_LIST |
|
|
|
#undef HLE_MACRO_ELEM
|
|
|
|
default: return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void MacroInterpreterImpl::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> params, u32 method) { |
|
|
|
Reset(); |
|
|
|
@ -1345,80 +1337,92 @@ static void Dump(u64 hash, std::span<const u32> code, bool decompiled = false) { |
|
|
|
macro_file.write(reinterpret_cast<const char*>(code.data()), code.size_bytes()); |
|
|
|
} |
|
|
|
|
|
|
|
void MacroEngine::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 method, std::span<const u32> parameters) { |
|
|
|
auto const execute_variant = [&system, &maxwell3d, ¶meters, method](AnyCachedMacro& acm) { |
|
|
|
if (auto a = std::get_if<HLE_DrawArraysIndirect>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_DrawIndexedIndirect>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_MultiDrawIndexedIndirectCount>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_MultiLayerClear>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_C713C83D8F63CCF3>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_D7333D26E0A93EDE>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_BindShader>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_SetRasterBoundingBox>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_ClearConstBuffer>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_ClearMemory>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_TransformFeedbackSetup>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<HLE_DrawIndirectByteCount>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<MacroInterpreterImpl>(&acm)) |
|
|
|
return a->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto a = std::get_if<std::unique_ptr<DynamicCachedMacro>>(&acm)) |
|
|
|
return a->get()->Execute(system, maxwell3d, parameters, method); |
|
|
|
void MacroEngine::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 method, |
|
|
|
std::span<const u32> parameters) { |
|
|
|
const auto execute_variant = [&system, &maxwell3d, ¶meters, |
|
|
|
method](AnyCachedMacro& cached) { |
|
|
|
if (std::holds_alternative<MacroInterpreterImpl>(cached) || |
|
|
|
std::holds_alternative<std::unique_ptr<DynamicCachedMacro>>(cached) || |
|
|
|
Settings::values.disable_macro_hle) { |
|
|
|
maxwell3d.RefreshParameters(); |
|
|
|
} |
|
|
|
|
|
|
|
if (auto program = std::get_if<HLE_DrawArraysIndirect>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_DrawIndexedIndirect>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_MultiDrawIndexedIndirectCount>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_MultiLayerClear>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_C713C83D8F63CCF3>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_D7333D26E0A93EDE>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_BindShader>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_SetRasterBoundingBox>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_ClearConstBuffer>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_ClearMemory>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_TransformFeedbackSetup>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<HLE_DrawIndirectByteCount>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<MacroInterpreterImpl>(&cached)) |
|
|
|
return program->Execute(system, maxwell3d, parameters, method); |
|
|
|
if (auto program = std::get_if<std::unique_ptr<DynamicCachedMacro>>(&cached)) |
|
|
|
return program->get()->Execute(system, maxwell3d, parameters, method); |
|
|
|
|
|
|
|
UNREACHABLE(); |
|
|
|
}; |
|
|
|
if (auto const it = macro_cache.find(method); it != macro_cache.end()) { |
|
|
|
auto& ci = it->second; |
|
|
|
if (!CanBeHLEProgram(ci.hash) || Settings::values.disable_macro_hle) |
|
|
|
maxwell3d.RefreshParameters(); //LLE must reload parameters
|
|
|
|
execute_variant(ci.program); |
|
|
|
} else { |
|
|
|
// Macro not compiled, check if it's uploaded and if so, compile it
|
|
|
|
execute_variant(it->second.program); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Macro not compiled, check if it's uploaded and if so, compile it
|
|
|
|
std::span<const u32> code; |
|
|
|
auto macro_code = uploaded_macro_code.find(method); |
|
|
|
if (macro_code == uploaded_macro_code.end()) { |
|
|
|
std::optional<u32> mid_method; |
|
|
|
const auto macro_code = uploaded_macro_code.find(method); |
|
|
|
if (macro_code == uploaded_macro_code.end()) { |
|
|
|
for (const auto& [method_base, code] : uploaded_macro_code) { |
|
|
|
if (method >= method_base && (method - method_base) < code.size()) { |
|
|
|
mid_method = method_base; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!mid_method.has_value()) { |
|
|
|
ASSERT_MSG(false, "Macro 0x{0:x} was not uploaded", method); |
|
|
|
return; |
|
|
|
for (const auto& [method_base, uploaded_code] : uploaded_macro_code) { |
|
|
|
if (method >= method_base && (method - method_base) < uploaded_code.size()) { |
|
|
|
mid_method = method_base; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
auto& ci = macro_cache[method]; |
|
|
|
if (mid_method) { |
|
|
|
const auto& macro_cached = uploaded_macro_code[mid_method.value()]; |
|
|
|
const auto rebased_method = method - mid_method.value(); |
|
|
|
auto& code = uploaded_macro_code[method]; |
|
|
|
code.resize(macro_cached.size() - rebased_method); |
|
|
|
std::memcpy(code.data(), macro_cached.data() + rebased_method, code.size() * sizeof(u32)); |
|
|
|
ci.hash = Common::HashValue(code); |
|
|
|
ci.program = Compile(system, maxwell3d, code); |
|
|
|
} else { |
|
|
|
ci.program = Compile(system, maxwell3d, macro_code->second); |
|
|
|
ci.hash = Common::HashValue(macro_code->second); |
|
|
|
} |
|
|
|
if (CanBeHLEProgram(ci.hash) && !Settings::values.disable_macro_hle) { |
|
|
|
ci.program = GetHLEProgram(ci.hash); |
|
|
|
} else { |
|
|
|
maxwell3d.RefreshParameters(); |
|
|
|
} |
|
|
|
execute_variant(ci.program); |
|
|
|
if (Settings::values.dump_macros) { |
|
|
|
Dump(ci.hash, macro_code->second, !std::holds_alternative<std::monostate>(ci.program)); |
|
|
|
if (!mid_method) { |
|
|
|
ASSERT_MSG(false, "Macro 0x{0:x} was not uploaded", method); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const auto source = uploaded_macro_code.find(*mid_method); |
|
|
|
ASSERT(source != uploaded_macro_code.end()); |
|
|
|
const auto rebased_method = method - *mid_method; |
|
|
|
std::vector<u32> rebased_code(source->second.begin() + rebased_method, |
|
|
|
source->second.end()); |
|
|
|
const auto [it, inserted] = uploaded_macro_code.emplace(method, std::move(rebased_code)); |
|
|
|
ASSERT(inserted); |
|
|
|
code = it->second; |
|
|
|
} else { |
|
|
|
code = macro_code->second; |
|
|
|
} |
|
|
|
|
|
|
|
auto& ci = macro_cache[method]; |
|
|
|
ci.hash = Common::HashRange(code.begin(), code.end()); |
|
|
|
if (!Settings::values.disable_macro_hle) { |
|
|
|
ci.program = GetHLEProgram(ci.hash); |
|
|
|
} |
|
|
|
if (std::holds_alternative<std::monostate>(ci.program)) { |
|
|
|
ci.program = Compile(system, maxwell3d, code); |
|
|
|
} |
|
|
|
|
|
|
|
execute_variant(ci.program); |
|
|
|
if (Settings::values.dump_macros) { |
|
|
|
Dump(ci.hash, code, !std::holds_alternative<std::monostate>(ci.program)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|