Search code examples
swiftswiftuimetal

What is the info property of SwiftUI::Layer


What is the info property of SwiftUI::Layer?

I couldn't find any document or resource about it.

It appears in SwiftUI::Layer's definition:

struct Layer {
  metal::texture2d<half> tex;
  float2 info[5];

  /// Samples the layer at `p`, in user-space coordinates,
  /// interpolating linearly between pixel values. Returns an RGBA
  /// pixel value, with color components premultipled by alpha (i.e.
  /// [R*A, G*A, B*A, A]), in the layer's working color space.
  half4 sample(float2 p) const {
    p = metal::fma(p.x, info[0], metal::fma(p.y, info[1], info[2]));
    p = metal::clamp(p, info[3], info[4]);
    return tex.sample(metal::sampler(metal::filter::linear), p);
  }
};

Solution

  • The info field is an implementation detail. You're just supposed to use the sample method.

    However, because the sample method's body is visible, we can figure out what info means.

    Here is the first line of sample:

    p = metal::fma(p.x, info[0], metal::fma(p.y, info[1], info[2]));
    

    The metal::fma(a, b, c) function computes a * b + c, but does so without rounding a * b before adding c. (“fma” stands for “fused multiply-add”.) Ignoring the rounding issue, we can rewrite that line like this:

    p = float2(
      p.x * info[0].x + p.y * info[1].x + info[2].x,
      p.x * info[0].y + p.y * info[1].y + info[2].y
    );
    

    You might recognize this as performing a 2D affine transformation. Mathematically, we typically write it as a vector/matrix multiplication in homogeneous coordinates, like this:

                ⎡ a   b   0 ⎤
    ( x  y  1 ) ⎢ c   d   0 ⎥
                ⎣ tx  ty  1 ⎦
    

    In this case, p = float2(x, y), info[0] = float2(a, b), info[1] = float2(c, d), and info[2] = float2(tx, ty).

    So we can understand the first three elements (at indices 0, 1, and 2) of info as containing a 2D affine transformation matrix which transforms user-space coordinates to texture coordinates.

    Here is the second line of sample:

    p = metal::clamp(p, info[3], info[4]);
    

    This clamps p.x to the range info[3].x ... info[4].x and clamps p.y to the range info[3].y ... info[4].y.

    So we can understand the last two elements (at indices 3 and 4) of info as containing the bounds (in texture coordinates) of the layer's image within the texture tex.