summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/drivers/swr/rasterizer/core/binner.cpp374
-rw-r--r--src/gallium/drivers/swr/rasterizer/core/knobs.h10
-rw-r--r--src/gallium/drivers/swr/rasterizer/core/rdtsc_core.cpp2
-rw-r--r--src/gallium/drivers/swr/rasterizer/core/rdtsc_core.h2
4 files changed, 388 insertions, 0 deletions
diff --git a/src/gallium/drivers/swr/rasterizer/core/binner.cpp b/src/gallium/drivers/swr/rasterizer/core/binner.cpp
index 9aa9f9e79b1..e2f32641f30 100644
--- a/src/gallium/drivers/swr/rasterizer/core/binner.cpp
+++ b/src/gallium/drivers/swr/rasterizer/core/binner.cpp
@@ -292,6 +292,341 @@ void TransposeVertices(simd4scalar(&dst)[16], const simd16scalar &src0, const si
vTranspose4x16(reinterpret_cast<simd16scalar(&)[4]>(dst), src0, src1, src2, _simd16_setzero_ps());
}
+
+#if KNOB_ENABLE_EARLY_RAST
+
+#define ER_SIMD_TILE_X_DIM (1 << ER_SIMD_TILE_X_SHIFT)
+#define ER_SIMD_TILE_Y_DIM (1 << ER_SIMD_TILE_Y_SHIFT)
+
+
+template<typename SIMD_T>
+struct EarlyRastHelper
+{
+};
+
+template<>
+struct EarlyRastHelper<SIMD256>
+{
+ static SIMD256::Integer InitShiftCntrl()
+ {
+ return SIMD256::set_epi32(24, 25, 26, 27, 28, 29, 30, 31);
+ }
+};
+
+#if USE_SIMD16_FRONTEND
+template<>
+struct EarlyRastHelper<SIMD512>
+{
+ static SIMD512::Integer InitShiftCntrl()
+ {
+ return SIMD512::set_epi32(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);
+ }
+};
+
+#endif
+//////////////////////////////////////////////////////////////////////////
+/// @brief Early Rasterizer (ER); triangles that fit small (e.g. 4x4) tile
+/// (ER tile) can be rasterized as early as in binner to check if
+/// they cover any pixels. If not - the triangles can be
+/// culled in binner.
+///
+/// @param er_bbox - coordinates of ER tile for each triangle
+/// @param vAi - A coefficients of triangle edges
+/// @param vBi - B coefficients of triangle edges
+/// @param vXi - X coordinates of triangle vertices
+/// @param vYi - Y coordinates of triangle vertices
+/// @param frontWindingTris - mask indicating CCW/CW triangles
+/// @param triMask - mask for valid SIMD lanes (triangles)
+/// @param oneTileMask - defines triangles for ER to work on
+/// (tris that fit into ER tile)
+template <typename SIMD_T, uint32_t SIMD_WIDTH, typename CT>
+uint32_t SIMDCALL EarlyRasterizer(
+ SIMDBBOX_T<SIMD_T> &er_bbox,
+ typename SIMD_T::Integer (&vAi)[3],
+ typename SIMD_T::Integer (&vBi)[3],
+ typename SIMD_T::Integer (&vXi)[3],
+ typename SIMD_T::Integer (&vYi)[3],
+ uint32_t cwTrisMask,
+ uint32_t triMask,
+ uint32_t oneTileMask)
+{
+ // step to pixel center of top-left pixel of the triangle bbox
+ typename SIMD_T::Integer vTopLeftX = SIMD_T::template slli_epi32<ER_SIMD_TILE_X_SHIFT + FIXED_POINT_SHIFT>(er_bbox.xmin);
+ vTopLeftX = SIMD_T::add_epi32(vTopLeftX, SIMD_T::set1_epi32(FIXED_POINT_SCALE / 2));
+
+ typename SIMD_T::Integer vTopLeftY = SIMD_T::template slli_epi32<ER_SIMD_TILE_Y_SHIFT + FIXED_POINT_SHIFT>(er_bbox.ymin);
+ vTopLeftY = SIMD_T::add_epi32(vTopLeftY, SIMD_T::set1_epi32(FIXED_POINT_SCALE / 2));
+
+ // negate A and B for CW tris
+ typename SIMD_T::Integer vNegA0 = SIMD_T::mullo_epi32(vAi[0], SIMD_T::set1_epi32(-1));
+ typename SIMD_T::Integer vNegA1 = SIMD_T::mullo_epi32(vAi[1], SIMD_T::set1_epi32(-1));
+ typename SIMD_T::Integer vNegA2 = SIMD_T::mullo_epi32(vAi[2], SIMD_T::set1_epi32(-1));
+ typename SIMD_T::Integer vNegB0 = SIMD_T::mullo_epi32(vBi[0], SIMD_T::set1_epi32(-1));
+ typename SIMD_T::Integer vNegB1 = SIMD_T::mullo_epi32(vBi[1], SIMD_T::set1_epi32(-1));
+ typename SIMD_T::Integer vNegB2 = SIMD_T::mullo_epi32(vBi[2], SIMD_T::set1_epi32(-1));
+
+ RDTSC_EVENT(FEEarlyRastEnter, _mm_popcnt_u32(oneTileMask & triMask), 0);
+
+ typename SIMD_T::Integer vShiftCntrl = EarlyRastHelper <SIMD_T>::InitShiftCntrl();
+ typename SIMD_T::Integer vCwTris = SIMD_T::set1_epi32(cwTrisMask);
+ typename SIMD_T::Integer vMask = SIMD_T::sllv_epi32(vCwTris, vShiftCntrl);
+
+ vAi[0] = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vAi[0]), SIMD_T::castsi_ps(vNegA0), SIMD_T::castsi_ps(vMask)));
+ vAi[1] = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vAi[1]), SIMD_T::castsi_ps(vNegA1), SIMD_T::castsi_ps(vMask)));
+ vAi[2] = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vAi[2]), SIMD_T::castsi_ps(vNegA2), SIMD_T::castsi_ps(vMask)));
+ vBi[0] = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vBi[0]), SIMD_T::castsi_ps(vNegB0), SIMD_T::castsi_ps(vMask)));
+ vBi[1] = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vBi[1]), SIMD_T::castsi_ps(vNegB1), SIMD_T::castsi_ps(vMask)));
+ vBi[2] = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vBi[2]), SIMD_T::castsi_ps(vNegB2), SIMD_T::castsi_ps(vMask)));
+
+ // evaluate edge equations at top-left pixel
+ typename SIMD_T::Integer vDeltaX0 = SIMD_T::sub_epi32(vTopLeftX, vXi[0]);
+ typename SIMD_T::Integer vDeltaX1 = SIMD_T::sub_epi32(vTopLeftX, vXi[1]);
+ typename SIMD_T::Integer vDeltaX2 = SIMD_T::sub_epi32(vTopLeftX, vXi[2]);
+
+ typename SIMD_T::Integer vDeltaY0 = SIMD_T::sub_epi32(vTopLeftY, vYi[0]);
+ typename SIMD_T::Integer vDeltaY1 = SIMD_T::sub_epi32(vTopLeftY, vYi[1]);
+ typename SIMD_T::Integer vDeltaY2 = SIMD_T::sub_epi32(vTopLeftY, vYi[2]);
+
+ typename SIMD_T::Integer vAX0 = SIMD_T::mullo_epi32(vAi[0], vDeltaX0);
+ typename SIMD_T::Integer vAX1 = SIMD_T::mullo_epi32(vAi[1], vDeltaX1);
+ typename SIMD_T::Integer vAX2 = SIMD_T::mullo_epi32(vAi[2], vDeltaX2);
+
+ typename SIMD_T::Integer vBY0 = SIMD_T::mullo_epi32(vBi[0], vDeltaY0);
+ typename SIMD_T::Integer vBY1 = SIMD_T::mullo_epi32(vBi[1], vDeltaY1);
+ typename SIMD_T::Integer vBY2 = SIMD_T::mullo_epi32(vBi[2], vDeltaY2);
+
+ typename SIMD_T::Integer vEdge0 = SIMD_T::add_epi32(vAX0, vBY0);
+ typename SIMD_T::Integer vEdge1 = SIMD_T::add_epi32(vAX1, vBY1);
+ typename SIMD_T::Integer vEdge2 = SIMD_T::add_epi32(vAX2, vBY2);
+
+ vEdge0 = SIMD_T::template srai_epi32<FIXED_POINT_SHIFT>(vEdge0);
+ vEdge1 = SIMD_T::template srai_epi32<FIXED_POINT_SHIFT>(vEdge1);
+ vEdge2 = SIMD_T::template srai_epi32<FIXED_POINT_SHIFT>(vEdge2);
+
+ // top left rule
+ typename SIMD_T::Integer vEdgeAdjust0 = SIMD_T::sub_epi32(vEdge0, SIMD_T::set1_epi32(1));
+ typename SIMD_T::Integer vEdgeAdjust1 = SIMD_T::sub_epi32(vEdge1, SIMD_T::set1_epi32(1));
+ typename SIMD_T::Integer vEdgeAdjust2 = SIMD_T::sub_epi32(vEdge2, SIMD_T::set1_epi32(1));
+
+ // vA < 0
+ vEdge0 = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vEdge0), SIMD_T::castsi_ps(vEdgeAdjust0), SIMD_T::castsi_ps(vAi[0])));
+ vEdge1 = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vEdge1), SIMD_T::castsi_ps(vEdgeAdjust1), SIMD_T::castsi_ps(vAi[1])));
+ vEdge2 = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vEdge2), SIMD_T::castsi_ps(vEdgeAdjust2), SIMD_T::castsi_ps(vAi[2])));
+
+ // vA == 0 && vB < 0
+ typename SIMD_T::Integer vCmp0 = SIMD_T::cmpeq_epi32(vAi[0], SIMD_T::setzero_si());
+ typename SIMD_T::Integer vCmp1 = SIMD_T::cmpeq_epi32(vAi[1], SIMD_T::setzero_si());
+ typename SIMD_T::Integer vCmp2 = SIMD_T::cmpeq_epi32(vAi[2], SIMD_T::setzero_si());
+
+ vCmp0 = SIMD_T::and_si(vCmp0, vBi[0]);
+ vCmp1 = SIMD_T::and_si(vCmp1, vBi[1]);
+ vCmp2 = SIMD_T::and_si(vCmp2, vBi[2]);
+
+ vEdge0 = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vEdge0), SIMD_T::castsi_ps(vEdgeAdjust0), SIMD_T::castsi_ps(vCmp0)));
+ vEdge1 = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vEdge1), SIMD_T::castsi_ps(vEdgeAdjust1), SIMD_T::castsi_ps(vCmp1)));
+ vEdge2 = SIMD_T::castps_si(SIMD_T::blendv_ps(SIMD_T::castsi_ps(vEdge2), SIMD_T::castsi_ps(vEdgeAdjust2), SIMD_T::castsi_ps(vCmp2)));
+
+
+#if ER_SIMD_TILE_X_DIM == 4 && ER_SIMD_TILE_Y_DIM == 4
+ // Go down
+ // coverage pixel 0
+ typename SIMD_T::Integer vMask0 = SIMD_T::and_si(vEdge0, vEdge1);
+ vMask0 = SIMD_T::and_si(vMask0, vEdge2);
+
+ // coverage pixel 1
+ typename SIMD_T::Integer vEdge0N = SIMD_T::add_epi32(vEdge0, vBi[0]);
+ typename SIMD_T::Integer vEdge1N = SIMD_T::add_epi32(vEdge1, vBi[1]);
+ typename SIMD_T::Integer vEdge2N = SIMD_T::add_epi32(vEdge2, vBi[2]);
+ typename SIMD_T::Integer vMask1 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask1 = SIMD_T::and_si(vMask1, vEdge2N);
+
+ // coverage pixel 2
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vBi[2]);
+ typename SIMD_T::Integer vMask2 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask2 = SIMD_T::and_si(vMask2, vEdge2N);
+
+ // coverage pixel 3
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vBi[2]);
+ typename SIMD_T::Integer vMask3 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask3 = SIMD_T::and_si(vMask3, vEdge2N);
+
+ // One step to the right and then up
+
+ // coverage pixel 4
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vAi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vAi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vAi[2]);
+ typename SIMD_T::Integer vMask4 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask4 = SIMD_T::and_si(vMask4, vEdge2N);
+
+ // coverage pixel 5
+ vEdge0N = SIMD_T::sub_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::sub_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::sub_epi32(vEdge2N, vBi[2]);
+ typename SIMD_T::Integer vMask5 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask5 = SIMD_T::and_si(vMask5, vEdge2N);
+
+ // coverage pixel 6
+ vEdge0N = SIMD_T::sub_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::sub_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::sub_epi32(vEdge2N, vBi[2]);
+ typename SIMD_T::Integer vMask6 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask6 = SIMD_T::and_si(vMask6, vEdge2N);
+
+ // coverage pixel 7
+ vEdge0N = SIMD_T::sub_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::sub_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::sub_epi32(vEdge2N, vBi[2]);
+ typename SIMD_T::Integer vMask7 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask7 = SIMD_T::and_si(vMask7, vEdge2N);
+
+ typename SIMD_T::Integer vLit1 = SIMD_T::or_si(vMask0, vMask1);
+ vLit1 = SIMD_T::or_si(vLit1, vMask2);
+ vLit1 = SIMD_T::or_si(vLit1, vMask3);
+ vLit1 = SIMD_T::or_si(vLit1, vMask4);
+ vLit1 = SIMD_T::or_si(vLit1, vMask5);
+ vLit1 = SIMD_T::or_si(vLit1, vMask6);
+ vLit1 = SIMD_T::or_si(vLit1, vMask7);
+
+ // Step to the right and go down again
+
+ // coverage pixel 0
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vAi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vAi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vAi[2]);
+ vMask0 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask0 = SIMD_T::and_si(vMask0, vEdge2N);
+
+ // coverage pixel 1
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vBi[2]);
+ vMask1 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask1 = SIMD_T::and_si(vMask1, vEdge2N);
+
+ // coverage pixel 2
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vBi[2]);
+ vMask2 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask2 = SIMD_T::and_si(vMask2, vEdge2N);
+
+ // coverage pixel 3
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vBi[2]);
+ vMask3 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask3 = SIMD_T::and_si(vMask3, vEdge2N);
+
+ // And for the last time - to the right and up
+
+ // coverage pixel 4
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vAi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vAi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vAi[2]);
+ vMask4 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask4 = SIMD_T::and_si(vMask4, vEdge2N);
+
+ // coverage pixel 5
+ vEdge0N = SIMD_T::sub_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::sub_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::sub_epi32(vEdge2N, vBi[2]);
+ vMask5 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask5 = SIMD_T::and_si(vMask5, vEdge2N);
+
+ // coverage pixel 6
+ vEdge0N = SIMD_T::sub_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::sub_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::sub_epi32(vEdge2N, vBi[2]);
+ vMask6 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask6 = SIMD_T::and_si(vMask6, vEdge2N);
+
+ // coverage pixel 7
+ vEdge0N = SIMD_T::sub_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::sub_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::sub_epi32(vEdge2N, vBi[2]);
+ vMask7 = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vMask7 = SIMD_T::and_si(vMask7, vEdge2N);
+
+ typename SIMD_T::Integer vLit2 = SIMD_T::or_si(vMask0, vMask1);
+ vLit2 = SIMD_T::or_si(vLit2, vMask2);
+ vLit2 = SIMD_T::or_si(vLit2, vMask3);
+ vLit2 = SIMD_T::or_si(vLit2, vMask4);
+ vLit2 = SIMD_T::or_si(vLit2, vMask5);
+ vLit2 = SIMD_T::or_si(vLit2, vMask6);
+ vLit2 = SIMD_T::or_si(vLit2, vMask7);
+
+ typename SIMD_T::Integer vLit = SIMD_T::or_si(vLit1, vLit2);
+
+#else
+ // Generic algorithm sweeping in row by row order
+ typename SIMD_T::Integer vRowMask[ER_SIMD_TILE_Y_DIM];
+
+ typename SIMD_T::Integer vEdge0N = vEdge0;
+ typename SIMD_T::Integer vEdge1N = vEdge1;
+ typename SIMD_T::Integer vEdge2N = vEdge2;
+
+ for (uint32_t row = 0; row < ER_SIMD_TILE_Y_DIM; row++)
+ {
+ // Store edge values at the beginning of the row
+ typename SIMD_T::Integer vRowEdge0 = vEdge0N;
+ typename SIMD_T::Integer vRowEdge1 = vEdge1N;
+ typename SIMD_T::Integer vRowEdge2 = vEdge2N;
+
+ typename SIMD_T::Integer vColMask[ER_SIMD_TILE_X_DIM];
+
+ for (uint32_t col = 0; col < ER_SIMD_TILE_X_DIM; col++)
+ {
+ vColMask[col] = SIMD_T::and_si(vEdge0N, vEdge1N);
+ vColMask[col] = SIMD_T::and_si(vColMask[col], vEdge2N);
+
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vAi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vAi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vAi[2]);
+ }
+ vRowMask[row] = vColMask[0];
+ for (uint32_t col = 1; col < ER_SIMD_TILE_X_DIM; col++)
+ {
+ vRowMask[row] = SIMD_T::or_si(vRowMask[row], vColMask[col]);
+ }
+ // Restore values and go to the next row
+ vEdge0N = vRowEdge0;
+ vEdge1N = vRowEdge1;
+ vEdge2N = vRowEdge2;
+
+ vEdge0N = SIMD_T::add_epi32(vEdge0N, vBi[0]);
+ vEdge1N = SIMD_T::add_epi32(vEdge1N, vBi[1]);
+ vEdge2N = SIMD_T::add_epi32(vEdge2N, vBi[2]);
+ }
+
+ // compress all masks
+ typename SIMD_T::Integer vLit = vRowMask[0];
+ for (uint32_t row = 1; row < ER_SIMD_TILE_Y_DIM; row++)
+ {
+ vLit = SIMD_T::or_si(vLit, vRowMask[row]);
+ }
+
+#endif
+ // Check which triangles has any pixel lit
+ uint32_t maskLit = SIMD_T::movemask_ps(SIMD_T::castsi_ps(vLit));
+ uint32_t maskUnlit = ~maskLit & oneTileMask;
+
+ uint32_t oldTriMask = triMask;
+ triMask &= ~maskUnlit;
+
+ if (triMask ^ oldTriMask)
+ {
+ RDTSC_EVENT(FEEarlyRastExit, _mm_popcnt_u32(triMask & oneTileMask), 0);
+ }
+ return triMask;
+}
+
+#endif // Early rasterizer
+
//////////////////////////////////////////////////////////////////////////
/// @brief Bin triangle primitives to macro tiles. Performs setup, clipping
/// culling, viewport transform, etc.
@@ -592,6 +927,45 @@ void SIMDCALL BinTrianglesImpl(
triMask = triMask & ~maskOutsideScissor;
}
+#if KNOB_ENABLE_EARLY_RAST
+ if (rastState.sampleCount == SWR_MULTISAMPLE_1X && !CT::IsConservativeT::value)
+ {
+ // Try early rasterization - culling small triangles which do not cover any pixels
+
+ // convert to ER tiles
+ SIMDBBOX_T<SIMD_T> er_bbox;
+
+ er_bbox.xmin = SIMD_T::template srai_epi32<ER_SIMD_TILE_X_SHIFT + FIXED_POINT_SHIFT>(bbox.xmin);
+ er_bbox.xmax = SIMD_T::template srai_epi32<ER_SIMD_TILE_X_SHIFT + FIXED_POINT_SHIFT>(bbox.xmax);
+ er_bbox.ymin = SIMD_T::template srai_epi32<ER_SIMD_TILE_Y_SHIFT + FIXED_POINT_SHIFT>(bbox.ymin);
+ er_bbox.ymax = SIMD_T::template srai_epi32<ER_SIMD_TILE_Y_SHIFT + FIXED_POINT_SHIFT>(bbox.ymax);
+
+ typename SIMD_T::Integer vTileX = SIMD_T::cmpeq_epi32(er_bbox.xmin, er_bbox.xmax);
+ typename SIMD_T::Integer vTileY = SIMD_T::cmpeq_epi32(er_bbox.ymin, er_bbox.ymax);
+
+ // Take only triangles that fit into ER tile
+ uint32_t oneTileMask = triMask & SIMD_T::movemask_ps(SIMD_T::castsi_ps(SIMD_T::and_si(vTileX, vTileY)));
+
+ if (oneTileMask)
+ {
+ // determine CW tris (det > 0)
+ uint32_t maskCwLo = SIMD_T::movemask_pd(SIMD_T::castsi_pd(SIMD_T::cmpgt_epi64(vDet[0], SIMD_T::setzero_si())));
+ uint32_t maskCwHi = SIMD_T::movemask_pd(SIMD_T::castsi_pd(SIMD_T::cmpgt_epi64(vDet[1], SIMD_T::setzero_si())));
+ uint32_t cwTrisMask = maskCwLo | (maskCwHi << (SIMD_WIDTH / 2));
+
+ // Try early rasterization
+ triMask = EarlyRasterizer<SIMD_T, SIMD_WIDTH, CT>(er_bbox, vAi, vBi, vXi, vYi, cwTrisMask, triMask, oneTileMask);
+
+ if (!triMask)
+ {
+ AR_END(FEBinTriangles, 1);
+ return;
+ }
+ }
+
+ }
+#endif
+
endBinTriangles:
diff --git a/src/gallium/drivers/swr/rasterizer/core/knobs.h b/src/gallium/drivers/swr/rasterizer/core/knobs.h
index 657c2eed76e..23a2876fb8a 100644
--- a/src/gallium/drivers/swr/rasterizer/core/knobs.h
+++ b/src/gallium/drivers/swr/rasterizer/core/knobs.h
@@ -165,6 +165,16 @@
// enables cut-aware primitive assembler
#define KNOB_ENABLE_CUT_AWARE_PA TRUE
+// enables early rasterization (useful for small triangles)
+#if !defined(KNOB_ENABLE_EARLY_RAST)
+#define KNOB_ENABLE_EARLY_RAST 0
+#endif
+
+#if KNOB_ENABLE_EARLY_RAST
+#define ER_SIMD_TILE_X_SHIFT 2
+#define ER_SIMD_TILE_Y_SHIFT 2
+#endif
+
///////////////////////////////////////////////////////////////////////////////
// Debug knobs
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gallium/drivers/swr/rasterizer/core/rdtsc_core.cpp b/src/gallium/drivers/swr/rasterizer/core/rdtsc_core.cpp
index 99b9f55ed12..f1355dd0d9f 100644
--- a/src/gallium/drivers/swr/rasterizer/core/rdtsc_core.cpp
+++ b/src/gallium/drivers/swr/rasterizer/core/rdtsc_core.cpp
@@ -56,6 +56,8 @@ BUCKET_DESC gCoreBuckets[] = {
{ "FEClipTriangles", "", false, 0xffffffff },
{ "FECullZeroAreaAndBackface", "", false, 0xffffffff },
{ "FECullBetweenCenters", "", false, 0xffffffff },
+ { "FEEarlyRastEnter", "", false, 0xffffffff },
+ { "FEEarlyRastExit", "", false, 0xffffffff },
{ "FEProcessStoreTiles", "", true, 0xff39c864 },
{ "FEProcessInvalidateTiles", "", true, 0xffffffff },
{ "WorkerWorkOnFifoBE", "", false, 0xff40261c },
diff --git a/src/gallium/drivers/swr/rasterizer/core/rdtsc_core.h b/src/gallium/drivers/swr/rasterizer/core/rdtsc_core.h
index 733ee18d5f1..5ee8dec6dab 100644
--- a/src/gallium/drivers/swr/rasterizer/core/rdtsc_core.h
+++ b/src/gallium/drivers/swr/rasterizer/core/rdtsc_core.h
@@ -61,6 +61,8 @@ enum CORE_BUCKETS
FEClipTriangles,
FECullZeroAreaAndBackface,
FECullBetweenCenters,
+ FEEarlyRastEnter,
+ FEEarlyRastExit,
FEProcessStoreTiles,
FEProcessInvalidateTiles,
WorkerWorkOnFifoBE,