Support timestamp behind flag enableTimestampQueries

All timestamp queries happen in the same disjoint query in one
Context11.

The whole design is that we start a disjoint query in D3D11 at the first
timestamp request and keep it continuously running in current context.
Only end it and read it back when the user queries if there is a
disjoint. We cache the frequency and assume it doesn't change. For the
first timestamp, we create a temporary D3D disjoint query and end it so
we have a frequency to convert the ticks to nanoseconds.

This task is taken over from
https://chromium-review.googlesource.com/c/angle/angle/+/3694732

Bug: angleproject:7367
Change-Id: I747c9b00e10ac58362df66332efd01a24aa395f2
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4021139
Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
This commit is contained in:
Qin Jiajia 2022-11-10 12:49:03 +08:00 коммит произвёл Angle LUCI CQ
Родитель 7cadf14d00
Коммит e58e77f52b
12 изменённых файлов: 243 добавлений и 16 удалений

Просмотреть файл

@ -168,6 +168,13 @@ struct FeaturesD3D : FeatureSetBase
FeatureInfo disableRasterizerOrderViews = {
"disableRasterizerOrderViews", FeatureCategory::D3DWorkarounds, "Disable ROVs for testing",
&members, "http://anglebug.com/7279"};
FeatureInfo enableTimestampQueries = {
"enableTimestampQueries",
FeatureCategory::D3DWorkarounds,
"Enable timestamp on GL_EXT_disjoint_timer_query extension",
&members,
};
};
inline FeaturesD3D::FeaturesD3D() = default;

Просмотреть файл

@ -185,6 +185,13 @@
"Disable ROVs for testing"
],
"issue": "http://anglebug.com/7279"
},
{
"name": "enable_timestamp_queries",
"category": "Workarounds",
"description": [
"Enable timestamp on GL_EXT_disjoint_timer_query extension"
]
}
]
}

Просмотреть файл

@ -1,6 +1,6 @@
{
"include/platform/FeaturesD3D_autogen.h":
"9923fb44d0a6f31948d0c8f46ee1d9e2",
"256cd7175aa885e9ec57ecb86d455fc4",
"include/platform/FeaturesGL_autogen.h":
"38325ab28fca006d06f46d1ad4ad2d63",
"include/platform/FeaturesMtl_autogen.h":
@ -10,7 +10,7 @@
"include/platform/FrontendFeatures_autogen.h":
"e8ba29b617e21fe318bf7e3c0aa5b071",
"include/platform/d3d_features.json":
"5f4e8c4cc64f0cc1ef6e658d2e443aa2",
"0d316218a4ac7c3bb9692e7525216973",
"include/platform/frontend_features.json":
"6a34aecba765523b1c0b50f4cd6ff897",
"include/platform/gen_features.py":
@ -22,7 +22,7 @@
"include/platform/vk_features.json":
"0915d2e171c000ea2147e59c894233e2",
"util/angle_features_autogen.cpp":
"c0db87c0191032b088e2ecd23b4991e9",
"1348b9b6a49a0fc5228f0bcce3d34611",
"util/angle_features_autogen.h":
"d9d1f90cf2e5ca8d842b7bf29a6fc8c8"
"c75229725c67fccdeea7aaf86ef0891c"
}

Просмотреть файл

@ -2273,6 +2273,10 @@ void Context::getIntegervImpl(GLenum pname, GLint *params) const
*params = mState.mCaps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes;
break;
case GL_QUERY_COUNTER_BITS_EXT:
*params = mState.mCaps.queryCounterBitsTimestamp;
break;
default:
ANGLE_CONTEXT_TRY(mState.getIntegerv(this, pname, params));
break;

Просмотреть файл

