Overte C++ Documentation
ShapePipeline.h
1 //
2 // ShapePipeline.h
3 // render/src/render
4 //
5 // Created by Zach Pomerantz on 12/31/15.
6 // Copyright 2015 High Fidelity, Inc.
7 // Copyright 2024 Overte e.V.
8 //
9 // Distributed under the Apache License, Version 2.0.
10 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 //
12 
13 #ifndef hifi_render_ShapePipeline_h
14 #define hifi_render_ShapePipeline_h
15 
16 #include <unordered_set>
17 
18 #include <gpu/Batch.h>
19 #include <graphics/Material.h>
20 
21 #include "Args.h"
22 
23 namespace render {
24 class Item;
25 class ShapePlumber;
26 
27 class ShapeKey {
28 public:
29  enum FlagBit {
30  MATERIAL = 0,
31  TRANSLUCENT,
32  LIGHTMAP,
33  TANGENTS,
34  UNLIT,
35  DEFORMED,
36  DUAL_QUAT_SKINNED,
37  DEPTH_BIAS,
38  WIREFRAME,
39  FADE,
40  CULL_FACE_NONE, // if neither of these are set, we're CULL_FACE_BACK
41  CULL_FACE_FRONT,
42  MTOON,
43  TRIPLANAR,
44  LAYERS2, // if neither of these are set, we just have 1 layer
45  LAYERS3,
46  SPLATMAP,
47 
48  OWN_PIPELINE,
49  INVALID,
50 
51  CUSTOM_0,
52  CUSTOM_1,
53  CUSTOM_2,
54  CUSTOM_3,
55  CUSTOM_4,
56  CUSTOM_5,
57  CUSTOM_6,
58  CUSTOM_7,
59 
60  NUM_FLAGS, // Not a valid flag
61  NUM_NON_CUSTOM = INVALID,
62 
63  CUSTOM_MASK = (0xFF << CUSTOM_0),
64 
65  };
66  using Flags = std::bitset<NUM_FLAGS>;
67 
68  Flags _flags;
69 
70  ShapeKey() : _flags{ 0 } {}
71  ShapeKey(const Flags& flags) : _flags{flags} {}
72 
73  friend ShapeKey operator&(const ShapeKey& _Left, const ShapeKey& _Right) { return ShapeKey(_Left._flags & _Right._flags); }
74  friend ShapeKey operator|(const ShapeKey& _Left, const ShapeKey& _Right) { return ShapeKey(_Left._flags | _Right._flags); }
75  friend ShapeKey operator^(const ShapeKey& _Left, const ShapeKey& _Right) { return ShapeKey(_Left._flags ^ _Right._flags); }
76 
77  class Builder {
78  public:
79  Builder() {}
80  Builder(ShapeKey key) : _flags{key._flags} {}
81 
82  ShapeKey build() const { return ShapeKey{_flags}; }
83 
84  Builder& withMaterial() { _flags.set(MATERIAL); return (*this); }
85  Builder& withTranslucent() { _flags.set(TRANSLUCENT); return (*this); }
86  Builder& withLightMap() { _flags.set(LIGHTMAP); return (*this); }
87  Builder& withTangents() { _flags.set(TANGENTS); return (*this); }
88  Builder& withoutTangents() { _flags.reset(TANGENTS); return (*this); }
89  Builder& withUnlit() { _flags.set(UNLIT); return (*this); }
90  Builder& withDeformed() { _flags.set(DEFORMED); return (*this); }
91  Builder& withDualQuatSkinned() { _flags.set(DUAL_QUAT_SKINNED); return (*this); }
92  Builder& withDepthBias() { _flags.set(DEPTH_BIAS); return (*this); }
93  Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); }
94  Builder& withFade() { _flags.set(FADE); return (*this); }
95  Builder& withMToon() { _flags.set(MTOON); return (*this); }
96  Builder& withTriplanar() { _flags.set(TRIPLANAR); return (*this); }
97 
98  Builder& withoutCullFace() { return withCullFaceMode(graphics::MaterialKey::CullFaceMode::CULL_NONE); }
99  Builder& withCullFaceMode(graphics::MaterialKey::CullFaceMode cullFaceMode) {
100  switch (cullFaceMode) {
101  case graphics::MaterialKey::CullFaceMode::CULL_NONE:
102  _flags.set(CULL_FACE_NONE);
103  _flags.reset(CULL_FACE_FRONT);
104  break;
105  case graphics::MaterialKey::CullFaceMode::CULL_FRONT:
106  _flags.reset(CULL_FACE_NONE);
107  _flags.set(CULL_FACE_FRONT);
108  break;
109  case graphics::MaterialKey::CullFaceMode::CULL_BACK:
110  _flags.reset(CULL_FACE_NONE);
111  _flags.reset(CULL_FACE_FRONT);
112  break;
113  default:
114  break;
115  }
116  return (*this);
117  }
118 
119  Builder& withLayers(uint8_t numLayers) {
120  switch (numLayers) {
121  case 3:
122  _flags.set(LAYERS3);
123  _flags.reset(LAYERS2);
124  break;
125  case 2:
126  _flags.reset(LAYERS3);
127  _flags.set(LAYERS2);
128  break;
129  default:
130  _flags.reset(LAYERS3);
131  _flags.reset(LAYERS2);
132  break;
133  }
134  return (*this);
135  }
136 
137  Builder& withSplatMap() { _flags.set(SPLATMAP); return (*this); }
138 
139  Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); }
140  Builder& invalidate() { _flags.set(INVALID); return (*this); }
141 
142  Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); return (*this); }
143 
144  static const ShapeKey ownPipeline() { return Builder().withOwnPipeline(); }
145  static const ShapeKey invalid() { return Builder().invalidate(); }
146 
147  protected:
148  friend class ShapeKey;
149  Flags _flags{0};
150  };
151  ShapeKey(const Builder& builder) : ShapeKey{builder._flags} {}
152 
153  class Filter {
154  public:
155  Filter(Flags flags, Flags mask) : _flags{flags}, _mask{mask} {}
156  Filter(const ShapeKey& key) : _flags{ key._flags } { _mask.set(); }
157 
158  // Build a standard filter (will always exclude OWN_PIPELINE and INVALID)
159  class Builder {
160  public:
161  Builder();
162 
163  Filter build() const { return Filter(_flags, _mask); }
164 
165  Builder& withMaterial() { _flags.set(MATERIAL); _mask.set(MATERIAL); return (*this); }
166  Builder& withoutMaterial() { _flags.reset(MATERIAL); _mask.set(MATERIAL); return (*this); }
167 
168  Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
169  Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
170 
171  Builder& withLightMap() { _flags.set(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); }
172  Builder& withoutLightMap() { _flags.reset(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); }
173 
174  Builder& withTangents() { _flags.set(TANGENTS); _mask.set(TANGENTS); return (*this); }
175  Builder& withoutTangents() { _flags.reset(TANGENTS); _mask.set(TANGENTS); return (*this); }
176 
177  Builder& withUnlit() { _flags.set(UNLIT); _mask.set(UNLIT); return (*this); }
178  Builder& withoutUnlit() { _flags.reset(UNLIT); _mask.set(UNLIT); return (*this); }
179 
180  Builder& withDeformed() { _flags.set(DEFORMED); _mask.set(DEFORMED); return (*this); }
181  Builder& withoutDeformed() { _flags.reset(DEFORMED); _mask.set(DEFORMED); return (*this); }
182 
183  Builder& withDualQuatSkinned() { _flags.set(DUAL_QUAT_SKINNED); _mask.set(DUAL_QUAT_SKINNED); return (*this); }
184  Builder& withoutDualQuatSkinned() { _flags.reset(DUAL_QUAT_SKINNED); _mask.set(DUAL_QUAT_SKINNED); return (*this); }
185 
186  Builder& withDepthBias() { _flags.set(DEPTH_BIAS); _mask.set(DEPTH_BIAS); return (*this); }
187  Builder& withoutDepthBias() { _flags.reset(DEPTH_BIAS); _mask.set(DEPTH_BIAS); return (*this); }
188 
189  Builder& withWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME); return (*this); }
190  Builder& withoutWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME); return (*this); }
191 
192  Builder& withCullFaceMode(graphics::MaterialKey::CullFaceMode cullFaceMode) {
193  switch (cullFaceMode) {
194  case graphics::MaterialKey::CullFaceMode::CULL_NONE:
195  _flags.set(CULL_FACE_NONE);
196  _flags.reset(CULL_FACE_FRONT);
197  break;
198  case graphics::MaterialKey::CullFaceMode::CULL_FRONT:
199  _flags.reset(CULL_FACE_NONE);
200  _flags.set(CULL_FACE_FRONT);
201  break;
202  case graphics::MaterialKey::CullFaceMode::CULL_BACK:
203  _flags.reset(CULL_FACE_NONE);
204  _flags.reset(CULL_FACE_FRONT);
205  break;
206  default:
207  break;
208  }
209  _mask.set(CULL_FACE_NONE);
210  _mask.set(CULL_FACE_FRONT);
211  return (*this);
212  }
213 
214  Builder& withFade() { _flags.set(FADE); _mask.set(FADE); return (*this); }
215  Builder& withoutFade() { _flags.reset(FADE); _mask.set(FADE); return (*this); }
216 
217  Builder& withMToon() { _flags.set(MTOON); _mask.set(MTOON); return (*this); }
218  Builder& withoutMToon() { _flags.reset(MTOON); _mask.set(MTOON); return (*this); }
219 
220  Builder& withTriplanar() { _flags.set(TRIPLANAR); _mask.set(TRIPLANAR); return (*this); }
221  Builder& withoutTriplanar() { _flags.reset(TRIPLANAR); _mask.set(TRIPLANAR); return (*this); }
222 
223  Builder& withLayers(uint8_t numLayers) {
224  switch (numLayers) {
225  case 3:
226  _flags.set(LAYERS3);
227  _flags.reset(LAYERS2);
228  break;
229  case 2:
230  _flags.reset(LAYERS3);
231  _flags.set(LAYERS2);
232  break;
233  default:
234  _flags.reset(LAYERS3);
235  _flags.reset(LAYERS2);
236  break;
237  }
238  _mask.set(LAYERS3);
239  _mask.set(LAYERS2);
240  return (*this);
241  }
242 
243  Builder& withSplatMap() { _flags.set(SPLATMAP); _mask.set(SPLATMAP); return (*this); }
244  Builder& withoutSplatMap() { _flags.reset(SPLATMAP); _mask.set(SPLATMAP); return (*this); }
245 
246  Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); _mask |= (CUSTOM_MASK); return (*this); }
247  Builder& withoutCustom() { _flags &= (~CUSTOM_MASK); _mask |= (CUSTOM_MASK); return (*this); }
248 
249  protected:
250  friend class Filter;
251  Flags _flags{0};
252  Flags _mask{0};
253  };
254  Filter(const Filter::Builder& builder) : Filter(builder._flags, builder._mask) {}
255  ShapeKey key() const { return ShapeKey(_flags); }
256  protected:
257  friend class ShapePlumber;
258  Flags _flags{0};
259  Flags _mask{0};
260  };
261 
262  bool useMaterial() const { return _flags[MATERIAL]; }
263  bool hasLightMap() const { return _flags[LIGHTMAP]; }
264  bool hasTangents() const { return _flags[TANGENTS]; }
265  bool isUnlit() const { return _flags[UNLIT]; }
266  bool isTranslucent() const { return _flags[TRANSLUCENT]; }
267  bool isDeformed() const { return _flags[DEFORMED]; }
268  bool isDualQuatSkinned() const { return _flags[DUAL_QUAT_SKINNED]; }
269  bool isDepthBiased() const { return _flags[DEPTH_BIAS]; }
270  bool isWireframe() const { return _flags[WIREFRAME]; }
271  bool isCullFace() const { return !_flags[CULL_FACE_NONE] && !_flags[CULL_FACE_FRONT]; }
272  bool isCullFaceNone() const { return _flags[CULL_FACE_NONE] && !_flags[CULL_FACE_FRONT]; }
273  bool isCullFaceFront() const { return !_flags[CULL_FACE_NONE] && _flags[CULL_FACE_FRONT]; }
274  bool isFaded() const { return _flags[FADE]; }
275  bool isMToon() const { return _flags[MTOON]; }
276  bool isTriplanar() const { return _flags[TRIPLANAR]; }
277  uint8_t numLayers() const { return 1 + (uint8_t)_flags[LAYERS2] + 2 * (uint8_t)_flags[LAYERS3]; }
278  bool isSplatMap() const { return _flags[SPLATMAP]; }
279 
280  bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; }
281  bool isValid() const { return !_flags[INVALID]; }
282 
283  uint8_t getCustom() const { return (_flags.to_ulong() & CUSTOM_MASK) >> CUSTOM_0; }
284  bool isCustom() const { return (_flags.to_ulong() & CUSTOM_MASK); }
285 
286  // Comparator for use in stl containers
287  class Hash {
288  public:
289  size_t operator() (const ShapeKey& key) const {
290  return std::hash<ShapeKey::Flags>()(key._flags);
291  }
292  };
293 
294  // Comparator for use in stl containers
295  class KeyEqual {
296  public:
297  bool operator()(const ShapeKey& lhs, const ShapeKey& rhs) const { return lhs._flags == rhs._flags; }
298  };
299 };
300 
301 inline QDebug operator<<(QDebug debug, const ShapeKey& key) {
302  if (key.isValid()) {
303  if (key.hasOwnPipeline()) {
304  debug << "[ShapeKey: OWN_PIPELINE]";
305  } else {
306  debug << "[ShapeKey:"
307  << "useMaterial:" << key.useMaterial()
308  << "hasLightmap:" << key.hasLightMap()
309  << "hasTangents:" << key.hasTangents()
310  << "isUnlit:" << key.isUnlit()
311  << "isTranslucent:" << key.isTranslucent()
312  << "isDeformed:" << key.isDeformed()
313  << "isDualQuatSkinned:" << key.isDualQuatSkinned()
314  << "isDepthBiased:" << key.isDepthBiased()
315  << "isWireframe:" << key.isWireframe()
316  << "isCullFace:" << key.isCullFace()
317  << "isFaded:" << key.isFaded()
318  << "isMToon:" << key.isMToon()
319  << "isTriplanar:" << key.isTriplanar()
320  << "numLayers:" << key.numLayers()
321  << "isSplatMap:" << key.isSplatMap()
322  << "]";
323  }
324  } else {
325  debug << "[ShapeKey: INVALID]";
326  }
327  return debug;
328 }
329 
330 // Rendering abstraction over gpu::Pipeline and map locations
331 // Meta-information (pipeline and locations) to render a shape
332 class ShapePipeline {
333 public:
334  class Locations {
335  public:
336  bool albedoTextureUnit{ false };
337  bool normalTextureUnit{ false };
338  bool roughnessTextureUnit{ false };
339  bool metallicTextureUnit{ false };
340  bool emissiveTextureUnit{ false };
341  bool occlusionTextureUnit{ false };
342  bool lightingModelBufferUnit{ false };
343  bool skinClusterBufferUnit{ false };
344  bool materialBufferUnit{ false };
345  bool keyLightBufferUnit{ false };
346  bool lightBufferUnit{ false };
347  bool lightAmbientBufferUnit{ false };
348  bool lightAmbientMapUnit{ false };
349  bool deferredFrameTransformBufferUnit{ false };
350  bool fadeMaskTextureUnit{ false };
351  bool fadeObjectParameterBufferUnit{ false };
352  bool hazeParameterBufferUnit{ false };
353  bool lightClusterGridBufferUnit{ false };
354  bool lightClusterContentBufferUnit{ false };
355  bool lightClusterFrustumBufferUnit{ false };
356  };
357  using LocationsPointer = std::shared_ptr<Locations>;
358 
359  using BatchSetter = std::function<void(const ShapePipeline*, gpu::Batch&, render::Args*)>;
360  using ItemSetter = std::function<void(const ShapePipeline*, render::Args*, const render::Item&)>;
361 
362  ShapePipeline(const gpu::PipelinePointer& pipeline, const LocationsPointer& locations, const BatchSetter& batchSetter = nullptr, const ItemSetter& itemSetter = nullptr) :
363  pipeline(pipeline),
364  locations(locations),
365  _batchSetter(batchSetter),
366  _itemSetter(itemSetter) {}
367 
368  // Normally, a pipeline is accessed through pickPipeline. If it needs to be set manually,
369  // after calling setPipeline this method should be called to prepare the pipeline with default buffers.
370  void prepare(gpu::Batch& batch, Args* args);
371 
372  gpu::PipelinePointer pipeline;
373  std::shared_ptr<Locations> locations;
374 
375  void prepareShapeItem(Args* args, const ShapeKey& key, const Item& shape);
376 
377 protected:
378  friend class ShapePlumber;
379 
380  BatchSetter _batchSetter;
381  ItemSetter _itemSetter;
382 public:
383  using CustomKey = uint8_t;
384  using CustomFactory = std::function<std::shared_ptr<ShapePipeline> (const ShapePlumber& plumber, const ShapeKey& key, RenderArgs* args)>;
385  using CustomFactoryMap = std::map<CustomKey, CustomFactory>;
386 
387  static CustomFactoryMap _globalCustomFactoryMap;
388 
389  static CustomKey registerCustomShapePipelineFactory(CustomFactory factory);
390 
391 };
392 using ShapePipelinePointer = std::shared_ptr<ShapePipeline>;
393 
394 class ShapePlumber {
395 public:
396  using Key = ShapeKey;
397  using Filter = Key::Filter;
398  using Pipeline = ShapePipeline;
399  using PipelinePointer = ShapePipelinePointer;
400  using PipelineMap = std::unordered_map<ShapeKey, PipelinePointer, ShapeKey::Hash, ShapeKey::KeyEqual>;
401  using PipelineOperator = std::function<void(void)>;
402  using PipelineOperatorMap = std::unordered_map<ShapeKey, PipelineOperator, ShapeKey::Hash, ShapeKey::KeyEqual>;
403  using Slot = int32_t;
404  using Locations = Pipeline::Locations;
405  using LocationsPointer = Pipeline::LocationsPointer;
406  using BatchSetter = Pipeline::BatchSetter;
407  using ItemSetter = Pipeline::ItemSetter;
408 
409  void addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
410  BatchSetter batchSetter = nullptr, ItemSetter itemSetter = nullptr);
411  void addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
412  BatchSetter batchSetter = nullptr, ItemSetter itemSetter = nullptr);
413 
414  void addPipelineOperator(const Key& key, const PipelineOperator& pipelineOperator) { _pipelineOperatorMap[key] = pipelineOperator; }
415 
416  const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const;
417 
418 protected:
419  void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline) const;
420  mutable PipelineMap _pipelineMap;
421  mutable PipelineOperatorMap _pipelineOperatorMap;
422 
423 private:
424  mutable std::unordered_set<Key, Key::Hash, Key::KeyEqual> _missingKeys;
425 };
426 
427 
428 using ShapePlumberPointer = std::shared_ptr<ShapePlumber>;
429 
430 }
431 
432 #endif // hifi_render_ShapePipeline_h