BPFunctions.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2009 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. // ------------------------------------------
  4. // Video backend must define these functions
  5. // ------------------------------------------
  6. #pragma once
  7. #include <utility>
  8. #include <vector>
  9. #include "Common/MathUtil.h"
  10. #include "VideoCommon/BPMemory.h"
  11. struct XFMemory;
  12. namespace BPFunctions
  13. {
  14. struct ScissorRange
  15. {
  16. constexpr ScissorRange() = default;
  17. constexpr ScissorRange(int offset_, int start_, int end_)
  18. : offset(offset_), start(start_), end(end_)
  19. {
  20. }
  21. int offset = 0;
  22. int start = 0;
  23. int end = 0;
  24. };
  25. struct ScissorRect
  26. {
  27. constexpr ScissorRect(ScissorRange x_range, ScissorRange y_range)
  28. : // Rectangle ctor takes x0, y0, x1, y1.
  29. rect(x_range.start, y_range.start, x_range.end, y_range.end), x_off(x_range.offset),
  30. y_off(y_range.offset)
  31. {
  32. }
  33. MathUtil::Rectangle<int> rect;
  34. int x_off;
  35. int y_off;
  36. int GetArea() const;
  37. };
  38. // Although the GameCube/Wii have only one scissor configuration and only one viewport
  39. // configuration, some values can result in multiple parts of the screen being updated.
  40. // This can happen if the scissor offset combined with the bottom or right coordinate ends up
  41. // exceeding 1024; then, both sides of the screen will be drawn to, while the middle is not.
  42. // Major Minor's Majestic March causes this to happen during loading screens and other scrolling
  43. // effects, though it draws on top of one of them.
  44. // This can also happen if the scissor rectangle is particularly large, but this will usually
  45. // involve drawing content outside of the viewport, which Dolphin does not currently handle.
  46. //
  47. // The hardware backends can currently only use one viewport and scissor rectangle, so we need to
  48. // pick the "best" rectangle based on how much of the viewport would be rendered to the screen.
  49. // If we choose the wrong one, then content might not actually show up when the game is expecting it
  50. // to. This does happen on Major Minor's Majestic March for the final few frames of the horizontal
  51. // scrolling animation, but it isn't that important. Note that the assumption that a "best"
  52. // rectangle exists is based on games only wanting to draw one rectangle, and accidentally
  53. // configuring the scissor offset and size of the scissor rectangle such that multiple show up;
  54. // there are no known games where this is not the case.
  55. //
  56. // An ImGui overlay that displays the scissor rectangle configuration as well as the generated
  57. // rectangles is available by setting OverlayScissorStats (GFX_OVERLAY_SCISSOR_STATS)
  58. // under [Settings] to True in GFX.ini.
  59. struct ScissorResult
  60. {
  61. ScissorResult(const BPMemory& bpmem, const XFMemory& xfmem);
  62. ~ScissorResult() = default;
  63. ScissorResult(const ScissorResult& other)
  64. : scissor_tl{.hex = other.scissor_tl.hex}, scissor_br{.hex = other.scissor_br.hex},
  65. scissor_off{.hex = other.scissor_off.hex}, viewport_left{other.viewport_left},
  66. viewport_right{other.viewport_right}, viewport_top{other.viewport_top},
  67. viewport_bottom{other.viewport_bottom}, m_result{other.m_result}
  68. {
  69. }
  70. ScissorResult& operator=(const ScissorResult& other)
  71. {
  72. if (this == &other)
  73. return *this;
  74. scissor_tl.hex = other.scissor_tl.hex;
  75. scissor_br.hex = other.scissor_br.hex;
  76. scissor_off.hex = other.scissor_off.hex;
  77. viewport_left = other.viewport_left;
  78. viewport_right = other.viewport_right;
  79. viewport_top = other.viewport_top;
  80. viewport_bottom = other.viewport_bottom;
  81. m_result = other.m_result;
  82. return *this;
  83. }
  84. ScissorResult(ScissorResult&& other)
  85. : scissor_tl{.hex = other.scissor_tl.hex}, scissor_br{.hex = other.scissor_br.hex},
  86. scissor_off{.hex = other.scissor_off.hex}, viewport_left{other.viewport_left},
  87. viewport_right{other.viewport_right}, viewport_top{other.viewport_top},
  88. viewport_bottom{other.viewport_bottom}, m_result{std::move(other.m_result)}
  89. {
  90. }
  91. ScissorResult& operator=(ScissorResult&& other)
  92. {
  93. if (this == &other)
  94. return *this;
  95. scissor_tl.hex = other.scissor_tl.hex;
  96. scissor_br.hex = other.scissor_br.hex;
  97. scissor_off.hex = other.scissor_off.hex;
  98. viewport_left = other.viewport_left;
  99. viewport_right = other.viewport_right;
  100. viewport_top = other.viewport_top;
  101. viewport_bottom = other.viewport_bottom;
  102. m_result = std::move(other.m_result);
  103. return *this;
  104. }
  105. // Input values, for use in statistics
  106. ScissorPos scissor_tl;
  107. ScissorPos scissor_br;
  108. ScissorOffset scissor_off;
  109. float viewport_left;
  110. float viewport_right;
  111. float viewport_top;
  112. float viewport_bottom;
  113. // Actual result
  114. std::vector<ScissorRect> m_result;
  115. ScissorRect Best() const;
  116. bool ScissorMatches(const ScissorResult& other) const
  117. {
  118. return scissor_tl.hex == other.scissor_tl.hex && scissor_br.hex == other.scissor_br.hex &&
  119. scissor_off.hex == other.scissor_off.hex;
  120. }
  121. bool ViewportMatches(const ScissorResult& other) const
  122. {
  123. return viewport_left == other.viewport_left && viewport_right == other.viewport_right &&
  124. viewport_top == other.viewport_top && viewport_bottom == other.viewport_bottom;
  125. }
  126. bool Matches(const ScissorResult& other, bool compare_scissor, bool compare_viewport) const
  127. {
  128. if (compare_scissor && !ScissorMatches(other))
  129. return false;
  130. if (compare_viewport && !ViewportMatches(other))
  131. return false;
  132. return true;
  133. }
  134. private:
  135. ScissorResult(const BPMemory& bpmem, std::pair<float, float> viewport_x,
  136. std::pair<float, float> viewport_y);
  137. int GetViewportArea(const ScissorRect& rect) const;
  138. bool IsWorse(const ScissorRect& lhs, const ScissorRect& rhs) const;
  139. };
  140. ScissorResult ComputeScissorRects();
  141. void FlushPipeline();
  142. void SetGenerationMode();
  143. void SetScissorAndViewport();
  144. void SetDepthMode();
  145. void SetBlendMode();
  146. void ClearScreen(const MathUtil::Rectangle<int>& rc);
  147. void OnPixelFormatChange();
  148. void SetInterlacingMode(const BPCmd& bp);
  149. } // namespace BPFunctions