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 | |
29 | SetupRoutine::SetupRoutine(const SetupProcessor::State &state) : state(state) |
30 | { |
31 | routine = 0; |
32 | } |
33 | |
34 | SetupRoutine::~SetupRoutine() |
35 | { |
36 | } |
37 | |
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 | |
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 | |
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 | |
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 | |
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 | |
668 | std::shared_ptr<Routine> SetupRoutine::getRoutine() |
669 | { |
670 | return routine; |
671 | } |
672 | } |
673 | |