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/program_cache.h"
6
7#include <string>
8#include "base/memory/scoped_ptr.h"
9#include "gpu/command_buffer/service/shader_manager.h"
10
11namespace gpu {
12namespace gles2 {
13
14ProgramCache::ProgramCache() {}
15ProgramCache::~ProgramCache() {}
16
17void ProgramCache::Clear() {
18  ClearBackend();
19  link_status_.clear();
20}
21
22ProgramCache::LinkedProgramStatus ProgramCache::GetLinkedProgramStatus(
23    const std::string& untranslated_a,
24    const ShaderTranslatorInterface* translator_a,
25    const std::string& untranslated_b,
26    const ShaderTranslatorInterface* translator_b,
27    const std::map<std::string, GLint>* bind_attrib_location_map) const {
28  char a_sha[kHashLength];
29  char b_sha[kHashLength];
30  ComputeShaderHash(untranslated_a, translator_a, a_sha);
31  ComputeShaderHash(untranslated_b, translator_b, b_sha);
32
33  char sha[kHashLength];
34  ComputeProgramHash(a_sha,
35                     b_sha,
36                     bind_attrib_location_map,
37                     sha);
38  const std::string sha_string(sha, kHashLength);
39
40  LinkStatusMap::const_iterator found = link_status_.find(sha_string);
41  if (found == link_status_.end()) {
42    return ProgramCache::LINK_UNKNOWN;
43  } else {
44    return found->second;
45  }
46}
47
48void ProgramCache::LinkedProgramCacheSuccess(
49    const std::string& shader_a,
50    const ShaderTranslatorInterface* translator_a,
51    const std::string& shader_b,
52    const ShaderTranslatorInterface* translator_b,
53    const LocationMap* bind_attrib_location_map) {
54  char a_sha[kHashLength];
55  char b_sha[kHashLength];
56  ComputeShaderHash(shader_a, translator_a, a_sha);
57  ComputeShaderHash(shader_b, translator_b, b_sha);
58  char sha[kHashLength];
59  ComputeProgramHash(a_sha,
60                     b_sha,
61                     bind_attrib_location_map,
62                     sha);
63  const std::string sha_string(sha, kHashLength);
64
65  LinkedProgramCacheSuccess(sha_string);
66}
67
68void ProgramCache::LinkedProgramCacheSuccess(const std::string& program_hash) {
69  link_status_[program_hash] = LINK_SUCCEEDED;
70}
71
72void ProgramCache::ComputeShaderHash(
73    const std::string& str,
74    const ShaderTranslatorInterface* translator,
75    char* result) const {
76  std::string s((
77      translator ? translator->GetStringForOptionsThatWouldAffectCompilation() :
78                   std::string()) + str);
79  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(s.c_str()),
80                      s.length(), reinterpret_cast<unsigned char*>(result));
81}
82
83void ProgramCache::Evict(const std::string& program_hash) {
84  link_status_.erase(program_hash);
85}
86
87namespace {
88size_t CalculateMapSize(const std::map<std::string, GLint>* map) {
89  if (!map) {
90    return 0;
91  }
92  std::map<std::string, GLint>::const_iterator it;
93  size_t total = 0;
94  for (it = map->begin(); it != map->end(); ++it) {
95    total += 4 + it->first.length();
96  }
97  return total;
98}
99}  // anonymous namespace
100
101void ProgramCache::ComputeProgramHash(
102    const char* hashed_shader_0,
103    const char* hashed_shader_1,
104    const std::map<std::string, GLint>* bind_attrib_location_map,
105    char* result) const {
106  const size_t shader0_size = kHashLength;
107  const size_t shader1_size = kHashLength;
108  const size_t map_size = CalculateMapSize(bind_attrib_location_map);
109  const size_t total_size = shader0_size + shader1_size + map_size;
110
111  scoped_ptr<unsigned char[]> buffer(new unsigned char[total_size]);
112  memcpy(buffer.get(), hashed_shader_0, shader0_size);
113  memcpy(&buffer[shader0_size], hashed_shader_1, shader1_size);
114  if (map_size != 0) {
115    // copy our map
116    size_t current_pos = shader0_size + shader1_size;
117    std::map<std::string, GLint>::const_iterator it;
118    for (it = bind_attrib_location_map->begin();
119         it != bind_attrib_location_map->end();
120         ++it) {
121      const size_t name_size = it->first.length();
122      memcpy(&buffer.get()[current_pos], it->first.c_str(), name_size);
123      current_pos += name_size;
124      const GLint value = it->second;
125      buffer[current_pos++] = value >> 24;
126      buffer[current_pos++] = value >> 16;
127      buffer[current_pos++] = value >> 8;
128      buffer[current_pos++] = value;
129    }
130  }
131  base::SHA1HashBytes(buffer.get(),
132                      total_size, reinterpret_cast<unsigned char*>(result));
133}
134
135}  // namespace gles2
136}  // namespace gpu
137