#pragma once #include "GLExtensions.h" #include #include #include class PboReadbackRing { public: struct CompletedReadback { GLuint pbo = 0; uint64_t frameIndex = 0; std::size_t byteCount = 0; }; PboReadbackRing() = default; PboReadbackRing(const PboReadbackRing&) = delete; PboReadbackRing& operator=(const PboReadbackRing&) = delete; ~PboReadbackRing(); bool Initialize(std::size_t depth, std::size_t byteCount); void Shutdown(); bool QueueReadback(GLuint framebuffer, unsigned width, unsigned height, uint64_t frameIndex); bool TryAcquireCompleted(CompletedReadback& readback); void ReleaseCompleted(const CompletedReadback& readback); void DrainCompleted(); std::size_t Depth() const { return mSlots.size(); } uint64_t QueueMisses() const { return mQueueMisses; } private: struct Slot { GLuint pbo = 0; GLsync fence = nullptr; bool inFlight = false; bool acquired = false; uint64_t frameIndex = 0; }; void ResetSlot(Slot& slot); std::vector mSlots; std::size_t mWriteIndex = 0; std::size_t mReadIndex = 0; std::size_t mByteCount = 0; uint64_t mQueueMisses = 0; };