Handle account removal correctly on all platforms.
[chromium-blink-merge.git] / gpu / command_buffer / service / memory_program_cache.cc
blob87378aa8aa6161c5b56785cea2cf64bf040607ed
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 #include "gpu/command_buffer/service/memory_program_cache.h"
7 #include "base/base64.h"
8 #include "base/command_line.h"
9 #include "base/metrics/histogram.h"
10 #include "base/sha1.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "gpu/command_buffer/common/constants.h"
13 #include "gpu/command_buffer/service/disk_cache_proto.pb.h"
14 #include "gpu/command_buffer/service/gl_utils.h"
15 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
16 #include "gpu/command_buffer/service/gpu_switches.h"
17 #include "gpu/command_buffer/service/shader_manager.h"
18 #include "gpu/command_buffer/service/shader_translator.h"
19 #include "ui/gl/gl_bindings.h"
21 namespace {
23 size_t GetCacheSizeBytes() {
24 const CommandLine* command_line = CommandLine::ForCurrentProcess();
25 if (command_line->HasSwitch(switches::kGpuProgramCacheSizeKb)) {
26 size_t size;
27 if (base::StringToSizeT(
28 command_line->GetSwitchValueNative(switches::kGpuProgramCacheSizeKb),
29 &size))
30 return size * 1024;
32 return gpu::kDefaultMaxProgramCacheMemoryBytes;
35 } // anonymous namespace
37 namespace gpu {
38 namespace gles2 {
40 namespace {
42 enum ShaderMapType {
43 ATTRIB_MAP = 0,
44 UNIFORM_MAP,
45 VARYING_MAP
48 void StoreShaderInfo(ShaderMapType type, ShaderProto *proto,
49 const ShaderTranslator::VariableMap& map) {
50 ShaderTranslator::VariableMap::const_iterator iter;
51 for (iter = map.begin(); iter != map.end(); ++iter) {
52 ShaderInfoProto* info = NULL;
53 switch (type) {
54 case UNIFORM_MAP:
55 info = proto->add_uniforms();
56 break;
57 case ATTRIB_MAP:
58 info = proto->add_attribs();
59 break;
60 case VARYING_MAP:
61 info = proto->add_varyings();
62 break;
63 default: NOTREACHED();
66 info->set_key(iter->first);
67 info->set_type(iter->second.type);
68 info->set_size(iter->second.size);
69 info->set_precision(iter->second.precision);
70 info->set_static_use(iter->second.static_use);
71 info->set_name(iter->second.name);
75 void RetrieveShaderInfo(const ShaderInfoProto& proto,
76 ShaderTranslator::VariableMap* map) {
77 ShaderTranslator::VariableInfo info(
78 proto.type(), proto.size(), proto.precision(),
79 proto.static_use(), proto.name());
80 (*map)[proto.key()] = info;
83 void FillShaderProto(ShaderProto* proto, const char* sha,
84 const Shader* shader) {
85 proto->set_sha(sha, gpu::gles2::ProgramCache::kHashLength);
86 StoreShaderInfo(ATTRIB_MAP, proto, shader->attrib_map());
87 StoreShaderInfo(UNIFORM_MAP, proto, shader->uniform_map());
88 StoreShaderInfo(VARYING_MAP, proto, shader->varying_map());
91 void RunShaderCallback(const ShaderCacheCallback& callback,
92 GpuProgramProto* proto,
93 std::string sha_string) {
94 std::string shader;
95 proto->SerializeToString(&shader);
97 std::string key;
98 base::Base64Encode(sha_string, &key);
99 callback.Run(key, shader);
102 } // namespace
104 MemoryProgramCache::MemoryProgramCache()
105 : max_size_bytes_(GetCacheSizeBytes()),
106 curr_size_bytes_(0),
107 store_(ProgramMRUCache::NO_AUTO_EVICT) {
110 MemoryProgramCache::MemoryProgramCache(const size_t max_cache_size_bytes)
111 : max_size_bytes_(max_cache_size_bytes),
112 curr_size_bytes_(0),
113 store_(ProgramMRUCache::NO_AUTO_EVICT) {
116 MemoryProgramCache::~MemoryProgramCache() {}
118 void MemoryProgramCache::ClearBackend() {
119 store_.Clear();
120 DCHECK_EQ(0U, curr_size_bytes_);
123 ProgramCache::ProgramLoadResult MemoryProgramCache::LoadLinkedProgram(
124 GLuint program,
125 Shader* shader_a,
126 const ShaderTranslatorInterface* translator_a,
127 Shader* shader_b,
128 const ShaderTranslatorInterface* translator_b,
129 const LocationMap* bind_attrib_location_map,
130 const ShaderCacheCallback& shader_callback) {
131 char a_sha[kHashLength];
132 char b_sha[kHashLength];
133 DCHECK(shader_a && !shader_a->signature_source().empty() &&
134 shader_b && !shader_b->signature_source().empty());
135 ComputeShaderHash(
136 shader_a->signature_source(), translator_a, a_sha);
137 ComputeShaderHash(
138 shader_b->signature_source(), translator_b, b_sha);
140 char sha[kHashLength];
141 ComputeProgramHash(a_sha,
142 b_sha,
143 bind_attrib_location_map,
144 sha);
145 const std::string sha_string(sha, kHashLength);
147 ProgramMRUCache::iterator found = store_.Get(sha_string);
148 if (found == store_.end()) {
149 return PROGRAM_LOAD_FAILURE;
151 const scoped_refptr<ProgramCacheValue> value = found->second;
152 glProgramBinary(program,
153 value->format(),
154 static_cast<const GLvoid*>(value->data()),
155 value->length());
156 GLint success = 0;
157 glGetProgramiv(program, GL_LINK_STATUS, &success);
158 if (success == GL_FALSE) {
159 return PROGRAM_LOAD_FAILURE;
161 shader_a->set_attrib_map(value->attrib_map_0());
162 shader_a->set_uniform_map(value->uniform_map_0());
163 shader_a->set_varying_map(value->varying_map_0());
164 shader_b->set_attrib_map(value->attrib_map_1());
165 shader_b->set_uniform_map(value->uniform_map_1());
166 shader_b->set_varying_map(value->varying_map_1());
168 if (!shader_callback.is_null() &&
169 !CommandLine::ForCurrentProcess()->HasSwitch(
170 switches::kDisableGpuShaderDiskCache)) {
171 scoped_ptr<GpuProgramProto> proto(
172 GpuProgramProto::default_instance().New());
173 proto->set_sha(sha, kHashLength);
174 proto->set_format(value->format());
175 proto->set_program(value->data(), value->length());
177 FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
178 FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
179 RunShaderCallback(shader_callback, proto.get(), sha_string);
182 return PROGRAM_LOAD_SUCCESS;
185 void MemoryProgramCache::SaveLinkedProgram(
186 GLuint program,
187 const Shader* shader_a,
188 const ShaderTranslatorInterface* translator_a,
189 const Shader* shader_b,
190 const ShaderTranslatorInterface* translator_b,
191 const LocationMap* bind_attrib_location_map,
192 const ShaderCacheCallback& shader_callback) {
193 GLenum format;
194 GLsizei length = 0;
195 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &length);
196 if (length == 0 || static_cast<unsigned int>(length) > max_size_bytes_) {
197 return;
199 scoped_ptr<char[]> binary(new char[length]);
200 glGetProgramBinary(program,
201 length,
202 NULL,
203 &format,
204 binary.get());
205 UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.ProgramBinarySizeBytes", length);
207 char a_sha[kHashLength];
208 char b_sha[kHashLength];
209 DCHECK(shader_a && !shader_a->signature_source().empty() &&
210 shader_b && !shader_b->signature_source().empty());
211 ComputeShaderHash(
212 shader_a->signature_source(), translator_a, a_sha);
213 ComputeShaderHash(
214 shader_b->signature_source(), translator_b, b_sha);
216 char sha[kHashLength];
217 ComputeProgramHash(a_sha,
218 b_sha,
219 bind_attrib_location_map,
220 sha);
221 const std::string sha_string(sha, sizeof(sha));
223 UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeBeforeKb",
224 curr_size_bytes_ / 1024);
226 // Evict any cached program with the same key in favor of the least recently
227 // accessed.
228 ProgramMRUCache::iterator existing = store_.Peek(sha_string);
229 if(existing != store_.end())
230 store_.Erase(existing);
232 while (curr_size_bytes_ + length > max_size_bytes_) {
233 DCHECK(!store_.empty());
234 store_.Erase(store_.rbegin());
237 if (!shader_callback.is_null() &&
238 !CommandLine::ForCurrentProcess()->HasSwitch(
239 switches::kDisableGpuShaderDiskCache)) {
240 scoped_ptr<GpuProgramProto> proto(
241 GpuProgramProto::default_instance().New());
242 proto->set_sha(sha, kHashLength);
243 proto->set_format(format);
244 proto->set_program(binary.get(), length);
246 FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
247 FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
248 RunShaderCallback(shader_callback, proto.get(), sha_string);
251 store_.Put(sha_string,
252 new ProgramCacheValue(length,
253 format,
254 binary.release(),
255 sha_string,
256 a_sha,
257 shader_a->attrib_map(),
258 shader_a->uniform_map(),
259 shader_a->varying_map(),
260 b_sha,
261 shader_b->attrib_map(),
262 shader_b->uniform_map(),
263 shader_b->varying_map(),
264 this));
266 UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
267 curr_size_bytes_ / 1024);
270 void MemoryProgramCache::LoadProgram(const std::string& program) {
271 scoped_ptr<GpuProgramProto> proto(GpuProgramProto::default_instance().New());
272 if (proto->ParseFromString(program)) {
273 ShaderTranslator::VariableMap vertex_attribs;
274 ShaderTranslator::VariableMap vertex_uniforms;
275 ShaderTranslator::VariableMap vertex_varyings;
277 for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) {
278 RetrieveShaderInfo(proto->vertex_shader().attribs(i), &vertex_attribs);
281 for (int i = 0; i < proto->vertex_shader().uniforms_size(); i++) {
282 RetrieveShaderInfo(proto->vertex_shader().uniforms(i), &vertex_uniforms);
285 for (int i = 0; i < proto->vertex_shader().varyings_size(); i++) {
286 RetrieveShaderInfo(proto->vertex_shader().varyings(i), &vertex_varyings);
289 ShaderTranslator::VariableMap fragment_attribs;
290 ShaderTranslator::VariableMap fragment_uniforms;
291 ShaderTranslator::VariableMap fragment_varyings;
293 for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) {
294 RetrieveShaderInfo(proto->fragment_shader().attribs(i),
295 &fragment_attribs);
298 for (int i = 0; i < proto->fragment_shader().uniforms_size(); i++) {
299 RetrieveShaderInfo(proto->fragment_shader().uniforms(i),
300 &fragment_uniforms);
303 for (int i = 0; i < proto->fragment_shader().varyings_size(); i++) {
304 RetrieveShaderInfo(proto->fragment_shader().varyings(i),
305 &fragment_varyings);
308 scoped_ptr<char[]> binary(new char[proto->program().length()]);
309 memcpy(binary.get(), proto->program().c_str(), proto->program().length());
311 store_.Put(proto->sha(),
312 new ProgramCacheValue(proto->program().length(),
313 proto->format(),
314 binary.release(),
315 proto->sha(),
316 proto->vertex_shader().sha().c_str(),
317 vertex_attribs,
318 vertex_uniforms,
319 vertex_varyings,
320 proto->fragment_shader().sha().c_str(),
321 fragment_attribs,
322 fragment_uniforms,
323 fragment_varyings,
324 this));
326 UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
327 curr_size_bytes_ / 1024);
328 } else {
329 LOG(ERROR) << "Failed to parse proto file.";
333 MemoryProgramCache::ProgramCacheValue::ProgramCacheValue(
334 GLsizei length,
335 GLenum format,
336 const char* data,
337 const std::string& program_hash,
338 const char* shader_0_hash,
339 const ShaderTranslator::VariableMap& attrib_map_0,
340 const ShaderTranslator::VariableMap& uniform_map_0,
341 const ShaderTranslator::VariableMap& varying_map_0,
342 const char* shader_1_hash,
343 const ShaderTranslator::VariableMap& attrib_map_1,
344 const ShaderTranslator::VariableMap& uniform_map_1,
345 const ShaderTranslator::VariableMap& varying_map_1,
346 MemoryProgramCache* program_cache)
347 : length_(length),
348 format_(format),
349 data_(data),
350 program_hash_(program_hash),
351 shader_0_hash_(shader_0_hash, kHashLength),
352 attrib_map_0_(attrib_map_0),
353 uniform_map_0_(uniform_map_0),
354 varying_map_0_(varying_map_0),
355 shader_1_hash_(shader_1_hash, kHashLength),
356 attrib_map_1_(attrib_map_1),
357 uniform_map_1_(uniform_map_1),
358 varying_map_1_(varying_map_1),
359 program_cache_(program_cache) {
360 program_cache_->curr_size_bytes_ += length_;
361 program_cache_->LinkedProgramCacheSuccess(program_hash);
364 MemoryProgramCache::ProgramCacheValue::~ProgramCacheValue() {
365 program_cache_->curr_size_bytes_ -= length_;
366 program_cache_->Evict(program_hash_);
369 } // namespace gles2
370 } // namespace gpu