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