BoundingBox.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright 2014 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "VideoCommon/BoundingBox.h"
  4. #include <algorithm>
  5. #include "Common/Assert.h"
  6. #include "Common/ChunkFile.h"
  7. #include "Common/CommonTypes.h"
  8. #include "VideoCommon/PixelShaderManager.h"
  9. #include "VideoCommon/VideoConfig.h"
  10. #include <algorithm>
  11. std::unique_ptr<BoundingBox> g_bounding_box;
  12. void BoundingBox::Enable(PixelShaderManager& pixel_shader_manager)
  13. {
  14. m_is_active = true;
  15. pixel_shader_manager.SetBoundingBoxActive(m_is_active);
  16. }
  17. void BoundingBox::Disable(PixelShaderManager& pixel_shader_manager)
  18. {
  19. m_is_active = false;
  20. pixel_shader_manager.SetBoundingBoxActive(m_is_active);
  21. }
  22. void BoundingBox::Flush()
  23. {
  24. if (!g_ActiveConfig.bBBoxEnable || !g_ActiveConfig.backend_info.bSupportsBBox)
  25. return;
  26. m_is_valid = false;
  27. if (std::none_of(m_dirty.begin(), m_dirty.end(), [](bool dirty) { return dirty; }))
  28. return;
  29. // TODO: Does this make any difference over just writing all the values?
  30. // Games only ever seem to write all 4 values at once anyways.
  31. for (u32 start = 0; start < NUM_BBOX_VALUES; ++start)
  32. {
  33. if (!m_dirty[start])
  34. continue;
  35. u32 end = start + 1;
  36. while (end < NUM_BBOX_VALUES && m_dirty[end])
  37. ++end;
  38. for (u32 i = start; i < end; ++i)
  39. m_dirty[i] = false;
  40. Write(start, std::span(m_values.begin() + start, m_values.begin() + end));
  41. }
  42. }
  43. void BoundingBox::Readback()
  44. {
  45. if (!g_ActiveConfig.backend_info.bSupportsBBox)
  46. return;
  47. auto read_values = Read(0, NUM_BBOX_VALUES);
  48. // Preserve dirty values, that way we don't need to sync.
  49. for (u32 i = 0; i < NUM_BBOX_VALUES; i++)
  50. {
  51. if (!m_dirty[i])
  52. m_values[i] = read_values[i];
  53. }
  54. m_is_valid = true;
  55. }
  56. u16 BoundingBox::Get(u32 index)
  57. {
  58. ASSERT(index < NUM_BBOX_VALUES);
  59. if (!g_ActiveConfig.bBBoxEnable || !g_ActiveConfig.backend_info.bSupportsBBox)
  60. return m_bounding_box_fallback[index];
  61. if (!m_is_valid)
  62. Readback();
  63. return static_cast<u16>(m_values[index]);
  64. }
  65. void BoundingBox::Set(u32 index, u16 value)
  66. {
  67. ASSERT(index < NUM_BBOX_VALUES);
  68. if (!g_ActiveConfig.bBBoxEnable || !g_ActiveConfig.backend_info.bSupportsBBox)
  69. {
  70. m_bounding_box_fallback[index] = value;
  71. return;
  72. }
  73. if (m_is_valid && m_values[index] == value)
  74. return;
  75. m_values[index] = value;
  76. m_dirty[index] = true;
  77. }
  78. // FIXME: This may not work correctly if we're in the middle of a draw.
  79. // We should probably ensure that state saves only happen on frame boundaries.
  80. // Nonetheless, it has been designed to be as safe as possible.
  81. void BoundingBox::DoState(PointerWrap& p)
  82. {
  83. p.DoArray(m_bounding_box_fallback);
  84. p.Do(m_is_active);
  85. p.DoArray(m_values);
  86. p.DoArray(m_dirty);
  87. p.Do(m_is_valid);
  88. // We handle saving the backend values specially rather than using Readback() and Flush() so that
  89. // we don't mess up the current cache state
  90. std::vector<BBoxType> backend_values(NUM_BBOX_VALUES);
  91. if (p.IsReadMode())
  92. {
  93. p.Do(backend_values);
  94. if (g_ActiveConfig.backend_info.bSupportsBBox)
  95. Write(0, backend_values);
  96. }
  97. else
  98. {
  99. if (g_ActiveConfig.backend_info.bSupportsBBox)
  100. backend_values = Read(0, NUM_BBOX_VALUES);
  101. p.Do(backend_values);
  102. }
  103. }