- updated gl_interface to deal with older GL versions.

- added the framework for allowing multipass textured dynamic lights again.
This commit is contained in:
Christoph Oelckers 2016-04-26 13:50:05 +02:00
parent 8b5c741358
commit 090d13b915
8 changed files with 151 additions and 33 deletions

View file

@ -109,7 +109,8 @@ void FGLRenderer::Initialize()
mVBO = new FFlatVertexBuffer;
mSkyVBO = new FSkyVertexBuffer;
mLights = new FLightBuffer();
if (gl.lightmethod != LM_SOFTWARE) mLights = new FLightBuffer();
else mLights = NULL;
gl_RenderState.SetVertexBuffer(mVBO);
mFBID = 0;
SetupLevel();

View file

@ -309,7 +309,7 @@ void FRenderState::ApplyMatrices()
void FRenderState::ApplyLightIndex(int index)
{
if (GLRenderer->mLights->GetBufferType() == GL_UNIFORM_BUFFER && index > -1)
if (index > -1 && GLRenderer->mLights->GetBufferType() == GL_UNIFORM_BUFFER)
{
index = GLRenderer->mLights->BindUBO(index);
}

View file

@ -193,7 +193,7 @@ void GLFlat::DrawSubsector(subsector_t * sub)
//==========================================================================
//
//
// this is only used by LM_DEFERRED
//
//==========================================================================
@ -399,7 +399,7 @@ void GLFlat::Draw(int pass, bool trans) // trans only has meaning for GLPASS_LIG
switch (pass)
{
case GLPASS_PLAIN: // Single-pass rendering
case GLPASS_ALL:
case GLPASS_ALL: // Same, but also creates the dynlight data.
gl_SetColor(lightlevel, rel, Colormap,1.0f);
gl_SetFog(lightlevel, rel, &Colormap, false);
if (sector->special != GLSector_Skybox)
@ -473,6 +473,7 @@ inline void GLFlat::PutFlat(bool fog)
bool masked = gltexture->isMasked() && ((renderflags&SSRF_RENDER3DPLANES) || stack);
list = masked ? GLDL_MASKEDFLATS : GLDL_PLAINFLATS;
}
dynlightindex = -1; // make sure this is always initialized to something proper.
gl_drawinfo->drawlists[list].AddFlat (this);
}

View file

