Run the light tiles compute shader

This commit is contained in:
Magnus Norddahl 2024-09-14 04:59:39 +02:00
commit 521e2ed39c
16 changed files with 162 additions and 11 deletions

View file

@ -699,6 +699,7 @@ public:
}
// Draw level mesh
virtual void DispatchLightTiles() { }
virtual void DrawLevelMesh(LevelMeshDrawType drawType, bool noFragmentShader) { }
virtual int GetNextQueryIndex() { return 0; }
virtual void BeginQuery() { }

View file

@ -33,6 +33,8 @@ struct HWViewpointUniforms
int mLightBlendMode = 0;
int mLightTilesWidth = 0;
void CalcDependencies()
{
mNormalViewMatrix.computeNormalMatrix(mViewMatrix);

View file

@ -43,9 +43,11 @@ VkDescriptorSetManager::VkDescriptorSetManager(VulkanRenderDevice* fb) : fb(fb)
CreateLevelMeshLayout();
CreateRSBufferLayout();
CreateFixedLayout();
CreateLightTilesLayout();
CreateLevelMeshPool();
CreateRSBufferPool();
CreateFixedPool();
CreateLightTilesPool();
CreateBindlessSet();
}
@ -59,6 +61,7 @@ void VkDescriptorSetManager::Init()
{
RSBuffer.Set = RSBuffer.Pool->allocate(RSBuffer.Layout.get());
LevelMesh.Set = LevelMesh.Pool->allocate(LevelMesh.Layout.get());
LightTiles.Set = LightTiles.Pool->allocate(LightTiles.Layout.get());
auto rsbuffers = fb->GetBufferManager()->GetRSBuffers();
WriteDescriptors()
@ -81,6 +84,7 @@ void VkDescriptorSetManager::BeginFrame()
{
UpdateFixedSet();
UpdateLevelMeshSet();
UpdateLightTilesSet();
}
void VkDescriptorSetManager::UpdateLevelMeshSet()
@ -97,6 +101,15 @@ void VkDescriptorSetManager::UpdateLevelMeshSet()
.Execute(fb->GetDevice());
}
void VkDescriptorSetManager::UpdateLightTilesSet()
{
WriteDescriptors()
.AddStorageImage(LightTiles.Set.get(), 0, fb->GetBuffers()->SceneZMinMax[4].View.get(), VK_IMAGE_LAYOUT_GENERAL)
.AddBuffer(LightTiles.Set.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetUniformsBuffer())
.AddBuffer(LightTiles.Set.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetBuffers()->SceneLightTiles.get())
.Execute(fb->GetDevice());
}
void VkDescriptorSetManager::UpdateFixedSet()
{
fb->GetCommands()->DrawDeleteList->Add(std::move(Fixed.Set));
@ -250,6 +263,26 @@ void VkDescriptorSetManager::CreateFixedLayout()
Fixed.Layout = builder.Create(fb->GetDevice());
}
void VkDescriptorSetManager::CreateLightTilesLayout()
{
LightTiles.Layout = DescriptorSetLayoutBuilder()
.AddBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT)
.AddBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT)
.AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT)
.DebugName("VkDescriptorSetManager.LightTiles.Layout")
.Create(fb->GetDevice());
}
void VkDescriptorSetManager::CreateLightTilesPool()
{
LightTiles.Pool = DescriptorPoolBuilder()
.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1)
.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2)
.MaxSets(1)
.DebugName("VkDescriptorSetManager.LightTiles.Pool")
.Create(fb->GetDevice());
}
void VkDescriptorSetManager::CreateLevelMeshPool()
{
LevelMesh.Pool = DescriptorPoolBuilder()

View file

@ -21,17 +21,18 @@ public:
void Deinit();
void BeginFrame();
void ResetHWTextureSets();
void UpdateLevelMeshSet();
VulkanDescriptorSetLayout* GetLevelMeshLayout() { return LevelMesh.Layout.get(); }
VulkanDescriptorSetLayout* GetRSBufferLayout() { return RSBuffer.Layout.get(); }
VulkanDescriptorSetLayout* GetFixedLayout() { return Fixed.Layout.get(); }
VulkanDescriptorSetLayout* GetBindlessLayout() { return Bindless.Layout.get(); }
VulkanDescriptorSetLayout* GetLightTilesLayout() { return LightTiles.Layout.get(); }
VulkanDescriptorSet* GetLevelMeshSet() { return LevelMesh.Set.get(); }
VulkanDescriptorSet* GetRSBufferSet() { return RSBuffer.Set.get(); }
VulkanDescriptorSet* GetFixedSet() { return Fixed.Set.get(); }
VulkanDescriptorSet* GetBindlessSet() { return Bindless.Set.get(); }
VulkanDescriptorSet* GetLightTilesSet() { return LightTiles.Set.get(); }
VulkanDescriptorSet* GetInput(VkPPRenderPassSetup* passSetup, const TArray<PPTextureInput>& textures, bool bindShadowMapBuffers);
@ -45,11 +46,15 @@ private:
void CreateLevelMeshLayout();
void CreateRSBufferLayout();
void CreateFixedLayout();
void CreateLightTilesLayout();
void CreateLevelMeshPool();
void CreateRSBufferPool();
void CreateFixedPool();
void CreateLightTilesPool();
void CreateBindlessSet();
void UpdateFixedSet();
void UpdateLevelMeshSet();
void UpdateLightTilesSet();
std::unique_ptr<VulkanDescriptorSet> AllocatePPSet(VulkanDescriptorSetLayout* layout);
@ -90,6 +95,13 @@ private:
std::unique_ptr<VulkanDescriptorPool> Pool;
} Postprocess;
struct
{
std::unique_ptr<VulkanDescriptorPool> Pool;
std::unique_ptr<VulkanDescriptorSet> Set;
std::unique_ptr<VulkanDescriptorSetLayout> Layout;
} LightTiles;
std::list<VkMaterial*> Materials;
static const int MaxFixedSets = 100;

