mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-28 06:10:12 +00:00
Separate mmpx enhance from mmpx (#3453)
Use conditional weak blending instead of pixel copying to eliminate artifacts on straight lines Reduce algorithm overhead use explicitly initialize to fix dx11 fxc uninitialized variable false positive Update gpu_hw_shadergen.cpp Update gpu_hw_shadergen.cpp
This commit is contained in:
parent
d83ecb0582
commit
99268f22ec
@ -727,10 +727,9 @@ void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limi
|
|||||||
|
|
||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
else if (texture_filter == GPUTextureFilter::MMPX || texture_filter == GPUTextureFilter::MMPXEnhanced)
|
else if (texture_filter == GPUTextureFilter::MMPX)
|
||||||
{
|
{
|
||||||
DefineMacro(ss, "TEXTURE_ALPHA_BLENDING", false);
|
DefineMacro(ss, "TEXTURE_ALPHA_BLENDING", false);
|
||||||
DefineMacro(ss, "MMPX_ENHANCED", (texture_filter == GPUTextureFilter::MMPXEnhanced));
|
|
||||||
|
|
||||||
ss << "#define src(xoffs, yoffs) packUnorm4x8(SampleFromVRAM(texpage, clamp(bcoords + float2((xoffs), (yoffs)), "
|
ss << "#define src(xoffs, yoffs) packUnorm4x8(SampleFromVRAM(texpage, clamp(bcoords + float2((xoffs), (yoffs)), "
|
||||||
"uv_limits.xy, uv_limits.zw)))\n";
|
"uv_limits.xy, uv_limits.zw)))\n";
|
||||||
@ -743,11 +742,7 @@ void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limi
|
|||||||
ss << R"(
|
ss << R"(
|
||||||
uint luma(uint C) {
|
uint luma(uint C) {
|
||||||
uint alpha = (C & 0xFF000000u) >> 24;
|
uint alpha = (C & 0xFF000000u) >> 24;
|
||||||
#if MMPX_ENHANCED
|
|
||||||
return (((C & 0x00FF0000u) >> 16) + ((C & 0x0000FF00u) >> 8) + (C & 0x000000FFu)) + (255u - alpha) * 3;
|
|
||||||
#else
|
|
||||||
return (((C & 0x00FF0000u) >> 16) + ((C & 0x0000FF00u) >> 8) + (C & 0x000000FFu) + 1u) * (256u - alpha);
|
return (((C & 0x00FF0000u) >> 16) + ((C & 0x0000FF00u) >> 8) + (C & 0x000000FFu) + 1u) * (256u - alpha);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool all_eq2(uint B, uint A0, uint A1) {
|
bool all_eq2(uint B, uint A0, uint A1) {
|
||||||
@ -774,26 +769,150 @@ bool none_eq4(uint B, uint A0, uint A1, uint A2, uint A3) {
|
|||||||
return B != A0 && B != A1 && B != A2 && B != A3;
|
return B != A0 && B != A1 && B != A2 && B != A3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MMPX_ENHANCED
|
void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limits, out float4 texcol, out float ialpha)
|
||||||
|
|
||||||
// Calculate the RGB distance between two ABGR8 colors
|
|
||||||
float rgb_distance(uint a, uint b)
|
|
||||||
{
|
{
|
||||||
vec4 ca = unpackUnorm4x8(a);
|
float2 bcoords = floor(coords);
|
||||||
vec4 cb = unpackUnorm4x8(b);
|
|
||||||
return distance(ca.rgb, cb.rgb);
|
uint A = src(-1, -1), B = src(+0, -1), C = src(+1, -1);
|
||||||
|
uint D = src(-1, +0), E = src(+0, +0), F = src(+1, +0);
|
||||||
|
uint G = src(-1, +1), H = src(+0, +1), I = src(+1, +1);
|
||||||
|
|
||||||
|
uint J = E, K = E, L = E, M = E;
|
||||||
|
|
||||||
|
if (((A ^ E) | (B ^ E) | (C ^ E) | (D ^ E) | (F ^ E) | (G ^ E) | (H ^ E) | (I ^ E)) != 0u) {
|
||||||
|
uint P = src(+0, -2), S = src(+0, +2);
|
||||||
|
uint Q = src(-2, +0), R = src(+2, +0);
|
||||||
|
uint Bl = luma(B), Dl = luma(D), El = luma(E), Fl = luma(F), Hl = luma(H);
|
||||||
|
|
||||||
|
// 1:1 slope rules
|
||||||
|
if ((D == B && D != H && D != F) && (El >= Dl || E == A) && any_eq3(E, A, C, G) && ((El < Dl) || A != D || E != P || E != Q)) J = D;
|
||||||
|
if ((B == F && B != D && B != H) && (El >= Bl || E == C) && any_eq3(E, A, C, I) && ((El < Bl) || C != B || E != P || E != R)) K = B;
|
||||||
|
if ((H == D && H != F && H != B) && (El >= Hl || E == G) && any_eq3(E, A, G, I) && ((El < Hl) || G != H || E != S || E != Q)) L = H;
|
||||||
|
if ((F == H && F != B && F != D) && (El >= Fl || E == I) && any_eq3(E, C, G, I) && ((El < Fl) || I != H || E != R || E != S)) M = F;
|
||||||
|
|
||||||
|
// Intersection rules
|
||||||
|
if ((E != F && all_eq4(E, C, I, D, Q) && all_eq2(F, B, H)) && (F != src(+3, +0))) K = M = F;
|
||||||
|
if ((E != D && all_eq4(E, A, G, F, R) && all_eq2(D, B, H)) && (D != src(-3, +0))) J = L = D;
|
||||||
|
if ((E != H && all_eq4(E, G, I, B, P) && all_eq2(H, D, F)) && (H != src(+0, +3))) L = M = H;
|
||||||
|
if ((E != B && all_eq4(E, A, C, H, S) && all_eq2(B, D, F)) && (B != src(+0, -3))) J = K = B;
|
||||||
|
if (Bl < El && all_eq4(E, G, H, I, S) && none_eq4(E, A, D, C, F)) J = K = B;
|
||||||
|
if (Hl < El && all_eq4(E, A, B, C, P) && none_eq4(E, D, G, I, F)) L = M = H;
|
||||||
|
if (Fl < El && all_eq4(E, A, D, G, Q) && none_eq4(E, B, C, I, H)) K = M = F;
|
||||||
|
if (Dl < El && all_eq4(E, C, F, I, R) && none_eq4(E, B, A, G, H)) J = L = D;
|
||||||
|
|
||||||
|
// 2:1 slope rules
|
||||||
|
if (H != B) {
|
||||||
|
if (H != A && H != E && H != C) {
|
||||||
|
if (all_eq3(H, G, F, R) && none_eq2(H, D, src(+2, -1))) L = M;
|
||||||
|
if (all_eq3(H, I, D, Q) && none_eq2(H, F, src(-2, -1))) M = L;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (B != I && B != G && B != E) {
|
||||||
|
if (all_eq3(B, A, F, R) && none_eq2(B, D, src(+2, +1))) J = K;
|
||||||
|
if (all_eq3(B, C, D, Q) && none_eq2(B, F, src(-2, +1))) K = J;
|
||||||
|
}
|
||||||
|
} // H !== B
|
||||||
|
|
||||||
|
if (F != D) {
|
||||||
|
if (D != I && D != E && D != C) {
|
||||||
|
if (all_eq3(D, A, H, S) && none_eq2(D, B, src(+1, +2))) J = L;
|
||||||
|
if (all_eq3(D, G, B, P) && none_eq2(D, H, src(+1, -2))) L = J;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (F != E && F != A && F != G) {
|
||||||
|
if (all_eq3(F, C, H, S) && none_eq2(F, B, src(-1, +2))) K = M;
|
||||||
|
if (all_eq3(F, I, B, P) && none_eq2(F, H, src(-1, -2))) M = K;
|
||||||
|
}
|
||||||
|
} // F !== D
|
||||||
|
} // not constant
|
||||||
|
|
||||||
|
// select quadrant based on fractional part of texture coordinates
|
||||||
|
float2 fpart = frac(coords);
|
||||||
|
uint res = (fpart.x < 0.5f) ? ((fpart.y < 0.5f) ? J : L) : ((fpart.y < 0.5f) ? K : M);
|
||||||
|
|
||||||
|
ialpha = float(res != 0u);
|
||||||
|
texcol = unpackUnorm4x8(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the luminance difference between two ABGR8 colors and normalize it
|
#undef src
|
||||||
float luma_distance(uint a, uint b)
|
)";
|
||||||
{
|
}
|
||||||
return abs(int(luma(a)) - int(luma(b))) * 0.0006535948f; // Multiplicative replacement for division by 1530
|
else if (texture_filter == GPUTextureFilter::MMPXEnhanced)
|
||||||
|
{
|
||||||
|
DefineMacro(ss, "TEXTURE_ALPHA_BLENDING", false);
|
||||||
|
DefineMacro(ss, "MMPX_ENHANCED", (texture_filter == GPUTextureFilter::MMPXEnhanced));
|
||||||
|
|
||||||
|
ss << "#define src(xoffs, yoffs) packUnorm4x8(SampleFromVRAM(texpage, clamp(bcoords + float2((xoffs), (yoffs)), "
|
||||||
|
"uv_limits.xy, uv_limits.zw)))\n";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This part of the shader is from MMPX.glc from https://casual-effects.com/research/McGuire2021PixelArt/index.html
|
||||||
|
* Copyright 2020 Morgan McGuire & Mara Gagiu.
|
||||||
|
* Provided under the Open Source MIT license https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
ss << R"(
|
||||||
|
uint luma(uint C) {
|
||||||
|
uint alpha = (C & 0xFF000000u) >> 24;
|
||||||
|
return (((C & 0x00FF0000u) >> 16) + ((C & 0x0000FF00u) >> 8) + (C & 0x000000FFu) + 1u) * (256u - alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool all_eq2(uint B, uint A0, uint A1) {
|
||||||
|
return ((B ^ A0) | (B ^ A1)) == 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_eq3(uint B, uint A0, uint A1, uint A2) {
|
||||||
|
return ((B ^ A0) | (B ^ A1) | (B ^ A2)) == 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_eq4(uint B, uint A0, uint A1, uint A2, uint A3) {
|
||||||
|
return ((B ^ A0) | (B ^ A1) | (B ^ A2) | (B ^ A3)) == 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool any_eq3(uint B, uint A0, uint A1, uint A2) {
|
||||||
|
return B == A0 || B == A1 || B == A2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool none_eq2(uint B, uint A0, uint A1) {
|
||||||
|
return (B != A0) && (B != A1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool none_eq4(uint B, uint A0, uint A1, uint A2, uint A3) {
|
||||||
|
return B != A0 && B != A1 && B != A2 && B != A3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Two-stage weak blending, mix/none
|
||||||
|
uint admix2d(uint a, uint b) {
|
||||||
|
float4 a_float = unpackUnorm4x8(a);
|
||||||
|
float4 b_float = unpackUnorm4x8(b);
|
||||||
|
float3 diff_rgb = a_float.rgb - b_float.rgb;
|
||||||
|
float rgbDist = dot(diff_rgb, diff_rgb);
|
||||||
|
|
||||||
|
// Combine conditional judgments (reduce branches)
|
||||||
|
bool aIsBlack = dot(a_float.rgb, a_float.rgb) < 0.01;
|
||||||
|
//bool aIsTransparent = a_float.a < 0.01;
|
||||||
|
//bool bIsTransparent = b_float.a < 0.01;
|
||||||
|
|
||||||
|
if (aIsBlack ) return b;
|
||||||
|
|
||||||
|
// Determine blending mode based on distance
|
||||||
|
float4 result;
|
||||||
|
if (rgbDist < 1.0) {
|
||||||
|
// Close distance: linearly blend RGB and Alpha
|
||||||
|
result = (a_float + b_float) * 0.5;
|
||||||
|
} else {
|
||||||
|
// Far distance: return b
|
||||||
|
result = b_float;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repack as uint
|
||||||
|
return packUnorm4x8(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*=============================================================================
|
/*=============================================================================
|
||||||
Helper function for 4-pixel intersection pattern matching: Scores the number of
|
Auxiliary function for 4-pixel cross determination: scores the number of matches at specific positions of the pattern.
|
||||||
matches for specific morphological positions. Three morphological conditions
|
Three pattern conditions are determined, requiring 6 points to be satisfied.
|
||||||
need to be met with a total score of 6.
|
|
||||||
┌───┬───┬───┐ ┌───┬───┬───┐
|
┌───┬───┬───┐ ┌───┬───┬───┐
|
||||||
│ A │ B │ C │ │ A │ B │ 1 │
|
│ A │ B │ C │ │ A │ B │ 1 │
|
||||||
├───┼───┼───┤ ├───┼───┼───┤
|
├───┼───┼───┤ ├───┼───┼───┤
|
||||||
@ -810,23 +929,26 @@ bool countPatternMatches(uint LA, uint LB, uint L1, uint L2, uint L3, uint L4, u
|
|||||||
int score3 = 0; // Horizontal/vertical line pattern
|
int score3 = 0; // Horizontal/vertical line pattern
|
||||||
int scoreBonus = 0;
|
int scoreBonus = 0;
|
||||||
|
|
||||||
// Jointly judge the visual difference between two pixels using RGB distance and luminance distance
|
// Replace Euclidean formula with dot product to save a square root calculation
|
||||||
float pixelDist = rgb_distance(LA, LB)*0.356822 + luma_distance(LA, LB)*0.382; // The ratio is the golden ratio
|
float4 a_float = unpackUnorm4x8(LA);
|
||||||
|
float4 b_float = unpackUnorm4x8(LB);
|
||||||
// Increase details for very similar colors and reduce details for highly contrasting colors (font edges).
|
float3 diff_rgb = a_float.rgb - b_float.rgb;
|
||||||
if (pixelDist < 0.12) { // Colors are quite similar
|
float rgbDist = dot(diff_rgb, diff_rgb);
|
||||||
|
|
||||||
|
// Add details for very close colors, reduce details for highly different colors (font edges)
|
||||||
|
if (rgbDist < 0.06386) { // Point set after quadratic golden section, colors are quite close
|
||||||
scoreBonus += 1;
|
scoreBonus += 1;
|
||||||
} else if (pixelDist > 0.9) { // Black and white contrast
|
} else if (rgbDist > 2.18847) { // Point set after quadratic golden section, significant difference
|
||||||
scoreBonus -= 1;
|
scoreBonus -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagonal patterns use a penalty system: intersections deduct points, meeting conditions adds points back
|
// Diagonals use a deduction system: deduct points for crosses, add back if conditions are met
|
||||||
// 1. Diagonal pattern ╲ (Condition: B = 2 or 4)
|
// 1. Diagonal pattern ╲ (Condition: B = 2 or 4)
|
||||||
if (LB == L2 || LB == L4) {
|
if (LB == L2 || LB == L4) {
|
||||||
score1 -= int(LB == L2 && LA == L1) * 1; // A-1, B-2 form an intersection, deduct points
|
score1 -= int(LB == L2 && LA == L1) * 1; // A-1 and B-2 form a cross, deduct points
|
||||||
score1 -= int(LB == L4 && LA == L5) * 1; // A-5, B-4 form an intersection, deduct points
|
score1 -= int(LB == L4 && LA == L5) * 1; // A-5 and B-4 form a cross, deduct points
|
||||||
|
|
||||||
// If the following triangular patterns are met, they can offset the intersection penalties
|
// If the following triangular pattern is satisfied, offset the above cross deductions
|
||||||
score1 += int(LB == L1 && L1 == L2) * 1; // B-1-2 form a triangular pattern, add points
|
score1 += int(LB == L1 && L1 == L2) * 1; // B-1-2 form a triangular pattern, add points
|
||||||
score1 += int(LB == L4 && L4 == L5) * 1; // B-4-5 form a triangular pattern, add points
|
score1 += int(LB == L4 && L4 == L5) * 1; // B-4-5 form a triangular pattern, add points
|
||||||
score1 += int(L2 == L3 && L3 == L4) * 1; // 2-3-4 form a triangular pattern, add points
|
score1 += int(L2 == L3 && L3 == L4) * 1; // 2-3-4 form a triangular pattern, add points
|
||||||
@ -836,11 +958,11 @@ bool countPatternMatches(uint LA, uint LB, uint L1, uint L2, uint L3, uint L4, u
|
|||||||
|
|
||||||
// 2. Diagonal pattern ╱ (Condition: A = 1 or 5)
|
// 2. Diagonal pattern ╱ (Condition: A = 1 or 5)
|
||||||
if (LA == L1 || LA == L5) {
|
if (LA == L1 || LA == L5) {
|
||||||
score2 -= int(LB == L2 && LA == L1) * 1; // A-1, B-2 intersection, deduct points
|
score2 -= int(LB == L2 && LA == L1) * 1; // A-1 and B-2 form a cross, deduct points
|
||||||
score2 -= int(LB == L4 && LA == L5) * 1; // A-5, B-4 intersection, deduct points
|
score2 -= int(LB == L4 && LA == L5) * 1; // A-5 and B-4 form a cross, deduct points
|
||||||
score2 -= int(LA == L3) * 1; // A-3 forms an intersection, deduct points
|
score2 -= int(LA == L3) * 1; // A-3 forms a cross, deduct points
|
||||||
|
|
||||||
// If the following triangular patterns are met, they can offset the intersection penalties
|
// If the following triangular pattern is satisfied, offset the above cross deductions
|
||||||
score2 += int(LB == L1 && L1 == L2) * 1; // B-1-2 form a triangular pattern, add points
|
score2 += int(LB == L1 && L1 == L2) * 1; // B-1-2 form a triangular pattern, add points
|
||||||
score2 += int(LB == L4 && L4 == L5) * 1; // B-4-5 form a triangular pattern, add points
|
score2 += int(LB == L4 && L4 == L5) * 1; // B-4-5 form a triangular pattern, add points
|
||||||
score2 += int(L2 == L3 && L3 == L4) * 1; // 2-3-4 form a triangular pattern, add points
|
score2 += int(L2 == L3 && L3 == L4) * 1; // 2-3-4 form a triangular pattern, add points
|
||||||
@ -848,45 +970,44 @@ bool countPatternMatches(uint LA, uint LB, uint L1, uint L2, uint L3, uint L4, u
|
|||||||
score2 += scoreBonus + 6;
|
score2 += scoreBonus + 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Horizontal/vertical line pattern (Condition: horizontal continuity) uses a reward system, only pass if conditions are met
|
// 3. Horizontal/vertical line pattern (Condition: horizontal continuity) uses a point addition system, passes only if conditions are met
|
||||||
if (LA == L2 || LB == L1 || LA == L4 || LB == L5 || (L1 == L2 && L2 == L3) || (L3 == L4 && L4 == L5)) {
|
if (LA == L2 || LB == L1 || LA == L4 || LB == L5 || (L1 == L2 && L2 == L3) || (L3 == L4 && L4 == L5)) {
|
||||||
score3 += int(LA == L2); // A same as 2 +1
|
score3 += int(LA == L2); // A equals 2, +1
|
||||||
score3 += int(LB == L1); // B same as 1 +1
|
score3 += int(LB == L1); // B equals 1, +1
|
||||||
score3 += int(L3 == L4); // 3 same as 4 +1
|
score3 += int(L3 == L4); // 3 equals 4, +1
|
||||||
score3 += int(L4 == L5); // 4 same as 5 +1
|
score3 += int(L4 == L5); // 4 equals 5, +1
|
||||||
score3 += int(L3 == L4 && L4 == L5); // 3-4-5 continuous
|
score3 += int(L3 == L4 && L4 == L5); // 3-4-5 continuous
|
||||||
|
|
||||||
score3 += int(LB == L5); // B same as 5 +1
|
score3 += int(LB == L5); // B equals 5, +1
|
||||||
score3 += int(LA == L4); // A same as 4 +1
|
score3 += int(LA == L4); // A equals 4, +1
|
||||||
score3 += int(L2 == L3); // 2 same as 3 +1
|
score3 += int(L2 == L3); // 2 equals 3, +1
|
||||||
score3 += int(L1 == L2); // 1 same as 2 +1
|
score3 += int(L1 == L2); // 1 equals 2, +1
|
||||||
score3 += int(L1 == L2 && L2 == L3); // 1-2-3 continuous
|
score3 += int(L1 == L2 && L2 == L3); // 1-2-3 continuous
|
||||||
|
|
||||||
// A x 4 square
|
// A x 4 square
|
||||||
score3 += int(LA == L2 && L2 == L3 && L3 == L4) * 2;
|
score3 += int(LA == L2 && L2 == L3 && L3 == L4) * 2;
|
||||||
|
|
||||||
// Patch for the previous rule to avoid bubbles in large cross-shaped patterns.
|
// Patch for the previous rule to avoid bubbles in large cross patterns. Some games use single-side patterns,
|
||||||
// Some games utilize single-sided patterns, so it's best to extend to bilateral judgment (WIP)
|
// so it's best to expand for bilateral judgment (Work in Progress)
|
||||||
score3 -= int(LB == L1 && L1 == L5 && LA == L2 && L2 == L4)*3;
|
score3 -= int(LB == L1 && L1 == L5 && LA == L2 && L2 == L4)*3;
|
||||||
|
|
||||||
score3 -= int(LA == L1 && LA == L5); // Deduct points if L1 and L5 are both A to avoid over-scoring
|
score3 -= int(LA == L1 && LA == L5); // Deduct points if both L1 and L5 are A to avoid excessive scores
|
||||||
// and the pattern turning into a diagonal pattern.
|
// and prevent the pattern from becoming a diagonal pattern.
|
||||||
|
|
||||||
// Bonus score
|
// Extra points
|
||||||
score3 += scoreBonus; // Experience: Even for very similar colors, don't add too many points here,
|
score3 += scoreBonus; // Experience: Even with very close colors, do not add too many points,
|
||||||
// as some Z-shaped intersections may produce bubbles
|
// as some Z-shaped crosses may produce bubbles.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take the maximum of the four scores
|
// Take the maximum of the four scores
|
||||||
int score = max(max(score1, score2), score3);
|
int score = max(max(score1, score2), score3);
|
||||||
|
|
||||||
return score < 6; // Need to reach 6 points
|
return score < 6; // Requires 6 points to be satisfied
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limits, out float4 texcol, out float ialpha)
|
void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limits, out float4 texcol, out float ialpha)
|
||||||
{
|
{
|
||||||
|
|
||||||
float2 bcoords = floor(coords);
|
float2 bcoords = floor(coords);
|
||||||
|
|
||||||
uint A = src(-1, -1), B = src(+0, -1), C = src(+1, -1);
|
uint A = src(-1, -1), B = src(+0, -1), C = src(+1, -1);
|
||||||
@ -895,79 +1016,74 @@ void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limi
|
|||||||
|
|
||||||
uint J = E, K = E, L = E, M = E;
|
uint J = E, K = E, L = E, M = E;
|
||||||
|
|
||||||
if (((A ^ E) | (B ^ E) | (C ^ E) | (D ^ E) | (F ^ E) | (G ^ E) | (H ^ E) | (I ^ E)) != 0u) {
|
// Explicitly initialize with the central pixel E by default
|
||||||
|
uint res = E;
|
||||||
|
ialpha = float(res != 0u);
|
||||||
|
texcol = unpackUnorm4x8(res);
|
||||||
|
|
||||||
|
if (((A ^ E) | (B ^ E) | (C ^ E) | (D ^ E) | (F ^ E) | (G ^ E) | (H ^ E) | (I ^ E)) == 0u) return;
|
||||||
|
|
||||||
uint P = src(+0, -2), S = src(+0, +2);
|
uint P = src(+0, -2), S = src(+0, +2);
|
||||||
uint Q = src(-2, +0), R = src(+2, +0);
|
uint Q = src(-2, +0), R = src(+2, +0);
|
||||||
uint Bl = luma(B), Dl = luma(D), El = luma(E), Fl = luma(F), Hl = luma(H);
|
uint Bl = luma(B), Dl = luma(D), El = luma(E), Fl = luma(F), Hl = luma(H);
|
||||||
|
|
||||||
#if MMPX_ENHANCED
|
|
||||||
if (
|
// Check the cross state of every 4 pixels in a "field" shape, and pass five surrounding pixels for pattern judgment
|
||||||
// Check for "convex" patterns to avoid single-pixel spurs on long line edges
|
if (A == E && B == D && A != B && countPatternMatches(A, B, C, F, I, H, G)) return;
|
||||||
(A == B && B == C && E == H && A != D && C != F && rgb_distance(D, F) < 0.2 && rgb_distance(B, E) > 0.6) ||
|
if (C == E && B == F && C != B && countPatternMatches(C, B, A, D, G, H, I)) return;
|
||||||
(A == D && D == G && E == F && A != B && G != H && rgb_distance(B, H) < 0.2 && rgb_distance(D, E) > 0.6) ||
|
if (G == E && D == H && G != H && countPatternMatches(G, H, I, F, C, B, A)) return;
|
||||||
(C == F && F == I && E == D && B != C && H != I && rgb_distance(B, H) < 0.2 && rgb_distance(E, F) > 0.6) ||
|
if (I == E && F == H && I != H && countPatternMatches(I, H, G, D, A, B, C)) return;
|
||||||
(G == H && H == I && B == E && D != G && F != I && rgb_distance(D, F) < 0.2 && rgb_distance(E, H) > 0.6) ||
|
|
||||||
|
|
||||||
// Check each 4-pixel intersection in a "grid" pattern and pass five surrounding pixels for pattern judgment
|
|
||||||
(A == E && B == D && A != B && countPatternMatches(A, B, C, F, I, H, G)) ||
|
|
||||||
(C == E && B == F && C != B && countPatternMatches(C, B, A, D, G, H, I)) ||
|
|
||||||
(G == E && D == H && G != H && countPatternMatches(G, H, I, F, C, B, A)) ||
|
|
||||||
(I == E && F == H && I != H && countPatternMatches(I, H, G, D, A, B, C))
|
|
||||||
) {
|
|
||||||
// Default to use center pixel E
|
|
||||||
// Fall through, J/K/L/M are already set to E. Setting the outputs here bugs out fxc.
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
// Original MMPX logic
|
|
||||||
|
|
||||||
// 1:1 slope rules
|
// main mmpx logic
|
||||||
if ((D == B && D != H && D != F) && (El >= Dl || E == A) && any_eq3(E, A, C, G) && ((El < Dl) || A != D || E != P || E != Q)) J = D;
|
|
||||||
if ((B == F && B != D && B != H) && (El >= Bl || E == C) && any_eq3(E, A, C, I) && ((El < Bl) || C != B || E != P || E != R)) K = B;
|
|
||||||
if ((H == D && H != F && H != B) && (El >= Hl || E == G) && any_eq3(E, A, G, I) && ((El < Hl) || G != H || E != S || E != Q)) L = H;
|
|
||||||
if ((F == H && F != B && F != D) && (El >= Fl || E == I) && any_eq3(E, C, G, I) && ((El < Fl) || I != H || E != R || E != S)) M = F;
|
|
||||||
|
|
||||||
// Intersection rules
|
// 1:1 slope rules
|
||||||
if ((E != F && all_eq4(E, C, I, D, Q) && all_eq2(F, B, H)) && (F != src(+3, +0))) K = M = F;
|
if ((D == B && D != H && D != F) && (El >= Dl || E == A) && any_eq3(E, A, C, G) && ((El < Dl) || A != D || E != P || E != Q)) J = D;
|
||||||
if ((E != D && all_eq4(E, A, G, F, R) && all_eq2(D, B, H)) && (D != src(-3, +0))) J = L = D;
|
if ((B == F && B != D && B != H) && (El >= Bl || E == C) && any_eq3(E, A, C, I) && ((El < Bl) || C != B || E != P || E != R)) K = B;
|
||||||
if ((E != H && all_eq4(E, G, I, B, P) && all_eq2(H, D, F)) && (H != src(+0, +3))) L = M = H;
|
if ((H == D && H != F && H != B) && (El >= Hl || E == G) && any_eq3(E, A, G, I) && ((El < Hl) || G != H || E != S || E != Q)) L = H;
|
||||||
if ((E != B && all_eq4(E, A, C, H, S) && all_eq2(B, D, F)) && (B != src(+0, -3))) J = K = B;
|
if ((F == H && F != B && F != D) && (El >= Fl || E == I) && any_eq3(E, C, G, I) && ((El < Fl) || I != H || E != R || E != S)) M = F;
|
||||||
if (Bl < El && all_eq4(E, G, H, I, S) && none_eq4(E, A, D, C, F)) J = K = B;
|
|
||||||
if (Hl < El && all_eq4(E, A, B, C, P) && none_eq4(E, D, G, I, F)) L = M = H;
|
|
||||||
if (Fl < El && all_eq4(E, A, D, G, Q) && none_eq4(E, B, C, I, H)) K = M = F;
|
|
||||||
if (Dl < El && all_eq4(E, C, F, I, R) && none_eq4(E, B, A, G, H)) J = L = D;
|
|
||||||
|
|
||||||
// 2:1 slope rules
|
// Intersection rules
|
||||||
if (H != B) {
|
if ((E != F && all_eq4(E, C, I, D, Q) && all_eq2(F, B, H)) && (F != src(+3, +0))) K = M = F;
|
||||||
if (H != A && H != E && H != C) {
|
if ((E != D && all_eq4(E, A, G, F, R) && all_eq2(D, B, H)) && (D != src(-3, +0))) J = L = D;
|
||||||
if (all_eq3(H, G, F, R) && none_eq2(H, D, src(+2, -1))) L = M;
|
if ((E != H && all_eq4(E, G, I, B, P) && all_eq2(H, D, F)) && (H != src(+0, +3))) L = M = H;
|
||||||
if (all_eq3(H, I, D, Q) && none_eq2(H, F, src(-2, -1))) M = L;
|
if ((E != B && all_eq4(E, A, C, H, S) && all_eq2(B, D, F)) && (B != src(+0, -3))) J = K = B;
|
||||||
}
|
|
||||||
|
|
||||||
if (B != I && B != G && B != E) {
|
// Use conditional weak blending instead of pixel copying to eliminate artifacts on straight lines
|
||||||
if (all_eq3(B, A, F, R) && none_eq2(B, D, src(+2, +1))) J = K;
|
if (Bl < El && all_eq4(E, G, H, I, S) && none_eq4(E, A, D, C, F)) {J=admix2d(B,J); K=admix2d(B,K);}
|
||||||
if (all_eq3(B, C, D, Q) && none_eq2(B, F, src(-2, +1))) K = J;
|
if (Hl < El && all_eq4(E, A, B, C, P) && none_eq4(E, D, G, I, F)) {L=admix2d(H,L); M=admix2d(H,M);}
|
||||||
}
|
if (Fl < El && all_eq4(E, A, D, G, Q) && none_eq4(E, B, C, I, H)) {K=admix2d(F,K); M=admix2d(F,M);}
|
||||||
} // H !== B
|
if (Dl < El && all_eq4(E, C, F, I, R) && none_eq4(E, B, A, G, H)) {J=admix2d(D,J); L=admix2d(D,L);}
|
||||||
|
|
||||||
if (F != D) {
|
// 2:1 slope rules
|
||||||
if (D != I && D != E && D != C) {
|
if (H != B) {
|
||||||
if (all_eq3(D, A, H, S) && none_eq2(D, B, src(+1, +2))) J = L;
|
if (H != A && H != E && H != C) {
|
||||||
if (all_eq3(D, G, B, P) && none_eq2(D, H, src(+1, -2))) L = J;
|
if (all_eq3(H, G, F, R) && none_eq2(H, D, src(+2, -1))) L = M;
|
||||||
}
|
if (all_eq3(H, I, D, Q) && none_eq2(H, F, src(-2, -1))) M = L;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (B != I && B != G && B != E) {
|
||||||
|
if (all_eq3(B, A, F, R) && none_eq2(B, D, src(+2, +1))) J = K;
|
||||||
|
if (all_eq3(B, C, D, Q) && none_eq2(B, F, src(-2, +1))) K = J;
|
||||||
|
}
|
||||||
|
} // H !== B
|
||||||
|
|
||||||
|
if (F != D) {
|
||||||
|
if (D != I && D != E && D != C) {
|
||||||
|
if (all_eq3(D, A, H, S) && none_eq2(D, B, src(+1, +2))) J = L;
|
||||||
|
if (all_eq3(D, G, B, P) && none_eq2(D, H, src(+1, -2))) L = J;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (F != E && F != A && F != G) {
|
||||||
|
if (all_eq3(F, C, H, S) && none_eq2(F, B, src(-1, +2))) K = M;
|
||||||
|
if (all_eq3(F, I, B, P) && none_eq2(F, H, src(-1, -2))) M = K;
|
||||||
|
}
|
||||||
|
} // F !== D
|
||||||
|
|
||||||
if (F != E && F != A && F != G) {
|
|
||||||
if (all_eq3(F, C, H, S) && none_eq2(F, B, src(-1, +2))) K = M;
|
|
||||||
if (all_eq3(F, I, B, P) && none_eq2(F, H, src(-1, -2))) M = K;
|
|
||||||
}
|
|
||||||
} // F !== D
|
|
||||||
#if MMPX_ENHANCED
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} // not constant
|
|
||||||
|
|
||||||
// select quadrant based on fractional part of texture coordinates
|
// select quadrant based on fractional part of texture coordinates
|
||||||
float2 fpart = frac(coords);
|
float2 fpart = frac(coords);
|
||||||
uint res = (fpart.x < 0.5f) ? ((fpart.y < 0.5f) ? J : L) : ((fpart.y < 0.5f) ? K : M);
|
res = (fpart.x < 0.5f) ? ((fpart.y < 0.5f) ? J : L) : ((fpart.y < 0.5f) ? K : M);
|
||||||
|
|
||||||
ialpha = float(res != 0u);
|
ialpha = float(res != 0u);
|
||||||
texcol = unpackUnorm4x8(res);
|
texcol = unpackUnorm4x8(res);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user