Skip to content

Commit

Permalink
Merge pull request #15998 from unknownbrackets/softgpu-rect
Browse files Browse the repository at this point in the history
softgpu: Allow almost flat rectangles to go fast
  • Loading branch information
hrydgard authored Sep 11, 2022
2 parents d011768 + f5f5c9e commit 04c0234
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 39 deletions.
2 changes: 1 addition & 1 deletion GPU/GeDisasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) {
{
int w = 1 << (data & 0xf);
int h = 1 << ((data>>8) & 0xf);
if ((data & ~0x0F0F) && w <= 512 && h <= 512)
if ((data & ~0x0F0F) == 0 && w <= 512 && h <= 512)
snprintf(buffer, bufsize, "Texture size %d: %dx%d", cmd - GE_CMD_TEXSIZE0, w, h);
else
snprintf(buffer, bufsize, "Texture size %d: %dx%d (extra %06x)", cmd - GE_CMD_TEXSIZE0, w, h, data);
Expand Down
76 changes: 39 additions & 37 deletions GPU/Software/RasterizerRectangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,26 +321,40 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b
return false;
}

bool DetectRectangleFromStrip(const RasterizerState &state, const VertexData data[4], int *tlIndex, int *brIndex) {
// Color and Z must be flat. Also find the TL and BR meanwhile.
int tl = 0, br = 0;
for (int i = 1; i < 4; ++i) {
if (!(data[i].color0 == data[0].color0))
static bool AreCoordsRectangleCompatible(const RasterizerState &state, const VertexData &data0, const VertexData &data1) {
if (!(data1.color0 == data0.color0))
return false;
if (!(data1.screenpos.z == data0.screenpos.z)) {
// Sometimes, we don't actually care about z.
if (state.pixelID.depthWrite || state.pixelID.DepthTestFunc() != GE_COMP_ALWAYS)
return false;
if (!(data[i].screenpos.z == data[0].screenpos.z)) {
// Sometimes, we don't actually care about z.
if (state.pixelID.depthWrite || state.pixelID.DepthTestFunc() != GE_COMP_ALWAYS)
}
if (!state.throughMode) {
if (!state.throughMode && !(data1.color1 == data0.color1))
return false;
// Do we have to think about perspective correction or slope mip level?
if (state.enableTextures && data1.clippos.w != data0.clippos.w) {
// If the w is off by less than a factor of 1/512, it should be safe to treat as a rectangle.
static constexpr float halftexel = 0.5f / 512.0f;
if (data1.clippos.w - halftexel > data0.clippos.w || data1.clippos.w + halftexel < data0.clippos.w)
return false;
}
if (!state.throughMode) {
if (!state.throughMode && !(data[i].color1 == data[0].color1))
return false;
// Do we have to think about perspective correction or slope mip level?
if (state.enableTextures && data[i].clippos.w != data[0].clippos.w)
return false;
if (state.pixelID.applyFog && data[i].fogdepth != data[0].fogdepth)
if (state.pixelID.applyFog && data1.fogdepth != data0.fogdepth) {
// Similar to w, this only matters if they're farther apart than 1/255.
static constexpr float foghalfstep = 0.5f / 255.0f;
if (data1.fogdepth - foghalfstep > data0.fogdepth || data1.fogdepth + foghalfstep < data0.fogdepth)
return false;
}
}
return true;
}

bool DetectRectangleFromStrip(const RasterizerState &state, const VertexData data[4], int *tlIndex, int *brIndex) {
// Color and Z must be flat. Also find the TL and BR meanwhile.
int tl = 0, br = 0;
for (int i = 1; i < 4; ++i) {
if (!AreCoordsRectangleCompatible(state, data[i], data[0]))
return false;

if (data[i].screenpos.x <= data[tl].screenpos.x && data[i].screenpos.y <= data[tl].screenpos.y)
tl = i;
Expand Down Expand Up @@ -394,34 +408,20 @@ bool DetectRectangleFromStrip(const RasterizerState &state, const VertexData dat
bool DetectRectangleFromFan(const RasterizerState &state, const VertexData *data, int c, int *tlIndex, int *brIndex) {
// Color and Z must be flat.
for (int i = 1; i < c; ++i) {
if (!(data[i].color0 == data[0].color0))
if (!AreCoordsRectangleCompatible(state, data[i], data[0]))
return false;
if (!(data[i].screenpos.z == data[0].screenpos.z)) {
// Sometimes, we don't actually care about z.
if (state.pixelID.depthWrite || state.pixelID.DepthTestFunc() != GE_COMP_ALWAYS)
return false;
}
if (!state.throughMode) {
if (!state.throughMode && !(data[i].color1 == data[0].color1))
return false;
// Do we have to think about perspective correction or slope mip level?
if (state.enableTextures && data[i].clippos.w != data[0].clippos.w)
return false;
if (state.pixelID.applyFog && data[i].fogdepth != data[0].fogdepth)
return false;
}
}

// Check for the common case: a single TL-TR-BR-BL.
if (c == 4) {
const auto &tl = data[0].screenpos, &tr = data[1].screenpos;
const auto &bl = data[3].screenpos, &br = data[2].screenpos;
if (tl.x == bl.x && tr.x == br.x && tl.y == tr.y && bl.y == br.y) {
const auto &pos0 = data[0].screenpos, &pos1 = data[1].screenpos;
const auto &pos2 = data[2].screenpos, &pos3 = data[3].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 = tl.y > bl.y ? 2 : 0;
*brIndex = tl.y > bl.y ? 0 : 2;
*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 (tl.x > tr.x) {
if (pos0.x > pos1.x) {
*tlIndex ^= 1;
*brIndex ^= 1;
}
Expand All @@ -435,7 +435,9 @@ bool DetectRectangleFromFan(const RasterizerState &state, const VertexData *data

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 && textl.x < texbr.x;
const auto &postl = data[*tlIndex].screenpos;
const auto &posbr = data[*brIndex].screenpos;
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/SoftGpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ void SoftGPU::Execute_Prim(u32 op, u32 diff) {
return;
}

const void *verts = Memory::GetPointer(gstate_c.vertexAddr);
const void *verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr);
const void *indices = NULL;
if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
if (!Memory::IsValidAddress(gstate_c.indexAddr)) {
Expand Down

0 comments on commit 04c0234

Please sign in to comment.