1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Tests for the QueryTracker.
7 #include "gpu/command_buffer/client/query_tracker.h"
9 #include <GLES2/gl2ext.h>
13 #include "base/memory/scoped_ptr.h"
14 #include "gpu/command_buffer/client/client_test_helper.h"
15 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
16 #include "gpu/command_buffer/client/mapped_memory.h"
17 #include "gpu/command_buffer/common/command_buffer.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/gmock/include/gmock/gmock.h"
24 class QuerySyncManagerTest
: public testing::Test
{
26 static const int32 kNumCommandEntries
= 400;
27 static const int32 kCommandBufferSizeBytes
=
28 kNumCommandEntries
* sizeof(CommandBufferEntry
);
30 void SetUp() override
{
31 command_buffer_
.reset(new MockClientCommandBuffer());
32 helper_
.reset(new GLES2CmdHelper(command_buffer_
.get()));
33 helper_
->Initialize(kCommandBufferSizeBytes
);
35 new MappedMemoryManager(helper_
.get(), MappedMemoryManager::kNoLimit
));
36 sync_manager_
.reset(new QuerySyncManager(mapped_memory_
.get()));
39 void TearDown() override
{
40 sync_manager_
.reset();
41 mapped_memory_
.reset();
43 command_buffer_
.reset();
46 scoped_ptr
<CommandBuffer
> command_buffer_
;
47 scoped_ptr
<GLES2CmdHelper
> helper_
;
48 scoped_ptr
<MappedMemoryManager
> mapped_memory_
;
49 scoped_ptr
<QuerySyncManager
> sync_manager_
;
52 TEST_F(QuerySyncManagerTest
, Basic
) {
53 QuerySyncManager::QueryInfo infos
[4];
54 memset(&infos
, 0xBD, sizeof(infos
));
56 for (size_t ii
= 0; ii
< arraysize(infos
); ++ii
) {
57 EXPECT_TRUE(sync_manager_
->Alloc(&infos
[ii
]));
58 EXPECT_NE(0, infos
[ii
].shm_id
);
59 ASSERT_TRUE(infos
[ii
].sync
!= NULL
);
60 EXPECT_EQ(0, infos
[ii
].sync
->process_count
);
61 EXPECT_EQ(0u, infos
[ii
].sync
->result
);
64 for (size_t ii
= 0; ii
< arraysize(infos
); ++ii
) {
65 sync_manager_
->Free(infos
[ii
]);
69 TEST_F(QuerySyncManagerTest
, DontFree
) {
70 QuerySyncManager::QueryInfo infos
[4];
71 memset(&infos
, 0xBD, sizeof(infos
));
73 for (size_t ii
= 0; ii
< arraysize(infos
); ++ii
) {
74 EXPECT_TRUE(sync_manager_
->Alloc(&infos
[ii
]));
78 class QueryTrackerTest
: public testing::Test
{
80 static const int32 kNumCommandEntries
= 400;
81 static const int32 kCommandBufferSizeBytes
=
82 kNumCommandEntries
* sizeof(CommandBufferEntry
);
84 void SetUp() override
{
85 command_buffer_
.reset(new MockClientCommandBuffer());
86 helper_
.reset(new GLES2CmdHelper(command_buffer_
.get()));
87 helper_
->Initialize(kCommandBufferSizeBytes
);
89 new MappedMemoryManager(helper_
.get(), MappedMemoryManager::kNoLimit
));
90 query_tracker_
.reset(new QueryTracker(mapped_memory_
.get()));
93 void TearDown() override
{
94 query_tracker_
.reset();
95 mapped_memory_
.reset();
97 command_buffer_
.reset();
100 QuerySync
* GetSync(QueryTracker::Query
* query
) {
101 return query
->info_
.sync
;
104 QuerySyncManager::Bucket
* GetBucket(QueryTracker::Query
* query
) {
105 return query
->info_
.bucket
;
108 uint32
GetBucketUsedCount(QuerySyncManager::Bucket
* bucket
) {
109 return bucket
->in_use_queries
.count();
112 uint32
GetFlushGeneration() { return helper_
->flush_generation(); }
114 scoped_ptr
<CommandBuffer
> command_buffer_
;
115 scoped_ptr
<GLES2CmdHelper
> helper_
;
116 scoped_ptr
<MappedMemoryManager
> mapped_memory_
;
117 scoped_ptr
<QueryTracker
> query_tracker_
;
120 TEST_F(QueryTrackerTest
, Basic
) {
121 const GLuint kId1
= 123;
122 const GLuint kId2
= 124;
124 // Check we can create a Query.
125 QueryTracker::Query
* query
= query_tracker_
->CreateQuery(
126 kId1
, GL_ANY_SAMPLES_PASSED_EXT
);
127 ASSERT_TRUE(query
!= NULL
);
128 // Check we can get the same Query.
129 EXPECT_EQ(query
, query_tracker_
->GetQuery(kId1
));
130 // Check we get nothing for a non-existent query.
131 EXPECT_TRUE(query_tracker_
->GetQuery(kId2
) == NULL
);
132 // Check we can delete the query.
133 query_tracker_
->RemoveQuery(kId1
);
134 // Check we get nothing for a non-existent query.
135 EXPECT_TRUE(query_tracker_
->GetQuery(kId1
) == NULL
);
138 TEST_F(QueryTrackerTest
, Query
) {
139 const GLuint kId1
= 123;
140 const int32 kToken
= 46;
141 const uint32 kResult
= 456;
144 QueryTracker::Query
* query
= query_tracker_
->CreateQuery(
145 kId1
, GL_ANY_SAMPLES_PASSED_EXT
);
146 ASSERT_TRUE(query
!= NULL
);
147 EXPECT_TRUE(query
->NeverUsed());
148 EXPECT_FALSE(query
->Pending());
149 EXPECT_EQ(0, query
->token());
150 EXPECT_EQ(0, query
->submit_count());
152 // Check MarkAsActive.
153 query
->MarkAsActive();
154 EXPECT_FALSE(query
->NeverUsed());
155 EXPECT_FALSE(query
->Pending());
156 EXPECT_EQ(0, query
->token());
157 EXPECT_EQ(1, query
->submit_count());
159 // Check MarkAsPending.
160 query
->MarkAsPending(kToken
);
161 EXPECT_FALSE(query
->NeverUsed());
162 EXPECT_TRUE(query
->Pending());
163 EXPECT_EQ(kToken
, query
->token());
164 EXPECT_EQ(1, query
->submit_count());
166 // Flush only once if no more flushes happened between a call to
167 // EndQuery command and CheckResultsAvailable
168 // Advance put_ so flush calls in CheckResultsAvailable go through
169 // and updates flush_generation count
172 // Store FlushGeneration count after EndQuery is called
173 uint32 gen1
= GetFlushGeneration();
175 // Check CheckResultsAvailable.
176 EXPECT_FALSE(query
->CheckResultsAvailable(helper_
.get()));
177 EXPECT_FALSE(query
->NeverUsed());
178 EXPECT_TRUE(query
->Pending());
180 uint32 gen2
= GetFlushGeneration();
181 EXPECT_NE(gen1
, gen2
);
183 // Repeated calls to CheckResultsAvailable should not flush unnecessarily
184 EXPECT_FALSE(query
->CheckResultsAvailable(helper_
.get()));
185 gen1
= GetFlushGeneration();
186 EXPECT_EQ(gen1
, gen2
);
187 EXPECT_FALSE(query
->CheckResultsAvailable(helper_
.get()));
188 gen1
= GetFlushGeneration();
189 EXPECT_EQ(gen1
, gen2
);
191 // Simulate GPU process marking it as available.
192 QuerySync
* sync
= GetSync(query
);
193 sync
->process_count
= query
->submit_count();
194 sync
->result
= kResult
;
196 // Check CheckResultsAvailable.
197 EXPECT_TRUE(query
->CheckResultsAvailable(helper_
.get()));
198 EXPECT_EQ(kResult
, query
->GetResult());
199 EXPECT_FALSE(query
->NeverUsed());
200 EXPECT_FALSE(query
->Pending());
203 TEST_F(QueryTrackerTest
, Remove
) {
204 const GLuint kId1
= 123;
205 const int32 kToken
= 46;
206 const uint32 kResult
= 456;
209 QueryTracker::Query
* query
= query_tracker_
->CreateQuery(
210 kId1
, GL_ANY_SAMPLES_PASSED_EXT
);
211 ASSERT_TRUE(query
!= NULL
);
213 QuerySyncManager::Bucket
* bucket
= GetBucket(query
);
214 EXPECT_EQ(1u, GetBucketUsedCount(bucket
));
216 query
->MarkAsActive();
217 query
->MarkAsPending(kToken
);
219 query_tracker_
->RemoveQuery(kId1
);
220 // Check we get nothing for a non-existent query.
221 EXPECT_TRUE(query_tracker_
->GetQuery(kId1
) == NULL
);
223 // Check that memory was not freed.
224 EXPECT_EQ(1u, GetBucketUsedCount(bucket
));
226 // Simulate GPU process marking it as available.
227 QuerySync
* sync
= GetSync(query
);
228 sync
->process_count
= query
->submit_count();
229 sync
->result
= kResult
;
231 // Check FreeCompletedQueries.
232 query_tracker_
->FreeCompletedQueries();
233 EXPECT_EQ(0u, GetBucketUsedCount(bucket
));
236 TEST_F(QueryTrackerTest
, ManyQueries
) {
237 const GLuint kId1
= 123;
238 const int32 kToken
= 46;
239 const uint32 kResult
= 456;
241 const size_t kTestSize
= 4000;
242 static_assert(kTestSize
> QuerySyncManager::kSyncsPerBucket
,
243 "We want to use more than one bucket");
244 // Create lots of queries.
245 std::vector
<QueryTracker::Query
*> queries
;
246 for (size_t i
= 0; i
< kTestSize
; i
++) {
247 QueryTracker::Query
* query
=
248 query_tracker_
->CreateQuery(kId1
+ i
, GL_ANY_SAMPLES_PASSED_EXT
);
249 ASSERT_TRUE(query
!= NULL
);
250 queries
.push_back(query
);
251 QuerySyncManager::Bucket
* bucket
= GetBucket(query
);
252 EXPECT_LE(1u, GetBucketUsedCount(bucket
));
255 QuerySyncManager::Bucket
* query_0_bucket
= GetBucket(queries
[0]);
256 uint32 expected_use_count
= QuerySyncManager::kSyncsPerBucket
;
257 EXPECT_EQ(expected_use_count
, GetBucketUsedCount(query_0_bucket
));
259 while (!queries
.empty()) {
260 QueryTracker::Query
* query
= queries
.back();
262 GLuint query_id
= kId1
+ queries
.size();
263 EXPECT_EQ(query_id
, query
->id());
264 query
->MarkAsActive();
265 query
->MarkAsPending(kToken
);
267 QuerySyncManager::Bucket
* bucket
= GetBucket(query
);
268 uint32 use_count_before_remove
= GetBucketUsedCount(bucket
);
269 query_tracker_
->FreeCompletedQueries();
270 EXPECT_EQ(use_count_before_remove
, GetBucketUsedCount(bucket
));
271 query_tracker_
->RemoveQuery(query_id
);
272 // Check we get nothing for a non-existent query.
273 EXPECT_TRUE(query_tracker_
->GetQuery(query_id
) == NULL
);
275 // Check that memory was not freed since it was not completed.
276 EXPECT_EQ(use_count_before_remove
, GetBucketUsedCount(bucket
));
278 // Simulate GPU process marking it as available.
279 QuerySync
* sync
= GetSync(query
);
280 sync
->process_count
= query
->submit_count();
281 sync
->result
= kResult
;
283 // Check FreeCompletedQueries.
284 query_tracker_
->FreeCompletedQueries();
285 EXPECT_EQ(use_count_before_remove
- 1, GetBucketUsedCount(bucket
));