• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "SetupRoutine.hpp"
16 
17 #include "Constants.hpp"
18 #include "Renderer/Primitive.hpp"
19 #include "Renderer/Polygon.hpp"
20 #include "Renderer/Renderer.hpp"
21 #include "Reactor/Reactor.hpp"
22 
23 namespace sw
24 {
25 	extern bool complementaryDepthBuffer;
26 	extern TranscendentalPrecision logPrecision;
27 	extern bool leadingVertexFirst;
28 
SetupRoutine(const SetupProcessor::State & state)29 	SetupRoutine::SetupRoutine(const SetupProcessor::State &state) : state(state)
30 	{
31 		routine = 0;
32 	}
33 
~SetupRoutine()34 	SetupRoutine::~SetupRoutine()
35 	{
36 	}
37 
generate()38 	void SetupRoutine::generate()
39 	{
40 		Function<Int(Pointer<Byte>, Pointer<Byte>, Pointer<Byte>, Pointer<Byte>)> function;
41 		{
42 			Pointer<Byte> primitive(function.Arg<0>());
43 			Pointer<Byte> tri(function.Arg<1>());
44 			Pointer<Byte> polygon(function.Arg<2>());
45 			Pointer<Byte> data(function.Arg<3>());
46 
47 			Pointer<Byte> constants = *Pointer<Pointer<Byte> >(data + OFFSET(DrawData,constants));
48 
49 			const bool point = state.isDrawPoint;
50 			const bool sprite = state.pointSprite;
51 			const bool line = state.isDrawLine;
52 			const bool triangle = state.isDrawSolidTriangle || sprite;
53 			const bool solidTriangle = state.isDrawSolidTriangle;
54 
55 			const int V0 = OFFSET(Triangle,v0);
56 			const int V1 = (triangle || line) ? OFFSET(Triangle,v1) : OFFSET(Triangle,v0);
57 			const int V2 = triangle ? OFFSET(Triangle,v2) : (line ? OFFSET(Triangle,v1) : OFFSET(Triangle,v0));
58 
59 			int pos = state.positionRegister;
60 
61 			Pointer<Byte> v0 = tri + V0;
62 			Pointer<Byte> v1 = tri + V1;
63 			Pointer<Byte> v2 = tri + V2;
64 
65 			Array<Int> X(16);
66 			Array<Int> Y(16);
67 
68 			X[0] = *Pointer<Int>(v0 + OFFSET(Vertex,X));
69 			X[1] = *Pointer<Int>(v1 + OFFSET(Vertex,X));
70 			X[2] = *Pointer<Int>(v2 + OFFSET(Vertex,X));
71 
72 			Y[0] = *Pointer<Int>(v0 + OFFSET(Vertex,Y));
73 			Y[1] = *Pointer<Int>(v1 + OFFSET(Vertex,Y));
74 			Y[2] = *Pointer<Int>(v2 + OFFSET(Vertex,Y));
75 
76 			Int d = 1;     // Winding direction
77 
78 			// Culling
79 			if(solidTriangle)
80 			{
81 				Float x0 = Float(X[0]);
82 				Float x1 = Float(X[1]);
83 				Float x2 = Float(X[2]);
84 
85 				Float y0 = Float(Y[0]);
86 				Float y1 = Float(Y[1]);
87 				Float y2 = Float(Y[2]);
88 
89 				Float A = (y2 - y0) * x1 + (y1 - y2) * x0 + (y0 - y1) * x2;   // Area
90 
91 				If(A == 0.0f)
92 				{
93 					Return(0);
94 				}
95 
96 				Int w0w1w2 = *Pointer<Int>(v0 + pos * 16 + 12) ^
97 							 *Pointer<Int>(v1 + pos * 16 + 12) ^
98 							 *Pointer<Int>(v2 + pos * 16 + 12);
99 
100 				A = IfThenElse(w0w1w2 < 0, -A, A);
101 
102 				if(state.cullMode == CULL_CLOCKWISE)
103 				{
104 					If(A >= 0.0f) Return(0);
105 				}
106 				else if(state.cullMode == CULL_COUNTERCLOCKWISE)
107 				{
108 					If(A <= 0.0f) Return(0);
109 				}
110 
111 				d = IfThenElse(A < 0.0f, d, Int(0));
112 
113 				if(state.twoSidedStencil)
114 				{
115 					If(A > 0.0f)
116 					{
117 						*Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask)) = Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
118 						*Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask)) = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
119 					}
120 					Else
121 					{
122 						*Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask)) = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
123 						*Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask)) = Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
124 					}
125 				}
126 
127 				if(state.vFace)
128 				{
129 					*Pointer<Float>(primitive + OFFSET(Primitive,area)) = 0.5f * A;
130 				}
131 			}
132 			else
133 			{
134 				if(state.twoSidedStencil)
135 				{
136 					*Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask)) = Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
137 					*Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask)) = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
138 				}
139 			}
140 
141 			Int n = *Pointer<Int>(polygon + OFFSET(Polygon,n));
142 			Int m = *Pointer<Int>(polygon + OFFSET(Polygon,i));
143 
144 			If(m != 0 || Bool(!solidTriangle))   // Clipped triangle; reproject
145 			{
146 				Pointer<Byte> V = polygon + OFFSET(Polygon,P) + m * sizeof(void*) * 16;
147 
148 				Int i = 0;
149 
150 				Do
151 				{
152 					Pointer<Float4> p = *Pointer<Pointer<Float4> >(V + i * sizeof(void*));
153 					Float4 v = *Pointer<Float4>(p, 16);
154 
155 					Float w = v.w;
156 					Float rhw = IfThenElse(w != 0.0f, 1.0f / w, Float(1.0f));
157 
158 					X[i] = RoundInt(*Pointer<Float>(data + OFFSET(DrawData,X0x16)) + v.x * rhw * *Pointer<Float>(data + OFFSET(DrawData,Wx16)));
159 					Y[i] = RoundInt(*Pointer<Float>(data + OFFSET(DrawData,Y0x16)) + v.y * rhw * *Pointer<Float>(data + OFFSET(DrawData,Hx16)));
160 
161 					i++;
162 				}
163 				Until(i >= n);
164 			}
165 
166 			// Vertical range
167 			Int yMin = Y[0];
168 			Int yMax = Y[0];
169 
170 			Int i = 1;
171 
172 			Do
173 			{
174 				yMin = Min(Y[i], yMin);
175 				yMax = Max(Y[i], yMax);
176 
177 				i++;
178 			}
179 			Until(i >= n);
180 
181 			if(state.multiSample > 1)
182 			{
183 				yMin = (yMin + 0x0A) >> 4;
184 				yMax = (yMax + 0x14) >> 4;
185 			}
186 			else
187 			{
188 				yMin = (yMin + 0x0F) >> 4;
189 				yMax = (yMax + 0x0F) >> 4;
190 			}
191 
192 			yMin = Max(yMin, *Pointer<Int>(data + OFFSET(DrawData,scissorY0)));
193 			yMax = Min(yMax, *Pointer<Int>(data + OFFSET(DrawData,scissorY1)));
194 
195 			// If yMin and yMax are initially negative, the scissor clamping above will typically result
196 			// in yMin == 0 and yMax unchanged. We bail as we don't need to rasterize this primitive, and
197 			// code below assumes yMin < yMax.
198 			If(yMin >= yMax)
199 			{
200 				Return(0);
201 			}
202 
203 			For(Int q = 0, q < state.multiSample, q++)
204 			{
205 				Array<Int> Xq(16);
206 				Array<Int> Yq(16);
207 
208 				Int i = 0;
209 
210 				Do
211 				{
212 					Xq[i] = X[i];
213 					Yq[i] = Y[i];
214 
215 					if(state.multiSample > 1)
216 					{
217 						Xq[i] = Xq[i] + *Pointer<Int>(constants + OFFSET(Constants,Xf) + q * sizeof(int));
218 						Yq[i] = Yq[i] + *Pointer<Int>(constants + OFFSET(Constants,Yf) + q * sizeof(int));
219 					}
220 
221 					i++;
222 				}
223 				Until(i >= n);
224 
225 				Pointer<Byte> leftEdge = Pointer<Byte>(primitive + OFFSET(Primitive,outline->left)) + q * sizeof(Primitive);
226 				Pointer<Byte> rightEdge = Pointer<Byte>(primitive + OFFSET(Primitive,outline->right)) + q * sizeof(Primitive);
227 
228 				if(state.multiSample > 1)
229 				{
230 					Int xMin = *Pointer<Int>(data + OFFSET(DrawData, scissorX0));
231 					Int xMax = *Pointer<Int>(data + OFFSET(DrawData, scissorX1));
232 					Short x = Short(Clamp((X[0] + 0xF) >> 4, xMin, xMax));
233 
234 					For(Int y = yMin - 1, y < yMax + 1, y++)
235 					{
236 						*Pointer<Short>(leftEdge + y * sizeof(Primitive::Span)) = x;
237 						*Pointer<Short>(rightEdge + y * sizeof(Primitive::Span)) = x;
238 					}
239 				}
240 
241 				Xq[n] = Xq[0];
242 				Yq[n] = Yq[0];
243 
244 				// Rasterize
245 				{
246 					Int i = 0;
247 
248 					Do
249 					{
250 						edge(primitive, data, Xq[i + 1 - d], Yq[i + 1 - d], Xq[i + d], Yq[i + d], q);
251 
252 						i++;
253 					}
254 					Until(i >= n);
255 				}
256 
257 				if(state.multiSample == 1)
258 				{
259 					For(, yMin < yMax && *Pointer<Short>(leftEdge + yMin * sizeof(Primitive::Span)) == *Pointer<Short>(rightEdge + yMin * sizeof(Primitive::Span)), yMin++)
260 					{
261 						// Increments yMin
262 					}
263 
264 					For(, yMax > yMin && *Pointer<Short>(leftEdge + (yMax - 1) * sizeof(Primitive::Span)) == *Pointer<Short>(rightEdge + (yMax - 1) * sizeof(Primitive::Span)), yMax--)
265 					{
266 						// Decrements yMax
267 					}
268 
269 					If(yMin == yMax)
270 					{
271 						Return(0);
272 					}
273 
274 					*Pointer<Short>(leftEdge + (yMin - 1) * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + yMin * sizeof(Primitive::Span));
275 					*Pointer<Short>(rightEdge + (yMin - 1) * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + yMin * sizeof(Primitive::Span));
276 					*Pointer<Short>(leftEdge + yMax * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + (yMax - 1) * sizeof(Primitive::Span));
277 					*Pointer<Short>(rightEdge + yMax * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + (yMax - 1) * sizeof(Primitive::Span));
278 				}
279 			}
280 
281 			*Pointer<Int>(primitive + OFFSET(Primitive,yMin)) = yMin;
282 			*Pointer<Int>(primitive + OFFSET(Primitive,yMax)) = yMax;
283 
284 			// Sort by minimum y
285 			if(solidTriangle && logPrecision >= WHQL)
286 			{
287 				Float y0 = *Pointer<Float>(v0 + pos * 16 + 4);
288 				Float y1 = *Pointer<Float>(v1 + pos * 16 + 4);
289 				Float y2 = *Pointer<Float>(v2 + pos * 16 + 4);
290 
291 				Float yMin = Min(Min(y0, y1), y2);
292 
293 				conditionalRotate1(yMin == y1, v0, v1, v2);
294 				conditionalRotate2(yMin == y2, v0, v1, v2);
295 			}
296 
297 			// Sort by maximum w
298 			if(solidTriangle)
299 			{
300 				Float w0 = *Pointer<Float>(v0 + pos * 16 + 12);
301 				Float w1 = *Pointer<Float>(v1 + pos * 16 + 12);
302 				Float w2 = *Pointer<Float>(v2 + pos * 16 + 12);
303 
304 				Float wMax = Max(Max(w0, w1), w2);
305 
306 				conditionalRotate1(wMax == w1, v0, v1, v2);
307 				conditionalRotate2(wMax == w2, v0, v1, v2);
308 			}
309 
310 			Float w0 = *Pointer<Float>(v0 + pos * 16 + 12);
311 			Float w1 = *Pointer<Float>(v1 + pos * 16 + 12);
312 			Float w2 = *Pointer<Float>(v2 + pos * 16 + 12);
313 
314 			Float4 w012;
315 
316 			w012.x = w0;
317 			w012.y = w1;
318 			w012.z = w2;
319 			w012.w = 1;
320 
321 			Float rhw0 = *Pointer<Float>(v0 + OFFSET(Vertex,W));
322 
323 			Int X0 = *Pointer<Int>(v0 + OFFSET(Vertex,X));
324 			Int X1 = *Pointer<Int>(v1 + OFFSET(Vertex,X));
325 			Int X2 = *Pointer<Int>(v2 + OFFSET(Vertex,X));
326 
327 			Int Y0 = *Pointer<Int>(v0 + OFFSET(Vertex,Y));
328 			Int Y1 = *Pointer<Int>(v1 + OFFSET(Vertex,Y));
329 			Int Y2 = *Pointer<Int>(v2 + OFFSET(Vertex,Y));
330 
331 			if(line)
332 			{
333 				X2 = X1 + Y1 - Y0;
334 				Y2 = Y1 + X0 - X1;
335 			}
336 
337 			Float dx = Float(X0) * (1.0f / 16.0f);
338 			Float dy = Float(Y0) * (1.0f / 16.0f);
339 
340 			X1 -= X0;
341 			Y1 -= Y0;
342 
343 			X2 -= X0;
344 			Y2 -= Y0;
345 
346 			Float x1 = w1 * (1.0f / 16.0f) * Float(X1);
347 			Float y1 = w1 * (1.0f / 16.0f) * Float(Y1);
348 
349 			Float x2 = w2 * (1.0f / 16.0f) * Float(X2);
350 			Float y2 = w2 * (1.0f / 16.0f) * Float(Y2);
351 
352 			Float a = x1 * y2 - x2 * y1;
353 
354 			Float4 xQuad = Float4(0, 1, 0, 1) - Float4(dx);
355 			Float4 yQuad = Float4(0, 0, 1, 1) - Float4(dy);
356 
357 			*Pointer<Float4>(primitive + OFFSET(Primitive,xQuad), 16) = xQuad;
358 			*Pointer<Float4>(primitive + OFFSET(Primitive,yQuad), 16) = yQuad;
359 
360 			Float4 M[3];
361 
362 			M[0] = Float4(0, 0, 0, 0);
363 			M[1] = Float4(0, 0, 0, 0);
364 			M[2] = Float4(0, 0, 0, 0);
365 
366 			M[0].z = rhw0;
367 
368 			If(a != 0.0f)
369 			{
370 				Float A = 1.0f / a;
371 				Float D = A * rhw0;
372 
373 				M[0].x = (y1 * w2 - y2 * w1) * D;
374 				M[0].y = (x2 * w1 - x1 * w2) * D;
375 			//	M[0].z = rhw0;
376 			//	M[0].w = 0;
377 
378 				M[1].x = y2 * A;
379 				M[1].y = -x2 * A;
380 			//	M[1].z = 0;
381 			//	M[1].w = 0;
382 
383 				M[2].x = -y1 * A;
384 				M[2].y = x1 * A;
385 			//	M[2].z = 0;
386 			//	M[2].w = 0;
387 			}
388 
389 			if(state.interpolateW)
390 			{
391 				Float4 ABC = M[0] + M[1] + M[2];
392 
393 				Float4 A = ABC.x;
394 				Float4 B = ABC.y;
395 				Float4 C = ABC.z;
396 
397 				*Pointer<Float4>(primitive + OFFSET(Primitive,w.A), 16) = A;
398 				*Pointer<Float4>(primitive + OFFSET(Primitive,w.B), 16) = B;
399 				*Pointer<Float4>(primitive + OFFSET(Primitive,w.C), 16) = C;
400 			}
401 
402 			if(state.interpolateZ)
403 			{
404 				Float z0 = *Pointer<Float>(v0 + OFFSET(Vertex,Z));
405 				Float z1 = *Pointer<Float>(v1 + OFFSET(Vertex,Z));
406 				Float z2 = *Pointer<Float>(v2 + OFFSET(Vertex,Z));
407 
408 				z1 -= z0;
409 				z2 -= z0;
410 
411 				Float4 A;
412 				Float4 B;
413 				Float4 C;
414 
415 				if(!point)
416 				{
417 					Float x1 = Float(X1) * (1.0f / 16.0f);
418 					Float y1 = Float(Y1) * (1.0f / 16.0f);
419 					Float x2 = Float(X2) * (1.0f / 16.0f);
420 					Float y2 = Float(Y2) * (1.0f / 16.0f);
421 
422 					Float D = *Pointer<Float>(data + OFFSET(DrawData,depthRange)) / (x1 * y2 - x2 * y1);
423 
424 					Float a = (y2 * z1 - y1 * z2) * D;
425 					Float b = (x1 * z2 - x2 * z1) * D;
426 
427 					A = Float4(a);
428 					B = Float4(b);
429 				}
430 				else
431 				{
432 					A = Float4(0, 0, 0, 0);
433 					B = Float4(0, 0, 0, 0);
434 				}
435 
436 				*Pointer<Float4>(primitive + OFFSET(Primitive,z.A), 16) = A;
437 				*Pointer<Float4>(primitive + OFFSET(Primitive,z.B), 16) = B;
438 
439 				Float c = z0;
440 
441 				if(state.isDrawTriangle && state.slopeDepthBias)
442 				{
443 					Float bias = Max(Abs(Float(A.x)), Abs(Float(B.x)));
444 					bias *= *Pointer<Float>(data + OFFSET(DrawData,slopeDepthBias));
445 
446 					if(complementaryDepthBuffer)
447 					{
448 						bias = -bias;
449 					}
450 
451 					c += bias;
452 				}
453 
454 				C = Float4(c * *Pointer<Float>(data + OFFSET(DrawData,depthRange)) + *Pointer<Float>(data + OFFSET(DrawData,depthNear)));
455 
456 				*Pointer<Float4>(primitive + OFFSET(Primitive,z.C), 16) = C;
457 			}
458 
459 			for(int interpolant = 0; interpolant < MAX_FRAGMENT_INPUTS; interpolant++)
460 			{
461 				for(int component = 0; component < 4; component++)
462 				{
463 					int attribute = state.gradient[interpolant][component].attribute;
464 					bool flat = state.gradient[interpolant][component].flat;
465 					bool wrap = state.gradient[interpolant][component].wrap;
466 
467 					if(attribute != Unused)
468 					{
469 						setupGradient(primitive, tri, w012, M, v0, v1, v2, OFFSET(Vertex,v[attribute][component]), OFFSET(Primitive,V[interpolant][component]), flat, sprite, state.perspective, wrap, component);
470 					}
471 				}
472 			}
473 
474 			if(state.fog.attribute == Fog)
475 			{
476 				setupGradient(primitive, tri, w012, M, v0, v1, v2, OFFSET(Vertex,f), OFFSET(Primitive,f), state.fog.flat, false, state.perspective, false, 0);
477 			}
478 
479 			Return(1);
480 		}
481 
482 		routine = function("SetupRoutine");
483 	}
484 
setupGradient(Pointer<Byte> & primitive,Pointer<Byte> & triangle,Float4 & w012,Float4 (& m)[3],Pointer<Byte> & v0,Pointer<Byte> & v1,Pointer<Byte> & v2,int attribute,int planeEquation,bool flat,bool sprite,bool perspective,bool wrap,int component)485 	void SetupRoutine::setupGradient(Pointer<Byte> &primitive, Pointer<Byte> &triangle, Float4 &w012, Float4 (&m)[3], Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2, int attribute, int planeEquation, bool flat, bool sprite, bool perspective, bool wrap, int component)
486 	{
487 		Float4 i;
488 
489 		if(!flat)
490 		{
491 			if(!sprite)
492 			{
493 				i.x = *Pointer<Float>(v0 + attribute);
494 				i.y = *Pointer<Float>(v1 + attribute);
495 				i.z = *Pointer<Float>(v2 + attribute);
496 				i.w = 0;
497 			}
498 			else
499 			{
500 				if(component == 0) i.x = 0.5f;
501 				if(component == 1) i.x = 0.5f;
502 				if(component == 2) i.x = 0.0f;
503 				if(component == 3) i.x = 1.0f;
504 
505 				if(component == 0) i.y = 1.0f;
506 				if(component == 1) i.y = 0.5f;
507 				if(component == 2) i.y = 0.0f;
508 				if(component == 3) i.y = 1.0f;
509 
510 				if(component == 0) i.z = 0.5f;
511 				if(component == 1) i.z = 1.0f;
512 				if(component == 2) i.z = 0.0f;
513 				if(component == 3) i.z = 1.0f;
514 
515 				i.w = 0;
516 			}
517 
518 			if(wrap)
519 			{
520 				Float m;
521 
522 				m = *Pointer<Float>(v0 + attribute);
523 				m = Max(m, *Pointer<Float>(v1 + attribute));
524 				m = Max(m, *Pointer<Float>(v2 + attribute));
525 				m -= 0.5f;
526 
527 				// FIXME: Vectorize
528 				If(Float(i.x) < m) i.x = i.x + 1.0f;
529 				If(Float(i.y) < m) i.y = i.y + 1.0f;
530 				If(Float(i.z) < m) i.z = i.z + 1.0f;
531 			}
532 
533 			if(!perspective)
534 			{
535 				i *= w012;
536 			}
537 
538 			Float4 A = i.xxxx * m[0];
539 			Float4 B = i.yyyy * m[1];
540 			Float4 C = i.zzzz * m[2];
541 
542 			C = A + B + C;
543 
544 			A = C.xxxx;
545 			B = C.yyyy;
546 			C = C.zzzz;
547 
548 			*Pointer<Float4>(primitive + planeEquation + 0, 16) = A;
549 			*Pointer<Float4>(primitive + planeEquation + 16, 16) = B;
550 			*Pointer<Float4>(primitive + planeEquation + 32, 16) = C;
551 		}
552 		else
553 		{
554 			int leadingVertex = leadingVertexFirst ? OFFSET(Triangle,v0) : OFFSET(Triangle,v2);
555 			Float C = *Pointer<Float>(triangle + leadingVertex + attribute);
556 
557 			*Pointer<Float4>(primitive + planeEquation + 0, 16) = Float4(0, 0, 0, 0);
558 			*Pointer<Float4>(primitive + planeEquation + 16, 16) = Float4(0, 0, 0, 0);
559 			*Pointer<Float4>(primitive + planeEquation + 32, 16) = Float4(C);
560 		}
561 	}
562 
edge(Pointer<Byte> & primitive,Pointer<Byte> & data,const Int & Xa,const Int & Ya,const Int & Xb,const Int & Yb,Int & q)563 	void SetupRoutine::edge(Pointer<Byte> &primitive, Pointer<Byte> &data, const Int &Xa, const Int &Ya, const Int &Xb, const Int &Yb, Int &q)
564 	{
565 		If(Ya != Yb)
566 		{
567 			Bool swap = Yb < Ya;
568 
569 			Int X1 = IfThenElse(swap, Xb, Xa);
570 			Int X2 = IfThenElse(swap, Xa, Xb);
571 			Int Y1 = IfThenElse(swap, Yb, Ya);
572 			Int Y2 = IfThenElse(swap, Ya, Yb);
573 
574 			Int y1 = Max((Y1 + 0x0000000F) >> 4, *Pointer<Int>(data + OFFSET(DrawData,scissorY0)));
575 			Int y2 = Min((Y2 + 0x0000000F) >> 4, *Pointer<Int>(data + OFFSET(DrawData,scissorY1)));
576 
577 			If(y1 < y2)
578 			{
579 				Int xMin = *Pointer<Int>(data + OFFSET(DrawData,scissorX0));
580 				Int xMax = *Pointer<Int>(data + OFFSET(DrawData,scissorX1));
581 
582 				Pointer<Byte> leftEdge = primitive + q * sizeof(Primitive) + OFFSET(Primitive,outline->left);
583 				Pointer<Byte> rightEdge = primitive + q * sizeof(Primitive) + OFFSET(Primitive,outline->right);
584 				Pointer<Byte> edge = IfThenElse(swap, rightEdge, leftEdge);
585 
586 				// Deltas
587 				Int DX12 = X2 - X1;
588 				Int DY12 = Y2 - Y1;
589 
590 				Int FDX12 = DX12 << 4;
591 				Int FDY12 = DY12 << 4;
592 
593 				Int X = DX12 * ((y1 << 4) - Y1) + (X1 & 0x0000000F) * DY12;
594 				Int x = (X1 >> 4) + X / FDY12;   // Edge
595 				Int d = X % FDY12;               // Error-term
596 				Int ceil = -d >> 31;             // Ceiling division: remainder <= 0
597 				x -= ceil;
598 				d -= ceil & FDY12;
599 
600 				Int Q = FDX12 / FDY12;   // Edge-step
601 				Int R = FDX12 % FDY12;   // Error-step
602 				Int floor = R >> 31;     // Flooring division: remainder >= 0
603 				Q += floor;
604 				R += floor & FDY12;
605 
606 				Int D = FDY12;   // Error-overflow
607 				Int y = y1;
608 
609 				Do
610 				{
611 					*Pointer<Short>(edge + y * sizeof(Primitive::Span)) = Short(Clamp(x, xMin, xMax));
612 
613 					x += Q;
614 					d += R;
615 
616 					Int overflow = -d >> 31;
617 
618 					d -= D & overflow;
619 					x -= overflow;
620 
621 					y++;
622 				}
623 				Until(y >= y2);
624 			}
625 		}
626 	}
627 
conditionalRotate1(Bool condition,Pointer<Byte> & v0,Pointer<Byte> & v1,Pointer<Byte> & v2)628 	void SetupRoutine::conditionalRotate1(Bool condition, Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2)
629 	{
630 		#if 0   // Rely on LLVM optimization
631 			If(condition)
632 			{
633 				Pointer<Byte> vX;
634 
635 				vX = v0;
636 				v0 = v1;
637 				v1 = v2;
638 				v2 = vX;
639 			}
640 		#else
641 			Pointer<Byte> vX = v0;
642 			v0 = IfThenElse(condition, v1, v0);
643 			v1 = IfThenElse(condition, v2, v1);
644 			v2 = IfThenElse(condition, vX, v2);
645 		#endif
646 	}
647 
conditionalRotate2(Bool condition,Pointer<Byte> & v0,Pointer<Byte> & v1,Pointer<Byte> & v2)648 	void SetupRoutine::conditionalRotate2(Bool condition, Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2)
649 	{
650 		#if 0   // Rely on LLVM optimization
651 			If(condition)
652 			{
653 				Pointer<Byte> vX;
654 
655 				vX = v2;
656 				v2 = v1;
657 				v1 = v0;
658 				v0 = vX;
659 			}
660 		#else
661 			Pointer<Byte> vX = v2;
662 			v2 = IfThenElse(condition, v1, v2);
663 			v1 = IfThenElse(condition, v0, v1);
664 			v0 = IfThenElse(condition, vX, v0);
665 		#endif
666 	}
667 
getRoutine()668 	std::shared_ptr<Routine> SetupRoutine::getRoutine()
669 	{
670 		return routine;
671 	}
672 }
673