diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp new file mode 100644 index 0000000000..38a7331b00 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/Fence11.cpp @@ -0,0 +1,234 @@ +// +// Copyright 2013 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Fence11.cpp: Defines the rx::FenceNV11 and rx::Sync11 classes which implement +// rx::FenceNVImpl and rx::SyncImpl. + +#include "libANGLE/renderer/d3d/d3d11/Fence11.h" + +#include "common/utilities.h" +#include "libANGLE/Context.h" +#include "libANGLE/renderer/d3d/d3d11/Context11.h" +#include "libANGLE/renderer/d3d/d3d11/Renderer11.h" + +namespace rx +{ + +// +// Template helpers for set and test operations. +// + +template <class FenceClass> +angle::Result FenceSetHelper(const gl::Context *context, FenceClass *fence) +{ + if (!fence->mQuery) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + Context11 *context11 = GetImplAs<Context11>(context); + HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery); + ANGLE_TRY_HR(context11, result, "Failed to create event query"); + } + + fence->mRenderer->getDeviceContext()->End(fence->mQuery); + return angle::Result::Continue; +} + +template <class FenceClass> +angle::Result FenceTestHelper(const gl::Context *context, + FenceClass *fence, + bool flushCommandBuffer, + GLboolean *outFinished) +{ + ASSERT(fence->mQuery); + + UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); + + Context11 *context11 = GetImplAs<Context11>(context); + HRESULT result = + fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, nullptr, 0, getDataFlags); + ANGLE_TRY_HR(context11, result, "Failed to get query data"); + + ASSERT(result == S_OK || result == S_FALSE); + *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); + return angle::Result::Continue; +} + +// +// FenceNV11 +// + +FenceNV11::FenceNV11(Renderer11 *renderer) : FenceNVImpl(), mRenderer(renderer), mQuery(nullptr) {} + +FenceNV11::~FenceNV11() +{ + SafeRelease(mQuery); +} + +angle::Result FenceNV11::set(const gl::Context *context, GLenum condition) +{ + return FenceSetHelper(context, this); +} + +angle::Result FenceNV11::test(const gl::Context *context, GLboolean *outFinished) +{ + return FenceTestHelper(context, this, true, outFinished); +} + +angle::Result FenceNV11::finish(const gl::Context *context) +{ + GLboolean finished = GL_FALSE; + + int loopCount = 0; + while (finished != GL_TRUE) + { + loopCount++; + ANGLE_TRY(FenceTestHelper(context, this, true, &finished)); + + bool checkDeviceLost = (loopCount % kPollingD3DDeviceLostCheckFrequency) == 0; + if (checkDeviceLost && mRenderer->testDeviceLost()) + { + ANGLE_TRY_HR(GetImplAs<Context11>(context), DXGI_ERROR_DRIVER_INTERNAL_ERROR, + "Device was lost while querying result of an event query."); + } + + ScheduleYield(); + } + + return angle::Result::Continue; +} + +// +// Sync11 +// + +// 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. + +Sync11::Sync11(Renderer11 *renderer) : SyncImpl(), mRenderer(renderer), mQuery(nullptr) +{ + LARGE_INTEGER counterFreqency = {}; + BOOL success = QueryPerformanceFrequency(&counterFreqency); + ASSERT(success); + + mCounterFrequency = counterFreqency.QuadPart; +} + +Sync11::~Sync11() +{ + SafeRelease(mQuery); +} + +angle::Result Sync11::set(const gl::Context *context, GLenum condition, GLbitfield flags) +{ + ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE && flags == 0); + return FenceSetHelper(context, this); +} + +angle::Result Sync11::clientWait(const gl::Context *context, + GLbitfield flags, + GLuint64 timeout, + GLenum *outResult) +{ + ASSERT(outResult); + + bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); + + *outResult = GL_WAIT_FAILED; + + GLboolean result = GL_FALSE; + ANGLE_TRY(FenceTestHelper(context, this, flushCommandBuffer, &result)); + + if (result == GL_TRUE) + { + *outResult = GL_ALREADY_SIGNALED; + return angle::Result::Continue; + } + + if (timeout == 0) + { + *outResult = GL_TIMEOUT_EXPIRED; + return angle::Result::Continue; + } + + LARGE_INTEGER currentCounter = {}; + BOOL success = QueryPerformanceCounter(¤tCounter); + ASSERT(success); + + LONGLONG timeoutInSeconds = static_cast<LONGLONG>(timeout / 1000000000ull); + LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + + // Extremely unlikely, but if mCounterFrequency is large enough, endCounter can wrap + if (endCounter < currentCounter.QuadPart) + { + endCounter = MAXLONGLONG; + } + + int loopCount = 0; + while (currentCounter.QuadPart < endCounter && !result) + { + loopCount++; + ScheduleYield(); + success = QueryPerformanceCounter(¤tCounter); + ASSERT(success); + + *outResult = GL_WAIT_FAILED; + + ANGLE_TRY(FenceTestHelper(context, this, flushCommandBuffer, &result)); + + bool checkDeviceLost = (loopCount % kPollingD3DDeviceLostCheckFrequency) == 0; + if (checkDeviceLost && mRenderer->testDeviceLost()) + { + *outResult = GL_WAIT_FAILED; + ANGLE_TRY_HR(GetImplAs<Context11>(context), DXGI_ERROR_DRIVER_INTERNAL_ERROR, + "Device was lost while querying result of an event query."); + } + } + + if (currentCounter.QuadPart >= endCounter) + { + *outResult = GL_TIMEOUT_EXPIRED; + } + else + { + *outResult = GL_CONDITION_SATISFIED; + } + + return angle::Result::Continue; +} + +angle::Result Sync11::serverWait(const gl::Context *context, GLbitfield flags, GLuint64 timeout) +{ + // 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 angle::Result::Continue; +} + +angle::Result Sync11::getStatus(const gl::Context *context, GLint *outResult) +{ + GLboolean result = GL_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. + *outResult = GL_SIGNALED; + ANGLE_TRY(FenceTestHelper(context, this, false, &result)); + + *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED); + return angle::Result::Continue; +} + +} // namespace rx |