diff options
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/Fence.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libGLESv2/Fence.cpp | 168 |
1 files changed, 155 insertions, 13 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.cpp b/src/3rdparty/angle/src/libGLESv2/Fence.cpp index e4218bbeec..ee9a07a5c4 100644 --- a/src/3rdparty/angle/src/libGLESv2/Fence.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Fence.cpp @@ -1,4 +1,3 @@ -#include "precompiled.h" // // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -7,46 +6,189 @@ // Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension. +// Important note on accurate timers in Windows: +// +// QueryPerformanceCounter has a few major issues, including being 10x as expensive to call +// as timeGetTime on laptops and "jumping" during certain hardware events. +// +// See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc" +// https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc +// +// We still opt to use QPC. In the present and moving forward, most newer systems will not suffer +// from buggy implementations. + #include "libGLESv2/Fence.h" #include "libGLESv2/renderer/FenceImpl.h" #include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/main.h" + +#include "angle_gl.h" namespace gl { -Fence::Fence(rx::Renderer *renderer) +FenceNV::FenceNV(rx::Renderer *renderer) { mFence = renderer->createFence(); } -Fence::~Fence() +FenceNV::~FenceNV() { delete mFence; } -GLboolean Fence::isFence() +GLboolean FenceNV::isFence() const { - return mFence->isFence(); + // GL_NV_fence spec: + // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. + return (mFence->isSet() ? GL_TRUE : GL_FALSE); } -void Fence::setFence(GLenum condition) +void FenceNV::setFence(GLenum condition) { - mFence->setFence(condition); + mFence->set(); + + mCondition = condition; + mStatus = GL_FALSE; } -GLboolean Fence::testFence() +GLboolean FenceNV::testFence() { - return mFence->testFence(); + // Flush the command buffer by default + bool result = mFence->test(true); + + mStatus = (result ? GL_TRUE : GL_FALSE); + return mStatus; } -void Fence::finishFence() +void FenceNV::finishFence() { - mFence->finishFence(); + ASSERT(mFence->isSet()); + + while (!mFence->test(true)) + { + Sleep(0); + } } -void Fence::getFenceiv(GLenum pname, GLint *params) +GLint FenceNV::getFencei(GLenum pname) { - mFence->getFenceiv(pname, params); + ASSERT(mFence->isSet()); + + switch (pname) + { + case GL_FENCE_STATUS_NV: + { + // GL_NV_fence spec: + // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV + // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. + if (mStatus == GL_TRUE) + { + return GL_TRUE; + } + + mStatus = (mFence->test(false) ? GL_TRUE : GL_FALSE); + return mStatus; + } + + case GL_FENCE_CONDITION_NV: + return mCondition; + + default: UNREACHABLE(); return 0; + } +} + +FenceSync::FenceSync(rx::Renderer *renderer, GLuint id) + : RefCountObject(id) +{ + mFence = renderer->createFence(); + + LARGE_INTEGER counterFreqency = { 0 }; + BOOL success = QueryPerformanceFrequency(&counterFreqency); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + mCounterFrequency = counterFreqency.QuadPart; +} + +FenceSync::~FenceSync() +{ + delete mFence; +} + +void FenceSync::set(GLenum condition) +{ + mCondition = condition; + mFence->set(); +} + +GLenum FenceSync::clientWait(GLbitfield flags, GLuint64 timeout) +{ + ASSERT(mFence->isSet()); + + bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); + + if (mFence->test(flushCommandBuffer)) + { + return GL_ALREADY_SIGNALED; + } + + if (mFence->hasError()) + { + return GL_WAIT_FAILED; + } + + if (timeout == 0) + { + return GL_TIMEOUT_EXPIRED; + } + + LARGE_INTEGER currentCounter = { 0 }; + BOOL success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + LONGLONG timeoutInSeconds = static_cast<LONGLONG>(timeout) * static_cast<LONGLONG>(1000000ll); + LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + + while (currentCounter.QuadPart < endCounter && !mFence->test(flushCommandBuffer)) + { + Sleep(0); + BOOL success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + } + + if (mFence->hasError()) + { + return GL_WAIT_FAILED; + } + + if (currentCounter.QuadPart >= endCounter) + { + return GL_TIMEOUT_EXPIRED; + } + + return GL_CONDITION_SATISFIED; +} + +void FenceSync::serverWait() +{ + // Because our API is currently designed to be called from a single thread, we don't need to do + // extra work for a server-side fence. GPU commands issued after the fence is created will always + // be processed after the fence is signaled. +} + +GLenum FenceSync::getStatus() const +{ + if (mFence->test(false)) + { + // The spec does not specify any way to report errors during the status test (e.g. device lost) + // so we report the fence is unblocked in case of error or signaled. + return GL_SIGNALED; + } + + return GL_UNSIGNALED; } } |