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