mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-26 06:20:48 +00:00
GL3: Use dlightbits/lightflags in shader
This makes the fragment shader faster by skipping lights that haven't marked this surface in GL3_MarkLights() This seems to improve performance at least slightly everywhere, but it really helps *a lot* on integrated intel GPUs like the one on their Sandy Bridge, Ivy Bride and Haswell CPUs (those are the ones we tested).
This commit is contained in:
parent
5656345d1f
commit
3503f91234
7 changed files with 79 additions and 39 deletions
|
@ -70,6 +70,12 @@ GL3_MarkLights(dlight_t *light, int bit, mnode_t *node)
|
||||||
|
|
||||||
for (i = 0; i < node->numsurfaces; i++, surf++)
|
for (i = 0; i < node->numsurfaces; i++, surf++)
|
||||||
{
|
{
|
||||||
|
if (surf->dlightframe != r_dlightframecount)
|
||||||
|
{
|
||||||
|
surf->dlightbits = 0;
|
||||||
|
surf->dlightframe = r_dlightframecount;
|
||||||
|
}
|
||||||
|
|
||||||
dist = DotProduct(light->origin, surf->plane->normal) - surf->plane->dist;
|
dist = DotProduct(light->origin, surf->plane->normal) - surf->plane->dist;
|
||||||
|
|
||||||
if (dist >= 0)
|
if (dist >= 0)
|
||||||
|
@ -86,12 +92,6 @@ GL3_MarkLights(dlight_t *light, int bit, mnode_t *node)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surf->dlightframe != r_dlightframecount)
|
|
||||||
{
|
|
||||||
surf->dlightbits = 0;
|
|
||||||
surf->dlightframe = r_dlightframecount;
|
|
||||||
}
|
|
||||||
|
|
||||||
surf->dlightbits |= bit;
|
surf->dlightbits |= bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,6 +196,7 @@ GL3_LM_BuildPolygonFromSurface(msurface_t *fa)
|
||||||
vert->lmTexCoord[1] = t;
|
vert->lmTexCoord[1] = t;
|
||||||
|
|
||||||
VectorCopy(normal, vert->normal);
|
VectorCopy(normal, vert->normal);
|
||||||
|
vert->lightFlags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
poly->numverts = lnumverts;
|
poly->numverts = lnumverts;
|
||||||
|
|
|
@ -110,6 +110,7 @@ CreateShaderProgram(int numShaders, const GLuint* shaders)
|
||||||
glBindAttribLocation(shaderProgram, GL3_ATTRIB_LMTEXCOORD, "lmTexCoord");
|
glBindAttribLocation(shaderProgram, GL3_ATTRIB_LMTEXCOORD, "lmTexCoord");
|
||||||
glBindAttribLocation(shaderProgram, GL3_ATTRIB_COLOR, "vertColor");
|
glBindAttribLocation(shaderProgram, GL3_ATTRIB_COLOR, "vertColor");
|
||||||
glBindAttribLocation(shaderProgram, GL3_ATTRIB_NORMAL, "normal");
|
glBindAttribLocation(shaderProgram, GL3_ATTRIB_NORMAL, "normal");
|
||||||
|
glBindAttribLocation(shaderProgram, GL3_ATTRIB_LIGHTFLAGS, "lightFlags");
|
||||||
|
|
||||||
// the following line is not necessary/implicit (as there's only one output)
|
// the following line is not necessary/implicit (as there's only one output)
|
||||||
// glBindFragDataLocation(shaderProgram, 0, "outColor"); XXX would this even be here?
|
// glBindFragDataLocation(shaderProgram, 0, "outColor"); XXX would this even be here?
|
||||||
|
@ -262,6 +263,7 @@ static const char* vertexCommon3D = MULTILINE_STRING(#version 150\n
|
||||||
in vec2 lmTexCoord; // GL3_ATTRIB_LMTEXCOORD
|
in vec2 lmTexCoord; // GL3_ATTRIB_LMTEXCOORD
|
||||||
in vec4 vertColor; // GL3_ATTRIB_COLOR
|
in vec4 vertColor; // GL3_ATTRIB_COLOR
|
||||||
in vec3 normal; // GL3_ATTRIB_NORMAL
|
in vec3 normal; // GL3_ATTRIB_NORMAL
|
||||||
|
in uint lightFlags; // GL3_ATTRIB_LIGHTFLAGS
|
||||||
|
|
||||||
out vec2 passTexCoord;
|
out vec2 passTexCoord;
|
||||||
|
|
||||||
|
@ -337,6 +339,7 @@ static const char* vertexSrc3Dlm = MULTILINE_STRING(
|
||||||
out vec2 passLMcoord;
|
out vec2 passLMcoord;
|
||||||
out vec3 passWorldCoord;
|
out vec3 passWorldCoord;
|
||||||
out vec3 passNormal;
|
out vec3 passNormal;
|
||||||
|
flat out uint passLightFlags;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
@ -344,6 +347,7 @@ static const char* vertexSrc3Dlm = MULTILINE_STRING(
|
||||||
passLMcoord = lmTexCoord;
|
passLMcoord = lmTexCoord;
|
||||||
passWorldCoord = position; // TODO: multiply with model matrix for brush-based entities
|
passWorldCoord = position; // TODO: multiply with model matrix for brush-based entities
|
||||||
passNormal = normalize(normal); // TODO: multiply with model matrix and normalize
|
passNormal = normalize(normal); // TODO: multiply with model matrix and normalize
|
||||||
|
passLightFlags = lightFlags;
|
||||||
|
|
||||||
gl_Position = transProj * transModelView * vec4(position, 1.0);
|
gl_Position = transProj * transModelView * vec4(position, 1.0);
|
||||||
}
|
}
|
||||||
|
@ -356,6 +360,7 @@ static const char* vertexSrc3DlmFlow = MULTILINE_STRING(
|
||||||
out vec2 passLMcoord;
|
out vec2 passLMcoord;
|
||||||
out vec3 passWorldCoord;
|
out vec3 passWorldCoord;
|
||||||
out vec3 passNormal;
|
out vec3 passNormal;
|
||||||
|
flat out uint passLightFlags;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
@ -363,6 +368,7 @@ static const char* vertexSrc3DlmFlow = MULTILINE_STRING(
|
||||||
passLMcoord = lmTexCoord;
|
passLMcoord = lmTexCoord;
|
||||||
passWorldCoord = position; // TODO: multiply with model matrix for brush-based entities
|
passWorldCoord = position; // TODO: multiply with model matrix for brush-based entities
|
||||||
passNormal = normalize(normal); // TODO: multiply with model matrix and normalize
|
passNormal = normalize(normal); // TODO: multiply with model matrix and normalize
|
||||||
|
passLightFlags = lightFlags;
|
||||||
|
|
||||||
gl_Position = transProj * transModelView * vec4(position, 1.0);
|
gl_Position = transProj * transModelView * vec4(position, 1.0);
|
||||||
}
|
}
|
||||||
|
@ -417,6 +423,7 @@ static const char* fragmentSrc3Dlm = MULTILINE_STRING(
|
||||||
in vec2 passLMcoord;
|
in vec2 passLMcoord;
|
||||||
in vec3 passWorldCoord;
|
in vec3 passWorldCoord;
|
||||||
in vec3 passNormal;
|
in vec3 passNormal;
|
||||||
|
flat in uint passLightFlags;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
@ -431,36 +438,37 @@ static const char* fragmentSrc3Dlm = MULTILINE_STRING(
|
||||||
lmTex += texture(lightmap2, passLMcoord) * lmScales[2];
|
lmTex += texture(lightmap2, passLMcoord) * lmScales[2];
|
||||||
lmTex += texture(lightmap3, passLMcoord) * lmScales[3];
|
lmTex += texture(lightmap3, passLMcoord) * lmScales[3];
|
||||||
|
|
||||||
float planeDist = -dot(passNormal, passWorldCoord); // signed dist to origin, hopefully like msurface_t->plane->dist
|
if(passLightFlags != 0u)
|
||||||
|
|
||||||
// TODO: or is hardcoding 32 better?
|
|
||||||
for(uint i=uint(0); i<numDynLights; ++i)
|
|
||||||
{
|
{
|
||||||
// I made the following up, it's probably not too cool..
|
// TODO: or is hardcoding 32 better?
|
||||||
// it basically checks if the light is on the right side of the surface
|
//for(uint i=0u; i<numDynLights; ++i)
|
||||||
// and, if it is, sets intensity according to distance between light and pixel on surface
|
for(uint i=0u; i < 32u; ++i)
|
||||||
|
{
|
||||||
|
// I made the following up, it's probably not too cool..
|
||||||
|
// it basically checks if the light is on the right side of the surface
|
||||||
|
// and, if it is, sets intensity according to distance between light and pixel on surface
|
||||||
|
|
||||||
// signed distance between light and plane
|
// dyn light number i does not affect this plane, just skip it
|
||||||
float fdist = dot(passNormal, dynLights[i].lightOrigin) + planeDist;
|
if((passLightFlags & (1u << i)) == 0u) continue;
|
||||||
|
|
||||||
if(fdist < 0) continue; // light is on wrong side of the plane
|
float intens = dynLights[i].lightColor.a;
|
||||||
|
|
||||||
float intens = dynLights[i].lightColor.a;
|
vec3 lightToPos = dynLights[i].lightOrigin - passWorldCoord;
|
||||||
|
float distLightToPos = length(lightToPos);
|
||||||
|
float fact = max(0, intens - distLightToPos - 64); // FIXME: really -64 for DLIGHT_CUTOFF?
|
||||||
|
|
||||||
vec3 lightToPos = dynLights[i].lightOrigin - passWorldCoord;
|
// also factor in angle between light and point on surface
|
||||||
float distLightToPos = length(lightToPos);
|
fact *= dot(passNormal, lightToPos/distLightToPos);
|
||||||
float fact = max(0, intens - distLightToPos - 64); // FIXME: really - 64 for DLIGHT_CUTOFF?
|
|
||||||
|
|
||||||
fact *= dot(passNormal, lightToPos/distLightToPos); // also factor in angle between light and surfaces
|
lmTex.rgb += dynLights[i].lightColor.rgb * fact * (1.0/256.0);
|
||||||
|
}
|
||||||
lmTex.rgb += dynLights[i].lightColor.rgb * fact * (1.0/256.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lmTex.rgb *= overbrightbits;
|
lmTex.rgb *= overbrightbits;
|
||||||
outColor = lmTex*texel;
|
outColor = lmTex*texel;
|
||||||
outColor.rgb = pow(outColor.rgb, vec3(gamma)); // apply gamma correction to result
|
outColor.rgb = pow(outColor.rgb, vec3(gamma)); // apply gamma correction to result
|
||||||
|
|
||||||
outColor.a = 1; // lightmaps aren't used with translucent surfaces
|
outColor.a = 1; // lightmaps aren't used with translucent surfaces
|
||||||
//texel.a*alpha; // I think alpha shouldn't be modified by gamma and intensity
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -845,13 +853,7 @@ initShader3D(gl3ShaderInfo_t* shaderInfo, const char* vertSrc, const char* fragS
|
||||||
|
|
||||||
glUniformBlockBinding(prog, blockIndex, GL3_BINDINGPOINT_UNILIGHTS);
|
glUniformBlockBinding(prog, blockIndex, GL3_BINDINGPOINT_UNILIGHTS);
|
||||||
}
|
}
|
||||||
else
|
// else: as uniLights is only used in the LM shaders, it's ok if it's missing
|
||||||
{
|
|
||||||
// TODO: warn about this? only the lightmapped shaders have/need this..
|
|
||||||
R_Printf(PRINT_ALL, "WARNING: Couldn't find uniform block index 'uniLights'\n");
|
|
||||||
|
|
||||||
//goto err_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure texture is GL_TEXTURE0
|
// make sure texture is GL_TEXTURE0
|
||||||
GLint texLoc = glGetUniformLocation(prog, "tex");
|
GLint texLoc = glGetUniformLocation(prog, "tex");
|
||||||
|
|
|
@ -43,9 +43,8 @@ extern int numgl3textures;
|
||||||
|
|
||||||
void GL3_SurfInit(void)
|
void GL3_SurfInit(void)
|
||||||
{
|
{
|
||||||
// init the VAO and VBO for the standard vertexdata: 7 floats
|
// init the VAO and VBO for the standard vertexdata: 10 floats and 1 uint
|
||||||
// (X, Y, Z), (S, T), (LMS, LMT), (normX, normY, normZ) - last two groups for lightmap/dynlights
|
// (X, Y, Z), (S, T), (LMS, LMT), (normX, normY, normZ) - last two groups for lightmap/dynlights
|
||||||
// TODO: remove LMS, LMT? only used for lightmapped surfaces, but those need normal as well for dyn lights
|
|
||||||
|
|
||||||
glGenVertexArrays(1, &gl3state.vao3D);
|
glGenVertexArrays(1, &gl3state.vao3D);
|
||||||
GL3_BindVAO(gl3state.vao3D);
|
GL3_BindVAO(gl3state.vao3D);
|
||||||
|
@ -65,6 +64,10 @@ void GL3_SurfInit(void)
|
||||||
glEnableVertexAttribArray(GL3_ATTRIB_NORMAL);
|
glEnableVertexAttribArray(GL3_ATTRIB_NORMAL);
|
||||||
qglVertexAttribPointer(GL3_ATTRIB_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(gl3_3D_vtx_t), offsetof(gl3_3D_vtx_t, normal));
|
qglVertexAttribPointer(GL3_ATTRIB_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(gl3_3D_vtx_t), offsetof(gl3_3D_vtx_t, normal));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(GL3_ATTRIB_LIGHTFLAGS);
|
||||||
|
qglVertexAttribIPointer(GL3_ATTRIB_LIGHTFLAGS, 1, GL_UNSIGNED_INT, sizeof(gl3_3D_vtx_t), offsetof(gl3_3D_vtx_t, lightFlags));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// init VAO and VBO for model vertexdata: 9 floats
|
// init VAO and VBO for model vertexdata: 9 floats
|
||||||
// (X,Y,Z), (S,T), (R,G,B,A)
|
// (X,Y,Z), (S,T), (R,G,B,A)
|
||||||
|
@ -169,9 +172,32 @@ TextureAnimation(mtexinfo_t *tex)
|
||||||
return tex->image;
|
return tex->image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
GL3_DrawGLPoly(glpoly_t *p)
|
static void
|
||||||
|
SetLightFlags(msurface_t *surf)
|
||||||
{
|
{
|
||||||
|
unsigned int lightFlags = 0;
|
||||||
|
if (surf->dlightframe == gl3_framecount)
|
||||||
|
{
|
||||||
|
lightFlags = surf->dlightbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl3_3D_vtx_t* verts = surf->polys->vertices;
|
||||||
|
|
||||||
|
int numVerts = surf->polys->numverts;
|
||||||
|
for(int i=0; i<numVerts; ++i)
|
||||||
|
{
|
||||||
|
verts[i].lightFlags = lightFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GL3_DrawGLPoly(msurface_t *fa)
|
||||||
|
{
|
||||||
|
glpoly_t *p = fa->polys;
|
||||||
|
|
||||||
|
SetLightFlags(fa);
|
||||||
|
|
||||||
GL3_BindVAO(gl3state.vao3D);
|
GL3_BindVAO(gl3state.vao3D);
|
||||||
GL3_BindVBO(gl3state.vbo3D);
|
GL3_BindVBO(gl3state.vbo3D);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(gl3_3D_vtx_t)*p->numverts, p->vertices, GL_STREAM_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(gl3_3D_vtx_t)*p->numverts, p->vertices, GL_STREAM_DRAW);
|
||||||
|
@ -185,6 +211,8 @@ GL3_DrawGLFlowingPoly(msurface_t *fa)
|
||||||
glpoly_t *p;
|
glpoly_t *p;
|
||||||
float scroll;
|
float scroll;
|
||||||
|
|
||||||
|
SetLightFlags(fa);
|
||||||
|
|
||||||
p = fa->polys;
|
p = fa->polys;
|
||||||
|
|
||||||
scroll = -64.0f * ((gl3_newrefdef.time / 40.0f) - (int)(gl3_newrefdef.time / 40.0f));
|
scroll = -64.0f * ((gl3_newrefdef.time / 40.0f) - (int)(gl3_newrefdef.time / 40.0f));
|
||||||
|
@ -372,7 +400,7 @@ RenderBrushPoly(msurface_t *fa)
|
||||||
{
|
{
|
||||||
GL3_UseProgram(gl3state.si3Dlm.shaderProgram);
|
GL3_UseProgram(gl3state.si3Dlm.shaderProgram);
|
||||||
UpdateLMscales(lmScales, &gl3state.si3Dlm);
|
UpdateLMscales(lmScales, &gl3state.si3Dlm);
|
||||||
GL3_DrawGLPoly(fa->polys);
|
GL3_DrawGLPoly(fa);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: lightmap chains are gone, lightmaps are rendered together with normal texture in one pass
|
// Note: lightmap chains are gone, lightmaps are rendered together with normal texture in one pass
|
||||||
|
@ -430,7 +458,7 @@ GL3_DrawAlphaSurfaces(void)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GL3_UseProgram(gl3state.si3Dtrans.shaderProgram);
|
GL3_UseProgram(gl3state.si3Dtrans.shaderProgram);
|
||||||
GL3_DrawGLPoly(s->polys);
|
GL3_DrawGLPoly(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +586,7 @@ RenderLightmappedPoly(msurface_t *surf)
|
||||||
{
|
{
|
||||||
GL3_UseProgram(gl3state.si3Dlm.shaderProgram);
|
GL3_UseProgram(gl3state.si3Dlm.shaderProgram);
|
||||||
UpdateLMscales(lmScales, &gl3state.si3Dlm);
|
UpdateLMscales(lmScales, &gl3state.si3Dlm);
|
||||||
GL3_DrawGLPoly(surf->polys);
|
GL3_DrawGLPoly(surf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,7 @@ R_SubdividePolygon(int numverts, float *verts, msurface_t *warpface)
|
||||||
poly->vertices[i + 1].texCoord[0] = s;
|
poly->vertices[i + 1].texCoord[0] = s;
|
||||||
poly->vertices[i + 1].texCoord[1] = t;
|
poly->vertices[i + 1].texCoord[1] = t;
|
||||||
VectorCopy(normal, poly->vertices[i + 1].normal);
|
VectorCopy(normal, poly->vertices[i + 1].normal);
|
||||||
|
poly->vertices[i + 1].lightFlags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
VectorScale(total, (1.0 / numverts), poly->vertices[0].pos);
|
VectorScale(total, (1.0 / numverts), poly->vertices[0].pos);
|
||||||
|
|
|
@ -64,6 +64,12 @@ qglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normaliz
|
||||||
glVertexAttribPointer(index, size, type, normalized, stride, (const void*)offset);
|
glVertexAttribPointer(index, size, type, normalized, stride, (const void*)offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
qglVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset)
|
||||||
|
{
|
||||||
|
glVertexAttribIPointer(index, size, type, stride, (void*)offset);
|
||||||
|
}
|
||||||
|
|
||||||
// attribute locations for vertex shaders
|
// attribute locations for vertex shaders
|
||||||
enum {
|
enum {
|
||||||
GL3_ATTRIB_POSITION = 0,
|
GL3_ATTRIB_POSITION = 0,
|
||||||
|
@ -71,6 +77,7 @@ enum {
|
||||||
GL3_ATTRIB_LMTEXCOORD = 2, // for lightmap
|
GL3_ATTRIB_LMTEXCOORD = 2, // for lightmap
|
||||||
GL3_ATTRIB_COLOR = 3, // per-vertex color
|
GL3_ATTRIB_COLOR = 3, // per-vertex color
|
||||||
GL3_ATTRIB_NORMAL = 4, // vertex normal
|
GL3_ATTRIB_NORMAL = 4, // vertex normal
|
||||||
|
GL3_ATTRIB_LIGHTFLAGS = 5 // uint, each set bit means "dyn light i affects this surface"
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: do we need the following configurable?
|
// TODO: do we need the following configurable?
|
||||||
|
@ -444,7 +451,7 @@ extern void GL3_AddSkySurface(msurface_t *fa);
|
||||||
// gl3_surf.c
|
// gl3_surf.c
|
||||||
extern void GL3_SurfInit(void);
|
extern void GL3_SurfInit(void);
|
||||||
extern void GL3_SurfShutdown(void);
|
extern void GL3_SurfShutdown(void);
|
||||||
extern void GL3_DrawGLPoly(glpoly_t *p);
|
extern void GL3_DrawGLPoly(msurface_t *fa);
|
||||||
extern void GL3_DrawGLFlowingPoly(msurface_t *fa);
|
extern void GL3_DrawGLFlowingPoly(msurface_t *fa);
|
||||||
extern void GL3_DrawTriangleOutlines(void);
|
extern void GL3_DrawTriangleOutlines(void);
|
||||||
extern void GL3_DrawAlphaSurfaces(void);
|
extern void GL3_DrawAlphaSurfaces(void);
|
||||||
|
|
|
@ -53,6 +53,7 @@ typedef struct gl3_3D_vtx_s {
|
||||||
float texCoord[2];
|
float texCoord[2];
|
||||||
float lmTexCoord[2]; // lightmap texture coordinate (sometimes unused)
|
float lmTexCoord[2]; // lightmap texture coordinate (sometimes unused)
|
||||||
vec3_t normal;
|
vec3_t normal;
|
||||||
|
GLuint lightFlags; // bit i set means: dynlight i affects surface
|
||||||
} gl3_3D_vtx_t;
|
} gl3_3D_vtx_t;
|
||||||
|
|
||||||
// used for vertex array elements when drawing models
|
// used for vertex array elements when drawing models
|
||||||
|
|
Loading…
Reference in a new issue