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, blend,
blendfixa, blendfixa,
blendfixb, blendfixb,
dith1, dithmtx[4],
dith2,
dith3,
dith4,
lop, // 0xE6 lop, // 0xE6
zmsk, zmsk,
pmskc, pmskc,
@ -249,6 +246,11 @@ struct GPUgstate {
// Dither // Dither
bool isDitherEnabled() const { return ditherEnable & 1; } 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 // Color Mask
u32 getColorMask() const { return (pmskc & 0xFFFFFF) | ((pmska & 0xFF) << 24); } 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); const u32 old_color = GetPixelColor(p.x, p.y);
u32 new_color; 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) { if (gstate.isAlphaBlendEnabled() && !clearMode) {
const Vec4<int> dst = Vec4<int>::FromRGBA(old_color); 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. // ToRGB() always automatically clamps.
new_color = AlphaBlendingResult(prim_color, dst).ToRGB(); new_color = blended.ToRGB();
new_color |= stencil << 24; new_color |= stencil << 24;
} else { } else {
if (gstate.isDitherEnabled()) {
// We'll discard alpha anyway.
prim_color += Vec4<int>::AssignToAll(gstate.getDitherValue(p.x, p.y));
}
#if defined(_M_SSE) #if defined(_M_SSE)
new_color = Vec3<int>(prim_color.ivec).ToRGB(); new_color = Vec3<int>(prim_color.ivec).ToRGB();
new_color |= stencil << 24; 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()); new_color = (new_color & ~gstate.getColorMask()) | (old_color & gstate.getColorMask());
// TODO: Dither before or inside SetPixelColor
SetPixelColor(p.x, p.y, new_color); SetPixelColor(p.x, p.y, new_color);
} }