- Move uniform declarations to the GLDEFS lump to make it Vulkan safe (a vulkan implementation can then declare them in an uniform block)

- Change SetUniform functions to be clearscope as they can be safely called from both play and ui
- Add PlayerInfo argument to SetUniform functions to force the modder to take network play into account
- Add enabled flag on custom postprocess shaders
- Removed custom texture support until a more clean implementation is written
This commit is contained in:
Magnus Norddahl 2017-07-08 14:44:07 +02:00
parent 8a0e801cb5
commit a38de996e7
4 changed files with 262 additions and 71 deletions

View file

@ -69,72 +69,29 @@ void FCustomPostProcessShaders::Run(FString target)
void PostProcessShaderInstance::Run() void PostProcessShaderInstance::Run()
{ {
if (!Program) if (!IsShaderSupported())
{ return;
const char *lumpName = Desc->ShaderLumpName.GetChars();
int lump = Wads.CheckNumForFullName(lumpName);
if (lump == -1) I_FatalError("Unable to load '%s'", lumpName);
FString code = Wads.ReadLump(lump).GetString().GetChars();
Program.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); // Hmm, should this use shader.shaderversion? CompileShader();
Program.Compile(FShaderProgram::Fragment, lumpName, code, "", Desc->ShaderVersion);
Program.SetFragDataLocation(0, "FragColor");
Program.Link(Desc->ShaderLumpName.GetChars());
Program.SetAttribLocation(0, "PositionInProjection");
InputTexture.Init(Program, "InputTexture");
CustomTexture.Init(Program, "CustomTexture");
if (Desc->Texture) if (!Desc->Enabled)
{ return;
HWTexture = new FHardwareTexture(Desc->Texture->GetWidth(), Desc->Texture->GetHeight(), false);
HWTexture->CreateTexture((unsigned char*)Desc->Texture->GetPixelsBgra(), Desc->Texture->GetWidth(), Desc->Texture->GetHeight(), 0, false, 0, "CustomTexture");
}
}
FGLDebug::PushGroup(Desc->ShaderLumpName.GetChars()); FGLDebug::PushGroup(Desc->ShaderLumpName.GetChars());
FGLPostProcessState savedState; FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
GLRenderer->mBuffers->BindNextFB(); GLRenderer->mBuffers->BindNextFB();
GLRenderer->mBuffers->BindCurrentTexture(0); GLRenderer->mBuffers->BindCurrentTexture(0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Program.Bind(); mProgram.Bind();
TMap<FString, float>::Iterator it1f(Desc->Uniform1f); UpdateUniforms();
TMap<FString, float>::Pair *pair1f;
while (it1f.NextPair(pair1f))
{
int location = glGetUniformLocation(Program, pair1f->Key.GetChars());
if (location != -1)
glUniform1f(location, pair1f->Value);
}
TMap<FString, int>::Iterator it1i(Desc->Uniform1i); mInputTexture.Set(0);
TMap<FString, int>::Pair *pair1i;
while (it1i.NextPair(pair1i))
{
int location = glGetUniformLocation(Program, pair1i->Key.GetChars());
if (location != -1)
glUniform1i(location, pair1i->Value);
}
InputTexture.Set(0);
if (HWTexture)
{
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, HWTexture->GetTextureHandle(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glActiveTexture(GL_TEXTURE0);
CustomTexture.Set(1);
}
GLRenderer->RenderScreenQuad(); GLRenderer->RenderScreenQuad();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -143,3 +100,95 @@ void PostProcessShaderInstance::Run()
FGLDebug::PopGroup(); FGLDebug::PopGroup();
} }
bool PostProcessShaderInstance::IsShaderSupported()
{
int activeShaderVersion = (int)round(gl.glslversion * 10) * 10;
return activeShaderVersion >= Desc->ShaderVersion;
}
void PostProcessShaderInstance::CompileShader()
{
if (mProgram)
return;
// Get the custom shader
const char *lumpName = Desc->ShaderLumpName.GetChars();
int lump = Wads.CheckNumForFullName(lumpName);
if (lump == -1) I_FatalError("Unable to load '%s'", lumpName);
FString code = Wads.ReadLump(lump).GetString().GetChars();
// Build an uniform block to use be used as input
// (this is technically not an uniform block, but it could be changed into that for Vulkan GLSL support)
FString uniformBlock;
TMap<FString, PostProcessUniformValue>::Iterator it(Desc->Uniforms);
TMap<FString, PostProcessUniformValue>::Pair *pair;
while (it.NextPair(pair))
{
FString type;
FString name = pair->Key;
switch (pair->Value.Type)
{
case PostProcessUniformType::Float: type = "float"; break;
case PostProcessUniformType::Int: type = "int"; break;
case PostProcessUniformType::Vec2: type = "vec2"; break;
case PostProcessUniformType::Vec3: type = "vec3"; break;
default: break;
}
if (!type.IsEmpty())
uniformBlock.AppendFormat("uniform %s %s;\n", type.GetChars(), name.GetChars());
}
// Build the input textures
FString uniformTextures;
uniformTextures += "uniform sampler2D InputTexture;\n";
// Setup pipeline
FString pipelineInOut;
pipelineInOut += "in vec2 TexCoord;\n";
pipelineInOut += "out vec4 FragColor;\n";
FString prolog;
prolog += uniformBlock;
prolog += uniformTextures;
prolog += pipelineInOut;
mProgram.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", Desc->ShaderVersion);
mProgram.Compile(FShaderProgram::Fragment, lumpName, code, prolog.GetChars(), Desc->ShaderVersion);
mProgram.SetFragDataLocation(0, "FragColor");
mProgram.Link(Desc->ShaderLumpName.GetChars());
mProgram.SetAttribLocation(0, "PositionInProjection");
mInputTexture.Init(mProgram, "InputTexture");
}
void PostProcessShaderInstance::UpdateUniforms()
{
TMap<FString, PostProcessUniformValue>::Iterator it(Desc->Uniforms);
TMap<FString, PostProcessUniformValue>::Pair *pair;
while (it.NextPair(pair))
{
int location = glGetUniformLocation(mProgram, pair->Key.GetChars());
if (location != -1)
{
switch (pair->Value.Type)
{
case PostProcessUniformType::Float:
glUniform1f(location, (float)pair->Value.Values[0]);
break;
case PostProcessUniformType::Int:
glUniform1i(location, (int)pair->Value.Values[0]);
break;
case PostProcessUniformType::Vec2:
glUniform2f(location, (float)pair->Value.Values[0], (float)pair->Value.Values[1]);
break;
case PostProcessUniformType::Vec3:
glUniform3f(location, (float)pair->Value.Values[0], (float)pair->Value.Values[1], (float)pair->Value.Values[2]);
break;
default:
break;
}
}
}
}

View file

@ -4,16 +4,31 @@
class PostProcessShaderInstance; class PostProcessShaderInstance;
enum class PostProcessUniformType
{
Undefined,
Int,
Float,
Vec2,
Vec3
};
struct PostProcessUniformValue
{
PostProcessUniformType Type = PostProcessUniformType::Undefined;
double Values[4] = { 0.0, 0.0, 0.0, 0.0 };
};
struct PostProcessShader struct PostProcessShader
{ {
FString Target; FString Target;
FString ShaderLumpName; FString ShaderLumpName;
int ShaderVersion = 0; int ShaderVersion = 0;
FTexture *Texture = nullptr;
FString Name; FString Name;
TMap<FString, int> Uniform1i; bool Enabled = false;
TMap<FString, float> Uniform1f;
TMap<FString, PostProcessUniformValue> Uniforms;
}; };
extern TArray<PostProcessShader> PostProcessShaders; extern TArray<PostProcessShader> PostProcessShaders;
@ -26,10 +41,14 @@ public:
void Run(); void Run();
PostProcessShader *Desc; PostProcessShader *Desc;
FShaderProgram Program;
FBufferedUniformSampler InputTexture; private:
FBufferedUniformSampler CustomTexture; bool IsShaderSupported();
FHardwareTexture *HWTexture = nullptr; void CompileShader();
void UpdateUniforms();
FShaderProgram mProgram;
FBufferedUniformSampler mInputTexture;
}; };
class FCustomPostProcessShaders class FCustomPostProcessShaders

