Use a uniform buffer for the light list

This commit is contained in:
Magnus Norddahl 2023-05-06 02:45:17 +02:00 committed by Christoph Oelckers
parent bc2105eab9
commit 795c0d90de
9 changed files with 46 additions and 45 deletions

View file

@ -36,23 +36,6 @@ struct FDynLightData
arrays[2].Clear();
}
void Combine(int *siz, int max)
{
siz[0] = arrays[0].Size();
siz[1] = siz[0] + arrays[1].Size();
siz[2] = siz[1] + arrays[2].Size();
arrays[0].Resize(arrays[0].Size() + arrays[1].Size() + arrays[2].Size());
memcpy(&arrays[0][siz[0]], &arrays[1][0], arrays[1].Size() * sizeof(float));
memcpy(&arrays[0][siz[1]], &arrays[2][0], arrays[2].Size() * sizeof(float));
siz[0]>>=2;
siz[1]>>=2;
siz[2]>>=2;
if (siz[0] > max) siz[0] = max;
if (siz[1] > max) siz[1] = max;
if (siz[2] > max) siz[2] = max;
}
};
extern thread_local FDynLightData lightdata;

View file

@ -54,16 +54,16 @@ void VkBufferManager::Init()
Viewpoint.Data = Viewpoint.UBO->Map(0, Viewpoint.UBO->size);
Lightbuffer.SSO = BufferBuilder()
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT)
Lightbuffer.UBO = BufferBuilder()
.Usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT)
.MemoryType(
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
.Size(Lightbuffer.Count * 4 * sizeof(FVector4))
.DebugName("Lightbuffer.SSO")
.DebugName("Lightbuffer.UBO")
.Create(fb->GetDevice());
Lightbuffer.Data = Lightbuffer.SSO->Map(0, Lightbuffer.SSO->size);
Lightbuffer.Data = Lightbuffer.UBO->Map(0, Lightbuffer.UBO->size);
Bonebuffer.SSO = BufferBuilder()
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT)
@ -89,9 +89,9 @@ void VkBufferManager::Deinit()
Viewpoint.UBO->Unmap();
Viewpoint.UBO.reset();
if (Lightbuffer.SSO)
Lightbuffer.SSO->Unmap();
Lightbuffer.SSO.reset();
if (Lightbuffer.UBO)
Lightbuffer.UBO->Unmap();
Lightbuffer.UBO.reset();
if (Bonebuffer.SSO)
Bonebuffer.SSO->Unmap();

View file

@ -40,7 +40,7 @@ public:
{
int UploadIndex = 0;
int Count = 80000;
std::unique_ptr<VulkanBuffer> SSO;
std::unique_ptr<VulkanBuffer> UBO;
void* Data = nullptr;
} Lightbuffer;

View file

@ -84,7 +84,7 @@ void VkDescriptorSetManager::UpdateHWBufferSet()
.AddBuffer(HWBufferSet.get(), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->GetBufferManager()->Viewpoint.UBO.get(), 0, sizeof(HWViewpointUniforms))
.AddBuffer(HWBufferSet.get(), 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->GetBufferManager()->MatrixBuffer->UBO.get(), 0, sizeof(MatricesUBO))
.AddBuffer(HWBufferSet.get(), 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->GetBufferManager()->StreamBuffer->UBO.get(), 0, sizeof(StreamUBO))
.AddBuffer(HWBufferSet.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->Lightbuffer.SSO.get())
.AddBuffer(HWBufferSet.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->GetBufferManager()->Lightbuffer.UBO.get(), 0, sizeof(LightBufferUBO))
.AddBuffer(HWBufferSet.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBufferManager()->Bonebuffer.SSO.get())
.Execute(fb->GetDevice());
}
@ -260,7 +260,7 @@ void VkDescriptorSetManager::CreateHWBufferSetLayout()
.AddBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
.AddBinding(1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
.AddBinding(2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
.AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
.AddBinding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT)
.AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT)
.DebugName("VkDescriptorSetManager.HWBufferSetLayout")
.Create(fb->GetDevice());
@ -288,8 +288,8 @@ void VkDescriptorSetManager::CreateFixedSetLayout()
void VkDescriptorSetManager::CreateHWBufferPool()
{
HWBufferDescriptorPool = DescriptorPoolBuilder()
.AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 3 * maxSets)
.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2 * maxSets)
.AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 4 * maxSets)
.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1 * maxSets)
.MaxSets(maxSets)
.DebugName("VkDescriptorSetManager.HWBufferDescriptorPool")
.Create(fb->GetDevice());

View file

@ -131,8 +131,9 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key)
std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *defines)
{
FString definesBlock;
definesBlock << defines << "\n";
definesBlock << "#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n";
definesBlock << defines;
definesBlock << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n";
definesBlock << "#define MAX_LIGHT_DATA " << std::to_string(MAX_LIGHT_DATA).c_str() << "\n";
#ifdef NPOT_EMULATION
definesBlock << "#define NPOT_EMULATION\n";
#endif
@ -166,6 +167,7 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername
if (fb->GetDevice()->SupportsExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME)) definesBlock << "\n#define SUPPORTS_RAYQUERY\n";
definesBlock << defines;
definesBlock << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n";
definesBlock << "#define MAX_LIGHT_DATA " << std::to_string(MAX_LIGHT_DATA).c_str() << "\n";
#ifdef NPOT_EMULATION
definesBlock << "#define NPOT_EMULATION\n";
#endif

View file

