gpu.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/assert.h"
  5. #include "common/microprofile.h"
  6. #include "core/core.h"
  7. #include "core/core_timing.h"
  8. #include "core/core_timing_util.h"
  9. #include "core/frontend/emu_window.h"
  10. #include "core/memory.h"
  11. #include "video_core/engines/fermi_2d.h"
  12. #include "video_core/engines/kepler_compute.h"
  13. #include "video_core/engines/kepler_memory.h"
  14. #include "video_core/engines/maxwell_3d.h"
  15. #include "video_core/engines/maxwell_dma.h"
  16. #include "video_core/gpu.h"
  17. #include "video_core/memory_manager.h"
  18. #include "video_core/renderer_base.h"
  19. #include "video_core/video_core.h"
  20. namespace Tegra {
  21. MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
  22. GPU::GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, bool is_async)
  23. : system{system}, renderer{std::move(renderer_)}, is_async{is_async} {
  24. auto& rasterizer{renderer->Rasterizer()};
  25. memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer);
  26. dma_pusher = std::make_unique<Tegra::DmaPusher>(system, *this);
  27. maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
  28. fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer);
  29. kepler_compute = std::make_unique<Engines::KeplerCompute>(system, rasterizer, *memory_manager);
  30. maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, *memory_manager);
  31. kepler_memory = std::make_unique<Engines::KeplerMemory>(system, *memory_manager);
  32. }
  33. GPU::~GPU() = default;
  34. Engines::Maxwell3D& GPU::Maxwell3D() {
  35. return *maxwell_3d;
  36. }
  37. const Engines::Maxwell3D& GPU::Maxwell3D() const {
  38. return *maxwell_3d;
  39. }
  40. Engines::KeplerCompute& GPU::KeplerCompute() {
  41. return *kepler_compute;
  42. }
  43. const Engines::KeplerCompute& GPU::KeplerCompute() const {
  44. return *kepler_compute;
  45. }
  46. MemoryManager& GPU::MemoryManager() {
  47. return *memory_manager;
  48. }
  49. const MemoryManager& GPU::MemoryManager() const {
  50. return *memory_manager;
  51. }
  52. DmaPusher& GPU::DmaPusher() {
  53. return *dma_pusher;
  54. }
  55. const DmaPusher& GPU::DmaPusher() const {
  56. return *dma_pusher;
  57. }
  58. void GPU::WaitFence(u32 syncpoint_id, u32 value) {
  59. // Synced GPU, is always in sync
  60. if (!is_async) {
  61. return;
  62. }
  63. MICROPROFILE_SCOPE(GPU_wait);
  64. std::unique_lock lock{sync_mutex};
  65. sync_cv.wait(lock, [=]() { return syncpoints[syncpoint_id].load() >= value; });
  66. }
  67. void GPU::IncrementSyncPoint(const u32 syncpoint_id) {
  68. syncpoints[syncpoint_id]++;
  69. std::lock_guard lock{sync_mutex};
  70. sync_cv.notify_all();
  71. if (!syncpt_interrupts[syncpoint_id].empty()) {
  72. u32 value = syncpoints[syncpoint_id].load();
  73. auto it = syncpt_interrupts[syncpoint_id].begin();
  74. while (it != syncpt_interrupts[syncpoint_id].end()) {
  75. if (value >= *it) {
  76. TriggerCpuInterrupt(syncpoint_id, *it);
  77. it = syncpt_interrupts[syncpoint_id].erase(it);
  78. continue;
  79. }
  80. it++;
  81. }
  82. }
  83. }
  84. u32 GPU::GetSyncpointValue(const u32 syncpoint_id) const {
  85. return syncpoints[syncpoint_id].load();
  86. }
  87. void GPU::RegisterSyncptInterrupt(const u32 syncpoint_id, const u32 value) {
  88. auto& interrupt = syncpt_interrupts[syncpoint_id];
  89. bool contains = std::any_of(interrupt.begin(), interrupt.end(),
  90. [value](u32 in_value) { return in_value == value; });
  91. if (contains) {
  92. return;
  93. }
  94. syncpt_interrupts[syncpoint_id].emplace_back(value);
  95. }
  96. bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) {
  97. std::lock_guard lock{sync_mutex};
  98. auto& interrupt = syncpt_interrupts[syncpoint_id];
  99. const auto iter =
  100. std::find_if(interrupt.begin(), interrupt.end(),
  101. [value](u32 interrupt_value) { return value == interrupt_value; });
  102. if (iter == interrupt.end()) {
  103. return false;
  104. }
  105. interrupt.erase(iter);
  106. return true;
  107. }
  108. u64 GPU::RequestFlush(VAddr addr, std::size_t size) {
  109. std::unique_lock lck{flush_request_mutex};
  110. const u64 fence = ++last_flush_fence;
  111. flush_requests.emplace_back(fence, addr, size);
  112. return fence;
  113. }
  114. void GPU::TickWork() {
  115. std::unique_lock lck{flush_request_mutex};
  116. while (!flush_requests.empty()) {
  117. auto& request = flush_requests.front();
  118. const u64 fence = request.fence;
  119. const VAddr addr = request.addr;
  120. const std::size_t size = request.size;
  121. flush_requests.pop_front();
  122. flush_request_mutex.unlock();
  123. renderer->Rasterizer().FlushRegion(addr, size);
  124. current_flush_fence.store(fence);
  125. flush_request_mutex.lock();
  126. }
  127. }
  128. u64 GPU::GetTicks() const {
  129. // This values were reversed engineered by fincs from NVN
  130. // The gpu clock is reported in units of 385/625 nanoseconds
  131. constexpr u64 gpu_ticks_num = 384;
  132. constexpr u64 gpu_ticks_den = 625;
  133. const u64 cpu_ticks = system.CoreTiming().GetTicks();
  134. const u64 nanoseconds = Core::Timing::CyclesToNs(cpu_ticks).count();
  135. const u64 nanoseconds_num = nanoseconds / gpu_ticks_den;
  136. const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den;
  137. return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
  138. }
  139. void GPU::FlushCommands() {
  140. renderer->Rasterizer().FlushCommands();
  141. }
  142. void GPU::SyncGuestHost() {
  143. renderer->Rasterizer().SyncGuestHost();
  144. }
  145. void GPU::OnCommandListEnd() {
  146. renderer->Rasterizer().ReleaseFences();
  147. }
  148. // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence
  149. // their numbers are written down multiplied by 4 in Docs. Here we are not multiply by 4.
  150. // So the values you see in docs might be multiplied by 4.
  151. enum class BufferMethods {
  152. BindObject = 0x0,
  153. Nop = 0x2,
  154. SemaphoreAddressHigh = 0x4,
  155. SemaphoreAddressLow = 0x5,
  156. SemaphoreSequence = 0x6,
  157. SemaphoreTrigger = 0x7,
  158. NotifyIntr = 0x8,
  159. WrcacheFlush = 0x9,
  160. Unk28 = 0xA,
  161. UnkCacheFlush = 0xB,
  162. RefCnt = 0x14,
  163. SemaphoreAcquire = 0x1A,
  164. SemaphoreRelease = 0x1B,
  165. FenceValue = 0x1C,
  166. FenceAction = 0x1D,
  167. Unk78 = 0x1E,
  168. Unk7c = 0x1F,
  169. Yield = 0x20,
  170. NonPullerMethods = 0x40,
  171. };
  172. enum class GpuSemaphoreOperation {
  173. AcquireEqual = 0x1,
  174. WriteLong = 0x2,
  175. AcquireGequal = 0x4,
  176. AcquireMask = 0x8,
  177. };
  178. void GPU::CallMethod(const MethodCall& method_call) {
  179. LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method,
  180. method_call.subchannel);
  181. ASSERT(method_call.subchannel < bound_engines.size());
  182. if (ExecuteMethodOnEngine(method_call)) {
  183. CallEngineMethod(method_call);
  184. } else {
  185. CallPullerMethod(method_call);
  186. }
  187. }
  188. bool GPU::ExecuteMethodOnEngine(const MethodCall& method_call) {
  189. const auto method = static_cast<BufferMethods>(method_call.method);
  190. return method >= BufferMethods::NonPullerMethods;
  191. }
  192. void GPU::CallPullerMethod(const MethodCall& method_call) {
  193. regs.reg_array[method_call.method] = method_call.argument;
  194. const auto method = static_cast<BufferMethods>(method_call.method);
  195. switch (method) {
  196. case BufferMethods::BindObject: {
  197. ProcessBindMethod(method_call);
  198. break;
  199. }
  200. case BufferMethods::Nop:
  201. case BufferMethods::SemaphoreAddressHigh:
  202. case BufferMethods::SemaphoreAddressLow:
  203. case BufferMethods::SemaphoreSequence:
  204. case BufferMethods::RefCnt:
  205. case BufferMethods::UnkCacheFlush:
  206. case BufferMethods::WrcacheFlush:
  207. case BufferMethods::FenceValue:
  208. case BufferMethods::FenceAction:
  209. break;
  210. case BufferMethods::SemaphoreTrigger: {
  211. ProcessSemaphoreTriggerMethod();
  212. break;
  213. }
  214. case BufferMethods::NotifyIntr: {
  215. // TODO(Kmather73): Research and implement this method.
  216. LOG_ERROR(HW_GPU, "Special puller engine method NotifyIntr not implemented");
  217. break;
  218. }
  219. case BufferMethods::Unk28: {
  220. // TODO(Kmather73): Research and implement this method.
  221. LOG_ERROR(HW_GPU, "Special puller engine method Unk28 not implemented");
  222. break;
  223. }
  224. case BufferMethods::SemaphoreAcquire: {
  225. ProcessSemaphoreAcquire();
  226. break;
  227. }
  228. case BufferMethods::SemaphoreRelease: {
  229. ProcessSemaphoreRelease();
  230. break;
  231. }
  232. case BufferMethods::Yield: {
  233. // TODO(Kmather73): Research and implement this method.
  234. LOG_ERROR(HW_GPU, "Special puller engine method Yield not implemented");
  235. break;
  236. }
  237. default:
  238. LOG_ERROR(HW_GPU, "Special puller engine method {:X} not implemented",
  239. static_cast<u32>(method));
  240. break;
  241. }
  242. }
  243. void GPU::CallEngineMethod(const MethodCall& method_call) {
  244. const EngineID engine = bound_engines[method_call.subchannel];
  245. switch (engine) {
  246. case EngineID::FERMI_TWOD_A:
  247. fermi_2d->CallMethod(method_call);
  248. break;
  249. case EngineID::MAXWELL_B:
  250. maxwell_3d->CallMethod(method_call);
  251. break;
  252. case EngineID::KEPLER_COMPUTE_B:
  253. kepler_compute->CallMethod(method_call);
  254. break;
  255. case EngineID::MAXWELL_DMA_COPY_A:
  256. maxwell_dma->CallMethod(method_call);
  257. break;
  258. case EngineID::KEPLER_INLINE_TO_MEMORY_B:
  259. kepler_memory->CallMethod(method_call);
  260. break;
  261. default:
  262. UNIMPLEMENTED_MSG("Unimplemented engine");
  263. }
  264. }
  265. void GPU::ProcessBindMethod(const MethodCall& method_call) {
  266. // Bind the current subchannel to the desired engine id.
  267. LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel,
  268. method_call.argument);
  269. bound_engines[method_call.subchannel] = static_cast<EngineID>(method_call.argument);
  270. }
  271. void GPU::ProcessSemaphoreTriggerMethod() {
  272. const auto semaphoreOperationMask = 0xF;
  273. const auto op =
  274. static_cast<GpuSemaphoreOperation>(regs.semaphore_trigger & semaphoreOperationMask);
  275. if (op == GpuSemaphoreOperation::WriteLong) {
  276. struct Block {
  277. u32 sequence;
  278. u32 zeros = 0;
  279. u64 timestamp;
  280. };
  281. Block block{};
  282. block.sequence = regs.semaphore_sequence;
  283. // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of
  284. // CoreTiming
  285. block.timestamp = GetTicks();
  286. memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block,
  287. sizeof(block));
  288. } else {
  289. const u32 word{memory_manager->Read<u32>(regs.semaphore_address.SemaphoreAddress())};
  290. if ((op == GpuSemaphoreOperation::AcquireEqual && word == regs.semaphore_sequence) ||
  291. (op == GpuSemaphoreOperation::AcquireGequal &&
  292. static_cast<s32>(word - regs.semaphore_sequence) > 0) ||
  293. (op == GpuSemaphoreOperation::AcquireMask && (word & regs.semaphore_sequence))) {
  294. // Nothing to do in this case
  295. } else {
  296. regs.acquire_source = true;
  297. regs.acquire_value = regs.semaphore_sequence;
  298. if (op == GpuSemaphoreOperation::AcquireEqual) {
  299. regs.acquire_active = true;
  300. regs.acquire_mode = false;
  301. } else if (op == GpuSemaphoreOperation::AcquireGequal) {
  302. regs.acquire_active = true;
  303. regs.acquire_mode = true;
  304. } else if (op == GpuSemaphoreOperation::AcquireMask) {
  305. // TODO(kemathe) The acquire mask operation waits for a value that, ANDed with
  306. // semaphore_sequence, gives a non-0 result
  307. LOG_ERROR(HW_GPU, "Invalid semaphore operation AcquireMask not implemented");
  308. } else {
  309. LOG_ERROR(HW_GPU, "Invalid semaphore operation");
  310. }
  311. }
  312. }
  313. }
  314. void GPU::ProcessSemaphoreRelease() {
  315. memory_manager->Write<u32>(regs.semaphore_address.SemaphoreAddress(), regs.semaphore_release);
  316. }
  317. void GPU::ProcessSemaphoreAcquire() {
  318. const u32 word = memory_manager->Read<u32>(regs.semaphore_address.SemaphoreAddress());
  319. const auto value = regs.semaphore_acquire;
  320. if (word != value) {
  321. regs.acquire_active = true;
  322. regs.acquire_value = value;
  323. // TODO(kemathe73) figure out how to do the acquire_timeout
  324. regs.acquire_mode = false;
  325. regs.acquire_source = false;
  326. }
  327. }
  328. } // namespace Tegra