dma_pusher.h 3.3 KB

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