History

Merge pull request #14042 from thoys/perf/create/getMultipleEntities

Speed up Entity List properties fetching by adding Entities.getMultipleEntities API

Brad Hefta-Gaub committed 8 years ago

Commit edd5db72 parents ef063a4 eeda74036 files · +343 −81Browse files

Showing the changes to libraries/entities/src/EntityScriptingInterface.cpp (1 of 36 files). Show all

Unified · Split

libraries/entities/src/EntityScriptingInterface.cpp+134−6
@@ -42,7 +42,7 @@ const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}"; · 41 unmodified lines
42const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}";42const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}";
43 43
44EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :44EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :
45 _entityTree(NULL),45 _entityTree(nullptr),
46 _bidOnSimulationOwnership(bidOnSimulationOwnership)46 _bidOnSimulationOwnership(bidOnSimulationOwnership)
47{47{
48 auto nodeList = DependencyManager::get<NodeList>();48 auto nodeList = DependencyManager::get<NodeList>();
@@ -350,19 +350,19 @@ QUuid EntityScriptingInterface::cloneEntity(QUuid entityIDToClone) { · 301 unmodified lines
350 }350 }
351}351}
352 352
353EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity) {353EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID) {
354 EntityPropertyFlags noSpecificProperties;354 const EntityPropertyFlags noSpecificProperties;
355 return getEntityProperties(identity, noSpecificProperties);355 return getEntityProperties(entityID, noSpecificProperties);
356}356}
357 357
358EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identity, EntityPropertyFlags desiredProperties) {358EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid entityID, EntityPropertyFlags desiredProperties) {
359 PROFILE_RANGE(script_entities, __FUNCTION__);359 PROFILE_RANGE(script_entities, __FUNCTION__);
360 360
361 bool scalesWithParent { false };361 bool scalesWithParent { false };
362 EntityItemProperties results;362 EntityItemProperties results;
363 if (_entityTree) {363 if (_entityTree) {
364 _entityTree->withReadLock([&] {364 _entityTree->withReadLock([&] {
365 EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity));365 EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
366 if (entity) {366 if (entity) {
367 scalesWithParent = entity->getScalesWithParent();367 scalesWithParent = entity->getScalesWithParent();
368 if (desiredProperties.getHasProperty(PROP_POSITION) ||368 if (desiredProperties.getHasProperty(PROP_POSITION) ||
@@ -397,6 +397,134 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit · 28 unmodified lines
397 return convertPropertiesToScriptSemantics(results, scalesWithParent);397 return convertPropertiesToScriptSemantics(results, scalesWithParent);
398}398}
399 399
400
401struct EntityPropertiesResult {
402 EntityPropertiesResult(const EntityItemProperties& properties, bool scalesWithParent) :
403 properties(properties),
404 scalesWithParent(scalesWithParent) {
405 }
406 EntityPropertiesResult() = default;
407 EntityItemProperties properties;
408 bool scalesWithParent{ false };
409};
410
411// Static method to make sure that we have the right script engine.
412// Using sender() or QtScriptable::engine() does not work for classes used by multiple threads (script-engines)
413QScriptValue EntityScriptingInterface::getMultipleEntityProperties(QScriptContext* context, QScriptEngine* engine) {
414 const int ARGUMENT_ENTITY_IDS = 0;
415 const int ARGUMENT_EXTENDED_DESIRED_PROPERTIES = 1;
416
417 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
418 const auto entityIDs = qScriptValueToValue<QVector<QUuid>>(context->argument(ARGUMENT_ENTITY_IDS));
419 return entityScriptingInterface->getMultipleEntityPropertiesInternal(engine, entityIDs, context->argument(ARGUMENT_EXTENDED_DESIRED_PROPERTIES));
420}
421
422QScriptValue EntityScriptingInterface::getMultipleEntityPropertiesInternal(QScriptEngine* engine, QVector<QUuid> entityIDs, const QScriptValue& extendedDesiredProperties) {
423 PROFILE_RANGE(script_entities, __FUNCTION__);
424
425 EntityPsuedoPropertyFlags psuedoPropertyFlags;
426 const auto readExtendedPropertyStringValue = [&](QScriptValue extendedProperty) {
427 const auto extendedPropertyString = extendedProperty.toString();
428 if (extendedPropertyString == "id") {
429 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::ID);
430 } else if (extendedPropertyString == "type") {
431 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::Type);
432 } else if (extendedPropertyString == "created") {
433 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::Created);
434 } else if (extendedPropertyString == "age") {
435 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::Age);
436 } else if (extendedPropertyString == "ageAsText") {
437 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::AgeAsText);
438 } else if (extendedPropertyString == "lastEdited") {
439 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::LastEdited);
440 } else if (extendedPropertyString == "boundingBox") {
441 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::BoundingBox);
442 } else if (extendedPropertyString == "originalTextures") {
443 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::OriginalTextures);
444 } else if (extendedPropertyString == "renderInfo") {
445 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::RenderInfo);
446 } else if (extendedPropertyString == "clientOnly") {
447 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::ClientOnly);
448 } else if (extendedPropertyString == "owningAvatarID") {
449 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::OwningAvatarID);
450 }
451 };
452
453 if (extendedDesiredProperties.isString()) {
454 readExtendedPropertyStringValue(extendedDesiredProperties);
455 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FlagsActive);
456 } else if (extendedDesiredProperties.isArray()) {
457 const quint32 length = extendedDesiredProperties.property("length").toInt32();
458 for (quint32 i = 0; i < length; i++) {
459 readExtendedPropertyStringValue(extendedDesiredProperties.property(i));
460 }
461 psuedoPropertyFlags.set(EntityPsuedoPropertyFlag::FlagsActive);
462 }
463
464 EntityPropertyFlags desiredProperties = qScriptValueToValue<EntityPropertyFlags>(extendedDesiredProperties);
465 bool needsScriptSemantics = desiredProperties.getHasProperty(PROP_POSITION) ||
466 desiredProperties.getHasProperty(PROP_ROTATION) ||
467 desiredProperties.getHasProperty(PROP_LOCAL_POSITION) ||
468 desiredProperties.getHasProperty(PROP_LOCAL_ROTATION) ||
469 desiredProperties.getHasProperty(PROP_LOCAL_VELOCITY) ||
470 desiredProperties.getHasProperty(PROP_LOCAL_ANGULAR_VELOCITY) ||
471 desiredProperties.getHasProperty(PROP_LOCAL_DIMENSIONS);
472 if (needsScriptSemantics) {
473 // if we are explicitly getting position or rotation, we need parent information to make sense of them.
474 desiredProperties.setHasProperty(PROP_PARENT_ID);
475 desiredProperties.setHasProperty(PROP_PARENT_JOINT_INDEX);
476 }
477 QVector<EntityPropertiesResult> resultProperties;
478 if (_entityTree) {
479 PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Obtaining Properties");
480 int i = 0;
481 const int lockAmount = 500;
482 int size = entityIDs.size();
483 while (i < size) {
484 _entityTree->withReadLock([&] {
485 for (int j = 0; j < lockAmount && i < size; ++i, ++j) {
486 const auto& entityID = entityIDs.at(i);
487 const EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
488 if (entity) {
489 if (psuedoPropertyFlags.none() && desiredProperties.isEmpty()) {
490 // these are left out of EntityItem::getEntityProperties so that localPosition and localRotation
491 // don't end up in json saves, etc. We still want them here, though.
492 EncodeBitstreamParams params; // unknown
493 desiredProperties = entity->getEntityProperties(params);
494 desiredProperties.setHasProperty(PROP_LOCAL_POSITION);
495 desiredProperties.setHasProperty(PROP_LOCAL_ROTATION);
496 desiredProperties.setHasProperty(PROP_LOCAL_VELOCITY);
497 desiredProperties.setHasProperty(PROP_LOCAL_ANGULAR_VELOCITY);
498 desiredProperties.setHasProperty(PROP_LOCAL_DIMENSIONS);
499 psuedoPropertyFlags.set();
500 needsScriptSemantics = true;
501 }
502
503 auto properties = entity->getProperties(desiredProperties, true);
504 EntityPropertiesResult result(properties, entity->getScalesWithParent());
505 resultProperties.append(result);
506 }
507 }
508 });
509 }
510 }
511 QScriptValue finalResult = engine->newArray(resultProperties.size());
512 quint32 i = 0;
513 if (needsScriptSemantics) {
514 PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Script Semantics");
515 foreach(const auto& result, resultProperties) {
516 finalResult.setProperty(i++, convertPropertiesToScriptSemantics(result.properties, result.scalesWithParent)
517 .copyToScriptValue(engine, false, false, false, psuedoPropertyFlags));
518 }
519 } else {
520 PROFILE_RANGE(script_entities, "EntityScriptingInterface::getMultipleEntityProperties>Skip Script Semantics");
521 foreach(const auto& result, resultProperties) {
522 finalResult.setProperty(i++, result.properties.copyToScriptValue(engine, false, false, false, psuedoPropertyFlags));
523 }
524 }
525 return finalResult;
526}
527
400QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {528QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
401 PROFILE_RANGE(script_entities, __FUNCTION__);529 PROFILE_RANGE(script_entities, __FUNCTION__);
402 530