Particles Engine and Slow FPS

Started by
41 comments, last by Medo Mex 11 years, 2 months ago

When things start getting slow are the particles quite large and/or taking up a significant portion of the screen? If so, then it's just simply overdraw and is expected behaviour.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Advertisement

@mhagain: Not large at all, just a small smoke from bullet impact, when I draw some smoke on different bullet hits infront of the screen, I see well noticed slow rendering.

This means that whenever the player is shooting, the rendering will slow down due to smoke particles.

[quote name='Medo3337' timestamp='1358314169' post='5022064']
This means that whenever the player is shooting, the rendering will slow down due to smoke particles.
[/quote]

Is the rendering slowing down only the moment the player shoots or is it slow as long as the particles are visible?

Possibly the way you allocate new particles is slow.

Are you recreating the dynamic vertex buffer every frame? That's likely to cause slowness.

[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler

I am doing the following every frame:


device->CreateVertexBuffer(particles.size() * sizeof(PARTICLE_VERTEX),
                           D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY|D3DUSAGE_POINTS,
                           CustomFVF,
                           D3DPOOL_DEFAULT,
                           &vbuffer,
                           NULL);

That could be slowing rendering, but I need to update the buffer length every frame since the number of particles will not stay the same.

Yep, I think we've found our culprit. MSDN (and your DXSDK) have an article on the proper way to do this; see: http://msdn.microsoft.com/en-us/library/windows/desktop/bb147263%28v=vs.85%29.aspx#Using_Dynamic_Vertex_and_Index_Buffers

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

I am now using CreateVertexBuffer() once and doing Lock() and Unlock() on the vertex buffer every frame, still have performance issue.

Use 2 vertex buffers and switch between them each frame.

Make sure you implement it so that you can expand it to 3 vertex buffers in the future, or 4, or N.

In other words, make it an array and use a macro or enum to determine the size of the array.

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Created 2 vertex buffers:


#define maxVBuffer 2

for (int i = 0; i < maxVBuffer; i++)
{
device->CreateVertexBuffer(10000 * sizeof(PARTICLE_VERTEX),
  D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY|D3DUSAGE_POINTS,
  CustomFVF,
  D3DPOOL_DEFAULT,
  &vbuffer[i],
  NULL);
}

And switched between them every frame, I even tried to use more than 2 buffers and switch between them every frame.

Still having the same performance problem.

Here's one example of a way of doing this that I coded up (but didn't test/etc), fairly rough and ready but it should illustrate the way things are done. PLEASE don't just copy & paste this code; use it as a way of understanding how dynamic vertex buffers should be handled instead, read the link I posted earlier and see how what's done here matches with what's described there.


class CDynamicVertexBuffer
{
public:
    CDynamicVertexBuffer (IDirect3DDevice9 *device, int maxitems, int itemsize) :
        Buffer (NULL),
        MaxItems (maxitems),
        ItemSize (itemsize)
    {
        assert (device != NULL);
        assert (maxitems > 0);
        assert (itemsize > 0);

        // AddRef the device because this needs to hold a reference to it
        this->Device = device;
        device->AddRef ();

        this->OnResetDevice ();
    }

    ~CDynamicVertexBuffer (void)
    {
        this->OnLostDevice ();

        if (this->Device)
        {
            this->Device->Release ();
            this->Device = NULL;
        }
    }

    void OnLostDevice (void)
    {
        if (this->Buffer)
        {
            this->Buffer->Release ();
            this->Buffer = NULL;
        }
    }

    void OnResetDevice (void)
    {
        assert (this->Buffer == NULL);
        assert (this->Device != NULL);

        HRESULT hr = E_FAIL;

        hr = this->Device->CreateVertexBuffer (
            this->ItemSize * this->MaxItems,
            D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC,
            0,    // FVF is only used if we're calling ProcessVertices, which we're not, so we don't set it
            D3DPOOL_DEFAULT,
            &this->Buffer,
            NULL
        );

        assert (SUCCEEDED (hr));

        this->CurrItem = 0;
    }

    void AddItems (const void *itemdata, int numitems)
    {
        assert (itemdata != NULL);
        assert (numitems > 0);
        assert (this->Buffer != NULL);

        // by default we're just appending to the buffer
        DWORD locktype = D3DLOCK_NOOVERWRITE | D3DLOCK_NOSYSLOCK;
        void *lockdata = NULL;
        HRESULT hr = E_FAIL;

        // check will these items overflow the buffer; if so flush it and rewind
        if (this->CurrItem + numitems >= this->MaxItems)
        {
            this->Draw ();
            this->CurrItem = 0;
            locktype = D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK;
        }

        hr = this->Buffer->Lock (
            this->CurrItem * this->ItemSize,
            numitems * this->ItemSize,
            (void **) &lockdata,
            locktype
        );

        assert (SUCCEEDED (hr));
        assert (SUCCEEDED (lockdata != NULL));

        memcpy (lockdata, itemdata, numitems * this->ItemSize);

        hr = this->Buffer->Unlock ();
        assert (SUCCEEDED (hr));

        // you may wish to draw here or you may not; up to you

        // advance the pointer
        this->CurrItem += numitems;
    }

    void Draw (void)
    {
        // fill this in yourself
    }

private:
    IDirect3DDevice9 *Device;
    IDirect3DVertexBuffer9 *Buffer;

    int CurrItem;
    int MaxItems;
    int ItemSize;
};

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

This topic is closed to new replies.

Advertisement