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#ifndef GPU_COMMAND_BUFFER_SERVICE_PROGRAM_MANAGER_H_
6#define GPU_COMMAND_BUFFER_SERVICE_PROGRAM_MANAGER_H_
7
8#include <map>
9#include <string>
10#include <vector>
11#include "base/basictypes.h"
12#include "base/logging.h"
13#include "base/memory/ref_counted.h"
14#include "gpu/command_buffer/service/common_decoder.h"
15#include "gpu/command_buffer/service/gl_utils.h"
16#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
17#include "gpu/command_buffer/service/shader_manager.h"
18#include "gpu/gpu_export.h"
19
20namespace gpu {
21namespace gles2 {
22
23class ProgramCache;
24class ProgramManager;
25class Shader;
26class ShaderManager;
27class ShaderTranslator;
28
29// This is used to track which attributes a particular program needs
30// so we can verify at glDrawXXX time that every attribute is either disabled
31// or if enabled that it points to a valid source.
32class GPU_EXPORT Program : public base::RefCounted<Program> {
33 public:
34  static const int kMaxAttachedShaders = 2;
35
36  enum VaryingsPackingOption {
37    kCountOnlyStaticallyUsed,
38    kCountAll
39  };
40
41  struct UniformInfo {
42    UniformInfo();
43    UniformInfo(
44        GLsizei _size, GLenum _type, GLint _fake_location_base,
45        const std::string& _name);
46    ~UniformInfo();
47
48    bool IsValid() const {
49      return size != 0;
50    }
51
52    bool IsSampler() const {
53      return type == GL_SAMPLER_2D || type == GL_SAMPLER_2D_RECT_ARB ||
54             type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES;
55    }
56
57    GLsizei size;
58    GLenum type;
59    GLint fake_location_base;
60    bool is_array;
61    std::string name;
62    std::vector<GLint> element_locations;
63    std::vector<GLuint> texture_units;
64  };
65  struct VertexAttrib {
66    VertexAttrib(GLsizei _size, GLenum _type, const std::string& _name,
67                     GLint _location)
68        : size(_size),
69          type(_type),
70          location(_location),
71          name(_name) {
72    }
73    GLsizei size;
74    GLenum type;
75    GLint location;
76    std::string name;
77  };
78
79  typedef std::vector<UniformInfo> UniformInfoVector;
80  typedef std::vector<VertexAttrib> AttribInfoVector;
81  typedef std::vector<int> SamplerIndices;
82  typedef std::map<std::string, GLint> LocationMap;
83
84  Program(ProgramManager* manager, GLuint service_id);
85
86  GLuint service_id() const {
87    return service_id_;
88  }
89
90  const SamplerIndices& sampler_indices() {
91    return sampler_indices_;
92  }
93
94  const AttribInfoVector& GetAttribInfos() const {
95    return attrib_infos_;
96  }
97
98  const VertexAttrib* GetAttribInfo(GLint index) const {
99    return (static_cast<size_t>(index) < attrib_infos_.size()) ?
100       &attrib_infos_[index] : NULL;
101  }
102
103  GLint GetAttribLocation(const std::string& name) const;
104
105  const VertexAttrib* GetAttribInfoByLocation(GLuint location) const {
106    if (location < attrib_location_to_index_map_.size()) {
107      GLint index = attrib_location_to_index_map_[location];
108      if (index >= 0) {
109        return &attrib_infos_[index];
110      }
111    }
112    return NULL;
113  }
114
115  const UniformInfo* GetUniformInfo(GLint index) const;
116
117  // If the original name is not found, return NULL.
118  const std::string* GetAttribMappedName(
119      const std::string& original_name) const;
120
121  // If the hashed name is not found, return NULL.
122  const std::string* GetOriginalNameFromHashedName(
123      const std::string& hashed_name) const;
124
125  // Gets the fake location of a uniform by name.
126  GLint GetUniformFakeLocation(const std::string& name) const;
127
128  // Gets the UniformInfo of a uniform by location.
129  const UniformInfo* GetUniformInfoByFakeLocation(
130      GLint fake_location, GLint* real_location, GLint* array_index) const;
131
132  // Gets all the program info.
133  void GetProgramInfo(
134      ProgramManager* manager, CommonDecoder::Bucket* bucket) const;
135
136  // Sets the sampler values for a uniform.
137  // This is safe to call for any location. If the location is not
138  // a sampler uniform nothing will happen.
139  // Returns false if fake_location is a sampler and any value
140  // is >= num_texture_units. Returns true otherwise.
141  bool SetSamplers(
142      GLint num_texture_units, GLint fake_location,
143      GLsizei count, const GLint* value);
144
145  bool IsDeleted() const {
146    return deleted_;
147  }
148
149  void GetProgramiv(GLenum pname, GLint* params);
150
151  bool IsValid() const {
152    return valid_;
153  }
154
155  bool AttachShader(ShaderManager* manager, Shader* shader);
156  bool DetachShader(ShaderManager* manager, Shader* shader);
157
158  bool CanLink() const;
159
160  // Performs glLinkProgram and related activities.
161  bool Link(ShaderManager* manager,
162            ShaderTranslator* vertex_translator,
163            ShaderTranslator* fragment_shader,
164            VaryingsPackingOption varyings_packing_option,
165            const ShaderCacheCallback& shader_callback);
166
167  // Performs glValidateProgram and related activities.
168  void Validate();
169
170  const std::string* log_info() const {
171    return log_info_.get();
172  }
173
174  bool InUse() const {
175    DCHECK_GE(use_count_, 0);
176    return use_count_ != 0;
177  }
178
179  // Sets attribute-location binding from a glBindAttribLocation() call.
180  void SetAttribLocationBinding(const std::string& attrib, GLint location) {
181    bind_attrib_location_map_[attrib] = location;
182  }
183
184  // Sets uniform-location binding from a glBindUniformLocationCHROMIUM call.
185  // returns false if error.
186  bool SetUniformLocationBinding(const std::string& name, GLint location);
187
188  // Detects if there are attribute location conflicts from
189  // glBindAttribLocation() calls.
190  // We only consider the declared attributes in the program.
191  bool DetectAttribLocationBindingConflicts() const;
192
193  // Detects if there are uniforms of the same name but different type
194  // or precision in vertex/fragment shaders.
195  // Return true if such cases are detected.
196  bool DetectUniformsMismatch() const;
197
198  // Return true if a varying is statically used in fragment shader, but it
199  // is not declared in vertex shader.
200  bool DetectVaryingsMismatch() const;
201
202  // Return true if an uniform and an attribute share the same name.
203  bool DetectGlobalNameConflicts() const;
204
205  // Return false if varyings can't be packed into the max available
206  // varying registers.
207  bool CheckVaryingsPacking(VaryingsPackingOption option) const;
208
209  // Visible for testing
210  const LocationMap& bind_attrib_location_map() const {
211    return bind_attrib_location_map_;
212  }
213
214 private:
215  friend class base::RefCounted<Program>;
216  friend class ProgramManager;
217
218  ~Program();
219
220  void set_log_info(const char* str) {
221    log_info_.reset(str ? new std::string(str) : NULL);
222  }
223
224  void ClearLinkStatus() {
225    link_status_ = false;
226  }
227
228  void IncUseCount() {
229    ++use_count_;
230  }
231
232  void DecUseCount() {
233    --use_count_;
234    DCHECK_GE(use_count_, 0);
235  }
236
237  void MarkAsDeleted() {
238    DCHECK(!deleted_);
239    deleted_ =  true;
240  }
241
242  // Resets the program.
243  void Reset();
244
245  // Updates the program info after a successful link.
246  void Update();
247
248  // Process the program log, replacing the hashed names with original names.
249  std::string ProcessLogInfo(const std::string& log);
250
251  // Updates the program log info from GL
252  void UpdateLogInfo();
253
254  // Clears all the uniforms.
255  void ClearUniforms(std::vector<uint8>* zero_buffer);
256
257  // If long attribate names are mapped during shader translation, call
258  // glBindAttribLocation() again with the mapped names.
259  // This is called right before the glLink() call, but after shaders are
260  // translated.
261  void ExecuteBindAttribLocationCalls();
262
263  bool AddUniformInfo(
264      GLsizei size, GLenum type, GLint location, GLint fake_base_location,
265      const std::string& name, const std::string& original_name,
266      size_t* next_available_index);
267
268  void GetCorrectedVariableInfo(
269      bool use_uniforms, const std::string& name, std::string* corrected_name,
270      std::string* original_name, GLsizei* size, GLenum* type) const;
271
272  void DetachShaders(ShaderManager* manager);
273
274  static inline GLint GetUniformInfoIndexFromFakeLocation(
275      GLint fake_location) {
276    return fake_location & 0xFFFF;
277  }
278
279  static inline GLint GetArrayElementIndexFromFakeLocation(
280      GLint fake_location) {
281    return (fake_location >> 16) & 0xFFFF;
282  }
283
284  ProgramManager* manager_;
285
286  int use_count_;
287
288  GLsizei max_attrib_name_length_;
289
290  // Attrib by index.
291  AttribInfoVector attrib_infos_;
292
293  // Attrib by location to index.
294  std::vector<GLint> attrib_location_to_index_map_;
295
296  GLsizei max_uniform_name_length_;
297
298  // Uniform info by index.
299  UniformInfoVector uniform_infos_;
300
301  // The indices of the uniforms that are samplers.
302  SamplerIndices sampler_indices_;
303
304  // The program this Program is tracking.
305  GLuint service_id_;
306
307  // Shaders by type of shader.
308  scoped_refptr<Shader>
309      attached_shaders_[kMaxAttachedShaders];
310
311  // True if this program is marked as deleted.
312  bool deleted_;
313
314  // This is true if glLinkProgram was successful at least once.
315  bool valid_;
316
317  // This is true if glLinkProgram was successful last time it was called.
318  bool link_status_;
319
320  // True if the uniforms have been cleared.
321  bool uniforms_cleared_;
322
323  // This is different than uniform_infos_.size() because
324  // that is a sparce array.
325  GLint num_uniforms_;
326
327  // Log info
328  scoped_ptr<std::string> log_info_;
329
330  // attribute-location binding map from glBindAttribLocation() calls.
331  LocationMap bind_attrib_location_map_;
332
333  // uniform-location binding map from glBindUniformLocationCHROMIUM() calls.
334  LocationMap bind_uniform_location_map_;
335};
336
337// Tracks the Programs.
338//
339// NOTE: To support shared resources an instance of this class will
340// need to be shared by multiple GLES2Decoders.
341class GPU_EXPORT ProgramManager {
342 public:
343  enum TranslatedShaderSourceType {
344    kANGLE,
345    kGL,  // GL or GLES
346  };
347
348  explicit ProgramManager(ProgramCache* program_cache,
349                          uint32 max_varying_vectors);
350  ~ProgramManager();
351
352  // Must call before destruction.
353  void Destroy(bool have_context);
354
355  // Creates a new program.
356  Program* CreateProgram(GLuint client_id, GLuint service_id);
357
358  // Gets a program.
359  Program* GetProgram(GLuint client_id);
360
361  // Gets a client id for a given service id.
362  bool GetClientId(GLuint service_id, GLuint* client_id) const;
363
364  // Gets the shader cache
365  ProgramCache* program_cache() const;
366
367  // Marks a program as deleted. If it is not used the program will be deleted.
368  void MarkAsDeleted(ShaderManager* shader_manager, Program* program);
369
370  // Marks a program as used.
371  void UseProgram(Program* program);
372
373  // Makes a program as unused. If deleted the program will be removed.
374  void UnuseProgram(ShaderManager* shader_manager, Program* program);
375
376  // Clears the uniforms for this program.
377  void ClearUniforms(Program* program);
378
379  // Returns true if prefix is invalid for gl.
380  static bool IsInvalidPrefix(const char* name, size_t length);
381
382  // Check if a Program is owned by this ProgramManager.
383  bool IsOwned(Program* program);
384
385  static int32 MakeFakeLocation(int32 index, int32 element);
386
387  void DoCompileShader(
388      Shader* shader,
389      ShaderTranslator* translator,
390      TranslatedShaderSourceType translated_shader_source_type);
391
392  uint32 max_varying_vectors() const {
393    return max_varying_vectors_;
394  }
395
396 private:
397  friend class Program;
398
399  void StartTracking(Program* program);
400  void StopTracking(Program* program);
401
402  void RemoveProgramInfoIfUnused(
403      ShaderManager* shader_manager, Program* program);
404
405  // Info for each "successfully linked" program by service side program Id.
406  // TODO(gman): Choose a faster container.
407  typedef std::map<GLuint, scoped_refptr<Program> > ProgramMap;
408  ProgramMap programs_;
409
410  // Counts the number of Program allocated with 'this' as its manager.
411  // Allows to check no Program will outlive this.
412  unsigned int program_count_;
413
414  bool have_context_;
415
416  // Used to clear uniforms.
417  std::vector<uint8> zero_;
418
419  ProgramCache* program_cache_;
420
421  uint32 max_varying_vectors_;
422
423  DISALLOW_COPY_AND_ASSIGN(ProgramManager);
424};
425
426}  // namespace gles2
427}  // namespace gpu
428
429#endif  // GPU_COMMAND_BUFFER_SERVICE_PROGRAM_MANAGER_H_
430