From 7dc050edb0c5911352d7dc945737b80149e8d371 Mon Sep 17 00:00:00 2001 From: RaveYard <29225776+MrRaveYard@users.noreply.github.com> Date: Sat, 22 Feb 2025 00:38:28 +0100 Subject: [PATCH] Refactor to reduce reallocations and copying --- .../hwrenderer/data/hw_lightprobe.cpp | 38 +++++++++++++------ .../rendering/hwrenderer/data/hw_lightprobe.h | 17 +++++++-- src/common/rendering/v_video.h | 4 +- .../rendering/vulkan/textures/vk_texture.cpp | 8 +--- .../rendering/vulkan/textures/vk_texture.h | 4 +- .../rendering/vulkan/vk_lightprober.cpp | 30 ++++++++++----- src/common/rendering/vulkan/vk_lightprober.h | 14 +++++-- .../rendering/vulkan/vk_renderdevice.cpp | 13 +++---- src/common/rendering/vulkan/vk_renderdevice.h | 4 +- src/rendering/hwrenderer/hw_entrypoint.cpp | 10 +++-- 10 files changed, 91 insertions(+), 51 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_lightprobe.cpp b/src/common/rendering/hwrenderer/data/hw_lightprobe.cpp index 3a5b873a9..ee8a56db2 100644 --- a/src/common/rendering/hwrenderer/data/hw_lightprobe.cpp +++ b/src/common/rendering/hwrenderer/data/hw_lightprobe.cpp @@ -1,6 +1,6 @@ #include "hw_lightprobe.h" -void LightProbeIncrementalBuilder::Step(const TArray& probes, std::function&, TArray&)> renderScene, std::function&&, TArray&&)> uploadEnv) +void LightProbeIncrementalBuilder::Step(const TArray& probes, std::function&, TArrayView&)> renderScene, std::function&, const TArray&)> uploadEnv) { if (lastIndex >= probes.size()) { @@ -12,28 +12,44 @@ void LightProbeIncrementalBuilder::Step(const TArray& probes, std::f } } - TArray irradianceMap; - TArray prefilterMap; + if (cubemapsAllocated != probes.size()) + { + int newSegments = probes.size(); + int lastSegments = cubemapsAllocated; - renderScene(probes[lastIndex++], irradianceMap, prefilterMap); + irradianceMaps.resize(probes.size() * irradianceBytes); + prefilterMaps.resize(probes.size() * prefilterBytes); + cubemapsAllocated = probes.size(); + + lastIndex = 0; + collected = 0; + + // needed because otherwise it somehow gets corrupted + memset(irradianceMaps.Data(), 0, irradianceMaps.Size() * sizeof(uint16_t)); + memset(prefilterMaps.Data(), 0, prefilterMaps.Size() * sizeof(uint16_t)); + + // workaround for lack of boundary checking in GPU + uploadEnv(this->irradianceMaps, this->prefilterMaps); + return; + } + + auto irradianceBuffer = TArrayView(irradianceMaps.data() + lastIndex * irradianceBytes, irradianceBytes); + auto prefilterBuffer = TArrayView(prefilterMaps.data() + lastIndex * prefilterBytes, prefilterBytes); + + renderScene(probes[lastIndex++], irradianceBuffer, prefilterBuffer); ++collected; - this->irradianceMaps.Append(irradianceMap); - this->prefilterMaps.Append(prefilterMap); - if (lastIndex >= probes.size()) { if (collected == probes.size()) { - uploadEnv(std::move(this->irradianceMaps), std::move(this->prefilterMaps)); + uploadEnv(this->irradianceMaps, this->prefilterMaps); } - this->irradianceMaps.Clear(); - this->prefilterMaps.Clear(); collected = 0; } } -void LightProbeIncrementalBuilder::Full(const TArray& probes, std::function&, TArray&)> renderScene, std::function&&, TArray&&)> uploadEnv) +void LightProbeIncrementalBuilder::Full(const TArray& probes, std::function&, TArrayView&)> renderScene, std::function&, const TArray&)> uploadEnv) { if (lastIndex >= probes.size()) { diff --git a/src/common/rendering/hwrenderer/data/hw_lightprobe.h b/src/common/rendering/hwrenderer/data/hw_lightprobe.h index 38a7c989f..7f7b06002 100644 --- a/src/common/rendering/hwrenderer/data/hw_lightprobe.h +++ b/src/common/rendering/hwrenderer/data/hw_lightprobe.h @@ -16,16 +16,25 @@ struct LightProbeTarget class LightProbeIncrementalBuilder { int lastIndex = 0; + int collected = 0; + + int cubemapsAllocated = 0; - int collected; - TArray irradianceMaps; TArray prefilterMaps; + size_t irradianceBytes; + size_t prefilterBytes; public: + LightProbeIncrementalBuilder(size_t irradianceTexels, size_t prefilterTexels, size_t irradianceChannels, size_t prefilterChannels) : + irradianceBytes(irradianceTexels * irradianceChannels), + prefilterBytes(prefilterTexels * prefilterChannels) + { + } - void Step(const TArray& probes, std::function&, TArray&)> renderScene, std::function&&, TArray&&)> uploadEnv); - void Full(const TArray& probes, std::function&, TArray&)> renderScene, std::function&&, TArray&&)> uploadEnv); + void Step(const TArray& probes, std::function&, TArrayView&)> renderScene, std::function&, const TArray&)> uploadEnv); + void Full(const TArray& probes, std::function&, TArrayView&)> renderScene, std::function&, const TArray&)> uploadEnv); auto GetStep() const { return lastIndex; } + auto GetBufferSize() const { return irradianceMaps.size() && prefilterMaps.size(); } }; \ No newline at end of file diff --git a/src/common/rendering/v_video.h b/src/common/rendering/v_video.h index 6b987af8f..792be2f9d 100644 --- a/src/common/rendering/v_video.h +++ b/src/common/rendering/v_video.h @@ -221,8 +221,8 @@ public: // Get the array index for the material in the textures array accessible from shaders virtual int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) { return -1; } - virtual void RenderEnvironmentMap(std::function renderFunc, TArray& irradianceMap, TArray& prefilterMap) {} - virtual void UploadEnvironmentMaps(int cubemapCount, TArray&& irradianceMaps, TArray&& prefilterMaps) {} + virtual void RenderEnvironmentMap(std::function renderFunc, TArrayView& irradianceMap, TArrayView& prefilterMap) {} + virtual void UploadEnvironmentMaps(int cubemapCount, const TArray& irradianceMaps, const TArray& prefilterMaps) {} // Screen wiping virtual FTexture *WipeStartScreen(); diff --git a/src/common/rendering/vulkan/textures/vk_texture.cpp b/src/common/rendering/vulkan/textures/vk_texture.cpp index da30bd190..a65ba5f07 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.cpp +++ b/src/common/rendering/vulkan/textures/vk_texture.cpp @@ -279,7 +279,7 @@ void VkTextureManager::CreatePrefiltermap() CreatePrefiltermap(size, 6, std::move(data)); } -void VkTextureManager::CreateIrradiancemap(int size, int count, TArray&& newPixelData) +void VkTextureManager::CreateIrradiancemap(int size, int count, const TArray& newPixelData) { if (Irradiancemap.Size == size && Irradiancemap.Count == count && newPixelData.Size() == 0) return; @@ -346,8 +346,6 @@ void VkTextureManager::CreateIrradiancemap(int size, int count, TArray cmdbuffer->copyBufferToImage(stagingBuffer->buffer, Irradiancemap.Image.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); - - newPixelData.Clear(); } VkImageTransition() @@ -355,7 +353,7 @@ void VkTextureManager::CreateIrradiancemap(int size, int count, TArray .Execute(cmdbuffer); } -void VkTextureManager::CreatePrefiltermap(int size, int count, TArray&& newPixelData) +void VkTextureManager::CreatePrefiltermap(int size, int count, const TArray& newPixelData) { if (Prefiltermap.Size == size && Prefiltermap.Count == count && newPixelData.Size() == 0) return; @@ -443,8 +441,6 @@ void VkTextureManager::CreatePrefiltermap(int size, int count, TArray& } fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); - - newPixelData.Clear(); } VkImageTransition() diff --git a/src/common/rendering/vulkan/textures/vk_texture.h b/src/common/rendering/vulkan/textures/vk_texture.h index 5292ecfb2..443a73201 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.h +++ b/src/common/rendering/vulkan/textures/vk_texture.h @@ -24,8 +24,8 @@ public: void BeginFrame(); void CreateLightmap(int size, int count, TArray&& data); - void CreateIrradiancemap(int size, int count, TArray&& data); - void CreatePrefiltermap(int size, int count, TArray&& data); + void CreateIrradiancemap(int size, int count, const TArray& data); + void CreatePrefiltermap(int size, int count, const TArray& data); void DownloadLightmap(int arrayIndex, uint16_t* buffer); VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex); diff --git a/src/common/rendering/vulkan/vk_lightprober.cpp b/src/common/rendering/vulkan/vk_lightprober.cpp index 37e444742..db1ae5a61 100644 --- a/src/common/rendering/vulkan/vk_lightprober.cpp +++ b/src/common/rendering/vulkan/vk_lightprober.cpp @@ -256,8 +256,15 @@ void VkLightprober::CreateIrradianceMap() } } -TArray VkLightprober::GenerateIrradianceMap() +bool VkLightprober::GenerateIrradianceMap(TArrayView& databuffer) { + const int texelCount = irrandiaceMapTexelCount; + + if (databuffer.Size() < texelCount) + { + return false; + } + auto staging = BufferBuilder() .Size(32 * 32 * 8 * 6) .Usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU) @@ -334,9 +341,7 @@ TArray VkLightprober::GenerateIrradianceMap() fb->GetCommands()->WaitForCommands(false); // Copy while dropping the alpha channel - int texelCount = 32 * 32 * 6; - TArray databuffer(texelCount * 3, true); - auto dst = databuffer.data(); + auto dst = databuffer.Data(); auto src = (uint16_t*)staging->Map(0, texelCount * 8); for (int i = 0; i < texelCount; i++) { @@ -346,7 +351,7 @@ TArray VkLightprober::GenerateIrradianceMap() src++; } staging->Unmap(); - return databuffer; + return true; } void VkLightprober::CreatePrefilterMap() @@ -398,8 +403,15 @@ void VkLightprober::CreatePrefilterMap() } } -TArray VkLightprober::GeneratePrefilterMap() +bool VkLightprober::GeneratePrefilterMap(TArrayView& databuffer) { + const int texelCount = prefilterMapTexelCount; + + if (databuffer.Size() < texelCount) + { + return false; + } + auto staging = BufferBuilder() .Size(prefilterMap.levelsSize * 6 * 8) .Usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_TO_CPU) @@ -484,9 +496,7 @@ TArray VkLightprober::GeneratePrefilterMap() fb->GetCommands()->WaitForCommands(false); // Copy while dropping the alpha channel - int texelCount = prefilterMap.levelsSize * 6; - TArray databuffer(texelCount * 3, true); - auto dst = databuffer.data(); + auto dst = databuffer.Data(); auto src = (uint16_t*)staging->Map(0, texelCount * 8); for (int i = 0; i < texelCount; i++) { @@ -496,7 +506,7 @@ TArray VkLightprober::GeneratePrefilterMap() src++; } staging->Unmap(); - return databuffer; + return true; } std::unique_ptr VkLightprober::CompileShader(const std::string& name, const std::string& filename, const char* debugName) diff --git a/src/common/rendering/vulkan/vk_lightprober.h b/src/common/rendering/vulkan/vk_lightprober.h index d3df9e12a..6987c56f0 100644 --- a/src/common/rendering/vulkan/vk_lightprober.h +++ b/src/common/rendering/vulkan/vk_lightprober.h @@ -35,8 +35,8 @@ public: ~VkLightprober(); void RenderEnvironmentMap(std::function renderFunc); - TArray GenerateIrradianceMap(); - TArray GeneratePrefilterMap(); + bool GenerateIrradianceMap(TArrayView& databuffer); + bool GeneratePrefilterMap(TArrayView& databuffer); private: void CreateBrdfLutResources(); @@ -89,7 +89,7 @@ private: std::unique_ptr views[6]; } irradianceMap; - struct + struct PrefilterMap { enum { @@ -108,4 +108,12 @@ private: } prefilterMap; VulkanRenderDevice* fb = nullptr; + +public: + // Used to pass buffer sizes + constexpr static const int irrandiaceMapTexelCount = 32 * 32 * 6; + constexpr static const int prefilterMapTexelCount = PrefilterMap::levelsSize * 6; + + constexpr static const int irradianceMapChannelCount = 3; + constexpr static const int prefilterMapChannelCount = 3; }; diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index 8b87354c0..630ed8748 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -321,18 +321,17 @@ void VulkanRenderDevice::RenderTextureView(FCanvasTexture* tex, std::functionSetUpdated(true); } -void VulkanRenderDevice::RenderEnvironmentMap(std::function renderFunc, TArray& irradianceMap, TArray& prefilterMap) +void VulkanRenderDevice::RenderEnvironmentMap(std::function renderFunc, TArrayView& irradianceMap, TArrayView& prefilterMap) { mLightprober->RenderEnvironmentMap(std::move(renderFunc)); - irradianceMap = mLightprober->GenerateIrradianceMap(); - prefilterMap = mLightprober->GeneratePrefilterMap(); - + mLightprober->GenerateIrradianceMap(irradianceMap); + mLightprober->GeneratePrefilterMap(prefilterMap); } -void VulkanRenderDevice::UploadEnvironmentMaps(int cubemapCount, TArray&& irradianceMaps, TArray&& prefilterMaps) +void VulkanRenderDevice::UploadEnvironmentMaps(int cubemapCount, const TArray& irradianceMaps, const TArray& prefilterMaps) { - mTextureManager->CreateIrradiancemap(32, 6 * cubemapCount, std::move(irradianceMaps)); - mTextureManager->CreatePrefiltermap(128, 6 * cubemapCount, std::move(prefilterMaps)); + mTextureManager->CreateIrradiancemap(32, 6 * cubemapCount, irradianceMaps); + mTextureManager->CreatePrefiltermap(128, 6 * cubemapCount, prefilterMaps); } void VulkanRenderDevice::PostProcessScene(bool swscene, int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) diff --git a/src/common/rendering/vulkan/vk_renderdevice.h b/src/common/rendering/vulkan/vk_renderdevice.h index 59392cf8a..4c21bb222 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.h +++ b/src/common/rendering/vulkan/vk_renderdevice.h @@ -104,8 +104,8 @@ public: private: void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) override; - void RenderEnvironmentMap(std::function renderFunc, TArray& irradianceMap, TArray& prefilterMap) override; - void UploadEnvironmentMaps(int cubemapCount, TArray&& irradianceMaps, TArray&& prefilterMaps) override; + void RenderEnvironmentMap(std::function renderFunc, TArrayView& irradianceMap, TArrayView& prefilterMap) override; + void UploadEnvironmentMaps(int cubemapCount, const TArray& irradianceMaps, const TArray& prefilterMaps) override; void PrintStartupLog(); void CopyScreenToBuffer(int w, int h, uint8_t *data) override; diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp index 40f7681f1..582a87b18 100644 --- a/src/rendering/hwrenderer/hw_entrypoint.cpp +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -50,6 +50,8 @@ #include "hwrenderer/scene/hw_drawcontext.h" #include "hw_vrmodes.h" +#include "common/rendering/vulkan/vk_lightprober.h" // to fetch irradiance and prefilter map texel counts + EXTERN_CVAR(Bool, cl_capfps) EXTERN_CVAR(Float, r_visibility) EXTERN_CVAR(Bool, gl_bandedswlight) @@ -333,7 +335,7 @@ static void CheckTimer(FRenderState &state, uint64_t ShaderStartTime) state.firstFrame = screen->FrameTime - 1; } -LightProbeIncrementalBuilder lightProbeBuilder; +LightProbeIncrementalBuilder lightProbeBuilder(VkLightprober::irrandiaceMapTexelCount, VkLightprober::prefilterMapTexelCount, VkLightprober::irradianceMapChannelCount, VkLightprober::prefilterMapChannelCount); sector_t* RenderView(player_t* player) { @@ -410,7 +412,7 @@ sector_t* RenderView(player_t* player) AActor* lightprobe = level.GetThinkerIterator(NAME_LightProbe, STAT_INFO).Next(); if (lightprobe) { - auto renderEnvMap = [&](const LightProbe& probe, TArray& irradianceMap, TArray& prefilteredMap) { + auto renderEnvMap = [&](const LightProbe& probe, TArrayView& irradianceMap, TArrayView& prefilteredMap) { lightprobe->SetOrigin(DVector3(probe.position), false); // crime against nature // The renderer interpolates camera in its own mechanism that has to be disabled when moving around the single probe @@ -425,8 +427,8 @@ sector_t* RenderView(player_t* player) r_NoInterpolate = noInterpolate; }; - auto renderEnvScreen = [&](TArray&& irradianceMaps, TArray&& prefilteredMaps) { - screen->UploadEnvironmentMaps(level.lightProbes.size(), std::move(irradianceMaps), std::move(prefilteredMaps)); + auto renderEnvScreen = [&](const TArray& irradianceMaps, const TArray& prefilteredMaps) { + screen->UploadEnvironmentMaps(level.lightProbes.size(), irradianceMaps, prefilteredMaps); }; lightProbeBuilder.Step(