dma_pusher.h 2.8 KB

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