diff options
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp | 214 |
1 files changed, 188 insertions, 26 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp index a841b52862..f44d934056 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp @@ -4,67 +4,229 @@ // found in the LICENSE file. // -// Fence11.cpp: Defines the rx::Fence11 class which implements rx::FenceImpl. +// Fence11.cpp: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. #include "libGLESv2/renderer/d3d/d3d11/Fence11.h" #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/main.h" +#include "common/utilities.h" + namespace rx { -Fence11::Fence11(rx::Renderer11 *renderer) +// +// Template helpers for set and test operations. +// + +template<class FenceClass> +gl::Error FenceSetHelper(FenceClass *fence) { - mRenderer = renderer; - mQuery = NULL; + if (!fence->mQuery) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); + } + } + + fence->mRenderer->getDeviceContext()->End(fence->mQuery); + return gl::Error(GL_NO_ERROR); } -Fence11::~Fence11() +template <class FenceClass> +gl::Error FenceTestHelper(FenceClass *fence, bool flushCommandBuffer, GLboolean *outFinished) +{ + ASSERT(fence->mQuery); + + UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); + HRESULT result = fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, NULL, 0, getDataFlags); + + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); + } + else if (fence->mRenderer->isDeviceLost()) + { + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); + } + + ASSERT(result == S_OK || result == S_FALSE); + *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); + return gl::Error(GL_NO_ERROR); +} + +// +// FenceNV11 +// + +FenceNV11::FenceNV11(Renderer11 *renderer) + : FenceNVImpl(), + mRenderer(renderer), + mQuery(NULL) +{ +} + +FenceNV11::~FenceNV11() { SafeRelease(mQuery); } -bool Fence11::isSet() const +gl::Error FenceNV11::set() { - return mQuery != NULL; + return FenceSetHelper(this); } -void Fence11::set() +gl::Error FenceNV11::test(bool flushCommandBuffer, GLboolean *outFinished) { - if (!mQuery) - { - D3D11_QUERY_DESC queryDesc; - queryDesc.Query = D3D11_QUERY_EVENT; - queryDesc.MiscFlags = 0; + return FenceTestHelper(this, flushCommandBuffer, outFinished); +} + +gl::Error FenceNV11::finishFence(GLboolean *outFinished) +{ + ASSERT(outFinished); - if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery))) + while (*outFinished != GL_TRUE) + { + gl::Error error = test(true, outFinished); + if (error.isError()) { - return gl::error(GL_OUT_OF_MEMORY); + return error; } + + Sleep(0); } - mRenderer->getDeviceContext()->End(mQuery); + return gl::Error(GL_NO_ERROR); } -bool Fence11::test(bool flushCommandBuffer) +// +// FenceSync11 +// + +// 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. + +FenceSync11::FenceSync11(Renderer11 *renderer) + : FenceSyncImpl(), + mRenderer(renderer), + mQuery(NULL) { - ASSERT(mQuery); + LARGE_INTEGER counterFreqency = { 0 }; + BOOL success = QueryPerformanceFrequency(&counterFreqency); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); - UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); - HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, NULL, 0, getDataFlags); + mCounterFrequency = counterFreqency.QuadPart; +} - if (mRenderer->isDeviceLost()) +FenceSync11::~FenceSync11() +{ + SafeRelease(mQuery); +} + +gl::Error FenceSync11::set() +{ + return FenceSetHelper(this); +} + +gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +{ + ASSERT(outResult); + + bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); + + GLboolean result = GL_FALSE; + gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result); + if (error.isError()) { - return gl::error(GL_OUT_OF_MEMORY, true); + *outResult = GL_WAIT_FAILED; + return error; } - ASSERT(result == S_OK || result == S_FALSE); - return (result == S_OK); + if (result == GL_TRUE) + { + *outResult = GL_ALREADY_SIGNALED; + return gl::Error(GL_NO_ERROR); + } + + if (timeout == 0) + { + *outResult = GL_TIMEOUT_EXPIRED; + return gl::Error(GL_NO_ERROR); + } + + 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 && !result) + { + Sleep(0); + BOOL success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + error = FenceTestHelper(this, flushCommandBuffer, &result); + if (error.isError()) + { + *outResult = GL_WAIT_FAILED; + return error; + } + } + + if (currentCounter.QuadPart >= endCounter) + { + *outResult = GL_TIMEOUT_EXPIRED; + } + else + { + *outResult = GL_CONDITION_SATISFIED; + } + + return gl::Error(GL_NO_ERROR); } -bool Fence11::hasError() const +gl::Error FenceSync11::serverWait(GLbitfield flags, GLuint64 timeout) { - return mRenderer->isDeviceLost(); + // 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. + return gl::Error(GL_NO_ERROR); } +gl::Error FenceSync11::getStatus(GLint *outResult) +{ + GLboolean result = GL_FALSE; + gl::Error error = FenceTestHelper(this, false, &result); + if (error.isError()) + { + // 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. + *outResult = GL_SIGNALED; + + return error; + } + + *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED); + return gl::Error(GL_NO_ERROR); } + +} // namespace rx |