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