dma_pusher.h 5.6 KB

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