- load all the shaders and use the right one for each renderpass

This commit is contained in:
Magnus Norddahl 2019-03-01 02:40:02 +01:00
commit d4118a755c
11 changed files with 173 additions and 64 deletions

View file

@ -138,8 +138,18 @@ void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key)
{
auto fb = GetVulkanFrameBuffer();
GraphicsPipelineBuilder builder;
builder.addVertexShader(fb->GetShaderManager()->vert.get());
builder.addFragmentShader(fb->GetShaderManager()->frag.get());
VkShaderProgram *program;
if (key.SpecialEffect != EFF_NONE)
{
program = fb->GetShaderManager()->GetEffect(key.SpecialEffect);
}
else
{
program = fb->GetShaderManager()->Get(key.EffectState, key.AlphaTest);
}
builder.addVertexShader(program->vert.get());
builder.addFragmentShader(program->frag.get());
builder.addVertexBufferBinding(0, sizeof(F2DDrawer::TwoDVertex));
builder.addVertexAttribute(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(F2DDrawer::TwoDVertex, x));

View file

@ -11,10 +11,15 @@ class VkRenderPassKey
{
public:
FRenderStyle RenderStyle;
int SpecialEffect;
int EffectState;
bool AlphaTest;
bool operator<(const VkRenderPassKey &other) const
{
return RenderStyle.AsDWORD < other.RenderStyle.AsDWORD;
uint64_t a = RenderStyle.AsDWORD | (static_cast<uint64_t>(SpecialEffect) << 32) | (static_cast<uint64_t>(EffectState) << 40) | (static_cast<uint64_t>(AlphaTest) << 48);
uint64_t b = other.RenderStyle.AsDWORD | (static_cast<uint64_t>(other.SpecialEffect) << 32) | (static_cast<uint64_t>(other.EffectState) << 40) | (static_cast<uint64_t>(other.AlphaTest) << 48);
return a < b;
}
};

View file

@ -148,6 +148,19 @@ void VkRenderState::Apply(int dt)
// Find a render pass that matches our state
VkRenderPassKey passKey;
passKey.RenderStyle = mRenderStyle;
if (mSpecialEffect > EFF_NONE)
{
passKey.SpecialEffect = mSpecialEffect;
passKey.EffectState = 0;
passKey.AlphaTest = false;
}
else
{
int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0);
passKey.SpecialEffect = EFF_NONE;
passKey.EffectState = mTextureEnabled ? effectState : SHADER_NoTexture;
passKey.AlphaTest = mAlphaThreshold >= 0.f;
}
VkRenderPassSetup *passSetup = passManager->GetRenderPass(passKey);
// Is this the one we already have or do we need to change render pass?

View file

