- merged gzdoom-gles2 and fixed some issues with pipeline size validation.
This commit is contained in:
parent
a8a5613675
commit
441cd0796f
116 changed files with 12502 additions and 80 deletions
952
src/common/rendering/gles/gles_shader.cpp
Normal file
952
src/common/rendering/gles/gles_shader.cpp
Normal file
|
|
@ -0,0 +1,952 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2004-2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
/*
|
||||
** gl_shader.cpp
|
||||
**
|
||||
** GLSL shader handling
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gles_system.h"
|
||||
#include "c_cvars.h"
|
||||
#include "v_video.h"
|
||||
#include "filesystem.h"
|
||||
#include "engineerrors.h"
|
||||
#include "cmdlib.h"
|
||||
#include "md5.h"
|
||||
#include "gles_shader.h"
|
||||
#include "hw_shaderpatcher.h"
|
||||
#include "shaderuniforms.h"
|
||||
#include "hw_viewpointuniforms.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "i_specialpaths.h"
|
||||
#include "printf.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "matrix.h"
|
||||
#include "gles_renderer.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace OpenGLESRenderer
|
||||
{
|
||||
|
||||
CVAR(Int, gles_glsl_precision, 2, 0); // 0 = low, 1 = medium, 2 = high
|
||||
|
||||
FString GetGLSLPrecision()
|
||||
{
|
||||
FString str = "precision highp int;\n \
|
||||
precision highp float;\n";
|
||||
|
||||
if (gles_glsl_precision == 0)
|
||||
str.Substitute("highp", "lowp");
|
||||
else if (gles_glsl_precision == 1)
|
||||
str.Substitute("highp", "mediump");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
struct ProgramBinary
|
||||
{
|
||||
uint32_t format;
|
||||
TArray<uint8_t> data;
|
||||
};
|
||||
|
||||
static const char *ShaderMagic = "ZDSC";
|
||||
|
||||
static std::map<FString, std::unique_ptr<ProgramBinary>> ShaderCache; // Not a TMap because it doesn't support unique_ptr move semantics
|
||||
|
||||
bool IsShaderCacheActive()
|
||||
{
|
||||
static bool active = true;
|
||||
static bool firstcall = true;
|
||||
|
||||
if (firstcall)
|
||||
{
|
||||
const char *vendor = (const char *)glGetString(GL_VENDOR);
|
||||
active = !(strstr(vendor, "Intel") == nullptr);
|
||||
firstcall = false;
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
static FString CalcProgramBinaryChecksum(const FString &vertex, const FString &fragment)
|
||||
{
|
||||
const GLubyte *vendor = glGetString(GL_VENDOR);
|
||||
const GLubyte *renderer = glGetString(GL_RENDERER);
|
||||
const GLubyte *version = glGetString(GL_VERSION);
|
||||
|
||||
uint8_t digest[16];
|
||||
MD5Context md5;
|
||||
md5.Update(vendor, (unsigned int)strlen((const char*)vendor));
|
||||
md5.Update(renderer, (unsigned int)strlen((const char*)renderer));
|
||||
md5.Update(version, (unsigned int)strlen((const char*)version));
|
||||
md5.Update((const uint8_t *)vertex.GetChars(), (unsigned int)vertex.Len());
|
||||
md5.Update((const uint8_t *)fragment.GetChars(), (unsigned int)fragment.Len());
|
||||
md5.Final(digest);
|
||||
|
||||
char hexdigest[33];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
int v = digest[i] >> 4;
|
||||
hexdigest[i * 2] = v < 10 ? ('0' + v) : ('a' + v - 10);
|
||||
v = digest[i] & 15;
|
||||
hexdigest[i * 2 + 1] = v < 10 ? ('0' + v) : ('a' + v - 10);
|
||||
}
|
||||
hexdigest[32] = 0;
|
||||
return hexdigest;
|
||||
}
|
||||
|
||||
static FString CreateProgramCacheName(bool create)
|
||||
{
|
||||
FString path = M_GetCachePath(create);
|
||||
if (create) CreatePath(path);
|
||||
path << "/shadercache.zdsc";
|
||||
return path;
|
||||
}
|
||||
|
||||
static void LoadShaders()
|
||||
{
|
||||
static bool loaded = false;
|
||||
if (loaded)
|
||||
return;
|
||||
loaded = true;
|
||||
|
||||
try
|
||||
{
|
||||
FString path = CreateProgramCacheName(false);
|
||||
FileReader fr;
|
||||
if (!fr.OpenFile(path))
|
||||
I_Error("Could not open shader file");
|
||||
|
||||
char magic[4];
|
||||
fr.Read(magic, 4);
|
||||
if (memcmp(magic, ShaderMagic, 4) != 0)
|
||||
I_Error("Not a shader cache file");
|
||||
|
||||
uint32_t count = fr.ReadUInt32();
|
||||
if (count > 512)
|
||||
I_Error("Too many shaders cached");
|
||||
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
char hexdigest[33];
|
||||
if (fr.Read(hexdigest, 32) != 32)
|
||||
I_Error("Read error");
|
||||
hexdigest[32] = 0;
|
||||
|
||||
std::unique_ptr<ProgramBinary> binary(new ProgramBinary());
|
||||
binary->format = fr.ReadUInt32();
|
||||
uint32_t size = fr.ReadUInt32();
|
||||
if (size > 1024 * 1024)
|
||||
I_Error("Shader too big, probably file corruption");
|
||||
|
||||
binary->data.Resize(size);
|
||||
if (fr.Read(binary->data.Data(), binary->data.Size()) != binary->data.Size())
|
||||
I_Error("Read error");
|
||||
|
||||
ShaderCache[hexdigest] = std::move(binary);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ShaderCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
static void SaveShaders()
|
||||
{
|
||||
FString path = CreateProgramCacheName(true);
|
||||
std::unique_ptr<FileWriter> fw(FileWriter::Open(path));
|
||||
if (fw)
|
||||
{
|
||||
uint32_t count = (uint32_t)ShaderCache.size();
|
||||
fw->Write(ShaderMagic, 4);
|
||||
fw->Write(&count, sizeof(uint32_t));
|
||||
for (const auto &it : ShaderCache)
|
||||
{
|
||||
uint32_t size = it.second->data.Size();
|
||||
fw->Write(it.first.GetChars(), 32);
|
||||
fw->Write(&it.second->format, sizeof(uint32_t));
|
||||
fw->Write(&size, sizeof(uint32_t));
|
||||
fw->Write(it.second->data.Data(), it.second->data.Size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TArray<uint8_t> LoadCachedProgramBinary(const FString &vertex, const FString &fragment, uint32_t &binaryFormat)
|
||||
{
|
||||
LoadShaders();
|
||||
|
||||
auto it = ShaderCache.find(CalcProgramBinaryChecksum(vertex, fragment));
|
||||
if (it != ShaderCache.end())
|
||||
{
|
||||
binaryFormat = it->second->format;
|
||||
return it->second->data;
|
||||
}
|
||||
else
|
||||
{
|
||||
binaryFormat = 0;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void SaveCachedProgramBinary(const FString &vertex, const FString &fragment, const TArray<uint8_t> &binary, uint32_t binaryFormat)
|
||||
{
|
||||
auto &entry = ShaderCache[CalcProgramBinaryChecksum(vertex, fragment)];
|
||||
entry.reset(new ProgramBinary());
|
||||
entry->format = binaryFormat;
|
||||
entry->data = binary;
|
||||
|
||||
SaveShaders();
|
||||
}
|
||||
|
||||
bool FShader::Configure(const char* name, const char* vert_prog_lump, const char* fragprog, const char* fragprog2, const char* light_fragprog, const char* defines)
|
||||
{
|
||||
mVertProg = vert_prog_lump;
|
||||
mFragProg = fragprog;
|
||||
mFragProg2 = fragprog2;
|
||||
mLightProg = light_fragprog;
|
||||
mDefinesBase = defines;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FShader::LoadVariant()
|
||||
{
|
||||
//mDefinesBase
|
||||
Load(mName.GetChars(), mVertProg, mFragProg, mFragProg2, mLightProg, mDefinesBase);
|
||||
}
|
||||
|
||||
bool FShader::Load(const char * name, const char * vert_prog_lump_, const char * frag_prog_lump_, const char * proc_prog_lump_, const char * light_fragprog_, const char * defines)
|
||||
{
|
||||
ShaderVariantData* shaderData = new ShaderVariantData();
|
||||
|
||||
FString vert_prog_lump = vert_prog_lump_;
|
||||
FString frag_prog_lump = frag_prog_lump_;
|
||||
FString proc_prog_lump = proc_prog_lump_;
|
||||
FString light_fragprog = light_fragprog_;
|
||||
|
||||
vert_prog_lump.Substitute("shaders/", "shaders_gles/");
|
||||
frag_prog_lump.Substitute("shaders/", "shaders_gles/");
|
||||
proc_prog_lump.Substitute("shaders/", "shaders_gles/");
|
||||
light_fragprog.Substitute("shaders/", "shaders_gles/");
|
||||
|
||||
//light_fragprog.Substitute("material_pbr", "material_normal");
|
||||
|
||||
if(light_fragprog.Len())
|
||||
light_fragprog = "shaders_gles/glsl/material_normal.fp"; // NOTE: Always use normal material for now, ignore others
|
||||
|
||||
|
||||
static char buffer[10000];
|
||||
FString error;
|
||||
|
||||
FString i_data = GetGLSLPrecision();
|
||||
|
||||
i_data += R"(
|
||||
|
||||
// light buffers
|
||||
uniform vec4 lights[MAXIMUM_LIGHT_VECTORS];
|
||||
|
||||
uniform mat4 ProjectionMatrix;
|
||||
uniform mat4 ViewMatrix;
|
||||
uniform mat4 NormalViewMatrix;
|
||||
|
||||
uniform vec4 uCameraPos;
|
||||
uniform vec4 uClipLine;
|
||||
|
||||
uniform float uGlobVis; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0
|
||||
uniform int uPalLightLevels;
|
||||
uniform int uViewHeight; // Software fuzz scaling
|
||||
uniform float uClipHeight;
|
||||
uniform float uClipHeightDirection;
|
||||
uniform int uShadowmapFilter;
|
||||
|
||||
uniform int uTextureMode;
|
||||
uniform vec2 uClipSplit;
|
||||
uniform float uAlphaThreshold;
|
||||
|
||||
// colors
|
||||
uniform vec4 uObjectColor;
|
||||
uniform vec4 uObjectColor2;
|
||||
uniform vec4 uDynLightColor;
|
||||
uniform vec4 uAddColor;
|
||||
uniform vec4 uTextureBlendColor;
|
||||
uniform vec4 uTextureModulateColor;
|
||||
uniform vec4 uTextureAddColor;
|
||||
uniform vec4 uFogColor;
|
||||
uniform float uDesaturationFactor;
|
||||
uniform float uInterpolationFactor;
|
||||
|
||||
// Glowing walls stuff
|
||||
uniform vec4 uGlowTopPlane;
|
||||
uniform vec4 uGlowTopColor;
|
||||
uniform vec4 uGlowBottomPlane;
|
||||
uniform vec4 uGlowBottomColor;
|
||||
|
||||
uniform vec4 uGradientTopPlane;
|
||||
uniform vec4 uGradientBottomPlane;
|
||||
|
||||
uniform vec4 uSplitTopPlane;
|
||||
uniform vec4 uSplitBottomPlane;
|
||||
|
||||
uniform vec4 uDetailParms;
|
||||
// Lighting + Fog
|
||||
uniform vec4 uLightAttr;
|
||||
#define uLightLevel uLightAttr.a
|
||||
#define uFogDensity uLightAttr.b
|
||||
#define uLightFactor uLightAttr.g
|
||||
#define uLightDist uLightAttr.r
|
||||
//uniform int uFogEnabled;
|
||||
|
||||
// dynamic lights
|
||||
uniform ivec4 uLightRange;
|
||||
|
||||
// Blinn glossiness and specular level
|
||||
uniform vec2 uSpecularMaterial;
|
||||
|
||||
// matrices
|
||||
uniform mat4 ModelMatrix;
|
||||
uniform mat4 NormalModelMatrix;
|
||||
uniform mat4 TextureMatrix;
|
||||
|
||||
uniform vec4 uFixedColormapStart;
|
||||
uniform vec4 uFixedColormapRange;
|
||||
|
||||
// textures
|
||||
uniform sampler2D tex;
|
||||
uniform sampler2D ShadowMap;
|
||||
uniform sampler2D texture2;
|
||||
uniform sampler2D texture3;
|
||||
uniform sampler2D texture4;
|
||||
uniform sampler2D texture5;
|
||||
uniform sampler2D texture6;
|
||||
uniform sampler2D texture7;
|
||||
uniform sampler2D texture8;
|
||||
uniform sampler2D texture9;
|
||||
uniform sampler2D texture10;
|
||||
uniform sampler2D texture11;
|
||||
|
||||
// timer data
|
||||
uniform float timer;
|
||||
|
||||
// material types
|
||||
#if defined(SPECULAR)
|
||||
#define normaltexture texture2
|
||||
#define speculartexture texture3
|
||||
#define brighttexture texture4
|
||||
#define detailtexture texture5
|
||||
#define glowtexture texture6
|
||||
#elif defined(PBR)
|
||||
#define normaltexture texture2
|
||||
#define metallictexture texture3
|
||||
#define roughnesstexture texture4
|
||||
#define aotexture texture5
|
||||
#define brighttexture texture6
|
||||
#define detailtexture texture7
|
||||
#define glowtexture texture8
|
||||
#else
|
||||
#define brighttexture texture2
|
||||
#define detailtexture texture3
|
||||
#define glowtexture texture4
|
||||
#endif
|
||||
)";
|
||||
|
||||
#ifdef NPOT_EMULATION
|
||||
i_data += "#define NPOT_EMULATION\nuniform vec2 uNpotEmulation;\n";
|
||||
#endif
|
||||
|
||||
int vp_lump = fileSystem.CheckNumForFullName(vert_prog_lump, 0);
|
||||
if (vp_lump == -1) I_Error("Unable to load '%s'", vert_prog_lump.GetChars());
|
||||
FileData vp_data = fileSystem.ReadFile(vp_lump);
|
||||
|
||||
int fp_lump = fileSystem.CheckNumForFullName(frag_prog_lump, 0);
|
||||
if (fp_lump == -1) I_Error("Unable to load '%s'", frag_prog_lump.GetChars());
|
||||
FileData fp_data = fileSystem.ReadFile(fp_lump);
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The following code uses GetChars on the strings to get rid of terminating 0 characters. Do not remove or the code may break!
|
||||
//
|
||||
FString vp_comb;
|
||||
|
||||
assert(screen->mLights != NULL);
|
||||
|
||||
bool lightbuffertype = screen->mLights->GetBufferType();
|
||||
unsigned int lightbuffersize = screen->mLights->GetBlockSize();
|
||||
|
||||
vp_comb.Format("#version 100\n#define NUM_UBO_LIGHTS %d\n#define NO_CLIPDISTANCE_SUPPORT\n", lightbuffersize);
|
||||
|
||||
FString fp_comb = vp_comb;
|
||||
vp_comb << defines << i_data.GetChars();
|
||||
fp_comb << "$placeholder$\n" << defines << i_data.GetChars();
|
||||
|
||||
vp_comb << "#line 1\n";
|
||||
fp_comb << "#line 1\n";
|
||||
|
||||
vp_comb << RemoveLayoutLocationDecl(vp_data.GetString(), "out").GetChars() << "\n";
|
||||
fp_comb << RemoveLayoutLocationDecl(fp_data.GetString(), "in").GetChars() << "\n";
|
||||
FString placeholder = "\n";
|
||||
|
||||
if (proc_prog_lump.Len())
|
||||
{
|
||||
fp_comb << "#line 1\n";
|
||||
|
||||
if (*proc_prog_lump != '#')
|
||||
{
|
||||
int pp_lump = fileSystem.CheckNumForFullName(proc_prog_lump);
|
||||
if (pp_lump == -1) I_Error("Unable to load '%s'", proc_prog_lump.GetChars());
|
||||
FileData pp_data = fileSystem.ReadFile(pp_lump);
|
||||
|
||||
if (pp_data.GetString().IndexOf("ProcessMaterial") < 0 && pp_data.GetString().IndexOf("SetupMaterial") < 0)
|
||||
{
|
||||
// this looks like an old custom hardware shader.
|
||||
|
||||
if (pp_data.GetString().IndexOf("GetTexCoord") >= 0)
|
||||
{
|
||||
int pl_lump = fileSystem.CheckNumForFullName("shaders_gles/glsl/func_defaultmat2.fp", 0);
|
||||
if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders_gles/glsl/func_defaultmat2.fp");
|
||||
FileData pl_data = fileSystem.ReadFile(pl_lump);
|
||||
fp_comb << "\n" << pl_data.GetString().GetChars();
|
||||
}
|
||||
else
|
||||
{
|
||||
int pl_lump = fileSystem.CheckNumForFullName("shaders_gles/glsl/func_defaultmat.fp", 0);
|
||||
if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders_gles/glsl/func_defaultmat.fp");
|
||||
FileData pl_data = fileSystem.ReadFile(pl_lump);
|
||||
fp_comb << "\n" << pl_data.GetString().GetChars();
|
||||
|
||||
if (pp_data.GetString().IndexOf("ProcessTexel") < 0)
|
||||
{
|
||||
// this looks like an even older custom hardware shader.
|
||||
// We need to replace the ProcessTexel call to make it work.
|
||||
|
||||
fp_comb.Substitute("material.Base = ProcessTexel();", "material.Base = Process(vec4(1.0));");
|
||||
}
|
||||
}
|
||||
|
||||
if (pp_data.GetString().IndexOf("ProcessLight") >= 0)
|
||||
{
|
||||
// The ProcessLight signatured changed. Forward to the old one.
|
||||
fp_comb << "\nvec4 ProcessLight(vec4 color);\n";
|
||||
fp_comb << "\nvec4 ProcessLight(Material material, vec4 color) { return ProcessLight(color); }\n";
|
||||
}
|
||||
}
|
||||
|
||||
fp_comb << RemoveLegacyUserUniforms(pp_data.GetString()).GetChars();
|
||||
fp_comb.Substitute("gl_TexCoord[0]", "vTexCoord"); // fix old custom shaders.
|
||||
|
||||
if (pp_data.GetString().IndexOf("ProcessLight") < 0)
|
||||
{
|
||||
int pl_lump = fileSystem.CheckNumForFullName("shaders_gles/glsl/func_defaultlight.fp", 0);
|
||||
if (pl_lump == -1) I_Error("Unable to load '%s'", "shaders_gles/glsl/func_defaultlight.fp");
|
||||
FileData pl_data = fileSystem.ReadFile(pl_lump);
|
||||
fp_comb << "\n" << pl_data.GetString().GetChars();
|
||||
}
|
||||
|
||||
// ProcessMaterial must be considered broken because it requires the user to fill in data they possibly cannot know all about.
|
||||
if (pp_data.GetString().IndexOf("ProcessMaterial") >= 0 && pp_data.GetString().IndexOf("SetupMaterial") < 0)
|
||||
{
|
||||
// This reactivates the old logic and disables all features that cannot be supported with that method.
|
||||
placeholder << "#define LEGACY_USER_SHADER\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Proc_prog_lump is not a lump name but the source itself (from generated shaders)
|
||||
fp_comb << proc_prog_lump.GetChars() + 1;
|
||||
}
|
||||
}
|
||||
fp_comb.Substitute("$placeholder$", placeholder);
|
||||
|
||||
if (light_fragprog.Len())
|
||||
{
|
||||
int pp_lump = fileSystem.CheckNumForFullName(light_fragprog, 0);
|
||||
if (pp_lump == -1) I_Error("Unable to load '%s'", light_fragprog.GetChars());
|
||||
FileData pp_data = fileSystem.ReadFile(pp_lump);
|
||||
fp_comb << pp_data.GetString().GetChars() << "\n";
|
||||
}
|
||||
|
||||
if (gles.flags & RFL_NO_CLIP_PLANES)
|
||||
{
|
||||
// On ATI's GL3 drivers we have to disable gl_ClipDistance because it's hopelessly broken.
|
||||
// This will cause some glitches and regressions but is the only way to avoid total display garbage.
|
||||
vp_comb.Substitute("gl_ClipDistance", "//");
|
||||
}
|
||||
|
||||
shaderData->hShader = glCreateProgram();
|
||||
|
||||
uint32_t binaryFormat = 0;
|
||||
TArray<uint8_t> binary;
|
||||
if (IsShaderCacheActive())
|
||||
binary = LoadCachedProgramBinary(vp_comb, fp_comb, binaryFormat);
|
||||
|
||||
bool linked = false;
|
||||
|
||||
if (!linked)
|
||||
{
|
||||
shaderData->hVertProg = glCreateShader(GL_VERTEX_SHADER);
|
||||
shaderData->hFragProg = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
int vp_size = (int)vp_comb.Len();
|
||||
int fp_size = (int)fp_comb.Len();
|
||||
|
||||
const char *vp_ptr = vp_comb.GetChars();
|
||||
const char *fp_ptr = fp_comb.GetChars();
|
||||
|
||||
glShaderSource(shaderData->hVertProg, 1, &vp_ptr, &vp_size);
|
||||
glShaderSource(shaderData->hFragProg, 1, &fp_ptr, &fp_size);
|
||||
|
||||
glCompileShader(shaderData->hVertProg);
|
||||
glCompileShader(shaderData->hFragProg);
|
||||
|
||||
glAttachShader(shaderData->hShader, shaderData->hVertProg);
|
||||
glAttachShader(shaderData->hShader, shaderData->hFragProg);
|
||||
|
||||
|
||||
glBindAttribLocation(shaderData->hShader, VATTR_VERTEX, "aPosition");
|
||||
glBindAttribLocation(shaderData->hShader, VATTR_TEXCOORD, "aTexCoord");
|
||||
glBindAttribLocation(shaderData->hShader, VATTR_COLOR, "aColor");
|
||||
glBindAttribLocation(shaderData->hShader, VATTR_VERTEX2, "aVertex2");
|
||||
glBindAttribLocation(shaderData->hShader, VATTR_NORMAL, "aNormal");
|
||||
glBindAttribLocation(shaderData->hShader, VATTR_NORMAL2, "aNormal2");
|
||||
|
||||
|
||||
glLinkProgram(shaderData->hShader);
|
||||
|
||||
glGetShaderInfoLog(shaderData->hVertProg, 10000, NULL, buffer);
|
||||
if (*buffer)
|
||||
{
|
||||
error << "Vertex shader:\n" << buffer << "\n";
|
||||
}
|
||||
glGetShaderInfoLog(shaderData->hFragProg, 10000, NULL, buffer);
|
||||
if (*buffer)
|
||||
{
|
||||
error << "Fragment shader:\n" << buffer << "\n";
|
||||
}
|
||||
|
||||
glGetProgramInfoLog(shaderData->hShader, 10000, NULL, buffer);
|
||||
if (*buffer)
|
||||
{
|
||||
error << "Linking:\n" << buffer << "\n";
|
||||
}
|
||||
GLint status = 0;
|
||||
glGetProgramiv(shaderData->hShader, GL_LINK_STATUS, &status);
|
||||
linked = (status == GL_TRUE);
|
||||
|
||||
if (!linked)
|
||||
{
|
||||
// only print message if there's an error.
|
||||
I_Error("Init Shader '%s':\n%s\n", name, error.GetChars());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shaderData->hVertProg = 0;
|
||||
shaderData->hFragProg = 0;
|
||||
}
|
||||
|
||||
shaderData->muProjectionMatrix.Init(shaderData->hShader, "ProjectionMatrix");
|
||||
shaderData->muViewMatrix.Init(shaderData->hShader, "ViewMatrix");
|
||||
shaderData->muNormalViewMatrix.Init(shaderData->hShader, "NormalViewMatrix");
|
||||
|
||||
//shaderData->ProjectionMatrix_index = glGetUniformLocation(shaderData->hShader, "ProjectionMatrix");
|
||||
//shaderData->ViewMatrix_index = glGetUniformLocation(shaderData->hShader, "ViewMatrix");
|
||||
//shaderData->NormalViewMatrix_index = glGetUniformLocation(shaderData->hShader, "NormalViewMatrix");
|
||||
|
||||
shaderData->muCameraPos.Init(shaderData->hShader, "uCameraPos");
|
||||
shaderData->muClipLine.Init(shaderData->hShader, "uClipLine");
|
||||
|
||||
shaderData->muGlobVis.Init(shaderData->hShader, "uGlobVis");
|
||||
shaderData->muPalLightLevels.Init(shaderData->hShader, "uPalLightLevels");
|
||||
shaderData->muViewHeight.Init(shaderData->hShader, "uViewHeight");
|
||||
shaderData->muClipHeight.Init(shaderData->hShader, "uClipHeight");
|
||||
shaderData->muClipHeightDirection.Init(shaderData->hShader, "uClipHeightDirection");
|
||||
shaderData->muShadowmapFilter.Init(shaderData->hShader, "uShadowmapFilter");
|
||||
|
||||
////
|
||||
|
||||
shaderData->muDesaturation.Init(shaderData->hShader, "uDesaturationFactor");
|
||||
shaderData->muFogEnabled.Init(shaderData->hShader, "uFogEnabled");
|
||||
shaderData->muTextureMode.Init(shaderData->hShader, "uTextureMode");
|
||||
shaderData->muLightParms.Init(shaderData->hShader, "uLightAttr");
|
||||
shaderData->muClipSplit.Init(shaderData->hShader, "uClipSplit");
|
||||
shaderData->muLightRange.Init(shaderData->hShader, "uLightRange");
|
||||
shaderData->muFogColor.Init(shaderData->hShader, "uFogColor");
|
||||
shaderData->muDynLightColor.Init(shaderData->hShader, "uDynLightColor");
|
||||
shaderData->muObjectColor.Init(shaderData->hShader, "uObjectColor");
|
||||
shaderData->muObjectColor2.Init(shaderData->hShader, "uObjectColor2");
|
||||
shaderData->muGlowBottomColor.Init(shaderData->hShader, "uGlowBottomColor");
|
||||
shaderData->muGlowTopColor.Init(shaderData->hShader, "uGlowTopColor");
|
||||
shaderData->muGlowBottomPlane.Init(shaderData->hShader, "uGlowBottomPlane");
|
||||
shaderData->muGlowTopPlane.Init(shaderData->hShader, "uGlowTopPlane");
|
||||
shaderData->muGradientBottomPlane.Init(shaderData->hShader, "uGradientBottomPlane");
|
||||
shaderData->muGradientTopPlane.Init(shaderData->hShader, "uGradientTopPlane");
|
||||
shaderData->muSplitBottomPlane.Init(shaderData->hShader, "uSplitBottomPlane");
|
||||
shaderData->muSplitTopPlane.Init(shaderData->hShader, "uSplitTopPlane");
|
||||
shaderData->muDetailParms.Init(shaderData->hShader, "uDetailParms");
|
||||
shaderData->muInterpolationFactor.Init(shaderData->hShader, "uInterpolationFactor");
|
||||
shaderData->muAlphaThreshold.Init(shaderData->hShader, "uAlphaThreshold");
|
||||
shaderData->muSpecularMaterial.Init(shaderData->hShader, "uSpecularMaterial");
|
||||
shaderData->muAddColor.Init(shaderData->hShader, "uAddColor");
|
||||
shaderData->muTextureAddColor.Init(shaderData->hShader, "uTextureAddColor");
|
||||
shaderData->muTextureModulateColor.Init(shaderData->hShader, "uTextureModulateColor");
|
||||
shaderData->muTextureBlendColor.Init(shaderData->hShader, "uTextureBlendColor");
|
||||
shaderData->muTimer.Init(shaderData->hShader, "timer");
|
||||
#ifdef NPOT_EMULATION
|
||||
shaderData->muNpotEmulation.Init(shaderData->hShader, "uNpotEmulation");
|
||||
#endif
|
||||
shaderData->muFixedColormapStart.Init(shaderData->hShader, "uFixedColormapStart");
|
||||
shaderData->muFixedColormapRange.Init(shaderData->hShader, "uFixedColormapRange");
|
||||
|
||||
shaderData->lights_index = glGetUniformLocation(shaderData->hShader, "lights");
|
||||
shaderData->modelmatrix_index = glGetUniformLocation(shaderData->hShader, "ModelMatrix");
|
||||
shaderData->texturematrix_index = glGetUniformLocation(shaderData->hShader, "TextureMatrix");
|
||||
shaderData->normalmodelmatrix_index = glGetUniformLocation(shaderData->hShader, "NormalModelMatrix");
|
||||
|
||||
|
||||
glUseProgram(shaderData->hShader);
|
||||
|
||||
// set up other texture units (if needed by the shader)
|
||||
for (int i = 2; i<16; i++)
|
||||
{
|
||||
char stringbuf[20];
|
||||
mysnprintf(stringbuf, 20, "texture%d", i);
|
||||
int tempindex = glGetUniformLocation(shaderData->hShader, stringbuf);
|
||||
if (tempindex > 0) glUniform1i(tempindex, i - 1);
|
||||
}
|
||||
|
||||
int shadowmapindex = glGetUniformLocation(shaderData->hShader, "ShadowMap");
|
||||
if (shadowmapindex > 0) glUniform1i(shadowmapindex, 16);
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
cur = shaderData;
|
||||
|
||||
return linked;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShader::~FShader()
|
||||
{
|
||||
/*
|
||||
glDeleteProgram(hShader);
|
||||
if (hVertProg != 0)
|
||||
glDeleteShader(hVertProg);
|
||||
if (hFragProg != 0)
|
||||
glDeleteShader(hFragProg);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FShader::Bind(ShaderFlavourData& flavour)
|
||||
{
|
||||
uint32_t tag = CreateShaderTag(flavour);
|
||||
|
||||
auto pos = variants.find(tag);
|
||||
|
||||
if (pos == variants.end())
|
||||
{
|
||||
FString variantConfig = "\n";
|
||||
|
||||
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_USE_U_LIGHT_LEVEL %d\n", flavour.useULightLevel);
|
||||
|
||||
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);
|
||||
|
||||
variantConfig.AppendFormat("#define DEF_USE_OBJECT_COLOR_2 %d\n", flavour.useObjectColor2);
|
||||
variantConfig.AppendFormat("#define DEF_USE_GLOW_TOP_COLOR %d\n", flavour.useGlowTopColor);
|
||||
variantConfig.AppendFormat("#define DEF_USE_GLOW_BOTTOM_COLOR %d\n", flavour.useGlowBottomColor);
|
||||
|
||||
variantConfig.AppendFormat("#define DEF_USE_COLOR_MAP %d\n", flavour.useColorMap);
|
||||
variantConfig.AppendFormat("#define DEF_BUILD_LIGHTING %d\n", flavour.buildLighting);
|
||||
variantConfig.AppendFormat("#define DEF_BANDED_SW_LIGHTING %d\n", flavour.bandedSwLight);
|
||||
|
||||
variantConfig.AppendFormat("#define USE_GLSL_V100 %d\n", gles.forceGLSLv100);
|
||||
|
||||
#ifdef NPOT_EMULATION
|
||||
variantConfig.AppendFormat("#define DEF_NPOT_EMULATION %d\n", flavour.npotEmulation);
|
||||
#endif
|
||||
|
||||
// Printf("Shader: %s, %08x %s", mFragProg2.GetChars(), tag, variantConfig.GetChars());
|
||||
|
||||
Load(mName.GetChars(), mVertProg, mFragProg, mFragProg2, mLightProg, mDefinesBase + variantConfig);
|
||||
|
||||
if (variants.insert(std::make_pair(tag, cur)).second == false)
|
||||
{
|
||||
Printf("ERROR INSERTING");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cur = pos->second;
|
||||
}
|
||||
|
||||
GLRenderer->mShaderManager->SetActiveShader(this->cur);
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Since all shaders are REQUIRED, any error here needs to be fatal
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType)
|
||||
{
|
||||
FString defines;
|
||||
defines += shaderdefines;
|
||||
// this can't be in the shader code due to ATI strangeness.
|
||||
if (!usediscard) defines += "#define NO_ALPHATEST\n";
|
||||
|
||||
FShader *shader = NULL;
|
||||
try
|
||||
{
|
||||
shader = new FShader(ShaderName);
|
||||
if (!shader->Configure(ShaderName, "shaders_gles/glsl/main.vp", "shaders_gles/glsl/main.fp", ShaderPath, LightModePath, defines.GetChars()))
|
||||
{
|
||||
I_FatalError("Unable to load shader %s\n", ShaderName);
|
||||
}
|
||||
}
|
||||
catch(CRecoverableError &err)
|
||||
{
|
||||
if (shader != NULL) delete shader;
|
||||
shader = NULL;
|
||||
I_FatalError("Unable to load shader %s:\n%s\n", ShaderName, err.GetMessage());
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderManager::FShaderManager()
|
||||
{
|
||||
for (int passType = 0; passType < MAX_PASS_TYPES; passType++)
|
||||
mPassShaders.Push(new FShaderCollection((EPassType)passType));
|
||||
}
|
||||
|
||||
FShaderManager::~FShaderManager()
|
||||
{
|
||||
glUseProgram(0);
|
||||
mActiveShader = NULL;
|
||||
|
||||
for (auto collection : mPassShaders)
|
||||
delete collection;
|
||||
}
|
||||
|
||||
void FShaderManager::SetActiveShader(FShader::ShaderVariantData *sh)
|
||||
{
|
||||
if (mActiveShader != sh)
|
||||
{
|
||||
glUseProgram(sh!= NULL? sh->GetHandle() : 0);
|
||||
mActiveShader = sh;
|
||||
}
|
||||
}
|
||||
|
||||
FShader *FShaderManager::BindEffect(int effect, EPassType passType, ShaderFlavourData &flavour)
|
||||
{
|
||||
if (passType < mPassShaders.Size())
|
||||
return mPassShaders[passType]->BindEffect(effect, flavour);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType)
|
||||
{
|
||||
if (passType < mPassShaders.Size())
|
||||
return mPassShaders[passType]->Get(eff, alphateston);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderCollection::FShaderCollection(EPassType passType)
|
||||
{
|
||||
CompileShaders(passType);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShaderCollection::~FShaderCollection()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderCollection::CompileShaders(EPassType passType)
|
||||
{
|
||||
mMaterialShaders.Clear();
|
||||
mMaterialShadersNAT.Clear();
|
||||
for (int i = 0; i < MAX_EFFECTS; i++)
|
||||
{
|
||||
mEffectShaders[i] = NULL;
|
||||
}
|
||||
|
||||
for(int i=0;defaultshaders[i].ShaderName != NULL;i++)
|
||||
{
|
||||
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, true, passType);
|
||||
mMaterialShaders.Push(shc);
|
||||
if (i < SHADER_NoTexture)
|
||||
{
|
||||
FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, defaultshaders[i].lightfunc, defaultshaders[i].Defines, false, passType);
|
||||
mMaterialShadersNAT.Push(shc);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
for(unsigned i = 0; i < usershaders.Size(); i++)
|
||||
{
|
||||
FString name = ExtractFileBase(usershaders[i].shader);
|
||||
FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines;
|
||||
FShader *shc = Compile(name, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, passType);
|
||||
mMaterialShaders.Push(shc);
|
||||
}
|
||||
#endif
|
||||
|
||||
for(int i=0;i<MAX_EFFECTS;i++)
|
||||
{
|
||||
FShader *eff = new FShader(effectshaders[i].ShaderName);
|
||||
if (!eff->Configure(effectshaders[i].ShaderName, effectshaders[i].vp, effectshaders[i].fp1,
|
||||
effectshaders[i].fp2, effectshaders[i].fp3, effectshaders[i].defines))
|
||||
{
|
||||
delete eff;
|
||||
}
|
||||
else mEffectShaders[i] = eff;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FShaderCollection::Clean()
|
||||
{
|
||||
for (unsigned int i = 0; i < mMaterialShadersNAT.Size(); i++)
|
||||
{
|
||||
if (mMaterialShadersNAT[i] != NULL) delete mMaterialShadersNAT[i];
|
||||
}
|
||||
for (unsigned int i = 0; i < mMaterialShaders.Size(); i++)
|
||||
{
|
||||
if (mMaterialShaders[i] != NULL) delete mMaterialShaders[i];
|
||||
}
|
||||
for (int i = 0; i < MAX_EFFECTS; i++)
|
||||
{
|
||||
if (mEffectShaders[i] != NULL) delete mEffectShaders[i];
|
||||
mEffectShaders[i] = NULL;
|
||||
}
|
||||
mMaterialShaders.Clear();
|
||||
mMaterialShadersNAT.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FShaderCollection::Find(const char * shn)
|
||||
{
|
||||
FName sfn = shn;
|
||||
|
||||
for(unsigned int i=0;i<mMaterialShaders.Size();i++)
|
||||
{
|
||||
if (mMaterialShaders[i]->mName == sfn)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FShader *FShaderCollection::BindEffect(int effect, ShaderFlavourData& flavour)
|
||||
{
|
||||
if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect] != NULL)
|
||||
{
|
||||
mEffectShaders[effect]->Bind(flavour);
|
||||
return mEffectShaders[effect];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void gl_DestroyUserShaders()
|
||||
{
|
||||
// todo
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue