gpu.cpp 12 KB

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