OpenSubdiv: Optimize drawing shader

The idea is to cut as much code as possible and use compile-time
ifdefs rather than runtime if() statements.

Gives about 2x speedup on catmark_car model from OpenSubdiv repository
making our FPS much closer to what glViewer is capable of.
This commit is contained in:
Sergey Sharybin 2015-08-04 10:49:32 +02:00
parent cff288cf3a
commit abb976ae88
2 changed files with 103 additions and 98 deletions

@ -215,8 +215,6 @@ uniform vec4 specular;
uniform float shininess;
uniform sampler2D texture_buffer;
uniform bool use_color_material;
uniform bool use_texture_2d;
in block {
VertexData v;
@ -236,99 +234,89 @@ void main()
vec3 L_diffuse = vec3(0.0);
vec3 L_specular = vec3(0.0);
if (use_color_material == false) {
/* Assume NUM_SOLID_LIGHTS directional lights. */
for (int i = 0; i < NUM_SOLID_LIGHTS; i++) {
vec3 light_direction = lightSource[i].position.xyz;
/* Diffuse light. */
vec3 light_diffuse = lightSource[i].diffuse.rgb;
float diffuse_bsdf = max(dot(N, light_direction), 0.0);
L_diffuse += light_diffuse * diffuse_bsdf;
/* Specular light. */
vec4 Plight = lightSource[i].position;
vec3 l = (Plight.w == 0.0)
? normalize(Plight.xyz) : normalize(Plight.xyz -
inpt.v.position.xyz);
vec3 light_specular = lightSource[i].specular.rgb;
vec3 H = normalize(l + vec3(0,0,1));
float specular_bsdf = pow(max(dot(N, H), 0.0),
shininess);
L_specular += light_specular * specular_bsdf;
}
#ifndef USE_COLOR_MATERIAL
/* Assume NUM_SOLID_LIGHTS directional lights. */
for (int i = 0; i < NUM_SOLID_LIGHTS; i++) {
vec4 Plight = lightSource[i].position;
#ifdef USE_DIRECTIONAL_LIGHT
vec3 l = (Plight.w == 0.0)
? normalize(Plight.xyz)
: normalize(inpt.v.position.xyz);
#else /* USE_DIRECTIONAL_LIGHT */
/* TODO(sergey): We can normalize it outside of the shader. */
vec3 l = normalize(Plight.xyz);
#endif /* USE_DIRECTIONAL_LIGHT */
vec3 h = normalize(l + vec3(0, 0, 1));
float d = max(0.0, dot(N, l));
float s = pow(max(0.0, dot(N, h)), 500.0f);
L_diffuse += d * lightSource[i].diffuse;
L_specular += s * lightSource[i].specular;
}
else {
vec3 varying_position = inpt.v.position.xyz;
vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ?
normalize(varying_position): vec3(0.0, 0.0, -1.0);
for (int i = 0; i < num_enabled_lights; i++) {
/* todo: this is a slow check for disabled lights */
if (lightSource[i].specular.a == 0.0)
continue;
#else /* USE_COLOR_MATERIAL */
vec3 varying_position = inpt.v.position.xyz;
vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ?
normalize(varying_position): vec3(0.0, 0.0, -1.0);
for (int i = 0; i < num_enabled_lights; i++) {
/* todo: this is a slow check for disabled lights */
if (lightSource[i].specular.a == 0.0)
continue;
float intensity = 1.0;
vec3 light_direction;
float intensity = 1.0;
vec3 light_direction;
if (lightSource[i].position.w == 0.0) {
/* directional light */
light_direction = lightSource[i].position.xyz;
}
else {
/* point light */
vec3 d = lightSource[i].position.xyz - varying_position;
light_direction = normalize(d);
if (lightSource[i].position.w == 0.0) {
/* directional light */
light_direction = lightSource[i].position.xyz;
}
else {
/* point light */
vec3 d = lightSource[i].position.xyz - varying_position;
light_direction = normalize(d);
/* spot light cone */
if (lightSource[i].spotCutoff < 90.0) {
float cosine = max(dot(light_direction,
-lightSource[i].spotDirection.xyz),
0.0);
intensity = pow(cosine, lightSource[i].spotExponent);
intensity *= step(lightSource[i].spotCosCutoff, cosine);
}
/* falloff */
float distance = length(d);
intensity /= lightSource[i].constantAttenuation +
lightSource[i].linearAttenuation * distance +
lightSource[i].quadraticAttenuation * distance * distance;
/* spot light cone */
if (lightSource[i].spotCutoff < 90.0) {
float cosine = max(dot(light_direction,
-lightSource[i].spotDirection.xyz),
0.0);
intensity = pow(cosine, lightSource[i].spotExponent);
intensity *= step(lightSource[i].spotCosCutoff, cosine);
}
/* diffuse light */
vec3 light_diffuse = lightSource[i].diffuse.rgb;
float diffuse_bsdf = max(dot(N, light_direction), 0.0);
L_diffuse += light_diffuse*diffuse_bsdf*intensity;
/* falloff */
float distance = length(d);
/* specular light */
vec3 light_specular = lightSource[i].specular.rgb;
vec3 H = normalize(light_direction - V);
float specular_bsdf = pow(max(dot(N, H), 0.0),
gl_FrontMaterial.shininess);
L_specular += light_specular*specular_bsdf * intensity;
intensity /= lightSource[i].constantAttenuation +
lightSource[i].linearAttenuation * distance +
lightSource[i].quadraticAttenuation * distance * distance;
}
/* diffuse light */
vec3 light_diffuse = lightSource[i].diffuse.rgb;
float diffuse_bsdf = max(dot(N, light_direction), 0.0);
L_diffuse += light_diffuse*diffuse_bsdf*intensity;
/* specular light */
vec3 light_specular = lightSource[i].specular.rgb;
vec3 H = normalize(light_direction - V);
float specular_bsdf = pow(max(dot(N, H), 0.0),
gl_FrontMaterial.shininess);
L_specular += light_specular*specular_bsdf * intensity;
}
#endif /* USE_COLOR_MATERIAL */
/* Compute diffuse color. */
float alpha;
if (use_texture_2d) {
L_diffuse *= texture2D(texture_buffer, inpt.v.uv).rgb;
}
else {
L_diffuse *= diffuse.rgb;
}
alpha = diffuse.a;
#ifdef USE_TEXTURE_2D
L_diffuse *= texture2D(texture_buffer, inpt.v.uv).rgb;
#else
L_diffuse *= diffuse.rgb;
#endif
/* Sum lighting. */
vec3 L = /*gl_FrontLightModelProduct.sceneColor.rgb +*/ L_diffuse;
if (shininess != 0.0f) {
L += L_specular * specular.rgb;
}
vec3 L = L_diffuse + L_specular * specular.rgb;
/* Write out fragment color. */
gl_FragColor = vec4(L, alpha);
gl_FragColor = vec4(L, diffuse.a);
#endif
}

@ -86,8 +86,10 @@ typedef struct Transform {
static bool g_use_osd_glsl = false;
static int g_active_uv_index = -1;
static GLuint g_flat_fill_program = 0;
static GLuint g_smooth_fill_program = 0;
static GLuint g_flat_fill_solid_program = 0;
static GLuint g_flat_fill_texture2d_program = 0;
static GLuint g_smooth_fill_solid_program = 0;
static GLuint g_smooth_fill_texture2d_program = 0;
static GLuint g_wireframe_program = 0;
static GLuint g_lighting_ub = 0;
@ -324,15 +326,8 @@ void bindProgram(PartitionedGLMeshInterface * /*mesh*/,
glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_lighting_ub);
/* Color */
GLboolean use_lighting, use_color_material, use_texture_2d;
GLboolean use_lighting;
glGetBooleanv(GL_LIGHTING, &use_lighting);
glGetBooleanv(GL_COLOR_MATERIAL, &use_color_material);
glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d);
glUniform1i(glGetUniformLocation(program, "use_color_material"),
use_color_material);
glUniform1i(glGetUniformLocation(program, "use_texture_2d"),
use_texture_2d);
if (use_lighting) {
float color[4];
@ -376,8 +371,10 @@ void openSubdiv_osdGLDisplayInit(void)
{
static bool need_init = true;
if (need_init) {
g_flat_fill_program = linkProgram("#define FLAT_SHADING\n");
g_smooth_fill_program = linkProgram("#define SMOOTH_SHADING\n");
g_flat_fill_solid_program = linkProgram("#define FLAT_SHADING\n");
g_flat_fill_texture2d_program = linkProgram("#define USE_TEXTURE_2D\n#define FLAT_SHADING\n");
g_smooth_fill_solid_program = linkProgram("#define SMOOTH_SHADING\n");
g_smooth_fill_texture2d_program = linkProgram("#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n");
g_wireframe_program = linkProgram("#define WIREFRAME\n");
glGenBuffers(1, &g_lighting_ub);
@ -394,11 +391,17 @@ void openSubdiv_osdGLDisplayDeinit(void)
if (g_lighting_ub != 0) {
glDeleteBuffers(1, &g_lighting_ub);
}
if (g_flat_fill_program) {
glDeleteProgram(g_flat_fill_program);
if (g_flat_fill_solid_program) {
glDeleteProgram(g_flat_fill_solid_program);
}
if (g_smooth_fill_program) {
glDeleteProgram(g_flat_fill_program);
if (g_flat_fill_texture2d_program) {
glDeleteProgram(g_flat_fill_texture2d_program);
}
if (g_smooth_fill_solid_program) {
glDeleteProgram(g_flat_fill_solid_program);
}
if (g_smooth_fill_texture2d_program) {
glDeleteProgram(g_smooth_fill_texture2d_program);
}
if (g_wireframe_program) {
glDeleteProgram(g_wireframe_program);
@ -505,12 +508,26 @@ static GLuint preapre_patchDraw(PartitionedGLMeshInterface *mesh,
return program;
}
program = g_smooth_fill_program;
if (fill_quads) {
int model;
GLboolean use_texture_2d;
glGetIntegerv(GL_SHADE_MODEL, &model);
glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d);
if (model == GL_FLAT) {
program = g_flat_fill_program;
if (use_texture_2d) {
program = g_flat_fill_texture2d_program;
}
else {
program = g_flat_fill_solid_program;
}
}
else {
if (use_texture_2d) {
program = g_smooth_fill_texture2d_program;
}
else {
program = g_smooth_fill_solid_program;
}
}
}
else {