Optimise lights to create separate shaders for different combinations. Code cleanup

This commit is contained in:
Emile Belanger 2021-03-09 17:54:37 +00:00
parent d333e46a45
commit 0dca516719
6 changed files with 122 additions and 70 deletions

View file

@ -109,7 +109,24 @@ bool FGLRenderState::ApplyShader()
}
}
// Need to calc light data now in order to select correct shader
float* lightPtr = NULL;
int modLights = 0;
int subLights = 0;
int addLights = 0;
if (mLightIndex >= 0)
{
lightPtr = ((float*)screen->mLights->GetBuffer()->Memory());
lightPtr += ((int64_t)mLightIndex * 4);
//float array[64];
//memcpy(array, ptr, 4 * 64);
// Calculate how much light data there is to upload, this is stored in the first 4 floats
modLights = int(lightPtr[1]) / LIGHT_VEC4_NUM;
subLights = (int(lightPtr[2]) - int(lightPtr[1])) / LIGHT_VEC4_NUM;
addLights = (int(lightPtr[3]) - int(lightPtr[2])) / LIGHT_VEC4_NUM;
}
if (mSpecialEffect > EFF_NONE)
{
@ -119,43 +136,46 @@ bool FGLRenderState::ApplyShader()
{
activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : SHADER_NoTexture, mAlphaThreshold >= 0.f, mPassType);
int textureMode = (mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode);
ShaderFlavourData flavour;
flavour.textureMode = (mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode);
int texFlags = mTextureModeFlags; if (!mBrightmapEnabled) texFlags &= ~(TEXF_Brightmap | TEXF_Glowmap);
texFlags >>= 16; //Move flags to start of word
flavour.texFlags = mTextureModeFlags; if (!mBrightmapEnabled) flavour.texFlags &= ~(TEXF_Brightmap | TEXF_Glowmap);
flavour.texFlags >>= 16; //Move flags to start of word
int blendFlags = (int)(mStreamData.uTextureAddColor.a + 0.01);
flavour.blendFlags = (int)(mStreamData.uTextureAddColor.a + 0.01);
bool twoDFog = false;
bool fogEnabled = false;
bool fogEquationRadial = false;
bool colouredFog = false;
flavour.twoDFog = false;
flavour.fogEnabled = false;
flavour.fogEquationRadial = false;
flavour.colouredFog = false;
if (mFogEnabled)
{
if (mFogEnabled == 2)
{
twoDFog = true;
flavour.twoDFog = true;
}
else if(gl_fogmode)
{
fogEnabled = true;
flavour.fogEnabled = true;
if (gl_fogmode == 2)
fogEquationRadial = true;
flavour.fogEquationRadial = true;
if ((GetFogColor() & 0xffffff) != 0)
colouredFog = true;
flavour.colouredFog = true;
}
}
bool doDesaturate = false;
doDesaturate = mStreamData.uDesaturationFactor != 0;
flavour.doDesaturate = mStreamData.uDesaturationFactor != 0;
bool dynLights = false;
dynLights = (mLightIndex >= 0);
// Yes create shaders for all combinations of active lights to avoid more branches
flavour.dynLightsMod = (modLights > 0);
flavour.dynLightsSub = (subLights > 0);
flavour.dynLightsAdd = (addLights > 0);
activeShader->Bind(textureMode, texFlags, blendFlags, twoDFog, fogEnabled, fogEquationRadial, colouredFog, doDesaturate, dynLights);
activeShader->Bind(flavour);
}
@ -260,15 +280,20 @@ bool FGLRenderState::ApplyShader()
matrixToGL(identityMatrix, activeShader->cur->normalmodelmatrix_index);
}
// Upload the light data
if (mLightIndex >= 0)
{
int totalLights = modLights + subLights + addLights;
float* ptr = ((float*)screen->mLights->GetBuffer()->Memory());
ptr += ((int64_t)mLightIndex * 4);
float array[64];
memcpy(array, ptr, 4 * 64);
// Calculate the total number of vec4s we need
int totalVectors = totalLights * LIGHT_VEC4_NUM + 1;
// TODO!!! If there are too many lights we need to remove some of the lights and modify the data
// At the moment the shader will just try to read off the end of the array...
if (totalVectors > gles.numlightvectors)
totalVectors = gles.numlightvectors;
glUniform4fv(activeShader->cur->lights_index, 64, ptr);
glUniform4fv(activeShader->cur->lights_index, totalVectors, lightPtr);
activeShader->cur->muLightIndex.Set(0);
}

View file

