tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Fence11.cpp (7147B)


      1 //
      2 // Copyright 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.
      5 //
      6 
      7 // Fence11.cpp: Defines the rx::FenceNV11 and rx::Sync11 classes which implement
      8 // rx::FenceNVImpl and rx::SyncImpl.
      9 
     10 #include "libANGLE/renderer/d3d/d3d11/Fence11.h"
     11 
     12 #include "common/utilities.h"
     13 #include "libANGLE/Context.h"
     14 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
     15 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
     16 
     17 namespace rx
     18 {
     19 
     20 //
     21 // Template helpers for set and test operations.
     22 //
     23 
     24 template <class FenceClass>
     25 angle::Result FenceSetHelper(const gl::Context *context, FenceClass *fence)
     26 {
     27    if (!fence->mQuery)
     28    {
     29        D3D11_QUERY_DESC queryDesc;
     30        queryDesc.Query     = D3D11_QUERY_EVENT;
     31        queryDesc.MiscFlags = 0;
     32 
     33        Context11 *context11 = GetImplAs<Context11>(context);
     34        HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery);
     35        ANGLE_TRY_HR(context11, result, "Failed to create event query");
     36    }
     37 
     38    fence->mRenderer->getDeviceContext()->End(fence->mQuery);
     39    return angle::Result::Continue;
     40 }
     41 
     42 template <class FenceClass>
     43 angle::Result FenceTestHelper(const gl::Context *context,
     44                              FenceClass *fence,
     45                              bool flushCommandBuffer,
     46                              GLboolean *outFinished)
     47 {
     48    ASSERT(fence->mQuery);
     49 
     50    UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH);
     51 
     52    Context11 *context11 = GetImplAs<Context11>(context);
     53    HRESULT result =
     54        fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, nullptr, 0, getDataFlags);
     55    ANGLE_TRY_HR(context11, result, "Failed to get query data");
     56 
     57    ASSERT(result == S_OK || result == S_FALSE);
     58    *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE);
     59    return angle::Result::Continue;
     60 }
     61 
     62 //
     63 // FenceNV11
     64 //
     65 
     66 FenceNV11::FenceNV11(Renderer11 *renderer) : FenceNVImpl(), mRenderer(renderer), mQuery(nullptr) {}
     67 
     68 FenceNV11::~FenceNV11()
     69 {
     70    SafeRelease(mQuery);
     71 }
     72 
     73 angle::Result FenceNV11::set(const gl::Context *context, GLenum condition)
     74 {
     75    return FenceSetHelper(context, this);
     76 }
     77 
     78 angle::Result FenceNV11::test(const gl::Context *context, GLboolean *outFinished)
     79 {
     80    return FenceTestHelper(context, this, true, outFinished);
     81 }
     82 
     83 angle::Result FenceNV11::finish(const gl::Context *context)
     84 {
     85    GLboolean finished = GL_FALSE;
     86 
     87    int loopCount = 0;
     88    while (finished != GL_TRUE)
     89    {
     90        loopCount++;
     91        ANGLE_TRY(FenceTestHelper(context, this, true, &finished));
     92 
     93        bool checkDeviceLost = (loopCount % kPollingD3DDeviceLostCheckFrequency) == 0;
     94        if (checkDeviceLost && mRenderer->testDeviceLost())
     95        {
     96            ANGLE_TRY_HR(GetImplAs<Context11>(context), DXGI_ERROR_DRIVER_INTERNAL_ERROR,
     97                         "Device was lost while querying result of an event query.");
     98        }
     99 
    100        ScheduleYield();
    101    }
    102 
    103    return angle::Result::Continue;
    104 }
    105 
    106 //
    107 // Sync11
    108 //
    109 
    110 // Important note on accurate timers in Windows:
    111 //
    112 // QueryPerformanceCounter has a few major issues, including being 10x as expensive to call
    113 // as timeGetTime on laptops and "jumping" during certain hardware events.
    114 //
    115 // See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc"
    116 //   https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc
    117 //
    118 // We still opt to use QPC. In the present and moving forward, most newer systems will not suffer
    119 // from buggy implementations.
    120 
    121 Sync11::Sync11(Renderer11 *renderer) : SyncImpl(), mRenderer(renderer), mQuery(nullptr)
    122 {
    123    LARGE_INTEGER counterFreqency = {};
    124    BOOL success                  = QueryPerformanceFrequency(&counterFreqency);
    125    ASSERT(success);
    126 
    127    mCounterFrequency = counterFreqency.QuadPart;
    128 }
    129 
    130 Sync11::~Sync11()
    131 {
    132    SafeRelease(mQuery);
    133 }
    134 
    135 angle::Result Sync11::set(const gl::Context *context, GLenum condition, GLbitfield flags)
    136 {
    137    ASSERT(condition == GL_SYNC_GPU_COMMANDS_COMPLETE && flags == 0);
    138    return FenceSetHelper(context, this);
    139 }
    140 
    141 angle::Result Sync11::clientWait(const gl::Context *context,
    142                                 GLbitfield flags,
    143                                 GLuint64 timeout,
    144                                 GLenum *outResult)
    145 {
    146    ASSERT(outResult);
    147 
    148    bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0);
    149 
    150    *outResult = GL_WAIT_FAILED;
    151 
    152    GLboolean result = GL_FALSE;
    153    ANGLE_TRY(FenceTestHelper(context, this, flushCommandBuffer, &result));
    154 
    155    if (result == GL_TRUE)
    156    {
    157        *outResult = GL_ALREADY_SIGNALED;
    158        return angle::Result::Continue;
    159    }
    160 
    161    if (timeout == 0)
    162    {
    163        *outResult = GL_TIMEOUT_EXPIRED;
    164        return angle::Result::Continue;
    165    }
    166 
    167    LARGE_INTEGER currentCounter = {};
    168    BOOL success                 = QueryPerformanceCounter(&currentCounter);
    169    ASSERT(success);
    170 
    171    LONGLONG timeoutInSeconds = static_cast<LONGLONG>(timeout / 1000000000ull);
    172    LONGLONG endCounter       = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds;
    173 
    174    // Extremely unlikely, but if mCounterFrequency is large enough, endCounter can wrap
    175    if (endCounter < currentCounter.QuadPart)
    176    {
    177        endCounter = MAXLONGLONG;
    178    }
    179 
    180    int loopCount = 0;
    181    while (currentCounter.QuadPart < endCounter && !result)
    182    {
    183        loopCount++;
    184        ScheduleYield();
    185        success = QueryPerformanceCounter(&currentCounter);
    186        ASSERT(success);
    187 
    188        *outResult = GL_WAIT_FAILED;
    189 
    190        ANGLE_TRY(FenceTestHelper(context, this, flushCommandBuffer, &result));
    191 
    192        bool checkDeviceLost = (loopCount % kPollingD3DDeviceLostCheckFrequency) == 0;
    193        if (checkDeviceLost && mRenderer->testDeviceLost())
    194        {
    195            *outResult = GL_WAIT_FAILED;
    196            ANGLE_TRY_HR(GetImplAs<Context11>(context), DXGI_ERROR_DRIVER_INTERNAL_ERROR,
    197                         "Device was lost while querying result of an event query.");
    198        }
    199    }
    200 
    201    if (currentCounter.QuadPart >= endCounter)
    202    {
    203        *outResult = GL_TIMEOUT_EXPIRED;
    204    }
    205    else
    206    {
    207        *outResult = GL_CONDITION_SATISFIED;
    208    }
    209 
    210    return angle::Result::Continue;
    211 }
    212 
    213 angle::Result Sync11::serverWait(const gl::Context *context, GLbitfield flags, GLuint64 timeout)
    214 {
    215    // Because our API is currently designed to be called from a single thread, we don't need to do
    216    // extra work for a server-side fence. GPU commands issued after the fence is created will
    217    // always be processed after the fence is signaled.
    218    return angle::Result::Continue;
    219 }
    220 
    221 angle::Result Sync11::getStatus(const gl::Context *context, GLint *outResult)
    222 {
    223    GLboolean result = GL_FALSE;
    224 
    225    // The spec does not specify any way to report errors during the status test (e.g. device
    226    // lost) so we report the fence is unblocked in case of error or signaled.
    227    *outResult = GL_SIGNALED;
    228    ANGLE_TRY(FenceTestHelper(context, this, false, &result));
    229 
    230    *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED);
    231    return angle::Result::Continue;
    232 }
    233 
    234 }  // namespace rx