diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index bd9b7555c8..c4d298a010 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 7ac3662a25..e305c2ae06 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 93e763bcf0..e0452890bc 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 86790ae845..4c43be42fd 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -31,6 +31,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); @@ -42,8 +53,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); @@ -53,7 +71,7 @@ void VkLightmap::Raytrace(LevelMesh* level, const TArray& sur { ResolveAtlasImage(pageIndex); BlurAtlasImage(pageIndex); - CopyAtlasImageResult(pageIndex); + CopyAtlasImageResult(pageIndex, surfaces); } } @@ -375,14 +393,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 3fd8a0b8e2..ffbf1e853f 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 7fd2f49e5b..8d3d44c2d7 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -531,17 +531,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) @@ -549,8 +552,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 6702f46c3c..9de2e53813 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 da7c6a79e3..598c5e376f 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 55a4fe8d5b..9e7b09724b 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 0b878da758..8130f694ef 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;