@@ -1317,11 +1317,24 @@ private static uint ScaleCount(uint value, uint numerator, uint denominator)
13171317 => Math . Max ( 1U , checked ( ( uint ) Math . Max ( 1UL , ( ( ulong ) Math . Max ( value , 1U ) * numerator ) / Math . Max ( denominator , 1U ) ) ) ) ;
13181318
13191319 /// <summary>
1320- /// Aligns a chunk height down to one coarse bin when possible so tile-local scratch buffers stay bin-shaped .
1320+ /// Aligns a chunk height to one coarse bin (16 tile rows) so the next chunk's tile-y start stays bin-aligned .
13211321 /// </summary>
13221322 /// <param name="tileHeight">The candidate real chunk height, in tile rows.</param>
13231323 /// <param name="maximumTileHeight">The maximum tile height allowed for this chunk.</param>
1324- /// <returns>The aligned chunk height, preserving short tail chunks when necessary.</returns>
1324+ /// <returns>The aligned chunk height, preserving short tail chunks only when there are no further rows to render.</returns>
1325+ /// <remarks>
1326+ /// <para>
1327+ /// Coarse rasterization reads the global binning grid using <c>chunk_tile_y_start / N_TILE_Y</c> and lays its
1328+ /// per-bin tiles out starting at <c>chunk_tile_y_start</c>. If a chunk's height is not a multiple of
1329+ /// <c>N_TILE_Y</c> (16), the next chunk's <c>chunk_tile_y_start</c> ends up bin-misaligned and the coarse
1330+ /// dispatch reads the wrong bin's content for the misaligned rows, dropping coverage in those rows.
1331+ /// </para>
1332+ /// <para>
1333+ /// This method therefore rounds non-final chunks up to the next multiple of 16 (the smallest legal chunk size
1334+ /// that preserves bin alignment) and only permits a sub-bin tail when <paramref name="maximumTileHeight"/>
1335+ /// itself is a sub-bin remainder — i.e., this is the final chunk and there are no further rows to render.
1336+ /// </para>
1337+ /// </remarks>
13251338 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
13261339 private static uint AlignChunkTileHeight ( uint tileHeight , uint maximumTileHeight )
13271340 {
@@ -1330,13 +1343,9 @@ private static uint AlignChunkTileHeight(uint tileHeight, uint maximumTileHeight
13301343 return maximumTileHeight ;
13311344 }
13321345
1333- if ( tileHeight <= 16U )
1334- {
1335- return tileHeight ;
1336- }
1337-
1338- uint alignedTileHeight = tileHeight & ~ 15U ;
1339- return alignedTileHeight > 0U ? alignedTileHeight : 16U ;
1346+ // Round up to a full bin row so the next chunk starts on a bin boundary.
1347+ uint alignedTileHeight = AlignUp ( Math . Max ( tileHeight , 1U ) , 16U ) ;
1348+ return alignedTileHeight >= maximumTileHeight ? maximumTileHeight : alignedTileHeight ;
13401349 }
13411350
13421351 /// <summary>
0 commit comments