View file

@ -64,6 +64,8 @@ VkRenderPassManager::VkRenderPassManager(VulkanRenderDevice* fb) : fb(fb)
}
PipelineCache = builder.Create(fb->GetDevice());
CreateLightTilesPipeline();
}
VkRenderPassManager::~VkRenderPassManager()
@ -154,6 +156,22 @@ VkPPRenderPassSetup* VkRenderPassManager::GetPPRenderPass(const VkPPRenderPassKe
return passSetup.get();
}
void VkRenderPassManager::CreateLightTilesPipeline()
{
LightTiles.Layout = PipelineLayoutBuilder()
.AddSetLayout(fb->GetDescriptorSetManager()->GetLightTilesLayout())
.AddPushConstantRange(VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(LightTilesPushConstants))
.DebugName("VkRenderPassManager.LightTiles.Layout")
.Create(fb->GetDevice());
LightTiles.Pipeline = ComputePipelineBuilder()
.Cache(PipelineCache.get())
.Layout(LightTiles.Layout.get())
.ComputeShader(fb->GetShaderManager()->GetLightTilesShader())
.DebugName("VkRenderPassManager.LightTiles.Pipeline")
.Create(fb->GetDevice());
}
/////////////////////////////////////////////////////////////////////////////
VkRenderPassSetup::VkRenderPassSetup(VulkanRenderDevice* fb, const VkRenderPassKey &key) : PassKey(key), fb(fb)

View file

@ -115,7 +115,12 @@ public:
VulkanPipelineCache* GetCache() { return PipelineCache.get(); }
VulkanPipelineLayout* GetLightTilesLayout() { return LightTiles.Layout.get(); }
VulkanPipeline* GetLightTilesPipeline() { return LightTiles.Pipeline.get(); }
private:
void CreateLightTilesPipeline();
VulkanRenderDevice* fb = nullptr;
std::map<VkRenderPassKey, std::unique_ptr<VkRenderPassSetup>> RenderPassSetup;
@ -124,6 +129,12 @@ private:
std::map<VkPPRenderPassKey, std::unique_ptr<VkPPRenderPassSetup>> PPRenderPassSetup;
struct
{
std::unique_ptr<VulkanPipelineLayout> Layout;
std::unique_ptr<VulkanPipeline> Pipeline;
} LightTiles;
FString CacheFilename;
std::unique_ptr<VulkanPipelineCache> PipelineCache;
};

View file

