gpu.cpp 15 KB

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