command_processor.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <array>
  5. #include <cstddef>
  6. #include <memory>
  7. #include <utility>
  8. #include "common/assert.h"
  9. #include "common/logging/log.h"
  10. #include "common/microprofile.h"
  11. #include "common/vector_math.h"
  12. #include "core/memory.h"
  13. #include "core/tracer/recorder.h"
  14. #include "video_core/command_processor.h"
  15. #include "video_core/engines/fermi_2d.h"
  16. #include "video_core/engines/kepler_memory.h"
  17. #include "video_core/engines/maxwell_3d.h"
  18. #include "video_core/engines/maxwell_compute.h"
  19. #include "video_core/engines/maxwell_dma.h"
  20. #include "video_core/gpu.h"
  21. #include "video_core/renderer_base.h"
  22. #include "video_core/video_core.h"
  23. namespace Tegra {
  24. enum class BufferMethods {
  25. BindObject = 0,
  26. CountBufferMethods = 0x40,
  27. };
  28. MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
  29. void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
  30. MICROPROFILE_SCOPE(ProcessCommandLists);
  31. auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) {
  32. LOG_TRACE(HW_GPU,
  33. "Processing method {:08X} on subchannel {} value "
  34. "{:08X} remaining params {}",
  35. method, subchannel, value, remaining_params);
  36. ASSERT(subchannel < bound_engines.size());
  37. if (method == static_cast<u32>(BufferMethods::BindObject)) {
  38. // Bind the current subchannel to the desired engine id.
  39. LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value);
  40. bound_engines[subchannel] = static_cast<EngineID>(value);
  41. return;
  42. }
  43. if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
  44. // TODO(Subv): Research and implement these methods.
  45. LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
  46. return;
  47. }
  48. const EngineID engine = bound_engines[subchannel];
  49. switch (engine) {
  50. case EngineID::FERMI_TWOD_A:
  51. fermi_2d->WriteReg(method, value);
  52. break;
  53. case EngineID::MAXWELL_B:
  54. maxwell_3d->WriteReg(method, value, remaining_params);
  55. break;
  56. case EngineID::MAXWELL_COMPUTE_B:
  57. maxwell_compute->WriteReg(method, value);
  58. break;
  59. case EngineID::MAXWELL_DMA_COPY_A:
  60. maxwell_dma->WriteReg(method, value);
  61. break;
  62. case EngineID::KEPLER_INLINE_TO_MEMORY_B:
  63. kepler_memory->WriteReg(method, value);
  64. break;
  65. default:
  66. UNIMPLEMENTED_MSG("Unimplemented engine");
  67. }
  68. };
  69. for (auto entry : commands) {
  70. Tegra::GPUVAddr address = entry.Address();
  71. u32 size = entry.sz;
  72. const boost::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address);
  73. VAddr current_addr = *head_address;
  74. while (current_addr < *head_address + size * sizeof(CommandHeader)) {
  75. const CommandHeader header = {Memory::Read32(current_addr)};
  76. current_addr += sizeof(u32);
  77. switch (header.mode.Value()) {
  78. case SubmissionMode::IncreasingOld:
  79. case SubmissionMode::Increasing: {
  80. // Increase the method value with each argument.
  81. for (unsigned i = 0; i < header.arg_count; ++i) {
  82. WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr),
  83. header.arg_count - i - 1);
  84. current_addr += sizeof(u32);
  85. }
  86. break;
  87. }
  88. case SubmissionMode::NonIncreasingOld:
  89. case SubmissionMode::NonIncreasing: {
  90. // Use the same method value for all arguments.
  91. for (unsigned i = 0; i < header.arg_count; ++i) {
  92. WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
  93. header.arg_count - i - 1);
  94. current_addr += sizeof(u32);
  95. }
  96. break;
  97. }
  98. case SubmissionMode::IncreaseOnce: {
  99. ASSERT(header.arg_count.Value() >= 1);
  100. // Use the original method for the first argument and then the next method for all
  101. // other arguments.
  102. WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
  103. header.arg_count - 1);
  104. current_addr += sizeof(u32);
  105. for (unsigned i = 1; i < header.arg_count; ++i) {
  106. WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr),
  107. header.arg_count - i - 1);
  108. current_addr += sizeof(u32);
  109. }
  110. break;
  111. }
  112. case SubmissionMode::Inline: {
  113. // The register value is stored in the bits 16-28 as an immediate
  114. WriteReg(header.method, header.subchannel, header.inline_data, 0);
  115. break;
  116. }
  117. default:
  118. UNIMPLEMENTED();
  119. }
  120. }
  121. }
  122. }
  123. } // namespace Tegra