From 5b5f43714e36c685d346bdea437f8de9f5950664 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 12 Oct 2023 17:55:49 +0200 Subject: [PATCH] Fix invalid particle attributes access inside emitter function #1640 --- .../Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp | 12 +++++++++++- .../Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp | 2 ++ .../Particles/Graph/CPU/ParticleEmitterGraph.CPU.h | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp index 9d91d0013..cb2d7004e 100644 --- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp +++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp @@ -7,7 +7,7 @@ #include "Engine/Graphics/RenderTask.h" #define GET_VIEW() auto mainViewTask = MainRenderTask::Instance && MainRenderTask::Instance->LastUsedFrame != 0 ? MainRenderTask::Instance : nullptr -#define ACCESS_PARTICLE_ATTRIBUTE(index) (context.Data->Buffer->GetParticleCPU(context.ParticleIndex) + context.Data->Buffer->Layout->Attributes[node->Attributes[index]].Offset) +#define ACCESS_PARTICLE_ATTRIBUTE(index) (context.Data->Buffer->GetParticleCPU(context.ParticleIndex) + context.Data->Buffer->Layout->Attributes[context.AttributesRemappingTable[node->Attributes[index]]].Offset) #define GET_PARTICLE_ATTRIBUTE(index, type) *(type*)ACCESS_PARTICLE_ATTRIBUTE(index) void ParticleEmitterGraphCPUExecutor::ProcessGroupParameters(Box* box, Node* node, Value& value) @@ -436,9 +436,19 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParticles(Box* box, Node* node auto* functionOutputNode = &graph->Nodes[function->Outputs[outputIndex]]; Box* functionOutputBox = functionOutputNode->TryGetBox(0); + // Setup particle attributes remapping (so particle data access nodes inside the function will read data at proper offset, see macro ACCESS_PARTICLE_ATTRIBUTE) + byte attributesRemappingTable[PARTICLE_ATTRIBUTES_MAX_COUNT]; + Platform::MemoryCopy(attributesRemappingTable, context.AttributesRemappingTable, sizeof(attributesRemappingTable)); + for (int32 i = 0; i < graph->Layout.Attributes.Count(); i++) + { + const ParticleAttribute& e = graph->Layout.Attributes[i]; + context.AttributesRemappingTable[i] = context.Data->Buffer->Layout->FindAttribute(e.Name, e.ValueType); + } + // Evaluate the function output context.GraphStack.Push(graph); value = functionOutputBox && functionOutputBox->HasConnection() ? eatBox(nodeBase, functionOutputBox->FirstConnection()) : Value::Zero; + Platform::MemoryCopy(context.AttributesRemappingTable, attributesRemappingTable, sizeof(attributesRemappingTable)); context.GraphStack.Pop(); break; } diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp index d86bc6d54..a8f7898e1 100644 --- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp +++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.cpp @@ -133,6 +133,8 @@ void ParticleEmitterGraphCPUExecutor::Init(ParticleEmitter* emitter, ParticleEff context.ViewTask = effect->GetRenderTask(); context.CallStackSize = 0; context.Functions.Clear(); + for (int32 i = 0; i < PARTICLE_ATTRIBUTES_MAX_COUNT; i++) + context.AttributesRemappingTable[i] = i; } bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, ParticleEffect* effect, ParticleEmitterInstance& data, BoundingBox& result) diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h index 9d1d48c81..4f55da6e2 100644 --- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h +++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.h @@ -119,6 +119,7 @@ struct ParticleEmitterGraphCPUContext class SceneRenderTask* ViewTask; Array> GraphStack; Dictionary Functions; + byte AttributesRemappingTable[PARTICLE_ATTRIBUTES_MAX_COUNT]; // Maps node attribute indices to the current particle layout (used to support accessing particle data from function graph which has different layout). int32 CallStackSize = 0; VisjectExecutor::Node* CallStack[PARTICLE_EMITTER_MAX_CALL_STACK]; };