Implement GL_CHROMIUM_sync_query for D3D9 and D3D11.
BUG=angleproject:1366
Change-Id: Iadde61968f45b969c76578a6dd9116a25d63fb4b
Reviewed-on: https://chromium-review.googlesource.com/341230
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index 1ffdcbb..56580b3 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -159,6 +159,7 @@
noError(false),
lossyETCDecode(false),
bindUniformLocation(false),
+ syncQuery(false),
colorBufferFloat(false)
{
}
@@ -232,6 +233,7 @@
InsertExtensionString("GL_ANGLE_lossy_etc_decode", lossyETCDecode, &extensionStrings);
InsertExtensionString("GL_CHROMIUM_bind_uniform_location", bindUniformLocation, &extensionStrings);
+ InsertExtensionString("GL_CHROMIUM_sync_query", syncQuery, &extensionStrings);
// clang-format on
return extensionStrings;
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index 32963b3..2ac3ef4 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -284,6 +284,9 @@
// GL_CHROMIUM_bind_uniform_location
bool bindUniformLocation;
+ // GL_CHROMIUM_sync_query
+ bool syncQuery;
+
// ES3 Extension support
// GL_EXT_color_buffer_float
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index a1d2752..40f0656 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -159,6 +159,7 @@
mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(nullptr);
mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(nullptr);
mActiveQueries[GL_TIME_ELAPSED_EXT].set(nullptr);
+ mActiveQueries[GL_COMMANDS_COMPLETED_CHROMIUM].set(nullptr);
mProgram = nullptr;
diff --git a/src/libANGLE/renderer/d3d/d3d11/Query11.cpp b/src/libANGLE/renderer/d3d/d3d11/Query11.cpp
index dad5f8c..861950d 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Query11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Query11.cpp
@@ -33,6 +33,9 @@
case GL_TIMESTAMP_EXT:
return newResult;
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ return newResult;
+
default:
UNREACHABLE();
return 0;
@@ -142,9 +145,10 @@
if (mActiveQuery->query != nullptr)
{
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
+ GLenum queryType = getType();
// If we are doing time elapsed query the end timestamp
- if (getType() == GL_TIME_ELAPSED_EXT)
+ if (queryType == GL_TIME_ELAPSED_EXT)
{
context->End(mActiveQuery->endTimestamp);
}
@@ -168,8 +172,11 @@
return error;
}
+ GLenum queryType = getType();
+ D3D11_QUERY d3dQueryType = gl_d3d11::ConvertQueryType(queryType);
+
D3D11_QUERY_DESC queryDesc;
- queryDesc.Query = gl_d3d11::ConvertQueryType(getType());
+ queryDesc.Query = d3dQueryType;
queryDesc.MiscFlags = 0;
ID3D11Device *device = mRenderer->getDevice();
@@ -182,7 +189,7 @@
}
// If we are doing time elapsed we also need a query to actually query the timestamp
- if (getType() == GL_TIME_ELAPSED_EXT)
+ if (queryType == GL_TIME_ELAPSED_EXT)
{
D3D11_QUERY_DESC desc;
desc.Query = D3D11_QUERY_TIMESTAMP;
@@ -203,10 +210,13 @@
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
- context->Begin(mActiveQuery->query);
+ if (d3dQueryType != D3D11_QUERY_EVENT)
+ {
+ context->Begin(mActiveQuery->query);
+ }
// If we are doing time elapsed, query the begin timestamp
- if (getType() == GL_TIME_ELAPSED_EXT)
+ if (queryType == GL_TIME_ELAPSED_EXT)
{
context->End(mActiveQuery->beginTimestamp);
}
@@ -358,6 +368,28 @@
}
break;
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ {
+ ASSERT(queryState->query);
+ BOOL completed = 0;
+ HRESULT result =
+ context->GetData(queryState->query, &completed, sizeof(completed), 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)
+ {
+ queryState->finished = true;
+ ASSERT(completed == TRUE);
+ mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE;
+ }
+ }
+ break;
+
default:
UNREACHABLE();
break;
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
index 37f9faa..614d887 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -130,7 +130,8 @@
}
static const GLenum QueryTypes[] = {GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
- GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_TIME_ELAPSED_EXT};
+ GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_TIME_ELAPSED_EXT,
+ GL_COMMANDS_COMPLETED_CHROMIUM};
StateManager11::StateManager11(Renderer11 *renderer)
: mRenderer(renderer),
diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
index e724ff5..a26152e 100644
--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
@@ -224,6 +224,8 @@
case GL_TIME_ELAPSED_EXT:
// Two internal queries are also created for begin/end timestamps
return D3D11_QUERY_TIMESTAMP_DISJOINT;
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ return D3D11_QUERY_EVENT;
default: UNREACHABLE(); return D3D11_QUERY_EVENT;
}
}
@@ -1236,6 +1238,7 @@
extensions->noError = true;
extensions->lossyETCDecode = true;
extensions->bindUniformLocation = true;
+ extensions->syncQuery = GetEventQuerySupport(featureLevel);
// D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing.
// D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't support gl_FrontFacing.
diff --git a/src/libANGLE/renderer/d3d/d3d9/Query9.cpp b/src/libANGLE/renderer/d3d/d3d9/Query9.cpp
index c826abf..9e5a90a 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Query9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Query9.cpp
@@ -30,20 +30,25 @@
gl::Error Query9::begin()
{
- if (mQuery == NULL)
+ D3DQUERYTYPE d3dQueryType = gl_d3d9::ConvertQueryType(getType());
+ if (mQuery == nullptr)
{
- HRESULT result = mRenderer->getDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery);
+ HRESULT result = mRenderer->getDevice()->CreateQuery(d3dQueryType, &mQuery);
if (FAILED(result))
{
return gl::Error(GL_OUT_OF_MEMORY, "Internal query creation failed, result: 0x%X.", result);
}
}
- HRESULT result = mQuery->Issue(D3DISSUE_BEGIN);
- ASSERT(SUCCEEDED(result));
- if (FAILED(result))
+ if (d3dQueryType != D3DQUERYTYPE_EVENT)
{
- return gl::Error(GL_OUT_OF_MEMORY, "Failed to begin internal query, result: 0x%X.", result);
+ HRESULT result = mQuery->Issue(D3DISSUE_BEGIN);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to begin internal query, result: 0x%X.",
+ result);
+ }
}
return gl::Error(GL_NO_ERROR);
@@ -133,26 +138,40 @@
{
ASSERT(mQuery);
- DWORD numPixels = 0;
-
- HRESULT hres = mQuery->GetData(&numPixels, sizeof(DWORD), D3DGETDATA_FLUSH);
- if (hres == S_OK)
+ HRESULT result = S_OK;
+ switch (getType())
{
- mQueryFinished = true;
-
- switch (getType())
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
{
- case GL_ANY_SAMPLES_PASSED_EXT:
- case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
- mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE;
- break;
-
- default:
- UNREACHABLE();
+ DWORD numPixels = 0;
+ result = mQuery->GetData(&numPixels, sizeof(numPixels), D3DGETDATA_FLUSH);
+ if (result == S_OK)
+ {
+ mQueryFinished = true;
+ mResult = (numPixels > 0) ? GL_TRUE : GL_FALSE;
+ }
break;
}
+
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ {
+ BOOL completed = FALSE;
+ result = mQuery->GetData(&completed, sizeof(completed), D3DGETDATA_FLUSH);
+ if (result == S_OK)
+ {
+ mQueryFinished = true;
+ mResult = (completed == TRUE) ? GL_TRUE : GL_FALSE;
+ }
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ break;
}
- else if (d3d9::isDeviceLostError(hres))
+
+ if (d3d9::isDeviceLostError(result))
{
mRenderer->notifyDeviceLost();
return gl::Error(GL_OUT_OF_MEMORY, "Failed to test get query result, device is lost.");
diff --git a/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
index 34efec7..b55f7dc 100644
--- a/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp
@@ -264,6 +264,21 @@
}
}
+D3DQUERYTYPE ConvertQueryType(GLenum queryType)
+{
+ switch (queryType)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ return D3DQUERYTYPE_OCCLUSION;
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ return D3DQUERYTYPE_EVENT;
+ default:
+ UNREACHABLE();
+ return static_cast<D3DQUERYTYPE>(0);
+ }
+}
+
D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples)
{
return (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE;
@@ -580,6 +595,7 @@
extensions->vertexArrayObject = true;
extensions->noError = true;
extensions->bindUniformLocation = true;
+ extensions->syncQuery = extensions->fence;
// D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil
// state.
diff --git a/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h b/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h
index aa494ad..5e2b6d2 100644
--- a/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h
+++ b/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.h
@@ -39,6 +39,7 @@
D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy);
void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter,
float *d3dLodBias, float maxAnisotropy, size_t baseLevel);
+D3DQUERYTYPE ConvertQueryType(GLenum queryType);
D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples);
diff --git a/src/libANGLE/renderer/gl/StateManagerGL.cpp b/src/libANGLE/renderer/gl/StateManagerGL.cpp
index aa189f4..a961653 100644
--- a/src/libANGLE/renderer/gl/StateManagerGL.cpp
+++ b/src/libANGLE/renderer/gl/StateManagerGL.cpp
@@ -28,7 +28,8 @@
{
static const GLenum QueryTypes[] = {GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
- GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_TIME_ELAPSED};
+ GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_TIME_ELAPSED,
+ GL_COMMANDS_COMPLETED_CHROMIUM};
StateManagerGL::IndexedBufferBinding::IndexedBufferBinding() : offset(0), size(0), buffer(0)
{
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index a84d9eb..40db7aa 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -398,6 +398,8 @@
return (context->getClientVersion() >= 3);
case GL_TIME_ELAPSED_EXT:
return context->getExtensions().disjointTimerQuery;
+ case GL_COMMANDS_COMPLETED_CHROMIUM:
+ return context->getExtensions().syncQuery;
default:
return false;
}
@@ -1220,7 +1222,7 @@
bool ValidateBeginQueryEXT(gl::Context *context, GLenum target, GLuint id)
{
if (!context->getExtensions().occlusionQueryBoolean &&
- !context->getExtensions().disjointTimerQuery)
+ !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
{
context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
return false;
@@ -1251,7 +1253,7 @@
bool ValidateEndQueryEXT(gl::Context *context, GLenum target)
{
if (!context->getExtensions().occlusionQueryBoolean &&
- !context->getExtensions().disjointTimerQuery)
+ !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
{
context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
return false;
@@ -1327,7 +1329,7 @@
bool ValidateGetQueryivEXT(Context *context, GLenum target, GLenum pname, GLint *params)
{
if (!context->getExtensions().occlusionQueryBoolean &&
- !context->getExtensions().disjointTimerQuery)
+ !context->getExtensions().disjointTimerQuery && !context->getExtensions().syncQuery)
{
context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
return false;
@@ -1379,7 +1381,7 @@
bool ValidateGetQueryObjectuivEXT(Context *context, GLuint id, GLenum pname, GLuint *params)
{
if (!context->getExtensions().disjointTimerQuery &&
- !context->getExtensions().occlusionQueryBoolean)
+ !context->getExtensions().occlusionQueryBoolean && !context->getExtensions().syncQuery)
{
context->handleError(Error(GL_INVALID_OPERATION, "Query extension not enabled"));
return false;
diff --git a/src/tests/angle_end2end_tests.gypi b/src/tests/angle_end2end_tests.gypi
index 020a61b..37490b2 100644
--- a/src/tests/angle_end2end_tests.gypi
+++ b/src/tests/angle_end2end_tests.gypi
@@ -60,6 +60,7 @@
'<(angle_path)/src/tests/gl_tests/SRGBTextureTest.cpp',
'<(angle_path)/src/tests/gl_tests/StateChangeTest.cpp',
'<(angle_path)/src/tests/gl_tests/SwizzleTest.cpp',
+ '<(angle_path)/src/tests/gl_tests/SyncQueriesTest.cpp',
'<(angle_path)/src/tests/gl_tests/TextureTest.cpp',
'<(angle_path)/src/tests/gl_tests/TimerQueriesTest.cpp',
'<(angle_path)/src/tests/gl_tests/TransformFeedbackTest.cpp',
diff --git a/src/tests/gl_tests/SyncQueriesTest.cpp b/src/tests/gl_tests/SyncQueriesTest.cpp
new file mode 100644
index 0000000..b363112
--- /dev/null
+++ b/src/tests/gl_tests/SyncQueriesTest.cpp
@@ -0,0 +1,108 @@
+//
+// Copyright 2016 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.
+//
+
+// SyncQueriesTest.cpp: Tests of the GL_CHROMIUM_sync_query extension
+
+#include "test_utils/ANGLETest.h"
+
+namespace angle
+{
+
+class SyncQueriesTest : public ANGLETest
+{
+ protected:
+ SyncQueriesTest()
+ {
+ setWindowWidth(128);
+ setWindowHeight(128);
+ setConfigRedBits(8);
+ setConfigGreenBits(8);
+ setConfigBlueBits(8);
+ setConfigAlphaBits(8);
+ setConfigDepthBits(24);
+ }
+
+ void TearDown() override
+ {
+ if (mQuery != 0)
+ {
+ glDeleteQueriesEXT(1, &mQuery);
+ mQuery = 0;
+ }
+
+ ANGLETest::TearDown();
+ }
+
+ GLuint mQuery = 0;
+};
+
+// Test basic usage of sync queries
+TEST_P(SyncQueriesTest, Basic)
+{
+ if (!extensionEnabled("GL_CHROMIUM_sync_query"))
+ {
+ std::cout << "Test skipped because GL_CHROMIUM_sync_query is not available." << std::endl;
+ return;
+ }
+
+ glGenQueriesEXT(1, &mQuery);
+ glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, mQuery);
+ EXPECT_GL_NO_ERROR();
+
+ glClearColor(0.0, 0.0, 1.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glEndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
+
+ glFlush();
+ GLuint result = 0;
+ glGetQueryObjectuivEXT(mQuery, GL_QUERY_RESULT_EXT, &result);
+ EXPECT_EQ(static_cast<GLuint>(GL_TRUE), result);
+ EXPECT_GL_NO_ERROR();
+}
+
+// Test that the sync query enums are not accepted unless the extension is available
+TEST_P(SyncQueriesTest, Validation)
+{
+ // Need the GL_EXT_occlusion_query_boolean extension for the entry points
+ if (!extensionEnabled("GL_EXT_occlusion_query_boolean"))
+ {
+ std::cout << "Test skipped because GL_EXT_occlusion_query_boolean is not available."
+ << std::endl;
+ return;
+ }
+
+ bool extensionAvailable = extensionEnabled("GL_CHROMIUM_sync_query");
+
+ glGenQueriesEXT(1, &mQuery);
+
+ glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, mQuery);
+ if (extensionAvailable)
+ {
+ EXPECT_GL_NO_ERROR();
+ }
+ else
+ {
+ EXPECT_GL_ERROR(GL_INVALID_ENUM);
+ }
+
+ glDeleteQueriesEXT(1, &mQuery);
+
+ EXPECT_GL_NO_ERROR();
+}
+
+// Use this to select which configurations (e.g. which renderer, which GLES major version) these
+// tests should be run against.
+ANGLE_INSTANTIATE_TEST(SyncQueriesTest,
+ ES2_D3D9(),
+ ES2_D3D11(),
+ ES3_D3D11(),
+ ES2_OPENGL(),
+ ES3_OPENGL(),
+ ES2_OPENGLES(),
+ ES3_OPENGLES());
+
+} // namespace angle