1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef SHADERS_COMMON_FXAA_REFERENCE_H
17 #define SHADERS_COMMON_FXAA_REFERENCE_H
18
19 #define FXAA_USE_PATCHES 1
20
21 // prefer high quality
22 #define FXAA_QUALITY 29
23
24 /**
25 * Based on the NVIDIA FXAA 3.11 reference implementation by TIMOTHY LOTTES
26 * See: https://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf
27 */
28
29 // integration settings
30 #ifndef FXAA_USE_PATCHES
31 #define FXAA_USE_PATCHES 0
32 #endif
33
34 #ifndef FXAA_LUMA_GREEN
35 #define FXAA_LUMA_GREEN 0
36 #endif
37
38 #define FxaaTexTop(t, s, p) textureLod(sampler2D(t, s), p, 0.0)
39 #define FxaaTexOff(t, s, p, o, r) textureLodOffset(sampler2D(t, s), p, 0.0, o)
40
41 #if (FXAA_LUMA_GREEN == 0)
FxaaCompLuma(vec4 rgba)42 float FxaaCompLuma(vec4 rgba)
43 {
44 return rgba.w;
45 }
46 #else
FxaaCompLuma(vec4 rgba)47 float FxaaCompLuma(vec4 rgba)
48 {
49 return rgba.y;
50 }
51 #endif
52
FxaaPixelShader(vec2 fragCoord,vec4 neighborCoords,texture2D texture,sampler samp,vec2 invFrameSize,vec4 invFrameOpt,vec4 invFrameOpt2,vec4 console360InvFrameOpt2,float subpixelQuality,float edgeThresholdQuality,float edgeThresholdMinQuality,float edgeSharpness,float edgeThreshold,float edgeThresholdMin,vec4 console360ConstDir)53 vec4 FxaaPixelShader(vec2 fragCoord, vec4 neighborCoords, texture2D texture, sampler samp, vec2 invFrameSize,
54 vec4 invFrameOpt, vec4 invFrameOpt2, vec4 console360InvFrameOpt2, float subpixelQuality, float edgeThresholdQuality,
55 float edgeThresholdMinQuality, float edgeSharpness, float edgeThreshold, float edgeThresholdMin,
56 vec4 console360ConstDir)
57 {
58 const float lumaNw = FxaaCompLuma(FxaaTexTop(texture, samp, neighborCoords.xy));
59 const float lumaSw = FxaaCompLuma(FxaaTexTop(texture, samp, neighborCoords.xw));
60 float lumaNe = FxaaCompLuma(FxaaTexTop(texture, samp, neighborCoords.zy));
61 const float lumaSe = FxaaCompLuma(FxaaTexTop(texture, samp, neighborCoords.zw));
62
63 // current pixel's color and luminance
64 const vec4 colorM = FxaaTexTop(texture, samp, fragCoord.xy);
65
66 #if (FXAA_LUMA_GREEN == 0)
67 const float lumaM = colorM.w;
68 #else
69 const float lumaM = colorM.y;
70 #endif
71
72 // min-max luminance around the pixel
73 const float lumaMaxNwSw = max(lumaNw, lumaSw);
74 #if FXAA_USE_PATCHES == 0
75 lumaNe += 1.0 / 384.0;
76 #endif
77 const float lumaMinNwSw = min(lumaNw, lumaSw);
78 const float lumaMaxNeSe = max(lumaNe, lumaSe);
79 const float lumaMinNeSe = min(lumaNe, lumaSe);
80 const float lumaMax = max(lumaMaxNeSe, lumaMaxNwSw);
81 const float lumaMin = min(lumaMinNeSe, lumaMinNwSw);
82
83 const float lumaMaxScaled = lumaMax * edgeThreshold;
84
85 const float lumaMinM = min(lumaMin, lumaM);
86 const float lumaMaxScaledClamped = max(edgeThresholdMin, lumaMaxScaled);
87
88 const float lumaMaxM = max(lumaMax, lumaM);
89
90 // edge direction
91 float dirSwMinusNe = lumaSw - lumaNe;
92 #if FXAA_USE_PATCHES
93 dirSwMinusNe += 1.0 / 512.0;
94 #endif
95
96 const float lumaRange = lumaMaxM - lumaMinM;
97 const float dirSeMinusNw = lumaSe - lumaNw;
98
99 if (lumaRange < lumaMaxScaledClamped) {
100 return colorM;
101 }
102
103 vec2 edgeDir;
104 edgeDir.x = dirSwMinusNe + dirSeMinusNw;
105 edgeDir.y = dirSwMinusNe - dirSeMinusNw;
106 const vec2 normEdgeDir = normalize(edgeDir.xy);
107
108 // sample colors along the edge
109 const vec4 colorN1 = FxaaTexTop(texture, samp, fragCoord.xy - normEdgeDir * invFrameOpt.zw);
110 const vec4 colorP1 = FxaaTexTop(texture, samp, fragCoord.xy + normEdgeDir * invFrameOpt.zw);
111
112 #if FXAA_USE_PATCHES
113 const float dirAbsMinTimesC = max(abs(normEdgeDir.x), abs(normEdgeDir.y)) * edgeSharpness * 0.015;
114 const vec2 scaledEdgeDir = normEdgeDir.xy * min(lumaRange / dirAbsMinTimesC, 3);
115 #else
116 const float dirAbsMinTimesC = min(abs(normEdgeDir.x), abs(normEdgeDir.y)) * edgeSharpness;
117 const vec2 scaledEdgeDir = clamp(normEdgeDir.xy / dirAbsMinTimesC, -2, 2);
118 #endif
119
120 const vec4 colorN2 = FxaaTexTop(texture, samp, fragCoord.xy - scaledEdgeDir * invFrameOpt2.zw);
121 const vec4 colorP2 = FxaaTexTop(texture, samp, fragCoord.xy + scaledEdgeDir * invFrameOpt2.zw);
122
123 const vec4 blendedA = colorN1 + colorP1;
124 vec4 blendedB = ((colorN2 + colorP2) * 0.25) + (blendedA * 0.25);
125
126 #if (FXAA_LUMA_GREEN == 0)
127 const bool useTwoTap = (blendedB.w < lumaMin) || (blendedB.w > lumaMax);
128 #else
129 const bool useTwoTap = (blendedB.y < lumaMin) || (blendedB.y > lumaMax);
130 #endif
131 if (useTwoTap) {
132 blendedB.xyz = blendedA.xyz * 0.5;
133 }
134
135 #if FXAA_USE_PATCHES
136 blendedB = mix(blendedB, colorM, 0.25);
137 #endif
138 return blendedB;
139 }
140
141 #endif // SHADERS_COMMON_FXAA_REFERENCE_H
142