Forward+ Rendering - best way to updating light buffer ?

Started by
2 comments, last by Krypt0n 9 years, 6 months ago

I've got a prototype implementation of it working with point lights at the moment based on the most recent AMD SDK sample. Problem is their implementation uses a statically allocated array of XMFLOAT4 light data containing Position(Center) and Radius that they use to create an ID3D11Buffer once.

Now of course I want to be able to instantiate point lights in my scene on a button press (also being able to remove them again) so I was wondering what you guys think the best approach to creating/updating this buffer during runtime would be ? I guess what I should do here is have some kind of dirty flag that is set when instantiating/removing or changing a light's position/radius, right ? But I still don't really know how to update the ID3D11Buffer...I would guess releasing/recreating it would not be a good idea (which is what I'm doing right now in my prototype only when a light is added).

But even then wouldn't that be expansive to update the entire buffer if one or several lights just changed position (even more so what if they keep moving all the time I would have to update it all the time).

Advertisement

I would guess releasing/recreating it would not be a good idea

You guessed right!

Simply create a ID3D11Buffer with D3D11_USAGE_DYNAMIC flag , large enough to hold the data of the maximum number of lights you'll need (512, 1024, 2048?), and update it using MAP_DISCARD every frame (or using a dirty flag when the lights change).

And pass the number of active lights in a cbuffer to the shader.

Since you're probably updating the light buffer once per frame this shouldn't be a bottleneck.

If you really need a more dynamic max number of lights try to reduce the number of times you release/create a buffer by doubling/halving it's size every time you resize it or something like that.

Ah so I can just basically do the same as with constant buffers ! smile.png

Having some issues copying the data due to heap corruption but that might be related to something else.

Is this the correct way of doing it ?

Update: yep that heap corruption was something else. Seems to be working now smile.png


if (!pointLights_center_and_radius.empty())
{
	this->numActiveLights = static_cast<unsigned int>(pointLights_center_and_radius.size());
	D3D11_MAPPED_SUBRESOURCE pointLightResource = {};
	if (SUCCEEDED(this->context->Map(this->pointLightBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &pointLightResource)))
	{
		DirectX::XMFLOAT4 *pData = (DirectX::XMFLOAT4*)pointLightResource.pData;
		memcpy(pData, &pointLights_center_and_radius[0], sizeof(DirectX::XMFLOAT4) * numActiveLights);
		this->context->Unmap(this->pointLightBuffer, 0);
	}
}

But even then wouldn't that be expansive to update the entire buffer if one or several lights just changed position (even more so what if they keep moving all the time I would have to update it all the time).

how big is the light constant buffer, 16kb? that's not problematic compared to all the other data you probably upload.

for very dynamic resources, it's best to use a staging buffer pool and over-allocate your rendering resources. thus you'd allocate 16kb of light constantbuffer even for just 1 lightsource, but update it by updating a small staging buffer and copy it to the big constant buffer.

usually you don't have access directly to VMem, what happens is that resources are mirrored in memory, if you update those, the driver copies them to VMEM. if you use a staging texture, you basically emulate that, paying with some cpu cost (as you need to invoke copysubresource) and getting paid back with some gpu/pcie reward.

This topic is closed to new replies.

Advertisement