Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / gpu / command_buffer / service / memory_program_cache.cc
blobcf3b0ca7d8d12d1478bebf4f8be1f7311b4efd2d
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 "ui/gl/gl_bindings.h"
20 namespace {
22 size_t GetCacheSizeBytes() {
23 const base::CommandLine* command_line =
24 base::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 FillShaderVariableProto(
49 ShaderVariableProto* proto, const sh::ShaderVariable& variable) {
50 proto->set_type(variable.type);
51 proto->set_precision(variable.precision);
52 proto->set_name(variable.name);
53 proto->set_mapped_name(variable.mappedName);
54 proto->set_array_size(variable.arraySize);
55 proto->set_static_use(variable.staticUse);
56 for (size_t ii = 0; ii < variable.fields.size(); ++ii) {
57 ShaderVariableProto* field = proto->add_fields();
58 FillShaderVariableProto(field, variable.fields[ii]);
60 proto->set_struct_name(variable.structName);
63 void FillShaderAttributeProto(
64 ShaderAttributeProto* proto, const sh::Attribute& attrib) {
65 FillShaderVariableProto(proto->mutable_basic(), attrib);
66 proto->set_location(attrib.location);
69 void FillShaderUniformProto(
70 ShaderUniformProto* proto, const sh::Uniform& uniform) {
71 FillShaderVariableProto(proto->mutable_basic(), uniform);
74 void FillShaderVaryingProto(
75 ShaderVaryingProto* proto, const sh::Varying& varying) {
76 FillShaderVariableProto(proto->mutable_basic(), varying);
77 proto->set_interpolation(varying.interpolation);
78 proto->set_is_invariant(varying.isInvariant);
81 void FillShaderProto(ShaderProto* proto, const char* sha,
82 const Shader* shader) {
83 proto->set_sha(sha, gpu::gles2::ProgramCache::kHashLength);
84 for (AttributeMap::const_iterator iter = shader->attrib_map().begin();
85 iter != shader->attrib_map().end(); ++iter) {
86 ShaderAttributeProto* info = proto->add_attribs();
87 FillShaderAttributeProto(info, iter->second);
89 for (UniformMap::const_iterator iter = shader->uniform_map().begin();
90 iter != shader->uniform_map().end(); ++iter) {
91 ShaderUniformProto* info = proto->add_uniforms();
92 FillShaderUniformProto(info, iter->second);
94 for (VaryingMap::const_iterator iter = shader->varying_map().begin();
95 iter != shader->varying_map().end(); ++iter) {
96 ShaderVaryingProto* info = proto->add_varyings();
97 FillShaderVaryingProto(info, iter->second);
101 void RetrieveShaderVariableInfo(
102 const ShaderVariableProto& proto, sh::ShaderVariable* variable) {
103 variable->type = proto.type();
104 variable->precision = proto.precision();
105 variable->name = proto.name();
106 variable->mappedName = proto.mapped_name();
107 variable->arraySize = proto.array_size();
108 variable->staticUse = proto.static_use();
109 variable->fields.resize(proto.fields_size());
110 for (int ii = 0; ii < proto.fields_size(); ++ii)
111 RetrieveShaderVariableInfo(proto.fields(ii), &(variable->fields[ii]));
112 variable->structName = proto.struct_name();
115 void RetrieveShaderAttributeInfo(
116 const ShaderAttributeProto& proto, AttributeMap* map) {
117 sh::Attribute attrib;
118 RetrieveShaderVariableInfo(proto.basic(), &attrib);
119 attrib.location = proto.location();
120 (*map)[proto.basic().mapped_name()] = attrib;
123 void RetrieveShaderUniformInfo(
124 const ShaderUniformProto& proto, UniformMap* map) {
125 sh::Uniform uniform;
126 RetrieveShaderVariableInfo(proto.basic(), &uniform);
127 (*map)[proto.basic().mapped_name()] = uniform;
130 void RetrieveShaderVaryingInfo(
131 const ShaderVaryingProto& proto, VaryingMap* map) {
132 sh::Varying varying;
133 RetrieveShaderVariableInfo(proto.basic(), &varying);
134 varying.interpolation = static_cast<sh::InterpolationType>(
135 proto.interpolation());
136 varying.isInvariant = proto.is_invariant();
137 (*map)[proto.basic().mapped_name()] = varying;
140 void RunShaderCallback(const ShaderCacheCallback& callback,
141 GpuProgramProto* proto,
142 std::string sha_string) {
143 std::string shader;
144 proto->SerializeToString(&shader);
146 std::string key;
147 base::Base64Encode(sha_string, &key);
148 callback.Run(key, shader);
151 } // namespace
153 MemoryProgramCache::MemoryProgramCache()
154 : max_size_bytes_(GetCacheSizeBytes()),
155 curr_size_bytes_(0),
156 store_(ProgramMRUCache::NO_AUTO_EVICT) {
159 MemoryProgramCache::MemoryProgramCache(const size_t max_cache_size_bytes)
160 : max_size_bytes_(max_cache_size_bytes),
161 curr_size_bytes_(0),
162 store_(ProgramMRUCache::NO_AUTO_EVICT) {
165 MemoryProgramCache::~MemoryProgramCache() {}
167 void MemoryProgramCache::ClearBackend() {
168 store_.Clear();
169 DCHECK_EQ(0U, curr_size_bytes_);
172 ProgramCache::ProgramLoadResult MemoryProgramCache::LoadLinkedProgram(
173 GLuint program,
174 Shader* shader_a,
175 Shader* shader_b,
176 const LocationMap* bind_attrib_location_map,
177 const std::vector<std::string>& transform_feedback_varyings,
178 GLenum transform_feedback_buffer_mode,
179 const ShaderCacheCallback& shader_callback) {
180 char a_sha[kHashLength];
181 char b_sha[kHashLength];
182 DCHECK(shader_a && !shader_a->last_compiled_source().empty() &&
183 shader_b && !shader_b->last_compiled_source().empty());
184 ComputeShaderHash(
185 shader_a->last_compiled_signature(), a_sha);
186 ComputeShaderHash(
187 shader_b->last_compiled_signature(), b_sha);
189 char sha[kHashLength];
190 ComputeProgramHash(a_sha,
191 b_sha,
192 bind_attrib_location_map,
193 transform_feedback_varyings,
194 transform_feedback_buffer_mode,
195 sha);
196 const std::string sha_string(sha, kHashLength);
198 ProgramMRUCache::iterator found = store_.Get(sha_string);
199 if (found == store_.end()) {
200 return PROGRAM_LOAD_FAILURE;
202 const scoped_refptr<ProgramCacheValue> value = found->second;
203 glProgramBinary(program,
204 value->format(),
205 static_cast<const GLvoid*>(value->data()),
206 value->length());
207 GLint success = 0;
208 glGetProgramiv(program, GL_LINK_STATUS, &success);
209 if (success == GL_FALSE) {
210 return PROGRAM_LOAD_FAILURE;
212 shader_a->set_attrib_map(value->attrib_map_0());
213 shader_a->set_uniform_map(value->uniform_map_0());
214 shader_a->set_varying_map(value->varying_map_0());
215 shader_b->set_attrib_map(value->attrib_map_1());
216 shader_b->set_uniform_map(value->uniform_map_1());
217 shader_b->set_varying_map(value->varying_map_1());
219 if (!shader_callback.is_null() &&
220 !base::CommandLine::ForCurrentProcess()->HasSwitch(
221 switches::kDisableGpuShaderDiskCache)) {
222 scoped_ptr<GpuProgramProto> proto(
223 GpuProgramProto::default_instance().New());
224 proto->set_sha(sha, kHashLength);
225 proto->set_format(value->format());
226 proto->set_program(value->data(), value->length());
228 FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
229 FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
230 RunShaderCallback(shader_callback, proto.get(), sha_string);
233 return PROGRAM_LOAD_SUCCESS;
236 void MemoryProgramCache::SaveLinkedProgram(
237 GLuint program,
238 const Shader* shader_a,
239 const Shader* shader_b,
240 const LocationMap* bind_attrib_location_map,
241 const std::vector<std::string>& transform_feedback_varyings,
242 GLenum transform_feedback_buffer_mode,
243 const ShaderCacheCallback& shader_callback) {
244 GLenum format;
245 GLsizei length = 0;
246 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &length);
247 if (length == 0 || static_cast<unsigned int>(length) > max_size_bytes_) {
248 return;
250 scoped_ptr<char[]> binary(new char[length]);
251 glGetProgramBinary(program,
252 length,
253 NULL,
254 &format,
255 binary.get());
256 UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.ProgramBinarySizeBytes", length);
258 char a_sha[kHashLength];
259 char b_sha[kHashLength];
260 DCHECK(shader_a && !shader_a->last_compiled_source().empty() &&
261 shader_b && !shader_b->last_compiled_source().empty());
262 ComputeShaderHash(
263 shader_a->last_compiled_signature(), a_sha);
264 ComputeShaderHash(
265 shader_b->last_compiled_signature(), b_sha);
267 char sha[kHashLength];
268 ComputeProgramHash(a_sha,
269 b_sha,
270 bind_attrib_location_map,
271 transform_feedback_varyings,
272 transform_feedback_buffer_mode,
273 sha);
274 const std::string sha_string(sha, sizeof(sha));
276 UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeBeforeKb",
277 curr_size_bytes_ / 1024);
279 // Evict any cached program with the same key in favor of the least recently
280 // accessed.
281 ProgramMRUCache::iterator existing = store_.Peek(sha_string);
282 if(existing != store_.end())
283 store_.Erase(existing);
285 while (curr_size_bytes_ + length > max_size_bytes_) {
286 DCHECK(!store_.empty());
287 store_.Erase(store_.rbegin());
290 if (!shader_callback.is_null() &&
291 !base::CommandLine::ForCurrentProcess()->HasSwitch(
292 switches::kDisableGpuShaderDiskCache)) {
293 scoped_ptr<GpuProgramProto> proto(
294 GpuProgramProto::default_instance().New());
295 proto->set_sha(sha, kHashLength);
296 proto->set_format(format);
297 proto->set_program(binary.get(), length);
299 FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
300 FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
301 RunShaderCallback(shader_callback, proto.get(), sha_string);
304 store_.Put(sha_string,
305 new ProgramCacheValue(length,
306 format,
307 binary.release(),
308 sha_string,
309 a_sha,
310 shader_a->attrib_map(),
311 shader_a->uniform_map(),
312 shader_a->varying_map(),
313 b_sha,
314 shader_b->attrib_map(),
315 shader_b->uniform_map(),
316 shader_b->varying_map(),
317 this));
319 UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
320 curr_size_bytes_ / 1024);
323 void MemoryProgramCache::LoadProgram(const std::string& program) {
324 scoped_ptr<GpuProgramProto> proto(GpuProgramProto::default_instance().New());
325 if (proto->ParseFromString(program)) {
326 AttributeMap vertex_attribs;
327 UniformMap vertex_uniforms;
328 VaryingMap vertex_varyings;
329 for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) {
330 RetrieveShaderAttributeInfo(proto->vertex_shader().attribs(i),
331 &vertex_attribs);
333 for (int i = 0; i < proto->vertex_shader().uniforms_size(); i++) {
334 RetrieveShaderUniformInfo(proto->vertex_shader().uniforms(i),
335 &vertex_uniforms);
337 for (int i = 0; i < proto->vertex_shader().varyings_size(); i++) {
338 RetrieveShaderVaryingInfo(proto->vertex_shader().varyings(i),
339 &vertex_varyings);
342 AttributeMap fragment_attribs;
343 UniformMap fragment_uniforms;
344 VaryingMap fragment_varyings;
345 for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) {
346 RetrieveShaderAttributeInfo(proto->fragment_shader().attribs(i),
347 &fragment_attribs);
349 for (int i = 0; i < proto->fragment_shader().uniforms_size(); i++) {
350 RetrieveShaderUniformInfo(proto->fragment_shader().uniforms(i),
351 &fragment_uniforms);
353 for (int i = 0; i < proto->fragment_shader().varyings_size(); i++) {
354 RetrieveShaderVaryingInfo(proto->fragment_shader().varyings(i),
355 &fragment_varyings);
358 scoped_ptr<char[]> binary(new char[proto->program().length()]);
359 memcpy(binary.get(), proto->program().c_str(), proto->program().length());
361 store_.Put(proto->sha(),
362 new ProgramCacheValue(proto->program().length(),
363 proto->format(),
364 binary.release(),
365 proto->sha(),
366 proto->vertex_shader().sha().c_str(),
367 vertex_attribs,
368 vertex_uniforms,
369 vertex_varyings,
370 proto->fragment_shader().sha().c_str(),
371 fragment_attribs,
372 fragment_uniforms,
373 fragment_varyings,
374 this));
376 UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
377 curr_size_bytes_ / 1024);
378 } else {
379 LOG(ERROR) << "Failed to parse proto file.";
383 MemoryProgramCache::ProgramCacheValue::ProgramCacheValue(
384 GLsizei length,
385 GLenum format,
386 const char* data,
387 const std::string& program_hash,
388 const char* shader_0_hash,
389 const AttributeMap& attrib_map_0,
390 const UniformMap& uniform_map_0,
391 const VaryingMap& varying_map_0,
392 const char* shader_1_hash,
393 const AttributeMap& attrib_map_1,
394 const UniformMap& uniform_map_1,
395 const VaryingMap& varying_map_1,
396 MemoryProgramCache* program_cache)
397 : length_(length),
398 format_(format),
399 data_(data),
400 program_hash_(program_hash),
401 shader_0_hash_(shader_0_hash, kHashLength),
402 attrib_map_0_(attrib_map_0),
403 uniform_map_0_(uniform_map_0),
404 varying_map_0_(varying_map_0),
405 shader_1_hash_(shader_1_hash, kHashLength),
406 attrib_map_1_(attrib_map_1),
407 uniform_map_1_(uniform_map_1),
408 varying_map_1_(varying_map_1),
409 program_cache_(program_cache) {
410 program_cache_->curr_size_bytes_ += length_;
411 program_cache_->LinkedProgramCacheSuccess(program_hash);
414 MemoryProgramCache::ProgramCacheValue::~ProgramCacheValue() {
415 program_cache_->curr_size_bytes_ -= length_;
416 program_cache_->Evict(program_hash_);
419 } // namespace gles2
420 } // namespace gpu