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 + Constants::yMinMultiSampleOffset) >> subPixB;
169 yMax = (yMax + Constants::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(point)
318 {
319 *Pointer<Float>(primitive + OFFSET(Primitive, pointCoordX)) = Float(1.0f / subPixF) * Float(X0);
320 *Pointer<Float>(primitive + OFFSET(Primitive, pointCoordY)) = Float(1.0f / subPixF) * Float(Y0);
321 }
322
323 if(line)
324 {
325 X2 = X1 + Y1 - Y0;
326 Y2 = Y1 + X0 - X1;
327 }
328
329 Float dx = Float(X0) * (1.0f / subPixF);
330 Float dy = Float(Y0) * (1.0f / subPixF);
331
332 X1 -= X0;
333 Y1 -= Y0;
334
335 X2 -= X0;
336 Y2 -= Y0;
337
338 Float x1 = w1 * (1.0f / subPixF) * Float(X1);
339 Float y1 = w1 * (1.0f / subPixF) * Float(Y1);
340
341 Float x2 = w2 * (1.0f / subPixF) * Float(X2);
342 Float y2 = w2 * (1.0f / subPixF) * Float(Y2);
343
344 Float a = x1 * y2 - x2 * y1;
345
346 Float4 xQuad = Float4(0, 1, 0, 1) - Float4(dx);
347 Float4 yQuad = Float4(0, 0, 1, 1) - Float4(dy);
348
349 *Pointer<Float4>(primitive + OFFSET(Primitive, xQuad), 16) = xQuad;
350 *Pointer<Float4>(primitive + OFFSET(Primitive, yQuad), 16) = yQuad;
351
352 Float4 M[3];
353
354 M[0] = Float4(0, 0, 0, 0);
355 M[1] = Float4(0, 0, 0, 0);
356 M[2] = Float4(0, 0, 0, 0);
357
358 M[0].z = rhw0;
359
360 If(a != 0.0f)
361 {
362 Float A = 1.0f / a;
363 Float D = A * rhw0;
364
365 M[0].x = (y1 * w2 - y2 * w1) * D;
366 M[0].y = (x2 * w1 - x1 * w2) * D;
367 // M[0].z = rhw0;
368 // M[0].w = 0;
369
370 M[1].x = y2 * A;
371 M[1].y = -x2 * A;
372 // M[1].z = 0;
373 // M[1].w = 0;
374
375 M[2].x = -y1 * A;
376 M[2].y = x1 * A;
377 // M[2].z = 0;
378 // M[2].w = 0;
379 }
380
381 if(state.interpolateW)
382 {
383 Float4 ABC = M[0] + M[1] + M[2];
384
385 Float4 A = ABC.x;
386 Float4 B = ABC.y;
387 Float4 C = ABC.z;
388
389 *Pointer<Float4>(primitive + OFFSET(Primitive, w.A), 16) = A;
390 *Pointer<Float4>(primitive + OFFSET(Primitive, w.B), 16) = B;
391 *Pointer<Float4>(primitive + OFFSET(Primitive, w.C), 16) = C;
392 }
393
394 if(state.interpolateZ)
395 {
396 Float z0 = *Pointer<Float>(v0 + OFFSET(Vertex, projected.z));
397 Float z1 = *Pointer<Float>(v1 + OFFSET(Vertex, projected.z));
398 Float z2 = *Pointer<Float>(v2 + OFFSET(Vertex, projected.z));
399
400 z1 -= z0;
401 z2 -= z0;
402
403 Float A;
404 Float B;
405 Float C;
406
407 if(!point)
408 {
409 Float x1 = Float(X1) * (1.0f / subPixF);
410 Float y1 = Float(Y1) * (1.0f / subPixF);
411 Float x2 = Float(X2) * (1.0f / subPixF);
412 Float y2 = Float(Y2) * (1.0f / subPixF);
413
414 Float D = *Pointer<Float>(data + OFFSET(DrawData, depthRange)) / (x1 * y2 - x2 * y1);
415
416 A = (y2 * z1 - y1 * z2) * D;
417 B = (x1 * z2 - x2 * z1) * D;
418 }
419 else
420 {
421 A = 0.0f;
422 B = 0.0f;
423 }
424
425 C = z0 * *Pointer<Float>(data + OFFSET(DrawData, depthRange)) + *Pointer<Float>(data + OFFSET(DrawData, depthNear));
426
427 *Pointer<Float4>(primitive + OFFSET(Primitive, z.A), 16) = Float4(A);
428 *Pointer<Float4>(primitive + OFFSET(Primitive, z.B), 16) = Float4(B);
429 *Pointer<Float4>(primitive + OFFSET(Primitive, z.C), 16) = Float4(C);
430
431 Float bias = 0.0f;
432
433 if(state.applyConstantDepthBias)
434 {
435 Float r; // Minimum resolvable difference
436
437 if(state.fixedPointDepthBuffer)
438 {
439 // TODO(b/139341727): Pre-multiply the constant depth bias factor by the minimum
440 // resolvable difference.
441
442 // TODO(b/139341727): When there's a fixed-point depth buffer and no depth bias clamp,
443 // the constant depth bias factor could be added to 'depthNear', eliminating the per-
444 // polygon addition.
445
446 r = *Pointer<Float>(data + OFFSET(DrawData, minimumResolvableDepthDifference));
447 }
448 else // Floating-point depth buffer
449 {
450 // "For floating-point depth buffers, there is no single minimum resolvable difference.
451 // In this case, the minimum resolvable difference for a given polygon is dependent on
452 // the maximum exponent, e, in the range of z values spanned by the primitive. If n is
453 // the number of bits in the floating-point mantissa, the minimum resolvable difference,
454 // r, for the given primitive is defined as r = 2^(e-n)."
455
456 Float Z0 = C;
457 Float Z1 = z1 * *Pointer<Float>(data + OFFSET(DrawData, depthRange)) + *Pointer<Float>(data + OFFSET(DrawData, depthNear));
458 Float Z2 = z2 * *Pointer<Float>(data + OFFSET(DrawData, depthRange)) + *Pointer<Float>(data + OFFSET(DrawData, depthNear));
459
460 Int e0 = As<Int>(Z0) & 0x7F800000;
461 Int e1 = As<Int>(Z1) & 0x7F800000;
462 Int e2 = As<Int>(Z2) & 0x7F800000;
463
464 Int e = Max(Max(e0, e1), e2);
465
466 r = As<Float>(e) * Float(1.0f / (1 << 23));
467 }
468
469 bias = r * *Pointer<Float>(data + OFFSET(DrawData, constantDepthBias));
470 }
471
472 if(state.applySlopeDepthBias)
473 {
474 Float m = Max(Abs(A), Abs(B));
475
476 bias += m * *Pointer<Float>(data + OFFSET(DrawData, slopeDepthBias)); // TODO(b/155302798): Optimize 0 += x;
477 }
478
479 if(state.applyConstantDepthBias || state.applySlopeDepthBias)
480 {
481 if(state.applyDepthBiasClamp)
482 {
483 Float clamp = *Pointer<Float>(data + OFFSET(DrawData, depthBiasClamp));
484
485 bias = IfThenElse(clamp > 0.0f, Min(bias, clamp), Max(bias, clamp));
486 }
487
488 *Pointer<Float4>(primitive + OFFSET(Primitive, zBias), 16) = Float4(bias);
489 }
490 }
491
492 int packedInterpolant = 0;
493 for(int interfaceInterpolant = 0; interfaceInterpolant < MAX_INTERFACE_COMPONENTS; interfaceInterpolant++)
494 {
495 if(state.gradient[interfaceInterpolant].Type != SpirvShader::ATTRIBTYPE_UNUSED)
496 {
497 setupGradient(primitive, tri, w012, M, v0, v1, v2,
498 OFFSET(Vertex, v[interfaceInterpolant]),
499 OFFSET(Primitive, V[packedInterpolant]),
500 state.gradient[interfaceInterpolant].Flat,
501 !state.gradient[interfaceInterpolant].NoPerspective);
502 packedInterpolant++;
503 }
504 }
505
506 for(unsigned int i = 0; i < state.numClipDistances; i++)
507 {
508 setupGradient(primitive, tri, w012, M, v0, v1, v2,
509 OFFSET(Vertex, clipDistance[i]),
510 OFFSET(Primitive, clipDistance[i]),
511 false, true);
512 }
513
514 for(unsigned int i = 0; i < state.numCullDistances; i++)
515 {
516 setupGradient(primitive, tri, w012, M, v0, v1, v2,
517 OFFSET(Vertex, cullDistance[i]),
518 OFFSET(Primitive, cullDistance[i]),
519 false, true);
520 }
521
522 Return(1);
523 }
524
525 routine = function("SetupRoutine");
526 }
527
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)528 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)
529 {
530 if(!flat)
531 {
532 Float4 i;
533 i.x = *Pointer<Float>(v0 + attribute);
534 i.y = *Pointer<Float>(v1 + attribute);
535 i.z = *Pointer<Float>(v2 + attribute);
536 i.w = 0;
537
538 if(!perspective)
539 {
540 i *= w012;
541 }
542
543 Float4 A = i.xxxx * m[0];
544 Float4 B = i.yyyy * m[1];
545 Float4 C = i.zzzz * m[2];
546
547 C = A + B + C;
548
549 A = C.xxxx;
550 B = C.yyyy;
551 C = C.zzzz;
552
553 *Pointer<Float4>(primitive + planeEquation + 0, 16) = A;
554 *Pointer<Float4>(primitive + planeEquation + 16, 16) = B;
555 *Pointer<Float4>(primitive + planeEquation + 32, 16) = C;
556 }
557 else
558 {
559 int leadingVertex = OFFSET(Triangle, v0);
560 Float C = *Pointer<Float>(triangle + leadingVertex + attribute);
561
562 *Pointer<Float4>(primitive + planeEquation + 0, 16) = Float4(0, 0, 0, 0);
563 *Pointer<Float4>(primitive + planeEquation + 16, 16) = Float4(0, 0, 0, 0);
564 *Pointer<Float4>(primitive + planeEquation + 32, 16) = Float4(C);
565 }
566 }
567
edge(Pointer<Byte> & primitive,Pointer<Byte> & data,const Int & Xa,const Int & Ya,const Int & Xb,const Int & Yb,Int & q)568 void SetupRoutine::edge(Pointer<Byte> &primitive, Pointer<Byte> &data, const Int &Xa, const Int &Ya, const Int &Xb, const Int &Yb, Int &q)
569 {
570 If(Ya != Yb)
571 {
572 Bool swap = Yb < Ya;
573
574 Int X1 = IfThenElse(swap, Xb, Xa);
575 Int X2 = IfThenElse(swap, Xa, Xb);
576 Int Y1 = IfThenElse(swap, Yb, Ya);
577 Int Y2 = IfThenElse(swap, Ya, Yb);
578
579 constexpr int subPixB = vk::SUBPIXEL_PRECISION_BITS;
580 constexpr int subPixM = vk::SUBPIXEL_PRECISION_MASK;
581
582 Int y1 = Max((Y1 + subPixM) >> subPixB, *Pointer<Int>(data + OFFSET(DrawData, scissorY0)));
583 Int y2 = Min((Y2 + subPixM) >> subPixB, *Pointer<Int>(data + OFFSET(DrawData, scissorY1)));
584
585 If(y1 < y2)
586 {
587 Int xMin = *Pointer<Int>(data + OFFSET(DrawData, scissorX0));
588 Int xMax = *Pointer<Int>(data + OFFSET(DrawData, scissorX1));
589
590 Pointer<Byte> leftEdge = primitive + q * sizeof(Primitive) + OFFSET(Primitive, outline->left);
591 Pointer<Byte> rightEdge = primitive + q * sizeof(Primitive) + OFFSET(Primitive, outline->right);
592 Pointer<Byte> edge = IfThenElse(swap, rightEdge, leftEdge);
593
594 // Deltas
595 Int DX12 = X2 - X1;
596 Int DY12 = Y2 - Y1;
597
598 Int FDX12 = DX12 << subPixB;
599 Int FDY12 = DY12 << subPixB;
600
601 Int X = DX12 * ((y1 << subPixB) - Y1) + (X1 & subPixM) * DY12;
602 Int x = (X1 >> subPixB) + X / FDY12; // Edge
603 Int d = X % FDY12; // Error-term
604 Int ceil = -d >> 31; // Ceiling division: remainder <= 0
605 x -= ceil;
606 d -= ceil & FDY12;
607
608 Int Q = FDX12 / FDY12; // Edge-step
609 Int R = FDX12 % FDY12; // Error-step
610 Int floor = R >> 31; // Flooring division: remainder >= 0
611 Q += floor;
612 R += floor & FDY12;
613
614 Int D = FDY12; // Error-overflow
615 Int y = y1;
616
617 Do
618 {
619 *Pointer<Short>(edge + y * sizeof(Primitive::Span)) = Short(Clamp(x, xMin, xMax));
620
621 x += Q;
622 d += R;
623
624 Int overflow = -d >> 31;
625
626 d -= D & overflow;
627 x -= overflow;
628
629 y++;
630 }
631 Until(y >= y2);
632 }
633 }
634 }
635
conditionalRotate1(Bool condition,Pointer<Byte> & v0,Pointer<Byte> & v1,Pointer<Byte> & v2)636 void SetupRoutine::conditionalRotate1(Bool condition, Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2)
637 {
638 #if 0 // Rely on LLVM optimization
639 If(condition)
640 {
641 Pointer<Byte> vX;
642
643 vX = v0;
644 v0 = v1;
645 v1 = v2;
646 v2 = vX;
647 }
648 #else
649 Pointer<Byte> vX = v0;
650 v0 = IfThenElse(condition, v1, v0);
651 v1 = IfThenElse(condition, v2, v1);
652 v2 = IfThenElse(condition, vX, v2);
653 #endif
654 }
655
conditionalRotate2(Bool condition,Pointer<Byte> & v0,Pointer<Byte> & v1,Pointer<Byte> & v2)656 void SetupRoutine::conditionalRotate2(Bool condition, Pointer<Byte> &v0, Pointer<Byte> &v1, Pointer<Byte> &v2)
657 {
658 #if 0 // Rely on LLVM optimization
659 If(condition)
660 {
661 Pointer<Byte> vX;
662
663 vX = v2;
664 v2 = v1;
665 v1 = v0;
666 v0 = vX;
667 }
668 #else
669 Pointer<Byte> vX = v2;
670 v2 = IfThenElse(condition, v1, v2);
671 v1 = IfThenElse(condition, v0, v1);
672 v0 = IfThenElse(condition, vX, v0);
673 #endif
674 }
675
getRoutine()676 SetupFunction::RoutineType SetupRoutine::getRoutine()
677 {
678 return routine;
679 }
680
681 } // namespace sw
682