implement custom uniforms for material shaders
This commit is contained in:
parent
d23c727350
commit
ea09ae1461
13 changed files with 406 additions and 299 deletions
|
|
@ -131,7 +131,7 @@ VkVertexFormat *VkRenderPassManager::GetVertexFormat(int index)
|
|||
return &VertexFormats[index];
|
||||
}
|
||||
|
||||
VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(bool levelmesh)
|
||||
VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(bool levelmesh, int UserUniformSize)
|
||||
{
|
||||
auto &layout = PipelineLayouts[levelmesh];
|
||||
if (layout)
|
||||
|
|
@ -144,6 +144,12 @@ VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(bool levelmesh)
|
|||
builder.AddSetLayout(levelmesh ? descriptors->GetLevelMeshLayout() : descriptors->GetRSBufferLayout());
|
||||
builder.AddSetLayout(descriptors->GetBindlessLayout());
|
||||
builder.AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants));
|
||||
|
||||
if(UserUniformSize > 0)
|
||||
{
|
||||
builder.AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(PushConstants), UserUniformSize);
|
||||
}
|
||||
|
||||
builder.DebugName("VkRenderPassManager.PipelineLayout");
|
||||
layout = builder.Create(fb->GetDevice());
|
||||
return layout.get();
|
||||
|
|
@ -273,15 +279,25 @@ VulkanRenderPass *VkRenderPassSetup::GetRenderPass(int clearTargets)
|
|||
return RenderPasses[clearTargets].get();
|
||||
}
|
||||
|
||||
VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key)
|
||||
VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms)
|
||||
{
|
||||
auto &item = Pipelines[key];
|
||||
if (!item)
|
||||
item = CreatePipeline(key);
|
||||
return item.get();
|
||||
auto item = Pipelines.find(key);
|
||||
if (item == Pipelines.end())
|
||||
{
|
||||
Uniforms.Clear();
|
||||
auto pipeline = CreatePipeline(key, Uniforms);
|
||||
auto ptr = pipeline.get();
|
||||
Pipelines.insert(std::pair<VkPipelineKey, PipelineData>{key, PipelineData{std::move(pipeline), Uniforms}});
|
||||
return ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
Uniforms = item->second.Uniforms;
|
||||
return item->second.pipeline.get();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key)
|
||||
std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms)
|
||||
{
|
||||
GraphicsPipelineBuilder builder;
|
||||
builder.Cache(fb->GetRenderPassManager()->GetCache());
|
||||
|
|
@ -365,10 +381,12 @@ std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipeli
|
|||
|
||||
builder.RasterizationSamples((VkSampleCountFlagBits)PassKey.Samples);
|
||||
|
||||
builder.Layout(fb->GetRenderPassManager()->GetPipelineLayout(key.ShaderKey.UseLevelMesh));
|
||||
builder.Layout(fb->GetRenderPassManager()->GetPipelineLayout(key.ShaderKey.UseLevelMesh, program->Uniforms.sz));
|
||||
builder.RenderPass(GetRenderPass(0));
|
||||
builder.DebugName("VkRenderPassSetup.Pipeline");
|
||||
|
||||
Uniforms = program->Uniforms;
|
||||
|
||||
return builder.Create(fb->GetDevice());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,21 +69,27 @@ public:
|
|||
bool operator!=(const VkRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkRenderPassKey)) != 0; }
|
||||
};
|
||||
|
||||
struct PipelineData
|
||||
{
|
||||
std::unique_ptr<VulkanPipeline> pipeline;
|
||||
UniformStructHolder Uniforms;
|
||||
};
|
||||
|
||||
class VkRenderPassSetup
|
||||
{
|
||||
public:
|
||||
VkRenderPassSetup(VulkanRenderDevice* fb, const VkRenderPassKey &key);
|
||||
|
||||
VulkanRenderPass *GetRenderPass(int clearTargets);
|
||||
VulkanPipeline *GetPipeline(const VkPipelineKey &key);
|
||||
VulkanPipeline *GetPipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms);
|
||||
|
||||
VkRenderPassKey PassKey;
|
||||
std::unique_ptr<VulkanRenderPass> RenderPasses[8];
|
||||
std::map<VkPipelineKey, std::unique_ptr<VulkanPipeline>> Pipelines;
|
||||
std::map<VkPipelineKey, PipelineData> Pipelines;
|
||||
|
||||
private:
|
||||
std::unique_ptr<VulkanRenderPass> CreateRenderPass(int clearTargets);
|
||||
std::unique_ptr<VulkanPipeline> CreatePipeline(const VkPipelineKey &key);
|
||||
std::unique_ptr<VulkanPipeline> CreatePipeline(const VkPipelineKey &key, UniformStructHolder &Uniforms);
|
||||
|
||||
VulkanRenderDevice* fb = nullptr;
|
||||
};
|
||||
|
|
@ -109,7 +115,7 @@ public:
|
|||
VkRenderPassSetup *GetRenderPass(const VkRenderPassKey &key);
|
||||
int GetVertexFormat(const std::vector<size_t>& bufferStrides, const std::vector<FVertexBufferAttribute>& attrs);
|
||||
VkVertexFormat *GetVertexFormat(int index);
|
||||
VulkanPipelineLayout* GetPipelineLayout(bool levelmesh);
|
||||
VulkanPipelineLayout* GetPipelineLayout(bool levelmesh, int UserUniformSize);
|
||||
|
||||
VkPPRenderPassSetup* GetPPRenderPass(const VkPPRenderPassKey& key);
|
||||
|
||||
|
|
|
|||
|
|
@ -138,14 +138,14 @@ FString VkPPShader::CreateUniformBlockDecl(const char* name, const std::vector<U
|
|||
decl.Format("layout(%s) uniform %s\n{\n", layout.GetChars(), name);
|
||||
for (size_t i = 0; i < fields.size(); i++)
|
||||
{
|
||||
decl.AppendFormat("\t%s %s;\n", GetTypeStr(fields[i].Type), fields[i].Name);
|
||||
decl.AppendFormat("\t%s %s;\n", GetTypeStr(fields[i].Type), fields[i].Name.GetChars());
|
||||
}
|
||||
decl += "};\n";
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
const char* VkPPShader::GetTypeStr(UniformType type)
|
||||
const char* GetTypeStr(UniformType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ public:
|
|||
private:
|
||||
FString LoadShaderCode(const FString &lumpname, const FString &defines, int version);
|
||||
static FString CreateUniformBlockDecl(const char* name, const std::vector<UniformFieldDesc>& fields, int bindingpoint);
|
||||
static const char* GetTypeStr(UniformType type);
|
||||
|
||||
ShaderIncludeResult OnInclude(FString headerName, FString includerName, size_t depth, bool system);
|
||||
FString LoadPublicShaderLump(const char* lumpname);
|
||||
|
|
|
|||
|
|
@ -113,9 +113,9 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key)
|
|||
};
|
||||
|
||||
const auto& desc = effectshaders[key.SpecialEffect];
|
||||
program.vert = LoadVertShader(desc.ShaderName, mainvp, vert_nocustom, desc.defines, key);
|
||||
program.vert = LoadVertShader(desc.ShaderName, mainvp, vert_nocustom, desc.defines, key, nullptr);
|
||||
if (!key.NoFragmentShader)
|
||||
program.frag = LoadFragShader(desc.ShaderName, desc.fp1, desc.fp2, desc.fp3, desc.fp4, desc.fp5, desc.defines, key);
|
||||
program.frag = LoadFragShader(desc.ShaderName, desc.fp1, desc.fp2, desc.fp3, desc.fp4, desc.fp5, desc.defines, key, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -153,9 +153,9 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key)
|
|||
if (key.EffectState < FIRST_USER_SHADER)
|
||||
{
|
||||
const auto& desc = defaultshaders[key.EffectState];
|
||||
program.vert = LoadVertShader(desc.ShaderName, mainvp, vert_nocustom, desc.Defines, key);
|
||||
program.vert = LoadVertShader(desc.ShaderName, mainvp, vert_nocustom, desc.Defines, key, nullptr);
|
||||
if (!key.NoFragmentShader)
|
||||
program.frag = LoadFragShader(desc.ShaderName, mainfp, desc.material_lump, desc.mateffect_lump, desc.lightmodel_lump_shared, desc.lightmodel_lump, desc.Defines, key);
|
||||
program.frag = LoadFragShader(desc.ShaderName, mainfp, desc.material_lump, desc.mateffect_lump, desc.lightmodel_lump_shared, desc.lightmodel_lump, desc.Defines, key, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -163,15 +163,45 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key)
|
|||
const FString& name = ExtractFileBase(desc.shader.GetChars());
|
||||
FString defines = defaultshaders[desc.shaderType].Defines + desc.defines;
|
||||
|
||||
program.vert = LoadVertShader(name, mainvp, desc.vertshader.IsEmpty() ? vert_nocustom : desc.vertshader.GetChars(), defines.GetChars(), key);
|
||||
program.vert = LoadVertShader(name, mainvp, desc.vertshader.IsEmpty() ? vert_nocustom : desc.vertshader.GetChars(), defines.GetChars(), key, &desc.Uniforms);
|
||||
if (!key.NoFragmentShader)
|
||||
program.frag = LoadFragShader(name, mainfp, desc.shader.GetChars(), defaultshaders[desc.shaderType].mateffect_lump, defaultshaders[desc.shaderType].lightmodel_lump_shared, defaultshaders[desc.shaderType].lightmodel_lump, defines.GetChars(), key);
|
||||
program.frag = LoadFragShader(name, mainfp, desc.shader.GetChars(), defaultshaders[desc.shaderType].mateffect_lump, defaultshaders[desc.shaderType].lightmodel_lump_shared, defaultshaders[desc.shaderType].lightmodel_lump, defines.GetChars(), key, &desc.Uniforms);
|
||||
|
||||
desc.Uniforms.WriteUniforms(program.Uniforms);
|
||||
}
|
||||
}
|
||||
return &program;
|
||||
}
|
||||
|
||||
std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key)
|
||||
static void addPushConstants(FString &layoutBlock, const UserUniforms *uniforms)
|
||||
{
|
||||
|
||||
layoutBlock << "// This must match the PushConstants struct\n";
|
||||
layoutBlock << "layout(push_constant) uniform PushConstants\n";
|
||||
layoutBlock << "{\n";
|
||||
layoutBlock << "#if defined(USE_LEVELMESH)\n";
|
||||
layoutBlock << " int unused0;\n";
|
||||
layoutBlock << " int unused1;\n";
|
||||
layoutBlock << "#else\n";
|
||||
layoutBlock << " int uDataIndex; // surfaceuniforms index\n";
|
||||
layoutBlock << " int uLightIndex; // dynamic lights\n";
|
||||
layoutBlock << "#endif\n";
|
||||
layoutBlock << " int uBoneIndexBase; // bone animation\n";
|
||||
layoutBlock << " int uFogballIndex; // fog balls\n";
|
||||
|
||||
if(uniforms && uniforms->UniformStructSize)
|
||||
{
|
||||
for(auto &field : uniforms->Fields)
|
||||
{
|
||||
//layoutBlock.AppendFormat(" layout(offset = %d) %s %s;\n", (field.Offset + sizeof(PushConstants)), GetTypeStr(field.Type), field.Name.GetChars());
|
||||
layoutBlock.AppendFormat(" %s %s;\n", GetTypeStr(field.Type), field.Name.GetChars());
|
||||
}
|
||||
}
|
||||
layoutBlock << "};\n";
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key, const UserUniforms *uniforms)
|
||||
{
|
||||
FString definesBlock;
|
||||
definesBlock << defines;
|
||||
|
|
@ -192,9 +222,11 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername
|
|||
definesBlock << "#define USE_LEVELMESH\n";
|
||||
|
||||
FString layoutBlock;
|
||||
addPushConstants(layoutBlock, uniforms);
|
||||
layoutBlock << LoadPrivateShaderLump("shaders/scene/layout_shared.glsl").GetChars() << "\n";
|
||||
layoutBlock << LoadPrivateShaderLump("shaders/scene/layout_vert.glsl").GetChars() << "\n";
|
||||
|
||||
|
||||
FString codeBlock;
|
||||
codeBlock << LoadPrivateShaderLump(vert_lump).GetChars() << "\n";
|
||||
codeBlock << LoadPublicShaderLump(vert_lump_custom).GetChars() << "\n";
|
||||
|
|
@ -211,7 +243,7 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername
|
|||
.Create(shadername.GetChars(), fb->GetDevice());
|
||||
}
|
||||
|
||||
std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char* mateffect_lump, const char *light_lump_shared, const char *light_lump, const char *defines, const VkShaderKey& key)
|
||||
std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char* mateffect_lump, const char *light_lump_shared, const char *light_lump, const char *defines, const VkShaderKey& key, const UserUniforms *uniforms)
|
||||
{
|
||||
FString definesBlock;
|
||||
if (fb->IsRayQueryEnabled()) definesBlock << "\n#define SUPPORTS_RAYQUERY\n";
|
||||
|
|
@ -299,9 +331,11 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername
|
|||
else definesBlock << "#define uFogEnabled 0\n";
|
||||
|
||||
FString layoutBlock;
|
||||
addPushConstants(layoutBlock, uniforms);
|
||||
layoutBlock << LoadPrivateShaderLump("shaders/scene/layout_shared.glsl").GetChars() << "\n";
|
||||
layoutBlock << LoadPrivateShaderLump("shaders/scene/layout_frag.glsl").GetChars() << "\n";
|
||||
|
||||
|
||||
FString codeBlock;
|
||||
codeBlock << LoadPrivateShaderLump(frag_lump).GetChars() << "\n";
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "hwrenderer/postprocessing/hw_useruniforms.h"
|
||||
|
||||
class ShaderIncludeResult;
|
||||
class VulkanRenderDevice;
|
||||
class VulkanDevice;
|
||||
|
|
@ -122,6 +124,8 @@ class VkShaderProgram
|
|||
public:
|
||||
std::unique_ptr<VulkanShader> vert;
|
||||
std::unique_ptr<VulkanShader> frag;
|
||||
|
||||
UniformStructHolder Uniforms;
|
||||
};
|
||||
|
||||
class VkShaderManager
|
||||
|
|
@ -146,8 +150,8 @@ public:
|
|||
VulkanShader* GetLightTilesShader() { return LightTiles.get(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<VulkanShader> LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key);
|
||||
std::unique_ptr<VulkanShader> LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char* mateffect_lump, const char *light_lump_shared, const char *lightmodel_lump, const char *defines, const VkShaderKey& key);
|
||||
std::unique_ptr<VulkanShader> LoadVertShader(FString shadername, const char *vert_lump, const char *vert_lump_custom, const char *defines, const VkShaderKey& key, const UserUniforms *uniforms);
|
||||
std::unique_ptr<VulkanShader> LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char* mateffect_lump, const char *light_lump_shared, const char *lightmodel_lump, const char *defines, const VkShaderKey& key, const UserUniforms *uniforms);
|
||||
|
||||
ShaderIncludeResult OnInclude(FString headerName, FString includerName, size_t depth, bool system);
|
||||
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ void VkRenderState::ApplyRenderPass(int dt)
|
|||
|
||||
if (changingPipeline)
|
||||
{
|
||||
mCommandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey));
|
||||
mCommandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey, mUniforms));
|
||||
mPipelineKey = pipelineKey;
|
||||
}
|
||||
}
|
||||
|
|
@ -444,7 +444,12 @@ void VkRenderState::ApplyPushConstants()
|
|||
mPushConstants.uBoneIndexBase = mBoneIndexBase;
|
||||
mPushConstants.uFogballIndex = mFogballIndex >= 0 ? (mFogballIndex % MAX_FOGBALL_DATA) : -1;
|
||||
|
||||
mCommandBuffer->pushConstants(fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants);
|
||||
mCommandBuffer->pushConstants(fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh, mUniforms.sz), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants);
|
||||
|
||||
if(mUniforms.sz > 0)
|
||||
{
|
||||
mCommandBuffer->pushConstants(fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh, mUniforms.sz), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, (uint32_t)sizeof(PushConstants), (uint32_t)mUniforms.sz, mUniforms.addr);
|
||||
}
|
||||
}
|
||||
|
||||
void VkRenderState::ApplyMatrices()
|
||||
|
|
@ -510,7 +515,7 @@ void VkRenderState::ApplyBufferSets()
|
|||
if (mViewpointOffset != mLastViewpointOffset || matrixOffset != mLastMatricesOffset || surfaceUniformsOffset != mLastSurfaceUniformsOffset || lightsOffset != mLastLightsOffset || fogballsOffset != mLastFogballsOffset)
|
||||
{
|
||||
auto descriptors = fb->GetDescriptorSetManager();
|
||||
VulkanPipelineLayout* layout = fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh);
|
||||
VulkanPipelineLayout* layout = fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.ShaderKey.UseLevelMesh, mUniforms.sz);
|
||||
|
||||
uint32_t offsets[5] = { mViewpointOffset, matrixOffset, surfaceUniformsOffset, lightsOffset, fogballsOffset };
|
||||
mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedSet());
|
||||
|
|
@ -1092,14 +1097,14 @@ void VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPip
|
|||
pushConstants.uBoneIndexBase = -1;
|
||||
pushConstants.uFogballIndex = -1;
|
||||
|
||||
VulkanPipelineLayout* layout = fb->GetRenderPassManager()->GetPipelineLayout(pipelineKey.ShaderKey.UseLevelMesh);
|
||||
VulkanPipelineLayout* layout = fb->GetRenderPassManager()->GetPipelineLayout(pipelineKey.ShaderKey.UseLevelMesh, mUniforms.sz);
|
||||
uint32_t viewpointOffset = mViewpointOffset;
|
||||
uint32_t matrixOffset = mRSBuffers->MatrixBuffer->Offset();
|
||||
uint32_t fogballsOffset = 0;
|
||||
uint32_t offsets[] = { viewpointOffset, matrixOffset, fogballsOffset };
|
||||
|
||||
auto descriptors = fb->GetDescriptorSetManager();
|
||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey));
|
||||
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mPassSetup->GetPipeline(pipelineKey, mUniforms));
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedSet());
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetLevelMeshSet(), 3, offsets);
|
||||
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptors->GetBindlessSet());
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ protected:
|
|||
bool mDepthClamp = true;
|
||||
VulkanCommandBuffer *mCommandBuffer = nullptr;
|
||||
VkPipelineKey mPipelineKey = {};
|
||||
UniformStructHolder mUniforms;
|
||||
VkRenderPassSetup* mPassSetup = nullptr;
|
||||
int mClearTargets = 0;
|
||||
bool mNeedApply = true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue