假设一个场景最多可以有 1024 个点光源。通常情况下会更少,但最坏的情况是 1024。它们将在一段时间内或在某个操作之后动态添加和删除。
1024 * sizeof(PointLight)分配一个 size 的统一缓冲区,在开头映射缓冲区并对其进行池化是否有意义?或者更好的想法是创建一个 CPU 侧池,然后使用glNamedBufferSubData每一帧将 CPU 侧数据提交到缓冲区?
像这样的事情非常简单,没有考虑统一的缓冲区对齐,因为它与问题无关。
template<typename T, size_t MAX_SIZE>
struct GPUPool
{
GPUPool()
{
glCreateBuffers(1, &ubo);
glNamedBufferStorage(ubo, MAX_SIZE * sizeof(T), nullptr, GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT);
memory = (T*)glMapNamedBufferRange(ubo, 0, MAX_SIZE * sizeof(T), GL_MAP_WRITE_BIT | GL_MAP_COHERENT_BIT | GL_MAP_PERSISTENT_BIT);
}
~GPUPool()
{
glDeleteBuffers(1, &ubo);
}
[[nodiscard]] inline uint32_t insert(const T& element)
{
if (!freeIndexes.empty()) {
auto index = freeIndexes.back();
freeIndexes.pop_back();
memcpy(add(memory, index), &element, sizeof(element));
++size;
return index;
}
memcpy(add(memory, backIndex), &element, sizeof(element));
auto ret = backIndex;
backIndex += sizeof(element);
++size;
return ret;
}
void Bind(uint32_t bindingIndex)
{
glBindBuffer(GL_UNIFORM_BUFFER, bindingIndex);
}
void erase(size_t index)
{
freeIndexes.push_back(index);
--size;
}
GLuint ubo = 0;
T* memory = nullptr;
std::vector<size_t> freeIndexes;
uint32_t backIndex = 0;
size_t size = 0;
};
Run Code Online (Sandbox Code Playgroud)
用法:
struct PointLight
{
vec3 position;
vec3 color;
float fallof;
float radius;
};
GPUPool<PointLight, 1024> pointLightPool;
std::vector<uint32_t> lightIndexes;
while(true)
{
if(Something_Happend_And_Lights_Are_Added()) {
for(uint32_t i = 0; i < 10; ++i)
lightIndexes.emplace_back() = pointLightPool.insert(someLight);
}
if(Something_Happend_And_Light_2_And_5_Are_Deleted()) {
//when lights get deleted, lightIndexes should also be updated, but let's leave it
//for simplicity
pointLightPool.erase(lightIndexes[1]);
pointLightPool.erase(lightIndexes[4]);
}
if(Something_Happend_And_More_Lights_Are_Added()) {
//light pool will place a new light into the old memory spot.
lightIndexes.emplace_back() = pointLightPool.insert(someLight);
}
pointLightPool.Bind(0);
//draw scene...
}
Run Code Online (Sandbox Code Playgroud)