mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-06 20:55:23 +02:00
Merge pull request #15200 from unknownbrackets/softjit-sampler
Use vectorcall and regcache in samplerjit (software renderer)
This commit is contained in:
+91
-126
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 ® : 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 ® : regs) {
|
||||
if (reg.reg == r && reg.purpose == p) {
|
||||
|
||||
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
+515
-250
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user