mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-17 08:20:30 +02:00
softgpu: Centralize more prim drawing state.
This commit is contained in:
1 parent
d06f17d27b
commit
d962fb35d3
3 files changed
+74
-53
No files matched your search
+52
-47
@@ -116,10 +116,12 @@ void ComputeRasterizerState(RasterizerState *state) {
|
||||
state->linear = state->nearest;
|
||||
}
|
||||
|
||||
int maxTexLevel = state->samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0;
|
||||
if (gstate.isTextureMapEnabled() && !state->pixelID.clearMode) {
|
||||
state->maxTexLevel = state->samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0;
|
||||
state->enableTextures = gstate.isTextureMapEnabled();
|
||||
|
||||
if (state->enableTextures && !state->pixelID.clearMode) {
|
||||
GETextureFormat texfmt = state->samplerID.TexFmt();
|
||||
for (int i = 0; i <= maxTexLevel; i++) {
|
||||
for (uint8_t i = 0; i <= state->maxTexLevel; i++) {
|
||||
u32 texaddr = gstate.getTextureAddress(i);
|
||||
state->texbufw[i] = GetTextureBufw(i, texaddr, texfmt);
|
||||
if (Memory::IsValidAddress(texaddr))
|
||||
@@ -128,6 +130,14 @@ void ComputeRasterizerState(RasterizerState *state) {
|
||||
state->texptr[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
state->texLevelMode = gstate.getTexLevelMode();
|
||||
state->texLevelOffset = (int8_t)gstate.getTexLevelOffset16();
|
||||
state->shadeGouraud = gstate.getShadeMode() == GE_SHADE_GOURAUD;
|
||||
state->throughMode = gstate.isModeThrough();
|
||||
state->mipFilt = gstate.isMipmapFilteringEnabled();
|
||||
state->minFilt = gstate.isMinifyFilteringEnabled();
|
||||
state->magFilt = gstate.isMagnifyFilteringEnabled();
|
||||
}
|
||||
|
||||
static inline u8 ClampFogDepth(float fogdepth) {
|
||||
@@ -506,9 +516,9 @@ Vec3<int> AlphaBlendingResult(const PixelFuncID &pixelID, const Vec4<int> &sourc
|
||||
}
|
||||
}
|
||||
|
||||
static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x, int y, Vec4IntArg prim_color, u8 *const texptr[], const int texbufw[], int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) {
|
||||
const u8 **tptr0 = const_cast<const u8 **>(&texptr[texlevel]);
|
||||
const int *bufw0 = &texbufw[texlevel];
|
||||
static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x, int y, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) {
|
||||
const u8 **tptr0 = const_cast<const u8 **>(&state.texptr[texlevel]);
|
||||
const int *bufw0 = &state.texbufw[texlevel];
|
||||
|
||||
if (!bilinear) {
|
||||
return state.nearest(s, t, x, y, prim_color, tptr0, bufw0, texlevel, frac_texlevel);
|
||||
@@ -516,8 +526,8 @@ static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x
|
||||
return state.linear(s, t, x, y, prim_color, tptr0, bufw0, texlevel, frac_texlevel);
|
||||
}
|
||||
|
||||
static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, int x, int y, Vec4IntArg prim_color, u8 *const texptr[], const int texbufw[], int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) {
|
||||
return ApplyTexturing(s, t, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, prim_color, texptr, texbufw, texlevel, frac_texlevel, bilinear, state);
|
||||
static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, int x, int y, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) {
|
||||
return ApplyTexturing(s, t, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, prim_color, texlevel, frac_texlevel, bilinear, state);
|
||||
}
|
||||
|
||||
// Produces a signed 1.27.4 value.
|
||||
@@ -535,13 +545,13 @@ static int TexLog2(float delta) {
|
||||
return useful - 127 * 16;
|
||||
}
|
||||
|
||||
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);
|
||||
static inline void CalculateSamplingParams(const float ds, const float dt, const RasterizerState &state, int &level, int &levelFrac, bool &filt) {
|
||||
const int width = 1 << state.samplerID.width0Shift;
|
||||
const int height = 1 << state.samplerID.height0Shift;
|
||||
|
||||
// With 8 bits of fraction (because texslope can be fairly precise.)
|
||||
int detail;
|
||||
switch (gstate.getTexLevelMode()) {
|
||||
switch (state.TexLevelMode()) {
|
||||
case GE_TEXLEVEL_MODE_AUTO:
|
||||
detail = TexLog2(std::max(ds * width, dt * height));
|
||||
break;
|
||||
@@ -556,13 +566,13 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const
|
||||
break;
|
||||
}
|
||||
|
||||
// Add in the bias (used in all modes), expanding to 8 bits of fraction.
|
||||
detail += gstate.getTexLevelOffset16();
|
||||
// Add in the bias (used in all modes), with 4 bits of fraction.
|
||||
detail += state.texLevelOffset;
|
||||
|
||||
if (detail > 0 && maxTexLevel > 0) {
|
||||
bool mipFilt = gstate.isMipmapFilteringEnabled();
|
||||
if (detail > 0 && state.maxTexLevel > 0) {
|
||||
bool mipFilt = state.mipFilt;
|
||||
|
||||
int level8 = std::min(detail, maxTexLevel * 16);
|
||||
int level8 = std::min(detail, state.maxTexLevel * 16);
|
||||
if (!mipFilt) {
|
||||
// Round up at 1.5.
|
||||
level8 += 8;
|
||||
@@ -575,24 +585,24 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const
|
||||
}
|
||||
|
||||
if (detail > 0)
|
||||
filt = gstate.isMinifyFilteringEnabled();
|
||||
filt = state.minFilt;
|
||||
else
|
||||
filt = gstate.isMagnifyFilteringEnabled();
|
||||
filt = state.magFilt;
|
||||
}
|
||||
|
||||
static inline void ApplyTexturing(const RasterizerState &state, Vec4<int> *prim_color, const Vec4<int> &mask, const Vec4<float> &s, const Vec4<float> &t, int maxTexLevel, u8 *const texptr[], const int texbufw[], int x, int y) {
|
||||
static inline void ApplyTexturing(const RasterizerState &state, Vec4<int> *prim_color, const Vec4<int> &mask, const Vec4<float> &s, const Vec4<float> &t, int x, int y) {
|
||||
float ds = s[1] - s[0];
|
||||
float dt = t[2] - t[0];
|
||||
|
||||
int level;
|
||||
int levelFrac;
|
||||
bool bilinear;
|
||||
CalculateSamplingParams(ds, dt, maxTexLevel, level, levelFrac, bilinear);
|
||||
CalculateSamplingParams(ds, dt, state, level, levelFrac, bilinear);
|
||||
|
||||
PROFILE_THIS_SCOPE("sampler");
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (mask[i] >= 0)
|
||||
prim_color[i] = ApplyTexturing(s[i], t[i], ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, ToVec4IntArg(prim_color[i]), texptr, texbufw, level, levelFrac, bilinear, state);
|
||||
prim_color[i] = ApplyTexturing(s[i], t[i], ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, ToVec4IntArg(prim_color[i]), level, levelFrac, bilinear, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,7 +785,6 @@ void DrawTriangleSlice(
|
||||
Vec4<int> bias2 = Vec4<int>::AssignToAll(IsRightSideOrFlatBottomLine(v2.screenpos.xy(), v0.screenpos.xy(), v1.screenpos.xy()) ? -1 : 0);
|
||||
|
||||
const PixelFuncID &pixelID = state.pixelID;
|
||||
int maxTexLevel = state.samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0;
|
||||
|
||||
TriangleEdge<useSSE4> e0;
|
||||
TriangleEdge<useSSE4> e1;
|
||||
@@ -791,7 +800,7 @@ void DrawTriangleSlice(
|
||||
// All the z values are the same, no interpolation required.
|
||||
// This is common, and when we interpolate, we lose accuracy.
|
||||
const bool flatZ = v0.screenpos.z == v1.screenpos.z && v0.screenpos.z == v2.screenpos.z;
|
||||
const bool flatColorAll = clearMode || gstate.getShadeMode() != GE_SHADE_GOURAUD;
|
||||
const bool flatColorAll = clearMode || !state.shadeGouraud;
|
||||
const bool flatColor0 = flatColorAll || (v0.color0 == v1.color0 && v0.color0 == v2.color0);
|
||||
const bool flatColor1 = flatColorAll || (v0.color1 == v1.color1 && v0.color1 == v2.color1);
|
||||
const bool noFog = clearMode || !pixelID.applyFog || (v0.fogdepth >= 1.0f && v1.fogdepth >= 1.0f && v2.fogdepth >= 1.0f);
|
||||
@@ -867,21 +876,21 @@ void DrawTriangleSlice(
|
||||
}
|
||||
}
|
||||
|
||||
if (gstate.isTextureMapEnabled() && !clearMode) {
|
||||
if (state.enableTextures && !clearMode) {
|
||||
Vec4<float> s, t;
|
||||
if (gstate.isModeThrough()) {
|
||||
if (state.throughMode) {
|
||||
s = Interpolate(v0.texturecoords.s(), v1.texturecoords.s(), v2.texturecoords.s(), w0, w1, w2, wsum_recip);
|
||||
t = Interpolate(v0.texturecoords.t(), v1.texturecoords.t(), v2.texturecoords.t(), w0, w1, w2, wsum_recip);
|
||||
|
||||
// For levels > 0, mipmapping is always based on level 0. Simpler to scale first.
|
||||
s *= 1.0f / (float)gstate.getTextureWidth(0);
|
||||
t *= 1.0f / (float)gstate.getTextureHeight(0);
|
||||
s *= 1.0f / (float)(1 << state.samplerID.width0Shift);
|
||||
t *= 1.0f / (float)(1 << state.samplerID.height0Shift);
|
||||
} else {
|
||||
// Texture coordinate interpolation must definitely be perspective-correct.
|
||||
GetTextureCoordinates(v0, v1, v2, w0, w1, w2, wsum_recip, s, t);
|
||||
}
|
||||
|
||||
ApplyTexturing(state, prim_color, mask, s, t, maxTexLevel, state.texptr, state.texbufw, curX, curY);
|
||||
ApplyTexturing(state, prim_color, mask, s, t, curX, curY);
|
||||
}
|
||||
|
||||
if (!clearMode) {
|
||||
@@ -1037,14 +1046,12 @@ void DrawPoint(const VertexData &v0, const RasterizerState &state) {
|
||||
auto &pixelID = state.pixelID;
|
||||
auto &samplerID = state.samplerID;
|
||||
|
||||
if (gstate.isTextureMapEnabled() && !pixelID.clearMode) {
|
||||
int maxTexLevel = samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0;
|
||||
|
||||
if (state.enableTextures && !pixelID.clearMode) {
|
||||
float s = v0.texturecoords.s();
|
||||
float t = v0.texturecoords.t();
|
||||
if (gstate.isModeThrough()) {
|
||||
s *= 1.0f / (float)gstate.getTextureWidth(0);
|
||||
t *= 1.0f / (float)gstate.getTextureHeight(0);
|
||||
if (state.throughMode) {
|
||||
s *= 1.0f / (float)(1 << state.samplerID.width0Shift);
|
||||
t *= 1.0f / (float)(1 << state.samplerID.height0Shift);
|
||||
} else {
|
||||
// Texture coordinate interpolation must definitely be perspective-correct.
|
||||
GetTextureCoordinates(v0, v0, 0.0f, s, t);
|
||||
@@ -1053,9 +1060,9 @@ void DrawPoint(const VertexData &v0, const RasterizerState &state) {
|
||||
int texLevel;
|
||||
int texLevelFrac;
|
||||
bool bilinear;
|
||||
CalculateSamplingParams(0.0f, 0.0f, maxTexLevel, texLevel, texLevelFrac, bilinear);
|
||||
CalculateSamplingParams(0.0f, 0.0f, state, texLevel, texLevelFrac, bilinear);
|
||||
PROFILE_THIS_SCOPE("sampler");
|
||||
prim_color = ApplyTexturingSingle(s, t, pos.x, pos.y, ToVec4IntArg(prim_color), state.texptr, state.texbufw, texLevel, texLevelFrac, bilinear, state);
|
||||
prim_color = ApplyTexturingSingle(s, t, pos.x, pos.y, ToVec4IntArg(prim_color), texLevel, texLevelFrac, bilinear, state);
|
||||
}
|
||||
|
||||
if (!pixelID.clearMode)
|
||||
@@ -1308,8 +1315,6 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState
|
||||
scissorBR.x += 15;
|
||||
scissorBR.y += 15;
|
||||
|
||||
int maxTexLevel = state.samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0;
|
||||
|
||||
auto &pixelID = state.pixelID;
|
||||
auto &samplerID = state.samplerID;
|
||||
|
||||
@@ -1349,17 +1354,17 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState
|
||||
prim_color.a() = 0x7F;
|
||||
}
|
||||
|
||||
if (gstate.isTextureMapEnabled() && !pixelID.clearMode) {
|
||||
if (state.enableTextures && !pixelID.clearMode) {
|
||||
float s, s1;
|
||||
float t, t1;
|
||||
if (gstate.isModeThrough()) {
|
||||
if (state.throughMode) {
|
||||
Vec2<float> tc = (v0.texturecoords * (float)(steps - i) + v1.texturecoords * (float)i) / steps1;
|
||||
Vec2<float> tc1 = (v0.texturecoords * (float)(steps - i - 1) + v1.texturecoords * (float)(i + 1)) / steps1;
|
||||
|
||||
s = tc.s() * (1.0f / (float)gstate.getTextureWidth(0));
|
||||
s1 = tc1.s() * (1.0f / (float)gstate.getTextureWidth(0));
|
||||
t = tc.t() * (1.0f / (float)gstate.getTextureHeight(0));
|
||||
t1 = tc1.t() * (1.0f / (float)gstate.getTextureHeight(0));
|
||||
s = tc.s() * (1.0f / (float)(1 << state.samplerID.width0Shift));
|
||||
s1 = tc1.s() * (1.0f / (float)(1 << state.samplerID.width0Shift));
|
||||
t = tc.t() * (1.0f / (float)(1 << state.samplerID.height0Shift));
|
||||
t1 = tc1.t() * (1.0f / (float)(1 << state.samplerID.height0Shift));
|
||||
} else {
|
||||
// Texture coordinate interpolation must definitely be perspective-correct.
|
||||
GetTextureCoordinates(v0, v1, (float)(steps - i) / steps1, s, t);
|
||||
@@ -1373,7 +1378,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState
|
||||
int texLevel;
|
||||
int texLevelFrac;
|
||||
bool texBilinear;
|
||||
CalculateSamplingParams(ds, dt, maxTexLevel, texLevel, texLevelFrac, texBilinear);
|
||||
CalculateSamplingParams(ds, dt, state, texLevel, texLevelFrac, texBilinear);
|
||||
|
||||
if (gstate.isAntiAliasEnabled()) {
|
||||
// TODO: This is a niave and wrong implementation.
|
||||
@@ -1385,7 +1390,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState
|
||||
}
|
||||
|
||||
PROFILE_THIS_SCOPE("sampler");
|
||||
prim_color = ApplyTexturingSingle(s, t, x, y, ToVec4IntArg(prim_color), state.texptr, state.texbufw, texLevel, texLevelFrac, texBilinear, state);
|
||||
prim_color = ApplyTexturingSingle(s, t, x, y, ToVec4IntArg(prim_color), texLevel, texLevelFrac, texBilinear, state);
|
||||
}
|
||||
|
||||
if (!pixelID.clearMode)
|
||||
|
||||
@@ -40,6 +40,22 @@ struct RasterizerState {
|
||||
Sampler::NearestFunc nearest;
|
||||
int texbufw[8]{};
|
||||
u8 *texptr[8]{};
|
||||
|
||||
struct {
|
||||
uint8_t maxTexLevel : 3;
|
||||
bool enableTextures : 1;
|
||||
uint8_t texLevelMode : 2;
|
||||
bool shadeGouraud : 1;
|
||||
bool throughMode : 1;
|
||||
int8_t texLevelOffset : 8;
|
||||
bool mipFilt : 1;
|
||||
bool minFilt : 1;
|
||||
bool magFilt : 1;
|
||||
};
|
||||
|
||||
GETexLevelMode TexLevelMode() const {
|
||||
return GETexLevelMode(texLevelMode);
|
||||
}
|
||||
};
|
||||
|
||||
void ComputeRasterizerState(RasterizerState *state);
|
||||
|
||||
@@ -102,7 +102,7 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const RasterizerStat
|
||||
|
||||
constexpr int MIN_LINES_PER_THREAD = 32;
|
||||
|
||||
if (gstate.isTextureMapEnabled()) {
|
||||
if (state.enableTextures) {
|
||||
// 1:1 (but with mirror support) texture mapping!
|
||||
int s_start = v0.texturecoords.x;
|
||||
int t_start = v0.texturecoords.y;
|
||||
@@ -184,10 +184,10 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const RasterizerStat
|
||||
int xoff = ((v0.screenpos.x & 15) + 1) / 2;
|
||||
int yoff = ((v0.screenpos.y & 15) + 1) / 2;
|
||||
|
||||
float dsf = ds * (1.0f / (float)gstate.getTextureWidth(0));
|
||||
float dtf = dt * (1.0f / (float)gstate.getTextureHeight(0));
|
||||
float sf_start = s_start * (1.0f / (float)gstate.getTextureWidth(0));
|
||||
float tf_start = t_start * (1.0f / (float)gstate.getTextureHeight(0));
|
||||
float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift));
|
||||
float dtf = dt * (1.0f / (float)(1 << state.samplerID.height0Shift));
|
||||
float sf_start = s_start * (1.0f / (float)(1 << state.samplerID.width0Shift));
|
||||
float tf_start = t_start * (1.0f / (float)(1 << state.samplerID.height0Shift));
|
||||
|
||||
ParallelRangeLoop(&g_threadManager, [=](int y1, int y2) {
|
||||
float t = tf_start + (y1 - pos0.y) * dtf;
|
||||
@@ -291,7 +291,7 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, const Rasteri
|
||||
// We already have a fast path for clear in ClearRectangle.
|
||||
bool state_check = !state.pixelID.clearMode && NoClampOrWrap(v0.texturecoords) && NoClampOrWrap(v1.texturecoords);
|
||||
// TODO: No mipmap levels? Might be a font at level 1...
|
||||
if ((coord_check || !gstate.isTextureMapEnabled()) && orient_check && state_check) {
|
||||
if ((coord_check || !state.enableTextures) && orient_check && state_check) {
|
||||
Rasterizer::DrawSprite(v0, v1, state);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user