gpu.cpp 11 KB

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