Optimize particles vertex data

Use uchar instead of float for vertex data that doesn't need float.
Continue using floats in shaders. Also remove animY2, which is same as
animY1. These changes reduce memory usage especially when the amount
of particles increases.

Testing on windows, memory reductions with emitters/trailemitter
example were:
- OpenGL: 82.7 MB -> 76.5 MB
- Vulkan: 130.8 MB -> 126.3 MB
- D3D11: 143.7 MB -> 135.8 MB

Task-number: QTBUG-88124
Change-Id: I8f8dcb3845323b0e69fb99b5bff830cd0f151a47
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
This commit is contained in:
Kaj Grönholm 2020-11-06 12:56:36 +02:00
parent 1df1167ff1
commit ebe3670522
16 changed files with 58 additions and 57 deletions

View File

@ -1067,8 +1067,8 @@ void QQuickImageParticle::createEngine()
}
static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
QSGGeometry::Attribute::create(0, 2, QSGGeometry::FloatType, true), // Position
QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data
QSGGeometry::Attribute::create(0, 2, QSGGeometry::FloatType, true), // Position
QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data
QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType) // Vectors
};
@ -1080,9 +1080,9 @@ static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
};
static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
QSGGeometry::Attribute::create(0, 2, QSGGeometry::FloatType, true), // Position
QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data
QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors
QSGGeometry::Attribute::create(0, 2, QSGGeometry::FloatType, true), // Position
QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data
QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors
QSGGeometry::Attribute::create(3, 4, QSGGeometry::UnsignedByteType), // Colors
};
@ -1094,36 +1094,36 @@ static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
};
static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
QSGGeometry::Attribute::create(0, 4, QSGGeometry::FloatType), // Position & TexCoord
QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data
QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors
QSGGeometry::Attribute::create(0, 4, QSGGeometry::FloatType), // Position & Rotation
QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data
QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors
QSGGeometry::Attribute::create(3, 4, QSGGeometry::UnsignedByteType), // Colors
QSGGeometry::Attribute::create(4, 4, QSGGeometry::FloatType), // DeformationVectors
QSGGeometry::Attribute::create(5, 3, QSGGeometry::FloatType), // Rotation
QSGGeometry::Attribute::create(4, 4, QSGGeometry::FloatType), // DeformationVectors
QSGGeometry::Attribute::create(5, 4, QSGGeometry::UnsignedByteType), // TexCoord & autoRotate
};
static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
{
6, // Attribute Count
(4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
(4 + 4 + 4 + 4) * sizeof(float) + (4 + 4) * sizeof(uchar),
DeformableParticle_Attributes
};
static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
QSGGeometry::Attribute::create(0, 4, QSGGeometry::FloatType), // Position & TexCoord
QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data
QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors
QSGGeometry::Attribute::create(0, 4, QSGGeometry::FloatType), // Position & Rotation
QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data
QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors
QSGGeometry::Attribute::create(3, 4, QSGGeometry::UnsignedByteType), // Colors
QSGGeometry::Attribute::create(4, 4, QSGGeometry::FloatType), // DeformationVectors
QSGGeometry::Attribute::create(5, 3, QSGGeometry::FloatType), // Rotation
QSGGeometry::Attribute::create(6, 3, QSGGeometry::FloatType), // Anim Data
QSGGeometry::Attribute::create(7, 4, QSGGeometry::FloatType) // Anim Pos
QSGGeometry::Attribute::create(4, 4, QSGGeometry::FloatType), // DeformationVectors
QSGGeometry::Attribute::create(5, 4, QSGGeometry::UnsignedByteType), // TexCoord & autoRotate
QSGGeometry::Attribute::create(6, 3, QSGGeometry::FloatType), // Anim Data
QSGGeometry::Attribute::create(7, 3, QSGGeometry::FloatType) // Anim Pos
};
static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
{
8, // Attribute Count
(4 + 4 + 4 + 4 + 3 + 3 + 4) * sizeof(float) + 4 * sizeof(uchar),
(4 + 4 + 4 + 4 + 3 + 3) * sizeof(float) + (4 + 4) * sizeof(uchar),
SpriteParticle_Attributes
};
@ -1622,7 +1622,6 @@ void QQuickImageParticle::spritesUpdate(qreal time)
spriteVertices[i].animX1 = x1;
spriteVertices[i].animY1 = y;
spriteVertices[i].animX2 = x2;
spriteVertices[i].animY2 = y;
spriteVertices[i].animW = w;
spriteVertices[i].animH = h;
spriteVertices[i].animProgress = progress;
@ -1677,7 +1676,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx)
float rotation;
float rotationVelocity;
float autoRotate;
uchar autoRotate;
switch (perfLevel){//Fall-through is intended on all of them
case Sprites:
// Initial Sprite State
@ -1749,7 +1748,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx)
(m_rotation + (m_rotationVariation - 2*QRandomGenerator::global()->bounded(m_rotationVariation)) ) * CONV;
rotationVelocity =
(m_rotationVelocity + (m_rotationVelocityVariation - 2*QRandomGenerator::global()->bounded(m_rotationVelocityVariation)) ) * CONV;
autoRotate = m_autoRotation?1.0:0.0;
autoRotate = m_autoRotation ? 1 : 0;
if (datum->rotationOwner == this) {
datum->rotation = rotation;
datum->rotationVelocity = rotationVelocity;

View File

@ -99,8 +99,8 @@ struct ColoredVertex {
struct DeformableVertex {
float x;
float y;
float tx;
float ty;
float rotation;
float rotationVelocity;
float t;
float lifeSpan;
float size;
@ -114,16 +114,17 @@ struct DeformableVertex {
float xy;
float yx;
float yy;
float rotation;
float rotationVelocity;
float autoRotate;//Assumed that GPUs prefer floats to bools
uchar tx;
uchar ty;
uchar autoRotate;
uchar _padding; // feel free to use
};
struct SpriteVertex {
float x;
float y;
float tx;
float ty;
float rotation;
float rotationVelocity;
float t;
float lifeSpan;
float size;
@ -137,16 +138,16 @@ struct SpriteVertex {
float xy;
float yx;
float yy;
float rotation;
float rotationVelocity;
float autoRotate;//Assumed that GPUs prefer floats to bools
uchar tx;
uchar ty;
uchar autoRotate;
uchar _padding; // feel free to use
float animW;
float animH;
float animProgress;
float animX1;
float animY1;
float animX2;
float animY2;
};
template <typename Vertex>
@ -433,18 +434,19 @@ private:
template<class Vertex>
void initTexCoords(Vertex* v, int count){
Vertex* end = v + count;
// Vertex coords between (0.0, 0.0) and (1.0, 1.0)
while (v < end){
v[0].tx = 0;
v[0].ty = 0;
v[1].tx = 1;
v[1].tx = 255;
v[1].ty = 0;
v[2].tx = 0;
v[2].ty = 1;
v[2].ty = 255;
v[3].tx = 1;
v[3].ty = 1;
v[3].tx = 255;
v[3].ty = 255;
v += 4;
}

View File

@ -301,7 +301,7 @@ public:
float yy;
float rotation;
float rotationVelocity;
float autoRotate;//Assume that GPUs prefer floats to bools
uchar autoRotate; // Basically a bool
//Used by ImageParticle Sprite mode
float animIdx;
float frameDuration;

View File

@ -4,7 +4,7 @@ layout(location = 1) in vec4 vData; // x = time, y = lifeSpan, z = size, w = end
layout(location = 2) in vec4 vVec; // x,y = constant velocity, z,w = acceleration
#if defined(DEFORM)
layout(location = 0) in vec4 vPosTex;
layout(location = 0) in vec4 vPosRot; //x = x, y = y, z = radians of rotation, w = rotation velocity
#else
layout(location = 0) in vec2 vPos;
#endif
@ -15,12 +15,12 @@ layout(location = 3) in vec4 vColor;
#if defined(DEFORM)
layout(location = 4) in vec4 vDeformVec; // x,y x unit vector; z,w = y unit vector
layout(location = 5) in vec3 vRotation; // x = radians of rotation, y = rotation velocity, z = bool autoRotate
layout(location = 5) in vec3 vTex; // x = tx, y = ty, z = bool autoRotate
#endif
#if defined(SPRITE)
layout(location = 6) in vec3 vAnimData; // w,h(premultiplied of anim), interpolation progress
layout(location = 7) in vec4 vAnimPos; // x,y, x,y (two frames for interpolation)
layout(location = 7) in vec3 vAnimPos; // x, y, x2 (two frames for interpolation)
#endif
#if defined(TABLE)
@ -55,7 +55,7 @@ void main()
float t = (ubuf.timestamp - vData.x) / vData.y;
if (t < 0. || t > 1.) {
#if defined(DEFORM)
gl_Position = ubuf.matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);
gl_Position = ubuf.matrix * vec4(vPosRot.x, vPosRot.y, 0., 1.);
#else
gl_PointSize = 0.;
#endif
@ -64,13 +64,13 @@ void main()
tt.y = vAnimData.z;
// Calculate frame location in texture
fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy;
fTexS.xy = vAnimPos.xy + vTex.xy * vAnimData.xy;
// Next frame is also passed, for interpolation
fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy;
fTexS.zw = vAnimPos.zy + vTex.xy * vAnimData.xy;
#elif defined(DEFORM)
fTex = vPosTex.zw;
fTex = vTex.xy;
#endif
float currentSize = mix(vData.z, vData.w, t * t);
float fade = 1.;
@ -89,7 +89,7 @@ void main()
if (currentSize <= 0.) {
#if defined(DEFORM)
gl_Position = ubuf.matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);
gl_Position = ubuf.matrix * vec4(vPosRot.x, vPosRot.y, 0., 1.);
#else
gl_PointSize = 0.;
#endif
@ -99,14 +99,14 @@ void main()
vec2 pos;
#if defined(DEFORM)
float rotation = vRotation.x + vRotation.y * t * vData.y;
if (vRotation.z == 1.0) {
float rotation = vPosRot.z + vPosRot.w * t * vData.y;
if (vTex.z > 0.) {
vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
if (length(curVel) > 0.)
rotation += atan(curVel.y, curVel.x);
}
vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5);
vec4 deform = vDeformVec * currentSize * (vTex.xxyy - 0.5);
vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;
rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));
/* The readable version:
@ -119,7 +119,7 @@ void main()
yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
*/
pos = vPosTex.xy
pos = vPosRot.xy
+ rotatedDeform.xy
+ rotatedDeform.zw
+ vVec.xy * t * vData.y // apply velocity

View File

@ -75,7 +75,7 @@ void tst_qquickcustomaffector::test_basic()
QCOMPARE(d->lifeSpan, 0.5f);
QCOMPARE(d->size, 100.f);
QCOMPARE(d->endSize, 100.f);
QCOMPARE(d->autoRotate, 1.f);
QCOMPARE(d->autoRotate, (uchar)1);
QCOMPARE(d->color.r, (uchar)0);
QCOMPARE(d->color.g, (uchar)255);
QCOMPARE(d->color.b, (uchar)0);

View File

@ -96,7 +96,7 @@ void tst_qquickimageparticle::test_basic()
QCOMPARE(d->yx, 0.0f);
QCOMPARE(d->rotation, 0.0f);
QCOMPARE(d->rotationVelocity, 0.0f);
QCOMPARE(d->autoRotate, 0.0f);
QCOMPARE(d->autoRotate, (uchar)0);
QCOMPARE(d->animX, 0.0f);
QCOMPARE(d->animY, 0.0f);
QCOMPARE(d->animWidth, 1.0f);
@ -140,7 +140,7 @@ void tst_qquickimageparticle::test_colored()
QCOMPARE(d->yx, 0.0f);
QCOMPARE(d->rotation, 0.0f);
QCOMPARE(d->rotationVelocity, 0.0f);
QCOMPARE(d->autoRotate, 0.0f);
QCOMPARE(d->autoRotate, (uchar)0);
QCOMPARE(d->animX, 0.0f);
QCOMPARE(d->animY, 0.0f);
QCOMPARE(d->animWidth, 1.0f);
@ -185,7 +185,7 @@ void tst_qquickimageparticle::test_colorVariance()
QCOMPARE(d->yx, 0.0f);
QCOMPARE(d->rotation, 0.0f);
QCOMPARE(d->rotationVelocity, 0.0f);
QCOMPARE(d->autoRotate, 0.0f);
QCOMPARE(d->autoRotate, (uchar)0);
QCOMPARE(d->animX, 0.0f);
QCOMPARE(d->animY, 0.0f);
QCOMPARE(d->animWidth, 1.0f);
@ -229,7 +229,7 @@ void tst_qquickimageparticle::test_deformed()
QCOMPARE(d->yx, 0.5f);
QCOMPARE(d->rotation, 90.0f * (float)CONV_FACTOR);
QCOMPARE(d->rotationVelocity, 90.0f * (float)CONV_FACTOR);
QCOMPARE(d->autoRotate, 1.0f);
QCOMPARE(d->autoRotate, (uchar)1);
QCOMPARE(d->animX, 0.0f);
QCOMPARE(d->animY, 0.0f);
QCOMPARE(d->animWidth, 1.0f);
@ -273,7 +273,7 @@ void tst_qquickimageparticle::test_tabled()
QCOMPARE(d->yx, 0.0f);
QCOMPARE(d->rotation, 0.0f);
QCOMPARE(d->rotationVelocity, 0.0f);
QCOMPARE(d->autoRotate, 0.0f);
QCOMPARE(d->autoRotate, (uchar)0);
QCOMPARE(d->animX, 0.0f);
QCOMPARE(d->animY, 0.0f);
QCOMPARE(d->animWidth, 1.0f);
@ -318,7 +318,7 @@ void tst_qquickimageparticle::test_sprite()
QCOMPARE(d->yx, 0.0f);
QCOMPARE(d->rotation, 0.0f);
QCOMPARE(d->rotationVelocity, 0.0f);
QCOMPARE(d->autoRotate, 0.0f);
QCOMPARE(d->autoRotate, (uchar)0);
QVERIFY(myFuzzyCompare(d->frameDuration, 120.f));
QCOMPARE(d->frameCount, 6.0f);
QVERIFY(d->animT > 0.0f);