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.
Particles Engine and Slow FPS
@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.
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
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
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;
};