macro.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cstring>
  5. #include <optional>
  6. #include <boost/container_hash/hash.hpp>
  7. #include "common/assert.h"
  8. #include "common/settings.h"
  9. #include "video_core/macro/macro.h"
  10. #include "video_core/macro/macro_hle.h"
  11. #include "video_core/macro/macro_interpreter.h"
  12. #include "video_core/macro/macro_jit_x64.h"
  13. namespace Tegra {
  14. MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d)
  15. : hle_macros{std::make_unique<Tegra::HLEMacro>(maxwell3d)} {}
  16. MacroEngine::~MacroEngine() = default;
  17. void MacroEngine::AddCode(u32 method, u32 data) {
  18. uploaded_macro_code[method].push_back(data);
  19. }
  20. void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
  21. auto compiled_macro = macro_cache.find(method);
  22. if (compiled_macro != macro_cache.end()) {
  23. const auto& cache_info = compiled_macro->second;
  24. if (cache_info.has_hle_program) {
  25. cache_info.hle_program->Execute(parameters, method);
  26. } else {
  27. cache_info.lle_program->Execute(parameters, method);
  28. }
  29. } else {
  30. // Macro not compiled, check if it's uploaded and if so, compile it
  31. std::optional<u32> mid_method;
  32. const auto macro_code = uploaded_macro_code.find(method);
  33. if (macro_code == uploaded_macro_code.end()) {
  34. for (const auto& [method_base, code] : uploaded_macro_code) {
  35. if (method >= method_base && (method - method_base) < code.size()) {
  36. mid_method = method_base;
  37. break;
  38. }
  39. }
  40. if (!mid_method.has_value()) {
  41. UNREACHABLE_MSG("Macro 0x{0:x} was not uploaded", method);
  42. return;
  43. }
  44. }
  45. auto& cache_info = macro_cache[method];
  46. if (!mid_method.has_value()) {
  47. cache_info.lle_program = Compile(macro_code->second);
  48. cache_info.hash = boost::hash_value(macro_code->second);
  49. } else {
  50. const auto& macro_cached = uploaded_macro_code[mid_method.value()];
  51. const auto rebased_method = method - mid_method.value();
  52. auto& code = uploaded_macro_code[method];
  53. code.resize(macro_cached.size() - rebased_method);
  54. std::memcpy(code.data(), macro_cached.data() + rebased_method,
  55. code.size() * sizeof(u32));
  56. cache_info.hash = boost::hash_value(code);
  57. cache_info.lle_program = Compile(code);
  58. }
  59. if (auto hle_program = hle_macros->GetHLEProgram(cache_info.hash)) {
  60. cache_info.has_hle_program = true;
  61. cache_info.hle_program = std::move(hle_program);
  62. cache_info.hle_program->Execute(parameters, method);
  63. } else {
  64. cache_info.lle_program->Execute(parameters, method);
  65. }
  66. }
  67. }
  68. std::unique_ptr<MacroEngine> GetMacroEngine(Engines::Maxwell3D& maxwell3d) {
  69. if (Settings::values.disable_macro_jit) {
  70. return std::make_unique<MacroInterpreter>(maxwell3d);
  71. }
  72. #ifdef ARCHITECTURE_x86_64
  73. return std::make_unique<MacroJITx64>(maxwell3d);
  74. #else
  75. return std::make_unique<MacroInterpreter>(maxwell3d);
  76. #endif
  77. }
  78. } // namespace Tegra