diff --git a/MobileGL/MG_Test/Query/QueryTest.cpp b/MobileGL/MG_Test/Query/QueryTest.cpp index 49dc3410..78c3c7d9 100644 --- a/MobileGL/MG_Test/Query/QueryTest.cpp +++ b/MobileGL/MG_Test/Query/QueryTest.cpp @@ -144,10 +144,19 @@ TEST_F(QueryTest, GenQueriesReturnsDistinctNonzeroIdsAndTracksLiveness) { EXPECT_NE(ids[0], ids[2]); EXPECT_NE(ids[1], ids[2]); + // GenQueries only reserves names: "they acquire query state only when they are first used by + // calling BeginQuery" (GL 4.6 core 4.2.1), and IsQuery answers for objects, not for reserved + // names. So all three read as FALSE here even though the names are taken. EXPECT_EQ(MG_Impl::GLImpl::IsQuery(0), GL_FALSE); + EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[0]), GL_FALSE); + EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[1]), GL_FALSE); + EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[2]), GL_FALSE); + + // First use is what creates the object. + MG_Impl::GLImpl::BeginQuery(GL_TIME_ELAPSED, ids[0]); + MG_Impl::GLImpl::EndQuery(GL_TIME_ELAPSED); EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[0]), GL_TRUE); - EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[1]), GL_TRUE); - EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[2]), GL_TRUE); + EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[1]), GL_FALSE); MG_Impl::GLImpl::DeleteQueries(3, ids); EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[0]), GL_FALSE); @@ -157,6 +166,26 @@ TEST_F(QueryTest, GenQueriesReturnsDistinctNonzeroIdsAndTracksLiveness) { EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); } +// The direct state access counterpart: glCreateQueries creates the object outright, so unlike a +// glGenQueries name it is a query before anything is ever recorded into it. +TEST_F(QueryTest, CreateQueriesYieldsQueryObjectsImmediately) { + GLuint ids[2] = {0, 0}; + MG_Impl::GLImpl::CreateQueries(GL_TIME_ELAPSED, 2, ids); + + EXPECT_NE(ids[0], 0u); + EXPECT_NE(ids[1], 0u); + EXPECT_NE(ids[0], ids[1]); + + EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[0]), GL_TRUE); + EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[1]), GL_TRUE); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); + + MG_Impl::GLImpl::DeleteQueries(2, ids); + EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[0]), GL_FALSE); + EXPECT_EQ(MG_Impl::GLImpl::IsQuery(ids[1]), GL_FALSE); + EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR); +} + TEST_F(QueryTest, TimeElapsedSpanFallsBackToImmediateZeroResult) { GLuint id = 0; MG_Impl::GLImpl::GenQueries(1, &id); diff --git a/MobileGL/MG_Test/SanityTest.cpp b/MobileGL/MG_Test/SanityTest.cpp index 130be5f0..7b64ad14 100644 --- a/MobileGL/MG_Test/SanityTest.cpp +++ b/MobileGL/MG_Test/SanityTest.cpp @@ -244,6 +244,19 @@ TEST(DirectGLESSanity, BindingZeroClearsPreviousNativeTextureBinding) { ASSERT_NE(frontendTextureObject, nullptr); ASSERT_EQ(frontendTextureObject->GetExternalIndex(), frontendTexture); + // A texture with no image is incomplete, and an incomplete texture samples as (0, 0, 0, 1) - + // which DirectGLES expresses by leaving the native target unbound (see "sample a + // mipmap-incomplete texture as black"). This test is about the bind-0 clear, so the texture + // has to be complete enough to get bound in the first place: a format plus a level 0. At 1x1 + // that single level is the whole mip chain, so it stays complete under any filter. The state + // is set directly rather than through glTexImage2D because the mock GLES table below wires + // only the binding entry points, not the upload path. + frontendTextureObject->SetInternalFormat(TextureInternalFormat::RGBA8); + MG_State::GLState::AsMipmapTexture(frontendTextureObject.get()) + ->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{1, 1, 1}, 4}); + ASSERT_FALSE(MG_State::GLState::SamplesAsIncompleteTexture( + frontendTextureObject.get(), frontendTextureObject->GetSamplerObject().get())); + auto& backendTexture = DirectGLES::TextureImpl::g_backendTextureObjects.GetOrCreate(frontendTextureObject); backendTexture = MakeShared(); const GLuint backendTextureId = backendTexture->GetBackendTextureId();