1 /* Copyright (c) 2020 Themaister
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be
12 * included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #ifndef BINNING_H_
24 #define BINNING_H_
25
26 // There are 4 critical Y coordinates to test when binning. Top, bottom, mid, and mid - 1.
27
28 const int SUBPIXELS_Y = 4;
29
quantize_x(ivec4 x)30 ivec4 quantize_x(ivec4 x)
31 {
32 return x >> 15;
33 }
34
minimum4(ivec4 v)35 int minimum4(ivec4 v)
36 {
37 ivec2 minimum2 = min(v.xy, v.zw);
38 return min(minimum2.x, minimum2.y);
39 }
40
maximum4(ivec4 v)41 int maximum4(ivec4 v)
42 {
43 ivec2 maximum2 = max(v.xy, v.zw);
44 return max(maximum2.x, maximum2.y);
45 }
46
interpolate_xs(TriangleSetup setup,ivec4 ys,bool flip,int scaling)47 ivec2 interpolate_xs(TriangleSetup setup, ivec4 ys, bool flip, int scaling)
48 {
49 int yh_interpolation_base = setup.yh & ~(SUBPIXELS_Y - 1);
50 int ym_interpolation_base = setup.ym;
51
52 yh_interpolation_base *= scaling;
53 ym_interpolation_base *= scaling;
54
55 ivec4 xh = scaling * setup.xh + (ys - yh_interpolation_base) * setup.dxhdy;
56 ivec4 xm = scaling * setup.xm + (ys - yh_interpolation_base) * setup.dxmdy;
57 ivec4 xl = scaling * setup.xl + (ys - ym_interpolation_base) * setup.dxldy;
58 xl = mix(xl, xm, lessThan(ys, ivec4(scaling * setup.ym)));
59
60 ivec4 xh_shifted = quantize_x(xh);
61 ivec4 xl_shifted = quantize_x(xl);
62
63 ivec4 xleft, xright;
64 if (flip)
65 {
66 xleft = xh_shifted;
67 xright = xl_shifted;
68 }
69 else
70 {
71 xleft = xl_shifted;
72 xright = xh_shifted;
73 }
74
75 return ivec2(minimum4(xleft), maximum4(xright));
76 }
77
bin_primitive(TriangleSetup setup,ivec2 lo,ivec2 hi,int scaling)78 bool bin_primitive(TriangleSetup setup, ivec2 lo, ivec2 hi, int scaling)
79 {
80 int start_y = lo.y * SUBPIXELS_Y;
81 int end_y = (hi.y * SUBPIXELS_Y) + (SUBPIXELS_Y - 1);
82
83 // First, we clip start/end against y_lo, y_hi.
84 start_y = max(start_y, scaling * int(setup.yh));
85 end_y = min(end_y, scaling * int(setup.yl) - 1);
86
87 // Y is clipped out, exit early.
88 if (end_y < start_y)
89 return false;
90
91 bool flip = (setup.flags & TRIANGLE_SETUP_FLIP_BIT) != 0;
92
93 // Sample the X ranges for min and max Y, and potentially the mid-point as well.
94 ivec4 ys = ivec4(start_y, end_y, clamp(setup.ym * scaling + ivec2(-1, 0), ivec2(start_y), ivec2(end_y)));
95 ivec2 x_range = interpolate_xs(setup, ys, flip, scaling);
96 x_range.x = max(x_range.x, lo.x);
97 x_range.y = min(x_range.y, hi.x);
98 return x_range.x <= x_range.y;
99 }
100
101 #endif