2
\$\begingroup\$

I'm new in DirectX and I'm making a 2D game. I want to use a particle system to simulate a 3D starfield, so each star has to set its own constant buffer for the vertexshader es. to set it's world matrix. So if i have 500 stars (that move every frame) i need to call 500 times VSsetconstantbuffer, and map/unmap each buffer. with 500 stars i have an average of 220 fps and that's quite good. My bottelneck is Vs/PsSetconstantbuffer. If i dont call this function i have 400 fps(obliviously nothing is display, since i dont set the position of the stars). So is there a method to speed up the render of the particle system??

Ps. I'm using intel integrate graphic (hd 2000-3000). with a nvidia (or amd) gpu will i have the same bottleneck?? If, for example, i dont call setshaderresource i have 10-20 fps more (for 500 objcets), that is not 180.Why does SetConstantBuffer take so long??

LPVOID VSdataPtr = VSmappedResource.pData;
memcpy(VSdataPtr, VSdata, CszVSdata);
context->Unmap(VertexBuffer, 0);

result = context->Map(PixelBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &PSmappedResource);
if (FAILED(result))
{
    outputResult.OutputErrorMessage(TITLE, L"Cannot map the PixelBuffer", &result, OUTPUT_ERROR_FILE);
    return;
}
LPVOID PSdataPtr = PSmappedResource.pData;
memcpy(PSdataPtr, PSdata, CszPSdata);
context->Unmap(PixelBuffer, 0);

context->VSSetConstantBuffers(0, 1, &VertexBuffer);
context->PSSetConstantBuffers(0, 1, &PixelBuffer);

this update and set the buffer. It's part of the render method of a sprite class that contains a the vertex buffer and the texture to apply to the quads(it's a 2d game) too. I have an array of 500 stars (sprite setup with a star texture). Every frame: clear back buffer; draw the array of stars; present the backbuffer;

draw also call the function update( which calculate the position of the sprite on screen based on a "camera class")

Ok, create a vertex buffer with the vertices of each quads(stars) seems to be good, since the stars don't change their "virtual" position; so.... In a particle system (where particles move) it's better to have all the object in only one vertices array, rather then an array of different sprite/object in order to update all the vertices' position with a single setbuffer call. In this case i have to use a dynamic vertex buffer with the vertices positions like this:

verticesForQuad={{ XMFLOAT3((float)halfDImensions.x-1+pos.x, (float)halfDImensions.y-1+pos.y, 1.0f), XMFLOAT2(1.0f, 0.0f) },
    { XMFLOAT3((float)halfDImensions.x-1+pos.x, -(float)halfDImensions.y-1+pos.y, 1.0f), XMFLOAT2(1.0f, 1.0f) },
    { XMFLOAT3(-(float)halfDImensions.x-1+pos.x, (float)halfDImensions.y-1.pos.y, 1.0f), XMFLOAT2(0.0f, 0.0f) },
    { XMFLOAT3(-(float)halfDImensions.x-1.pos.x, -(float)halfDImensions.y-1+pos.y, 1.0f), XMFLOAT2(0.0f, 1.0f) },

....other quads}

where halfDimensions is the halfsize in pixel of a texture and pos the virtual position of a star. than create an array of verticesForQuad and create the vertex buffer

ZeroMemory(&vertexDesc, sizeof(vertexDesc));
vertexDesc.Usage =      D3D11_USAGE_DEFAULT;
vertexDesc.BindFlags =  D3D11_BIND_VERTEX_BUFFER;
vertexDesc.ByteWidth =  sizeof(VertexType)* 4*numStars;

ZeroMemory(&resourceData, sizeof(resourceData));
resourceData.pSysMem =  verticesForQuad;

result = device->CreateBuffer(&vertexDesc, &resourceData, &CvertexBuffer);

and call each frame Context->IASetVertexBuffers(0, 1, &CvertexBuffer, &stride, &offset);

But if i want to add and remove obj i have to recreate the buffer each time, havent i?? There is a faster way? I think i can create a vertex buffer with a max size (es. 10000 objs) and when i update it set only the 250 position (for 250 onjs for example) and pass this number as the vertexCount to the draw function (numObjs*4), or i'm worng

\$\endgroup\$
7
  • 1
    \$\begingroup\$ It is a very bad idea to update a constant buffer for every particle. You should have each particle's attributes in the vertex buffer and updating the whole thing once each frame. Then the constant buffer would contain camera matrices and be updated once each frame. \$\endgroup\$ May 5, 2014 at 7:54
  • \$\begingroup\$ Ok,i can do this but: -I need to create a shader that has an array of positions with a maximum planned capacity, so i can't add infinite particles.-if i set a matrix composed by 16 positions, how can the 6th star, for example, know that it has to read the sixth position?? \$\endgroup\$
    – Liuka
    May 5, 2014 at 8:33
  • 1
    \$\begingroup\$ No you are wrong, you need to do a draw call for all of your particles at once for the whole vertex buffer. No need for any arrays in the shader at all. The vertex shader will run through all your vertices (particles). \$\endgroup\$ May 5, 2014 at 8:55
  • \$\begingroup\$ so a single vertex buffer that contains the vertex of all the particles' quads, set the primitive topology as triangle list and call contex->draw(4*numparticles) once ?? -because i don't update the vertex buffers, since they don't contain the world coordinates(i obtain them multiply it by a world matrix), but only the texture size and coordinates; and i have to change a lot of my code. \$\endgroup\$
    – Liuka
    May 5, 2014 at 10:14
  • 1
    \$\begingroup\$ Yes you should use a dynamic vertex buffer which you update. You store the positions for a single vertex anyway. If you want to billboard them you can also rotate them in the vertex shader based on your view matrix. \$\endgroup\$ May 5, 2014 at 12:43

1 Answer 1

1
\$\begingroup\$

This is a question of how the performance goes on different cards. I would assume that setting and remapping the constant buffer is a big performance hit for you since it usually always is. But you can never be 100% sure with out proper profiling.

Why It takes so long is because it´s sending data from the cpu to the gpu. this generally takes a few cycles to do. To optimize this is to create a smart way of using your constant buffers. Usually sort your drawcalls so that you have to do as little update between the calls as possible. that is, for every particle that will have the same color, sort then and only update that value when you can.

unfortunately with out more information about how your renderer works it´s super hard to say how to either organize or structure your shader programs. If you would supply more code it would be much easier.

\$\endgroup\$
1
  • \$\begingroup\$ Yes, i know i can call SetConstantBuffer only if the buffer change, the problem is that position change every frame. I will post the code \$\endgroup\$
    – Liuka
    May 5, 2014 at 7:50

You must log in to answer this question.

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