// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #include #include #include #include #include #include namespace anki { Bool Fence::clientWait(Second seconds) { if(static_cast(*this).m_signaled.load()) { return true; } class CheckFenceCommand final : public GlCommand { public: FencePtr m_fence; Second m_timeout; Second m_flushTime; Barrier* m_barrier; CheckFenceCommand(FencePtr fence, Second timeout, Second flushTime, Barrier* barrier) : m_fence(fence) , m_timeout(timeout) , m_flushTime(flushTime) , m_barrier(barrier) { } Error operator()(GlState&) { // Since there is a delay between flushing the cmdb and returning this result try to adjust the time we // wait Second timeToWait; if(m_timeout != 0.0) { timeToWait = m_timeout - (HighRezTimer::getCurrentTime() - m_flushTime); timeToWait = max(0.0, timeToWait); } else { timeToWait = 0.0; } FenceImpl& impl = static_cast(*m_fence); GLenum out = glClientWaitSync(impl.m_fence, GL_SYNC_FLUSH_COMMANDS_BIT, timeToWait * 1e+9); if(out == GL_ALREADY_SIGNALED || out == GL_CONDITION_SATISFIED) { impl.m_signaled.store(true); } else if(out == GL_TIMEOUT_EXPIRED) { // Do nothing } else { ANKI_ASSERT(out == GL_WAIT_FAILED); return Error::FUNCTION_FAILED; } if(m_barrier) { m_barrier->wait(); } return Error::NONE; } }; CommandBufferPtr cmdb = getManager().newCommandBuffer(CommandBufferInitInfo()); if(seconds == 0.0) { // Send a cmd that will update the fence's status in case someone calls clientWait with seconds==0.0 all the // time static_cast(*cmdb).pushBackNewCommand(FencePtr(this), seconds, 0.0, nullptr); static_cast(*cmdb).flush(); return false; } else { Barrier barrier(2); Second flushTime = HighRezTimer::getCurrentTime(); static_cast(*cmdb).pushBackNewCommand(FencePtr(this), seconds, flushTime, &barrier); static_cast(*cmdb).flush(); barrier.wait(); return static_cast(*this).m_signaled.load(); } } } // end namespace anki