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);
27 struct hash<PickCacheKey> {
28 size_t operator()(
const PickCacheKey& k)
const {
29 return ((hash<PickFilter::Flags>()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1);
37 class PickCacheOptimizer {
40 QVector3D update(std::unordered_map<uint32_t, std::shared_ptr<PickQuery>>& picks, uint32_t& nextToUpdate, uint64_t expiry,
bool shouldPickHUD);
43 typedef std::unordered_map<T, std::unordered_map<PickCacheKey, PickResultPointer>> PickCache;
46 bool checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res,
const PickCacheKey& key);
47 void cacheResult(
const bool intersects,
const PickResultPointer& resTemp,
const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache,
const std::shared_ptr<Pick<T>> pick);
51 bool PickCacheOptimizer<T>::checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res,
const PickCacheKey& key) {
52 if (cache.find(pick) != cache.end() && cache[pick].find(key) != cache[pick].end()) {
53 res = res->compareAndProcessNewResult(cache[pick][key]);
60 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) {
61 if (needToCompareResults) {
62 cache[mathPick][key] = resTemp;
63 res = res->compareAndProcessNewResult(resTemp);
65 cache[mathPick][key] = pick->getDefaultResult(mathPick.toVariantMap());
70 QVector3D PickCacheOptimizer<T>::update(std::unordered_map<uint32_t, std::shared_ptr<PickQuery>>& picks,
71 uint32_t& nextToUpdate, uint64_t expiry,
bool shouldPickHUD) {
72 QVector3D numIntersectionsComputed;
74 const uint32_t INVALID_PICK_ID = 0;
75 auto itr = picks.begin();
76 if (nextToUpdate != INVALID_PICK_ID) {
77 itr = picks.find(nextToUpdate);
78 if (itr == picks.end()) {
82 uint32_t numUpdates = 0;
83 while(numUpdates < picks.size()) {
84 std::shared_ptr<Pick<T>> pick = std::static_pointer_cast<Pick<T>>(itr->second);
85 T mathematicalPick = pick->getMathematicalPick();
86 PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap());
88 if (!pick->isEnabled() || pick->getMaxDistance() < 0.0f || !mathematicalPick) {
89 pick->setPickResult(res);
91 if (pick->getFilter().doesPickDomainEntities() || pick->getFilter().doesPickAvatarEntities() || pick->getFilter().doesPickLocalEntities()) {
92 PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
93 if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) {
94 PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick);
95 numIntersectionsComputed[0]++;
97 cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick);
102 if (pick->getFilter().doesPickAvatars()) {
103 PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
104 if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) {
105 PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick);
106 numIntersectionsComputed[1]++;
108 cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick);
114 if (pick->getFilter().doesPickHUD() && shouldPickHUD) {
115 PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
116 if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) {
117 PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick);
118 numIntersectionsComputed[2]++;
120 cacheResult(
true, hudRes, hudKey, res, mathematicalPick, results, pick);
125 if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) {
126 pick->setPickResult(res);
128 pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap()));
133 if (itr == picks.end()) {
136 nextToUpdate = itr->first;
138 if (usecTimestampNow() > expiry) {
142 return numIntersectionsComputed;