gpu.cpp 11 KB

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