gpu.cpp 11 KB

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