@ -3174,6 +3174,7 @@ bool GetQueryParameterInfo(const State &glState,
case GL_TEXTURE_BINDING_2D:
case GL_TEXTURE_BINDING_CUBE_MAP:
case GL_RESET_NOTIFICATION_STRATEGY_EXT:
case GL_QUERY_COUNTER_BITS_EXT:
{
*type = GL_INT;
*numParams = 1;

Просмотреть файл

@ -116,7 +116,11 @@ angle::Result ReadbackIndirectBuffer(const gl::Context *context,
} // anonymous namespace
Context11::Context11(const gl::State &state, gl::ErrorSet *errorSet, Renderer11 *renderer)
: ContextD3D(state, errorSet), mRenderer(renderer), mDisjoint(false)
: ContextD3D(state, errorSet),
mRenderer(renderer),
mDisjointQueryStarted(false),
mDisjoint(false),
mFrequency(0)
{}
Context11::~Context11() {}
@ -800,6 +804,54 @@ angle::Result Context11::syncState(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result Context11::checkDisjointQuery()
{
if (!mDisjointQuery.valid())
{
D3D11_QUERY_DESC queryDesc;
queryDesc.Query = gl_d3d11::ConvertQueryType(gl::QueryType::Timestamp);
queryDesc.MiscFlags = 0;
ANGLE_TRY(mRenderer->allocateResource(this, queryDesc, &mDisjointQuery));
mRenderer->getDeviceContext()->Begin(mDisjointQuery.get());
mDisjointQueryStarted = true;
}
return angle::Result::Continue;
}
HRESULT Context11::checkDisjointQueryStatus()
{
HRESULT result = S_OK;
if (mDisjointQuery.valid())
{
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
if (mDisjointQueryStarted)
{
context->End(mDisjointQuery.get());
mDisjointQueryStarted = false;
}
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {};
result = context->GetData(mDisjointQuery.get(), &timeStats, sizeof(timeStats), 0);
if (result == S_OK)
{
mFrequency = timeStats.Frequency;
mDisjoint = timeStats.Disjoint;
mDisjointQuery.reset();
}
}
return result;
}
UINT64 Context11::getDisjointFrequency()
{
return mFrequency;
}
void Context11::setDisjointFrequency(UINT64 frequency)
{
mFrequency = frequency;
}
void Context11::setGPUDisjoint()
{
mDisjoint = true;
@ -807,6 +859,10 @@ void Context11::setGPUDisjoint()
GLint Context11::getGPUDisjoint()
{
if (mRenderer->getFeatures().enableTimestampQueries.enabled)
{
checkDisjointQueryStatus();
}
bool disjoint = mDisjoint;
// Disjoint flag is cleared when read

Просмотреть файл

@ -13,6 +13,7 @@
#include <stack>
#include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/d3d/ContextD3D.h"
#include "libANGLE/renderer/d3d/d3d11/ResourceManager11.h"
namespace rx
{
@ -263,6 +264,10 @@ class Context11 : public ContextD3D, public MultisampleTextureInitializer
unsigned int line) override;
void setGPUDisjoint();
angle::Result checkDisjointQuery();
HRESULT checkDisjointQueryStatus();
UINT64 getDisjointFrequency();
void setDisjointFrequency(UINT64 frequency);
private:
angle::Result drawElementsImpl(const gl::Context *context,
@ -279,7 +284,10 @@ class Context11 : public ContextD3D, public MultisampleTextureInitializer
Renderer11 *mRenderer;
IncompleteTextureSet mIncompleteTextures;
std::stack<std::string> mMarkerStack;
d3d11::Query mDisjointQuery;
bool mDisjointQueryStarted;
bool mDisjoint;
UINT64 mFrequency;
};
} // namespace rx

Просмотреть файл

@ -81,10 +81,39 @@ angle::Result Query11::end(const gl::Context *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()));
if (!mRenderer->getFeatures().enableTimestampQueries.enabled)
{
mResultSum = 0;
return angle::Result::Continue;
}
Context11 *context11 = GetImplAs<Context11>(context);
D3D11_QUERY_DESC queryDesc;
queryDesc.MiscFlags = 0;
queryDesc.Query = D3D11_QUERY_TIMESTAMP;
ANGLE_TRY(mRenderer->allocateResource(context11, queryDesc, &mActiveQuery->endTimestamp));
ANGLE_TRY(context11->checkDisjointQuery());
ID3D11DeviceContext *contextD3D11 = mRenderer->getDeviceContext();
if (context11->getDisjointFrequency() > 0)
{
contextD3D11->End(mActiveQuery->endTimestamp.get());
}
else
{
// If the frequency hasn't been cached, insert a disjoint query to get the frequency.
queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
ANGLE_TRY(mRenderer->allocateResource(context11, queryDesc, &mActiveQuery->query));
contextD3D11->Begin(mActiveQuery->query.get());
contextD3D11->End(mActiveQuery->endTimestamp.get());
contextD3D11->End(mActiveQuery->query.get());
}
mPendingQueries.push_back(std::move(mActiveQuery));
mActiveQuery = std::unique_ptr<QueryState>(new QueryState());
return angle::Result::Continue;
}
@ -309,12 +338,68 @@ angle::Result Query11::testQuery(Context11 *context11, QueryState *queryState)
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;
if (!mRenderer->getFeatures().enableTimestampQueries.enabled)
{
mResult = 0;
queryState->finished = true;
}
else
{
bool hasFrequency = context11->getDisjointFrequency() > 0;
HRESULT result = S_OK;
if (!hasFrequency)
{
ASSERT(queryState->query.valid());
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {};
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)
{
context11->setDisjointFrequency(timeStats.Frequency);
if (timeStats.Disjoint)
{
context11->setGPUDisjoint();
}
}
}
if (result == S_OK)
{
ASSERT(queryState->endTimestamp.valid());
UINT64 timestamp = 0;
HRESULT timestampRes = context->GetData(queryState->endTimestamp.get(),
&timestamp, sizeof(UINT64), 0);
ANGLE_TRY_HR(context11, timestampRes,
"Failed to get the data of an internal query");
if (timestampRes == S_OK)
{
ASSERT(context11->getDisjointFrequency() > 0);
queryState->finished = true;
static_assert(sizeof(UINT64) == sizeof(unsigned long long),
"D3D UINT64 isn't 64 bits");
timestamp = static_cast<uint64_t>(
timestamp *
(1000000000.0 /
static_cast<double>(context11->getDisjointFrequency())));
angle::CheckedNumeric<UINT64> checkedTime(timestamp);
if (checkedTime.IsValid())
{
mResult = checkedTime.ValueOrDie();
}
else
{
mResult = std::numeric_limits<GLuint64>::max();
// If an overflow does somehow occur, there is no way the elapsed
// time is accurate, so we generate a disjoint event
context11->setGPUDisjoint();
}
}
}
}
}
break;

