Skip to content
  • Content »
  • Fusion »
  • WebGL to DCTL »

Swizzling

Background

WebGL supports the so called swizzling. This is to generate a vector out of single and reordered elements of another vector.

vec3 a(1.,2.);
vec4 b=a.xyxx; // b is (1.,2.,1.,1.)
vec2 c=a.yy // c is (2.,2.)

Swizzling for r-values

We can eliminate this by defines as follows:

#define swixy(V) to_float2((V).x,(V).y)

A typical scenario is the iResolution.xy that you often see in shader code and which would then translate to swixy(iResolution).

As [[Metal]] has full support for swizzling we don't need this workaround here, which would make it:

#if defined (DEVICE_IS_METAL)
  #define swixy(V) (V).xy
#else
  #define swixy(V) to_float2((V).x,(V).y)
#endif

It's simple to extend the list of these defines to whatever is needed in the respective shader:

#ifdef DEVICE_IS_METAL
  #define swixy(V) (V).xy
  #define swiyx(V) (V).yx
  #define swixz(V) (V).xz
  #define swiyz(V) (V).yz
  #define swixyz(V) (V).xyz
  #define swixxy(V) (V).xxy
  #define swixyx(V) (V).xyx
  #define swiyxx(V) (V).yxx
#else
  #define swixy(V) to_float2((V).x,(V).y)
  #define swiyx(V) to_float2((V).y,(V).x)
  #define swixz(V) to_float2((V).x,(V).z)
  #define swiyz(V) to_float2((V).y,(V).z)
  #define swixyz(V) to_float3((V).x,(V).y,(V).z)
  #define swixxy(V) to_float3((V).x,(V).x,(V).y)
  #define swixyx(V) to_float3((V).x,(V).y,(V).x)
  #define swiyxx(V) to_float3((V).y,(V).x,(V).x)
#endif

Swizzling for l-values

But furthermore swizzling is also possible for l-values. Here defines as follow can help, but are not that generic as the above definitions for r-values:

#if defined (DEVICE_IS_METAL)
  #define lswixy(L,R) (L).xy = (R)
  #define lswiyx(L,R) (L).yx = (R)
  #define lswiyz(L,R) (L).yz = (R)
  #define lswixz(L,R) (L).xz = (R)
  #define lswixyz(L,R) (L).xyz = (R)
  // ...
#else
  #define lswixy(L,R) { float2 tmp = (R); (L).x=tmp.x; (L).y=tmp.y; }
  #define lswiyx(L,R) { float2 tmp = (R); (L).y=tmp.x; (L).x=tmp.y; }
  #define lswiyz(L,R) { float2 tmp = (R); (L).y=tmp.x; (L).z=tmp.y; }
  #define lswixz(L,R) { float2 tmp = (R); (L).x=tmp.x; (L).z=tmp.y; }
  #define lswixyz(L,R) { float3 tmp = (R); (L).x=tmp.x; (L).y=tmp.y; (L).z=tmp.z; }
  // ...
#endif

With these ugly little helpers you can make for example a ...
dir.yz=prod_float2_mat2(swiyz(dir),to_mat2(_cosf(an),_sinf(an),-_sinf(an),_cosf(an)));

that would compile neither on OpenCL nor on CUDA, a
lswiyz(dir,prod_float2_mat2(swiyz(dir),to_mat2(_cosf(an),_sinf(an),-_sinf(an),_cosf(an))));

which should run on all platforms.