@ -351,7 +351,8 @@ void FGLRenderer::RenderScene(int recursion)
// if we don't have a persistently mapped buffer, we have to process all the dynamic lights up front,
// so that we don't have to do repeated map/unmap calls on the buffer.
if (mLightCount > 0 && gl_fixedcolormap == CM_DEFAULT && gl_lights && !(gl.flags & RFL_BUFFER_STORAGE))
bool haslights = mLightCount > 0 && gl_fixedcolormap == CM_DEFAULT && gl_lights;
if (gl.lightmethod == LM_DEFERRED && haslights)
{
GLRenderer->mLights->Begin();
gl_drawinfo->drawlists[GLDL_PLAINWALLS].DrawWalls(GLPASS_LIGHTSONLY);
@ -371,12 +372,20 @@ void FGLRenderer::RenderScene(int recursion)
int pass;
if (mLightCount > 0 && gl_fixedcolormap == CM_DEFAULT && gl_lights && (gl.flags & RFL_BUFFER_STORAGE))
if (!haslights || gl.lightmethod == LM_DEFERRED)
{
pass = GLPASS_PLAIN;
}
else if (gl.lightmethod == LM_DIRECT)
{
pass = GLPASS_ALL;
}
else
{
// Todo: Draw lights with multipass rendering.
// RenderMultpassStuff();
// The remaining stuff which is unaffected by dynamic lights is just processed as normal.
pass = GLPASS_PLAIN;
}
@ -418,6 +427,10 @@ void FGLRenderer::RenderScene(int recursion)
// this is the only geometry type on which decals can possibly appear
gl_drawinfo->drawlists[GLDL_PLAINWALLS].DrawDecals();
if (gl.lightmethod == LM_SOFTWARE)
{
// also process the render lists with walls and dynamic lights
}
gl_RenderState.SetTextureMode(TM_MODULATE);
@ -870,7 +883,7 @@ void FGLRenderer::RenderView (player_t* player)
P_FindParticleSubsectors ();
GLRenderer->mLights->Clear();
if (gl.lightmethod != LM_SOFTWARE) GLRenderer->mLights->Clear();
// NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below.
bool saved_niv = NoInterpolateView;
@ -925,7 +938,7 @@ void FGLRenderer::WriteSavePic (player_t *player, FILE *file, int width, int hei
SetFixedColormap(player);
gl_RenderState.SetVertexBuffer(mVBO);
GLRenderer->mVBO->Reset();
GLRenderer->mLights->Clear();
if (gl.lightmethod != LM_SOFTWARE) GLRenderer->mLights->Clear();
// Check if there's some lights. If not some code can be skipped.
TThinkerIterator<ADynamicLight> it(STAT_DLIGHT);

View file

@ -1422,7 +1422,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
glseg.y2 = v2->fY();
Colormap = frontsector->ColorMap;
flags = 0;
dynlightindex = UINT_MAX;
dynlightindex = -1;
lightlist = NULL;
int rel = 0;
@ -1681,7 +1681,7 @@ void GLWall::ProcessLowerMiniseg(seg_t *seg, sector_t * frontsector, sector_t *
bottomflat = frontsector->GetTexture(sector_t::floor);
topplane = frontsector->ceilingplane;
bottomplane = frontsector->floorplane;
dynlightindex = UINT_MAX;
dynlightindex = -1;
zfloor[0] = zfloor[1] = ffh;

View file

@ -87,25 +87,37 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
//
// The following code uses GetChars on the strings to get rid of terminating 0 characters. Do not remove or the code may break!
//
unsigned int lightbuffertype = GLRenderer->mLights->GetBufferType();
unsigned int lightbuffersize = GLRenderer->mLights->GetBlockSize();
FString vp_comb;
if (lightbuffertype == GL_UNIFORM_BUFFER)
if (gl.lightmethod == LM_SOFTWARE)
{
if (gl.glslversion < 1.4f || gl.version < 3.1f)
if (gl.compatibility >= CMPT_GL3)
{
vp_comb.Format("#version 130\n#extension GL_ARB_uniform_buffer_object : require\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
}
else
{
vp_comb.Format("#version 140\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
vp_comb = "#version 130\n";
}
}
else
{
vp_comb = "#version 400 core\n#extension GL_ARB_shader_storage_buffer_object : require\n#define SHADER_STORAGE_LIGHTS\n";
assert(GLRenderer->mLights != NULL);
// On the shader side there is no difference between LM_DEFERRED and LM_DIRECT, it only matters which buffer type is used by the light buffer.
unsigned int lightbuffertype = GLRenderer->mLights->GetBufferType();
unsigned int lightbuffersize = GLRenderer->mLights->GetBlockSize();
if (lightbuffertype == GL_UNIFORM_BUFFER)
{
// This differentiation is for some Intel drivers which fail on #extension, so use of #version 140 is necessary
if (gl.glslversion < 1.4f || gl.version < 3.1f)
{
vp_comb.Format("#version 130\n#extension GL_ARB_uniform_buffer_object : require\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
}
else
{
vp_comb.Format("#version 140\n#define NUM_UBO_LIGHTS %d\n", lightbuffersize);
}
}
else
{
vp_comb = "#version 400 core\n#extension GL_ARB_shader_storage_buffer_object : require\n#define SHADER_STORAGE_LIGHTS\n";
}
}
vp_comb << defines << i_data.GetString().GetChars();

View file

@ -107,35 +107,77 @@ static void InitContext()
//
//==========================================================================
#define FUDGE_FUNC(name, ext) if (_ptrc_##name == NULL) _ptrc_##name = _ptrc_##name##ext;
void gl_LoadExtensions()
{
InitContext();
CollectExtensions();
const char *version = Args->CheckValue("-glversion");
if (version == NULL) version = (const char*)glGetString(GL_VERSION);
else Printf("Emulating OpenGL v %s\n", version);
const char *glversion = (const char*)glGetString(GL_VERSION);
if (version == NULL)
{
version = glversion;
}
else
{
double v1 = strtod(version, NULL);
double v2 = strtod(glversion, NULL);
if (v2 < v1) version = glversion;
else Printf("Emulating OpenGL v %s\n", version);
}
gl.version = strtod(version, NULL) + 0.01f;
// Don't even start if it's lower than 3.0
if (strcmp(version, "3.0") < 0)
if ((gl.version < 2.0 || !CheckExtension("GL_EXT_framebuffer_object")) && gl.version < 3.0)
{
I_FatalError("Unsupported OpenGL version.\nAt least OpenGL 3.0 is required to run " GAMENAME ".\n");
I_FatalError("Unsupported OpenGL version.\nAt least OpenGL 2.0 with framebuffer support is required to run " GAMENAME ".\n");
}
// add 0.01 to account for roundoff errors making the number a tad smaller than the actual version
gl.version = strtod(version, NULL) + 0.01f;
gl.glslversion = strtod((char*)glGetString(GL_SHADING_LANGUAGE_VERSION), NULL) + 0.01f;
gl.vendorstring = (char*)glGetString(GL_VENDOR);
gl.lightmethod = LM_SOFTWARE;
if (gl.version >= 3.3f || CheckExtension("GL_ARB_sampler_objects"))
{
gl.flags |= RFL_SAMPLER_OBJECTS;
}
// Buffer lighting is only feasible with GLSL 1.3 and higher, even if 1.2 supports the extension.
if (gl.version > 3.0f && (gl.version >= 3.3f || CheckExtension("GL_ARB_uniform_buffer_object")))
{
gl.flags |= RFL_SAMPLER_OBJECTS;
gl.lightmethod = LM_DEFERRED;
}
if (CheckExtension("GL_ARB_texture_compression")) gl.flags|=RFL_TEXTURE_COMPRESSION;
if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags|=RFL_TEXTURE_COMPRESSION_S3TC;
if (!Args->CheckParm("-gl3"))
if (CheckExtension("GL_ARB_texture_compression")) gl.flags |= RFL_TEXTURE_COMPRESSION;
if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags |= RFL_TEXTURE_COMPRESSION_S3TC;
if (Args->CheckParm("-noshader"))
{
gl.compatibility = CMPT_GL2; // force the low end path
}
if (gl.version < 3.0f)
{
if (CheckExtension("GL_NV_GPU_shader4") || CheckExtension("GL_EXT_GPU_shader4")) gl.compatibility = CMPT_GL2_SHADER; // for pre-3.0 drivers that support capable hardware. Needed for Apple.
else gl.compatibility = CMPT_GL2;
}
else if (gl.version < 4.f)
{
if (strstr(gl.vendorstring, "ATI Tech"))
{
gl.compatibility = CMPT_GL2_SHADER; // most of these drivers are irreperably broken with GLSL 1.3 and higher.
gl.lightmethod = LM_SOFTWARE; // do not use uniform buffers with the fallback shader, it may cause problems.
}
else gl.compatibility = CMPT_GL3;
}
else
{
// don't use GL 4.x features when running in GL 3 emulation mode.
if (CheckExtension("GL_ARB_buffer_storage"))
@ -151,9 +193,22 @@ void gl_LoadExtensions()
}
}
gl.flags |= RFL_BUFFER_STORAGE;
gl.compatibility = CMPT_GL4;
gl.lightmethod = LM_DIRECT;
}
else
{
gl.compatibility = CMPT_GL3;
}
}
const char *lm = Args->CheckValue("-lightmethod");
if (lm != NULL)
{
if (!stricmp(lm, "deferred") && gl.lightmethod == LM_DIRECT) gl.lightmethod = LM_DEFERRED;
if (!stricmp(lm, "textured")) gl.lightmethod = LM_SOFTWARE;
}
int v;
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &v);
gl.maxuniforms = v;
@ -161,9 +216,26 @@ void gl_LoadExtensions()
gl.maxuniformblock = v;
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &v);
gl.uniformblockalignment = v;
glGetIntegerv(GL_MAX_TEXTURE_SIZE,&gl.max_texturesize);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl.max_texturesize);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// fudge a bit with the framebuffer stuff to avoid redundancies in the main code. Some of the older cards do not have the ARB stuff but the calls are nearly identical.
FUDGE_FUNC(glGenerateMipmap, EXT);
FUDGE_FUNC(glGenFramebuffers, EXT);
FUDGE_FUNC(glBindFramebuffer, EXT);
FUDGE_FUNC(glDeleteFramebuffers, EXT);
FUDGE_FUNC(glFramebufferTexture2D, EXT);
FUDGE_FUNC(glGenerateMipmap, EXT);
FUDGE_FUNC(glGenFramebuffers, EXT);
FUDGE_FUNC(glBindFramebuffer, EXT);
FUDGE_FUNC(glDeleteFramebuffers, EXT);
FUDGE_FUNC(glFramebufferTexture2D, EXT);
FUDGE_FUNC(glFramebufferRenderbuffer, EXT);
FUDGE_FUNC(glGenRenderbuffers, EXT);
FUDGE_FUNC(glDeleteRenderbuffers, EXT);
FUDGE_FUNC(glRenderbufferStorage, EXT);
FUDGE_FUNC(glBindRenderbuffer, EXT);
}
//==========================================================================

