]> git.sesse.net Git - nageru/blobdiff - sor.frag
Allow symlinked frame files. Useful for testing.
[nageru] / sor.frag
index ac5b83c09f7be1c8a6eb66267562b5fcf2f74d78..9a8e1e40aa0a32490091c5e2eb7b1b671ad3ff2e 100644 (file)
--- a/sor.frag
+++ b/sor.frag
@@ -1,13 +1,16 @@
 #version 450 core
 
-in vec2 tc;
-in float element_sum_idx;
+in vec3 tc, tc_left, tc_down;
+in vec3 equation_tc_assuming_left, equation_tc_assuming_right;
+in float element_x_idx, element_sum_idx;
 out vec2 diff_flow;
 
-uniform sampler2D diff_flow_tex, smoothness_x_tex, smoothness_y_tex;
-uniform usampler2D equation_tex;
+uniform sampler2DArray diff_flow_tex, diffusivity_tex;
+uniform usampler2DArray equation_red_tex, equation_black_tex;
 uniform int phase;
 
+uniform int num_nonzero_phases;
+
 // See pack_floats_shared() in equations.frag.
 vec2 unpack_floats_shared(uint c)
 {
@@ -25,6 +28,16 @@ vec2 unpack_floats_shared(uint c)
        return vec2(a, b);
 }
 
+float zero_if_outside_border(vec4 val)
+{
+       if (val.w < 1.0f) {
+               // We hit the border (or more like half-way to it), so zero smoothness.
+               return 0.0f;
+       } else {
+               return val.x;
+       }
+}
+
 void main()
 {
        // Red-black SOR: Every other pass, we update every other element in a
@@ -32,36 +45,59 @@ void main()
        // just immediately throws away half of the warp, but it helps convergence
        // a _lot_ (rough testing indicates that five iterations of SOR is as good
        // as ~50 iterations of Jacobi). We could probably do better by reorganizing
-       // the data into two-values-per-pixel, so-called “twinning buffering”,
-       // but it makes for rather annoying code in the rest of the pipeline.
+       // the data into two-values-per-pixel, so-called “twinned buffering”;
+       // seemingly, it helps Haswell by ~15% on the SOR code, but GTX 950 not at all
+       // (at least not on 720p). Presumably the latter is already bandwidth bound.
        int color = int(round(element_sum_idx)) & 1;
        if (color != phase) discard;
 
-       uvec4 equation = texture(equation_tex, tc);
+       uvec4 equation;
+       vec3 equation_tc;
+       if ((int(round(element_x_idx)) & 1) == 0) {
+               equation_tc = equation_tc_assuming_left;
+       } else {
+               equation_tc = equation_tc_assuming_right;
+       }
+       if (phase == 0) {
+               equation = texture(equation_red_tex, equation_tc);
+       } else {
+               equation = texture(equation_black_tex, equation_tc);
+       }
        float inv_A11 = uintBitsToFloat(equation.x);
        float A12 = uintBitsToFloat(equation.y);
        float inv_A22 = uintBitsToFloat(equation.z);
        vec2 b = unpack_floats_shared(equation.w);
 
-       // Subtract the missing terms from the right-hand side
-       // (it couldn't be done earlier, because we didn't know
-       // the values of the neighboring pixels; they change for
-       // each SOR iteration).
-       float smooth_l = textureOffset(smoothness_x_tex, tc, ivec2(-1,  0)).x;
-       float smooth_r = texture(smoothness_x_tex, tc).x;
-       float smooth_d = textureOffset(smoothness_y_tex, tc, ivec2( 0, -1)).x;
-       float smooth_u = texture(smoothness_y_tex, tc).x;
-       b += smooth_l * textureOffset(diff_flow_tex, tc, ivec2(-1,  0)).xy;
-       b += smooth_r * textureOffset(diff_flow_tex, tc, ivec2( 1,  0)).xy;
-       b += smooth_d * textureOffset(diff_flow_tex, tc, ivec2( 0, -1)).xy;
-       b += smooth_u * textureOffset(diff_flow_tex, tc, ivec2( 0,  1)).xy;
-
        const float omega = 1.8;  // Marginally better than 1.6, it seems.
-       diff_flow = texture(diff_flow_tex, tc).xy;
 
-       // From https://en.wikipedia.org/wiki/Successive_over-relaxation.
-       float sigma_u = A12 * diff_flow.y;
-       diff_flow.x += omega * ((b.x - sigma_u) * inv_A11 - diff_flow.x);
-       float sigma_v = A12 * diff_flow.x;
-       diff_flow.y += omega * ((b.y - sigma_v) * inv_A22 - diff_flow.y);
+       if (num_nonzero_phases == 0) {
+               // Simplified version of the code below, assuming diff_flow == 0.0f everywhere.
+               diff_flow.x = omega * b.x * inv_A11;
+               diff_flow.y = omega * b.y * inv_A22;
+       } else {
+               // Subtract the missing terms from the right-hand side
+               // (it couldn't be done earlier, because we didn't know
+               // the values of the neighboring pixels; they change for
+               // each SOR iteration).
+               float smooth_l = zero_if_outside_border(texture(diffusivity_tex, tc_left));
+               float smooth_r = zero_if_outside_border(textureOffset(diffusivity_tex, tc_left, ivec2(1, 0)));
+               float smooth_d = zero_if_outside_border(texture(diffusivity_tex, tc_down));
+               float smooth_u = zero_if_outside_border(textureOffset(diffusivity_tex, tc_down, ivec2(0, 1)));
+               b += smooth_l * textureOffset(diff_flow_tex, tc, ivec2(-1,  0)).xy;
+               b += smooth_r * textureOffset(diff_flow_tex, tc, ivec2( 1,  0)).xy;
+               b += smooth_d * textureOffset(diff_flow_tex, tc, ivec2( 0, -1)).xy;
+               b += smooth_u * textureOffset(diff_flow_tex, tc, ivec2( 0,  1)).xy;
+
+               if (num_nonzero_phases == 1) {
+                       diff_flow = vec2(0.0f);
+               } else {
+                       diff_flow = texture(diff_flow_tex, tc).xy;
+               }
+
+               // From https://en.wikipedia.org/wiki/Successive_over-relaxation.
+               float sigma_u = A12 * diff_flow.y;
+               diff_flow.x += omega * ((b.x - sigma_u) * inv_A11 - diff_flow.x);
+               float sigma_v = A12 * diff_flow.x;
+               diff_flow.y += omega * ((b.y - sigma_v) * inv_A22 - diff_flow.y);
+       }
 }