dma_pusher.h 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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 <vector>
  6. #include <queue>
  7. #include "common/bit_field.h"
  8. #include "common/common_types.h"
  9. namespace Tegra {
  10. enum class SubmissionMode : u32 {
  11. IncreasingOld = 0,
  12. Increasing = 1,
  13. NonIncreasingOld = 2,
  14. NonIncreasing = 3,
  15. Inline = 4,
  16. IncreaseOnce = 5
  17. };
  18. struct CommandListHeader {
  19. union {
  20. u64 raw;
  21. BitField<0, 40, GPUVAddr> addr;
  22. BitField<41, 1, u64> is_non_main;
  23. BitField<42, 21, u64> size;
  24. };
  25. };
  26. static_assert(sizeof(CommandListHeader) == sizeof(u64), "CommandListHeader is incorrect size");
  27. union CommandHeader {
  28. u32 argument;
  29. BitField<0, 13, u32> method;
  30. BitField<0, 24, u32> method_count_;
  31. BitField<13, 3, u32> subchannel;
  32. BitField<16, 13, u32> arg_count;
  33. BitField<16, 13, u32> method_count;
  34. BitField<29, 3, SubmissionMode> mode;
  35. };
  36. static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout");
  37. static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
  38. class GPU;
  39. using CommandList = std::vector<Tegra::CommandListHeader>;
  40. /**
  41. * The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the
  42. * emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled
  43. * into a "command stream" consisting of 32-bit words that make up "commands".
  44. * See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for
  45. * details on this implementation.
  46. */
  47. class DmaPusher {
  48. public:
  49. explicit DmaPusher(GPU& gpu);
  50. ~DmaPusher();
  51. void Push(CommandList&& entries) {
  52. dma_pushbuffer.push(std::move(entries));
  53. }
  54. void DispatchCalls();
  55. private:
  56. bool Step();
  57. void SetState(const CommandHeader& command_header);
  58. void CallMethod(u32 argument) const;
  59. GPU& gpu;
  60. std::vector<CommandHeader> command_headers; ///< Buffer for list of commands fetched at once
  61. std::queue<CommandList> dma_pushbuffer; ///< Queue of command lists to be processed
  62. std::size_t dma_pushbuffer_subindex{}; ///< Index within a command list within the pushbuffer
  63. struct DmaState {
  64. u32 method; ///< Current method
  65. u32 subchannel; ///< Current subchannel
  66. u32 method_count; ///< Current method count
  67. u32 length_pending; ///< Large NI command length pending
  68. bool non_incrementing; ///< Current command's NI flag
  69. };
  70. DmaState dma_state{};
  71. bool dma_increment_once{};
  72. GPUVAddr dma_mget{}; ///< main pushbuffer last read address
  73. bool ib_enable{true}; ///< IB mode enabled
  74. };
  75. } // namespace Tegra