mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 15:00:30 +02:00
SoftGPU: Fewer address and plane computations per textured pixel
A texel's byte offset is a sum of one for its row and one for its column, swizzled or not, so the four texels of a bilinear sample now take two of each, and the CLUT offset of a mip level is found once per sample. The UV planes at a quad's four pixels are one sum plus steps, as for depth. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
3b26ba54ba
commit
8c7d600b74
2 files changed
+83
-32
No files matched your search
@@ -1211,10 +1211,23 @@ static inline Vec4<float> LodQFromPlanes(const UVPlanes &planes, int64_t centerX
|
||||
return q;
|
||||
}
|
||||
|
||||
// A plane's values at a quad's four pixel centers: a pixel's step adds k * 16 to the sum before the shift.
|
||||
static inline void PlaneQuad(const DepthPlane &plane, int64_t centerX, int64_t centerY, int64_t out[4]) {
|
||||
const int64_t v = plane.base + plane.kx * centerX + plane.ky * centerY;
|
||||
const int64_t dx = plane.kx * SCREEN_SCALE_FACTOR, dy = plane.ky * SCREEN_SCALE_FACTOR;
|
||||
out[0] = v >> 14;
|
||||
out[1] = (v + dx) >> 14;
|
||||
out[2] = (v + dy) >> 14;
|
||||
out[3] = (v + dx + dy) >> 14;
|
||||
}
|
||||
|
||||
static inline void GetTextureCoordinatesGE(const UVPlanes &planes, int64_t centerX, int64_t centerY, Vec4<float> &s, Vec4<float> &t, Vec4<float> &qOut) {
|
||||
int64_t qs[4], ss[4], ts[4];
|
||||
PlaneQuad(planes.q, centerX, centerY, qs);
|
||||
PlaneQuad(planes.s, centerX, centerY, ss);
|
||||
PlaneQuad(planes.t, centerX, centerY, ts);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
const int64_t x = centerX + (i & 1) * SCREEN_SCALE_FACTOR, y = centerY + (i >> 1) * SCREEN_SCALE_FACTOR;
|
||||
const float q = TruncateToFloat24((float)((double)planes.q.At(x, y) * planes.scaleQ));
|
||||
const float q = TruncateToFloat24((float)((double)qs[i] * planes.scaleQ));
|
||||
qOut[i] = q;
|
||||
if (!(q > 0.0f)) {
|
||||
s[i] = 0.0f;
|
||||
@@ -1222,8 +1235,8 @@ static inline void GetTextureCoordinatesGE(const UVPlanes &planes, int64_t cente
|
||||
continue;
|
||||
}
|
||||
const double r = GERecip(q);
|
||||
s[i] = GEUVProduct((double)TruncateToFloat24((float)((double)planes.s.At(x, y) * planes.scaleS)) * r);
|
||||
t[i] = GEUVProduct((double)TruncateToFloat24((float)((double)planes.t.At(x, y) * planes.scaleT)) * r);
|
||||
s[i] = GEUVProduct((double)TruncateToFloat24((float)((double)ss[i] * planes.scaleS)) * r);
|
||||
t[i] = GEUVProduct((double)TruncateToFloat24((float)((double)ts[i] * planes.scaleT)) * r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+66
-28
@@ -800,9 +800,7 @@ static inline uint64_t LerpSpread(uint64_t a, uint64_t b, int f) {
|
||||
}
|
||||
|
||||
template <GEPaletteFormat clutFmt>
|
||||
static inline uint32_t LookupClutT(uint32_t index, int level, const SamplerID &samplerID, bool clut4) {
|
||||
if (!samplerID.useSharedClut)
|
||||
index += clut4 ? level * 16 : (level & 1) * 256;
|
||||
static inline uint32_t LookupClutT(uint32_t index, const SamplerID &samplerID) {
|
||||
switch (clutFmt) {
|
||||
case GE_CMODE_16BIT_BGR5650: return RGB565ToRGBA8888(samplerID.cached.clut16[index]);
|
||||
case GE_CMODE_16BIT_ABGR5551: return RGBA5551ToRGBA8888(samplerID.cached.clut16[index]);
|
||||
@@ -811,32 +809,54 @@ static inline uint32_t LookupClutT(uint32_t index, int level, const SamplerID &s
|
||||
}
|
||||
}
|
||||
|
||||
template <GETextureFormat fmt, bool swizzled, GEPaletteFormat clutFmt>
|
||||
static inline uint32_t ReadTexelT(const u8 *src, int bufw, int u, int v, int level, const SamplerID &samplerID) {
|
||||
template <GETextureFormat fmt>
|
||||
static constexpr uint32_t TexelBitsT() {
|
||||
switch (fmt) {
|
||||
case GE_TFMT_4444: return RGBA4444ToRGBA8888(*(const u16 *)(src + GetPixelDataOffset<16>(bufw, u, v, swizzled)));
|
||||
case GE_TFMT_5551: return RGBA5551ToRGBA8888(*(const u16 *)(src + GetPixelDataOffset<16>(bufw, u, v, swizzled)));
|
||||
case GE_TFMT_5650: return RGB565ToRGBA8888(*(const u16 *)(src + GetPixelDataOffset<16>(bufw, u, v, swizzled)));
|
||||
case GE_TFMT_8888: return *(const u32 *)(src + GetPixelDataOffset<32>(bufw, u, v, swizzled));
|
||||
case GE_TFMT_CLUT32: {
|
||||
const u8 *p = src + GetPixelDataOffset<32>(bufw, u, v, swizzled);
|
||||
const u32 val = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
|
||||
return LookupClutT<clutFmt>(TransformClutIndex(val, samplerID), 0, samplerID, false);
|
||||
case GE_TFMT_8888: case GE_TFMT_CLUT32: return 32;
|
||||
case GE_TFMT_CLUT8: return 8;
|
||||
case GE_TFMT_CLUT4: return 4;
|
||||
default: return 16;
|
||||
}
|
||||
case GE_TFMT_CLUT16: {
|
||||
const u8 *p = src + GetPixelDataOffset<16>(bufw, u, v, swizzled);
|
||||
return LookupClutT<clutFmt>(TransformClutIndex(p[0] + (p[1] << 8), samplerID), 0, samplerID, false);
|
||||
}
|
||||
case GE_TFMT_CLUT8:
|
||||
return LookupClutT<clutFmt>(TransformClutIndex(src[GetPixelDataOffset<8>(bufw, u, v, swizzled)], samplerID), level, samplerID, false);
|
||||
case GE_TFMT_CLUT4: {
|
||||
const u8 b = src[GetPixelDataOffset<4>(bufw, u, v, swizzled)];
|
||||
return LookupClutT<clutFmt>(TransformClutIndex((u & 1) ? (b >> 4) : (b & 0xF), samplerID), level, samplerID, true);
|
||||
}
|
||||
|
||||
// A texel's byte offset is the sum of one for its row and one for its column (as GetPixelDataOffset), so
|
||||
// the four texels of a bilinear sample only need two of each.
|
||||
template <uint32_t bits, bool swizzled>
|
||||
static inline uint32_t RowOffsetT(int bufw, int v) {
|
||||
if (!swizzled)
|
||||
return v * (bufw * bits >> 3);
|
||||
// Blocks of 16 bytes by 8 rows.
|
||||
return (v >> 3) * ((bufw * bits / 32) * 32) + (v & 7) * 16;
|
||||
}
|
||||
|
||||
template <uint32_t bits, bool swizzled>
|
||||
static inline uint32_t ColumnOffsetT(int u) {
|
||||
const uint32_t b = u * bits >> 3;
|
||||
return swizzled ? (b >> 4) * 128 + (b & 15) : b;
|
||||
}
|
||||
|
||||
// The texel at p (u picks the nibble of CLUT4). clutOffset is where the level's palette starts.
|
||||
template <GETextureFormat fmt, GEPaletteFormat clutFmt>
|
||||
static inline uint32_t ReadTexelT(const u8 *p, int u, uint32_t clutOffset, const SamplerID &samplerID) {
|
||||
switch (fmt) {
|
||||
case GE_TFMT_4444: return RGBA4444ToRGBA8888(*(const u16 *)p);
|
||||
case GE_TFMT_5551: return RGBA5551ToRGBA8888(*(const u16 *)p);
|
||||
case GE_TFMT_5650: return RGB565ToRGBA8888(*(const u16 *)p);
|
||||
case GE_TFMT_8888: return *(const u32 *)p;
|
||||
case GE_TFMT_CLUT32: return LookupClutT<clutFmt>(TransformClutIndex(p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24), samplerID) + clutOffset, samplerID);
|
||||
case GE_TFMT_CLUT16: return LookupClutT<clutFmt>(TransformClutIndex(p[0] + (p[1] << 8), samplerID) + clutOffset, samplerID);
|
||||
case GE_TFMT_CLUT8: return LookupClutT<clutFmt>(TransformClutIndex(*p, samplerID) + clutOffset, samplerID);
|
||||
case GE_TFMT_CLUT4: return LookupClutT<clutFmt>(TransformClutIndex((u & 1) ? (*p >> 4) : (*p & 0xF), samplerID) + clutOffset, samplerID);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <GETextureFormat fmt>
|
||||
static inline uint32_t ReadDXTTexelT(const u8 *src, int bufw, int u, int v) {
|
||||
switch (fmt) {
|
||||
case GE_TFMT_DXT1: return GetDXT1Texel((const DXT1Block *)src + (v >> 2) * (bufw >> 2) + (u >> 2), u & 3, v & 3);
|
||||
case GE_TFMT_DXT3: return GetDXT3Texel((const DXT3Block *)src + (v >> 2) * (bufw >> 2) + (u >> 2), u & 3, v & 3);
|
||||
case GE_TFMT_DXT5: return GetDXT5Texel((const DXT5Block *)src + (v >> 2) * (bufw >> 2) + (u >> 2), u & 3, v & 3);
|
||||
default: return 0;
|
||||
default: return GetDXT5Texel((const DXT5Block *)src + (v >> 2) * (bufw >> 2) + (u >> 2), u & 3, v & 3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,10 +883,28 @@ static inline uint64_t SampleLinearLevelT(float s, float t, const u8 *tptr, int
|
||||
int u0, u1, v0, v1, fracU, fracV;
|
||||
TexelPairT(s, samplerID.cached.sizes[level].w, samplerID.clampS, u0, u1, fracU);
|
||||
TexelPairT(t, samplerID.cached.sizes[level].h, samplerID.clampT, v0, v1, fracV);
|
||||
const uint64_t tl = SpreadRGBA(ReadTexelT<fmt, swizzled, clutFmt>(tptr, bufw, u0, v0, level, samplerID));
|
||||
const uint64_t tr = SpreadRGBA(ReadTexelT<fmt, swizzled, clutFmt>(tptr, bufw, u1, v0, level, samplerID));
|
||||
const uint64_t bl = SpreadRGBA(ReadTexelT<fmt, swizzled, clutFmt>(tptr, bufw, u0, v1, level, samplerID));
|
||||
const uint64_t br = SpreadRGBA(ReadTexelT<fmt, swizzled, clutFmt>(tptr, bufw, u1, v1, level, samplerID));
|
||||
uint64_t tl, tr, bl, br;
|
||||
if constexpr (fmt == GE_TFMT_DXT1 || fmt == GE_TFMT_DXT3 || fmt == GE_TFMT_DXT5) {
|
||||
tl = SpreadRGBA(ReadDXTTexelT<fmt>(tptr, bufw, u0, v0));
|
||||
tr = SpreadRGBA(ReadDXTTexelT<fmt>(tptr, bufw, u1, v0));
|
||||
bl = SpreadRGBA(ReadDXTTexelT<fmt>(tptr, bufw, u0, v1));
|
||||
br = SpreadRGBA(ReadDXTTexelT<fmt>(tptr, bufw, u1, v1));
|
||||
} else {
|
||||
constexpr uint32_t bits = TexelBitsT<fmt>();
|
||||
// Levels past the first have their own palette unless it's shared: 16 entries on for CLUT4, 256 on for
|
||||
// CLUT8 at odd levels.
|
||||
uint32_t clutOffset = 0;
|
||||
if ((fmt == GE_TFMT_CLUT4 || fmt == GE_TFMT_CLUT8) && !samplerID.useSharedClut)
|
||||
clutOffset = fmt == GE_TFMT_CLUT4 ? level * 16 : (level & 1) * 256;
|
||||
const u8 *row0 = tptr + RowOffsetT<bits, swizzled>(bufw, v0);
|
||||
const u8 *row1 = tptr + RowOffsetT<bits, swizzled>(bufw, v1);
|
||||
const uint32_t col0 = ColumnOffsetT<bits, swizzled>(u0);
|
||||
const uint32_t col1 = ColumnOffsetT<bits, swizzled>(u1);
|
||||
tl = SpreadRGBA(ReadTexelT<fmt, clutFmt>(row0 + col0, u0, clutOffset, samplerID));
|
||||
tr = SpreadRGBA(ReadTexelT<fmt, clutFmt>(row0 + col1, u1, clutOffset, samplerID));
|
||||
bl = SpreadRGBA(ReadTexelT<fmt, clutFmt>(row1 + col0, u0, clutOffset, samplerID));
|
||||
br = SpreadRGBA(ReadTexelT<fmt, clutFmt>(row1 + col1, u1, clutOffset, samplerID));
|
||||
}
|
||||
// Like the GE: horizontal lerps truncated to 8 bits, then the vertical one (gpu/probe exp52).
|
||||
return LerpSpread(LerpSpread(tl, tr, fracU), LerpSpread(bl, br, fracU), fracV);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user