Handle nullptr in GetQueryObjectParameter()
There are applications that disable validation using
EGL_CONTEXT_OPENGL_NO_ERROR_KHR extension. In such usecases
the GetQueryObjectParameter() method needs to account for the
possibility that the query object has not yet been created.
Bug: angleproject:5704
Tests: angle_end2end_tests --gtest_filter=QueryObjectTest*
Change-Id: Ib9e1cb32a6d64f2772124178223cf07cbb84691b
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2729298
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Mohan Maiya <m.maiya@samsung.com>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 2cb5cbf..ea42d24 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -67,7 +67,25 @@
template <typename T>
angle::Result GetQueryObjectParameter(const Context *context, Query *query, GLenum pname, T *params)
{
- ASSERT(query != nullptr || pname == GL_QUERY_RESULT_AVAILABLE_EXT);
+ if (!query)
+ {
+ // Some applications call into glGetQueryObjectuiv(...) prior to calling glBeginQuery(...)
+ // This wouldn't be an issue since the validation layer will handle such a usecases but when
+ // the app enables EGL_KHR_create_context_no_error extension, we skip the validation layer.
+ switch (pname)
+ {
+ case GL_QUERY_RESULT_EXT:
+ *params = 0;
+ break;
+ case GL_QUERY_RESULT_AVAILABLE_EXT:
+ *params = GL_FALSE;
+ break;
+ default:
+ UNREACHABLE();
+ return angle::Result::Stop;
+ }
+ return angle::Result::Continue;
+ }
switch (pname)
{
diff --git a/src/tests/angle_end2end_tests.gni b/src/tests/angle_end2end_tests.gni
index 16c9afb..5b20401 100644
--- a/src/tests/angle_end2end_tests.gni
+++ b/src/tests/angle_end2end_tests.gni
@@ -108,6 +108,7 @@
"gl_tests/ProgramParameterTest.cpp",
"gl_tests/ProgramPipelineTest.cpp",
"gl_tests/ProvokingVertexTest.cpp",
+ "gl_tests/QueryObjectValidation.cpp",
"gl_tests/ReadOnlyFeedbackLoopTest.cpp",
"gl_tests/ReadPixelsTest.cpp",
"gl_tests/RenderbufferMultisampleTest.cpp",
diff --git a/src/tests/gl_tests/QueryObjectValidation.cpp b/src/tests/gl_tests/QueryObjectValidation.cpp
new file mode 100644
index 0000000..ea11e2c
--- /dev/null
+++ b/src/tests/gl_tests/QueryObjectValidation.cpp
@@ -0,0 +1,157 @@
+//
+// Copyright 2021 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.
+//
+// QueryObjectValidation.cpp : Tests between gl.*Query.* functions and interactions with
+// EGL_CONTEXT_OPENGL_NO_ERROR_KHR
+#include <gtest/gtest.h>
+
+#include "test_utils/ANGLETest.h"
+#include "util/EGLWindow.h"
+#include "util/test_utils.h"
+
+namespace angle
+{
+
+using QueryObjectTestParams = std::tuple<angle::PlatformParameters, bool>;
+
+std::string PrintToStringParamName(const ::testing::TestParamInfo<QueryObjectTestParams> &info)
+{
+ std::stringstream ss;
+ ss << std::get<0>(info.param);
+ if (std::get<1>(info.param))
+ {
+ ss << "__ValidationDisabled";
+ }
+ else
+ {
+ ss << "__ValidationEnabled";
+ }
+ return ss.str();
+}
+
+class QueryObjectTest : public ANGLETestWithParam<QueryObjectTestParams>
+{
+ protected:
+ QueryObjectTest() : mQueryObjectName(0), mQueryResult(false)
+ {
+ setNoErrorEnabled(testing::get<1>(GetParam()));
+ }
+
+ void createQuery()
+ {
+ glGenQueries(1, &mQueryObjectName);
+ ASSERT_NE(mQueryObjectName, (GLuint)0u);
+ ASSERT_GL_NO_ERROR();
+ }
+
+ void testSetUp() override { createQuery(); }
+
+ void testTearDown() override
+ {
+ if (mQueryObjectName)
+ {
+ glDeleteQueries(1, &mQueryObjectName);
+ }
+ }
+
+ GLuint mQueryObjectName = 0;
+ GLuint mQueryResult = 0;
+};
+
+class QueryObjectTestES32 : public QueryObjectTest
+{};
+
+// Test if a generated query is a query before glBeginQuery
+TEST_P(QueryObjectTest, QueryObjectIsQuery)
+{
+ GLboolean isQueryResult = glIsQuery(mQueryObjectName);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_FALSE(isQueryResult);
+}
+
+// Negative test for glGetQueryObjectuiv before glBegin with GL_QUERY_RESULT
+TEST_P(QueryObjectTest, QueryObjectResultBeforeBegin)
+{
+ glGetQueryObjectuiv(mQueryObjectName, GL_QUERY_RESULT, &mQueryResult);
+
+ bool isNoError = testing::get<1>(GetParam());
+ if (isNoError)
+ {
+ ASSERT_GL_NO_ERROR();
+ }
+ else
+ {
+ ASSERT_EQ(glGetError(), (GLenum)GL_INVALID_OPERATION);
+ }
+}
+
+// Negative test for glGetQueryObjectuiv before glBegin with GL_QUERY_RESULT_AVAILABLE
+TEST_P(QueryObjectTest, QueryObjectResultAvailableBeforeBegin)
+{
+ glGetQueryObjectuiv(mQueryObjectName, GL_QUERY_RESULT_AVAILABLE, &mQueryResult);
+
+ bool isNoError = testing::get<1>(GetParam());
+ if (isNoError)
+ {
+ ASSERT_GL_NO_ERROR();
+ }
+ else
+ {
+ ASSERT_EQ(glGetError(), (GLenum)GL_INVALID_OPERATION);
+ }
+}
+
+// Test glGetQueryObjectuiv after glEndQuery
+TEST_P(QueryObjectTest, QueryObjectResultAfterEnd)
+{
+ glBeginQuery(GL_ANY_SAMPLES_PASSED, mQueryObjectName);
+ ASSERT_GL_NO_ERROR();
+
+ glEndQuery(GL_ANY_SAMPLES_PASSED);
+ ASSERT_GL_NO_ERROR();
+
+ glGetQueryObjectuiv(mQueryObjectName, GL_QUERY_RESULT_AVAILABLE, &mQueryResult);
+}
+
+// Test glGetQueryObjectuiv after glEndQuery with GL_PRIMITIVES_GENERATED
+TEST_P(QueryObjectTestES32, QueryObjectResultAfterEndPrimitivesGenerated)
+{
+ // TODO(anglebug.com/5430): Allow GL_PRIMITIVES_GENERATED query objects
+ // when transform feedback is not active
+ ANGLE_SKIP_TEST_IF(IsVulkan());
+ glBeginQuery(GL_PRIMITIVES_GENERATED, mQueryObjectName);
+ ASSERT_GL_NO_ERROR();
+
+ glEndQuery(GL_PRIMITIVES_GENERATED);
+ ASSERT_GL_NO_ERROR();
+
+ while (mQueryResult != GL_TRUE)
+ {
+ glGetQueryObjectuiv(mQueryObjectName, GL_QUERY_RESULT_AVAILABLE, &mQueryResult);
+ ASSERT_GL_NO_ERROR();
+ angle::Sleep(50);
+ }
+
+ GLboolean isQueryResult = glIsQuery(mQueryObjectName);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_TRUE(isQueryResult);
+}
+
+static const bool noErrorFlags[] = {true, false};
+
+ANGLE_INSTANTIATE_TEST_COMBINE_1(QueryObjectTest,
+ PrintToStringParamName,
+ testing::ValuesIn(noErrorFlags),
+ ANGLE_ALL_TEST_PLATFORMS_ES3);
+
+ANGLE_INSTANTIATE_TEST_COMBINE_1(QueryObjectTestES32,
+ PrintToStringParamName,
+ testing::ValuesIn(noErrorFlags),
+ ANGLE_ALL_TEST_PLATFORMS_ES32);
+
+// This test suite is not instantiated on some OSes.
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(QueryObjectTestES32);
+
+} // namespace angle