aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYulong Bai <yulong.bai@qt.io>2019-12-05 15:23:38 +0100
committerYulong Bai <yulong.bai@qt.io>2019-12-09 12:56:20 +0000
commite93a471dfde3c3b08d41eac53e595129ca520c68 (patch)
tree30468a68575eba45987028c10dacb980b5a29744
parentff6bd91f580fa5ddae2d02f32b9d83be4374a445 (diff)
Particle system: fix infinite loop after running for many hours
The infinite loop was triggered by several issues coincide together. In short, the direct cause is the particle's born time and lifespan were represented in 32 bit floats and not precise enough to pass aliveness check as time grows large. While the time grows large, the resolution of floating point decreases to the extent that resolution is even bigger than 2 milliseconds. Then it will fail to pass the aliveness check. Then, the dead particles will be treated alive and they are kept inserting into and popping out of the particles heap, which is similar to a live-lock. The fix is to separate freeing dead and inserting back alive ones in two different loops, ensure that the emitter can update time for next frame. There are still other issues: 1) as the times runs very long, the particle needs several frames's updates to actually make the states change noticeable, which means animation may become not so smooth after running for too long (like several days). May change particle's born/lifespan time to 64 bits in another patch. 2) the particle system's and animation's timers are 32 bit integers, after 2^31 milliseconds(24.8551348 days), they will overflow. May promote them to 64 bits in another patch. 3) as the time grows even larger such that the resolution is bigger than 16ms at 60 hz frame rate, the live-lock may occur again. Because the timer advances/delta will be not large enough to make dead ones reused. The next live-lock estimated time is 2^24*16 milliseconds = 3.10689185 days. The final fixes are 1) and 2) 4) may change the particle system's internal timer be set to arbitrary value (fast forward to large value) for easier writing autotest for above cases. Change-Id: I1190c0814c8197876b26dd4182dc4b065dd1ece6 Task-number: QTBUG-64138 Reviewed-by: Vitaly Fanaskov <vitaly.fanaskov@qt.io> (cherry picked from commit f8df9dc8b45cd9e386b66255183c58f3dfcc41a9) Reviewed-by: Liang Qi <liang.qi@qt.io>
-rw-r--r--src/particles/qquickparticlesystem.cpp7
-rw-r--r--src/particles/qquickparticlesystem_p.h2
2 files changed, 8 insertions, 1 deletions
diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp
index 1499df0360..8e8c73320e 100644
--- a/src/particles/qquickparticlesystem.cpp
+++ b/src/particles/qquickparticlesystem.cpp
@@ -389,16 +389,21 @@ QQuickParticleData* QQuickParticleGroupData::newDatum(bool respectsLimits)
bool QQuickParticleGroupData::recycle()
{
+ m_latestAliveParticles.clear();
+
while (dataHeap.top() <= m_system->timeInt) {
foreach (QQuickParticleData* datum, dataHeap.pop()) {
if (!datum->stillAlive(m_system)) {
freeList.free(datum->index);
} else {
- prepareRecycler(datum); //ttl has been altered mid-way, put it back
+ m_latestAliveParticles.push_back(datum);
}
}
}
+ for (auto particle : m_latestAliveParticles)
+ prepareRecycler(particle); //ttl has been altered mid-way, put it back
+
//TODO: If the data is clear, gc (consider shrinking stack size)?
return freeList.count() == 0;
}
diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h
index 73351fb99a..d88e4949e3 100644
--- a/src/particles/qquickparticlesystem_p.h
+++ b/src/particles/qquickparticlesystem_p.h
@@ -226,6 +226,8 @@ public:
private:
int m_size;
QQuickParticleSystem* m_system;
+ // Only used in recycle() for tracking of alive particles after latest recycling round
+ QVector<QQuickParticleData*> m_latestAliveParticles;
};
struct Color4ub {