Edit

kc3-lang/angle/src/libANGLE/renderer/d3d/d3d11/Query11.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2019-10-24 12:55:09
    Hash : a6206854
    Message : Enable "-Wmissing-field-initializers". This is another warning required by Skia. This one didn't find anything that surprising. Enabling the warning does help enforce code consistency and avoids a bit of possible undefined behaviour. Bug: angleproject:4046 Change-Id: Ifec7f4afad49cd820bf3c0a79df3f46559473ee2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1877477 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/renderer/d3d/d3d11/Query11.cpp
  • //
    // 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.
    //
    
    // Query11.cpp: Defines the rx::Query11 class which implements rx::QueryImpl.
    
    #include "libANGLE/renderer/d3d/d3d11/Query11.h"
    
    #include <GLES2/gl2ext.h>
    
    #include "common/utilities.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/renderer/d3d/d3d11/Context11.h"
    #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
    #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
    
    namespace
    {
    
    GLuint64 MergeQueryResults(gl::QueryType type, GLuint64 currentResult, GLuint64 newResult)
    {
        switch (type)
        {
            case gl::QueryType::AnySamples:
            case gl::QueryType::AnySamplesConservative:
                return (currentResult == GL_TRUE || newResult == GL_TRUE) ? GL_TRUE : GL_FALSE;
    
            case gl::QueryType::TransformFeedbackPrimitivesWritten:
                return currentResult + newResult;
    
            case gl::QueryType::TimeElapsed:
                return currentResult + newResult;
    
            case gl::QueryType::Timestamp:
                return newResult;
    
            case gl::QueryType::CommandsCompleted:
                return newResult;
    
            default:
                UNREACHABLE();
                return 0;
        }
    }
    
    }  // anonymous namespace
    
    namespace rx
    {
    
    Query11::QueryState::QueryState()
        : getDataAttemptCount(0), query(), beginTimestamp(), endTimestamp(), finished(false)
    {}
    
    Query11::QueryState::~QueryState() {}
    
    Query11::Query11(Renderer11 *renderer, gl::QueryType type)
        : QueryImpl(type), mResult(0), mResultSum(0), mRenderer(renderer)
    {
        mActiveQuery = std::unique_ptr<QueryState>(new QueryState());
    }
    
    Query11::~Query11()
    {
        mRenderer->getStateManager()->onDeleteQueryObject(this);
    }
    
    angle::Result Query11::begin(const gl::Context *context)
    {
        mResultSum = 0;
        mRenderer->getStateManager()->onBeginQuery(this);
        return resume(GetImplAs<Context11>(context));
    }
    
    angle::Result Query11::end(const gl::Context *context)
    {
        return pause(GetImplAs<Context11>(context));
    }
    
    angle::Result Query11::queryCounter(const gl::Context *context)
    {
        // This doesn't do anything for D3D11 as we don't support timestamps
        ASSERT(getType() == gl::QueryType::Timestamp);
        mResultSum = 0;
        mPendingQueries.push_back(std::unique_ptr<QueryState>(new QueryState()));
        return angle::Result::Continue;
    }
    
    template <typename T>
    angle::Result Query11::getResultBase(Context11 *context11, T *params)
    {
        ASSERT(!mActiveQuery->query.valid());
        ANGLE_TRY(flush(context11, true));
        ASSERT(mPendingQueries.empty());
        *params = static_cast<T>(mResultSum);
    
        return angle::Result::Continue;
    }
    
    angle::Result Query11::getResult(const gl::Context *context, GLint *params)
    {
        return getResultBase(GetImplAs<Context11>(context), params);
    }
    
    angle::Result Query11::getResult(const gl::Context *context, GLuint *params)
    {
        return getResultBase(GetImplAs<Context11>(context), params);
    }
    
    angle::Result Query11::getResult(const gl::Context *context, GLint64 *params)
    {
        return getResultBase(GetImplAs<Context11>(context), params);
    }
    
    angle::Result Query11::getResult(const gl::Context *context, GLuint64 *params)
    {
        return getResultBase(GetImplAs<Context11>(context), params);
    }
    
    angle::Result Query11::isResultAvailable(const gl::Context *context, bool *available)
    {
        ANGLE_TRY(flush(GetImplAs<Context11>(context), false));
    
        *available = mPendingQueries.empty();
        return angle::Result::Continue;
    }
    
    angle::Result Query11::pause(Context11 *context11)
    {
        if (mActiveQuery->query.valid())
        {
            ID3D11DeviceContext *context = mRenderer->getDeviceContext();
            gl::QueryType type           = getType();
    
            // If we are doing time elapsed query the end timestamp
            if (type == gl::QueryType::TimeElapsed)
            {
                context->End(mActiveQuery->endTimestamp.get());
            }
    
            context->End(mActiveQuery->query.get());
    
            mPendingQueries.push_back(std::move(mActiveQuery));
            mActiveQuery = std::unique_ptr<QueryState>(new QueryState());
        }
    
        return flush(context11, false);
    }
    
    angle::Result Query11::resume(Context11 *context11)
    {
        if (!mActiveQuery->query.valid())
        {
            ANGLE_TRY(flush(context11, false));
    
            gl::QueryType type       = getType();
            D3D11_QUERY d3dQueryType = gl_d3d11::ConvertQueryType(type);
    
            D3D11_QUERY_DESC queryDesc;
            queryDesc.Query     = d3dQueryType;
            queryDesc.MiscFlags = 0;
    
            ANGLE_TRY(mRenderer->allocateResource(context11, queryDesc, &mActiveQuery->query));
    
            // If we are doing time elapsed we also need a query to actually query the timestamp
            if (type == gl::QueryType::TimeElapsed)
            {
                D3D11_QUERY_DESC desc;
                desc.Query     = D3D11_QUERY_TIMESTAMP;
                desc.MiscFlags = 0;
    
                ANGLE_TRY(mRenderer->allocateResource(context11, desc, &mActiveQuery->beginTimestamp));
                ANGLE_TRY(mRenderer->allocateResource(context11, desc, &mActiveQuery->endTimestamp));
            }
    
            ID3D11DeviceContext *context = mRenderer->getDeviceContext();
    
            if (d3dQueryType != D3D11_QUERY_EVENT)
            {
                context->Begin(mActiveQuery->query.get());
            }
    
            // If we are doing time elapsed, query the begin timestamp
            if (type == gl::QueryType::TimeElapsed)
            {
                context->End(mActiveQuery->beginTimestamp.get());
            }
        }
    
        return angle::Result::Continue;
    }
    
    angle::Result Query11::flush(Context11 *context11, bool force)
    {
        while (!mPendingQueries.empty())
        {
            QueryState *query = mPendingQueries.front().get();
    
            do
            {
                ANGLE_TRY(testQuery(context11, query));
                if (!query->finished && !force)
                {
                    return angle::Result::Continue;
                }
            } while (!query->finished);
    
            mResultSum = MergeQueryResults(getType(), mResultSum, mResult);
            mPendingQueries.pop_front();
        }
    
        return angle::Result::Continue;
    }
    
    angle::Result Query11::testQuery(Context11 *context11, QueryState *queryState)
    {
        if (!queryState->finished)
        {
            ID3D11DeviceContext *context = mRenderer->getDeviceContext();
            switch (getType())
            {
                case gl::QueryType::AnySamples:
                case gl::QueryType::AnySamplesConservative:
                {
                    ASSERT(queryState->query.valid());
                    UINT64 numPixels = 0;
                    HRESULT result =
                        context->GetData(queryState->query.get(), &numPixels, sizeof(numPixels), 0);
                    ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query");
    
                    if (result == S_OK)
                    {
                        queryState->finished = true;
                        mResult              = (numPixels > 0) ? GL_TRUE : GL_FALSE;
                    }
                }
                break;
    
                case gl::QueryType::TransformFeedbackPrimitivesWritten:
                {
                    ASSERT(queryState->query.valid());
                    D3D11_QUERY_DATA_SO_STATISTICS soStats = {};
                    HRESULT result =
                        context->GetData(queryState->query.get(), &soStats, sizeof(soStats), 0);
                    ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query");
    
                    if (result == S_OK)
                    {
                        queryState->finished = true;
                        mResult              = static_cast<GLuint64>(soStats.NumPrimitivesWritten);
                    }
                }
                break;
    
                case gl::QueryType::TimeElapsed:
                {
                    ASSERT(queryState->query.valid());
                    ASSERT(queryState->beginTimestamp.valid());
                    ASSERT(queryState->endTimestamp.valid());
                    D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {};
                    HRESULT result =
                        context->GetData(queryState->query.get(), &timeStats, sizeof(timeStats), 0);
                    ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query");
    
                    if (result == S_OK)
                    {
                        UINT64 beginTime = 0;
                        HRESULT beginRes = context->GetData(queryState->beginTimestamp.get(),
                                                            &beginTime, sizeof(UINT64), 0);
                        ANGLE_TRY_HR(context11, beginRes,
                                     "Failed to get the data of an internal query");
    
                        UINT64 endTime = 0;
                        HRESULT endRes = context->GetData(queryState->endTimestamp.get(), &endTime,
                                                          sizeof(UINT64), 0);
                        ANGLE_TRY_HR(context11, endRes, "Failed to get the data of an internal query");
    
                        if (beginRes == S_OK && endRes == S_OK)
                        {
                            queryState->finished = true;
                            if (timeStats.Disjoint)
                            {
                                mRenderer->setGPUDisjoint();
                            }
                            static_assert(sizeof(UINT64) == sizeof(unsigned long long),
                                          "D3D UINT64 isn't 64 bits");
    
                            angle::CheckedNumeric<UINT64> checkedTime(endTime);
                            checkedTime -= beginTime;
                            checkedTime *= 1000000000ull;
                            checkedTime /= timeStats.Frequency;
                            if (checkedTime.IsValid())
                            {
                                mResult = checkedTime.ValueOrDie();
                            }
                            else
                            {
                                mResult = std::numeric_limits<GLuint64>::max() / timeStats.Frequency;
                                // If an overflow does somehow occur, there is no way the elapsed time
                                // is accurate, so we generate a disjoint event
                                mRenderer->setGPUDisjoint();
                            }
                        }
                    }
                }
                break;
    
                case gl::QueryType::Timestamp:
                {
                    // D3D11 doesn't support GL timestamp queries as D3D timestamps are not guaranteed
                    // to have any sort of continuity outside of a disjoint timestamp query block, which
                    // GL depends on
                    ASSERT(!queryState->query.valid());
                    mResult              = 0;
                    queryState->finished = true;
                }
                break;
    
                case gl::QueryType::CommandsCompleted:
                {
                    ASSERT(queryState->query.valid());
                    BOOL completed = 0;
                    HRESULT result =
                        context->GetData(queryState->query.get(), &completed, sizeof(completed), 0);
                    ANGLE_TRY_HR(context11, result, "Failed to get the data of an internal query");
    
                    if (result == S_OK)
                    {
                        queryState->finished = true;
                        ASSERT(completed == TRUE);
                        mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE;
                    }
                }
                break;
    
                default:
                    UNREACHABLE();
                    break;
            }
    
            queryState->getDataAttemptCount++;
            bool checkDeviceLost =
                (queryState->getDataAttemptCount % kPollingD3DDeviceLostCheckFrequency) == 0;
            if (!queryState->finished && checkDeviceLost && mRenderer->testDeviceLost())
            {
                mRenderer->notifyDeviceLost();
                ANGLE_TRY_HR(context11, E_OUTOFMEMORY,
                             "Failed to test get query result, device is lost.");
            }
        }
    
        return angle::Result::Continue;
    }
    
    }  // namespace rx