View file

@ -3,6 +3,14 @@
#include "basictypes.h"
enum GLCompat
{
CMPT_GL2,
CMPT_GL2_SHADER,
CMPT_GL3,
CMPT_GL4
};
enum RenderFlags
{
// [BB] Added texture compression flags.
@ -11,7 +19,7 @@ enum RenderFlags
RFL_SHADER_STORAGE_BUFFER = 4,
RFL_BUFFER_STORAGE = 8,
RFL_SAMPLER_OBJECTS = 16
RFL_SAMPLER_OBJECTS = 16,
};
enum TexMode
@ -22,6 +30,15 @@ enum TexMode
TM_INVERSE, // (1-r, 1-g, 1-b, a)
TM_REDTOALPHA, // (1, 1, 1, r)
TM_CLAMPY, // (r, g, b, (t >= 0.0 && t <= 1.0)? a:0)
TM_INVERTOPAQUE, // used by GL 2.x fallback code.
};
enum ELightMethod
{
LM_SOFTWARE = 0, // multi-pass texturing
LM_DEFERRED = 1, // calculate lights up front in a separate pass
LM_DIRECT = 2, // calculate lights on the fly along with the render data
};
struct RenderContext
@ -30,6 +47,8 @@ struct RenderContext
unsigned int maxuniforms;
unsigned int maxuniformblock;
unsigned int uniformblockalignment;
int lightmethod;
int compatibility;
float version;
float glslversion;
int max_texturesize;