mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-03-13 22:42:07 +00:00
Improve VkShaderProgram to handle more program types
Fix memory alignment issues with the shader/pipeline keys
This commit is contained in:
parent
e5848ead7a
commit
3b93dd3d7e
3 changed files with 67 additions and 146 deletions
|
@ -17,36 +17,42 @@ class GraphicsPipelineBuilder;
|
|||
class VkPipelineKey
|
||||
{
|
||||
public:
|
||||
FRenderStyle RenderStyle;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t DrawType : 3;
|
||||
uint32_t CullMode : 2;
|
||||
uint32_t ColorMask : 4;
|
||||
uint32_t DepthWrite : 1;
|
||||
uint32_t DepthTest : 1;
|
||||
uint32_t DepthClamp : 1;
|
||||
uint32_t DepthBias : 1;
|
||||
uint32_t DepthFunc : 2;
|
||||
uint32_t StencilTest : 1;
|
||||
uint32_t StencilPassOp : 2;
|
||||
uint32_t Unused : 14;
|
||||
uint64_t DrawType : 3;
|
||||
uint64_t CullMode : 2;
|
||||
uint64_t ColorMask : 4;
|
||||
uint64_t DepthWrite : 1;
|
||||
uint64_t DepthTest : 1;
|
||||
uint64_t DepthClamp : 1;
|
||||
uint64_t DepthBias : 1;
|
||||
uint64_t DepthFunc : 2;
|
||||
uint64_t StencilTest : 1;
|
||||
uint64_t StencilPassOp : 2;
|
||||
uint64_t Unused : 46;
|
||||
};
|
||||
uint32_t AsDWORD = 0;
|
||||
uint64_t AsQWORD = 0;
|
||||
};
|
||||
|
||||
VkShaderKey ShaderKey;
|
||||
int VertexFormat = 0;
|
||||
int NumTextureLayers = 0;
|
||||
|
||||
VkShaderKey ShaderKey;
|
||||
FRenderStyle RenderStyle;
|
||||
|
||||
int Padding = 0; // for 64 bit alignment
|
||||
|
||||
bool operator<(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) < 0; }
|
||||
bool operator==(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) == 0; }
|
||||
bool operator!=(const VkPipelineKey &other) const { return memcmp(this, &other, sizeof(VkPipelineKey)) != 0; }
|
||||
};
|
||||
|
||||
static_assert(sizeof(FRenderStyle) == 4, "sizeof(FRenderStyle) is not its expected size!");
|
||||
static_assert(sizeof(VkShaderKey) == 16, "sizeof(VkShaderKey) is not its expected size!");
|
||||
static_assert(sizeof(VkPipelineKey) == 16 + 16 + 8, "sizeof(VkPipelineKey) is not its expected size!"); // If this assert fails, the flags union no longer adds up to 64 bits. Or there are gaps in the class so the memcmp doesn't work.
|
||||
|
||||
class VkRenderPassKey
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -30,89 +30,6 @@
|
|||
#include "version.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
bool VkShaderManager::CompileNextShader()
|
||||
{
|
||||
const char *mainvp = "shaders/scene/vert_main.glsl";
|
||||
const char *mainfp = "shaders/scene/frag_surface.glsl";
|
||||
int i = compileIndex;
|
||||
|
||||
if (compileState == 0)
|
||||
{
|
||||
// regular material shaders
|
||||
|
||||
VkShaderProgram prog;
|
||||
prog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines);
|
||||
prog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].material_lump, defaultshaders[i].mateffect_lump, defaultshaders[i].lightmodel_lump, defaultshaders[i].Defines, true, compilePass == GBUFFER_PASS);
|
||||
mMaterialShaders[compilePass].push_back(std::move(prog));
|
||||
|
||||
compileIndex++;
|
||||
if (defaultshaders[compileIndex].ShaderName == nullptr)
|
||||
{
|
||||
compileIndex = 0;
|
||||
compileState++;
|
||||
}
|
||||
}
|
||||
else if (compileState == 1)
|
||||
{
|
||||
// NAT material shaders
|
||||
|
||||
VkShaderProgram natprog;
|
||||
natprog.vert = LoadVertShader(defaultshaders[i].ShaderName, mainvp, defaultshaders[i].Defines);
|
||||
natprog.frag = LoadFragShader(defaultshaders[i].ShaderName, mainfp, defaultshaders[i].material_lump, defaultshaders[i].mateffect_lump, defaultshaders[i].lightmodel_lump, defaultshaders[i].Defines, false, compilePass == GBUFFER_PASS);
|
||||
mMaterialShadersNAT[compilePass].push_back(std::move(natprog));
|
||||
|
||||
compileIndex++;
|
||||
if (compileIndex == SHADER_NoTexture)
|
||||
{
|
||||
compileIndex = 0;
|
||||
compileState++;
|
||||
if (usershaders.Size() == 0) compileState++;
|
||||
}
|
||||
}
|
||||
else if (compileState == 2)
|
||||
{
|
||||
// user shaders
|
||||
|
||||
const FString& name = ExtractFileBase(usershaders[i].shader);
|
||||
FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines;
|
||||
|
||||
VkShaderProgram prog;
|
||||
prog.vert = LoadVertShader(name, mainvp, defines);
|
||||
prog.frag = LoadFragShader(name, mainfp, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].mateffect_lump, defaultshaders[usershaders[i].shaderType].lightmodel_lump, defines, true, compilePass == GBUFFER_PASS);
|
||||
mMaterialShaders[compilePass].push_back(std::move(prog));
|
||||
|
||||
compileIndex++;
|
||||
if (compileIndex >= (int)usershaders.Size())
|
||||
{
|
||||
compileIndex = 0;
|
||||
compileState++;
|
||||
}
|
||||
}
|
||||
else if (compileState == 3)
|
||||
{
|
||||
// Effect shaders
|
||||
|
||||
VkShaderProgram prog;
|
||||
prog.vert = LoadVertShader(effectshaders[i].ShaderName, mainvp, effectshaders[i].defines);
|
||||
prog.frag = LoadFragShader(effectshaders[i].ShaderName, effectshaders[i].fp1, effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].fp4, effectshaders[i].defines, true, compilePass == GBUFFER_PASS);
|
||||
mEffectShaders[compilePass].push_back(std::move(prog));
|
||||
|
||||
compileIndex++;
|
||||
if (compileIndex >= MAX_EFFECTS)
|
||||
{
|
||||
compileIndex = 0;
|
||||
compilePass++;
|
||||
if (compilePass == MAX_PASS_TYPES)
|
||||
{
|
||||
compileIndex = -1; // we're done.
|
||||
return true;
|
||||
}
|
||||
compileState = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VkShaderManager::VkShaderManager(VulkanRenderDevice* fb) : fb(fb)
|
||||
{
|
||||
CompileNextShader();
|
||||
|
@ -128,41 +45,42 @@ void VkShaderManager::Deinit()
|
|||
RemoveVkPPShader(PPShaders.back());
|
||||
}
|
||||
|
||||
VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key, EPassType passType)
|
||||
VkShaderProgram* VkShaderManager::Get(const VkShaderKey& k, EPassType passType)
|
||||
{
|
||||
if (key.SpecialEffect != EFF_NONE)
|
||||
VkShaderKey key = k;
|
||||
key.GBufferPass = passType;
|
||||
auto& program = programs[key];
|
||||
if (!program.frag)
|
||||
{
|
||||
return GetEffect(key.SpecialEffect, passType);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Get(key.EffectState, key.AlphaTest, passType);
|
||||
}
|
||||
}
|
||||
const char* mainvp = "shaders/scene/vert_main.glsl";
|
||||
const char* mainfp = "shaders/scene/frag_surface.glsl";
|
||||
|
||||
VkShaderProgram *VkShaderManager::GetEffect(int effect, EPassType passType)
|
||||
{
|
||||
if (compileIndex == -1 && effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[passType][effect].frag)
|
||||
{
|
||||
return &mEffectShaders[passType][effect];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
if (key.SpecialEffect != EFF_NONE)
|
||||
{
|
||||
const auto& desc = effectshaders[key.SpecialEffect];
|
||||
program.vert = LoadVertShader(desc.ShaderName, mainvp, desc.defines);
|
||||
program.frag = LoadFragShader(desc.ShaderName, desc.fp1, desc.fp2, desc.fp3, desc.fp4, desc.defines, true, key.GBufferPass);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key.EffectState < FIRST_USER_SHADER)
|
||||
{
|
||||
const auto& desc = defaultshaders[key.EffectState];
|
||||
program.vert = LoadVertShader(desc.ShaderName, mainvp, desc.Defines);
|
||||
program.frag = LoadFragShader(desc.ShaderName, mainfp, desc.material_lump, desc.mateffect_lump, desc.lightmodel_lump, desc.Defines, key.AlphaTest, key.GBufferPass);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& desc = usershaders[key.EffectState];
|
||||
const FString& name = ExtractFileBase(desc.shader);
|
||||
FString defines = defaultshaders[desc.shaderType].Defines + desc.defines;
|
||||
|
||||
VkShaderProgram *VkShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType)
|
||||
{
|
||||
if (compileIndex != -1)
|
||||
return &mMaterialShaders[0][0];
|
||||
// indices 0-2 match the warping modes, 3 no texture, the following are custom
|
||||
if (!alphateston && eff < SHADER_NoTexture)
|
||||
{
|
||||
return &mMaterialShadersNAT[passType][eff]; // Non-alphatest shaders are only created for default, warp1+2. The rest won't get used anyway
|
||||
program.vert = LoadVertShader(name, mainvp, defines);
|
||||
program.frag = LoadFragShader(name, mainfp, desc.shader, defaultshaders[desc.shaderType].mateffect_lump, defaultshaders[desc.shaderType].lightmodel_lump, defines, key.AlphaTest, key.GBufferPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (eff < (unsigned int)mMaterialShaders[passType].size())
|
||||
{
|
||||
return &mMaterialShaders[passType][eff];
|
||||
}
|
||||
return nullptr;
|
||||
return &program;
|
||||
}
|
||||
|
||||
std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(FString shadername, const char *vert_lump, const char *defines)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "name.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#define SHADER_MIN_REQUIRED_TEXTURE_LAYERS 11
|
||||
|
||||
|
@ -65,16 +66,17 @@ public:
|
|||
{
|
||||
struct
|
||||
{
|
||||
uint32_t AlphaTest : 1;
|
||||
uint32_t Simple2D : 1; // uFogEnabled == -3
|
||||
uint32_t TextureMode : 3; // uTextureMode & 0xffff
|
||||
uint32_t ClampY : 1; // uTextureMode & TEXF_ClampY
|
||||
uint32_t Brightmap : 1; // uTextureMode & TEXF_Brightmap
|
||||
uint32_t Detailmap : 1; // uTextureMode & TEXF_Detailmap
|
||||
uint32_t Glowmap : 1; // uTextureMode & TEXF_Glowmap
|
||||
uint32_t Unused : 23;
|
||||
uint64_t AlphaTest : 1; // !NO_ALPHATEST
|
||||
uint64_t Simple2D : 1; // uFogEnabled == -3
|
||||
uint64_t TextureMode : 3; // uTextureMode & 0xffff
|
||||
uint64_t ClampY : 1; // uTextureMode & TEXF_ClampY
|
||||
uint64_t Brightmap : 1; // uTextureMode & TEXF_Brightmap
|
||||
uint64_t Detailmap : 1; // uTextureMode & TEXF_Detailmap
|
||||
uint64_t Glowmap : 1; // uTextureMode & TEXF_Glowmap
|
||||
uint64_t GBufferPass : 1; // GBUFFER_PASS
|
||||
uint64_t Unused : 54;
|
||||
};
|
||||
uint32_t AsDWORD = 0;
|
||||
uint64_t AsQWORD = 0;
|
||||
};
|
||||
|
||||
int SpecialEffect = 0;
|
||||
|
@ -85,6 +87,8 @@ public:
|
|||
bool operator!=(const VkShaderKey& other) const { return memcmp(this, &other, sizeof(VkShaderKey)) != 0; }
|
||||
};
|
||||
|
||||
static_assert(sizeof(VkShaderKey) == 16, "sizeof(VkShaderKey) is not its expected size!"); // If this assert fails, the flags union no longer adds up to 64 bits. Or there are gaps in the class so the memcmp doesn't work.
|
||||
|
||||
class VkShaderProgram
|
||||
{
|
||||
public:
|
||||
|
@ -102,7 +106,7 @@ public:
|
|||
|
||||
VkShaderProgram* Get(const VkShaderKey& key, EPassType passType);
|
||||
|
||||
bool CompileNextShader();
|
||||
bool CompileNextShader() { return true; }
|
||||
|
||||
VkPPShader* GetVkShader(PPShader* shader);
|
||||
|
||||
|
@ -110,9 +114,6 @@ public:
|
|||
void RemoveVkPPShader(VkPPShader* shader);
|
||||
|
||||
private:
|
||||
VkShaderProgram* GetEffect(int effect, EPassType passType);
|
||||
VkShaderProgram* Get(unsigned int eff, bool alphateston, EPassType passType);
|
||||
|
||||
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* mateffect_lump, const char *lightmodel_lump, const char *defines, bool alphatest, bool gbufferpass);
|
||||
|
||||
|
@ -124,11 +125,7 @@ private:
|
|||
|
||||
VulkanRenderDevice* fb = nullptr;
|
||||
|
||||
std::vector<VkShaderProgram> mMaterialShaders[MAX_PASS_TYPES];
|
||||
std::vector<VkShaderProgram> mMaterialShadersNAT[MAX_PASS_TYPES];
|
||||
std::vector<VkShaderProgram> mEffectShaders[MAX_PASS_TYPES];
|
||||
uint8_t compilePass = 0, compileState = 0;
|
||||
int compileIndex = 0;
|
||||
std::map<VkShaderKey, VkShaderProgram> programs;
|
||||
|
||||
std::list<VkPPShader*> PPShaders;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue