From 76536be8041c7c904ad6e9032b25149dcb45635f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 16 Sep 2024 18:06:21 +0200 Subject: [PATCH] Use the dynamic lights from the level mesh in the light tiles shader --- .../hwrenderer/data/hw_levelmesh.cpp | 2 +- .../descriptorsets/vk_descriptorset.cpp | 2 +- .../rendering/vulkan/shaders/vk_shader.h | 4 - .../rendering/vulkan/vk_renderstate.cpp | 4 - src/rendering/hwrenderer/doom_levelmesh.cpp | 53 +++++++++++- src/rendering/hwrenderer/doom_levelmesh.h | 3 + .../static/shaders/scene/comp_lighttiles.glsl | 81 ++++++++++++------- 7 files changed, 107 insertions(+), 42 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp index 85c6880d6..62c9203ab 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.cpp @@ -33,7 +33,7 @@ void LevelMesh::Reset(const LevelMeshLimits& limits) Mesh.Lights.Resize(16); Mesh.LightIndexes.Resize(16); - Mesh.DynLights.Resize(16); + Mesh.DynLights.Resize(50'000 * 4); Mesh.Indexes.Resize(limits.MaxIndexes); Mesh.SurfaceIndexes.Resize(limits.MaxIndexes / 3 + 1); diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp index 711fea0a0..aa63ac417 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp @@ -111,7 +111,7 @@ void VkDescriptorSetManager::UpdateLightTilesSet() { WriteDescriptors() .AddStorageImage(LightTiles.Set.get(), 0, fb->GetBuffers()->SceneZMinMax[5].View.get(), VK_IMAGE_LAYOUT_GENERAL) - .AddBuffer(LightTiles.Set.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetUniformsBuffer()) + .AddBuffer(LightTiles.Set.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetDynLightBuffer()) .AddBuffer(LightTiles.Set.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBuffers()->SceneLightTiles.get()) .Execute(fb->GetDevice()); } diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index ba46c50e6..6ad43464c 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -63,10 +63,6 @@ struct ZMinMaxPushConstants struct LightTilesPushConstants { - int additiveCount; - int modulatedCount; - int subtractiveCount; - int padding0; FVector2 posToViewA; FVector2 posToViewB; FVector2 viewportPos; diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index ee26209e8..f55bdb0f0 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -968,10 +968,6 @@ void VkRenderState::DispatchLightTiles(const VSMatrix& worldToView, float m5) float invFocalLenY = tanHalfFovy; LightTilesPushConstants pushConstants = {}; - //auto mesh = fb->GetLevelMesh()->GetMesh(); - //pushConstants.normalLightCount = mesh->Mesh.NormalLightCount; - //pushConstants.modulatedLightCount = mesh->Mesh.ModulatedLightCount; - //pushConstants.subtractiveLightCount = mesh->Mesh.SubtractiveLightCount; pushConstants.posToViewA = { 2.0f * invFocalLenX / sceneWidth, 2.0f * invFocalLenY / sceneHeight }; pushConstants.posToViewB = { -invFocalLenX, -invFocalLenY }; pushConstants.viewportPos = { 0.0f, 0.0f }; diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index bc3097fae..67a36829a 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -9,6 +9,7 @@ #include "a_dynlight.h" #include "hw_renderstate.h" #include "hw_vertexbuilder.h" +#include "hw_dynlightdata.h" #include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_walldispatcher.h" @@ -65,7 +66,7 @@ ADD_STAT(levelmesh) auto& stats = level.levelMesh->LastFrameStats; FString out; if (level.levelMesh) - out.Format("Sides=%d, flats=%d, portals=%d", stats.SidesUpdated, stats.FlatsUpdated, stats.Portals); + out.Format("Sides=%d, flats=%d, portals=%d, dynlights=%d", stats.SidesUpdated, stats.FlatsUpdated, stats.Portals, stats.DynLights); else out = "No level mesh"; return out; @@ -253,6 +254,56 @@ void DoomLevelMesh::BeginFrame(FLevelLocals& doomMap) CreateLights(doomMap); UpdateWallPortals(); + + UploadDynLights(doomMap); +} + +void DoomLevelMesh::UploadDynLights(FLevelLocals& doomMap) +{ + lightdata.Clear(); + for (auto light = doomMap.lights; light; light = light->next) + { + int portalGroup = 0; // What value should this have? + AddLightToList(lightdata, portalGroup, light, false); + CurFrameStats.DynLights++; + } + + // All meaasurements here are in vec4's. + int size0 = lightdata.arrays[0].Size() / 4; + int size1 = lightdata.arrays[1].Size() / 4; + int size2 = lightdata.arrays[2].Size() / 4; + int totalsize = size0 + size1 + size2 + 1; + int maxLightData = Mesh.DynLights.Size(); + + // Clamp lights so they aren't bigger than what fits into a single dynamic uniform buffer page + if (totalsize > maxLightData) + { + int diff = totalsize - maxLightData; + + size2 -= diff; + if (size2 < 0) + { + size1 += size2; + size2 = 0; + } + if (size1 < 0) + { + size0 += size1; + size1 = 0; + } + totalsize = size0 + size1 + size2 + 1; + } + size0 = std::min(size0, maxLightData - 1); + + float parmcnt[] = { 0, float(size0), float(size0 + size1), float(size0 + size1 + size2) }; + + float* copyptr = (float*)Mesh.DynLights.Data(); + memcpy(©ptr[0], parmcnt, sizeof(FVector4)); + memcpy(©ptr[4], &lightdata.arrays[0][0], size0 * sizeof(FVector4)); + memcpy(©ptr[4 + 4 * size0], &lightdata.arrays[1][0], size1 * sizeof(FVector4)); + memcpy(©ptr[4 + 4 * (size0 + size1)], &lightdata.arrays[2][0], size2 * sizeof(FVector4)); + + AddRange(UploadRanges.DynLight, { 0, totalsize }); } void DoomLevelMesh::UpdateWallPortals() diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 3f6263d9d..4aeb89331 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -127,6 +127,7 @@ public: int FlatsUpdated = 0; int SidesUpdated = 0; int Portals = 0; + int DynLights = 0; }; Stats LastFrameStats, CurFrameStats; @@ -170,6 +171,8 @@ private: void RemoveFromDrawList(const TArray& drawRanges); void SortDrawLists(); + void UploadDynLights(FLevelLocals& doomMap); + TArray DoomSurfaceInfos; TArray Sides; diff --git a/wadsrc/static/shaders/scene/comp_lighttiles.glsl b/wadsrc/static/shaders/scene/comp_lighttiles.glsl index 18734e47c..a6ded965c 100644 --- a/wadsrc/static/shaders/scene/comp_lighttiles.glsl +++ b/wadsrc/static/shaders/scene/comp_lighttiles.glsl @@ -17,10 +17,6 @@ layout(set = 0, binding = 2) buffer Tiles layout(push_constant) uniform LightTilesPushConstants { - int additiveCount; - int modulatedCount; - int subtractiveCount; - int padding0; vec2 posToViewA; vec2 posToViewB; vec2 viewportPos; @@ -53,38 +49,61 @@ void main() const int maxLights = 16; const int lightSize = 4; int tileOffset = (tilePos.x + tilePos.y * zminmaxSize.x) * (1 + maxLights * lightSize); - int outLightOffset = tileOffset + 1; - int tileAdditiveCount = 0; - int tileModulatedCount = 0; - int tileSubtractiveCount = 0; + ivec4 inRanges = ivec4(lights[0]) + ivec4(1); + ivec4 outRanges = ivec4(0); - vec4 testLight = vec4(-316.0, 64.0, 621.0, 200.0); - - if (isLightVisible(tile, (worldToView * vec4(testLight.xyz, 1.0)).xyz, testLight.w)) + int count = 0; + int offset = tileOffset + 1; + for (int i = inRanges.x; i < inRanges.y; i += 4) { - vec3 pos = testLight.xyz; - float radius = testLight.w; - vec3 color = vec3(1.0, 1.0, 1.0); - float shadowIndex = -1025.0; - vec3 spotDir = vec3(0.0); - float lightType = 0.0; - float spotInnerAngle = 0.0; - float spotOuterAngle = 0.0; - float softShadowRadius = 0.0; - - tileAdditiveCount++; - tiles[outLightOffset++] = vec4(pos, radius); - tiles[outLightOffset++] = vec4(color, shadowIndex); - tiles[outLightOffset++] = vec4(spotDir, lightType); - tiles[outLightOffset++] = vec4(spotInnerAngle, spotOuterAngle, softShadowRadius, 0.0); + vec4 inLight = lights[i]; + vec3 pos = (worldToView * vec4(inLight.xyz, 1.0)).xyz; + float radius = inLight.w; + if (isLightVisible(tile, pos, radius)) + { + tiles[offset++] = inLight; + tiles[offset++] = lights[i + 1]; + tiles[offset++] = lights[i + 2]; + tiles[offset++] = lights[i + 3]; + count += 4; + } } + outRanges.y = count; - tiles[tileOffset] = vec4(ivec4( - 0, - tileAdditiveCount, - tileAdditiveCount + tileModulatedCount, - tileAdditiveCount + tileModulatedCount + tileSubtractiveCount)); + for (int i = inRanges.y; i < inRanges.z; i += 4) + { + vec4 inLight = lights[i]; + vec3 pos = (worldToView * vec4(inLight.xyz, 1.0)).xyz; + float radius = inLight.w; + if (isLightVisible(tile, pos, radius)) + { + tiles[offset++] = inLight; + tiles[offset++] = lights[i + 1]; + tiles[offset++] = lights[i + 2]; + tiles[offset++] = lights[i + 3]; + count += 4; + } + } + outRanges.z = count; + + for (int i = inRanges.z; i < inRanges.w; i += 4) + { + vec4 inLight = lights[i]; + vec3 pos = (worldToView * vec4(inLight.xyz, 1.0)).xyz; + float radius = inLight.w; + if (isLightVisible(tile, pos, radius)) + { + tiles[offset++] = inLight; + tiles[offset++] = lights[i + 1]; + tiles[offset++] = lights[i + 2]; + tiles[offset++] = lights[i + 3]; + count += 4; + } + } + outRanges.w = count; + + tiles[tileOffset] = vec4(outRanges); } bool isLightVisible(Tile tile, vec3 lightPos, float lightRadius)