OpenSubdiv: Optimize drawing shader
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 4 Aug 2015 08:49:32 +0000 (10:49 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Tue, 4 Aug 2015 08:52:50 +0000 (10:52 +0200)
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.

intern/opensubdiv/gpu_shader_opensubd_display.glsl
intern/opensubdiv/opensubdiv_gpu_capi.cc

index 110898ad917689d63e419fc3eb8eea9593d7de43..e343c9529447eb272bc45c3476178450d5576aec 100644 (file)
@@ -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;
-
-                       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);
-
-                               /* 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;
+#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;
+
+               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);
                        }
 
-                       /* 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
 }
 
index d46211f36689b9a81d6f17ff625eb63eabca3ef7..9498f936b6b9be99be84f8a3e599c1a72b2ff08c 100644 (file)
@@ -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_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_program) {
-               glDeleteProgram(g_flat_fill_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 {