command_processor.cpp 5.0 KB

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