dma_pusher.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <array>
  6. #include <vector>
  7. #include <queue>
  8. #include "common/bit_field.h"
  9. #include "common/common_types.h"
  10. #include "video_core/engines/engine_interface.h"
  11. namespace Core {
  12. class System;
  13. }
  14. namespace Tegra {
  15. class GPU;
  16. enum class SubmissionMode : u32 {
  17. IncreasingOld = 0,
  18. Increasing = 1,
  19. NonIncreasingOld = 2,
  20. NonIncreasing = 3,
  21. Inline = 4,
  22. IncreaseOnce = 5
  23. };
  24. // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence
  25. // their numbers are written down multiplied by 4 in Docs. Here we are not multiply by 4.
  26. // So the values you see in docs might be multiplied by 4.
  27. enum class BufferMethods : u32 {
  28. BindObject = 0x0,
  29. Nop = 0x2,
  30. SemaphoreAddressHigh = 0x4,
  31. SemaphoreAddressLow = 0x5,
  32. SemaphoreSequence = 0x6,
  33. SemaphoreTrigger = 0x7,
  34. NotifyIntr = 0x8,
  35. WrcacheFlush = 0x9,
  36. Unk28 = 0xA,
  37. UnkCacheFlush = 0xB,
  38. RefCnt = 0x14,
  39. SemaphoreAcquire = 0x1A,
  40. SemaphoreRelease = 0x1B,
  41. FenceValue = 0x1C,
  42. FenceAction = 0x1D,
  43. WaitForInterrupt = 0x1E,
  44. Unk7c = 0x1F,
  45. Yield = 0x20,
  46. NonPullerMethods = 0x40,
  47. };
  48. struct CommandListHeader {
  49. union {
  50. u64 raw;
  51. BitField<0, 40, GPUVAddr> addr;
  52. BitField<41, 1, u64> is_non_main;
  53. BitField<42, 21, u64> size;
  54. };
  55. };
  56. static_assert(sizeof(CommandListHeader) == sizeof(u64), "CommandListHeader is incorrect size");
  57. union CommandHeader {
  58. u32 argument;
  59. BitField<0, 13, u32> method;
  60. BitField<0, 24, u32> method_count_;
  61. BitField<13, 3, u32> subchannel;
  62. BitField<16, 13, u32> arg_count;
  63. BitField<16, 13, u32> method_count;
  64. BitField<29, 3, SubmissionMode> mode;
  65. };
  66. static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout");
  67. static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
  68. inline CommandHeader BuildCommandHeader(BufferMethods method, u32 arg_count, SubmissionMode mode) {
  69. CommandHeader result{};
  70. result.method.Assign(static_cast<u32>(method));
  71. result.arg_count.Assign(arg_count);
  72. result.mode.Assign(mode);
  73. return result;
  74. }
  75. struct CommandList final {
  76. CommandList() = default;
  77. explicit CommandList(std::size_t size) : command_lists(size) {}
  78. explicit CommandList(std::vector<Tegra::CommandHeader>&& prefetch_command_list)
  79. : prefetch_command_list{std::move(prefetch_command_list)} {}
  80. std::vector<Tegra::CommandListHeader> command_lists;
  81. std::vector<Tegra::CommandHeader> prefetch_command_list;
  82. };
  83. /**
  84. * The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the
  85. * emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled
  86. * into a "command stream" consisting of 32-bit words that make up "commands".
  87. * See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for
  88. * details on this implementation.
  89. */
  90. class DmaPusher final {
  91. public:
  92. explicit DmaPusher(Core::System& system, GPU& gpu);
  93. ~DmaPusher();
  94. void Push(CommandList&& entries) {
  95. dma_pushbuffer.push(std::move(entries));
  96. }
  97. void DispatchCalls();
  98. void BindSubchannel(Tegra::Engines::EngineInterface* engine, u32 subchannel_id) {
  99. subchannels[subchannel_id] = engine;
  100. }
  101. private:
  102. static constexpr u32 non_puller_methods = 0x40;
  103. static constexpr u32 max_subchannels = 8;
  104. bool Step();
  105. void SetState(const CommandHeader& command_header);
  106. void CallMethod(u32 argument) const;
  107. void CallMultiMethod(const u32* base_start, u32 num_methods) const;
  108. std::vector<CommandHeader> command_headers; ///< Buffer for list of commands fetched at once
  109. std::queue<CommandList> dma_pushbuffer; ///< Queue of command lists to be processed
  110. std::size_t dma_pushbuffer_subindex{}; ///< Index within a command list within the pushbuffer
  111. struct DmaState {
  112. u32 method; ///< Current method
  113. u32 subchannel; ///< Current subchannel
  114. u32 method_count; ///< Current method count
  115. u32 length_pending; ///< Large NI command length pending
  116. bool non_incrementing; ///< Current command's NI flag
  117. bool is_last_call;
  118. };
  119. DmaState dma_state{};
  120. bool dma_increment_once{};
  121. bool ib_enable{true}; ///< IB mode enabled
  122. std::array<Tegra::Engines::EngineInterface*, max_subchannels> subchannels{};
  123. GPU& gpu;
  124. Core::System& system;
  125. };
  126. } // namespace Tegra