gpu.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <chrono>
  5. #include "common/assert.h"
  6. #include "common/microprofile.h"
  7. #include "core/core.h"
  8. #include "core/core_timing.h"
  9. #include "core/core_timing_util.h"
  10. #include "core/frontend/emu_window.h"
  11. #include "core/hardware_interrupt_manager.h"
  12. #include "core/memory.h"
  13. #include "core/settings.h"
  14. #include "video_core/engines/fermi_2d.h"
  15. #include "video_core/engines/kepler_compute.h"
  16. #include "video_core/engines/kepler_memory.h"
  17. #include "video_core/engines/maxwell_3d.h"
  18. #include "video_core/engines/maxwell_dma.h"
  19. #include "video_core/gpu.h"
  20. #include "video_core/memory_manager.h"
  21. #include "video_core/renderer_base.h"
  22. #include "video_core/shader_notify.h"
  23. #include "video_core/video_core.h"
  24. namespace Tegra {
  25. MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
  26. GPU::GPU(Core::System& system_, bool is_async_, bool use_nvdec_)
  27. : system{system_}, memory_manager{std::make_unique<Tegra::MemoryManager>(system)},
  28. dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)}, use_nvdec{use_nvdec_},
  29. maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)},
  30. fermi_2d{std::make_unique<Engines::Fermi2D>()},
  31. kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)},
  32. maxwell_dma{std::make_unique<Engines::MaxwellDMA>(system, *memory_manager)},
  33. kepler_memory{std::make_unique<Engines::KeplerMemory>(system, *memory_manager)},
  34. shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_},
  35. gpu_thread{system_, is_async_} {}
  36. GPU::~GPU() = default;
  37. void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
  38. renderer = std::move(renderer_);
  39. rasterizer = renderer->ReadRasterizer();
  40. memory_manager->BindRasterizer(rasterizer);
  41. maxwell_3d->BindRasterizer(rasterizer);
  42. fermi_2d->BindRasterizer(rasterizer);
  43. kepler_compute->BindRasterizer(rasterizer);
  44. }
  45. Engines::Maxwell3D& GPU::Maxwell3D() {
  46. return *maxwell_3d;
  47. }
  48. const Engines::Maxwell3D& GPU::Maxwell3D() const {
  49. return *maxwell_3d;
  50. }
  51. Engines::KeplerCompute& GPU::KeplerCompute() {
  52. return *kepler_compute;
  53. }
  54. const Engines::KeplerCompute& GPU::KeplerCompute() const {
  55. return *kepler_compute;
  56. }
  57. MemoryManager& GPU::MemoryManager() {
  58. return *memory_manager;
  59. }
  60. const MemoryManager& GPU::MemoryManager() const {
  61. return *memory_manager;
  62. }
  63. DmaPusher& GPU::DmaPusher() {
  64. return *dma_pusher;
  65. }
  66. Tegra::CDmaPusher& GPU::CDmaPusher() {
  67. return *cdma_pusher;
  68. }
  69. const DmaPusher& GPU::DmaPusher() const {
  70. return *dma_pusher;
  71. }
  72. const Tegra::CDmaPusher& GPU::CDmaPusher() const {
  73. return *cdma_pusher;
  74. }
  75. void GPU::WaitFence(u32 syncpoint_id, u32 value) {
  76. // Synced GPU, is always in sync
  77. if (!is_async) {
  78. return;
  79. }
  80. if (syncpoint_id == UINT32_MAX) {
  81. // TODO: Research what this does.
  82. LOG_ERROR(HW_GPU, "Waiting for syncpoint -1 not implemented");
  83. return;
  84. }
  85. MICROPROFILE_SCOPE(GPU_wait);
  86. std::unique_lock lock{sync_mutex};
  87. sync_cv.wait(lock, [=, this] { return syncpoints.at(syncpoint_id).load() >= value; });
  88. }
  89. void GPU::IncrementSyncPoint(const u32 syncpoint_id) {
  90. auto& syncpoint = syncpoints.at(syncpoint_id);
  91. syncpoint++;
  92. std::lock_guard lock{sync_mutex};
  93. sync_cv.notify_all();
  94. auto& interrupt = syncpt_interrupts.at(syncpoint_id);
  95. if (!interrupt.empty()) {
  96. u32 value = syncpoint.load();
  97. auto it = interrupt.begin();
  98. while (it != interrupt.end()) {
  99. if (value >= *it) {
  100. TriggerCpuInterrupt(syncpoint_id, *it);
  101. it = interrupt.erase(it);
  102. continue;
  103. }
  104. it++;
  105. }
  106. }
  107. }
  108. u32 GPU::GetSyncpointValue(const u32 syncpoint_id) const {
  109. return syncpoints.at(syncpoint_id).load();
  110. }
  111. void GPU::RegisterSyncptInterrupt(const u32 syncpoint_id, const u32 value) {
  112. auto& interrupt = syncpt_interrupts.at(syncpoint_id);
  113. bool contains = std::any_of(interrupt.begin(), interrupt.end(),
  114. [value](u32 in_value) { return in_value == value; });
  115. if (contains) {
  116. return;
  117. }
  118. interrupt.emplace_back(value);
  119. }
  120. bool GPU::CancelSyncptInterrupt(const u32 syncpoint_id, const u32 value) {
  121. std::lock_guard lock{sync_mutex};
  122. auto& interrupt = syncpt_interrupts.at(syncpoint_id);
  123. const auto iter =
  124. std::find_if(interrupt.begin(), interrupt.end(),
  125. [value](u32 interrupt_value) { return value == interrupt_value; });
  126. if (iter == interrupt.end()) {
  127. return false;
  128. }
  129. interrupt.erase(iter);
  130. return true;
  131. }
  132. u64 GPU::RequestFlush(VAddr addr, std::size_t size) {
  133. std::unique_lock lck{flush_request_mutex};
  134. const u64 fence = ++last_flush_fence;
  135. flush_requests.emplace_back(fence, addr, size);
  136. return fence;
  137. }
  138. void GPU::TickWork() {
  139. std::unique_lock lck{flush_request_mutex};
  140. while (!flush_requests.empty()) {
  141. auto& request = flush_requests.front();
  142. const u64 fence = request.fence;
  143. const VAddr addr = request.addr;
  144. const std::size_t size = request.size;
  145. flush_requests.pop_front();
  146. flush_request_mutex.unlock();
  147. rasterizer->FlushRegion(addr, size);
  148. current_flush_fence.store(fence);
  149. flush_request_mutex.lock();
  150. }
  151. }
  152. u64 GPU::GetTicks() const {
  153. // This values were reversed engineered by fincs from NVN
  154. // The gpu clock is reported in units of 385/625 nanoseconds
  155. constexpr u64 gpu_ticks_num = 384;
  156. constexpr u64 gpu_ticks_den = 625;
  157. u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count();
  158. if (Settings::values.use_fast_gpu_time.GetValue()) {
  159. nanoseconds /= 256;
  160. }
  161. const u64 nanoseconds_num = nanoseconds / gpu_ticks_den;
  162. const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den;
  163. return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
  164. }
  165. void GPU::FlushCommands() {
  166. rasterizer->FlushCommands();
  167. }
  168. void GPU::SyncGuestHost() {
  169. rasterizer->SyncGuestHost();
  170. }
  171. enum class GpuSemaphoreOperation {
  172. AcquireEqual = 0x1,
  173. WriteLong = 0x2,
  174. AcquireGequal = 0x4,
  175. AcquireMask = 0x8,
  176. };
  177. void GPU::CallMethod(const MethodCall& method_call) {
  178. LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method,
  179. method_call.subchannel);
  180. ASSERT(method_call.subchannel < bound_engines.size());
  181. if (ExecuteMethodOnEngine(method_call.method)) {
  182. CallEngineMethod(method_call);
  183. } else {
  184. CallPullerMethod(method_call);
  185. }
  186. }
  187. void GPU::CallMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
  188. u32 methods_pending) {
  189. LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method, subchannel);
  190. ASSERT(subchannel < bound_engines.size());
  191. if (ExecuteMethodOnEngine(method)) {
  192. CallEngineMultiMethod(method, subchannel, base_start, amount, methods_pending);
  193. } else {
  194. for (std::size_t i = 0; i < amount; i++) {
  195. CallPullerMethod(MethodCall{
  196. method,
  197. base_start[i],
  198. subchannel,
  199. methods_pending - static_cast<u32>(i),
  200. });
  201. }
  202. }
  203. }
  204. bool GPU::ExecuteMethodOnEngine(u32 method) {
  205. const auto buffer_method = static_cast<BufferMethods>(method);
  206. return buffer_method >= BufferMethods::NonPullerMethods;
  207. }
  208. void GPU::CallPullerMethod(const MethodCall& method_call) {
  209. regs.reg_array[method_call.method] = method_call.argument;
  210. const auto method = static_cast<BufferMethods>(method_call.method);
  211. switch (method) {
  212. case BufferMethods::BindObject: {
  213. ProcessBindMethod(method_call);
  214. break;
  215. }
  216. case BufferMethods::Nop:
  217. case BufferMethods::SemaphoreAddressHigh:
  218. case BufferMethods::SemaphoreAddressLow:
  219. case BufferMethods::SemaphoreSequence:
  220. case BufferMethods::RefCnt:
  221. case BufferMethods::UnkCacheFlush:
  222. case BufferMethods::WrcacheFlush:
  223. case BufferMethods::FenceValue:
  224. break;
  225. case BufferMethods::FenceAction:
  226. ProcessFenceActionMethod();
  227. break;
  228. case BufferMethods::WaitForInterrupt:
  229. ProcessWaitForInterruptMethod();
  230. break;
  231. case BufferMethods::SemaphoreTrigger: {
  232. ProcessSemaphoreTriggerMethod();
  233. break;
  234. }
  235. case BufferMethods::NotifyIntr: {
  236. // TODO(Kmather73): Research and implement this method.
  237. LOG_ERROR(HW_GPU, "Special puller engine method NotifyIntr not implemented");
  238. break;
  239. }
  240. case BufferMethods::Unk28: {
  241. // TODO(Kmather73): Research and implement this method.
  242. LOG_ERROR(HW_GPU, "Special puller engine method Unk28 not implemented");
  243. break;
  244. }
  245. case BufferMethods::SemaphoreAcquire: {
  246. ProcessSemaphoreAcquire();
  247. break;
  248. }
  249. case BufferMethods::SemaphoreRelease: {
  250. ProcessSemaphoreRelease();
  251. break;
  252. }
  253. case BufferMethods::Yield: {
  254. // TODO(Kmather73): Research and implement this method.
  255. LOG_ERROR(HW_GPU, "Special puller engine method Yield not implemented");
  256. break;
  257. }
  258. default:
  259. LOG_ERROR(HW_GPU, "Special puller engine method {:X} not implemented", method);
  260. break;
  261. }
  262. }
  263. void GPU::CallEngineMethod(const MethodCall& method_call) {
  264. const EngineID engine = bound_engines[method_call.subchannel];
  265. switch (engine) {
  266. case EngineID::FERMI_TWOD_A:
  267. fermi_2d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
  268. break;
  269. case EngineID::MAXWELL_B:
  270. maxwell_3d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
  271. break;
  272. case EngineID::KEPLER_COMPUTE_B:
  273. kepler_compute->CallMethod(method_call.method, method_call.argument,
  274. method_call.IsLastCall());
  275. break;
  276. case EngineID::MAXWELL_DMA_COPY_A:
  277. maxwell_dma->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall());
  278. break;
  279. case EngineID::KEPLER_INLINE_TO_MEMORY_B:
  280. kepler_memory->CallMethod(method_call.method, method_call.argument,
  281. method_call.IsLastCall());
  282. break;
  283. default:
  284. UNIMPLEMENTED_MSG("Unimplemented engine");
  285. }
  286. }
  287. void GPU::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_start, u32 amount,
  288. u32 methods_pending) {
  289. const EngineID engine = bound_engines[subchannel];
  290. switch (engine) {
  291. case EngineID::FERMI_TWOD_A:
  292. fermi_2d->CallMultiMethod(method, base_start, amount, methods_pending);
  293. break;
  294. case EngineID::MAXWELL_B:
  295. maxwell_3d->CallMultiMethod(method, base_start, amount, methods_pending);
  296. break;
  297. case EngineID::KEPLER_COMPUTE_B:
  298. kepler_compute->CallMultiMethod(method, base_start, amount, methods_pending);
  299. break;
  300. case EngineID::MAXWELL_DMA_COPY_A:
  301. maxwell_dma->CallMultiMethod(method, base_start, amount, methods_pending);
  302. break;
  303. case EngineID::KEPLER_INLINE_TO_MEMORY_B:
  304. kepler_memory->CallMultiMethod(method, base_start, amount, methods_pending);
  305. break;
  306. default:
  307. UNIMPLEMENTED_MSG("Unimplemented engine");
  308. }
  309. }
  310. void GPU::ProcessBindMethod(const MethodCall& method_call) {
  311. // Bind the current subchannel to the desired engine id.
  312. LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel,
  313. method_call.argument);
  314. const auto engine_id = static_cast<EngineID>(method_call.argument);
  315. bound_engines[method_call.subchannel] = static_cast<EngineID>(engine_id);
  316. switch (engine_id) {
  317. case EngineID::FERMI_TWOD_A:
  318. dma_pusher->BindSubchannel(fermi_2d.get(), method_call.subchannel);
  319. break;
  320. case EngineID::MAXWELL_B:
  321. dma_pusher->BindSubchannel(maxwell_3d.get(), method_call.subchannel);
  322. break;
  323. case EngineID::KEPLER_COMPUTE_B:
  324. dma_pusher->BindSubchannel(kepler_compute.get(), method_call.subchannel);
  325. break;
  326. case EngineID::MAXWELL_DMA_COPY_A:
  327. dma_pusher->BindSubchannel(maxwell_dma.get(), method_call.subchannel);
  328. break;
  329. case EngineID::KEPLER_INLINE_TO_MEMORY_B:
  330. dma_pusher->BindSubchannel(kepler_memory.get(), method_call.subchannel);
  331. break;
  332. default:
  333. UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id);
  334. }
  335. }
  336. void GPU::ProcessFenceActionMethod() {
  337. switch (regs.fence_action.op) {
  338. case FenceOperation::Acquire:
  339. WaitFence(regs.fence_action.syncpoint_id, regs.fence_value);
  340. break;
  341. case FenceOperation::Increment:
  342. IncrementSyncPoint(regs.fence_action.syncpoint_id);
  343. break;
  344. default:
  345. UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value());
  346. }
  347. }
  348. void GPU::ProcessWaitForInterruptMethod() {
  349. // TODO(bunnei) ImplementMe
  350. LOG_WARNING(HW_GPU, "(STUBBED) called");
  351. }
  352. void GPU::ProcessSemaphoreTriggerMethod() {
  353. const auto semaphoreOperationMask = 0xF;
  354. const auto op =
  355. static_cast<GpuSemaphoreOperation>(regs.semaphore_trigger & semaphoreOperationMask);
  356. if (op == GpuSemaphoreOperation::WriteLong) {
  357. struct Block {
  358. u32 sequence;
  359. u32 zeros = 0;
  360. u64 timestamp;
  361. };
  362. Block block{};
  363. block.sequence = regs.semaphore_sequence;
  364. // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of
  365. // CoreTiming
  366. block.timestamp = GetTicks();
  367. memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block,
  368. sizeof(block));
  369. } else {
  370. const u32 word{memory_manager->Read<u32>(regs.semaphore_address.SemaphoreAddress())};
  371. if ((op == GpuSemaphoreOperation::AcquireEqual && word == regs.semaphore_sequence) ||
  372. (op == GpuSemaphoreOperation::AcquireGequal &&
  373. static_cast<s32>(word - regs.semaphore_sequence) > 0) ||
  374. (op == GpuSemaphoreOperation::AcquireMask && (word & regs.semaphore_sequence))) {
  375. // Nothing to do in this case
  376. } else {
  377. regs.acquire_source = true;
  378. regs.acquire_value = regs.semaphore_sequence;
  379. if (op == GpuSemaphoreOperation::AcquireEqual) {
  380. regs.acquire_active = true;
  381. regs.acquire_mode = false;
  382. } else if (op == GpuSemaphoreOperation::AcquireGequal) {
  383. regs.acquire_active = true;
  384. regs.acquire_mode = true;
  385. } else if (op == GpuSemaphoreOperation::AcquireMask) {
  386. // TODO(kemathe) The acquire mask operation waits for a value that, ANDed with
  387. // semaphore_sequence, gives a non-0 result
  388. LOG_ERROR(HW_GPU, "Invalid semaphore operation AcquireMask not implemented");
  389. } else {
  390. LOG_ERROR(HW_GPU, "Invalid semaphore operation");
  391. }
  392. }
  393. }
  394. }
  395. void GPU::ProcessSemaphoreRelease() {
  396. memory_manager->Write<u32>(regs.semaphore_address.SemaphoreAddress(), regs.semaphore_release);
  397. }
  398. void GPU::ProcessSemaphoreAcquire() {
  399. const u32 word = memory_manager->Read<u32>(regs.semaphore_address.SemaphoreAddress());
  400. const auto value = regs.semaphore_acquire;
  401. if (word != value) {
  402. regs.acquire_active = true;
  403. regs.acquire_value = value;
  404. // TODO(kemathe73) figure out how to do the acquire_timeout
  405. regs.acquire_mode = false;
  406. regs.acquire_source = false;
  407. }
  408. }
  409. void GPU::Start() {
  410. gpu_thread.StartThread(*renderer, renderer->Context(), *dma_pusher);
  411. cpu_context = renderer->GetRenderWindow().CreateSharedContext();
  412. cpu_context->MakeCurrent();
  413. }
  414. void GPU::ObtainContext() {
  415. cpu_context->MakeCurrent();
  416. }
  417. void GPU::ReleaseContext() {
  418. cpu_context->DoneCurrent();
  419. }
  420. void GPU::PushGPUEntries(Tegra::CommandList&& entries) {
  421. gpu_thread.SubmitList(std::move(entries));
  422. }
  423. void GPU::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) {
  424. if (!use_nvdec) {
  425. return;
  426. }
  427. // This condition fires when a video stream ends, clear all intermediary data
  428. if (entries[0].raw == 0xDEADB33F) {
  429. cdma_pusher.reset();
  430. return;
  431. }
  432. if (!cdma_pusher) {
  433. cdma_pusher = std::make_unique<Tegra::CDmaPusher>(*this);
  434. }
  435. // SubmitCommandBuffer would make the nvdec operations async, this is not currently working
  436. // TODO(ameerj): RE proper async nvdec operation
  437. // gpu_thread.SubmitCommandBuffer(std::move(entries));
  438. cdma_pusher->ProcessEntries(std::move(entries));
  439. }
  440. void GPU::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
  441. gpu_thread.SwapBuffers(framebuffer);
  442. }
  443. void GPU::FlushRegion(VAddr addr, u64 size) {
  444. gpu_thread.FlushRegion(addr, size);
  445. }
  446. void GPU::InvalidateRegion(VAddr addr, u64 size) {
  447. gpu_thread.InvalidateRegion(addr, size);
  448. }
  449. void GPU::FlushAndInvalidateRegion(VAddr addr, u64 size) {
  450. gpu_thread.FlushAndInvalidateRegion(addr, size);
  451. }
  452. void GPU::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) const {
  453. auto& interrupt_manager = system.InterruptManager();
  454. interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value);
  455. }
  456. void GPU::ShutDown() {
  457. gpu_thread.ShutDown();
  458. }
  459. void GPU::OnCommandListEnd() {
  460. if (is_async) {
  461. // This command only applies to asynchronous GPU mode
  462. gpu_thread.OnCommandListEnd();
  463. }
  464. }
  465. } // namespace Tegra