Fix crash in particles system when assets gets loading/unloaded while async jobs are active
This commit is contained in:
@@ -120,7 +120,7 @@ void AnimationsSystem::Execute(TaskGraph* graph)
|
|||||||
return;
|
return;
|
||||||
Active = true;
|
Active = true;
|
||||||
|
|
||||||
// Ensure no animation assets it being reloading/modified before running async update
|
// Ensure no animation assets can be reloaded/modified during async update
|
||||||
Animations::SystemLocker.Begin(false);
|
Animations::SystemLocker.Begin(false);
|
||||||
|
|
||||||
// Setup data for async update
|
// Setup data for async update
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ namespace
|
|||||||
|
|
||||||
Asset::LoadResult ParticleEmitter::load()
|
Asset::LoadResult ParticleEmitter::load()
|
||||||
{
|
{
|
||||||
|
ConcurrentSystemLocker::WriteScope systemScope(Particles::SystemLocker);
|
||||||
|
|
||||||
// Load the graph
|
// Load the graph
|
||||||
const auto surfaceChunk = GetChunk(SHADER_FILE_CHUNK_VISJECT_SURFACE);
|
const auto surfaceChunk = GetChunk(SHADER_FILE_CHUNK_VISJECT_SURFACE);
|
||||||
if (!surfaceChunk)
|
if (!surfaceChunk)
|
||||||
@@ -287,6 +289,7 @@ Asset::LoadResult ParticleEmitter::load()
|
|||||||
|
|
||||||
void ParticleEmitter::unload(bool isReloading)
|
void ParticleEmitter::unload(bool isReloading)
|
||||||
{
|
{
|
||||||
|
ConcurrentSystemLocker::WriteScope systemScope(Particles::SystemLocker);
|
||||||
#if COMPILE_WITH_SHADER_COMPILER
|
#if COMPILE_WITH_SHADER_COMPILER
|
||||||
UnregisterForShaderReloads(this);
|
UnregisterForShaderReloads(this);
|
||||||
#endif
|
#endif
|
||||||
@@ -389,7 +392,7 @@ bool ParticleEmitter::SaveSurface(BytesContainer& data)
|
|||||||
LOG(Error, "Asset loading failed. Cannot save it.");
|
LOG(Error, "Asset loading failed. Cannot save it.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
ConcurrentSystemLocker::WriteScope systemScope(Particles::SystemLocker);
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
// Release all chunks
|
// Release all chunks
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
#include "ParticleEmitterFunction.h"
|
#include "ParticleEmitterFunction.h"
|
||||||
|
#include "Particles.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
@@ -39,6 +40,8 @@ ParticleEmitterFunction::ParticleEmitterFunction(const SpawnParams& params, cons
|
|||||||
|
|
||||||
Asset::LoadResult ParticleEmitterFunction::load()
|
Asset::LoadResult ParticleEmitterFunction::load()
|
||||||
{
|
{
|
||||||
|
ConcurrentSystemLocker::WriteScope systemScope(Particles::SystemLocker);
|
||||||
|
|
||||||
// Load graph
|
// Load graph
|
||||||
const auto surfaceChunk = GetChunk(0);
|
const auto surfaceChunk = GetChunk(0);
|
||||||
if (!surfaceChunk || !surfaceChunk->IsLoaded())
|
if (!surfaceChunk || !surfaceChunk->IsLoaded())
|
||||||
@@ -90,6 +93,7 @@ Asset::LoadResult ParticleEmitterFunction::load()
|
|||||||
|
|
||||||
void ParticleEmitterFunction::unload(bool isReloading)
|
void ParticleEmitterFunction::unload(bool isReloading)
|
||||||
{
|
{
|
||||||
|
ConcurrentSystemLocker::WriteScope systemScope(Particles::SystemLocker);
|
||||||
Graph.Clear();
|
Graph.Clear();
|
||||||
#if COMPILE_WITH_PARTICLE_GPU_GRAPH
|
#if COMPILE_WITH_PARTICLE_GPU_GRAPH
|
||||||
GraphGPU.Clear();
|
GraphGPU.Clear();
|
||||||
@@ -190,7 +194,7 @@ bool ParticleEmitterFunction::SaveSurface(BytesContainer& data)
|
|||||||
LOG(Error, "Asset loading failed. Cannot save it.");
|
LOG(Error, "Asset loading failed. Cannot save it.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
ConcurrentSystemLocker::WriteScope systemScope(Particles::SystemLocker);
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
// Set Visject Surface data
|
// Set Visject Surface data
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ namespace ParticleManagerImpl
|
|||||||
using namespace ParticleManagerImpl;
|
using namespace ParticleManagerImpl;
|
||||||
|
|
||||||
TaskGraphSystem* Particles::System = nullptr;
|
TaskGraphSystem* Particles::System = nullptr;
|
||||||
|
ConcurrentSystemLocker Particles::SystemLocker;
|
||||||
bool Particles::EnableParticleBufferPooling = true;
|
bool Particles::EnableParticleBufferPooling = true;
|
||||||
float Particles::ParticleBufferRecycleTimeout = 10.0f;
|
float Particles::ParticleBufferRecycleTimeout = 10.0f;
|
||||||
|
|
||||||
@@ -139,6 +140,8 @@ class ParticlesSystem : public TaskGraphSystem
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
float DeltaTime, UnscaledDeltaTime, Time, UnscaledTime;
|
float DeltaTime, UnscaledDeltaTime, Time, UnscaledTime;
|
||||||
|
bool Active;
|
||||||
|
|
||||||
void Job(int32 index);
|
void Job(int32 index);
|
||||||
void Execute(TaskGraph* graph) override;
|
void Execute(TaskGraph* graph) override;
|
||||||
void PostExecute(TaskGraph* graph) override;
|
void PostExecute(TaskGraph* graph) override;
|
||||||
@@ -1390,6 +1393,10 @@ void ParticlesSystem::Execute(TaskGraph* graph)
|
|||||||
{
|
{
|
||||||
if (UpdateList.Count() == 0)
|
if (UpdateList.Count() == 0)
|
||||||
return;
|
return;
|
||||||
|
Active = true;
|
||||||
|
|
||||||
|
// Ensure no particle assets can be reloaded/modified during async update
|
||||||
|
Particles::SystemLocker.Begin(false);
|
||||||
|
|
||||||
// Setup data for async update
|
// Setup data for async update
|
||||||
const auto& tickData = Time::Update;
|
const auto& tickData = Time::Update;
|
||||||
@@ -1406,8 +1413,13 @@ void ParticlesSystem::Execute(TaskGraph* graph)
|
|||||||
|
|
||||||
void ParticlesSystem::PostExecute(TaskGraph* graph)
|
void ParticlesSystem::PostExecute(TaskGraph* graph)
|
||||||
{
|
{
|
||||||
|
if (!Active)
|
||||||
|
return;
|
||||||
PROFILE_CPU_NAMED("Particles.PostExecute");
|
PROFILE_CPU_NAMED("Particles.PostExecute");
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
Particles::SystemLocker.End(false);
|
||||||
|
Active = false;
|
||||||
UpdateList.Clear();
|
UpdateList.Clear();
|
||||||
|
|
||||||
#if COMPILE_WITH_GPU_PARTICLES
|
#if COMPILE_WITH_GPU_PARTICLES
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Engine/Scripting/ScriptingType.h"
|
#include "Engine/Scripting/ScriptingType.h"
|
||||||
|
#include "Engine/Threading/ConcurrentSystemLocker.h"
|
||||||
|
|
||||||
class TaskGraphSystem;
|
class TaskGraphSystem;
|
||||||
struct RenderContext;
|
struct RenderContext;
|
||||||
@@ -27,6 +28,9 @@ API_CLASS(Static) class FLAXENGINE_API Particles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(ReadOnly) static TaskGraphSystem* System;
|
API_FIELD(ReadOnly) static TaskGraphSystem* System;
|
||||||
|
|
||||||
|
// Data access locker for animations data.
|
||||||
|
static ConcurrentSystemLocker SystemLocker;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the effect during next particles simulation tick.
|
/// Updates the effect during next particles simulation tick.
|
||||||
|
|||||||
Reference in New Issue
Block a user