SoftGPU: Implement dithering.

Note: it applies even in 8888, so it can be used as a slight brightness
adjustment.
This commit is contained in:
Unknown W. Brackets 2019-05-26 09:52:34 -07:00
parent eff793cb7b
commit 7412e13767
2 changed files with 19 additions and 6 deletions

View File

@ -173,10 +173,7 @@ struct GPUgstate {
blend,
blendfixa,
blendfixb,
dith1,
dith2,
dith3,
dith4,
dithmtx[4],
lop, // 0xE6
zmsk,
pmskc,
@ -249,6 +246,11 @@ struct GPUgstate {
// Dither
bool isDitherEnabled() const { return ditherEnable & 1; }
int getDitherValue(int x, int y) const {
u8 raw = (dithmtx[y & 3] >> ((x & 3) * 4)) & 0xF;
// Apply sign extension to make 8-F negative, 0-7 positive.
return ((s8)(raw << 4)) >> 4;
}
// Color Mask
u32 getColorMask() const { return (pmskc & 0xFFFFFF) | ((pmska & 0xFF) << 24); }

View File

@ -895,12 +895,24 @@ inline void DrawSinglePixel(const DrawingCoords &p, u16 z, u8 fog, const Vec4<in
const u32 old_color = GetPixelColor(p.x, p.y);
u32 new_color;
// Dithering happens before the logic op and regardless of framebuffer format or clear mode.
// We do it while alpha blending because it happens before clamping.
if (gstate.isAlphaBlendEnabled() && !clearMode) {
const Vec4<int> dst = Vec4<int>::FromRGBA(old_color);
Vec3<int> blended = AlphaBlendingResult(prim_color, dst);
if (gstate.isDitherEnabled()) {
blended += Vec3<int>::AssignToAll(gstate.getDitherValue(p.x, p.y));
}
// ToRGB() always automatically clamps.
new_color = AlphaBlendingResult(prim_color, dst).ToRGB();
new_color = blended.ToRGB();
new_color |= stencil << 24;
} else {
if (gstate.isDitherEnabled()) {
// We'll discard alpha anyway.
prim_color += Vec4<int>::AssignToAll(gstate.getDitherValue(p.x, p.y));
}
#if defined(_M_SSE)
new_color = Vec3<int>(prim_color.ivec).ToRGB();
new_color |= stencil << 24;
@ -920,7 +932,6 @@ inline void DrawSinglePixel(const DrawingCoords &p, u16 z, u8 fog, const Vec4<in
}
new_color = (new_color & ~gstate.getColorMask()) | (old_color & gstate.getColorMask());
// TODO: Dither before or inside SetPixelColor
SetPixelColor(p.x, p.y, new_color);
}