tor-browser

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

Query11.cpp (11942B)


      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 // Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl.
      8 
      9 #include "libANGLE/renderer/d3d/d3d11/Query11.h"
     10 
     11 #include <GLES2/gl2ext.h>
     12 
     13 #include "common/utilities.h"
     14 #include "libANGLE/Context.h"
     15 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
     16 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
     17 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
     18 
     19 namespace
     20 {
     21 
     22 GLuint64 MergeQueryResults(gl::QueryType type, GLuint64 currentResult, GLuint64 newResult)
     23 {
     24    switch (type)
     25    {
     26        case gl::QueryType::AnySamples:
     27        case gl::QueryType::AnySamplesConservative:
     28            return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE;
     29 
     30        case gl::QueryType::TransformFeedbackPrimitivesWritten:
     31            return currentResult + newResult;
     32 
     33        case gl::QueryType::TimeElapsed:
     34            return currentResult + newResult;
     35 
     36        case gl::QueryType::Timestamp:
     37            return newResult;
     38 
     39        case gl::QueryType::CommandsCompleted:
     40            return newResult;
     41 
     42        default:
     43            UNREACHABLE();
     44            return 0;
     45    }
     46 }
     47 
     48 }  // anonymous namespace
     49 
     50 namespace rx
     51 {
     52 
     53 Query11::QueryState::QueryState()
     54    : getDataAttemptCount(0), query(), beginTimestamp(), endTimestamp(), finished(false)
     55 {}
     56 
     57 Query11::QueryState::~QueryState() {}
     58 
     59 Query11::Query11(Renderer11 *renderer, gl::QueryType type)
     60    : QueryImpl(type), mResult(0), mResultSum(0), mRenderer(renderer)
     61 {
     62    mActiveQuery = std::unique_ptr<QueryState>(new QueryState());
     63 }
     64 
     65 Query11::~Query11()
     66 {
     67    mRenderer->getStateManager()->onDeleteQueryObject(this);
     68 }
     69 
     70 angle::Result Query11::begin(const gl::Context *context)
     71 {
     72    mResultSum = 0;
     73    mRenderer->getStateManager()->onBeginQuery(this);
     74    return resume(GetImplAs<Context11>(context));
     75 }
     76 
     77 angle::Result Query11::end(const gl::Context *context)
     78 {
     79    return pause(GetImplAs<Context11>(context));
     80 }
     81 
     82 angle::Result Query11::queryCounter(const gl::Context *context)
     83 {
     84    // This doesn't do anything for D3D11 as we don't support timestamps
     85    ASSERT(getType() == gl::QueryType::Timestamp);
     86    mResultSum = 0;
     87    mPendingQueries.push_back(std::unique_ptr<QueryState>(new QueryState()));
     88    return angle::Result::Continue;
     89 }
     90 
     91 template <typename T>
     92 angle::Result Query11::getResultBase(Context11 *context11, T *params)
     93 {
     94    ASSERT(!mActiveQuery->query.valid());
     95    ANGLE_TRY(flush(context11, true));
     96    ASSERT(mPendingQueries.empty());
     97    *params = static_cast<T>(mResultSum);
     98 
     99    return angle::Result::Continue;
    100 }
    101 
    102 angle::Result Query11::getResult(const gl::Context *context, GLint *params)
    103 {
    104    return getResultBase(GetImplAs<Context11>(context), params);
    105 }
    106 
    107 angle::Result Query11::getResult(const gl::Context *context, GLuint *params)
    108 {
    109    return getResultBase(GetImplAs<Context11>(context), params);
    110 }
    111 
    112 angle::Result Query11::getResult(const gl::Context *context, GLint64 *params)
    113 {
    114    return getResultBase(GetImplAs<Context11>(context), params);
    115 }
    116 
    117 angle::Result Query11::getResult(const gl::Context *context, GLuint64 *params)
    118 {
    119    return getResultBase(GetImplAs<Context11>(context), params);
    120 }
    121 
    122 angle::Result Query11::isResultAvailable(const gl::Context *context, bool *available)
    123 {
    124    ANGLE_TRY(flush(GetImplAs<Context11>(context), false));
    125 
    126    *available = mPendingQueries.empty();
    127    return angle::Result::Continue;
    128 }
    129 
    130 angle::Result Query11::pause(Context11 *context11)
    131 {
    132    if (mActiveQuery->query.valid())
    133    {
    134        ID3D11DeviceContext *context = mRenderer->getDeviceContext();
    135        gl::QueryType type           = getType();
    136 
    137        // If we are doing time elapsed query the end timestamp
    138        if (type == gl::QueryType::TimeElapsed)
    139        {
    140            context->End(mActiveQuery->endTimestamp.get());
    141        }
    142 
    143        context->End(mActiveQuery->query.get());
    144 
    145        mPendingQueries.push_back(std::move(mActiveQuery));
    146        mActiveQuery = std::unique_ptr<QueryState>(new QueryState());
    147    }
    148 
    149    return flush(context11, false);
    150 }
    151 
    152 angle::Result Query11::resume(Context11 *context11)
    153 {
    154    if (!mActiveQuery->query.valid())
    155    {
    156        ANGLE_TRY(flush(context11, false));
    157 
    158        gl::QueryType type       = getType();
    159        D3D11_QUERY d3dQueryType = gl_d3d11::ConvertQueryType(type);
    160 
    161        D3D11_QUERY_DESC queryDesc;
    162        queryDesc.Query     = d3dQueryType;
    163        queryDesc.MiscFlags = 0;
    164 
    165        ANGLE_TRY(mRenderer->allocateResource(context11, queryDesc, &mActiveQuery->query));
    166 
    167        // If we are doing time elapsed we also need a query to actually query the timestamp
    168        if (type == gl::QueryType::TimeElapsed)
    169        {
    170            D3D11_QUERY_DESC desc;
    171            desc.Query     = D3D11_QUERY_TIMESTAMP;
    172            desc.MiscFlags = 0;
    173 
    174            ANGLE_TRY(mRenderer->allocateResource(context11, desc, &mActiveQuery->beginTimestamp));
    175            ANGLE_TRY(mRenderer->allocateResource(context11, desc, &mActiveQuery->endTimestamp));
    176        }
    177 
    178        ID3D11DeviceContext *context = mRenderer->getDeviceContext();
    179 
    180        if (d3dQueryType != D3D11_QUERY_EVENT)
    181        {
    182            context->Begin(mActiveQuery->query.get());
    183        }
    184 
    185        // If we are doing time elapsed, query the begin timestamp
    186        if (type == gl::QueryType::TimeElapsed)
    187        {
    188            context->End(mActiveQuery->beginTimestamp.get());
    189        }
    190    }
    191 
    192    return angle::Result::Continue;
    193 }
    194 
    195 angle::Result Query11::flush(Context11 *context11, bool force)
    196 {
    197    while (!mPendingQueries.empty())
    198    {
    199        QueryState *query = mPendingQueries.front().get();
    200 
    201        do
    202        {
    203            ANGLE_TRY(testQuery(context11, query));
    204            if (!query->finished && !force)
    205            {
    206                return angle::Result::Continue;
    207            }
    208        } while (!query->finished);
    209 
    210        mResultSum = MergeQueryResults(getType(), mResultSum, mResult);
    211        mPendingQueries.pop_front();
    212    }
    213 
    214    return angle::Result::Continue;
    215 }
    216 
    217 angle::Result Query11::testQuery(Context11 *context11, QueryState *queryState)
    218 {
    219    if (!queryState->finished)
    220    {
    221        ID3D11DeviceContext *context = mRenderer->getDeviceContext();
    222        switch (getType())
    223        {
    224            case gl::QueryType::AnySamples:
    225            case gl::QueryType::AnySamplesConservative:
    226            {
    227                ASSERT(queryState->query.valid());
    228                UINT64 numPixels = 0;
    229                HRESULT result =
    230                    context->GetData(queryState->query.get(), &numPixels, sizeof(numPixels), 0);
    231                ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query");
    232 
    233                if (result == S_OK)
    234                {
    235                    queryState->finished = true;
    236                    mResult              = (numPixels > 0) ? GL_TRUE : GL_FALSE;
    237                }
    238            }
    239            break;
    240 
    241            case gl::QueryType::TransformFeedbackPrimitivesWritten:
    242            {
    243                ASSERT(queryState->query.valid());
    244                D3D11_QUERY_DATA_SO_STATISTICS soStats = {};
    245                HRESULT result =
    246                    context->GetData(queryState->query.get(), &soStats, sizeof(soStats), 0);
    247                ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query");
    248 
    249                if (result == S_OK)
    250                {
    251                    queryState->finished = true;
    252                    mResult              = static_cast<GLuint64>(soStats.NumPrimitivesWritten);
    253                }
    254            }
    255            break;
    256 
    257            case gl::QueryType::TimeElapsed:
    258            {
    259                ASSERT(queryState->query.valid());
    260                ASSERT(queryState->beginTimestamp.valid());
    261                ASSERT(queryState->endTimestamp.valid());
    262                D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {};
    263                HRESULT result =
    264                    context->GetData(queryState->query.get(), &timeStats, sizeof(timeStats), 0);
    265                ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query");
    266 
    267                if (result == S_OK)
    268                {
    269                    UINT64 beginTime = 0;
    270                    HRESULT beginRes = context->GetData(queryState->beginTimestamp.get(),
    271                                                        &beginTime, sizeof(UINT64), 0);
    272                    ANGLE_TRY_HR(context11, beginRes,
    273                                 "Failed to get the data of an internal query");
    274 
    275                    UINT64 endTime = 0;
    276                    HRESULT endRes = context->GetData(queryState->endTimestamp.get(), &endTime,
    277                                                      sizeof(UINT64), 0);
    278                    ANGLE_TRY_HR(context11, endRes, "Failed to get the data of an internal query");
    279 
    280                    if (beginRes == S_OK && endRes == S_OK)
    281                    {
    282                        queryState->finished = true;
    283                        if (timeStats.Disjoint)
    284                        {
    285                            mRenderer->setGPUDisjoint();
    286                        }
    287                        static_assert(sizeof(UINT64) == sizeof(unsigned long long),
    288                                      "D3D UINT64 isn't 64 bits");
    289 
    290                        angle::CheckedNumeric<UINT64> checkedTime(endTime);
    291                        checkedTime -= beginTime;
    292                        checkedTime *= 1000000000ull;
    293                        checkedTime /= timeStats.Frequency;
    294                        if (checkedTime.IsValid())
    295                        {
    296                            mResult = checkedTime.ValueOrDie();
    297                        }
    298                        else
    299                        {
    300                            mResult = std::numeric_limits<GLuint64>::max() / timeStats.Frequency;
    301                            // If an overflow does somehow occur, there is no way the elapsed time
    302                            // is accurate, so we generate a disjoint event
    303                            mRenderer->setGPUDisjoint();
    304                        }
    305                    }
    306                }
    307            }
    308            break;
    309 
    310            case gl::QueryType::Timestamp:
    311            {
    312                // D3D11 doesn't support GL timestamp queries as D3D timestamps are not guaranteed
    313                // to have any sort of continuity outside of a disjoint timestamp query block, which
    314                // GL depends on
    315                ASSERT(!queryState->query.valid());
    316                mResult              = 0;
    317                queryState->finished = true;
    318            }
    319            break;
    320 
    321            case gl::QueryType::CommandsCompleted:
    322            {
    323                ASSERT(queryState->query.valid());
    324                BOOL completed = 0;
    325                HRESULT result =
    326                    context->GetData(queryState->query.get(), &completed, sizeof(completed), 0);
    327                ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query");
    328 
    329                if (result == S_OK)
    330                {
    331                    queryState->finished = true;
    332                    ASSERT(completed == TRUE);
    333                    mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE;
    334                }
    335            }
    336            break;
    337 
    338            default:
    339                UNREACHABLE();
    340                break;
    341        }
    342 
    343        queryState->getDataAttemptCount++;
    344        bool checkDeviceLost =
    345            (queryState->getDataAttemptCount % kPollingD3DDeviceLostCheckFrequency) == 0;
    346        if (!queryState->finished && checkDeviceLost && mRenderer->testDeviceLost())
    347        {
    348            mRenderer->notifyDeviceLost();
    349            ANGLE_TRY_HR(context11, E_OUTOFMEMORY,
    350                         "Failed to test get query result, device is lost.");
    351        }
    352    }
    353 
    354    return angle::Result::Continue;
    355 }
    356 
    357 }  // namespace rx