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