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"
29 class QuerySyncManagerTest
: public testing::Test
{
31 static const int32 kNumCommandEntries
= 400;
32 static const int32 kCommandBufferSizeBytes
=
33 kNumCommandEntries
* sizeof(CommandBufferEntry
);
35 void SetUp() override
{
36 command_buffer_
.reset(new MockClientCommandBuffer());
37 helper_
.reset(new GLES2CmdHelper(command_buffer_
.get()));
38 helper_
->Initialize(kCommandBufferSizeBytes
);
39 mapped_memory_
.reset(new MappedMemoryManager(
40 helper_
.get(), base::Bind(&EmptyPoll
), MappedMemoryManager::kNoLimit
));
41 sync_manager_
.reset(new QuerySyncManager(mapped_memory_
.get()));
44 void TearDown() override
{
45 sync_manager_
.reset();
46 mapped_memory_
.reset();
48 command_buffer_
.reset();
51 scoped_ptr
<CommandBuffer
> command_buffer_
;
52 scoped_ptr
<GLES2CmdHelper
> helper_
;
53 scoped_ptr
<MappedMemoryManager
> mapped_memory_
;
54 scoped_ptr
<QuerySyncManager
> sync_manager_
;
57 TEST_F(QuerySyncManagerTest
, Basic
) {
58 QuerySyncManager::QueryInfo infos
[4];
59 memset(&infos
, 0xBD, sizeof(infos
));
61 for (size_t ii
= 0; ii
< arraysize(infos
); ++ii
) {
62 EXPECT_TRUE(sync_manager_
->Alloc(&infos
[ii
]));
63 EXPECT_NE(0, infos
[ii
].shm_id
);
64 ASSERT_TRUE(infos
[ii
].sync
!= NULL
);
65 EXPECT_EQ(0, infos
[ii
].sync
->process_count
);
66 EXPECT_EQ(0u, infos
[ii
].sync
->result
);
69 for (size_t ii
= 0; ii
< arraysize(infos
); ++ii
) {
70 sync_manager_
->Free(infos
[ii
]);
74 TEST_F(QuerySyncManagerTest
, DontFree
) {
75 QuerySyncManager::QueryInfo infos
[4];
76 memset(&infos
, 0xBD, sizeof(infos
));
78 for (size_t ii
= 0; ii
< arraysize(infos
); ++ii
) {
79 EXPECT_TRUE(sync_manager_
->Alloc(&infos
[ii
]));
83 class QueryTrackerTest
: public testing::Test
{
85 static const int32 kNumCommandEntries
= 400;
86 static const int32 kCommandBufferSizeBytes
=
87 kNumCommandEntries
* sizeof(CommandBufferEntry
);
89 void SetUp() override
{
90 command_buffer_
.reset(new MockClientCommandBuffer());
91 helper_
.reset(new GLES2CmdHelper(command_buffer_
.get()));
92 helper_
->Initialize(kCommandBufferSizeBytes
);
93 mapped_memory_
.reset(new MappedMemoryManager(
94 helper_
.get(), base::Bind(&EmptyPoll
), MappedMemoryManager::kNoLimit
));
95 query_tracker_
.reset(new QueryTracker(mapped_memory_
.get()));
98 void TearDown() override
{
99 query_tracker_
.reset();
100 mapped_memory_
.reset();
102 command_buffer_
.reset();
105 QuerySync
* GetSync(QueryTracker::Query
* query
) {
106 return query
->info_
.sync
;
109 QuerySyncManager::Bucket
* GetBucket(QueryTracker::Query
* query
) {
110 return query
->info_
.bucket
;
113 uint32
GetBucketUsedCount(QuerySyncManager::Bucket
* bucket
) {
114 return bucket
->in_use_queries
.count();
117 uint32
GetFlushGeneration() { return helper_
->flush_generation(); }
119 scoped_ptr
<CommandBuffer
> command_buffer_
;
120 scoped_ptr
<GLES2CmdHelper
> helper_
;
121 scoped_ptr
<MappedMemoryManager
> mapped_memory_
;
122 scoped_ptr
<QueryTracker
> query_tracker_
;
125 TEST_F(QueryTrackerTest
, Basic
) {
126 const GLuint kId1
= 123;
127 const GLuint kId2
= 124;
129 // Check we can create a Query.
130 QueryTracker::Query
* query
= query_tracker_
->CreateQuery(
131 kId1
, GL_ANY_SAMPLES_PASSED_EXT
);
132 ASSERT_TRUE(query
!= NULL
);
133 // Check we can get the same Query.
134 EXPECT_EQ(query
, query_tracker_
->GetQuery(kId1
));
135 // Check we get nothing for a non-existent query.
136 EXPECT_TRUE(query_tracker_
->GetQuery(kId2
) == NULL
);
137 // Check we can delete the query.
138 query_tracker_
->RemoveQuery(kId1
);
139 // Check we get nothing for a non-existent query.
140 EXPECT_TRUE(query_tracker_
->GetQuery(kId1
) == NULL
);
143 TEST_F(QueryTrackerTest
, Query
) {
144 const GLuint kId1
= 123;
145 const int32 kToken
= 46;
146 const uint32 kResult
= 456;
149 QueryTracker::Query
* query
= query_tracker_
->CreateQuery(
150 kId1
, GL_ANY_SAMPLES_PASSED_EXT
);
151 ASSERT_TRUE(query
!= NULL
);
152 EXPECT_TRUE(query
->NeverUsed());
153 EXPECT_FALSE(query
->Pending());
154 EXPECT_EQ(0, query
->token());
155 EXPECT_EQ(0, query
->submit_count());
157 // Check MarkAsActive.
158 query
->MarkAsActive();
159 EXPECT_FALSE(query
->NeverUsed());
160 EXPECT_FALSE(query
->Pending());
161 EXPECT_EQ(0, query
->token());
162 EXPECT_EQ(1, query
->submit_count());
164 // Check MarkAsPending.
165 query
->MarkAsPending(kToken
);
166 EXPECT_FALSE(query
->NeverUsed());
167 EXPECT_TRUE(query
->Pending());
168 EXPECT_EQ(kToken
, query
->token());
169 EXPECT_EQ(1, query
->submit_count());
171 // Flush only once if no more flushes happened between a call to
172 // EndQuery command and CheckResultsAvailable
173 // Advance put_ so flush calls in CheckResultsAvailable go through
174 // and updates flush_generation count
177 // Store FlushGeneration count after EndQuery is called
178 uint32 gen1
= GetFlushGeneration();
180 // Check CheckResultsAvailable.
181 EXPECT_FALSE(query
->CheckResultsAvailable(helper_
.get()));
182 EXPECT_FALSE(query
->NeverUsed());
183 EXPECT_TRUE(query
->Pending());
185 uint32 gen2
= GetFlushGeneration();
186 EXPECT_NE(gen1
, gen2
);
188 // Repeated calls to CheckResultsAvailable should not flush unnecessarily
189 EXPECT_FALSE(query
->CheckResultsAvailable(helper_
.get()));
190 gen1
= GetFlushGeneration();
191 EXPECT_EQ(gen1
, gen2
);
192 EXPECT_FALSE(query
->CheckResultsAvailable(helper_
.get()));
193 gen1
= GetFlushGeneration();
194 EXPECT_EQ(gen1
, gen2
);
196 // Simulate GPU process marking it as available.
197 QuerySync
* sync
= GetSync(query
);
198 sync
->process_count
= query
->submit_count();
199 sync
->result
= kResult
;
201 // Check CheckResultsAvailable.
202 EXPECT_TRUE(query
->CheckResultsAvailable(helper_
.get()));
203 EXPECT_EQ(kResult
, query
->GetResult());
204 EXPECT_FALSE(query
->NeverUsed());
205 EXPECT_FALSE(query
->Pending());
208 TEST_F(QueryTrackerTest
, Remove
) {
209 const GLuint kId1
= 123;
210 const int32 kToken
= 46;
211 const uint32 kResult
= 456;
214 QueryTracker::Query
* query
= query_tracker_
->CreateQuery(
215 kId1
, GL_ANY_SAMPLES_PASSED_EXT
);
216 ASSERT_TRUE(query
!= NULL
);
218 QuerySyncManager::Bucket
* bucket
= GetBucket(query
);
219 EXPECT_EQ(1u, GetBucketUsedCount(bucket
));
221 query
->MarkAsActive();
222 query
->MarkAsPending(kToken
);
224 query_tracker_
->RemoveQuery(kId1
);
225 // Check we get nothing for a non-existent query.
226 EXPECT_TRUE(query_tracker_
->GetQuery(kId1
) == NULL
);
228 // Check that memory was not freed.
229 EXPECT_EQ(1u, GetBucketUsedCount(bucket
));
231 // Simulate GPU process marking it as available.
232 QuerySync
* sync
= GetSync(query
);
233 sync
->process_count
= query
->submit_count();
234 sync
->result
= kResult
;
236 // Check FreeCompletedQueries.
237 query_tracker_
->FreeCompletedQueries();
238 EXPECT_EQ(0u, GetBucketUsedCount(bucket
));
241 TEST_F(QueryTrackerTest
, ManyQueries
) {
242 const GLuint kId1
= 123;
243 const int32 kToken
= 46;
244 const uint32 kResult
= 456;
246 const size_t kTestSize
= 4000;
247 static_assert(kTestSize
> QuerySyncManager::kSyncsPerBucket
,
248 "We want to use more than one bucket");
249 // Create lots of queries.
250 std::vector
<QueryTracker::Query
*> queries
;
251 for (size_t i
= 0; i
< kTestSize
; i
++) {
252 QueryTracker::Query
* query
=
253 query_tracker_
->CreateQuery(kId1
+ i
, GL_ANY_SAMPLES_PASSED_EXT
);
254 ASSERT_TRUE(query
!= NULL
);
255 queries
.push_back(query
);
256 QuerySyncManager::Bucket
* bucket
= GetBucket(query
);
257 EXPECT_LE(1u, GetBucketUsedCount(bucket
));
260 QuerySyncManager::Bucket
* query_0_bucket
= GetBucket(queries
[0]);
261 uint32 expected_use_count
= QuerySyncManager::kSyncsPerBucket
;
262 EXPECT_EQ(expected_use_count
, GetBucketUsedCount(query_0_bucket
));
264 while (!queries
.empty()) {
265 QueryTracker::Query
* query
= queries
.back();
267 GLuint query_id
= kId1
+ queries
.size();
268 EXPECT_EQ(query_id
, query
->id());
269 query
->MarkAsActive();
270 query
->MarkAsPending(kToken
);
272 QuerySyncManager::Bucket
* bucket
= GetBucket(query
);
273 uint32 use_count_before_remove
= GetBucketUsedCount(bucket
);
274 query_tracker_
->FreeCompletedQueries();
275 EXPECT_EQ(use_count_before_remove
, GetBucketUsedCount(bucket
));
276 query_tracker_
->RemoveQuery(query_id
);
277 // Check we get nothing for a non-existent query.
278 EXPECT_TRUE(query_tracker_
->GetQuery(query_id
) == NULL
);
280 // Check that memory was not freed since it was not completed.
281 EXPECT_EQ(use_count_before_remove
, GetBucketUsedCount(bucket
));
283 // Simulate GPU process marking it as available.
284 QuerySync
* sync
= GetSync(query
);
285 sync
->process_count
= query
->submit_count();
286 sync
->result
= kResult
;
288 // Check FreeCompletedQueries.
289 query_tracker_
->FreeCompletedQueries();
290 EXPECT_EQ(use_count_before_remove
- 1, GetBucketUsedCount(bucket
));