diff --git a/src/common/rendering/hwrenderer/data/hw_dynlightdata.h b/src/common/rendering/hwrenderer/data/hw_dynlightdata.h index 7da1c1b5a..41c0c7284 100644 --- a/src/common/rendering/hwrenderer/data/hw_dynlightdata.h +++ b/src/common/rendering/hwrenderer/data/hw_dynlightdata.h @@ -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; diff --git a/src/common/rendering/vulkan/buffers/vk_buffer.cpp b/src/common/rendering/vulkan/buffers/vk_buffer.cpp index 6edafcbfe..d2422e7e9 100644 --- a/src/common/rendering/vulkan/buffers/vk_buffer.cpp +++ b/src/common/rendering/vulkan/buffers/vk_buffer.cpp @@ -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(); diff --git a/src/common/rendering/vulkan/buffers/vk_buffer.h b/src/common/rendering/vulkan/buffers/vk_buffer.h index e3d977218..b6476d818 100644 --- a/src/common/rendering/vulkan/buffers/vk_buffer.h +++ b/src/common/rendering/vulkan/buffers/vk_buffer.h @@ -40,7 +40,7 @@ public: { int UploadIndex = 0; int Count = 80000; - std::unique_ptr SSO; + std::unique_ptr UBO; void* Data = nullptr; } Lightbuffer; diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp index 60a876498..d04a53b10 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp @@ -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()); diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 94a986a61..52f680381 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -130,8 +130,9 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key) std::unique_ptr 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 @@ -165,6 +166,7 @@ std::unique_ptr 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 diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index 1a0dc4ee6..84b52e053 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -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 diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index d4df0a74d..450ea2087 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -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(©ptr[0], parmcnt, sizeof(FVector4)); memcpy(©ptr[4], &data.arrays[0][0], size0 * sizeof(FVector4)); memcpy(©ptr[4 + 4 * size0], &data.arrays[1][0], size1 * sizeof(FVector4)); diff --git a/src/common/rendering/vulkan/vk_renderstate.h b/src/common/rendering/vulkan/vk_renderstate.h index 6189d8556..5214d1963 100644 --- a/src/common/rendering/vulkan/vk_renderstate.h +++ b/src/common/rendering/vulkan/vk_renderstate.h @@ -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; diff --git a/wadsrc/static/shaders/scene/layout_shared.glsl b/wadsrc/static/shaders/scene/layout_shared.glsl index 745b259a0..7f30d3ae2 100644 --- a/wadsrc/static/shaders/scene/layout_shared.glsl +++ b/wadsrc/static/shaders/scene/layout_shared.glsl @@ -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