From b163901862f11b6ea61dbd7cc1b9878740a0ecac Mon Sep 17 00:00:00 2001 From: RaveYard <29225776+MrRaveYard@users.noreply.github.com> Date: Thu, 7 Sep 2023 23:27:20 +0200 Subject: [PATCH] WIP partial lightmapping --- .../rendering/hwrenderer/data/hw_levelmesh.h | 2 ++ .../hwrenderer/data/hw_renderstate.h | 18 +++++++++++++ src/common/rendering/v_video.h | 1 + .../vulkan/accelstructs/vk_lightmap.cpp | 26 ++++++++++++++++--- .../vulkan/accelstructs/vk_lightmap.h | 2 +- .../rendering/vulkan/vk_renderdevice.cpp | 22 ++++++++++++++-- src/common/rendering/vulkan/vk_renderdevice.h | 1 + src/rendering/hwrenderer/doom_levelmesh.cpp | 12 +++++++++ src/rendering/hwrenderer/hw_entrypoint.cpp | 3 +++ src/rendering/hwrenderer/scene/hw_flats.cpp | 4 +++ 10 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index bd9b7555c..c4d298a01 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -52,6 +52,8 @@ struct LevelMeshSurface int texWidth = 0; int texHeight = 0; + bool needsUpdate = true; + // // Required for internal lightmapper: // diff --git a/src/common/rendering/hwrenderer/data/hw_renderstate.h b/src/common/rendering/hwrenderer/data/hw_renderstate.h index 7ac3662a2..e305c2ae0 100644 --- a/src/common/rendering/hwrenderer/data/hw_renderstate.h +++ b/src/common/rendering/hwrenderer/data/hw_renderstate.h @@ -3,6 +3,7 @@ #include "vectors.h" #include "matrix.h" #include "hw_material.h" +#include "hw_levelmesh.h" #include "texmanip.h" #include "version.h" #include "i_interface.h" @@ -257,6 +258,7 @@ protected: EPassType mPassType = NORMAL_PASS; + TArray mActiveLightmapSurfaces; public: uint64_t firstFrame = 0; @@ -729,6 +731,22 @@ public: return SetViewpoint(matrices); } + inline void PushVisibleSurface(LevelMeshSurface* surface) + { + if(surface && surface->needsUpdate && mActiveLightmapSurfaces.Find(surface) >= mActiveLightmapSurfaces.Size()) // yikes, how awful + mActiveLightmapSurfaces.Push(surface); + } + + inline const auto& GetVisibleSurfaceList() const + { + return mActiveLightmapSurfaces; + } + + inline void ClearVisibleSurfaceList() + { + mActiveLightmapSurfaces.Clear(); + } + // API-dependent render interface // Worker threads diff --git a/src/common/rendering/v_video.h b/src/common/rendering/v_video.h index 45c7e5db3..c6eafc1f6 100644 --- a/src/common/rendering/v_video.h +++ b/src/common/rendering/v_video.h @@ -156,6 +156,7 @@ public: virtual bool IsPoly() { return false; } virtual bool CompileNextShader() { return true; } virtual void SetLevelMesh(LevelMesh *mesh) { } + virtual void UpdateLightmaps(const TArray& surfaces) {} bool allowSSBO() const { #ifndef HW_BLOCK_SSBO diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp index 694235be7..2de6c2aad 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -30,6 +30,17 @@ VkLightmap::~VkLightmap() lights.Buffer->Unmap(); } +static int lastSurfaceCount; + +ADD_STAT(lightmapper) +{ + FString out; + + out.Format("Last batch surface count: %d", lastSurfaceCount); + + return out; +} + void VkLightmap::Raytrace(LevelMesh* level, const TArray& surfaces) { bool newLevel = (mesh != level); @@ -41,8 +52,15 @@ void VkLightmap::Raytrace(LevelMesh* level, const TArray& sur CreateAtlasImages(); } + for (auto surface : surfaces) + { + surface->needsUpdate = false; + } + UploadUniforms(); + lastSurfaceCount = surfaces.Size(); + for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) { RenderAtlasImage(pageIndex, surfaces); @@ -52,7 +70,7 @@ void VkLightmap::Raytrace(LevelMesh* level, const TArray& sur { ResolveAtlasImage(pageIndex); BlurAtlasImage(pageIndex); - CopyAtlasImageResult(pageIndex); + CopyAtlasImageResult(pageIndex, surfaces); } } @@ -374,14 +392,14 @@ void VkLightmap::BlurAtlasImage(size_t pageIndex) } } -void VkLightmap::CopyAtlasImageResult(size_t pageIndex) +void VkLightmap::CopyAtlasImageResult(size_t pageIndex, const TArray& surfaces) { LightmapImage& img = atlasImages[pageIndex]; std::vector regions; - for (int i = 0, count = mesh->GetSurfaceCount(); i < count; i++) + for (int i = 0, count = surfaces.Size(); i < count; i++) { - LevelMeshSurface* surface = mesh->GetSurface(i); + LevelMeshSurface* surface = surfaces[i]; if (surface->lightmapperAtlasPage != pageIndex) continue; diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.h b/src/common/rendering/vulkan/accelstructs/vk_lightmap.h index 3fd8a0b8e..ffbf1e853 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.h +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.h @@ -96,7 +96,7 @@ private: void RenderAtlasImage(size_t pageIndex, const TArray& surfaces); void ResolveAtlasImage(size_t pageIndex); void BlurAtlasImage(size_t pageIndex); - void CopyAtlasImageResult(size_t pageIndex); + void CopyAtlasImageResult(size_t pageIndex, const TArray& surfaces); LightmapImage CreateImage(int width, int height); diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index bfc6de8c1..7cb5b3543 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -529,17 +529,20 @@ void VulkanRenderDevice::PrintStartupLog() Printf("Min. uniform buffer offset alignment: %" PRIu64 "\n", limits.minUniformBufferOffsetAlignment); } +LevelMesh* lastMesh = nullptr; // Temp hack; Since this function is called every frame we only want to do this once + void VulkanRenderDevice::SetLevelMesh(LevelMesh* mesh) { mRaytrace->SetLevelMesh(mesh); - static LevelMesh* lastMesh = nullptr; // Temp hack; Since this function is called every frame we only want to do this once if (lastMesh != mesh && mesh->GetSurfaceCount() > 0) { lastMesh = mesh; mesh->UpdateLightLists(); + GetTextureManager()->CreateLightmap(mesh->LMTextureSize, mesh->LMTextureCount); +#if 0 // full lightmap generation TArray surfaces; surfaces.Reserve(mesh->GetSurfaceCount()); for (unsigned i = 0, count = mesh->GetSurfaceCount(); i < count; ++i) @@ -547,8 +550,23 @@ void VulkanRenderDevice::SetLevelMesh(LevelMesh* mesh) surfaces[i] = mesh->GetSurface(i); } - GetTextureManager()->CreateLightmap(mesh->LMTextureSize, mesh->LMTextureCount); GetLightmap()->Raytrace(mesh, surfaces); +#else + GetLightmap()->Raytrace(mesh, {}); +#endif + } +} + +void VulkanRenderDevice::UpdateLightmaps(const TArray& surfaces) +{ + if (surfaces.Size() > 0) + { + auto levelMesh = lastMesh; // There's nothing more permanent than a temporary solution + + if (levelMesh) + { + GetLightmap()->Raytrace(levelMesh, surfaces); + } } } diff --git a/src/common/rendering/vulkan/vk_renderdevice.h b/src/common/rendering/vulkan/vk_renderdevice.h index 6702f46c3..9de2e5381 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.h +++ b/src/common/rendering/vulkan/vk_renderdevice.h @@ -63,6 +63,7 @@ public: void AmbientOccludeScene(float m5) override; void SetSceneRenderTarget(bool useSSAO) override; void SetLevelMesh(LevelMesh* mesh) override; + void UpdateLightmaps(const TArray& surfaces) override; void SetShadowMaps(const TArray& lights, hwrenderer::LevelAABBTree* tree, bool newTree) override; void SetSaveBuffers(bool yes) override; void ImageTransitionScene(bool unknown) override; diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index da7c6a79e..598c5e376 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -23,6 +23,18 @@ CCMD(dumplevelmesh) } } +CCMD(invalidatelightmap) +{ + int count = 0; + for (auto& surface : level.levelMesh->Surfaces) + { + if (!surface.needsUpdate) + ++count; + surface.needsUpdate = true; + } + Printf("Marked %d out of %d surfaces for update.\n", count, level.levelMesh->Surfaces.Size()); +} + DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap) { SunColor = doomMap.SunColor; // TODO keep only one copy? diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp index 55a4fe8d5..9e7b09724 100644 --- a/src/rendering/hwrenderer/hw_entrypoint.cpp +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -124,6 +124,7 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou screen->mShadowMap->SetCollectLights(nullptr); } + RenderState.ClearVisibleSurfaceList(); screen->SetLevelMesh(camera->Level->levelMesh); static HWDrawContext mainthread_drawctx; @@ -197,6 +198,8 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou screen->NextEye(eyeCount); } + screen->UpdateLightmaps(RenderState.GetVisibleSurfaceList()); + return mainvp.sector; } diff --git a/src/rendering/hwrenderer/scene/hw_flats.cpp b/src/rendering/hwrenderer/scene/hw_flats.cpp index 0b878da75..8130f694e 100644 --- a/src/rendering/hwrenderer/scene/hw_flats.cpp +++ b/src/rendering/hwrenderer/scene/hw_flats.cpp @@ -192,6 +192,10 @@ void HWFlat::DrawSubsectors(HWDrawInfo *di, FRenderState &state) } state.SetLightIndex(dynlightindex); + for (auto& subsector : section->subsectors) + { + state.PushVisibleSurface(subsector->lightmap[ceiling ? 1 : 0][0]); + } state.DrawIndexed(DT_Triangles, iboindex + section->vertexindex, section->vertexcount); flatvertices += section->vertexcount;