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