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