macro_hle.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <array>
  4. #include <vector>
  5. #include "common/scope_exit.h"
  6. #include "video_core/dirty_flags.h"
  7. #include "video_core/engines/maxwell_3d.h"
  8. #include "video_core/macro/macro.h"
  9. #include "video_core/macro/macro_hle.h"
  10. #include "video_core/rasterizer_interface.h"
  11. namespace Tegra {
  12. namespace {
  13. using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters);
  14. // HLE'd functions
  15. void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
  16. const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B);
  17. maxwell3d.regs.draw.topology.Assign(
  18. static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0x3ffffff));
  19. maxwell3d.regs.global_base_instance_index = parameters[5];
  20. maxwell3d.regs.global_base_vertex_index = parameters[3];
  21. maxwell3d.regs.index_buffer.count = parameters[1];
  22. maxwell3d.regs.index_buffer.first = parameters[4];
  23. if (maxwell3d.ShouldExecute()) {
  24. maxwell3d.Rasterizer().Draw(true, instance_count);
  25. }
  26. maxwell3d.regs.index_buffer.count = 0;
  27. }
  28. void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
  29. const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
  30. maxwell3d.regs.vertex_buffer.first = parameters[3];
  31. maxwell3d.regs.vertex_buffer.count = parameters[1];
  32. maxwell3d.regs.global_base_instance_index = parameters[4];
  33. maxwell3d.regs.draw.topology.Assign(
  34. static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
  35. if (maxwell3d.ShouldExecute()) {
  36. maxwell3d.Rasterizer().Draw(false, instance_count);
  37. }
  38. maxwell3d.regs.vertex_buffer.count = 0;
  39. }
  40. void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
  41. const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
  42. const u32 element_base = parameters[4];
  43. const u32 base_instance = parameters[5];
  44. maxwell3d.regs.index_buffer.first = parameters[3];
  45. maxwell3d.regs.vertex_id_base = element_base;
  46. maxwell3d.regs.index_buffer.count = parameters[1];
  47. maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
  48. maxwell3d.regs.global_base_vertex_index = element_base;
  49. maxwell3d.regs.global_base_instance_index = base_instance;
  50. maxwell3d.CallMethod(0x8e3, 0x640, true);
  51. maxwell3d.CallMethod(0x8e4, element_base, true);
  52. maxwell3d.CallMethod(0x8e5, base_instance, true);
  53. maxwell3d.regs.draw.topology.Assign(
  54. static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
  55. if (maxwell3d.ShouldExecute()) {
  56. maxwell3d.Rasterizer().Draw(true, instance_count);
  57. }
  58. maxwell3d.regs.vertex_id_base = 0x0;
  59. maxwell3d.regs.index_buffer.count = 0;
  60. maxwell3d.regs.global_base_vertex_index = 0x0;
  61. maxwell3d.regs.global_base_instance_index = 0x0;
  62. maxwell3d.CallMethod(0x8e3, 0x640, true);
  63. maxwell3d.CallMethod(0x8e4, 0x0, true);
  64. maxwell3d.CallMethod(0x8e5, 0x0, true);
  65. }
  66. // Multidraw Indirect
  67. void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) {
  68. SCOPE_EXIT({
  69. // Clean everything.
  70. maxwell3d.regs.vertex_id_base = 0x0;
  71. maxwell3d.regs.index_buffer.count = 0;
  72. maxwell3d.regs.global_base_vertex_index = 0x0;
  73. maxwell3d.regs.global_base_instance_index = 0x0;
  74. maxwell3d.CallMethod(0x8e3, 0x640, true);
  75. maxwell3d.CallMethod(0x8e4, 0x0, true);
  76. maxwell3d.CallMethod(0x8e5, 0x0, true);
  77. maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
  78. });
  79. const u32 start_indirect = parameters[0];
  80. const u32 end_indirect = parameters[1];
  81. if (start_indirect >= end_indirect) {
  82. // Nothing to do.
  83. return;
  84. }
  85. const auto topology =
  86. static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[2]);
  87. maxwell3d.regs.draw.topology.Assign(topology);
  88. const u32 padding = parameters[3];
  89. const std::size_t max_draws = parameters[4];
  90. const u32 indirect_words = 5 + padding;
  91. const std::size_t first_draw = start_indirect;
  92. const std::size_t effective_draws = end_indirect - start_indirect;
  93. const std::size_t last_draw = start_indirect + std::min(effective_draws, max_draws);
  94. for (std::size_t index = first_draw; index < last_draw; index++) {
  95. const std::size_t base = index * indirect_words + 5;
  96. const u32 num_vertices = parameters[base];
  97. const u32 instance_count = parameters[base + 1];
  98. const u32 first_index = parameters[base + 2];
  99. const u32 base_vertex = parameters[base + 3];
  100. const u32 base_instance = parameters[base + 4];
  101. maxwell3d.regs.index_buffer.first = first_index;
  102. maxwell3d.regs.vertex_id_base = base_vertex;
  103. maxwell3d.regs.index_buffer.count = num_vertices;
  104. maxwell3d.regs.global_base_vertex_index = base_vertex;
  105. maxwell3d.regs.global_base_instance_index = base_instance;
  106. maxwell3d.CallMethod(0x8e3, 0x640, true);
  107. maxwell3d.CallMethod(0x8e4, base_vertex, true);
  108. maxwell3d.CallMethod(0x8e5, base_instance, true);
  109. maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true;
  110. if (maxwell3d.ShouldExecute()) {
  111. maxwell3d.Rasterizer().Draw(true, instance_count);
  112. }
  113. }
  114. }
  115. constexpr std::array<std::pair<u64, HLEFunction>, 4> hle_funcs{{
  116. {0x771BB18C62444DA0, &HLE_771BB18C62444DA0},
  117. {0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD},
  118. {0x0217920100488FF7, &HLE_0217920100488FF7},
  119. {0x3F5E74B9C9A50164, &HLE_3F5E74B9C9A50164},
  120. }};
  121. class HLEMacroImpl final : public CachedMacro {
  122. public:
  123. explicit HLEMacroImpl(Engines::Maxwell3D& maxwell3d_, HLEFunction func_)
  124. : maxwell3d{maxwell3d_}, func{func_} {}
  125. void Execute(const std::vector<u32>& parameters, u32 method) override {
  126. func(maxwell3d, parameters);
  127. }
  128. private:
  129. Engines::Maxwell3D& maxwell3d;
  130. HLEFunction func;
  131. };
  132. } // Anonymous namespace
  133. HLEMacro::HLEMacro(Engines::Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} {}
  134. HLEMacro::~HLEMacro() = default;
  135. std::unique_ptr<CachedMacro> HLEMacro::GetHLEProgram(u64 hash) const {
  136. const auto it = std::find_if(hle_funcs.cbegin(), hle_funcs.cend(),
  137. [hash](const auto& pair) { return pair.first == hash; });
  138. if (it == hle_funcs.end()) {
  139. return nullptr;
  140. }
  141. return std::make_unique<HLEMacroImpl>(maxwell3d, it->second);
  142. }
  143. } // namespace Tegra