dma_pusher.h 2.8 KB

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