Files
ppsspp/GPU/Common/SoftwareTransformCommon.h
T
Henrik RydgårdandClaude Opus 5.5 7c5eda25f4 Software transform clipping: split clipped quads like the GE, cull beyond far first
With one vertex behind the near plane, the GE splits the remaining quad from
the vertex before the clipped one (gpu/probe exp43, exp44, as in SoftGPU's
Clipper.cpp). The other diagonal could put a far off-screen near-plane vertex
in both halves, so range culling dropped the whole triangle: the floor in
#16131's box test vanished. The index generator reverses triangles to flip
culling, so the batch's order is passed along.

Triangles entirely beyond the far plane are now culled even when in front of
the near plane, with the cull-distance epsilon, so z/w = 1.0000172 (exactly
1.0 to the GE) still counts as inside.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 16:16:24 +02:00

90 lines
3.6 KiB
C++

// Copyright (c) 2013- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/Math/lin/matrix4x4.h"
#include "GPU/Common/VertexDecoderCommon.h"
#include "GPU/Common/TransformCommon.h"
#include "GPU/GPUCommon.h"
class FramebufferManagerCommon;
class TextureCacheCommon;
enum SoftwareTransformAction {
SW_DRAW_INDEXED,
SW_CLEAR,
SW_CULLED, // don't draw
};
struct TransformStats {
u16 culledTrianglesNear;
u16 culledTrianglesFar;
u16 clippedTriangles; // Only near plane is clipped against
};
struct SoftwareTransformResult {
u32 color;
float depth;
bool setStencil;
u8 stencilValue;
TransformedVertex *drawBuffer;
int drawVertexCount;
int drawIndexCount;
bool pixelMapped;
TransformStats stats;
};
struct SoftwareTransformParams {
u8 *decoded;
TransformedVertex *transformed;
TransformedVertex *transformedExpanded;
ClipInfoFlags clipInfoFlags;
bool allowClear;
bool allowSeparateAlphaClear;
bool everUsedEqualDepth;
float pointScale = 1.0f; // Useful to increase these for debug views of bounding box corners.
// The index generator reversed every triangle (to flip the winding for culling), so they're not in the GE's order.
bool trianglesReversed = false;
};
// Converts an index buffer to make the provoking vertex the last.
// In-place. So, better not be doing this on GPU memory!
// TODO: We could do this already during index decode.
void IndexBufferProvokingLastToFirst(int prim, u16 *inds, int indsSize);
// indsSize is in indices, not bytes.
// NOTE: In case of clipping, this might write extra vertices after params.transformed.
// NOTE: Does not handle line strips, triangle strips or triangle fans - generate indices for those beforehand.
// NOTE2: The output is ALWAYS an indexed triangle list, no matter the input primitive.
SoftwareTransformAction RunSoftwareTransform(SoftwareTransformParams &params, int prim, u32 vertexType, const DecVtxFormat &decVtxFormat, int numDecodedVerts, int vertsSize, int vertexCount, u16 *&inds, int indsSize, SoftwareTransformResult *result);
class DrawEngineCommon;
// Slow. See description in the cpp file.
u32 NormalizeVertices(SimpleVertex *sverts, u8 *bufPtr, const u8 *inPtr, int lowerBound, int upperBound, const UVScale &uvScale, const VertexDecoder *dec, u32 vertType);
// In the returned data, you should subtract the value of lowerIndexBound from the indices to get the actual vertex index in the vertices array.
// This is because some draws in some games use very large indices, but they only use a small range of them in each PRIM submission.
// Additionally, if the transformed flag is set in flags, the indices will be transformed into "generic" types (triangles instead of strips), etc.
bool GetCurrentDrawAsDebugVertices(DrawEngineCommon *drawEngine, GECommand cmd, GEPrimitiveType prim, GEPrimitiveType *outPrim, int count, std::vector<GPUDebugVertex> *vertices, std::vector<u16> *indices, int *lowerIndexBound, TransformStats *stats, DebugVertexFlags flags);