// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Tests for the QueryTracker. #include "gpu/command_buffer/client/query_tracker.h" #include #include "base/memory/scoped_ptr.h" #include "gpu/command_buffer/client/client_test_helper.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/mapped_memory.h" #include "gpu/command_buffer/common/command_buffer.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gmock/include/gmock/gmock.h" namespace gpu { namespace gles2 { namespace { void EmptyPoll() { } } class QuerySyncManagerTest : public testing::Test { protected: static const int32 kNumCommandEntries = 400; static const int32 kCommandBufferSizeBytes = kNumCommandEntries * sizeof(CommandBufferEntry); virtual void SetUp() { command_buffer_.reset(new MockClientCommandBuffer()); helper_.reset(new GLES2CmdHelper(command_buffer_.get())); helper_->Initialize(kCommandBufferSizeBytes); mapped_memory_.reset(new MappedMemoryManager( helper_.get(), base::Bind(&EmptyPoll), MappedMemoryManager::kNoLimit)); sync_manager_.reset(new QuerySyncManager(mapped_memory_.get())); } virtual void TearDown() { sync_manager_.reset(); mapped_memory_.reset(); helper_.reset(); command_buffer_.reset(); } scoped_ptr command_buffer_; scoped_ptr helper_; scoped_ptr mapped_memory_; scoped_ptr sync_manager_; }; TEST_F(QuerySyncManagerTest, Basic) { QuerySyncManager::QueryInfo infos[4]; memset(&infos, 0xBD, sizeof(infos)); for (size_t ii = 0; ii < arraysize(infos); ++ii) { EXPECT_TRUE(sync_manager_->Alloc(&infos[ii])); EXPECT_NE(0, infos[ii].shm_id); ASSERT_TRUE(infos[ii].sync != NULL); EXPECT_EQ(0, infos[ii].sync->process_count); EXPECT_EQ(0u, infos[ii].sync->result); } for (size_t ii = 0; ii < arraysize(infos); ++ii) { sync_manager_->Free(infos[ii]); } } TEST_F(QuerySyncManagerTest, DontFree) { QuerySyncManager::QueryInfo infos[4]; memset(&infos, 0xBD, sizeof(infos)); for (size_t ii = 0; ii < arraysize(infos); ++ii) { EXPECT_TRUE(sync_manager_->Alloc(&infos[ii])); } } class QueryTrackerTest : public testing::Test { protected: static const int32 kNumCommandEntries = 400; static const int32 kCommandBufferSizeBytes = kNumCommandEntries * sizeof(CommandBufferEntry); virtual void SetUp() { command_buffer_.reset(new MockClientCommandBuffer()); helper_.reset(new GLES2CmdHelper(command_buffer_.get())); helper_->Initialize(kCommandBufferSizeBytes); mapped_memory_.reset(new MappedMemoryManager( helper_.get(), base::Bind(&EmptyPoll), MappedMemoryManager::kNoLimit)); query_tracker_.reset(new QueryTracker(mapped_memory_.get())); } virtual void TearDown() { query_tracker_.reset(); mapped_memory_.reset(); helper_.reset(); command_buffer_.reset(); } QuerySync* GetSync(QueryTracker::Query* query) { return query->info_.sync; } QuerySyncManager::Bucket* GetBucket(QueryTracker::Query* query) { return query->info_.bucket; } uint32 GetFlushGeneration() { return helper_->flush_generation(); } scoped_ptr command_buffer_; scoped_ptr helper_; scoped_ptr mapped_memory_; scoped_ptr query_tracker_; }; TEST_F(QueryTrackerTest, Basic) { const GLuint kId1 = 123; const GLuint kId2 = 124; // Check we can create a Query. QueryTracker::Query* query = query_tracker_->CreateQuery( kId1, GL_ANY_SAMPLES_PASSED_EXT); ASSERT_TRUE(query != NULL); // Check we can get the same Query. EXPECT_EQ(query, query_tracker_->GetQuery(kId1)); // Check we get nothing for a non-existent query. EXPECT_TRUE(query_tracker_->GetQuery(kId2) == NULL); // Check we can delete the query. query_tracker_->RemoveQuery(kId1); // Check we get nothing for a non-existent query. EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL); } TEST_F(QueryTrackerTest, Query) { const GLuint kId1 = 123; const int32 kToken = 46; const uint32 kResult = 456; // Create a Query. QueryTracker::Query* query = query_tracker_->CreateQuery( kId1, GL_ANY_SAMPLES_PASSED_EXT); ASSERT_TRUE(query != NULL); EXPECT_TRUE(query->NeverUsed()); EXPECT_FALSE(query->Pending()); EXPECT_EQ(0, query->token()); EXPECT_EQ(0, query->submit_count()); // Check MarkAsActive. query->MarkAsActive(); EXPECT_FALSE(query->NeverUsed()); EXPECT_FALSE(query->Pending()); EXPECT_EQ(0, query->token()); EXPECT_EQ(1, query->submit_count()); // Check MarkAsPending. query->MarkAsPending(kToken); EXPECT_FALSE(query->NeverUsed()); EXPECT_TRUE(query->Pending()); EXPECT_EQ(kToken, query->token()); EXPECT_EQ(1, query->submit_count()); // Check CheckResultsAvailable. EXPECT_FALSE(query->CheckResultsAvailable(helper_.get())); EXPECT_FALSE(query->NeverUsed()); EXPECT_TRUE(query->Pending()); // Flush only once if no more flushes happened between a call to // EndQuery command and CheckResultsAvailable // Advance put_ so flush calls in CheckResultsAvailable go through // and updates flush_generation count helper_->Noop(1); // Set Query in pending state_ to simulate EndQuery command is called query->MarkAsPending(kToken); EXPECT_TRUE(query->Pending()); // Store FlushGeneration count after EndQuery is called uint32 gen1 = GetFlushGeneration(); EXPECT_FALSE(query->CheckResultsAvailable(helper_.get())); uint32 gen2 = GetFlushGeneration(); EXPECT_NE(gen1, gen2); // Repeated calls to CheckResultsAvailable should not flush unnecessarily EXPECT_FALSE(query->CheckResultsAvailable(helper_.get())); gen1 = GetFlushGeneration(); EXPECT_EQ(gen1, gen2); EXPECT_FALSE(query->CheckResultsAvailable(helper_.get())); gen1 = GetFlushGeneration(); EXPECT_EQ(gen1, gen2); // Simulate GPU process marking it as available. QuerySync* sync = GetSync(query); sync->process_count = query->submit_count(); sync->result = kResult; // Check CheckResultsAvailable. EXPECT_TRUE(query->CheckResultsAvailable(helper_.get())); EXPECT_EQ(kResult, query->GetResult()); EXPECT_FALSE(query->NeverUsed()); EXPECT_FALSE(query->Pending()); } TEST_F(QueryTrackerTest, Remove) { const GLuint kId1 = 123; const int32 kToken = 46; const uint32 kResult = 456; // Create a Query. QueryTracker::Query* query = query_tracker_->CreateQuery( kId1, GL_ANY_SAMPLES_PASSED_EXT); ASSERT_TRUE(query != NULL); QuerySyncManager::Bucket* bucket = GetBucket(query); EXPECT_EQ(1u, bucket->used_query_count); query->MarkAsActive(); query->MarkAsPending(kToken); query_tracker_->RemoveQuery(kId1); // Check we get nothing for a non-existent query. EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL); // Check that memory was not freed. EXPECT_EQ(1u, bucket->used_query_count); // Simulate GPU process marking it as available. QuerySync* sync = GetSync(query); sync->process_count = query->submit_count(); sync->result = kResult; // Check FreeCompletedQueries. query_tracker_->FreeCompletedQueries(); EXPECT_EQ(0u, bucket->used_query_count); } } // namespace gles2 } // namespace gpu