diff --git a/Content/Documentation/WickedEngine-Documentation.md b/Content/Documentation/WickedEngine-Documentation.md index 4da2768e4..6998f6679 100644 --- a/Content/Documentation/WickedEngine-Documentation.md +++ b/Content/Documentation/WickedEngine-Documentation.md @@ -495,7 +495,7 @@ bool IsDoubleSided() const { return _flags & DOUBLE_SIDED; } void SetDoubleSided(bool value) { if (value) { _flags |= DOUBLE_SIDED; } else { _flags &= ~DOUBLE_SIDED; } } ``` -It is good practice to not implement constructors and destructors for components. Wherever possible, initialization of values in declaration should be preferred. If desctructors are defined, move contructors, etc. will also need to be defined for compatibility with the [ComponentManager](#componentmanager), so default constructors and destructors should be preferred. Member objects should be able to desctruct themselves implicitly. If pointers need to be stored within the component that manage object lifetime, std::unique_ptr or std::shared_ptr can be used, which will be destructed implicitly. +It is good practice to not implement constructors and destructors for components. Wherever possible, initialization of values in declaration should be preferred. If desctructors are defined, move contructors, etc. will also need to be defined for compatibility with the [ComponentManager](#componentmanager), so default constructors and destructors should be preferred. Member objects should be able to desctruct themselves implicitly. If pointers need to be stored within the component that manage object lifetime, std::unique_ptr or wi::allocator::shared_ptr can be used, which will be destructed implicitly. #### NameComponent [[Header]](../../WickedEngine/wiScene.h) [[Cpp]](../../WickedEngine/wiScene.cpp) diff --git a/Editor/ConstraintWindow.cpp b/Editor/ConstraintWindow.cpp index 4cf3da38c..d400c9f77 100644 --- a/Editor/ConstraintWindow.cpp +++ b/Editor/ConstraintWindow.cpp @@ -67,7 +67,7 @@ void ConstraintWindow::Create(EditorComponent* _editor) collisionCheckBox.SetTooltip("Disable collision between the two bodies that this constraint targets.\nNote: changing this will recreate the constraint in the current pose relative to the bodies."); collisionCheckBox.OnClick(forEachSelected([] (auto physicscomponent, auto args) { physicscomponent->SetDisableSelfCollision(args.bValue); - physicscomponent->physicsobject = nullptr; + physicscomponent->physicsobject.reset(); })); AddWidget(&collisionCheckBox); @@ -80,7 +80,7 @@ void ConstraintWindow::Create(EditorComponent* _editor) rebindButton.Create("Rebind Constraint"); rebindButton.OnClick(forEachSelected([](auto physicscomponent, auto args) { - physicscomponent->physicsobject = nullptr; + physicscomponent->physicsobject.reset(); })); AddWidget(&rebindButton); @@ -97,7 +97,7 @@ void ConstraintWindow::Create(EditorComponent* _editor) PhysicsConstraintComponent::Type type = (PhysicsConstraintComponent::Type)args.userdata; if (physicscomponent->type != type) { - physicscomponent->physicsobject = nullptr; + physicscomponent->physicsobject.reset(); physicscomponent->type = type; } })); @@ -109,14 +109,14 @@ void ConstraintWindow::Create(EditorComponent* _editor) bodyAComboBox.Create("Body A: "); bodyAComboBox.OnSelect(forEachSelected([](auto physicscomponent, auto args) { physicscomponent->bodyA = args.userdata; - physicscomponent->physicsobject = nullptr; + physicscomponent->physicsobject.reset(); })); AddWidget(&bodyAComboBox); bodyBComboBox.Create("Body B: "); bodyBComboBox.OnSelect(forEachSelected([](auto physicscomponent, auto args) { physicscomponent->bodyB = args.userdata; - physicscomponent->physicsobject = nullptr; + physicscomponent->physicsobject.reset(); })); AddWidget(&bodyBComboBox); diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index e71e63b0d..a994d17c6 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -5227,7 +5227,7 @@ void EditorComponent::Open(std::string filename) wi::jobsystem::Execute(loadmodel_workload, [=] (wi::jobsystem::JobArgs) { wi::backlog::post("[Editor] started loading model: " + filename); - std::shared_ptr scene = std::make_shared(); + wi::allocator::shared_ptr scene = wi::allocator::make_shared_single(); if (type == FileType::WISCENE) { wi::scene::LoadModel(*scene, filename); diff --git a/Editor/RigidBodyWindow.cpp b/Editor/RigidBodyWindow.cpp index 8017dee65..cd6d2356e 100644 --- a/Editor/RigidBodyWindow.cpp +++ b/Editor/RigidBodyWindow.cpp @@ -59,7 +59,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) RigidBodyPhysicsComponent::CollisionShape shape = (RigidBodyPhysicsComponent::CollisionShape)args.userdata; if (physicscomponent->shape != shape) { - physicscomponent->physicsobject = nullptr; + physicscomponent->physicsobject.reset(); physicscomponent->shape = shape; } })(args); @@ -87,7 +87,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) physicscomponent->capsule.height = args.fValue; break; } - physicscomponent->physicsobject = nullptr; + physicscomponent->physicsobject.reset(); })); ZSlider.SetLocalizationEnabled(false); @@ -106,7 +106,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) physicsComponent->capsule.radius = args.fValue; break; } - physicsComponent->physicsobject = nullptr; + physicsComponent->physicsobject.reset(); })); ZSlider.SetLocalizationEnabled(false); AddWidget(&YSlider); @@ -121,7 +121,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) physicscomponent->box.halfextents.z = args.fValue; break; } - physicscomponent->physicsobject = nullptr; + physicscomponent->physicsobject.reset(); })); ZSlider.SetLocalizationEnabled(false); AddWidget(&ZSlider); @@ -173,7 +173,7 @@ void RigidBodyWindow::Create(EditorComponent* _editor) physicsMeshLODSlider.OnSlide(forEachSelectedPhysicsComponentWithRefresh([](auto physicscomponent, auto args) { if (physicscomponent->mesh_lod != uint32_t(args.iValue)) { - physicscomponent->physicsobject = nullptr; // will be recreated automatically + physicscomponent->physicsobject.reset(); // will be recreated automatically physicscomponent->mesh_lod = uint32_t(args.iValue); } physicscomponent->mesh_lod = uint32_t(args.iValue); diff --git a/Editor/TerrainWindow.cpp b/Editor/TerrainWindow.cpp index 5a9077a95..bab5f0ea0 100644 --- a/Editor/TerrainWindow.cpp +++ b/Editor/TerrainWindow.cpp @@ -919,9 +919,9 @@ void TerrainWindow::Create(EditorComponent* _editor) break; } - std::shared_ptr terrain_perlin = std::make_shared(); + wi::allocator::shared_ptr terrain_perlin = wi::allocator::make_shared_single(); terrain->modifiers.emplace_back() = terrain_perlin; - std::shared_ptr terrain_voronoi = std::make_shared(); + wi::allocator::shared_ptr terrain_voronoi = wi::allocator::make_shared_single(); terrain->modifiers.emplace_back() = terrain_voronoi; perlin->Bind(terrain_perlin.get()); @@ -959,7 +959,7 @@ void TerrainWindow::Create(EditorComponent* _editor) case 0: { PerlinModifierWindow* ptr = new PerlinModifierWindow; - std::shared_ptr modifier = std::make_shared(); + wi::allocator::shared_ptr modifier = wi::allocator::make_shared_single(); terrain->modifiers.push_back(modifier); ptr->From(modifier.get()); AddModifier(ptr); @@ -968,7 +968,7 @@ void TerrainWindow::Create(EditorComponent* _editor) case 1: { VoronoiModifierWindow* ptr = new VoronoiModifierWindow; - std::shared_ptr modifier = std::make_shared(); + wi::allocator::shared_ptr modifier = wi::allocator::make_shared_single(); terrain->modifiers.push_back(modifier); ptr->From(modifier.get()); AddModifier(ptr); @@ -977,7 +977,7 @@ void TerrainWindow::Create(EditorComponent* _editor) case 2: { HeightmapModifierWindow* ptr = new HeightmapModifierWindow; - std::shared_ptr modifier = std::make_shared(); + wi::allocator::shared_ptr modifier = wi::allocator::make_shared_single(); terrain->modifiers.push_back(modifier); ptr->From(modifier.get()); AddModifier(ptr); diff --git a/WickedEngine/wiAllocator.h b/WickedEngine/wiAllocator.h index ca5f8ae57..8090094a6 100644 --- a/WickedEngine/wiAllocator.h +++ b/WickedEngine/wiAllocator.h @@ -91,177 +91,11 @@ namespace wi::allocator } }; - // Allocation and freeing of an arbitrary number of bytes, managed in pages of the same size - // - this is a wrapper around OffsetAllocator that adds thread safety and refcounting - // - also supports deferred release for suballocated GPU resources - struct PageAllocator - { - uint32_t page_count = 0; - uint32_t page_size = 0; - struct AllocationInternal - { - std::atomic refcount{ 0 }; - OffsetAllocator::Allocation allocation; - }; - struct AllocatorInternal - { - std::mutex locker; - OffsetAllocator::Allocator allocator; - BlockAllocator internal_blocks; - bool deferred_release_enabled = false; - uint64_t deferred_release_frame = 0; - std::deque> deferred_release_queue; - }; - std::shared_ptr allocator; // shared ptr is used to let any allocations extend the lifeftime of the allocator - - // Returns the total size that the allocator manages: - constexpr uint64_t total_size_in_bytes() const { return uint64_t(page_count) * uint64_t(page_size); } - - // Calculates the page count that will accomodate an allocation size request - constexpr uint32_t page_count_from_bytes(uint64_t sizeInBytes) const { return uint32_t(align((uint64_t)sizeInBytes, (uint64_t)page_size) / (uint64_t)page_size); } - - // Initializes the allocator, only after which it can be used - // total_size_in_bytes : the allocator will manage this number of bytes - // page_size : the allocation granularity in bytes, each allocation will be aligned to this - // deferred_release : if false, allocations are freed immediately (suitable for CPU only allocations), otherwise they are freed after a number of frames passed (which should be used for GPU allocations) - void init(uint64_t total_size_in_bytes, uint32_t page_size = 64u * 1024u, bool deferred_release = false) - { - this->page_size = page_size; - this->page_count = page_count_from_bytes(total_size_in_bytes); - allocator = std::make_shared(); - allocator->allocator.init(page_count, std::min(page_count, OffsetAllocator::default_maxallocations)); - allocator->deferred_release_enabled = deferred_release; - allocator->deferred_release_frame = 0; - allocator->deferred_release_queue.clear(); - } - // This needs to be called every frame if deferred release is enabled: - void update_deferred_release(uint64_t framecount, uint32_t buffercount) - { - if (allocator == nullptr) - return; - std::scoped_lock lck(allocator->locker); - allocator->deferred_release_frame = framecount; - while (!allocator->deferred_release_queue.empty() && allocator->deferred_release_queue.front().second + buffercount < framecount) - { - allocator->allocator.free(allocator->deferred_release_queue.front().first); - allocator->deferred_release_queue.pop_front(); - } - } - - struct Allocation - { - std::shared_ptr allocator; // the allocator is retained so that allocation can deallocate itself - AllocationInternal* internal_state = nullptr; // this is pointing within the allocator which is retained by shared_ptr - uint64_t byte_offset = ~0ull; - - Allocation() - { - Reset(); - } - Allocation(const Allocation& other) - { - Reset(); - allocator = other.allocator; - internal_state = other.internal_state; - byte_offset = other.byte_offset; - if (internal_state != nullptr) - { - internal_state->refcount.fetch_add(1); - } - } - Allocation(Allocation&& other) noexcept - { - Reset(); - allocator = std::move(other.allocator); - internal_state = std::move(other.internal_state); - byte_offset = other.byte_offset; - other.allocator = nullptr; - other.internal_state = nullptr; - other.byte_offset = ~0ull; - } - ~Allocation() - { - Reset(); - } - Allocation& operator=(const Allocation& other) - { - Reset(); - allocator = other.allocator; - internal_state = other.internal_state; - byte_offset = other.byte_offset; - if (internal_state != nullptr) - { - internal_state->refcount.fetch_add(1); - } - return *this; - } - Allocation& operator=(Allocation&& other) noexcept - { - Reset(); - allocator = std::move(other.allocator); - internal_state = std::move(other.internal_state); - byte_offset = other.byte_offset; - other.allocator = nullptr; - other.internal_state = nullptr; - other.byte_offset = ~0ull; - return *this; - } - void Reset() - { - if (IsValid() && (internal_state->refcount.fetch_sub(1) <= 1)) - { - std::scoped_lock lck(allocator->locker); - if (allocator->deferred_release_enabled) - { - // can only be reclaimed after buffering amount of frames passed, this is usually used for GPU resources: - allocator->deferred_release_queue.push_back(std::make_pair(internal_state->allocation, allocator->deferred_release_frame)); - } - else - { - // reclaimed immediately: - allocator->allocator.free(internal_state->allocation); - } - allocator->internal_blocks.free(internal_state); - } - allocator = {}; - internal_state = nullptr; - byte_offset = ~0ull; - } - - constexpr bool IsValid() const { return internal_state != nullptr; } - }; - - // Allocates a reference counted allocation, viewing at least the requested amount of bytes - // To check if the allocation succeeded, call IsValid() on the returned object - inline Allocation allocate(size_t sizeInBytes) - { - const uint32_t pages = page_count_from_bytes(sizeInBytes); - std::scoped_lock lck(allocator->locker); - OffsetAllocator::Allocation offsetallocation = allocator->allocator.allocate(pages); - Allocation alloc; - if (offsetallocation.offset != OffsetAllocator::Allocation::NO_SPACE) - { - alloc.allocator = allocator; - alloc.internal_state = allocator->internal_blocks.allocate(); - alloc.internal_state->refcount.store(1); - alloc.internal_state->allocation = offsetallocation; - alloc.byte_offset = offsetallocation.offset * page_size; - } - return alloc; - } - - // returns true if no pages are allocated - inline bool is_empty() const - { - return allocator->allocator.storageReport().totalFreeSpace == page_count; - } - }; - - // Interface for allocating pooled shared_ptr - struct SharedBlockAllocator + // Interface for lifetime management allocator of shared_ptr + struct SharedAllocator { virtual void init_refcount(void* ptr) = 0; virtual uint32_t get_refcount(void* ptr) = 0; @@ -273,21 +107,18 @@ namespace wi::allocator }; // The per-type block allocators can be indexed with bottom 8 bits of the shared_ptr's handle: - inline SharedBlockAllocator* block_allocators[256] = {}; + inline SharedAllocator* shared_allocators[256] = {}; inline std::atomic next_allocator_id{ 0 }; - inline uint8_t register_shared_block_allocator(SharedBlockAllocator* allocator) + inline uint8_t register_shared_allocator(SharedAllocator* allocator) { uint8_t id = next_allocator_id.fetch_add(1); - assert(id < arraysize(block_allocators)); - block_allocators[id] = allocator; + assert(id < arraysize(shared_allocators)); + shared_allocators[id] = allocator; return id; } - inline uint8_t get_shared_block_allocator_count() { return next_allocator_id.load(); } + inline uint8_t get_shared_allocator_count() { return next_allocator_id.load(); } - // Shared ptr using a block allocation strategy, refcounted, thread-safe, reduced size using single uint64_t handle - // This makes it easy to swap-out std::shared_ptr, but not feature complete, only has minimal feature set - // Use this if you require many object of the same type, their memory allocation will be pooled - // If you require just a single object, it will be better to use std::shared_ptr instead + // Custom shared_ptr that has compact handle size, supports block allocation for pooling many objects, or heap allocation for single objects. Not feature-complete with std:: but a minimal simplified implementation. template struct shared_ptr { @@ -296,7 +127,7 @@ namespace wi::allocator constexpr bool IsValid() const { return handle != 0; } constexpr T* get_ptr() const { return (T*)(handle & (~0ull << 8ull)); } - constexpr SharedBlockAllocator* get_allocator() const { return block_allocators[handle & 0xFF]; } + constexpr SharedAllocator* get_allocator() const { return shared_allocators[handle & 0xFF]; } constexpr T* operator->() const { return get_ptr(); } constexpr operator T* () const { return get_ptr(); } @@ -340,7 +171,7 @@ namespace wi::allocator uint32_t use_count() const { return IsValid() ? get_allocator()->get_refcount(get_ptr()) : 0; } }; - // Similar to std::weak_ptr but works with the shared block allocator, and reduced feature set + // Similar to std::weak_ptr but reduced size and works with the shared block allocator. Not feature-complete with std:: but a minimal simplified implementation. template struct weak_ptr { @@ -349,7 +180,7 @@ namespace wi::allocator constexpr bool IsValid() const { return handle != 0; } constexpr T* get_ptr() const { return (T*)(handle & (~0ull << 8ull)); } - constexpr SharedBlockAllocator* get_allocator() const { return block_allocators[handle & 0xFF]; } + constexpr SharedAllocator* get_allocator() const { return shared_allocators[handle & 0xFF]; } template operator weak_ptr& () const { return *(weak_ptr*)this; } @@ -376,13 +207,13 @@ namespace wi::allocator if (!IsValid()) return {}; - SharedBlockAllocator* alloc = get_allocator(); + SharedAllocator* alloc = get_allocator(); T* ptr = get_ptr(); uint32_t old_strong = alloc->inc_refcount(ptr); if (old_strong == 0) { - alloc->dec_refcount(ptr, false); // undo refcount + alloc->dec_refcount(ptr, false); // undo refcount (not allowed to destruct, already destructed) return {}; } @@ -425,9 +256,9 @@ namespace wi::allocator // Implementation of a thread-safe refcounted block allocator template - struct SharedBlockAllocatorImpl final : public SharedBlockAllocator + struct SharedBlockAllocator final : public SharedAllocator { - const uint8_t allocator_id = register_shared_block_allocator(this); + const uint8_t allocator_id = register_shared_allocator(this); struct alignas(std::max(size_t(256), alignof(T))) RawStruct // 256 alignment is used at least because I use bottom 8 bits of pointer as allocator id { @@ -522,9 +353,81 @@ namespace wi::allocator } }; + // Implementation of a thread-safe refcounted heap allocator + template + struct SharedHeapAllocator final : public SharedAllocator + { + const uint8_t allocator_id = register_shared_allocator(this); + + struct alignas(std::max(size_t(256), alignof(T))) RawStruct // 256 alignment is used at least because I use bottom 8 bits of pointer as allocator id + { + uint8_t data[sizeof(T)]; + std::atomic refcount; + std::atomic refcount_weak; + }; + static_assert(offsetof(RawStruct, data) == 0); // we assume that data is located at 0 when casting ptr to T*, this avoids having to do a function call that would return T* like the refcounts + + template + inline shared_ptr allocate(ARG&&... args) + { + RawStruct* ptr = new RawStruct; + new (ptr) T(std::forward(args)...); + init_refcount(ptr); + shared_ptr allocation; + allocation.handle = uint64_t(ptr) | uint64_t(allocator_id); + return allocation; + } + + void reclaim(void* ptr) + { + delete static_cast(ptr); + } + + void init_refcount(void* ptr) override + { + static_cast(ptr)->refcount.store(1, std::memory_order_relaxed); + static_cast(ptr)->refcount_weak.store(1, std::memory_order_relaxed); + } + uint32_t get_refcount(void* ptr) override + { + return static_cast(ptr)->refcount.load(std::memory_order_acquire); + } + uint32_t inc_refcount(void* ptr) override + { + return static_cast(ptr)->refcount.fetch_add(1, std::memory_order_relaxed); + } + uint32_t dec_refcount(void* ptr, bool destruct_on_zero) override + { + uint32_t old = static_cast(ptr)->refcount.fetch_sub(1, std::memory_order_acq_rel); + if (old == 1) + { + if (destruct_on_zero) static_cast(ptr)->~T(); + dec_refcount_weak(ptr); + } + return old; + } + uint32_t get_refcount_weak(void* ptr) override + { + return static_cast(ptr)->refcount_weak.load(std::memory_order_acquire); + } + uint32_t inc_refcount_weak(void* ptr) override + { + return static_cast(ptr)->refcount_weak.fetch_add(1, std::memory_order_relaxed); + } + uint32_t dec_refcount_weak(void* ptr) override + { + uint32_t old = static_cast(ptr)->refcount_weak.fetch_sub(1, std::memory_order_acq_rel); + if (old == 1) + { + reclaim(ptr); + } + return old; + } + }; + // The allocators are global intentionally, this avoids runtime construction, guard check template - inline static SharedBlockAllocatorImpl* shared_block_allocator = new SharedBlockAllocatorImpl; // only destroyed after program exit, never earlier + inline static SharedBlockAllocator* shared_block_allocator = new SharedBlockAllocator; // only destroyed after program exit, never earlier // Create a new shared pooled object: template @@ -533,4 +436,186 @@ namespace wi::allocator return shared_block_allocator->allocate(std::forward(args)...); } + // Create a new shared individually allocated object: + template + inline shared_ptr make_shared_single(ARG&&... args) + { + // Allocator is created here, it's safer for global construction. The heap allocator is not used in high-performance code + static SharedHeapAllocator* shared_heap_allocator = new SharedHeapAllocator; // only destroyed after program exit, never earlier + return shared_heap_allocator->allocate(std::forward(args)...); + } + + + + + + + + + // Allocation and freeing of an arbitrary number of bytes, managed in pages of the same size + // - this is a wrapper around OffsetAllocator that adds thread safety and refcounting + // - also supports deferred release for suballocated GPU resources + struct PageAllocator + { + uint32_t page_count = 0; + uint32_t page_size = 0; + struct AllocationInternal + { + std::atomic refcount{ 0 }; + OffsetAllocator::Allocation allocation; + }; + struct AllocatorInternal + { + std::mutex locker; + OffsetAllocator::Allocator allocator; + BlockAllocator internal_blocks; + bool deferred_release_enabled = false; + uint64_t deferred_release_frame = 0; + std::deque> deferred_release_queue; + }; + wi::allocator::shared_ptr allocator; // shared ptr is used to let any allocations extend the lifeftime of the allocator + + // Returns the total size that the allocator manages: + constexpr uint64_t total_size_in_bytes() const { return uint64_t(page_count) * uint64_t(page_size); } + + // Calculates the page count that will accomodate an allocation size request + constexpr uint32_t page_count_from_bytes(uint64_t sizeInBytes) const { return uint32_t(align((uint64_t)sizeInBytes, (uint64_t)page_size) / (uint64_t)page_size); } + + // Initializes the allocator, only after which it can be used + // total_size_in_bytes : the allocator will manage this number of bytes + // page_size : the allocation granularity in bytes, each allocation will be aligned to this + // deferred_release : if false, allocations are freed immediately (suitable for CPU only allocations), otherwise they are freed after a number of frames passed (which should be used for GPU allocations) + void init(uint64_t total_size_in_bytes, uint32_t page_size = 64u * 1024u, bool deferred_release = false) + { + this->page_size = page_size; + this->page_count = page_count_from_bytes(total_size_in_bytes); + allocator = wi::allocator::make_shared_single(); + allocator->allocator.init(page_count, std::min(page_count, OffsetAllocator::default_maxallocations)); + allocator->deferred_release_enabled = deferred_release; + allocator->deferred_release_frame = 0; + allocator->deferred_release_queue.clear(); + } + // This needs to be called every frame if deferred release is enabled: + void update_deferred_release(uint64_t framecount, uint32_t buffercount) + { + if (allocator == nullptr) + return; + std::scoped_lock lck(allocator->locker); + allocator->deferred_release_frame = framecount; + while (!allocator->deferred_release_queue.empty() && allocator->deferred_release_queue.front().second + buffercount < framecount) + { + allocator->allocator.free(allocator->deferred_release_queue.front().first); + allocator->deferred_release_queue.pop_front(); + } + } + + struct Allocation + { + wi::allocator::shared_ptr allocator; // the allocator is retained so that allocation can deallocate itself + AllocationInternal* internal_state = nullptr; // this is pointing within the allocator which is retained by shared_ptr + uint64_t byte_offset = ~0ull; + + Allocation() + { + Reset(); + } + Allocation(const Allocation& other) + { + Reset(); + allocator = other.allocator; + internal_state = other.internal_state; + byte_offset = other.byte_offset; + if (internal_state != nullptr) + { + internal_state->refcount.fetch_add(1); + } + } + Allocation(Allocation&& other) noexcept + { + Reset(); + allocator = std::move(other.allocator); + internal_state = std::move(other.internal_state); + byte_offset = other.byte_offset; + other.allocator.reset(); + other.internal_state = nullptr; + other.byte_offset = ~0ull; + } + ~Allocation() + { + Reset(); + } + Allocation& operator=(const Allocation& other) + { + Reset(); + allocator = other.allocator; + internal_state = other.internal_state; + byte_offset = other.byte_offset; + if (internal_state != nullptr) + { + internal_state->refcount.fetch_add(1); + } + return *this; + } + Allocation& operator=(Allocation&& other) noexcept + { + Reset(); + allocator = std::move(other.allocator); + internal_state = std::move(other.internal_state); + byte_offset = other.byte_offset; + other.allocator.reset(); + other.internal_state = nullptr; + other.byte_offset = ~0ull; + return *this; + } + void Reset() + { + if (IsValid() && (internal_state->refcount.fetch_sub(1) <= 1)) + { + std::scoped_lock lck(allocator->locker); + if (allocator->deferred_release_enabled) + { + // can only be reclaimed after buffering amount of frames passed, this is usually used for GPU resources: + allocator->deferred_release_queue.push_back(std::make_pair(internal_state->allocation, allocator->deferred_release_frame)); + } + else + { + // reclaimed immediately: + allocator->allocator.free(internal_state->allocation); + } + allocator->internal_blocks.free(internal_state); + } + allocator = {}; + internal_state = nullptr; + byte_offset = ~0ull; + } + + constexpr bool IsValid() const { return internal_state != nullptr; } + }; + + // Allocates a reference counted allocation, viewing at least the requested amount of bytes + // To check if the allocation succeeded, call IsValid() on the returned object + inline Allocation allocate(size_t sizeInBytes) + { + const uint32_t pages = page_count_from_bytes(sizeInBytes); + std::scoped_lock lck(allocator->locker); + OffsetAllocator::Allocation offsetallocation = allocator->allocator.allocate(pages); + Allocation alloc; + if (offsetallocation.offset != OffsetAllocator::Allocation::NO_SPACE) + { + alloc.allocator = allocator; + alloc.internal_state = allocator->internal_blocks.allocate(); + alloc.internal_state->refcount.store(1); + alloc.internal_state->allocation = offsetallocation; + alloc.byte_offset = offsetallocation.offset * page_size; + } + return alloc; + } + + // returns true if no pages are allocated + inline bool is_empty() const + { + return allocator->allocator.storageReport().totalFreeSpace == page_count; + } + }; + } diff --git a/WickedEngine/wiAudio.cpp b/WickedEngine/wiAudio.cpp index 4941bc29c..5cd1be3dd 100644 --- a/WickedEngine/wiAudio.cpp +++ b/WickedEngine/wiAudio.cpp @@ -206,22 +206,22 @@ namespace wi::audio constexpr bool IsValid() const { return success; } }; - static std::shared_ptr audio_internal; + static wi::allocator::shared_ptr audio_internal; void Initialize() { - audio_internal = std::make_shared(); + audio_internal = wi::allocator::make_shared_single(); } struct SoundInternal { - std::shared_ptr audio; + wi::allocator::shared_ptr audio; WAVEFORMATEX wfx = {}; wi::vector audioData; }; struct SoundInstanceInternal : public IXAudio2VoiceCallback { - std::shared_ptr audio; + wi::allocator::shared_ptr audio; wi::allocator::shared_ptr soundinternal; IXAudio2SourceVoice* sourceVoice = nullptr; XAUDIO2_VOICE_DETAILS voiceDetails = {}; @@ -879,20 +879,20 @@ namespace wi::audio } constexpr bool IsValid() const { return success; } }; - static std::shared_ptr audio_internal; + static wi::allocator::shared_ptr audio_internal; void Initialize() { - audio_internal = std::make_shared(); + audio_internal = wi::allocator::make_shared_single(); } struct SoundInternal{ - std::shared_ptr audio; + wi::allocator::shared_ptr audio; FAudioWaveFormatEx wfx = {}; wi::vector audioData; }; struct SoundInstanceInternal{ - std::shared_ptr audio; + wi::allocator::shared_ptr audio; wi::allocator::shared_ptr soundinternal; FAudioSourceVoice* sourceVoice = nullptr; FAudioVoiceDetails voiceDetails = {}; diff --git a/WickedEngine/wiEventHandler.cpp b/WickedEngine/wiEventHandler.cpp index 8ed7bfb61..6f4caa5fd 100644 --- a/WickedEngine/wiEventHandler.cpp +++ b/WickedEngine/wiEventHandler.cpp @@ -14,11 +14,11 @@ namespace wi::eventhandler wi::unordered_map>> subscribers_once; std::mutex locker; }; - std::shared_ptr manager = std::make_shared(); + wi::allocator::shared_ptr manager = wi::allocator::make_shared_single(); struct EventInternal { - std::shared_ptr manager; + wi::allocator::shared_ptr manager; int id = 0; std::function callback; @@ -36,7 +36,7 @@ namespace wi::eventhandler Handle Subscribe(int id, std::function callback) { Handle handle; - auto eventinternal = std::make_shared(); + auto eventinternal = wi::allocator::make_shared(); handle.internal_state = eventinternal; eventinternal->manager = manager; eventinternal->id = id; diff --git a/WickedEngine/wiEventHandler.h b/WickedEngine/wiEventHandler.h index 24146d374..45449e04e 100644 --- a/WickedEngine/wiEventHandler.h +++ b/WickedEngine/wiEventHandler.h @@ -1,7 +1,7 @@ #pragma once #include "CommonInclude.h" +#include "wiAllocator.h" -#include #include namespace wi::eventhandler @@ -12,8 +12,8 @@ namespace wi::eventhandler struct Handle { - std::shared_ptr internal_state; - inline bool IsValid() const { return internal_state.get() != nullptr; } + wi::allocator::shared_ptr internal_state; + constexpr bool IsValid() const { return internal_state.get() != nullptr; } }; Handle Subscribe(int id, std::function callback); diff --git a/WickedEngine/wiGraphicsDevice_DX12.cpp b/WickedEngine/wiGraphicsDevice_DX12.cpp index bd12533a5..e7509cdf5 100644 --- a/WickedEngine/wiGraphicsDevice_DX12.cpp +++ b/WickedEngine/wiGraphicsDevice_DX12.cpp @@ -1172,7 +1172,7 @@ namespace dx12_internal struct SingleDescriptor { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; D3D12_CPU_DESCRIPTOR_HANDLE handle = {}; D3D12_DESCRIPTOR_HEAP_TYPE type = {}; int index = -1; // bindless @@ -1334,7 +1334,7 @@ namespace dx12_internal struct Resource_DX12 { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; ComPtr allocation; ComPtr resource; SingleDescriptor srv; @@ -1404,7 +1404,7 @@ namespace dx12_internal }; struct Sampler_DX12 { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; SingleDescriptor descriptor; ~Sampler_DX12() @@ -1416,7 +1416,7 @@ namespace dx12_internal }; struct QueryHeap_DX12 { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; ComPtr heap; ~QueryHeap_DX12() @@ -1428,7 +1428,7 @@ namespace dx12_internal }; struct PipelineState_DX12 { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; ComPtr resource; ComPtr rootSignature; @@ -1488,7 +1488,7 @@ namespace dx12_internal }; struct RTPipelineState_DX12 { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; ComPtr resource; ComPtr stateObjectProperties; @@ -1508,7 +1508,7 @@ namespace dx12_internal }; struct SwapChain_DX12 { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; #ifdef PLATFORM_XBOX uint32_t bufferIndex = 0; #else @@ -1545,7 +1545,7 @@ namespace dx12_internal }; struct VideoDecoder_DX12 { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; ComPtr decoder_heap; ComPtr decoder; @@ -2441,7 +2441,7 @@ std::mutex queue_locker; allocatorDesc.Flags |= D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED; allocatorDesc.Flags |= D3D12MA::ALLOCATOR_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED; - allocationhandler = std::make_shared(); + allocationhandler = wi::allocator::make_shared_single(); allocationhandler->device = device; hr = dx12_check(D3D12MA::CreateAllocator(&allocatorDesc, &allocationhandler->allocator)); diff --git a/WickedEngine/wiGraphicsDevice_DX12.h b/WickedEngine/wiGraphicsDevice_DX12.h index f2ad35eec..6ccf909b8 100644 --- a/WickedEngine/wiGraphicsDevice_DX12.h +++ b/WickedEngine/wiGraphicsDevice_DX12.h @@ -617,7 +617,7 @@ namespace wi::graphics } } }; - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; }; diff --git a/WickedEngine/wiGraphicsDevice_Vulkan.cpp b/WickedEngine/wiGraphicsDevice_Vulkan.cpp index b4a43f26a..eecf7102a 100644 --- a/WickedEngine/wiGraphicsDevice_Vulkan.cpp +++ b/WickedEngine/wiGraphicsDevice_Vulkan.cpp @@ -655,7 +655,7 @@ namespace vulkan_internal }; struct Buffer_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VmaAllocation allocation = nullptr; VkBuffer resource = VK_NULL_HANDLE; struct BufferSubresource @@ -753,7 +753,7 @@ namespace vulkan_internal }; struct Texture_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VmaAllocation allocation = nullptr; VkImage resource = VK_NULL_HANDLE; VkImageLayout defaultLayout = VK_IMAGE_LAYOUT_GENERAL; @@ -864,7 +864,7 @@ namespace vulkan_internal }; struct Sampler_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VkSampler resource = VK_NULL_HANDLE; int index = -1; @@ -881,7 +881,7 @@ namespace vulkan_internal }; struct QueryHeap_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VkQueryPool pool = VK_NULL_HANDLE; ~QueryHeap_Vulkan() @@ -896,11 +896,11 @@ namespace vulkan_internal }; struct Shader_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VkShaderModule shaderModule = VK_NULL_HANDLE; VkPipeline pipeline_cs = VK_NULL_HANDLE; VkPipelineShaderStageCreateInfo stageInfo = {}; - std::shared_ptr layout_lifetime; // lifetime management only + wi::allocator::shared_ptr layout_lifetime; // lifetime management only VkPipelineLayout pipelineLayout_cs = VK_NULL_HANDLE; // no lifetime management here VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; // no lifetime management here wi::vector layoutBindings; @@ -928,9 +928,9 @@ namespace vulkan_internal }; struct PipelineState_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VkPipeline pipeline = VK_NULL_HANDLE; - std::shared_ptr layout_lifetime; // lifetime management only + wi::allocator::shared_ptr layout_lifetime; // lifetime management only VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; // no lifetime management here VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; // no lifetime management here wi::vector layoutBindings; @@ -968,7 +968,7 @@ namespace vulkan_internal }; struct BVH_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VmaAllocation allocation = nullptr; VkBuffer buffer = VK_NULL_HANDLE; VkAccelerationStructureKHR resource = VK_NULL_HANDLE; @@ -996,7 +996,7 @@ namespace vulkan_internal }; struct RTPipelineState_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VkPipeline pipeline; ~RTPipelineState_Vulkan() @@ -1011,7 +1011,7 @@ namespace vulkan_internal }; struct SwapChain_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VkSwapchainKHR swapChain = VK_NULL_HANDLE; VkFormat swapChainImageFormat; VkExtent2D swapChainExtent; @@ -1061,7 +1061,7 @@ namespace vulkan_internal }; struct VideoDecoder_Vulkan { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VkVideoSessionKHR video_session = VK_NULL_HANDLE; VkVideoSessionParametersKHR session_parameters = VK_NULL_HANDLE; wi::vector allocations; @@ -1111,7 +1111,7 @@ namespace vulkan_internal SwapChain_Vulkan* internal_state, VkPhysicalDevice physicalDevice, VkDevice device, - std::shared_ptr allocationhandler + wi::allocator::shared_ptr allocationhandler ) { // In vulkan, the swapchain recreate can happen whenever it gets outdated, it's not in application's control @@ -2325,7 +2325,7 @@ using namespace vulkan_internal; // Issue: https://github.com/KhronosGroup/Vulkan-Docs/issues/2079 capabilities |= GraphicsDeviceCapability::COPY_BETWEEN_DIFFERENT_IMAGE_ASPECTS_NOT_SUPPORTED; - wi::unordered_map> queue_lockers; + wi::unordered_map> queue_lockers; TOPLEVEL_ACCELERATION_STRUCTURE_INSTANCE_SIZE = sizeof(VkAccelerationStructureInstanceKHR); @@ -3087,7 +3087,7 @@ using namespace vulkan_internal; float queuePriority = 1.0f; for (uint32_t queueFamily : uniqueQueueFamilies) { - queue_lockers.emplace(queueFamily, std::make_shared()); + queue_lockers.emplace(queueFamily, wi::allocator::make_shared_single()); VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = queueFamily; @@ -3165,7 +3165,7 @@ using namespace vulkan_internal; capabilities |= GraphicsDeviceCapability::CACHE_COHERENT_UMA; } - allocationhandler = std::make_shared(); + allocationhandler = wi::allocator::make_shared_single(); allocationhandler->device = device; allocationhandler->instance = instance; @@ -5028,7 +5028,7 @@ using namespace vulkan_internal; if (res == VK_SUCCESS) { auto& cached_layout = pso_layout_cache[layout_hasher]; - cached_layout = std::make_shared(); + cached_layout = wi::allocator::make_shared(); cached_layout->allocationhandler = allocationhandler; cached_layout->descriptorSetLayout = internal_state->descriptorSetLayout; cached_layout->pipelineLayout = internal_state->pipelineLayout_cs; @@ -5532,7 +5532,7 @@ using namespace vulkan_internal; if (res == VK_SUCCESS) { auto& cached_layout = pso_layout_cache[layout_hasher]; - cached_layout = std::make_shared(); + cached_layout = wi::allocator::make_shared(); cached_layout->allocationhandler = allocationhandler; cached_layout->descriptorSetLayout = internal_state->descriptorSetLayout; cached_layout->pipelineLayout = internal_state->pipelineLayout; diff --git a/WickedEngine/wiGraphicsDevice_Vulkan.h b/WickedEngine/wiGraphicsDevice_Vulkan.h index f818e0553..9b1477d29 100644 --- a/WickedEngine/wiGraphicsDevice_Vulkan.h +++ b/WickedEngine/wiGraphicsDevice_Vulkan.h @@ -210,7 +210,7 @@ namespace wi::graphics wi::vector swapchainImageIndices; bool sparse_binding_supported = false; - std::shared_ptr locker; + wi::allocator::shared_ptr locker; void clear(); void signal(VkSemaphore semaphore); @@ -894,12 +894,12 @@ namespace wi::graphics }); } }; - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; struct PSOLayout { - std::shared_ptr allocationhandler; + wi::allocator::shared_ptr allocationhandler; VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE; wi::vector bindlessSets; @@ -915,7 +915,7 @@ namespace wi::graphics allocationhandler->destroylocker.unlock(); } }; - mutable wi::unordered_map> pso_layout_cache; + mutable wi::unordered_map> pso_layout_cache; mutable std::mutex pso_layout_cache_mutex; }; } diff --git a/WickedEngine/wiInitializer.cpp b/WickedEngine/wiInitializer.cpp index da02871fd..e4a8dcf95 100644 --- a/WickedEngine/wiInitializer.cpp +++ b/WickedEngine/wiInitializer.cpp @@ -139,7 +139,7 @@ namespace wi::initializer } #ifdef _DEBUG - wilog("\nNumber of shared block allocated types: %d", (int)wi::allocator::get_shared_block_allocator_count()); + wilog("\nNumber of shared allocators (there is one per object type): %d", (int)wi::allocator::get_shared_allocator_count()); #endif // _DEBUG wi::backlog::post(""); diff --git a/WickedEngine/wiNetwork.h b/WickedEngine/wiNetwork.h index 9c04d206a..4c9121470 100644 --- a/WickedEngine/wiNetwork.h +++ b/WickedEngine/wiNetwork.h @@ -1,14 +1,14 @@ #pragma once #include "CommonInclude.h" +#include "wiAllocator.h" -#include #include namespace wi::network { struct Socket { - std::shared_ptr internal_state; + wi::allocator::shared_ptr internal_state; inline bool IsValid() const { return internal_state.get() != nullptr; } }; diff --git a/WickedEngine/wiNetwork_Linux.cpp b/WickedEngine/wiNetwork_Linux.cpp index edd41935e..2b04891e1 100644 --- a/WickedEngine/wiNetwork_Linux.cpp +++ b/WickedEngine/wiNetwork_Linux.cpp @@ -40,7 +40,7 @@ namespace wi::network bool CreateSocket(Socket* sock) { - std::shared_ptr socketinternal = std::make_shared(); + wi::allocator::shared_ptr socketinternal = wi::allocator::make_shared(); sock->internal_state = socketinternal; socketinternal->handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); diff --git a/WickedEngine/wiNetwork_Windows.cpp b/WickedEngine/wiNetwork_Windows.cpp index 835dac5c9..eca86a16f 100644 --- a/WickedEngine/wiNetwork_Windows.cpp +++ b/WickedEngine/wiNetwork_Windows.cpp @@ -37,15 +37,15 @@ namespace wi::network WSACleanup(); } }; - inline std::shared_ptr& network_internal() + inline wi::allocator::shared_ptr& network_internal() { - static std::shared_ptr internal_state = std::make_shared(); + static wi::allocator::shared_ptr internal_state = wi::allocator::make_shared_single(); return internal_state; } struct SocketInternal { - std::shared_ptr networkinternal; + wi::allocator::shared_ptr networkinternal; SOCKET handle = NULL; ~SocketInternal() @@ -65,7 +65,7 @@ namespace wi::network bool CreateSocket(Socket* sock) { - std::shared_ptr socketinternal = std::make_shared(); + wi::allocator::shared_ptr socketinternal = wi::allocator::make_shared(); socketinternal->networkinternal = network_internal(); sock->internal_state = socketinternal; diff --git a/WickedEngine/wiPhysics.h b/WickedEngine/wiPhysics.h index b4e5f62f6..d7dfa3d76 100644 --- a/WickedEngine/wiPhysics.h +++ b/WickedEngine/wiPhysics.h @@ -235,7 +235,7 @@ namespace wi::physics struct PickDragOperation { - std::shared_ptr internal_state; + wi::allocator::shared_ptr internal_state; inline bool IsValid() const { return internal_state != nullptr; } }; enum class ConstraintType diff --git a/WickedEngine/wiPhysics_Jolt.cpp b/WickedEngine/wiPhysics_Jolt.cpp index adfbc9612..09927a118 100644 --- a/WickedEngine/wiPhysics_Jolt.cpp +++ b/WickedEngine/wiPhysics_Jolt.cpp @@ -281,7 +281,7 @@ namespace wi::physics { if (scene.physics_scene == nullptr) { - auto physics_scene = std::make_shared(); + auto physics_scene = wi::allocator::make_shared_single(); physics_scene->physics_system.Init( cMaxBodies, @@ -300,7 +300,7 @@ namespace wi::physics struct RigidBody { - std::shared_ptr physics_scene; + wi::allocator::shared_ptr physics_scene; Entity entity = INVALID_ENTITY; ShapeRefC shape; BodyID bodyID; @@ -384,7 +384,7 @@ namespace wi::physics }; struct SoftBody { - std::shared_ptr physics_scene; + wi::allocator::shared_ptr physics_scene; Entity entity = INVALID_ENTITY; BodyID bodyID; float friction = 0; @@ -415,7 +415,7 @@ namespace wi::physics }; struct Constraint { - std::shared_ptr physics_scene; + wi::allocator::shared_ptr physics_scene; Entity entity = INVALID_ENTITY; Ref constraint; BodyID body1_self; @@ -456,7 +456,7 @@ namespace wi::physics { if (physicscomponent.physicsobject == nullptr) { - physicscomponent.physicsobject = std::make_shared(); + physicscomponent.physicsobject = wi::allocator::make_shared(); } return *(RigidBody*)physicscomponent.physicsobject.get(); } @@ -468,7 +468,7 @@ namespace wi::physics { if (physicscomponent.physicsobject == nullptr) { - physicscomponent.physicsobject = std::make_shared(); + physicscomponent.physicsobject = wi::allocator::make_shared(); } return *(SoftBody*)physicscomponent.physicsobject.get(); } @@ -480,7 +480,7 @@ namespace wi::physics { if (physicscomponent.physicsobject == nullptr) { - physicscomponent.physicsobject = std::make_shared(); + physicscomponent.physicsobject = wi::allocator::make_shared(); } return *(Constraint*)physicscomponent.physicsobject.get(); } @@ -1289,7 +1289,7 @@ namespace wi::physics BODYPART_COUNT }; - std::shared_ptr physics_scene; + wi::allocator::shared_ptr physics_scene; RigidBody rigidbodies[BODYPART_COUNT]; Entity saved_parents[BODYPART_COUNT] = {}; Skeleton skeleton; @@ -2150,7 +2150,7 @@ namespace wi::physics } if (humanoid.ragdoll == nullptr) { - humanoid.ragdoll = std::make_shared(scene, humanoid, humanoidEntity, scale); + humanoid.ragdoll = wi::allocator::make_shared(scene, humanoid, humanoidEntity, scale); } }); @@ -2160,12 +2160,12 @@ namespace wi::physics PhysicsConstraintComponent& physicscomponent = scene.constraints[args.jobIndex]; if (physicscomponent.bodyA == INVALID_ENTITY && physicscomponent.bodyB == INVALID_ENTITY) { - physicscomponent.physicsobject = nullptr; + physicscomponent.physicsobject.reset(); return; } if (!scene.rigidbodies.Contains(physicscomponent.bodyA) && !scene.rigidbodies.Contains(physicscomponent.bodyB)) { - physicscomponent.physicsobject = nullptr; + physicscomponent.physicsobject.reset(); return; } if (physicscomponent.physicsobject != nullptr) @@ -2181,7 +2181,7 @@ namespace wi::physics if (body.bodyID != constraint.body1_ref) { // Rigidbody to constraint object mismatch! - physicscomponent.physicsobject = nullptr; + physicscomponent.physicsobject.reset(); return; } } @@ -2195,7 +2195,7 @@ namespace wi::physics if (body.bodyID != constraint.body2_ref) { // Rigidbody to constraint object mismatch! - physicscomponent.physicsobject = nullptr; + physicscomponent.physicsobject.reset(); return; } } @@ -3927,7 +3927,7 @@ namespace wi::physics struct PickDragOperation_Jolt { - std::shared_ptr physics_scene; + wi::allocator::shared_ptr physics_scene; Ref constraint; float pick_distance = 0; Body* bodyA = nullptr; @@ -4005,7 +4005,7 @@ namespace wi::physics return; Body* body = (Body*)result.physicsobject; - auto internal_state = std::make_shared(); + auto internal_state = wi::allocator::make_shared(); internal_state->physics_scene = scene.physics_scene; internal_state->pick_distance = wi::math::Distance(ray.origin, result.position); internal_state->bodyB = body; diff --git a/WickedEngine/wiRenderPath3D.cpp b/WickedEngine/wiRenderPath3D.cpp index 5eb37da4f..af651cfce 100644 --- a/WickedEngine/wiRenderPath3D.cpp +++ b/WickedEngine/wiRenderPath3D.cpp @@ -2640,7 +2640,7 @@ namespace wi camera.render_to_texture.tileCount = tiledres.tileCount; camera.render_to_texture.entityTiles = tiledres.entityTiles; - camera.render_to_texture.visibility = std::make_shared(); + camera.render_to_texture.visibility = wi::allocator::make_shared(); } if (getSceneUpdateEnabled()) { diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index a86623a77..db14dcf78 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -5865,7 +5865,7 @@ namespace wi::scene if (character.pathfinding_thread == nullptr && character.process_goal) { - character.pathfinding_thread = std::make_shared(); + character.pathfinding_thread = wi::allocator::make_shared(); } if (character.pathfinding_thread) { diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 343e39649..f7ab1998e 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -75,7 +75,7 @@ namespace wi::scene float time = 0; CameraComponent camera; // for LOD and 3D sound update - std::shared_ptr physics_scene; + wi::allocator::shared_ptr physics_scene; wi::SpinLock locker; wi::primitive::AABB bounds; wi::vector parallel_bounds; diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 01e81b6a9..70693385c 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -524,7 +524,7 @@ namespace wi::scene } character; // Non-serialized attributes: - std::shared_ptr physicsobject = nullptr; // You can set to null to recreate the physics object the next time phsyics system will be running. + wi::allocator::shared_ptr physicsobject; // You can reset this to recreate the physics object the next time phsyics system will be running. constexpr void SetDisableDeactivation(bool value) { if (value) { _flags |= DISABLE_DEACTIVATION; } else { _flags &= ~DISABLE_DEACTIVATION; } } constexpr void SetKinematic(bool value) { if (value) { _flags |= KINEMATIC; } else { _flags &= ~KINEMATIC; } } @@ -637,7 +637,7 @@ namespace wi::scene float break_distance = FLT_MAX; // how much the constraint is allowed to be exerted before breaking, calculated as relative distance // Non-serialized attributes: - std::shared_ptr physicsobject = nullptr; // You can set to null to recreate the physics object the next time phsyics system will be running. + wi::allocator::shared_ptr physicsobject; // You can reset this to recreate the physics object the next time phsyics system will be running. // Request refreshing of constraint settings without recreating the constraint constexpr void SetRefreshParametersNeeded(bool value = true) { if (value) { _flags |= REFRESH_PARAMETERS_REQUEST; } else { _flags &= ~REFRESH_PARAMETERS_REQUEST; } } @@ -1269,7 +1269,7 @@ namespace wi::scene wi::vector weights; // weight per physics vertex controlling the mass. (0: disable weight (no physics, only animation), 1: default weight) // Non-serialized attributes: - std::shared_ptr physicsobject = nullptr; // You can set to null to recreate the physics object the next time phsyics system will be running. + wi::allocator::shared_ptr physicsobject; // You can reset this to recreate the physics object the next time phsyics system will be running. XMFLOAT4X4 worldMatrix = wi::math::IDENTITY_MATRIX; wi::vector boneData; // simulated soft body nodes as bone matrices that can be fed into skinning wi::primitive::AABB aabb; @@ -1284,7 +1284,7 @@ namespace wi::scene { physicsIndices.clear(); physicsToGraphicsVertexMapping.clear(); - physicsobject = {}; + physicsobject.reset(); } void SetDetail(float loddetail) @@ -1481,7 +1481,7 @@ namespace wi::scene wi::graphics::Texture depthstencil_resolved; XMUINT2 tileCount = {}; wi::graphics::GPUBuffer entityTiles; - std::shared_ptr visibility; + wi::allocator::shared_ptr visibility; } render_to_texture; void CreateOrtho(float newWidth, float newHeight, float newNear, float newFar, float newVerticalSize = 1); @@ -2333,7 +2333,7 @@ namespace wi::scene XMFLOAT4 lookAtDeltaRotationState_Head = XMFLOAT4(0, 0, 0, 1); XMFLOAT4 lookAtDeltaRotationState_LeftEye = XMFLOAT4(0, 0, 0, 1); XMFLOAT4 lookAtDeltaRotationState_RightEye = XMFLOAT4(0, 0, 0, 1); - std::shared_ptr ragdoll = nullptr; // physics system implementation-specific object + wi::allocator::shared_ptr ragdoll; // physics system implementation-specific object float default_facing = 0; // 0 = not yet computed, otherwise Z direction float knee_bending = 0; // 0 = not yet computed, otherwise Z direction @@ -2523,7 +2523,7 @@ namespace wi::scene wi::jobsystem::Wait(ctx); } }; - std::shared_ptr pathfinding_thread; // separate allocation, mustn't be reallocated while path finding thread is running + wi::allocator::shared_ptr pathfinding_thread; // separate allocation, mustn't be reallocated while path finding thread is running const wi::VoxelGrid* voxelgrid = nullptr; // Apply movement to the character in the next update diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index 896f7c4bd..5bd8f1d21 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -417,7 +417,7 @@ namespace wi::terrain grass_properties.viewDistance = chunk_width; - generator = std::make_shared(); + generator = wi::allocator::make_shared_single(); materialEntities.resize(MATERIAL_COUNT); } @@ -2391,7 +2391,7 @@ namespace wi::terrain default: case Modifier::Type::Perlin: { - std::shared_ptr modifier = std::make_shared(); + wi::allocator::shared_ptr modifier = wi::allocator::make_shared_single(); modifiers[i] = modifier; archive >> modifier->octaves; archive >> modifier->seed; @@ -2400,7 +2400,7 @@ namespace wi::terrain break; case Modifier::Type::Voronoi: { - std::shared_ptr modifier = std::make_shared(); + wi::allocator::shared_ptr modifier = wi::allocator::make_shared_single(); modifiers[i] = modifier; archive >> modifier->fade; archive >> modifier->shape; @@ -2412,7 +2412,7 @@ namespace wi::terrain break; case Modifier::Type::Heightmap: { - std::shared_ptr modifier = std::make_shared(); + wi::allocator::shared_ptr modifier = wi::allocator::make_shared_single(); modifiers[i] = modifier; archive >> modifier->amount; archive >> modifier->data; diff --git a/WickedEngine/wiTerrain.h b/WickedEngine/wiTerrain.h index 073c1a8ff..150308573 100644 --- a/WickedEngine/wiTerrain.h +++ b/WickedEngine/wiTerrain.h @@ -295,7 +295,7 @@ namespace wi::terrain // For generating scene on a background thread: float generation_time_budget_milliseconds = 8; // after this much time, the generation thread will start to exit. This can help avoid a very long running, resource consuming and slow cancellation generation - std::shared_ptr generator; + wi::allocator::shared_ptr generator; wi::vector virtual_textures_in_use; wi::graphics::Sampler sampler; @@ -332,7 +332,7 @@ namespace wi::terrain float region2 = 2; float region3 = 8; - wi::vector> modifiers; + wi::vector> modifiers; wi::vector modifiers_to_remove; Terrain(); diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 3fe254d90..eae4b8b16 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 858; + const int revision = 859; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision); diff --git a/WickedEngine/wickedengine.natvis b/WickedEngine/wickedengine.natvis index 418fec9ab..c9f03776c 100644 --- a/WickedEngine/wickedengine.natvis +++ b/WickedEngine/wickedengine.natvis @@ -17,7 +17,7 @@ {{ handle={handle} }} reinterpret_cast<$T1*>(handle & (~0ull << 8ull)) - block_allocators[handle & 0xFF] + shared_allocators[handle & 0xFF]