OLD | NEW |
| (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/threading/thread_checker.h" | |
8 #include "content/browser/gpu/gpu_process_host.h" | |
9 #include "content/public/browser/browser_thread.h" | |
10 #include "net/base/io_buffer.h" | |
11 #include "net/base/net_errors.h" | |
12 | |
13 namespace content { | |
14 | |
15 namespace { | |
16 | |
17 static const base::FilePath::CharType kGpuCachePath[] = | |
18 FILE_PATH_LITERAL("GPUCache"); | |
19 | |
20 void EntryCloser(disk_cache::Entry* entry) { | |
21 entry->Close(); | |
22 } | |
23 | |
24 } // namespace | |
25 | |
26 // ShaderDiskCacheEntry handles the work of caching/updating the cached | |
27 // shaders. | |
28 class ShaderDiskCacheEntry | |
29 : public base::ThreadChecker, | |
30 public base::RefCounted<ShaderDiskCacheEntry> { | |
31 public: | |
32 ShaderDiskCacheEntry(base::WeakPtr<ShaderDiskCache> cache, | |
33 const std::string& key, | |
34 const std::string& shader); | |
35 void Cache(); | |
36 | |
37 private: | |
38 friend class base::RefCounted<ShaderDiskCacheEntry>; | |
39 | |
40 enum OpType { | |
41 TERMINATE, | |
42 OPEN_ENTRY, | |
43 WRITE_DATA, | |
44 CREATE_ENTRY, | |
45 }; | |
46 | |
47 ~ShaderDiskCacheEntry(); | |
48 | |
49 void OnOpComplete(int rv); | |
50 | |
51 int OpenCallback(int rv); | |
52 int WriteCallback(int rv); | |
53 int IOComplete(int rv); | |
54 | |
55 base::WeakPtr<ShaderDiskCache> cache_; | |
56 OpType op_type_; | |
57 std::string key_; | |
58 std::string shader_; | |
59 disk_cache::Entry* entry_; | |
60 | |
61 DISALLOW_COPY_AND_ASSIGN(ShaderDiskCacheEntry); | |
62 }; | |
63 | |
64 // ShaderDiskReadHelper is used to load all of the cached shaders from the | |
65 // disk cache and send to the memory cache. | |
66 class ShaderDiskReadHelper | |
67 : public base::ThreadChecker, | |
68 public base::RefCounted<ShaderDiskReadHelper> { | |
69 public: | |
70 ShaderDiskReadHelper(base::WeakPtr<ShaderDiskCache> cache, int host_id); | |
71 void LoadCache(); | |
72 | |
73 private: | |
74 friend class base::RefCounted<ShaderDiskReadHelper>; | |
75 | |
76 enum OpType { | |
77 TERMINATE, | |
78 OPEN_NEXT, | |
79 OPEN_NEXT_COMPLETE, | |
80 READ_COMPLETE, | |
81 ITERATION_FINISHED | |
82 }; | |
83 | |
84 | |
85 ~ShaderDiskReadHelper(); | |
86 | |
87 void OnOpComplete(int rv); | |
88 | |
89 int OpenNextEntry(); | |
90 int OpenNextEntryComplete(int rv); | |
91 int ReadComplete(int rv); | |
92 int IterationComplete(int rv); | |
93 | |
94 base::WeakPtr<ShaderDiskCache> cache_; | |
95 OpType op_type_; | |
96 void* iter_; | |
97 scoped_refptr<net::IOBufferWithSize> buf_; | |
98 int host_id_; | |
99 disk_cache::Entry* entry_; | |
100 | |
101 DISALLOW_COPY_AND_ASSIGN(ShaderDiskReadHelper); | |
102 }; | |
103 | |
104 ShaderDiskCacheEntry::ShaderDiskCacheEntry(base::WeakPtr<ShaderDiskCache> cache, | |
105 const std::string& key, | |
106 const std::string& shader) | |
107 : cache_(cache), | |
108 op_type_(OPEN_ENTRY), | |
109 key_(key), | |
110 shader_(shader), | |
111 entry_(NULL) { | |
112 } | |
113 | |
114 ShaderDiskCacheEntry::~ShaderDiskCacheEntry() { | |
115 if (entry_) | |
116 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
117 base::Bind(&EntryCloser, entry_)); | |
118 } | |
119 | |
120 void ShaderDiskCacheEntry::Cache() { | |
121 DCHECK(CalledOnValidThread()); | |
122 if (!cache_) | |
123 return; | |
124 | |
125 int rv = cache_->backend()->OpenEntry( | |
126 key_, | |
127 &entry_, | |
128 base::Bind(&ShaderDiskCacheEntry::OnOpComplete, this)); | |
129 if (rv != net::ERR_IO_PENDING) | |
130 OnOpComplete(rv); | |
131 } | |
132 | |
133 void ShaderDiskCacheEntry::OnOpComplete(int rv) { | |
134 DCHECK(CalledOnValidThread()); | |
135 if (!cache_) | |
136 return; | |
137 | |
138 do { | |
139 switch (op_type_) { | |
140 case OPEN_ENTRY: | |
141 rv = OpenCallback(rv); | |
142 break; | |
143 case CREATE_ENTRY: | |
144 rv = WriteCallback(rv); | |
145 break; | |
146 case WRITE_DATA: | |
147 rv = IOComplete(rv); | |
148 break; | |
149 case TERMINATE: | |
150 rv = net::ERR_IO_PENDING; // break the loop. | |
151 break; | |
152 default: | |
153 NOTREACHED(); // Invalid op_type_ provided. | |
154 break; | |
155 } | |
156 } while (rv != net::ERR_IO_PENDING); | |
157 } | |
158 | |
159 int ShaderDiskCacheEntry::OpenCallback(int rv) { | |
160 DCHECK(CalledOnValidThread()); | |
161 // Called through OnOpComplete, so we know |cache_| is valid. | |
162 if (rv == net::OK) { | |
163 cache_->backend()->OnExternalCacheHit(key_); | |
164 cache_->EntryComplete(this); | |
165 op_type_ = TERMINATE; | |
166 return rv; | |
167 } | |
168 | |
169 op_type_ = CREATE_ENTRY; | |
170 return cache_->backend()->CreateEntry( | |
171 key_, | |
172 &entry_, | |
173 base::Bind(&ShaderDiskCacheEntry::OnOpComplete, this)); | |
174 } | |
175 | |
176 int ShaderDiskCacheEntry::WriteCallback(int rv) { | |
177 DCHECK(CalledOnValidThread()); | |
178 // Called through OnOpComplete, so we know |cache_| is valid. | |
179 if (rv != net::OK) { | |
180 LOG(ERROR) << "Failed to create shader cache entry: " << rv; | |
181 cache_->EntryComplete(this); | |
182 op_type_ = TERMINATE; | |
183 return rv; | |
184 } | |
185 | |
186 op_type_ = WRITE_DATA; | |
187 scoped_refptr<net::StringIOBuffer> io_buf = new net::StringIOBuffer(shader_); | |
188 return entry_->WriteData(1, 0, io_buf, shader_.length(), | |
189 base::Bind(&ShaderDiskCacheEntry::OnOpComplete, | |
190 this), | |
191 false); | |
192 } | |
193 | |
194 int ShaderDiskCacheEntry::IOComplete(int rv) { | |
195 DCHECK(CalledOnValidThread()); | |
196 // Called through OnOpComplete, so we know |cache_| is valid. | |
197 cache_->EntryComplete(this); | |
198 op_type_ = TERMINATE; | |
199 return rv; | |
200 } | |
201 | |
202 ShaderDiskReadHelper::ShaderDiskReadHelper( | |
203 base::WeakPtr<ShaderDiskCache> cache, | |
204 int host_id) | |
205 : cache_(cache), | |
206 op_type_(OPEN_NEXT), | |
207 iter_(NULL), | |
208 buf_(NULL), | |
209 host_id_(host_id), | |
210 entry_(NULL) { | |
211 } | |
212 | |
213 void ShaderDiskReadHelper::LoadCache() { | |
214 DCHECK(CalledOnValidThread()); | |
215 if (!cache_) | |
216 return; | |
217 OnOpComplete(net::OK); | |
218 } | |
219 | |
220 void ShaderDiskReadHelper::OnOpComplete(int rv) { | |
221 DCHECK(CalledOnValidThread()); | |
222 if (!cache_) | |
223 return; | |
224 | |
225 do { | |
226 switch (op_type_) { | |
227 case OPEN_NEXT: | |
228 rv = OpenNextEntry(); | |
229 break; | |
230 case OPEN_NEXT_COMPLETE: | |
231 rv = OpenNextEntryComplete(rv); | |
232 break; | |
233 case READ_COMPLETE: | |
234 rv = ReadComplete(rv); | |
235 break; | |
236 case ITERATION_FINISHED: | |
237 rv = IterationComplete(rv); | |
238 break; | |
239 case TERMINATE: | |
240 cache_->ReadComplete(); | |
241 rv = net::ERR_IO_PENDING; // break the loop | |
242 break; | |
243 default: | |
244 NOTREACHED(); // Invalid state for read helper | |
245 rv = net::ERR_FAILED; | |
246 break; | |
247 } | |
248 } while (rv != net::ERR_IO_PENDING); | |
249 } | |
250 | |
251 int ShaderDiskReadHelper::OpenNextEntry() { | |
252 DCHECK(CalledOnValidThread()); | |
253 // Called through OnOpComplete, so we know |cache_| is valid. | |
254 op_type_ = OPEN_NEXT_COMPLETE; | |
255 return cache_->backend()->OpenNextEntry( | |
256 &iter_, | |
257 &entry_, | |
258 base::Bind(&ShaderDiskReadHelper::OnOpComplete, this)); | |
259 } | |
260 | |
261 int ShaderDiskReadHelper::OpenNextEntryComplete(int rv) { | |
262 DCHECK(CalledOnValidThread()); | |
263 // Called through OnOpComplete, so we know |cache_| is valid. | |
264 if (rv == net::ERR_FAILED) { | |
265 op_type_ = ITERATION_FINISHED; | |
266 return net::OK; | |
267 } | |
268 | |
269 if (rv < 0) | |
270 return rv; | |
271 | |
272 op_type_ = READ_COMPLETE; | |
273 buf_ = new net::IOBufferWithSize(entry_->GetDataSize(1)); | |
274 return entry_->ReadData(1, 0, buf_, buf_->size(), | |
275 base::Bind(&ShaderDiskReadHelper::OnOpComplete, | |
276 this)); | |
277 } | |
278 | |
279 int ShaderDiskReadHelper::ReadComplete(int rv) { | |
280 DCHECK(CalledOnValidThread()); | |
281 // Called through OnOpComplete, so we know |cache_| is valid. | |
282 if (rv && rv == buf_->size()) { | |
283 GpuProcessHost* host = GpuProcessHost::FromID(host_id_); | |
284 if (host) | |
285 host->LoadedShader(entry_->GetKey(), std::string(buf_->data(), | |
286 buf_->size())); | |
287 } | |
288 | |
289 buf_ = NULL; | |
290 entry_->Close(); | |
291 entry_ = NULL; | |
292 | |
293 op_type_ = OPEN_NEXT; | |
294 return net::OK; | |
295 } | |
296 | |
297 int ShaderDiskReadHelper::IterationComplete(int rv) { | |
298 DCHECK(CalledOnValidThread()); | |
299 // Called through OnOpComplete, so we know |cache_| is valid. | |
300 cache_->backend()->EndEnumeration(&iter_); | |
301 iter_ = NULL; | |
302 op_type_ = TERMINATE; | |
303 return net::OK; | |
304 } | |
305 | |
306 ShaderDiskReadHelper::~ShaderDiskReadHelper() { | |
307 if (entry_) | |
308 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
309 base::Bind(&EntryCloser, entry_)); | |
310 } | |
311 | |
312 ShaderCacheFactory* ShaderCacheFactory::GetInstance() { | |
313 return Singleton<ShaderCacheFactory, | |
314 LeakySingletonTraits<ShaderCacheFactory> >::get(); | |
315 } | |
316 | |
317 ShaderCacheFactory::ShaderCacheFactory() { | |
318 } | |
319 | |
320 ShaderCacheFactory::~ShaderCacheFactory() { | |
321 } | |
322 | |
323 void ShaderCacheFactory::SetCacheInfo(int32 client_id, | |
324 const base::FilePath& path) { | |
325 client_id_to_path_map_[client_id] = path.Append(kGpuCachePath); | |
326 } | |
327 | |
328 void ShaderCacheFactory::RemoveCacheInfo(int32 client_id) { | |
329 client_id_to_path_map_.erase(client_id); | |
330 } | |
331 | |
332 scoped_refptr<ShaderDiskCache> ShaderCacheFactory::Get(int32 client_id) { | |
333 ClientIdToPathMap::iterator client_iter = | |
334 client_id_to_path_map_.find(client_id); | |
335 if (client_iter == client_id_to_path_map_.end()) | |
336 return NULL; | |
337 | |
338 ShaderCacheMap::iterator iter = shader_cache_map_.find(client_iter->second); | |
339 if (iter != shader_cache_map_.end()) | |
340 return iter->second; | |
341 | |
342 ShaderDiskCache* cache = new ShaderDiskCache(client_iter->second); | |
343 cache->Init(); | |
344 | |
345 return cache; | |
346 } | |
347 | |
348 void ShaderCacheFactory::AddToCache(const base::FilePath& key, | |
349 ShaderDiskCache* cache) { | |
350 shader_cache_map_[key] = cache; | |
351 } | |
352 | |
353 void ShaderCacheFactory::RemoveFromCache(const base::FilePath& key) { | |
354 shader_cache_map_.erase(key); | |
355 } | |
356 | |
357 ShaderDiskCache::ShaderDiskCache(const base::FilePath& cache_path) | |
358 : cache_available_(false), | |
359 max_cache_size_(0), | |
360 host_id_(0), | |
361 cache_path_(cache_path), | |
362 is_initialized_(false), | |
363 backend_(NULL) { | |
364 ShaderCacheFactory::GetInstance()->AddToCache(cache_path_, this); | |
365 } | |
366 | |
367 ShaderDiskCache::~ShaderDiskCache() { | |
368 ShaderCacheFactory::GetInstance()->RemoveFromCache(cache_path_); | |
369 } | |
370 | |
371 void ShaderDiskCache::Init() { | |
372 if (is_initialized_) { | |
373 NOTREACHED(); // can't initialize disk cache twice. | |
374 return; | |
375 } | |
376 is_initialized_ = true; | |
377 | |
378 int rv = disk_cache::CreateCacheBackend( | |
379 net::SHADER_CACHE, | |
380 cache_path_, | |
381 max_cache_size_, | |
382 true, | |
383 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE), | |
384 NULL, | |
385 &backend_, | |
386 base::Bind(&ShaderDiskCache::CacheCreatedCallback, this)); | |
387 | |
388 if (rv == net::OK) | |
389 cache_available_ = true; | |
390 } | |
391 | |
392 void ShaderDiskCache::Cache(const std::string& key, const std::string& shader) { | |
393 if (!cache_available_) | |
394 return; | |
395 | |
396 ShaderDiskCacheEntry* shim = | |
397 new ShaderDiskCacheEntry(AsWeakPtr(), key, shader); | |
398 shim->Cache(); | |
399 | |
400 entry_map_[shim] = shim; | |
401 } | |
402 | |
403 void ShaderDiskCache::CacheCreatedCallback(int rv) { | |
404 if (rv != net::OK) { | |
405 LOG(ERROR) << "Shader Cache Creation failed: " << rv; | |
406 return; | |
407 } | |
408 | |
409 cache_available_ = true; | |
410 | |
411 helper_ = new ShaderDiskReadHelper(AsWeakPtr(), host_id_); | |
412 helper_->LoadCache(); | |
413 } | |
414 | |
415 void ShaderDiskCache::EntryComplete(void* entry) { | |
416 entry_map_.erase(entry); | |
417 } | |
418 | |
419 void ShaderDiskCache::ReadComplete() { | |
420 helper_ = NULL; | |
421 } | |
422 | |
423 } // namespace content | |
424 | |
OLD | NEW |