gpu.cpp 15 KB

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