Commit f04f6671 by Ian Ewell

Add support for timer queries in D3D11

Timer queries without context virtualization are now supported in the Direct3D11 backend. Only the elapsed time portion of the GL extension is supported though due to limitations of D3D11 preventing a reliable implementation of the timestamp functionality. As a result of this, the counter bits for the timestamp is set to 0 and any queries of the timestamp will always return 0. BUG=angleproject:657 Change-Id: I51ca1a1a6bd6bc13155cebeacdca414b764db168 Reviewed-on: https://chromium-review.googlesource.com/325780Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 6b3c1db5
......@@ -45,7 +45,8 @@ RendererD3D::RendererD3D(egl::Display *display)
mAnnotator(nullptr),
mPresentPathFastEnabled(false),
mScratchMemoryBufferResetCounter(0),
mWorkaroundsInitialized(false)
mWorkaroundsInitialized(false),
mDisjoint(false)
{
}
......@@ -666,14 +667,24 @@ void RendererD3D::popGroupMarker()
getAnnotator()->endEvent();
}
void RendererD3D::setGPUDisjoint()
{
mDisjoint = true;
}
GLint RendererD3D::getGPUDisjoint()
{
return 0;
bool disjoint = mDisjoint;
// Disjoint flag is cleared when read
mDisjoint = false;
return disjoint;
}
GLint64 RendererD3D::getTimestamp()
{
UNIMPLEMENTED();
// D3D has no way to get an actual timestamp reliably so 0 is returned
return 0;
}
......
......@@ -243,6 +243,8 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
void pushGroupMarker(GLsizei length, const char *marker) override;
void popGroupMarker() override;
void setGPUDisjoint();
GLint getGPUDisjoint() override;
GLint64 getTimestamp() override;
......@@ -330,6 +332,8 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
mutable bool mWorkaroundsInitialized;
mutable WorkaroundsD3D mWorkarounds;
bool mDisjoint;
};
}
......
......@@ -21,38 +21,81 @@ Query11::Query11(Renderer11 *renderer, GLenum type)
mResult(0),
mQueryFinished(false),
mRenderer(renderer),
mQuery(NULL)
mQuery(nullptr),
mTimestampBeginQuery(nullptr),
mTimestampEndQuery(nullptr)
{
}
Query11::~Query11()
{
SafeRelease(mQuery);
SafeRelease(mTimestampBeginQuery);
SafeRelease(mTimestampEndQuery);
}
gl::Error Query11::begin()
{
if (mQuery == NULL)
if (mQuery == nullptr)
{
D3D11_QUERY_DESC queryDesc;
queryDesc.Query = gl_d3d11::ConvertQueryType(getType());
queryDesc.MiscFlags = 0;
HRESULT result = mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery);
ID3D11Device *device = mRenderer->getDevice();
HRESULT result = device->CreateQuery(&queryDesc, &mQuery);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result);
}
// If we are doing time elapsed we also need a query to actually query the timestamp
if (getType() == GL_TIME_ELAPSED_EXT)
{
D3D11_QUERY_DESC desc;
desc.Query = D3D11_QUERY_TIMESTAMP;
desc.MiscFlags = 0;
result = device->CreateQuery(&desc, &mTimestampBeginQuery);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.",
result);
}
result = device->CreateQuery(&desc, &mTimestampEndQuery);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.",
result);
}
}
}
mRenderer->getDeviceContext()->Begin(mQuery);
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
context->Begin(mQuery);
// If we are doing time elapsed query the begin timestamp
if (getType() == GL_TIME_ELAPSED_EXT)
{
context->End(mTimestampBeginQuery);
}
return gl::Error(GL_NO_ERROR);
}
gl::Error Query11::end()
{
ASSERT(mQuery);
mRenderer->getDeviceContext()->End(mQuery);
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
// If we are doing time elapsed query the end timestamp
if (getType() == GL_TIME_ELAPSED_EXT)
{
context->End(mTimestampEndQuery);
}
context->End(mQuery);
mQueryFinished = false;
mResult = GL_FALSE;
......@@ -62,8 +105,11 @@ gl::Error Query11::end()
gl::Error Query11::queryCounter()
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION, "Unimplemented");
// This doesn't do anything for D3D11 as we don't support timestamps
ASSERT(getType() == GL_TIMESTAMP_EXT);
mQueryFinished = true;
mResult = 0;
return gl::Error(GL_NO_ERROR);
}
template <typename T>
......@@ -166,6 +212,72 @@ gl::Error Query11::testQuery()
}
break;
case GL_TIME_ELAPSED_EXT:
{
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timeStats = {0};
HRESULT result = context->GetData(mQuery, &timeStats, sizeof(timeStats), 0);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY,
"Failed to get the data of an internal query, result: 0x%X.",
result);
}
if (result == S_OK)
{
UINT64 beginTime = 0;
HRESULT beginRes =
context->GetData(mTimestampBeginQuery, &beginTime, sizeof(UINT64), 0);
if (FAILED(beginRes))
{
return gl::Error(
GL_OUT_OF_MEMORY,
"Failed to get the data of an internal query, result: 0x%X.", beginRes);
}
UINT64 endTime = 0;
HRESULT endRes =
context->GetData(mTimestampEndQuery, &endTime, sizeof(UINT64), 0);
if (FAILED(endRes))
{
return gl::Error(
GL_OUT_OF_MEMORY,
"Failed to get the data of an internal query, result: 0x%X.", endRes);
}
if (beginRes == S_OK && endRes == S_OK)
{
mQueryFinished = true;
if (timeStats.Disjoint)
{
mRenderer->setGPUDisjoint();
}
static_assert(sizeof(UINT64) == sizeof(unsigned long long),
"D3D UINT64 isn't 64 bits");
if (rx::IsUnsignedMultiplicationSafe(endTime - beginTime, 1000000000ull))
{
mResult = ((endTime - beginTime) * 1000000000ull) / timeStats.Frequency;
}
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_TIMESTAMP_EXT:
{
// 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
mResult = 0;
}
break;
default:
UNREACHABLE();
break;
......
......@@ -42,6 +42,8 @@ class Query11 : public QueryImpl
Renderer11 *mRenderer;
ID3D11Query *mQuery;
ID3D11Query *mTimestampBeginQuery;
ID3D11Query *mTimestampEndQuery;
};
}
......
......@@ -221,6 +221,9 @@ D3D11_QUERY ConvertQueryType(GLenum queryType)
case GL_ANY_SAMPLES_PASSED_EXT:
case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT: return D3D11_QUERY_OCCLUSION;
case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: return D3D11_QUERY_SO_STATISTICS;
case GL_TIME_ELAPSED_EXT:
// Two internal queries are also created for begin/end timestamps
return D3D11_QUERY_TIMESTAMP_DISJOINT;
default: UNREACHABLE(); return D3D11_QUERY_EVENT;
}
}
......@@ -1198,7 +1201,10 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons
extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel);
extensions->fence = GetEventQuerySupport(featureLevel);
extensions->timerQuery = false; // Unimplemented
extensions->disjointTimerQuery = false;
extensions->disjointTimerQuery = true;
extensions->queryCounterBitsTimeElapsed = 64;
extensions->queryCounterBitsTimestamp =
0; // Timestamps cannot be supported due to D3D11 limitations
extensions->robustness = true;
extensions->blendMinMax = true;
extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel);
......
......@@ -289,7 +289,6 @@ TEST_P(TimerQueriesTest, Timestamp)
class TimerQueriesTestES3 : public TimerQueriesTest
{
};
// Tests getting timestamps via glGetInteger64v
......@@ -336,6 +335,4 @@ ANGLE_INSTANTIATE_TEST(TimerQueriesTest,
ES2_OPENGL(),
ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(TimerQueriesTestES3,
ES3_D3D11(),
ES3_OPENGL());
\ No newline at end of file
ANGLE_INSTANTIATE_TEST(TimerQueriesTestES3, ES3_D3D11(), ES3_OPENGL());
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment