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

Side by Side Diff: content/browser/gpu/shader_disk_cache.cc

Issue 2555693005: gpu: Move ShaderDiskCache into //gpu/ipc/host component. (Closed)
Patch Set: tot merge Created 4 years 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) 2013 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 "content/browser/gpu/shader_disk_cache.h"
6
7 #include "base/macros.h"
8 #include "base/memory/ptr_util.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/threading/thread_checker.h"
11 #include "gpu/command_buffer/common/constants.h"
12 #include "net/base/cache_type.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
15
16 namespace content {
17
18 namespace {
19
20 static const base::FilePath::CharType kGpuCachePath[] =
21 FILE_PATH_LITERAL("GPUCache");
22
23 } // namespace
24
25 // ShaderDiskCacheEntry handles the work of caching/updating the cached
26 // shaders.
27 class ShaderDiskCacheEntry : public base::ThreadChecker {
28 public:
29 ShaderDiskCacheEntry(ShaderDiskCache* cache,
30 const std::string& key,
31 const std::string& shader);
32 ~ShaderDiskCacheEntry();
33
34 void Cache();
35
36 private:
37 enum OpType {
38 OPEN_ENTRY,
39 WRITE_DATA,
40 CREATE_ENTRY,
41 };
42
43 void OnOpComplete(int rv);
44
45 int OpenCallback(int rv);
46 int WriteCallback(int rv);
47 int IOComplete(int rv);
48
49 ShaderDiskCache* cache_;
50 OpType op_type_;
51 std::string key_;
52 std::string shader_;
53 disk_cache::Entry* entry_;
54 base::WeakPtr<ShaderDiskCacheEntry> weak_ptr_;
55 base::WeakPtrFactory<ShaderDiskCacheEntry> weak_ptr_factory_;
56
57 DISALLOW_COPY_AND_ASSIGN(ShaderDiskCacheEntry);
58 };
59
60 // ShaderDiskReadHelper is used to load all of the cached shaders from the
61 // disk cache and send to the memory cache.
62 class ShaderDiskReadHelper : public base::ThreadChecker {
63 public:
64 using ShaderLoadedCallback = ShaderDiskCache::ShaderLoadedCallback;
65 ShaderDiskReadHelper(ShaderDiskCache* cache,
66 const ShaderLoadedCallback& callback);
67 ~ShaderDiskReadHelper();
68
69 void LoadCache();
70
71 private:
72 enum OpType {
73 TERMINATE,
74 OPEN_NEXT,
75 OPEN_NEXT_COMPLETE,
76 READ_COMPLETE,
77 ITERATION_FINISHED
78 };
79
80
81 void OnOpComplete(int rv);
82
83 int OpenNextEntry();
84 int OpenNextEntryComplete(int rv);
85 int ReadComplete(int rv);
86 int IterationComplete(int rv);
87
88 ShaderDiskCache* cache_;
89 ShaderLoadedCallback shader_loaded_callback_;
90 OpType op_type_;
91 std::unique_ptr<disk_cache::Backend::Iterator> iter_;
92 scoped_refptr<net::IOBufferWithSize> buf_;
93 disk_cache::Entry* entry_;
94 base::WeakPtrFactory<ShaderDiskReadHelper> weak_ptr_factory_;
95
96 DISALLOW_COPY_AND_ASSIGN(ShaderDiskReadHelper);
97 };
98
99 class ShaderClearHelper : public base::ThreadChecker {
100 public:
101 ShaderClearHelper(ShaderCacheFactory* factory,
102 scoped_refptr<ShaderDiskCache> cache,
103 const base::FilePath& path,
104 const base::Time& delete_begin,
105 const base::Time& delete_end,
106 const base::Closure& callback);
107 ~ShaderClearHelper();
108
109 void Clear();
110
111 private:
112 enum OpType {
113 TERMINATE,
114 VERIFY_CACHE_SETUP,
115 DELETE_CACHE
116 };
117
118 void DoClearShaderCache(int rv);
119
120 ShaderCacheFactory* factory_;
121 scoped_refptr<ShaderDiskCache> cache_;
122 OpType op_type_;
123 base::FilePath path_;
124 base::Time delete_begin_;
125 base::Time delete_end_;
126 base::Closure callback_;
127 base::WeakPtrFactory<ShaderClearHelper> weak_ptr_factory_;
128
129 DISALLOW_COPY_AND_ASSIGN(ShaderClearHelper);
130 };
131
132 ////////////////////////////////////////////////////////////////////////////////
133 // ShaderDiskCacheEntry
134
135 ShaderDiskCacheEntry::ShaderDiskCacheEntry(ShaderDiskCache* cache,
136 const std::string& key,
137 const std::string& shader)
138 : cache_(cache),
139 op_type_(OPEN_ENTRY),
140 key_(key),
141 shader_(shader),
142 entry_(nullptr),
143 weak_ptr_factory_(this) {
144 weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
145 }
146
147 ShaderDiskCacheEntry::~ShaderDiskCacheEntry() {
148 DCHECK(CalledOnValidThread());
149 if (entry_)
150 entry_->Close();
151 }
152
153 void ShaderDiskCacheEntry::Cache() {
154 DCHECK(CalledOnValidThread());
155 int rv = cache_->backend()->OpenEntry(
156 key_, &entry_, base::Bind(&ShaderDiskCacheEntry::OnOpComplete,
157 weak_ptr_factory_.GetWeakPtr()));
158 if (rv != net::ERR_IO_PENDING)
159 OnOpComplete(rv);
160 }
161
162 void ShaderDiskCacheEntry::OnOpComplete(int rv) {
163 DCHECK(CalledOnValidThread());
164 // The function calls inside the switch block below can end up destroying
165 // |this|. So hold on to a WeakPtr<>, and terminate the while loop if |this|
166 // has been destroyed.
167 auto weak_ptr = std::move(weak_ptr_);
168 do {
169 switch (op_type_) {
170 case OPEN_ENTRY:
171 rv = OpenCallback(rv);
172 break;
173 case CREATE_ENTRY:
174 rv = WriteCallback(rv);
175 break;
176 case WRITE_DATA:
177 rv = IOComplete(rv);
178 break;
179 }
180 } while (rv != net::ERR_IO_PENDING && weak_ptr);
181 if (weak_ptr)
182 weak_ptr_ = std::move(weak_ptr);
183 }
184
185 int ShaderDiskCacheEntry::OpenCallback(int rv) {
186 DCHECK(CalledOnValidThread());
187 if (rv == net::OK) {
188 cache_->backend()->OnExternalCacheHit(key_);
189 cache_->EntryComplete(this);
190 return rv;
191 }
192
193 op_type_ = CREATE_ENTRY;
194 return cache_->backend()->CreateEntry(
195 key_, &entry_, base::Bind(&ShaderDiskCacheEntry::OnOpComplete,
196 weak_ptr_factory_.GetWeakPtr()));
197 }
198
199 int ShaderDiskCacheEntry::WriteCallback(int rv) {
200 DCHECK(CalledOnValidThread());
201 if (rv != net::OK) {
202 LOG(ERROR) << "Failed to create shader cache entry: " << rv;
203 cache_->EntryComplete(this);
204 return rv;
205 }
206
207 op_type_ = WRITE_DATA;
208 scoped_refptr<net::StringIOBuffer> io_buf = new net::StringIOBuffer(shader_);
209 return entry_->WriteData(1, 0, io_buf.get(), shader_.length(),
210 base::Bind(&ShaderDiskCacheEntry::OnOpComplete,
211 weak_ptr_factory_.GetWeakPtr()),
212 false);
213 }
214
215 int ShaderDiskCacheEntry::IOComplete(int rv) {
216 DCHECK(CalledOnValidThread());
217 cache_->EntryComplete(this);
218 return rv;
219 }
220
221 ////////////////////////////////////////////////////////////////////////////////
222 // ShaderDiskReadHelper
223
224 ShaderDiskReadHelper::ShaderDiskReadHelper(ShaderDiskCache* cache,
225 const ShaderLoadedCallback& callback)
226 : cache_(cache),
227 shader_loaded_callback_(callback),
228 op_type_(OPEN_NEXT),
229 buf_(NULL),
230 entry_(NULL),
231 weak_ptr_factory_(this) {}
232
233 ShaderDiskReadHelper::~ShaderDiskReadHelper() {
234 DCHECK(CalledOnValidThread());
235 if (entry_)
236 entry_->Close();
237 iter_ = nullptr;
238 }
239
240 void ShaderDiskReadHelper::LoadCache() {
241 DCHECK(CalledOnValidThread());
242 OnOpComplete(net::OK);
243 }
244
245 void ShaderDiskReadHelper::OnOpComplete(int rv) {
246 DCHECK(CalledOnValidThread());
247 do {
248 switch (op_type_) {
249 case OPEN_NEXT:
250 rv = OpenNextEntry();
251 break;
252 case OPEN_NEXT_COMPLETE:
253 rv = OpenNextEntryComplete(rv);
254 break;
255 case READ_COMPLETE:
256 rv = ReadComplete(rv);
257 break;
258 case ITERATION_FINISHED:
259 rv = IterationComplete(rv);
260 break;
261 case TERMINATE:
262 cache_->ReadComplete();
263 rv = net::ERR_IO_PENDING; // break the loop
264 break;
265 }
266 } while (rv != net::ERR_IO_PENDING);
267 }
268
269 int ShaderDiskReadHelper::OpenNextEntry() {
270 DCHECK(CalledOnValidThread());
271 op_type_ = OPEN_NEXT_COMPLETE;
272 if (!iter_)
273 iter_ = cache_->backend()->CreateIterator();
274 return iter_->OpenNextEntry(&entry_,
275 base::Bind(&ShaderDiskReadHelper::OnOpComplete,
276 weak_ptr_factory_.GetWeakPtr()));
277 }
278
279 int ShaderDiskReadHelper::OpenNextEntryComplete(int rv) {
280 DCHECK(CalledOnValidThread());
281 if (rv == net::ERR_FAILED) {
282 iter_.reset();
283 op_type_ = ITERATION_FINISHED;
284 return net::OK;
285 }
286
287 if (rv < 0)
288 return rv;
289
290 op_type_ = READ_COMPLETE;
291 buf_ = new net::IOBufferWithSize(entry_->GetDataSize(1));
292 return entry_->ReadData(1, 0, buf_.get(), buf_->size(),
293 base::Bind(&ShaderDiskReadHelper::OnOpComplete,
294 weak_ptr_factory_.GetWeakPtr()));
295 }
296
297 int ShaderDiskReadHelper::ReadComplete(int rv) {
298 DCHECK(CalledOnValidThread());
299 if (rv && rv == buf_->size() && !shader_loaded_callback_.is_null()) {
300 shader_loaded_callback_.Run(entry_->GetKey(),
301 std::string(buf_->data(), buf_->size()));
302 }
303
304 buf_ = NULL;
305 entry_->Close();
306 entry_ = NULL;
307
308 op_type_ = OPEN_NEXT;
309 return net::OK;
310 }
311
312 int ShaderDiskReadHelper::IterationComplete(int rv) {
313 DCHECK(CalledOnValidThread());
314 iter_.reset();
315 op_type_ = TERMINATE;
316 return net::OK;
317 }
318
319 ////////////////////////////////////////////////////////////////////////////////
320 // ShaderClearHelper
321
322 ShaderClearHelper::ShaderClearHelper(ShaderCacheFactory* factory,
323 scoped_refptr<ShaderDiskCache> cache,
324 const base::FilePath& path,
325 const base::Time& delete_begin,
326 const base::Time& delete_end,
327 const base::Closure& callback)
328 : factory_(factory),
329 cache_(std::move(cache)),
330 op_type_(VERIFY_CACHE_SETUP),
331 path_(path),
332 delete_begin_(delete_begin),
333 delete_end_(delete_end),
334 callback_(callback),
335 weak_ptr_factory_(this) {}
336
337 ShaderClearHelper::~ShaderClearHelper() {
338 DCHECK(CalledOnValidThread());
339 }
340
341 void ShaderClearHelper::Clear() {
342 DCHECK(CalledOnValidThread());
343 DoClearShaderCache(net::OK);
344 }
345
346 void ShaderClearHelper::DoClearShaderCache(int rv) {
347 DCHECK(CalledOnValidThread());
348 while (rv != net::ERR_IO_PENDING) {
349 switch (op_type_) {
350 case VERIFY_CACHE_SETUP:
351 rv = cache_->SetAvailableCallback(
352 base::Bind(&ShaderClearHelper::DoClearShaderCache,
353 weak_ptr_factory_.GetWeakPtr()));
354 op_type_ = DELETE_CACHE;
355 break;
356 case DELETE_CACHE:
357 rv = cache_->Clear(delete_begin_, delete_end_,
358 base::Bind(&ShaderClearHelper::DoClearShaderCache,
359 weak_ptr_factory_.GetWeakPtr()));
360 op_type_ = TERMINATE;
361 break;
362 case TERMINATE:
363 callback_.Run();
364 // Calling CacheCleared() destroys |this|.
365 factory_->CacheCleared(path_);
366 rv = net::ERR_IO_PENDING; // Break the loop.
367 break;
368 }
369 }
370 }
371
372 ////////////////////////////////////////////////////////////////////////////////
373 // ShaderCacheFactory
374
375 ShaderCacheFactory::ShaderCacheFactory(
376 scoped_refptr<base::SingleThreadTaskRunner> cache_task_runner)
377 : cache_task_runner_(std::move(cache_task_runner)) {}
378
379 ShaderCacheFactory::~ShaderCacheFactory() {
380 }
381
382 void ShaderCacheFactory::SetCacheInfo(int32_t client_id,
383 const base::FilePath& path) {
384 DCHECK(CalledOnValidThread());
385 client_id_to_path_map_[client_id] = path;
386 }
387
388 void ShaderCacheFactory::RemoveCacheInfo(int32_t client_id) {
389 DCHECK(CalledOnValidThread());
390 client_id_to_path_map_.erase(client_id);
391 }
392
393 scoped_refptr<ShaderDiskCache> ShaderCacheFactory::Get(int32_t client_id) {
394 DCHECK(CalledOnValidThread());
395 ClientIdToPathMap::iterator iter = client_id_to_path_map_.find(client_id);
396 if (iter == client_id_to_path_map_.end())
397 return NULL;
398 return ShaderCacheFactory::GetByPath(iter->second);
399 }
400
401 scoped_refptr<ShaderDiskCache> ShaderCacheFactory::GetByPath(
402 const base::FilePath& path) {
403 DCHECK(CalledOnValidThread());
404 ShaderCacheMap::iterator iter = shader_cache_map_.find(path);
405 if (iter != shader_cache_map_.end())
406 return iter->second;
407
408 ShaderDiskCache* cache = new ShaderDiskCache(this, path);
409 cache->Init(cache_task_runner_);
410 return cache;
411 }
412
413 void ShaderCacheFactory::AddToCache(const base::FilePath& key,
414 ShaderDiskCache* cache) {
415 DCHECK(CalledOnValidThread());
416 shader_cache_map_[key] = cache;
417 }
418
419 void ShaderCacheFactory::RemoveFromCache(const base::FilePath& key) {
420 DCHECK(CalledOnValidThread());
421 shader_cache_map_.erase(key);
422 }
423
424 void ShaderCacheFactory::ClearByPath(const base::FilePath& path,
425 const base::Time& delete_begin,
426 const base::Time& delete_end,
427 const base::Closure& callback) {
428 DCHECK(CalledOnValidThread());
429 DCHECK(!callback.is_null());
430
431 auto helper = base::MakeUnique<ShaderClearHelper>(
432 this, GetByPath(path), path, delete_begin, delete_end, callback);
433
434 // We could receive requests to clear the same path with different
435 // begin/end times. So, we keep a list of requests. If we haven't seen this
436 // path before we kick off the clear and add it to the list. If we have see it
437 // already, then we already have a clear running. We add this clear to the
438 // list and wait for any previous clears to finish.
439 ShaderClearMap::iterator iter = shader_clear_map_.find(path);
440 if (iter != shader_clear_map_.end()) {
441 iter->second.push(std::move(helper));
442 return;
443 }
444
445 // Insert the helper in the map before calling Clear(), since it can lead to a
446 // call back into CacheCleared().
447 ShaderClearHelper* helper_ptr = helper.get();
448 shader_clear_map_.insert(
449 std::pair<base::FilePath, ShaderClearQueue>(path, ShaderClearQueue()));
450 shader_clear_map_[path].push(std::move(helper));
451 helper_ptr->Clear();
452 }
453
454 void ShaderCacheFactory::CacheCleared(const base::FilePath& path) {
455 DCHECK(CalledOnValidThread());
456
457 ShaderClearMap::iterator iter = shader_clear_map_.find(path);
458 if (iter == shader_clear_map_.end()) {
459 LOG(ERROR) << "Completed clear but missing clear helper.";
460 return;
461 }
462
463 iter->second.pop();
464
465 // If there are remaining items in the list we trigger the Clear on the
466 // next one.
467 if (!iter->second.empty()) {
468 iter->second.front()->Clear();
469 return;
470 }
471
472 shader_clear_map_.erase(iter);
473 }
474
475 ////////////////////////////////////////////////////////////////////////////////
476 // ShaderDiskCache
477
478 ShaderDiskCache::ShaderDiskCache(ShaderCacheFactory* factory,
479 const base::FilePath& cache_path)
480 : factory_(factory),
481 cache_available_(false),
482 cache_path_(cache_path),
483 is_initialized_(false) {
484 factory_->AddToCache(cache_path_, this);
485 }
486
487 ShaderDiskCache::~ShaderDiskCache() {
488 factory_->RemoveFromCache(cache_path_);
489 }
490
491 void ShaderDiskCache::Init(
492 scoped_refptr<base::SingleThreadTaskRunner> cache_task_runner) {
493 if (is_initialized_) {
494 NOTREACHED(); // can't initialize disk cache twice.
495 return;
496 }
497 is_initialized_ = true;
498
499 int rv = disk_cache::CreateCacheBackend(
500 net::SHADER_CACHE, net::CACHE_BACKEND_DEFAULT,
501 cache_path_.Append(kGpuCachePath),
502 gpu::kDefaultMaxProgramCacheMemoryBytes, true, cache_task_runner, NULL,
503 &backend_, base::Bind(&ShaderDiskCache::CacheCreatedCallback, this));
504
505 if (rv == net::OK)
506 cache_available_ = true;
507 }
508
509 void ShaderDiskCache::Cache(const std::string& key, const std::string& shader) {
510 if (!cache_available_)
511 return;
512
513 auto shim = base::MakeUnique<ShaderDiskCacheEntry>(this, key, shader);
514 shim->Cache();
515 auto* raw_ptr = shim.get();
516 entries_.insert(std::make_pair(raw_ptr, std::move(shim)));
517 }
518
519 int ShaderDiskCache::Clear(
520 const base::Time begin_time, const base::Time end_time,
521 const net::CompletionCallback& completion_callback) {
522 int rv;
523 if (begin_time.is_null()) {
524 rv = backend_->DoomAllEntries(completion_callback);
525 } else {
526 rv = backend_->DoomEntriesBetween(begin_time, end_time,
527 completion_callback);
528 }
529 return rv;
530 }
531
532 int32_t ShaderDiskCache::Size() {
533 if (!cache_available_)
534 return -1;
535 return backend_->GetEntryCount();
536 }
537
538 int ShaderDiskCache::SetAvailableCallback(
539 const net::CompletionCallback& callback) {
540 if (cache_available_)
541 return net::OK;
542 available_callback_ = callback;
543 return net::ERR_IO_PENDING;
544 }
545
546 void ShaderDiskCache::CacheCreatedCallback(int rv) {
547 if (rv != net::OK) {
548 LOG(ERROR) << "Shader Cache Creation failed: " << rv;
549 return;
550 }
551 helper_ =
552 base::MakeUnique<ShaderDiskReadHelper>(this, shader_loaded_callback_);
553 helper_->LoadCache();
554 }
555
556 void ShaderDiskCache::EntryComplete(ShaderDiskCacheEntry* entry) {
557 entries_.erase(entry);
558 if (entries_.empty() && !cache_complete_callback_.is_null())
559 cache_complete_callback_.Run(net::OK);
560 }
561
562 void ShaderDiskCache::ReadComplete() {
563 helper_ = nullptr;
564
565 // The cache is considered available after we have finished reading any
566 // of the old cache values off disk. This prevents a potential race where we
567 // are reading from disk and execute a cache clear at the same time.
568 cache_available_ = true;
569 if (!available_callback_.is_null()) {
570 available_callback_.Run(net::OK);
571 available_callback_.Reset();
572 }
573 }
574
575 int ShaderDiskCache::SetCacheCompleteCallback(
576 const net::CompletionCallback& callback) {
577 if (entries_.empty()) {
578 return net::OK;
579 }
580 cache_complete_callback_ = callback;
581 return net::ERR_IO_PENDING;
582 }
583
584 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/gpu/shader_disk_cache.h ('k') | content/browser/gpu/shader_disk_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698