@ -247,8 +247,9 @@ bool FShader::Load(const char * name, const char * vert_prog_lump_, const char *
precision mediump int;
precision mediump float;
// This must match the HWViewpointUniforms struct
// light buffers
uniform vec4 lights[MAXIMUM_LIGHT_VECTORS];
uniform mat4 ProjectionMatrix;
uniform mat4 ViewMatrix;
uniform mat4 NormalViewMatrix;
@ -311,9 +312,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump_, const char *
uniform mat4 NormalModelMatrix;
uniform mat4 TextureMatrix;
// light buffers
uniform vec4 lights[128];
// textures
uniform sampler2D tex;
@ -646,9 +645,9 @@ FShader::~FShader()
//
//==========================================================================
bool FShader::Bind(int textureMode, int texFlags, int blendFlags, bool twoDFog, bool fogEnabled, bool fogEquationRadial, bool colouredFog, bool doDesaturate, bool dynLights)
bool FShader::Bind(ShaderFlavourData& flavour)
{
uint32_t tag = CreateShaderTag(textureMode, texFlags, blendFlags, twoDFog, fogEnabled, fogEquationRadial, colouredFog, doDesaturate, dynLights);
uint32_t tag = CreateShaderTag(flavour);
cur = variants[tag];
@ -656,16 +655,20 @@ bool FShader::Bind(int textureMode, int texFlags, int blendFlags, bool twoDFog,
if (!cur)
{
FString variantConfig = "\n";
variantConfig.AppendFormat("#define DEF_TEXTURE_MODE %d\n", textureMode);
variantConfig.AppendFormat("#define DEF_TEXTURE_FLAGS %d\n", texFlags);
variantConfig.AppendFormat("#define DEF_BLEND_FLAGS %d\n", blendFlags);
variantConfig.AppendFormat("#define DEF_FOG_2D %d\n", twoDFog);
variantConfig.AppendFormat("#define DEF_FOG_ENABLED %d\n", fogEnabled);
variantConfig.AppendFormat("#define DEF_FOG_RADIAL %d\n", fogEquationRadial);
variantConfig.AppendFormat("#define DEF_FOG_COLOURED %d\n", colouredFog);
variantConfig.AppendFormat("#define MAXIMUM_LIGHT_VECTORS %d\n", gles.numlightvectors);
variantConfig.AppendFormat("#define DEF_TEXTURE_MODE %d\n", flavour.textureMode);
variantConfig.AppendFormat("#define DEF_TEXTURE_FLAGS %d\n", flavour.texFlags);
variantConfig.AppendFormat("#define DEF_BLEND_FLAGS %d\n", flavour.blendFlags);
variantConfig.AppendFormat("#define DEF_FOG_2D %d\n", flavour.twoDFog);
variantConfig.AppendFormat("#define DEF_FOG_ENABLED %d\n", flavour.fogEnabled);
variantConfig.AppendFormat("#define DEF_FOG_RADIAL %d\n", flavour.fogEquationRadial);
variantConfig.AppendFormat("#define DEF_FOG_COLOURED %d\n", flavour.colouredFog);
variantConfig.AppendFormat("#define DEF_DO_DESATURATE %d\n", doDesaturate);
variantConfig.AppendFormat("#define DEF_DYNAMIC_LIGHTS %d\n", dynLights);
variantConfig.AppendFormat("#define DEF_DO_DESATURATE %d\n", flavour.doDesaturate);
variantConfig.AppendFormat("#define DEF_DYNAMIC_LIGHTS_MOD %d\n", flavour.dynLightsMod);
variantConfig.AppendFormat("#define DEF_DYNAMIC_LIGHTS_SUB %d\n", flavour.dynLightsSub);
variantConfig.AppendFormat("#define DEF_DYNAMIC_LIGHTS_ADD %d\n", flavour.dynLightsAdd);
Printf("Shader: %s", variantConfig.GetChars());
@ -879,7 +882,8 @@ FShader *FShaderCollection::BindEffect(int effect)
{
if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect] != NULL)
{
mEffectShaders[effect]->Bind(0,0,0,0,0,0,0,0,0);
ShaderFlavourData flavour;
mEffectShaders[effect]->Bind(flavour);
return mEffectShaders[effect];
}
return NULL;

View file

@ -249,6 +249,22 @@ public:
}
};
class ShaderFlavourData
{
public:
int textureMode;
int texFlags;
int blendFlags;
bool twoDFog;
bool fogEnabled;
bool fogEquationRadial;
bool colouredFog;
bool doDesaturate;
bool dynLightsMod;
bool dynLightsSub;
bool dynLightsAdd;
};
class FShader
{
friend class FShaderCollection;
@ -353,28 +369,33 @@ public:
void LoadVariant();
uint32_t CreateShaderTag(int textureMode, int texf, int blendFlags, bool twoDFog, bool fogEnabled, bool fogEquationRadial, bool colouredFog, bool doDesaturate, bool dynLights)
uint32_t CreateShaderTag(ShaderFlavourData &flavour)
{
uint32_t tag = 0;
tag |= (textureMode & 0x7);
tag |= (flavour.textureMode & 0x7);
tag |= (texf & 7) << 3;
tag |= (flavour.texFlags & 7) << 3;
tag |= (blendFlags & 7) << 6;
tag |= (flavour.blendFlags & 7) << 6;
tag |= (twoDFog & 1) << 7;
tag |= (fogEnabled & 1) << 8;
tag |= (fogEquationRadial & 1) << 9;
tag |= (colouredFog & 1) << 10;
tag |= (flavour.twoDFog & 1) << 7;
tag |= (flavour.fogEnabled & 1) << 8;
tag |= (flavour.fogEquationRadial & 1) << 9;
tag |= (flavour.colouredFog & 1) << 10;
tag |= (doDesaturate & 1) << 11;
tag |= (flavour.doDesaturate & 1) << 11;
tag |= (dynLights & 1) << 12;
tag |= (flavour.dynLightsMod & 1) << 12;
tag |= (flavour.dynLightsSub & 1) << 13;
tag |= (flavour.dynLightsAdd & 1) << 14;
return tag;
}
bool Bind(int textureMode, int texFlags, int blendFlags, bool twoDFog, bool fogEnabled, bool fogEquationRadial, bool colouredFog, bool doDesaturate, bool dynLights);
bool Bind(ShaderFlavourData& flavour);
};

View file

@ -103,6 +103,8 @@ namespace OpenGLESRenderer
gles.max_texturesize = 1024 * 4;
gles.modelstring = (char*)"MODEL";
gles.vendorstring = (char*)"EMILES";
gles.maxlights = 32;
gles.numlightvectors = (gles.maxlights * 4) + 1; // maxlights lights, + size vector at the beginning
}
}

