Updated ozz-animation to version 0.14.1 @35b2efd4

This commit is contained in:
Martin Felis
2023-03-26 13:28:12 +02:00
parent bf3189ff49
commit 15871f349c
194 changed files with 3495 additions and 1957 deletions
+1 -1
View File
@@ -28,10 +28,10 @@ add_executable(sample_multithread
"${CMAKE_CURRENT_BINARY_DIR}/README.md"
"${CMAKE_CURRENT_BINARY_DIR}/media/skeleton.ozz"
"${CMAKE_CURRENT_BINARY_DIR}/media/animation.ozz")
target_link_libraries(sample_multithread
sample_framework
${CMAKE_THREAD_LIBS_INIT})
target_copy_shared_libraries(sample_multithread)
set_target_properties(sample_multithread
PROPERTIES FOLDER "samples")
+1 -1
View File
@@ -20,5 +20,5 @@ The number of characters can also be set from the GUI.
## Implementation
1. This sample extends "playback" sample, and uses the same procedure to load skeleton and animation objects.
2. For each character, allocates runtime buffers (local-space transforms of type ozz::math::SoaTransform, model-space matrices of type ozz::math::Float4x4) with the number of elements required for the skeleton, and a sampling cache (ozz::animation::SamplingCache). Only the skeleton and the animation are shared amongst all characters, as they are read only objects, not modified during jobs execution.
2. For each character, allocates runtime buffers (local-space transforms of type ozz::math::SoaTransform, model-space matrices of type ozz::math::Float4x4) with the number of elements required for the skeleton, and a sampling context (ozz::animation::SamplingJob::Context). Only the skeleton and the animation are shared amongst all characters, as they are read only objects, not modified during jobs execution.
3. Update function uses a parallel-for loop to split up characters' update loop amongst std::async tasks (sampling and local-to-model jobs execution), allowing all characters' update to be executed in concurrent batches.
@@ -30,28 +30,23 @@
#include <cstdlib>
#include <future>
#include "framework/application.h"
#include "framework/imgui.h"
#include "framework/renderer.h"
#include "framework/utils.h"
#include "ozz/animation/runtime/animation.h"
#include "ozz/animation/runtime/local_to_model_job.h"
#include "ozz/animation/runtime/sampling_job.h"
#include "ozz/animation/runtime/skeleton.h"
#include "ozz/base/log.h"
#include "ozz/base/containers/vector.h"
#include "ozz/base/log.h"
#include "ozz/base/maths/box.h"
#include "ozz/base/maths/math_ex.h"
#include "ozz/base/maths/simd_math.h"
#include "ozz/base/maths/soa_transform.h"
#include "ozz/base/maths/vec_float.h"
#include "ozz/options/options.h"
#include "framework/application.h"
#include "framework/imgui.h"
#include "framework/renderer.h"
#include "framework/utils.h"
#if EMSCRIPTEN
#include <emscripten.h>
#include <emscripten/threading.h>
@@ -118,7 +113,7 @@ class MultithreadSampleApplication : public ozz::sample::Application {
// Setup sampling job.
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = &_animation;
sampling_job.cache = &_character->cache;
sampling_job.context = &_character->context;
sampling_job.ratio = _character->controller.time_ratio();
sampling_job.output = make_span(_character->locals);
@@ -150,7 +145,8 @@ class MultithreadSampleApplication : public ozz::sample::Application {
// Data used to monitor and analyze threading.
// Every task will push its thread id to an array. We can then process it to
// find how many threads were used.
struct ParallelMonitor {
class ParallelMonitor {
public:
ParallelMonitor() {
// Finds the maximum possible number of tasks considering kMinGrain grain
// size for kMaxCharacters characters.
@@ -159,19 +155,39 @@ class MultithreadSampleApplication : public ozz::sample::Application {
processed *= 2, max_tasks *= 2) {
}
thread_ids_.resize(max_tasks);
num_async_tasks.store(0);
num_async_tasks_.store(0);
}
ozz::vector<std::thread::id> thread_ids_;
std::atomic_uint num_async_tasks;
void Reset() { num_async_tasks_.store(0); }
// Stores this thread identifier to a new task slot.
void PushTask() {
thread_ids_[num_async_tasks_++] = hasher_(std::this_thread::get_id());
}
// Finds number of threads, which is the number of unique thread ids
// found.
int ThreadCount() {
std::sort(thread_ids_.begin(), thread_ids_.begin() + num_async_tasks_);
auto end = std::unique(thread_ids_.begin(),
thread_ids_.begin() + num_async_tasks_);
return static_cast<int>(end - thread_ids_.begin());
}
int TaskCount() const { return num_async_tasks_; }
private:
std::hash<std::thread::id> hasher_;
ozz::vector<size_t> thread_ids_;
std::atomic_uint num_async_tasks_;
};
static bool ParallelUpdate(const ParallelArgs& _args, Character* _characters,
int _num, ParallelMonitor* _monitor) {
bool success = true;
if (_num <= _args.grain_size) {
// Stores this thread identifier to a new task slot.
_monitor->thread_ids_[_monitor->num_async_tasks++] =
std::this_thread::get_id();
_monitor->PushTask();
for (int i = 0; i < _num; ++i) {
success &= UpdateCharacter(*_args.animation, *_args.skeleton, _args.dt,
@@ -197,7 +213,7 @@ class MultithreadSampleApplication : public ozz::sample::Application {
bool success = true;
if (enable_theading_) {
// Initialize task counter. It's only used to monitor threading behavior.
monitor_.num_async_tasks.store(0);
monitor_.Reset();
const ParallelArgs args = {&animation_, &skeleton_, _dt, grain_size_};
success = ParallelUpdate(args, array_begin(characters_), num_characters_,
@@ -256,7 +272,7 @@ class MultithreadSampleApplication : public ozz::sample::Application {
character.locals.resize(skeleton_.num_soa_joints());
character.models.resize(skeleton_.num_joints());
character.cache.Resize(animation_.num_tracks());
character.context.Resize(animation_.num_tracks());
}
return true;
@@ -290,18 +306,9 @@ class MultithreadSampleApplication : public ozz::sample::Application {
std::sprintf(label, "Grain size: %d", grain_size_);
_im_gui->DoSlider(label, kMinGrainSize, kMaxCharacters, &grain_size_,
.2f);
// Finds number of threads, which is the number of unique thread ids
// found.
std::sort(monitor_.thread_ids_.begin(),
monitor_.thread_ids_.begin() + monitor_.num_async_tasks);
auto end = std::unique(
monitor_.thread_ids_.begin(),
monitor_.thread_ids_.begin() + monitor_.num_async_tasks);
const int num_threads =
static_cast<int>(end - monitor_.thread_ids_.begin());
const int num_threads = monitor_.ThreadCount();
std::sprintf(label, "Thread/task count: %d/%d", num_threads,
monitor_.num_async_tasks.load());
monitor_.TaskCount());
_im_gui->DoLabel(label);
}
}
@@ -334,8 +341,8 @@ class MultithreadSampleApplication : public ozz::sample::Application {
// controlling animation playback time.
ozz::sample::PlaybackController controller;
// Sampling cache.
ozz::animation::SamplingCache cache;
// Sampling context.
ozz::animation::SamplingJob::Context context;
// Buffer of local transforms which stores the blending result.
ozz::vector<ozz::math::SoaTransform> locals;