Updated ozz-animation to version 0.14.1 @35b2efd4
This commit is contained in:
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user