10 #ifndef hifi_GLEscrow_h
11 #define hifi_GLEscrow_h
16 #include <forward_list>
20 #include <SharedUtil.h>
21 #include <NumericalConstants.h>
54 static const uint64_t MAX_UNSIGNALED_TIME = USECS_PER_SECOND / 2;
56 const T& invalid()
const {
57 static const T INVALID_RESULT;
58 return INVALID_RESULT;
64 const uint64_t _created;
66 Item(T value, GLsync sync) :
67 _value(value), _sync(sync), _created(usecTimestampNow())
71 uint64_t age()
const {
72 return usecTimestampNow() - _created;
75 bool signaled()
const {
76 auto result = glClientWaitSync(_sync, 0, 0);
77 if (GL_TIMEOUT_EXPIRED != result && GL_WAIT_FAILED != result) {
84 using Mutex = std::mutex;
85 using Recycler = std::function<void(T t)>;
87 using Deque = std::deque<Item>;
88 using List = std::forward_list<Item>;
90 void setRecycler(Recycler recycler) {
96 using Lock = std::unique_lock<Mutex>;
101 template <
typename F>
103 using Lock = std::unique_lock<Mutex>;
105 Lock lock(_mutex, std::try_to_lock_t());
106 if (lock.owns_lock()) {
117 result = _submits.size();
127 size_t submit(T t, GLsync writeSync = 0) {
130 writeSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
135 _submits.push_back(Item(t, writeSync));
144 bool fetchSignaled(T& t) {
151 if (signaled(_submits, 0)) {
153 t = _submits.at(0)._value;
154 _submits.pop_front();
163 bool fetchWithFence(T& t, GLsync& sync) {
169 if (!_submits.empty()) {
172 auto item = _submits.back();
176 for (const auto& oldItem : _submits) {
177 _trash.push_front(oldItem);
188 bool fetchWithGpuWait(T& t) {
190 if (fetchWithFence(t, sync)) {
194 glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
206 bool fetchSignaledAndRelease(T& value) {
207 T originalValue = value;
208 if (fetchSignaled(value)) {
209 if (originalValue != invalid()) {
210 release(originalValue);
217 bool fetchAndReleaseWithFence(T& value, GLsync& sync) {
218 T originalValue = value;
219 if (fetchWithFence(value, sync)) {
220 if (originalValue != invalid()) {
221 release(originalValue);
228 bool fetchAndReleaseWithGpuWait(T& value) {
229 T originalValue = value;
230 if (fetchWithGpuWait(value)) {
231 if (originalValue != invalid()) {
232 release(originalValue);
241 void release(
const T& t, GLsync readSync = 0) {
244 readSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
249 _releases.push_back(Item(t, readSync));
254 size_t cleanTrash() {
255 size_t wastedWork{ 0 };
258 while (!_submits.empty()) {
259 const auto& item = _submits.front();
260 if (!item._sync || item.age() < MAX_UNSIGNALED_TIME) {
263 qWarning() <<
"Long unsignaled sync " << item._sync <<
" unsignaled for " << item.age();
264 _trash.push_front(item);
265 _submits.pop_front();
272 while (signaled(_submits, 1)) {
273 _trash.push_front(_submits.front());
274 _submits.pop_front();
279 while (signaled(_releases, 0)) {
280 _trash.push_front(_releases.front());
281 _releases.pop_front();
289 std::for_each(trash.begin(), trash.end(), [&](
typename List::const_reference item) {
291 _recycler(item._value);
294 glDeleteSync(item._sync);
301 bool signaled(Deque& deque,
size_t i) {
302 if (i >= deque.size()) {
306 auto& item = deque.at(i);
315 if (item.signaled()) {
317 _trash.push_front(Item(invalid(), item._sync));
337 inline const GLuint& GLEscrow<GLuint>::invalid()
const {
338 static const GLuint INVALID_RESULT { 0 };
339 return INVALID_RESULT;
342 using GLTextureEscrow = GLEscrow<GLuint>;