OpenGL2: Add GPU vertex skinning for IQM models

Using GPU vertex skinning is significantly faster than CPU vertex
skinning. Especially since OpenGL2 has to run R_VaoPackNormal() and
R_VaoPackTangent() each vertex each frame which causes CPU vertex
skinning to be significantly slower than OpenGL1 renderer.
This commit is contained in:
Zack Middleton 2018-07-27 17:40:25 -05:00
parent cccd283be8
commit 11337c9fa2
10 changed files with 533 additions and 34 deletions

View file

@ -148,6 +148,8 @@ static uniformInfo_t uniformsInfo[] =
{ "u_CubeMapInfo", GLSL_VEC4 },
{ "u_AlphaTest", GLSL_INT },
{ "u_BoneMatrix", GLSL_MAT16_BONEMATRIX },
};
typedef enum
@ -555,6 +557,12 @@ static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int
if(attribs & ATTR_LIGHTDIRECTION)
qglBindAttribLocation(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection");
if(attribs & ATTR_BONE_INDEXES)
qglBindAttribLocation(program->program, ATTR_INDEX_BONE_INDEXES, "attr_BoneIndexes");
if(attribs & ATTR_BONE_WEIGHTS)
qglBindAttribLocation(program->program, ATTR_INDEX_BONE_WEIGHTS, "attr_BoneWeights");
if(attribs & ATTR_POSITION2)
qglBindAttribLocation(program->program, ATTR_INDEX_POSITION2, "attr_Position2");
@ -660,6 +668,9 @@ void GLSL_InitUniforms(shaderProgram_t *program)
case GLSL_MAT16:
size += sizeof(vec_t) * 16;
break;
case GLSL_MAT16_BONEMATRIX:
size += sizeof(vec_t) * 16 * glRefConfig.glslMaxAnimatedBones;
break;
default:
break;
}
@ -843,6 +854,38 @@ void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t
qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], 1, GL_FALSE, matrix);
}
void GLSL_SetUniformMat4BoneMatrix(shaderProgram_t *program, int uniformNum, /*const*/ mat4_t *matrix, int numMatricies)
{
GLint *uniforms = program->uniforms;
vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]);
if (uniforms[uniformNum] == -1) {
return;
}
if (uniformsInfo[uniformNum].type != GLSL_MAT16_BONEMATRIX)
{
ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4BoneMatrix: wrong type for uniform %i in program %s\n", uniformNum, program->name);
return;
}
if (numMatricies > glRefConfig.glslMaxAnimatedBones)
{
ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4BoneMatrix: too many matricies (%d/%d) for uniform %i in program %s\n",
numMatricies, glRefConfig.glslMaxAnimatedBones, uniformNum, program->name);
return;
}
if (!memcmp(matrix, compare, numMatricies * sizeof(mat4_t)))
{
return;
}
Com_Memcpy(compare, matrix, numMatricies * sizeof(mat4_t));
qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], numMatricies, GL_FALSE, &matrix[0][0]);
}
void GLSL_DeleteGPUShader(shaderProgram_t *program)
{
if(program->program)
@ -886,6 +929,12 @@ void GLSL_InitGPUShaders(void)
for (i = 0; i < GENERICDEF_COUNT; i++)
{
if ((i & GENERICDEF_USE_VERTEX_ANIMATION) && (i & GENERICDEF_USE_BONE_ANIMATION))
continue;
if ((i & GENERICDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
continue;
attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR;
extradefines[0] = '\0';
@ -903,6 +952,11 @@ void GLSL_InitGPUShaders(void)
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
}
else if (i & GENERICDEF_USE_BONE_ANIMATION)
{
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
}
if (i & GENERICDEF_USE_FOG)
Q_strcat(extradefines, 1024, "#define USE_FOG\n");
@ -943,14 +997,28 @@ void GLSL_InitGPUShaders(void)
for (i = 0; i < FOGDEF_COUNT; i++)
{
attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;
if ((i & FOGDEF_USE_VERTEX_ANIMATION) && (i & FOGDEF_USE_BONE_ANIMATION))
continue;
if ((i & FOGDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
continue;
attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD;
extradefines[0] = '\0';
if (i & FOGDEF_USE_DEFORM_VERTEXES)
Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n");
if (i & FOGDEF_USE_VERTEX_ANIMATION)
{
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
}
else if (i & FOGDEF_USE_BONE_ANIMATION)
{
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
}
if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp))
{
@ -1001,6 +1069,12 @@ void GLSL_InitGPUShaders(void)
if ((i & LIGHTDEF_USE_SHADOWMAP) && (!lightType || !r_sunlightMode->integer))
continue;
if ((i & LIGHTDEF_ENTITY_VERTEX_ANIMATION) && (i & LIGHTDEF_ENTITY_BONE_ANIMATION))
continue;
if ((i & LIGHTDEF_ENTITY_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
continue;
attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL;
extradefines[0] = '\0';
@ -1043,7 +1117,7 @@ void GLSL_InitGPUShaders(void)
attribs |= ATTR_TANGENT;
if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer)
if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY_VERTEX_ANIMATION) && !(i & LIGHTDEF_ENTITY_BONE_ANIMATION) && r_parallaxMapping->integer)
{
Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n");
if (r_parallaxMapping->integer > 1)
@ -1093,7 +1167,7 @@ void GLSL_InitGPUShaders(void)
Q_strcat(extradefines, 1024, "#define USE_TCMOD\n");
}
if (i & LIGHTDEF_ENTITY)
if (i & LIGHTDEF_ENTITY_VERTEX_ANIMATION)
{
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n");
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
@ -1103,6 +1177,12 @@ void GLSL_InitGPUShaders(void)
attribs |= ATTR_TANGENT2;
}
}
else if (i & LIGHTDEF_ENTITY_BONE_ANIMATION)
{
Q_strcat(extradefines, 1024, "#define USE_MODELMATRIX\n");
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
}
if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp))
{
@ -1124,20 +1204,41 @@ void GLSL_InitGPUShaders(void)
numLightShaders++;
}
attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD;
extradefines[0] = '\0';
if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp))
for (i = 0; i < SHADOWMAPDEF_COUNT; i++)
{
ri.Error(ERR_FATAL, "Could not load shadowfill shader!");
if ((i & SHADOWMAPDEF_USE_VERTEX_ANIMATION) && (i & SHADOWMAPDEF_USE_BONE_ANIMATION))
continue;
if ((i & SHADOWMAPDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones)
continue;
attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD;
extradefines[0] = '\0';
if (i & SHADOWMAPDEF_USE_VERTEX_ANIMATION)
{
Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n");
attribs |= ATTR_POSITION2 | ATTR_NORMAL2;
}
if (i & SHADOWMAPDEF_USE_BONE_ANIMATION)
{
Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones));
attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS;
}
if (!GLSL_InitGPUShader(&tr.shadowmapShader[i], "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp))
{
ri.Error(ERR_FATAL, "Could not load shadowfill shader!");
}
GLSL_InitUniforms(&tr.shadowmapShader[i]);
GLSL_FinishGPUShader(&tr.shadowmapShader[i]);
numEtcShaders++;
}
GLSL_InitUniforms(&tr.shadowmapShader);
GLSL_FinishGPUShader(&tr.shadowmapShader);
numEtcShaders++;
attribs = ATTR_POSITION | ATTR_NORMAL;
extradefines[0] = '\0';
@ -1363,7 +1464,9 @@ void GLSL_ShutdownGPUShaders(void)
for ( i = 0; i < LIGHTDEF_COUNT; i++)
GLSL_DeleteGPUShader(&tr.lightallShader[i]);
GLSL_DeleteGPUShader(&tr.shadowmapShader);
for ( i = 0; i < SHADOWMAPDEF_COUNT; i++)
GLSL_DeleteGPUShader(&tr.shadowmapShader[i]);
GLSL_DeleteGPUShader(&tr.pshadowShader);
GLSL_DeleteGPUShader(&tr.down4xShader);
GLSL_DeleteGPUShader(&tr.bokehShader);
@ -1439,6 +1542,10 @@ shaderProgram_t *GLSL_GetGenericShaderProgram(int stage)
{
shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
}
else if (glState.boneAnimation)
{
shaderAttribs |= GENERICDEF_USE_BONE_ANIMATION;
}
if (pStage->bundle[0].numTexMods)
{