[Bf-blender-cvs] [27db38f0a72] cycles-x: Cycles X: Shading performance improvements by changing inlining behavior for SVM

Patrick Mours noreply at git.blender.org
Tue Jul 6 15:52:24 CEST 2021


Commit: 27db38f0a729411f13c99a60574d59c70d461be5
Author: Patrick Mours
Date:   Mon Jul 5 12:58:22 2021 +0200
Branches: cycles-x
https://developer.blender.org/rB27db38f0a729411f13c99a60574d59c70d461be5

Cycles X: Shading performance improvements by changing inlining behavior for SVM

The shading kernels (shade_surface, ...) are limited by memory a lot. I found several hotspots
where execution was stalled waiting for spills to be loaded back into registers. That's
something that can be adjusted by changing the inlining logic:

For example, the compiler did not inline "kernel_write_denoising_features" (even though it
was marked __inline__), which caused it to force synchronization before the function call.
Forcing it inline avoided that and got rid of that hotspot.

Then there was cubic texture filtering and NanoVDB, which introduced huge code chunks
into each texture sampling evaluation (increasing register and instruction cache pressure),
even though they are rarely actually used. Making them __noinline__ outsources that
overhead to only occur when actually used.

Another case is the SVM. The compiler currently converts the node type switch statement
into a binary searched branch sequence. This means depending on the SVM node hit, the
GPU has to branch over large portions of code, which increases instruction cache pressure
immensely (GPU is fetching lots of code even for stuff it immediately jumps away from
again, while jumping through the binary searched branches). This can be reduced somewhat
by making all the node functions __noinline__, so that the GPU only has to branch over a
bunch of call instructions, rather than all the inlined code.
The SVM "offset" value is passed by value into the node functions now and returned through
function return value, to make the compiler keep it in a register. Otherwise when passed as
a pointer, in OptiX the compiler was forced to move it into local memory (since functions
are compiled separately there, so the compiler is unaware of how that pointer is used).

Differential Revision: https://developer.blender.org/D11816

===================================================================

M	intern/cycles/kernel/device/cuda/image.h
M	intern/cycles/kernel/kernel_passes.h
M	intern/cycles/kernel/svm/svm.h
M	intern/cycles/kernel/svm/svm_ao.h
M	intern/cycles/kernel/svm/svm_attribute.h
M	intern/cycles/kernel/svm/svm_bevel.h
M	intern/cycles/kernel/svm/svm_blackbody.h
M	intern/cycles/kernel/svm/svm_brick.h
M	intern/cycles/kernel/svm/svm_brightness.h
M	intern/cycles/kernel/svm/svm_bump.h
M	intern/cycles/kernel/svm/svm_camera.h
M	intern/cycles/kernel/svm/svm_checker.h
M	intern/cycles/kernel/svm/svm_clamp.h
M	intern/cycles/kernel/svm/svm_closure.h
M	intern/cycles/kernel/svm/svm_convert.h
M	intern/cycles/kernel/svm/svm_displace.h
M	intern/cycles/kernel/svm/svm_fresnel.h
M	intern/cycles/kernel/svm/svm_gamma.h
M	intern/cycles/kernel/svm/svm_geometry.h
M	intern/cycles/kernel/svm/svm_gradient.h
M	intern/cycles/kernel/svm/svm_hsv.h
M	intern/cycles/kernel/svm/svm_ies.h
M	intern/cycles/kernel/svm/svm_image.h
M	intern/cycles/kernel/svm/svm_invert.h
M	intern/cycles/kernel/svm/svm_light_path.h
M	intern/cycles/kernel/svm/svm_magic.h
M	intern/cycles/kernel/svm/svm_map_range.h
M	intern/cycles/kernel/svm/svm_mapping.h
M	intern/cycles/kernel/svm/svm_math.h
M	intern/cycles/kernel/svm/svm_mix.h
M	intern/cycles/kernel/svm/svm_musgrave.h
M	intern/cycles/kernel/svm/svm_noisetex.h
M	intern/cycles/kernel/svm/svm_normal.h
M	intern/cycles/kernel/svm/svm_ramp.h
M	intern/cycles/kernel/svm/svm_sepcomb_hsv.h
M	intern/cycles/kernel/svm/svm_sky.h
M	intern/cycles/kernel/svm/svm_tex_coord.h
M	intern/cycles/kernel/svm/svm_types.h
M	intern/cycles/kernel/svm/svm_value.h
M	intern/cycles/kernel/svm/svm_vector_rotate.h
M	intern/cycles/kernel/svm/svm_vector_transform.h
M	intern/cycles/kernel/svm/svm_vertex_color.h
M	intern/cycles/kernel/svm/svm_voronoi.h
M	intern/cycles/kernel/svm/svm_voxel.h
M	intern/cycles/kernel/svm/svm_wave.h
M	intern/cycles/kernel/svm/svm_wavelength.h
M	intern/cycles/kernel/svm/svm_white_noise.h
M	intern/cycles/kernel/svm/svm_wireframe.h

