KiCad PCB EDA Suite
gl_builtin_shaders.cpp
Go to the documentation of this file.
1 /*
2 * This program source code file is part of KICAD, a free EDA CAD application.
3 *
4 * Copyright (C) 2016 Kicad Developers, see change_log.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23 
24 #include "gl_builtin_shaders.h"
25 
26 namespace KIGFX {
27 namespace BUILTIN_SHADERS {
28 
29 /*
30  *
31  * KiCad shaders
32  *
33  */
34 
35 const char kicad_vertex_shader[] = R"SHADER_SOURCE(
36 
37 /*
38  * This program source code file is part of KICAD, a free EDA CAD application.
39  *
40  * Copyright (C) 2013-2016 CERN
41  * @author Maciej Suminski <maciej.suminski@cern.ch>
42  *
43  * Vertex shader
44  *
45  * This program is free software; you can redistribute it and/or
46  * modify it under the terms of the GNU General Public License
47  * as published by the Free Software Foundation; either version 2
48  * of the License, or (at your option) any later version.
49  *
50  * This program is distributed in the hope that it will be useful,
51  * but WITHOUT ANY WARRANTY; without even the implied warranty of
52  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53  * GNU General Public License for more details.
54  *
55  * You should have received a copy of the GNU General Public License
56  * along with this program; if not, you may find one here:
57  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
58  * or you may search the http://www.gnu.org website for the version 2 license,
59  * or you may write to the Free Software Foundation, Inc.,
60  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
61  */
62 
63 #version 120
64 
65 // Shader types
66 const float SHADER_FILLED_CIRCLE = 2.0;
67 const float SHADER_STROKED_CIRCLE = 3.0;
68 const float SHADER_FONT = 4.0;
69 const float SHADER_LINE_A = 5.0;
70 const float SHADER_LINE_B = 6.0;
71 const float SHADER_LINE_C = 7.0;
72 const float SHADER_LINE_D = 8.0;
73 const float SHADER_LINE_E = 9.0;
74 const float SHADER_LINE_F = 10.0;
75 
76 // Minimum line width
77 const float MIN_WIDTH = 1.0;
78 
79 attribute vec4 attrShaderParams;
80 varying vec4 shaderParams;
81 varying vec2 circleCoords;
82 uniform float worldPixelSize;
83 
84 void computeLineCoords( bool posture, vec2 offset, vec2 texcoord, vec2 dir )
85 {
86  float w = length( offset );
87 
88  if( w > worldPixelSize )
89  {
90  gl_Position = gl_ModelViewProjectionMatrix * vec4( gl_Vertex.x + offset.x, gl_Vertex.y + offset.y, gl_Vertex.z, gl_Vertex.w );
91  shaderParams[0] = SHADER_LINE_A;
92  gl_TexCoord[0].st = texcoord;
93  }
94  else
95  {
96  vec4 pos = gl_Vertex;
97  pos.xy += ( posture ? dir : dir.yx ) * worldPixelSize / 2.0;
98  gl_Position = gl_ModelViewProjectionMatrix * pos;
99  shaderParams[0] = SHADER_LINE_B;
100  }
101 }
102 
103 
104 void main()
105 {
106  float mode = attrShaderParams[0];
107 
108  // Pass attributes to the fragment shader
109  shaderParams = attrShaderParams;
110 
111  float aspect = shaderParams.y;
112  vec2 vs = shaderParams.zw;
113  vec2 vp = vec2(-vs.y, vs.x);
114  bool posture = abs( vs.x ) < abs(vs.y);
115 
116  if( mode == SHADER_LINE_A )
117  computeLineCoords( posture, vp - vs, vec2( -aspect, -1 ), vec2( -1, 0 ) );
118  else if( mode == SHADER_LINE_B )
119  computeLineCoords( posture, -vp - vs, vec2( -aspect, 1 ), vec2( 1, 0 ) );
120  else if( mode == SHADER_LINE_C )
121  computeLineCoords( posture, -vp + vs, vec2( aspect, 1 ), vec2( 1, 0 ) );
122  else if( mode == SHADER_LINE_D )
123  computeLineCoords( posture, -vp + vs, vec2( -aspect, -1 ), vec2( 1, 0 ) );
124  else if( mode == SHADER_LINE_E )
125  computeLineCoords( posture, vp + vs, vec2( -aspect, 1 ), vec2( -1, 0 ) );
126  else if( mode == SHADER_LINE_F )
127  computeLineCoords( posture, vp - vs, vec2( aspect, 1 ), vec2( -1, 0 ) );
128  else if( mode == SHADER_STROKED_CIRCLE ||
129  mode == SHADER_FILLED_CIRCLE )
130  {
131  // Compute relative circle coordinates basing on indices
132  // Circle
133  if( shaderParams[1] == 1.0 )
134  circleCoords = vec2( -sqrt( 3.0 ), -1.0 );
135  else if( shaderParams[1] == 2.0 )
136  circleCoords = vec2( sqrt( 3.0 ), -1.0 );
137  else if( shaderParams[1] == 3.0 )
138  circleCoords = vec2( 0.0, 2.0 );
139 
140  // Semicircle
141  else if( shaderParams[1] == 4.0 )
142  circleCoords = vec2( -3.0 / sqrt( 3.0 ), 0.0 );
143  else if( shaderParams[1] == 5.0 )
144  circleCoords = vec2( 3.0 / sqrt( 3.0 ), 0.0 );
145  else if( shaderParams[1] == 6.0 )
146  circleCoords = vec2( 0.0, 2.0 );
147 
148  // Make the line appear to be at least 1 pixel wide
149  float lineWidth = shaderParams[3];
150  float worldScale = abs( gl_ModelViewMatrix[0][0] );
151 
152  if( worldScale * lineWidth < MIN_WIDTH )
153  shaderParams[3] = shaderParams[3] / ( worldScale * lineWidth );
154 
155  gl_Position = ftransform();
156  }
157  else
158  {
159  // Pass through the coordinates like in the fixed pipeline
160  gl_Position = ftransform();
161  }
162 
163  gl_FrontColor = gl_Color;
164 }
165 
166 )SHADER_SOURCE";
167 
168 const char kicad_fragment_shader[] = R"SHADER_SOURCE(
169 
170 /*
171  * This program source code file is part of KICAD, a free EDA CAD application.
172  *
173  * Copyright (C) 2013-2016 CERN
174  * Copyright (C) 2016 Kicad Developers, see authors.txt for contributors.
175  * @author Maciej Suminski <maciej.suminski@cern.ch>
176  *
177  * Fragment shader
178  *
179  * This program is free software; you can redistribute it and/or
180  * modify it under the terms of the GNU General Public License
181  * as published by the Free Software Foundation; either version 2
182  * of the License, or (at your option) any later version.
183  *
184  * This program is distributed in the hope that it will be useful,
185  * but WITHOUT ANY WARRANTY; without even the implied warranty of
186  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
187  * GNU General Public License for more details.
188  *
189  * You should have received a copy of the GNU General Public License
190  * along with this program; if not, you may find one here:
191  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
192  * or you may search the http://www.gnu.org website for the version 2 license,
193  * or you may write to the Free Software Foundation, Inc.,
194  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
195  */
196 
197 #version 120
198 
199 // Multi-channel signed distance field
200 #define USE_MSDF
201 
202 // Shader types
203 const float SHADER_FILLED_CIRCLE = 2.0;
204 const float SHADER_STROKED_CIRCLE = 3.0;
205 const float SHADER_FONT = 4.0;
206 const float SHADER_LINE_A = 5.0;
207 const float SHADER_LINE_B = 6.0;
208 
209 varying vec4 shaderParams;
210 varying vec2 circleCoords;
211 uniform sampler2D fontTexture;
212 uniform float worldPixelSize;
213 
214 // Needed to reconstruct the mipmap level / texel derivative
215 uniform int fontTextureWidth;
216 
217 void filledCircle( vec2 aCoord )
218 {
219  if( dot( aCoord, aCoord ) < 1.0 )
220  gl_FragColor = gl_Color;
221  else
222  discard;
223 }
224 
225 float pixelSegDistance( vec2 aCoord )
226 {
227  if( shaderParams[0] == SHADER_LINE_B )
228  {
229  gl_FragColor = gl_Color;
230  return 0.0;
231  }
232 
233  float aspect = shaderParams[1];
234  float dist;
235  vec2 v = vec2( 1.0 - ( aspect - abs( aCoord.s ) ), aCoord.t );
236 
237  if( v.x <= 0.0 )
238  {
239  dist = abs( aCoord.t );
240  }
241  else
242  {
243  dist = length( v );
244  }
245 
246  return dist;
247 }
248 
249 int isPixelInSegment( vec2 aCoord )
250 {
251  return pixelSegDistance( aCoord ) <= 1.0 ? 1 : 0;
252 }
253 
254 
255 
256 void strokedCircle( vec2 aCoord, float aRadius, float aWidth )
257 {
258  float outerRadius = max( aRadius + ( aWidth / 2 ), 0.0 );
259  float innerRadius = max( aRadius - ( aWidth / 2 ), 0.0 );
260  float relWidth = innerRadius / outerRadius;
261 
262  if( ( dot( aCoord, aCoord ) < 1.0 ) &&
263  ( dot( aCoord, aCoord ) > relWidth * relWidth ) )
264  gl_FragColor = gl_Color;
265  else
266  discard;
267 }
268 
269 
270 void drawLine( vec2 aCoord )
271 {
272  if( isPixelInSegment( aCoord ) != 0)
273  gl_FragColor = gl_Color;
274  else
275  discard;
276 }
277 
278 #ifdef USE_MSDF
279 float median( vec3 v )
280 {
281  return max( min( v.r, v.g ), min( max( v.r, v.g ), v.b ) );
282 }
283 #endif
284 
285 void main()
286 {
287  if( shaderParams[0] == SHADER_LINE_A )
288  {
289  drawLine( gl_TexCoord[0].st );
290  }
291  else if( shaderParams[0] == SHADER_FILLED_CIRCLE )
292  {
293  filledCircle( circleCoords );
294  }
295  else if( shaderParams[0] == SHADER_STROKED_CIRCLE )
296  {
297  strokedCircle( circleCoords, shaderParams[2], shaderParams[3] );
298  }
299  else if( shaderParams[0] == SHADER_FONT )
300  {
301  vec2 tex = shaderParams.yz;
302 
303  // Unless we're stretching chars it is okay to consider
304  // one derivative for filtering
305  float derivative = length( dFdx( tex ) ) * fontTextureWidth / 4;
306 
307 #ifdef USE_MSDF
308  float dist = median( texture2D( fontTexture, tex ).rgb );
309 #else
310  float dist = texture2D( fontTexture, tex ).r;
311 #endif
312 
313  // use the derivative for zoom-adaptive filtering
314  float alpha = smoothstep( 0.5 - derivative, 0.5 + derivative, dist );
315 
316  gl_FragColor = vec4( gl_Color.rgb, alpha );
317  }
318  else
319  {
320  // Simple pass-through
321  gl_FragColor = gl_Color;
322  }
323 }
324 
325 )SHADER_SOURCE";
326 
327 const char ssaa_x4_vertex_shader[] = R"SHADER_SOURCE(
328 
329 #version 120
330 varying vec2 texcoord;
331 void main()
332 {
333  texcoord = gl_MultiTexCoord0.st;
334  gl_Position = ftransform();
335 }
336 
337 )SHADER_SOURCE";
338 
339 const char ssaa_x4_fragment_shader[] = R"SHADER_SOURCE(
340 
341 #version 120
342 varying vec2 texcoord;
343 uniform sampler2D source;
344 void main()
345 {
346  float step_x = dFdx(texcoord.x)/4.;
347  float step_y = dFdy(texcoord.y)/4.;
348 
349  vec4 q00 = texture2D( source, texcoord + vec2(-step_x, -step_y) );
350  vec4 q01 = texture2D( source, texcoord + vec2( step_x, -step_y) );
351  vec4 q10 = texture2D( source, texcoord + vec2(-step_x, step_y) );
352  vec4 q11 = texture2D( source, texcoord + vec2( step_x, step_y) );
353 
354  gl_FragColor = (q00+q01+q10+q11)/4;
355 }
356 
357 )SHADER_SOURCE";
358 
359 const char smaa_base_shader_p1[] = R"SHADER_SOURCE(
360 
658 //-----------------------------------------------------------------------------
659 // SMAA Presets
660 
666 #if defined(SMAA_PRESET_LOW)
667 #define SMAA_THRESHOLD 0.15
668 #define SMAA_MAX_SEARCH_STEPS 4
669 #define SMAA_DISABLE_DIAG_DETECTION
670 #define SMAA_DISABLE_CORNER_DETECTION
671 #elif defined(SMAA_PRESET_MEDIUM)
672 #define SMAA_THRESHOLD 0.1
673 #define SMAA_MAX_SEARCH_STEPS 8
674 #define SMAA_DISABLE_DIAG_DETECTION
675 #define SMAA_DISABLE_CORNER_DETECTION
676 #elif defined(SMAA_PRESET_HIGH)
677 #define SMAA_THRESHOLD 0.1
678 #define SMAA_MAX_SEARCH_STEPS 16
679 #define SMAA_MAX_SEARCH_STEPS_DIAG 8
680 #define SMAA_CORNER_ROUNDING 25
681 #elif defined(SMAA_PRESET_ULTRA)
682 #define SMAA_THRESHOLD 0.005
683 //0.05
684 #define SMAA_MAX_SEARCH_STEPS 64
685 //32
686 #define SMAA_MAX_SEARCH_STEPS_DIAG 32
687 //16
688 #define SMAA_CORNER_ROUNDING 25
689 #endif
690 
691 //-----------------------------------------------------------------------------
692 // Configurable Defines
693 
706 #ifndef SMAA_THRESHOLD
707 #define SMAA_THRESHOLD 0.1
708 #endif
709 
715 #ifndef SMAA_DEPTH_THRESHOLD
716 #define SMAA_DEPTH_THRESHOLD (0.1 * SMAA_THRESHOLD)
717 #endif
718 
729 #ifndef SMAA_MAX_SEARCH_STEPS
730 #define SMAA_MAX_SEARCH_STEPS 16
731 #endif
732 )SHADER_SOURCE";
733 
734 const char smaa_base_shader_p2[] = R"SHADER_SOURCE(
747 #ifndef SMAA_MAX_SEARCH_STEPS_DIAG
748 #define SMAA_MAX_SEARCH_STEPS_DIAG 8
749 #endif
750 
758 #ifndef SMAA_CORNER_ROUNDING
759 #define SMAA_CORNER_ROUNDING 25
760 #endif
761 
770 #ifndef SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR
771 #define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.0
772 #endif
773 
788 #ifndef SMAA_PREDICATION
789 #define SMAA_PREDICATION 0
790 #endif
791 
798 #ifndef SMAA_PREDICATION_THRESHOLD
799 #define SMAA_PREDICATION_THRESHOLD 0.01
800 #endif
801 
808 #ifndef SMAA_PREDICATION_SCALE
809 #define SMAA_PREDICATION_SCALE 2.0
810 #endif
811 
817 #ifndef SMAA_PREDICATION_STRENGTH
818 #define SMAA_PREDICATION_STRENGTH 0.4
819 #endif
820 
832 #ifndef SMAA_REPROJECTION
833 #define SMAA_REPROJECTION 0
834 #endif
835 
847 #ifndef SMAA_REPROJECTION_WEIGHT_SCALE
848 #define SMAA_REPROJECTION_WEIGHT_SCALE 30.0
849 #endif
850 
855 #ifndef SMAA_INCLUDE_VS
856 #define SMAA_INCLUDE_VS 1
857 #endif
858 #ifndef SMAA_INCLUDE_PS
859 #define SMAA_INCLUDE_PS 1
860 #endif
861 
862 //-----------------------------------------------------------------------------
863 // Texture Access Defines
864 
865 #ifndef SMAA_AREATEX_SELECT
866 #if defined(SMAA_HLSL_3)
867 #define SMAA_AREATEX_SELECT(sample) sample.ra
868 #else
869 #define SMAA_AREATEX_SELECT(sample) sample.rg
870 #endif
871 #endif
872 
873 #ifndef SMAA_SEARCHTEX_SELECT
874 #define SMAA_SEARCHTEX_SELECT(sample) sample.r
875 #endif
876 
877 #ifndef SMAA_DECODE_VELOCITY
878 #define SMAA_DECODE_VELOCITY(sample) sample.rg
879 #endif
880 
881 //-----------------------------------------------------------------------------
882 // Non-Configurable Defines
883 
884 #define SMAA_AREATEX_MAX_DISTANCE 16
885 #define SMAA_AREATEX_MAX_DISTANCE_DIAG 20
886 #define SMAA_AREATEX_PIXEL_SIZE (1.0 / float2(160.0, 560.0))
887 #define SMAA_AREATEX_SUBTEX_SIZE (1.0 / 7.0)
888 #define SMAA_SEARCHTEX_SIZE float2(66.0, 33.0)
889 #define SMAA_SEARCHTEX_PACKED_SIZE float2(64.0, 16.0)
890 #define SMAA_CORNER_ROUNDING_NORM (float(SMAA_CORNER_ROUNDING) / 100.0)
891 
892 //-----------------------------------------------------------------------------
893 // Porting Functions
894 
895 #if defined(SMAA_HLSL_3)
896 #define SMAATexture2D(tex) sampler2D tex
897 #define SMAATexturePass2D(tex) tex
898 #define SMAASampleLevelZero(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0))
899 #define SMAASampleLevelZeroPoint(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0))
900 #define SMAASampleLevelZeroOffset(tex, coord, offset) tex2Dlod(tex, float4(coord + offset * SMAA_RT_METRICS.xy, 0.0, 0.0))
901 #define SMAASample(tex, coord) tex2D(tex, coord)
902 #define SMAASamplePoint(tex, coord) tex2D(tex, coord)
903 #define SMAASampleOffset(tex, coord, offset) tex2D(tex, coord + offset * SMAA_RT_METRICS.xy)
904 #define SMAA_FLATTEN [flatten]
905 #define SMAA_BRANCH [branch]
906 #endif
907 #if defined(SMAA_HLSL_4) || defined(SMAA_HLSL_4_1)
908 SamplerState LinearSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; };
909 SamplerState PointSampler { Filter = MIN_MAG_MIP_POINT; AddressU = Clamp; AddressV = Clamp; };
910 #define SMAATexture2D(tex) Texture2D tex
911 #define SMAATexturePass2D(tex) tex
912 #define SMAASampleLevelZero(tex, coord) tex.SampleLevel(LinearSampler, coord, 0)
913 #define SMAASampleLevelZeroPoint(tex, coord) tex.SampleLevel(PointSampler, coord, 0)
914 #define SMAASampleLevelZeroOffset(tex, coord, offset) tex.SampleLevel(LinearSampler, coord, 0, offset)
915 #define SMAASample(tex, coord) tex.Sample(LinearSampler, coord)
916 #define SMAASamplePoint(tex, coord) tex.Sample(PointSampler, coord)
917 #define SMAASampleOffset(tex, coord, offset) tex.Sample(LinearSampler, coord, offset)
918 #define SMAA_FLATTEN [flatten]
919 #define SMAA_BRANCH [branch]
920 #define SMAATexture2DMS2(tex) Texture2DMS<float4, 2> tex
921 #define SMAALoad(tex, pos, sample) tex.Load(pos, sample)
922 #if defined(SMAA_HLSL_4_1)
923 #define SMAAGather(tex, coord) tex.Gather(LinearSampler, coord, 0)
924 #endif
925 #endif
926 #if defined(SMAA_GLSL_2_1) || defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4)
927 #define SMAATexture2D(tex) sampler2D tex
928 #define SMAATexturePass2D(tex) tex
929 #define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0)
930 #define SMAASampleLevelZeroPoint(tex, coord) textureLod(tex, coord, 0.0)
931 #define SMAASampleLevelZeroOffset(tex, coord, offset) textureLodOffset(tex, coord, 0.0, offset)
932 #if defined(SMAA_GLSL_2_1)
933 #define SMAASample(tex, coord) texture2D(tex, coord)
934 #define SMAASamplePoint(tex, coord) texture2D(tex, coord)
935 #define SMAASampleOffset(tex, coord, offset) texture2D(tex, coord + offset * SMAA_RT_METRICS.rg)
936 #define round(x) floor(x + 0.5)
937 #define textureLod(tex, coord, level) texture2D(tex, coord)
938 #define textureLodOffset(tex, coord, level, offset) texture2D(tex, coord + offset * SMAA_RT_METRICS.rg)
939 #else
940 #define SMAASample(tex, coord) texture(tex, coord)
941 #define SMAASamplePoint(tex, coord) texture(tex, coord)
942 #define SMAASampleOffset(tex, coord, offset) texture(tex, coord, offset)
943 #endif
944 #define SMAA_FLATTEN
945 #define SMAA_BRANCH
946 #define lerp(a, b, t) mix(a, b, t)
947 #define saturate(a) clamp(a, 0.0, 1.0)
948 #if defined(SMAA_GLSL_4)
949 #define mad(a, b, c) fma(a, b, c)
950 #define SMAAGather(tex, coord) textureGather(tex, coord)
951 #else
952 #define mad(a, b, c) (a * b + c)
953 #endif
954 #define float2 vec2
955 #define float3 vec3
956 #define float4 vec4
957 #define int2 ivec2
958 #define int3 ivec3
959 #define int4 ivec4
960 #define bool2 bvec2
961 #define bool3 bvec3
962 #define bool4 bvec4
963 #endif
964 
965 #if !defined(SMAA_HLSL_3) && !defined(SMAA_HLSL_4) && !defined(SMAA_HLSL_4_1) && !defined(SMAA_GLSL_2_1) && !defined(SMAA_GLSL_3) && !defined(SMAA_GLSL_4) && !defined(SMAA_CUSTOM_SL)
966 #error you must define the shading language: SMAA_HLSL_*, SMAA_GLSL_* or SMAA_CUSTOM_SL
967 #endif
968 
969 //-----------------------------------------------------------------------------
970 // Misc functions
971 
975 float3 SMAAGatherNeighbours(float2 texcoord,
976  float4 offset[3],
977  SMAATexture2D(tex)) {
978  #ifdef SMAAGather
979  return SMAAGather(tex, texcoord + SMAA_RT_METRICS.xy * float2(-0.5, -0.5)).grb;
980  #else
981  float P = SMAASamplePoint(tex, texcoord).r;
982  float Pleft = SMAASamplePoint(tex, offset[0].xy).r;
983  float Ptop = SMAASamplePoint(tex, offset[0].zw).r;
984  return float3(P, Pleft, Ptop);
985  #endif
986 }
987 
991 float2 SMAACalculatePredicatedThreshold(float2 texcoord,
992  float4 offset[3],
993  SMAATexture2D(predicationTex)) {
994  float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(predicationTex));
995  float2 delta = abs(neighbours.xx - neighbours.yz);
996  float2 edges = step(SMAA_PREDICATION_THRESHOLD, delta);
997  return SMAA_PREDICATION_SCALE * SMAA_THRESHOLD * (1.0 - SMAA_PREDICATION_STRENGTH * edges);
998 }
999 
1003 void SMAAMovc(bool2 cond, inout float2 variable, float2 value) {
1004  SMAA_FLATTEN if (cond.x) variable.x = value.x;
1005  SMAA_FLATTEN if (cond.y) variable.y = value.y;
1006 }
1007 
1008 void SMAAMovc(bool4 cond, inout float4 variable, float4 value) {
1009  SMAAMovc(cond.xy, variable.xy, value.xy);
1010  SMAAMovc(cond.zw, variable.zw, value.zw);
1011 }
1012 
1013 
1014 #if SMAA_INCLUDE_VS
1015 //-----------------------------------------------------------------------------
1016 // Vertex Shaders
1017 
1021 void SMAAEdgeDetectionVS(float2 texcoord,
1022  out float4 offset[3]) {
1023  offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-1.0, 0.0, 0.0, -1.0), texcoord.xyxy);
1024  offset[1] = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy);
1025  offset[2] = mad(SMAA_RT_METRICS.xyxy, float4(-2.0, 0.0, 0.0, -2.0), texcoord.xyxy);
1026 }
1027 
1031 void SMAABlendingWeightCalculationVS(float2 texcoord,
1032  out float2 pixcoord,
1033  out float4 offset[3]) {
1034  pixcoord = texcoord * SMAA_RT_METRICS.zw;
1035 
1036  // We will use these offsets for the searches later on (see @PSEUDO_GATHER4):
1037  offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-0.25, -0.125, 1.25, -0.125), texcoord.xyxy);
1038  offset[1] = mad(SMAA_RT_METRICS.xyxy, float4(-0.125, -0.25, -0.125, 1.25), texcoord.xyxy);
1039 
1040  // And these for the searches, they indicate the ends of the loops:
1041  offset[2] = mad(SMAA_RT_METRICS.xxyy,
1042  float4(-2.0, 2.0, -2.0, 2.0) * float(SMAA_MAX_SEARCH_STEPS),
1043  float4(offset[0].xz, offset[1].yw));
1044 }
1045 
1049 void SMAANeighborhoodBlendingVS(float2 texcoord,
1050  out float4 offset) {
1051  offset = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy);
1052 }
1053 #endif // SMAA_INCLUDE_VS
1054 
1055 #if SMAA_INCLUDE_PS
1056 //-----------------------------------------------------------------------------
1057 // Edge Detection Pixel Shaders (First Pass)
1058 
1065 float2 SMAALumaEdgeDetectionPS(float2 texcoord,
1066  float4 offset[3],
1067  SMAATexture2D(colorTex)
1068  #if SMAA_PREDICATION
1069  , SMAATexture2D(predicationTex)
1070  #endif
1071  ) {
1072  // Calculate the threshold:
1073  #if SMAA_PREDICATION
1074  float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, SMAATexturePass2D(predicationTex));
1075  #else
1076  float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
1077  #endif
1078 
1079  // Calculate lumas:
1080  float3 weights = float3(0.2126, 0.7152, 0.0722);
1081  float L = dot(SMAASamplePoint(colorTex, texcoord).rgb, weights);
1082 
1083  float Lleft = dot(SMAASamplePoint(colorTex, offset[0].xy).rgb, weights);
1084  float Ltop = dot(SMAASamplePoint(colorTex, offset[0].zw).rgb, weights);
1085 
1086  // We do the usual threshold:
1087  float4 delta;
1088  delta.xy = abs(L - float2(Lleft, Ltop));
1089  float2 edges = step(threshold, delta.xy);
1090 
1091  // Then discard if there is no edge:
1092  if (dot(edges, float2(1.0, 1.0)) == 0.0)
1093  discard;
1094 
1095  // Calculate right and bottom deltas:
1096  float Lright = dot(SMAASamplePoint(colorTex, offset[1].xy).rgb, weights);
1097  float Lbottom = dot(SMAASamplePoint(colorTex, offset[1].zw).rgb, weights);
1098  delta.zw = abs(L - float2(Lright, Lbottom));
1099 
1100  // Calculate the maximum delta in the direct neighborhood:
1101  float2 maxDelta = max(delta.xy, delta.zw);
1102 
1103  // Calculate left-left and top-top deltas:
1104  float Lleftleft = dot(SMAASamplePoint(colorTex, offset[2].xy).rgb, weights);
1105  float Ltoptop = dot(SMAASamplePoint(colorTex, offset[2].zw).rgb, weights);
1106  delta.zw = abs(float2(Lleft, Ltop) - float2(Lleftleft, Ltoptop));
1107 
1108  // Calculate the final maximum delta:
1109  maxDelta = max(maxDelta.xy, delta.zw);
1110  float finalDelta = max(maxDelta.x, maxDelta.y);
1111 
1112  // Local contrast adaptation:
1113  edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
1114 
1115  return edges;
1116 }
1117 
1124 float2 SMAAColorEdgeDetectionPS(float2 texcoord,
1125  float4 offset[3],
1126  SMAATexture2D(colorTex)
1127  #if SMAA_PREDICATION
1128  , SMAATexture2D(predicationTex)
1129  #endif
1130  ) {
1131  // Calculate the threshold:
1132  #if SMAA_PREDICATION
1133  float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, predicationTex);
1134  #else
1135  float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
1136  #endif
1137 
1138  // Calculate color deltas:
1139  float4 delta;
1140  float3 C = SMAASamplePoint(colorTex, texcoord).rgb;
1141 
1142  float3 Cleft = SMAASamplePoint(colorTex, offset[0].xy).rgb;
1143  float3 t = abs(C - Cleft);
1144  delta.x = max(max(t.r, t.g), t.b);
1145 
1146  float3 Ctop = SMAASamplePoint(colorTex, offset[0].zw).rgb;
1147  t = abs(C - Ctop);
1148  delta.y = max(max(t.r, t.g), t.b);
1149 
1150  // We do the usual threshold:
1151  float2 edges = step(threshold, delta.xy);
1152 
1153  // Then discard if there is no edge:
1154  if (dot(edges, float2(1.0, 1.0)) == 0.0)
1155  discard;
1156 
1157  // Calculate right and bottom deltas:
1158  float3 Cright = SMAASamplePoint(colorTex, offset[1].xy).rgb;
1159  t = abs(C - Cright);
1160  delta.z = max(max(t.r, t.g), t.b);
1161 
1162  float3 Cbottom = SMAASamplePoint(colorTex, offset[1].zw).rgb;
1163  t = abs(C - Cbottom);
1164  delta.w = max(max(t.r, t.g), t.b);
1165 
1166  // Calculate the maximum delta in the direct neighborhood:
1167  float2 maxDelta = max(delta.xy, delta.zw);
1168 
1169  // Calculate left-left and top-top deltas:
1170  float3 Cleftleft = SMAASamplePoint(colorTex, offset[2].xy).rgb;
1171  t = abs(C - Cleftleft);
1172  delta.z = max(max(t.r, t.g), t.b);
1173 
1174  float3 Ctoptop = SMAASamplePoint(colorTex, offset[2].zw).rgb;
1175  t = abs(C - Ctoptop);
1176  delta.w = max(max(t.r, t.g), t.b);
1177 
1178  // Calculate the final maximum delta:
1179  maxDelta = max(maxDelta.xy, delta.zw);
1180  float finalDelta = max(maxDelta.x, maxDelta.y);
1181 
1182  // Local contrast adaptation:
1183  edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
1184 
1185  return edges;
1186 }
1187 )SHADER_SOURCE";
1188 
1189 extern const char smaa_base_shader_p3[] = R"SHADER_SOURCE(
1193 float2 SMAADepthEdgeDetectionPS(float2 texcoord,
1194  float4 offset[3],
1195  SMAATexture2D(depthTex)) {
1196  float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(depthTex));
1197  float2 delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z));
1198  float2 edges = step(SMAA_DEPTH_THRESHOLD, delta);
1199 
1200  if (dot(edges, float2(1.0, 1.0)) == 0.0)
1201  discard;
1202 
1203  return edges;
1204 }
1205 
1206 //-----------------------------------------------------------------------------
1207 // Diagonal Search Functions
1208 
1209 #if !defined(SMAA_DISABLE_DIAG_DETECTION)
1210 
1214 float2 SMAADecodeDiagBilinearAccess(float2 e) {
1215  // Bilinear access for fetching 'e' have a 0.25 offset, and we are
1216  // interested in the R and G edges:
1217  //
1218  // +---G---+-------+
1219  // | x o R x |
1220  // +-------+-------+
1221  //
1222  // Then, if one of these edge is enabled:
1223  // Red: (0.75 * X + 0.25 * 1) => 0.25 or 1.0
1224  // Green: (0.75 * 1 + 0.25 * X) => 0.75 or 1.0
1225  //
1226  // This function will unpack the values (mad + mul + round):
1227  // wolframalpha.com: round(x * abs(5 * x - 5 * 0.75)) plot 0 to 1
1228  e.r = e.r * abs(5.0 * e.r - 5.0 * 0.75);
1229  return round(e);
1230 }
1231 
1232 float4 SMAADecodeDiagBilinearAccess(float4 e) {
1233  e.rb = e.rb * abs(5.0 * e.rb - 5.0 * 0.75);
1234  return round(e);
1235 }
1236 
1240 float2 SMAASearchDiag1(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) {
1241  float4 coord = float4(texcoord, -1.0, 1.0);
1242  float3 t = float3(SMAA_RT_METRICS.xy, 1.0);
1243  while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) &&
1244  coord.w > 0.9) {
1245  coord.xyz = mad(t, float3(dir, 1.0), coord.xyz);
1246  e = SMAASampleLevelZero(edgesTex, coord.xy).rg;
1247  coord.w = dot(e, float2(0.5, 0.5));
1248  }
1249  return coord.zw;
1250 }
1251 
1252 float2 SMAASearchDiag2(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) {
1253  float4 coord = float4(texcoord, -1.0, 1.0);
1254  coord.x += 0.25 * SMAA_RT_METRICS.x; // See @SearchDiag2Optimization
1255  float3 t = float3(SMAA_RT_METRICS.xy, 1.0);
1256  while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) &&
1257  coord.w > 0.9) {
1258  coord.xyz = mad(t, float3(dir, 1.0), coord.xyz);
1259 
1260  // @SearchDiag2Optimization
1261  // Fetch both edges at once using bilinear filtering:
1262  e = SMAASampleLevelZero(edgesTex, coord.xy).rg;
1263  e = SMAADecodeDiagBilinearAccess(e);
1264 
1265  // Non-optimized version:
1266  // e.g = SMAASampleLevelZero(edgesTex, coord.xy).g;
1267  // e.r = SMAASampleLevelZeroOffset(edgesTex, coord.xy, int2(1, 0)).r;
1268 
1269  coord.w = dot(e, float2(0.5, 0.5));
1270  }
1271  return coord.zw;
1272 }
1273 
1278 float2 SMAAAreaDiag(SMAATexture2D(areaTex), float2 dist, float2 e, float offset) {
1279  float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE_DIAG, SMAA_AREATEX_MAX_DISTANCE_DIAG), e, dist);
1280 
1281  // We do a scale and bias for mapping to texel space:
1282  texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
1283 
1284  // Diagonal areas are on the second half of the texture:
1285  texcoord.x += 0.5;
1286 
1287  // Move to proper place, according to the subpixel offset:
1288  texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;
1289 
1290  // Do it!
1291  return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
1292 }
1293 
1297 float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex), SMAATexture2D(areaTex), float2 texcoord, float2 e, float4 subsampleIndices) {
1298  float2 weights = float2(0.0, 0.0);
1299 
1300  // Search for the line ends:
1301  float4 d;
1302  float2 end;
1303  if (e.r > 0.0) {
1304  d.xz = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, 1.0), end);
1305  d.x += float(end.y > 0.9);
1306  } else
1307  d.xz = float2(0.0, 0.0);
1308  d.yw = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, -1.0), end);
1309 
1310  SMAA_BRANCH
1311  if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3
1312  // Fetch the crossing edges:
1313  float4 coords = mad(float4(-d.x + 0.25, d.x, d.y, -d.y - 0.25), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
1314  float4 c;
1315  c.xy = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).rg;
1316  c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).rg;
1317  c.yxwz = SMAADecodeDiagBilinearAccess(c.xyzw);
1318 
1319  // Non-optimized version:
1320  // float4 coords = mad(float4(-d.x, d.x, d.y, -d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
1321  // float4 c;
1322  // c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g;
1323  // c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, 0)).r;
1324  // c.z = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).g;
1325  // c.w = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, -1)).r;
1326 
1327  // Merge crossing edges at each side into a single value:
1328  float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw);
1329 
1330  // Remove the crossing edge if we didn't found the end of the line:
1331  SMAAMovc(bool2(step(0.9, d.zw)), cc, float2(0.0, 0.0));
1332 
1333  // Fetch the areas for this line:
1334  weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.z);
1335  }
1336 
1337  // Search for the line ends:
1338  d.xz = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, -1.0), end);
1339  if (SMAASampleLevelZeroOffset(edgesTex, texcoord, int2(1, 0)).r > 0.0) {
1340  d.yw = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, 1.0), end);
1341  d.y += float(end.y > 0.9);
1342  } else
1343  d.yw = float2(0.0, 0.0);
1344 
1345  SMAA_BRANCH
1346  if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3
1347  // Fetch the crossing edges:
1348  float4 coords = mad(float4(-d.x, -d.x, d.y, d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
1349  float4 c;
1350  c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g;
1351  c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, -1)).r;
1352  c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).gr;
1353  float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw);
1354 
1355  // Remove the crossing edge if we didn't found the end of the line:
1356  SMAAMovc(bool2(step(0.9, d.zw)), cc, float2(0.0, 0.0));
1357 
1358  // Fetch the areas for this line:
1359  weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.w).gr;
1360  }
1361 
1362  return weights;
1363 }
1364 #endif
1365 
1366 //-----------------------------------------------------------------------------
1367 // Horizontal/Vertical Search Functions
1368 
1375 float SMAASearchLength(SMAATexture2D(searchTex), float2 e, float offset) {
1376  // The texture is flipped vertically, with left and right cases taking half
1377  // of the space horizontally:
1378  float2 scale = SMAA_SEARCHTEX_SIZE * float2(0.5, -1.0);
1379  float2 bias = SMAA_SEARCHTEX_SIZE * float2(offset, 1.0);
1380 
1381  // Scale and bias to access texel centers:
1382  scale += float2(-1.0, 1.0);
1383  bias += float2( 0.5, -0.5);
1384 
1385  // Convert from pixel coordinates to texcoords:
1386  // (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped)
1387  scale *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
1388  bias *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
1389 
1390  // Lookup the search texture:
1391  return SMAA_SEARCHTEX_SELECT(SMAASampleLevelZero(searchTex, mad(scale, e, bias)));
1392 }
1393 
1397 float SMAASearchXLeft(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1405  float2 e = float2(0.0, 1.0);
1406  while (texcoord.x > end &&
1407  e.g > 0.8281 && // Is there some edge not activated?
1408  e.r == 0.0) { // Or is there a crossing edge that breaks the line?
1409  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1410  texcoord = mad(-float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord);
1411  }
1412 
1413  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0), 3.25);
1414  return mad(SMAA_RT_METRICS.x, offset, texcoord.x);
1415 
1416  // Non-optimized version:
1417  // We correct the previous (-0.25, -0.125) offset we applied:
1418  // texcoord.x += 0.25 * SMAA_RT_METRICS.x;
1419 
1420  // The searches are bias by 1, so adjust the coords accordingly:
1421  // texcoord.x += SMAA_RT_METRICS.x;
1422 
1423  // Disambiguate the length added by the last step:
1424  // texcoord.x += 2.0 * SMAA_RT_METRICS.x; // Undo last step
1425  // texcoord.x -= SMAA_RT_METRICS.x * (255.0 / 127.0) * SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0);
1426  // return mad(SMAA_RT_METRICS.x, offset, texcoord.x);
1427 }
1428 
1429 float SMAASearchXRight(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1430  float2 e = float2(0.0, 1.0);
1431  while (texcoord.x < end &&
1432  e.g > 0.8281 && // Is there some edge not activated?
1433  e.r == 0.0) { // Or is there a crossing edge that breaks the line?
1434  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1435  texcoord = mad(float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord);
1436  }
1437  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.5), 3.25);
1438  return mad(-SMAA_RT_METRICS.x, offset, texcoord.x);
1439 }
1440 
1441 float SMAASearchYUp(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1442  float2 e = float2(1.0, 0.0);
1443  while (texcoord.y > end &&
1444  e.r > 0.8281 && // Is there some edge not activated?
1445  e.g == 0.0) { // Or is there a crossing edge that breaks the line?
1446  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1447  texcoord = mad(-float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord);
1448  }
1449  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.0), 3.25);
1450  return mad(SMAA_RT_METRICS.y, offset, texcoord.y);
1451 }
1452 
1453 float SMAASearchYDown(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1454  float2 e = float2(1.0, 0.0);
1455  while (texcoord.y < end &&
1456  e.r > 0.8281 && // Is there some edge not activated?
1457  e.g == 0.0) { // Or is there a crossing edge that breaks the line?
1458  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1459  texcoord = mad(float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord);
1460  }
1461  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.5), 3.25);
1462  return mad(-SMAA_RT_METRICS.y, offset, texcoord.y);
1463 }
1464 
1469 float2 SMAAArea(SMAATexture2D(areaTex), float2 dist, float e1, float e2, float offset) {
1470  // Rounding prevents precision errors of bilinear filtering:
1471  float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE), round(4.0 * float2(e1, e2)), dist);
1472 
1473  // We do a scale and bias for mapping to texel space:
1474  texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
1475 
1476  // Move to proper place, according to the subpixel offset:
1477  texcoord.y = mad(SMAA_AREATEX_SUBTEX_SIZE, offset, texcoord.y);
1478 
1479  // Do it!
1480  return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
1481 }
1482 
1483 //-----------------------------------------------------------------------------
1484 // Corner Detection Functions
1485 
1486 void SMAADetectHorizontalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) {
1487  #if !defined(SMAA_DISABLE_CORNER_DETECTION)
1488  float2 leftRight = step(d.xy, d.yx);
1489  float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight;
1490 
1491  rounding /= leftRight.x + leftRight.y; // Reduce blending for pixels in the center of a line.
1492 
1493  float2 factor = float2(1.0, 1.0);
1494  factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, 1)).r;
1495  factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, 1)).r;
1496  factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, -2)).r;
1497  factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, -2)).r;
1498 
1499  weights *= saturate(factor);
1500  #endif
1501 }
1502 
1503 void SMAADetectVerticalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) {
1504  #if !defined(SMAA_DISABLE_CORNER_DETECTION)
1505  float2 leftRight = step(d.xy, d.yx);
1506  float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight;
1507 
1508  rounding /= leftRight.x + leftRight.y;
1509 
1510  float2 factor = float2(1.0, 1.0);
1511  factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2( 1, 0)).g;
1512  factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2( 1, 1)).g;
1513  factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(-2, 0)).g;
1514  factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(-2, 1)).g;
1515 
1516  weights *= saturate(factor);
1517  #endif
1518 }
1519 
1520 //-----------------------------------------------------------------------------
1521 // Blending Weight Calculation Pixel Shader (Second Pass)
1522 
1523 float4 SMAABlendingWeightCalculationPS(float2 texcoord,
1524  float2 pixcoord,
1525  float4 offset[3],
1526  SMAATexture2D(edgesTex),
1527  SMAATexture2D(areaTex),
1528  SMAATexture2D(searchTex),
1529  float4 subsampleIndices) { // Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES.
1530  float4 weights = float4(0.0, 0.0, 0.0, 0.0);
1531 
1532  float2 e = SMAASample(edgesTex, texcoord).rg;
1533 
1534  SMAA_BRANCH
1535  if (e.g > 0.0) { // Edge at north
1536  #if !defined(SMAA_DISABLE_DIAG_DETECTION)
1537  // Diagonals have both north and west edges, so searching for them in
1538  // one of the boundaries is enough.
1539  weights.rg = SMAACalculateDiagWeights(SMAATexturePass2D(edgesTex), SMAATexturePass2D(areaTex), texcoord, e, subsampleIndices);
1540 
1541  // We give priority to diagonals, so if we find a diagonal we skip
1542  // horizontal/vertical processing.
1543  SMAA_BRANCH
1544  if (weights.r == -weights.g) { // weights.r + weights.g == 0.0
1545  #endif
1546 
1547  float2 d;
1548 
1549  // Find the distance to the left:
1550  float3 coords;
1551  coords.x = SMAASearchXLeft(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].xy, offset[2].x);
1552  coords.y = offset[1].y; // offset[1].y = texcoord.y - 0.25 * SMAA_RT_METRICS.y (@CROSSING_OFFSET)
1553  d.x = coords.x;
1554 
1555  // Now fetch the left crossing edges, two at a time using bilinear
1556  // filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to
1557  // discern what value each edge has:
1558  float e1 = SMAASampleLevelZero(edgesTex, coords.xy).r;
1559 
1560  // Find the distance to the right:
1561  coords.z = SMAASearchXRight(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].zw, offset[2].y);
1562  d.y = coords.z;
1563 
1564  // We want the distances to be in pixel units (doing this here allow one
1565  // to better interleave arithmetic and memory accesses):
1566  d = abs(round(mad(SMAA_RT_METRICS.zz, d, -pixcoord.xx)));
1567 
1568  // SMAAArea below needs a sqrt, as the areas texture is compressed
1569  // quadratically:
1570  float2 sqrt_d = sqrt(d);
1571 )SHADER_SOURCE";
1572 
1573 extern const char smaa_base_shader_p4[] = R"SHADER_SOURCE(
1574  // Fetch the right crossing edges:
1575  float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.zy, int2(1, 0)).r;
1576 
1577  // Ok, we know how this pattern looks like, now it is time for getting
1578  // the actual area:
1579  weights.rg = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.y);
1580 
1581  // Fix corners:
1582  coords.y = texcoord.y;
1583  SMAADetectHorizontalCornerPattern(SMAATexturePass2D(edgesTex), weights.rg, coords.xyzy, d);
1584 
1585  #if !defined(SMAA_DISABLE_DIAG_DETECTION)
1586  } else
1587  e.r = 0.0; // Skip vertical processing.
1588  #endif
1589  }
1590 
1591  SMAA_BRANCH
1592  if (e.r > 0.0) { // Edge at west
1593  float2 d;
1594 
1595  // Find the distance to the top:
1596  float3 coords;
1597  coords.y = SMAASearchYUp(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].xy, offset[2].z);
1598  coords.x = offset[0].x; // offset[1].x = texcoord.x - 0.25 * SMAA_RT_METRICS.x;
1599  d.x = coords.y;
1600 
1601  // Fetch the top crossing edges:
1602  float e1 = SMAASampleLevelZero(edgesTex, coords.xy).g;
1603 
1604  // Find the distance to the bottom:
1605  coords.z = SMAASearchYDown(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].zw, offset[2].w);
1606  d.y = coords.z;
1607 
1608  // We want the distances to be in pixel units:
1609  d = abs(round(mad(SMAA_RT_METRICS.ww, d, -pixcoord.yy)));
1610 
1611  // SMAAArea below needs a sqrt, as the areas texture is compressed
1612  // quadratically:
1613  float2 sqrt_d = sqrt(d);
1614 
1615  // Fetch the bottom crossing edges:
1616  float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.xz, int2(0, 1)).g;
1617 
1618  // Get the area for this direction:
1619  weights.ba = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.x);
1620 
1621  // Fix corners:
1622  coords.x = texcoord.x;
1623  SMAADetectVerticalCornerPattern(SMAATexturePass2D(edgesTex), weights.ba, coords.xyxz, d);
1624  }
1625 
1626  return weights;
1627 }
1628 
1629 //-----------------------------------------------------------------------------
1630 // Neighborhood Blending Pixel Shader (Third Pass)
1631 
1632 float4 SMAANeighborhoodBlendingPS(float2 texcoord,
1633  float4 offset,
1634  SMAATexture2D(colorTex),
1635  SMAATexture2D(blendTex)
1636  #if SMAA_REPROJECTION
1637  , SMAATexture2D(velocityTex)
1638  #endif
1639  ) {
1640  // Fetch the blending weights for current pixel:
1641  float4 a;
1642  a.x = SMAASample(blendTex, offset.xy).a; // Right
1643  a.y = SMAASample(blendTex, offset.zw).g; // Top
1644  a.wz = SMAASample(blendTex, texcoord).xz; // Bottom / Left
1645 
1646  // Is there any blending weight with a value greater than 0.0?
1647  SMAA_BRANCH
1648  if (dot(a, float4(1.0, 1.0, 1.0, 1.0)) < 1e-5) {
1649  float4 color = SMAASampleLevelZero(colorTex, texcoord);
1650 
1651  #if SMAA_REPROJECTION
1652  float2 velocity = SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, texcoord));
1653 
1654  // Pack velocity into the alpha channel:
1655  color.a = sqrt(5.0 * length(velocity));
1656  #endif
1657 
1658  return color;
1659  } else {
1660  bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical)
1661 
1662  // Calculate the blending offsets:
1663  float4 blendingOffset = float4(0.0, a.y, 0.0, a.w);
1664  float2 blendingWeight = a.yw;
1665  SMAAMovc(bool4(h, h, h, h), blendingOffset, float4(a.x, 0.0, a.z, 0.0));
1666  SMAAMovc(bool2(h, h), blendingWeight, a.xz);
1667  blendingWeight /= dot(blendingWeight, float2(1.0, 1.0));
1668 
1669  // Calculate the texture coordinates:
1670  float4 blendingCoord = mad(blendingOffset, float4(SMAA_RT_METRICS.xy, -SMAA_RT_METRICS.xy), texcoord.xyxy);
1671 
1672  // We exploit bilinear filtering to mix current pixel with the chosen
1673  // neighbor:
1674  float4 color = blendingWeight.x * SMAASampleLevelZero(colorTex, blendingCoord.xy);
1675  color += blendingWeight.y * SMAASampleLevelZero(colorTex, blendingCoord.zw);
1676 
1677  #if SMAA_REPROJECTION
1678  // Antialias velocity for proper reprojection in a later stage:
1679  float2 velocity = blendingWeight.x * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.xy));
1680  velocity += blendingWeight.y * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.zw));
1681 
1682  // Pack velocity into the alpha channel:
1683  color.a = sqrt(5.0 * length(velocity));
1684  #endif
1685 
1686  return color;
1687  }
1688 }
1689 
1690 //-----------------------------------------------------------------------------
1691 // Temporal Resolve Pixel Shader (Optional Pass)
1692 
1693 float4 SMAAResolvePS(float2 texcoord,
1694  SMAATexture2D(currentColorTex),
1695  SMAATexture2D(previousColorTex)
1696  #if SMAA_REPROJECTION
1697  , SMAATexture2D(velocityTex)
1698  #endif
1699  ) {
1700  #if SMAA_REPROJECTION
1701  // Velocity is assumed to be calculated for motion blur, so we need to
1702  // inverse it for reprojection:
1703  float2 velocity = -SMAA_DECODE_VELOCITY(SMAASamplePoint(velocityTex, texcoord).rg);
1704 
1705  // Fetch current pixel:
1706  float4 current = SMAASamplePoint(currentColorTex, texcoord);
1707 
1708  // Reproject current coordinates and fetch previous pixel:
1709  float4 previous = SMAASamplePoint(previousColorTex, texcoord + velocity);
1710 
1711  // Attenuate the previous pixel if the velocity is different:
1712  float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0;
1713  float weight = 0.5 * saturate(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE);
1714 
1715  // Blend the pixels according to the calculated weight:
1716  return lerp(current, previous, weight);
1717  #else
1718  // Just blend the pixels:
1719  float4 current = SMAASamplePoint(currentColorTex, texcoord);
1720  float4 previous = SMAASamplePoint(previousColorTex, texcoord);
1721  return lerp(current, previous, 0.5);
1722  #endif
1723 }
1724 
1725 //-----------------------------------------------------------------------------
1726 // Separate Multisamples Pixel Shader (Optional Pass)
1727 
1728 #ifdef SMAALoad
1729 void SMAASeparatePS(float4 position,
1730  float2 texcoord,
1731  out float4 target0,
1732  out float4 target1,
1733  SMAATexture2DMS2(colorTexMS)) {
1734  int2 pos = int2(position.xy);
1735  target0 = SMAALoad(colorTexMS, pos, 0);
1736  target1 = SMAALoad(colorTexMS, pos, 1);
1737 }
1738 #endif
1739 
1740 //-----------------------------------------------------------------------------
1741 #endif // SMAA_INCLUDE_PS
1742 
1743 )SHADER_SOURCE";
1744 
1745 const char smaa_pass_1_vertex_shader[] = R"SHADER_SOURCE(
1746 
1747 varying vec4 offset[3];
1748 varying vec2 texcoord;
1749 
1750 void main()
1751 {
1752  texcoord = gl_MultiTexCoord0.st;
1753  SMAAEdgeDetectionVS( texcoord, offset);
1754  gl_Position = ftransform();
1755 
1756 }
1757 
1758 )SHADER_SOURCE";
1759 
1760 const char smaa_pass_1_fragment_shader[] = R"SHADER_SOURCE(
1761 
1762 varying vec2 texcoord;
1763 varying vec4 offset[3];
1764 uniform sampler2D colorTex;
1765 
1766 void main()
1767 {
1768  gl_FragColor.xy = SMAALumaEdgeDetectionPS(texcoord, offset, colorTex).xy;
1769 }
1770 
1771 )SHADER_SOURCE";
1772 
1773 const char smaa_pass_2_vertex_shader[] = R"SHADER_SOURCE(
1774 
1775 varying vec4 offset[3];
1776 varying vec2 texcoord;
1777 varying vec2 pixcoord;
1778 
1779 void main()
1780 {
1781  texcoord = gl_MultiTexCoord0.st;
1782  SMAABlendingWeightCalculationVS( texcoord, pixcoord, offset );
1783  gl_Position = ftransform();
1784 }
1785 
1786 )SHADER_SOURCE";
1787 
1788 const char smaa_pass_2_fragment_shader[] = R"SHADER_SOURCE(
1789 
1790 varying vec2 texcoord;
1791 varying vec2 pixcoord;
1792 varying vec4 offset[3];
1793 uniform sampler2D edgesTex;
1794 uniform sampler2D areaTex;
1795 uniform sampler2D searchTex;
1796 
1797 void main()
1798 {
1799  gl_FragColor = SMAABlendingWeightCalculationPS(texcoord, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0.,0.,0.,0.));
1800 }
1801 
1802 )SHADER_SOURCE";
1803 
1804 const char smaa_pass_3_vertex_shader[] = R"SHADER_SOURCE(
1805 
1806 varying vec4 offset;
1807 varying vec2 texcoord;
1808 
1809 void main()
1810 {
1811  texcoord = gl_MultiTexCoord0.st;
1812  SMAANeighborhoodBlendingVS( texcoord, offset );
1813  gl_Position = ftransform();
1814 }
1815 
1816 )SHADER_SOURCE";
1817 
1818 const char smaa_pass_3_fragment_shader[] = R"SHADER_SOURCE(
1819 
1820 varying vec2 texcoord;
1821 varying vec4 offset;
1822 uniform sampler2D colorTex;
1823 uniform sampler2D blendTex;
1824 
1825 void main()
1826 {
1827  gl_FragColor = SMAANeighborhoodBlendingPS(texcoord, offset, colorTex, blendTex);
1828 }
1829 
1830 )SHADER_SOURCE";
1831 
1832 }
1833 }
1834 
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:58
const char smaa_pass_3_fragment_shader[]
const char smaa_base_shader_p4[]
const char smaa_pass_1_fragment_shader[]
const char smaa_pass_2_fragment_shader[]
const char smaa_base_shader_p3[]