Skip to content

Commit b1a00ff

Browse files
fix triangle and quad spans applying pixels out of bounds
1 parent 95bfa19 commit b1a00ff

1 file changed

Lines changed: 50 additions & 21 deletions

File tree

src/external/rlsw.h

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5389,6 +5389,11 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
53895389
int xEnd = (int)end->position[0];
53905390
if (xStart == xEnd) return;
53915391

5392+
// Get the current row and skip if outside the framebuffer.
5393+
// Maybe this check is better suited elsewhere?
5394+
int y = (int)start->position[1];
5395+
if (y < 0 || y >= RLSW.colorBuffer->height) return;
5396+
53925397
// Compute the inverse horizontal distance along the X axis
53935398
float dxRcp = sw_rcp(end->position[0] - start->position[0]);
53945399

@@ -5411,38 +5416,45 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
54115416
// Compute the subpixel distance to traverse before the first pixel
54125417
float xSubstep = 1.0f - sw_fract(start->position[0]);
54135418

5414-
// Initializing the interpolation starting values
5415-
float w = start->position[3] + dWdx*xSubstep;
5419+
// Intercept the span bounds to ensure we don't write before the framebuffer.
5420+
int xLoopStart = sw_clamp_int(xStart, 0, RLSW.colorBuffer->width - 1);
5421+
int dxStart = xLoopStart - xStart;
5422+
5423+
// Initializing the interpolation starting values.
5424+
// Also step further into them to move away from the colorbuffer edge.
5425+
float w = start->position[3] + dWdx*xSubstep + dWdx*dxStart;
54165426
float color[4] = {
5417-
start->color[0] + dCdx[0]*xSubstep,
5418-
start->color[1] + dCdx[1]*xSubstep,
5419-
start->color[2] + dCdx[2]*xSubstep,
5420-
start->color[3] + dCdx[3]*xSubstep
5427+
start->color[0] + dCdx[0]*xSubstep + dCdx[0]*dxStart,
5428+
start->color[1] + dCdx[1]*xSubstep + dCdx[1]*dxStart,
5429+
start->color[2] + dCdx[2]*xSubstep + dCdx[2]*dxStart,
5430+
start->color[3] + dCdx[3]*xSubstep + dCdx[3]*dxStart
54215431
};
54225432
#ifdef SW_ENABLE_DEPTH_TEST
5423-
float z = start->position[2] + dZdx*xSubstep;
5433+
float z = start->position[2] + dZdx*xSubstep + dZdx*dxStart;
54245434
#endif
54255435
#ifdef SW_ENABLE_TEXTURE
5426-
float u = start->texcoord[0] + dUdx*xSubstep;
5427-
float v = start->texcoord[1] + dVdx*xSubstep;
5436+
float u = start->texcoord[0] + dUdx*xSubstep + dUdx*dxStart;
5437+
float v = start->texcoord[1] + dVdx*xSubstep + dVdx*dxStart;
54285438
#endif
54295439

54305440
// Pre-calculate the starting pointers for the framebuffer row
5431-
int y = (int)start->position[1];
5432-
int baseOffset = y*RLSW.colorBuffer->width + xStart;
5441+
// Don't allow a y value outside the buffer.
5442+
int baseOffset = y*RLSW.colorBuffer->width + xLoopStart;
54335443
uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE;
54345444
#ifdef SW_ENABLE_DEPTH_TEST
54355445
uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE;
54365446
#endif
54375447

54385448
#define SW_AFFINE_BLOCK 16
54395449

5440-
int x = xStart;
5441-
while (x < xEnd)
5450+
int x = xLoopStart;
5451+
// Prevent pixels from beyond the buffer from processing.
5452+
int xLoopEnd = sw_clamp_int(xEnd, 0, RLSW.colorBuffer->width - 1);
5453+
while (x < xLoopEnd)
54425454
{
54435455
// Clamp last block to remaining pixels
54445456
int blockEnd = x + SW_AFFINE_BLOCK;
5445-
if (blockEnd > xEnd) blockEnd = xEnd;
5457+
if (blockEnd > xLoopEnd) blockEnd = xLoopEnd;
54465458
float blockLenF = (float)(blockEnd - x);
54475459
float blockLenRcp = sw_rcp(blockLenF);
54485460

@@ -5730,21 +5742,38 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
57305742
uint8_t *dPixels = RLSW.depthBuffer->pixels;
57315743
#endif
57325744

5733-
for (int y = yMin; y < yMax; y++)
5745+
// Intercept the boundaries to stay within the framebuffer.
5746+
int yLoopMin = sw_clamp_int(yMin, 0, RLSW.colorBuffer->height - 1);
5747+
int yLoopMax = sw_clamp_int(yMax, 0, RLSW.colorBuffer->height - 1);
5748+
int xLoopMin = sw_clamp_int(xMin, 0, RLSW.colorBuffer->width - 1);
5749+
int xLoopMax = sw_clamp_int(xMax, 0, RLSW.colorBuffer->width - 1);
5750+
int dxMin = xLoopMin - xMin;
5751+
#if defined(SW_ENABLE_DEPTH_TEST) || defined(SW_ENABLE_TEXTURE)
5752+
int dyMin = yLoopMin - yMin;
5753+
#endif
5754+
5755+
for (int y = yLoopMin; y < yLoopMax; y++)
57345756
{
5735-
int baseOffset = y*stride + xMin;
5757+
int baseOffset = y*stride + xLoopMin;
57365758
uint8_t *cPtr = cPixels + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE;
57375759
#ifdef SW_ENABLE_DEPTH_TEST
57385760
uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE;
5739-
float z = zRow;
5761+
// Correct our start by how far we clipped outside the framebuffer.
5762+
float z = zRow + dZdy*dyMin;
57405763
#endif
57415764
#ifdef SW_ENABLE_TEXTURE
5742-
float u = uRow;
5743-
float v = vRow;
5765+
// Correct our start by how far we clipped outside the framebuffer.
5766+
float u = uRow + dUdy*dyMin;
5767+
float v = vRow + dVdy*dyMin;
57445768
#endif
5745-
float color[4] = { cRow[0], cRow[1], cRow[2], cRow[3] };
5769+
float color[4] = {
5770+
cRow[0] + dCdx[0]*dxMin,
5771+
cRow[1] + dCdx[1]*dxMin,
5772+
cRow[2] + dCdx[2]*dxMin,
5773+
cRow[3] + dCdx[3]*dxMin
5774+
};
57465775

5747-
for (int x = xMin; x < xMax; x++)
5776+
for (int x = xLoopMin; x < xLoopMax; x++)
57485777
{
57495778
float srcColor[4] = { color[0], color[1], color[2], color[3] };
57505779

0 commit comments

Comments
 (0)