diff options
17 files changed, 659 insertions, 442 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index fbaa67d..59bbde3 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -451,6 +451,7 @@ _ENUM_LISTS = { 'valid': [ 'GL_ANY_SAMPLES_PASSED_EXT', 'GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT', + 'GL_COMMANDS_ISSUED_CHROMIUM', ], }, 'RenderBufferParameter': { @@ -795,6 +796,7 @@ _PEPPER_INTERFACES = [ # valid_args: A dictionary of argument indices to args to use in unit tests # when they can not be automatically determined. # pepper_interface: The pepper interface that is used for this extension +# invalid_test: False if no invalid test needed. _FUNCTION_INFO = { 'ActiveTexture': { @@ -1594,12 +1596,14 @@ _FUNCTION_INFO = { 'gl_test_func': 'glGenQueriesARB', 'resource_type': 'Query', 'resource_types': 'Queries', + 'unit_test': False, }, 'DeleteQueriesEXT': { 'type': 'DELn', 'gl_test_func': 'glDeleteQueriesARB', 'resource_type': 'Query', 'resource_types': 'Queries', + 'unit_test': False, }, 'IsQueryEXT': { 'gen_cmd': False, @@ -2797,7 +2801,7 @@ TEST_F(%(test_name)s, %(name)sValidArgs) { EXPECT_TRUE(Get%(resource_name)sInfo(kNewClientId) != NULL); } """ - self.WriteValidUnitTest(func, file, valid_test, { + self.WriteValidUnitTest(func, file, valid_test, { 'resource_name': func.GetInfo('resource_type'), }) invalid_test = """ diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 6ec6e14..495a913 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -1410,8 +1410,7 @@ void TexStorage2DEXT( } void GenQueriesEXT(GLsizei n, GLuint* queries) { - GPU_CLIENT_LOG("[" << this << "] glGenQueriesEXT(" << n << ", " - << static_cast<const void*>(queries) << ")"); // NOLINT + GPU_CLIENT_LOG("[" << this << "] glGenQueriesEXT(" << n << ", " << static_cast<const void*>(queries) << ")"); // NOLINT if (n < 0) { SetGLError(GL_INVALID_VALUE, "glGenQueriesEXT: n < 0"); return; @@ -1429,8 +1428,7 @@ void GenQueriesEXT(GLsizei n, GLuint* queries) { void DeleteQueriesEXT(GLsizei n, const GLuint* queries) { GPU_CLIENT_SINGLE_THREAD_CHECK(); - GPU_CLIENT_LOG("[" << this << "] glDeleteQueriesEXT(" << n << ", " - << static_cast<const void*>(queries) << ")"); // NOLINT + GPU_CLIENT_LOG("[" << this << "] glDeleteQueriesEXT(" << n << ", " << static_cast<const void*>(queries) << ")"); // NOLINT GPU_CLIENT_LOG_CODE_BLOCK({ for (GLsizei i = 0; i < n; ++i) { GPU_CLIENT_LOG(" " << i << ": " << queries[i]); diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h index 26e7bf8..2d725d0 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h @@ -941,6 +941,7 @@ std::string GLES2Util::GetStringQueryTarget(uint32 value) { { GL_ANY_SAMPLES_PASSED_EXT, "GL_ANY_SAMPLES_PASSED_EXT" }, { GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, "GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT" }, + { GL_COMMANDS_ISSUED_CHROMIUM, "GL_COMMANDS_ISSUED_CHROMIUM" }, }; return GLES2Util::GetQualifiedEnumString( string_table, arraysize(string_table), value); diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index b31a5e5..9b83aca 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -118,6 +118,7 @@ void FeatureInfo::AddFeatures(const char* desired_features) { AddExtensionString("GL_CHROMIUM_rate_limit_offscreen_context"); AddExtensionString("GL_CHROMIUM_set_visibility"); AddExtensionString("GL_CHROMIUM_gpu_memory_manager"); + AddExtensionString("GL_CHROMIUM_command_buffer_query"); AddExtensionString("GL_ANGLE_translated_shader_source"); if (ext.Have("GL_ANGLE_translated_shader_source")) { @@ -439,12 +440,15 @@ void FeatureInfo::AddFeatures(const char* desired_features) { } } + bool have_ext_occlusion_query_boolean = + ext.Have("GL_EXT_occlusion_query_boolean"); + bool have_arb_occlusion_query2 = ext.Have("GL_ARB_occlusion_query2"); if (ext.Desire("GL_EXT_occlusion_query_boolean") && - (ext.Have("GL_EXT_occlusion_query_boolean") || - ext.Have("GL_ARB_occlusion_query2"))) { - // TODO(gman): Comment in the next line once this really works. - // AddExtensionString("GL_EXT_occlusion_query_boolean"); + (have_ext_occlusion_query_boolean || have_arb_occlusion_query2)) { + AddExtensionString("GL_EXT_occlusion_query_boolean"); feature_flags_.occlusion_query_boolean = true; + feature_flags_.use_arb_occlusion_query2_for_occlusion_query_boolean = + !have_ext_occlusion_query_boolean; } if (ext.Desire("GL_ANGLE_instanced_arrays") && diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 4bac947..71c9b71 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h @@ -33,7 +33,8 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> { angle_pack_reverse_row_order(false), arb_texture_rectangle(false), angle_instanced_arrays(false), - occlusion_query_boolean(false) { + occlusion_query_boolean(false), + use_arb_occlusion_query2_for_occlusion_query_boolean(false) { } bool chromium_framebuffer_multisample; @@ -49,6 +50,7 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> { bool arb_texture_rectangle; bool angle_instanced_arrays; bool occlusion_query_boolean; + bool use_arb_occlusion_query2_for_occlusion_query_boolean; }; FeatureInfo(); diff --git a/gpu/command_buffer/service/gl_utils.h b/gpu/command_buffer/service/gl_utils.h index ce65cb2..64495b3 100644 --- a/gpu/command_buffer/service/gl_utils.h +++ b/gpu/command_buffer/service/gl_utils.h @@ -76,6 +76,10 @@ #define GL_QUERY_RESULT_EXT 0x8866 #define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867 +// GL_CHROMIUM_command_buffer_query +#define GL_COMMANDS_ISSUED_CHROMIUM 0x84F2 + + #define GL_GLEXT_PROTOTYPES 1 // Define this for extra GL error debugging (slower). diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 2f4c1e6..3811ac8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -2023,7 +2023,8 @@ bool GLES2DecoderImpl::Initialize( vertex_attrib_manager_.reset(new VertexAttribManager()); vertex_attrib_manager_->Initialize(group_->max_vertex_attribs()); - query_manager_.reset(new QueryManager()); + query_manager_.reset(new QueryManager(this, feature_info_->feature_flags( + ).use_arb_occlusion_query2_for_occlusion_query_boolean)); util_.set_num_compressed_texture_formats( validators_->compressed_texture_format.GetValues().size()); @@ -7931,11 +7932,7 @@ bool GLES2DecoderImpl::GenQueriesEXTHelper( return false; } } - scoped_array<GLuint> service_ids(new GLuint[n]); - glGenQueriesARB(n, service_ids.get()); - for (GLsizei ii = 0; ii < n; ++ii) { - query_manager_->CreateQuery(client_ids[ii], service_ids[ii]); - } + // NOTE: We don't generate Query objects here. Only in BeginQueryEXT return true; } @@ -7947,8 +7944,7 @@ void GLES2DecoderImpl::DeleteQueriesEXTHelper( if (query == current_query_) { current_query_ = NULL; } - GLuint service_id = query->service_id(); - glDeleteQueriesARB(1, &service_id); + query->Destroy(true); query_manager_->RemoveQuery(client_ids[ii]); } } @@ -7958,7 +7954,7 @@ bool GLES2DecoderImpl::ProcessPendingQueries() { if (query_manager_.get() == NULL) { return false; } - if (!query_manager_->ProcessPendingQueries(this)) { + if (!query_manager_->ProcessPendingQueries()) { current_decoder_error_ = error::kOutOfBounds; } return query_manager_->HavePendingQueries(); @@ -7971,9 +7967,15 @@ error::Error GLES2DecoderImpl::HandleBeginQueryEXT( int32 sync_shm_id = static_cast<int32>(c.sync_data_shm_id); uint32 sync_shm_offset = static_cast<uint32>(c.sync_data_shm_offset); - if (!feature_info_->feature_flags().occlusion_query_boolean) { - SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT: not enabled"); - return error::kNoError; + switch (target) { + case GL_COMMANDS_ISSUED_CHROMIUM: + break; + default: + if (!feature_info_->feature_flags().occlusion_query_boolean) { + SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT: not enabled"); + return error::kNoError; + } + break; } if (current_query_) { @@ -7989,31 +7991,28 @@ error::Error GLES2DecoderImpl::HandleBeginQueryEXT( QueryManager::Query* query = query_manager_->GetQuery(client_id); if (!query) { + // TODO(gman): Decide if we need this check. + // // Checks id was made by glGenQueries - IdAllocatorInterface* id_allocator = - group_->GetIdAllocator(id_namespaces::kQueries); - if (!id_allocator->InUse(client_id)) { - SetGLError(GL_INVALID_OPERATION, - "glBeginQueryEXT: id not made by glGenQueriesEXT"); - return error::kNoError; - } - // Makes object and assoicates with memory. - GLuint service_id = 0; - glGenQueriesARB(1, &service_id); - DCHECK_NE(0u, service_id); - query = query_manager_->CreateQuery(client_id, service_id); - } - - QuerySync* sync = GetSharedMemoryAs<QuerySync*>( - sync_shm_id, sync_shm_offset, sizeof(*sync)); - if (!sync) { - DLOG(ERROR) << "Invalid shared memory referenced by query"; - return error::kOutOfBounds; - } - - if (!query->IsInitialized()) { - query->Initialize(target, sync_shm_id, sync_shm_offset); - } else if (query->target() != target) { + // + // From the POV of OpenGL ES 2.0 you need to call glGenQueriesEXT + // for all Query ids but from the POV of the command buffer service maybe + // you don't. + // + // The client can enforce this. I don't think the service cares. + // + // IdAllocatorInterface* id_allocator = + // group_->GetIdAllocator(id_namespaces::kQueries); + // if (!id_allocator->InUse(client_id)) { + // SetGLError(GL_INVALID_OPERATION, + // "glBeginQueryEXT: id not made by glGenQueriesEXT"); + // return error::kNoError; + // } + query = query_manager_->CreateQuery( + target, client_id, sync_shm_id, sync_shm_offset); + } + + if (query->target() != target) { SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT: target does not match"); return error::kNoError; } else if (query->shm_id() != sync_shm_id || @@ -8022,11 +8021,11 @@ error::Error GLES2DecoderImpl::HandleBeginQueryEXT( return error::kInvalidArguments; } - query_manager_->RemovePendingQuery(query); + if (!query_manager_->BeginQuery(query)) { + return error::kOutOfBounds; + } - glBeginQueryARB(target, query->service_id()); current_query_ = query; - return error::kNoError; } @@ -8044,10 +8043,12 @@ error::Error GLES2DecoderImpl::HandleEndQueryEXT( "glEndQueryEXT: target does not match active query"); return error::kNoError; } - glEndQueryARB(target); - query_manager_->AddPendingQuery(current_query_, submit_count); - current_query_ = NULL; + if (!query_manager_->EndQuery(current_query_, submit_count)) { + return error::kOutOfBounds; + } + + current_query_ = NULL; return error::kNoError; } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 94f2e95..ca1d5c6 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -6583,13 +6583,7 @@ TEST_F(GLES2DecoderManualInitTest, BeingEndQueryEXT) { EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd)); EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); - // Test a non-generated id fails. BeginQueryEXT begin_cmd; - begin_cmd.Init( - GL_ANY_SAMPLES_PASSED_EXT, kInvalidClientId, - kSharedMemoryId, kSharedMemoryOffset); - EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd)); - EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); // Test id = 0 fails. begin_cmd.Init( @@ -6597,22 +6591,12 @@ TEST_F(GLES2DecoderManualInitTest, BeingEndQueryEXT) { EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd)); EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); - EXPECT_CALL(*gl_, GenQueriesARB(1, _)) - .WillOnce(SetArgumentPointee<1>(kNewServiceId)) - .RetiresOnSaturation(); GenHelper<GenQueriesEXTImmediate>(kNewClientId); - // Test bad shared memory fails - begin_cmd.Init( - GL_ANY_SAMPLES_PASSED_EXT, kNewClientId, - kInvalidSharedMemoryId, kSharedMemoryOffset); - EXPECT_NE(error::kNoError, ExecuteCmd(begin_cmd)); - begin_cmd.Init( - GL_ANY_SAMPLES_PASSED_EXT, kNewClientId, - kSharedMemoryId, kInvalidSharedMemoryOffset); - EXPECT_NE(error::kNoError, ExecuteCmd(begin_cmd)); - // Test valid parameters work. + EXPECT_CALL(*gl_, GenQueriesARB(1, _)) + .WillOnce(SetArgumentPointee<1>(kNewServiceId)) + .RetiresOnSaturation(); EXPECT_CALL(*gl_, BeginQueryARB(GL_ANY_SAMPLES_PASSED_EXT, kNewServiceId)) .Times(1) .RetiresOnSaturation(); @@ -6651,6 +6635,117 @@ TEST_F(GLES2DecoderManualInitTest, BeingEndQueryEXT) { .RetiresOnSaturation(); } +static void CheckBeginEndQueryBadMemoryFails( + GLES2DecoderTestBase* test, + GLuint client_id, + GLuint service_id, + int32 shm_id, + uint32 shm_offset) { + ::testing::StrictMock< ::gfx::MockGLInterface>* gl = test->GetGLMock(); + + BeginQueryEXT begin_cmd; + + test->GenHelper<GenQueriesEXTImmediate>(client_id); + + EXPECT_CALL(*gl, GenQueriesARB(1, _)) + .WillOnce(SetArgumentPointee<1>(service_id)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, BeginQueryARB(GL_ANY_SAMPLES_PASSED_EXT, service_id)) + .Times(1) + .RetiresOnSaturation(); + + // Test bad shared memory fails + begin_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, client_id, shm_id, shm_offset); + error::Error error1 = test->ExecuteCmd(begin_cmd); + + EXPECT_CALL(*gl, EndQueryARB(GL_ANY_SAMPLES_PASSED_EXT)) + .Times(1) + .RetiresOnSaturation(); + + EndQueryEXT end_cmd; + end_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, 1); + error::Error error2 = test->ExecuteCmd(end_cmd); + + EXPECT_CALL(*gl, + GetQueryObjectuivARB(service_id, GL_QUERY_RESULT_AVAILABLE_EXT, _)) + .WillOnce(SetArgumentPointee<2>(1)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, + GetQueryObjectuivARB(service_id, GL_QUERY_RESULT_EXT, _)) + .WillOnce(SetArgumentPointee<2>(1)) + .RetiresOnSaturation(); + + QueryManager* query_manager = test->GetDecoder()->GetQueryManager(); + ASSERT_TRUE(query_manager != NULL); + bool process_success = query_manager->ProcessPendingQueries(); + + EXPECT_TRUE(error1 != error::kNoError || + error2 != error::kNoError || + !process_success); + + EXPECT_CALL(*gl, DeleteQueriesARB(1, _)) + .Times(1) + .RetiresOnSaturation(); +} + +TEST_F(GLES2DecoderManualInitTest, BeingEndQueryEXTBadMemoryIdFails) { + InitDecoder( + "GL_EXT_occlusion_query_boolean", // extensions + true, // has alpha + false, // has depth + false, // has stencil + true, // request alpha + false, // request depth + false, // request stencil + true); // bind generates resource + + CheckBeginEndQueryBadMemoryFails( + this, kNewClientId, kNewServiceId, + kInvalidSharedMemoryId, kSharedMemoryOffset); +} + +TEST_F(GLES2DecoderManualInitTest, BeingEndQueryEXTBadMemoryOffsetFails) { + InitDecoder( + "GL_EXT_occlusion_query_boolean", // extensions + true, // has alpha + false, // has depth + false, // has stencil + true, // request alpha + false, // request depth + false, // request stencil + true); // bind generates resource + + CheckBeginEndQueryBadMemoryFails( + this, kNewClientId, kNewServiceId, + kSharedMemoryId, kInvalidSharedMemoryOffset); +} + +TEST_F(GLES2DecoderTest, BeingEndQueryEXTCommandsIssuedCHROMIUM) { + BeginQueryEXT begin_cmd; + + GenHelper<GenQueriesEXTImmediate>(kNewClientId); + + // Test valid parameters work. + begin_cmd.Init( + GL_COMMANDS_ISSUED_CHROMIUM, kNewClientId, + kSharedMemoryId, kSharedMemoryOffset); + EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + QueryManager* query_manager = decoder_->GetQueryManager(); + ASSERT_TRUE(query_manager != NULL); + QueryManager::Query* query = query_manager->GetQuery(kNewClientId); + ASSERT_TRUE(query != NULL); + EXPECT_FALSE(query->pending()); + + // Test end succeeds + EndQueryEXT end_cmd; + end_cmd.Init(GL_COMMANDS_ISSUED_CHROMIUM, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_FALSE(query->pending()); +} + // TODO(gman): Complete this test. // TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc index f92a0f6..d9adbfb 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc @@ -39,17 +39,10 @@ void GLES2DecoderTestBase::SpecializedSetup<GenQueriesEXT, 0>( // Make the client_query_id_ so that trying to make it again // will fail. GetSharedMemoryAs<GLuint*>()[0] = client_query_id_; - EXPECT_CALL(*gl_, GenQueriesARB(1, _)) - .WillOnce(SetArgumentPointee<1>(kNewServiceId)); GenQueriesEXT cmd; cmd.Init(1, shared_memory_id_, shared_memory_offset_); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); } - // In the valid case this deletes the one created in the test. In the invalid - // case it deleted the one above. - EXPECT_CALL(*gl_, DeleteQueriesARB(1, _)) - .Times(1) - .RetiresOnSaturation(); }; template <> @@ -59,17 +52,10 @@ void GLES2DecoderTestBase::SpecializedSetup<GenQueriesEXTImmediate, 0>( // Make the client_query_id_ so that trying to make it again // will fail. GetSharedMemoryAs<GLuint*>()[0] = client_query_id_; - EXPECT_CALL(*gl_, GenQueriesARB(1, _)) - .WillOnce(SetArgumentPointee<1>(kNewServiceId)); GenQueriesEXT cmd; cmd.Init(1, shared_memory_id_, shared_memory_offset_); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); } - // In the valid case this deletes the one created in the test. In the invalid - // case it deleted the one above. - EXPECT_CALL(*gl_, DeleteQueriesARB(1, _)) - .Times(1) - .RetiresOnSaturation(); }; template <> @@ -78,8 +64,6 @@ void GLES2DecoderTestBase::SpecializedSetup<DeleteQueriesEXT, 0>( if (valid) { // Make the client_query_id_ so that trying to delete it will succeed. GetSharedMemoryAs<GLuint*>()[0] = client_query_id_; - EXPECT_CALL(*gl_, GenQueriesARB(1, _)) - .WillOnce(SetArgumentPointee<1>(kServiceQueryId)); GenQueriesEXT cmd; cmd.Init(1, shared_memory_id_, shared_memory_offset_); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); @@ -92,8 +76,6 @@ void GLES2DecoderTestBase::SpecializedSetup<DeleteQueriesEXTImmediate, 0>( if (valid) { // Make the client_query_id_ so that trying to delete it will succeed. GetSharedMemoryAs<GLuint*>()[0] = client_query_id_; - EXPECT_CALL(*gl_, GenQueriesARB(1, _)) - .WillOnce(SetArgumentPointee<1>(kServiceQueryId)); GenQueriesEXT cmd; cmd.Init(1, shared_memory_id_, shared_memory_offset_); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h index ea1be28..6a62607 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h @@ -1806,98 +1806,10 @@ TEST_F(GLES2DecoderTest2, ViewportInvalidArgs3_0) { // TODO(gman): BlitFramebufferEXT // TODO(gman): RenderbufferStorageMultisampleEXT // TODO(gman): TexStorage2DEXT - -TEST_F(GLES2DecoderTest2, GenQueriesEXTValidArgs) { - EXPECT_CALL(*gl_, GenQueriesARB(1, _)) - .WillOnce(SetArgumentPointee<1>(kNewServiceId)); - GetSharedMemoryAs<GLuint*>()[0] = kNewClientId; - SpecializedSetup<GenQueriesEXT, 0>(true); - GenQueriesEXT cmd; - cmd.Init(1, shared_memory_id_, shared_memory_offset_); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); - EXPECT_TRUE(GetQueryInfo(kNewClientId) != NULL); -} - -TEST_F(GLES2DecoderTest2, GenQueriesEXTInvalidArgs) { - EXPECT_CALL(*gl_, GenQueriesARB(_, _)).Times(0); - GetSharedMemoryAs<GLuint*>()[0] = client_query_id_; - SpecializedSetup<GenQueriesEXT, 0>(false); - GenQueriesEXT cmd; - cmd.Init(1, shared_memory_id_, shared_memory_offset_); - EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd)); -} - -TEST_F(GLES2DecoderTest2, GenQueriesEXTImmediateValidArgs) { - EXPECT_CALL(*gl_, GenQueriesARB(1, _)) - .WillOnce(SetArgumentPointee<1>(kNewServiceId)); - GenQueriesEXTImmediate* cmd = GetImmediateAs<GenQueriesEXTImmediate>(); - GLuint temp = kNewClientId; - SpecializedSetup<GenQueriesEXTImmediate, 0>(true); - cmd->Init(1, &temp); - EXPECT_EQ(error::kNoError, - ExecuteImmediateCmd(*cmd, sizeof(temp))); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); - EXPECT_TRUE(GetQueryInfo(kNewClientId) != NULL); -} - -TEST_F(GLES2DecoderTest2, GenQueriesEXTImmediateInvalidArgs) { - EXPECT_CALL(*gl_, GenQueriesARB(_, _)).Times(0); - GenQueriesEXTImmediate* cmd = GetImmediateAs<GenQueriesEXTImmediate>(); - SpecializedSetup<GenQueriesEXTImmediate, 0>(false); - cmd->Init(1, &client_query_id_); - EXPECT_EQ(error::kInvalidArguments, - ExecuteImmediateCmd(*cmd, sizeof(&client_query_id_))); -} - -TEST_F(GLES2DecoderTest2, DeleteQueriesEXTValidArgs) { - EXPECT_CALL( - *gl_, - DeleteQueriesARB(1, Pointee(kServiceQueryId))) - .Times(1); - GetSharedMemoryAs<GLuint*>()[0] = client_query_id_; - SpecializedSetup<DeleteQueriesEXT, 0>(true); - DeleteQueriesEXT cmd; - cmd.Init(1, shared_memory_id_, shared_memory_offset_); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); - EXPECT_TRUE( - GetQueryInfo(client_query_id_) == NULL); -} - -TEST_F(GLES2DecoderTest2, DeleteQueriesEXTInvalidArgs) { - GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId; - SpecializedSetup<DeleteQueriesEXT, 0>(false); - DeleteQueriesEXT cmd; - cmd.Init(1, shared_memory_id_, shared_memory_offset_); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); -} - -TEST_F(GLES2DecoderTest2, DeleteQueriesEXTImmediateValidArgs) { - EXPECT_CALL( - *gl_, - DeleteQueriesARB(1, Pointee(kServiceQueryId))) - .Times(1); - DeleteQueriesEXTImmediate& cmd = - *GetImmediateAs<DeleteQueriesEXTImmediate>(); - SpecializedSetup<DeleteQueriesEXTImmediate, 0>(true); - cmd.Init(1, &client_query_id_); - EXPECT_EQ(error::kNoError, - ExecuteImmediateCmd(cmd, sizeof(client_query_id_))); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); - EXPECT_TRUE( - GetQueryInfo(client_query_id_) == NULL); -} - -TEST_F(GLES2DecoderTest2, DeleteQueriesEXTImmediateInvalidArgs) { - DeleteQueriesEXTImmediate& cmd = - *GetImmediateAs<DeleteQueriesEXTImmediate>(); - SpecializedSetup<DeleteQueriesEXTImmediate, 0>(false); - GLuint temp = kInvalidClientId; - cmd.Init(1, &temp); - EXPECT_EQ(error::kNoError, - ExecuteImmediateCmd(cmd, sizeof(temp))); -} +// TODO(gman): GenQueriesEXT +// TODO(gman): GenQueriesEXTImmediate +// TODO(gman): DeleteQueriesEXT +// TODO(gman): DeleteQueriesEXTImmediate // TODO(gman): BeginQueryEXT // TODO(gman): EndQueryEXT diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index 7dcdddb..c73fb0a 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h @@ -30,94 +30,6 @@ class GLES2DecoderTestBase : public testing::Test { GLES2DecoderTestBase(); virtual ~GLES2DecoderTestBase(); - protected: - static const GLint kMaxTextureSize = 2048; - static const GLint kMaxCubeMapTextureSize = 256; - static const GLint kNumVertexAttribs = 16; - static const GLint kNumTextureUnits = 8; - static const GLint kMaxTextureImageUnits = 8; - static const GLint kMaxVertexTextureImageUnits = 2; - static const GLint kMaxFragmentUniformVectors = 16; - static const GLint kMaxVaryingVectors = 8; - static const GLint kMaxVertexUniformVectors = 128; - - static const GLuint kServiceAttrib0BufferId = 801; - static const GLuint kServiceFixedAttribBufferId = 802; - - static const GLuint kServiceBufferId = 301; - static const GLuint kServiceFramebufferId = 302; - static const GLuint kServiceRenderbufferId = 303; - static const GLuint kServiceTextureId = 304; - static const GLuint kServiceProgramId = 305; - static const GLuint kServiceShaderId = 306; - static const GLuint kServiceElementBufferId = 308; - static const GLuint kServiceQueryId = 309; - - static const int32 kSharedMemoryId = 401; - static const size_t kSharedBufferSize = 2048; - static const uint32 kSharedMemoryOffset = 132; - static const int32 kInvalidSharedMemoryId = 402; - static const uint32 kInvalidSharedMemoryOffset = kSharedBufferSize + 1; - static const uint32 kInitialResult = 0xBDBDBDBDu; - static const uint8 kInitialMemoryValue = 0xBDu; - - static const uint32 kNewClientId = 501; - static const uint32 kNewServiceId = 502; - static const uint32 kInvalidClientId = 601; - - static const int kBackBufferWidth = 128; - static const int kBackBufferHeight = 64; - - static const GLuint kServiceVertexShaderId = 321; - static const GLuint kServiceFragmentShaderId = 322; - - static const GLsizei kNumVertices = 100; - static const GLsizei kNumIndices = 10; - static const int kValidIndexRangeStart = 1; - static const int kValidIndexRangeCount = 7; - static const int kInvalidIndexRangeStart = 0; - static const int kInvalidIndexRangeCount = 7; - static const int kOutOfRangeIndexRangeEnd = 10; - static const GLuint kMaxValidIndex = 7; - - static const GLint kMaxAttribLength = 10; - static const char* kAttrib1Name; - static const char* kAttrib2Name; - static const char* kAttrib3Name; - static const GLint kAttrib1Size = 1; - static const GLint kAttrib2Size = 1; - static const GLint kAttrib3Size = 1; - static const GLint kAttrib1Location = 0; - static const GLint kAttrib2Location = 1; - static const GLint kAttrib3Location = 2; - static const GLenum kAttrib1Type = GL_FLOAT_VEC4; - static const GLenum kAttrib2Type = GL_FLOAT_VEC2; - static const GLenum kAttrib3Type = GL_FLOAT_VEC3; - static const GLint kInvalidAttribLocation = 30; - static const GLint kBadAttribIndex = kNumVertexAttribs; - - static const GLint kMaxUniformLength = 12; - static const char* kUniform1Name; - static const char* kUniform2Name; - static const char* kUniform3Name; - static const GLint kUniform1Size = 1; - static const GLint kUniform2Size = 3; - static const GLint kUniform3Size = 2; - static const GLint kUniform1RealLocation = 3; - static const GLint kUniform2RealLocation = 10; - static const GLint kUniform2ElementRealLocation = 12; - static const GLint kUniform3RealLocation = 20; - static const GLint kUniform1FakeLocation = 0; // These are - static const GLint kUniform2FakeLocation = 1; // hardcoded - static const GLint kUniform2ElementFakeLocation = 0x10001; // to match - static const GLint kUniform3FakeLocation = 2; // ProgramManager. - static const GLenum kUniform1Type = GL_SAMPLER_2D; - static const GLenum kUniform2Type = GL_INT_VEC2; - static const GLenum kUniform3Type = GL_FLOAT_VEC3; - static const GLenum kUniformCubemapType = GL_SAMPLER_CUBE; - static const GLint kInvalidUniformLocation = 30; - static const GLint kBadUniformIndex = 1000; - // Template to call glGenXXX functions. template <typename T> void GenHelper(GLuint client_id) { @@ -234,6 +146,14 @@ class GLES2DecoderTestBase : public testing::Test { return *group_.get(); } + ::testing::StrictMock< ::gfx::MockGLInterface>* GetGLMock() const { + return gl_.get(); + } + + GLES2Decoder* GetDecoder() const { + return decoder_.get(); + } + struct AttribInfo { const char* name; GLint size; @@ -405,6 +325,94 @@ class GLES2DecoderTestBase : public testing::Test { return isObject; } + protected: + static const GLint kMaxTextureSize = 2048; + static const GLint kMaxCubeMapTextureSize = 256; + static const GLint kNumVertexAttribs = 16; + static const GLint kNumTextureUnits = 8; + static const GLint kMaxTextureImageUnits = 8; + static const GLint kMaxVertexTextureImageUnits = 2; + static const GLint kMaxFragmentUniformVectors = 16; + static const GLint kMaxVaryingVectors = 8; + static const GLint kMaxVertexUniformVectors = 128; + + static const GLuint kServiceAttrib0BufferId = 801; + static const GLuint kServiceFixedAttribBufferId = 802; + + static const GLuint kServiceBufferId = 301; + static const GLuint kServiceFramebufferId = 302; + static const GLuint kServiceRenderbufferId = 303; + static const GLuint kServiceTextureId = 304; + static const GLuint kServiceProgramId = 305; + static const GLuint kServiceShaderId = 306; + static const GLuint kServiceElementBufferId = 308; + static const GLuint kServiceQueryId = 309; + + static const int32 kSharedMemoryId = 401; + static const size_t kSharedBufferSize = 2048; + static const uint32 kSharedMemoryOffset = 132; + static const int32 kInvalidSharedMemoryId = 402; + static const uint32 kInvalidSharedMemoryOffset = kSharedBufferSize + 1; + static const uint32 kInitialResult = 0xBDBDBDBDu; + static const uint8 kInitialMemoryValue = 0xBDu; + + static const uint32 kNewClientId = 501; + static const uint32 kNewServiceId = 502; + static const uint32 kInvalidClientId = 601; + + static const int kBackBufferWidth = 128; + static const int kBackBufferHeight = 64; + + static const GLuint kServiceVertexShaderId = 321; + static const GLuint kServiceFragmentShaderId = 322; + + static const GLsizei kNumVertices = 100; + static const GLsizei kNumIndices = 10; + static const int kValidIndexRangeStart = 1; + static const int kValidIndexRangeCount = 7; + static const int kInvalidIndexRangeStart = 0; + static const int kInvalidIndexRangeCount = 7; + static const int kOutOfRangeIndexRangeEnd = 10; + static const GLuint kMaxValidIndex = 7; + + static const GLint kMaxAttribLength = 10; + static const char* kAttrib1Name; + static const char* kAttrib2Name; + static const char* kAttrib3Name; + static const GLint kAttrib1Size = 1; + static const GLint kAttrib2Size = 1; + static const GLint kAttrib3Size = 1; + static const GLint kAttrib1Location = 0; + static const GLint kAttrib2Location = 1; + static const GLint kAttrib3Location = 2; + static const GLenum kAttrib1Type = GL_FLOAT_VEC4; + static const GLenum kAttrib2Type = GL_FLOAT_VEC2; + static const GLenum kAttrib3Type = GL_FLOAT_VEC3; + static const GLint kInvalidAttribLocation = 30; + static const GLint kBadAttribIndex = kNumVertexAttribs; + + static const GLint kMaxUniformLength = 12; + static const char* kUniform1Name; + static const char* kUniform2Name; + static const char* kUniform3Name; + static const GLint kUniform1Size = 1; + static const GLint kUniform2Size = 3; + static const GLint kUniform3Size = 2; + static const GLint kUniform1RealLocation = 3; + static const GLint kUniform2RealLocation = 10; + static const GLint kUniform2ElementRealLocation = 12; + static const GLint kUniform3RealLocation = 20; + static const GLint kUniform1FakeLocation = 0; // These are + static const GLint kUniform2FakeLocation = 1; // hardcoded + static const GLint kUniform2ElementFakeLocation = 0x10001; // to match + static const GLint kUniform3FakeLocation = 2; // ProgramManager. + static const GLenum kUniform1Type = GL_SAMPLER_2D; + static const GLenum kUniform2Type = GL_INT_VEC2; + static const GLenum kUniform3Type = GL_FLOAT_VEC3; + static const GLenum kUniformCubemapType = GL_SAMPLER_CUBE; + static const GLint kInvalidUniformLocation = 30; + static const GLint kBadUniformIndex = 1000; + // Use StrictMock to make 100% sure we know how GL will be called. scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; scoped_refptr<gfx::GLSurfaceStub> surface_; diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h index 8574e53..2d00da9 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h @@ -279,6 +279,7 @@ static GLenum valid_query_parameter_table[] = { static GLenum valid_query_target_table[] = { GL_ANY_SAMPLES_PASSED_EXT, GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, + GL_COMMANDS_ISSUED_CHROMIUM, }; static GLenum valid_read_pixel_format_table[] = { diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc index baad7f6..c8f06a3 100644 --- a/gpu/command_buffer/service/query_manager.cc +++ b/gpu/command_buffer/service/query_manager.cc @@ -5,14 +5,123 @@ #include "gpu/command_buffer/service/query_manager.h" #include "base/atomicops.h" #include "base/logging.h" +#include "base/time.h" #include "gpu/command_buffer/common/gles2_cmd_format.h" #include "gpu/command_buffer/service/common_decoder.h" namespace gpu { namespace gles2 { -QueryManager::QueryManager() - : query_count_(0) { +class AllSamplesPassedQuery : public QueryManager::Query { + public: + AllSamplesPassedQuery( + QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset, + GLuint service_id); + virtual ~AllSamplesPassedQuery(); + virtual bool Begin() OVERRIDE; + virtual bool End(uint32 submit_count) OVERRIDE; + virtual bool Process() OVERRIDE; + virtual void Destroy(bool have_context) OVERRIDE; + + private: + // Service side query id. + GLuint service_id_; +}; + +AllSamplesPassedQuery::AllSamplesPassedQuery( + QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset, + GLuint service_id) + : Query(manager, target, shm_id, shm_offset), + service_id_(service_id) { +} + +AllSamplesPassedQuery::~AllSamplesPassedQuery() { +} + +void AllSamplesPassedQuery::Destroy(bool have_context) { + if (have_context && !IsDeleted()) { + glDeleteQueriesARB(1, &service_id_); + MarkAsDeleted(); + } +} + +bool AllSamplesPassedQuery::Begin() { + BeginQueryHelper(target(), service_id_); + return true; +} + +bool AllSamplesPassedQuery::End(uint32 submit_count) { + EndQueryHelper(target()); + return AddToPendingQueue(submit_count); +} + +bool AllSamplesPassedQuery::Process() { + GLuint available = 0; + glGetQueryObjectuivARB( + service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available); + if (!available) { + return true; + } + GLuint result = 0; + glGetQueryObjectuivARB( + service_id_, GL_QUERY_RESULT_EXT, &result); + + return MarkAsCompleted(result); +} + +class CommandsIssuedQuery : public QueryManager::Query { + public: + CommandsIssuedQuery( + QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset); + virtual ~CommandsIssuedQuery(); + + virtual bool Begin() OVERRIDE; + virtual bool End(uint32 submit_count) OVERRIDE; + virtual bool Process() OVERRIDE; + virtual void Destroy(bool have_context) OVERRIDE; + + private: + base::TimeTicks begin_time_; +}; + +CommandsIssuedQuery::CommandsIssuedQuery( + QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) + : Query(manager, target, shm_id, shm_offset) { +} + +CommandsIssuedQuery::~CommandsIssuedQuery() { +} + +bool CommandsIssuedQuery::Process() { + NOTREACHED(); + return true; +} + +bool CommandsIssuedQuery::Begin() { + begin_time_ = base::TimeTicks::HighResNow(); + return true; +} + +bool CommandsIssuedQuery::End(uint32 submit_count) { + base::TimeDelta elapsed = base::TimeTicks::HighResNow() - begin_time_; + MarkAsPending(submit_count); + return MarkAsCompleted( + std::min(elapsed.InMicroseconds(), static_cast<int64>(0xFFFFFFFFL))); +} + +void CommandsIssuedQuery::Destroy(bool /* have_context */) { + if (!IsDeleted()) { + MarkAsDeleted(); + } +} + +QueryManager::QueryManager( + CommonDecoder* decoder, + bool use_arb_occlusion_query2_for_occlusion_query_boolean) + : decoder_(decoder), + use_arb_occlusion_query2_for_occlusion_query_boolean_( + use_arb_occlusion_query2_for_occlusion_query_boolean), + query_count_(0) { } QueryManager::~QueryManager() { @@ -27,21 +136,27 @@ void QueryManager::Destroy(bool have_context) { pending_queries_.clear(); while (!queries_.empty()) { Query* query = queries_.begin()->second; - if (have_context) { - if (!query->IsDeleted()) { - GLuint service_id = query->service_id(); - glDeleteQueriesARB(1, &service_id); - query->MarkAsDeleted(); - } - } + query->Destroy(have_context); queries_.erase(queries_.begin()); } } QueryManager::Query* QueryManager::CreateQuery( - GLuint client_id, - GLuint service_id) { - Query::Ref query(new Query(this, service_id)); + GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) { + Query::Ref query; + switch (target) { + case GL_COMMANDS_ISSUED_CHROMIUM: + query = new CommandsIssuedQuery(this, target, shm_id, shm_offset); + break; + default: { + GLuint service_id = 0; + glGenQueriesARB(1, &service_id); + DCHECK_NE(0u, service_id); + query = new AllSamplesPassedQuery( + this, target, shm_id, shm_offset, service_id); + break; + } + } std::pair<QueryMap::iterator, bool> result = queries_.insert(std::make_pair(client_id, query)); DCHECK(result.second); @@ -72,16 +187,33 @@ void QueryManager::StopTracking(QueryManager::Query* /* query */) { --query_count_; } +void QueryManager::BeginQueryHelper(GLenum target, GLuint id) { + // ARB_occlusion_query2 does not have a GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT + // target. + if (use_arb_occlusion_query2_for_occlusion_query_boolean_) { + target = GL_ANY_SAMPLES_PASSED_EXT; + } + glBeginQueryARB(target, id); +} + +void QueryManager::EndQueryHelper(GLenum target) { + // ARB_occlusion_query2 does not have a GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT + // target. + if (use_arb_occlusion_query2_for_occlusion_query_boolean_) { + target = GL_ANY_SAMPLES_PASSED_EXT; + } + glEndQueryARB(target); +} + QueryManager::Query::Query( - QueryManager* manager, - GLuint service_id) + QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset) : manager_(manager), - service_id_(service_id), - target_(0), - shm_id_(0), - shm_offset_(0), + target_(target), + shm_id_(shm_id), + shm_offset_(shm_offset), submit_count_(0), - pending_(false) { + pending_(false), + deleted_(false) { DCHECK(manager); manager_->StartTracking(this); } @@ -93,53 +225,33 @@ QueryManager::Query::~Query() { } } -void QueryManager::Query::Initialize( - GLenum target, int32 shm_id, uint32 shm_offset) { - DCHECK(!IsInitialized()); - target_ = target; - shm_id_ = shm_id; - shm_offset_ = shm_offset; -} - -bool QueryManager::GetClientId(GLuint service_id, GLuint* client_id) const { - DCHECK(client_id); - // This doesn't need to be fast. It's only used during slow queries. - for (QueryMap::const_iterator it = queries_.begin(); - it != queries_.end(); ++it) { - if (it->second->service_id() == service_id) { - *client_id = it->first; - return true; - } +bool QueryManager::Query::MarkAsCompleted(GLuint result) { + DCHECK(pending_); + QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>( + shm_id_, shm_offset_, sizeof(*sync)); + if (!sync) { + return false; } - return false; + + pending_ = false; + sync->result = result; + // Need a MemoryBarrier here so that sync->result is written before + // sync->process_count. + base::subtle::MemoryBarrier(); + sync->process_count = submit_count_; + + return true; } -bool QueryManager::ProcessPendingQueries(CommonDecoder* decoder) { - DCHECK(decoder); +bool QueryManager::ProcessPendingQueries() { while (!pending_queries_.empty()) { Query* query = pending_queries_.front().get(); - GLuint available = 0; - glGetQueryObjectuivARB( - query->service_id(), GL_QUERY_RESULT_AVAILABLE_EXT, &available); - if (!available) { - return true; - } - GLuint result = 0; - glGetQueryObjectuivARB( - query->service_id(), GL_QUERY_RESULT_EXT, &result); - QuerySync* sync = decoder->GetSharedMemoryAs<QuerySync*>( - query->shm_id(), query->shm_offset(), sizeof(*sync)); - if (!sync) { + if (!query->Process()) { return false; } - - sync->result = result; - // Need a MemoryBarrier here so that sync->result is written before - // sync->process_count. - base::subtle::MemoryBarrier(); - sync->process_count = query->submit_count(); - - query->MarkAsCompleted(); + if (query->pending()) { + return true; + } pending_queries_.pop_front(); } @@ -150,16 +262,18 @@ bool QueryManager::HavePendingQueries() { return !pending_queries_.empty(); } -void QueryManager::AddPendingQuery(Query* query, uint32 submit_count) { +bool QueryManager::AddPendingQuery(Query* query, uint32 submit_count) { DCHECK(query); - DCHECK(query->IsInitialized()); DCHECK(!query->IsDeleted()); - RemovePendingQuery(query); + if (!RemovePendingQuery(query)) { + return false; + } query->MarkAsPending(submit_count); pending_queries_.push_back(query); + return true; } -void QueryManager::RemovePendingQuery(Query* query) { +bool QueryManager::RemovePendingQuery(Query* query) { DCHECK(query); if (query->pending()) { // TODO(gman): Speed this up if this is a common operation. This would only @@ -172,8 +286,27 @@ void QueryManager::RemovePendingQuery(Query* query) { break; } } - query->MarkAsCompleted(); + if (!query->MarkAsCompleted(0)) { + return false; + } + } + return true; +} + +bool QueryManager::BeginQuery(Query* query) { + DCHECK(query); + if (!RemovePendingQuery(query)) { + return false; + } + return query->Begin(); +} + +bool QueryManager::EndQuery(Query* query, uint32 submit_count) { + DCHECK(query); + if (!RemovePendingQuery(query)) { + return false; } + return query->End(submit_count); } } // namespace gles2 diff --git a/gpu/command_buffer/service/query_manager.h b/gpu/command_buffer/service/query_manager.h index a813ad3..36753e7 100644 --- a/gpu/command_buffer/service/query_manager.h +++ b/gpu/command_buffer/service/query_manager.h @@ -28,30 +28,26 @@ class GPU_EXPORT QueryManager { public: typedef scoped_refptr<Query> Ref; - Query(QueryManager* manager, GLuint service_id); - - void Initialize(GLenum target, int32 shm_id, uint32 shm_offset); - - bool IsInitialized() const { - return target_ != 0; - } - - GLuint service_id() const { - return service_id_; - } + Query( + QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset); + virtual ~Query(); GLenum target() const { return target_; } bool IsDeleted() const { - return service_id_ == 0; + return deleted_; } bool IsValid() const { return target() && !IsDeleted(); } + bool pending() const { + return pending_; + } + int32 shm_id() const { return shm_id_; } @@ -60,16 +56,28 @@ class GPU_EXPORT QueryManager { return shm_offset_; } - bool pending() const { - return pending_; + // Returns false if shared memory for sync is invalid. + virtual bool Begin() = 0; + + // Returns false if shared memory for sync is invalid. + virtual bool End(uint32 submit_count) = 0; + + // Returns false if shared memory for sync is invalid. + virtual bool Process() = 0; + + virtual void Destroy(bool have_context) = 0; + + protected: + QueryManager* manager() const { + return manager_; } - private: - friend class QueryManager; - friend class QueryManagerTest; - friend class base::RefCounted<Query>; + void MarkAsDeleted() { + deleted_ = true; + } - ~Query(); + // Returns false if shared memory for sync is invalid. + bool MarkAsCompleted(GLuint result); void MarkAsPending(uint32 submit_count) { DCHECK(!pending_); @@ -77,25 +85,31 @@ class GPU_EXPORT QueryManager { submit_count_ = submit_count; } - void MarkAsCompleted() { - DCHECK(pending_); - pending_ = false; + // Returns false if shared memory for sync is invalid. + bool AddToPendingQueue(uint32 submit_count) { + return manager_->AddPendingQuery(this, submit_count); } - uint32 submit_count() const { - return submit_count_; + void BeginQueryHelper(GLenum target, GLuint id) { + manager_->BeginQueryHelper(target, id); } - void MarkAsDeleted() { - service_id_ = 0; + void EndQueryHelper(GLenum target) { + manager_->EndQueryHelper(target); + } + + private: + friend class QueryManager; + friend class QueryManagerTest; + friend class base::RefCounted<Query>; + + uint32 submit_count() const { + return submit_count_; } // The manager that owns this Query. QueryManager* manager_; - // Service side query id. - GLuint service_id_; - // The type of query. GLenum target_; @@ -106,18 +120,24 @@ class GPU_EXPORT QueryManager { // Count to set process count do when completed. uint32 submit_count_; - // True if in the Queue. + // True if in the queue. bool pending_; + + // True if deleted. + bool deleted_; }; - QueryManager(); + QueryManager( + CommonDecoder* decoder, + bool use_arb_occlusion_query2_for_occlusion_query_boolean); ~QueryManager(); // Must call before destruction. void Destroy(bool have_context); // Creates a Query for the given query. - Query* CreateQuery(GLuint client_id, GLuint service_id); + Query* CreateQuery( + GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset); // Gets the query info for the given query. Query* GetQuery(GLuint client_id); @@ -125,18 +145,15 @@ class GPU_EXPORT QueryManager { // Removes a query info for the given query. void RemoveQuery(GLuint client_id); - // Gets a client id for a given service id. - bool GetClientId(GLuint service_id, GLuint* client_id) const; - - // Adds to queue of queries waiting for completion. - void AddPendingQuery(Query* query, uint32 submit_count); + // Returns false if any query is pointing to invalid shared memory. + bool BeginQuery(Query* query); - // Removes a query from the queue of pending queries. - void RemovePendingQuery(Query* query); + // Returns false if any query is pointing to invalid shared memory. + bool EndQuery(Query* query, uint32 submit_count); // Processes pending queries. Returns false if any queries are pointing // to invalid shared memory. - bool ProcessPendingQueries(CommonDecoder* decoder); + bool ProcessPendingQueries(); // True if there are pending queries. bool HavePendingQueries(); @@ -145,6 +162,24 @@ class GPU_EXPORT QueryManager { void StartTracking(Query* query); void StopTracking(Query* query); + // Wrappers for BeginQueryARB and EndQueryARB to hide differences between + // ARB_occlusion_query2 and EXT_occlusion_query_boolean. + void BeginQueryHelper(GLenum target, GLuint id); + void EndQueryHelper(GLenum target); + + // Adds to queue of queries waiting for completion. + // Returns false if any query is pointing to invalid shared memory. + bool AddPendingQuery(Query* query, uint32 submit_count); + + // Removes a query from the queue of pending queries. + // Returns false if any query is pointing to invalid shared memory. + bool RemovePendingQuery(Query* query); + + // Used to validate shared memory. + CommonDecoder* decoder_; + + bool use_arb_occlusion_query2_for_occlusion_query_boolean_; + // Counts the number of Queries allocated with 'this' as their manager. // Allows checking no Query will outlive this. unsigned query_count_; diff --git a/gpu/command_buffer/service/query_manager_unittest.cc b/gpu/command_buffer/service/query_manager_unittest.cc index 17e03ce..38eea14 100644 --- a/gpu/command_buffer/service/query_manager_unittest.cc +++ b/gpu/command_buffer/service/query_manager_unittest.cc @@ -48,7 +48,7 @@ class QueryManagerTest : public testing::Test { engine_.reset(new MockCommandBufferEngine()); decoder_.reset(new MockDecoder()); decoder_->set_engine(engine_.get()); - manager_.reset(new QueryManager()); + manager_.reset(new QueryManager(decoder_.get(), false)); } virtual void TearDown() { @@ -60,6 +60,27 @@ class QueryManagerTest : public testing::Test { gl_.reset(); } + QueryManager::Query* CreateQuery( + GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset, + GLuint service_id) { + EXPECT_CALL(*gl_, GenQueriesARB(1, _)) + .WillOnce(SetArgumentPointee<1>(service_id)) + .RetiresOnSaturation(); + return manager_->CreateQuery(target, client_id, shm_id, shm_offset); + } + + void QueueQuery( + QueryManager::Query* query, GLuint service_id, uint32 submit_count) { + EXPECT_CALL(*gl_, BeginQueryARB(query->target(), service_id)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, EndQueryARB(query->target())) + .Times(1) + .RetiresOnSaturation(); + EXPECT_TRUE(manager_->BeginQuery(query)); + EXPECT_TRUE(manager_->EndQuery(query, submit_count)); + } + // Use StrictMock to make 100% sure we know how GL will be called. scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; scoped_ptr<MockDecoder> decoder_; @@ -135,15 +156,11 @@ TEST_F(QueryManagerTest, Basic) { EXPECT_FALSE(manager_->HavePendingQueries()); // Check we can create a Query. QueryManager::Query::Ref query( - manager_->CreateQuery(kClient1Id, kService1Id)); + CreateQuery(GL_ANY_SAMPLES_PASSED_EXT, kClient1Id, + kSharedMemoryId, kSharedMemoryOffset, kService1Id)); ASSERT_TRUE(query.get() != NULL); // Check we can get the same Query. EXPECT_EQ(query.get(), manager_->GetQuery(kClient1Id)); - // Check we can get the client id. - GLuint client_id = -1; - EXPECT_TRUE(manager_->GetClientId(kService1Id, &client_id)); - EXPECT_EQ(kClient1Id, client_id); - EXPECT_FALSE(manager_->HavePendingQueries()); // Check we get nothing for a non-existent query. EXPECT_TRUE(manager_->GetQuery(kClient2Id) == NULL); // Check we can delete the query. @@ -161,7 +178,8 @@ TEST_F(QueryManagerTest, Destroy) { // Create Query. QueryManager::Query::Ref query( - manager_->CreateQuery(kClient1Id, kService1Id)); + CreateQuery(GL_ANY_SAMPLES_PASSED_EXT, kClient1Id, + kSharedMemoryId, kSharedMemoryOffset, kService1Id)); ASSERT_TRUE(query.get() != NULL); EXPECT_CALL(*gl_, DeleteQueriesARB(1, ::testing::Pointee(kService1Id))) .Times(1) @@ -176,37 +194,20 @@ TEST_F(QueryManagerTest, Destroy) { TEST_F(QueryManagerTest, QueryBasic) { const GLuint kClient1Id = 1; const GLuint kService1Id = 11; + const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT; // Create Query. QueryManager::Query::Ref query( - manager_->CreateQuery(kClient1Id, kService1Id)); + CreateQuery(kTarget, kClient1Id, + kSharedMemoryId, kSharedMemoryOffset, kService1Id)); ASSERT_TRUE(query.get() != NULL); - EXPECT_FALSE(query->IsValid()); + EXPECT_TRUE(query->IsValid()); EXPECT_FALSE(query->IsDeleted()); - EXPECT_FALSE(query->IsInitialized()); EXPECT_FALSE(query->pending()); -} - -TEST_F(QueryManagerTest, QueryInitialize) { - const GLuint kClient1Id = 1; - const GLuint kService1Id = 11; - const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT; - - // Create Query. - QueryManager::Query::Ref query( - manager_->CreateQuery(kClient1Id, kService1Id)); - ASSERT_TRUE(query.get() != NULL); - - query->Initialize(kTarget, kSharedMemoryId, kSharedMemoryOffset); EXPECT_EQ(kTarget, query->target()); EXPECT_EQ(kSharedMemoryId, query->shm_id()); EXPECT_EQ(kSharedMemoryOffset, query->shm_offset()); - - EXPECT_TRUE(query->IsValid()); - EXPECT_FALSE(query->IsDeleted()); - EXPECT_TRUE(query->IsInitialized()); - EXPECT_FALSE(query->pending()); } TEST_F(QueryManagerTest, ProcessPendingQuery) { @@ -217,13 +218,13 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) { const GLuint kResult = 456; // Check nothing happens if there are no pending queries. - EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get())); + EXPECT_TRUE(manager_->ProcessPendingQueries()); // Create Query. QueryManager::Query::Ref query( - manager_->CreateQuery(kClient1Id, kService1Id)); + CreateQuery(kTarget, kClient1Id, + kSharedMemoryId, kSharedMemoryOffset, kService1Id)); ASSERT_TRUE(query.get() != NULL); - query->Initialize(kTarget, kSharedMemoryId, kSharedMemoryOffset); // Setup shared memory like client would. QuerySync* sync = decoder_->GetSharedMemoryAs<QuerySync*>( @@ -232,7 +233,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) { sync->Reset(); // Queue it - manager_->AddPendingQuery(query.get(), kSubmitCount); + QueueQuery(query.get(), kService1Id, kSubmitCount); EXPECT_TRUE(query->pending()); EXPECT_TRUE(manager_->HavePendingQueries()); @@ -242,7 +243,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) { GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _)) .WillOnce(SetArgumentPointee<2>(0)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get())); + EXPECT_TRUE(manager_->ProcessPendingQueries()); EXPECT_TRUE(query->pending()); EXPECT_EQ(0u, sync->process_count); EXPECT_EQ(0u, sync->result); @@ -257,7 +258,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) { GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _)) .WillOnce(SetArgumentPointee<2>(kResult)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get())); + EXPECT_TRUE(manager_->ProcessPendingQueries()); EXPECT_FALSE(query->pending()); EXPECT_EQ(kSubmitCount, sync->process_count); EXPECT_EQ(kResult, sync->result); @@ -265,7 +266,7 @@ TEST_F(QueryManagerTest, ProcessPendingQuery) { // Process with no queries. // Expect no GL commands/ - EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get())); + EXPECT_TRUE(manager_->ProcessPendingQueries()); } TEST_F(QueryManagerTest, ProcessPendingQueries) { @@ -283,39 +284,39 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) { const GLuint kResult2 = 457; const GLuint kResult3 = 458; + // Setup shared memory like client would. + QuerySync* sync1 = decoder_->GetSharedMemoryAs<QuerySync*>( + kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync1) * 3); + ASSERT_TRUE(sync1 != NULL); + QuerySync* sync2 = sync1 + 1; + QuerySync* sync3 = sync2 + 1; + // Create Queries. QueryManager::Query::Ref query1( - manager_->CreateQuery(kClient1Id, kService1Id)); + CreateQuery(kTarget, kClient1Id, + kSharedMemoryId, kSharedMemoryOffset + sizeof(*sync1) * 0, + kService1Id)); QueryManager::Query::Ref query2( - manager_->CreateQuery(kClient2Id, kService2Id)); + CreateQuery(kTarget, kClient2Id, + kSharedMemoryId, kSharedMemoryOffset + sizeof(*sync1) * 1, + kService2Id)); QueryManager::Query::Ref query3( - manager_->CreateQuery(kClient3Id, kService3Id)); + CreateQuery(kTarget, kClient3Id, + kSharedMemoryId, kSharedMemoryOffset + sizeof(*sync1) * 2, + kService3Id)); ASSERT_TRUE(query1.get() != NULL); ASSERT_TRUE(query2.get() != NULL); ASSERT_TRUE(query3.get() != NULL); EXPECT_FALSE(manager_->HavePendingQueries()); - // Setup shared memory like client would. - QuerySync* sync1 = decoder_->GetSharedMemoryAs<QuerySync*>( - kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync1) * 3); - ASSERT_TRUE(sync1 != NULL); - QuerySync* sync2 = sync1 + 1; - QuerySync* sync3 = sync2 + 1; - sync1->Reset(); sync2->Reset(); sync3->Reset(); - query1->Initialize(kTarget, kSharedMemoryId, kSharedMemoryOffset); - query2->Initialize(kTarget, kSharedMemoryId, - kSharedMemoryOffset + sizeof(*sync1)); - query3->Initialize(kTarget, kSharedMemoryId, - kSharedMemoryOffset + sizeof(*sync1) * 2); - // Queue them - manager_->AddPendingQuery(query1.get(), kSubmitCount1); - manager_->AddPendingQuery(query2.get(), kSubmitCount2); - manager_->AddPendingQuery(query3.get(), kSubmitCount3); + QueueQuery(query1.get(), kService1Id, kSubmitCount1); + QueueQuery(query2.get(), kService2Id, kSubmitCount2); + QueueQuery(query3.get(), kService3Id, kSubmitCount3); EXPECT_TRUE(query1->pending()); EXPECT_TRUE(query2->pending()); EXPECT_TRUE(query3->pending()); @@ -345,7 +346,7 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) { GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _)) .WillOnce(SetArgumentPointee<2>(0)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get())); + EXPECT_TRUE(manager_->ProcessPendingQueries()); } EXPECT_FALSE(query1->pending()); EXPECT_FALSE(query2->pending()); @@ -364,7 +365,7 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) { GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _)) .WillOnce(SetArgumentPointee<2>(0)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get())); + EXPECT_TRUE(manager_->ProcessPendingQueries()); EXPECT_TRUE(query3->pending()); EXPECT_EQ(0u, sync3->process_count); EXPECT_EQ(0u, sync3->result); @@ -380,7 +381,7 @@ TEST_F(QueryManagerTest, ProcessPendingQueries) { GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_EXT, _)) .WillOnce(SetArgumentPointee<2>(kResult3)) .RetiresOnSaturation(); - EXPECT_TRUE(manager_->ProcessPendingQueries(decoder_.get())); + EXPECT_TRUE(manager_->ProcessPendingQueries()); EXPECT_FALSE(query3->pending()); EXPECT_EQ(kSubmitCount3, sync3->process_count); EXPECT_EQ(kResult3, sync3->result); @@ -396,12 +397,12 @@ TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryId) { // Create Query. QueryManager::Query::Ref query( - manager_->CreateQuery(kClient1Id, kService1Id)); + CreateQuery(kTarget, kClient1Id, + kInvalidSharedMemoryId, kSharedMemoryOffset, kService1Id)); ASSERT_TRUE(query.get() != NULL); - query->Initialize(kTarget, kInvalidSharedMemoryId, kSharedMemoryOffset); // Queue it - manager_->AddPendingQuery(query.get(), kSubmitCount); + QueueQuery(query.get(), kService1Id, kSubmitCount); // Process with return available. // Expect 2 GL commands. @@ -413,7 +414,7 @@ TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryId) { GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _)) .WillOnce(SetArgumentPointee<2>(kResult)) .RetiresOnSaturation(); - EXPECT_FALSE(manager_->ProcessPendingQueries(decoder_.get())); + EXPECT_FALSE(manager_->ProcessPendingQueries()); } TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryOffset) { @@ -425,12 +426,12 @@ TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryOffset) { // Create Query. QueryManager::Query::Ref query( - manager_->CreateQuery(kClient1Id, kService1Id)); + CreateQuery(kTarget, kClient1Id, + kSharedMemoryId, kInvalidSharedMemoryOffset, kService1Id)); ASSERT_TRUE(query.get() != NULL); - query->Initialize(kTarget, kSharedMemoryId, kInvalidSharedMemoryOffset); // Queue it - manager_->AddPendingQuery(query.get(), kSubmitCount); + QueueQuery(query.get(), kService1Id, kSubmitCount); // Process with return available. // Expect 2 GL commands. @@ -442,7 +443,7 @@ TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryOffset) { GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _)) .WillOnce(SetArgumentPointee<2>(kResult)) .RetiresOnSaturation(); - EXPECT_FALSE(manager_->ProcessPendingQueries(decoder_.get())); + EXPECT_FALSE(manager_->ProcessPendingQueries()); } TEST_F(QueryManagerTest, ExitWithPendingQuery) { @@ -453,12 +454,38 @@ TEST_F(QueryManagerTest, ExitWithPendingQuery) { // Create Query. QueryManager::Query::Ref query( - manager_->CreateQuery(kClient1Id, kService1Id)); + CreateQuery(kTarget, kClient1Id, + kSharedMemoryId, kSharedMemoryOffset, kService1Id)); ASSERT_TRUE(query.get() != NULL); - query->Initialize(kTarget, kSharedMemoryId, kSharedMemoryOffset); // Queue it - manager_->AddPendingQuery(query.get(), kSubmitCount); + QueueQuery(query.get(), kService1Id, kSubmitCount); +} + +TEST_F(QueryManagerTest, ARBOcclusionQuery2) { + const GLuint kClient1Id = 1; + const GLuint kService1Id = 11; + const GLenum kTarget = GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT; + const uint32 kSubmitCount = 123; + + scoped_ptr<QueryManager> manager(new QueryManager(decoder_.get(), true)); + + EXPECT_CALL(*gl_, GenQueriesARB(1, _)) + .WillOnce(SetArgumentPointee<1>(kService1Id)) + .RetiresOnSaturation(); + QueryManager::Query* query = manager->CreateQuery( + kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset); + ASSERT_TRUE(query != NULL); + + EXPECT_CALL(*gl_, BeginQueryARB(GL_ANY_SAMPLES_PASSED_EXT, kService1Id)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, EndQueryARB(GL_ANY_SAMPLES_PASSED_EXT)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_TRUE(manager->BeginQuery(query)); + EXPECT_TRUE(manager->EndQuery(query, kSubmitCount)); + manager->Destroy(false); } } // namespace gles2 diff --git a/third_party/khronos/GLES2/gl2ext.h b/third_party/khronos/GLES2/gl2ext.h index fd39ca3..04fa4e0 100644 --- a/third_party/khronos/GLES2/gl2ext.h +++ b/third_party/khronos/GLES2/gl2ext.h @@ -1955,6 +1955,15 @@ typedef void (GL_APIENTRYP PFNGLTEXIMAGEIOSURFACE2DCHROMIUM) (GLenum target, GLs #endif #endif +/* GL_CHROMIUM_command_buffer_query */ +/* Exposes GL_CHROMIUM_command_buffer_query. + */ +#ifndef GL_CHROMIUM_command_buffer_query +#define GL_CHROMIUM_command_buffer_query 1 +// TODO(gman): Get official numbers for these constants. +#define GL_COMMANDS_ISSUED_CHROMIUM 0x84F2 +#endif + #ifdef __cplusplus } #endif diff --git a/third_party/khronos/README.chromium b/third_party/khronos/README.chromium index aa2accc..fb7daee 100644 --- a/third_party/khronos/README.chromium +++ b/third_party/khronos/README.chromium @@ -20,5 +20,6 @@ GLES2/gl2ext.h - Added Chromium and Angle extensions. - Added ANGLE_instanced_arrays - Added GL_EXT_framebuffer_multisample + - Added GL_CHROMIUM_command_buffer_query EGL/eglplatform.h - Added EGLNative*Type for Mac. |