Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / service / memory_program_cache.cc
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.
4
5 #include "gpu/command_buffer/service/memory_program_cache.h"
6
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"
20
21 namespace {
22
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;
31   }
32   return gpu::kDefaultMaxProgramCacheMemoryBytes;
33 }
34
35 }  // anonymous namespace
36
37 namespace gpu {
38 namespace gles2 {
39
40 namespace {
41
42 enum ShaderMapType {
43   ATTRIB_MAP = 0,
44   UNIFORM_MAP,
45   VARYING_MAP
46 };
47
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]);
59   }
60   proto->set_struct_name(variable.structName);
61 }
62
63 void FillShaderAttributeProto(
64     ShaderAttributeProto* proto, const sh::Attribute& attrib) {
65   FillShaderVariableProto(proto->mutable_basic(), attrib);
66   proto->set_location(attrib.location);
67 }
68
69 void FillShaderUniformProto(
70     ShaderUniformProto* proto, const sh::Uniform& uniform) {
71   FillShaderVariableProto(proto->mutable_basic(), uniform);
72 }
73
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);
79 }
80
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);
88   }
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);
93   }
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);
98   }
99 }
100
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();
113 }
114
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;
121 }
122
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;
128 }
129
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;
138 }
139
140 void RunShaderCallback(const ShaderCacheCallback& callback,
141                        GpuProgramProto* proto,
142                        std::string sha_string) {
143   std::string shader;
144   proto->SerializeToString(&shader);
145
146   std::string key;
147   base::Base64Encode(sha_string, &key);
148   callback.Run(key, shader);
149 }
150
151 }  // namespace
152
153 MemoryProgramCache::MemoryProgramCache()
154     : max_size_bytes_(GetCacheSizeBytes()),
155       curr_size_bytes_(0),
156       store_(ProgramMRUCache::NO_AUTO_EVICT) {
157 }
158
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) {
163 }
164
165 MemoryProgramCache::~MemoryProgramCache() {}
166
167 void MemoryProgramCache::ClearBackend() {
168   store_.Clear();
169   DCHECK_EQ(0U, curr_size_bytes_);
170 }
171
172 ProgramCache::ProgramLoadResult MemoryProgramCache::LoadLinkedProgram(
173     GLuint program,
174     Shader* shader_a,
175     const ShaderTranslatorInterface* translator_a,
176     Shader* shader_b,
177     const ShaderTranslatorInterface* translator_b,
178     const LocationMap* bind_attrib_location_map,
179     const ShaderCacheCallback& shader_callback) {
180   char a_sha[kHashLength];
181   char b_sha[kHashLength];
182   DCHECK(shader_a && !shader_a->signature_source().empty() &&
183          shader_b && !shader_b->signature_source().empty());
184   ComputeShaderHash(
185       shader_a->signature_source(), translator_a, a_sha);
186   ComputeShaderHash(
187       shader_b->signature_source(), translator_b, b_sha);
188
189   char sha[kHashLength];
190   ComputeProgramHash(a_sha,
191                      b_sha,
192                      bind_attrib_location_map,
193                      sha);
194   const std::string sha_string(sha, kHashLength);
195
196   ProgramMRUCache::iterator found = store_.Get(sha_string);
197   if (found == store_.end()) {
198     return PROGRAM_LOAD_FAILURE;
199   }
200   const scoped_refptr<ProgramCacheValue> value = found->second;
201   glProgramBinary(program,
202                   value->format(),
203                   static_cast<const GLvoid*>(value->data()),
204                   value->length());
205   GLint success = 0;
206   glGetProgramiv(program, GL_LINK_STATUS, &success);
207   if (success == GL_FALSE) {
208     return PROGRAM_LOAD_FAILURE;
209   }
210   shader_a->set_attrib_map(value->attrib_map_0());
211   shader_a->set_uniform_map(value->uniform_map_0());
212   shader_a->set_varying_map(value->varying_map_0());
213   shader_b->set_attrib_map(value->attrib_map_1());
214   shader_b->set_uniform_map(value->uniform_map_1());
215   shader_b->set_varying_map(value->varying_map_1());
216
217   if (!shader_callback.is_null() &&
218       !CommandLine::ForCurrentProcess()->HasSwitch(
219           switches::kDisableGpuShaderDiskCache)) {
220     scoped_ptr<GpuProgramProto> proto(
221         GpuProgramProto::default_instance().New());
222     proto->set_sha(sha, kHashLength);
223     proto->set_format(value->format());
224     proto->set_program(value->data(), value->length());
225
226     FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
227     FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
228     RunShaderCallback(shader_callback, proto.get(), sha_string);
229   }
230
231   return PROGRAM_LOAD_SUCCESS;
232 }
233
234 void MemoryProgramCache::SaveLinkedProgram(
235     GLuint program,
236     const Shader* shader_a,
237     const ShaderTranslatorInterface* translator_a,
238     const Shader* shader_b,
239     const ShaderTranslatorInterface* translator_b,
240     const LocationMap* bind_attrib_location_map,
241     const ShaderCacheCallback& shader_callback) {
242   GLenum format;
243   GLsizei length = 0;
244   glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &length);
245   if (length == 0 || static_cast<unsigned int>(length) > max_size_bytes_) {
246     return;
247   }
248   scoped_ptr<char[]> binary(new char[length]);
249   glGetProgramBinary(program,
250                      length,
251                      NULL,
252                      &format,
253                      binary.get());
254   UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.ProgramBinarySizeBytes", length);
255
256   char a_sha[kHashLength];
257   char b_sha[kHashLength];
258   DCHECK(shader_a && !shader_a->signature_source().empty() &&
259          shader_b && !shader_b->signature_source().empty());
260   ComputeShaderHash(
261       shader_a->signature_source(), translator_a, a_sha);
262   ComputeShaderHash(
263       shader_b->signature_source(), translator_b, b_sha);
264
265   char sha[kHashLength];
266   ComputeProgramHash(a_sha,
267                      b_sha,
268                      bind_attrib_location_map,
269                      sha);
270   const std::string sha_string(sha, sizeof(sha));
271
272   UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeBeforeKb",
273                        curr_size_bytes_ / 1024);
274
275   // Evict any cached program with the same key in favor of the least recently
276   // accessed.
277   ProgramMRUCache::iterator existing = store_.Peek(sha_string);
278   if(existing != store_.end())
279     store_.Erase(existing);
280
281   while (curr_size_bytes_ + length > max_size_bytes_) {
282     DCHECK(!store_.empty());
283     store_.Erase(store_.rbegin());
284   }
285
286   if (!shader_callback.is_null() &&
287       !CommandLine::ForCurrentProcess()->HasSwitch(
288           switches::kDisableGpuShaderDiskCache)) {
289     scoped_ptr<GpuProgramProto> proto(
290         GpuProgramProto::default_instance().New());
291     proto->set_sha(sha, kHashLength);
292     proto->set_format(format);
293     proto->set_program(binary.get(), length);
294
295     FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
296     FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
297     RunShaderCallback(shader_callback, proto.get(), sha_string);
298   }
299
300   store_.Put(sha_string,
301              new ProgramCacheValue(length,
302                                    format,
303                                    binary.release(),
304                                    sha_string,
305                                    a_sha,
306                                    shader_a->attrib_map(),
307                                    shader_a->uniform_map(),
308                                    shader_a->varying_map(),
309                                    b_sha,
310                                    shader_b->attrib_map(),
311                                    shader_b->uniform_map(),
312                                    shader_b->varying_map(),
313                                    this));
314
315   UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
316                        curr_size_bytes_ / 1024);
317 }
318
319 void MemoryProgramCache::LoadProgram(const std::string& program) {
320   scoped_ptr<GpuProgramProto> proto(GpuProgramProto::default_instance().New());
321   if (proto->ParseFromString(program)) {
322     AttributeMap vertex_attribs;
323     UniformMap vertex_uniforms;
324     VaryingMap vertex_varyings;
325     for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) {
326       RetrieveShaderAttributeInfo(proto->vertex_shader().attribs(i),
327                                   &vertex_attribs);
328     }
329     for (int i = 0; i < proto->vertex_shader().uniforms_size(); i++) {
330       RetrieveShaderUniformInfo(proto->vertex_shader().uniforms(i),
331                                 &vertex_uniforms);
332     }
333     for (int i = 0; i < proto->vertex_shader().varyings_size(); i++) {
334       RetrieveShaderVaryingInfo(proto->vertex_shader().varyings(i),
335                                 &vertex_varyings);
336     }
337
338     AttributeMap fragment_attribs;
339     UniformMap fragment_uniforms;
340     VaryingMap fragment_varyings;
341     for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) {
342       RetrieveShaderAttributeInfo(proto->fragment_shader().attribs(i),
343                                   &fragment_attribs);
344     }
345     for (int i = 0; i < proto->fragment_shader().uniforms_size(); i++) {
346       RetrieveShaderUniformInfo(proto->fragment_shader().uniforms(i),
347                                 &fragment_uniforms);
348     }
349     for (int i = 0; i < proto->fragment_shader().varyings_size(); i++) {
350       RetrieveShaderVaryingInfo(proto->fragment_shader().varyings(i),
351                                 &fragment_varyings);
352     }
353
354     scoped_ptr<char[]> binary(new char[proto->program().length()]);
355     memcpy(binary.get(), proto->program().c_str(), proto->program().length());
356
357     store_.Put(proto->sha(),
358                new ProgramCacheValue(proto->program().length(),
359                                      proto->format(),
360                                      binary.release(),
361                                      proto->sha(),
362                                      proto->vertex_shader().sha().c_str(),
363                                      vertex_attribs,
364                                      vertex_uniforms,
365                                      vertex_varyings,
366                                      proto->fragment_shader().sha().c_str(),
367                                      fragment_attribs,
368                                      fragment_uniforms,
369                                      fragment_varyings,
370                                      this));
371
372     UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
373                          curr_size_bytes_ / 1024);
374   } else {
375     LOG(ERROR) << "Failed to parse proto file.";
376   }
377 }
378
379 MemoryProgramCache::ProgramCacheValue::ProgramCacheValue(
380     GLsizei length,
381     GLenum format,
382     const char* data,
383     const std::string& program_hash,
384     const char* shader_0_hash,
385     const AttributeMap& attrib_map_0,
386     const UniformMap& uniform_map_0,
387     const VaryingMap& varying_map_0,
388     const char* shader_1_hash,
389     const AttributeMap& attrib_map_1,
390     const UniformMap& uniform_map_1,
391     const VaryingMap& varying_map_1,
392     MemoryProgramCache* program_cache)
393     : length_(length),
394       format_(format),
395       data_(data),
396       program_hash_(program_hash),
397       shader_0_hash_(shader_0_hash, kHashLength),
398       attrib_map_0_(attrib_map_0),
399       uniform_map_0_(uniform_map_0),
400       varying_map_0_(varying_map_0),
401       shader_1_hash_(shader_1_hash, kHashLength),
402       attrib_map_1_(attrib_map_1),
403       uniform_map_1_(uniform_map_1),
404       varying_map_1_(varying_map_1),
405       program_cache_(program_cache) {
406   program_cache_->curr_size_bytes_ += length_;
407   program_cache_->LinkedProgramCacheSuccess(program_hash);
408 }
409
410 MemoryProgramCache::ProgramCacheValue::~ProgramCacheValue() {
411   program_cache_->curr_size_bytes_ -= length_;
412   program_cache_->Evict(program_hash_);
413 }
414
415 }  // namespace gles2
416 }  // namespace gpu