184ded5ab289e1fe5cfa35f28d63f9246d127e54
[mesa.git] / src / gallium / drivers / swr / rasterizer / core / rasterizer.cpp
1 /****************************************************************************
2 * Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * @file rasterizer.cpp
24 *
25 * @brief Implementation for the rasterizer.
26 *
27 ******************************************************************************/
28
29 #include <vector>
30 #include <algorithm>
31
32 #include "rasterizer.h"
33 #include "rdtsc_core.h"
34 #include "backend.h"
35 #include "utils.h"
36 #include "frontend.h"
37 #include "tilemgr.h"
38 #include "memory/tilingtraits.h"
39
40 template <uint32_t numSamples = 1>
41 void GetRenderHotTiles(DRAW_CONTEXT *pDC, uint32_t macroID, uint32_t x, uint32_t y, RenderOutputBuffers &renderBuffers, uint32_t renderTargetArrayIndex);
42 template <typename RT>
43 void StepRasterTileX(uint32_t MaxRT, RenderOutputBuffers &buffers);
44 template <typename RT>
45 void StepRasterTileY(uint32_t MaxRT, RenderOutputBuffers &buffers, RenderOutputBuffers &startBufferRow);
46
47 #define MASKTOVEC(i3,i2,i1,i0) {-i0,-i1,-i2,-i3}
48 const __m256d gMaskToVecpd[] =
49 {
50 MASKTOVEC(0, 0, 0, 0),
51 MASKTOVEC(0, 0, 0, 1),
52 MASKTOVEC(0, 0, 1, 0),
53 MASKTOVEC(0, 0, 1, 1),
54 MASKTOVEC(0, 1, 0, 0),
55 MASKTOVEC(0, 1, 0, 1),
56 MASKTOVEC(0, 1, 1, 0),
57 MASKTOVEC(0, 1, 1, 1),
58 MASKTOVEC(1, 0, 0, 0),
59 MASKTOVEC(1, 0, 0, 1),
60 MASKTOVEC(1, 0, 1, 0),
61 MASKTOVEC(1, 0, 1, 1),
62 MASKTOVEC(1, 1, 0, 0),
63 MASKTOVEC(1, 1, 0, 1),
64 MASKTOVEC(1, 1, 1, 0),
65 MASKTOVEC(1, 1, 1, 1),
66 };
67
68 struct POS
69 {
70 int32_t x, y;
71 };
72
73 struct EDGE
74 {
75 double a, b; // a, b edge coefficients in fix8
76 double stepQuadX; // step to adjacent horizontal quad in fix16
77 double stepQuadY; // step to adjacent vertical quad in fix16
78 double stepRasterTileX; // step to adjacent horizontal raster tile in fix16
79 double stepRasterTileY; // step to adjacent vertical raster tile in fix16
80
81 __m256d vQuadOffsets; // offsets for 4 samples of a quad
82 __m256d vRasterTileOffsets; // offsets for the 4 corners of a raster tile
83 };
84
85 //////////////////////////////////////////////////////////////////////////
86 /// @brief rasterize a raster tile partially covered by the triangle
87 /// @param vEdge0-2 - edge equations evaluated at sample pos at each of the 4 corners of a raster tile
88 /// @param vA, vB - A & B coefs for each edge of the triangle (Ax + Bx + C)
89 /// @param vStepQuad0-2 - edge equations evaluated at the UL corners of the 2x2 pixel quad.
90 /// Used to step between quads when sweeping over the raster tile.
91 template<uint32_t NumEdges, typename EdgeMaskT>
92 INLINE uint64_t rasterizePartialTile(DRAW_CONTEXT *pDC, double startEdges[NumEdges], EDGE *pRastEdges)
93 {
94 uint64_t coverageMask = 0;
95
96 __m256d vEdges[NumEdges];
97 __m256d vStepX[NumEdges];
98 __m256d vStepY[NumEdges];
99
100 for (uint32_t e = 0; e < NumEdges; ++e)
101 {
102 // Step to the pixel sample locations of the 1st quad
103 vEdges[e] = _mm256_add_pd(_mm256_set1_pd(startEdges[e]), pRastEdges[e].vQuadOffsets);
104
105 // compute step to next quad (mul by 2 in x and y direction)
106 vStepX[e] = _mm256_set1_pd(pRastEdges[e].stepQuadX);
107 vStepY[e] = _mm256_set1_pd(pRastEdges[e].stepQuadY);
108 }
109
110 // fast unrolled version for 8x8 tile
111 #if KNOB_TILE_X_DIM == 8 && KNOB_TILE_Y_DIM == 8
112 int edgeMask[NumEdges];
113 uint64_t mask;
114
115 auto eval_lambda = [&](int e){edgeMask[e] = _mm256_movemask_pd(vEdges[e]);};
116 auto update_lambda = [&](int e){mask &= edgeMask[e];};
117 auto incx_lambda = [&](int e){vEdges[e] = _mm256_add_pd(vEdges[e], vStepX[e]);};
118 auto incy_lambda = [&](int e){vEdges[e] = _mm256_add_pd(vEdges[e], vStepY[e]);};
119 auto decx_lambda = [&](int e){vEdges[e] = _mm256_sub_pd(vEdges[e], vStepX[e]);};
120
121 // evaluate which pixels in the quad are covered
122 #define EVAL \
123 UnrollerLMask<0, NumEdges, 1, EdgeMaskT::value>::step(eval_lambda);
124
125 // update coverage mask
126 // if edge 0 is degenerate and will be skipped; init the mask
127 #define UPDATE_MASK(bit) \
128 if(std::is_same<EdgeMaskT, E1E2ValidT>::value || std::is_same<EdgeMaskT, NoEdgesValidT>::value){\
129 mask = 0xf;\
130 }\
131 else{\
132 mask = edgeMask[0]; \
133 }\
134 UnrollerLMask<1, NumEdges, 1, EdgeMaskT::value>::step(update_lambda); \
135 coverageMask |= (mask << bit);
136
137 // step in the +x direction to the next quad
138 #define INCX \
139 UnrollerLMask<0, NumEdges, 1, EdgeMaskT::value>::step(incx_lambda);
140
141 // step in the +y direction to the next quad
142 #define INCY \
143 UnrollerLMask<0, NumEdges, 1, EdgeMaskT::value>::step(incy_lambda);
144
145 // step in the -x direction to the next quad
146 #define DECX \
147 UnrollerLMask<0, NumEdges, 1, EdgeMaskT::value>::step(decx_lambda);
148
149 // sweep 2x2 quad back and forth through the raster tile,
150 // computing coverage masks for the entire tile
151
152 // raster tile
153 // 0 1 2 3 4 5 6 7
154 // x x
155 // x x ------------------>
156 // x x |
157 // <-----------------x x V
158 // ..
159
160 // row 0
161 EVAL;
162 UPDATE_MASK(0);
163 INCX;
164 EVAL;
165 UPDATE_MASK(4);
166 INCX;
167 EVAL;
168 UPDATE_MASK(8);
169 INCX;
170 EVAL;
171 UPDATE_MASK(12);
172 INCY;
173
174 //row 1
175 EVAL;
176 UPDATE_MASK(28);
177 DECX;
178 EVAL;
179 UPDATE_MASK(24);
180 DECX;
181 EVAL;
182 UPDATE_MASK(20);
183 DECX;
184 EVAL;
185 UPDATE_MASK(16);
186 INCY;
187
188 // row 2
189 EVAL;
190 UPDATE_MASK(32);
191 INCX;
192 EVAL;
193 UPDATE_MASK(36);
194 INCX;
195 EVAL;
196 UPDATE_MASK(40);
197 INCX;
198 EVAL;
199 UPDATE_MASK(44);
200 INCY;
201
202 // row 3
203 EVAL;
204 UPDATE_MASK(60);
205 DECX;
206 EVAL;
207 UPDATE_MASK(56);
208 DECX;
209 EVAL;
210 UPDATE_MASK(52);
211 DECX;
212 EVAL;
213 UPDATE_MASK(48);
214 #else
215 uint32_t bit = 0;
216 for (uint32_t y = 0; y < KNOB_TILE_Y_DIM/2; ++y)
217 {
218 __m256d vStartOfRowEdge[NumEdges];
219 for (uint32_t e = 0; e < NumEdges; ++e)
220 {
221 vStartOfRowEdge[e] = vEdges[e];
222 }
223
224 for (uint32_t x = 0; x < KNOB_TILE_X_DIM/2; ++x)
225 {
226 int edgeMask[NumEdges];
227 for (uint32_t e = 0; e < NumEdges; ++e)
228 {
229 edgeMask[e] = _mm256_movemask_pd(vEdges[e]);
230 }
231
232 uint64_t mask = edgeMask[0];
233 for (uint32_t e = 1; e < NumEdges; ++e)
234 {
235 mask &= edgeMask[e];
236 }
237 coverageMask |= (mask << bit);
238
239 // step to the next pixel in the x
240 for (uint32_t e = 0; e < NumEdges; ++e)
241 {
242 vEdges[e] = _mm256_add_pd(vEdges[e], vStepX[e]);
243 }
244 bit+=4;
245 }
246
247 // step to the next row
248 for (uint32_t e = 0; e < NumEdges; ++e)
249 {
250 vEdges[e] = _mm256_add_pd(vStartOfRowEdge[e], vStepY[e]);
251 }
252 }
253 #endif
254 return coverageMask;
255
256 }
257 // Top left rule:
258 // Top: if an edge is horizontal, and it is above other edges in tri pixel space, it is a 'top' edge
259 // Left: if an edge is not horizontal, and it is on the left side of the triangle in pixel space, it is a 'left' edge
260 // Top left: a sample is in if it is a top or left edge.
261 // Out: !(horizontal && above) = !horizontal && below
262 // Out: !horizontal && left = !(!horizontal && left) = horizontal and right
263 INLINE void adjustTopLeftRuleIntFix16(const __m128i vA, const __m128i vB, __m256d &vEdge)
264 {
265 // if vA < 0, vC--
266 // if vA == 0 && vB < 0, vC--
267
268 __m256d vEdgeOut = vEdge;
269 __m256d vEdgeAdjust = _mm256_sub_pd(vEdge, _mm256_set1_pd(1.0));
270
271 // if vA < 0 (line is not horizontal and below)
272 int msk = _mm_movemask_ps(_mm_castsi128_ps(vA));
273
274 // if vA == 0 && vB < 0 (line is horizontal and we're on the left edge of a tri)
275 __m128i vCmp = _mm_cmpeq_epi32(vA, _mm_setzero_si128());
276 int msk2 = _mm_movemask_ps(_mm_castsi128_ps(vCmp));
277 msk2 &= _mm_movemask_ps(_mm_castsi128_ps(vB));
278
279 // if either of these are true and we're on the line (edge == 0), bump it outside the line
280 vEdge = _mm256_blendv_pd(vEdgeOut, vEdgeAdjust, gMaskToVecpd[msk | msk2]);
281 }
282
283 //////////////////////////////////////////////////////////////////////////
284 /// @brief calculates difference in precision between the result of manh
285 /// calculation and the edge precision, based on compile time trait values
286 template<typename RT>
287 constexpr int64_t ManhToEdgePrecisionAdjust()
288 {
289 static_assert(RT::PrecisionT::BitsT::value + RT::ConservativePrecisionT::BitsT::value >= RT::EdgePrecisionT::BitsT::value,
290 "Inadequate precision of result of manh calculation ");
291 return ((RT::PrecisionT::BitsT::value + RT::ConservativePrecisionT::BitsT::value) - RT::EdgePrecisionT::BitsT::value);
292 }
293
294 //////////////////////////////////////////////////////////////////////////
295 /// @struct adjustEdgeConservative
296 /// @brief Primary template definition used for partially specializing
297 /// the adjustEdgeConservative function. This struct should never
298 /// be instantiated.
299 /// @tparam RT: rasterizer traits
300 /// @tparam ConservativeEdgeOffsetT: does the edge need offsetting?
301 template <typename RT, typename ConservativeEdgeOffsetT>
302 struct adjustEdgeConservative
303 {
304 //////////////////////////////////////////////////////////////////////////
305 /// @brief Performs calculations to adjust each edge of a triangle away
306 /// from the pixel center by 1/2 pixel + uncertainty region in both the x and y
307 /// direction.
308 ///
309 /// Uncertainty regions arise from fixed point rounding, which
310 /// can snap a vertex +/- by min fixed point value.
311 /// Adding 1/2 pixel in x/y bumps the edge equation tests out towards the pixel corners.
312 /// This allows the rasterizer to test for coverage only at the pixel center,
313 /// instead of having to test individual pixel corners for conservative coverage
314 INLINE adjustEdgeConservative(const __m128i &vAi, const __m128i &vBi, __m256d &vEdge)
315 {
316 // Assumes CCW winding order. Subtracting from the evaluated edge equation moves the edge away
317 // from the pixel center (in the direction of the edge normal A/B)
318
319 // edge = Ax + Bx + C - (manh/e)
320 // manh = manhattan distance = abs(A) + abs(B)
321 // e = absolute rounding error from snapping from float to fixed point precision
322
323 // 'fixed point' multiply (in double to be avx1 friendly)
324 // need doubles to hold result of a fixed multiply: 16.8 * 16.9 = 32.17, for example
325 __m256d vAai = _mm256_cvtepi32_pd(_mm_abs_epi32(vAi)), vBai = _mm256_cvtepi32_pd(_mm_abs_epi32(vBi));
326 __m256d manh = _mm256_add_pd(_mm256_mul_pd(vAai, _mm256_set1_pd(ConservativeEdgeOffsetT::value)),
327 _mm256_mul_pd(vBai, _mm256_set1_pd(ConservativeEdgeOffsetT::value)));
328
329 static_assert(RT::PrecisionT::BitsT::value + RT::ConservativePrecisionT::BitsT::value >= RT::EdgePrecisionT::BitsT::value,
330 "Inadequate precision of result of manh calculation ");
331
332 // rasterizer incoming edge precision is x.16, so we need to get our edge offset into the same precision
333 // since we're doing fixed math in double format, multiply by multiples of 1/2 instead of a bit shift right
334 manh = _mm256_mul_pd(manh, _mm256_set1_pd(ManhToEdgePrecisionAdjust<RT>() * 0.5));
335
336 // move the edge away from the pixel center by the required conservative precision + 1/2 pixel
337 // this allows the rasterizer to do a single conservative coverage test to see if the primitive
338 // intersects the pixel at all
339 vEdge = _mm256_sub_pd(vEdge, manh);
340 };
341 };
342
343 //////////////////////////////////////////////////////////////////////////
344 /// @brief adjustEdgeConservative specialization where no edge offset is needed
345 template <typename RT>
346 struct adjustEdgeConservative<RT, std::integral_constant<int32_t, 0>>
347 {
348 INLINE adjustEdgeConservative(const __m128i &vAi, const __m128i &vBi, __m256d &vEdge) {};
349 };
350
351 //////////////////////////////////////////////////////////////////////////
352 /// @brief calculates the distance a degenerate BBox needs to be adjusted
353 /// for conservative rast based on compile time trait values
354 template<typename RT>
355 constexpr int64_t ConservativeScissorOffset()
356 {
357 static_assert(RT::ConservativePrecisionT::BitsT::value - RT::PrecisionT::BitsT::value >= 0, "Rasterizer precision > conservative precision");
358 // if we have a degenerate triangle, we need to compensate for adjusting the degenerate BBox when calculating scissor edges
359 typedef std::integral_constant<int32_t, (RT::ValidEdgeMaskT::value == ALL_EDGES_VALID) ? 0 : 1> DegenerateEdgeOffsetT;
360 // 1/2 pixel edge offset + conservative offset - degenerateTriangle
361 return RT::ConservativeEdgeOffsetT::value - (DegenerateEdgeOffsetT::value << (RT::ConservativePrecisionT::BitsT::value - RT::PrecisionT::BitsT::value));
362 }
363
364 //////////////////////////////////////////////////////////////////////////
365 /// @brief Performs calculations to adjust each a vector of evaluated edges out
366 /// from the pixel center by 1/2 pixel + uncertainty region in both the x and y
367 /// direction.
368 template <typename RT>
369 INLINE void adjustScissorEdge(const double a, const double b, __m256d &vEdge)
370 {
371 int64_t aabs = std::abs(static_cast<int64_t>(a)), babs = std::abs(static_cast<int64_t>(b));
372 int64_t manh = ((aabs * ConservativeScissorOffset<RT>()) + (babs * ConservativeScissorOffset<RT>())) >> ManhToEdgePrecisionAdjust<RT>();
373 vEdge = _mm256_sub_pd(vEdge, _mm256_set1_pd(manh));
374 };
375
376 //////////////////////////////////////////////////////////////////////////
377 /// @brief Performs calculations to adjust each a scalar evaluated edge out
378 /// from the pixel center by 1/2 pixel + uncertainty region in both the x and y
379 /// direction.
380 template <typename RT, typename OffsetT>
381 INLINE double adjustScalarEdge(const double a, const double b, const double Edge)
382 {
383 int64_t aabs = std::abs(static_cast<int64_t>(a)), babs = std::abs(static_cast<int64_t>(b));
384 int64_t manh = ((aabs * OffsetT::value) + (babs * OffsetT::value)) >> ManhToEdgePrecisionAdjust<RT>();
385 return (Edge - manh);
386 };
387
388 //////////////////////////////////////////////////////////////////////////
389 /// @brief Perform any needed adjustments to evaluated triangle edges
390 template <typename RT, typename EdgeOffsetT>
391 struct adjustEdgesFix16
392 {
393 INLINE adjustEdgesFix16(const __m128i &vAi, const __m128i &vBi, __m256d &vEdge)
394 {
395 static_assert(std::is_same<typename RT::EdgePrecisionT, FixedPointTraits<Fixed_X_16>>::value,
396 "Edge equation expected to be in x.16 fixed point");
397
398 static_assert(RT::IsConservativeT::value, "Edge offset assumes conservative rasterization is enabled");
399
400 // need to apply any edge offsets before applying the top-left rule
401 adjustEdgeConservative<RT, EdgeOffsetT>(vAi, vBi, vEdge);
402
403 adjustTopLeftRuleIntFix16(vAi, vBi, vEdge);
404 }
405 };
406
407 //////////////////////////////////////////////////////////////////////////
408 /// @brief Perform top left adjustments to evaluated triangle edges
409 template <typename RT>
410 struct adjustEdgesFix16<RT, std::integral_constant<int32_t, 0>>
411 {
412 INLINE adjustEdgesFix16(const __m128i &vAi, const __m128i &vBi, __m256d &vEdge)
413 {
414 adjustTopLeftRuleIntFix16(vAi, vBi, vEdge);
415 }
416 };
417
418 // max(abs(dz/dx), abs(dz,dy)
419 INLINE float ComputeMaxDepthSlope(const SWR_TRIANGLE_DESC* pDesc)
420 {
421 /*
422 // evaluate i,j at (0,0)
423 float i00 = pDesc->I[0] * 0.0f + pDesc->I[1] * 0.0f + pDesc->I[2];
424 float j00 = pDesc->J[0] * 0.0f + pDesc->J[1] * 0.0f + pDesc->J[2];
425
426 // evaluate i,j at (1,0)
427 float i10 = pDesc->I[0] * 1.0f + pDesc->I[1] * 0.0f + pDesc->I[2];
428 float j10 = pDesc->J[0] * 1.0f + pDesc->J[1] * 0.0f + pDesc->J[2];
429
430 // compute dz/dx
431 float d00 = pDesc->Z[0] * i00 + pDesc->Z[1] * j00 + pDesc->Z[2];
432 float d10 = pDesc->Z[0] * i10 + pDesc->Z[1] * j10 + pDesc->Z[2];
433 float dzdx = abs(d10 - d00);
434
435 // evaluate i,j at (0,1)
436 float i01 = pDesc->I[0] * 0.0f + pDesc->I[1] * 1.0f + pDesc->I[2];
437 float j01 = pDesc->J[0] * 0.0f + pDesc->J[1] * 1.0f + pDesc->J[2];
438
439 float d01 = pDesc->Z[0] * i01 + pDesc->Z[1] * j01 + pDesc->Z[2];
440 float dzdy = abs(d01 - d00);
441 */
442
443 // optimized version of above
444 float dzdx = fabsf(pDesc->recipDet * (pDesc->Z[0] * pDesc->I[0] + pDesc->Z[1] * pDesc->J[0]));
445 float dzdy = fabsf(pDesc->recipDet * (pDesc->Z[0] * pDesc->I[1] + pDesc->Z[1] * pDesc->J[1]));
446
447 return std::max(dzdx, dzdy);
448 }
449
450 INLINE float ComputeBiasFactor(const SWR_RASTSTATE* pState, const SWR_TRIANGLE_DESC* pDesc, const float* z)
451 {
452 if (pState->depthFormat == R24_UNORM_X8_TYPELESS)
453 {
454 return (1.0f / (1 << 24));
455 }
456 else if (pState->depthFormat == R16_UNORM)
457 {
458 return (1.0f / (1 << 16));
459 }
460 else
461 {
462 SWR_ASSERT(pState->depthFormat == R32_FLOAT);
463
464 // for f32 depth, factor = 2^(exponent(max(abs(z) - 23)
465 float zMax = std::max(fabsf(z[0]), std::max(fabsf(z[1]), fabsf(z[2])));
466 uint32_t zMaxInt = *(uint32_t*)&zMax;
467 zMaxInt &= 0x7f800000;
468 zMax = *(float*)&zMaxInt;
469
470 return zMax * (1.0f / (1 << 23));
471 }
472 }
473
474 INLINE float ComputeDepthBias(const SWR_RASTSTATE* pState, const SWR_TRIANGLE_DESC* pTri, const float* z)
475 {
476 if (pState->depthBias == 0 && pState->slopeScaledDepthBias == 0)
477 {
478 return 0.0f;
479 }
480
481 float scale = pState->slopeScaledDepthBias;
482 if (scale != 0.0f)
483 {
484 scale *= ComputeMaxDepthSlope(pTri);
485 }
486
487 float bias = pState->depthBias;
488 if (!pState->depthBiasPreAdjusted)
489 {
490 bias *= ComputeBiasFactor(pState, pTri, z);
491 }
492 bias += scale;
493
494 if (pState->depthBiasClamp > 0.0f)
495 {
496 bias = std::min(bias, pState->depthBiasClamp);
497 }
498 else if (pState->depthBiasClamp < 0.0f)
499 {
500 bias = std::max(bias, pState->depthBiasClamp);
501 }
502
503 return bias;
504 }
505
506 // Prevent DCE by writing coverage mask from rasterizer to volatile
507 #if KNOB_ENABLE_TOSS_POINTS
508 __declspec(thread) volatile uint64_t gToss;
509 #endif
510
511 static const uint32_t vertsPerTri = 3, componentsPerAttrib = 4;
512 // try to avoid _chkstk insertions; make this thread local
513 static THREAD OSALIGNLINE(float) perspAttribsTLS[vertsPerTri * KNOB_NUM_ATTRIBUTES * componentsPerAttrib];
514
515 INLINE
516 void ComputeEdgeData(int32_t a, int32_t b, EDGE& edge)
517 {
518 edge.a = a;
519 edge.b = b;
520
521 // compute constant steps to adjacent quads
522 edge.stepQuadX = (double)((int64_t)a * (int64_t)(2 * FIXED_POINT_SCALE));
523 edge.stepQuadY = (double)((int64_t)b * (int64_t)(2 * FIXED_POINT_SCALE));
524
525 // compute constant steps to adjacent raster tiles
526 edge.stepRasterTileX = (double)((int64_t)a * (int64_t)(KNOB_TILE_X_DIM * FIXED_POINT_SCALE));
527 edge.stepRasterTileY = (double)((int64_t)b * (int64_t)(KNOB_TILE_Y_DIM * FIXED_POINT_SCALE));
528
529 // compute quad offsets
530 const __m256d vQuadOffsetsXIntFix8 = _mm256_set_pd(FIXED_POINT_SCALE, 0, FIXED_POINT_SCALE, 0);
531 const __m256d vQuadOffsetsYIntFix8 = _mm256_set_pd(FIXED_POINT_SCALE, FIXED_POINT_SCALE, 0, 0);
532
533 __m256d vQuadStepXFix16 = _mm256_mul_pd(_mm256_set1_pd(edge.a), vQuadOffsetsXIntFix8);
534 __m256d vQuadStepYFix16 = _mm256_mul_pd(_mm256_set1_pd(edge.b), vQuadOffsetsYIntFix8);
535 edge.vQuadOffsets = _mm256_add_pd(vQuadStepXFix16, vQuadStepYFix16);
536
537 // compute raster tile offsets
538 const __m256d vTileOffsetsXIntFix8 = _mm256_set_pd((KNOB_TILE_X_DIM - 1)*FIXED_POINT_SCALE, 0, (KNOB_TILE_X_DIM - 1)*FIXED_POINT_SCALE, 0);
539 const __m256d vTileOffsetsYIntFix8 = _mm256_set_pd((KNOB_TILE_Y_DIM - 1)*FIXED_POINT_SCALE, (KNOB_TILE_Y_DIM - 1)*FIXED_POINT_SCALE, 0, 0);
540
541 __m256d vTileStepXFix16 = _mm256_mul_pd(_mm256_set1_pd(edge.a), vTileOffsetsXIntFix8);
542 __m256d vTileStepYFix16 = _mm256_mul_pd(_mm256_set1_pd(edge.b), vTileOffsetsYIntFix8);
543 edge.vRasterTileOffsets = _mm256_add_pd(vTileStepXFix16, vTileStepYFix16);
544 }
545
546 INLINE
547 void ComputeEdgeData(const POS& p0, const POS& p1, EDGE& edge)
548 {
549 ComputeEdgeData(p0.y - p1.y, p1.x - p0.x, edge);
550 }
551
552 //////////////////////////////////////////////////////////////////////////
553 /// @brief Primary template definition used for partially specializing
554 /// the UpdateEdgeMasks function. Offset evaluated edges from UL pixel
555 /// corner to sample position, and test for coverage
556 /// @tparam sampleCount: multisample count
557 template <typename NumSamplesT>
558 INLINE void UpdateEdgeMasks(const __m256d (&vEdgeTileBbox)[3], const __m256d* vEdgeFix16,
559 int32_t &mask0, int32_t &mask1, int32_t &mask2)
560 {
561 __m256d vSampleBboxTest0, vSampleBboxTest1, vSampleBboxTest2;
562 // evaluate edge equations at the tile multisample bounding box
563 vSampleBboxTest0 = _mm256_add_pd(vEdgeTileBbox[0], vEdgeFix16[0]);
564 vSampleBboxTest1 = _mm256_add_pd(vEdgeTileBbox[1], vEdgeFix16[1]);
565 vSampleBboxTest2 = _mm256_add_pd(vEdgeTileBbox[2], vEdgeFix16[2]);
566 mask0 = _mm256_movemask_pd(vSampleBboxTest0);
567 mask1 = _mm256_movemask_pd(vSampleBboxTest1);
568 mask2 = _mm256_movemask_pd(vSampleBboxTest2);
569 }
570
571 //////////////////////////////////////////////////////////////////////////
572 /// @brief UpdateEdgeMasks<SingleSampleT> specialization, instantiated
573 /// when only rasterizing a single coverage test point
574 template <>
575 INLINE void UpdateEdgeMasks<SingleSampleT>(const __m256d(&)[3], const __m256d* vEdgeFix16,
576 int32_t &mask0, int32_t &mask1, int32_t &mask2)
577 {
578 mask0 = _mm256_movemask_pd(vEdgeFix16[0]);
579 mask1 = _mm256_movemask_pd(vEdgeFix16[1]);
580 mask2 = _mm256_movemask_pd(vEdgeFix16[2]);
581 }
582
583 //////////////////////////////////////////////////////////////////////////
584 /// @struct ComputeScissorEdges
585 /// @brief Primary template definition. Allows the function to be generically
586 /// called. When paired with below specializations, will result in an empty
587 /// inlined function if scissor is not enabled
588 /// @tparam RasterScissorEdgesT: is scissor enabled?
589 /// @tparam IsConservativeT: is conservative rast enabled?
590 /// @tparam RT: rasterizer traits
591 template <typename RasterScissorEdgesT, typename IsConservativeT, typename RT>
592 struct ComputeScissorEdges
593 {
594 INLINE ComputeScissorEdges(const SWR_RECT &triBBox, const SWR_RECT &scissorBBox, const int32_t x, const int32_t y,
595 EDGE (&rastEdges)[RT::NumEdgesT::value], __m256d (&vEdgeFix16)[7]){};
596 };
597
598 //////////////////////////////////////////////////////////////////////////
599 /// @brief ComputeScissorEdges<std::true_type, std::true_type, RT> partial
600 /// specialization. Instantiated when conservative rast and scissor are enabled
601 template <typename RT>
602 struct ComputeScissorEdges<std::true_type, std::true_type, RT>
603 {
604 //////////////////////////////////////////////////////////////////////////
605 /// @brief Intersect tri bbox with scissor, compute scissor edge vectors,
606 /// evaluate edge equations and offset them away from pixel center.
607 INLINE ComputeScissorEdges(const SWR_RECT &triBBox, const SWR_RECT &scissorBBox, const int32_t x, const int32_t y,
608 EDGE (&rastEdges)[RT::NumEdgesT::value], __m256d (&vEdgeFix16)[7])
609 {
610 // if conservative rasterizing, triangle bbox intersected with scissor bbox is used
611 SWR_RECT scissor;
612 scissor.xmin = std::max(triBBox.xmin, scissorBBox.xmin);
613 scissor.xmax = std::min(triBBox.xmax, scissorBBox.xmax);
614 scissor.ymin = std::max(triBBox.ymin, scissorBBox.ymin);
615 scissor.ymax = std::min(triBBox.ymax, scissorBBox.ymax);
616
617 POS topLeft{scissor.xmin, scissor.ymin};
618 POS bottomLeft{scissor.xmin, scissor.ymax};
619 POS topRight{scissor.xmax, scissor.ymin};
620 POS bottomRight{scissor.xmax, scissor.ymax};
621
622 // construct 4 scissor edges in ccw direction
623 ComputeEdgeData(topLeft, bottomLeft, rastEdges[3]);
624 ComputeEdgeData(bottomLeft, bottomRight, rastEdges[4]);
625 ComputeEdgeData(bottomRight, topRight, rastEdges[5]);
626 ComputeEdgeData(topRight, topLeft, rastEdges[6]);
627
628 vEdgeFix16[3] = _mm256_set1_pd((rastEdges[3].a * (x - scissor.xmin)) + (rastEdges[3].b * (y - scissor.ymin)));
629 vEdgeFix16[4] = _mm256_set1_pd((rastEdges[4].a * (x - scissor.xmin)) + (rastEdges[4].b * (y - scissor.ymax)));
630 vEdgeFix16[5] = _mm256_set1_pd((rastEdges[5].a * (x - scissor.xmax)) + (rastEdges[5].b * (y - scissor.ymax)));
631 vEdgeFix16[6] = _mm256_set1_pd((rastEdges[6].a * (x - scissor.xmax)) + (rastEdges[6].b * (y - scissor.ymin)));
632
633 // if conservative rasterizing, need to bump the scissor edges out by the conservative uncertainty distance, else do nothing
634 adjustScissorEdge<RT>(rastEdges[3].a, rastEdges[3].b, vEdgeFix16[3]);
635 adjustScissorEdge<RT>(rastEdges[4].a, rastEdges[4].b, vEdgeFix16[4]);
636 adjustScissorEdge<RT>(rastEdges[5].a, rastEdges[5].b, vEdgeFix16[5]);
637 adjustScissorEdge<RT>(rastEdges[6].a, rastEdges[6].b, vEdgeFix16[6]);
638
639 // Upper left rule for scissor
640 vEdgeFix16[3] = _mm256_sub_pd(vEdgeFix16[3], _mm256_set1_pd(1.0));
641 vEdgeFix16[6] = _mm256_sub_pd(vEdgeFix16[6], _mm256_set1_pd(1.0));
642 }
643 };
644
645 //////////////////////////////////////////////////////////////////////////
646 /// @brief ComputeScissorEdges<std::true_type, std::false_type, RT> partial
647 /// specialization. Instantiated when scissor is enabled and conservative rast
648 /// is disabled.
649 template <typename RT>
650 struct ComputeScissorEdges<std::true_type, std::false_type, RT>
651 {
652 //////////////////////////////////////////////////////////////////////////
653 /// @brief Compute scissor edge vectors and evaluate edge equations
654 INLINE ComputeScissorEdges(const SWR_RECT &, const SWR_RECT &scissorBBox, const int32_t x, const int32_t y,
655 EDGE (&rastEdges)[RT::NumEdgesT::value], __m256d (&vEdgeFix16)[7])
656 {
657 const SWR_RECT &scissor = scissorBBox;
658 POS topLeft{scissor.xmin, scissor.ymin};
659 POS bottomLeft{scissor.xmin, scissor.ymax};
660 POS topRight{scissor.xmax, scissor.ymin};
661 POS bottomRight{scissor.xmax, scissor.ymax};
662
663 // construct 4 scissor edges in ccw direction
664 ComputeEdgeData(topLeft, bottomLeft, rastEdges[3]);
665 ComputeEdgeData(bottomLeft, bottomRight, rastEdges[4]);
666 ComputeEdgeData(bottomRight, topRight, rastEdges[5]);
667 ComputeEdgeData(topRight, topLeft, rastEdges[6]);
668
669 vEdgeFix16[3] = _mm256_set1_pd((rastEdges[3].a * (x - scissor.xmin)) + (rastEdges[3].b * (y - scissor.ymin)));
670 vEdgeFix16[4] = _mm256_set1_pd((rastEdges[4].a * (x - scissor.xmin)) + (rastEdges[4].b * (y - scissor.ymax)));
671 vEdgeFix16[5] = _mm256_set1_pd((rastEdges[5].a * (x - scissor.xmax)) + (rastEdges[5].b * (y - scissor.ymax)));
672 vEdgeFix16[6] = _mm256_set1_pd((rastEdges[6].a * (x - scissor.xmax)) + (rastEdges[6].b * (y - scissor.ymin)));
673
674 // Upper left rule for scissor
675 vEdgeFix16[3] = _mm256_sub_pd(vEdgeFix16[3], _mm256_set1_pd(1.0));
676 vEdgeFix16[6] = _mm256_sub_pd(vEdgeFix16[6], _mm256_set1_pd(1.0));
677 }
678 };
679
680 //////////////////////////////////////////////////////////////////////////
681 /// @brief Primary function template for TrivialRejectTest. Should
682 /// never be called, but TemplateUnroller instantiates a few unused values,
683 /// so it calls a runtime assert instead of a static_assert.
684 template <typename ValidEdgeMaskT>
685 INLINE bool TrivialRejectTest(const int, const int, const int)
686 {
687 SWR_ASSERT(0, "Primary templated function should never be called");
688 return false;
689 };
690
691 //////////////////////////////////////////////////////////////////////////
692 /// @brief E0E1ValidT specialization of TrivialRejectTest. Tests edge 0
693 /// and edge 1 for trivial coverage reject
694 template <>
695 INLINE bool TrivialRejectTest<E0E1ValidT>(const int mask0, const int mask1, const int)
696 {
697 return (!(mask0 && mask1)) ? true : false;
698 };
699
700 //////////////////////////////////////////////////////////////////////////
701 /// @brief E0E2ValidT specialization of TrivialRejectTest. Tests edge 0
702 /// and edge 2 for trivial coverage reject
703 template <>
704 INLINE bool TrivialRejectTest<E0E2ValidT>(const int mask0, const int, const int mask2)
705 {
706 return (!(mask0 && mask2)) ? true : false;
707 };
708
709 //////////////////////////////////////////////////////////////////////////
710 /// @brief E1E2ValidT specialization of TrivialRejectTest. Tests edge 1
711 /// and edge 2 for trivial coverage reject
712 template <>
713 INLINE bool TrivialRejectTest<E1E2ValidT>(const int, const int mask1, const int mask2)
714 {
715 return (!(mask1 && mask2)) ? true : false;
716 };
717
718 //////////////////////////////////////////////////////////////////////////
719 /// @brief AllEdgesValidT specialization of TrivialRejectTest. Tests all
720 /// primitive edges for trivial coverage reject
721 template <>
722 INLINE bool TrivialRejectTest<AllEdgesValidT>(const int mask0, const int mask1, const int mask2)
723 {
724 return (!(mask0 && mask1 && mask2)) ? true : false;;
725 };
726
727 //////////////////////////////////////////////////////////////////////////
728 /// @brief NoEdgesValidT specialization of TrivialRejectTest. Degenerate
729 /// point, so return false and rasterize against conservative BBox
730 template <>
731 INLINE bool TrivialRejectTest<NoEdgesValidT>(const int, const int, const int)
732 {
733 return false;
734 };
735
736 //////////////////////////////////////////////////////////////////////////
737 /// @brief Primary function template for TrivialAcceptTest. Always returns
738 /// false, since it will only be called for degenerate tris, and as such
739 /// will never cover the entire raster tile
740 template <typename ScissorEnableT>
741 INLINE bool TrivialAcceptTest(const int, const int, const int)
742 {
743 return false;
744 };
745
746 //////////////////////////////////////////////////////////////////////////
747 /// @brief AllEdgesValidT specialization for TrivialAcceptTest. Test all
748 /// edge masks for a fully covered raster tile
749 template <>
750 INLINE bool TrivialAcceptTest<std::false_type>(const int mask0, const int mask1, const int mask2)
751 {
752 return ((mask0 & mask1 & mask2) == 0xf);
753 };
754
755 //////////////////////////////////////////////////////////////////////////
756 /// @brief Primary function template for GenerateSVInnerCoverage. Results
757 /// in an empty function call if SVInnerCoverage isn't requested
758 template <typename RT, typename ValidEdgeMaskT, typename InputCoverageT>
759 struct GenerateSVInnerCoverage
760 {
761 INLINE GenerateSVInnerCoverage(DRAW_CONTEXT*, EDGE*, double*, uint64_t &){};
762 };
763
764 //////////////////////////////////////////////////////////////////////////
765 /// @brief Specialization of GenerateSVInnerCoverage where all edges
766 /// are non-degenerate and SVInnerCoverage is requested. Offsets the evaluated
767 /// edge values from OuterConservative to InnerConservative and rasterizes.
768 template <typename RT>
769 struct GenerateSVInnerCoverage<RT, AllEdgesValidT, InnerConservativeCoverageT>
770 {
771 INLINE GenerateSVInnerCoverage(DRAW_CONTEXT* pDC, EDGE* pRastEdges, double* pStartQuadEdges, uint64_t &innerCoverageMask)
772 {
773 double startQuadEdgesAdj[RT::NumEdgesT::value];
774 for(uint32_t e = 0; e < RT::NumEdgesT::value; ++e)
775 {
776 startQuadEdgesAdj[e] = adjustScalarEdge<RT, typename RT::InnerConservativeEdgeOffsetT>(pRastEdges[e].a, pRastEdges[e].b, pStartQuadEdges[e]);
777 }
778
779 // not trivial accept or reject, must rasterize full tile
780 RDTSC_START(BERasterizePartial);
781 innerCoverageMask = rasterizePartialTile<RT::NumEdgesT::value, typename RT::ValidEdgeMaskT>(pDC, startQuadEdgesAdj, pRastEdges);
782 RDTSC_STOP(BERasterizePartial, 0, 0);
783 }
784 };
785
786 //////////////////////////////////////////////////////////////////////////
787 /// @brief Primary function template for UpdateEdgeMasksInnerConservative. Results
788 /// in an empty function call if SVInnerCoverage isn't requested
789 template <typename RT, typename ValidEdgeMaskT, typename InputCoverageT>
790 struct UpdateEdgeMasksInnerConservative
791 {
792 INLINE UpdateEdgeMasksInnerConservative(const __m256d (&vEdgeTileBbox)[3], const __m256d*,
793 const __m128i, const __m128i, int32_t &, int32_t &, int32_t &){};
794 };
795
796 //////////////////////////////////////////////////////////////////////////
797 /// @brief Specialization of UpdateEdgeMasksInnerConservative where all edges
798 /// are non-degenerate and SVInnerCoverage is requested. Offsets the edges
799 /// evaluated at raster tile corners to inner conservative position and
800 /// updates edge masks
801 template <typename RT>
802 struct UpdateEdgeMasksInnerConservative<RT, AllEdgesValidT, InnerConservativeCoverageT>
803 {
804 INLINE UpdateEdgeMasksInnerConservative(const __m256d (&vEdgeTileBbox)[3], const __m256d* vEdgeFix16,
805 const __m128i vAi, const __m128i vBi, int32_t &mask0, int32_t &mask1, int32_t &mask2)
806 {
807 __m256d vTempEdge[3]{vEdgeFix16[0], vEdgeFix16[1], vEdgeFix16[2]};
808
809 // instead of keeping 2 copies of evaluated edges around, just compensate for the outer
810 // conservative evaluated edge when adjusting the edge in for inner conservative tests
811 adjustEdgeConservative<RT, typename RT::InnerConservativeEdgeOffsetT>(vAi, vBi, vTempEdge[0]);
812 adjustEdgeConservative<RT, typename RT::InnerConservativeEdgeOffsetT>(vAi, vBi, vTempEdge[1]);
813 adjustEdgeConservative<RT, typename RT::InnerConservativeEdgeOffsetT>(vAi, vBi, vTempEdge[2]);
814
815 UpdateEdgeMasks<typename RT::NumRasterSamplesT>(vEdgeTileBbox, vTempEdge, mask0, mask1, mask2);
816 }
817 };
818
819 //////////////////////////////////////////////////////////////////////////
820 /// @brief Specialization of UpdateEdgeMasksInnerConservative where SVInnerCoverage
821 /// is requested but at least one edge is degenerate. Since a degenerate triangle cannot
822 /// cover an entire raster tile, set mask0 to 0 to force it down the
823 /// rastierizePartialTile path
824 template <typename RT, typename ValidEdgeMaskT>
825 struct UpdateEdgeMasksInnerConservative<RT, ValidEdgeMaskT, InnerConservativeCoverageT>
826 {
827 INLINE UpdateEdgeMasksInnerConservative(const __m256d (&)[3], const __m256d*,
828 const __m128i, const __m128i, int32_t &mask0, int32_t &, int32_t &)
829 {
830 // set one mask to zero to force the triangle down the rastierizePartialTile path
831 mask0 = 0;
832 }
833 };
834
835 template <typename RT>
836 void RasterizeTriangle(DRAW_CONTEXT* pDC, uint32_t workerId, uint32_t macroTile, void* pDesc)
837 {
838 const TRIANGLE_WORK_DESC &workDesc = *((TRIANGLE_WORK_DESC*)pDesc);
839 #if KNOB_ENABLE_TOSS_POINTS
840 if (KNOB_TOSS_BIN_TRIS)
841 {
842 return;
843 }
844 #endif
845 RDTSC_START(BERasterizeTriangle);
846
847 RDTSC_START(BETriangleSetup);
848 const API_STATE &state = GetApiState(pDC);
849 const SWR_RASTSTATE &rastState = state.rastState;
850 const BACKEND_FUNCS& backendFuncs = pDC->pState->backendFuncs;
851
852 OSALIGNSIMD(SWR_TRIANGLE_DESC) triDesc;
853 triDesc.pUserClipBuffer = workDesc.pUserClipBuffer;
854
855 __m128 vX, vY, vZ, vRecipW;
856
857 // pTriBuffer data layout: grouped components of the 3 triangle points and 1 don't care
858 // eg: vX = [x0 x1 x2 dc]
859 vX = _mm_load_ps(workDesc.pTriBuffer);
860 vY = _mm_load_ps(workDesc.pTriBuffer + 4);
861 vZ = _mm_load_ps(workDesc.pTriBuffer + 8);
862 vRecipW = _mm_load_ps(workDesc.pTriBuffer + 12);
863
864 // convert to fixed point
865 static_assert(std::is_same<typename RT::PrecisionT, FixedPointTraits<Fixed_16_8>>::value, "Rasterizer expects 16.8 fixed point precision");
866 __m128i vXi = fpToFixedPoint(vX);
867 __m128i vYi = fpToFixedPoint(vY);
868
869 // quantize floating point position to fixed point precision
870 // to prevent attribute creep around the triangle vertices
871 vX = _mm_mul_ps(_mm_cvtepi32_ps(vXi), _mm_set1_ps(1.0f / FIXED_POINT_SCALE));
872 vY = _mm_mul_ps(_mm_cvtepi32_ps(vYi), _mm_set1_ps(1.0f / FIXED_POINT_SCALE));
873
874 // triangle setup - A and B edge equation coefs
875 __m128 vA, vB;
876 triangleSetupAB(vX, vY, vA, vB);
877
878 __m128i vAi, vBi;
879 triangleSetupABInt(vXi, vYi, vAi, vBi);
880
881 // determinant
882 float det = calcDeterminantInt(vAi, vBi);
883
884 // Verts in Pixel Coordinate Space at this point
885 // Det > 0 = CW winding order
886 // Convert CW triangles to CCW
887 if (det > 0.0)
888 {
889 vA = _mm_mul_ps(vA, _mm_set1_ps(-1));
890 vB = _mm_mul_ps(vB, _mm_set1_ps(-1));
891 vAi = _mm_mullo_epi32(vAi, _mm_set1_epi32(-1));
892 vBi = _mm_mullo_epi32(vBi, _mm_set1_epi32(-1));
893 det = -det;
894 }
895
896 __m128 vC;
897 // Finish triangle setup - C edge coef
898 triangleSetupC(vX, vY, vA, vB, vC);
899
900 if(RT::ValidEdgeMaskT::value != ALL_EDGES_VALID)
901 {
902 // If we have degenerate edge(s) to rasterize, set I and J coefs
903 // to 0 for constant interpolation of attributes
904 triDesc.I[0] = 0.0f;
905 triDesc.I[1] = 0.0f;
906 triDesc.I[2] = 0.0f;
907 triDesc.J[0] = 0.0f;
908 triDesc.J[1] = 0.0f;
909 triDesc.J[2] = 0.0f;
910
911 // Degenerate triangles have no area
912 triDesc.recipDet = 0.0f;
913 }
914 else
915 {
916 // only extract coefs for 2 of the barycentrics; the 3rd can be
917 // determined from the barycentric equation:
918 // i + j + k = 1 <=> k = 1 - j - i
919 _MM_EXTRACT_FLOAT(triDesc.I[0], vA, 1);
920 _MM_EXTRACT_FLOAT(triDesc.I[1], vB, 1);
921 _MM_EXTRACT_FLOAT(triDesc.I[2], vC, 1);
922 _MM_EXTRACT_FLOAT(triDesc.J[0], vA, 2);
923 _MM_EXTRACT_FLOAT(triDesc.J[1], vB, 2);
924 _MM_EXTRACT_FLOAT(triDesc.J[2], vC, 2);
925
926 // compute recipDet, used to calculate barycentric i and j in the backend
927 triDesc.recipDet = 1.0f/det;
928 }
929
930 OSALIGNSIMD(float) oneOverW[4];
931 _mm_store_ps(oneOverW, vRecipW);
932 triDesc.OneOverW[0] = oneOverW[0] - oneOverW[2];
933 triDesc.OneOverW[1] = oneOverW[1] - oneOverW[2];
934 triDesc.OneOverW[2] = oneOverW[2];
935
936 // calculate perspective correct coefs per vertex attrib
937 float* pPerspAttribs = perspAttribsTLS;
938 float* pAttribs = workDesc.pAttribs;
939 triDesc.pPerspAttribs = pPerspAttribs;
940 triDesc.pAttribs = pAttribs;
941 float *pRecipW = workDesc.pTriBuffer + 12;
942 triDesc.pRecipW = pRecipW;
943 __m128 vOneOverWV0 = _mm_broadcast_ss(pRecipW);
944 __m128 vOneOverWV1 = _mm_broadcast_ss(pRecipW+=1);
945 __m128 vOneOverWV2 = _mm_broadcast_ss(pRecipW+=1);
946 for(uint32_t i = 0; i < workDesc.numAttribs; i++)
947 {
948 __m128 attribA = _mm_load_ps(pAttribs);
949 __m128 attribB = _mm_load_ps(pAttribs+=4);
950 __m128 attribC = _mm_load_ps(pAttribs+=4);
951 pAttribs+=4;
952
953 attribA = _mm_mul_ps(attribA, vOneOverWV0);
954 attribB = _mm_mul_ps(attribB, vOneOverWV1);
955 attribC = _mm_mul_ps(attribC, vOneOverWV2);
956
957 _mm_store_ps(pPerspAttribs, attribA);
958 _mm_store_ps(pPerspAttribs+=4, attribB);
959 _mm_store_ps(pPerspAttribs+=4, attribC);
960 pPerspAttribs+=4;
961 }
962
963 // compute bary Z
964 // zInterp = zVert0 + i(zVert1-zVert0) + j (zVert2 - zVert0)
965 OSALIGNSIMD(float) a[4];
966 _mm_store_ps(a, vZ);
967 triDesc.Z[0] = a[0] - a[2];
968 triDesc.Z[1] = a[1] - a[2];
969 triDesc.Z[2] = a[2];
970
971 // add depth bias
972 triDesc.Z[2] += ComputeDepthBias(&rastState, &triDesc, workDesc.pTriBuffer + 8);
973
974 // Calc bounding box of triangle
975 OSALIGNSIMD(SWR_RECT) bbox;
976 calcBoundingBoxInt(vXi, vYi, bbox);
977
978 const SWR_RECT &scissorInFixedPoint = state.scissorsInFixedPoint[workDesc.triFlags.viewportIndex];
979
980 if(RT::ValidEdgeMaskT::value != ALL_EDGES_VALID)
981 {
982 // If we're rasterizing a degenerate triangle, expand bounding box to guarantee the BBox is valid
983 bbox.xmin--; bbox.xmax++; bbox.ymin--; bbox.ymax++;
984 SWR_ASSERT(scissorInFixedPoint.xmin >= 0 && scissorInFixedPoint.ymin >= 0,
985 "Conservative rast degenerate handling requires a valid scissor rect");
986 }
987
988 // Intersect with scissor/viewport
989 OSALIGNSIMD(SWR_RECT) intersect;
990 intersect.xmin = std::max(bbox.xmin, scissorInFixedPoint.xmin);
991 intersect.xmax = std::min(bbox.xmax - 1, scissorInFixedPoint.xmax);
992 intersect.ymin = std::max(bbox.ymin, scissorInFixedPoint.ymin);
993 intersect.ymax = std::min(bbox.ymax - 1, scissorInFixedPoint.ymax);
994
995 triDesc.triFlags = workDesc.triFlags;
996
997 // further constrain backend to intersecting bounding box of macro tile and scissored triangle bbox
998 uint32_t macroX, macroY;
999 MacroTileMgr::getTileIndices(macroTile, macroX, macroY);
1000 int32_t macroBoxLeft = macroX * KNOB_MACROTILE_X_DIM_FIXED;
1001 int32_t macroBoxRight = macroBoxLeft + KNOB_MACROTILE_X_DIM_FIXED - 1;
1002 int32_t macroBoxTop = macroY * KNOB_MACROTILE_Y_DIM_FIXED;
1003 int32_t macroBoxBottom = macroBoxTop + KNOB_MACROTILE_Y_DIM_FIXED - 1;
1004
1005 intersect.xmin = std::max(intersect.xmin, macroBoxLeft);
1006 intersect.ymin = std::max(intersect.ymin, macroBoxTop);
1007 intersect.xmax = std::min(intersect.xmax, macroBoxRight);
1008 intersect.ymax = std::min(intersect.ymax, macroBoxBottom);
1009
1010 SWR_ASSERT(intersect.xmin <= intersect.xmax && intersect.ymin <= intersect.ymax && intersect.xmin >= 0 && intersect.xmax >= 0 && intersect.ymin >= 0 && intersect.ymax >= 0);
1011
1012 RDTSC_STOP(BETriangleSetup, 0, pDC->drawId);
1013
1014 // update triangle desc
1015 uint32_t minTileX = intersect.xmin >> (KNOB_TILE_X_DIM_SHIFT + FIXED_POINT_SHIFT);
1016 uint32_t minTileY = intersect.ymin >> (KNOB_TILE_Y_DIM_SHIFT + FIXED_POINT_SHIFT);
1017 uint32_t maxTileX = intersect.xmax >> (KNOB_TILE_X_DIM_SHIFT + FIXED_POINT_SHIFT);
1018 uint32_t maxTileY = intersect.ymax >> (KNOB_TILE_Y_DIM_SHIFT + FIXED_POINT_SHIFT);
1019 uint32_t numTilesX = maxTileX - minTileX + 1;
1020 uint32_t numTilesY = maxTileY - minTileY + 1;
1021
1022 if (numTilesX == 0 || numTilesY == 0)
1023 {
1024 RDTSC_EVENT(BEEmptyTriangle, 1, 0);
1025 RDTSC_STOP(BERasterizeTriangle, 1, 0);
1026 return;
1027 }
1028
1029 RDTSC_START(BEStepSetup);
1030
1031 // Step to pixel center of top-left pixel of the triangle bbox
1032 // Align intersect bbox (top/left) to raster tile's (top/left).
1033 int32_t x = AlignDown(intersect.xmin, (FIXED_POINT_SCALE * KNOB_TILE_X_DIM));
1034 int32_t y = AlignDown(intersect.ymin, (FIXED_POINT_SCALE * KNOB_TILE_Y_DIM));
1035
1036 // convenience typedef
1037 typedef typename RT::NumRasterSamplesT NumRasterSamplesT;
1038
1039 // single sample rasterization evaluates edges at pixel center,
1040 // multisample evaluates edges UL pixel corner and steps to each sample position
1041 if(std::is_same<NumRasterSamplesT, SingleSampleT>::value)
1042 {
1043 // Add 0.5, in fixed point, to offset to pixel center
1044 x += (FIXED_POINT_SCALE / 2);
1045 y += (FIXED_POINT_SCALE / 2);
1046 }
1047
1048 __m128i vTopLeftX = _mm_set1_epi32(x);
1049 __m128i vTopLeftY = _mm_set1_epi32(y);
1050
1051 // evaluate edge equations at top-left pixel using 64bit math
1052 //
1053 // line = Ax + By + C
1054 // solving for C:
1055 // C = -Ax - By
1056 // we know x0 and y0 are on the line; plug them in:
1057 // C = -Ax0 - By0
1058 // plug C back into line equation:
1059 // line = Ax - By - Ax0 - By0
1060 // line = A(x - x0) + B(y - y0)
1061 // dX = (x-x0), dY = (y-y0)
1062 // so all this simplifies to
1063 // edge = A(dX) + B(dY), our first test at the top left of the bbox we're rasterizing within
1064
1065 __m128i vDeltaX = _mm_sub_epi32(vTopLeftX, vXi);
1066 __m128i vDeltaY = _mm_sub_epi32(vTopLeftY, vYi);
1067
1068 // evaluate A(dx) and B(dY) for all points
1069 __m256d vAipd = _mm256_cvtepi32_pd(vAi);
1070 __m256d vBipd = _mm256_cvtepi32_pd(vBi);
1071 __m256d vDeltaXpd = _mm256_cvtepi32_pd(vDeltaX);
1072 __m256d vDeltaYpd = _mm256_cvtepi32_pd(vDeltaY);
1073
1074 __m256d vAiDeltaXFix16 = _mm256_mul_pd(vAipd, vDeltaXpd);
1075 __m256d vBiDeltaYFix16 = _mm256_mul_pd(vBipd, vDeltaYpd);
1076 __m256d vEdge = _mm256_add_pd(vAiDeltaXFix16, vBiDeltaYFix16);
1077
1078 // apply any edge adjustments(top-left, crast, etc)
1079 adjustEdgesFix16<RT, typename RT::ConservativeEdgeOffsetT>(vAi, vBi, vEdge);
1080
1081 // broadcast respective edge results to all lanes
1082 double* pEdge = (double*)&vEdge;
1083 __m256d vEdgeFix16[7];
1084 vEdgeFix16[0] = _mm256_set1_pd(pEdge[0]);
1085 vEdgeFix16[1] = _mm256_set1_pd(pEdge[1]);
1086 vEdgeFix16[2] = _mm256_set1_pd(pEdge[2]);
1087
1088 OSALIGNSIMD(int32_t) aAi[4], aBi[4];
1089 _mm_store_si128((__m128i*)aAi, vAi);
1090 _mm_store_si128((__m128i*)aBi, vBi);
1091 EDGE rastEdges[RT::NumEdgesT::value];
1092
1093 // Compute and store triangle edge data
1094 ComputeEdgeData(aAi[0], aBi[0], rastEdges[0]);
1095 ComputeEdgeData(aAi[1], aBi[1], rastEdges[1]);
1096 ComputeEdgeData(aAi[2], aBi[2], rastEdges[2]);
1097
1098 // Compute and store triangle edge data if scissor needs to rasterized
1099 ComputeScissorEdges<typename RT::RasterizeScissorEdgesT, typename RT::IsConservativeT, RT>
1100 (bbox, scissorInFixedPoint, x, y, rastEdges, vEdgeFix16);
1101
1102 // Evaluate edge equations at sample positions of each of the 4 corners of a raster tile
1103 // used to for testing if entire raster tile is inside a triangle
1104 for (uint32_t e = 0; e < RT::NumEdgesT::value; ++e)
1105 {
1106 vEdgeFix16[e] = _mm256_add_pd(vEdgeFix16[e], rastEdges[e].vRasterTileOffsets);
1107 }
1108
1109 // at this point vEdge has been evaluated at the UL pixel corners of raster tile bbox
1110 // step sample positions to the raster tile bbox of multisample points
1111 // min(xSamples),min(ySamples) ------ max(xSamples),min(ySamples)
1112 // | |
1113 // | |
1114 // min(xSamples),max(ySamples) ------ max(xSamples),max(ySamples)
1115 __m256d vEdgeTileBbox[3];
1116 if (NumRasterSamplesT::value > 1)
1117 {
1118 __m128i vTileSampleBBoxXh = RT::MT::TileSampleOffsetsX();
1119 __m128i vTileSampleBBoxYh = RT::MT::TileSampleOffsetsY();
1120
1121 __m256d vTileSampleBBoxXFix8 = _mm256_cvtepi32_pd(vTileSampleBBoxXh);
1122 __m256d vTileSampleBBoxYFix8 = _mm256_cvtepi32_pd(vTileSampleBBoxYh);
1123
1124 // step edge equation tests from Tile
1125 // used to for testing if entire raster tile is inside a triangle
1126 for (uint32_t e = 0; e < 3; ++e)
1127 {
1128 __m256d vResultAxFix16 = _mm256_mul_pd(_mm256_set1_pd(rastEdges[e].a), vTileSampleBBoxXFix8);
1129 __m256d vResultByFix16 = _mm256_mul_pd(_mm256_set1_pd(rastEdges[e].b), vTileSampleBBoxYFix8);
1130 vEdgeTileBbox[e] = _mm256_add_pd(vResultAxFix16, vResultByFix16);
1131
1132 // adjust for msaa tile bbox edges outward for conservative rast, if enabled
1133 adjustEdgeConservative<RT, typename RT::ConservativeEdgeOffsetT>(vAi, vBi, vEdgeTileBbox[e]);
1134 }
1135 }
1136
1137 RDTSC_STOP(BEStepSetup, 0, pDC->drawId);
1138
1139 uint32_t tY = minTileY;
1140 uint32_t tX = minTileX;
1141 uint32_t maxY = maxTileY;
1142 uint32_t maxX = maxTileX;
1143
1144 RenderOutputBuffers renderBuffers, currentRenderBufferRow;
1145 GetRenderHotTiles<RT::MT::numSamples>(pDC, macroTile, minTileX, minTileY, renderBuffers, triDesc.triFlags.renderTargetArrayIndex);
1146 currentRenderBufferRow = renderBuffers;
1147
1148 // rasterize and generate coverage masks per sample
1149 for (uint32_t tileY = tY; tileY <= maxY; ++tileY)
1150 {
1151 __m256d vStartOfRowEdge[RT::NumEdgesT::value];
1152 for (uint32_t e = 0; e < RT::NumEdgesT::value; ++e)
1153 {
1154 vStartOfRowEdge[e] = vEdgeFix16[e];
1155 }
1156
1157 for (uint32_t tileX = tX; tileX <= maxX; ++tileX)
1158 {
1159 triDesc.anyCoveredSamples = 0;
1160
1161 // is the corner of the edge outside of the raster tile? (vEdge < 0)
1162 int mask0, mask1, mask2;
1163 UpdateEdgeMasks<NumRasterSamplesT>(vEdgeTileBbox, vEdgeFix16, mask0, mask1, mask2);
1164
1165 for (uint32_t sampleNum = 0; sampleNum < NumRasterSamplesT::value; sampleNum++)
1166 {
1167 // trivial reject, at least one edge has all 4 corners of raster tile outside
1168 bool trivialReject = TrivialRejectTest<typename RT::ValidEdgeMaskT>(mask0, mask1, mask2);
1169
1170 if (!trivialReject)
1171 {
1172 // trivial accept mask
1173 triDesc.coverageMask[sampleNum] = 0xffffffffffffffffULL;
1174
1175 // Update the raster tile edge masks based on inner conservative edge offsets, if enabled
1176 UpdateEdgeMasksInnerConservative<RT, typename RT::ValidEdgeMaskT, typename RT::InputCoverageT>
1177 (vEdgeTileBbox, vEdgeFix16, vAi, vBi, mask0, mask1, mask2);
1178
1179 // @todo Make this a bit smarter to allow use of trivial accept when:
1180 // 1) scissor/vp intersection rect is raster tile aligned
1181 // 2) raster tile is entirely within scissor/vp intersection rect
1182 if (TrivialAcceptTest<typename RT::RasterizeScissorEdgesT>(mask0, mask1, mask2))
1183 {
1184 // trivial accept, all 4 corners of all 3 edges are negative
1185 // i.e. raster tile completely inside triangle
1186 triDesc.anyCoveredSamples = triDesc.coverageMask[sampleNum];
1187 if(std::is_same<typename RT::InputCoverageT, InnerConservativeCoverageT>::value)
1188 {
1189 triDesc.innerCoverageMask = 0xffffffffffffffffULL;
1190 }
1191 RDTSC_EVENT(BETrivialAccept, 1, 0);
1192 }
1193 else
1194 {
1195 __m256d vEdgeAtSample[RT::NumEdgesT::value];
1196 if(std::is_same<NumRasterSamplesT, SingleSampleT>::value)
1197 {
1198 // should get optimized out for single sample case (global value numbering or copy propagation)
1199 for (uint32_t e = 0; e < RT::NumEdgesT::value; ++e)
1200 {
1201 vEdgeAtSample[e] = vEdgeFix16[e];
1202 }
1203 }
1204 else
1205 {
1206 __m128i vSampleOffsetXh = RT::MT::vXi(sampleNum);
1207 __m128i vSampleOffsetYh = RT::MT::vYi(sampleNum);
1208 __m256d vSampleOffsetX = _mm256_cvtepi32_pd(vSampleOffsetXh);
1209 __m256d vSampleOffsetY = _mm256_cvtepi32_pd(vSampleOffsetYh);
1210
1211 // step edge equation tests from UL tile corner to pixel sample position
1212 for (uint32_t e = 0; e < RT::NumEdgesT::value; ++e)
1213 {
1214 __m256d vResultAxFix16 = _mm256_mul_pd(_mm256_set1_pd(rastEdges[e].a), vSampleOffsetX);
1215 __m256d vResultByFix16 = _mm256_mul_pd(_mm256_set1_pd(rastEdges[e].b), vSampleOffsetY);
1216 vEdgeAtSample[e] = _mm256_add_pd(vResultAxFix16, vResultByFix16);
1217 vEdgeAtSample[e] = _mm256_add_pd(vEdgeFix16[e], vEdgeAtSample[e]);
1218 }
1219 }
1220
1221 double startQuadEdges[RT::NumEdgesT::value];
1222 const __m256i vLane0Mask = _mm256_set_epi32(0, 0, 0, 0, 0, 0, -1, -1);
1223 for (uint32_t e = 0; e < RT::NumEdgesT::value; ++e)
1224 {
1225 _mm256_maskstore_pd(&startQuadEdges[e], vLane0Mask, vEdgeAtSample[e]);
1226 }
1227
1228 // not trivial accept or reject, must rasterize full tile
1229 RDTSC_START(BERasterizePartial);
1230 triDesc.coverageMask[sampleNum] = rasterizePartialTile<RT::NumEdgesT::value, typename RT::ValidEdgeMaskT>(pDC, startQuadEdges, rastEdges);
1231 RDTSC_STOP(BERasterizePartial, 0, 0);
1232
1233 triDesc.anyCoveredSamples |= triDesc.coverageMask[sampleNum];
1234
1235 // Output SV InnerCoverage, if needed
1236 GenerateSVInnerCoverage<RT, typename RT::ValidEdgeMaskT, typename RT::InputCoverageT>(pDC, rastEdges, startQuadEdges, triDesc.innerCoverageMask);
1237 }
1238 }
1239 else
1240 {
1241 // if we're calculating coverage per sample, need to store it off. otherwise no covered samples, don't need to do anything
1242 if(NumRasterSamplesT::value > 1)
1243 {
1244 triDesc.coverageMask[sampleNum] = 0;
1245 }
1246 RDTSC_EVENT(BETrivialReject, 1, 0);
1247 }
1248 }
1249
1250 #if KNOB_ENABLE_TOSS_POINTS
1251 if(KNOB_TOSS_RS)
1252 {
1253 gToss = triDesc.coverageMask[0];
1254 }
1255 else
1256 #endif
1257 if(triDesc.anyCoveredSamples)
1258 {
1259 // if conservative rast and MSAA are enabled, conservative coverage for a pixel means all samples in that pixel are covered
1260 // copy conservative coverage result to all samples
1261 if(RT::IsConservativeT::value)
1262 {
1263 auto copyCoverage = [&](int sample){triDesc.coverageMask[sample] = triDesc.coverageMask[0]; };
1264 UnrollerL<1, RT::MT::numSamples, 1>::step(copyCoverage);
1265 }
1266
1267 RDTSC_START(BEPixelBackend);
1268 backendFuncs.pfnBackend(pDC, workerId, tileX << KNOB_TILE_X_DIM_SHIFT, tileY << KNOB_TILE_Y_DIM_SHIFT, triDesc, renderBuffers);
1269 RDTSC_STOP(BEPixelBackend, 0, 0);
1270 }
1271
1272 // step to the next tile in X
1273 for (uint32_t e = 0; e < RT::NumEdgesT::value; ++e)
1274 {
1275 vEdgeFix16[e] = _mm256_add_pd(vEdgeFix16[e], _mm256_set1_pd(rastEdges[e].stepRasterTileX));
1276 }
1277 StepRasterTileX<RT>(state.psState.numRenderTargets, renderBuffers);
1278 }
1279
1280 // step to the next tile in Y
1281 for (uint32_t e = 0; e < RT::NumEdgesT::value; ++e)
1282 {
1283 vEdgeFix16[e] = _mm256_add_pd(vStartOfRowEdge[e], _mm256_set1_pd(rastEdges[e].stepRasterTileY));
1284 }
1285 StepRasterTileY<RT>(state.psState.numRenderTargets, renderBuffers, currentRenderBufferRow);
1286 }
1287
1288 RDTSC_STOP(BERasterizeTriangle, 1, 0);
1289 }
1290
1291 void RasterizeTriPoint(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t macroTile, void* pData)
1292 {
1293 const TRIANGLE_WORK_DESC& workDesc = *(const TRIANGLE_WORK_DESC*)pData;
1294 const SWR_RASTSTATE& rastState = pDC->pState->state.rastState;
1295 const SWR_BACKEND_STATE& backendState = pDC->pState->state.backendState;
1296
1297 bool isPointSpriteTexCoordEnabled = backendState.pointSpriteTexCoordMask != 0;
1298
1299 // load point vertex
1300 float x = *workDesc.pTriBuffer;
1301 float y = *(workDesc.pTriBuffer + 1);
1302 float z = *(workDesc.pTriBuffer + 2);
1303
1304 // create a copy of the triangle buffer to write our adjusted vertices to
1305 OSALIGNSIMD(float) newTriBuffer[4 * 4];
1306 TRIANGLE_WORK_DESC newWorkDesc = workDesc;
1307 newWorkDesc.pTriBuffer = &newTriBuffer[0];
1308
1309 // create a copy of the attrib buffer to write our adjusted attribs to
1310 OSALIGNSIMD(float) newAttribBuffer[4 * 3 * KNOB_NUM_ATTRIBUTES];
1311 newWorkDesc.pAttribs = &newAttribBuffer[0];
1312
1313 newWorkDesc.pUserClipBuffer = workDesc.pUserClipBuffer;
1314 newWorkDesc.numAttribs = workDesc.numAttribs;
1315 newWorkDesc.triFlags = workDesc.triFlags;
1316
1317 // construct two tris by bloating point by point size
1318 float halfPointSize = workDesc.triFlags.pointSize * 0.5f;
1319 float lowerX = x - halfPointSize;
1320 float upperX = x + halfPointSize;
1321 float lowerY = y - halfPointSize;
1322 float upperY = y + halfPointSize;
1323
1324 // tri 0
1325 float *pBuf = &newTriBuffer[0];
1326 *pBuf++ = lowerX;
1327 *pBuf++ = lowerX;
1328 *pBuf++ = upperX;
1329 pBuf++;
1330 *pBuf++ = lowerY;
1331 *pBuf++ = upperY;
1332 *pBuf++ = upperY;
1333 pBuf++;
1334 _mm_store_ps(pBuf, _mm_set1_ps(z));
1335 _mm_store_ps(pBuf+=4, _mm_set1_ps(1.0f));
1336
1337 // setup triangle rasterizer function
1338 PFN_WORK_FUNC pfnTriRast;
1339 // for center sample pattern, all samples are at pixel center; calculate coverage
1340 // once at center and broadcast the results in the backend
1341 uint32_t sampleCount = (rastState.samplePattern == SWR_MSAA_STANDARD_PATTERN) ? rastState.sampleCount : SWR_MULTISAMPLE_1X;
1342 // conservative rast not supported for points/lines
1343 pfnTriRast = GetRasterizerFunc(sampleCount, false, SWR_INPUT_COVERAGE_NONE, ALL_EDGES_VALID, (rastState.scissorEnable > 0) || (pDC->pState->state.scissorsTileAligned == false));
1344
1345 // overwrite texcoords for point sprites
1346 if (isPointSpriteTexCoordEnabled)
1347 {
1348 // copy original attribs
1349 memcpy(&newAttribBuffer[0], workDesc.pAttribs, 4 * 3 * workDesc.numAttribs * sizeof(float));
1350 newWorkDesc.pAttribs = &newAttribBuffer[0];
1351
1352 // overwrite texcoord for point sprites
1353 uint32_t texCoordMask = backendState.pointSpriteTexCoordMask;
1354 DWORD texCoordAttrib = 0;
1355
1356 while (_BitScanForward(&texCoordAttrib, texCoordMask))
1357 {
1358 texCoordMask &= ~(1 << texCoordAttrib);
1359 __m128* pTexAttrib = (__m128*)&newAttribBuffer[0] + 3 * texCoordAttrib;
1360 if (rastState.pointSpriteTopOrigin)
1361 {
1362 pTexAttrib[0] = _mm_set_ps(1, 0, 0, 0);
1363 pTexAttrib[1] = _mm_set_ps(1, 0, 1, 0);
1364 pTexAttrib[2] = _mm_set_ps(1, 0, 1, 1);
1365 }
1366 else
1367 {
1368 pTexAttrib[0] = _mm_set_ps(1, 0, 1, 0);
1369 pTexAttrib[1] = _mm_set_ps(1, 0, 0, 0);
1370 pTexAttrib[2] = _mm_set_ps(1, 0, 0, 1);
1371 }
1372 }
1373 }
1374 else
1375 {
1376 // no texcoord overwrite, can reuse the attrib buffer from frontend
1377 newWorkDesc.pAttribs = workDesc.pAttribs;
1378 }
1379
1380 pfnTriRast(pDC, workerId, macroTile, (void*)&newWorkDesc);
1381
1382 // tri 1
1383 pBuf = &newTriBuffer[0];
1384 *pBuf++ = lowerX;
1385 *pBuf++ = upperX;
1386 *pBuf++ = upperX;
1387 pBuf++;
1388 *pBuf++ = lowerY;
1389 *pBuf++ = upperY;
1390 *pBuf++ = lowerY;
1391 // z, w unchanged
1392
1393 if (isPointSpriteTexCoordEnabled)
1394 {
1395 uint32_t texCoordMask = backendState.pointSpriteTexCoordMask;
1396 DWORD texCoordAttrib = 0;
1397
1398 while (_BitScanForward(&texCoordAttrib, texCoordMask))
1399 {
1400 texCoordMask &= ~(1 << texCoordAttrib);
1401 __m128* pTexAttrib = (__m128*)&newAttribBuffer[0] + 3 * texCoordAttrib;
1402 if (rastState.pointSpriteTopOrigin)
1403 {
1404 pTexAttrib[0] = _mm_set_ps(1, 0, 0, 0);
1405 pTexAttrib[1] = _mm_set_ps(1, 0, 1, 1);
1406 pTexAttrib[2] = _mm_set_ps(1, 0, 0, 1);
1407
1408 }
1409 else
1410 {
1411 pTexAttrib[0] = _mm_set_ps(1, 0, 1, 0);
1412 pTexAttrib[1] = _mm_set_ps(1, 0, 0, 1);
1413 pTexAttrib[2] = _mm_set_ps(1, 0, 1, 1);
1414 }
1415 }
1416 }
1417
1418 pfnTriRast(pDC, workerId, macroTile, (void*)&newWorkDesc);
1419 }
1420
1421 void RasterizeSimplePoint(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t macroTile, void* pData)
1422 {
1423 #if KNOB_ENABLE_TOSS_POINTS
1424 if (KNOB_TOSS_BIN_TRIS)
1425 {
1426 return;
1427 }
1428 #endif
1429
1430 const TRIANGLE_WORK_DESC& workDesc = *(const TRIANGLE_WORK_DESC*)pData;
1431 const BACKEND_FUNCS& backendFuncs = pDC->pState->backendFuncs;
1432
1433 // map x,y relative offsets from start of raster tile to bit position in
1434 // coverage mask for the point
1435 static const uint32_t coverageMap[8][8] = {
1436 { 0, 1, 4, 5, 8, 9, 12, 13 },
1437 { 2, 3, 6, 7, 10, 11, 14, 15 },
1438 { 16, 17, 20, 21, 24, 25, 28, 29 },
1439 { 18, 19, 22, 23, 26, 27, 30, 31 },
1440 { 32, 33, 36, 37, 40, 41, 44, 45 },
1441 { 34, 35, 38, 39, 42, 43, 46, 47 },
1442 { 48, 49, 52, 53, 56, 57, 60, 61 },
1443 { 50, 51, 54, 55, 58, 59, 62, 63 }
1444 };
1445
1446 OSALIGNSIMD(SWR_TRIANGLE_DESC) triDesc;
1447
1448 // pull point information from triangle buffer
1449 // @todo use structs for readability
1450 uint32_t tileAlignedX = *(uint32_t*)workDesc.pTriBuffer;
1451 uint32_t tileAlignedY = *(uint32_t*)(workDesc.pTriBuffer + 1);
1452 float z = *(workDesc.pTriBuffer + 2);
1453
1454 // construct triangle descriptor for point
1455 // no interpolation, set up i,j for constant interpolation of z and attribs
1456 // @todo implement an optimized backend that doesn't require triangle information
1457
1458 // compute coverage mask from x,y packed into the coverageMask flag
1459 // mask indices by the maximum valid index for x/y of coveragemap.
1460 uint32_t tX = workDesc.triFlags.coverageMask & 0x7;
1461 uint32_t tY = (workDesc.triFlags.coverageMask >> 4) & 0x7;
1462 // todo: multisample points?
1463 triDesc.coverageMask[0] = 1ULL << coverageMap[tY][tX];
1464
1465 // no persp divide needed for points
1466 triDesc.pAttribs = triDesc.pPerspAttribs = workDesc.pAttribs;
1467 triDesc.triFlags = workDesc.triFlags;
1468 triDesc.recipDet = 1.0f;
1469 triDesc.OneOverW[0] = triDesc.OneOverW[1] = triDesc.OneOverW[2] = 1.0f;
1470 triDesc.I[0] = triDesc.I[1] = triDesc.I[2] = 0.0f;
1471 triDesc.J[0] = triDesc.J[1] = triDesc.J[2] = 0.0f;
1472 triDesc.Z[0] = triDesc.Z[1] = triDesc.Z[2] = z;
1473
1474 RenderOutputBuffers renderBuffers;
1475 GetRenderHotTiles(pDC, macroTile, tileAlignedX >> KNOB_TILE_X_DIM_SHIFT , tileAlignedY >> KNOB_TILE_Y_DIM_SHIFT,
1476 renderBuffers, triDesc.triFlags.renderTargetArrayIndex);
1477
1478 RDTSC_START(BEPixelBackend);
1479 backendFuncs.pfnBackend(pDC, workerId, tileAlignedX, tileAlignedY, triDesc, renderBuffers);
1480 RDTSC_STOP(BEPixelBackend, 0, 0);
1481 }
1482
1483 // Get pointers to hot tile memory for color RT, depth, stencil
1484 template <uint32_t numSamples>
1485 void GetRenderHotTiles(DRAW_CONTEXT *pDC, uint32_t macroID, uint32_t tileX, uint32_t tileY, RenderOutputBuffers &renderBuffers, uint32_t renderTargetArrayIndex)
1486 {
1487 const API_STATE& state = GetApiState(pDC);
1488 SWR_CONTEXT *pContext = pDC->pContext;
1489
1490 uint32_t mx, my;
1491 MacroTileMgr::getTileIndices(macroID, mx, my);
1492 tileX -= KNOB_MACROTILE_X_DIM_IN_TILES * mx;
1493 tileY -= KNOB_MACROTILE_Y_DIM_IN_TILES * my;
1494
1495 // compute tile offset for active hottile buffers
1496 const uint32_t pitch = KNOB_MACROTILE_X_DIM * FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp / 8;
1497 uint32_t offset = ComputeTileOffset2D<TilingTraits<SWR_TILE_SWRZ, FormatTraits<KNOB_COLOR_HOT_TILE_FORMAT>::bpp> >(pitch, tileX, tileY);
1498 offset*=numSamples;
1499
1500 unsigned long rtSlot = 0;
1501 uint32_t colorHottileEnableMask = state.colorHottileEnable;
1502 while(_BitScanForward(&rtSlot, colorHottileEnableMask))
1503 {
1504 HOTTILE *pColor = pContext->pHotTileMgr->GetHotTile(pContext, pDC, macroID, (SWR_RENDERTARGET_ATTACHMENT)(SWR_ATTACHMENT_COLOR0 + rtSlot), true,
1505 numSamples, renderTargetArrayIndex);
1506 pColor->state = HOTTILE_DIRTY;
1507 renderBuffers.pColor[rtSlot] = pColor->pBuffer + offset;
1508
1509 colorHottileEnableMask &= ~(1 << rtSlot);
1510 }
1511 if(state.depthHottileEnable)
1512 {
1513 const uint32_t pitch = KNOB_MACROTILE_X_DIM * FormatTraits<KNOB_DEPTH_HOT_TILE_FORMAT>::bpp / 8;
1514 uint32_t offset = ComputeTileOffset2D<TilingTraits<SWR_TILE_SWRZ, FormatTraits<KNOB_DEPTH_HOT_TILE_FORMAT>::bpp> >(pitch, tileX, tileY);
1515 offset*=numSamples;
1516 HOTTILE *pDepth = pContext->pHotTileMgr->GetHotTile(pContext, pDC, macroID, SWR_ATTACHMENT_DEPTH, true,
1517 numSamples, renderTargetArrayIndex);
1518 pDepth->state = HOTTILE_DIRTY;
1519 SWR_ASSERT(pDepth->pBuffer != nullptr);
1520 renderBuffers.pDepth = pDepth->pBuffer + offset;
1521 }
1522 if(state.stencilHottileEnable)
1523 {
1524 const uint32_t pitch = KNOB_MACROTILE_X_DIM * FormatTraits<KNOB_STENCIL_HOT_TILE_FORMAT>::bpp / 8;
1525 uint32_t offset = ComputeTileOffset2D<TilingTraits<SWR_TILE_SWRZ, FormatTraits<KNOB_STENCIL_HOT_TILE_FORMAT>::bpp> >(pitch, tileX, tileY);
1526 offset*=numSamples;
1527 HOTTILE* pStencil = pContext->pHotTileMgr->GetHotTile(pContext, pDC, macroID, SWR_ATTACHMENT_STENCIL, true,
1528 numSamples, renderTargetArrayIndex);
1529 pStencil->state = HOTTILE_DIRTY;
1530 SWR_ASSERT(pStencil->pBuffer != nullptr);
1531 renderBuffers.pStencil = pStencil->pBuffer + offset;
1532 }
1533 }
1534
1535 template <typename RT>
1536 INLINE void StepRasterTileX(uint32_t NumRT, RenderOutputBuffers &buffers)
1537 {
1538 for(uint32_t rt = 0; rt < NumRT; ++rt)
1539 {
1540 buffers.pColor[rt] += RT::colorRasterTileStep;
1541 }
1542
1543 buffers.pDepth += RT::depthRasterTileStep;
1544 buffers.pStencil += RT::stencilRasterTileStep;
1545 }
1546
1547 template <typename RT>
1548 INLINE void StepRasterTileY(uint32_t NumRT, RenderOutputBuffers &buffers, RenderOutputBuffers &startBufferRow)
1549 {
1550 for(uint32_t rt = 0; rt < NumRT; ++rt)
1551 {
1552 startBufferRow.pColor[rt] += RT::colorRasterTileRowStep;
1553 buffers.pColor[rt] = startBufferRow.pColor[rt];
1554 }
1555 startBufferRow.pDepth += RT::depthRasterTileRowStep;
1556 buffers.pDepth = startBufferRow.pDepth;
1557
1558 startBufferRow.pStencil += RT::stencilRasterTileRowStep;
1559 buffers.pStencil = startBufferRow.pStencil;
1560 }
1561
1562 void RasterizeLine(DRAW_CONTEXT *pDC, uint32_t workerId, uint32_t macroTile, void *pData)
1563 {
1564 const TRIANGLE_WORK_DESC &workDesc = *((TRIANGLE_WORK_DESC*)pData);
1565 #if KNOB_ENABLE_TOSS_POINTS
1566 if (KNOB_TOSS_BIN_TRIS)
1567 {
1568 return;
1569 }
1570 #endif
1571
1572 // bloat line to two tris and call the triangle rasterizer twice
1573 RDTSC_START(BERasterizeLine);
1574
1575 const API_STATE &state = GetApiState(pDC);
1576 const SWR_RASTSTATE &rastState = state.rastState;
1577
1578 // macrotile dimensioning
1579 uint32_t macroX, macroY;
1580 MacroTileMgr::getTileIndices(macroTile, macroX, macroY);
1581 int32_t macroBoxLeft = macroX * KNOB_MACROTILE_X_DIM_FIXED;
1582 int32_t macroBoxRight = macroBoxLeft + KNOB_MACROTILE_X_DIM_FIXED - 1;
1583 int32_t macroBoxTop = macroY * KNOB_MACROTILE_Y_DIM_FIXED;
1584 int32_t macroBoxBottom = macroBoxTop + KNOB_MACROTILE_Y_DIM_FIXED - 1;
1585
1586 const SWR_RECT &scissorInFixedPoint = state.scissorsInFixedPoint[workDesc.triFlags.viewportIndex];
1587
1588 // create a copy of the triangle buffer to write our adjusted vertices to
1589 OSALIGNSIMD(float) newTriBuffer[4 * 4];
1590 TRIANGLE_WORK_DESC newWorkDesc = workDesc;
1591 newWorkDesc.pTriBuffer = &newTriBuffer[0];
1592
1593 // create a copy of the attrib buffer to write our adjusted attribs to
1594 OSALIGNSIMD(float) newAttribBuffer[4 * 3 * KNOB_NUM_ATTRIBUTES];
1595 newWorkDesc.pAttribs = &newAttribBuffer[0];
1596
1597 const __m128 vBloat0 = _mm_set_ps(0.5f, -0.5f, -0.5f, 0.5f);
1598 const __m128 vBloat1 = _mm_set_ps(0.5f, 0.5f, 0.5f, -0.5f);
1599
1600 __m128 vX, vY, vZ, vRecipW;
1601
1602 vX = _mm_load_ps(workDesc.pTriBuffer);
1603 vY = _mm_load_ps(workDesc.pTriBuffer + 4);
1604 vZ = _mm_load_ps(workDesc.pTriBuffer + 8);
1605 vRecipW = _mm_load_ps(workDesc.pTriBuffer + 12);
1606
1607 // triangle 0
1608 // v0,v1 -> v0,v0,v1
1609 __m128 vXa = _mm_shuffle_ps(vX, vX, _MM_SHUFFLE(1, 1, 0, 0));
1610 __m128 vYa = _mm_shuffle_ps(vY, vY, _MM_SHUFFLE(1, 1, 0, 0));
1611 __m128 vZa = _mm_shuffle_ps(vZ, vZ, _MM_SHUFFLE(1, 1, 0, 0));
1612 __m128 vRecipWa = _mm_shuffle_ps(vRecipW, vRecipW, _MM_SHUFFLE(1, 1, 0, 0));
1613
1614 __m128 vLineWidth = _mm_set1_ps(pDC->pState->state.rastState.lineWidth);
1615 __m128 vAdjust = _mm_mul_ps(vLineWidth, vBloat0);
1616 if (workDesc.triFlags.yMajor)
1617 {
1618 vXa = _mm_add_ps(vAdjust, vXa);
1619 }
1620 else
1621 {
1622 vYa = _mm_add_ps(vAdjust, vYa);
1623 }
1624
1625 // Store triangle description for rasterizer
1626 _mm_store_ps((float*)&newTriBuffer[0], vXa);
1627 _mm_store_ps((float*)&newTriBuffer[4], vYa);
1628 _mm_store_ps((float*)&newTriBuffer[8], vZa);
1629 _mm_store_ps((float*)&newTriBuffer[12], vRecipWa);
1630
1631 // binner bins 3 edges for lines as v0, v1, v1
1632 // tri0 needs v0, v0, v1
1633 for (uint32_t a = 0; a < workDesc.numAttribs; ++a)
1634 {
1635 __m128 vAttrib0 = _mm_load_ps(&workDesc.pAttribs[a*12 + 0]);
1636 __m128 vAttrib1 = _mm_load_ps(&workDesc.pAttribs[a*12 + 4]);
1637
1638 _mm_store_ps((float*)&newAttribBuffer[a*12 + 0], vAttrib0);
1639 _mm_store_ps((float*)&newAttribBuffer[a*12 + 4], vAttrib0);
1640 _mm_store_ps((float*)&newAttribBuffer[a*12 + 8], vAttrib1);
1641 }
1642
1643 // Store user clip distances for triangle 0
1644 float newClipBuffer[3 * 8];
1645 uint32_t numClipDist = _mm_popcnt_u32(state.rastState.clipDistanceMask);
1646 if (numClipDist)
1647 {
1648 newWorkDesc.pUserClipBuffer = newClipBuffer;
1649
1650 float* pOldBuffer = workDesc.pUserClipBuffer;
1651 float* pNewBuffer = newClipBuffer;
1652 for (uint32_t i = 0; i < numClipDist; ++i)
1653 {
1654 // read barycentric coeffs from binner
1655 float a = *(pOldBuffer++);
1656 float b = *(pOldBuffer++);
1657
1658 // reconstruct original clip distance at vertices
1659 float c0 = a + b;
1660 float c1 = b;
1661
1662 // construct triangle barycentrics
1663 *(pNewBuffer++) = c0 - c1;
1664 *(pNewBuffer++) = c0 - c1;
1665 *(pNewBuffer++) = c1;
1666 }
1667 }
1668
1669 // setup triangle rasterizer function
1670 PFN_WORK_FUNC pfnTriRast;
1671 uint32_t sampleCount = (rastState.samplePattern == SWR_MSAA_STANDARD_PATTERN) ? rastState.sampleCount : SWR_MULTISAMPLE_1X;
1672 // conservative rast not supported for points/lines
1673 pfnTriRast = GetRasterizerFunc(sampleCount, false, SWR_INPUT_COVERAGE_NONE, ALL_EDGES_VALID, (rastState.scissorEnable > 0) || (pDC->pState->state.scissorsTileAligned == false));
1674
1675 // make sure this macrotile intersects the triangle
1676 __m128i vXai = fpToFixedPoint(vXa);
1677 __m128i vYai = fpToFixedPoint(vYa);
1678 OSALIGNSIMD(SWR_RECT) bboxA;
1679 calcBoundingBoxInt(vXai, vYai, bboxA);
1680
1681 if (!(bboxA.xmin > macroBoxRight ||
1682 bboxA.xmin > scissorInFixedPoint.xmax ||
1683 bboxA.xmax - 1 < macroBoxLeft ||
1684 bboxA.xmax - 1 < scissorInFixedPoint.xmin ||
1685 bboxA.ymin > macroBoxBottom ||
1686 bboxA.ymin > scissorInFixedPoint.ymax ||
1687 bboxA.ymax - 1 < macroBoxTop ||
1688 bboxA.ymax - 1 < scissorInFixedPoint.ymin)) {
1689 // rasterize triangle
1690 pfnTriRast(pDC, workerId, macroTile, (void*)&newWorkDesc);
1691 }
1692
1693 // triangle 1
1694 // v0,v1 -> v1,v1,v0
1695 vXa = _mm_shuffle_ps(vX, vX, _MM_SHUFFLE(1, 0, 1, 1));
1696 vYa = _mm_shuffle_ps(vY, vY, _MM_SHUFFLE(1, 0, 1, 1));
1697 vZa = _mm_shuffle_ps(vZ, vZ, _MM_SHUFFLE(1, 0, 1, 1));
1698 vRecipWa = _mm_shuffle_ps(vRecipW, vRecipW, _MM_SHUFFLE(1, 0, 1, 1));
1699
1700 vAdjust = _mm_mul_ps(vLineWidth, vBloat1);
1701 if (workDesc.triFlags.yMajor)
1702 {
1703 vXa = _mm_add_ps(vAdjust, vXa);
1704 }
1705 else
1706 {
1707 vYa = _mm_add_ps(vAdjust, vYa);
1708 }
1709
1710 // Store triangle description for rasterizer
1711 _mm_store_ps((float*)&newTriBuffer[0], vXa);
1712 _mm_store_ps((float*)&newTriBuffer[4], vYa);
1713 _mm_store_ps((float*)&newTriBuffer[8], vZa);
1714 _mm_store_ps((float*)&newTriBuffer[12], vRecipWa);
1715
1716 // binner bins 3 edges for lines as v0, v1, v1
1717 // tri1 needs v1, v1, v0
1718 for (uint32_t a = 0; a < workDesc.numAttribs; ++a)
1719 {
1720 __m128 vAttrib0 = _mm_load_ps(&workDesc.pAttribs[a * 12 + 0]);
1721 __m128 vAttrib1 = _mm_load_ps(&workDesc.pAttribs[a * 12 + 4]);
1722
1723 _mm_store_ps((float*)&newAttribBuffer[a * 12 + 0], vAttrib1);
1724 _mm_store_ps((float*)&newAttribBuffer[a * 12 + 4], vAttrib1);
1725 _mm_store_ps((float*)&newAttribBuffer[a * 12 + 8], vAttrib0);
1726 }
1727
1728 // store user clip distance for triangle 1
1729 if (numClipDist)
1730 {
1731 float* pOldBuffer = workDesc.pUserClipBuffer;
1732 float* pNewBuffer = newClipBuffer;
1733 for (uint32_t i = 0; i < numClipDist; ++i)
1734 {
1735 // read barycentric coeffs from binner
1736 float a = *(pOldBuffer++);
1737 float b = *(pOldBuffer++);
1738
1739 // reconstruct original clip distance at vertices
1740 float c0 = a + b;
1741 float c1 = b;
1742
1743 // construct triangle barycentrics
1744 *(pNewBuffer++) = c1 - c0;
1745 *(pNewBuffer++) = c1 - c0;
1746 *(pNewBuffer++) = c0;
1747 }
1748 }
1749
1750 vXai = fpToFixedPoint(vXa);
1751 vYai = fpToFixedPoint(vYa);
1752 calcBoundingBoxInt(vXai, vYai, bboxA);
1753
1754 if (!(bboxA.xmin > macroBoxRight ||
1755 bboxA.xmin > scissorInFixedPoint.xmax ||
1756 bboxA.xmax - 1 < macroBoxLeft ||
1757 bboxA.xmax - 1 < scissorInFixedPoint.xmin ||
1758 bboxA.ymin > macroBoxBottom ||
1759 bboxA.ymin > scissorInFixedPoint.ymax ||
1760 bboxA.ymax - 1 < macroBoxTop ||
1761 bboxA.ymax - 1 < scissorInFixedPoint.ymin)) {
1762 // rasterize triangle
1763 pfnTriRast(pDC, workerId, macroTile, (void*)&newWorkDesc);
1764 }
1765
1766 RDTSC_STOP(BERasterizeLine, 1, 0);
1767 }
1768
1769 struct RasterizerChooser
1770 {
1771 typedef PFN_WORK_FUNC FuncType;
1772
1773 template <typename... ArgsB>
1774 static FuncType GetFunc()
1775 {
1776 return RasterizeTriangle<RasterizerTraits<ArgsB...>>;
1777 }
1778 };
1779
1780 // Selector for correct templated RasterizeTriangle function
1781 PFN_WORK_FUNC GetRasterizerFunc(
1782 uint32_t numSamples,
1783 bool IsConservative,
1784 uint32_t InputCoverage,
1785 uint32_t EdgeEnable,
1786 bool RasterizeScissorEdges
1787 )
1788 {
1789 return TemplateArgUnroller<RasterizerChooser>::GetFunc(
1790 IntArg<SWR_MULTISAMPLE_1X,SWR_MULTISAMPLE_TYPE_COUNT-1>{numSamples},
1791 IsConservative,
1792 IntArg<SWR_INPUT_COVERAGE_NONE, SWR_INPUT_COVERAGE_COUNT-1>{InputCoverage},
1793 IntArg<0, VALID_TRI_EDGE_COUNT-1>{EdgeEnable},
1794 RasterizeScissorEdges);
1795 }