Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
shaderinputregistry.h
Go to the documentation of this file.
1 
18 #ifndef ION_GFX_SHADERINPUTREGISTRY_H_
19 #define ION_GFX_SHADERINPUTREGISTRY_H_
20 
21 #include <functional>
22 #include <map>
23 #include <string>
24 #include <vector>
25 
26 #include "base/macros.h"
27 #include "ion/base/allocator.h"
28 #include "ion/base/logging.h"
29 #include "ion/base/referent.h"
33 #include "ion/base/stringutils.h"
35 #include "ion/gfx/attribute.h"
36 #include "ion/gfx/resourceholder.h"
37 #include "ion/gfx/uniform.h"
38 
39 namespace ion {
40 namespace gfx {
41 
43 
46 
88 class ION_API ShaderInputRegistry : public ResourceHolder {
89  public:
91  enum {
92  kUniformAdded = kNumBaseChanges,
93  kNumChanges
94  };
95 
110  template <typename T>
112  typedef std::function<const T(const T& old_value, const T& new_value)> Type;
113  };
114 
124  template <typename T>
126  typedef std::function<std::vector<T>(const T& current_value)> Type;
127  };
128 
130  template <typename T>
131  struct Spec {
132  Spec(const std::string& name_in = std::string(),
133  typename T::ValueType value_type_in =
134  static_cast<typename T::ValueType>(0),
135  const std::string& doc_string_in = std::string(),
136  typename CombineFunction<T>::Type combine_function_in = nullptr,
137  typename GenerateFunction<T>::Type generate_function_in = nullptr)
138  : name(name_in),
139  value_type(value_type_in),
140  doc_string(doc_string_in),
141  index(0),
142  registry_id(0),
143  registry(NULL),
144  combine_function(combine_function_in),
145  generate_function(generate_function_in) {}
146 
147  std::string name; // Name of the shader input argument.
148  typename T::ValueType value_type; // Type of the value of the shader input.
149  std::string doc_string; // String describing its use.
150  size_t index; // Unique index within registry.
151  size_t registry_id; // Id of the owning registry.
155 
160  };
161 
164 
166 
169  size_t GetId() const { return id_; }
170 
176  bool Include(const ShaderInputRegistryPtr& reg);
177 
181  bool IncludeGlobalRegistry();
182 
185  return includes_;
186  }
187 
190  bool CheckInputsAreUnique() const;
191 
194  template <typename T> bool Add(const Spec<T>& spec) {
195  size_t array_index = 0;
196  std::string name;
197  if (Contains(spec.name)) {
198  LOG(WARNING) << "Can't add " << T::GetShaderInputTypeName() << " spec"
199  << " for '" << spec.name << "': already present in registry"
200  << " or its includes";
201  return false;
202  } else if (!ParseShaderInputName(spec.name, &name, &array_index)) {
203  LOG(WARNING) << "Can't add " << T::GetShaderInputTypeName() << " spec"
204  << " for '" << spec.name << "': invalid input name.";
205  return false;
206  } else {
208  base::AllocDeque<Spec<T> >& specs = *GetMutableSpecs<T>();
209  const size_t index = specs.size();
210  specs.push_back(spec);
211  specs.back().index = index;
212  specs.back().registry_id = id_;
213  specs.back().registry = this;
214  UpdateLargestRegistrySize(specs.size());
216  spec_map_[spec.name] = SpecMapEntry(T::GetTag(), index, id_);
217  return true;
218  }
219  }
220 
223  bool Contains(const std::string& name) const;
224 
227  template <typename T> const Spec<T>* Find(const std::string& name) const {
228  const size_t num_includes = includes_.size();
229  for (size_t i = 0; i < num_includes; ++i) {
230  const Spec<T>* spec = includes_[i]->Find<T>(name);
231  if (spec)
232  return spec;
233  }
234  const SpecMapType::const_iterator it = spec_map_.find(name);
235  if (it == spec_map_.end()) {
238  return NULL;
239  } else if (it->second.tag != T::GetTag()) {
242  return NULL;
243  } else {
245  return &GetSpecs<T>()[it->second.index];
246  }
247  }
248 
250  template <typename T> const base::AllocDeque<Spec<T> >& GetSpecs() const;
251 
257  template <typename ShaderInputType, typename T>
258  const ShaderInputType Create(const std::string& name_in, const T& value) {
260  typedef typename base::VariantTypeResolver<
261  typename ShaderInputType::HolderType, T>::Type StoredType;
262  typename ShaderInputType::ValueType value_type =
263  ShaderInputType::template GetTypeByValue<StoredType>();
264  std::string name;
265  ShaderInputType input;
266  size_t index = 0, registry_id = 0, array_index = 0;
267  ShaderInputRegistry* registry = NULL;
268  if (ParseShaderInputName(name_in, &name, &array_index)) {
269  if (!Find<ShaderInputType>(name))
270  Add<ShaderInputType>(Spec<ShaderInputType>(name, value_type));
271  if (ValidateNameAndType<ShaderInputType>(name, value_type, 0U, &registry,
272  &registry_id, &index))
273  input.template Init<T>(*registry, registry_id, index, array_index,
274  value_type, value);
275  }
276  return input;
277  }
278  template <typename ShaderInputType, typename T>
279  const ShaderInputType Create(const std::string& name_in,
280  const T& value) const {
282  typedef typename base::VariantTypeResolver<
283  typename ShaderInputType::HolderType, T>::Type StoredType;
284  typename ShaderInputType::ValueType value_type =
285  ShaderInputType::template GetTypeByValue<StoredType>();
286  std::string name;
287  ShaderInputType input;
288  size_t index = 0, registry_id = 0, array_index = 0;
289  ShaderInputRegistry* registry = NULL;
290  if (ParseShaderInputName(name_in, &name, &array_index) &&
291  ValidateNameAndType<ShaderInputType>(name, value_type, 0U, &registry,
292  &registry_id, &index))
293  input.template Init<T>(*registry, registry_id, index, array_index,
294  value_type, value);
295  return input;
296  }
297 
305  template <typename T>
306  const Uniform CreateArrayUniform(const std::string& name_in, const T* values,
307  size_t count,
308  const base::AllocatorPtr& allocator) {
311  StoredType;
312  Uniform input;
313  size_t index = 0, registry_id = 0, array_index = 0;
314  ShaderInputRegistry* registry = NULL;
315  UniformType value_type = Uniform::GetTypeByValue<StoredType>();
316  std::string name;
317  if (ParseShaderInputName(name_in, &name, &array_index)) {
318  if (!Find<Uniform>(name)) Add<Uniform>(Spec<Uniform>(name, value_type));
319  ValidateNameAndType<Uniform>(name, value_type, count, &registry,
320  &registry_id, &index);
321  input.template InitArray<T>(*registry, registry_id, index, array_index,
322  value_type, values, count, allocator);
323  }
324  return input;
325  }
326  template <typename T>
327  const Uniform CreateArrayUniform(const std::string& name_in, const T* values,
328  size_t count,
329  const base::AllocatorPtr& allocator) const {
332  StoredType;
333  Uniform input;
334  size_t index = 0, registry_id = 0, array_index = 0;
335  ShaderInputRegistry* registry = NULL;
336  UniformType value_type = Uniform::GetTypeByValue<StoredType>();
337  std::string name;
338  if (ParseShaderInputName(name_in, &name, &array_index) &&
339  ValidateNameAndType<Uniform>(name, value_type, count, &registry,
340  &registry_id, &index))
341  input.template InitArray<T>(*registry, registry_id, index, array_index,
342  value_type, values, count, allocator);
343  return input;
344  }
345 
349  template <typename T>
350  static const Spec<T>* GetSpec(const T& input) {
351  return !input.IsValid() ? NULL :
352  &input.GetRegistry().template GetSpecs<T>()[input.GetIndexInRegistry()];
353  }
354 
357  static const ShaderInputRegistryPtr& GetGlobalRegistry();
358 
359  protected:
362  ~ShaderInputRegistry() override;
363 
364  private:
367  class StaticData;
371  class StaticGlobalRegistryData;
372 
375  static StaticData* GetStaticData();
376 
379  static StaticGlobalRegistryData* GetStaticGlobalRegistryData();
380 
382  static void UpdateLargestRegistrySize(size_t size);
383 
384  struct SpecMapEntry {
385  SpecMapEntry()
386  : tag(ShaderInputBase::kUniform),
387  index(0),
388  registry_id(0) {}
389 
390  SpecMapEntry(const ShaderInputBase::Tag& tag_in, size_t index_in,
391  size_t registry_id_in)
392  : tag(tag_in),
393  index(index_in),
394  registry_id(registry_id_in) {}
395 
397  size_t index;
398  size_t registry_id;
399  };
400  typedef base::AllocMap<const std::string, SpecMapEntry> SpecMapType;
401 
403  const SpecMapType GetAllSpecEntries() const;
404 
406  template <typename T>
407  base::AllocDeque<Spec<T> >* GetMutableSpecs();
408 
414  template <typename T>
415  bool ValidateNameAndType(const std::string& name,
416  const typename T::ValueType value_type, size_t size,
417  ShaderInputRegistry** registry, size_t* registry_id,
418  size_t* index) const {
419  DCHECK(index);
420  if (const Spec<T>* spec = Find<T>(name)) {
421  if (spec->value_type == value_type) {
422  *index = spec->index;
423  *registry_id = spec->registry_id;
424  *registry = spec->registry;
425  return true;
426  } else {
427  LOG(ERROR) << "Can't create " << T::GetShaderInputTypeName() << " '"
428  << name << "': wrong value_type (got "
429  << T::GetValueTypeName(value_type) << ", expected "
430  << T::GetValueTypeName(spec->value_type) << ")";
431  return false;
432  }
433  } else {
434  LOG(ERROR) << "Can't create " << T::GetShaderInputTypeName() << " '"
435  << name << "': no Spec exists for this name, did you forget "
436  << "to Add() it?";
437  return false;
438  }
439  }
440 
443  bool ParseShaderInputName(const std::string& input, std::string* name,
444  size_t* index) const {
446  *index = 0;
447  name->clear();
448  const size_t open_pos = input.find("[");
449  const size_t close_pos = input.find("]");
450  if (open_pos != std::string::npos && close_pos != std::string::npos &&
451  close_pos > open_pos + 1U) {
452  const std::vector<std::string> tokens = base::SplitString(input, "[]");
453  *name = tokens[0];
454  if (tokens.size() > 1 && !tokens[1].empty())
455  *index = base::StringToInt32(tokens[1]);
456  } else if (open_pos == std::string::npos &&
457  close_pos == std::string::npos) {
458  *name = input;
459  } else {
460  return false;
461  }
462  return true;
463  }
464 
465 
467  Field<base::AllocDeque<UniformSpec> > uniform_specs_;
468  base::AllocDeque<AttributeSpec> attribute_specs_;
469 
471  base::AllocVector<ShaderInputRegistryPtr> includes_;
472 
474  SpecMapType spec_map_;
475 
477  size_t id_;
478 
480  DISALLOW_COPY_AND_ASSIGN(ShaderInputRegistry);
481 };
482 
483 } // namespace gfx
484 } // namespace ion
485 
486 #endif // ION_GFX_SHADERINPUTREGISTRY_H_
internal::ResolverHelper< VariantType, TypeToResolve, TypeToResolve >::Type Type
const Spec< T > * Find(const std::string &name) const
Returns the Spec for an input, or NULL if there isn't yet one.
GenerateFunction< T >::Type generate_function
Function used to generate values.
The VariantTypeResolver struct allows users of the Variant class to determine which type defined by a...
const base::AllocVector< ShaderInputRegistryPtr > & GetIncludes() const
Returns the vector of included registries.
This struct is stored for each registered ShaderInput.
std::function< std::vector< T >const T &current_value)> Type
#define DCHECK(expr)
Definition: logging.h:331
double value
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
Definition: logging.h:216
const ShaderInputType Create(const std::string &name_in, const T &value)
Constructs a ShaderInput with the given name and value.
const Uniform CreateArrayUniform(const std::string &name_in, const T *values, size_t count, const base::AllocatorPtr &allocator) const
A Uniform instance represents a uniform shader argument.
Definition: uniform.h:76
Spec(const std::string &name_in=std::string(), typename T::ValueType value_type_in=static_cast< typename T::ValueType >(0), const std::string &doc_string_in=std::string(), typename CombineFunction< T >::Type combine_function_in=nullptr, typename GenerateFunction< T >::Type generate_function_in=nullptr)
std::vector< std::string > ION_API SplitString(const std::string &str, const std::string &delimiters)
Splits a string into a vector of substrings, given a set of delimiter characters (expressed as a stri...
Definition: stringutils.cc:187
Tag
This is only used to determine the type of a ShaderInputRegistry::Spec since Attributes and Uniforms ...
Definition: shaderinput.h:35
bool Add(const Spec< T > &spec)
Adds a type specification to the registry.
size_t GetId() const
Each ShaderInputRegistry instance is assigned a unique integer ID.
const Uniform CreateArrayUniform(const std::string &name_in, const T *values, size_t count, const base::AllocatorPtr &allocator)
Constructs an array Uniform with the given name and values, using the passed allocator to construct t...
A ShaderInputRegistry is used to manage a collection of shader inputs to a specific ShaderProgram (bo...
static const Spec< T > * GetSpec(const T &input)
Convenience function that returns a pointer to the Spec associated with an Attribute or Uniform insta...
std::string name
Definition: printer.cc:324
int32 ION_API StringToInt32(const std::string &str)
Extracts and returns an integral value from str.
Definition: stringutils.cc:328
This type defines a function that is used to combine values for two instances of a registered shader ...
This class can be used in place of std::deque to allow an Ion Allocator to be used for memory allocat...
Definition: allocdeque.h:50
ShaderInputRegistry * registry
The registry that created this spec.
CombineFunction< T >::Type combine_function
Function used to combine values.
Copyright 2016 Google Inc.
A GenerateFunction is similar to a CombineFunction, above, but generates additional inputs based on t...
const ShaderInputType Create(const std::string &name_in, const T &value) const
base::ReferentPtr< ShaderInputRegistry >::Type ShaderInputRegistryPtr
Convenience typedef for shared pointer to a ShaderInputRegistry.
std::function< const T(const T &old_value, const T &new_value)> Type
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
ResourceHolder is an internal base class for objects that hold resources managed by an outside entity...
UniformType
The UniformType enum defines all supported uniform shader argument types.
Definition: uniform.h:37
This class can be used in place of std::vector to allow an Ion Allocator to be used for memory alloca...
Definition: allocvector.h:50