Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

softgpu: Correct linear interp for uneven positions #16241

Merged
merged 3 commits into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions GPU/Software/Rasterizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,11 +796,18 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords &
int entireY1 = std::min(v0.screenpos.y, v1.screenpos.y);
int entireX2 = std::max(v0.screenpos.x, v1.screenpos.x) - 1;
int entireY2 = std::max(v0.screenpos.y, v1.screenpos.y) - 1;
int minX = std::max(entireX1, range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1);
int minY = std::max(entireY1, range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1);
int minX = std::max(entireX1 & ~(SCREEN_SCALE_FACTOR - 1), range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1);
int minY = std::max(entireY1 & ~(SCREEN_SCALE_FACTOR - 1), range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1);
int maxX = std::min(entireX2, range.x2);
int maxY = std::min(entireY2, range.y2);

// If TL x or y was after the half, we don't draw the pixel.
// TODO: Verify what center is used, allowing slight offset makes gpu/primitives/trianglefan pass.
if (minX < entireX1 - 1)
minX += SCREEN_SCALE_FACTOR;
if (minY < entireY1 - 1)
minY += SCREEN_SCALE_FACTOR;

RasterizerState state = OptimizeFlatRasterizerState(rastState, v1);

Vec2f rowST(0.0f, 0.0f);
Expand All @@ -819,8 +826,8 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords &
tc1.t() *= 1.0f / (float)(1 << state.samplerID.height0Shift);
}

int diffX = (entireX2 - entireX1 + 1) / SCREEN_SCALE_FACTOR;
int diffY = (entireY2 - entireY1 + 1) / SCREEN_SCALE_FACTOR;
float diffX = (entireX2 - entireX1 + 1) / (float)SCREEN_SCALE_FACTOR;
float diffY = (entireY2 - entireY1 + 1) / (float)SCREEN_SCALE_FACTOR;
float diffS = tc1.s() - tc0.s();
float diffT = tc1.t() - tc0.t();

Expand Down Expand Up @@ -853,8 +860,8 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords &
}

// Okay, now move ST to the minX, minY position.
rowST += (stx / (float)(SCREEN_SCALE_FACTOR * 2)) * (minX - entireX1);
rowST += (sty / (float)(SCREEN_SCALE_FACTOR * 2)) * (minY - entireY1);
rowST += (stx / (float)(SCREEN_SCALE_FACTOR * 2)) * (minX - entireX1 + 1);
rowST += (sty / (float)(SCREEN_SCALE_FACTOR * 2)) * (minY - entireY1 + 1);
}

// And now what we add to spread out to 4 values.
Expand Down Expand Up @@ -1043,10 +1050,17 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1, const BinCoords
int entireY1 = std::min(v0.screenpos.y, v1.screenpos.y);
int entireX2 = std::max(v0.screenpos.x, v1.screenpos.x) - 1;
int entireY2 = std::max(v0.screenpos.y, v1.screenpos.y) - 1;
int minX = std::max(entireX1, range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1);
int minY = std::max(entireY1, range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1);
int minX = std::max(entireX1 & ~(SCREEN_SCALE_FACTOR - 1), range.x1) | (SCREEN_SCALE_FACTOR / 2 - 1);
int minY = std::max(entireY1 & ~(SCREEN_SCALE_FACTOR - 1), range.y1) | (SCREEN_SCALE_FACTOR / 2 - 1);
int maxX = std::min(entireX2, range.x2);
int maxY = std::min(entireY2, range.y2);

// If TL x or y was after the half, we don't draw the pixel.
if (minX < entireX1 - 1)
minX += SCREEN_SCALE_FACTOR;
if (minY < entireY1 - 1)
minY += SCREEN_SCALE_FACTOR;

const DrawingCoords pprime = TransformUnit::ScreenToDrawing(minX, minY);
const DrawingCoords pend = TransformUnit::ScreenToDrawing(maxX, maxY);
auto &pixelID = state.pixelID;
Expand Down
63 changes: 37 additions & 26 deletions GPU/Software/RasterizerRectangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,40 +483,51 @@ bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData
return false;
}

bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int c, int *tlIndex, int *brIndex) {
bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int *tlIndex, int *brIndex) {
// Color and Z must be flat.
for (int i = 1; i < c; ++i) {
int tl = 0, br = 0;
for (int i = 1; i < 4; ++i) {
if (!AreCoordsRectangleCompatible(state, data[i], data[0]))
return false;

if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y <= data[tl].v.screenpos.y)
tl = i;
if (data[i].v.screenpos.x >= data[br].v.screenpos.x && data[i].v.screenpos.y >= data[br].v.screenpos.y)
br = i;
}

// Check for the common case: a single TL-TR-BR-BL.
if (c == 4) {
const auto &pos0 = data[0].v.screenpos, &pos1 = data[1].v.screenpos;
const auto &pos2 = data[2].v.screenpos, &pos3 = data[3].v.screenpos;
if (pos0.x == pos3.x && pos1.x == pos2.x && pos0.y == pos1.y && pos3.y == pos2.y) {
// Looking like yes. Set TL/BR based on y order first...
*tlIndex = pos0.y > pos3.y ? 2 : 0;
*brIndex = pos0.y > pos3.y ? 0 : 2;
// And if it's horizontally flipped, trade to the actual TL/BR.
if (pos0.x > pos1.x) {
*tlIndex ^= 1;
*brIndex ^= 1;
}
*tlIndex = tl;
*brIndex = br;

// Do we need to think about rotation?
if (!state.enableTextures)
return true;
int tr = 1, bl = 1;
for (int i = 0; i < 4; ++i) {
if (i == tl || i == br)
continue;

const auto &textl = data[*tlIndex].v.texturecoords, &textr = data[*tlIndex ^ 1].v.texturecoords;
const auto &texbl = data[*brIndex ^ 1].v.texturecoords, &texbr = data[*brIndex].v.texturecoords;
if (data[i].v.screenpos.x <= data[tl].v.screenpos.x && data[i].v.screenpos.y >= data[tl].v.screenpos.y)
bl = i;
if (data[i].v.screenpos.x >= data[br].v.screenpos.x && data[i].v.screenpos.y <= data[br].v.screenpos.y)
tr = i;
}

if (textl.x == texbl.x && textr.x == texbr.x && textl.y == textr.y && texbl.y == texbr.y) {
// Okay, the texture is also good, but let's avoid rotation issues.
const auto &postl = data[*tlIndex].v.screenpos;
const auto &posbr = data[*brIndex].v.screenpos;
return textl.y < texbr.y && postl.y < posbr.y && textl.x < texbr.x && postl.x < posbr.x;
}
// Must have found each of the coordinates.
if (tl + tr + bl + br != 6)
return false;

// Note the common case is a single TL-TR-BR-BL.
const auto &postl = data[tl].v.screenpos, &postr = data[tr].v.screenpos;
const auto &posbr = data[br].v.screenpos, &posbl = data[bl].v.screenpos;
if (postl.x == posbl.x && postr.x == posbr.x && postl.y == postr.y && posbl.y == posbr.y) {
// Do we need to think about rotation?
if (!state.enableTextures)
return true;

const auto &textl = data[tl].v.texturecoords, &textr = data[tr].v.texturecoords;
const auto &texbl = data[bl].v.texturecoords, &texbr = data[br].v.texturecoords;

if (textl.x == texbl.x && textr.x == texbr.x && textl.y == textr.y && texbl.y == texbr.y) {
// Okay, the texture is also good, but let's avoid rotation issues.
return textl.y < texbr.y && postl.y < posbr.y && textl.x < texbr.x && postl.x < posbr.x;
}
}

Expand Down
2 changes: 1 addition & 1 deletion GPU/Software/RasterizerRectangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace Rasterizer {
void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state);

bool DetectRectangleFromStrip(const RasterizerState &state, const ClipVertexData data[4], int *tlIndex, int *brIndex);
bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int c, int *tlIndex, int *brIndex);
bool DetectRectangleFromFan(const RasterizerState &state, const ClipVertexData *data, int *tlIndex, int *brIndex);
bool DetectRectangleFromPair(const RasterizerState &state, const ClipVertexData data[6], int *tlIndex, int *brIndex);
bool DetectRectangleThroughModeSlices(const RasterizerState &state, const ClipVertexData data[4]);
}
2 changes: 1 addition & 1 deletion GPU/Software/TransformUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ void TransformUnit::SubmitPrimitive(const void* vertices, const void* indices, G
}

int tl = -1, br = -1;
if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, vertex_count, &tl, &br)) {
if (Rasterizer::DetectRectangleFromFan(binner_->State(), data_, &tl, &br)) {
Clipper::ProcessRect(data_[tl], data_[br], *binner_);
break;
}
Expand Down