gpu.cpp 11 KB

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