fermi_2d.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/assert.h"
  5. #include "common/logging/log.h"
  6. #include "video_core/engines/fermi_2d.h"
  7. #include "video_core/memory_manager.h"
  8. #include "video_core/rasterizer_interface.h"
  9. namespace Tegra::Engines {
  10. Fermi2D::Fermi2D() = default;
  11. Fermi2D::~Fermi2D() = default;
  12. void Fermi2D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
  13. rasterizer = &rasterizer_;
  14. }
  15. void Fermi2D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
  16. ASSERT_MSG(method < Regs::NUM_REGS,
  17. "Invalid Fermi2D register, increase the size of the Regs structure");
  18. regs.reg_array[method] = method_argument;
  19. switch (method) {
  20. // Trigger the surface copy on the last register write. This is blit_src_y, but this is 64-bit,
  21. // so trigger on the second 32-bit write.
  22. case FERMI2D_REG_INDEX(blit_src_y) + 1: {
  23. HandleSurfaceCopy();
  24. break;
  25. }
  26. }
  27. }
  28. void Fermi2D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, u32 methods_pending) {
  29. for (std::size_t i = 0; i < amount; i++) {
  30. CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1);
  31. }
  32. }
  33. static std::pair<u32, u32> DelimitLine(u32 src_1, u32 src_2, u32 dst_1, u32 dst_2, u32 src_line) {
  34. const u32 line_a = src_2 - src_1;
  35. const u32 line_b = dst_2 - dst_1;
  36. const u32 excess = std::max<s32>(0, line_a - src_line + src_1);
  37. return {line_b - (excess * line_b) / line_a, excess};
  38. }
  39. void Fermi2D::HandleSurfaceCopy() {
  40. LOG_DEBUG(HW_GPU, "Requested a surface copy with operation {}",
  41. static_cast<u32>(regs.operation));
  42. // TODO(Subv): Only raw copies are implemented.
  43. ASSERT(regs.operation == Operation::SrcCopy);
  44. const u32 src_blit_x1{static_cast<u32>(regs.blit_src_x >> 32)};
  45. const u32 src_blit_y1{static_cast<u32>(regs.blit_src_y >> 32)};
  46. u32 src_blit_x2, src_blit_y2;
  47. if (regs.blit_control.origin == Origin::Corner) {
  48. src_blit_x2 =
  49. static_cast<u32>((regs.blit_src_x + (regs.blit_du_dx * regs.blit_dst_width)) >> 32);
  50. src_blit_y2 =
  51. static_cast<u32>((regs.blit_src_y + (regs.blit_dv_dy * regs.blit_dst_height)) >> 32);
  52. } else {
  53. src_blit_x2 = static_cast<u32>((regs.blit_src_x >> 32) + regs.blit_dst_width);
  54. src_blit_y2 = static_cast<u32>((regs.blit_src_y >> 32) + regs.blit_dst_height);
  55. }
  56. u32 dst_blit_x2 = regs.blit_dst_x + regs.blit_dst_width;
  57. u32 dst_blit_y2 = regs.blit_dst_y + regs.blit_dst_height;
  58. const auto [new_dst_w, src_excess_x] =
  59. DelimitLine(src_blit_x1, src_blit_x2, regs.blit_dst_x, dst_blit_x2, regs.src.width);
  60. const auto [new_dst_h, src_excess_y] =
  61. DelimitLine(src_blit_y1, src_blit_y2, regs.blit_dst_y, dst_blit_y2, regs.src.height);
  62. dst_blit_x2 = new_dst_w + regs.blit_dst_x;
  63. src_blit_x2 = src_blit_x2 - src_excess_x;
  64. dst_blit_y2 = new_dst_h + regs.blit_dst_y;
  65. src_blit_y2 = src_blit_y2 - src_excess_y;
  66. const auto [new_src_w, dst_excess_x] =
  67. DelimitLine(regs.blit_dst_x, dst_blit_x2, src_blit_x1, src_blit_x2, regs.dst.width);
  68. const auto [new_src_h, dst_excess_y] =
  69. DelimitLine(regs.blit_dst_y, dst_blit_y2, src_blit_y1, src_blit_y2, regs.dst.height);
  70. src_blit_x2 = new_src_w + src_blit_x1;
  71. dst_blit_x2 = dst_blit_x2 - dst_excess_x;
  72. src_blit_y2 = new_src_h + src_blit_y1;
  73. dst_blit_y2 = dst_blit_y2 - dst_excess_y;
  74. const Common::Rectangle<u32> src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2};
  75. const Common::Rectangle<u32> dst_rect{regs.blit_dst_x, regs.blit_dst_y, dst_blit_x2,
  76. dst_blit_y2};
  77. const Config copy_config{
  78. .operation = regs.operation,
  79. .filter = regs.blit_control.filter,
  80. .src_rect = src_rect,
  81. .dst_rect = dst_rect,
  82. };
  83. if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) {
  84. UNIMPLEMENTED();
  85. }
  86. }
  87. } // namespace Tegra::Engines