Readback.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Renderer/RendererObject.h>
  7. #include <AnKi/Core/GpuMemory/GpuReadbackMemoryPool.h>
  8. namespace anki {
  9. /// @addtogroup renderer
  10. /// @{
  11. /// A persistent GPU readback token. It's essentially a group of allocations.
  12. class MultiframeReadbackToken
  13. {
  14. friend class ReadbackManager;
  15. private:
  16. Array<GpuReadbackMemoryAllocation, kMaxFramesInFlight> m_allocations;
  17. Array<U64, kMaxFramesInFlight> m_frameIds = {};
  18. U32 m_slot = 0;
  19. };
  20. /// A small class that is used to streamling the use of GPU readbacks.
  21. class ReadbackManager
  22. {
  23. public:
  24. Error init()
  25. {
  26. // Just for the interface
  27. return Error::kNone;
  28. }
  29. /// Read the most up to date data from the GPU. 1st thing to call in a frame.
  30. void readMostRecentData(const MultiframeReadbackToken& token, void* data, PtrSize dataSize, PtrSize& dataOut) const;
  31. /// Read the most up to date data from the GPU.
  32. template<typename T, typename TMemPool>
  33. void readMostRecentData(const MultiframeReadbackToken& token, DynamicArray<T, TMemPool>& data) const
  34. {
  35. const U32 slot = findBestSlot(token);
  36. if(slot != kMaxU32 && token.m_allocations[slot].isValid())
  37. {
  38. const GpuReadbackMemoryAllocation& allocation = token.m_allocations[slot];
  39. data.resize(allocation.getAllocatedSize() / sizeof(T));
  40. memcpy(&data[0], static_cast<const U8*>(allocation.getMappedMemory()), allocation.getAllocatedSize());
  41. }
  42. else
  43. {
  44. data.resize(0);
  45. }
  46. }
  47. /// Allocate new data for the following frame. 2nd thing to call in a frame.
  48. template<typename T>
  49. BufferView allocateStructuredBuffer(MultiframeReadbackToken& token, U32 count) const
  50. {
  51. ANKI_ASSERT(count > 0);
  52. for([[maybe_unused]] U64 frame : token.m_frameIds)
  53. {
  54. ANKI_ASSERT(frame != m_frameId && "Can't allocate multiple times in a frame");
  55. }
  56. GpuReadbackMemoryAllocation& allocation = token.m_allocations[token.m_slot];
  57. if(allocation.isValid() && allocation.getAllocatedSize() != sizeof(T) * count)
  58. {
  59. GpuReadbackMemoryPool::getSingleton().deferredFree(allocation);
  60. }
  61. if(!allocation.isValid())
  62. {
  63. allocation = GpuReadbackMemoryPool::getSingleton().allocateStructuredBuffer<T>(count);
  64. }
  65. token.m_frameIds[token.m_slot] = m_frameId;
  66. token.m_slot = (token.m_slot + 1) % kMaxFramesInFlight;
  67. return BufferView(&allocation.getBuffer(), allocation.getOffset(), sizeof(T) * count);
  68. }
  69. /// Last thing to call in a frame.
  70. void endFrame(Fence* fence);
  71. private:
  72. class Frame
  73. {
  74. public:
  75. FencePtr m_fence;
  76. };
  77. Array<Frame, kMaxFramesInFlight> m_frames;
  78. U64 m_frameId = kMaxFramesInFlight;
  79. U32 findBestSlot(const MultiframeReadbackToken& token) const;
  80. };
  81. /// @}
  82. } // end namespace anki