@ -53,6 +53,13 @@ struct PushConstants
int uFogballIndex; // fog balls
};
struct LightTilesPushConstants
{
int normalLightCount;
int modulatedLightCount;
int subtractiveLightCount;
};
class VkShaderKey
{
public:

View file

@ -292,7 +292,7 @@ void VkRenderBuffers::CreateSceneZMinMax(int width, int height)
SceneZMinMax[i].Image = ImageBuilder()
.Size(width, height)
.Format(VK_FORMAT_R32G32_SFLOAT)
.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT)
.DebugName("VkRenderBuffers.SceneZMinMax")
.Create(fb->GetDevice());
@ -309,7 +309,7 @@ void VkRenderBuffers::CreateSceneLightTiles(int width, int height)
height = (height + 63) / 64;
// Make room for 16 lights plus the lightdata header
size_t blockSize = (1 + 3 * 16) * sizeof(FVector4);
size_t blockSize = (1 + 4 * 16) * sizeof(FVector4);
SceneLightTiles = BufferBuilder()
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)

View file

@ -236,6 +236,7 @@ void VulkanRenderDevice::InitializeState()
mPostprocess.reset(new VkPostprocess(this));
mDescriptorSetManager.reset(new VkDescriptorSetManager(this));
mShaderManager.reset(new VkShaderManager(this));
mRenderPassManager.reset(new VkRenderPassManager(this));
mLevelMesh.reset(new VkLevelMesh(this));
mLightmapper.reset(new VkLightmapper(this));
@ -245,7 +246,6 @@ void VulkanRenderDevice::InitializeState()
mSkyData = new FSkyVertexBuffer(this);
mShadowMap = new ShadowMap(this);
mShaderManager.reset(new VkShaderManager(this));
mDescriptorSetManager->Init();
#ifdef __APPLE__

View file