View file

@ -37,6 +37,7 @@
#include "sc_man.h" #include "sc_man.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "vm.h" #include "vm.h"
#include "d_player.h"
#include "gl/system/gl_interface.h" #include "gl/system/gl_interface.h"
#include "gl/system/gl_debug.h" #include "gl/system/gl_debug.h"
@ -698,11 +699,28 @@ void gl_ParseHardwareShader(FScanner &sc, int deflump)
sc.MustGetString(); sc.MustGetString();
shaderdesc.Name = sc.String; shaderdesc.Name = sc.String;
} }
else if (sc.Compare("texture")) else if (sc.Compare("uniform"))
{ {
sc.MustGetString(); sc.MustGetString();
FTextureID no = TexMan.CheckForTexture(sc.String, FTexture::TEX_Wall); FString uniformType = sc.String;
shaderdesc.Texture = TexMan[no]; uniformType.ToLower();
sc.MustGetString();
FString uniformName = sc.String;
PostProcessUniformType parsedType = PostProcessUniformType::Undefined;
if (uniformType.Compare("int") == 0)
parsedType = PostProcessUniformType::Int;
else if (uniformType.Compare("float") == 0)
parsedType = PostProcessUniformType::Float;
else if (uniformType.Compare("vec2") == 0)
parsedType = PostProcessUniformType::Vec2;
else if (uniformType.Compare("vec3") == 0)
parsedType = PostProcessUniformType::Vec3;
if (parsedType != PostProcessUniformType::Undefined)
shaderdesc.Uniforms[uniformName].Type = parsedType;
} }
} }
@ -769,18 +787,110 @@ void gl_ParseHardwareShader(FScanner &sc, int deflump)
} }
} }
static bool IsConsolePlayer(player_t *player)
{
AActor *activator = player ? player->mo : nullptr;
if (activator == nullptr || activator->player == nullptr)
return false;
return int(activator->player - players) == consoleplayer;
}
DEFINE_ACTION_FUNCTION(_Shader, SetEnabled)
{
PARAM_PROLOGUE;
PARAM_POINTER_DEF(player, player_t);
PARAM_STRING(shaderName);
PARAM_BOOL_DEF(value);
if (IsConsolePlayer(player))
{
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
{
PostProcessShader &shader = PostProcessShaders[i];
if (shader.Name == shaderName)
shader.Enabled = value;
}
}
return 0;
}
DEFINE_ACTION_FUNCTION(_Shader, SetUniform1f) DEFINE_ACTION_FUNCTION(_Shader, SetUniform1f)
{ {
PARAM_PROLOGUE; PARAM_PROLOGUE;
PARAM_POINTER_DEF(player, player_t);
PARAM_STRING(shaderName); PARAM_STRING(shaderName);
PARAM_STRING(uniformName); PARAM_STRING(uniformName);
PARAM_FLOAT_DEF(value); PARAM_FLOAT_DEF(value);
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) if (IsConsolePlayer(player))
{ {
PostProcessShader &shader = PostProcessShaders[i]; for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
if (shader.Name == shaderName) {
shader.Uniform1f[uniformName] = value; PostProcessShader &shader = PostProcessShaders[i];
if (shader.Name == shaderName)
{
double *vec4 = shader.Uniforms[uniformName].Values;
vec4[0] = value;
vec4[1] = 0.0;
vec4[2] = 0.0;
vec4[3] = 1.0;
}
}
}
return 0;
}
DEFINE_ACTION_FUNCTION(_Shader, SetUniform2f)
{
PARAM_PROLOGUE;
PARAM_POINTER_DEF(player, player_t);
PARAM_STRING(shaderName);
PARAM_STRING(uniformName);
PARAM_FLOAT_DEF(x);
PARAM_FLOAT_DEF(y);
if (IsConsolePlayer(player))
{
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
{
PostProcessShader &shader = PostProcessShaders[i];
if (shader.Name == shaderName)
{
double *vec4 = shader.Uniforms[uniformName].Values;
vec4[0] = x;
vec4[1] = y;
vec4[2] = 0.0;
vec4[3] = 1.0;
}
}
}
return 0;
}
DEFINE_ACTION_FUNCTION(_Shader, SetUniform3f)
{
PARAM_PROLOGUE;
PARAM_POINTER_DEF(player, player_t);
PARAM_STRING(shaderName);
PARAM_STRING(uniformName);
PARAM_FLOAT_DEF(x);
PARAM_FLOAT_DEF(y);
PARAM_FLOAT_DEF(z);
if (IsConsolePlayer(player))
{
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
{
PostProcessShader &shader = PostProcessShaders[i];
if (shader.Name == shaderName)
{
double *vec4 = shader.Uniforms[uniformName].Values;
vec4[0] = x;
vec4[1] = y;
vec4[2] = z;
vec4[3] = 1.0;
}
}
} }
return 0; return 0;
} }
@ -788,15 +898,25 @@ DEFINE_ACTION_FUNCTION(_Shader, SetUniform1f)
DEFINE_ACTION_FUNCTION(_Shader, SetUniform1i) DEFINE_ACTION_FUNCTION(_Shader, SetUniform1i)
{ {
PARAM_PROLOGUE; PARAM_PROLOGUE;
PARAM_POINTER_DEF(player, player_t);
PARAM_STRING(shaderName); PARAM_STRING(shaderName);
PARAM_STRING(uniformName); PARAM_STRING(uniformName);
PARAM_INT_DEF(value); PARAM_INT_DEF(value);
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++) if (IsConsolePlayer(player))
{ {
PostProcessShader &shader = PostProcessShaders[i]; for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
if (shader.Name == shaderName) {
shader.Uniform1i[uniformName] = value; PostProcessShader &shader = PostProcessShaders[i];
if (shader.Name == shaderName)
{
double *vec4 = shader.Uniforms[uniformName].Values;
vec4[0] = (double)value;
vec4[1] = 0.0;
vec4[2] = 0.0;
vec4[3] = 1.0;
}
}
} }
return 0; return 0;
} }

View file

@ -777,6 +777,9 @@ class Lighting : SectorEffect native
struct Shader native struct Shader native
{ {
native static void SetUniform1f(string shaderName, string uniformName, float value); native clearscope static void SetEnabled(PlayerInfo player, string shaderName, bool enable);
native static void SetUniform1i(string shaderName, string uniformName, int value); native clearscope static void SetUniform1f(PlayerInfo player, string shaderName, string uniformName, float value);
native clearscope static void SetUniform2f(PlayerInfo player, string shaderName, string uniformName, vector2 value);
native clearscope static void SetUniform3f(PlayerInfo player, string shaderName, string uniformName, vector3 value);
native clearscope static void SetUniform1i(PlayerInfo player, string shaderName, string uniformName, int value);
} }