2 // Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
7 // Fence11.cpp: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl.
9 #include "libGLESv2/renderer/d3d/d3d11/Fence11.h"
10 #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
11 #include "libGLESv2/main.h"
13 #include "common/utilities.h"
19 // Template helpers for set and test operations.
22 template<class FenceClass>
23 gl::Error FenceSetHelper(FenceClass *fence)
27 D3D11_QUERY_DESC queryDesc;
28 queryDesc.Query = D3D11_QUERY_EVENT;
29 queryDesc.MiscFlags = 0;
31 HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery);
34 return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result);
38 fence->mRenderer->getDeviceContext()->End(fence->mQuery);
39 return gl::Error(GL_NO_ERROR);
42 template <class FenceClass>
43 gl::Error FenceTestHelper(FenceClass *fence, bool flushCommandBuffer, GLboolean *outFinished)
45 ASSERT(fence->mQuery);
47 UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH);
48 HRESULT result = fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, NULL, 0, getDataFlags);
52 return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result);
54 else if (fence->mRenderer->isDeviceLost())
56 return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query.");
59 ASSERT(result == S_OK || result == S_FALSE);
60 *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE);
61 return gl::Error(GL_NO_ERROR);
68 FenceNV11::FenceNV11(Renderer11 *renderer)
75 FenceNV11::~FenceNV11()
80 gl::Error FenceNV11::set()
82 return FenceSetHelper(this);
85 gl::Error FenceNV11::test(bool flushCommandBuffer, GLboolean *outFinished)
87 return FenceTestHelper(this, flushCommandBuffer, outFinished);
90 gl::Error FenceNV11::finishFence(GLboolean *outFinished)
94 while (*outFinished != GL_TRUE)
96 gl::Error error = test(true, outFinished);
105 return gl::Error(GL_NO_ERROR);
112 // Important note on accurate timers in Windows:
114 // QueryPerformanceCounter has a few major issues, including being 10x as expensive to call
115 // as timeGetTime on laptops and "jumping" during certain hardware events.
117 // See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc"
118 // https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc
120 // We still opt to use QPC. In the present and moving forward, most newer systems will not suffer
121 // from buggy implementations.
123 FenceSync11::FenceSync11(Renderer11 *renderer)
128 LARGE_INTEGER counterFreqency = { 0 };
129 BOOL success = QueryPerformanceFrequency(&counterFreqency);
130 UNUSED_ASSERTION_VARIABLE(success);
133 mCounterFrequency = counterFreqency.QuadPart;
136 FenceSync11::~FenceSync11()
141 gl::Error FenceSync11::set()
143 return FenceSetHelper(this);
146 gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult)
150 bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0);
152 GLboolean result = GL_FALSE;
153 gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result);
156 *outResult = GL_WAIT_FAILED;
160 if (result == GL_TRUE)
162 *outResult = GL_ALREADY_SIGNALED;
163 return gl::Error(GL_NO_ERROR);
168 *outResult = GL_TIMEOUT_EXPIRED;
169 return gl::Error(GL_NO_ERROR);
172 LARGE_INTEGER currentCounter = { 0 };
173 BOOL success = QueryPerformanceCounter(¤tCounter);
174 UNUSED_ASSERTION_VARIABLE(success);
177 LONGLONG timeoutInSeconds = static_cast<LONGLONG>(timeout) * static_cast<LONGLONG>(1000000ll);
178 LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds;
180 while (currentCounter.QuadPart < endCounter && !result)
183 BOOL success = QueryPerformanceCounter(¤tCounter);
184 UNUSED_ASSERTION_VARIABLE(success);
187 error = FenceTestHelper(this, flushCommandBuffer, &result);
190 *outResult = GL_WAIT_FAILED;
195 if (currentCounter.QuadPart >= endCounter)
197 *outResult = GL_TIMEOUT_EXPIRED;
201 *outResult = GL_CONDITION_SATISFIED;
204 return gl::Error(GL_NO_ERROR);
207 gl::Error FenceSync11::serverWait(GLbitfield flags, GLuint64 timeout)
209 // Because our API is currently designed to be called from a single thread, we don't need to do
210 // extra work for a server-side fence. GPU commands issued after the fence is created will always
211 // be processed after the fence is signaled.
212 return gl::Error(GL_NO_ERROR);
215 gl::Error FenceSync11::getStatus(GLint *outResult)
217 GLboolean result = GL_FALSE;
218 gl::Error error = FenceTestHelper(this, false, &result);
221 // The spec does not specify any way to report errors during the status test (e.g. device lost)
222 // so we report the fence is unblocked in case of error or signaled.
223 *outResult = GL_SIGNALED;
228 *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED);
229 return gl::Error(GL_NO_ERROR);