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 uniform vec2 screenPixelSize;
84 uniform float pixelSizeMultiplier;
85 uniform float minLinePixelWidth;
86 
87 
88 float roundr( float f, float r )
89 {
90  return floor(f / r + 0.5) * r;
91 }
92 
93 vec4 roundv( vec4 x, vec2 t)
94 {
95  return vec4( roundr(x.x, t.x), roundr(x.y, t.y), x.z, x.w );
96 }
97 
98 void computeLineCoords( bool posture, vec2 vs, vec2 vp, vec2 texcoord, vec2 dir, float lineWidth, bool endV )
99 {
100  float lineLength = length(vs);
101  vec4 screenPos = gl_ModelViewProjectionMatrix * gl_Vertex + vec4(1, 1, 0, 0);
102  float w = ((lineWidth == 0.0) ? worldPixelSize : lineWidth );
103  float pixelWidth = roundr( w / worldPixelSize, 1.0 );
104  float aspect = ( lineLength + w ) / w;
105  vec4 color = gl_Color;
106  vec2 s = sign( vec2( gl_ModelViewProjectionMatrix[0][0], gl_ModelViewProjectionMatrix[1][1] ) );
107 
108 
109  if( pixelWidth < 1.0 )
110  pixelWidth = 1.0;
111 
112  if ( pixelWidth > 1.0 || pixelSizeMultiplier > 1.0 )
113  {
114  vec2 offsetNorm = (vs + vp) * pixelWidth / lineLength * 0.5;
115  vec4 screenOffset = vec4( s.x * offsetNorm.x * screenPixelSize.x, s.y * offsetNorm.y * screenPixelSize.y , 0, 0);
116  vec4 adjust = vec4(-1, -1, 0, 0);
117 
118  if( mod( pixelWidth * pixelSizeMultiplier, 2.0 ) > 0.9 )
119  {
120  adjust += vec4( screenPixelSize.x, screenPixelSize.y, 0, 0 ) * 0.5;
121  }
122 
123  gl_Position = roundv(screenPos, screenPixelSize) + adjust + screenOffset;
124 
125  shaderParams[0] = SHADER_LINE_A;
126  }
127  else {
128  vec4 pos0 = screenPos;
129  pos0.xy += ( posture ? dir.xy : dir.yx ) * screenPixelSize / 2.0;
130 
131  if(posture)
132  {
133  pos0.y -= screenPixelSize.y * sign(vs.y) * 0.5;
134  }
135  else
136  {
137  pos0.x += screenPixelSize.x * sign(vs.x) * 0.5;
138  }
139 
140  gl_Position = pos0 - vec4(1, 1, 0, 0);
141  shaderParams[0] = SHADER_LINE_B;
142  }
143 
144  shaderParams[1] = aspect;
145 
146  gl_TexCoord[0].st = vec2(aspect * texcoord.x, texcoord.y);
147  gl_FrontColor = gl_Color;
148 }
149 
150 
151 void computeCircleCoords( float mode, float vertexIndex, float radius, float lineWidth )
152 {
153  vec4 delta;
154  vec4 center = roundv( gl_ModelViewProjectionMatrix * gl_Vertex + vec4(1, 1, 0, 0), screenPixelSize );
155  float pixelWidth = roundr( lineWidth / worldPixelSize, 1.0);
156  float pixelR = roundr( radius / worldPixelSize, 1.0);
157 
158  if( mode == SHADER_STROKED_CIRCLE)
159  pixelR += pixelWidth / 2.0;
160 
161  vec4 adjust = vec4(-1, -1, 0, 0);
162 
163  if( pixelWidth < 1.0 )
164  pixelWidth = 1.0;
165 
166  if( vertexIndex == 1.0 )
167  {
168  circleCoords = vec2( -sqrt( 3.0 ), -1.0 );
169  delta = vec4( -pixelR * sqrt(3.0), -pixelR, 0, 0 );
170  }
171  else if( vertexIndex == 2.0 )
172  {
173  circleCoords = vec2( sqrt( 3.0 ), -1.0 );
174  delta = vec4( pixelR * sqrt( 3.0 ), -pixelR, 0, 0 );
175  }
176  else if( vertexIndex == 3.0 )
177  {
178  circleCoords = vec2( 0.0, 2.0 );
179  delta = vec4( 0, 2 * pixelR, 0, 0 );
180  }
181  else if( vertexIndex == 4.0 )
182  {
183  circleCoords = vec2( -sqrt( 3.0 ), 0.0 );
184  delta = vec4( 0, 0, 0, 0 );
185  }
186  else if( vertexIndex == 5.0 )
187  {
188  circleCoords = vec2( sqrt( 3.0 ), 0.0 );
189  delta = vec4( 0, 0, 0, 0 );
190  }
191  else if( vertexIndex == 6.0 )
192  {
193  circleCoords = vec2( 0.0, 2.0 );
194  delta = vec4( 0, 0, 0, 0 );
195  }
196 
197  shaderParams[2] = pixelR;
198  shaderParams[3] = pixelWidth;
199 
200  delta.x *= screenPixelSize.x;
201  delta.y *= screenPixelSize.y;
202 
203  gl_Position = center + delta + adjust;
204  gl_FrontColor = gl_Color;
205 }
206 
207 
208 void main()
209 {
210  float mode = attrShaderParams[0];
211 
212  // Pass attributes to the fragment shader
213  shaderParams = attrShaderParams;
214 
215  float lineWidth = shaderParams.y;
216  vec2 vs = shaderParams.zw;
217  vec2 vp = vec2(-vs.y, vs.x);
218  bool posture = abs( vs.x ) < abs(vs.y);
219 
220  if( mode == SHADER_LINE_A )
221  computeLineCoords( posture, -vs, vp, vec2( -1, -1 ), vec2( -1, 0 ), lineWidth, false );
222  else if( mode == SHADER_LINE_B )
223  computeLineCoords( posture, -vs, -vp, vec2( -1, 1 ), vec2( 1, 0 ), lineWidth, false );
224  else if( mode == SHADER_LINE_C )
225  computeLineCoords( posture, vs, -vp, vec2( 1, 1 ), vec2( 1, 0 ), lineWidth, true );
226  else if( mode == SHADER_LINE_D )
227  computeLineCoords( posture, vs, -vp, vec2( -1, -1 ), vec2( 1, 0 ), lineWidth, true );
228  else if( mode == SHADER_LINE_E )
229  computeLineCoords( posture, vs, vp, vec2( -1, 1 ), vec2( -1, 0 ), lineWidth, true );
230  else if( mode == SHADER_LINE_F )
231  computeLineCoords( posture, -vs, vp, vec2( 1, 1 ), vec2( -1, 0 ), lineWidth, false );
232  else if( mode == SHADER_FILLED_CIRCLE || mode == SHADER_STROKED_CIRCLE)
233  computeCircleCoords( mode, shaderParams.y, shaderParams.z, shaderParams.w );
234  else
235  {
236  // Pass through the coordinates like in the fixed pipeline
237  gl_Position = ftransform();
238  gl_FrontColor = gl_Color;
239 
240  }
241 
242 }
243 
244 )SHADER_SOURCE";
245 
246 const char kicad_fragment_shader[] = R"SHADER_SOURCE(
247 
248 /*
249  * This program source code file is part of KICAD, a free EDA CAD application.
250  *
251  * Copyright (C) 2013-2016 CERN
252  * Copyright (C) 2016 Kicad Developers, see authors.txt for contributors.
253  * @author Maciej Suminski <maciej.suminski@cern.ch>
254  *
255  * Fragment shader
256  *
257  * This program is free software; you can redistribute it and/or
258  * modify it under the terms of the GNU General Public License
259  * as published by the Free Software Foundation; either version 2
260  * of the License, or (at your option) any later version.
261  *
262  * This program is distributed in the hope that it will be useful,
263  * but WITHOUT ANY WARRANTY; without even the implied warranty of
264  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
265  * GNU General Public License for more details.
266  *
267  * You should have received a copy of the GNU General Public License
268  * along with this program; if not, you may find one here:
269  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
270  * or you may search the http://www.gnu.org website for the version 2 license,
271  * or you may write to the Free Software Foundation, Inc.,
272  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
273  */
274 
275 #version 120
276 
277 // Multi-channel signed distance field
278 #define USE_MSDF
279 
280 // Shader types
281 const float SHADER_FILLED_CIRCLE = 2.0;
282 const float SHADER_STROKED_CIRCLE = 3.0;
283 const float SHADER_FONT = 4.0;
284 const float SHADER_LINE_A = 5.0;
285 const float SHADER_LINE_B = 6.0;
286 
287 varying vec4 shaderParams;
288 varying vec2 circleCoords;
289 uniform sampler2D fontTexture;
290 uniform float worldPixelSize;
291 
292 // Needed to reconstruct the mipmap level / texel derivative
293 uniform int fontTextureWidth;
294 
295 void filledCircle( vec2 aCoord )
296 {
297  if( dot( aCoord, aCoord ) < 1.0 )
298  gl_FragColor = gl_Color;
299  else
300  discard;
301 }
302 
303 float pixelSegDistance( vec2 aCoord )
304 {
305  if( shaderParams[0] == SHADER_LINE_B )
306  {
307  gl_FragColor = gl_Color;
308  return 0.0;
309  }
310 
311  float aspect = shaderParams[1];
312  float dist;
313  vec2 v = vec2( 1.0 - ( aspect - abs( aCoord.s ) ), aCoord.t );
314 
315  if( v.x <= 0.0 )
316  {
317  dist = abs( aCoord.t );
318  }
319  else
320  {
321  dist = length( v );
322  }
323 
324  return dist;
325 }
326 
327 int isPixelInSegment( vec2 aCoord )
328 {
329  return pixelSegDistance( aCoord ) <= 1.0 ? 1 : 0;
330 }
331 
332 
333 
334 void strokedCircle( vec2 aCoord, float aRadius, float aWidth )
335 {
336  float outerRadius = max( aRadius, 0.0 );
337  float innerRadius = max( aRadius - aWidth, 0.0 );
338 
339  if( ( dot( aCoord, aCoord ) < 1.0 ) &&
340  ( dot( aCoord, aCoord ) * ( outerRadius * outerRadius ) > innerRadius * innerRadius ) )
341  gl_FragColor = gl_Color;
342  else
343  discard;
344 }
345 
346 
347 void drawLine( vec2 aCoord )
348 {
349  if( isPixelInSegment( aCoord ) != 0)
350  gl_FragColor = gl_Color;
351  else
352  discard;
353 }
354 
355 #ifdef USE_MSDF
356 float median( vec3 v )
357 {
358  return max( min( v.r, v.g ), min( max( v.r, v.g ), v.b ) );
359 }
360 #endif
361 
362 void main()
363 {
364  if( shaderParams[0] == SHADER_LINE_A )
365  {
366  drawLine( gl_TexCoord[0].st );
367  }
368  else if( shaderParams[0] == SHADER_FILLED_CIRCLE )
369  {
370  filledCircle( circleCoords );
371  }
372  else if( shaderParams[0] == SHADER_STROKED_CIRCLE )
373  {
374  strokedCircle( circleCoords, shaderParams[2], shaderParams[3] );
375  }
376  else if( shaderParams[0] == SHADER_FONT )
377  {
378  vec2 tex = shaderParams.yz;
379 
380  // Unless we're stretching chars it is okay to consider
381  // one derivative for filtering
382  float derivative = length( dFdx( tex ) ) * fontTextureWidth / 4;
383 
384 #ifdef USE_MSDF
385  float dist = median( texture2D( fontTexture, tex ).rgb );
386 #else
387  float dist = texture2D( fontTexture, tex ).r;
388 #endif
389 
390  // use the derivative for zoom-adaptive filtering
391  float alpha = smoothstep( 0.5 - derivative, 0.5 + derivative, dist );
392 
393  gl_FragColor = vec4( gl_Color.rgb, alpha );
394  }
395  else
396  {
397  // Simple pass-through
398  gl_FragColor = gl_Color;
399  }
400 }
401 
402 )SHADER_SOURCE";
403 
404 const char ssaa_x4_vertex_shader[] = R"SHADER_SOURCE(
405 
406 #version 120
407 varying vec2 texcoord;
408 void main()
409 {
410  texcoord = gl_MultiTexCoord0.st;
411  gl_Position = ftransform();
412 }
413 
414 )SHADER_SOURCE";
415 
416 const char ssaa_x4_fragment_shader[] = R"SHADER_SOURCE(
417 
418 #version 120
419 varying vec2 texcoord;
420 uniform sampler2D source;
421 void main()
422 {
423  float step_x = dFdx(texcoord.x)/4.;
424  float step_y = dFdy(texcoord.y)/4.;
425 
426  vec4 q00 = texture2D( source, texcoord + vec2(-step_x, -step_y) );
427  vec4 q01 = texture2D( source, texcoord + vec2( step_x, -step_y) );
428  vec4 q10 = texture2D( source, texcoord + vec2(-step_x, step_y) );
429  vec4 q11 = texture2D( source, texcoord + vec2( step_x, step_y) );
430 
431  gl_FragColor = (q00+q01+q10+q11)/4;
432 }
433 
434 )SHADER_SOURCE";
435 
436 const char smaa_base_shader_p1[] = R"SHADER_SOURCE(
437 
735 //-----------------------------------------------------------------------------
736 // SMAA Presets
737 
743 #if defined(SMAA_PRESET_LOW)
744 #define SMAA_THRESHOLD 0.15
745 #define SMAA_MAX_SEARCH_STEPS 4
746 #define SMAA_DISABLE_DIAG_DETECTION
747 #define SMAA_DISABLE_CORNER_DETECTION
748 #elif defined(SMAA_PRESET_MEDIUM)
749 #define SMAA_THRESHOLD 0.1
750 #define SMAA_MAX_SEARCH_STEPS 8
751 #define SMAA_DISABLE_DIAG_DETECTION
752 #define SMAA_DISABLE_CORNER_DETECTION
753 #elif defined(SMAA_PRESET_HIGH)
754 #define SMAA_THRESHOLD 0.1
755 #define SMAA_MAX_SEARCH_STEPS 16
756 #define SMAA_MAX_SEARCH_STEPS_DIAG 8
757 #define SMAA_CORNER_ROUNDING 25
758 #elif defined(SMAA_PRESET_ULTRA)
759 #define SMAA_THRESHOLD 0.005
760 //0.05
761 #define SMAA_MAX_SEARCH_STEPS 64
762 //32
763 #define SMAA_MAX_SEARCH_STEPS_DIAG 32
764 //16
765 #define SMAA_CORNER_ROUNDING 25
766 #endif
767 
768 //-----------------------------------------------------------------------------
769 // Configurable Defines
770 
783 #ifndef SMAA_THRESHOLD
784 #define SMAA_THRESHOLD 0.1
785 #endif
786 
792 #ifndef SMAA_DEPTH_THRESHOLD
793 #define SMAA_DEPTH_THRESHOLD (0.1 * SMAA_THRESHOLD)
794 #endif
795 
806 #ifndef SMAA_MAX_SEARCH_STEPS
807 #define SMAA_MAX_SEARCH_STEPS 16
808 #endif
809 )SHADER_SOURCE";
810 
811 const char smaa_base_shader_p2[] = R"SHADER_SOURCE(
824 #ifndef SMAA_MAX_SEARCH_STEPS_DIAG
825 #define SMAA_MAX_SEARCH_STEPS_DIAG 8
826 #endif
827 
835 #ifndef SMAA_CORNER_ROUNDING
836 #define SMAA_CORNER_ROUNDING 25
837 #endif
838 
847 #ifndef SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR
848 #define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 2.0
849 #endif
850 
865 #ifndef SMAA_PREDICATION
866 #define SMAA_PREDICATION 0
867 #endif
868 
875 #ifndef SMAA_PREDICATION_THRESHOLD
876 #define SMAA_PREDICATION_THRESHOLD 0.01
877 #endif
878 
885 #ifndef SMAA_PREDICATION_SCALE
886 #define SMAA_PREDICATION_SCALE 2.0
887 #endif
888 
894 #ifndef SMAA_PREDICATION_STRENGTH
895 #define SMAA_PREDICATION_STRENGTH 0.4
896 #endif
897 
909 #ifndef SMAA_REPROJECTION
910 #define SMAA_REPROJECTION 0
911 #endif
912 
924 #ifndef SMAA_REPROJECTION_WEIGHT_SCALE
925 #define SMAA_REPROJECTION_WEIGHT_SCALE 30.0
926 #endif
927 
932 #ifndef SMAA_INCLUDE_VS
933 #define SMAA_INCLUDE_VS 1
934 #endif
935 #ifndef SMAA_INCLUDE_PS
936 #define SMAA_INCLUDE_PS 1
937 #endif
938 
939 //-----------------------------------------------------------------------------
940 // Texture Access Defines
941 
942 #ifndef SMAA_AREATEX_SELECT
943 #if defined(SMAA_HLSL_3)
944 #define SMAA_AREATEX_SELECT(sample) sample.ra
945 #else
946 #define SMAA_AREATEX_SELECT(sample) sample.rg
947 #endif
948 #endif
949 
950 #ifndef SMAA_SEARCHTEX_SELECT
951 #define SMAA_SEARCHTEX_SELECT(sample) sample.r
952 #endif
953 
954 #ifndef SMAA_DECODE_VELOCITY
955 #define SMAA_DECODE_VELOCITY(sample) sample.rg
956 #endif
957 
958 //-----------------------------------------------------------------------------
959 // Non-Configurable Defines
960 
961 #define SMAA_AREATEX_MAX_DISTANCE 16
962 #define SMAA_AREATEX_MAX_DISTANCE_DIAG 20
963 #define SMAA_AREATEX_PIXEL_SIZE (1.0 / float2(160.0, 560.0))
964 #define SMAA_AREATEX_SUBTEX_SIZE (1.0 / 7.0)
965 #define SMAA_SEARCHTEX_SIZE float2(66.0, 33.0)
966 #define SMAA_SEARCHTEX_PACKED_SIZE float2(64.0, 16.0)
967 #define SMAA_CORNER_ROUNDING_NORM (float(SMAA_CORNER_ROUNDING) / 100.0)
968 
969 //-----------------------------------------------------------------------------
970 // Porting Functions
971 
972 #if defined(SMAA_HLSL_3)
973 #define SMAATexture2D(tex) sampler2D tex
974 #define SMAATexturePass2D(tex) tex
975 #define SMAASampleLevelZero(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0))
976 #define SMAASampleLevelZeroPoint(tex, coord) tex2Dlod(tex, float4(coord, 0.0, 0.0))
977 #define SMAASampleLevelZeroOffset(tex, coord, offset) tex2Dlod(tex, float4(coord + offset * SMAA_RT_METRICS.xy, 0.0, 0.0))
978 #define SMAASample(tex, coord) tex2D(tex, coord)
979 #define SMAASamplePoint(tex, coord) tex2D(tex, coord)
980 #define SMAASampleOffset(tex, coord, offset) tex2D(tex, coord + offset * SMAA_RT_METRICS.xy)
981 #define SMAA_FLATTEN [flatten]
982 #define SMAA_BRANCH [branch]
983 #endif
984 #if defined(SMAA_HLSL_4) || defined(SMAA_HLSL_4_1)
985 SamplerState LinearSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; };
986 SamplerState PointSampler { Filter = MIN_MAG_MIP_POINT; AddressU = Clamp; AddressV = Clamp; };
987 #define SMAATexture2D(tex) Texture2D tex
988 #define SMAATexturePass2D(tex) tex
989 #define SMAASampleLevelZero(tex, coord) tex.SampleLevel(LinearSampler, coord, 0)
990 #define SMAASampleLevelZeroPoint(tex, coord) tex.SampleLevel(PointSampler, coord, 0)
991 #define SMAASampleLevelZeroOffset(tex, coord, offset) tex.SampleLevel(LinearSampler, coord, 0, offset)
992 #define SMAASample(tex, coord) tex.Sample(LinearSampler, coord)
993 #define SMAASamplePoint(tex, coord) tex.Sample(PointSampler, coord)
994 #define SMAASampleOffset(tex, coord, offset) tex.Sample(LinearSampler, coord, offset)
995 #define SMAA_FLATTEN [flatten]
996 #define SMAA_BRANCH [branch]
997 #define SMAATexture2DMS2(tex) Texture2DMS<float4, 2> tex
998 #define SMAALoad(tex, pos, sample) tex.Load(pos, sample)
999 #if defined(SMAA_HLSL_4_1)
1000 #define SMAAGather(tex, coord) tex.Gather(LinearSampler, coord, 0)
1001 #endif
1002 #endif
1003 #if defined(SMAA_GLSL_2_1) || defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4)
1004 #define SMAATexture2D(tex) sampler2D tex
1005 #define SMAATexturePass2D(tex) tex
1006 #define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0)
1007 #define SMAASampleLevelZeroPoint(tex, coord) textureLod(tex, coord, 0.0)
1008 #define SMAASampleLevelZeroOffset(tex, coord, offset) textureLodOffset(tex, coord, 0.0, offset)
1009 #if defined(SMAA_GLSL_2_1)
1010 #define SMAASample(tex, coord) texture2D(tex, coord)
1011 #define SMAASamplePoint(tex, coord) texture2D(tex, coord)
1012 #define SMAASampleOffset(tex, coord, offset) texture2D(tex, coord + offset * SMAA_RT_METRICS.rg)
1013 #define round(x) floor(x + 0.5)
1014 #define textureLod(tex, coord, level) texture2D(tex, coord)
1015 #define textureLodOffset(tex, coord, level, offset) texture2D(tex, coord + offset * SMAA_RT_METRICS.rg)
1016 #else
1017 #define SMAASample(tex, coord) texture(tex, coord)
1018 #define SMAASamplePoint(tex, coord) texture(tex, coord)
1019 #define SMAASampleOffset(tex, coord, offset) texture(tex, coord, offset)
1020 #endif
1021 #define SMAA_FLATTEN
1022 #define SMAA_BRANCH
1023 #define lerp(a, b, t) mix(a, b, t)
1024 #define saturate(a) clamp(a, 0.0, 1.0)
1025 #if defined(SMAA_GLSL_4)
1026 #define mad(a, b, c) fma(a, b, c)
1027 #define SMAAGather(tex, coord) textureGather(tex, coord)
1028 #else
1029 #define mad(a, b, c) (a * b + c)
1030 #endif
1031 #define float2 vec2
1032 #define float3 vec3
1033 #define float4 vec4
1034 #define int2 ivec2
1035 #define int3 ivec3
1036 #define int4 ivec4
1037 #define bool2 bvec2
1038 #define bool3 bvec3
1039 #define bool4 bvec4
1040 #endif
1041 
1042 #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)
1043 #error you must define the shading language: SMAA_HLSL_*, SMAA_GLSL_* or SMAA_CUSTOM_SL
1044 #endif
1045 
1046 //-----------------------------------------------------------------------------
1047 // Misc functions
1048 
1052 float3 SMAAGatherNeighbours(float2 texcoord,
1053  float4 offset[3],
1054  SMAATexture2D(tex)) {
1055  #ifdef SMAAGather
1056  return SMAAGather(tex, texcoord + SMAA_RT_METRICS.xy * float2(-0.5, -0.5)).grb;
1057  #else
1058  float P = SMAASamplePoint(tex, texcoord).r;
1059  float Pleft = SMAASamplePoint(tex, offset[0].xy).r;
1060  float Ptop = SMAASamplePoint(tex, offset[0].zw).r;
1061  return float3(P, Pleft, Ptop);
1062  #endif
1063 }
1064 
1068 float2 SMAACalculatePredicatedThreshold(float2 texcoord,
1069  float4 offset[3],
1070  SMAATexture2D(predicationTex)) {
1071  float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(predicationTex));
1072  float2 delta = abs(neighbours.xx - neighbours.yz);
1073  float2 edges = step(SMAA_PREDICATION_THRESHOLD, delta);
1074  return SMAA_PREDICATION_SCALE * SMAA_THRESHOLD * (1.0 - SMAA_PREDICATION_STRENGTH * edges);
1075 }
1076 
1080 void SMAAMovc(bool2 cond, inout float2 variable, float2 value) {
1081  SMAA_FLATTEN if (cond.x) variable.x = value.x;
1082  SMAA_FLATTEN if (cond.y) variable.y = value.y;
1083 }
1084 
1085 void SMAAMovc(bool4 cond, inout float4 variable, float4 value) {
1086  SMAAMovc(cond.xy, variable.xy, value.xy);
1087  SMAAMovc(cond.zw, variable.zw, value.zw);
1088 }
1089 
1090 
1091 #if SMAA_INCLUDE_VS
1092 //-----------------------------------------------------------------------------
1093 // Vertex Shaders
1094 
1098 void SMAAEdgeDetectionVS(float2 texcoord,
1099  out float4 offset[3]) {
1100  offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-1.0, 0.0, 0.0, -1.0), texcoord.xyxy);
1101  offset[1] = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy);
1102  offset[2] = mad(SMAA_RT_METRICS.xyxy, float4(-2.0, 0.0, 0.0, -2.0), texcoord.xyxy);
1103 }
1104 
1108 void SMAABlendingWeightCalculationVS(float2 texcoord,
1109  out float2 pixcoord,
1110  out float4 offset[3]) {
1111  pixcoord = texcoord * SMAA_RT_METRICS.zw;
1112 
1113  // We will use these offsets for the searches later on (see @PSEUDO_GATHER4):
1114  offset[0] = mad(SMAA_RT_METRICS.xyxy, float4(-0.25, -0.125, 1.25, -0.125), texcoord.xyxy);
1115  offset[1] = mad(SMAA_RT_METRICS.xyxy, float4(-0.125, -0.25, -0.125, 1.25), texcoord.xyxy);
1116 
1117  // And these for the searches, they indicate the ends of the loops:
1118  offset[2] = mad(SMAA_RT_METRICS.xxyy,
1119  float4(-2.0, 2.0, -2.0, 2.0) * float(SMAA_MAX_SEARCH_STEPS),
1120  float4(offset[0].xz, offset[1].yw));
1121 }
1122 
1126 void SMAANeighborhoodBlendingVS(float2 texcoord,
1127  out float4 offset) {
1128  offset = mad(SMAA_RT_METRICS.xyxy, float4( 1.0, 0.0, 0.0, 1.0), texcoord.xyxy);
1129 }
1130 #endif // SMAA_INCLUDE_VS
1131 
1132 #if SMAA_INCLUDE_PS
1133 //-----------------------------------------------------------------------------
1134 // Edge Detection Pixel Shaders (First Pass)
1135 
1142 float2 SMAALumaEdgeDetectionPS(float2 texcoord,
1143  float4 offset[3],
1144  SMAATexture2D(colorTex)
1145  #if SMAA_PREDICATION
1146  , SMAATexture2D(predicationTex)
1147  #endif
1148  ) {
1149  // Calculate the threshold:
1150  #if SMAA_PREDICATION
1151  float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, SMAATexturePass2D(predicationTex));
1152  #else
1153  float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
1154  #endif
1155 
1156  // Calculate lumas:
1157  float3 weights = float3(0.2126, 0.7152, 0.0722);
1158  float L = dot(SMAASamplePoint(colorTex, texcoord).rgb, weights);
1159 
1160  float Lleft = dot(SMAASamplePoint(colorTex, offset[0].xy).rgb, weights);
1161  float Ltop = dot(SMAASamplePoint(colorTex, offset[0].zw).rgb, weights);
1162 
1163  // We do the usual threshold:
1164  float4 delta;
1165  delta.xy = abs(L - float2(Lleft, Ltop));
1166  float2 edges = step(threshold, delta.xy);
1167 
1168  // Then discard if there is no edge:
1169  if (dot(edges, float2(1.0, 1.0)) == 0.0)
1170  discard;
1171 
1172  // Calculate right and bottom deltas:
1173  float Lright = dot(SMAASamplePoint(colorTex, offset[1].xy).rgb, weights);
1174  float Lbottom = dot(SMAASamplePoint(colorTex, offset[1].zw).rgb, weights);
1175  delta.zw = abs(L - float2(Lright, Lbottom));
1176 
1177  // Calculate the maximum delta in the direct neighborhood:
1178  float2 maxDelta = max(delta.xy, delta.zw);
1179 
1180  // Calculate left-left and top-top deltas:
1181  float Lleftleft = dot(SMAASamplePoint(colorTex, offset[2].xy).rgb, weights);
1182  float Ltoptop = dot(SMAASamplePoint(colorTex, offset[2].zw).rgb, weights);
1183  delta.zw = abs(float2(Lleft, Ltop) - float2(Lleftleft, Ltoptop));
1184 
1185  // Calculate the final maximum delta:
1186  maxDelta = max(maxDelta.xy, delta.zw);
1187  float finalDelta = max(maxDelta.x, maxDelta.y);
1188 
1189  // Local contrast adaptation:
1190  edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
1191 
1192  return edges;
1193 }
1194 
1201 float2 SMAAColorEdgeDetectionPS(float2 texcoord,
1202  float4 offset[3],
1203  SMAATexture2D(colorTex)
1204  #if SMAA_PREDICATION
1205  , SMAATexture2D(predicationTex)
1206  #endif
1207  ) {
1208  // Calculate the threshold:
1209  #if SMAA_PREDICATION
1210  float2 threshold = SMAACalculatePredicatedThreshold(texcoord, offset, predicationTex);
1211  #else
1212  float2 threshold = float2(SMAA_THRESHOLD, SMAA_THRESHOLD);
1213  #endif
1214 
1215  // Calculate color deltas:
1216  float4 delta;
1217  float3 C = SMAASamplePoint(colorTex, texcoord).rgb;
1218 
1219  float3 Cleft = SMAASamplePoint(colorTex, offset[0].xy).rgb;
1220  float3 t = abs(C - Cleft);
1221  delta.x = max(max(t.r, t.g), t.b);
1222 
1223  float3 Ctop = SMAASamplePoint(colorTex, offset[0].zw).rgb;
1224  t = abs(C - Ctop);
1225  delta.y = max(max(t.r, t.g), t.b);
1226 
1227  // We do the usual threshold:
1228  float2 edges = step(threshold, delta.xy);
1229 
1230  // Then discard if there is no edge:
1231  if (dot(edges, float2(1.0, 1.0)) == 0.0)
1232  discard;
1233 
1234  // Calculate right and bottom deltas:
1235  float3 Cright = SMAASamplePoint(colorTex, offset[1].xy).rgb;
1236  t = abs(C - Cright);
1237  delta.z = max(max(t.r, t.g), t.b);
1238 
1239  float3 Cbottom = SMAASamplePoint(colorTex, offset[1].zw).rgb;
1240  t = abs(C - Cbottom);
1241  delta.w = max(max(t.r, t.g), t.b);
1242 
1243  // Calculate the maximum delta in the direct neighborhood:
1244  float2 maxDelta = max(delta.xy, delta.zw);
1245 
1246  // Calculate left-left and top-top deltas:
1247  float3 Cleftleft = SMAASamplePoint(colorTex, offset[2].xy).rgb;
1248  t = abs(C - Cleftleft);
1249  delta.z = max(max(t.r, t.g), t.b);
1250 
1251  float3 Ctoptop = SMAASamplePoint(colorTex, offset[2].zw).rgb;
1252  t = abs(C - Ctoptop);
1253  delta.w = max(max(t.r, t.g), t.b);
1254 
1255  // Calculate the final maximum delta:
1256  maxDelta = max(maxDelta.xy, delta.zw);
1257  float finalDelta = max(maxDelta.x, maxDelta.y);
1258 
1259  // Local contrast adaptation:
1260  edges.xy *= step(finalDelta, SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR * delta.xy);
1261 
1262  return edges;
1263 }
1264 )SHADER_SOURCE";
1265 
1266 extern const char smaa_base_shader_p3[] = R"SHADER_SOURCE(
1270 float2 SMAADepthEdgeDetectionPS(float2 texcoord,
1271  float4 offset[3],
1272  SMAATexture2D(depthTex)) {
1273  float3 neighbours = SMAAGatherNeighbours(texcoord, offset, SMAATexturePass2D(depthTex));
1274  float2 delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z));
1275  float2 edges = step(SMAA_DEPTH_THRESHOLD, delta);
1276 
1277  if (dot(edges, float2(1.0, 1.0)) == 0.0)
1278  discard;
1279 
1280  return edges;
1281 }
1282 
1283 //-----------------------------------------------------------------------------
1284 // Diagonal Search Functions
1285 
1286 #if !defined(SMAA_DISABLE_DIAG_DETECTION)
1287 
1291 float2 SMAADecodeDiagBilinearAccess(float2 e) {
1292  // Bilinear access for fetching 'e' have a 0.25 offset, and we are
1293  // interested in the R and G edges:
1294  //
1295  // +---G---+-------+
1296  // | x o R x |
1297  // +-------+-------+
1298  //
1299  // Then, if one of these edge is enabled:
1300  // Red: (0.75 * X + 0.25 * 1) => 0.25 or 1.0
1301  // Green: (0.75 * 1 + 0.25 * X) => 0.75 or 1.0
1302  //
1303  // This function will unpack the values (mad + mul + round):
1304  // wolframalpha.com: round(x * abs(5 * x - 5 * 0.75)) plot 0 to 1
1305  e.r = e.r * abs(5.0 * e.r - 5.0 * 0.75);
1306  return round(e);
1307 }
1308 
1309 float4 SMAADecodeDiagBilinearAccess(float4 e) {
1310  e.rb = e.rb * abs(5.0 * e.rb - 5.0 * 0.75);
1311  return round(e);
1312 }
1313 
1317 float2 SMAASearchDiag1(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) {
1318  float4 coord = float4(texcoord, -1.0, 1.0);
1319  float3 t = float3(SMAA_RT_METRICS.xy, 1.0);
1320  while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) &&
1321  coord.w > 0.9) {
1322  coord.xyz = mad(t, float3(dir, 1.0), coord.xyz);
1323  e = SMAASampleLevelZero(edgesTex, coord.xy).rg;
1324  coord.w = dot(e, float2(0.5, 0.5));
1325  }
1326  return coord.zw;
1327 }
1328 
1329 float2 SMAASearchDiag2(SMAATexture2D(edgesTex), float2 texcoord, float2 dir, out float2 e) {
1330  float4 coord = float4(texcoord, -1.0, 1.0);
1331  coord.x += 0.25 * SMAA_RT_METRICS.x; // See @SearchDiag2Optimization
1332  float3 t = float3(SMAA_RT_METRICS.xy, 1.0);
1333  while (coord.z < float(SMAA_MAX_SEARCH_STEPS_DIAG - 1) &&
1334  coord.w > 0.9) {
1335  coord.xyz = mad(t, float3(dir, 1.0), coord.xyz);
1336 
1337  // @SearchDiag2Optimization
1338  // Fetch both edges at once using bilinear filtering:
1339  e = SMAASampleLevelZero(edgesTex, coord.xy).rg;
1340  e = SMAADecodeDiagBilinearAccess(e);
1341 
1342  // Non-optimized version:
1343  // e.g = SMAASampleLevelZero(edgesTex, coord.xy).g;
1344  // e.r = SMAASampleLevelZeroOffset(edgesTex, coord.xy, int2(1, 0)).r;
1345 
1346  coord.w = dot(e, float2(0.5, 0.5));
1347  }
1348  return coord.zw;
1349 }
1350 
1355 float2 SMAAAreaDiag(SMAATexture2D(areaTex), float2 dist, float2 e, float offset) {
1356  float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE_DIAG, SMAA_AREATEX_MAX_DISTANCE_DIAG), e, dist);
1357 
1358  // We do a scale and bias for mapping to texel space:
1359  texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
1360 
1361  // Diagonal areas are on the second half of the texture:
1362  texcoord.x += 0.5;
1363 
1364  // Move to proper place, according to the subpixel offset:
1365  texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;
1366 
1367  // Do it!
1368  return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
1369 }
1370 
1374 float2 SMAACalculateDiagWeights(SMAATexture2D(edgesTex), SMAATexture2D(areaTex), float2 texcoord, float2 e, float4 subsampleIndices) {
1375  float2 weights = float2(0.0, 0.0);
1376 
1377  // Search for the line ends:
1378  float4 d;
1379  float2 end;
1380  if (e.r > 0.0) {
1381  d.xz = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, 1.0), end);
1382  d.x += float(end.y > 0.9);
1383  } else
1384  d.xz = float2(0.0, 0.0);
1385  d.yw = SMAASearchDiag1(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, -1.0), end);
1386 
1387  SMAA_BRANCH
1388  if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3
1389  // Fetch the crossing edges:
1390  float4 coords = mad(float4(-d.x + 0.25, d.x, d.y, -d.y - 0.25), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
1391  float4 c;
1392  c.xy = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).rg;
1393  c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).rg;
1394  c.yxwz = SMAADecodeDiagBilinearAccess(c.xyzw);
1395 
1396  // Non-optimized version:
1397  // float4 coords = mad(float4(-d.x, d.x, d.y, -d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
1398  // float4 c;
1399  // c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g;
1400  // c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, 0)).r;
1401  // c.z = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).g;
1402  // c.w = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, -1)).r;
1403 
1404  // Merge crossing edges at each side into a single value:
1405  float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw);
1406 
1407  // Remove the crossing edge if we didn't found the end of the line:
1408  SMAAMovc(bool2(step(0.9, d.zw)), cc, float2(0.0, 0.0));
1409 
1410  // Fetch the areas for this line:
1411  weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.z);
1412  }
1413 
1414  // Search for the line ends:
1415  d.xz = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(-1.0, -1.0), end);
1416  if (SMAASampleLevelZeroOffset(edgesTex, texcoord, int2(1, 0)).r > 0.0) {
1417  d.yw = SMAASearchDiag2(SMAATexturePass2D(edgesTex), texcoord, float2(1.0, 1.0), end);
1418  d.y += float(end.y > 0.9);
1419  } else
1420  d.yw = float2(0.0, 0.0);
1421 
1422  SMAA_BRANCH
1423  if (d.x + d.y > 2.0) { // d.x + d.y + 1 > 3
1424  // Fetch the crossing edges:
1425  float4 coords = mad(float4(-d.x, -d.x, d.y, d.y), SMAA_RT_METRICS.xyxy, texcoord.xyxy);
1426  float4 c;
1427  c.x = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2(-1, 0)).g;
1428  c.y = SMAASampleLevelZeroOffset(edgesTex, coords.xy, int2( 0, -1)).r;
1429  c.zw = SMAASampleLevelZeroOffset(edgesTex, coords.zw, int2( 1, 0)).gr;
1430  float2 cc = mad(float2(2.0, 2.0), c.xz, c.yw);
1431 
1432  // Remove the crossing edge if we didn't found the end of the line:
1433  SMAAMovc(bool2(step(0.9, d.zw)), cc, float2(0.0, 0.0));
1434 
1435  // Fetch the areas for this line:
1436  weights += SMAAAreaDiag(SMAATexturePass2D(areaTex), d.xy, cc, subsampleIndices.w).gr;
1437  }
1438 
1439  return weights;
1440 }
1441 #endif
1442 
1443 //-----------------------------------------------------------------------------
1444 // Horizontal/Vertical Search Functions
1445 
1452 float SMAASearchLength(SMAATexture2D(searchTex), float2 e, float offset) {
1453  // The texture is flipped vertically, with left and right cases taking half
1454  // of the space horizontally:
1455  float2 scale = SMAA_SEARCHTEX_SIZE * float2(0.5, -1.0);
1456  float2 bias = SMAA_SEARCHTEX_SIZE * float2(offset, 1.0);
1457 
1458  // Scale and bias to access texel centers:
1459  scale += float2(-1.0, 1.0);
1460  bias += float2( 0.5, -0.5);
1461 
1462  // Convert from pixel coordinates to texcoords:
1463  // (We use SMAA_SEARCHTEX_PACKED_SIZE because the texture is cropped)
1464  scale *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
1465  bias *= 1.0 / SMAA_SEARCHTEX_PACKED_SIZE;
1466 
1467  // Lookup the search texture:
1468  return SMAA_SEARCHTEX_SELECT(SMAASampleLevelZero(searchTex, mad(scale, e, bias)));
1469 }
1470 
1474 float SMAASearchXLeft(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1482  float2 e = float2(0.0, 1.0);
1483  while (texcoord.x > end &&
1484  e.g > 0.8281 && // Is there some edge not activated?
1485  e.r == 0.0) { // Or is there a crossing edge that breaks the line?
1486  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1487  texcoord = mad(-float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord);
1488  }
1489 
1490  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0), 3.25);
1491  return mad(SMAA_RT_METRICS.x, offset, texcoord.x);
1492 
1493  // Non-optimized version:
1494  // We correct the previous (-0.25, -0.125) offset we applied:
1495  // texcoord.x += 0.25 * SMAA_RT_METRICS.x;
1496 
1497  // The searches are bias by 1, so adjust the coords accordingly:
1498  // texcoord.x += SMAA_RT_METRICS.x;
1499 
1500  // Disambiguate the length added by the last step:
1501  // texcoord.x += 2.0 * SMAA_RT_METRICS.x; // Undo last step
1502  // texcoord.x -= SMAA_RT_METRICS.x * (255.0 / 127.0) * SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0);
1503  // return mad(SMAA_RT_METRICS.x, offset, texcoord.x);
1504 }
1505 
1506 float SMAASearchXRight(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1507  float2 e = float2(0.0, 1.0);
1508  while (texcoord.x < end &&
1509  e.g > 0.8281 && // Is there some edge not activated?
1510  e.r == 0.0) { // Or is there a crossing edge that breaks the line?
1511  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1512  texcoord = mad(float2(2.0, 0.0), SMAA_RT_METRICS.xy, texcoord);
1513  }
1514  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.5), 3.25);
1515  return mad(-SMAA_RT_METRICS.x, offset, texcoord.x);
1516 }
1517 
1518 float SMAASearchYUp(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1519  float2 e = float2(1.0, 0.0);
1520  while (texcoord.y > end &&
1521  e.r > 0.8281 && // Is there some edge not activated?
1522  e.g == 0.0) { // Or is there a crossing edge that breaks the line?
1523  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1524  texcoord = mad(-float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord);
1525  }
1526  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.0), 3.25);
1527  return mad(SMAA_RT_METRICS.y, offset, texcoord.y);
1528 }
1529 
1530 float SMAASearchYDown(SMAATexture2D(edgesTex), SMAATexture2D(searchTex), float2 texcoord, float end) {
1531  float2 e = float2(1.0, 0.0);
1532  while (texcoord.y < end &&
1533  e.r > 0.8281 && // Is there some edge not activated?
1534  e.g == 0.0) { // Or is there a crossing edge that breaks the line?
1535  e = SMAASampleLevelZero(edgesTex, texcoord).rg;
1536  texcoord = mad(float2(0.0, 2.0), SMAA_RT_METRICS.xy, texcoord);
1537  }
1538  float offset = mad(-(255.0 / 127.0), SMAASearchLength(SMAATexturePass2D(searchTex), e.gr, 0.5), 3.25);
1539  return mad(-SMAA_RT_METRICS.y, offset, texcoord.y);
1540 }
1541 
1546 float2 SMAAArea(SMAATexture2D(areaTex), float2 dist, float e1, float e2, float offset) {
1547  // Rounding prevents precision errors of bilinear filtering:
1548  float2 texcoord = mad(float2(SMAA_AREATEX_MAX_DISTANCE, SMAA_AREATEX_MAX_DISTANCE), round(4.0 * float2(e1, e2)), dist);
1549 
1550  // We do a scale and bias for mapping to texel space:
1551  texcoord = mad(SMAA_AREATEX_PIXEL_SIZE, texcoord, 0.5 * SMAA_AREATEX_PIXEL_SIZE);
1552 
1553  // Move to proper place, according to the subpixel offset:
1554  texcoord.y = mad(SMAA_AREATEX_SUBTEX_SIZE, offset, texcoord.y);
1555 
1556  // Do it!
1557  return SMAA_AREATEX_SELECT(SMAASampleLevelZero(areaTex, texcoord));
1558 }
1559 
1560 //-----------------------------------------------------------------------------
1561 // Corner Detection Functions
1562 
1563 void SMAADetectHorizontalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) {
1564  #if !defined(SMAA_DISABLE_CORNER_DETECTION)
1565  float2 leftRight = step(d.xy, d.yx);
1566  float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight;
1567 
1568  rounding /= leftRight.x + leftRight.y; // Reduce blending for pixels in the center of a line.
1569 
1570  float2 factor = float2(1.0, 1.0);
1571  factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, 1)).r;
1572  factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, 1)).r;
1573  factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(0, -2)).r;
1574  factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(1, -2)).r;
1575 
1576  weights *= saturate(factor);
1577  #endif
1578 }
1579 
1580 void SMAADetectVerticalCornerPattern(SMAATexture2D(edgesTex), inout float2 weights, float4 texcoord, float2 d) {
1581  #if !defined(SMAA_DISABLE_CORNER_DETECTION)
1582  float2 leftRight = step(d.xy, d.yx);
1583  float2 rounding = (1.0 - SMAA_CORNER_ROUNDING_NORM) * leftRight;
1584 
1585  rounding /= leftRight.x + leftRight.y;
1586 
1587  float2 factor = float2(1.0, 1.0);
1588  factor.x -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2( 1, 0)).g;
1589  factor.x -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2( 1, 1)).g;
1590  factor.y -= rounding.x * SMAASampleLevelZeroOffset(edgesTex, texcoord.xy, int2(-2, 0)).g;
1591  factor.y -= rounding.y * SMAASampleLevelZeroOffset(edgesTex, texcoord.zw, int2(-2, 1)).g;
1592 
1593  weights *= saturate(factor);
1594  #endif
1595 }
1596 
1597 //-----------------------------------------------------------------------------
1598 // Blending Weight Calculation Pixel Shader (Second Pass)
1599 
1600 float4 SMAABlendingWeightCalculationPS(float2 texcoord,
1601  float2 pixcoord,
1602  float4 offset[3],
1603  SMAATexture2D(edgesTex),
1604  SMAATexture2D(areaTex),
1605  SMAATexture2D(searchTex),
1606  float4 subsampleIndices) { // Just pass zero for SMAA 1x, see @SUBSAMPLE_INDICES.
1607  float4 weights = float4(0.0, 0.0, 0.0, 0.0);
1608 
1609  float2 e = SMAASample(edgesTex, texcoord).rg;
1610 
1611  SMAA_BRANCH
1612  if (e.g > 0.0) { // Edge at north
1613  #if !defined(SMAA_DISABLE_DIAG_DETECTION)
1614  // Diagonals have both north and west edges, so searching for them in
1615  // one of the boundaries is enough.
1616  weights.rg = SMAACalculateDiagWeights(SMAATexturePass2D(edgesTex), SMAATexturePass2D(areaTex), texcoord, e, subsampleIndices);
1617 
1618  // We give priority to diagonals, so if we find a diagonal we skip
1619  // horizontal/vertical processing.
1620  SMAA_BRANCH
1621  if (weights.r == -weights.g) { // weights.r + weights.g == 0.0
1622  #endif
1623 
1624  float2 d;
1625 
1626  // Find the distance to the left:
1627  float3 coords;
1628  coords.x = SMAASearchXLeft(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].xy, offset[2].x);
1629  coords.y = offset[1].y; // offset[1].y = texcoord.y - 0.25 * SMAA_RT_METRICS.y (@CROSSING_OFFSET)
1630  d.x = coords.x;
1631 
1632  // Now fetch the left crossing edges, two at a time using bilinear
1633  // filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to
1634  // discern what value each edge has:
1635  float e1 = SMAASampleLevelZero(edgesTex, coords.xy).r;
1636 
1637  // Find the distance to the right:
1638  coords.z = SMAASearchXRight(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[0].zw, offset[2].y);
1639  d.y = coords.z;
1640 
1641  // We want the distances to be in pixel units (doing this here allow one
1642  // to better interleave arithmetic and memory accesses):
1643  d = abs(round(mad(SMAA_RT_METRICS.zz, d, -pixcoord.xx)));
1644 
1645  // SMAAArea below needs a sqrt, as the areas texture is compressed
1646  // quadratically:
1647  float2 sqrt_d = sqrt(d);
1648 )SHADER_SOURCE";
1649 
1650 extern const char smaa_base_shader_p4[] = R"SHADER_SOURCE(
1651  // Fetch the right crossing edges:
1652  float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.zy, int2(1, 0)).r;
1653 
1654  // Ok, we know how this pattern looks like, now it is time for getting
1655  // the actual area:
1656  weights.rg = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.y);
1657 
1658  // Fix corners:
1659  coords.y = texcoord.y;
1660  SMAADetectHorizontalCornerPattern(SMAATexturePass2D(edgesTex), weights.rg, coords.xyzy, d);
1661 
1662  #if !defined(SMAA_DISABLE_DIAG_DETECTION)
1663  } else
1664  e.r = 0.0; // Skip vertical processing.
1665  #endif
1666  }
1667 
1668  SMAA_BRANCH
1669  if (e.r > 0.0) { // Edge at west
1670  float2 d;
1671 
1672  // Find the distance to the top:
1673  float3 coords;
1674  coords.y = SMAASearchYUp(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].xy, offset[2].z);
1675  coords.x = offset[0].x; // offset[1].x = texcoord.x - 0.25 * SMAA_RT_METRICS.x;
1676  d.x = coords.y;
1677 
1678  // Fetch the top crossing edges:
1679  float e1 = SMAASampleLevelZero(edgesTex, coords.xy).g;
1680 
1681  // Find the distance to the bottom:
1682  coords.z = SMAASearchYDown(SMAATexturePass2D(edgesTex), SMAATexturePass2D(searchTex), offset[1].zw, offset[2].w);
1683  d.y = coords.z;
1684 
1685  // We want the distances to be in pixel units:
1686  d = abs(round(mad(SMAA_RT_METRICS.ww, d, -pixcoord.yy)));
1687 
1688  // SMAAArea below needs a sqrt, as the areas texture is compressed
1689  // quadratically:
1690  float2 sqrt_d = sqrt(d);
1691 
1692  // Fetch the bottom crossing edges:
1693  float e2 = SMAASampleLevelZeroOffset(edgesTex, coords.xz, int2(0, 1)).g;
1694 
1695  // Get the area for this direction:
1696  weights.ba = SMAAArea(SMAATexturePass2D(areaTex), sqrt_d, e1, e2, subsampleIndices.x);
1697 
1698  // Fix corners:
1699  coords.x = texcoord.x;
1700  SMAADetectVerticalCornerPattern(SMAATexturePass2D(edgesTex), weights.ba, coords.xyxz, d);
1701  }
1702 
1703  return weights;
1704 }
1705 
1706 //-----------------------------------------------------------------------------
1707 // Neighborhood Blending Pixel Shader (Third Pass)
1708 
1709 float4 SMAANeighborhoodBlendingPS(float2 texcoord,
1710  float4 offset,
1711  SMAATexture2D(colorTex),
1712  SMAATexture2D(blendTex)
1713  #if SMAA_REPROJECTION
1714  , SMAATexture2D(velocityTex)
1715  #endif
1716  ) {
1717  // Fetch the blending weights for current pixel:
1718  float4 a;
1719  a.x = SMAASample(blendTex, offset.xy).a; // Right
1720  a.y = SMAASample(blendTex, offset.zw).g; // Top
1721  a.wz = SMAASample(blendTex, texcoord).xz; // Bottom / Left
1722 
1723  // Is there any blending weight with a value greater than 0.0?
1724  SMAA_BRANCH
1725  if (dot(a, float4(1.0, 1.0, 1.0, 1.0)) < 1e-5) {
1726  float4 color = SMAASampleLevelZero(colorTex, texcoord);
1727 
1728  #if SMAA_REPROJECTION
1729  float2 velocity = SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, texcoord));
1730 
1731  // Pack velocity into the alpha channel:
1732  color.a = sqrt(5.0 * length(velocity));
1733  #endif
1734 
1735  return color;
1736  } else {
1737  bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical)
1738 
1739  // Calculate the blending offsets:
1740  float4 blendingOffset = float4(0.0, a.y, 0.0, a.w);
1741  float2 blendingWeight = a.yw;
1742  SMAAMovc(bool4(h, h, h, h), blendingOffset, float4(a.x, 0.0, a.z, 0.0));
1743  SMAAMovc(bool2(h, h), blendingWeight, a.xz);
1744  blendingWeight /= dot(blendingWeight, float2(1.0, 1.0));
1745 
1746  // Calculate the texture coordinates:
1747  float4 blendingCoord = mad(blendingOffset, float4(SMAA_RT_METRICS.xy, -SMAA_RT_METRICS.xy), texcoord.xyxy);
1748 
1749  // We exploit bilinear filtering to mix current pixel with the chosen
1750  // neighbor:
1751  float4 color = blendingWeight.x * SMAASampleLevelZero(colorTex, blendingCoord.xy);
1752  color += blendingWeight.y * SMAASampleLevelZero(colorTex, blendingCoord.zw);
1753 
1754  #if SMAA_REPROJECTION
1755  // Antialias velocity for proper reprojection in a later stage:
1756  float2 velocity = blendingWeight.x * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.xy));
1757  velocity += blendingWeight.y * SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, blendingCoord.zw));
1758 
1759  // Pack velocity into the alpha channel:
1760  color.a = sqrt(5.0 * length(velocity));
1761  #endif
1762 
1763  return color;
1764  }
1765 }
1766 
1767 //-----------------------------------------------------------------------------
1768 // Temporal Resolve Pixel Shader (Optional Pass)
1769 
1770 float4 SMAAResolvePS(float2 texcoord,
1771  SMAATexture2D(currentColorTex),
1772  SMAATexture2D(previousColorTex)
1773  #if SMAA_REPROJECTION
1774  , SMAATexture2D(velocityTex)
1775  #endif
1776  ) {
1777  #if SMAA_REPROJECTION
1778  // Velocity is assumed to be calculated for motion blur, so we need to
1779  // inverse it for reprojection:
1780  float2 velocity = -SMAA_DECODE_VELOCITY(SMAASamplePoint(velocityTex, texcoord).rg);
1781 
1782  // Fetch current pixel:
1783  float4 current = SMAASamplePoint(currentColorTex, texcoord);
1784 
1785  // Reproject current coordinates and fetch previous pixel:
1786  float4 previous = SMAASamplePoint(previousColorTex, texcoord + velocity);
1787 
1788  // Attenuate the previous pixel if the velocity is different:
1789  float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0;
1790  float weight = 0.5 * saturate(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE);
1791 
1792  // Blend the pixels according to the calculated weight:
1793  return lerp(current, previous, weight);
1794  #else
1795  // Just blend the pixels:
1796  float4 current = SMAASamplePoint(currentColorTex, texcoord);
1797  float4 previous = SMAASamplePoint(previousColorTex, texcoord);
1798  return lerp(current, previous, 0.5);
1799  #endif
1800 }
1801 
1802 //-----------------------------------------------------------------------------
1803 // Separate Multisamples Pixel Shader (Optional Pass)
1804 
1805 #ifdef SMAALoad
1806 void SMAASeparatePS(float4 position,
1807  float2 texcoord,
1808  out float4 target0,
1809  out float4 target1,
1810  SMAATexture2DMS2(colorTexMS)) {
1811  int2 pos = int2(position.xy);
1812  target0 = SMAALoad(colorTexMS, pos, 0);
1813  target1 = SMAALoad(colorTexMS, pos, 1);
1814 }
1815 #endif
1816 
1817 //-----------------------------------------------------------------------------
1818 #endif // SMAA_INCLUDE_PS
1819 
1820 )SHADER_SOURCE";
1821 
1822 const char smaa_pass_1_vertex_shader[] = R"SHADER_SOURCE(
1823 
1824 varying vec4 offset[3];
1825 varying vec2 texcoord;
1826 
1827 void main()
1828 {
1829  texcoord = gl_MultiTexCoord0.st;
1830  SMAAEdgeDetectionVS( texcoord, offset);
1831  gl_Position = ftransform();
1832 
1833 }
1834 
1835 )SHADER_SOURCE";
1836 
1837 const char smaa_pass_1_fragment_shader[] = R"SHADER_SOURCE(
1838 
1839 varying vec2 texcoord;
1840 varying vec4 offset[3];
1841 uniform sampler2D colorTex;
1842 
1843 void main()
1844 {
1845  gl_FragColor.xy = SMAALumaEdgeDetectionPS(texcoord, offset, colorTex).xy;
1846 }
1847 
1848 )SHADER_SOURCE";
1849 
1850 const char smaa_pass_2_vertex_shader[] = R"SHADER_SOURCE(
1851 
1852 varying vec4 offset[3];
1853 varying vec2 texcoord;
1854 varying vec2 pixcoord;
1855 
1856 void main()
1857 {
1858  texcoord = gl_MultiTexCoord0.st;
1859  SMAABlendingWeightCalculationVS( texcoord, pixcoord, offset );
1860  gl_Position = ftransform();
1861 }
1862 
1863 )SHADER_SOURCE";
1864 
1865 const char smaa_pass_2_fragment_shader[] = R"SHADER_SOURCE(
1866 
1867 varying vec2 texcoord;
1868 varying vec2 pixcoord;
1869 varying vec4 offset[3];
1870 uniform sampler2D edgesTex;
1871 uniform sampler2D areaTex;
1872 uniform sampler2D searchTex;
1873 
1874 void main()
1875 {
1876  gl_FragColor = SMAABlendingWeightCalculationPS(texcoord, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0.,0.,0.,0.));
1877 }
1878 
1879 )SHADER_SOURCE";
1880 
1881 const char smaa_pass_3_vertex_shader[] = R"SHADER_SOURCE(
1882 
1883 varying vec4 offset;
1884 varying vec2 texcoord;
1885 
1886 void main()
1887 {
1888  texcoord = gl_MultiTexCoord0.st;
1889  SMAANeighborhoodBlendingVS( texcoord, offset );
1890  gl_Position = ftransform();
1891 }
1892 
1893 )SHADER_SOURCE";
1894 
1895 const char smaa_pass_3_fragment_shader[] = R"SHADER_SOURCE(
1896 
1897 varying vec2 texcoord;
1898 varying vec4 offset;
1899 uniform sampler2D colorTex;
1900 uniform sampler2D blendTex;
1901 
1902 void main()
1903 {
1904  gl_FragColor = SMAANeighborhoodBlendingPS(texcoord, offset, colorTex, blendTex);
1905 }
1906 
1907 )SHADER_SOURCE";
1908 
1909 }
1910 }
1911 
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:131
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[]