893 lines · 32.5 KB · Text
RawDownload
#include <metal_stdlib>#include <simd/simd.h> using namespace metal; float4 hsla_to_rgba(Hsla hsla);float3 srgb_to_linear(float3 color);float3 linear_to_srgb(float3 color);float4 srgb_to_oklab(float4 color);float4 oklab_to_srgb(float4 color);float4 to_device_position(float2 unit_vertex, Bounds_ScaledPixels bounds,                          constant Size_DevicePixels *viewport_size);float4 to_device_position_transformed(float2 unit_vertex, Bounds_ScaledPixels bounds,                          TransformationMatrix transformation,                          constant Size_DevicePixels *input_viewport_size); float2 to_tile_position(float2 unit_vertex, AtlasTile tile,                        constant Size_DevicePixels *atlas_size);float4 distance_from_clip_rect(float2 unit_vertex, Bounds_ScaledPixels bounds,                               Bounds_ScaledPixels clip_bounds);float quad_sdf(float2 point, Bounds_ScaledPixels bounds,               Corners_ScaledPixels corner_radii);float gaussian(float x, float sigma);float2 erf(float2 x);float blur_along_x(float x, float y, float sigma, float corner,                   float2 half_size);float4 over(float4 below, float4 above);float radians(float degrees);float4 fill_color(Background background, float2 position, Bounds_ScaledPixels bounds,  float4 solid_color, float4 color0, float4 color1); struct GradientColor {  float4 solid;  float4 color0;  float4 color1;};GradientColor prepare_fill_color(uint tag, uint color_space, Hsla solid, Hsla color0, Hsla color1); struct QuadVertexOutput {  uint quad_id [[flat]];  float4 position [[position]];  float4 border_color [[flat]];  float4 background_solid [[flat]];  float4 background_color0 [[flat]];  float4 background_color1 [[flat]];  float clip_distance [[clip_distance]][4];}; struct QuadFragmentInput {  uint quad_id [[flat]];  float4 position [[position]];  float4 border_color [[flat]];  float4 background_solid [[flat]];  float4 background_color0 [[flat]];  float4 background_color1 [[flat]];}; vertex QuadVertexOutput quad_vertex(uint unit_vertex_id [[vertex_id]],                                    uint quad_id [[instance_id]],                                    constant float2 *unit_vertices                                    [[buffer(QuadInputIndex_Vertices)]],                                    constant Quad *quads                                    [[buffer(QuadInputIndex_Quads)]],                                    constant Size_DevicePixels *viewport_size                                    [[buffer(QuadInputIndex_ViewportSize)]]) {  float2 unit_vertex = unit_vertices[unit_vertex_id];  Quad quad = quads[quad_id];  float4 device_position =      to_device_position(unit_vertex, quad.bounds, viewport_size);  float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds,                                                 quad.content_mask.bounds);  float4 border_color = hsla_to_rgba(quad.border_color);   GradientColor gradient = prepare_fill_color(    quad.background.tag,    quad.background.color_space,    quad.background.solid,    quad.background.colors[0].color,    quad.background.colors[1].color  );   return QuadVertexOutput{      quad_id,      device_position,      border_color,      gradient.solid,      gradient.color0,      gradient.color1,      {clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};} fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]],                              constant Quad *quads                              [[buffer(QuadInputIndex_Quads)]]) {  Quad quad = quads[input.quad_id];  float2 half_size = float2(quad.bounds.size.width, quad.bounds.size.height) / 2.;  float2 center = float2(quad.bounds.origin.x, quad.bounds.origin.y) + half_size;  float2 center_to_point = input.position.xy - center;  float4 color = fill_color(quad.background, input.position.xy, quad.bounds,    input.background_solid, input.background_color0, input.background_color1);   // Fast path when the quad is not rounded and doesn't have any border.  if (quad.corner_radii.top_left == 0. && quad.corner_radii.bottom_left == 0. &&      quad.corner_radii.top_right == 0. &&      quad.corner_radii.bottom_right == 0. && quad.border_widths.top == 0. &&      quad.border_widths.left == 0. && quad.border_widths.right == 0. &&      quad.border_widths.bottom == 0.) {    return color;  }   float corner_radius;  if (center_to_point.x < 0.) {    if (center_to_point.y < 0.) {      corner_radius = quad.corner_radii.top_left;    } else {      corner_radius = quad.corner_radii.bottom_left;    }  } else {    if (center_to_point.y < 0.) {      corner_radius = quad.corner_radii.top_right;    } else {      corner_radius = quad.corner_radii.bottom_right;    }  }   float2 rounded_edge_to_point =      fabs(center_to_point) - half_size + corner_radius;  float distance =      length(max(0., rounded_edge_to_point)) +      min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) -      corner_radius;   float vertical_border = center_to_point.x <= 0. ? quad.border_widths.left                                                  : quad.border_widths.right;  float horizontal_border = center_to_point.y <= 0. ? quad.border_widths.top                                                    : quad.border_widths.bottom;  float2 inset_size =      half_size - corner_radius - float2(vertical_border, horizontal_border);  float2 point_to_inset_corner = fabs(center_to_point) - inset_size;  float border_width;  if (point_to_inset_corner.x < 0. && point_to_inset_corner.y < 0.) {    border_width = 0.;  } else if (point_to_inset_corner.y > point_to_inset_corner.x) {    border_width = horizontal_border;  } else {    border_width = vertical_border;  }   if (border_width != 0.) {    float inset_distance = distance + border_width;    // Blend the border on top of the background and then linearly interpolate    // between the two as we slide inside the background.    float4 blended_border = over(color, input.border_color);    color = mix(blended_border, color,                saturate(0.5 - inset_distance));  }   return color * float4(1., 1., 1., saturate(0.5 - distance));} struct ShadowVertexOutput {  float4 position [[position]];  float4 color [[flat]];  uint shadow_id [[flat]];  float clip_distance [[clip_distance]][4];}; struct ShadowFragmentInput {  float4 position [[position]];  float4 color [[flat]];  uint shadow_id [[flat]];}; vertex ShadowVertexOutput shadow_vertex(    uint unit_vertex_id [[vertex_id]], uint shadow_id [[instance_id]],    constant float2 *unit_vertices [[buffer(ShadowInputIndex_Vertices)]],    constant Shadow *shadows [[buffer(ShadowInputIndex_Shadows)]],    constant Size_DevicePixels *viewport_size    [[buffer(ShadowInputIndex_ViewportSize)]]) {  float2 unit_vertex = unit_vertices[unit_vertex_id];  Shadow shadow = shadows[shadow_id];   float margin = 3. * shadow.blur_radius;  // Set the bounds of the shadow and adjust its size based on the shadow's  // spread radius to achieve the spreading effect  Bounds_ScaledPixels bounds = shadow.bounds;  bounds.origin.x -= margin;  bounds.origin.y -= margin;  bounds.size.width += 2. * margin;  bounds.size.height += 2. * margin;   float4 device_position =      to_device_position(unit_vertex, bounds, viewport_size);  float4 clip_distance =      distance_from_clip_rect(unit_vertex, bounds, shadow.content_mask.bounds);  float4 color = hsla_to_rgba(shadow.color);   return ShadowVertexOutput{      device_position,      color,      shadow_id,      {clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};} fragment float4 shadow_fragment(ShadowFragmentInput input [[stage_in]],                                constant Shadow *shadows                                [[buffer(ShadowInputIndex_Shadows)]]) {  Shadow shadow = shadows[input.shadow_id];   float2 origin = float2(shadow.bounds.origin.x, shadow.bounds.origin.y);  float2 size = float2(shadow.bounds.size.width, shadow.bounds.size.height);  float2 half_size = size / 2.;  float2 center = origin + half_size;  float2 point = input.position.xy - center;  float corner_radius;  if (point.x < 0.) {    if (point.y < 0.) {      corner_radius = shadow.corner_radii.top_left;    } else {      corner_radius = shadow.corner_radii.bottom_left;    }  } else {    if (point.y < 0.) {      corner_radius = shadow.corner_radii.top_right;    } else {      corner_radius = shadow.corner_radii.bottom_right;    }  }   float alpha;  if (shadow.blur_radius == 0.) {    float distance = quad_sdf(input.position.xy, shadow.bounds, shadow.corner_radii);    alpha = saturate(0.5 - distance);  } else {    // The signal is only non-zero in a limited range, so don't waste samples    float low = point.y - half_size.y;    float high = point.y + half_size.y;    float start = clamp(-3. * shadow.blur_radius, low, high);    float end = clamp(3. * shadow.blur_radius, low, high);     // Accumulate samples (we can get away with surprisingly few samples)    float step = (end - start) / 4.;    float y = start + step * 0.5;    alpha = 0.;    for (int i = 0; i < 4; i++) {      alpha += blur_along_x(point.x, point.y - y, shadow.blur_radius,                            corner_radius, half_size) *               gaussian(y, shadow.blur_radius) * step;      y += step;    }  }   return input.color * float4(1., 1., 1., alpha);} struct UnderlineVertexOutput {  float4 position [[position]];  float4 color [[flat]];  uint underline_id [[flat]];  float clip_distance [[clip_distance]][4];}; struct UnderlineFragmentInput {  float4 position [[position]];  float4 color [[flat]];  uint underline_id [[flat]];}; vertex UnderlineVertexOutput underline_vertex(    uint unit_vertex_id [[vertex_id]], uint underline_id [[instance_id]],    constant float2 *unit_vertices [[buffer(UnderlineInputIndex_Vertices)]],    constant Underline *underlines [[buffer(UnderlineInputIndex_Underlines)]],    constant Size_DevicePixels *viewport_size    [[buffer(ShadowInputIndex_ViewportSize)]]) {  float2 unit_vertex = unit_vertices[unit_vertex_id];  Underline underline = underlines[underline_id];  float4 device_position =      to_device_position(unit_vertex, underline.bounds, viewport_size);  float4 clip_distance = distance_from_clip_rect(unit_vertex, underline.bounds,                                                 underline.content_mask.bounds);  float4 color = hsla_to_rgba(underline.color);  return UnderlineVertexOutput{      device_position,      color,      underline_id,      {clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};} fragment float4 underline_fragment(UnderlineFragmentInput input [[stage_in]],                                   constant Underline *underlines                                   [[buffer(UnderlineInputIndex_Underlines)]]) {  Underline underline = underlines[input.underline_id];  if (underline.wavy) {    float half_thickness = underline.thickness * 0.5;    float2 origin =        float2(underline.bounds.origin.x, underline.bounds.origin.y);    float2 st = ((input.position.xy - origin) / underline.bounds.size.height) -                float2(0., 0.5);    float frequency = (M_PI_F * (3. * underline.thickness)) / 8.;    float amplitude = 1. / (2. * underline.thickness);    float sine = sin(st.x * frequency) * amplitude;    float dSine = cos(st.x * frequency) * amplitude * frequency;    float distance = (st.y - sine) / sqrt(1. + dSine * dSine);    float distance_in_pixels = distance * underline.bounds.size.height;    float distance_from_top_border = distance_in_pixels - half_thickness;    float distance_from_bottom_border = distance_in_pixels + half_thickness;    float alpha = saturate(        0.5 - max(-distance_from_bottom_border, distance_from_top_border));    return input.color * float4(1., 1., 1., alpha);  } else {    return input.color;  }} struct MonochromeSpriteVertexOutput {  float4 position [[position]];  float2 tile_position;  float4 color [[flat]];  float clip_distance [[clip_distance]][4];}; struct MonochromeSpriteFragmentInput {  float4 position [[position]];  float2 tile_position;  float4 color [[flat]];}; vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex(    uint unit_vertex_id [[vertex_id]], uint sprite_id [[instance_id]],    constant float2 *unit_vertices [[buffer(SpriteInputIndex_Vertices)]],    constant MonochromeSprite *sprites [[buffer(SpriteInputIndex_Sprites)]],    constant Size_DevicePixels *viewport_size    [[buffer(SpriteInputIndex_ViewportSize)]],    constant Size_DevicePixels *atlas_size    [[buffer(SpriteInputIndex_AtlasTextureSize)]]) {  float2 unit_vertex = unit_vertices[unit_vertex_id];  MonochromeSprite sprite = sprites[sprite_id];  float4 device_position =      to_device_position_transformed(unit_vertex, sprite.bounds, sprite.transformation, viewport_size);  float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds,                                                 sprite.content_mask.bounds);  float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size);  float4 color = hsla_to_rgba(sprite.color);  return MonochromeSpriteVertexOutput{      device_position,      tile_position,      color,      {clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};} fragment float4 monochrome_sprite_fragment(    MonochromeSpriteFragmentInput input [[stage_in]],    constant MonochromeSprite *sprites [[buffer(SpriteInputIndex_Sprites)]],    texture2d<float> atlas_texture [[texture(SpriteInputIndex_AtlasTexture)]]) {  constexpr sampler atlas_texture_sampler(mag_filter::linear,                                          min_filter::linear);  float4 sample =      atlas_texture.sample(atlas_texture_sampler, input.tile_position);  float4 color = input.color;  color.a *= sample.a;  return color;} struct PolychromeSpriteVertexOutput {  float4 position [[position]];  float2 tile_position;  uint sprite_id [[flat]];  float clip_distance [[clip_distance]][4];}; struct PolychromeSpriteFragmentInput {  float4 position [[position]];  float2 tile_position;  uint sprite_id [[flat]];}; vertex PolychromeSpriteVertexOutput polychrome_sprite_vertex(    uint unit_vertex_id [[vertex_id]], uint sprite_id [[instance_id]],    constant float2 *unit_vertices [[buffer(SpriteInputIndex_Vertices)]],    constant PolychromeSprite *sprites [[buffer(SpriteInputIndex_Sprites)]],    constant Size_DevicePixels *viewport_size    [[buffer(SpriteInputIndex_ViewportSize)]],    constant Size_DevicePixels *atlas_size    [[buffer(SpriteInputIndex_AtlasTextureSize)]]) {   float2 unit_vertex = unit_vertices[unit_vertex_id];  PolychromeSprite sprite = sprites[sprite_id];  float4 device_position =      to_device_position(unit_vertex, sprite.bounds, viewport_size);  float4 clip_distance = distance_from_clip_rect(unit_vertex, sprite.bounds,                                                 sprite.content_mask.bounds);  float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size);  return PolychromeSpriteVertexOutput{      device_position,      tile_position,      sprite_id,      {clip_distance.x, clip_distance.y, clip_distance.z, clip_distance.w}};} fragment float4 polychrome_sprite_fragment(    PolychromeSpriteFragmentInput input [[stage_in]],    constant PolychromeSprite *sprites [[buffer(SpriteInputIndex_Sprites)]],    texture2d<float> atlas_texture [[texture(SpriteInputIndex_AtlasTexture)]]) {  PolychromeSprite sprite = sprites[input.sprite_id];  constexpr sampler atlas_texture_sampler(mag_filter::linear,                                          min_filter::linear);  float4 sample =      atlas_texture.sample(atlas_texture_sampler, input.tile_position);  float distance =      quad_sdf(input.position.xy, sprite.bounds, sprite.corner_radii);   float4 color = sample;  if (sprite.grayscale) {    float grayscale = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;    color.r = grayscale;    color.g = grayscale;    color.b = grayscale;  }  color.a *= sprite.opacity * saturate(0.5 - distance);  return color;} struct PathRasterizationVertexOutput {  float4 position [[position]];  float2 st_position;  float clip_rect_distance [[clip_distance]][4];}; struct PathRasterizationFragmentInput {  float4 position [[position]];  float2 st_position;}; vertex PathRasterizationVertexOutput path_rasterization_vertex(    uint vertex_id [[vertex_id]],    constant PathVertex_ScaledPixels *vertices    [[buffer(PathRasterizationInputIndex_Vertices)]],    constant Size_DevicePixels *atlas_size    [[buffer(PathRasterizationInputIndex_AtlasTextureSize)]]) {  PathVertex_ScaledPixels v = vertices[vertex_id];  float2 vertex_position = float2(v.xy_position.x, v.xy_position.y);  float2 viewport_size = float2(atlas_size->width, atlas_size->height);  return PathRasterizationVertexOutput{      float4(vertex_position / viewport_size * float2(2., -2.) +                 float2(-1., 1.),             0., 1.),      float2(v.st_position.x, v.st_position.y),      {v.xy_position.x - v.content_mask.bounds.origin.x,       v.content_mask.bounds.origin.x + v.content_mask.bounds.size.width -           v.xy_position.x,       v.xy_position.y - v.content_mask.bounds.origin.y,       v.content_mask.bounds.origin.y + v.content_mask.bounds.size.height -           v.xy_position.y}};} fragment float4 path_rasterization_fragment(PathRasterizationFragmentInput input                                            [[stage_in]]) {  float2 dx = dfdx(input.st_position);  float2 dy = dfdy(input.st_position);  float2 gradient = float2((2. * input.st_position.x) * dx.x - dx.y,                           (2. * input.st_position.x) * dy.x - dy.y);  float f = (input.st_position.x * input.st_position.x) - input.st_position.y;  float distance = f / length(gradient);  float alpha = saturate(0.5 - distance);  return float4(alpha, 0., 0., 1.);} struct PathSpriteVertexOutput {  float4 position [[position]];  float2 tile_position;  uint sprite_id [[flat]];  float4 solid_color [[flat]];  float4 color0 [[flat]];  float4 color1 [[flat]];}; vertex PathSpriteVertexOutput path_sprite_vertex(    uint unit_vertex_id [[vertex_id]], uint sprite_id [[instance_id]],    constant float2 *unit_vertices [[buffer(SpriteInputIndex_Vertices)]],    constant PathSprite *sprites [[buffer(SpriteInputIndex_Sprites)]],    constant Size_DevicePixels *viewport_size    [[buffer(SpriteInputIndex_ViewportSize)]],    constant Size_DevicePixels *atlas_size    [[buffer(SpriteInputIndex_AtlasTextureSize)]]) {   float2 unit_vertex = unit_vertices[unit_vertex_id];  PathSprite sprite = sprites[sprite_id];  // Don't apply content mask because it was already accounted for when  // rasterizing the path.  float4 device_position =      to_device_position(unit_vertex, sprite.bounds, viewport_size);  float2 tile_position = to_tile_position(unit_vertex, sprite.tile, atlas_size);   GradientColor gradient = prepare_fill_color(    sprite.color.tag,    sprite.color.color_space,    sprite.color.solid,    sprite.color.colors[0].color,    sprite.color.colors[1].color  );

Lines 1–500 of 893.