13 #ifndef hifi_render_ShapePipeline_h
14 #define hifi_render_ShapePipeline_h
16 #include <unordered_set>
18 #include <gpu/Batch.h>
19 #include <graphics/Material.h>
61 NUM_NON_CUSTOM = INVALID,
63 CUSTOM_MASK = (0xFF << CUSTOM_0),
66 using Flags = std::bitset<NUM_FLAGS>;
70 ShapeKey() : _flags{ 0 } {}
71 ShapeKey(
const Flags& flags) : _flags{flags} {}
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); }
80 Builder(ShapeKey key) : _flags{key._flags} {}
82 ShapeKey build()
const {
return ShapeKey{_flags}; }
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); }
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);
105 case graphics::MaterialKey::CullFaceMode::CULL_FRONT:
106 _flags.reset(CULL_FACE_NONE);
107 _flags.set(CULL_FACE_FRONT);
109 case graphics::MaterialKey::CullFaceMode::CULL_BACK:
110 _flags.reset(CULL_FACE_NONE);
111 _flags.reset(CULL_FACE_FRONT);
119 Builder& withLayers(uint8_t numLayers) {
123 _flags.reset(LAYERS2);
126 _flags.reset(LAYERS3);
130 _flags.reset(LAYERS3);
131 _flags.reset(LAYERS2);
137 Builder& withSplatMap() { _flags.set(SPLATMAP);
return (*
this); }
139 Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE);
return (*
this); }
140 Builder& invalidate() { _flags.set(INVALID);
return (*
this); }
142 Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0);
return (*
this); }
144 static const ShapeKey ownPipeline() {
return Builder().withOwnPipeline(); }
145 static const ShapeKey invalid() {
return Builder().invalidate(); }
148 friend class ShapeKey;
151 ShapeKey(
const Builder& builder) : ShapeKey{builder._flags} {}
155 Filter(Flags flags, Flags mask) : _flags{flags}, _mask{mask} {}
156 Filter(
const ShapeKey& key) : _flags{ key._flags } { _mask.set(); }
163 Filter build()
const {
return Filter(_flags, _mask); }
165 Builder& withMaterial() { _flags.set(MATERIAL); _mask.set(MATERIAL);
return (*
this); }
166 Builder& withoutMaterial() { _flags.reset(MATERIAL); _mask.set(MATERIAL);
return (*
this); }
168 Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT);
return (*
this); }
169 Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT);
return (*
this); }
171 Builder& withLightMap() { _flags.set(LIGHTMAP); _mask.set(LIGHTMAP);
return (*
this); }
172 Builder& withoutLightMap() { _flags.reset(LIGHTMAP); _mask.set(LIGHTMAP);
return (*
this); }
174 Builder& withTangents() { _flags.set(TANGENTS); _mask.set(TANGENTS);
return (*
this); }
175 Builder& withoutTangents() { _flags.reset(TANGENTS); _mask.set(TANGENTS);
return (*
this); }
177 Builder& withUnlit() { _flags.set(UNLIT); _mask.set(UNLIT);
return (*
this); }
178 Builder& withoutUnlit() { _flags.reset(UNLIT); _mask.set(UNLIT);
return (*
this); }
180 Builder& withDeformed() { _flags.set(DEFORMED); _mask.set(DEFORMED);
return (*
this); }
181 Builder& withoutDeformed() { _flags.reset(DEFORMED); _mask.set(DEFORMED);
return (*
this); }
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); }
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); }
189 Builder& withWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME);
return (*
this); }
190 Builder& withoutWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME);
return (*
this); }
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);
198 case graphics::MaterialKey::CullFaceMode::CULL_FRONT:
199 _flags.reset(CULL_FACE_NONE);
200 _flags.set(CULL_FACE_FRONT);
202 case graphics::MaterialKey::CullFaceMode::CULL_BACK:
203 _flags.reset(CULL_FACE_NONE);
204 _flags.reset(CULL_FACE_FRONT);
209 _mask.set(CULL_FACE_NONE);
210 _mask.set(CULL_FACE_FRONT);
214 Builder& withFade() { _flags.set(FADE); _mask.set(FADE);
return (*
this); }
215 Builder& withoutFade() { _flags.reset(FADE); _mask.set(FADE);
return (*
this); }
217 Builder& withMToon() { _flags.set(MTOON); _mask.set(MTOON);
return (*
this); }
218 Builder& withoutMToon() { _flags.reset(MTOON); _mask.set(MTOON);
return (*
this); }
220 Builder& withTriplanar() { _flags.set(TRIPLANAR); _mask.set(TRIPLANAR);
return (*
this); }
221 Builder& withoutTriplanar() { _flags.reset(TRIPLANAR); _mask.set(TRIPLANAR);
return (*
this); }
223 Builder& withLayers(uint8_t numLayers) {
227 _flags.reset(LAYERS2);
230 _flags.reset(LAYERS3);
234 _flags.reset(LAYERS3);
235 _flags.reset(LAYERS2);
243 Builder& withSplatMap() { _flags.set(SPLATMAP); _mask.set(SPLATMAP);
return (*
this); }
244 Builder& withoutSplatMap() { _flags.reset(SPLATMAP); _mask.set(SPLATMAP);
return (*
this); }
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); }
254 Filter(
const Filter::Builder& builder) : Filter(builder._flags, builder._mask) {}
255 ShapeKey key()
const {
return ShapeKey(_flags); }
257 friend class ShapePlumber;
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]; }
280 bool hasOwnPipeline()
const {
return _flags[OWN_PIPELINE]; }
281 bool isValid()
const {
return !_flags[INVALID]; }
283 uint8_t getCustom()
const {
return (_flags.to_ulong() & CUSTOM_MASK) >> CUSTOM_0; }
284 bool isCustom()
const {
return (_flags.to_ulong() & CUSTOM_MASK); }
289 size_t operator() (
const ShapeKey& key)
const {
290 return std::hash<ShapeKey::Flags>()(key._flags);
297 bool operator()(
const ShapeKey& lhs,
const ShapeKey& rhs)
const {
return lhs._flags == rhs._flags; }
301 inline QDebug operator<<(QDebug debug,
const ShapeKey& key) {
303 if (key.hasOwnPipeline()) {
304 debug <<
"[ShapeKey: OWN_PIPELINE]";
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()
325 debug <<
"[ShapeKey: INVALID]";
332 class ShapePipeline {
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 };
357 using LocationsPointer = std::shared_ptr<Locations>;
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&)>;
362 ShapePipeline(
const gpu::PipelinePointer& pipeline,
const LocationsPointer& locations,
const BatchSetter& batchSetter =
nullptr,
const ItemSetter& itemSetter =
nullptr) :
364 locations(locations),
365 _batchSetter(batchSetter),
366 _itemSetter(itemSetter) {}
370 void prepare(gpu::Batch& batch, Args* args);
372 gpu::PipelinePointer pipeline;
373 std::shared_ptr<Locations> locations;
375 void prepareShapeItem(Args* args,
const ShapeKey& key,
const Item& shape);
378 friend class ShapePlumber;
380 BatchSetter _batchSetter;
381 ItemSetter _itemSetter;
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>;
387 static CustomFactoryMap _globalCustomFactoryMap;
389 static CustomKey registerCustomShapePipelineFactory(CustomFactory factory);
392 using ShapePipelinePointer = std::shared_ptr<ShapePipeline>;
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;
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);
414 void addPipelineOperator(
const Key& key,
const PipelineOperator& pipelineOperator) { _pipelineOperatorMap[key] = pipelineOperator; }
416 const PipelinePointer pickPipeline(RenderArgs* args,
const Key& key)
const;
419 void addPipelineHelper(
const Filter& filter, Key key,
int bit,
const PipelinePointer& pipeline)
const;
420 mutable PipelineMap _pipelineMap;
421 mutable PipelineOperatorMap _pipelineOperatorMap;
424 mutable std::unordered_set<Key, Key::Hash, Key::KeyEqual> _missingKeys;
428 using ShapePlumberPointer = std::shared_ptr<ShapePlumber>;