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 "Device/Polygon.hpp"
19 #include "Device/Primitive.hpp"
20 #include "Device/Renderer.hpp"
21 #include "Device/Vertex.hpp"
22 #include "Reactor/Reactor.hpp"
23 #include "Vulkan/VkDevice.hpp"
24
25 namespace sw {
26
SetupRoutine(const SetupProcessor::State & state)27 SetupRoutine::SetupRoutine(const SetupProcessor::State &state)
28 : state(state)
29 {
30 }
31
~SetupRoutine()32 SetupRoutine::~SetupRoutine()
33 {
34 }
35
generate()36 void SetupRoutine::generate()
37 {
38 SetupFunction function;
39 {
40 Pointer<Byte> device(function.Arg<0>());
41 Pointer<Byte> primitive(function.Arg<1>());
42 Pointer<Byte> tri(function.Arg<2>());
43 Pointer<Byte> polygon(function.Arg<3>());
44 Pointer<Byte> data(function.Arg<4>());
45
46 Pointer<Byte> constants = device + OFFSET(vk::Device, constants);
47
48 const bool point = state.isDrawPoint;
49 const bool line = state.isDrawLine;
50 const bool triangle = state.isDrawTriangle;
51
52 const int V0 = OFFSET(Triangle, v0);
53 const int V1 = (triangle || line) ? OFFSET(Triangle, v1) : OFFSET(Triangle, v0);
54 const int V2 = triangle ? OFFSET(Triangle, v2) : (line ? OFFSET(Triangle, v1) : OFFSET(Triangle, v0));
55
56 Pointer<Byte> v0 = tri + V0;
57 Pointer<Byte> v1 = tri + V1;
58 Pointer<Byte> v2 = tri + V2;
59
60 Array<Int> X(16);
61 Array<Int> Y(16);
62
63 X[0] = *Pointer<Int>(v0 + OFFSET(Vertex, projected.x));
64 X[1] = *Pointer<Int>(v1 + OFFSET(Vertex, projected.x));
65 X[2] = *Pointer<Int>(v2 + OFFSET(Vertex, projected.x));
66
67 Y[0] = *Pointer<Int>(v0 + OFFSET(Vertex, projected.y));
68 Y[1] = *Pointer<Int>(v1 + OFFSET(Vertex, projected.y));
69 Y[2] = *Pointer<Int>(v2 + OFFSET(Vertex, projected.y));
70
71 Int d = 1; // Winding direction
72
73 // Culling
74 if(triangle)
75 {
76 Float x0 = Float(X[0]);
77 Float x1 = Float(X[1]);
78 Float x2 = Float(X[2]);
79
80 Float y0 = Float(Y[0]);
81 Float y1 = Float(Y[1]);
82 Float y2 = Float(Y[2]);
83
84 Float A = (y0 - y2) * x1 + (y2 - y1) * x0 + (y1 - y0) * x2; // Area
85
86 Int w0w1w2 = *Pointer<Int>(v0 + OFFSET(Vertex, w)) ^
87 *Pointer<Int>(v1 + OFFSET(Vertex, w)) ^
88 *Pointer<Int>(v2 + OFFSET(Vertex, w));
89
90 A = IfThenElse(w0w1w2 < 0, -A, A);
91
92 Bool frontFacing = (state.frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE) ? (A >= 0.0f) : (A <= 0.0f);
93
94 if(state.cullMode & VK_CULL_MODE_FRONT_BIT)
95 {
96 If(frontFacing) Return(0);
97 }
98 if(state.cullMode & VK_CULL_MODE_BACK_BIT)
99 {
100 If(!frontFacing) Return(0);
101 }
102
103 d = IfThenElse(A > 0.0f, d, Int(0));
104
105 If(frontFacing)
106 {
107 *Pointer<Byte8>(primitive + OFFSET(Primitive, clockwiseMask)) = Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
108 *Pointer<Byte8>(primitive + OFFSET(Primitive, invClockwiseMask)) = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
109 }
110 Else
111 {
112 *Pointer<Byte8>(primitive + OFFSET(Primitive, clockwiseMask)) = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
113 *Pointer<Byte8>(primitive + OFFSET(Primitive, invClockwiseMask)) = Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
114 }
115 }
116 else
117 {
118 *Pointer<Byte8>(primitive + OFFSET(Primitive, clockwiseMask)) = Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
119 *Pointer<Byte8>(primitive + OFFSET(Primitive, invClockwiseMask)) = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
120 }
121
122 Int n = *Pointer<Int>(polygon + OFFSET(Polygon, n));
123 Int m = *Pointer<Int>(polygon + OFFSET(Polygon, i));
124
125 If(m != 0 || Bool(!triangle)) // Clipped triangle; reproject
126 {
127 Pointer<Byte> V = polygon + OFFSET(Polygon, P) + m * sizeof(void *) * 16;
128
129 Int i = 0;
130
131 Do
132 {
133 Pointer<Float4> p = *Pointer<Pointer<Float4> >(V + i * sizeof(void *));
134 Float4 v = *Pointer<Float4>(p, 16);
135
136 Float w = v.w;
137 Float rhw = IfThenElse(w != 0.0f, 1.0f / w, Float(1.0f));
138
139 X[i] = RoundInt(*Pointer<Float>(data + OFFSET(DrawData, X0xF)) + v.x * rhw * *Pointer<Float>(data + OFFSET(DrawData, WxF)));
140 Y[i] = RoundInt(*Pointer<Float>(data + OFFSET(DrawData, Y0xF)) + v.y * rhw * *Pointer<Float>(data + OFFSET(DrawData, HxF)));
141
142 i++;
143 }
144 Until(i >= n);
145 }
146
147 // Vertical range
148 Int yMin = Y[0];
149 Int yMax = Y[0];
150
151 Int i = 1;
152
153 Do
154 {
155 yMin = Min(Y[i], yMin);
156 yMax = Max(Y[i], yMax);
157
158 i++;
159 }
160 Until(i >= n);
161
162 constexpr int subPixB = vk::SUBPIXEL_PRECISION_BITS;
163 constexpr int subPixM = vk::SUBPIXEL_PRECISION_MASK;
164 constexpr float subPixF = vk::SUBPIXEL_PRECISION_FACTOR;
165
166 if(state.enableMultiSampling)
167 {
168 yMin = (yMin + yMinMultiSampleOffset) >> subPixB;
169 yMax = (yMax + yMaxMultiSampleOffset) >> subPixB;
170 }
171 else
172 {
173 yMin = (yMin + subPixM) >> subPixB;
174 yMax = (yMax + subPixM) >> subPixB;
175 }
176
177 yMin = Max(yMin, *Pointer<Int>(data + OFFSET(DrawData, scissorY0)));
178 yMax = Min(yMax, *Pointer<Int>(data + OFFSET(DrawData, scissorY1)));
179
180 // If yMin and yMax are initially negative, the scissor clamping above will typically result
181 // in yMin == 0 and yMax unchanged. We bail as we don't need to rasterize this primitive, and
182 // code below assumes yMin < yMax.
183 If(yMin >= yMax)
184 {
185 Return(0);
186 }
187
188 For(Int q = 0, q < state.multiSampleCount, q++)
189 {
190 Array<Int> Xq(16);
191 Array<Int> Yq(16);
192
193 Int i = 0;
194
195 Do
196 {
197 Xq[i] = X[i];
198 Yq[i] = Y[i];
199
200 if(state.enableMultiSampling)
201 {
202 // The subtraction here is because we're not moving the point, we're testing the edge against it
203 Xq[i] = Xq[i] - *Pointer<Int>(constants + OFFSET(Constants, Xf) + q * sizeof(int));
204 Yq[i] = Yq[i] - *Pointer<Int>(constants + OFFSET(Constants, Yf) + q * sizeof(int));
205 }
206
207 i++;
208 }
209 Until(i >= n);
210
211 Pointer<Byte> leftEdge = Pointer<Byte>(primitive + OFFSET(Primitive, outline->left)) + q * sizeof(Primitive);
212 Pointer<Byte> rightEdge = Pointer<Byte>(primitive + OFFSET(Primitive, outline->right)) + q * sizeof(Primitive);
213
214 if(state.enableMultiSampling)
215 {
216 Int xMin = *Pointer<Int>(data + OFFSET(DrawData, scissorX0));
217 Int xMax = *Pointer<Int>(data + OFFSET(DrawData, scissorX1));
218 Short x = Short(Clamp((X[0] + subPixM) >> subPixB, xMin, xMax));
219
220 For(Int y = yMin - 1, y < yMax + 1, y++)
221 {
222 *Pointer<Short>(leftEdge + y * sizeof(Primitive::Span)) = x;
223 *Pointer<Short>(rightEdge + y * sizeof(Primitive::Span)) = x;
224 }
225 }
226
227 Xq[n] = Xq[0];
228 Yq[n] = Yq[0];
229
230 // Rasterize
231 {
232 Int i = 0;
233
234 Do
235 {
236 edge(primitive, data, Xq[i + 1 - d], Yq[i + 1 - d], Xq[i + d], Yq[i + d], q);
237
238 i++;
239 }
240 Until(i >= n);
241 }
242
243 if(!state.enableMultiSampling)
244 {
245 For(, yMin < yMax && *Pointer<Short>(leftEdge + yMin * sizeof(Primitive::Span)) == *Pointer<Short>(rightEdge + yMin * sizeof(Primitive::Span)), yMin++)
246 {
247 // Increments yMin
248 }
249
250 For(, yMax > yMin && *Pointer<Short>(leftEdge + (yMax - 1) * sizeof(Primitive::Span)) == *Pointer<Short>(rightEdge + (yMax - 1) * sizeof(Primitive::Span)), yMax--)
251 {
252 // Decrements yMax
253 }
254
255 If(yMin == yMax)
256 {
257 Return(0);
258 }
259
260 *Pointer<Short>(leftEdge + (yMin - 1) * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + yMin * sizeof(Primitive::Span));
261 *Pointer<Short>(rightEdge + (yMin - 1) * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + yMin * sizeof(Primitive::Span));
262 *Pointer<Short>(leftEdge + yMax * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + (yMax - 1) * sizeof(Primitive::Span));
263 *Pointer<Short>(rightEdge + yMax * sizeof(Primitive::Span)) = *Pointer<Short>(leftEdge + (yMax - 1) * sizeof(Primitive::Span));
264 }
265 }
266
267 *Pointer<Int>(primitive + OFFSET(Primitive, yMin)) = yMin;
268 *Pointer<Int>(primitive + OFFSET(Primitive, yMax)) = yMax;
269
270 // Sort by minimum y
271 if(triangle)
272 {
273 Float y0 = *Pointer<Float>(v0 + OFFSET(Vertex, y));
274 Float y1 = *Pointer<Float>(v1 + OFFSET(Vertex, y));
275 Float y2 = *Pointer<Float>(v2 + OFFSET(Vertex, y));
276
277 Float yMin = Min(Min(y0, y1), y2);
278
279 conditionalRotate1(yMin == y1, v0, v1, v2);
280 conditionalRotate2(yMin == y2, v0, v1, v2);
281 }
282
283 // Sort by maximum w
284 if(triangle)
285 {
286 Float w0 = *Pointer<Float>(v0 + OFFSET(Vertex, w));
287 Float w1 = *Pointer<Float>(v1 + OFFSET(Vertex, w));
288 Float w2 = *Pointer<Float>(v2 + OFFSET(Vertex, w));
289
290 Float wMax = Max(Max(w0, w1), w2);
291
292 conditionalRotate1(wMax == w1, v0, v1, v2);
293 conditionalRotate2(wMax == w2, v0, v1, v2);
294 }
295
296 Float w0 = *Pointer<Float>(v0 + OFFSET(Vertex, w));
297 Float w1 = *Pointer<Float>(v1 + OFFSET(Vertex, w));
298 Float w2 = *Pointer<Float>(v2 + OFFSET(Vertex, w));
299
300 Float4 w012;
301
302 w012.x = w0;
303 w012.y = w1;
304 w012.z = w2;
305 w012.w = 1;
306
307 Float rhw0 = *Pointer<Float>(v0 + OFFSET(Vertex, projected.w));
308
309 Int X0 = *Pointer<Int>(v0 + OFFSET(Vertex, projected.x));
310 Int X1 = *Pointer<Int>(v1 + OFFSET(Vertex, projected.x));
311 Int X2 = *Pointer<Int>(v2 + OFFSET(Vertex, projected.x));
312
313 Int Y0 = *Pointer<Int>(v0 + OFFSET(Vertex, projected.y));
314 Int Y1 = *Pointer<Int>(v1 + OFFSET(Vertex, projected.y));
315 Int Y2 = *Pointer<Int>(v2 + OFFSET(Vertex, projected.y));
316
317 if(line)
318 {
319 X2 = X1 + Y1 - Y0;
320 Y2 = Y1 + X0 - X1;
321 }
322
323 Float x0 = Float(X0) * (1.0f / subPixF);
324 Float y0 = Float(Y0) * (1.0f / subPixF);
325 *Pointer<Float>(primitive + OFFSET(Primitive, x0)) = x0;
326 *Pointer<Float>(primitive + OFFSET(Primitive, y0)) = y0;
327
328 X1 -= X0;
329 Y1 -= Y0;
330
331 X2 -= X0;
332 Y2 -= Y0;
333
334 Float x1 = w1 * (1.0f / subPixF) * Float(X1);
335 Float y1 = w1 * (1.0f / subPixF) * Float(Y1);
336
337 Float x2 = w2 * (1.0f / subPixF) * Float(X2);
338 Float y2 = w2 * (1.0f / subPixF) * Float(Y2);
339
340 Float a = x1 * y2 - x2 * y1;
341
342 Float4 M[3];
343
344 M[0] = Float4(0, 0, 0, 0);
345 M[1] = Float4(0, 0, 0, 0);
346 M[2] = Float4(0, 0, 0, 0);
347
348 M[0].z = rhw0;
349
350 If(a != 0.0f)
351 {
352 Float A = 1.0f / a;
353 Float D = A * rhw0;
354
355 M[0].x = (y1 * w2 - y2 * w1) * D;
356 M[0].y = (x2 * w1 - x1 * w2) * D;
357 // M[0].z = rhw0;
358 // M[0].w = 0;
359
360 M[1].x = y2 * A;
361 M[1].y = -x2 * A;
362 // M[1].z = 0;
363 // M[1].w = 0;
364
365 M[2].x = -y1 * A;
366 M[2].y = x1 * A;
367 // M[2].z = 0;
368 // M[2].w = 0;
369 }
370
371 if(state.interpolateW)
372 {
373 Float4 ABC = M[0] + M[1] + M[2];
374
375 *Pointer<Float>(primitive + OFFSET(Primitive, w.A)) = ABC.x;
376 *Pointer<Float>(primitive + OFFSET(Primitive, w.B)) = ABC.y;
377 *Pointer<Float>(primitive + OFFSET(Primitive, w.C)) = ABC.z;
378 }
379
380 if(state.interpolateZ)
381 {
382 Float z0 = *Pointer<Float>(v0 + OFFSET(Vertex, projected.z));
383 Float z1 = *Pointer<Float>(v1 + OFFSET(Vertex, projected.z));
384 Float z2 = *Pointer<Float>(v2 + OFFSET(Vertex, projected.z));
385
386 z1 -= z0;
387 z2 -= z0;
388
389 Float A;
390 Float B;
391 Float C;
392
393 if(!point)
394 {
395 Float x1 = Float(X1) * (1.0f / subPixF);
396 Float y1 = Float(Y1) * (1.0f / subPixF);
397 Float x2 = Float(X2) * (1.0f / subPixF);
398 Float y2 = Float(Y2) * (1.0f / subPixF);
399
400 Float D = *Pointer<Float>(data + OFFSET(DrawData, depthRange)) / (x1 * y2 - x2 * y1);
401
402 A = (y2 * z1 - y1 * z2) * D;
403 B = (x1 * z2 - x2 * z1) * D;
404 }
405 else
406 {
407 A = 0.0f;
408 B = 0.0f;
409 }
410
411 C = z0 * *Pointer<Float>(data + OFFSET(DrawData, depthRange)) + *Pointer<Float>(data + OFFSET(DrawData, depthNear));
412
413 *Pointer<Float>(primitive + OFFSET(Primitive, z.A)) = A;
414 *Pointer<Float>(primitive + OFFSET(Primitive, z.B)) = B;
415 *Pointer<Float>(primitive + OFFSET(Primitive, z.C)) = C;
416
417 Float bias = 0.0f;
418
419 if(state.applyConstantDepthBias)
420 {
421 Float r; // Minimum resolvable difference
422
423 if(state.fixedPointDepthBuffer)
424 {
425 // TODO(b/139341727): Pre-multiply the constant depth bias factor by the minimum
426 // resolvable difference.
427
428 // TODO(b/139341727): When there's a fixed-point depth buffer and no depth bias clamp,
429 // the constant depth bias factor could be added to 'depthNear', eliminating the per-
430 // polygon addition.
431
432 r = *Pointer<Float>(data + OFFSET(DrawData, minimumResolvableDepthDifference));
433 }
434 else // Floating-point depth buffer
435 {
436 // "For floating-point depth buffers, there is no single minimum resolvable difference.
437 // In this case, the minimum resolvable difference for a given polygon is dependent on
438 // the maximum exponent, e, in the range of z values spanned by the primitive. If n is
439 // the number of bits in the floating-point mantissa, the minimum resolvable difference,
440 // r, for the given primitive is defined as r = 2^(e-n)."
441
442 Float Z0 = C;
443 Float Z1 = z1 * *Pointer<Float>(data + OFFSET(DrawData, depthRange)) + *Pointer<Float>(data + OFFSET(DrawData, depthNear));
444 Float Z2 = z2 * *Pointer<Float>(data + OFFSET(DrawData, depthRange)) + *Pointer<Float>(data + OFFSET(DrawData, depthNear));
445
446 Int e0 = As<Int>(Z0) & 0x7F800000;
447 Int e1 = As<Int>(Z1) & 0x7F800000;
448 Int e2 = As<Int>(Z2) & 0x7F800000;
449
450 Int e = Max(Max(e0, e1), e2);
451
452 r = As<Float>(e) * Float(1.0f / (1 << 23));
453 }
454
455 bias = r * *Pointer<Float>(data + OFFSET(DrawData, constantDepthBias));
456 }
457
458 if(state.applySlopeDepthBias)
459 {
460 Float m = Max(Abs(A), Abs(B));
461
462 bias += m * *Pointer<Float>(data + OFFSET(DrawData, slopeDepthBias)); // TODO(b/155302798): Optimize 0 += x;
463 }
464
465 if(state.applyConstantDepthBias || state.applySlopeDepthBias)
466 {
467 if(state.applyDepthBiasClamp)
468 {
469 Float clamp = *Pointer<Float>(data + OFFSET(DrawData, depthBiasClamp));
470
471 bias = IfThenElse(clamp > 0.0f, Min(bias, clamp), Max(bias, clamp));
472 }
473
474 *Pointer<Float>(primitive + OFFSET(Primitive, zBias)) = bias;
475 }
476 }
477
478 int packedInterpolant = 0;
479 for(int interfaceInterpolant = 0; interfaceInterpolant < MAX_INTERFACE_COMPONENTS; interfaceInterpolant++)
480 {
481 if(state.gradient[interfaceInterpolant].Type != SpirvShader::ATTRIBTYPE_UNUSED)
482 {
483 setupGradient(primitive, tri, w012, M, v0, v1, v2,
484 OFFSET(Vertex, v[interfaceInterpolant]),
485 OFFSET(Primitive, V[packedInterpolant]),
486 state.gradient[interfaceInterpolant].Flat,
487 !state.gradient[interfaceInterpolant].NoPerspective);
488 packedInterpolant++;
489 }
490 }
491
492 for(unsigned int i = 0; i < state.numClipDistances; i++)
493 {
494 setupGradient(primitive, tri, w012, M, v0, v1, v2,
495 OFFSET(Vertex, clipDistance[i]),
496 OFFSET(Primitive, clipDistance[i]),
497 false, true);
498 }
499
500 for(unsigned int i = 0; i < state.numCullDistances; i++)
501 {
502 setupGradient(primitive, tri, w012, M, v0, v1, v2,
503 OFFSET(Vertex, cullDistance[i]),
504 OFFSET(Primitive, cullDistance[i]),
505 false, true);
506 }
507
508 Return(1);
509 }
510
511 routine = function("SetupRoutine");
512 }
513
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 perspective)514 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 perspective)
515 {
516 if(!flat)
517 {
518 Float4 i;
519 i.x = *Pointer<Float>(v0 + attribute);
520 i.y = *Pointer<Float>(v1 + attribute);
521 i.z = *Pointer<Float>(v2 + attribute);
522 i.w = 0;
523
524 if(!perspective)
525 {
526 i *= w012;
527 }
528
529 Float4 A = i.xxxx * m[0];
530 Float4 B = i.yyyy * m[1];
531 Float4 C = i.zzzz * m[2];
532
533 Float4 P = A + B + C;
534
535 *Pointer<Float>(primitive + planeEquation + 0) = P.x;
536 *Pointer<Float>(primitive + planeEquation + 4) = P.y;
537 *Pointer<Float>(primitive + planeEquation + 8) = P.z;
538 }
539 else
540 {
541 int leadingVertex = OFFSET(Triangle, v0);
542 Float C = *Pointer<Float>(triangle + leadingVertex + attribute);
543
544 *Pointer<Float>(primitive + planeEquation + 0) = 0;
545 *Pointer<Float>(primitive + planeEquation + 4) = 0;
546 *Pointer<Float>(primitive + planeEquation + 8) = C;
547 }
548 }
549
edge(Pointer<Byte> & primitive,Pointer<Byte> & data,const Int & Xa,const Int & Ya,const Int & Xb,const Int & Yb,Int & q)550 void SetupRoutine::edge(Pointer<Byte> &primitive, Pointer<Byte> &data, const Int &Xa, const Int &Ya, const Int &Xb, const Int &Yb, Int &q)
551 {
552 If(Ya != Yb)
553 {
554 Bool swap = Yb < Ya;
555
556 Int X1 = IfThenElse(swap, Xb, Xa);
557 Int X2 = IfThenElse(swap, Xa, Xb);
558 Int Y1 = IfThenElse(swap, Yb, Ya);
559 Int Y2 = IfThenElse(swap, Ya, Yb);
560
561 constexpr int subPixB = vk::SUBPIXEL_PRECISION_BITS;
562 constexpr int subPixM = vk::SUBPIXEL_PRECISION_MASK;
563
564 Int y1 = (Y1 + subPixM) >> subPixB;
565 Int y2 = (Y2 + subPixM) >> subPixB;
566 Int yMin = Max(y1, *Pointer<Int>(data + OFFSET(DrawData, scissorY0)));
567 Int yMax = Min(y2, *Pointer<Int>(data + OFFSET(DrawData, scissorY1)));
568
569 If(yMin < yMax)
570 {
571 Int xMin = *Pointer<Int>(data + OFFSET(DrawData, scissorX0));
572 Int xMax = *Pointer<Int>(data + OFFSET(DrawData, scissorX1));
573
574 Pointer<Byte> leftEdge = primitive + q * sizeof(Primitive) + OFFSET(Primitive, outline->left);
575 Pointer<Byte> rightEdge = primitive + q * sizeof(Primitive) + OFFSET(Primitive, outline->right);
576 Pointer<Byte> edge = IfThenElse(swap, rightEdge, leftEdge);
577
578 // Deltas
579 Int DX12 = X2 - X1;
580 Int DY12 = Y2 - Y1;
581
582 Int FDX12 = DX12 << subPixB;
583 Int FDY12 = DY12 << subPixB;
584
585 Int X = DX12 * ((y1 << subPixB) - Y1) + (X1 & subPixM) * DY12;
586 Int x = (X1 >> subPixB) + X / FDY12; // Edge
587 Int d = X % FDY12; // Error-term
588 Int ceil = -d >> 31; // Ceiling division: remainder <= 0
589 x -= ceil;
590 d -= ceil & FDY12;
591
592 Int Q = FDX12 / FDY12; // Edge-step
593 Int R = FDX12 % FDY12; // Error-step
594 Int floor = R >> 31; // Flooring division: remainder >= 0
595 Q += floor;
596 R += floor & FDY12;
597
598 Int D = FDY12; // Error-overflow
599 Int y = y1;
600
601 Do
602 {
603 If(y >= yMin)
604 {
605 *Pointer<Short>(edge + y * sizeof(Primitive::Span)) = Short(Clamp(x, xMin, xMax));
606 }
607
608 x += Q;
609 d += R;
610
611 Int overflow = -d >> 31;
612
613 d -= D & overflow;
614 x -= overflow;
615
616 y++;
617 }
618 Until(y >= yMax);
619 }
620 }
621 }
622
conditionalRotate1(Bool condition,Pointer<Byte> & v0,Pointer<Byte> & v1,Pointer<Byte> & v2)623 void SetupRoutine::conditionalRotate1(Bool condition, Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2)
624 {
625 #if 0 // Rely on LLVM optimization
626 If(condition)
627 {
628 Pointer<Byte> vX;
629
630 vX = v0;
631 v0 = v1;
632 v1 = v2;
633 v2 = vX;
634 }
635 #else
636 Pointer<Byte> vX = v0;
637 v0 = IfThenElse(condition, v1, v0);
638 v1 = IfThenElse(condition, v2, v1);
639 v2 = IfThenElse(condition, vX, v2);
640 #endif
641 }
642
conditionalRotate2(Bool condition,Pointer<Byte> & v0,Pointer<Byte> & v1,Pointer<Byte> & v2)643 void SetupRoutine::conditionalRotate2(Bool condition, Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2)
644 {
645 #if 0 // Rely on LLVM optimization
646 If(condition)
647 {
648 Pointer<Byte> vX;
649
650 vX = v2;
651 v2 = v1;
652 v1 = v0;
653 v0 = vX;
654 }
655 #else
656 Pointer<Byte> vX = v2;
657 v2 = IfThenElse(condition, v1, v2);
658 v1 = IfThenElse(condition, v0, v1);
659 v0 = IfThenElse(condition, vX, v0);
660 #endif
661 }
662
getRoutine()663 SetupFunction::RoutineType SetupRoutine::getRoutine()
664 {
665 return routine;
666 }
667
668 } // namespace sw
669