usage_tracker.h 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-3.0-or-later
  3. #pragma once
  4. #include "common/alignment.h"
  5. #include "common/common_types.h"
  6. namespace VideoCommon {
  7. class UsageTracker {
  8. static constexpr size_t BYTES_PER_BIT_SHIFT = 6;
  9. static constexpr size_t PAGE_SHIFT = 6 + BYTES_PER_BIT_SHIFT;
  10. static constexpr size_t PAGE_BYTES = 1 << PAGE_SHIFT;
  11. public:
  12. explicit UsageTracker(size_t size) {
  13. const size_t num_pages = (size >> PAGE_SHIFT) + 1;
  14. pages.resize(num_pages, 0ULL);
  15. }
  16. void Reset() noexcept {
  17. std::ranges::fill(pages, 0ULL);
  18. }
  19. void Track(u64 offset, u64 size) noexcept {
  20. const size_t page = offset >> PAGE_SHIFT;
  21. const size_t page_end = (offset + size) >> PAGE_SHIFT;
  22. TrackPage(page, offset, size);
  23. if (page == page_end) {
  24. return;
  25. }
  26. for (size_t i = page + 1; i < page_end; i++) {
  27. pages[i] = ~u64{0};
  28. }
  29. const size_t offset_end = offset + size;
  30. const size_t offset_end_page_aligned = Common::AlignDown(offset_end, PAGE_BYTES);
  31. TrackPage(page_end, offset_end_page_aligned, offset_end - offset_end_page_aligned);
  32. }
  33. [[nodiscard]] bool IsUsed(u64 offset, u64 size) const noexcept {
  34. const size_t page = offset >> PAGE_SHIFT;
  35. const size_t page_end = (offset + size) >> PAGE_SHIFT;
  36. if (IsPageUsed(page, offset, size)) {
  37. return true;
  38. }
  39. for (size_t i = page + 1; i < page_end; i++) {
  40. if (pages[i] != 0) {
  41. return true;
  42. }
  43. }
  44. const size_t offset_end = offset + size;
  45. const size_t offset_end_page_aligned = Common::AlignDown(offset_end, PAGE_BYTES);
  46. return IsPageUsed(page_end, offset_end_page_aligned, offset_end - offset_end_page_aligned);
  47. }
  48. private:
  49. void TrackPage(u64 page, u64 offset, u64 size) noexcept {
  50. const size_t offset_in_page = offset % PAGE_BYTES;
  51. const size_t first_bit = offset_in_page >> BYTES_PER_BIT_SHIFT;
  52. const size_t num_bits = std::min<size_t>(size, PAGE_BYTES) >> BYTES_PER_BIT_SHIFT;
  53. const size_t mask = ~u64{0} >> (64 - num_bits);
  54. pages[page] |= (~u64{0} & mask) << first_bit;
  55. }
  56. bool IsPageUsed(u64 page, u64 offset, u64 size) const noexcept {
  57. const size_t offset_in_page = offset % PAGE_BYTES;
  58. const size_t first_bit = offset_in_page >> BYTES_PER_BIT_SHIFT;
  59. const size_t num_bits = std::min<size_t>(size, PAGE_BYTES) >> BYTES_PER_BIT_SHIFT;
  60. const size_t mask = ~u64{0} >> (64 - num_bits);
  61. const size_t mask2 = (~u64{0} & mask) << first_bit;
  62. return (pages[page] & mask2) != 0;
  63. }
  64. private:
  65. std::vector<u64> pages;
  66. };
  67. } // namespace VideoCommon