command_processor.cpp 4.4 KB

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