4
\$\begingroup\$

Alright, I'm not quite sure what is going on with my code at the moment.

I'm currently getting around to defining behavior for my particle system, and to better do this I need to know how many particles are in the buffer on the CPU side. (The particles are held in a structured buffer GPU side)

So I'm using a staging buffer with CPU read access that gets the particle buffer's size using CopyStructureCount and then mapping the staging buffer and reading the count.

This works fine for the first 2 or 3 frames. The count I get from the staging buffer matches how many particles have been spawned. However, once the buffer hits about 400 particles or so all of a sudden my count from the staging buffer resets. I don't have my system killing any particles off at the moment so I know these values are incorrect. I also know there isn't anything wrong my particle system either. I can render, update, and spawn them no problem. (I just need the particle count to help me figure out how many I can spawn and optimize the rendering draw count a tiny bit.)

Here is how I read the staging buffer.

struct ParticleUpdatePass_ParticleCountBuffer {
    unsigned int particleCount;
};

// Yeah, I know. Lots of function calls. (Inlined though) I've got wrapper classes for all the D3D11 resources.
pDeviceManager->GetDeviceContext()->CopyStructureCount(particleCountReadBuffer.GetBuffer(), 0,
    _emitter.GetActiveStateBuffer()->GetUnorderedAccessView().GetUnorderedAccessView());
D3D11_MAPPED_SUBRESOURCE _subresource;
particleCountReadBuffer.Map(_subresource, 0); // Essentially translates to - pDeviceManager->GetDeviceContext()->Map(pBuffer, 0, D3D11_MAP_READ, &_subresource;);
ParticleUpdatePass_ParticleCountBuffer _countBuffer(*(ParticleUpdatePass_ParticleCountBuffer*)_subresource.pData);
particleCountReadBuffer.Unmap(0); // pDeviceManager->GetDeviceContext()->Unmap(pBuffer, 0);
_emitter.SetParticleCount(_countBuffer.particleCount);

So my question is essentially, what could I possibly be doing wrong?

Edit - I'm starting to think that the problem isn't in reading and copying the structure count but in my actual particle update code. I'm using two buffers each update. One contains the particle's initial state, and the other receives the updated particles and they swap. I actually started checking the count for both buffers and saw that the "empty" buffer is retaining a count. I don't see why the initial state buffer wouldn't be getting completely consumed though.

It may be slightly off topic but I'm going to post my update shader. Notice that it also relies on a structure count being copied to a constant buffer. Based on the implementation from this book

struct Particle {
    float3 position;
    float  time;
    float3 direction;
    float pad;
};

ConsumeStructuredBuffer<Particle> beforeState : register(u0);
AppendStructuredBuffer<Particle>  afterState : register(u1);


cbuffer SimulationParameters : register(b0) {
    float3 cameraSpaceDelta; // Used to update the particles with how much the camera has moved.
                             // Prevents particles from following the camera around as their space is transformed.
    float timeDelta,
          expirationTime,
          velocity;
};

cbuffer ParticleCount : register(b1) {
    uint particleCount; // Needs the structure count copied from the particle buffer.
};

[numthreads(512, 1, 1)]

void CS(uint3 DispatchThreadID : SV_DispatchThreadID) {
    uint _id = (DispatchThreadID.x)
               + ((DispatchThreadID.y) * 512)
               + ((DispatchThreadID.z) * 512 * 512);

    if (_id < particleCount) {
        Particle p = beforeState.Consume();

        p.time += timeDelta;
        //if (p.time < expirationTime) {
            // Particles are in camera space so they need to be moved with it.
            // Direction also probably needs transformed but that's irrevelevant for the moment.
            p.position -= cameraSpaceDelta;
            p.position += p.direction * timeDelta * velocity;
            afterState.Append(p);
        //}
    }
}

Edit 2 - Alright so now I've narrowed it down to my particle spawn shader. Not doing any buffer swapping or particle updating. (Just spawning to the same buffer frame after frame) The count is correct the first two frames but then it starts lagging behind. This makes absolutely no sense to me. My thoughts are that the hidden structure count isn't correctly updating (this is out of my control) or I'm just not reading the staging buffer correctly. (Don't think this is the issue either since it stays close)

Here is my particle spawn shader...

struct Particle {
    float3 position;
    float  time;
    float3 direction;
    float pad;
};

AppendStructuredBuffer<Particle> simulationState : register(u0);

cbuffer SimulationParameters : register(b0) {
    float3 emitterLocation,
           directionVector;
};

[numthreads(8, 1, 1)]

void CS(uint3 GroupThreadID : SV_GroupThreadID, uint3 DispatchThreadID : SV_DispatchThreadID) {
    Particle p;

    p.position = emitterLocation;
    p.direction = directionVector;
    p.time = 0.0f;
    p.pad = 0.0f;

    simulationState.Append(p);
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Alright, think I found the culprit! My count is behaving correctly now. Apparently a structured buffer's count doesn't get initialized upon declaring and creating it. It is initialized while binding that buffer to the pipeline. So the first time my buffer is bound to the pipeline, it needs to have 0 for the count parameter and every other time -1 to use the current count. I also have to be careful and bind my appended buffer with 0 (not -1) every frame since it is suppose to be empty prior to each update.

http://msdn.microsoft.com/en-us/library/ff476404(VS.85).aspx for the function details.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .