Merge pull request #15200 from unknownbrackets/softjit-sampler

Use vectorcall and regcache in samplerjit (software renderer)
This commit is contained in:
Henrik Rydgård
2021-12-05 09:34:15 +01:00
committed by GitHub
8 changed files with 681 additions and 398 deletions
+91 -126
View File
@@ -205,60 +205,35 @@ static inline void GetTexelCoordinatesQuad(int level, float in_s, float in_t, in
}
static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& v1, const float p, float &s, float &t) {
switch (gstate.getUVGenMode()) {
case GE_TEXMAP_TEXTURE_COORDS:
case GE_TEXMAP_UNKNOWN:
case GE_TEXMAP_ENVIRONMENT_MAP:
case GE_TEXMAP_TEXTURE_MATRIX:
{
// TODO: What happens if vertex has no texture coordinates?
// Note that for environment mapping, texture coordinates have been calculated during lighting
float q0 = 1.f / v0.clippos.w;
float q1 = 1.f / v1.clippos.w;
float wq0 = p * q0;
float wq1 = (1.0f - p) * q1;
// All UV gen modes, by the time they get here, behave the same.
float q_recip = 1.0f / (wq0 + wq1);
s = (v0.texturecoords.s() * wq0 + v1.texturecoords.s() * wq1) * q_recip;
t = (v0.texturecoords.t() * wq0 + v1.texturecoords.t() * wq1) * q_recip;
}
break;
default:
ERROR_LOG_REPORT(G3D, "Software: Unsupported texture mapping mode %x!", gstate.getUVGenMode());
s = 0.0f;
t = 0.0f;
break;
}
// TODO: What happens if vertex has no texture coordinates?
// Note that for environment mapping, texture coordinates have been calculated during lighting
float q0 = 1.f / v0.clippos.w;
float q1 = 1.f / v1.clippos.w;
float wq0 = p * q0;
float wq1 = (1.0f - p) * q1;
float q_recip = 1.0f / (wq0 + wq1);
s = (v0.texturecoords.s() * wq0 + v1.texturecoords.s() * wq1) * q_recip;
t = (v0.texturecoords.t() * wq0 + v1.texturecoords.t() * wq1) * q_recip;
}
static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& v1, const VertexData& v2, const Vec4<int> &w0, const Vec4<int> &w1, const Vec4<int> &w2, const Vec4<float> &wsum_recip, Vec4<float> &s, Vec4<float> &t)
{
switch (gstate.getUVGenMode()) {
case GE_TEXMAP_TEXTURE_COORDS:
case GE_TEXMAP_UNKNOWN:
case GE_TEXMAP_ENVIRONMENT_MAP:
case GE_TEXMAP_TEXTURE_MATRIX:
{
// TODO: What happens if vertex has no texture coordinates?
// Note that for environment mapping, texture coordinates have been calculated during lighting
float q0 = 1.f / v0.clippos.w;
float q1 = 1.f / v1.clippos.w;
float q2 = 1.f / v2.clippos.w;
Vec4<float> wq0 = w0.Cast<float>() * q0;
Vec4<float> wq1 = w1.Cast<float>() * q1;
Vec4<float> wq2 = w2.Cast<float>() * q2;
static inline void GetTextureCoordinates(const VertexData &v0, const VertexData &v1, const VertexData &v2, const Vec4<int> &w0, const Vec4<int> &w1, const Vec4<int> &w2, const Vec4<float> &wsum_recip, Vec4<float> &s, Vec4<float> &t) {
// All UV gen modes, by the time they get here, behave the same.
Vec4<float> q_recip = (wq0 + wq1 + wq2).Reciprocal();
s = Interpolate(v0.texturecoords.s(), v1.texturecoords.s(), v2.texturecoords.s(), wq0, wq1, wq2, q_recip);
t = Interpolate(v0.texturecoords.t(), v1.texturecoords.t(), v2.texturecoords.t(), wq0, wq1, wq2, q_recip);
}
break;
default:
ERROR_LOG_REPORT(G3D, "Software: Unsupported texture mapping mode %x!", gstate.getUVGenMode());
s = Vec4<float>::AssignToAll(0.0f);
t = Vec4<float>::AssignToAll(0.0f);
break;
}
// TODO: What happens if vertex has no texture coordinates?
// Note that for environment mapping, texture coordinates have been calculated during lighting.
float q0 = 1.f / v0.clippos.w;
float q1 = 1.f / v1.clippos.w;
float q2 = 1.f / v2.clippos.w;
Vec4<float> wq0 = w0.Cast<float>() * q0;
Vec4<float> wq1 = w1.Cast<float>() * q1;
Vec4<float> wq2 = w2.Cast<float>() * q2;
Vec4<float> q_recip = (wq0 + wq1 + wq2).Reciprocal();
s = Interpolate(v0.texturecoords.s(), v1.texturecoords.s(), v2.texturecoords.s(), wq0, wq1, wq2, q_recip);
t = Interpolate(v0.texturecoords.t(), v1.texturecoords.t(), v2.texturecoords.t(), wq0, wq1, wq2, q_recip);
}
static inline void SetPixelDepth(int x, int y, u16 value)
@@ -290,8 +265,10 @@ static inline bool IsRightSideOrFlatBottomLine(const Vec2<int>& vertex, const Ve
}
}
Vec4<int> GetTextureFunctionOutput(const Vec4<int>& prim_color, const Vec4<int>& texcolor)
{
Vec4IntResult SOFTRAST_CALL GetTextureFunctionOutput(Vec4IntArg prim_color_in, Vec4IntArg texcolor_in) {
const Vec4<int> prim_color = prim_color_in;
const Vec4<int> texcolor = texcolor_in;
Vec3<int> out_rgb;
int out_a;
@@ -314,7 +291,7 @@ Vec4<int> GetTextureFunctionOutput(const Vec4<int>& prim_color, const Vec4<int>&
}
if (rgba) {
return Vec4<int>(out_rgb.ivec);
return ToVec4IntResult(Vec4<int>(out_rgb.ivec));
} else {
out_a = prim_color.a();
}
@@ -366,7 +343,7 @@ Vec4<int> GetTextureFunctionOutput(const Vec4<int>& prim_color, const Vec4<int>&
out_a = 0;
}
return Vec4<int>(out_rgb.r(), out_rgb.g(), out_rgb.b(), out_a);
return ToVec4IntResult(Vec4<int>(out_rgb, out_a));
}
static inline Vec3<int> GetSourceFactor(GEBlendSrcFactor factor, const Vec4<int> &source, const Vec4<int> &dst) {
@@ -559,44 +536,45 @@ Vec3<int> AlphaBlendingResult(const PixelFuncID &pixelID, const Vec4<int> &sourc
}
}
static inline void ApplyTexturing(Sampler::Funcs sampler, Vec4<int> &prim_color, float s, float t, int texlevel, int frac_texlevel, bool bilinear, u8 *texptr[], int texbufw[]) {
template <bool mayHaveMipLevels>
static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(Sampler::Funcs sampler, Vec4IntArg prim_color, float s, float t, int texlevel, int frac_texlevel, bool bilinear, u8 *texptr[], int texbufw[]) {
int u[8] = {0}, v[8] = {0}; // 1.23.8 fixed point
int frac_u[2], frac_v[2];
Vec4<int> texcolor0;
Vec4<int> texcolor1;
const u8 *tptr0 = texptr[texlevel];
int bufw0 = texbufw[texlevel];
const u8 *tptr1 = texptr[texlevel + 1];
int bufw1 = texbufw[texlevel + 1];
const u8 *tptr0 = texptr[mayHaveMipLevels ? texlevel : 0];
int bufw0 = texbufw[mayHaveMipLevels ? texlevel : 0];
const u8 *tptr1 = texptr[mayHaveMipLevels ? texlevel + 1 : 0];
int bufw1 = texbufw[mayHaveMipLevels ? texlevel + 1 : 0];
if (!bilinear) {
// Nearest filtering only. Round texcoords.
GetTexelCoordinates(texlevel, s, t, u[0], v[0]);
if (frac_texlevel) {
GetTexelCoordinates(mayHaveMipLevels ? texlevel : 0, s, t, u[0], v[0]);
if (mayHaveMipLevels && frac_texlevel) {
GetTexelCoordinates(texlevel + 1, s, t, u[1], v[1]);
}
texcolor0 = Vec4<int>::FromRGBA(sampler.nearest(u[0], v[0], tptr0, bufw0, texlevel));
if (frac_texlevel) {
texcolor1 = Vec4<int>::FromRGBA(sampler.nearest(u[1], v[1], tptr1, bufw1, texlevel + 1));
texcolor0 = Vec4<int>(sampler.nearest(u[0], v[0], tptr0, bufw0, mayHaveMipLevels ? texlevel : 0));
if (mayHaveMipLevels && frac_texlevel) {
texcolor1 = Vec4<int>(sampler.nearest(u[1], v[1], tptr1, bufw1, texlevel + 1));
}
} else {
GetTexelCoordinatesQuad(texlevel, s, t, u, v, frac_u[0], frac_v[0]);
if (frac_texlevel) {
GetTexelCoordinatesQuad(mayHaveMipLevels ? texlevel : 0, s, t, u, v, frac_u[0], frac_v[0]);
if (mayHaveMipLevels && frac_texlevel) {
GetTexelCoordinatesQuad(texlevel + 1, s, t, u + 4, v + 4, frac_u[1], frac_v[1]);
}
texcolor0 = Vec4<int>::FromRGBA(sampler.linear(u, v, frac_u[0], frac_v[0], tptr0, bufw0, texlevel));
if (frac_texlevel) {
texcolor1 = Vec4<int>::FromRGBA(sampler.linear(u + 4, v + 4, frac_u[1], frac_v[1], tptr1, bufw1, texlevel + 1));
texcolor0 = Vec4<int>(sampler.linear(u, v, frac_u[0], frac_v[0], tptr0, bufw0, mayHaveMipLevels ? texlevel : 0));
if (mayHaveMipLevels && frac_texlevel) {
texcolor1 = Vec4<int>(sampler.linear(u + 4, v + 4, frac_u[1], frac_v[1], tptr1, bufw1, texlevel + 1));
}
}
if (frac_texlevel) {
if (mayHaveMipLevels && frac_texlevel) {
texcolor0 = (texcolor1 * frac_texlevel + texcolor0 * (256 - frac_texlevel)) / 256;
}
prim_color = GetTextureFunctionOutput(prim_color, texcolor0);
return GetTextureFunctionOutput(prim_color, ToVec4IntArg(texcolor0));
}
// Produces a signed 1.23.8 value.
@@ -614,6 +592,7 @@ static int TexLog2(float delta) {
return useful - 127 * 256;
}
template <bool mayHaveMipLevels>
static inline void CalculateSamplingParams(const float ds, const float dt, const int maxTexLevel, int &level, int &levelFrac, bool &filt) {
const int width = gstate.getTextureWidth(0);
const int height = gstate.getTextureHeight(0);
@@ -638,19 +617,21 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const
// Add in the bias (used in all modes), expanding to 8 bits of fraction.
detail += gstate.getTexLevelOffset16() << 4;
if (detail > 0 && maxTexLevel > 0) {
bool mipFilt = gstate.isMipmapFilteringEnabled();
if (mayHaveMipLevels) {
if (detail > 0 && maxTexLevel > 0) {
bool mipFilt = gstate.isMipmapFilteringEnabled();
int level8 = std::min(detail, maxTexLevel * 256);
if (!mipFilt) {
// Round up at 1.5.
level8 += 128;
int level8 = std::min(detail, maxTexLevel * 256);
if (!mipFilt) {
// Round up at 1.5.
level8 += 128;
}
level = level8 >> 8;
levelFrac = mipFilt ? level8 & 0xFF : 0;
} else {
level = 0;
levelFrac = 0;
}
level = level8 >> 8;
levelFrac = mipFilt ? level8 & 0xFF : 0;
} else {
level = 0;
levelFrac = 0;
}
if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) {
@@ -662,6 +643,7 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const
}
}
template <bool hasMipLevels>
static inline void ApplyTexturing(Sampler::Funcs sampler, Vec4<int> *prim_color, const Vec4<float> &s, const Vec4<float> &t, int maxTexLevel, u8 *texptr[], int texbufw[]) {
float ds = s[1] - s[0];
float dt = t[2] - t[0];
@@ -669,10 +651,10 @@ static inline void ApplyTexturing(Sampler::Funcs sampler, Vec4<int> *prim_color,
int level;
int levelFrac;
bool bilinear;
CalculateSamplingParams(ds, dt, maxTexLevel, level, levelFrac, bilinear);
CalculateSamplingParams<hasMipLevels>(ds, dt, maxTexLevel, level, levelFrac, bilinear);
for (int i = 0; i < 4; ++i) {
ApplyTexturing(sampler, prim_color[i], s[i], t[i], level, levelFrac, bilinear, texptr, texbufw);
prim_color[i] = ApplyTexturing<hasMipLevels>(sampler, ToVec4IntArg(prim_color[i]), s[i], t[i], level, levelFrac, bilinear, texptr, texbufw);
}
}
@@ -751,7 +733,7 @@ static inline Vec4<float> EdgeRecip(const Vec4<int> &w0, const Vec4<int> &w1, co
#endif
}
template <bool clearMode>
template <bool clearMode, bool hasMipLevels>
void DrawTriangleSlice(
const VertexData& v0, const VertexData& v1, const VertexData& v2,
int x1, int y1, int x2, int y2,
@@ -763,15 +745,10 @@ void DrawTriangleSlice(
Vec4<int> bias1 = Vec4<int>::AssignToAll(IsRightSideOrFlatBottomLine(v1.screenpos.xy(), v2.screenpos.xy(), v0.screenpos.xy()) ? -1 : 0);
Vec4<int> bias2 = Vec4<int>::AssignToAll(IsRightSideOrFlatBottomLine(v2.screenpos.xy(), v0.screenpos.xy(), v1.screenpos.xy()) ? -1 : 0);
int texbufw[8] = {0};
int texbufw[hasMipLevels ? 8 : 1] = {0};
int maxTexLevel = gstate.getTextureMaxLevel();
u8 *texptr[8] = {NULL};
if (!gstate.isMipmapEnabled()) {
// No mipmapping enabled
maxTexLevel = 0;
}
int maxTexLevel = hasMipLevels ? gstate.getTextureMaxLevel() : 0;
u8 *texptr[hasMipLevels ? 8 : 1] = {NULL};
if (gstate.isTextureMapEnabled() && !clearMode) {
GETextureFormat texfmt = gstate.getTextureFormat();
@@ -865,7 +842,7 @@ void DrawTriangleSlice(
GetTextureCoordinates(v0, v1, v2, w0, w1, w2, wsum_recip, s, t);
}
ApplyTexturing(sampler, prim_color, s, t, maxTexLevel, texptr, texbufw);
ApplyTexturing<hasMipLevels>(sampler, prim_color, s, t, maxTexLevel, texptr, texbufw);
}
if (!clearMode) {
@@ -945,39 +922,27 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData&
PixelFuncID pixelID;
ComputePixelFuncID(&pixelID);
Rasterizer::SingleFunc drawPixel = Rasterizer::GetSingleFunc(pixelID);
const bool hasMipLevels = gstate.isMipmapEnabled() ? gstate.getTextureMaxLevel() > 0 : false;
auto drawSlice = (hasMipLevels ?
(gstate.isModeClear() ? &DrawTriangleSlice<true, true> : &DrawTriangleSlice<false, true>) :
(gstate.isModeClear() ? &DrawTriangleSlice<true, false> : &DrawTriangleSlice<false, false>)
);
const int MIN_LINES_PER_THREAD = 4;
if (rangeY >= 12 && rangeX >= rangeY * 4) {
if (gstate.isModeClear()) {
auto bound = [&](int a, int b) -> void {
DrawTriangleSlice<true>(v0, v1, v2, minX, minY, maxX, maxY, false, a, b, pixelID, drawPixel);
};
ParallelRangeLoop(&g_threadManager, bound, 0, rangeX, MIN_LINES_PER_THREAD);
} else {
auto bound = [&](int a, int b) -> void {
DrawTriangleSlice<false>(v0, v1, v2, minX, minY, maxX, maxY, false, a, b, pixelID, drawPixel);
};
ParallelRangeLoop(&g_threadManager, bound, 0, rangeX, MIN_LINES_PER_THREAD);
}
auto bound = [&](int a, int b) -> void {
drawSlice(v0, v1, v2, minX, minY, maxX, maxY, false, a, b, pixelID, drawPixel);
};
ParallelRangeLoop(&g_threadManager, bound, 0, rangeX, MIN_LINES_PER_THREAD);
} else if (rangeY >= 12 && rangeX >= 12) {
if (gstate.isModeClear()) {
auto bound = [&](int a, int b) -> void {
DrawTriangleSlice<true>(v0, v1, v2, minX, minY, maxX, maxY, true, a, b, pixelID, drawPixel);
};
ParallelRangeLoop(&g_threadManager, bound, 0, rangeY, MIN_LINES_PER_THREAD);
} else {
auto bound = [&](int a, int b) -> void {
DrawTriangleSlice<false>(v0, v1, v2, minX, minY, maxX, maxY, true, a, b, pixelID, drawPixel);
};
ParallelRangeLoop(&g_threadManager, bound, 0, rangeY, MIN_LINES_PER_THREAD);
}
auto bound = [&](int a, int b) -> void {
drawSlice(v0, v1, v2, minX, minY, maxX, maxY, true, a, b, pixelID, drawPixel);
};
ParallelRangeLoop(&g_threadManager, bound, 0, rangeY, MIN_LINES_PER_THREAD);
} else {
if (gstate.isModeClear()) {
DrawTriangleSlice<true>(v0, v1, v2, minX, minY, maxX, maxY, true, 0, rangeY, pixelID, drawPixel);
} else {
DrawTriangleSlice<false>(v0, v1, v2, minX, minY, maxX, maxY, true, 0, rangeY, pixelID, drawPixel);
}
drawSlice(v0, v1, v2, minX, minY, maxX, maxY, true, 0, rangeY, pixelID, drawPixel);
}
}
@@ -1037,8 +1002,8 @@ void DrawPoint(const VertexData &v0)
int texLevel;
int texLevelFrac;
bool bilinear;
CalculateSamplingParams(0.0f, 0.0f, maxTexLevel, texLevel, texLevelFrac, bilinear);
ApplyTexturing(sampler, prim_color, s, t, texLevel, texLevelFrac, bilinear, texptr, texbufw);
CalculateSamplingParams<true>(0.0f, 0.0f, maxTexLevel, texLevel, texLevelFrac, bilinear);
prim_color = ApplyTexturing<true>(sampler, ToVec4IntArg(prim_color), s, t, texLevel, texLevelFrac, bilinear, texptr, texbufw);
}
if (!pixelID.clearMode)
@@ -1324,7 +1289,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1)
int texLevel;
int texLevelFrac;
bool texBilinear;
CalculateSamplingParams(ds, dt, maxTexLevel, texLevel, texLevelFrac, texBilinear);
CalculateSamplingParams<true>(ds, dt, maxTexLevel, texLevel, texLevelFrac, texBilinear);
if (gstate.isAntiAliasEnabled()) {
// TODO: This is a niave and wrong implementation.
@@ -1335,7 +1300,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1)
texBilinear = true;
}
ApplyTexturing(sampler, prim_color, s, t, texLevel, texLevelFrac, texBilinear, texptr, texbufw);
prim_color = ApplyTexturing<true>(sampler, ToVec4IntArg(prim_color), s, t, texLevel, texLevelFrac, texBilinear, texptr, texbufw);
}
if (!pixelID.clearMode)
@@ -1392,7 +1357,7 @@ bool GetCurrentTexture(GPUDebugBuffer &buffer, int level)
u32 *row = (u32 *)buffer.GetData();
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
row[x] = sampler.nearest(x, y, texptr, texbufw, level);
row[x] = Vec4<int>(sampler.nearest(x, y, texptr, texbufw, level)).ToRGBA();
}
row += w;
}
+2 -1
View File
@@ -18,6 +18,7 @@
#pragma once
#include "GPU/Software/FuncId.h"
#include "GPU/Software/RasterizerRegCache.h"
#include "GPU/Software/TransformUnit.h" // for DrawingCoords
struct GPUDebugBuffer;
@@ -35,6 +36,6 @@ bool GetCurrentTexture(GPUDebugBuffer &buffer, int level);
// Shared functions with RasterizerRectangle.cpp
Vec3<int> AlphaBlendingResult(const PixelFuncID &pixelID, const Vec4<int> &source, const Vec4<int> &dst);
Vec4<int> GetTextureFunctionOutput(const Vec4<int>& prim_color, const Vec4<int>& texcolor);
Vec4IntResult SOFTRAST_CALL GetTextureFunctionOutput(Vec4IntArg prim_color, Vec4IntArg texcolor);
} // namespace Rasterizer
+4 -4
View File
@@ -153,7 +153,7 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) {
int s = s_start;
u16 *pixel = fb.Get16Ptr(pos0.x, y, gstate.FrameBufStride());
for (int x = pos0.x; x < pos1.x; x++) {
u32 tex_color = nearestFunc(s, t, texptr, texbufw, 0);
u32 tex_color = Vec4<int>(nearestFunc(s, t, texptr, texbufw, 0)).ToRGBA();
if (tex_color & 0xFF000000) {
DrawSinglePixel5551(pixel, tex_color, pixelID);
}
@@ -171,7 +171,7 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) {
u16 *pixel = fb.Get16Ptr(pos0.x, y, gstate.FrameBufStride());
for (int x = pos0.x; x < pos1.x; x++) {
Vec4<int> prim_color = v1.color0;
Vec4<int> tex_color = Vec4<int>::FromRGBA(nearestFunc(s, t, texptr, texbufw, 0));
Vec4<int> tex_color = nearestFunc(s, t, texptr, texbufw, 0);
prim_color = ModulateRGBA(prim_color, tex_color);
if (prim_color.a() > 0) {
DrawSinglePixel5551(pixel, prim_color.ToRGBA(), pixelID);
@@ -191,8 +191,8 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) {
// Not really that fast but faster than triangle.
for (int x = pos0.x; x < pos1.x; x++) {
Vec4<int> prim_color = v1.color0;
Vec4<int> tex_color = Vec4<int>::FromRGBA(nearestFunc(s, t, texptr, texbufw, 0));
prim_color = GetTextureFunctionOutput(prim_color, tex_color);
Vec4<int> tex_color = nearestFunc(s, t, texptr, texbufw, 0);
prim_color = GetTextureFunctionOutput(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color));
drawPixel(x, y, z, 255, ToVec4IntArg(prim_color), pixelID);
s += ds;
}
+22
View File
@@ -335,6 +335,28 @@ void RegCache::GrabReg(Reg r, Purpose p, bool &needsSwap, Reg swapReg, Purpose s
_assert_msg_(false, "softjit GrabReg() reg that isn't there");
}
bool RegCache::ChangeReg(Reg r, Purpose p) {
for (auto &reg : regs) {
if (reg.reg != r)
continue;
if ((reg.purpose & FLAG_GEN) != (p & FLAG_GEN))
continue;
if (reg.purpose == p)
return true;
_assert_msg_(!Has(p), "softjit ChangeReg() duplicate purpose (%04X)", p);
if (reg.locked != 0 || reg.forceRetained)
return false;
reg.purpose = p;
return true;
}
_assert_msg_(false, "softjit ChangeReg() reg that isn't there");
return false;
}
RegCache::RegStatus *RegCache::FindReg(Reg r, Purpose p) {
for (auto &reg : regs) {
if (reg.reg == r && reg.purpose == p) {
+26
View File
@@ -64,13 +64,25 @@ typedef FakeGen::FakeXCodeBlock CodeBlock;
// We also have the types of things that end up in regs.
#if PPSSPP_ARCH(ARM64)
typedef int32x4_t Vec4IntArg;
typedef int32x4_t Vec4IntResult;
typedef float32x4_t Vec4FloatArg;
static inline Vec4IntArg ToVec4IntArg(const Math3D::Vec4<int> &a) { return vld1q_s32(a.AsArray()); }
static inline Vec4IntResult ToVec4IntResult(const Math3D::Vec4<int> &a) { return vld1q_s32(a.AsArray()); }
static inline Vec4FloatArg ToVec4FloatArg(const Math3D::Vec4<float> &a) { return vld1q_f32(a.AsArray()); }
#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
typedef __m128i Vec4IntArg;
typedef __m128i Vec4IntResult;
typedef __m128 Vec4FloatArg;
static inline Vec4IntArg ToVec4IntArg(const Math3D::Vec4<int> &a) { return a.ivec; }
static inline Vec4IntResult ToVec4IntResult(const Math3D::Vec4<int> &a) { return a.ivec; }
static inline Vec4FloatArg ToVec4FloatArg(const Math3D::Vec4<float> &a) { return a.vec; }
#else
typedef const Math3D::Vec4<int> &Vec4IntArg;
typedef Math3D::Vec4<int> Vec4IntResult;
typedef const Math3D::Vec4<float> &Vec4FloatArg;
static inline Vec4IntArg ToVec4IntArg(const Math3D::Vec4<int> &a) { return a; }
static inline Vec4IntResult ToVec4IntResult(const Math3D::Vec4<int> &a) { return a; }
static inline Vec4FloatArg ToVec4FloatArg(const Math3D::Vec4<float> &a) { return a; }
#endif
#if PPSSPP_ARCH(AMD64) && PPSSPP_PLATFORM(WINDOWS) && (defined(_MSC_VER) || defined(__clang__) || defined(__INTEL_COMPILER))
@@ -85,6 +97,7 @@ struct RegCache {
FLAG_TEMP = 0x1000,
VEC_ZERO = 0x0000,
VEC_RESULT = 0x0001,
GEN_SRC_ALPHA = 0x0100,
GEN_GSTATE = 0x0101,
@@ -92,12 +105,23 @@ struct RegCache {
GEN_STENCIL = 0x0103,
GEN_COLOR_OFF = 0x0104,
GEN_DEPTH_OFF = 0x0105,
GEN_RESULT = 0x0106,
GEN_SHIFTVAL = 0x0107,
GEN_ARG_X = 0x0180,
GEN_ARG_Y = 0x0181,
GEN_ARG_Z = 0x0182,
GEN_ARG_FOG = 0x0183,
GEN_ARG_ID = 0x0184,
GEN_ARG_U = 0x0185,
GEN_ARG_V = 0x0186,
GEN_ARG_TEXPTR = 0x0187,
GEN_ARG_BUFW = 0x0188,
GEN_ARG_LEVEL = 0x0189,
GEN_ARG_U_PTR = 0x018A,
GEN_ARG_V_PTR = 0x018B,
GEN_ARG_FRAC_U = 0x018C,
GEN_ARG_FRAC_V = 0x018D,
VEC_ARG_COLOR = 0x0080,
VEC_ARG_MASK = 0x0081,
@@ -170,6 +194,8 @@ struct RegCache {
// For getting a specific reg. WARNING: May return a locked reg, so you have to check.
void GrabReg(Reg r, Purpose p, bool &needsSwap, Reg swapReg, Purpose swapPurpose);
// For setting the purpose of a specific reg. Returns false if it is locked.
bool ChangeReg(Reg r, Purpose p);
private:
RegStatus *FindReg(Reg r, Purpose p);
+18 -15
View File
@@ -23,6 +23,7 @@
#include "Core/Reporting.h"
#include "GPU/Common/TextureDecoder.h"
#include "GPU/GPUState.h"
#include "GPU/Software/RasterizerRegCache.h"
#include "GPU/Software/Sampler.h"
#if defined(_M_SSE)
@@ -30,13 +31,14 @@
#endif
using namespace Math3D;
using namespace Rasterizer;
extern u32 clut[4096];
namespace Sampler {
static u32 SampleNearest(int u, int v, const u8 *tptr, int bufw, int level);
static u32 SampleLinear(int u[4], int v[4], int frac_u, int frac_v, const u8 *tptr, int bufw, int level);
static Vec4IntResult SOFTRAST_CALL SampleNearest(int u, int v, const u8 *tptr, int bufw, int level);
static Vec4IntResult SOFTRAST_CALL SampleLinear(int u[4], int v[4], int frac_u, int frac_v, const u8 *tptr, int bufw, int level);
std::mutex jitCacheLock;
SamplerJitCache *jitCache = nullptr;
@@ -111,10 +113,17 @@ void SamplerJitCache::Clear() {
void SamplerJitCache::ComputeSamplerID(SamplerID *id_out, bool linear) {
SamplerID id{};
int maxLevel = gstate.isMipmapEnabled() ? gstate.getTextureMaxLevel() : 0;
for (int i = 0; i <= maxLevel; ++i) {
if (gstate.getTextureAddress(i) == 0) {
id.hasInvalidPtr = true;
}
}
id.texfmt = gstate.getTextureFormat();
id.swizzle = gstate.isTextureSwizzled();
// Only CLUT4 can use separate CLUTs per mimap.
id.useSharedClut = gstate.getTextureFormat() != GE_TFMT_CLUT4 || !gstate.isMipmapEnabled() || gstate.isClutSharedForMipmaps();
id.useSharedClut = gstate.getTextureFormat() != GE_TFMT_CLUT4 || maxLevel == 0 || !gstate.isMipmapEnabled() || gstate.isClutSharedForMipmaps();
if (gstate.isTextureFormatIndexed()) {
id.clutfmt = gstate.getClutPaletteFormat();
id.hasClutMask = gstate.getClutIndexMask() != 0xFF;
@@ -122,12 +131,6 @@ void SamplerJitCache::ComputeSamplerID(SamplerID *id_out, bool linear) {
id.hasClutOffset = gstate.getClutIndexStartPos() != 0;
}
id.linear = linear;
int maxLevel = gstate.isMipmapEnabled() ? gstate.getTextureMaxLevel() : 0;
for (int i = 0; i <= maxLevel; ++i) {
if (gstate.getTextureAddress(i) == 0) {
id.hasInvalidPtr = true;
}
}
*id_out = id;
}
@@ -305,8 +308,7 @@ struct Nearest4 {
};
template <int N>
inline static Nearest4 SampleNearest(int u[N], int v[N], const u8 *srcptr, int texbufw, int level)
{
inline static Nearest4 SOFTRAST_CALL SampleNearest(int u[N], int v[N], const u8 *srcptr, int texbufw, int level) {
Nearest4 res;
if (!srcptr) {
memset(res.v, 0, sizeof(res.v));
@@ -407,11 +409,12 @@ inline static Nearest4 SampleNearest(int u[N], int v[N], const u8 *srcptr, int t
}
}
static u32 SampleNearest(int u, int v, const u8 *tptr, int bufw, int level) {
return SampleNearest<1>(&u, &v, tptr, bufw, level);
static Vec4IntResult SOFTRAST_CALL SampleNearest(int u, int v, const u8 *tptr, int bufw, int level) {
Nearest4 c = SampleNearest<1>(&u, &v, tptr, bufw, level);
return ToVec4IntResult(Vec4<int>::FromRGBA(c.v[0]));
}
static u32 SampleLinear(int u[4], int v[4], int frac_u, int frac_v, const u8 *tptr, int bufw, int texlevel) {
static Vec4IntResult SOFTRAST_CALL SampleLinear(int u[4], int v[4], int frac_u, int frac_v, const u8 *tptr, int bufw, int texlevel) {
Nearest4 c = SampleNearest<4>(u, v, tptr, bufw, texlevel);
Vec4<int> texcolor_tl = Vec4<int>::FromRGBA(c.v[0]);
@@ -420,7 +423,7 @@ static u32 SampleLinear(int u[4], int v[4], int frac_u, int frac_v, const u8 *tp
Vec4<int> texcolor_br = Vec4<int>::FromRGBA(c.v[3]);
Vec4<int> t = texcolor_tl * (0x100 - frac_u) + texcolor_tr * frac_u;
Vec4<int> b = texcolor_bl * (0x100 - frac_u) + texcolor_br * frac_u;
return ((t * (0x100 - frac_v) + b * frac_v) / (256 * 256)).ToRGBA();
return ToVec4IntResult((t * (0x100 - frac_v) + b * frac_v) / (256 * 256));
}
};
+3 -2
View File
@@ -26,10 +26,10 @@
namespace Sampler {
typedef u32 (*NearestFunc)(int u, int v, const u8 *tptr, int bufw, int level);
typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *NearestFunc)(int u, int v, const u8 *tptr, int bufw, int level);
NearestFunc GetNearestFunc();
typedef u32 (*LinearFunc)(int u[4], int v[4], int frac_u, int frac_v, const u8 *tptr, int bufw, int level);
typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(int u[4], int v[4], int frac_u, int frac_v, const u8 *tptr, int bufw, int level);
LinearFunc GetLinearFunc();
struct Funcs {
@@ -84,6 +84,7 @@ private:
std::unordered_map<SamplerID, NearestFunc> cache_;
std::unordered_map<SamplerID, const u8 *> addresses_;
Rasterizer::RegCache regCache_;
};
};
File diff suppressed because it is too large Load Diff