Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
buffertoattributebinder.h
Go to the documentation of this file.
1 
18 #ifndef ION_GFXUTILS_BUFFERTOATTRIBUTEBINDER_H_
19 #define ION_GFXUTILS_BUFFERTOATTRIBUTEBINDER_H_
20 
21 #include <string>
22 
23 #include "base/integral_types.h"
24 #include "ion/base/invalid.h"
25 #include "ion/base/logging.h"
26 #include "ion/base/static_assert.h"
27 #include "ion/base/type_structs.h"
29 #include "ion/gfx/attribute.h"
30 #include "ion/gfx/attributearray.h"
31 #include "ion/gfx/bufferobject.h"
33 
34 namespace ion {
35 namespace gfxutils {
36 
43 template <typename T> ION_API
45 template <typename T> ION_API size_t GetComponentCount();
46 
99 
100 template <typename T>
102  public:
103  explicit BufferToAttributeBinder(const T& base_struct)
104  : base_address_(reinterpret_cast<const char*>(&base_struct)) {
105  DCHECK(base_address_);
106  }
107 
109 
111  const gfx::AttributeArrayPtr& aa,
112  const gfx::BufferObjectPtr& bo) {
113  const size_t num_bindings = bindings_.size();
114  for (size_t i = 0; i < num_bindings; ++i) {
115  const size_t element_index = bo->AddSpec(
116  bindings_[i].type, bindings_[i].count, bindings_[i].offset);
117  gfx::Attribute a = reg->Create<gfx::Attribute>(
118  bindings_[i].name, gfx::BufferObjectElement(bo, element_index));
119  DCHECK(a.IsValid());
120  a.SetFixedPointNormalized(bindings_[i].normalize);
121  a.SetDivisor(bindings_[i].divisor);
122  aa->AddAttribute(a);
123  }
124  }
125 
134  size_t struct_size = 0;
135  bool struct_is_packed = true;
136  const size_t num_bindings = bindings_.size();
137  for (size_t i = 0; i < num_bindings; ++i) {
138  if (reg.Contains(bindings_[i].name)) {
139  struct_size += bindings_[i].size;
141  if (bindings_[i].offset) {
142  size_t closest = i;
143  if (!IsBindingPacked(i, &closest)) {
144  LOG(WARNING)
145  << "Attribute '" << bindings_[i].name << "' is not"
146  << " tightly packed, performance may suffer. The closest"
147  << " binding before it is '" << bindings_[closest].name
148  << ",' but it ends at offset "
149  << (bindings_[closest].offset + bindings_[closest].size)
150  << ", while '" << bindings_[i].name << "' starts at offset "
151  << bindings_[i].offset;
152  struct_is_packed = false;
153  }
154  }
155  }
156  }
157  if (struct_size != sizeof(T)) {
158  LOG(WARNING) << "Vertex struct is not tightly packed ("
159  << (sizeof(T) - struct_size)
160  << " byte(s) are wasted), performance may suffer.";
161  struct_is_packed = false;
162  }
163  return struct_is_packed;
164  }
165 
166  template <typename FieldType>
167  BufferToAttributeBinder& Bind(const FieldType& field,
168  const std::string& attribute_name) {
169  return BindInternal(field, attribute_name, false, 0);
170  }
171 
172  template <typename FieldType>
173  BufferToAttributeBinder& BindAndNormalize(const FieldType& field,
174  const std::string& attribute_name) {
175  return BindInternal(field, attribute_name, true, 0);
176  }
177 
178  template <typename FieldType>
179  BufferToAttributeBinder& Bind(const FieldType& field,
180  const std::string& attribute_name,
181  unsigned int divisor) {
182  return BindInternal(field, attribute_name, false, divisor);
183  }
184 
185  template <typename FieldType>
186  BufferToAttributeBinder& BindAndNormalize(const FieldType& field,
187  const std::string& attribute_name,
188  unsigned int divisor) {
189  return BindInternal(field, attribute_name, true, divisor);
190  }
191 
192  private:
194  typedef base::Variant<int8, uint8, int16, uint16, int32, uint32,
195  float,
196  math::VectorBase1i8, math::VectorBase1ui8,
197  math::VectorBase1i16, math::VectorBase1ui16,
198  math::VectorBase1i, math::VectorBase1ui,
199  math::VectorBase1f,
200  math::VectorBase2i8, math::VectorBase2ui8,
201  math::VectorBase2i16, math::VectorBase2ui16,
202  math::VectorBase2i, math::VectorBase2ui,
203  math::VectorBase2f,
204  math::VectorBase3i8, math::VectorBase3ui8,
205  math::VectorBase3i16, math::VectorBase3ui16,
206  math::VectorBase3i, math::VectorBase3ui,
207  math::VectorBase3f,
208  math::VectorBase4i8, math::VectorBase4ui8,
209  math::VectorBase4i16, math::VectorBase4ui16,
210  math::VectorBase4i, math::VectorBase4ui,
211  math::VectorBase4f, math::Matrix2f, math::Matrix3f,
213 
214  struct Binding {
215  Binding(size_t offset_in, size_t count_in, size_t size_in,
216  const std::string& name_in,
217  gfx::BufferObject::ComponentType type_in, bool normalize_in,
218  unsigned int divisor_in)
219  : offset(offset_in),
220  count(count_in),
221  size(size_in),
222  name(name_in),
223  type(type_in),
224  normalize(normalize_in),
225  divisor(divisor_in) {}
226  size_t offset;
227  size_t count;
228  size_t size;
229  std::string name;
231  bool normalize;
232  unsigned int divisor;
233  };
234 
236  BufferToAttributeBinder()
237  : base_address_(NULL) {}
238 
239  template <typename FieldType>
240  BufferToAttributeBinder& BindInternal(const FieldType& field,
241  const std::string& attribute_name,
242  bool normalize, unsigned int divisor) {
243  typedef typename base::VariantTypeResolver<
244  AttributeType, FieldType>::Type ResolvedFieldType;
246  "Cannot resolve attribute type to bind");
247  const char* field_address = reinterpret_cast<const char*>(&field);
248  const ssize_t offset = field_address - base_address_;
249  bindings_.push_back(Binding(offset, GetComponentCount<ResolvedFieldType>(),
250  sizeof(FieldType), attribute_name,
251  GetComponentType<ResolvedFieldType>(),
252  normalize, divisor));
253  return *this;
254  }
255 
258  bool IsBindingPacked(size_t i, size_t* closest) {
259  bool packed = false;
262  size_t closest_index = i;
263  size_t closest_distance = 0;
264  const size_t num_bindings = bindings_.size();
265  for (size_t j = 0; j < num_bindings; ++j) {
268  const size_t end_of_binding = bindings_[j].offset + bindings_[j].size;
269  if (end_of_binding == bindings_[i].offset) {
272  packed = true;
273  break;
274  } else if (end_of_binding < bindings_[i].offset &&
275  end_of_binding > closest_distance) {
278  closest_index = j;
279  closest_distance = end_of_binding;
280  }
281  }
282  if (closest)
283  *closest = closest_index;
284  return packed;
285  }
286 
287  const char* base_address_;
288  std::vector<Binding> bindings_;
289 };
290 
291 } // namespace gfxutils
292 } // namespace ion
293 
294 #endif // ION_GFXUTILS_BUFFERTOATTRIBUTEBINDER_H_
BufferToAttributeBinder & Bind(const FieldType &field, const std::string &attribute_name, unsigned int divisor)
std::string type
Definition: printer.cc:353
#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
BufferToAttributeBinder & BindAndNormalize(const FieldType &field, const std::string &attribute_name)
Matrix< 3, float > Matrix3f
Definition: matrix.h:369
ION_API gfx::BufferObject::ComponentType GetComponentType()
These functions must be specialized for every type used in a vertex.
uint32 offset
Structure for clients to use to encapsulate Elements.
Definition: bufferobject.h:378
A ShaderInputRegistry is used to manage a collection of shader inputs to a specific ShaderProgram (bo...
void SetDivisor(unsigned int divisor)
Definition: attribute.h:97
The Matrix class defines a square N-dimensional matrix.
Definition: matrix.h:35
The Variant class is similar to boost::variant.
Definition: variant.h:201
std::string name
Definition: printer.cc:324
ComponentType
The type of the components of a spec.
Definition: bufferobject.h:77
bool Contains(const std::string &name) const
Returns if a Spec for an input of the passed name exists in the registry or its includes.
BufferToAttributeBinder is a simple interface to insert a set of Attributes containing BufferObjectEl...
Copyright 2016 Google Inc.
BufferToAttributeBinder & Bind(const FieldType &field, const std::string &attribute_name)
Matrix< 2, float > Matrix2f
Dimension- and type-specific typedefs.
Definition: matrix.h:367
void SetFixedPointNormalized(bool normalize)
Definition: attribute.h:87
#define ION_STATIC_ASSERT(expr, message)
Copyright 2016 Google Inc.
Definition: static_assert.h:35
ION_API size_t GetComponentCount()
bool IsValid() const
Returns true if this is a valid instance created by a ShaderInputRegistry.
Definition: shaderinput.h:59
bool AreBindingsPacked(const gfx::ShaderInputRegistry &reg)
Validates that the bindings within the binder are consistent with a packed struct, logging warning messages if they are not.
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
BufferToAttributeBinder & BindAndNormalize(const FieldType &field, const std::string &attribute_name, unsigned int divisor)
void Apply(const gfx::ShaderInputRegistryPtr &reg, const gfx::AttributeArrayPtr &aa, const gfx::BufferObjectPtr &bo)