Ticket #1707: rangemanager_vectorization_binsearch.patch
File rangemanager_vectorization_binsearch.patch, 16.1 KB (added by , 11 years ago) |
---|
-
source/simulation2/components/CCmpRangeManager.cpp
92 92 */ 93 93 struct EntityData 94 94 { 95 EntityData() : retainInFog(0), owner(-1), inWorld(0), flags(1) { } 95 EntityData(entity_id_t entity = INVALID_ENTITY) : 96 id(entity), retainInFog(0), owner(-1), inWorld(0), flags(1) 97 { 98 } 99 100 entity_id_t id; 96 101 entity_pos_t x, z; 97 102 entity_pos_t visionRange; 98 103 u8 retainInFog; // boolean … … 101 106 u8 flags; // See GetEntityFlagMask 102 107 }; 103 108 104 cassert(sizeof(EntityData) == 16);109 cassert(sizeof(EntityData) == 20); 105 110 106 111 107 112 /** … … 131 136 template<typename S> 132 137 void operator()(S& serialize, const char* UNUSED(name), EntityData& value) 133 138 { 139 serialize.NumberU32_Unbounded("id", value.id); 134 140 serialize.NumberFixed_Unbounded("x", value.x); 135 141 serialize.NumberFixed_Unbounded("z", value.z); 136 142 serialize.NumberFixed_Unbounded("vision", value.visionRange); … … 143 149 144 150 145 151 /** 152 * Search entity by id in a vector of EntityData. 153 * Adapted binary search, for sorted set of (non-negative) integers. The min and max entity id's are used to speed up the search. 154 */ 155 cassert(sizeof(entity_id_t) <= sizeof(size_t)); 156 157 template<class EntityDataRandomAccessIterator> 158 static inline EntityDataRandomAccessIterator find_entity(EntityDataRandomAccessIterator first, EntityDataRandomAccessIterator last, entity_id_t entity, entity_id_t minentity, entity_id_t maxentity) 159 { 160 if (first == last) 161 { 162 return last; 163 } 164 165 size_t imin, imax, minoffset, maxoffset; 166 imin = 0; 167 imax = (last-first)-1; 168 minoffset = (size_t)minentity-imin; 169 maxoffset = (size_t)maxentity-imax; 170 imin = std::max<size_t>(imin, (entity>maxoffset)?entity-maxoffset:0); 171 imax = std::min<size_t>(imax, (entity>minoffset)?entity-minoffset:0); 172 while(imax >= imin) 173 { 174 size_t imid = imin + ((imax - imin) / 2); 175 entity_id_t entitymid = first[imid].id; 176 if (entity < entitymid) 177 { 178 maxoffset = entitymid - imid; 179 imin = std::max<size_t>(imin, (entity>maxoffset)?entity-maxoffset:0); 180 imax = imid - 1; 181 } 182 else if (entity > entitymid) 183 { 184 minoffset = entitymid - imid; 185 imin = imid + 1; 186 imax = std::min<size_t>(imax, (entity>minoffset)?entity-minoffset:0); 187 } 188 else 189 { 190 return first + imid; 191 } 192 } 193 return last; 194 } 195 196 template<class EntityDataRandomAccessIterator> 197 static inline EntityDataRandomAccessIterator find_entity(EntityDataRandomAccessIterator first, EntityDataRandomAccessIterator last, entity_id_t entity) 198 { 199 if (first == last) 200 { 201 return last; 202 } 203 204 entity_id_t minentity = first->id; 205 entity_id_t maxentity = (last-1)->id; 206 return find_entity(first, last, entity, minentity, maxentity); 207 } 208 209 /** 210 * Standard binary search 211 */ 212 struct EntityIdComp 213 { 214 inline bool operator()(const EntityData &data, const entity_id_t id) 215 { 216 return data.id < id; 217 } 218 }; 219 template<class EntityDataRandomAccessIterator> 220 static inline EntityDataRandomAccessIterator find_entity_std(EntityDataRandomAccessIterator first, EntityDataRandomAccessIterator last, entity_id_t entity) 221 { 222 EntityIdComp comp; 223 EntityDataRandomAccessIterator it = std::lower_bound(first, last, entity, comp); 224 225 if (it != last && it->id == entity) 226 { 227 return it; 228 } 229 else 230 { 231 return last; 232 } 233 } 234 235 /** 146 236 * Functor for sorting entities by distance from a source point. 147 237 * It must only be passed entities that are in 'entities' 148 238 * and are currently in the world. 149 239 */ 150 240 struct EntityDistanceOrdering 151 241 { 152 EntityDistanceOrdering(const std:: map<entity_id_t, EntityData>&entities, const CFixedVector2D& source) :242 EntityDistanceOrdering(const std::vector<EntityData> &entities, const CFixedVector2D& source) : 153 243 m_EntityData(entities), m_Source(source) 154 244 { 245 m_MinEntityId = m_EntityData.front().id; 246 m_MaxEntityId = m_EntityData.back().id; 155 247 } 156 248 157 249 bool operator()(entity_id_t a, entity_id_t b) 158 250 { 159 const EntityData& da = m_EntityData.find(a)->second;160 const EntityData& db = m_EntityData.find(b)->second;251 const EntityData& da = *find_entity(m_EntityData.begin(), m_EntityData.end(), a, m_MinEntityId, m_MaxEntityId); 252 const EntityData& db = *find_entity(m_EntityData.begin(), m_EntityData.end(), b, m_MinEntityId, m_MaxEntityId); 161 253 CFixedVector2D vecA = CFixedVector2D(da.x, da.z) - m_Source; 162 254 CFixedVector2D vecB = CFixedVector2D(db.x, db.z) - m_Source; 163 255 return (vecA.CompareLength(vecB) < 0); 164 256 } 165 257 166 const std::map<entity_id_t, EntityData>& m_EntityData; 258 const std::vector<EntityData> m_EntityData; 259 entity_id_t m_MinEntityId, m_MaxEntityId; 167 260 CFixedVector2D m_Source; 168 261 169 262 private: … … 210 303 // Range query state: 211 304 tag_t m_QueryNext; // next allocated id 212 305 std::map<tag_t, Query> m_Queries; 213 std:: map<entity_id_t,EntityData> m_EntityData;306 std::vector<EntityData> m_EntityData; 214 307 SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData 215 308 216 309 // LOS state: … … 284 377 285 378 serialize.NumberU32_Unbounded("query next", m_QueryNext); 286 379 SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries); 287 Serialize Map<SerializeU32_Unbounded,SerializeEntityData>()(serialize, "entity data", m_EntityData);380 SerializeVector<SerializeEntityData>()(serialize, "entity data", m_EntityData); 288 381 289 382 SerializeMap<SerializeI32_Unbounded, SerializeBool>()(serialize, "los reveal all", m_LosRevealAll); 290 383 serialize.Bool("los circular", m_LosCircular); … … 335 428 // The newly-created entity will have owner -1 and position out-of-world 336 429 // (any initialisation of those values will happen later), so we can just 337 430 // use the default-constructed EntityData here 338 EntityData entdata ;431 EntityData entdata(ent); 339 432 340 433 // Store the LOS data, if any 341 434 CmpPtr<ICmpVision> cmpVision(GetSimContext(), ent); … … 345 438 entdata.retainInFog = (cmpVision->GetRetainInFog() ? 1 : 0); 346 439 } 347 440 441 // The entity id's are expected to be increasing 442 ENSURE(m_EntityData.empty() || ent > m_EntityData.back().id); 443 348 444 // Remember this entity 349 m_EntityData. insert(std::make_pair(ent, entdata));445 m_EntityData.push_back(entdata); 350 446 351 447 break; 352 448 } … … 355 451 const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg); 356 452 entity_id_t ent = msgData.entity; 357 453 358 std:: map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);454 std::vector<EntityData>::iterator it = FindEntityData(ent); 359 455 360 456 // Ignore if we're not already tracking this entity 361 457 if (it == m_EntityData.end()) … … 363 459 364 460 if (msgData.inWorld) 365 461 { 366 if (it-> second.inWorld)462 if (it->inWorld) 367 463 { 368 CFixedVector2D from(it-> second.x, it->second.z);464 CFixedVector2D from(it->x, it->z); 369 465 CFixedVector2D to(msgData.x, msgData.z); 370 466 m_Subdivision.Move(ent, from, to); 371 LosMove(it-> second.owner, it->second.visionRange, from, to);467 LosMove(it->owner, it->visionRange, from, to); 372 468 } 373 469 else 374 470 { 375 471 CFixedVector2D to(msgData.x, msgData.z); 376 472 m_Subdivision.Add(ent, to); 377 LosAdd(it-> second.owner, it->second.visionRange, to);473 LosAdd(it->owner, it->visionRange, to); 378 474 } 379 475 380 it-> second.inWorld = 1;381 it-> second.x = msgData.x;382 it-> second.z = msgData.z;476 it->inWorld = 1; 477 it->x = msgData.x; 478 it->z = msgData.z; 383 479 } 384 480 else 385 481 { 386 if (it-> second.inWorld)482 if (it->inWorld) 387 483 { 388 CFixedVector2D from(it-> second.x, it->second.z);484 CFixedVector2D from(it->x, it->z); 389 485 m_Subdivision.Remove(ent, from); 390 LosRemove(it-> second.owner, it->second.visionRange, from);486 LosRemove(it->owner, it->visionRange, from); 391 487 } 392 488 393 it-> second.inWorld = 0;394 it-> second.x = entity_pos_t::Zero();395 it-> second.z = entity_pos_t::Zero();489 it->inWorld = 0; 490 it->x = entity_pos_t::Zero(); 491 it->z = entity_pos_t::Zero(); 396 492 } 397 493 398 494 break; … … 402 498 const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); 403 499 entity_id_t ent = msgData.entity; 404 500 405 std:: map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);501 std::vector<EntityData>::iterator it = FindEntityData(ent); 406 502 407 503 // Ignore if we're not already tracking this entity 408 504 if (it == m_EntityData.end()) 409 505 break; 410 506 411 if (it-> second.inWorld)507 if (it->inWorld) 412 508 { 413 CFixedVector2D pos(it-> second.x, it->second.z);414 LosRemove(it-> second.owner, it->second.visionRange, pos);415 LosAdd(msgData.to, it-> second.visionRange, pos);509 CFixedVector2D pos(it->x, it->z); 510 LosRemove(it->owner, it->visionRange, pos); 511 LosAdd(msgData.to, it->visionRange, pos); 416 512 } 417 513 418 514 ENSURE(-128 <= msgData.to && msgData.to <= 127); 419 it-> second.owner = (i8)msgData.to;515 it->owner = (i8)msgData.to; 420 516 421 517 break; 422 518 } … … 425 521 const CMessageDestroy& msgData = static_cast<const CMessageDestroy&> (msg); 426 522 entity_id_t ent = msgData.entity; 427 523 428 std:: map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);524 std::vector<EntityData>::iterator it = FindEntityData(ent); 429 525 430 526 // Ignore if we're not already tracking this entity 431 527 if (it == m_EntityData.end()) 432 528 break; 433 529 434 if (it-> second.inWorld)435 m_Subdivision.Remove(ent, CFixedVector2D(it-> second.x, it->second.z));530 if (it->inWorld) 531 m_Subdivision.Remove(ent, CFixedVector2D(it->x, it->z)); 436 532 437 533 // This will be called after Ownership's OnDestroy, so ownership will be set 438 534 // to -1 already and we don't have to do a LosRemove here 439 ENSURE(it-> second.owner == -1);535 ENSURE(it->owner == -1); 440 536 537 // TODO: be smarter and just mark the data as deleted and then do a bulk-remove once performing queries. 441 538 m_EntityData.erase(it); 442 539 443 540 break; … … 447 544 const CMessageVisionRangeChanged& msgData = static_cast<const CMessageVisionRangeChanged&> (msg); 448 545 entity_id_t ent = msgData.entity; 449 546 450 std:: map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);547 std::vector<EntityData>::iterator it = FindEntityData(ent); 451 548 452 549 // Ignore if we're not already tracking this entity 453 550 if (it == m_EntityData.end()) … … 457 554 if (!cmpVision) 458 555 break; 459 556 460 entity_pos_t oldRange = it-> second.visionRange;557 entity_pos_t oldRange = it->visionRange; 461 558 entity_pos_t newRange = msgData.newRange; 462 559 463 560 // If the range changed and the entity's in-world, we need to manually adjust it 464 561 // but if it's not in-world, we only need to set the new vision range 465 CFixedVector2D pos(it-> second.x, it->second.z);466 if (it-> second.inWorld)467 LosRemove(it-> second.owner, oldRange, pos);562 CFixedVector2D pos(it->x, it->z); 563 if (it->inWorld) 564 LosRemove(it->owner, oldRange, pos); 468 565 469 it-> second.visionRange = newRange;566 it->visionRange = newRange; 470 567 471 if (it-> second.inWorld)472 LosAdd(it-> second.owner, newRange, pos);568 if (it->inWorld) 569 LosAdd(it->owner, newRange, pos); 473 570 474 571 break; 475 572 } … … 555 652 m_LosStateRevealed.clear(); 556 653 m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide); 557 654 558 for (std:: map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)655 for (std::vector<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 559 656 { 560 if (it-> second.inWorld)561 LosAdd(it-> second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z));657 if (it->inWorld) 658 LosAdd(it->owner, it->visionRange, CFixedVector2D(it->x, it->z)); 562 659 } 563 660 564 661 for (ssize_t j = 0; j < m_TerrainVerticesPerSide; ++j) … … 572 669 // (TODO: find the optimal number instead of blindly guessing) 573 670 m_Subdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); 574 671 575 for (std:: map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)672 for (std::vector<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 576 673 { 577 if (it-> second.inWorld)578 m_Subdivision.Add(it-> first, CFixedVector2D(it->second.x, it->second.z));674 if (it->inWorld) 675 m_Subdivision.Add(it->id, CFixedVector2D(it->x, it->z)); 579 676 } 580 677 } 581 678 … … 589 686 return id; 590 687 } 591 688 689 virtual std::vector<EntityData>::iterator FindEntityData(entity_id_t entity) 690 { 691 std::vector<EntityData>::iterator it = find_entity(m_EntityData.begin(), m_EntityData.end(), entity); 692 return it; 693 } 694 592 695 virtual void DestroyActiveQuery(tag_t tag) 593 696 { 594 697 if (m_Queries.find(tag) == m_Queries.end()) … … 693 796 694 797 u32 ownerMask = CalcOwnerMask(player); 695 798 696 for (std:: map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)799 for (std::vector<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 697 800 { 698 801 // Check owner and add to list if it matches 699 if (CalcOwnerMask(it-> second.owner) & ownerMask)700 entities.push_back(it-> first);802 if (CalcOwnerMask(it->owner) & ownerMask) 803 entities.push_back(it->id); 701 804 } 702 805 703 806 return entities; … … 766 869 /** 767 870 * Returns whether the given entity matches the given query (ignoring maxRange) 768 871 */ 769 bool TestEntityQuery(const Query& q, entity_id_t id,const EntityData& entity)872 bool TestEntityQuery(const Query& q, const EntityData& entity) 770 873 { 771 874 // Quick filter to ignore entities with the wrong owner 772 875 if (!(CalcOwnerMask(entity.owner) & q.ownersMask)) … … 781 884 return false; 782 885 783 886 // Ignore self 784 if ( id == q.source)887 if (entity.id == q.source) 785 888 return false; 786 889 787 890 // Ignore if it's missing the required interface 788 if (q.interface && !GetSimContext().GetComponentManager().QueryInterface( id, q.interface))891 if (q.interface && !GetSimContext().GetComponentManager().QueryInterface(entity.id, q.interface)) 789 892 return false; 790 893 791 894 return true; … … 796 899 */ 797 900 void PerformQuery(const Query& q, std::vector<entity_id_t>& r) 798 901 { 902 PROFILE("PerformQuery"); 799 903 CmpPtr<ICmpPosition> cmpSourcePosition(GetSimContext(), q.source); 800 904 if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld()) 801 905 return; … … 804 908 // Special case: range -1.0 means check all entities ignoring distance 805 909 if (q.maxRange == entity_pos_t::FromInt(-1)) 806 910 { 807 for (std:: map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)911 for (std::vector<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 808 912 { 809 if (!TestEntityQuery(q, it->first, it->second))913 if (!TestEntityQuery(q, *it)) 810 914 continue; 811 915 812 r.push_back(it-> first);916 r.push_back(it->id); 813 917 } 814 918 } 815 919 else … … 819 923 820 924 for (size_t i = 0; i < ents.size(); ++i) 821 925 { 822 std:: map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]);926 std::vector<EntityData>::const_iterator it = FindEntityData(ents[i]); 823 927 ENSURE(it != m_EntityData.end()); 824 928 825 if (!TestEntityQuery(q, it->first, it->second))929 if (!TestEntityQuery(q, *it)) 826 930 continue; 827 931 828 932 // Restrict based on precise distance 829 int distVsMax = (CFixedVector2D(it-> second.x, it->second.z) - pos).CompareLength(q.maxRange);933 int distVsMax = (CFixedVector2D(it->x, it->z) - pos).CompareLength(q.maxRange); 830 934 if (distVsMax > 0) 831 935 continue; 832 936 833 937 if (!q.minRange.IsZero()) 834 938 { 835 int distVsMin = (CFixedVector2D(it-> second.x, it->second.z) - pos).CompareLength(q.minRange);939 int distVsMin = (CFixedVector2D(it->x, it->z) - pos).CompareLength(q.minRange); 836 940 if (distVsMin < 0) 837 941 continue; 838 942 } 839 943 840 r.push_back( it->first);944 r.push_back(ents[i]); 841 945 } 842 946 } 843 947 } … … 945 1049 946 1050 virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value) 947 1051 { 948 std:: map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);1052 std::vector<EntityData>::iterator it = FindEntityData(ent); 949 1053 950 1054 // We don't have this entity 951 1055 if (it == m_EntityData.end()) … … 961 1065 } 962 1066 963 1067 if (value) 964 it-> second.flags |= flag;1068 it->flags |= flag; 965 1069 else 966 it-> second.flags &= ~flag;1070 it->flags &= ~flag; 967 1071 } 968 1072 969 1073 // ****************************************************************