Overte C++ Documentation
ShapeManager.h
1 //
2 // ShapeManager.h
3 // libraries/physics/src
4 //
5 // Created by Andrew Meadows 2014.10.29
6 // Copyright 2014 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 
12 #ifndef hifi_ShapeManager_h
13 #define hifi_ShapeManager_h
14 
15 #include <atomic>
16 #include <chrono>
17 #include <vector>
18 
19 #include <QObject>
20 #include <btBulletDynamicsCommon.h>
21 #include <LinearMath/btHashMap.h>
22 
23 #include <ShapeInfo.h>
24 
25 #include "ShapeFactory.h"
26 #include "HashKey.h"
27 
28 // The ShapeManager handles the ref-counting on shared shapes:
29 //
30 // Each object added to the physics simulation gets a corresponding btRigidBody.
31 // The body has a btCollisionShape that represents the contours of its collision
32 // surface. Multiple bodies may have the same shape. Rather than create a unique
33 // btCollisionShape instance for every body with a particular shape we can instead
34 // use a single shape instance for all of the bodies. This is called "shape
35 // sharing".
36 //
37 // When body needs a new shape a description of ths shape (ShapeInfo) is assembled
38 // and a request is sent to the ShapeManager for a corresponding btCollisionShape
39 // pointer. The ShapeManager will compute a hash of the ShapeInfo's data and use
40 // that to find the shape in its map. If it finds one it increments the ref-count
41 // and returns the pointer. If not it asks the ShapeFactory to create it, adds an
42 // entry in the map with a ref-count of 1, and returns the pointer.
43 //
44 // When a body stops using a shape the ShapeManager must be informed so it can
45 // decrement its ref-count. When a ref-count drops to zero the ShapeManager
46 // doesn't delete it right away. Instead it puts the shape's key on a list delete
47 // later. When that list grows big enough the ShapeManager will remove any matching
48 // entries that still have zero ref-count.
49 
50 
51 class ShapeManager : public QObject {
52  Q_OBJECT
53 public:
54 
55  ShapeManager();
56  ~ShapeManager();
57 
59  const btCollisionShape* getShape(const ShapeInfo& info);
60  const btCollisionShape* getShapeByKey(uint64_t key);
61  bool hasShapeWithKey(uint64_t key) const;
62 
64  bool releaseShape(const btCollisionShape* shape);
65 
67  void collectGarbage();
68 
69  // validation methods
70  int getNumShapes() const { return _shapeMap.size(); }
71  int getNumReferences(const ShapeInfo& info) const;
72  int getNumReferences(const btCollisionShape* shape) const;
73  bool hasShape(const btCollisionShape* shape) const;
74  uint32_t getWorkRequestCount() const { return _workRequestCount; }
75  uint32_t getWorkDeliveryCount() const { return _workDeliveryCount; }
76 
77 protected slots:
78  void acceptWork(ShapeFactory::Worker* worker);
79 
80 private:
81  void addToGarbage(uint64_t key);
82  bool releaseShapeByKey(uint64_t key);
83 
84  class ShapeReference {
85  public:
86  int refCount;
87  const btCollisionShape* shape;
88  uint64_t key { 0 };
89  ShapeReference() : refCount(0), shape(nullptr) {}
90  };
91 
92  using TimePoint = std::chrono::time_point<std::chrono::steady_clock>;
93  class KeyExpiry {
94  public:
95  KeyExpiry(uint64_t k, std::chrono::time_point<std::chrono::steady_clock> e) : expiry(e), key(k) {}
96  TimePoint expiry;
97  uint64_t key;
98  };
99 
100  // btHashMap is required because it supports memory alignment of the btCollisionShapes
101  btHashMap<HashKey, ShapeReference> _shapeMap;
102  std::vector<uint64_t> _garbageRing;
103  std::vector<uint64_t> _pendingMeshShapes;
104  std::vector<KeyExpiry> _orphans;
105  ShapeFactory::Worker* _deadWorker { nullptr };
106  TimePoint _nextOrphanExpiry;
107  uint32_t _ringIndex { 0 };
108  std::atomic_uint _workRequestCount { 0 };
109  std::atomic_uint _workDeliveryCount { 0 };
110 };
111 
112 #endif // hifi_ShapeManager_h