@ -10,8 +10,46 @@ VkShaderManager::VkShaderManager(VulkanDevice *device) : device(device)
{
ShInitialize();
vert = LoadVertShader("shaders/glsl/main.vp", "");
frag = LoadFragShader("shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "");
const char *mainvp = "shaders/glsl/main.vp";
const char *mainfp = "shaders/glsl/main.fp";
bool gbufferpass = false;
for (int i = 0; defaultshaders[i].ShaderName != NULL; i++)
{
// To do: use defaultshaders[i].ShaderName for better debugging
VkShaderProgram prog;
prog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines);
prog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, gbufferpass);
mMaterialShaders.push_back(std::move(prog));
if (i < SHADER_NoTexture)
{
VkShaderProgram natprog;
natprog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines);
natprog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, gbufferpass);
mMaterialShadersNAT.push_back(std::move(natprog));
}
}
for (unsigned i = 0; i < usershaders.Size(); i++)
{
FString name = ExtractFileBase(usershaders[i].shader);
FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines;
VkShaderProgram prog;
prog.vert = LoadVertShader(name, mainvp, defaultshaders[i].Defines);
prog.frag = LoadFragShader(name, mainfp, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, gbufferpass);
mMaterialShaders.push_back(std::move(prog));
}
for (int i = 0; i < MAX_EFFECTS; i++)
{
VkShaderProgram prog;
prog.vert = LoadVertShader(effectshaders[i].ShaderName, effectshaders[i].vp, defaultshaders[i].Defines);
prog.frag = LoadFragShader(effectshaders[i].ShaderName, effectshaders[i].fp1, effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines, true, false);
mEffectShaders[i] = std::move(prog);
}
}
VkShaderManager::~VkShaderManager()
@ -19,6 +57,29 @@ VkShaderManager::~VkShaderManager()
ShFinalize();
}
VkShaderProgram *VkShaderManager::GetEffect(int effect)
{
if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect].frag)
{
return &mEffectShaders[effect];
}
return nullptr;
}
VkShaderProgram *VkShaderManager::Get(unsigned int eff, bool alphateston)
{
// indices 0-2 match the warping modes, 3 is brightmap, 4 no texture, the following are custom
if (!alphateston && eff <= 3)
{
return &mMaterialShadersNAT[eff]; // Non-alphatest shaders are only created for default, warp1+2 and brightmap. The rest won't get used anyway
}
else if (eff < (unsigned int)mMaterialShaders.size())
{
return &mMaterialShaders[eff];
}
return nullptr;
}
static const char *shaderBindings = R"(
// This must match the HWViewpointUniforms struct
@ -125,7 +186,7 @@ static const char *shaderBindings = R"(
#define VULKAN_COORDINATE_SYSTEM
)";
std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(const char *vert_lump, const char *defines)
std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *defines)
{
FString code = GetTargetGlslVersion();
code << defines << shaderBindings;
@ -137,10 +198,14 @@ std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(const char *vert_l
return builder.create(device);
}
std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(const char *frag_lump, const char *material_lump, const char *light_lump, const char *defines)
std::unique_ptr<VulkanShader> VkShaderManager::LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char *light_lump, const char *defines, bool alphatest, bool gbufferpass)
{
FString code = GetTargetGlslVersion();
code << defines << shaderBindings;
if (!alphatest) code << "#define NO_ALPHATEST\n";
if (gbufferpass) code << "#define GBUFFER_PASS\n";
code << "\n#line 1\n";
code << LoadShaderLump(frag_lump).GetChars() << "\n";

View file

@ -4,6 +4,7 @@
#include "utility/vectors.h"
#include "r_data/matrix.h"
#include "name.h"
#include "hwrenderer/scene/hw_renderstate.h"
class VulkanDevice;
class VulkanShader;
@ -63,21 +64,32 @@ struct PushConstants
FVector2 uSpecularMaterial;
};
class VkShaderProgram
{
public:
std::unique_ptr<VulkanShader> vert;
std::unique_ptr<VulkanShader> frag;
};
class VkShaderManager
{
public:
VkShaderManager(VulkanDevice *device);
~VkShaderManager();
std::unique_ptr<VulkanShader> vert;
std::unique_ptr<VulkanShader> frag;
VkShaderProgram *GetEffect(int effect);
VkShaderProgram *Get(unsigned int eff, bool alphateston);
private:
std::unique_ptr<VulkanShader> LoadVertShader(const char *vert_lump, const char *defines);
std::unique_ptr<VulkanShader> LoadFragShader(const char *frag_lump, const char *material_lump, const char *light_lump, const char *defines);
std::unique_ptr<VulkanShader> LoadVertShader(FString shadername, const char *vert_lump, const char *defines);
std::unique_ptr<VulkanShader> LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char *light_lump, const char *defines, bool alphatest, bool gbufferpass);
FString GetTargetGlslVersion();
FString LoadShaderLump(const char *lumpname);
VulkanDevice *device;
std::vector<VkShaderProgram> mMaterialShaders;
std::vector<VkShaderProgram> mMaterialShadersNAT;
VkShaderProgram mEffectShaders[MAX_EFFECTS];
};