macro.cpp 3.3 KB

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