@ -867,6 +867,43 @@ void VkRenderState::ApplyLevelMesh()
mCommandBuffer->bindIndexBuffer(fb->GetLevelMesh()->GetDrawIndexBuffer()->buffer, 0, VK_INDEX_TYPE_UINT32);
}
void VkRenderState::DispatchLightTiles()
{
EndRenderPass();
auto cmdbuffer = fb->GetCommands()->GetDrawCommands();
// To do: run the zminmax pass
VkImageTransition()
.AddImage(&fb->GetBuffers()->SceneZMinMax[4], VK_IMAGE_LAYOUT_GENERAL, true /* false */)
.Execute(cmdbuffer);
PipelineBarrier()
.AddBuffer(fb->GetBuffers()->SceneLightTiles.get(), VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_WRITE_BIT)
.Execute(cmdbuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
LightTilesPushConstants pushConstants = {};
//auto mesh = fb->GetLevelMesh()->GetMesh();
//pushConstants.normalLightCount = mesh->Mesh.NormalLightCount;
//pushConstants.modulatedLightCount = mesh->Mesh.ModulatedLightCount;
//pushConstants.subtractiveLightCount = mesh->Mesh.SubtractiveLightCount;
auto pipelines = fb->GetRenderPassManager();
auto descriptors = fb->GetDescriptorSetManager();
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipelines->GetLightTilesPipeline());
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_COMPUTE, pipelines->GetLightTilesLayout(), 0, descriptors->GetLightTilesSet());
cmdbuffer->pushConstants(pipelines->GetLightTilesLayout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, (uint32_t)sizeof(LightTilesPushConstants), &pushConstants);
cmdbuffer->dispatch(
(fb->GetBuffers()->GetWidth() + 63) / 64,
(fb->GetBuffers()->GetHeight() + 63) / 64,
1);
PipelineBarrier()
.AddBuffer(fb->GetBuffers()->SceneLightTiles.get(), VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
.Execute(cmdbuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
}
void VkRenderState::DrawLevelMesh(LevelMeshDrawType drawType, bool noFragmentShader)
{
ApplyLevelMesh();

View file

@ -57,6 +57,7 @@ public:
void ResetVertices() override;
// Draw level mesh
void DispatchLightTiles() override;
void DrawLevelMesh(LevelMeshDrawType drawType, bool noFragmentShader) override;
int GetNextQueryIndex() override;
void BeginQuery() override;

View file

@ -114,6 +114,7 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni
VPUniforms.mViewOffsetX = -screen->mSceneViewport.left;
VPUniforms.mViewOffsetY = -screen->mSceneViewport.top;
VPUniforms.mViewHeight = viewheight;
VPUniforms.mLightTilesWidth = (screen->mScreenViewport.width + 63) / 64;
if (lightmode == ELightMode::Build)
{
VPUniforms.mGlobVis = 1 / 64.f;
@ -442,6 +443,7 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state)
state.SetColorMask(false);
state.SetCulling(Cull_CW);
state.DrawLevelMesh(LevelMeshDrawType::Opaque, true);
state.DispatchLightTiles();
state.DrawLevelMesh(LevelMeshDrawType::Masked, false); // To do: properly mark wall top/bottom as opaque so we don't need this
if (gl_portals)
{

View file

@ -19,6 +19,8 @@ layout(set = 1, binding = 0, std140) uniform ViewpointUBO
int uShadowmapFilter;
int uLightBlendMode;
int uLightTilesWidth; // Levelmesh light tiles
};
layout(set = 1, binding = 1, std140) uniform MatricesUBO

View file

@ -1,12 +1,12 @@
layout(local_size_x = 32, local_size_y = 32) in;
layout(binding = 0, rg32f) readonly uniform image2D zminmax;
layout(set = 0, binding = 0, rg32f) readonly uniform image2D zminmax;
layout(binding = 1) readonly buffer Lights
layout(set = 0, binding = 1) readonly buffer Lights
{
vec4 lights[];
};
layout(binding = 1) buffer Tiles
layout(set = 0, binding = 2) buffer Tiles
{
vec4 tiles[];
};
@ -26,18 +26,37 @@ void main()
return;
const int maxLights = 16;
const int lightSize = 3;
const int lightSize = 4;
int tileOffset = (tilePos.x + tilePos.y * zminmaxSize.x) * (1 + maxLights * lightSize);
vec2 minmax = imageLoad(zminmax, tilePos).xy;
float zmin = minmax.x;
float zmax = minmax.y;
int tileNormalCount = 0;
int tileNormalCount = 1;
int tileModulatedCount = 0;
int tileSubtractiveCount = 0;
// To do: cull and add lights
tiles[tileOffset] = vec4(ivec4(tileNormalCount, tileModulatedCount, tileSubtractiveCount, 0));
tiles[tileOffset] = vec4(ivec4(
0,
tileNormalCount,
tileNormalCount + tileModulatedCount,
tileNormalCount + tileModulatedCount + tileSubtractiveCount));
vec3 pos = vec3(-316.0, 64.0, 621.0);
float radius = 200.0;
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;
tiles[tileOffset + 1] = vec4(pos, radius);
tiles[tileOffset + 2] = vec4(color, shadowIndex);
tiles[tileOffset + 3] = vec4(spotDir, lightType);
tiles[tileOffset + 4] = vec4(spotInnerAngle, spotOuterAngle, softShadowRadius, 0.0);
}

View file

@ -21,6 +21,11 @@ void main()
if (ClipDistanceA.x < 0 || ClipDistanceA.y < 0 || ClipDistanceA.z < 0 || ClipDistanceA.w < 0 || ClipDistanceB.x < 0) discard;
#endif
#if defined(USE_LEVELMESH)
const int lightTileSize = 1 + 16 * 4;
uLightIndex = int(uint(gl_FragCoord.x) / 64 + uint(gl_FragCoord.y) / 64 * uLightTilesWidth) * lightTileSize;
#endif
Material material = CreateMaterial();
#ifndef NO_ALPHATEST

View file

@ -73,7 +73,8 @@ layout(push_constant) uniform PushConstants
#define uVertexColor lightdata[uDataIndex].uVertexColor
#define uDesaturationFactor lightdata[uDataIndex].uDesaturationFactor
#define uLightLevel lightdata[uDataIndex].uLightLevel
#define uLightIndex lightdata[uDataIndex].uLightIndex
//#define uLightIndex lightdata[uDataIndex].uLightIndex
int uLightIndex;
#else
#define uVertexColor data[uDataIndex].uVertexColor
#define uDesaturationFactor data[uDataIndex].uDesaturationFactor