Refactor to reduce reallocations and copying

This commit is contained in:
RaveYard 2025-02-22 00:38:28 +01:00 committed by Magnus Norddahl
commit 7dc050edb0
10 changed files with 91 additions and 51 deletions

View file

@ -1,6 +1,6 @@
#include "hw_lightprobe.h"
void LightProbeIncrementalBuilder::Step(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArray<uint16_t>&, TArray<uint16_t>&)> renderScene, std::function<void(TArray<uint16_t>&&, TArray<uint16_t>&&)> uploadEnv)
void LightProbeIncrementalBuilder::Step(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArrayView<uint16_t>&, TArrayView<uint16_t>&)> renderScene, std::function<void(const TArray<uint16_t>&, const TArray<uint16_t>&)> uploadEnv)
{
if (lastIndex >= probes.size())
{
@ -12,28 +12,44 @@ void LightProbeIncrementalBuilder::Step(const TArray<LightProbe>& probes, std::f
}
}
TArray<uint16_t> irradianceMap;
TArray<uint16_t> 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<uint16_t>(irradianceMaps.data() + lastIndex * irradianceBytes, irradianceBytes);
auto prefilterBuffer = TArrayView<uint16_t>(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<LightProbe>& probes, std::function<void(const LightProbe&, TArray<uint16_t>&, TArray<uint16_t>&)> renderScene, std::function<void(TArray<uint16_t>&&, TArray<uint16_t>&&)> uploadEnv)
void LightProbeIncrementalBuilder::Full(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArrayView<uint16_t>&, TArrayView<uint16_t>&)> renderScene, std::function<void(const TArray<uint16_t>&, const TArray<uint16_t>&)> uploadEnv)
{
if (lastIndex >= probes.size())
{

View file

@ -16,16 +16,25 @@ struct LightProbeTarget
class LightProbeIncrementalBuilder
{
int lastIndex = 0;
int collected = 0;
int cubemapsAllocated = 0;
int collected;
TArray<uint16_t> irradianceMaps;
TArray<uint16_t> 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<LightProbe>& probes, std::function<void(const LightProbe&, TArray<uint16_t>&, TArray<uint16_t>&)> renderScene, std::function<void(TArray<uint16_t>&&, TArray<uint16_t>&&)> uploadEnv);
void Full(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArray<uint16_t>&, TArray<uint16_t>&)> renderScene, std::function<void(TArray<uint16_t>&&, TArray<uint16_t>&&)> uploadEnv);
void Step(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArrayView<uint16_t>&, TArrayView<uint16_t>&)> renderScene, std::function<void(const TArray<uint16_t>&, const TArray<uint16_t>&)> uploadEnv);
void Full(const TArray<LightProbe>& probes, std::function<void(const LightProbe&, TArrayView<uint16_t>&, TArrayView<uint16_t>&)> renderScene, std::function<void(const TArray<uint16_t>&, const TArray<uint16_t>&)> uploadEnv);
auto GetStep() const { return lastIndex; }
auto GetBufferSize() const { return irradianceMaps.size() && prefilterMaps.size(); }
};

View file

@ -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<void(IntRect& bounds, int side)> renderFunc, TArray<uint16_t>& irradianceMap, TArray<uint16_t>& prefilterMap) {}
virtual void UploadEnvironmentMaps(int cubemapCount, TArray<uint16_t>&& irradianceMaps, TArray<uint16_t>&& prefilterMaps) {}
virtual void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc, TArrayView<uint16_t>& irradianceMap, TArrayView<uint16_t>& prefilterMap) {}
virtual void UploadEnvironmentMaps(int cubemapCount, const TArray<uint16_t>& irradianceMaps, const TArray<uint16_t>& prefilterMaps) {}
// Screen wiping
virtual FTexture *WipeStartScreen();

View file

@ -279,7 +279,7 @@ void VkTextureManager::CreatePrefiltermap()
CreatePrefiltermap(size, 6, std::move(data));
}
void VkTextureManager::CreateIrradiancemap(int size, int count, TArray<uint16_t>&& newPixelData)
void VkTextureManager::CreateIrradiancemap(int size, int count, const TArray<uint16_t>& newPixelData)
{
if (Irradiancemap.Size == size && Irradiancemap.Count == count && newPixelData.Size() == 0)
return;
@ -346,8 +346,6 @@ void VkTextureManager::CreateIrradiancemap(int size, int count, TArray<uint16_t>
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, Irradiancemap.Image.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer));
newPixelData.Clear();
}
VkImageTransition()
@ -355,7 +353,7 @@ void VkTextureManager::CreateIrradiancemap(int size, int count, TArray<uint16_t>
.Execute(cmdbuffer);
}
void VkTextureManager::CreatePrefiltermap(int size, int count, TArray<uint16_t>&& newPixelData)
void VkTextureManager::CreatePrefiltermap(int size, int count, const TArray<uint16_t>& newPixelData)
{
if (Prefiltermap.Size == size && Prefiltermap.Count == count && newPixelData.Size() == 0)
return;
@ -443,8 +441,6 @@ void VkTextureManager::CreatePrefiltermap(int size, int count, TArray<uint16_t>&
}
fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer));
newPixelData.Clear();
}
VkImageTransition()

View file