===================================================================

diff --git a/intern/cycles/kernel/device/cuda/image.h b/intern/cycles/kernel/device/cuda/image.h
index 92a66ecf9a0..e127fe88df3 100644
--- a/intern/cycles/kernel/device/cuda/image.h
+++ b/intern/cycles/kernel/device/cuda/image.h
@@ -65,7 +65,7 @@ ccl_device float cubic_h1(float a)
 
 /* Fast bicubic texture lookup using 4 bilinear lookups, adapted from CUDA samples. */
 template<typename T>
-ccl_device T kernel_tex_image_interp_bicubic(const TextureInfo &info, float x, float y)
+ccl_device_noinline T kernel_tex_image_interp_bicubic(const TextureInfo &info, float x, float y)
 {
   CUtexObject tex = (CUtexObject)info.data;
 
@@ -91,7 +91,8 @@ ccl_device T kernel_tex_image_interp_bicubic(const TextureInfo &info, float x, f
 
 /* Fast tricubic texture lookup using 8 trilinear lookups. */
 template<typename T>
-ccl_device T kernel_tex_image_interp_tricubic(const TextureInfo &info, float x, float y, float z)
+ccl_device_noinline T
+kernel_tex_image_interp_tricubic(const TextureInfo &info, float x, float y, float z)
 {
   CUtexObject tex = (CUtexObject)info.data;
 
@@ -161,7 +162,7 @@ ccl_device T kernel_tex_image_interp_tricubic_nanovdb(S &s, float x, float y, fl
 }
 
 template<typename T>
-ccl_device_inline T kernel_tex_image_interp_nanovdb(
+ccl_device_noinline T kernel_tex_image_interp_nanovdb(
     const TextureInfo &info, float x, float y, float z, uint interpolation)
 {
   using namespace nanovdb;
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index f9aff28df2b..da4d12d8891 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -35,7 +35,7 @@ ccl_device_forceinline ccl_global float *kernel_pass_pixel_render_buffer(
 
 #ifdef __DENOISING_FEATURES__
 
-ccl_device_inline void kernel_write_denoising_features(
+ccl_device_forceinline void kernel_write_denoising_features(
     INTEGRATOR_STATE_ARGS, const ShaderData *sd, ccl_global float *ccl_restrict render_buffer)
 {
   if (!(INTEGRATOR_STATE(path, flag) & PATH_RAY_DENOISING_FEATURES)) {
@@ -127,7 +127,7 @@ ccl_device_inline void kernel_write_denoising_features(
 #ifdef __SHADOW_CATCHER__
 
 /* Write shadow catcher passes on a bounce from the shadow catcher object. */
-ccl_device_inline void kernel_write_shadow_catcher_bounce_data(
+ccl_device_forceinline void kernel_write_shadow_catcher_bounce_data(
     INTEGRATOR_STATE_ARGS, const ShaderData *sd, ccl_global float *ccl_restrict render_buffer)
 {
   if (!kernel_data.integrator.has_shadow_catcher) {
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index aa77d3d44ba..82e9064da83 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -48,16 +48,18 @@ ccl_device_inline float3 stack_load_float3(float *stack, uint a)
 {
   kernel_assert(a + 2 < SVM_STACK_SIZE);
 
-  return make_float3(stack[a + 0], stack[a + 1], stack[a + 2]);
+  float *stack_a = stack + a;
+  return make_float3(stack_a[0], stack_a[1], stack_a[2]);
 }
 
 ccl_device_inline void stack_store_float3(float *stack, uint a, float3 f)
 {
   kernel_assert(a + 2 < SVM_STACK_SIZE);
 
-  stack[a + 0] = f.x;
-  stack[a + 1] = f.y;
-  stack[a + 2] = f.z;
+  float *stack_a = stack + a;
+  stack_a[0] = f.x;
+  stack_a[1] = f.y;
+  stack_a[2] = f.z;
 }
 
 ccl_device_inline float stack_load_float(float *stack, uint a)
@@ -245,7 +247,8 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
         break;
       }
       case NODE_CLOSURE_BSDF:
-        svm_node_closure_bsdf<node_feature_mask, type>(kg, sd, stack, node, path_flag, &offset);
+        offset = svm_node_closure_bsdf<node_feature_mask, type>(
+            kg, sd, stack, node, path_flag, offset);
         break;
       case NODE_CLOSURE_EMISSION:
         if (NODES_FEATURE(EMISSION)) {
@@ -286,13 +289,13 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
         svm_node_convert(kg, sd, stack, node.y, node.z, node.w);
         break;
       case NODE_TEX_COORD:
-        svm_node_tex_coord(kg, sd, path_flag, stack, node, &offset);
+        offset = svm_node_tex_coord(kg, sd, path_flag, stack, node, offset);
         break;
       case NODE_VALUE_F:
         svm_node_value_f(kg, sd, stack, node.y, node.z);
         break;
       case NODE_VALUE_V:
-        svm_node_value_v(kg, sd, stack, node.y, &offset);
+        offset = svm_node_value_v(kg, sd, stack, node.y, offset);
         break;
       case NODE_ATTR:
         svm_node_attr<node_feature_mask>(kg, sd, stack, node);
@@ -322,17 +325,17 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
         break;
       case NODE_VECTOR_DISPLACEMENT:
         if (NODES_FEATURE(BUMP)) {
-          svm_node_vector_displacement(kg, sd, stack, node, &offset);
+          offset = svm_node_vector_displacement(kg, sd, stack, node, offset);
         }
         break;
       case NODE_TEX_IMAGE:
-        svm_node_tex_image(kg, sd, stack, node, &offset);
+        offset = svm_node_tex_image(kg, sd, stack, node, offset);
         break;
       case NODE_TEX_IMAGE_BOX:
         svm_node_tex_image_box(kg, sd, stack, node);
         break;
       case NODE_TEX_NOISE:
-        svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, &offset);
+        offset = svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, offset);
         break;
       case NODE_SET_BUMP:
         if (NODES_FEATURE(BUMP)) {
@@ -361,12 +364,12 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
         break;
       case NODE_TEX_COORD_BUMP_DX:
         if (NODES_FEATURE(BUMP)) {
-          svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, &offset);
+          offset = svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, offset);
         }
         break;
       case NODE_TEX_COORD_BUMP_DY:
         if (NODES_FEATURE(BUMP)) {
-          svm_node_tex_coord_bump_dy(kg, sd, path_flag, stack, node, &offset);
+          offset = svm_node_tex_coord_bump_dy(kg, sd, path_flag, stack, node, offset);
         }
         break;
       case NODE_CLOSURE_SET_NORMAL:
@@ -385,7 +388,7 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
         }
         break;
       case NODE_HSV:
-        svm_node_hsv(kg, sd, stack, node, &offset);
+        svm_node_hsv(kg, sd, stack, node);
         break;
 #endif /* NODES_GROUP(NODE_GROUP_LEVEL_0) */
 
@@ -406,17 +409,17 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
         break;
       case NODE_PRINCIPLED_VOLUME:
         if (NODES_FEATURE(VOLUME)) {
-          svm_node_principled_volume<type>(kg, sd, stack, node, path_flag, &offset);
+          offset = svm_node_principled_volume<type>(kg, sd, stack, node, path_flag, offset);
         }
         break;
       case NODE_MATH:
-        svm_node_math(kg, sd, stack, node.y, node.z, node.w, &offset);
+        svm_node_math(kg, sd, stack, node.y, node.z, node.w);
         break;
       case NODE_VECTOR_MATH:
-        svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, &offset);
+        offset = svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, offset);
         break;
       case NODE_RGB_RAMP:
-        svm_node_rgb_ramp(kg, sd, stack, node, &offset);
+        offset = svm_node_rgb_ramp(kg, sd, stack, node, offset);
         break;
       case NODE_GAMMA:
         svm_node_gamma(sd, stack, node.y, node.z, node.w);
@@ -444,13 +447,13 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
 
 #if NODES_GROUP(NODE_GROUP_LEVEL_2)
       case NODE_TEXTURE_MAPPING:
-        svm_node_texture_mapping(kg, sd, stack, node.y, node.z, &offset);
+        offset = svm_node_texture_mapping(kg, sd, stack, node.y, node.z, offset);
         break;
       case NODE_MAPPING:
-        svm_node_mapping(kg, sd, stack, node.y, node.z, node.w, &offset);
+        svm_node_mapping(kg, sd, stack, node.y, node.z, node.w);
         break;
       case NODE_MIN_MAX:
-        svm_node_min_max(kg, sd, stack, node.y, node.z, &offset);
+        offset = svm_node_min_max(kg, sd, stack, node.y, node.z, offset);
         break;
       case NODE_CAMERA:
         svm_node_camera(kg, sd, stack, node.y, node.z, node.w);
@@ -459,47 +462,48 @@ ccl_device void svm_eval_nodes(INTEGRATOR_STATE_CONST_ARGS,
         svm_node_tex_environment(kg, sd, stack, node);
         break;
       case NODE_TEX_SKY:
-        svm_node_tex_sky(kg, sd, stack, node, &offset);
+        offset = svm_node_tex_sky(kg, sd, stack, node, offset);
         break;
       case NODE_TEX_GRADIENT:
         svm_node_tex_gradient(sd, stack, node);
         break;
       case NODE_TEX_VORONOI:
-        svm_node_tex_voronoi<node_feature_mask>(kg, sd, stack, node.y, node.z, node.w, &offset);
+        offset = svm_node_tex_voronoi<node_feature_mask>(
+            kg, sd, stack, node.y, node.z, node.w, offset);
         break;
       case NODE_TEX_MUSGRAVE:
-        svm_node_tex_musgrave(kg, sd, stack, node.y, node.z, node.w, &offset);
+        offset = svm_node_tex_musgrave(kg, sd, stack, node.y, node.z, node.w, offset);
         break;
       case NODE_TEX_WAVE:
-        svm_node_tex_wave(kg, sd, stack, node, &offset);
+        offset = svm_node_tex_wave(kg, sd, stack, node, offset);
         break;
       case NODE_TEX_MAGIC:
-        svm_node_tex_magic(kg, sd, stack, node, &offset);
+        offset = svm_node_tex_magic(kg, sd, stack, node, offset);
         break;
       case NODE_TEX_CHECKER:
         svm_node_tex_checker(kg, sd, stack, node);
         break;
       case NODE_TEX_BRICK:
-        svm_node_tex_brick(kg, sd, stack, node, &offset);
+        offset = svm_node_tex_brick(kg, sd, stack, node, offset);
         break;
       case NODE_TEX_WHITE_NOISE:
-        svm_node_tex_white_noise(kg, sd, stack, node.y, node.z, node.w, &offset);
+        svm_node_tex_white_noise(kg, sd, stack, node.y, node.z, node.w);
         break;
       case NODE_NORMAL:
-        svm_node_normal(kg, sd, stack, node.y, node.z, node.w, &offset);
+        offset = svm_node_normal(kg, sd, stack, node.y, node.z, node.w, offset);
         break;
       case NODE_LIGHT_FALLOFF:
         svm_node_light_falloff(sd, stack, node);
         break;
       case NODE_IES:
-        svm_node_ies(kg, sd, stack, node, &offset);
+

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list