8 #ifndef hifi_PickCacheOptimizer_h
9 #define hifi_PickCacheOptimizer_h
11 #include <unordered_map>
15 typedef struct PickCacheKey {
16 PickFilter::Flags mask;
17 QVector<QUuid> include;
18 QVector<QUuid> ignore;
20 bool operator==(
const PickCacheKey& other)
const {
21 return (mask == other.mask && include == other.include && ignore == other.ignore);
26 struct std::hash<PickCacheKey> {
27 size_t operator()(
const PickCacheKey& k)
const {
28 return ((std::hash<PickFilter::Flags>()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1);
35 class PickCacheOptimizer {
38 QVector3D update(std::unordered_map<uint32_t, std::shared_ptr<PickQuery>>& picks, uint32_t& nextToUpdate, uint64_t expiry,
bool shouldPickHUD);
41 typedef std::unordered_map<T, std::unordered_map<PickCacheKey, PickResultPointer>> PickCache;
44 bool checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res,
const PickCacheKey& key);
45 void cacheResult(
const bool intersects,
const PickResultPointer& resTemp,
const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache,
const std::shared_ptr<Pick<T>> pick);
49 bool PickCacheOptimizer<T>::checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res,
const PickCacheKey& key) {
50 if (cache.find(pick) != cache.end() && cache[pick].find(key) != cache[pick].end()) {
51 res = res->compareAndProcessNewResult(cache[pick][key]);
58 void PickCacheOptimizer<T>::cacheResult(
const bool needToCompareResults,
const PickResultPointer& resTemp,
const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache,
const std::shared_ptr<Pick<T>> pick) {
59 if (needToCompareResults) {
60 cache[mathPick][key] = resTemp;
61 res = res->compareAndProcessNewResult(resTemp);
63 cache[mathPick][key] = pick->getDefaultResult(mathPick.toVariantMap());
68 QVector3D PickCacheOptimizer<T>::update(std::unordered_map<uint32_t, std::shared_ptr<PickQuery>>& picks,
69 uint32_t& nextToUpdate, uint64_t expiry,
bool shouldPickHUD) {
70 QVector3D numIntersectionsComputed;
72 const uint32_t INVALID_PICK_ID = 0;
73 auto itr = picks.begin();
74 if (nextToUpdate != INVALID_PICK_ID) {
75 itr = picks.find(nextToUpdate);
76 if (itr == picks.end()) {
80 uint32_t numUpdates = 0;
81 while(numUpdates < picks.size()) {
82 std::shared_ptr<Pick<T>> pick = std::static_pointer_cast<Pick<T>>(itr->second);
83 T mathematicalPick = pick->getMathematicalPick();
84 PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap());
86 if (!pick->isEnabled() || pick->getMaxDistance() < 0.0f || !mathematicalPick) {
87 pick->setPickResult(res);
89 if (pick->getFilter().doesPickDomainEntities() || pick->getFilter().doesPickAvatarEntities() || pick->getFilter().doesPickLocalEntities()) {
90 PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
91 if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) {
92 PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick);
93 numIntersectionsComputed[0]++;
95 cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick);
100 if (pick->getFilter().doesPickAvatars()) {
101 PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
102 if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) {
103 PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick);
104 numIntersectionsComputed[1]++;
106 cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick);
112 if (pick->getFilter().doesPickHUD() && shouldPickHUD) {
113 PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
114 if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) {
115 PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick);
116 numIntersectionsComputed[2]++;
118 cacheResult(
true, hudRes, hudKey, res, mathematicalPick, results, pick);
123 if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) {
124 pick->setPickResult(res);
126 pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap()));
131 if (itr == picks.end()) {
134 nextToUpdate = itr->first;
136 if (usecTimestampNow() > expiry) {
140 return numIntersectionsComputed;