vkdoom_m/src/rendering/vulkan/shaders/vk_shader.cpp
2019-02-26 20:19:54 +01:00

213 lines
5.5 KiB
C++

#include "vk_shader.h"
#include "vulkan/system/vk_builders.h"
#include "hwrenderer/utility/hw_shaderpatcher.h"
#include "w_wad.h"
#include "doomerrors.h"
#include <ShaderLang.h>
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", "");
}
VkShaderManager::~VkShaderManager()
{
ShFinalize();
}
static const char *shaderBindings = R"(
// This must match the HWViewpointUniforms struct
layout(set = 0, binding = 0, std140) uniform ViewpointUBO {
mat4 ProjectionMatrix;
mat4 ViewMatrix;
mat4 NormalViewMatrix;
vec4 uCameraPos;
vec4 uClipLine;
float uGlobVis; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0
int uPalLightLevels;
int uViewHeight; // Software fuzz scaling
float uClipHeight;
float uClipHeightDirection;
int uShadowmapFilter;
float timer; // timer data for material shaders
};
// light buffers
layout(set = 0, binding = 1, std430) buffer LightBufferSSO
{
vec4 lights[];
};
layout(set = 0, binding = 2, std140) uniform MatricesUBO {
mat4 ModelMatrix;
mat4 NormalModelMatrix;
mat4 TextureMatrix;
};
layout(set = 0, binding = 3, std140) uniform ColorsUBO {
vec4 uObjectColor;
vec4 uObjectColor2;
vec4 uDynLightColor;
vec4 uAddColor;
vec4 uFogColor;
float uDesaturationFactor;
float uInterpolationFactor;
float padding0, padding1;
};
layout(set = 0, binding = 4, std140) uniform GlowingWallsUBO {
vec4 uGlowTopPlane;
vec4 uGlowTopColor;
vec4 uGlowBottomPlane;
vec4 uGlowBottomColor;
vec4 uGradientTopPlane;
vec4 uGradientBottomPlane;
vec4 uSplitTopPlane;
vec4 uSplitBottomPlane;
};
// textures
layout(set = 1, binding = 0) uniform sampler2D tex;
// layout(set = 1, binding = 1) uniform sampler2D texture2;
// layout(set = 1, binding = 2) uniform sampler2D texture3;
// layout(set = 1, binding = 3) uniform sampler2D texture4;
// layout(set = 1, binding = 4) uniform sampler2D texture5;
// layout(set = 1, binding = 5) uniform sampler2D texture6;
// layout(set = 1, binding = 16) uniform sampler2D ShadowMap;
// This must match the PushConstants struct
layout(push_constant) uniform PushConstants
{
int uTextureMode;
float uAlphaThreshold;
vec2 uClipSplit;
// Lighting + Fog
float uLightLevel;
float uFogDensity;
float uLightFactor;
float uLightDist;
int uFogEnabled;
// dynamic lights
int uLightIndex;
// Blinn glossiness and specular level
vec2 uSpecularMaterial;
};
// material types
#if defined(SPECULAR)
#define normaltexture texture2
#define speculartexture texture3
#define brighttexture texture4
#elif defined(PBR)
#define normaltexture texture2
#define metallictexture texture3
#define roughnesstexture texture4
#define aotexture texture5
#define brighttexture texture6
#else
#define brighttexture texture2
#endif
// #define SUPPORTS_SHADOWMAPS
#define VULKAN_COORDINATE_SYSTEM
)";
std::unique_ptr<VulkanShader> VkShaderManager::LoadVertShader(const char *vert_lump, const char *defines)
{
FString code = GetTargetGlslVersion();
code << defines << shaderBindings;
code << "#line 1\n";
code << LoadShaderLump(vert_lump).GetChars() << "\n";
ShaderBuilder builder;
builder.setVertexShader(code);
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)
{
FString code = GetTargetGlslVersion();
code << defines << shaderBindings;
code << "\n#line 1\n";
code << LoadShaderLump(frag_lump).GetChars() << "\n";
if (material_lump)
{
if (material_lump[0] != '#')
{
FString pp_code = LoadShaderLump(material_lump);
if (pp_code.IndexOf("ProcessMaterial") < 0)
{
// this looks like an old custom hardware shader.
// add ProcessMaterial function that calls the older ProcessTexel function
code << "\n" << LoadShaderLump("shaders/glsl/func_defaultmat.fp").GetChars() << "\n";
if (pp_code.IndexOf("ProcessTexel") < 0)
{
// this looks like an even older custom hardware shader.
// We need to replace the ProcessTexel call to make it work.
code.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));");
}
if (pp_code.IndexOf("ProcessLight") >= 0)
{
// The ProcessLight signatured changed. Forward to the old one.
code << "\nvec4 ProcessLight(vec4 color);\n";
code << "\nvec4 ProcessLight(Material material, vec4 color) { return ProcessLight(color); }\n";
}
}
code << "\n#line 1\n";
code << RemoveLegacyUserUniforms(pp_code).GetChars();
code.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders.
if (pp_code.IndexOf("ProcessLight") < 0)
{
code << "\n" << LoadShaderLump("shaders/glsl/func_defaultlight.fp").GetChars() << "\n";
}
}
else
{
// material_lump is not a lump name but the source itself (from generated shaders)
code << (material_lump + 1) << "\n";
}
}
if (light_lump)
{
code << "\n#line 1\n";
code << LoadShaderLump(light_lump).GetChars();
}
ShaderBuilder builder;
builder.setFragmentShader(code);
return builder.create(device);
}
FString VkShaderManager::GetTargetGlslVersion()
{
return "#version 450 core\n";
}
FString VkShaderManager::LoadShaderLump(const char *lumpname)
{
int lump = Wads.CheckNumForFullName(lumpname, 0);
if (lump == -1) I_Error("Unable to load '%s'", lumpname);
FMemLump data = Wads.ReadLump(lump);
return data.GetString();
}