Просмотреть файл

@ -1602,8 +1602,10 @@ void GenerateCaps(ID3D11Device *device,
caps->maxTextureAnisotropy = GetMaximumAnisotropy(featureLevel);
caps->queryCounterBitsTimeElapsed = 64;
caps->queryCounterBitsTimestamp = 0; // Timestamps cannot be supported due to D3D11 limitations
caps->maxDualSourceDrawBuffers = 1;
caps->queryCounterBitsTimestamp = features.enableTimestampQueries.enabled ? 64 : 0;
caps->maxDualSourceDrawBuffers = 1;
// GL extension support
extensions->setTextureExtensionSupport(*textureCapsMap);
@ -2123,6 +2125,9 @@ D3D11_QUERY ConvertQueryType(gl::QueryType type)
case gl::QueryType::TimeElapsed:
// Two internal queries are also created for begin/end timestamps
return D3D11_QUERY_TIMESTAMP_DISJOINT;
case gl::QueryType::Timestamp:
// A disjoint query is also created for timestamp
return D3D11_QUERY_TIMESTAMP_DISJOINT;
case gl::QueryType::CommandsCompleted:
return D3D11_QUERY_EVENT;
default:

Просмотреть файл

@ -8,6 +8,7 @@
//
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include "util/EGLWindow.h"
#include "util/random_utils.h"
#include "util/test_utils.h"
@ -482,6 +483,51 @@ TEST_P(TimerQueriesTest, Timestamp)
EXPECT_LT(result1, result2);
}
void getQueryResult(GLuint queryObjectName, GLuint64 *result)
{
GLuint queryResult = GL_FALSE;
while (queryResult != GL_TRUE)
{
glGetQueryObjectuivEXT(queryObjectName, GL_QUERY_RESULT_AVAILABLE, &queryResult);
ASSERT_GL_NO_ERROR();
angle::Sleep(50);
}
glGetQueryObjectui64vEXT(queryObjectName, GL_QUERY_RESULT_EXT, result);
}
class TimerstampQueriesTest : public TimerQueriesTest
{};
// Tests getting timestamps via glGetQueryObjectui64vEXT
TEST_P(TimerstampQueriesTest, TimestampBasic)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
ANGLE_SKIP_TEST_IF(!IsD3D11() || !IsWindows());
GLint queryTimestampBits = 0;
glGetQueryivEXT(GL_TIMESTAMP_EXT, GL_QUERY_COUNTER_BITS_EXT, &queryTimestampBits);
ASSERT_GL_NO_ERROR();
std::cout << "Timestamp counter bits: " << queryTimestampBits << std::endl;
GLQuery queryObject1, queryObject2;
glQueryCounterEXT(queryObject1, GL_TIMESTAMP_EXT);
ASSERT_GL_NO_ERROR();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
drawQuad(mProgramCostly, "position", 0.8f);
glQueryCounterEXT(queryObject2, GL_TIMESTAMP_EXT);
ASSERT_GL_NO_ERROR();
GLuint64 result1 = 0;
getQueryResult(queryObject1, &result1);
GLuint64 result2 = 0;
getQueryResult(queryObject2, &result2);
std::cout << "Timestamps: " << result1 << " " << result2 << std::endl;
if (queryTimestampBits != 0)
{
ASSERT_TRUE(result1 != 0 && result2 > result1);
}
}
class TimerQueriesTestES3 : public TimerQueriesTest
{};
@ -515,6 +561,12 @@ TEST_P(TimerQueriesTestES3, TimestampGetInteger64)
EXPECT_LT(result1, result2);
}
ANGLE_INSTANTIATE_TEST_ES2_AND(TimerstampQueriesTest,
ES3_D3D11().disable(Feature::EnableTimestampQueries),
ES3_D3D11().enable(Feature::EnableTimestampQueries));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TimestampQueriesTest);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(TimerQueriesTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TimerQueriesTestES3);

Просмотреть файл

@ -118,6 +118,7 @@ constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{
{Feature::EnablePrecisionQualifiers, "enablePrecisionQualifiers"},
{Feature::EnablePreRotateSurfaces, "enablePreRotateSurfaces"},
{Feature::EnableProgramBinaryForCapture, "enableProgramBinaryForCapture"},
{Feature::EnableTimestampQueries, "enableTimestampQueries"},
{Feature::ExpandIntegerPowExpressions, "expandIntegerPowExpressions"},
{Feature::ExplicitlyEnablePerSampleShading, "explicitlyEnablePerSampleShading"},
{Feature::ExposeNonConformantExtensionsAndVersions, "exposeNonConformantExtensionsAndVersions"},

Просмотреть файл

@ -112,6 +112,7 @@ enum class Feature
EnablePrecisionQualifiers,
EnablePreRotateSurfaces,
EnableProgramBinaryForCapture,
EnableTimestampQueries,
ExpandIntegerPowExpressions,
ExplicitlyEnablePerSampleShading,
ExposeNonConformantExtensionsAndVersions,