@ -24,8 +24,8 @@ public:
void BeginFrame();
void CreateLightmap(int size, int count, TArray<uint16_t>&& data);
void CreateIrradiancemap(int size, int count, TArray<uint16_t>&& data);
void CreatePrefiltermap(int size, int count, TArray<uint16_t>&& data);
void CreateIrradiancemap(int size, int count, const TArray<uint16_t>& data);
void CreatePrefiltermap(int size, int count, const TArray<uint16_t>& data);
void DownloadLightmap(int arrayIndex, uint16_t* buffer);
VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex);

View file

@ -256,8 +256,15 @@ void VkLightprober::CreateIrradianceMap()
}
}
TArray<uint16_t> VkLightprober::GenerateIrradianceMap()
bool VkLightprober::GenerateIrradianceMap(TArrayView<uint16_t>& 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<uint16_t> VkLightprober::GenerateIrradianceMap()
fb->GetCommands()->WaitForCommands(false);
// Copy while dropping the alpha channel
int texelCount = 32 * 32 * 6;
TArray<uint16_t> 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<uint16_t> VkLightprober::GenerateIrradianceMap()
src++;
}
staging->Unmap();
return databuffer;
return true;
}
void VkLightprober::CreatePrefilterMap()
@ -398,8 +403,15 @@ void VkLightprober::CreatePrefilterMap()
}
}
TArray<uint16_t> VkLightprober::GeneratePrefilterMap()
bool VkLightprober::GeneratePrefilterMap(TArrayView<uint16_t>& 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<uint16_t> VkLightprober::GeneratePrefilterMap()
fb->GetCommands()->WaitForCommands(false);
// Copy while dropping the alpha channel
int texelCount = prefilterMap.levelsSize * 6;
TArray<uint16_t> 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<uint16_t> VkLightprober::GeneratePrefilterMap()
src++;
}
staging->Unmap();
return databuffer;
return true;
}
std::unique_ptr<VulkanShader> VkLightprober::CompileShader(const std::string& name, const std::string& filename, const char* debugName)

View file

@ -35,8 +35,8 @@ public:
~VkLightprober();
void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc);
TArray<uint16_t> GenerateIrradianceMap();
TArray<uint16_t> GeneratePrefilterMap();
bool GenerateIrradianceMap(TArrayView<uint16_t>& databuffer);
bool GeneratePrefilterMap(TArrayView<uint16_t>& databuffer);
private:
void CreateBrdfLutResources();
@ -89,7 +89,7 @@ private:
std::unique_ptr<VulkanImageView> 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;
};

View file

@ -321,18 +321,17 @@ void VulkanRenderDevice::RenderTextureView(FCanvasTexture* tex, std::function<vo
tex->SetUpdated(true);
}
void VulkanRenderDevice::RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc, TArray<uint16_t>& irradianceMap, TArray<uint16_t>& prefilterMap)
void VulkanRenderDevice::RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc, TArrayView<uint16_t>& irradianceMap, TArrayView<uint16_t>& prefilterMap)
{
mLightprober->RenderEnvironmentMap(std::move(renderFunc));
irradianceMap = mLightprober->GenerateIrradianceMap();
prefilterMap = mLightprober->GeneratePrefilterMap();
mLightprober->GenerateIrradianceMap(irradianceMap);
mLightprober->GeneratePrefilterMap(prefilterMap);
}
void VulkanRenderDevice::UploadEnvironmentMaps(int cubemapCount, TArray<uint16_t>&& irradianceMaps, TArray<uint16_t>&& prefilterMaps)
void VulkanRenderDevice::UploadEnvironmentMaps(int cubemapCount, const TArray<uint16_t>& irradianceMaps, const TArray<uint16_t>& 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<void()> &afterBloomDrawEndScene2D)

View file

@ -104,8 +104,8 @@ public:
private:
void RenderTextureView(FCanvasTexture* tex, std::function<void(IntRect &)> renderFunc) override;
void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc, TArray<uint16_t>& irradianceMap, TArray<uint16_t>& prefilterMap) override;
void UploadEnvironmentMaps(int cubemapCount, TArray<uint16_t>&& irradianceMaps, TArray<uint16_t>&& prefilterMaps) override;
void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc, TArrayView<uint16_t>& irradianceMap, TArrayView<uint16_t>& prefilterMap) override;
void UploadEnvironmentMaps(int cubemapCount, const TArray<uint16_t>& irradianceMaps, const TArray<uint16_t>& prefilterMaps) override;
void PrintStartupLog();
void CopyScreenToBuffer(int w, int h, uint8_t *data) override;

View file

@ -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<AActor>(NAME_LightProbe, STAT_INFO).Next();
if (lightprobe)
{
auto renderEnvMap = [&](const LightProbe& probe, TArray<uint16_t>& irradianceMap, TArray<uint16_t>& prefilteredMap) {
auto renderEnvMap = [&](const LightProbe& probe, TArrayView<uint16_t>& irradianceMap, TArrayView<uint16_t>& 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<uint16_t>&& irradianceMaps, TArray<uint16_t>&& prefilteredMaps) {
screen->UploadEnvironmentMaps(level.lightProbes.size(), std::move(irradianceMaps), std::move(prefilteredMaps));
auto renderEnvScreen = [&](const TArray<uint16_t>& irradianceMaps, const TArray<uint16_t>& prefilteredMaps) {
screen->UploadEnvironmentMaps(level.lightProbes.size(), irradianceMaps, prefilteredMaps);
};
lightProbeBuilder.Step(