mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
softgpu: Correctly fix inversions, matching tests.
Inversions are allowed just fine, but if clipping results in coordinates outside range, the triangle should be culled. Fixes more wanted inversions.
This commit is contained in:
parent
b62790fd00
commit
dc962094f8
3 changed files with 19 additions and 23 deletions
|
@ -50,16 +50,15 @@ inline float clip_dotprod(const ClipVertexData &vert, float A, float B, float C,
|
|||
}
|
||||
|
||||
inline void clip_interpolate(ClipVertexData &dest, float t, const ClipVertexData &a, const ClipVertexData &b) {
|
||||
if (different_signs(a.clippos.w, b.clippos.w)) {
|
||||
if (a.clippos.w < -1.0f || b.clippos.w < -1.0f) {
|
||||
dest.v.screenpos.x = 0x7FFFFFFF;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool outsideRange = false;
|
||||
dest.Lerp(t, a, b);
|
||||
dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos);
|
||||
dest.v.screenpos = TransformUnit::ClipToScreen(dest.clippos, &outsideRange);
|
||||
dest.v.clipw = dest.clippos.w;
|
||||
|
||||
// If the clipped coordinate is outside range, then we throw it away.
|
||||
// This prevents a lot of inversions that shouldn't be drawn.
|
||||
if (outsideRange)
|
||||
dest.v.screenpos.x = 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
#define CLIP_POLY( PLANE_BIT, A, B, C, D ) \
|
||||
|
|
|
@ -162,7 +162,7 @@ ClipCoords TransformUnit::ViewToClip(const ViewCoords &coords) {
|
|||
return Vec3ByMatrix44(coords, gstate.projMatrix);
|
||||
}
|
||||
|
||||
template <bool depthClamp, bool writeOutsideFlag>
|
||||
template <bool depthClamp, bool alwaysCheckRange>
|
||||
static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, bool *outside_range_flag) {
|
||||
ScreenCoords ret;
|
||||
|
||||
|
@ -173,7 +173,7 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords,
|
|||
// This matches hardware tests - depth is clamped when this flag is on.
|
||||
if (depthClamp) {
|
||||
// Note: if the depth is clipped (z/w <= -1.0), the outside_range_flag should NOT be set, even for x and y.
|
||||
if (writeOutsideFlag && coords.z > -coords.w && (scaled.x >= SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) {
|
||||
if ((alwaysCheckRange || coords.z > -coords.w) && (scaled.x >= SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) {
|
||||
*outside_range_flag = true;
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords,
|
|||
scaled.z = 0.f;
|
||||
else if (scaled.z > 65535.0f)
|
||||
scaled.z = 65535.0f;
|
||||
} else if (writeOutsideFlag && (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0)) {
|
||||
} else if (scaled.x > SCREEN_BOUND || scaled.y >= SCREEN_BOUND || scaled.x < 0 || scaled.y < 0) {
|
||||
*outside_range_flag = true;
|
||||
}
|
||||
|
||||
|
@ -209,17 +209,13 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords &coords, bool *
|
|||
float z = coords.z * zScale / coords.w + zCenter;
|
||||
|
||||
if (gstate.isDepthClampEnabled()) {
|
||||
if (outside_range_flag)
|
||||
return ClipToScreenInternal<true, true>(Vec3f(x, y, z), coords, outside_range_flag);
|
||||
return ClipToScreenInternal<true, false>(Vec3f(x, y, z), coords, outside_range_flag);
|
||||
return ClipToScreenInternal<true, true>(Vec3f(x, y, z), coords, outside_range_flag);
|
||||
}
|
||||
if (outside_range_flag)
|
||||
return ClipToScreenInternal<false, true>(Vec3f(x, y, z), coords, outside_range_flag);
|
||||
return ClipToScreenInternal<false, false>(Vec3f(x, y, z), coords, outside_range_flag);
|
||||
return ClipToScreenInternal<false, true>(Vec3f(x, y, z), coords, outside_range_flag);
|
||||
}
|
||||
|
||||
ScreenCoords TransformUnit::ClipToScreen(const ClipCoords &coords) {
|
||||
return ClipToScreenInternal(coords, nullptr);
|
||||
ScreenCoords TransformUnit::ClipToScreen(const ClipCoords &coords, bool *outsideRangeFlag) {
|
||||
return ClipToScreenInternal(coords, outsideRangeFlag);
|
||||
}
|
||||
|
||||
ScreenCoords TransformUnit::DrawingToScreen(const DrawingCoords &coords, u16 z) {
|
||||
|
@ -317,9 +313,9 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) {
|
|||
}
|
||||
|
||||
if (gstate.isDepthClampEnabled())
|
||||
state->roundToScreen = &ClipToScreenInternal<true, true>;
|
||||
state->roundToScreen = &ClipToScreenInternal<true, false>;
|
||||
else
|
||||
state->roundToScreen = &ClipToScreenInternal<false, true>;
|
||||
state->roundToScreen = &ClipToScreenInternal<false, false>;
|
||||
}
|
||||
|
||||
ClipVertexData TransformUnit::ReadVertex(VertexReader &vreader, const TransformState &state) {
|
||||
|
@ -977,7 +973,8 @@ bool TransformUnit::GetCurrentSimpleVertices(int count, std::vector<GPUDebugVert
|
|||
vertices[i].z = vert.pos.z;
|
||||
} else {
|
||||
Vec4f clipPos = Vec3ByMatrix44(vert.pos, worldviewproj);
|
||||
ScreenCoords screenPos = ClipToScreen(clipPos);
|
||||
bool outsideRangeFlag;
|
||||
ScreenCoords screenPos = ClipToScreen(clipPos, &outsideRangeFlag);
|
||||
float z = clipPos.z * zScale / clipPos.w + zCenter;
|
||||
|
||||
if (gstate.vertType & GE_VTYPE_TC_MASK) {
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
static WorldCoords ModelToWorld(const ModelCoords& coords);
|
||||
static ViewCoords WorldToView(const WorldCoords& coords);
|
||||
static ClipCoords ViewToClip(const ViewCoords& coords);
|
||||
static ScreenCoords ClipToScreen(const ClipCoords& coords);
|
||||
static ScreenCoords ClipToScreen(const ClipCoords &coords, bool *outsideRangeFlag);
|
||||
static inline DrawingCoords ScreenToDrawing(int x, int y) {
|
||||
DrawingCoords ret;
|
||||
// When offset > coord, this is negative and force-scissors.
|
||||
|
|
Loading…
Add table
Reference in a new issue