Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(611)

Side by Side Diff: gpu/command_buffer/service/service_discardable_manager_unittest.cc

Issue 2814583002: Service/ClientDiscardableManager (Closed)
Patch Set: Feedback Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2017 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.
4
5 #include "gpu/command_buffer/service/service_discardable_manager.h"
6
7 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
8 #include "gpu/command_buffer/service/gpu_service_test.h"
9 #include "gpu/command_buffer/service/mailbox_manager.h"
10 #include "gpu/command_buffer/service/memory_tracking.h"
11 #include "gpu/command_buffer/service/mocks.h"
12 #include "gpu/command_buffer/service/test_helper.h"
13 #include "gpu/command_buffer/service/texture_manager.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/gl/gl_image_stub.h"
16 #include "ui/gl/gl_mock.h"
17 #include "ui/gl/gl_switches.h"
18
19 using ::testing::Pointee;
20 using ::testing::_;
21 using ::testing::Invoke;
22 using ::testing::Mock;
23 using ::testing::InSequence;
24
25 namespace gpu {
26 namespace gles2 {
27 namespace {
28
29 void CreateLockedHandlesForTesting(
30 std::unique_ptr<ServiceDiscardableHandle>* service_handle,
31 std::unique_ptr<ClientDiscardableHandle>* client_handle) {
32 std::unique_ptr<base::SharedMemory> shared_mem(new base::SharedMemory);
33 shared_mem->CreateAndMapAnonymous(sizeof(uint32_t));
34 scoped_refptr<gpu::Buffer> buffer =
35 MakeBufferFromSharedMemory(std::move(shared_mem), sizeof(uint32_t));
36
37 client_handle->reset(new ClientDiscardableHandle(buffer, 0, 0));
38 service_handle->reset(new ServiceDiscardableHandle(buffer, 0, 0));
39 }
40
41 ServiceDiscardableHandle CreateLockedServiceHandleForTesting() {
42 std::unique_ptr<ServiceDiscardableHandle> service_handle;
43 std::unique_ptr<ClientDiscardableHandle> client_handle;
44 CreateLockedHandlesForTesting(&service_handle, &client_handle);
45 return *service_handle;
46 }
47
48 class MockDestructionObserver : public TextureManager::DestructionObserver {
49 public:
50 MOCK_METHOD1(OnTextureManagerDestroying, void(TextureManager* manager));
51 MOCK_METHOD1(OnTextureRefDestroying, void(TextureRef* ref));
52 };
53
54 } // namespace
55
56 class ServiceDiscardableManagerTest : public GpuServiceTest {
57 public:
58 ServiceDiscardableManagerTest() {}
59 ~ServiceDiscardableManagerTest() override {}
60
61 protected:
62 void SetUp() override {
63 GpuServiceTest::SetUp();
64 decoder_.reset(new MockGLES2Decoder());
65 feature_info_ = new FeatureInfo();
66 context_group_ = scoped_refptr<ContextGroup>(new ContextGroup(
67 gpu_preferences_, nullptr, nullptr, nullptr, nullptr, feature_info_,
68 false, nullptr, nullptr, GpuFeatureInfo(), &discardable_manager_));
69 TestHelper::SetupContextGroupInitExpectations(
70 gl_.get(), DisallowedFeatures(), "", "", CONTEXT_TYPE_OPENGLES2, false);
71 context_group_->Initialize(decoder_.get(), CONTEXT_TYPE_OPENGLES2,
72 DisallowedFeatures());
73 texture_manager_ = context_group_->texture_manager();
74 texture_manager_->AddObserver(&destruction_observer_);
75 }
76
77 void TearDown() override {
78 EXPECT_CALL(destruction_observer_, OnTextureManagerDestroying(_))
79 .RetiresOnSaturation();
80 // Texture manager will destory the 6 black/default textures.
piman 2017/05/12 18:01:27 nit: typo destory->destroy
piman 2017/05/12 18:01:27 nit: TextureManager::kNumDefaultTextures instead o
ericrk 2017/05/12 20:24:00 Done.
ericrk 2017/05/12 20:24:00 need to get a spell checker for my current editor.
81 EXPECT_CALL(*gl_, DeleteTextures(6, _));
82
83 context_group_->Destroy(decoder_.get(), true);
84 context_group_ = nullptr;
85 EXPECT_EQ(0u, discardable_manager_.NumCacheEntriesForTesting());
86 GpuServiceTest::TearDown();
87 }
88
89 void ExpectUnlockedTextureDeletion(uint32_t client_id) {
90 TextureRef* ref = discardable_manager_.UnlockedTextureRefForTesting(
91 client_id, texture_manager_);
92 ExpectTextureRefDeletion(ref);
93 }
94
95 void ExpectTextureDeletion(uint32_t client_id) {
96 TextureRef* ref = texture_manager_->GetTexture(client_id);
97 ExpectTextureRefDeletion(ref);
98 }
99
100 void ExpectTextureRefDeletion(TextureRef* ref) {
101 EXPECT_NE(nullptr, ref);
102 ref->AddObserver();
103 EXPECT_CALL(destruction_observer_, OnTextureRefDestroying(ref))
104 .WillOnce(Invoke([](TextureRef* ref) { ref->RemoveObserver(); }));
105 EXPECT_CALL(*gl_, DeleteTextures(1, Pointee(ref->service_id())))
106 .RetiresOnSaturation();
107 }
108
109 ServiceDiscardableManager discardable_manager_;
110 GpuPreferences gpu_preferences_;
111 scoped_refptr<FeatureInfo> feature_info_;
112 MockDestructionObserver destruction_observer_;
113 TextureManager* texture_manager_;
114 std::unique_ptr<MockGLES2Decoder> decoder_;
115 scoped_refptr<gles2::ContextGroup> context_group_;
116 };
117
118 TEST_F(ServiceDiscardableManagerTest, BasicUsage) {
119 const GLuint kClientId = 1;
120 const GLuint kServiceId = 2;
121 const size_t texture_size = 4 * 1024 * 1024;
122
123 // Create and insert a new texture.
124 texture_manager_->CreateTexture(kClientId, kServiceId);
125 auto handle = CreateLockedServiceHandleForTesting();
126 discardable_manager_.InsertLockedTexture(kClientId, texture_size,
127 texture_manager_, handle);
128 EXPECT_EQ(1u, discardable_manager_.NumCacheEntriesForTesting());
129 EXPECT_TRUE(discardable_manager_.IsEntryLockedForTesting(kClientId,
130 texture_manager_));
131 EXPECT_NE(nullptr, texture_manager_->GetTexture(kClientId));
132
133 // Unlock the texture, ServiceDiscardableManager should take ownership of the
134 // TextureRef.
135 gles2::TextureRef* texture_to_unbind;
136 EXPECT_TRUE(discardable_manager_.UnlockTexture(kClientId, texture_manager_,
137 &texture_to_unbind));
138 EXPECT_NE(nullptr, texture_to_unbind);
139 EXPECT_FALSE(discardable_manager_.IsEntryLockedForTesting(kClientId,
140 texture_manager_));
141 EXPECT_EQ(nullptr, texture_manager_->GetTexture(kClientId));
142
143 // Re-lock the texture, the TextureManager should now resume ownership of
144 // the TextureRef.
145 discardable_manager_.LockTexture(kClientId, texture_manager_);
146 EXPECT_NE(nullptr, texture_manager_->GetTexture(kClientId));
147
148 // Delete the texture from the TextureManager, it should also be removed from
149 // the ServiceDiscardableManager.
150 ExpectTextureDeletion(kClientId);
151 texture_manager_->RemoveTexture(kClientId);
152 EXPECT_EQ(0u, discardable_manager_.NumCacheEntriesForTesting());
153 }
154
155 TEST_F(ServiceDiscardableManagerTest, DeleteAtShutdown) {
156 const size_t texture_size = 4 * 16 * 16;
157
158 // Create 8 small textures (which will not hit memory limits), leaving every
159 // other one unlocked.
160 for (int i = 1; i <= 8; ++i) {
161 texture_manager_->CreateTexture(i, i);
162 auto handle = CreateLockedServiceHandleForTesting();
163 discardable_manager_.InsertLockedTexture(i, texture_size, texture_manager_,
164 handle);
165 if (i % 2) {
166 TextureRef* texture_to_unbind;
167 EXPECT_TRUE(discardable_manager_.UnlockTexture(i, texture_manager_,
168 &texture_to_unbind));
169 EXPECT_NE(nullptr, texture_to_unbind);
170 }
171 }
172
173 // Expect that all 8 will be deleted at shutdown, regardless of
174 // locked/unlocked state.
175 for (int i = 1; i <= 8; ++i) {
176 if (i % 2) {
177 ExpectUnlockedTextureDeletion(i);
178 } else {
179 ExpectTextureDeletion(i);
180 }
181 }
182
183 // Let the test shut down, the expectations should be fulfilled.
184 }
185
186 TEST_F(ServiceDiscardableManagerTest, UnlockInvalid) {
187 const GLuint kClientId = 1;
188 gles2::TextureRef* texture_to_unbind;
189 EXPECT_FALSE(discardable_manager_.UnlockTexture(kClientId, texture_manager_,
190 &texture_to_unbind));
191 EXPECT_EQ(nullptr, texture_to_unbind);
192 }
193
194 TEST_F(ServiceDiscardableManagerTest, Limits) {
195 const size_t texture_size = 64 * 1024 * 1024;
196 const size_t large_texture_size = 3 * 64 * 1024 * 1024;
piman 2017/05/12 18:01:27 nit: could we base these constants on ServiceDisca
ericrk 2017/05/12 20:24:00 Done.
197
198 // Create 4 textures, this should fill up the discardable cache.
199 for (int i = 1; i < 5; ++i) {
200 texture_manager_->CreateTexture(i, i);
201 auto handle = CreateLockedServiceHandleForTesting();
202 discardable_manager_.InsertLockedTexture(i, texture_size, texture_manager_,
203 handle);
204 }
205
206 gles2::TextureRef* texture_to_unbind;
207 EXPECT_TRUE(discardable_manager_.UnlockTexture(3, texture_manager_,
208 &texture_to_unbind));
209 EXPECT_NE(nullptr, texture_to_unbind);
210 EXPECT_TRUE(discardable_manager_.UnlockTexture(1, texture_manager_,
211 &texture_to_unbind));
212 EXPECT_NE(nullptr, texture_to_unbind);
213 EXPECT_TRUE(discardable_manager_.UnlockTexture(2, texture_manager_,
214 &texture_to_unbind));
215 EXPECT_NE(nullptr, texture_to_unbind);
216 EXPECT_TRUE(discardable_manager_.UnlockTexture(4, texture_manager_,
217 &texture_to_unbind));
218 EXPECT_NE(nullptr, texture_to_unbind);
219
220 // Allocate four more textures - the previous 4 should be evicted / deleted in
221 // LRU order.
222 {
223 InSequence s;
224 ExpectUnlockedTextureDeletion(3);
225 ExpectUnlockedTextureDeletion(1);
226 ExpectUnlockedTextureDeletion(2);
227 ExpectUnlockedTextureDeletion(4);
228 }
229
230 for (int i = 5; i < 9; ++i) {
231 texture_manager_->CreateTexture(i, i);
232 auto handle = CreateLockedServiceHandleForTesting();
233 discardable_manager_.InsertLockedTexture(i, texture_size, texture_manager_,
234 handle);
235 }
236
237 // Ensure that the above expectations are handled by this point.
238 Mock::VerifyAndClearExpectations(gl_.get());
239 Mock::VerifyAndClearExpectations(&destruction_observer_);
240
241 // Unlock the next four textures:
242 EXPECT_TRUE(discardable_manager_.UnlockTexture(5, texture_manager_,
243 &texture_to_unbind));
244 EXPECT_NE(nullptr, texture_to_unbind);
245 EXPECT_TRUE(discardable_manager_.UnlockTexture(6, texture_manager_,
246 &texture_to_unbind));
247 EXPECT_NE(nullptr, texture_to_unbind);
248 EXPECT_TRUE(discardable_manager_.UnlockTexture(8, texture_manager_,
249 &texture_to_unbind));
250 EXPECT_NE(nullptr, texture_to_unbind);
251 EXPECT_TRUE(discardable_manager_.UnlockTexture(7, texture_manager_,
252 &texture_to_unbind));
253 EXPECT_NE(nullptr, texture_to_unbind);
254
255 // Allocate one more *large* texture, it should evict the LRU 3 textures.
256 {
257 InSequence s;
258 ExpectUnlockedTextureDeletion(5);
259 ExpectUnlockedTextureDeletion(6);
260 ExpectUnlockedTextureDeletion(8);
261 }
262
263 texture_manager_->CreateTexture(9, 9);
264 auto handle = CreateLockedServiceHandleForTesting();
265 discardable_manager_.InsertLockedTexture(9, large_texture_size,
266 texture_manager_, handle);
267
268 // Expect the two remaining textures to clean up.
269 ExpectTextureDeletion(9);
270 ExpectUnlockedTextureDeletion(7);
271 }
272
273 TEST_F(ServiceDiscardableManagerTest, TextureSizeChanged) {
274 const GLuint kClientId = 1;
275 const GLuint kServiceId = 2;
276 const size_t texture_size = 4 * 1024 * 1024;
277
278 texture_manager_->CreateTexture(kClientId, kServiceId);
279 TextureRef* texture_ref = texture_manager_->GetTexture(kClientId);
280 auto handle = CreateLockedServiceHandleForTesting();
281 discardable_manager_.InsertLockedTexture(kClientId, 0, texture_manager_,
282 handle);
283 EXPECT_EQ(0u, discardable_manager_.TotalSizeForTesting());
284 texture_manager_->SetTarget(texture_ref, GL_TEXTURE_2D);
285 texture_manager_->SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_RGBA, 1024,
286 1024, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
287 gfx::Rect(1024, 1024));
288 EXPECT_EQ(texture_size, discardable_manager_.TotalSizeForTesting());
289
290 ExpectTextureDeletion(kClientId);
291 }
292
293 TEST_F(ServiceDiscardableManagerTest, OwnershipOnUnlock) {
294 const GLuint kClientId = 1;
295 const GLuint kServiceId = 2;
296 const size_t texture_size = 4 * 1024 * 1024;
297
298 std::unique_ptr<ServiceDiscardableHandle> service_handle;
299 std::unique_ptr<ClientDiscardableHandle> client_handle;
300 CreateLockedHandlesForTesting(&service_handle, &client_handle);
301 texture_manager_->CreateTexture(kClientId, kServiceId);
302 discardable_manager_.InsertLockedTexture(kClientId, texture_size,
303 texture_manager_, *service_handle);
304
305 // Ensure that the service ref count is used to determine ownership changes.
306 client_handle->Lock();
307 TextureRef* texture_to_unbind;
308 discardable_manager_.UnlockTexture(kClientId, texture_manager_,
309 &texture_to_unbind);
310 EXPECT_NE(nullptr, texture_to_unbind);
311 EXPECT_TRUE(discardable_manager_.IsEntryLockedForTesting(kClientId,
312 texture_manager_));
313
314 // Get the counts back in sync.
315 discardable_manager_.LockTexture(kClientId, texture_manager_);
316 discardable_manager_.UnlockTexture(kClientId, texture_manager_,
317 &texture_to_unbind);
318 EXPECT_NE(nullptr, texture_to_unbind);
319 EXPECT_FALSE(discardable_manager_.IsEntryLockedForTesting(kClientId,
320 texture_manager_));
321
322 // Re-lock the texture twice.
323 client_handle->Lock();
324 discardable_manager_.LockTexture(kClientId, texture_manager_);
325 client_handle->Lock();
326 discardable_manager_.LockTexture(kClientId, texture_manager_);
327
328 // Ensure that unlocking once doesn't cause us to unbind the texture.
329 discardable_manager_.UnlockTexture(kClientId, texture_manager_,
330 &texture_to_unbind);
331 EXPECT_EQ(nullptr, texture_to_unbind);
332 EXPECT_TRUE(discardable_manager_.IsEntryLockedForTesting(kClientId,
333 texture_manager_));
334
335 // The second unlock should unbind/unlock the texture.
336 discardable_manager_.UnlockTexture(kClientId, texture_manager_,
337 &texture_to_unbind);
338 EXPECT_NE(nullptr, texture_to_unbind);
339 EXPECT_FALSE(discardable_manager_.IsEntryLockedForTesting(kClientId,
340 texture_manager_));
341
342 ExpectUnlockedTextureDeletion(kClientId);
343 }
344
345 TEST_F(ServiceDiscardableManagerTest, BindGeneratedTextureCollision) {
346 const GLuint kClientId = 1;
347 const GLuint kServiceId = 2;
348 const GLuint kGeneratedServiceId = 3;
349 const size_t texture_size = 4 * 1024 * 1024;
350
351 // Create and insert a new texture.
352 texture_manager_->CreateTexture(kClientId, kServiceId);
353 auto handle = CreateLockedServiceHandleForTesting();
354 discardable_manager_.InsertLockedTexture(kClientId, texture_size,
355 texture_manager_, handle);
356
357 // Unlock the texture, ServiceDiscardableManager should take ownership of the
358 // TextureRef.
359 gles2::TextureRef* texture_to_unbind;
360 EXPECT_TRUE(discardable_manager_.UnlockTexture(kClientId, texture_manager_,
361 &texture_to_unbind));
362 EXPECT_NE(nullptr, texture_to_unbind);
363 EXPECT_EQ(nullptr, texture_manager_->GetTexture(kClientId));
364
365 // Generate a new texture for the given client id, similar to "bind generates
366 // resource" behavior.
367 texture_manager_->CreateTexture(kClientId, kGeneratedServiceId);
368 TextureRef* generated_texture_ref = texture_manager_->GetTexture(kClientId);
369
370 // Re-lock the texture, the TextureManager should delete the returned
371 // texture and keep the generated one.
372 ExpectUnlockedTextureDeletion(kClientId);
373 discardable_manager_.LockTexture(kClientId, texture_manager_);
374 EXPECT_EQ(generated_texture_ref, texture_manager_->GetTexture(kClientId));
375
376 // Delete the texture from the TextureManager, it should also be removed from
377 // the ServiceDiscardableManager.
378 ExpectTextureDeletion(kClientId);
379 texture_manager_->RemoveTexture(kClientId);
380 EXPECT_EQ(0u, discardable_manager_.NumCacheEntriesForTesting());
piman 2017/05/12 18:01:27 Another edge case worth testing: glGenTextures ->
ericrk 2017/05/12 20:24:00 This shouldn't be allowed by the client gles2_impl
381 }
382
383 } // namespace gles2
384 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698