gpu.cpp 13 KB

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