]> git.sesse.net Git - nageru/blob - futatabi/sor.frag
Log a warning when we kill a client that is not keeping up.
[nageru] / futatabi / sor.frag
1 #version 450 core
2
3 in vec3 tc, tc_left, tc_down;
4 in vec3 equation_tc_assuming_left, equation_tc_assuming_right;
5 in float element_x_idx, element_sum_idx;
6 out vec2 diff_flow;
7
8 uniform sampler2DArray diff_flow_tex, diffusivity_tex;
9 uniform usampler2DArray equation_red_tex, equation_black_tex;
10 uniform int phase;
11
12 uniform int num_nonzero_phases;
13
14 // See pack_floats_shared() in equations.frag.
15 vec2 unpack_floats_shared(uint c)
16 {
17         // Recover the exponent, and multiply it in. Add one because
18         // we have denormalized mantissas, then another one because we
19         // already reduced the exponent by one. Then subtract 20, because
20         // we are going to shift up the number by 20 below to recover the sign bits.
21         float normalizer = uintBitsToFloat(((c >> 1) & 0x7f800000u) - (18 << 23));
22         normalizer *= (1.0 / 2047.0);
23
24         // Shift the values up so that we recover the sign bit, then normalize.
25         float a = int(uint(c & 0x000fffu) << 20) * normalizer;
26         float b = int(uint(c & 0xfff000u) << 8) * normalizer;
27
28         return vec2(a, b);
29 }
30
31 float zero_if_outside_border(vec4 val)
32 {
33         if (val.w < 1.0f) {
34                 // We hit the border (or more like half-way to it), so zero smoothness.
35                 return 0.0f;
36         } else {
37                 return val.x;
38         }
39 }
40
41 void main()
42 {
43         // Red-black SOR: Every other pass, we update every other element in a
44         // checkerboard pattern. This is rather suboptimal for the GPU, as it
45         // just immediately throws away half of the warp, but it helps convergence
46         // a _lot_ (rough testing indicates that five iterations of SOR is as good
47         // as ~50 iterations of Jacobi). We could probably do better by reorganizing
48         // the data into two-values-per-pixel, so-called “twinned buffering”;
49         // seemingly, it helps Haswell by ~15% on the SOR code, but GTX 950 not at all
50         // (at least not on 720p). Presumably the latter is already bandwidth bound.
51         int color = int(round(element_sum_idx)) & 1;
52         if (color != phase) discard;
53
54         uvec4 equation;
55         vec3 equation_tc;
56         if ((int(round(element_x_idx)) & 1) == 0) {
57                 equation_tc = equation_tc_assuming_left;
58         } else {
59                 equation_tc = equation_tc_assuming_right;
60         }
61         if (phase == 0) {
62                 equation = texture(equation_red_tex, equation_tc);
63         } else {
64                 equation = texture(equation_black_tex, equation_tc);
65         }
66         float inv_A11 = uintBitsToFloat(equation.x);
67         float A12 = uintBitsToFloat(equation.y);
68         float inv_A22 = uintBitsToFloat(equation.z);
69         vec2 b = unpack_floats_shared(equation.w);
70
71         const float omega = 1.8;  // Marginally better than 1.6, it seems.
72
73         if (num_nonzero_phases == 0) {
74                 // Simplified version of the code below, assuming diff_flow == 0.0f everywhere.
75                 diff_flow.x = omega * b.x * inv_A11;
76                 diff_flow.y = omega * b.y * inv_A22;
77         } else {
78                 // Subtract the missing terms from the right-hand side
79                 // (it couldn't be done earlier, because we didn't know
80                 // the values of the neighboring pixels; they change for
81                 // each SOR iteration).
82                 float smooth_l = zero_if_outside_border(texture(diffusivity_tex, tc_left));
83                 float smooth_r = zero_if_outside_border(textureOffset(diffusivity_tex, tc_left, ivec2(1, 0)));
84                 float smooth_d = zero_if_outside_border(texture(diffusivity_tex, tc_down));
85                 float smooth_u = zero_if_outside_border(textureOffset(diffusivity_tex, tc_down, ivec2(0, 1)));
86                 b += smooth_l * textureOffset(diff_flow_tex, tc, ivec2(-1,  0)).xy;
87                 b += smooth_r * textureOffset(diff_flow_tex, tc, ivec2( 1,  0)).xy;
88                 b += smooth_d * textureOffset(diff_flow_tex, tc, ivec2( 0, -1)).xy;
89                 b += smooth_u * textureOffset(diff_flow_tex, tc, ivec2( 0,  1)).xy;
90
91                 if (num_nonzero_phases == 1) {
92                         diff_flow = vec2(0.0f);
93                 } else {
94                         diff_flow = texture(diff_flow_tex, tc).xy;
95                 }
96
97                 // From https://en.wikipedia.org/wiki/Successive_over-relaxation.
98                 float sigma_u = A12 * diff_flow.y;
99                 diff_flow.x += omega * ((b.x - sigma_u) * inv_A11 - diff_flow.x);
100                 float sigma_v = A12 * diff_flow.x;
101                 diff_flow.y += omega * ((b.y - sigma_v) * inv_A22 - diff_flow.y);
102         }
103 }