dma_pusher.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <array>
  5. #include <span>
  6. #include <vector>
  7. #include <queue>
  8. #include "common/bit_field.h"
  9. #include "common/common_types.h"
  10. #include "common/scratch_buffer.h"
  11. #include "video_core/engines/engine_interface.h"
  12. #include "video_core/engines/puller.h"
  13. namespace Core {
  14. class System;
  15. }
  16. namespace Tegra {
  17. namespace Control {
  18. struct ChannelState;
  19. }
  20. class GPU;
  21. class MemoryManager;
  22. enum class SubmissionMode : u32 {
  23. IncreasingOld = 0,
  24. Increasing = 1,
  25. NonIncreasingOld = 2,
  26. NonIncreasing = 3,
  27. Inline = 4,
  28. IncreaseOnce = 5
  29. };
  30. // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence
  31. // their numbers are written down multiplied by 4 in Docs. Here we are not multiply by 4.
  32. // So the values you see in docs might be multiplied by 4.
  33. // Register documentation:
  34. // https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/classes/host/cla26f.h
  35. //
  36. // Register Description (approx):
  37. // https://github.com/NVIDIA/open-gpu-doc/blob/ab27fc22db5de0d02a4cabe08e555663b62db4d4/manuals/volta/gv100/dev_pbdma.ref.txt
  38. enum class BufferMethods : u32 {
  39. BindObject = 0x0,
  40. Illegal = 0x1,
  41. Nop = 0x2,
  42. SemaphoreAddressHigh = 0x4,
  43. SemaphoreAddressLow = 0x5,
  44. SemaphoreSequencePayload = 0x6,
  45. SemaphoreOperation = 0x7,
  46. NonStallInterrupt = 0x8,
  47. WrcacheFlush = 0x9,
  48. MemOpA = 0xA,
  49. MemOpB = 0xB,
  50. MemOpC = 0xC,
  51. MemOpD = 0xD,
  52. RefCnt = 0x14,
  53. SemaphoreAcquire = 0x1A,
  54. SemaphoreRelease = 0x1B,
  55. SyncpointPayload = 0x1C,
  56. SyncpointOperation = 0x1D,
  57. WaitForIdle = 0x1E,
  58. CRCCheck = 0x1F,
  59. Yield = 0x20,
  60. NonPullerMethods = 0x40,
  61. };
  62. struct CommandListHeader {
  63. union {
  64. u64 raw;
  65. BitField<0, 40, GPUVAddr> addr;
  66. BitField<41, 1, u64> is_non_main;
  67. BitField<42, 21, u64> size;
  68. };
  69. };
  70. static_assert(sizeof(CommandListHeader) == sizeof(u64), "CommandListHeader is incorrect size");
  71. union CommandHeader {
  72. u32 argument;
  73. BitField<0, 13, u32> method;
  74. BitField<0, 24, u32> method_count_;
  75. BitField<13, 3, u32> subchannel;
  76. BitField<16, 13, u32> arg_count;
  77. BitField<16, 13, u32> method_count;
  78. BitField<29, 3, SubmissionMode> mode;
  79. };
  80. static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout");
  81. static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
  82. inline CommandHeader BuildCommandHeader(BufferMethods method, u32 arg_count, SubmissionMode mode) {
  83. CommandHeader result{};
  84. result.method.Assign(static_cast<u32>(method));
  85. result.arg_count.Assign(arg_count);
  86. result.mode.Assign(mode);
  87. return result;
  88. }
  89. struct CommandList final {
  90. CommandList() = default;
  91. explicit CommandList(std::size_t size) : command_lists(size) {}
  92. explicit CommandList(std::vector<CommandHeader>&& prefetch_command_list_)
  93. : prefetch_command_list{std::move(prefetch_command_list_)} {}
  94. std::vector<CommandListHeader> command_lists;
  95. std::vector<CommandHeader> prefetch_command_list;
  96. };
  97. /**
  98. * The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the
  99. * emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled
  100. * into a "command stream" consisting of 32-bit words that make up "commands".
  101. * See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for
  102. * details on this implementation.
  103. */
  104. class DmaPusher final {
  105. public:
  106. explicit DmaPusher(Core::System& system_, GPU& gpu_, MemoryManager& memory_manager_,
  107. Control::ChannelState& channel_state_);
  108. ~DmaPusher();
  109. void Push(CommandList&& entries) {
  110. dma_pushbuffer.push(std::move(entries));
  111. }
  112. void DispatchCalls();
  113. void BindSubchannel(Engines::EngineInterface* engine, u32 subchannel_id) {
  114. subchannels[subchannel_id] = engine;
  115. }
  116. void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
  117. private:
  118. static constexpr u32 non_puller_methods = 0x40;
  119. static constexpr u32 max_subchannels = 8;
  120. bool Step();
  121. void ProcessCommands(std::span<const CommandHeader> commands);
  122. void SetState(const CommandHeader& command_header);
  123. void CallMethod(u32 argument) const;
  124. void CallMultiMethod(const u32* base_start, u32 num_methods) const;
  125. Common::ScratchBuffer<CommandHeader>
  126. command_headers; ///< Buffer for list of commands fetched at once
  127. std::queue<CommandList> dma_pushbuffer; ///< Queue of command lists to be processed
  128. std::size_t dma_pushbuffer_subindex{}; ///< Index within a command list within the pushbuffer
  129. struct DmaState {
  130. u32 method; ///< Current method
  131. u32 subchannel; ///< Current subchannel
  132. u32 method_count; ///< Current method count
  133. u32 length_pending; ///< Large NI command length pending
  134. GPUVAddr dma_get; ///< Currently read segment
  135. u64 dma_word_offset; ///< Current word ofset from address
  136. bool non_incrementing; ///< Current command's NI flag
  137. bool is_last_call;
  138. };
  139. DmaState dma_state{};
  140. bool dma_increment_once{};
  141. const bool ib_enable{true}; ///< IB mode enabled
  142. std::array<Engines::EngineInterface*, max_subchannels> subchannels{};
  143. GPU& gpu;
  144. Core::System& system;
  145. MemoryManager& memory_manager;
  146. mutable Engines::Puller puller;
  147. };
  148. } // namespace Tegra