View file

@ -36,6 +36,9 @@
#include <OpenGL/OpenGL.h>
#endif
// This is the number of vec4s make up the light data
#define LIGHT_VEC4_NUM 4
namespace OpenGLESRenderer
{
struct RenderContextGLES
@ -44,6 +47,8 @@ namespace OpenGLESRenderer
unsigned int maxuniforms;
unsigned int maxuniformblock;
unsigned int uniformblockalignment;
unsigned int maxlights;
unsigned int numlightvectors;
float glslversion;
int max_texturesize;
char* vendorstring;

View file

@ -42,29 +42,27 @@ vec3 ProcessMaterialLight(Material material, vec3 color)
vec4 dynlight = uDynLightColor;
vec3 normal = material.Normal;
#if (DEF_DYNAMIC_LIGHTS == 1)
ivec4 lightRange = ivec4(lights[uLightIndex]) + ivec4(uLightIndex + 1);
//if (lightRange.z > lightRange.x)
#if (DEF_DYNAMIC_LIGHTS_MOD == 1)
// modulated lights
for(int i=lightRange.x; i<lightRange.y; i+=4)
{
// modulated lights
for(int i=lightRange.x; i<lightRange.y; i+=4)
{
dynlight.rgb += lightContribution(i, normal);
}
// subtractive lights
for(int i=lightRange.y; i<lightRange.z; i+=4)
{
dynlight.rgb -= lightContribution(i, normal);
}
dynlight.rgb += lightContribution(i, normal);
}
#endif
#if (DEF_DYNAMIC_LIGHTS_SUB == 1)
// subtractive lights
for(int i=lightRange.y; i<lightRange.z; i+=4)
{
dynlight.rgb -= lightContribution(i, normal);
}
#endif
vec3 frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
//if (lightRange.w > lightRange.z)
{
#if (DEF_DYNAMIC_LIGHTS_ADD == 1)
vec4 addlight = vec4(0.0,0.0,0.0,0.0);
// additive lights
@ -74,10 +72,7 @@ vec3 ProcessMaterialLight(Material material, vec3 color)
}
frag = clamp(frag + desaturate(addlight).rgb, 0.0, 1.0);
}
#endif
return frag;
#else
return material.Base.rgb * clamp(color, 0.0, 1.4);
#endif
}