diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt index 0ef1427306..d24a84c6a5 100644 --- a/android/app/CMakeLists.txt +++ b/android/app/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME native-lib) setup_hifi_library() -link_hifi_libraries(shared networking gl gpu qml image fbx render-utils physics entities octree ${PLATFORM_GL_BACKEND}) +link_hifi_libraries(shared task networking gl gpu qml image fbx render-utils physics entities octree ${PLATFORM_GL_BACKEND}) target_opengl() target_bullet() diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 728f1467e0..85007f5f15 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -204,13 +204,14 @@ endif() # link required hifi libraries link_hifi_libraries( - shared octree ktx gpu gl procedural graphics render + shared task octree ktx gpu gl procedural graphics render pointers recording fbx networking model-networking entities avatars trackers audio audio-client animation script-engine physics render-utils entities-renderer avatars-renderer ui qml auto-updater midi controllers plugins image trackers ui-plugins display-plugins input-plugins + workload ${PLATFORM_GL_BACKEND} ) diff --git a/libraries/avatars-renderer/CMakeLists.txt b/libraries/avatars-renderer/CMakeLists.txt index 1f740700c5..40e1607b2a 100644 --- a/libraries/avatars-renderer/CMakeLists.txt +++ b/libraries/avatars-renderer/CMakeLists.txt @@ -13,5 +13,6 @@ include_hifi_library_headers(entities-renderer) include_hifi_library_headers(audio) include_hifi_library_headers(entities) include_hifi_library_headers(octree) +include_hifi_library_headers(task) target_bullet() diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 4eaa16a107..0f33a73e40 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -13,6 +13,7 @@ include_hifi_library_headers(fbx) include_hifi_library_headers(entities) include_hifi_library_headers(avatars) include_hifi_library_headers(controllers) +include_hifi_library_headers(task) target_bullet() target_polyvox() diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bf29f3bec9..60bcc85575 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -913,18 +913,25 @@ void EntityTree::findEntities(RecurseOctreeOperation& elementFilter, recurseTreeWithOperation(elementFilter, nullptr); } -EntityItemPointer EntityTree::findEntityByID(const QUuid& id) { +EntityItemPointer EntityTree::findEntityByID(const QUuid& id) const { EntityItemID entityID(id); return findEntityByEntityItemID(entityID); } -EntityItemPointer EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) /*const*/ { - EntityItemPointer foundEntity = NULL; - EntityTreeElementPointer containingElement = getContainingElement(entityID); - if (containingElement) { - foundEntity = containingElement->getEntityWithEntityItemID(entityID); +EntityItemPointer EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) const { + EntityItemPointer foundEntity = nullptr; + { + QReadLocker locker(&_entityMapLock); + foundEntity = _entityMap.value(entityID); + } + if (foundEntity && !foundEntity->getElement()) { + // special case to maintain legacy behavior: + // if the entity is in the map but not in the tree + // then pretend the entity doesn't exist + return EntityItemPointer(nullptr); + } else { + return foundEntity; } - return foundEntity; } void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList& changedProperties) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8cb89d6493..90fe342f57 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -132,9 +132,9 @@ public: /// \param position point of query in world-frame (meters) /// \param targetRadius radius of query (meters) EntityItemPointer findClosestEntity(const glm::vec3& position, float targetRadius); - EntityItemPointer findEntityByID(const QUuid& id); - EntityItemPointer findEntityByEntityItemID(const EntityItemID& entityID); - virtual SpatiallyNestablePointer findByID(const QUuid& id) override { return findEntityByID(id); } + EntityItemPointer findEntityByID(const QUuid& id) const; + EntityItemPointer findEntityByEntityItemID(const EntityItemID& entityID) const; + virtual SpatiallyNestablePointer findByID(const QUuid& id) const override { return findEntityByID(id); } EntityItemID assignEntityID(const EntityItemID& entityItemID); /// Assigns a known ID for a creator token ID diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index 57e3572012..3e01fd2643 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -3,10 +3,10 @@ AUTOSCRIBE_SHADER_LIB(gpu graphics render) # pull in the resources.qrc file qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc") setup_hifi_library(Gui Network Qml Quick Script) -link_hifi_libraries(shared ktx gpu graphics model-networking render animation fbx image procedural) +link_hifi_libraries(shared task ktx gpu graphics model-networking render animation fbx image procedural) +include_hifi_library_headers(audio) include_hifi_library_headers(networking) include_hifi_library_headers(octree) -include_hifi_library_headers(audio) if (NOT ANDROID) target_nsight() diff --git a/libraries/render-utils/src/ZoneRenderer.h b/libraries/render-utils/src/ZoneRenderer.h index 5737499270..419db4ebe2 100644 --- a/libraries/render-utils/src/ZoneRenderer.h +++ b/libraries/render-utils/src/ZoneRenderer.h @@ -88,4 +88,4 @@ protected: }; -#endif \ No newline at end of file +#endif diff --git a/libraries/render/CMakeLists.txt b/libraries/render/CMakeLists.txt index 1d88c3e5f5..2a888a5b18 100644 --- a/libraries/render/CMakeLists.txt +++ b/libraries/render/CMakeLists.txt @@ -3,6 +3,6 @@ AUTOSCRIBE_SHADER_LIB(gpu graphics) setup_hifi_library() # render needs octree only for getAccuracyAngle(float, int) -link_hifi_libraries(shared ktx gpu graphics octree) +link_hifi_libraries(shared task ktx gpu graphics octree) target_nsight() diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index 1650d09c5d..0271c71529 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -14,9 +14,10 @@ #include -#include "Scene.h" -#include "../task/Task.h" #include +#include + +#include "Scene.h" namespace render { @@ -24,6 +25,7 @@ namespace render { class RenderContext : public task::JobContext { public: + RenderContext() : task::JobContext(trace_render()) {} virtual ~RenderContext() {} RenderArgs* args; @@ -100,7 +102,7 @@ namespace render { protected: RenderContextPointer _renderContext; - + void run(const RenderContextPointer& context) override { assert(_renderContext); Task::run(_renderContext); } }; using EnginePointer = std::shared_ptr; diff --git a/libraries/render/src/render/SortTask.h b/libraries/render/src/render/SortTask.h index de670b1676..8e4c58803e 100644 --- a/libraries/render/src/render/SortTask.h +++ b/libraries/render/src/render/SortTask.h @@ -55,4 +55,4 @@ namespace render { }; } -#endif // hifi_render_SortTask_h; \ No newline at end of file +#endif // hifi_render_SortTask_h; diff --git a/libraries/shared/src/Profile.cpp b/libraries/shared/src/Profile.cpp index eb7440f4b3..97def2015a 100644 --- a/libraries/shared/src/Profile.cpp +++ b/libraries/shared/src/Profile.cpp @@ -27,6 +27,7 @@ Q_LOGGING_CATEGORY(trace_simulation_animation, "trace.simulation.animation") Q_LOGGING_CATEGORY(trace_simulation_animation_detail, "trace.simulation.animation.detail") Q_LOGGING_CATEGORY(trace_simulation_physics, "trace.simulation.physics") Q_LOGGING_CATEGORY(trace_simulation_physics_detail, "trace.simulation.physics.detail") +Q_LOGGING_CATEGORY(trace_workload, "trace.workload") #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" diff --git a/libraries/shared/src/Profile.h b/libraries/shared/src/Profile.h index fc6a2a52cb..f2a747afa3 100644 --- a/libraries/shared/src/Profile.h +++ b/libraries/shared/src/Profile.h @@ -32,6 +32,7 @@ Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation_detail) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_physics) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_physics_detail) +Q_DECLARE_LOGGING_CATEGORY(trace_workload) class Duration { public: diff --git a/libraries/shared/src/SpatialParentFinder.h b/libraries/shared/src/SpatialParentFinder.h index aae7d9f040..c19babbc7f 100644 --- a/libraries/shared/src/SpatialParentFinder.h +++ b/libraries/shared/src/SpatialParentFinder.h @@ -21,7 +21,7 @@ using SpatiallyNestableWeakPointer = std::weak_ptr; using SpatiallyNestablePointer = std::shared_ptr; class SpatialParentTree { public: - virtual SpatiallyNestablePointer findByID(const QUuid& id) { return nullptr; } + virtual SpatiallyNestablePointer findByID(const QUuid& id) const { return nullptr; } }; class SpatialParentFinder : public Dependency { diff --git a/libraries/task/CMakeLists.txt b/libraries/task/CMakeLists.txt new file mode 100644 index 0000000000..4c97f34acd --- /dev/null +++ b/libraries/task/CMakeLists.txt @@ -0,0 +1,3 @@ +set(TARGET_NAME task) +setup_hifi_library() +link_hifi_libraries(shared) diff --git a/libraries/render/src/task/Config.cpp b/libraries/task/src/task/Config.cpp similarity index 100% rename from libraries/render/src/task/Config.cpp rename to libraries/task/src/task/Config.cpp diff --git a/libraries/render/src/task/Config.h b/libraries/task/src/task/Config.h similarity index 98% rename from libraries/render/src/task/Config.h rename to libraries/task/src/task/Config.h index 7632d4e85d..36dfb35f25 100644 --- a/libraries/render/src/task/Config.h +++ b/libraries/task/src/task/Config.h @@ -20,8 +20,6 @@ #include "SettingHandle.h" -#include "Logging.h" - namespace task { class JobConcept; @@ -140,12 +138,12 @@ public: TaskConfig(bool enabled) : JobConfig(enabled) {} - + // Get a sub job config through task.getConfig(path) // where path can be: // - search for the first job named job_name traversing the the sub graph of task and jobs (from this task as root) // - .[.] - // Allowing to first look for the parent_name job (from this task as root) and then search from there for the + // Allowing to first look for the parent_name job (from this task as root) and then search from there for the // optional sub_parent_names and finally from there looking for the job_name (assuming every job in the path were found) // // getter for qml integration, prefer the templated getter @@ -174,7 +172,7 @@ public: void connectChildConfig(QConfigPointer childConfig, const std::string& name); void transferChildrenConfigs(QConfigPointer source); - + JobConcept* _task; public slots: @@ -182,7 +180,7 @@ public slots: }; using QConfigPointer = std::shared_ptr; - + } #endif // hifi_task_Config_h diff --git a/libraries/render/src/task/Task.h b/libraries/task/src/task/Task.h similarity index 86% rename from libraries/render/src/task/Task.h rename to libraries/task/src/task/Task.h index 63bda7bafa..b75f6d7321 100644 --- a/libraries/render/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -1,6 +1,6 @@ // // Task.h -// render/src/task +// task/src/task // // Created by Zach Pomerantz on 1/6/2016. // Copyright 2016 High Fidelity, Inc. @@ -17,23 +17,25 @@ #include "SettingHandle.h" -#include "Logging.h" - #include #include namespace task { class JobConcept; -template class JobT; -template class TaskT; +template class JobT; +template class TaskT; class JobNoIO {}; class JobContext { public: + JobContext(const QLoggingCategory& category) : profileCategory(category) { + assert(&category); + } virtual ~JobContext() {} std::shared_ptr jobConfig { nullptr }; + const QLoggingCategory& profileCategory; }; using JobContextPointer = std::shared_ptr; @@ -68,23 +70,23 @@ template void jobConfigure(T&, const TaskConfig&) { // nop, as the default TaskConfig was used, so the data does not need a configure method } -template void jobRun(T& data, const RC& renderContext, const JobNoIO& input, JobNoIO& output) { - data.run(renderContext); +template void jobRun(T& data, const JC& jobContext, const JobNoIO& input, JobNoIO& output) { + data.run(jobContext); } -template void jobRun(T& data, const RC& renderContext, const I& input, JobNoIO& output) { - data.run(renderContext, input); +template void jobRun(T& data, const JC& jobContext, const I& input, JobNoIO& output) { + data.run(jobContext, input); } -template void jobRun(T& data, const RC& renderContext, const JobNoIO& input, O& output) { - data.run(renderContext, output); +template void jobRun(T& data, const JC& jobContext, const JobNoIO& input, O& output) { + data.run(jobContext, output); } -template void jobRun(T& data, const RC& renderContext, const I& input, O& output) { - data.run(renderContext, input, output); +template void jobRun(T& data, const JC& jobContext, const I& input, O& output) { + data.run(jobContext, input, output); } -template +template class Job { public: - using Context = RC; + using Context = JC; using ContextPointer = std::shared_ptr; using Config = JobConfig; using None = JobNoIO; @@ -94,7 +96,7 @@ public: Concept(QConfigPointer config) : JobConcept(config) {} virtual ~Concept() = default; - virtual void run(const ContextPointer& renderContext) = 0; + virtual void run(const ContextPointer& jobContext) = 0; }; using ConceptPointer = std::shared_ptr; @@ -130,12 +132,12 @@ public: jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); } - void run(const ContextPointer& renderContext) override { - renderContext->jobConfig = std::static_pointer_cast(Concept::_config); - if (renderContext->jobConfig->alwaysEnabled || renderContext->jobConfig->isEnabled()) { - jobRun(_data, renderContext, _input.get(), _output.edit()); + void run(const ContextPointer& jobContext) override { + jobContext->jobConfig = std::static_pointer_cast(Concept::_config); + if (jobContext->jobConfig->alwaysEnabled || jobContext->jobConfig->isEnabled()) { + jobRun(_data, jobContext, _input.get(), _output.edit()); } - renderContext->jobConfig.reset(); + jobContext->jobConfig.reset(); } }; template using ModelI = Model; @@ -161,12 +163,13 @@ public: return concept->_data; } - virtual void run(const ContextPointer& renderContext) { + virtual void run(const ContextPointer& jobContext) { PerformanceTimer perfTimer(_name.c_str()); - PROFILE_RANGE(render, _name.c_str()); + // NOTE: rather than use the PROFILE_RANGE macro, we create a Duration manually + Duration profileRange(jobContext->profileCategory, _name.c_str()); auto start = usecTimestampNow(); - _concept->run(renderContext); + _concept->run(jobContext); _concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0); } @@ -183,16 +186,16 @@ protected: // It can be created on any type T by aliasing the type JobModel in the class T // using JobModel = Task::Model // The class T is expected to have a "build" method acting as a constructor. -// The build method is where child Jobs can be added internally to the task +// The build method is where child Jobs can be added internally to the task // where the input of the task can be setup to feed the child jobs // and where the output of the task is defined -template -class Task : public Job { +template +class Task : public Job { public: - using Context = RC; + using Context = JC; using ContextPointer = std::shared_ptr; using Config = TaskConfig; - using JobType = Job; + using JobType = Job; using None = typename JobType::None; using Concept = typename JobType::Concept; using ConceptPointer = typename JobType::ConceptPointer; @@ -300,11 +303,11 @@ public: } } - void run(const ContextPointer& renderContext) override { + void run(const ContextPointer& jobContext) override { auto config = std::static_pointer_cast(Concept::_config); if (config->alwaysEnabled || config->enabled) { for (auto job : TaskConcept::_jobs) { - job.run(renderContext); + job.run(jobContext); } } } diff --git a/libraries/render/src/task/Varying.h b/libraries/task/src/task/Varying.h similarity index 100% rename from libraries/render/src/task/Varying.h rename to libraries/task/src/task/Varying.h diff --git a/libraries/workload/CMakeLists.txt b/libraries/workload/CMakeLists.txt new file mode 100644 index 0000000000..3fcf00e0e9 --- /dev/null +++ b/libraries/workload/CMakeLists.txt @@ -0,0 +1,5 @@ +set(TARGET_NAME workload) +setup_hifi_library() + +link_hifi_libraries(shared) + diff --git a/libraries/workload/src/workload/Space.cpp b/libraries/workload/src/workload/Space.cpp new file mode 100644 index 0000000000..1e2bfb228a --- /dev/null +++ b/libraries/workload/src/workload/Space.cpp @@ -0,0 +1,94 @@ +// +// Space.h +// libraries/shared/src/ +// +// Created by Andrew Meadows 2018.01.30 +// Copyright 2018 High Fidelity, Inc. +// +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// Simple plane class. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Space.h" + +#include + +#include + +using namespace workload; + +int32_t Space::createProxy(const Space::Sphere& newSphere) { + if (_freeIndices.empty()) { + _proxies.emplace_back(Space::Proxy(newSphere)); + return (int32_t)_proxies.size() - 1; + } else { + int32_t index = _freeIndices.back(); + _freeIndices.pop_back(); + _proxies[index].sphere = newSphere; + _proxies[index].region = Space::REGION_UNKNOWN; + _proxies[index].prevRegion = Space::REGION_UNKNOWN; + return index; + } +} + +void Space::deleteProxy(int32_t proxyId) { + if (proxyId >= (int32_t)_proxies.size() || _proxies.empty()) { + return; + } + if (proxyId == (int32_t)_proxies.size() - 1) { + // remove proxy on back + _proxies.pop_back(); + if (!_freeIndices.empty()) { + // remove any freeIndices on back + std::sort(_freeIndices.begin(), _freeIndices.end()); + while(!_freeIndices.empty() && _freeIndices.back() == (int32_t)_proxies.size() - 1) { + _freeIndices.pop_back(); + _proxies.pop_back(); + } + } + } else { + _proxies[proxyId].region = Space::REGION_INVALID; + _freeIndices.push_back(proxyId); + } +} + +void Space::updateProxy(int32_t proxyId, const Space::Sphere& newSphere) { + if (proxyId >= (int32_t)_proxies.size()) { + return; + } + _proxies[proxyId].sphere = newSphere; +} + +void Space::setViews(const std::vector& views) { + _views = views; +} + +void Space::categorizeAndGetChanges(std::vector& changes) { + uint32_t numProxies = (uint32_t)_proxies.size(); + uint32_t numViews = (uint32_t)_views.size(); + for (uint32_t i = 0; i < numProxies; ++i) { + Proxy& proxy = _proxies[i]; + if (proxy.region < Space::REGION_INVALID) { + uint8_t region = Space::REGION_UNKNOWN; + for (uint32_t j = 0; j < numViews; ++j) { + float distance2 = glm::distance2(_views[j].center, glm::vec3(_proxies[i].sphere)); + for (uint8_t c = 0; c < region; ++c) { + float touchDistance = _views[j].radiuses[c] + _proxies[i].sphere.w; + if (distance2 < touchDistance * touchDistance) { + region = c; + break; + } + } + } + proxy.prevRegion = proxy.region; + proxy.region = region; + if (proxy.region != proxy.prevRegion) { + changes.emplace_back(Space::Change((int32_t)i, proxy.region, proxy.prevRegion)); + } + } + } +} + diff --git a/libraries/workload/src/workload/Space.h b/libraries/workload/src/workload/Space.h new file mode 100644 index 0000000000..be47cddc4e --- /dev/null +++ b/libraries/workload/src/workload/Space.h @@ -0,0 +1,79 @@ +// +// Space.h +// libraries/workload/src/workload +// +// Created by Andrew Meadows 2018.01.30 +// Copyright 2018 High Fidelity, Inc. +// +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// Simple plane class. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_workload_Space_h +#define hifi_workload_Space_h + +#include +#include + +namespace workload { + +class Space { +public: + static const uint8_t REGION_NEAR = 0; + static const uint8_t REGION_MIDDLE = 1; + static const uint8_t REGION_FAR = 2; + static const uint8_t REGION_UNKNOWN = 3; + static const uint8_t REGION_INVALID = 4; + + using Sphere = glm::vec4; // = center, w = radius + + class Proxy { + public: + Proxy(const Sphere& s) : sphere(s) {} + Sphere sphere; + uint8_t region { REGION_UNKNOWN }; + uint8_t prevRegion { REGION_UNKNOWN }; + }; + + class View { + public: + View(const glm::vec3& pos, float nearRadius, float midRadius, float farRadius) : center(pos) { + radiuses[0] = nearRadius; + radiuses[1] = midRadius; + radiuses[2] = farRadius; + } + glm::vec3 center { 0.0f, 0.0f, 0.0f }; + float radiuses[3] { 0.0f, 0.0f, 0.0f }; + }; + + class Change { + public: + Change(int32_t i, uint32_t c, uint32_t p) : proxyId(i), region(c), prevRegion(p) {} + int32_t proxyId { -1 }; + uint8_t region { 0 }; + uint8_t prevRegion { 0 }; + }; + + Space() {} + + int32_t createProxy(const Sphere& sphere); + void deleteProxy(int32_t proxyId); + void updateProxy(int32_t proxyId, const Sphere& sphere); + void setViews(const std::vector& views); + + uint32_t getNumObjects() const { return (uint32_t)(_proxies.size() - _freeIndices.size()); } + + void categorizeAndGetChanges(std::vector& changes); + +private: + std::vector _proxies; + std::vector _views; + std::vector _freeIndices; +}; + +} // namespace workload + +#endif // hifi_workload_Space_h diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 2a011a349a..638cadf574 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -19,7 +19,7 @@ if (WIN32 AND (NOT USE_GLES)) set(TARGET_NAME oculus) setup_hifi_plugin(Multimedia) link_hifi_libraries( - shared gl gpu gpu-gl controllers ui qml + shared task gl gpu gpu-gl controllers ui qml plugins ui-plugins display-plugins input-plugins audio-client networking render-utils ${PLATFORM_GL_BACKEND} diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index a6e90aa5a6..ff94152d57 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -11,7 +11,7 @@ if (WIN32 AND (NOT USE_GLES)) add_definitions(-DGLEW_STATIC) set(TARGET_NAME openvr) setup_hifi_plugin(Gui Qml Multimedia) - link_hifi_libraries(shared gl qml networking controllers ui + link_hifi_libraries(shared task gl qml networking controllers ui plugins display-plugins ui-plugins input-plugins script-engine audio-client render-utils graphics gpu render model-networking fbx ktx image procedural ${PLATFORM_GL_BACKEND}) diff --git a/tests/gpu-test/CMakeLists.txt b/tests/gpu-test/CMakeLists.txt index 7bc1349091..336dcf753c 100644 --- a/tests/gpu-test/CMakeLists.txt +++ b/tests/gpu-test/CMakeLists.txt @@ -5,7 +5,7 @@ setup_hifi_project(Quick Gui Script) setup_memory_debugger() set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries( - shared networking gl + shared task networking gl ktx gpu procedural octree image graphics model-networking fbx animation script-engine render render-utils diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index 57ae7dace7..7ad38c5795 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -13,7 +13,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") # link in the shared libraries link_hifi_libraries( - shared networking animation + shared task networking animation ktx image octree gl gpu gpu-gl render render-utils graphics fbx model-networking diff --git a/tests/render-texture-load/CMakeLists.txt b/tests/render-texture-load/CMakeLists.txt index 2ed905a3ef..b3e49d830b 100644 --- a/tests/render-texture-load/CMakeLists.txt +++ b/tests/render-texture-load/CMakeLists.txt @@ -13,7 +13,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") # link in the shared libraries link_hifi_libraries( - shared networking octree + shared task networking octree gl gpu render ktx image animation graphics fbx model-networking render-utils diff --git a/tests/workload/CMakeLists.txt b/tests/workload/CMakeLists.txt new file mode 100644 index 0000000000..53ee7acba1 --- /dev/null +++ b/tests/workload/CMakeLists.txt @@ -0,0 +1,8 @@ + +# Declare dependencies +macro (setup_testcase_dependencies) + link_hifi_libraries(shared workload) + package_libraries_for_deployment() +endmacro () + +setup_hifi_testcase() diff --git a/tests/workload/src/SpaceTests.cpp b/tests/workload/src/SpaceTests.cpp new file mode 100644 index 0000000000..1c6b0491a7 --- /dev/null +++ b/tests/workload/src/SpaceTests.cpp @@ -0,0 +1,272 @@ +// +// SpaceTests.cpp +// tests/physics/src +// +// Created by Andrew Meadows on 2017.01.26 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "SpaceTests.h" + +#include + +#include +#include +#include + + +const float INV_SQRT_3 = 1.0f / sqrtf(3.0f); + +QTEST_MAIN(SpaceTests) + +void SpaceTests::testOverlaps() { + workload::Space space; + using Changes = std::vector; + using Views = std::vector; + + glm::vec3 viewCenter(0.0f, 0.0f, 0.0f); + float near = 1.0f; + float mid = 2.0f; + float far = 3.0f; + + Views views; + views.push_back(workload::Space::View(viewCenter, near, mid, far)); + space.setViews(views); + + int32_t proxyId = 0; + const float DELTA = 0.001f; + float proxyRadius = 0.5f; + glm::vec3 proxyPosition = viewCenter + glm::vec3(0.0f, 0.0f, far + proxyRadius + DELTA); + workload::Space::Sphere proxySphere(proxyPosition, proxyRadius); + + { // create very_far proxy + proxyId = space.createProxy(proxySphere); + QVERIFY(space.getNumObjects() == 1); + + Changes changes; + space.categorizeAndGetChanges(changes); + QVERIFY(changes.size() == 0); + } + + { // move proxy far + float newRadius = 1.0f; + glm::vec3 newPosition = viewCenter + glm::vec3(0.0f, 0.0f, far + newRadius - DELTA); + workload::Space::Sphere newSphere(newPosition, newRadius); + space.updateProxy(proxyId, newSphere); + Changes changes; + space.categorizeAndGetChanges(changes); + QVERIFY(changes.size() == 1); + QVERIFY(changes[0].proxyId == proxyId); + QVERIFY(changes[0].region == workload::Space::REGION_FAR); + QVERIFY(changes[0].prevRegion == workload::Space::REGION_UNKNOWN); + } + + { // move proxy mid + float newRadius = 1.0f; + glm::vec3 newPosition = viewCenter + glm::vec3(0.0f, 0.0f, mid + newRadius - DELTA); + workload::Space::Sphere newSphere(newPosition, newRadius); + space.updateProxy(proxyId, newSphere); + Changes changes; + space.categorizeAndGetChanges(changes); + QVERIFY(changes.size() == 1); + QVERIFY(changes[0].proxyId == proxyId); + QVERIFY(changes[0].region == workload::Space::REGION_MIDDLE); + QVERIFY(changes[0].prevRegion == workload::Space::REGION_FAR); + } + + { // move proxy near + float newRadius = 1.0f; + glm::vec3 newPosition = viewCenter + glm::vec3(0.0f, 0.0f, near + newRadius - DELTA); + workload::Space::Sphere newSphere(newPosition, newRadius); + space.updateProxy(proxyId, newSphere); + Changes changes; + space.categorizeAndGetChanges(changes); + QVERIFY(changes.size() == 1); + QVERIFY(changes[0].proxyId == proxyId); + QVERIFY(changes[0].region == workload::Space::REGION_NEAR); + QVERIFY(changes[0].prevRegion == workload::Space::REGION_MIDDLE); + } + + { // delete proxy + // NOTE: atm deleting a proxy doesn't result in a "Change" + space.deleteProxy(proxyId); + Changes changes; + space.categorizeAndGetChanges(changes); + QVERIFY(changes.size() == 0); + QVERIFY(space.getNumObjects() == 0); + } +} + +#ifdef MANUAL_TEST + +const float WORLD_WIDTH = 1000.0f; +const float MIN_RADIUS = 1.0f; +const float MAX_RADIUS = 100.0f; + +float randomFloat() { + return 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f; +} + +glm::vec3 randomVec3() { + glm::vec3 v(randomFloat(), randomFloat(), randomFloat()); + return v; +} + +void generateSpheres(uint32_t numProxies, std::vector& spheres) { + spheres.reserve(numProxies); + for (uint32_t i = 0; i < numProxies; ++i) { + workload::Space::Sphere sphere( + WORLD_WIDTH * randomFloat(), + WORLD_WIDTH * randomFloat(), + WORLD_WIDTH * randomFloat(), + (MIN_RADIUS + (MAX_RADIUS - MIN_RADIUS)) * randomFloat()); + spheres.push_back(sphere); + } +} + +void generatePositions(uint32_t numProxies, std::vector& positions) { + positions.reserve(numProxies); + for (uint32_t i = 0; i < numProxies; ++i) { + positions.push_back(WORLD_WIDTH * randomVec3()); + } +} + +void generateRadiuses(uint32_t numRadiuses, std::vector& radiuses) { + radiuses.reserve(numRadiuses); + for (uint32_t i = 0; i < numRadiuses; ++i) { + radiuses.push_back(MIN_RADIUS + (MAX_RADIUS - MIN_RADIUS) * randomFloat()); + } +} + +void SpaceTests::benchmark() { + uint32_t numProxies[] = { 100, 1000, 10000, 100000 }; + uint32_t numTests = 4; + std::vector timeToAddAll; + std::vector timeToRemoveAll; + std::vector timeToMoveView; + std::vector timeToMoveProxies; + for (uint32_t i = 0; i < numTests; ++i) { + + workload::Space space; + + { // build the views + std::vector viewPositions; + viewPositions.push_back(glm::vec3(0.0f, 0.0f, 0.0f)); + viewPositions.push_back(glm::vec3(0.0f, 0.0f, 0.1f * WORLD_WIDTH)); + float radius0 = 0.25f * WORLD_WIDTH; + float radius1 = 0.50f * WORLD_WIDTH; + float radius2 = 0.75f * WORLD_WIDTH; + std::vector views; + views.push_back(workload::Space::View(viewPositions[0], radius0, radius1, radius2)); + views.push_back(workload::Space::View(viewPositions[1], radius0, radius1, radius2)); + space.setViews(views); + } + + // build the proxies + uint32_t n = numProxies[i]; + std::vector proxySpheres; + generateSpheres(n, proxySpheres); + std::vector proxyKeys; + proxyKeys.reserve(n); + + // measure time to put proxies in the space + uint64_t startTime = usecTimestampNow(); + for (uint32_t j = 0; j < n; ++j) { + int32_t key = space.createProxy(proxySpheres[j]); + proxyKeys.push_back(key); + } + uint64_t usec = usecTimestampNow() - startTime; + timeToAddAll.push_back(usec); + + { + // build the views + std::vector viewPositions; + viewPositions.push_back(glm::vec3(1.0f, 2.0f, 3.0f)); + viewPositions.push_back(glm::vec3(1.0f, 2.0f, 3.0f + 0.1f * WORLD_WIDTH)); + float radius0 = 0.25f * WORLD_WIDTH; + float radius1 = 0.50f * WORLD_WIDTH; + float radius2 = 0.75f * WORLD_WIDTH; + std::vector views; + views.push_back(workload::Space::View(viewPositions[0], radius0, radius1, radius2)); + views.push_back(workload::Space::View(viewPositions[1], radius0, radius1, radius2)); + space.setViews(views); + } + + // measure time to categorizeAndGetChanges everything + std::vector changes; + startTime = usecTimestampNow(); + space.categorizeAndGetChanges(changes); + usec = usecTimestampNow() - startTime; + timeToMoveView.push_back(usec); + + // move every 10th proxy around + const float proxySpeed = 1.0f; + std::vector newSpheres; + uint32_t numMovingProxies = n / 10; + uint32_t jstep = n / numMovingProxies; + uint32_t maxJ = numMovingProxies * jstep - 1; + glm::vec3 direction; + for (uint32_t j = 0; j < maxJ - jstep; j += jstep) { + glm::vec3 position = (glm::vec3)proxySpheres[j]; + glm::vec3 destination = (glm::vec3)proxySpheres[j + jstep]; + direction = glm::normalize(destination - position); + glm::vec3 newPosition = position + proxySpeed * direction; + newSpheres.push_back(workload::Space::Sphere(newPosition, proxySpheres[j].w)); + } + glm::vec3 position = (glm::vec3)proxySpheres[maxJ = jstep]; + glm::vec3 destination = (glm::vec3)proxySpheres[0]; + direction = glm::normalize(destination - position); + direction = position + proxySpeed * direction; + newSpheres.push_back(workload::Space::Sphere(direction, proxySpheres[0].w)); + uint32_t k = 0; + startTime = usecTimestampNow(); + for (uint32_t j = 0; j < maxJ; j += jstep) { + space.updateProxy(proxyKeys[j], newSpheres[k++]); + } + changes.clear(); + space.categorizeAndGetChanges(changes); + usec = usecTimestampNow() - startTime; + timeToMoveProxies.push_back(usec); + + // measure time to remove proxies from space + startTime = usecTimestampNow(); + for (uint32_t j = 0; j < n; ++j) { + space.deleteProxy(proxyKeys[j]); + } + usec = usecTimestampNow() - startTime; + timeToRemoveAll.push_back(usec); + } + + std::cout << "[numProxies, timeToAddAll] = [" << std::endl; + for (uint32_t i = 0; i < timeToAddAll.size(); ++i) { + uint32_t n = numProxies[i]; + std::cout << " " << n << ", " << timeToAddAll[i] << std::endl; + } + std::cout << "];" << std::endl; + + std::cout << "[numProxies, timeToMoveView] = [" << std::endl; + for (uint32_t i = 0; i < timeToMoveView.size(); ++i) { + uint32_t n = numProxies[i]; + std::cout << " " << n << ", " << timeToMoveView[i] << std::endl; + } + std::cout << "];" << std::endl; + + std::cout << "[numProxies, timeToMoveProxies] = [" << std::endl; + for (uint32_t i = 0; i < timeToMoveProxies.size(); ++i) { + uint32_t n = numProxies[i]; + std::cout << " " << n << "/10, " << timeToMoveProxies[i] << std::endl; + } + std::cout << "];" << std::endl; + + std::cout << "[numProxies, timeToRemoveAll] = [" << std::endl; + for (uint32_t i = 0; i < timeToRemoveAll.size(); ++i) { + uint32_t n = numProxies[i]; + std::cout << " " << n << ", " << timeToRemoveAll[i] << std::endl; + } + std::cout << "];" << std::endl; +} + +#endif // MANUAL_TEST diff --git a/tests/workload/src/SpaceTests.h b/tests/workload/src/SpaceTests.h new file mode 100644 index 0000000000..153b89dfc5 --- /dev/null +++ b/tests/workload/src/SpaceTests.h @@ -0,0 +1,29 @@ +// +// SpaceTests.h +// tests/physics/src +// +// Created by Andrew Meadows on 2017.01.26 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_workload_SpaceTests_h +#define hifi_workload_SpaceTests_h + +#include + +//#define MANUAL_TEST + +class SpaceTests : public QObject { + Q_OBJECT + +private slots: + void testOverlaps(); +#ifdef MANUAL_TEST + void benchmark(); +#endif // MANUAL_TEST +}; + +#endif // hifi_workload_SpaceTests_h