@ -33,6 +33,13 @@ struct StreamUBO
StreamData data[MAX_STREAM_DATA];
};
#define MAX_LIGHT_DATA ((int)(65536 / sizeof(FVector4)))
struct LightBufferUBO
{
FVector4 lights[MAX_LIGHT_DATA];
};
struct PushConstants
{
int uDataIndex; // streamdata index

View file

@ -406,7 +406,7 @@ void VkRenderState::ApplyStreamData()
void VkRenderState::ApplyPushConstants()
{
mPushConstants.uDataIndex = mStreamBufferWriter.DataIndex();
mPushConstants.uLightIndex = mLightIndex;
mPushConstants.uLightIndex = mLightIndex >= 0 ? (mLightIndex % MAX_LIGHT_DATA) : -1;
mPushConstants.uBoneIndexBase = mBoneIndexBase;
auto passManager = fb->GetRenderPassManager();
@ -468,18 +468,20 @@ void VkRenderState::ApplyHWBufferSet()
{
uint32_t matrixOffset = mMatrixBufferWriter.Offset();
uint32_t streamDataOffset = mStreamBufferWriter.StreamDataOffset();
if (mViewpointOffset != mLastViewpointOffset || matrixOffset != mLastMatricesOffset || streamDataOffset != mLastStreamDataOffset)
uint32_t lightsOffset = mLightIndex >= 0 ? (uint32_t)(mLightIndex / MAX_LIGHT_DATA) * sizeof(FVector4) : mLastLightsOffset;
if (mViewpointOffset != mLastViewpointOffset || matrixOffset != mLastMatricesOffset || streamDataOffset != mLastStreamDataOffset || lightsOffset != mLastLightsOffset)
{
auto passManager = fb->GetRenderPassManager();
auto descriptors = fb->GetDescriptorSetManager();
uint32_t offsets[3] = { mViewpointOffset, matrixOffset, streamDataOffset };
uint32_t offsets[4] = { mViewpointOffset, matrixOffset, streamDataOffset, lightsOffset };
mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 0, fb->GetDescriptorSetManager()->GetFixedDescriptorSet());
mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 1, descriptors->GetHWBufferDescriptorSet(), 3, offsets);
mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passManager->GetPipelineLayout(mPipelineKey.NumTextureLayers), 1, descriptors->GetHWBufferDescriptorSet(), 4, offsets);
mLastViewpointOffset = mViewpointOffset;
mLastMatricesOffset = matrixOffset;
mLastStreamDataOffset = streamDataOffset;
mLastLightsOffset = lightsOffset;
}
}
@ -536,9 +538,10 @@ int VkRenderState::UploadLights(const FDynLightData& data)
int size2 = data.arrays[2].Size() / 4;
int totalsize = size0 + size1 + size2 + 1;
if (totalsize > buffers->Lightbuffer.Count)
// Clamp lights so they aren't bigger than what fits into a single dynamic uniform buffer page
if (totalsize > MAX_LIGHT_DATA)
{
int diff = totalsize - buffers->Lightbuffer.Count;
int diff = totalsize - MAX_LIGHT_DATA;
size2 -= diff;
if (size2 < 0)
@ -554,17 +557,22 @@ int VkRenderState::UploadLights(const FDynLightData& data)
totalsize = size0 + size1 + size2 + 1;
}
if (totalsize <= 1) return -1; // there are no lights
// Check if we still have any lights
if (totalsize <= 1)
return -1;
// Make sure the light list doesn't cross a page boundary
if (buffers->Lightbuffer.UploadIndex % MAX_LIGHT_DATA + totalsize > MAX_LIGHT_DATA)
buffers->Lightbuffer.UploadIndex = buffers->Lightbuffer.UploadIndex / MAX_LIGHT_DATA * MAX_LIGHT_DATA + 1;
int thisindex = buffers->Lightbuffer.UploadIndex;
buffers->Lightbuffer.UploadIndex += totalsize;
float parmcnt[] = { 0, float(size0), float(size0 + size1), float(size0 + size1 + size2) };
if (thisindex + totalsize <= buffers->Lightbuffer.Count)
{
float* copyptr = (float*)buffers->Lightbuffer.Data + thisindex * 4;
buffers->Lightbuffer.UploadIndex += totalsize;
float parmcnt[] = { 0, float(size0), float(size0 + size1), float(size0 + size1 + size2) };
float* copyptr = (float*)buffers->Lightbuffer.Data + thisindex * 4;
memcpy(&copyptr[0], parmcnt, sizeof(FVector4));
memcpy(&copyptr[4], &data.arrays[0][0], size0 * sizeof(FVector4));
memcpy(&copyptr[4 + 4 * size0], &data.arrays[1][0], size1 * sizeof(FVector4));

View file

@ -103,6 +103,7 @@ protected:
uint32_t mLastViewpointOffset = 0xffffffff;
uint32_t mLastMatricesOffset = 0xffffffff;
uint32_t mLastStreamDataOffset = 0xffffffff;
uint32_t mLastLightsOffset = 0;
uint32_t mViewpointOffset = 0;
VkStreamBufferWriter mStreamBufferWriter;

View file

@ -108,9 +108,9 @@ layout(set = 1, binding = 2, std140) uniform StreamUBO
};
// light buffers
layout(set = 1, binding = 3, std430) buffer LightBufferSSO
layout(set = 1, binding = 3, std140) uniform LightBufferUBO
{
vec4 lights[];
vec4 lights[MAX_LIGHT_DATA];
};
// bone matrix buffers