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_LINE = 1.0;
67 const float SHADER_FILLED_CIRCLE = 2.0;
68 const float SHADER_STROKED_CIRCLE = 3.0;
69 const float SHADER_FONT = 4.0;
70 
71 // Minimum line width
72 const float MIN_WIDTH = 1.0;
73 
74 attribute vec4 attrShaderParams;
75 varying vec4 shaderParams;
76 varying vec2 circleCoords;
77 
78 void main()
79 {
80  // Pass attributes to the fragment shader
81  shaderParams = attrShaderParams;
82 
83  if( shaderParams[0] == SHADER_LINE )
84  {
85  float lineWidth = shaderParams[3];
86  float worldScale = abs( gl_ModelViewMatrix[0][0] );
87 
88  // Make lines appear to be at least 1 pixel wide
89  if( worldScale * lineWidth < MIN_WIDTH )
90  gl_Position = gl_ModelViewProjectionMatrix *
91  ( gl_Vertex + vec4( shaderParams.yz * MIN_WIDTH / ( worldScale * lineWidth ), 0.0, 0.0 ) );
92  else
93  gl_Position = gl_ModelViewProjectionMatrix *
94  ( gl_Vertex + vec4( shaderParams.yz, 0.0, 0.0 ) );
95  }
96  else if( ( shaderParams[0] == SHADER_STROKED_CIRCLE ) ||
97  ( shaderParams[0] == SHADER_FILLED_CIRCLE ) )
98  {
99  // Compute relative circle coordinates basing on indices
100  // Circle
101  if( shaderParams[1] == 1.0 )
102  circleCoords = vec2( -sqrt( 3.0 ), -1.0 );
103  else if( shaderParams[1] == 2.0 )
104  circleCoords = vec2( sqrt( 3.0 ), -1.0 );
105  else if( shaderParams[1] == 3.0 )
106  circleCoords = vec2( 0.0, 2.0 );
107 
108  // Semicircle
109  else if( shaderParams[1] == 4.0 )
110  circleCoords = vec2( -3.0 / sqrt( 3.0 ), 0.0 );
111  else if( shaderParams[1] == 5.0 )
112  circleCoords = vec2( 3.0 / sqrt( 3.0 ), 0.0 );
113  else if( shaderParams[1] == 6.0 )
114  circleCoords = vec2( 0.0, 2.0 );
115 
116  // Make the line appear to be at least 1 pixel wide
117  float lineWidth = shaderParams[3];
118  float worldScale = abs( gl_ModelViewMatrix[0][0] );
119 
120  if( worldScale * lineWidth < MIN_WIDTH )
121  shaderParams[3] = shaderParams[3] / ( worldScale * lineWidth );
122 
123  gl_Position = ftransform();
124  }
125  else
126  {
127  // Pass through the coordinates like in the fixed pipeline
128  gl_Position = ftransform();
129  }
130 
131  gl_FrontColor = gl_Color;
132 }
133 
134 )SHADER_SOURCE";
135 
136 const char kicad_fragment_shader[] = R"SHADER_SOURCE(
137 
138 /*
139  * This program source code file is part of KICAD, a free EDA CAD application.
140  *
141  * Copyright (C) 2013-2016 CERN
142  * Copyright (C) 2016 Kicad Developers, see authors.txt for contributors.
143  * @author Maciej Suminski <maciej.suminski@cern.ch>
144  *
145  * Fragment shader
146  *
147  * This program is free software; you can redistribute it and/or
148  * modify it under the terms of the GNU General Public License
149  * as published by the Free Software Foundation; either version 2
150  * of the License, or (at your option) any later version.
151  *
152  * This program is distributed in the hope that it will be useful,
153  * but WITHOUT ANY WARRANTY; without even the implied warranty of
154  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
155  * GNU General Public License for more details.
156  *
157  * You should have received a copy of the GNU General Public License
158  * along with this program; if not, you may find one here:
159  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
160  * or you may search the http://www.gnu.org website for the version 2 license,
161  * or you may write to the Free Software Foundation, Inc.,
162  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
163  */
164 
165 #version 120
166 
167 // Multi-channel signed distance field
168 #define USE_MSDF
169 
170 // Shader types
171 const float SHADER_LINE = 1.0;
172 const float SHADER_FILLED_CIRCLE = 2.0;
173 const float SHADER_STROKED_CIRCLE = 3.0;
174 const float SHADER_FONT = 4.0;
175 
176 varying vec4 shaderParams;
177 varying vec2 circleCoords;
178 uniform sampler2D fontTexture;
179 
180 // Needed to reconstruct the mipmap level / texel derivative
181 uniform int fontTextureWidth;
182 
183 void filledCircle( vec2 aCoord )
184 {
185  if( dot( aCoord, aCoord ) < 1.0 )
186  gl_FragColor = gl_Color;
187  else
188  discard;
189 }
190 
191 
192 void strokedCircle( vec2 aCoord, float aRadius, float aWidth )
193 {
194  float outerRadius = aRadius + ( aWidth / 2 );
195  float innerRadius = aRadius - ( aWidth / 2 );
196  float relWidth = innerRadius / outerRadius;
197 
198  if( ( dot( aCoord, aCoord ) < 1.0 ) &&
199  ( dot( aCoord, aCoord ) > relWidth * relWidth ) )
200  gl_FragColor = gl_Color;
201  else
202  discard;
203 }
204 
205 #ifdef USE_MSDF
206 float median( vec3 v )
207 {
208  return max( min( v.r, v.g ), min( max( v.r, v.g ), v.b ) );
209 }
210 #endif
211 
212 void main()
213 {
214  if( shaderParams[0] == SHADER_FILLED_CIRCLE )
215  {
216  filledCircle( circleCoords );
217  }
218  else if( shaderParams[0] == SHADER_STROKED_CIRCLE )
219  {
220  strokedCircle( circleCoords, shaderParams[2], shaderParams[3] );
221  }
222  else if( shaderParams[0] == SHADER_FONT )
223  {
224  vec2 tex = shaderParams.yz;
225 
226  // Unless we're streching chars it is okay to consider
227  // one derivative for filtering
228  float derivative = length( dFdx( tex ) ) * fontTextureWidth / 4;
229 
230 #ifdef USE_MSDF
231  float dist = median( texture2D( fontTexture, tex ).rgb );
232 #else
233  float dist = texture2D( fontTexture, tex ).r;
234 #endif
235 
236  // use the derivative for zoom-adaptive filtering
237  float alpha = smoothstep( 0.5 - derivative, 0.5 + derivative, dist );
238 
239  gl_FragColor = vec4( gl_Color.rgb, alpha );
240  }
241  else
242  {
243  // Simple pass-through
244  gl_FragColor = gl_Color;
245  }
246 }
247 
248 )SHADER_SOURCE";
249 
250 const char ssaa_x4_vertex_shader[] = R"SHADER_SOURCE(
251 
252 #version 120
253 varying vec2 texcoord;
254 void main()
255 {
256  texcoord = gl_MultiTexCoord0.st;
257  gl_Position = ftransform();
258 }
259 
260 )SHADER_SOURCE";
261 
262 const char ssaa_x4_fragment_shader[] = R"SHADER_SOURCE(
263 
264 #version 120
265 varying vec2 texcoord;
266 uniform sampler2D source;
267 void main()
268 {
269  float step_x = dFdx(texcoord.x)/4.;
270  float step_y = dFdy(texcoord.y)/4.;
271 
272  vec4 q00 = texture2D( source, texcoord + vec2(-step_x, -step_y) );
273  vec4 q01 = texture2D( source, texcoord + vec2( step_x, -step_y) );
274  vec4 q10 = texture2D( source, texcoord + vec2(-step_x, step_y) );
275  vec4 q11 = texture2D( source, texcoord + vec2( step_x, step_y) );
276 
277  gl_FragColor = (q00+q01+q10+q11)/4;
278 }
279 
280 )SHADER_SOURCE";
281 
282 const char smaa_base_shader_p1[] = R"SHADER_SOURCE(
283 
581 //-----------------------------------------------------------------------------
582 // SMAA Presets
583 
589 #if defined(SMAA_PRESET_LOW)
590 #define SMAA_THRESHOLD 0.15
591 #define SMAA_MAX_SEARCH_STEPS 4
592 #define SMAA_DISABLE_DIAG_DETECTION
593 #define SMAA_DISABLE_CORNER_DETECTION
594 #elif defined(SMAA_PRESET_MEDIUM)
595 #define SMAA_THRESHOLD 0.1
596 #define SMAA_MAX_SEARCH_STEPS 8
597 #define SMAA_DISABLE_DIAG_DETECTION
598 #define SMAA_DISABLE_CORNER_DETECTION
599 #elif defined(SMAA_PRESET_HIGH)
600 #define SMAA_THRESHOLD 0.1
601 #define SMAA_MAX_SEARCH_STEPS 16
602 #define SMAA_MAX_SEARCH_STEPS_DIAG 8
603 #define SMAA_CORNER_ROUNDING 25
604 #elif defined(SMAA_PRESET_ULTRA)
605 #define SMAA_THRESHOLD 0.005
606 //0.05
607 #define SMAA_MAX_SEARCH_STEPS 64
608 //32
609 #define SMAA_MAX_SEARCH_STEPS_DIAG 32
610 //16
611 #define SMAA_CORNER_ROUNDING 25
612 #endif
613 
614 //-----------------------------------------------------------------------------
615 // Configurable Defines
616 
629 #ifndef SMAA_THRESHOLD
630 #define SMAA_THRESHOLD 0.1
631 #endif
632 
638 #ifndef SMAA_DEPTH_THRESHOLD
639 #define SMAA_DEPTH_THRESHOLD (0.1 * SMAA_THRESHOLD)
640 #endif
641 
652 #ifndef SMAA_MAX_SEARCH_STEPS
653 #define SMAA_MAX_SEARCH_STEPS 16
654 #endif
655 )SHADER_SOURCE";
656 
657 const char smaa_base_shader_p2[] = R"SHADER_SOURCE(
670 #ifndef SMAA_MAX_SEARCH_STEPS_DIAG
671 #define SMAA_MAX_SEARCH_STEPS_DIAG 8
672 #endif
673 
681 #ifndef SMAA_CORNER_ROUNDING
682 #define SMAA_CORNER_ROUNDING 25
683 #endif
684 
693 #ifndef SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR
694 #define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.0
695 #endif
696 
711 #ifndef SMAA_PREDICATION
712 #define SMAA_PREDICATION 0
713 #endif
714 
721 #ifndef SMAA_PREDICATION_THRESHOLD
722 #define SMAA_PREDICATION_THRESHOLD 0.01
723 #endif
724 
731 #ifndef SMAA_PREDICATION_SCALE
732 #define SMAA_PREDICATION_SCALE 2.0
733 #endif
734 
740 #ifndef SMAA_PREDICATION_STRENGTH
741 #define SMAA_PREDICATION_STRENGTH 0.4
742 #endif
743 
755 #ifndef SMAA_REPROJECTION
756 #define SMAA_REPROJECTION 0
757 #endif
758 
770 #ifndef SMAA_REPROJECTION_WEIGHT_SCALE
771 #define SMAA_REPROJECTION_WEIGHT_SCALE 30.0
772 #endif
773 
778 #ifndef SMAA_INCLUDE_VS
779 #define SMAA_INCLUDE_VS 1
780 #endif
781 #ifndef SMAA_INCLUDE_PS
782 #define SMAA_INCLUDE_PS 1
783 #endif
784 
785 //-----------------------------------------------------------------------------
786 // Texture Access Defines
787 
788 #ifndef SMAA_AREATEX_SELECT
789 #if defined(SMAA_HLSL_3)
790 #define SMAA_AREATEX_SELECT(sample) sample.ra
791 #else
792 #define SMAA_AREATEX_SELECT(sample) sample.rg
793 #endif
794 #endif
795 
796 #ifndef SMAA_SEARCHTEX_SELECT
797 #define SMAA_SEARCHTEX_SELECT(sample) sample.r
798 #endif
799 
800 #ifndef SMAA_DECODE_VELOCITY
801 #define SMAA_DECODE_VELOCITY(sample) sample.rg
802 #endif
803 
804 //-----------------------------------------------------------------------------
805 // Non-Configurable Defines
806 
807 #define SMAA_AREATEX_MAX_DISTANCE 16
808 #define SMAA_AREATEX_MAX_DISTANCE_DIAG 20
809 #define SMAA_AREATEX_PIXEL_SIZE (1.0 / float2(160.0, 560.0))
810 #define SMAA_AREATEX_SUBTEX_SIZE (1.0 / 7.0)
811 #define SMAA_SEARCHTEX_SIZE float2(66.0, 33.0)
812 #define SMAA_SEARCHTEX_PACKED_SIZE float2(64.0, 16.0)
813 #define SMAA_CORNER_ROUNDING_NORM (float(SMAA_CORNER_ROUNDING) / 100.0)
814 
815 //-----------------------------------------------------------------------------
816 // Porting Functions
817 
818 #if defined(SMAA_HLSL_3)
819 #define SMAATexture2D(tex) sampler2D tex
820 #define SMAATexturePass2D(tex) tex
821 #define SMAASampleLevelZero(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0))
822 #define SMAASampleLevelZeroPoint(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0))
823 #define SMAASampleLevelZeroOffset(tex, coord, offset) tex2Dlod(tex, float4(coord + offset * SMAA_RT_METRICS.xy, 0.0, 0.0))
824 #define SMAASample(tex, coord) tex2D(tex, coord)
825 #define SMAASamplePoint(tex, coord) tex2D(tex, coord)
826 #define SMAASampleOffset(tex, coord, offset) tex2D(tex, coord + offset * SMAA_RT_METRICS.xy)
827 #define SMAA_FLATTEN [flatten]
828 #define SMAA_BRANCH [branch]
829 #endif
830 #if defined(SMAA_HLSL_4) || defined(SMAA_HLSL_4_1)
831 SamplerState LinearSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; };
832 SamplerState PointSampler { Filter = MIN_MAG_MIP_POINT; AddressU = Clamp; AddressV = Clamp; };
833 #define SMAATexture2D(tex) Texture2D tex
834 #define SMAATexturePass2D(tex) tex
835 #define SMAASampleLevelZero(tex, coord) tex.SampleLevel(LinearSampler, coord, 0)
836 #define SMAASampleLevelZeroPoint(tex, coord) tex.SampleLevel(PointSampler, coord, 0)
837 #define SMAASampleLevelZeroOffset(tex, coord, offset) tex.SampleLevel(LinearSampler, coord, 0, offset)
838 #define SMAASample(tex, coord) tex.Sample(LinearSampler, coord)
839 #define SMAASamplePoint(tex, coord) tex.Sample(PointSampler, coord)
840 #define SMAASampleOffset(tex, coord, offset) tex.Sample(LinearSampler, coord, offset)
841 #define SMAA_FLATTEN [flatten]
842 #define SMAA_BRANCH [branch]
843 #define SMAATexture2DMS2(tex) Texture2DMS<float4, 2> tex
844 #define SMAALoad(tex, pos, sample) tex.Load(pos, sample)
845 #if defined(SMAA_HLSL_4_1)
846 #define SMAAGather(tex, coord) tex.Gather(LinearSampler, coord, 0)
847 #endif
848 #endif
849 #if defined(SMAA_GLSL_2_1) || defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4)
850 #define SMAATexture2D(tex) sampler2D tex
851 #define SMAATexturePass2D(tex) tex
852 #define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0)
853 #define SMAASampleLevelZeroPoint(tex, coord) textureLod(tex, coord, 0.0)
854 #define SMAASampleLevelZeroOffset(tex, coord, offset) textureLodOffset(tex, coord, 0.0, offset)
855 #if defined(SMAA_GLSL_2_1)
856 #define SMAASample(tex, coord) texture2D(tex, coord)
857 #define SMAASamplePoint(tex, coord) texture2D(tex, coord)
858 #define SMAASampleOffset(tex, coord, offset) texture2D(tex, coord + offset * SMAA_RT_METRICS.rg)
859 #define round(x) floor(x + 0.5)
860 #define textureLod(tex, coord, level) texture2D(tex, coord)
861 #define textureLodOffset(tex, coord, level, offset) texture2D(tex, coord + offset * SMAA_RT_METRICS.rg)
862 #else
863 #define SMAASample(tex, coord) texture(tex, coord)
864 #define SMAASamplePoint(tex, coord) texture(tex, coord)
865 #define SMAASampleOffset(tex, coord, offset) texture(tex, coord, offset)
866 #endif
867 #define SMAA_FLATTEN
868 #define SMAA_BRANCH
869 #define lerp(a, b, t) mix(a, b, t)
870 #define saturate(a) clamp(a, 0.0, 1.0)
871 #if defined(SMAA_GLSL_4)
872 #define mad(a, b, c) fma(a, b, c)
873 #define SMAAGather(tex, coord) textureGather(tex, coord)
874 #else
875 #define mad(a, b, c) (a * b + c)
876 #endif
877 #define float2 vec2
878 #define float3 vec3
879 #define float4 vec4
880 #define int2 ivec2
881 #define int3 ivec3
882 #define int4 ivec4
883 #define bool2 bvec2
884 #define bool3 bvec3
885 #define bool4 bvec4
886 #endif
887 
888 #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)
889 #error you must define the shading language: SMAA_HLSL_*, SMAA_GLSL_* or SMAA_CUSTOM_SL
890 #endif
891 
892 //-----------------------------------------------------------------------------
893 // Misc functions
894 
898 float3 SMAAGatherNeighbours(float2 texcoord,
899  float4 offset[3],
900  SMAATexture2D(tex)) {
901  #ifdef SMAAGather
902  return SMAAGather(tex, texcoord + SMAA_RT_METRICS.xy * float2(-0.5, -0.5)).grb;
903  #else
904  float P = SMAASamplePoint(tex, texcoord).r;
905  float Pleft = SMAASamplePoint(tex, offset[0].xy).r;
906  float Ptop = SMAASamplePoint(tex, offset[0].zw).r;
907  return float3(P, Pleft, Ptop);
908  #endif
909 }
910 
914 float2 SMAACalculatePredicatedThreshold(float2 texcoord,
915  float4 offset[3],
916  SMAATexture2D(predicationTex)) {
917  float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(predicationTex));
918  float2 delta = abs(neighbours.xx - neighbours.yz);
919  float2 edges = step(SMAA_PREDICATION_THRESHOLD, delta);
920  return SMAA_PREDICATION_SCALE * SMAA_THRESHOLD * (1.0 - SMAA_PREDICATION_STRENGTH * edges);
921 }
922 
926 void SMAAMovc(bool2 cond, inout float2 variable, float2 value) {
927  SMAA_FLATTEN if (cond.x) variable.x = value.x;
928  SMAA_FLATTEN if (cond.y) variable.y = value.y;
929 }
930 
931 void SMAAMovc(bool4 cond, inout float4 variable, float4 value) {
932  SMAAMovc(cond.xy, variable.xy, value.xy);
933  SMAAMovc(cond.zw, variable.zw, value.zw);
934 }
935 
936 
937 #if SMAA_INCLUDE_VS
938 //-----------------------------------------------------------------------------
939 // Vertex Shaders
940 
944 void SMAAEdgeDetectionVS(float2 texcoord,
945  out float4 offset[3]) {
946  offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-1.0, 0.0, 0.0, -1.0), texcoord.xyxy);
947  offset[1] = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy);
948  offset[2] = mad(SMAA_RT_METRICS.xyxy, float4(-2.0, 0.0, 0.0, -2.0), texcoord.xyxy);
949 }
950 
954 void SMAABlendingWeightCalculationVS(float2 texcoord,
955  out float2 pixcoord,
956  out float4 offset[3]) {
957  pixcoord = texcoord * SMAA_RT_METRICS.zw;
958 
959  // We will use these offsets for the searches later on (see @PSEUDO_GATHER4):
960  offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-0.25, -0.125, 1.25, -0.125), texcoord.xyxy);
961  offset[1] = mad(SMAA_RT_METRICS.xyxy, float4(-0.125, -0.25, -0.125, 1.25), texcoord.xyxy);
962 
963  // And these for the searches, they indicate the ends of the loops:
964  offset[2] = mad(SMAA_RT_METRICS.xxyy,
965  float4(-2.0, 2.0, -2.0, 2.0) * float(SMAA_MAX_SEARCH_STEPS),
966  float4(offset[0].xz, offset[1].yw));
967 }
968 
972 void SMAANeighborhoodBlendingVS(float2 texcoord,
973  out float4 offset) {
974  offset = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy);
975 }
976 #endif // SMAA_INCLUDE_VS
977 
978 #if SMAA_INCLUDE_PS
979 //-----------------------------------------------------------------------------
980 // Edge Detection Pixel Shaders (First Pass)
981 
988 float2 SMAALumaEdgeDetectionPS(float2 texcoord,
989  float4 offset[3],
990  SMAATexture2D(colorTex)
991  #if SMAA_PREDICATION
992  , SMAATexture2D(predicationTex)
993  #endif
994  ) {
995  // Calculate the threshold:
996  #if SMAA_PREDICATION
997  float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, SMAATexturePass2D(predicationTex));
998  #else
999  float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
1000  #endif
1001 
1002  // Calculate lumas:
1003  float3 weights = float3(0.2126, 0.7152, 0.0722);
1004  float L = dot(SMAASamplePoint(colorTex, texcoord).rgb, weights);
1005 
1006  float Lleft = dot(SMAASamplePoint(colorTex, offset[0].xy).rgb, weights);
1007  float Ltop = dot(SMAASamplePoint(colorTex, offset[0].zw).rgb, weights);
1008 
1009  // We do the usual threshold:
1010  float4 delta;
1011  delta.xy = abs(L - float2(Lleft, Ltop));
1012  float2 edges = step(threshold, delta.xy);
1013 
1014  // Then discard if there is no edge:
1015  if (dot(edges, float2(1.0, 1.0)) == 0.0)
1016  discard;
1017 
1018  // Calculate right and bottom deltas:
1019  float Lright = dot(SMAASamplePoint(colorTex, offset[1].xy).rgb, weights);
1020  float Lbottom = dot(SMAASamplePoint(colorTex, offset[1].zw).rgb, weights);
1021  delta.zw = abs(L - float2(Lright, Lbottom));
1022 
1023  // Calculate the maximum delta in the direct neighborhood:
1024  float2 maxDelta = max(delta.xy, delta.zw);
1025 
1026  // Calculate left-left and top-top deltas:
1027  float Lleftleft = dot(SMAASamplePoint(colorTex, offset[2].xy).rgb, weights);
1028  float Ltoptop = dot(SMAASamplePoint(colorTex, offset[2].zw).rgb, weights);
1029  delta.zw = abs(float2(Lleft, Ltop) - float2(Lleftleft, Ltoptop));
1030 
1031  // Calculate the final maximum delta:
1032  maxDelta = max(maxDelta.xy, delta.zw);
1033  float finalDelta = max(maxDelta.x, maxDelta.y);
1034 
1035  // Local contrast adaptation:
1036  edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
1037 
1038  return edges;
1039 }
1040 
1047 float2 SMAAColorEdgeDetectionPS(float2 texcoord,
1048  float4 offset[3],
1049  SMAATexture2D(colorTex)
1050  #if SMAA_PREDICATION
1051  , SMAATexture2D(predicationTex)
1052  #endif
1053  ) {
1054  // Calculate the threshold:
1055  #if SMAA_PREDICATION
1056  float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, predicationTex);
1057  #else
1058  float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
1059  #endif
1060 
1061  // Calculate color deltas:
1062  float4 delta;
1063  float3 C = SMAASamplePoint(colorTex, texcoord).rgb;
1064 
1065  float3 Cleft = SMAASamplePoint(colorTex, offset[0].xy).rgb;
1066  float3 t = abs(C - Cleft);
1067  delta.x = max(max(t.r, t.g), t.b);
1068 
1069  float3 Ctop = SMAASamplePoint(colorTex, offset[0].zw).rgb;
1070  t = abs(C - Ctop);
1071  delta.y = max(max(t.r, t.g), t.b);
1072 
1073  // We do the usual threshold:
1074  float2 edges = step(threshold, delta.xy);
1075 
1076  // Then discard if there is no edge:
1077  if (dot(edges, float2(1.0, 1.0)) == 0.0)
1078  discard;
1079 
1080  // Calculate right and bottom deltas:
1081  float3 Cright = SMAASamplePoint(colorTex, offset[1].xy).rgb;
1082  t = abs(C - Cright);
1083  delta.z = max(max(t.r, t.g), t.b);
1084 
1085  float3 Cbottom = SMAASamplePoint(colorTex, offset[1].zw).rgb;
1086  t = abs(C - Cbottom);
1087  delta.w = max(max(t.r, t.g), t.b);
1088 
1089  // Calculate the maximum delta in the direct neighborhood:
1090  float2 maxDelta = max(delta.xy, delta.zw);
1091 
1092  // Calculate left-left and top-top deltas:
1093  float3 Cleftleft = SMAASamplePoint(colorTex, offset[2].xy).rgb;
1094  t = abs(C - Cleftleft);
1095  delta.z = max(max(t.r, t.g), t.b);
1096 
1097  float3 Ctoptop = SMAASamplePoint(colorTex, offset[2].zw).rgb;
1098  t = abs(C - Ctoptop);
1099  delta.w = max(max(t.r, t.g), t.b);
1100 
1101  // Calculate the final maximum delta:
1102  maxDelta = max(maxDelta.xy, delta.zw);
1103  float finalDelta = max(maxDelta.x, maxDelta.y);
1104 
1105  // Local contrast adaptation:
1106  edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
1107 
1108  return edges;
1109 }
1110 )SHADER_SOURCE";
1111 
1112 extern const char smaa_base_shader_p3[] = R"SHADER_SOURCE(
1116 float2 SMAADepthEdgeDetectionPS(float2 texcoord,
1117  float4 offset[3],
1118  SMAATexture2D(depthTex)) {
1119  float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(depthTex));
1120  float2 delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z));
1121  float2 edges = step(SMAA_DEPTH_THRESHOLD, delta);
1122 
1123  if (dot(edges, float2(1.0, 1.0)) == 0.0)
1124  discard;
1125 
1126  return edges;
1127 }
1128 
1129 //-----------------------------------------------------------------------------
1130 // Diagonal Search Functions
1131 
1132 #if !defined(SMAA_DISABLE_DIAG_DETECTION)
1133 
1137 float2 SMAADecodeDiagBilinearAccess(float2 e) {
1138  // Bilinear access for fetching 'e' have a 0.25 offset, and we are
1139  // interested in the R and G edges:
1140  //
1141  // +---G---+-------+
1142  // | x o R x |
1143  // +-------+-------+
1144  //
1145  // Then, if one of these edge is enabled:
1146  // Red: (0.75 * X + 0.25 * 1) => 0.25 or 1.0
1147  // Green: (0.75 * 1 + 0.25 * X) => 0.75 or 1.0
1148  //
1149  // This function will unpack the values (mad + mul + round):
1150  // wolframalpha.com: round(x * abs(5 * x - 5 * 0.75)) plot 0 to 1
1151  e.r = e.r * abs(5.0 * e.r - 5.0 * 0.75);
1152  return round(e);
1153 }
1154 
1155 float4 SMAADecodeDiagBilinearAccess(float4 e) {
1156  e.rb = e.rb * abs(5.0 * e.rb - 5.0 * 0.75);
1157  return round(e);
1158 }
1159 
1163 float2 SMAASearchDiag1(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) {
1164  float4 coord = float4(texcoord, -1.0, 1.0);
1165  float3 t = float3(SMAA_RT_METRICS.xy, 1.0);
1166  while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) &&
1167  coord.w > 0.9) {
1168  coord.xyz = mad(t, float3(dir, 1.0), coord.xyz);
1169  e = SMAASampleLevelZero(edgesTex, coord.xy).rg;
1170  coord.w = dot(e, float2(0.5, 0.5));
1171  }
1172  return coord.zw;
1173 }
1174 
1175 float2 SMAASearchDiag2(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) {
1176  float4 coord = float4(texcoord, -1.0, 1.0);
1177  coord.x += 0.25 * SMAA_RT_METRICS.x; // See @SearchDiag2Optimization
1178  float3 t = float3(SMAA_RT_METRICS.xy, 1.0);
1179  while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) &&
1180  coord.w > 0.9) {
1181  coord.xyz = mad(t, float3(dir, 1.0), coord.xyz);
1182 
1183  // @SearchDiag2Optimization
1184  // Fetch both edges at once using bilinear filtering:
1185  e = SMAASampleLevelZero(edgesTex, coord.xy).rg;
1186  e = SMAADecodeDiagBilinearAccess(e);
1187 
1188  // Non-optimized version:
1189  // e.g = SMAASampleLevelZero(edgesTex, coord.xy).g;
1190  // e.r = SMAASampleLevelZeroOffset(edgesTex, coord.xy, int2(1, 0)).r;
1191 
1192  coord.w = dot(e, float2(0.5, 0.5));
1193  }
1194  return coord.zw;
1195 }
1196 
1201 float2 SMAAAreaDiag(SMAATexture2D(areaTex), float2 dist, float2 e, float offset) {
1202  float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE_DIAG, SMAA_AREATEX_MAX_DISTANCE_DIAG), e, dist);
1203 
1204  // We do a scale and bias for mapping to texel space:
1205  texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
1206 
1207  // Diagonal areas are on the second half of the texture:
1208  texcoord.x += 0.5;
1209 
1210  // Move to proper place, according to the subpixel offset:
1211  texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;
1212 
1213  // Do it!
1214  return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
1215 }
1216 
1220 float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex), SMAATexture2D(areaTex), float2 texcoord, float2 e, float4 subsampleIndices) {
1221  float2 weights = float2(0.0, 0.0);
1222 
1223  // Search for the line ends:
1224  float4 d;
1225  float2 end;
1226  if (e.r > 0.0) {
1227  d.xz = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, 1.0), end);
1228  d.x += float(end.y > 0.9);
1229  } else
1230  d.xz = float2(0.0, 0.0);
1231  d.yw = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, -1.0), end);
1232 
1233  SMAA_BRANCH
1234  if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3
1235  // Fetch the crossing edges:
1236  float4 coords = mad(float4(-d.x + 0.25, d.x, d.y, -d.y - 0.25), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
1237  float4 c;
1238  c.xy = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).rg;
1239  c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).rg;
1240  c.yxwz = SMAADecodeDiagBilinearAccess(c.xyzw);
1241 
1242  // Non-optimized version:
1243  // float4 coords = mad(float4(-d.x, d.x, d.y, -d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
1244  // float4 c;
1245  // c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g;
1246  // c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, 0)).r;
1247  // c.z = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).g;
1248  // c.w = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, -1)).r;
1249 
1250  // Merge crossing edges at each side into a single value:
1251  float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw);
1252 
1253  // Remove the crossing edge if we didn't found the end of the line:
1254  SMAAMovc(bool2(step(0.9, d.zw)), cc, float2(0.0, 0.0));
1255 
1256  // Fetch the areas for this line:
1257  weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.z);
1258  }
1259 
1260  // Search for the line ends:
1261  d.xz = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, -1.0), end);
1262  if (SMAASampleLevelZeroOffset(edgesTex, texcoord, int2(1, 0)).r > 0.0) {
1263  d.yw = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, 1.0), end);
1264  d.y += float(end.y > 0.9);
1265  } else
1266  d.yw = float2(0.0, 0.0);
1267 
1268  SMAA_BRANCH
1269  if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3
1270  // Fetch the crossing edges:
1271  float4 coords = mad(float4(-d.x, -d.x, d.y, d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
1272  float4 c;
1273  c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g;
1274  c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, -1)).r;
1275  c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).gr;
1276  float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw);
1277 
1278  // Remove the crossing edge if we didn't found the end of the line:
1279  SMAAMovc(bool2(step(0.9, d.zw)), cc, float2(0.0, 0.0));
1280 
1281  // Fetch the areas for this line:
1282  weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.w).gr;
1283  }
1284 
1285  return weights;
1286 }
1287 #endif
1288 
1289 //-----------------------------------------------------------------------------
1290 // Horizontal/Vertical Search Functions
1291 
1298 float SMAASearchLength(SMAATexture2D(searchTex), float2 e, float offset) {
1299  // The texture is flipped vertically, with left and right cases taking half
1300  // of the space horizontally:
1301  float2 scale = SMAA_SEARCHTEX_SIZE * float2(0.5, -1.0);
1302  float2 bias = SMAA_SEARCHTEX_SIZE * float2(offset, 1.0);
1303 
1304  // Scale and bias to access texel centers:
1305  scale += float2(-1.0, 1.0);
1306  bias += float2( 0.5, -0.5);
1307 
1308  // Convert from pixel coordinates to texcoords:
1309  // (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped)
1310  scale *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
1311  bias *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
1312 
1313  // Lookup the search texture:
1314  return SMAA_SEARCHTEX_SELECT(SMAASampleLevelZero(searchTex, mad(scale, e, bias)));
1315 }
1316 
1320 float SMAASearchXLeft(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1328  float2 e = float2(0.0, 1.0);
1329  while (texcoord.x > end &&
1330  e.g > 0.8281 && // Is there some edge not activated?
1331  e.r == 0.0) { // Or is there a crossing edge that breaks the line?
1332  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1333  texcoord = mad(-float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord);
1334  }
1335 
1336  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0), 3.25);
1337  return mad(SMAA_RT_METRICS.x, offset, texcoord.x);
1338 
1339  // Non-optimized version:
1340  // We correct the previous (-0.25, -0.125) offset we applied:
1341  // texcoord.x += 0.25 * SMAA_RT_METRICS.x;
1342 
1343  // The searches are bias by 1, so adjust the coords accordingly:
1344  // texcoord.x += SMAA_RT_METRICS.x;
1345 
1346  // Disambiguate the length added by the last step:
1347  // texcoord.x += 2.0 * SMAA_RT_METRICS.x; // Undo last step
1348  // texcoord.x -= SMAA_RT_METRICS.x * (255.0 / 127.0) * SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0);
1349  // return mad(SMAA_RT_METRICS.x, offset, texcoord.x);
1350 }
1351 
1352 float SMAASearchXRight(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1353  float2 e = float2(0.0, 1.0);
1354  while (texcoord.x < end &&
1355  e.g > 0.8281 && // Is there some edge not activated?
1356  e.r == 0.0) { // Or is there a crossing edge that breaks the line?
1357  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1358  texcoord = mad(float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord);
1359  }
1360  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.5), 3.25);
1361  return mad(-SMAA_RT_METRICS.x, offset, texcoord.x);
1362 }
1363 
1364 float SMAASearchYUp(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1365  float2 e = float2(1.0, 0.0);
1366  while (texcoord.y > end &&
1367  e.r > 0.8281 && // Is there some edge not activated?
1368  e.g == 0.0) { // Or is there a crossing edge that breaks the line?
1369  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1370  texcoord = mad(-float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord);
1371  }
1372  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.0), 3.25);
1373  return mad(SMAA_RT_METRICS.y, offset, texcoord.y);
1374 }
1375 
1376 float SMAASearchYDown(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1377  float2 e = float2(1.0, 0.0);
1378  while (texcoord.y < end &&
1379  e.r > 0.8281 && // Is there some edge not activated?
1380  e.g == 0.0) { // Or is there a crossing edge that breaks the line?
1381  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1382  texcoord = mad(float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord);
1383  }
1384  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.5), 3.25);
1385  return mad(-SMAA_RT_METRICS.y, offset, texcoord.y);
1386 }
1387 
1392 float2 SMAAArea(SMAATexture2D(areaTex), float2 dist, float e1, float e2, float offset) {
1393  // Rounding prevents precision errors of bilinear filtering:
1394  float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE), round(4.0 * float2(e1, e2)), dist);
1395 
1396  // We do a scale and bias for mapping to texel space:
1397  texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
1398 
1399  // Move to proper place, according to the subpixel offset:
1400  texcoord.y = mad(SMAA_AREATEX_SUBTEX_SIZE, offset, texcoord.y);
1401 
1402  // Do it!
1403  return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
1404 }
1405 
1406 //-----------------------------------------------------------------------------
1407 // Corner Detection Functions
1408 
1409 void SMAADetectHorizontalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) {
1410  #if !defined(SMAA_DISABLE_CORNER_DETECTION)
1411  float2 leftRight = step(d.xy, d.yx);
1412  float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight;
1413 
1414  rounding /= leftRight.x + leftRight.y; // Reduce blending for pixels in the center of a line.
1415 
1416  float2 factor = float2(1.0, 1.0);
1417  factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, 1)).r;
1418  factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, 1)).r;
1419  factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, -2)).r;
1420  factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, -2)).r;
1421 
1422  weights *= saturate(factor);
1423  #endif
1424 }
1425 
1426 void SMAADetectVerticalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) {
1427  #if !defined(SMAA_DISABLE_CORNER_DETECTION)
1428  float2 leftRight = step(d.xy, d.yx);
1429  float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight;
1430 
1431  rounding /= leftRight.x + leftRight.y;
1432 
1433  float2 factor = float2(1.0, 1.0);
1434  factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2( 1, 0)).g;
1435  factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2( 1, 1)).g;
1436  factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(-2, 0)).g;
1437  factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(-2, 1)).g;
1438 
1439  weights *= saturate(factor);
1440  #endif
1441 }
1442 
1443 //-----------------------------------------------------------------------------
1444 // Blending Weight Calculation Pixel Shader (Second Pass)
1445 
1446 float4 SMAABlendingWeightCalculationPS(float2 texcoord,
1447  float2 pixcoord,
1448  float4 offset[3],
1449  SMAATexture2D(edgesTex),
1450  SMAATexture2D(areaTex),
1451  SMAATexture2D(searchTex),
1452  float4 subsampleIndices) { // Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES.
1453  float4 weights = float4(0.0, 0.0, 0.0, 0.0);
1454 
1455  float2 e = SMAASample(edgesTex, texcoord).rg;
1456 
1457  SMAA_BRANCH
1458  if (e.g > 0.0) { // Edge at north
1459  #if !defined(SMAA_DISABLE_DIAG_DETECTION)
1460  // Diagonals have both north and west edges, so searching for them in
1461  // one of the boundaries is enough.
1462  weights.rg = SMAACalculateDiagWeights(SMAATexturePass2D(edgesTex), SMAATexturePass2D(areaTex), texcoord, e, subsampleIndices);
1463 
1464  // We give priority to diagonals, so if we find a diagonal we skip
1465  // horizontal/vertical processing.
1466  SMAA_BRANCH
1467  if (weights.r == -weights.g) { // weights.r + weights.g == 0.0
1468  #endif
1469 
1470  float2 d;
1471 
1472  // Find the distance to the left:
1473  float3 coords;
1474  coords.x = SMAASearchXLeft(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].xy, offset[2].x);
1475  coords.y = offset[1].y; // offset[1].y = texcoord.y - 0.25 * SMAA_RT_METRICS.y (@CROSSING_OFFSET)
1476  d.x = coords.x;
1477 
1478  // Now fetch the left crossing edges, two at a time using bilinear
1479  // filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to
1480  // discern what value each edge has:
1481  float e1 = SMAASampleLevelZero(edgesTex, coords.xy).r;
1482 
1483  // Find the distance to the right:
1484  coords.z = SMAASearchXRight(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].zw, offset[2].y);
1485  d.y = coords.z;
1486 
1487  // We want the distances to be in pixel units (doing this here allow to
1488  // better interleave arithmetic and memory accesses):
1489  d = abs(round(mad(SMAA_RT_METRICS.zz, d, -pixcoord.xx)));
1490 
1491  // SMAAArea below needs a sqrt, as the areas texture is compressed
1492  // quadratically:
1493  float2 sqrt_d = sqrt(d);
1494 )SHADER_SOURCE";
1495 
1496 extern const char smaa_base_shader_p4[] = R"SHADER_SOURCE(
1497  // Fetch the right crossing edges:
1498  float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.zy, int2(1, 0)).r;
1499 
1500  // Ok, we know how this pattern looks like, now it is time for getting
1501  // the actual area:
1502  weights.rg = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.y);
1503 
1504  // Fix corners:
1505  coords.y = texcoord.y;
1506  SMAADetectHorizontalCornerPattern(SMAATexturePass2D(edgesTex), weights.rg, coords.xyzy, d);
1507 
1508  #if !defined(SMAA_DISABLE_DIAG_DETECTION)
1509  } else
1510  e.r = 0.0; // Skip vertical processing.
1511  #endif
1512  }
1513 
1514  SMAA_BRANCH
1515  if (e.r > 0.0) { // Edge at west
1516  float2 d;
1517 
1518  // Find the distance to the top:
1519  float3 coords;
1520  coords.y = SMAASearchYUp(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].xy, offset[2].z);
1521  coords.x = offset[0].x; // offset[1].x = texcoord.x - 0.25 * SMAA_RT_METRICS.x;
1522  d.x = coords.y;
1523 
1524  // Fetch the top crossing edges:
1525  float e1 = SMAASampleLevelZero(edgesTex, coords.xy).g;
1526 
1527  // Find the distance to the bottom:
1528  coords.z = SMAASearchYDown(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].zw, offset[2].w);
1529  d.y = coords.z;
1530 
1531  // We want the distances to be in pixel units:
1532  d = abs(round(mad(SMAA_RT_METRICS.ww, d, -pixcoord.yy)));
1533 
1534  // SMAAArea below needs a sqrt, as the areas texture is compressed
1535  // quadratically:
1536  float2 sqrt_d = sqrt(d);
1537 
1538  // Fetch the bottom crossing edges:
1539  float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.xz, int2(0, 1)).g;
1540 
1541  // Get the area for this direction:
1542  weights.ba = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.x);
1543 
1544  // Fix corners:
1545  coords.x = texcoord.x;
1546  SMAADetectVerticalCornerPattern(SMAATexturePass2D(edgesTex), weights.ba, coords.xyxz, d);
1547  }
1548 
1549  return weights;
1550 }
1551 
1552 //-----------------------------------------------------------------------------
1553 // Neighborhood Blending Pixel Shader (Third Pass)
1554 
1555 float4 SMAANeighborhoodBlendingPS(float2 texcoord,
1556  float4 offset,
1557  SMAATexture2D(colorTex),
1558  SMAATexture2D(blendTex)
1559  #if SMAA_REPROJECTION
1560  , SMAATexture2D(velocityTex)
1561  #endif
1562  ) {
1563  // Fetch the blending weights for current pixel:
1564  float4 a;
1565  a.x = SMAASample(blendTex, offset.xy).a; // Right
1566  a.y = SMAASample(blendTex, offset.zw).g; // Top
1567  a.wz = SMAASample(blendTex, texcoord).xz; // Bottom / Left
1568 
1569  // Is there any blending weight with a value greater than 0.0?
1570  SMAA_BRANCH
1571  if (dot(a, float4(1.0, 1.0, 1.0, 1.0)) < 1e-5) {
1572  float4 color = SMAASampleLevelZero(colorTex, texcoord);
1573 
1574  #if SMAA_REPROJECTION
1575  float2 velocity = SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, texcoord));
1576 
1577  // Pack velocity into the alpha channel:
1578  color.a = sqrt(5.0 * length(velocity));
1579  #endif
1580 
1581  return color;
1582  } else {
1583  bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical)
1584 
1585  // Calculate the blending offsets:
1586  float4 blendingOffset = float4(0.0, a.y, 0.0, a.w);
1587  float2 blendingWeight = a.yw;
1588  SMAAMovc(bool4(h, h, h, h), blendingOffset, float4(a.x, 0.0, a.z, 0.0));
1589  SMAAMovc(bool2(h, h), blendingWeight, a.xz);
1590  blendingWeight /= dot(blendingWeight, float2(1.0, 1.0));
1591 
1592  // Calculate the texture coordinates:
1593  float4 blendingCoord = mad(blendingOffset, float4(SMAA_RT_METRICS.xy, -SMAA_RT_METRICS.xy), texcoord.xyxy);
1594 
1595  // We exploit bilinear filtering to mix current pixel with the chosen
1596  // neighbor:
1597  float4 color = blendingWeight.x * SMAASampleLevelZero(colorTex, blendingCoord.xy);
1598  color += blendingWeight.y * SMAASampleLevelZero(colorTex, blendingCoord.zw);
1599 
1600  #if SMAA_REPROJECTION
1601  // Antialias velocity for proper reprojection in a later stage:
1602  float2 velocity = blendingWeight.x * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.xy));
1603  velocity += blendingWeight.y * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.zw));
1604 
1605  // Pack velocity into the alpha channel:
1606  color.a = sqrt(5.0 * length(velocity));
1607  #endif
1608 
1609  return color;
1610  }
1611 }
1612 
1613 //-----------------------------------------------------------------------------
1614 // Temporal Resolve Pixel Shader (Optional Pass)
1615 
1616 float4 SMAAResolvePS(float2 texcoord,
1617  SMAATexture2D(currentColorTex),
1618  SMAATexture2D(previousColorTex)
1619  #if SMAA_REPROJECTION
1620  , SMAATexture2D(velocityTex)
1621  #endif
1622  ) {
1623  #if SMAA_REPROJECTION
1624  // Velocity is assumed to be calculated for motion blur, so we need to
1625  // inverse it for reprojection:
1626  float2 velocity = -SMAA_DECODE_VELOCITY(SMAASamplePoint(velocityTex, texcoord).rg);
1627 
1628  // Fetch current pixel:
1629  float4 current = SMAASamplePoint(currentColorTex, texcoord);
1630 
1631  // Reproject current coordinates and fetch previous pixel:
1632  float4 previous = SMAASamplePoint(previousColorTex, texcoord + velocity);
1633 
1634  // Attenuate the previous pixel if the velocity is different:
1635  float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0;
1636  float weight = 0.5 * saturate(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE);
1637 
1638  // Blend the pixels according to the calculated weight:
1639  return lerp(current, previous, weight);
1640  #else
1641  // Just blend the pixels:
1642  float4 current = SMAASamplePoint(currentColorTex, texcoord);
1643  float4 previous = SMAASamplePoint(previousColorTex, texcoord);
1644  return lerp(current, previous, 0.5);
1645  #endif
1646 }
1647 
1648 //-----------------------------------------------------------------------------
1649 // Separate Multisamples Pixel Shader (Optional Pass)
1650 
1651 #ifdef SMAALoad
1652 void SMAASeparatePS(float4 position,
1653  float2 texcoord,
1654  out float4 target0,
1655  out float4 target1,
1656  SMAATexture2DMS2(colorTexMS)) {
1657  int2 pos = int2(position.xy);
1658  target0 = SMAALoad(colorTexMS, pos, 0);
1659  target1 = SMAALoad(colorTexMS, pos, 1);
1660 }
1661 #endif
1662 
1663 //-----------------------------------------------------------------------------
1664 #endif // SMAA_INCLUDE_PS
1665 
1666 )SHADER_SOURCE";
1667 
1668 const char smaa_pass_1_vertex_shader[] = R"SHADER_SOURCE(
1669 
1670 varying vec4 offset[3];
1671 varying vec2 texcoord;
1672 
1673 void main()
1674 {
1675  texcoord = gl_MultiTexCoord0.st;
1676  SMAAEdgeDetectionVS( texcoord, offset);
1677  gl_Position = ftransform();
1678 
1679 }
1680 
1681 )SHADER_SOURCE";
1682 
1683 const char smaa_pass_1_fragment_shader[] = R"SHADER_SOURCE(
1684 
1685 varying vec2 texcoord;
1686 varying vec4 offset[3];
1687 uniform sampler2D colorTex;
1688 
1689 void main()
1690 {
1691  gl_FragColor.xy = SMAALumaEdgeDetectionPS(texcoord, offset, colorTex).xy;
1692 }
1693 
1694 )SHADER_SOURCE";
1695 
1696 const char smaa_pass_2_vertex_shader[] = R"SHADER_SOURCE(
1697 
1698 varying vec4 offset[3];
1699 varying vec2 texcoord;
1700 varying vec2 pixcoord;
1701 
1702 void main()
1703 {
1704  texcoord = gl_MultiTexCoord0.st;
1705  SMAABlendingWeightCalculationVS( texcoord, pixcoord, offset );
1706  gl_Position = ftransform();
1707 }
1708 
1709 )SHADER_SOURCE";
1710 
1711 const char smaa_pass_2_fragment_shader[] = R"SHADER_SOURCE(
1712 
1713 varying vec2 texcoord;
1714 varying vec2 pixcoord;
1715 varying vec4 offset[3];
1716 uniform sampler2D edgesTex;
1717 uniform sampler2D areaTex;
1718 uniform sampler2D searchTex;
1719 
1720 void main()
1721 {
1722  gl_FragColor = SMAABlendingWeightCalculationPS(texcoord, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0.,0.,0.,0.));
1723 }
1724 
1725 )SHADER_SOURCE";
1726 
1727 const char smaa_pass_3_vertex_shader[] = R"SHADER_SOURCE(
1728 
1729 varying vec4 offset;
1730 varying vec2 texcoord;
1731 
1732 void main()
1733 {
1734  texcoord = gl_MultiTexCoord0.st;
1735  SMAANeighborhoodBlendingVS( texcoord, offset );
1736  gl_Position = ftransform();
1737 }
1738 
1739 )SHADER_SOURCE";
1740 
1741 const char smaa_pass_3_fragment_shader[] = R"SHADER_SOURCE(
1742 
1743 varying vec2 texcoord;
1744 varying vec4 offset;
1745 uniform sampler2D colorTex;
1746 uniform sampler2D blendTex;
1747 
1748 void main()
1749 {
1750  gl_FragColor = SMAANeighborhoodBlendingPS(texcoord, offset, colorTex, blendTex);
1751 }
1752 
1753 )SHADER_SOURCE";
1754 
1755 }
1756 }
1757 
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:57
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[]